Deciding what information to send to the server in order to reproduce a true real-time multiplayer experience is the first step towards designing effective networking communications. Unsurprisingly, there are more key aspects to consider before you can get there.
I’m sure you’ve heard about lag, and pretty sure you’ve experienced it yourself in a FPS or RTS. Those are games that only make sense in actual real-time, and lag makes this hard.
That’s why I’ll talk about how lag affects games, why addressing lag matters, and offer some techniques to deal with the lag problem. These are the lag compensation techniques, which can be applied from the client-side or the server-side.
Understanding lag compensation
These are the basic concepts we need to understand to be able to deal with lag compensation problems:
- Round trip time
- Lag compensation
Round Trip Time
It’s an essential concept to understand the nature of networking communications. It is defined by the amount of time taken by a packet of information that is sent from a client to get to the server and return to that client, without considering the processing times.
Round Trip Time = Time to send + Time to receive
So, what is lag and how does round trip time (RTT) affect it?
Lag is the delay that happens since the player sends the “action” (shoot, jump, duck) to when she receives the “reaction” of the server (shoot the bullet, avoid the hit).
Let’s find out how RTT affects lag with a practical example.
How RTT affects lag
Say we have two people, Mary and John, playing a western shootout duel game. They have different round trip times with the server. If John has a shorter RTT than Mary does, his actions will get there before and therefore the server will react before for John than for Mary.
Following is a sequence diagram depicting this example:
In this example, even though Mary sends “shoot” earlier in time than John does, due to John’s RTT being much shorter (in this case client-to-server) than Mary’s, the server receives the “shoot” action by John first and in consequence Mary is hit. This is, according to the server.
Lag compensation is a technique that stems from the need to address the kind of server communication problems I described above. What lag compensation intends to do is to reduce the discrepancy in the time of response to offer smoother gameplay. This technique can be applied at the client level or at the server level depending on the type of game you’re developing and the kind of feedback you want to transmit to the player.
Client-side lag compensation
In order to solve some lag issues from the client we could work with an interpolation system for positioning the characters in the game.
This approach has the simulation in the client a few simulation steps behind the simulation in the server. When the data from the server is received, let’s say the position of an enemy, the client simulation isn’t updated right away, but it compensates considering the delays from other clients.
You could also extrapolate in a way that the client predicts what should be the next position of the character and corrects the position when receives the data from the server. Meaning that the client supposes that if a character is moving in a certain direction, it will keep moving towards that same direction.
Server-side lag compensation
Lag compensation solutions in the client cover a limited amount of situations and might not work with many gameplay experiences you want to achieve for your multiplayer games. That’s why we have the server alternative to achieve a better lag compensation, although these solutions can get complicated pretty fast.
Following I’ll explain three simple ways to compensate lag from the server side.
#1 Deterministic simulation
This approach has all the simulation happen in the server based on the user inputs that the clients send to the server. This way we achieve a very similar lag on all clients and are able to reduce the problems of compensation.
The downside of this solution is that it directly impacts the user interaction with the game. The result is that the player perception of the time of response is slow. Why? Because since the user input happens, the data gets to the server, it is executed, and the server sends back a response, precious time is spent. And that’s noticeable by the player.
Good for: games where user input doesn’t require a fast response. For instance, in a RTS like the classic Age of Empires.
Tip: you could add a small animation to be executed from the client upon certain user input to masquerade the lag discrepancy between players. e.g. When you send your troops to charge, load an animation that has no impact on the actual gameplay but helps you cushion the perception of lag.
#2 Reliable protocols (TCP)
By using a reliable communication protocol such as TCP you won’t have to worry about data packets reliable delivery. Messages are always received with TCP, and in correct order, which makes the processing on the client and the server simpler. That’s why I love TCP!
If you’re a more advanced network developer, you could even substitute TCP for a custom game protocol based in UDP designed with lighter encapsulation in order to reduce the inherent overhead associated to TCP.
Good for: games with few simultaneous players in the same room, or games that need to send few updates to the server.
#3 Send all simulation state
With this solution what we share is the total state of the game. We must guarantee that the operations are atomic, so that only one client can be modifying the game state at any point time. This way we make sure that every client and the server always have the latest valid version of the game and thus can act accordingly.
We could even combine this technique with the character positioning extrapolation from the client I covered before. While we’re waiting for an update on the game state, we can get ahead and start estimating where we anticipate the other players will be, and when our client receives the real data we simply update the position with that.
Good for: if we’re capable of designing the full representation of the game state in a few hundreds of bytes this technique works well. An example of a game that used this solution is the infamous Quake 3.
Finding the best solution for lag compensation will depend on the a) design of your game, b) what you’re trying to achieve, and c) what really matters for that particular case that you can’t give up. To decipher what’s essential to the gameplay you want to achieve, making sequence diagrams for the different situations in the game can help you a lot. These will help you anticipate possible issues, some directly noticeable by the user and some that won’t. For example:
- Grenade throw
- Character deaths
- Direct combat
- Direct orders to our characters
- NPC movements
In future articles I’ll try to explain advanced techniques of lag compensation from the server side that solve some of the problems with these basic approaches we covered here.
I hope this introductory article was useful for you. If you have any doubts, please leave a comment and I’ll try to address it!
And if you’re planning on developing a new title that has real-time requirements, drop by our site. We’ve a room-based solution to host multiplayer games that could make your life easier. Check it out here!