Client-Server networking: synching entity movement

A forum to store posts deemed exceptionally wise and useful
Post Reply
keless
Posts: 805
Joined: Mon Dec 15, 2003 10:37 pm
Location: Los Angeles, California, USA

Client-Server networking: synching entity movement

Post by keless »

I was able to work on IrrlichtRPG some more: im still working on the Client-Server architecture. Particularly, I felt the movement system looked jittery, so I reviewed what was going on. I made it feel a little better (though its still not professional strength) and I thought I would share my insight with anyone who cared to hear it.

Basically we're trying to synch the client and server so that they both represent the position of an object at the same place. when the server updates the world and finds that an object has moved, it will send that information to the client-- its important that that position is not much different than what the client currently has or object will apear to jump or 'teleport' when updated with the correct position value.

First lets start with what data is being dealt with on the client and on the server:

Client has:
Entity ( position, facing, velocity )

Server has:
Entity ( position, facing, velocity )

On Update, the client and server BOTH to the following to their entity:

Code: Select all

Entity.pos += Entity.facing.normalize() * Entity.velocity * (float)(timeSinceLastUpdate/1000.0f);
What is this bit about time you ask? We cannot simply apply the velocity to the entity every update, since the client and server could be running updates at different frequencies (in which case the client could add velocity more or less often than the server, and things would get out of synch quickly).

Instead, we add a part of the velocity according to how much time has passed. This means that if the client updates 40x/sec and the server updates 30x/sec, they will still move the Entity by the same amount.

So far so good?

Now the trouble starts when the client wants to tell the server to move one of the Entities. The biggest trouble is the difference in time between when the user pushes a 'movement' button on the client, and when the server recieves that command.

Lets go over a simple brute-force way first: the client will send a packet to the server saying it wants to set the velocity(and/or)facing of Entity to something new. The server will store this SEPERATELY from the Entity's current velocity(and/or)facing. Then on update, the server will run this code instead:

Code: Select all

Entity.pos += Entity.facing.normalize() * Entity.velocity * (float)(timeSinceLastUpdate/1000.0f);
Entity.velocity = newUserVelocity;
Entity.facing = newUserFacing;
Note: the velocity and facing are set AFTER we apply the OLD velocity and facing to the entity! Why is this? Consider the following:
Image

In the above image I show 2 ways of doing things. Green lines represent the Entity velocity and position on the client and server across multiple world updates. The red circles represent user input, and the black arrows show the lag time it takes to get from the client to the server. Note, the first user input is created and applied during the SAME world update, but its possible (as in the second case) that user input is created and not recieved by the server until one or even MORE world updates later.

In the above image the TOP row shows what happens when we apply the user input to the entity AFTER the world update (all of the green lines are synched up nicely). The BOTTOM shows what happens when we apply the user input BEFORE the update. In the bottom one we see that the entity position/velocity gets out of synch during world update 0 and during world update 2. This will result in a jump of the enity on the client side when it recieves world updates 1 and 3. Thats why we want to hold off on applying the user input until after the world update we recieve it in.

This example assumes that the client and the server run world updates at the same frequency (since the world update 'bars' are the same on client and server).

Furthermore, there is still the problem of lag time between when the user pressed the movement key, when the server recieved it and when the client then displayed that new position.

What we'd like to see is for the client to start applying the result of the user input as soon as it happens, assuming that the server will return the next world update with that movement already taken into account. Thats what I'm currently working on. :oops:
a screen cap is worth 0x100000 DWORDS
MikeR
Posts: 767
Joined: Sun Dec 26, 2004 4:03 pm
Location: Northern California USA
Contact:

Post by MikeR »

That's a great explination. Thanks.
If it exists in the real world, it can be created in 3d

Sys specs:
AMD 3700+ 64 processor
1.0 gb ram
e-Geforce 6600 graphics 256 mb onboard ram
Spintz
Posts: 1688
Joined: Thu Nov 04, 2004 3:25 pm

Post by Spintz »

You should look into Dead Reckoning Algorithms
Image
keless
Posts: 805
Joined: Mon Dec 15, 2003 10:37 pm
Location: Los Angeles, California, USA

Post by keless »

i know a bit about them, but my first attempt failed and I had to start over from the basics-- i figured while i was doing that, i'd record my efforts so less experienced people could catch on.

Prediction (aka, Dead Reckoning) is what I plan on adding next to smooth things out. I'll be posting more when I get something good working in my engine. There seems to be a good article on it here though: http://www.gamasutra.com/features/19970 ... son_01.htm for those that want to read up in advance.
a screen cap is worth 0x100000 DWORDS
Spintz
Posts: 1688
Joined: Thu Nov 04, 2004 3:25 pm

Post by Spintz »

I deal with dead reckoning all the time at work with out simulation systems. Tomorrow I'll try to remember to post some info on it.
Image
keless
Posts: 805
Joined: Mon Dec 15, 2003 10:37 pm
Location: Los Angeles, California, USA

Post by keless »

I read up on some dead-reckoning topics. Firstly, the simplest version of it is what I already am doing: interpolating object positions between world updates.

There are then more high-level versions that only apply if you have objects with rational movement patterns that are known to both client and server. Basically in this case you take advantage of known patterns and simply give a 'where in this pattern am I' instead of a series of full updates. The client then has to calculate where the object is and what its doing based on the known pattern and the given 'where in the pattern' value.

I'm currently working on user-controlled entities; so this is not applicable yet.
a screen cap is worth 0x100000 DWORDS
Post Reply