FPS and SpiderMonkey

Send a fire key pressed, the server side weapon object decides then what it does.



I pass in my networkcode a BitSet with enumerations as index

private static BitSet bitset = new BitSet(Keybind.values().length);



Ina shared class, wich use server and client.



public enum Keybind {

forward,

backward,

strafeleft,

straferight,

sprint,

jump,

duck,

attack,

secattack,

use,

rollleft,

rollright,

hudtoggle

}



Pro: I don’t even need to care wich key the client actually presses, In the game settings it is possible to attach any key to any binding.

Efficient: Each 50ms update the player sends a bitSet with zeros and ones depending if the key/binding is pressed. Serverside that Bitset is stored in the player entity. This entity also have a function



@Override

public boolean inBind(Keybind bind) {

if (keydata == null) {

return false;

}

return keydata.get(bind.ordinal());

}



To allow easy use of the bindings





if (ply.inBind(Keybind.forward)) {

cache = new Vector3d();

ply.getForward(cache);

cache.scale(forwardforce,cache );

movevec.add(cache);

}

Let see if I’ve understand: Do you have 2 kind of message [bitset and status]?

I suppose your display refresh rate is fixed at 60 fps, and so the update(tpf) in the application class [about 17ms].

Instead, the bitset rate is fixed at 20 UPS [50ms].

And the sending rate of the status? I mean position and rotation.

To calculate a displayed enemy position do you use a part of status [position and rotation] combined with a part of the bitset [keypressed forward, back, strafeL, strafeR …]? Isn’t asynchronous?

Maybe I haven’t understand…

Framerate is independent, its as fast as the machine allows.

The update is fixed, cause else fast mahines spam the server.

The ticktime is identically with the one the server has, that one is limited to 20fps. At the end of each step it sends all changed data in case of mostly static entities over tcp. Or in case of moving physic entities it sends it every tick all position data (so vector velocity rotation angular velocity) unreliable via udp.

Reason is, that for objects like a tree there is nerly never a change, (it might grow every few hours for example) so i only need to send it once but must be sure it reaches the client.

For objects like a soccer ball that are constantly moving and changing velocity I send the data much more often, however if one update does not arrive at the client there is no need to resend it, as the next one will be there in 50ms anyway.





BitSet is a java class, its kinda like a boolean array, but a bit more efficient since boolean use 1 byte, where as in a bitset I only need 1 bit per value. When sending I use the next highest byte amount(Network implementation only allows to send complete bytes) and just leave the unused bits at zero.



Example for movement

I press W

→ Enumerations inForward

in the BitSet the index representing inForward is set to 1

→ In next update BitSet is send to server

→ Serverside player objects checks in update if InForward is 1

→ Serverside force is applied to my player object and it starts moving

→ in the next serversideupdate the new position is send to the client

→ Client reads new position and interpolates between the old and the new, so that I don’t have objects lagging as if there where only 20fps. Or in other words the client calculates the missing positions between the serverside new and old positions so a smooth movement is possible.



Basically this would mean that the client looks around 75 ms in the past if his ping is lower than that. else it would be 140,215 ect

However as I make a space/tank warfare game mostly, it is not that much of a problem as noone would expect a tank to turn instantly in 75 ms anyway.



→ Sidetrick

View direction of the client is clientside calculated(and send to server), as else you would feel really sluggish with that delay, but for some reason you barely notice the delay in moving.

Idea if i look at something and press fire, untill the InAttack reaches the Gun object at the server, the Rotation is also updated with the new from the client.

→ Assumption with clientside rotation you can’t cheat much since the tank whatever won’t rotate instantly so you still have to wait till you can shoot even if you would use a aimbot.



There are a few more tricks possible.

→ When inforward is set to true I could check on the client if it seems like I could move and just move the camera forward. This is what CounterstrikeSource does. (Also the reason you fell lagging when walking right behind one, client things way is blocked, but other player moves away, so server moves you anyway and client is set to the new position.

→ Ever got the felling ina game that you just reached cover when you suddenly got shoot? Probably it used prediction and on your client you where already in cover, but not on the server.



→ If the server runs with more fps/ticks the delay will be lower if the ping is good, however at the cost of increased network bandwidth and more calculations.



A completly other approch is the one done by most mmorpgs. The collision and moving of the player is clientside and the client sends updates about it’s position to the server. The server only does some checks then if they are plausible. → Aka player can run at 10m/s if he suddently tries to tell the server that he move 20m/s he is set back at the last valid position. However this one is usually not possible for shooter games.

I’ve understand pretty well all the process up to line:

Basically this would mean that the client looks around 75 ms in the past if his ping is lower than that. else it would be 140,215 ect

But not the last one.

And I've got another few questions:
1) Do you run an app which extends the jme3.Applicaion class onto the server? So you can use "rayCasting methods" to recognize deads, physics to manage real object? If it is the case, do you run it headless?
2) To ticktiming client and server, what do I should use?

EmpirePhoenix and scrubalub, thanks to both of you, because you are a living book!

I run none jme at all on the server, I use a own scenegraph implementation(more a clone of the jme one with) based on the vecmath package that the core of jbullet also uses.



On the server for ticking I suggest takcing a look at the timer class or similar.

On the client I track the current time(var x) in the update(tpf) and when 75>X i make a fixedtick and set the time to x = x -75 to compensate fluctating fps (because updates is of course not called such that i exactly reach 75). So basically its not exactly 75ms but over a few minutes you have the same amount of ticks, small differences inside a second actually are not even noticable.



Well what I mean if the client has a ping lower than 75

Clientfixedupdate → send to server

Serverupdate within at most a delay of 75ms after message reached

→ server processes and sends data back

Next ClientFixedUpdate with new data



When higher than 75

Clientfixedupdate → send to server

Serverupdate within at most a delay of 75ms after message reached

→ server processes and sends data back

Next ClientFixedUpdate but new data not reached client yet

~75ms later

Next ClientFixedUpdate with new data