Your Netcode Works. Then Someone Unplugs Their Router.
Cheaters, disconnections, lag, and player trust: why multiplayer netcode needs prediction, interpolation, bounded rewind, and replays you can inspect.
The first multiplayer prototype feels like magic. You open two windows, move a character in one, and watch it move in the other. A few packets, a little serialization, and suddenly your game has company.
Then someone plays over unreliable Wi-Fi. Someone disconnects while collecting a reward. Someone discovers that your server believes whatever their client tells it.
Writing your own netcode means deciding what happens when players disagree about reality—and making those decisions feel fair.

Your first difficult customer is the player who edits the rules.
Suppose your client sends, “My character is now at this position.” That is convenient until a modified client starts reporting positions through walls. In a competitive action game, an authoritative server should determine valid movement instead of accepting the client’s claimed result. The client can predict movement locally for responsiveness, but the server gets the final say. Glenn Fiedler explains this trust boundary.
That principle spreads through the entire game. A request to fire needs checks for ammunition, cooldowns, and player state. A request to collect an item needs checks for ownership, availability, and distance. Every shortcut becomes a question: can a player manufacture this message, repeat it, or send it at an unexpected time?
Server authority also has limits. An aimbot can produce inputs that obey the game’s rules. Hidden information sent to a client may become visible through a modified interface. Preventing impossible actions and detecting abusive behavior are different engineering problems.
The practical lesson is to design each message as a request that needs justification. A client saying “I earned this reward” should carry roughly the same weight as a customer announcing their own discount at checkout.
In irt.io, ownership and server authority let you separate player intent from authoritative outcomes, while visibility rules control which state reaches each client. These give you a foundation for protecting scores, damage, and hidden information. Your game still supplies the rules that make an action valid.
Disconnections expose a different weakness: uncertainty.
A silent player might have quit, lost connectivity, or temporarily stopped receiving traffic. Your game needs a timeout, but choosing one creates a tradeoff. A short timeout ejects players during recoverable interruptions. A long timeout leaves teammates waiting beside an apparently lifeless character.
Reconnecting introduces more decisions. Does the character remain vulnerable? Does the match reserve their slot? What happens if they return after the round ends? If leaving removes their character from danger, pulling the network cable can become a defensive ability.
Even a simple reward can become complicated. Imagine the server grants an item, but the connection drops before confirmation reaches the client. The client reconnects and tries again. Without a stable operation identifier and duplicate handling, one reward can become two. This is why retryable operations often need to be idempotent: repeating the request must not repeat its effect. Microsoft’s retry guidance describes this failure mode.
A reconnect therefore needs more than a working socket. It needs authenticated session recovery, authoritative state, and a clear answer about which earlier actions completed.
Our client handles connection retries with backoff and a resume token. A reconnect grace period holds the player’s session so they can return with the same identity and records. You still decide what happens to their character while they are away, but you have explicit reconnect status and lifecycle hooks to build that behavior around.

Lag makes all these decisions visible.
Players say “lag” when inputs feel delayed, opponents stutter, or movement suddenly snaps backward. Those symptoms can come from different causes: network delay, fluctuating arrival times, packet loss, or a server struggling to finish its work.
Prediction helps your own character respond immediately. When the server disagrees, reconciliation corrects the predicted state and replays outstanding inputs. The challenge is making that correction accurate without making movement feel like an elastic band. Fiedler’s networking walkthrough describes the prediction-and-replay approach.
Our client-side physics prediction uses a shared world builder and input-to-force logic on the client and server. When authoritative state arrives, the client restores it, reapplies buffered inputs, and simulates forward to catch up. That rewind-and-replay step preserves responsiveness while accepting the server’s correction. Correction smoothing eases smaller visual jumps; corrections beyond the supported replay window snap to authority.
Other players present a different problem. Buffering updates and interpolating between them can smooth their movement, but adds visual delay. Lag compensation can evaluate a shot against historical positions, helping a shooter hit what they actually saw. The tradeoff is familiar: the target may feel they were already behind cover when the hit arrived. Valve documents these techniques and their consequences.
irt.io exposes interpolation through room.render, blending remote numeric state between authoritative updates at the display’s frame rate. Predicted bodies also come through that render view, so your drawing code has one place to read smooth motion. The interpolation delay is configurable because a slow board game and a fast arena game need different compromises.
For shots, our server-side room.rewind lets your hit query inspect recorded body poses at a past tick, then apply the result to the current game. This is a historical query in a separate world: it does not rerun the whole match or retroactively apply every late input. You choose the history depth, and queries outside that history are clamped and flagged so your game can decide how to handle them.
There is no setting that makes every perspective perfectly current. You choose how much delay, correction, and historical generosity your game can tolerate.
That choice also affects cheating. An overly generous rewind window can reward extreme latency. Accepting arbitrary client timestamps invites manipulation. Treating every movement discrepancy as cheating risks punishing players whose connections are simply unstable.
The hardest bugs live where these systems meet.
A player reconnects while a predicted action is unresolved. An old packet arrives after a new session begins. A server hitch causes movement corrections that resemble a speed hack. Each component may work in isolation while their interaction breaks the match.
That is why testing two clients on your own machine proves so little. A useful test environment deliberately introduces delay, jitter, packet loss, and interrupted connections. Disconnect during a trade. Reconnect after death. Repeat an acknowledged request. Run the server under load.
Record enough information to explain the result: session identifiers, input sequences, server ticks, correction sizes, and disconnect reasons. Without that evidence, “the game ate my shot” is almost impossible to investigate.
Our simulation tools help exercise those assumptions with real client sessions and degraded connections. Prediction statistics expose corrections and snaps, while the bandwidth profiler helps identify expensive state updates. These measurements let you investigate what players feel instead of tuning delays by guesswork.
There is another part of correctness: earning players’ trust in it.
A server can apply its rules consistently and still look unfair to someone who just lost. “The server said so” gives that player very little to work with. Clear rules about lag compensation, consistent disconnect behavior, and a way to review disputed moments make the result easier to understand. Trust also means being willing to find a bug and correct it when the evidence points there.
That’s one reason we built replays. irt.io can save the recent action as a clip or record a whole match, then play recorded room state through your game’s own rendering code. You can build killcams, shareable clips, and bug reports that include the moment in question. Playback controls let you pause, seek, and slow things down so a disagreement becomes something you can inspect together.
A replay captures recorded room state, rather than every player’s exact screen and network timing. It helps explain the authoritative sequence, but proving why a particular shot was accepted may also require the judging tick and hit-query details in your logs. Configure replay visibility carefully in games with hidden information. Used together, replays and diagnostics give players an explanation and developers a way to check whether that explanation is correct.
Writing your own netcode can be rewarding. It gives you control over the rules that make multiplayer feel responsive and believable. But the real work starts after the characters move correctly across two windows.
It starts when the connection fails, the client lies, and both players are certain they won.