Input Delay vs. Rollback
Lag is a fact of life when it comes to online multiplayer. No matter how excellent the connection, it will always take time for messages to travel from a client to the server and vice versa, usually over the course of several frames of the simulation. Here we describe two common network models that address this time interval—in completely opposite ways.
Common Networking Models
Lockstep (Input Delay)
The first is a networking model most commonly referred to as lockstep. Under this model, clients send their inputs to the server and then, when they receive the simulation results from the server, they show those results to the player. This can be visualized in the following diagram:
The downside of this model can be seen if you look at the brace in the above diagram labeled RTT, or round trip time. This round trip time represents the time it takes for a client to send a message to the server and receive a response. Although the client sends input to the server immediately, it takes a full round trip to the server and back before the client can receive the simulation results from that input, and therefore before the resulting frame can be displayed. For a player, this means that the time it takes for them to press a button and then see the resulting action take place is governed by their round trip latency to the server, also commonly called ping.
The upside is that there are no visual artifacts or glitches. Each player sees exactly what the server says is happening at all times and there are no disagreements. Depending on your game genre, and with a low enough ping of maybe 50ms or less, this can provide an acceptable experience. Most RTS games, many sports games, and many (especially older) fighting games are networked using a model similar to this.
Rollback (Client-Side Prediction)
Another way to address network latency is by using client-side prediction, also commonly called rollback. Under this model, clients send their inputs to the server as before, but they also simulate the results of that input and show those results to the player immediately, without waiting for the server’s response. Because the client performs this simulation without knowing what the server’s response will be or what any of the inputs from the other players are, it is called prediction. This can be visualized in the diagram below:
This resolves the downside from the lockstep model, but introduces a new one. The client will now have presented several frames to the player by the time the server’s response to an earlier input arrives. In the diagram above you can see that, although the client sends its first input on frame 1, the response from the server is not received until frame 4. The process by which clients integrate the results from a previous frame (in this case frame 1) into a later frame (in this case frame 4) is called reconciliation. This is done by rolling back the client’s simulation to the results from frame 1, resimulating frames 2 and 3, and then finally simulating the new frame, frame 4. Due to this process, visual artifacts and glitches can arise when the client mispredicts simulation results. Most commonly, mispredictions manifest as objects teleporting or spontaneously appearing/disappearing. Because reconciling prediction also requires resimulating many frames when a message is received from the server, it incurs a heavy CPU cost.
Of course, the upside is that players see the results of their actions immediately upon pressing a button. Games where reaction time is an important factor, like shooters and fighting games, benefit immensely from using prediction/rollback.
As an attempt to get the best of both worlds, many fighting games allow you to configure a fixed amount of input delay that you can apply to your online matches, while using prediction to cover any remaining additional latency. While SnapNet certainly supports this, it also has the option to take this concept one step further and dynamically select the optimal input delay on-the-fly.
Configuring input delay and rollback
Configuring the tradeoff between input delay and rollback in your game can be done by tuning the following three settings in SnapNet. Note that these settings are soft constraints and that any latency unaccounted for while SnapNet is adjusting to the current network conditions will be compensated for via prediction.
1. Minimum input delay before prediction
This setting controls the minimum amount of input delay that will be applied, regardless of latency. Typically, you want this set to 0. Some games, like certain fighting games, may prefer to enforce a minimum amount of input delay (often the same as the maximum input delay as specified below) to ensure a consistent game feel when entering precise inputs. Nevertheless, a value of 0 is almost always recommended to ensure your game is as responsive as possible.
2. Maximum input delay before prediction
This setting controls the maximum amount of input delay that will be applied in order to cover latency, before any prediction is done to cover additional latency. As described above, input delay can be ideal in low latency situations because it can minimize networking artifacts, but it must be balanced against the acceptable responsiveness of the application. Even at higher latencies, it’s often ideal to first apply however much input delay your game can tolerate before performing prediction as doing so limits how much prediction is needed and thus the artifacts and CPU costs incurred. The default value is 50ms. That means that players with 50ms of latency or less to the server will have up to 50ms of input delay applied but should otherwise have a near-artifact-free experience. With a good distribution of dedicated server locations, this is an achievable latency target for many players.
3. Maximum predicted time
This setting controls how far ahead the simulation is allowed to predict in order to cover latency. As mentioned above, prediction keeps your game responsive at the cost of CPU cycles and potential artifacts from misprediction. The default value is 100ms which is large enough to cover the majority of latency while remaining small enough that the artifacts should be minimal. When combined with the default of 50ms for the previous setting, this means that players with latencies to the server between 50ms and 150ms will have 50ms of input delay applied but an otherwise responsive experience with only minor hiccups in extreme circumstances. With a good distribution of dedicated server locations, it should be possible for nearly all of your players to achieve this experience.
Any additional latency beyond this would be mitigated with additional input delay. Using default settings, as a player’s latency rises above 150ms, their controls would become gradually more sluggish but the game would remain playable. For extremely high latency connections, this is often a preferable result to performing additional prediction because the artifacts from mispredicting over such a long time horizon can render the game experience erratic and unplayable.
Changing the settings
Head to Edit → Project Settings → Plugins → SnapNet, expand the Client section, and set the values as desired.
Set the appropriate variables in the snapnet_client_configuration structure that you pass on client creation:
// ...additional setup... struct snapnet_client_configuration client_configuration; snapnet_client_configuration_get_default( &client_configuration ); client_configuration.min_input_delay_before_prediction_milliseconds = 0; client_configuration.max_input_delay_before_prediction_milliseconds = 50; client_configuration.max_predicted_milliseconds = 100; // ...additional setup... struct snapnet_client* client = snapnet_client_create( &shared_configuration, &client_configuration );
The default values of 0-50ms of input delay and up to 100ms of prediction are recommended. You may want to consider raising the the maximum amount of prediction to 150ms if you want your game to remain more responsive at higher latencies and your game design lends itself to a longer prediction window.
The default values of 0-50ms of input delay and up to 100ms of prediction are recommended. You may want to consider raising the minimum input delay to 50ms to match the maximum if you feel consistent input delay is more important than responsiveness for your title.
Since shooters typically only predict local players, they have an advantage as to how much prediction they can tolerate. Misprediction is far less common for local players since their input is known and this allows a much longer prediction window. Additionally, since shooters are so sensitive to input latency, it is recommended to set both the minimum and maximum input delay to 0 and the maximum prediction time to 1000ms (1 second) to cover all but the most extreme scenarios.