Client-side prediction

Client-side prediction is the process of removing the feeling of latency from actions taken on the game client. When done correctly client-side prediction yields a game that feels as if it is single player despite being played over a network.

Before understanding how prediction works, we first must understand the system on which it is built.

In a non-predictive network model:

  1. player presses an arrow key
  2. game client sends a movement command to the server
  3. server processes movement command and moves the player
  4. server sends out new game state
  5. game client receives new game state
  6. player sees themselves move

This process takes time - there's the latency on the way to the server, on the way back to the client, and sometimes there's added delay to make things look smoother related to rendering. Also this movement will feel different over different connections because the latencies will be different.

So how bad is the delay really? Well if the server is nearby and the player has fast internet then the delay can be pretty mild. Also certain games don't suffer as much from having a little bit of delay. Slow-moving top down games can certainly get away with it. Fast-moving games, or first person games suffer pretty drastically from added input delay. Even 200 ms of latency is enough to make it frustrating to walk through a doorway in a first person shooter.

Client-side prediction begins by having the player move around with instant feedback on their own game client even though they're playing a networked game. This is accomplished by taking whatever logic would've been executed on the server to process a command, and running it locally. And us game network programmers sure wish that was the end of the story.

So why isn't that the end of the story?

Well, letting the game client choose the position of their entity in the game world is a fundamental security problem. If the game server is in the habbit of believing the game client when it says "hey I'm at x: 522, y: 320" then it is trivial for a hacker compromise the game. They could simply send any value they wanted, granting themselves amazing speed or teleportation.

To maintain an authoritative server while still letting the player move instantly, we have to get fancy. We need a way grant the player instanteous movement but without ever making them the authority on the position of their character.

One way to accomplish this is to send commands to the server that contain data like "hey I want to move forwards" instead of data like "make my x: 600, y: 550!" By sending "move forwards" our server can then apply its own logic to decide the position of our entity. There's no longer an intrinsic trust of client-side state. At worst the client can send us "move forwards" multiple times in a single frame as a fraudlent attempt to speed hack. But this is easily detected and the server can simply ignore it.

To perform client-side prediction we collect input on the client, e.g. "move forwards" and then we BOTH A) simulate the result of executing "move forwards" locally on the client, and B) send "move forwards" to the server. If the server decides not to move us forward, then our client will find out about this discrepency when it next receives data, and it must take the server's decision as final. This is why the term is client-side "prediction" -- the instantenous movement seen on the client is not the true authortative server state, it is merely a prediction of what that state will be, and if the client is wrong it must be undone. The term for undoing an incorrect prediction is reconciliation.

I hope you found this conceptual overview of client-side prediction valuable. If you'd like to dig deeper then it is time to get into actual implementations (check out the nengi api documentation or game demos).