The problem it exists to solve
A deterministic peer-to-peer simulation cannot advance a frame until it holds every player's input for that frame. The straightforward response is delay-based netcode: hold the local player's input in a buffer for as many frames as the round trip requires, so both machines receive both inputs before either simulates. It is correct, it never diverges, and it makes the game feel wrong, because the delay lands on your own button press. At a 60Hz simulation each frame is about 16.7ms, so an 80ms round trip costs roughly five frames of delay on every input you make — in a genre where a reversal window is a handful of frames, that is the difference between the game being playable and not.
Rollback removes the delay from the local input by refusing to wait. When the remote input for the current frame has not arrived, the simulation guesses it — almost always by repeating the last input actually received, because human inputs are held rather than tapped and the previous frame's button state is a very good predictor — and advances immediately. Your own input is never predicted, because you produced it locally, which is why your own character always responds on the frame you pressed.
What happens when the guess was wrong
The machine keeps a ring buffer of saved simulation states and a ring buffer of inputs, both covering the last several frames. When a packet arrives carrying the remote player's real input for frame 300, the simulation compares it against what it predicted for frame 300. If they match, nothing happens and the packet cost nothing. If they differ, the state saved at frame 300 is restored, the recorded inputs from 300 up to the current frame are replayed with the correct remote input substituted, and the simulation arrives back at the present with a corrected world — all before this frame is presented.
frame: 297 298 299 300 301 302 303 <- now
local input: L L L L L L L (always real)
remote input: R R R P P P P (P = predicted)
packet arrives: real remote input for 300 != prediction
restore state saved at 300
re-simulate 300, 301, 302, 303 with real input at 300
and predictions for 301..303
present frame 303
The line to read there is the last one. Frames 301 to 303 are still built on predictions, because their real inputs have not arrived either; a rollback does not resolve the future, it only corrects as far forward as the packet reached. That means the same frame may be simulated several times over its life, each time with a slightly more complete input set, and the version the player finally sees is whichever one happened to be current when the frame was presented.
What it costs in CPU
The budget arithmetic is direct. If your link is such that predictions typically span four frames, then a frame where a rollback occurs runs the simulation step five times instead of once, plus a state restore. Your simulation step therefore has to fit inside roughly a fifth of the frame budget rather than all of it, and a spike in prediction depth must not be able to push you over. This is the reason rollback is native to two-character fighting games and awkward everywhere else: the per-frame simulation cost is small and, critically, bounded, because there are two characters and a fixed-size stage rather than an open area of unpredictable complexity.
Save and restore cost is the second half, and it is the part that shapes the code rather than merely constraining it. Snapshotting the world every frame is only cheap if the world is a flat, fixed-size block of plain data with no pointers, no heap allocation during a frame, and no state living in objects that own resources. Teams retro-fitting rollback onto an existing engine usually find this is the actual project: not the rollback loop, which is a few hundred lines, but disentangling the simulation from everything that cannot be rewound.
The things you cannot un-simulate
A rollback rewinds simulation state. It does not rewind anything the simulation caused outside itself. If frame 300 spawned a hit spark, played an impact sound and started a controller rumble, then re-simulating frame 300 will do all three again, and the player hears the hit twice. If frame 300 sent a packet, re-simulating must not send it again.
The general fix is to make those effects derived rather than triggered: the renderer and the audio mixer inspect the current simulation state and decide what should be playing, instead of being told imperatively at the moment of impact. Where that is impractical, effects are queued during simulation and only flushed for the frame that is actually presented, so a frame simulated four times still emits its sound once.
The artefact players see, and why it is on the other character
Rollback does not make the network invisible; it chooses where the error surfaces. Your own character is always correct, because your input was never a guess. The remote character is the one that gets rewritten — it appears to begin a movement, and then, when the real input contradicts the prediction, it is retroactively somewhere else. On a stable connection with short predictions this reads as a slight shimmer. On a bad connection with deep predictions it reads as the opponent teleporting, or as an attack that visibly connected being erased.
That is a deliberate bargain and it is the part candidates most often get backwards. Delay-based netcode degrades by making everybody's controls worse and keeping the picture coherent. Rollback keeps the controls perfect and lets the picture be temporarily wrong about the person you are not controlling. Competitive players overwhelmingly prefer the second, because input timing is the skill the genre is built on and a visual glitch is not. Saying which artefact you have chosen, and why the genre prefers it, is what separates an answer that has understood the technique from one that has memorised the word.
Rollback is not latency hiding in general; it is a specific decision to spend CPU and visual coherence on the remote character so that local input never waits.
© 2026 Preptima. Originally published at preptima.com (opens in a new tab).