What is it?
In my last entry I talked about server authenticated movement, but I left out the most fun part – client side prediction! (cries in emoji). If our game had server auth movement with no client side prediction, our character would just be waiting around for the server to reply to our walk forward request. While for some game genres this is perfectly okay, it would result in a less than desired experience in our first person game. Simply put client-side prediction is the client predicting what the result of our input would be on the server.
Below I’ve made a rather extreme example of this. In this case our users’ ping is 500 milliseconds. This means when the user presses ‘W’ the client sends the input to the server, and 500 milliseconds later we receive our new position. Ideally our ping would be somewhere closer to 30 milliseconds, which may not show up in the gif, but without client-side prediction you would definitely feel it while playing.
How does it work?
First’s lets add a new concept of “ticks”. In our example the server and clients have a tick rate of 60. This means 60 times a second they take input and process the results. Let’s assume that our client’s ping is 500, and our game’s tick rate is 60. I’ve been trying (and failing) to write technical processes in paragraphs, so let’s try something. Here is a basic framework of whats happening.
Every tick:
- Client sends new input to server.
- Server processes client input, and sends the results back.
- Client receives old input results from server.
So here’s the problem; When do we have time to process and apply our prediction if we’re constantly receiving old results from the server? The solution is to hold a queue of all the inputs we’ve sent the server since the last result we received. Since our ping is 500ms and the tick rate is 60 we’re holding a queue of 30 inputs! Each time the client receives a result we snap our character’s state back to the position and velocity the result says, run through the queue recalculating each input. If everything goes correctly this whole process should be completely seamless and we’ll end up in the correct state.
Let’s try making this a little more concrete.
Tick 100: Client sends input to server. Tick 115: Server receives input, processes it, and sends results back to client. Tick 130:
- Client receives results for input sent in tick 100.
- Client runs through every input we’ve sent to the server since tick 100 (30 ticks worth) and recalculates all the physics and movement code. Since our calculations should match what the server will calculate in the future, we’ll end up in the correct place and state.
We won’t always get the same results though, and this can cause funny things to happen. I’m sure everyone has experienced them, probably without knowing what’s going on. Games will usually use client side prediction for more than just movement. An example would be shooting someone in a game like Overwatch. You see the other character react, and maybe their health goes down. Your client may predict that the shot was legitimate and show the health go down, but sometimes the server will disagree, and it will take time for those results to get synced to your client. As far as you saw the health went down, and then snapped back to where it was.
I’m really sorry if this was hard to understand, I kind of struggled for hours trying to describe it as clearly as possible. Hopefully I will get better at this!