Latency woes…

First up, lets start with some definitions.  “Local Player” refers to the player that the user is currently controlling on their local device.  “Remote Clients” refer to all other player controlled entities that the local player can see.

The General problem: Since there is latency between the clients and the server, updating the position of other players on the local players screen can appear jittery due to the OTHER players latency with the server.

To solve half of this problem I implemented remote player interpolation with an interpolation buffer. The server sends out updates of remote player positions at a tick rate of 30 times a second. Instead of acting on these as soon as they are received by the local player I queue them up and add an artificial delay (buffer) to the start of their processing. This way I am always a set amount of time behind the latest position that has been received.  Since I’m always behind in the queue it doesn’t matter if new ones arrives a little late. The delay is large enough that even with major latency hiccups there is always at least two positions in the queue ready to lerp between when needed. This results in buttery smooth movement if the remote player that is being interpolated is not lagging himself. For more info see “entity interpolation” on this page .

The Specific Problem: If the remote player is lagging, and their inputs are delayed in getting TO the server, then the server sends OUT multiple updates of the same position. Since the server did not receive any inputs due to the lag, the players position is not changed. By the time the next server update gets sent out, the server will now have received the delayed input, plus possibly the next set of inputs. When interpolating these player states on the local player what happens is, the remote player appears to not move, then move very fast.

Example Time:

I’ve slowed these .gifs down significantly to hopefully make it easier to see the issues.

Player 1 – 0ms latency:

The local player (Player 1) is on the left, and the remote client (player 2) is on the right. As we can see in the gif player 1 is fairly smooth with consistent movement updates. Part of this is due to the client side prediction, the other part is due to 0ms latency as this is on a LAN connection with the server.

The remote client (player 2) is on the right. As we can see his movement is jittery and inconsistent. Even though he is being correctly interpolated and is using an interpolation buffer.

Server – 0ms latency:

This is the view from the server. Player 1 is on the left and player 2 is on the right. As we can see player 1’s movement on the server is very smooth thanks to his 0 ms latency allowing his user input to arrive without issue.

On the other hand player 2 is very jittery. This is caused by player 2’s latency preventing his inputs from arriving to the server in a regular and timely matter. The server in this image is updating player positions at 30 times a second and sending out those new player positions to both clients at the same 30 times a second.

Player 2 – 200ms latency:

In this image since the camera’s are reversed, Player 2 is on the left and Player 1 is on the right. Player 2 is buttery smooth thanks to client side prediction. Player 1 is also smooth thanks to the interpolation buffer that shows player 1 a few hundred miliseconds behind the server. This way the server states are cached on the client so they can be smoothly interpolated between without latency causing problems.

Player 2’s large latency causes inconsistent movement results on the server. This results in inconsistent position updates being sent to other players.

1.) The servers position update of Player 1 per tick:
0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 13 -> 14 -> 15 -> 16
2.)The servers position update of Player 2 per tick:
0 -> 0 -> 0 -> 0 -> 0 -> 0 -> 0 -> 0 -> 0 -> 0 -> 10 -> 10 -> 10 -> 10 -> 10 -> 10 -> 16

To be continued…