Rollback Netcode: How Online Fighting Games Hide Latency
How rollback netcode predicts remote inputs, restores deterministic state, re-simulates missed frames, detects desyncs, and balances delay with artifacts.
Fighting games are unusually sensitive to network latency: inputs matter down to individual frames (at 60fps, a single frame is 16.6ms), and a round-trip across the internet routinely takes far longer than that. Two broad approaches exist for handling this, and they make almost opposite trade-offs.
Rollback does not eliminate propagation time. It keeps the local response immediate and predicts remote behavior until authoritative remote inputs arrive. Consequences that truly depend on the remote player’s newest decision cannot be known early; the system chooses a plausible timeline and corrects it when necessary.
Delay-based netcode: wait for certainty
The straightforward approach is to simply delay local input by a few frames before applying it, buying enough time for the remote player’s input for that same frame to arrive first. This guarantees both sides simulate the exact same, fully-correct game state at every step — there’s never a wrong guess to correct — at the direct cost of added, visible input lag: every button press feels delayed by however many frames were reserved for network travel time.
In practice, games can combine a small fixed or adaptive input delay with rollback. A little delay increases the chance that remote input arrives before prediction is needed and reduces visible corrections, while keeping substantially less latency than a pure delay budget sized for worst-case jitter. The useful balance depends on round-trip time, variance, packet loss, game speed, and the maximum rollback window.
Rollback: guess, simulate, correct if wrong
Rollback netcode takes the opposite trade: never wait. Each side keeps simulating every frame immediately using its own real local input and, for the remote player, its best guess at their input (typically “repeat their last known input,” a good predictor for held directions and neutral frames, which are the majority of any match).
Frame N: local input (real) + remote input (guessed) → simulate → display
Frame N+1: ...same pattern, keeps advancing without waiting...
[ a few frames later, the remote player's REAL input for frame N arrives ]
if (guessed input == real input):
nothing to do — the simulation was already correct
else:
→ roll back to frame N (reload the save state from that frame)
→ re-simulate every frame from N to now, using the REAL input this time
→ the corrected frames replace what was already shown, all in a
single instant — visible, if at all, as a brief, small correction
Repeating the last input is often a useful predictor for held directions and buttons, but its success rate depends on the game and moment. A wrong prediction may make a remote character snap, shorten or skip an animation, change collision results, or correct effects. The local player’s controls can feel immediate while remote information still appears delayed or revised.
The client should not render every intermediate resimulation frame. It restores the last confirmed state, applies the corrected input history, advances rapidly to the current presentation point, and shows the latest corrected result. Simulation and rendering must therefore be separable; doing full GPU and audio work for every hidden replay wastes the rollback budget.
Why this depends entirely on save states
Rolling back requires reloading the exact game state from several frames ago, then re-simulating forward — which is precisely what a save state is for. Rollback netcode is, mechanically, “take a save state every frame, and reload one whenever a prediction turns out wrong” — which means it inherits every requirement a save state has: the simulation has to be fully deterministic (identical inputs must always produce identical output, every time, or resimulation would diverge from what was already shown) and fast enough to re-run several frames’ worth of simulation faster than real time, since all of that re-simulation has to complete within the same single frame it’s correcting.
State can be stored every frame or through a scheme that reconstructs required checkpoints, but the restore point must precede the earliest incorrect prediction. The snapshot includes gameplay-relevant timers, random-number state, entity allocation, physics, pending events, and any other data that can influence future simulation. Wall-clock time, unordered iteration, floating-point differences, races, and untracked external state can all cause desynchronization.
Memory and CPU costs scale with snapshot size and rollback depth. Engines often serialize compact deterministic state, use ring buffers, and cap the maximum number of frames they will replay. When a packet arrives beyond that window, the game needs an explicit policy: add delay, pause, drop the peer, or perform a coordinated state recovery. Silently continuing from incompatible timelines is not a solution.
Networking still needs reliability logic
Inputs are small, so protocols can include frame numbers, acknowledgments, and redundant recent inputs to tolerate packet loss without waiting for retransmission of every individual packet. Sequence numbers distinguish old packets from current ones. Clock and frame synchronization prevent one peer from running steadily ahead of the other.
Rollback does not make latency spikes or loss harmless. A burst of missing inputs creates a long prediction span, followed by expensive replay and a larger visual correction. Matchmaking, regional relays, connection-quality indicators, and rollback-window limits remain important.
Periodically compare deterministic state checksums at agreed frames. A mismatch identifies a desync, but the checksum must cover authoritative simulation state and be computed consistently. Diagnostic builds can narrow the first divergent frame and compare subsystems. Production behavior should fail clearly or recover through a designed protocol instead of letting each player watch a different match.
Side effects cannot simply run twice
Simulation replay may encounter the same hit spark, sound, rumble, camera shake, achievement, or network event again. External effects need deduplication or delayed commitment so a rollback does not play audio twice, submit duplicate analytics, or award an achievement from a discarded timeline. Visual effects can be regenerated from corrected state, while audio often needs carefully chosen suppression and continuity rules because already-played sound cannot be taken back.
The presentation layer may smooth small position corrections, but interpolation must not feed back into authoritative collision or game logic. Competitive integrity depends on every peer simulating the same rules, not on making the correction cosmetically invisible at any cost.
Where this came from
GGPO — built by Tony Cannon, co-founder of the Evolution Championship Series (Evo) and the fighting-game community site Shoryuken — is the project most directly responsible for popularizing rollback in fighting games specifically. Cannon built it after being dissatisfied with the online experience of a 2006 fighting-game re-release, first releasing GGPO later that same year; it went on to be used in games including Skullgirls and Street Fighter III: 3rd Strike Online Edition. On October 9, 2019, Cannon released GGPO as open source under the MIT license, making the technique freely available to any developer rather than requiring a custom licensing arrangement — a significant factor in rollback becoming the expected standard for fighting-game netcode across the industry in the years since.
The open-source GGPO SDK defines an interface between the networking/session layer and a game’s deterministic save, load, advance, and event callbacks. That boundary is the key engineering lesson: a library can coordinate inputs and rollback, but the game must supply deterministic state management and side-effect-safe simulation.
Test adverse conditions deliberately
Automated sessions should inject one-way delay, jitter, reordering, duplication, packet loss, and bursts, then verify both peers finish with matching hashes. Test different CPUs and operating systems when floating-point or threading behavior could vary. Measure worst-case resimulation time, not only average frame time, and preserve headroom for rendering and audio.
Human playtests remain important because acceptable correction artifacts depend on animation, camera, genre, and player expectation. Report ping and rollback frames honestly. A match that stays deterministic but visibly jumps every exchange is technically synchronized and still a poor experience.
Why delay-based netcode hasn’t disappeared
Rollback isn’t strictly better in every dimension — the momentary resimulation-driven correction is a real visual artifact (a character’s position “popping” slightly when a guess was wrong), and implementing it correctly requires a fully deterministic simulation, which isn’t a given for every game engine. Delay-based netcode remains a reasonable, simpler choice when a game’s simulation isn’t (or can’t easily be made) fully deterministic, or when consistent, small, predictable delay is judged preferable to occasional visible correction — but for competitive fighting games specifically, where every frame of unnecessary delay is felt directly, rollback’s trade-off has become the clear industry consensus.
Related:
- GGPO Rollback Netcode Goes Open Source
- How Save States Work: Serializing an Entire Virtual Machine to Disk
Sources: