Real-time Multiplayer Networking: Tick Rate and Interpolation

by Chris Dadabo
  games, real-time, networking

In the two previous posts, we discussed how to remedy the problems caused by an authoritative server model, but only from the perspective of a single user. We’ll now look at what happens when we introduce other players and their data.

Getting Other Players’ Data

Whenever any player passes input to their client, we need to send it to the server and use it to update the game state. However, our server can’t keep updating the game state every time it gets new inputs and rebroadcasting it to every client, because this would put a significant strain on the server’s resources, and consume a huge amount of bandwidth by constantly sending out new game state updates to its clients.

To avoid this, we decide that the server will constantly collect input from all its clients, queue the inputs in the order received, and then apply them in order at a chosen interval. This interval is usually referred to as the time step or more frequently, tick rate. With a tick rate of 100ms, the game state will be recalculated 10 times per second regardless of the number of inputs the server receives, helping to prevent resource bottlenecking.

Client-side Prediction, Revisited

So now our client is getting game state data every tick, updating it on every other player’s movement. But how do we know where other players are going? What are the players doing since the last game state update? What will the client see?

Solving the issue of our own player’s movement was trivial; we just assumed their client wasn’t cheating, and allowed it to apply the effects of its inputs locally and let the server override it if necessary. But we can’t do that with other players, because we won’t get any of their inputs or the effects they had on the game state until the next update. So what now?

We could send each player’s velocity and/or acceleration and use that to predict their movement in the meantime. But that will only work if the player doesn’t do anything interesting – like change direction – in the next 100ms. Not having that information could make the next game state update a nasty surprise for the client.

The trick is to show each client a game state that is actually one tick in the past, and have the game state contain several different locations that each player occupied over the course of that tick. To avoid jittery movement, the client can use the location data it received for each player over the course of the last tick and “fill in the gaps,” giving the impression of smooth movement rather than a series of “jumps” from position to position. This smoothing process is called interpolation.

You Guessed It: Another Problem

Each client is now seeing every other player 100ms (or whatever the tick rate is) in the past. This small amount of time difference won’t be noticeable for pretty much anything a player could do, unless that player wants do something that requires a high level of precision, for example, shooting at someone.

This presents an interesting problem. Each player isn’t seeing the entire game state 100ms in the past – he’s seeing a unique perspective of the world in which everyone but himself is 100ms in the past. But he assumes that everything he’s seeing is in the present, so when he shoots someone, he expects that they’re there right now. He wants to hit. So what do we do? What is authoritative now? Does the bullet hit?

Find out in the riveting conclusion, Real-time Multiplayer Networking: Time Travel for Headshots and Profit.