# Interpolating server updates with client prediction: how to actually find time variable

I'm working on a 3D web game with client-side prediction, etc. I have implemented interpolation for my entities, but it seems a bit laggy sometimes even on localhost. First I will describe the algorithm, and then I will describe the problem.

Interpolation algorithm:

1. SERVER sends to all players (at 20 ticks per sec):

1.1) positions and rotations of all players

1.2) server time at the moment of sending this data (for example serverTime == Date.now() (it is calculated a little differently, but the value is roughly the same as Date.now(); the error is 20 ms), that calculates every server tick)

2. CLIENT receives all data and:

3. Saves received serverTime to global variable named localServerTime

4. Pushes player's positions and rotations to their buffers (f.e. player1 has buffer1: { time: number, position: Vector3, rotation: Vector2 }[], so we push received(from server) player1 position and rotation to the buffer1: buffer1.push({ time: localServerTime, position: receivesPlayer1Pos, rotaiton: receivedPlayer1Rotation })

5. CLIENT executes local game loop and changes localServerTime: localServerTime += deltaMs

6. CLIENT interpolates all other players positions and rotations like this:

7. We will interpolate players with offset == 100: INTERPOLATION_OFFSET_MS = 100, so find current lerp time: currentLerpTime = localServerTime - INTERPOLATION_OFFSET_MS

8. For all other players:

9. I will consider player1: get player1's buffer: buffer1 and get state interpolate FROM(stateInterpolateFrom) and state interpolate TO(stateInterpolateTo) ( we will find this two states by currentLerpTime, so stateInterpolateFrom.time < currentLerpTime and stateInterpolateTo.time >= currentLerpTime).

10. Then we will find alpha(number, that is in range 0-1): alpha = (currentLerpTime - stateInterpolateFrom.time) / (stateInterpolateTo.time - stateInterpolateFrom.time).

11. Finally, i will interpolate position and rotation: player1.position = lerp(stateInterpolateFrom.position, stateInterpolateTo.position, alpha), same for rotation

My problem here is the following: sometimes I have small lags that arise for some reason. I read that I need to synchronize time; I read a bunch of articles about entity interpolation, and the general principle is described there, but I did not find an algorithm about time synchronization anywhere, so I am asking for help.

I realized that the matter is in the localServerTime, I calculate it incorrectly, but I don’t understand what exactly needs to be done, how to calculate it. If anyone has any relevant articles to put things in place, I would be very happy if you share them.

P.S. On the client I have variable syncedServerTimeMs, when player connecting to the server, server send data: { serverTime: number, serverTick: number} and client calculates syncedServerTimeMs, so I can exactly say the serverTime when I need on it. In the client loop I update syncedServerTimeMs: syncedServerTimeMs += deltaMs, maybe I must use this variable somehow?

To get a more accurate server time, you need to know a few basic facts:

1. You cannot rely on the client and server system time being the same.
2. You cannot rely on time increments(such as deltaMs), some program time consumption or floating-point precision issues can cause delta time to accumulate errors on a long-time running.
3. The difference in system time (CPU time) can be relied upon. On any device t1-t0 are accurate.
4. There is a delay in the communication between the client and the server, and it is affected by various reasons (network delay, protocol parsing, thread communication...) This delay is unstable.You cannot assume the delay is non-existent or stable.

So the solution I suggest is that the client actively asks the server time regularly, calculates the delay through the time of the packet return, and saves the calculated server time and the client time when saving. When the server time needs to be used, the current server time is calculated by the current client time, the saved server time, and the client time when the server time is saved.

Pseudocode:

savedServerTime = 0//saved server time
savedClientTime = 0//client time when the server time is saved

void ServerTimeRequest(){
SendToServer({ClientTime:Time.now()})
}

void ServerTimeResponse(data){
rtt = Time.now() - data.ClientTime
savedServerTime = data.ServerTime + rtt/2
savedClientTime = Time.now()
}

int GetServerTime(){
return savedServerTime + (Time.now() - savedClientTime)
}


Related:

Network client-server message exchange and clock synchronization help

Simple Network Time Protocol (SNTP)

• I answered you below Jan 1, 2023 at 12:05

@Mangata, I didn’t care about time synchronization at all, I needed to know what time to use in interpolation, I would handle the synchronization myself. But I appreciate what you wrote, thanks.

I had to write this in the answers, not in the comments, because comment is limited by the number of characters.

in your case the error is +- rtt/2, because time to reach the server and time to reach the client maybe different. F.e. lets imagine time to reach the server(TTRS) = 5 ms, however time to reach client(TTRC) = 150 ms, then all calculations will be wrong.

I use JavaScript on client and Node.js on server. so we can something like this:

CLIENT:  SendToServer(SyncTimeKey)
SERVER: SendToClient({ serverTime: serverTime, dateNow: Date.now() })
CLIENT:
void ServerTimeResponse(data){
savedDateNow = Date.now()
savedServerTime = data.serverTime + savedDateNow - data.dateNow
}
GetServerTime function is the same as yours.


In this case all will be ok, but as i mentioned, question was about other problem)

• As for the delay of interpolation, I think it is due to the way of interpolation. The client-side interpolation with prediction needs to predict the content of the data before the server sends the data. stateInterpolateTo should be a state that is inferred based on the existing data. If it is taken from the buffer, then you are not predicting(extrapolation). This(interpolation) will inevitably cause delay, and the degree of delay depends on the frequency of server sending packets and the network delay. Jan 3, 2023 at 3:14