
Network latency (lag) is a reality that needs to be considered in multiplayer games. Messages sent over the Internet take time to reach the destination. Depending on the route and its length, the transmission of these messages can take quite a long time. This can negatively influence the game process, especially in dynamic client-server games, such as FPS. What seems to be a very simple task (shoot, trying to hit the target), suddenly becomes very difficult to create a smooth game process for all players. I think it is not necessary to say that creating multiplayer games is difficult, and there are many problems that developers must solve. In this article, I will tell you how the MechWarrior Online weapon system deals with the lag.
One of the strategies to solve the lag problem is to reduce the distances and thus improve the route between the players and the game server so that the lag is not so noticeable. This can be achieved by creating a system of regional servers and connecting players only to those servers that are closer to them; or it is possible to ensure transmission of gaming traffic along routes through certain networks for optimal transmission to servers. Unfortunately, this method is not always possible due to the high cost and can be used with limited data volumes; but even in this case, it does not always work for players who are located in remote regions or have poor Internet connection quality. MechWarrior Online (MWO) approaches this problem in the same way and uses regional dedicated servers to minimize delays for players. However, this is often not enough for most players, and we need to do something else.
Client side prediction
You may have heard the expression “client side prediction” in discussions of client-server multiplayer games. This is an important concept, allowing to ensure the smoothness of the gameplay, especially in dynamic games. Without it, even a small lag can be very noticeable and annoying. The idea of ​​client-side prediction is simple: instead of waiting for the server to transmit the result of the action to the client, the client predicts the outcome of this action, as if it were taking place immediately. For example, if a player wants to go forward, we immediately begin to move the player on the client side, and then send the move request to the server. From the player’s point of view, it seems that he is moving immediately, but in reality for the server he has not moved yet. If the game client's predictions are always correct, then the player perceives this as a lack of lag. Of course, forecasts cannot always be correct, and this problem must be somehow solved, but we will not deal with it in this article. MWO is very dependent on client-side prediction. Both the movement and the weapon system - when a player tries to move his fur or fire a weapon, the game reacts immediately.
')
Lag compensation
Now we have a client who immediately reacts to the player's behavior and eliminates the sensation of lag; however, there is another problem. Despite the apparent instantaneous reaction to the actions of the player, the game world reacts to them with a slowdown. We have only eliminated the appearance of lag, but the information received from the server still comes with a delay. This means that the goal that the player sees for the server is actually in a different place; even worse, when a player shoots a target and the server receives a shooting request, the target moves further from its original position. The time required to receive information and send a request to the server is called the time of transmission and confirmation, or ping. If a player has a non-zero latency, then without compensating for the lag, players would have to shoot at the target in advance to get into it; the higher the ping, the further the anticipation should be. You can imagine how annoying the players would be. You can illustrate the situation with the following images.
What the player sees at lag
What does the server see at lagFrom the point of view of the player, he absolutely hits his target, but the server sees that the player is shooting completely past. To solve this problem, you need to somehow compensate for the lag of the player.
Now you can ask a question: why solve this problem at all? If the client predicts everything, can the client simply tell the server whether the player hit the target or not? The easiest answer is “yes”, this option is possible; however, it has a big flaw. When the game client is allowed to report something to the server, the possibility of cheating is created. When playing on a computer, the game client can be easily modified, and the cunning cheater will change the game client in such a way that it will send messages about the hit when the cheater wants, even if he is far from the target or does not see it at all. Therefore, the transfer of such rights to the client, especially with regard to damage to enemies, is an incredibly risky proposition. If a multiplayer game is designed for platforms that provide some kind of "protection" for the game client, for example, for consoles, then this may be an acceptable solution. But in the PC world, if you give the client any control over the state of the game, it will almost certainly be used to your advantage. There are many ways to cheat in battle, but in this article we will not consider them either. For us, the safest solution would be to provide full control to the server; this is exactly the approach that is implemented in the MWO.
In MWO there are two categories of weapons, and for each lag must be compensated in its own way. Weapons are divided into straight-line weapons (such as lasers and machine guns) and artillery weapons (for example, missiles and ballistic weapons). It's much easier to work with straight arms, so let's start with it.
Rectilinear weapon with lag compensation
Rectilinear weapon fires instantly, reaching the goal at the time of the shot. This is provided by
reykasting or tracing lines in the current state of the game world to determine the point of impact of the weapon. Therefore, to compensate for the lag you need to trace the lines. If the server stores previous positions and directions of targets, it can use the player’s ping data to determine the location of the target at the time of the player’s shot. This location is indicated by the blue fur in the image below. It is aligned with the screen position of the shooting player. MWO refers to the position of this blue fur as the “rewinding time” position of the target. Now that the server knows where the target should be, it can move the target back to this point, trace the lines to determine if there is a hit, and then place the target at its starting point. Thus, the server makes the prediction of the game client accurate.
How the server sees the "rewound" target positionIn the case of an MWO, it is not enough to simply keep previous positions and directions. Each component of the fur can be damaged separately, and this is a very important game mechanic, so a state of animation is also needed. It should also be remembered and "rewound" on the server. In the picture it can be seen as the difference in the cycle of movement of the "past" and "present" fur. So, we have dealt with straight-line weapons, now let's find a solution for artillery weapons.
Artillery weapon with lag compensation
The behavior of artillery is very different from the behavior of straight-line weapons. They shoot geometric objects, such as shells or rockets, these objects move through the air, and then cause damage, colliding with the target. In this case, a simple "rewind" will not work. If we used the same approach as for a straight-line weapon, and would accept that the shells were moving at infinite speed, the server could incorrectly determine that the projectile instantly collided with the target, even if the target could already have gone its way before the collision. Worse, the players deliberately fired their artillery at the advance, because they are counting on where the projectile will be at the time when it reaches the target; if we used such a method, then a player with a perfect eye on the server with perfect “rewind” would constantly miss. We need a different approach.
Proactive artillery shooting on the game clientWe would like to
rewind the projectile on the server to determine its position as predicted by the client. If we make the client's prediction correct, we will compensate for the lag on the game client. To achieve this, we divide the cycle of the "life" of the projectile into two parts.
By the time the server receives a request for a shot, half the time to transfer and confirm the player passes. But it must be remembered that the server must be ahead of the client by half the time for transmission and confirmation, since the server processed by the projectile had to exist within seconds of ping to match everything else in the server world. During this time, the projectile can already face the target in the client, and the server should react to it, but let's not worry about it for now. Let's call this first stage of the life of the projectile a period of "rewind." Everything after this first part of the life of the projectile will be the point at which the simulation of the projectile by the server and the prediction of the behavior of the projectile by the client should be synchronized. It is important to note that synchronization in this context does not mean that the projectile must be at the same points in the client and on the server. The client should lag behind the server by half the time for transmission and acknowledgment. Therefore, in this case, synchronization means that the projectile is in the same place relative to other objects in the world, both in the client and on the server. We call this stage of the life of the projectile synchronized period. Working with the first part is a little more difficult, so let's start with the second one first.
Suppose that the projectile has simple physics and moves in a straight line at a constant speed. In this case, at the time the server receives a request for a shot, the projectile will have already passed a distance in the game client equal to its speed multiplied by the client's ping. If the projectile has more complex physics, for example, taking into account friction and gravity, it should still be possible to calculate the distance covered by it using a more complex formula.
The trajectory of the projectile on the server, top viewIf we ignore the “rewind” period for the time being, the server can make the client's prediction correct or
synchronize with the client, simply by creating a projectile at a distance that he traveled from the usual position of creation. In other words, the server will not fire a projectile from the barrel of a weapon, but instead fire it at the desired distance along its path. If the projectile has a more complex physics, the server may need to calculate the desired speed and acceleration, which the projectile must have at the corresponding point of the trajectory. Assuming that the projectile moves
deterministically , it should now move along the trajectory synchronized between the client and the server. It's pretty simple, but what about the “rewind” period?
If we always created projectiles at a distance of the "rewind" period, projectiles could pass through targets or even static objects. It's pretty easy to limit passing through static objects using line tracing, but what about moving targets? If the target is within the "rewind" period, the projectile, according to the client's forecast, may already encounter the target before the request reaches the server. This is the real problem with projectiles - the server must be able to recognize such situations in order to implement client predictions.
One of the ways to solve the problem is iterative, combining a “rewind” with a certain simulation of “forward”. When a shot request reaches the server, it can “rewind” the target, create a projectile, and cycle the projectile and target “rewind forward” during the “rewind” period. In the event of a collision between the target and the projectile in the cyclical miscalculation forward, we can damage the target and generally avoid creating a projectile. If a collision is not detected, we can create a projectile in its synchronized period.
Unfortunately, this solution has a couple of other problems. The first is that fast projectiles without any method of continuous collision detection in each cycle will be able to penetrate targets in their own cycle. The second is that this type of solution is very expensive to use on the server. The number of iterations corresponds to the duration of the "rewind" period. So if the players have increased pings, the processing of each shot by the projectile will be more resource-intensive. In MWO there are a lot of shells, and they fly very fast; for these and other reasons that we will not consider here, this solution did not suit us.
To create a non-iterative solution, let's first make some assumptions that simplify the problem. We will take the following assumptions for the projectiles: the projectile can be approximately considered a full stop, so you can use line tracing to approximate its trajectory; the trajectory of the "rewind" period is fairly well approximated by a straight line; it can also be assumed that the shells during the rewind period have a constant speed. In MWO, ballistic physics is used for projectiles, so they do not always move along straight lines, but they are
very small relative to furs, move
very quickly and
do not reduce speed when moving in air, so these assumptions are suitable for us. We also need to make assumptions about the movement of targets. Let us assume that the movement of a target between the rewind position and the current position on the server can be fairly well approximated using a straight line; also assume that the speed of the target during this period is also constant. Such assumptions can be quite inconvenient in some dynamic games, but fortunately, in MWO, the bellows are rotated, accelerated and slowed down slowly and smoothly, so these conditions are suitable for us.
By accepting these assumptions, we can break the problem into two parts. In the first part, we want to know
if a collision with a goal is
possible at all . If a collision with a target is possible, then we perform a calculation to determine the time at which a collision
should occur during the "rewind" period. In the second part, we use this information to perform the usual “rewind” of straight-line fire with a modified ping value to determine if there was a hit.
To check for the possibility of hitting, we first determine the position of the “rewound” target based on the current ping of the player and the vector representing the trajectory of the projectile during the “rewind” period. This is similar to what we did when “rewinding” rectilinear fire. We want to know whether these two objects intersect when moving along their own paths. The assumptions made earlier allow us to reduce this problem to the trace of a single line, making the velocity of the projectile relative to the stationary “rewound” target. You can see this in the image below.
By applying our assumptions, the server can reduce the problem on the left to the problem on the right, which is much easier to solve.The solution to this problem is similar to the solution to the problem of passing through objects, which is mentioned above. One can imagine how the projectile moves from its initial position to the end of its “rewind” period in one cycle; the presence of collisions during the movement of these objects between the start and end points is performed by continuous checking of collision detection. It is also important to note that this check is not completely analogous to normal line tracing. We deliberately ignore the rest of the world and consider only the “rewound” target and the modified trajectory - this is a very important detail. If we do not ignore the rest of the world, we may mistakenly get a result indicating that it is impossible for a collision to occur, while it may be. For example, if a player is standing next to a wall, we may have a false negative result. You can see it in the picture below.
A possible situation in which an object of the world leads to an erroneous result when checking a modified trajectoryRemember that this check only tells us about the possibility of a collision; it does not guarantee that a collision will occur. Other moving or static objects may be on the way. So, we still want to perform some kind of "rewind" check along the original trajectory of the projectile, similar to the one we did for the weapon of rectilinear fire. If the first part of this test is successful, it gives us exactly the information that we need for this. She reports that the collision occurred, it occurred at a certain distance in percent along the path from the “rewound” position to the current position of the target. Since both the projectile and the target move during one time interval, this percentage is equal to the percentage along the modified trajectory where a collision occurs - sometimes it is called the “hit time”. We can use the hit time to calculate the value of the modified ping, which “rewinds” the target to this average position.
The state of "rewind" shells on the server. The black line is the original vector of the fire during the "rewind" period. The blue line is a modified fire vector for continuous verification of collision detection. Black fur - the current position of the fur-target when firing a projectile. Blue Fur is the “rewound” position of the target fur based on the player’s ping. Yellow fur - potential position for the final check "rewind"This middle position is the “rewound” position, for which we want to perform a “rewind” check of straight-line fire. We can perform a normal backward rewind check of a rectilinear fire with a modified ping value to determine if it was actually hit. If the hit was, we cause the target damage and do without creating a projectile. If there is no hit, we create a projectile in its synchronized period, as described above. In the case of the image above, we see that there is a hit in this situation.
Conclusion
Lag-compensating weapons are just one example of the complex problems that MWO and other multiplayer games typically face; in this article we showed only the smallest part. We didn’t even begin to discuss the effects of explosions, tracers, inconsistencies that “rewind” between players with and without lags can bring, and also the ways in which the server can effectively do all this work for several purposes. Along with weapon lag compensation, there are still a lot of problems that multiplayer games have to deal with, including customer forecasting errors, cheating, bandwidth control, server performance management, and many others. Now you can understand how much strength and skill is invested in creating what seems to be a simple element of a multiplayer game. I hope this article will shed some light on how complex the development of a multiplayer game can be, and next time playing your favorite online game you will appreciate all this work.