Skip to main content

Command Palette

Search for a command to run...

How online games actually work

Published
8 min read
How online games actually work

Introduction

A direct walkthrough of the four techniques that make multiplayer games feel responsive over the internet. Same material Gambetta covers, explained my way.

The core problem

The internet is slow. 50ms to 200ms round trips are normal. If your game does "send input, wait for server, render result," every keypress feels delayed by your full ping. Unplayable for anything fast-paced.

But you cannot just let the client do whatever it wants. Cheaters will teleport, set infinite health, and ruin the game. The server must be in control.

So the hard problem is: how do you keep the server in full control of the truth, while making the game feel instant to the player?

Four techniques, stacked. That is the whole field.

Foundation: the authoritative server

The server holds the real game state. Clients send inputs ("I pressed right"). The server processes them, updates the world, sends state back. The client just renders what the server tells it.

This kills most cheating. The client can lie about its health, but the server knows the truth and acts on the truth. Cheater's screen says "9999 HP." They still die in one hit because the server says they have 10 HP.

Problem: in a naive version, your keypress has to travel to the server, get processed, and the result has to travel back. At 150ms ping, you wait 150ms every time you move. Terrible.

The next three techniques fix this without giving up server authority.

Technique 1: client-side prediction

The client runs the same simulation code as the server. Locally. Immediately.

When you press right, the client does not wait. It applies your input to its local state right now, and also fires it off to the server. You see the result instantly. The server will confirm later.

For this to work, the client and server must produce the same result from the same input. Same function, same inputs, same output. This is called determinism. If your simulation uses wall-clock time, unseeded randoms, or anything that differs between machines, prediction breaks.

When it works (which is most of the time), your inputs feel instant. Zero lag, regardless of your ping. The server confirmation arrives in the background and quietly agrees with what you already showed.

When it does not work: the server disagrees with your prediction, usually because something you did not know about affected you (another player shot you, you hit a wall the server saw first). Your local state is now wrong. Technique 2 handles that.

Technique 2: server reconciliation

When the server disagrees with your prediction, you cannot just snap to the server's answer. Why: the server is always behind you in time. It has not yet seen your most recent inputs. Its answer is the truth at some point in the past, not your present.

If you snapped, you would rubber-band backward every time a server message arrived, even when your prediction was fine.

The fix is to replay your recent inputs on top of the server's truth.

Here is how it works concretely:

  1. Every input you send has a sequence number. 1, 2, 3, 4, 5.

  2. You keep a buffer of every input you have sent but not yet heard back about.

  3. When the server sends state, it includes "last input I processed was #3."

  4. Client snaps its state to what the server said.

  5. Client throws away inputs 1-3 from the buffer. Server has seen them.

  6. Client replays inputs 4 and 5 on top. Applies them in order.

  7. Done. Client is now in sync with the server's truth, with its recent inputs still applied.

In one line: currentState = serverState + replay(unackedInputs).

Worked example. Say you press right 3 times rapidly and predict x=11, x=12, x=13. Before any server message arrives, you are locally at x=13 with inputs [1, 2, 3] in your buffer. Server message arrives: "x=12, last processed was #2."

  • Snap to x=12.

  • Throw away inputs 1 and 2.

  • Replay input 3. x becomes 13.

  • Final position: x=13. Matches what you had. Nothing visibly changed.

Most of the time, prediction was right, and reconciliation is invisible. When prediction was wrong, you get a small correction. Good games smooth the correction across a few frames so it looks natural instead of snapping.

Technique 3: entity interpolation

Prediction works for your own player because you have your own inputs. It does not work for other players, because you do not have theirs. They could turn, stop, or jump unpredictably.

But you still need their motion to look smooth, even though the server only sends state 10-30 times per second. Snapping other players to each new snapshot looks like they are teleporting in chunks.

The trick: render other players slightly in the past.

Example. You receive two recent positions for another player:

  • t=900: x=50

  • t=1000: x=60

Your clock is at t=1050. You render them at x=55 (halfway between the two known positions). At t=1075, render them at x=57.5. Smooth motion between real server data.

Why "in the past": to interpolate you need two points, a start and an end. If you try to render "now", you only have the most recent server position. There is nothing newer to interpolate toward yet. By rendering a fixed amount in the past (usually ~100ms), you always have a pair of known positions straddling the time you are rendering. Motion is smooth and guaranteed correct, because it is literally playback of real server data, slightly delayed.

The tradeoff: other players appear ~100ms behind their actual position. For movement, this is invisible. The eye does not notice 100ms of positional delay. The eye absolutely notices stutter and rubber-banding. You trade something invisible for something visible.

This is also why games can send state only 20 times per second and still look smooth at 60 FPS. Interpolation fills in the frames between server updates with real data. No guessing. No stuttering. Bandwidth stays low, visuals look native.

Technique 4: lag compensation

Interpolation creates a new problem. You see other players in the past. When you click to shoot them, your crosshair is on where they WERE, not where they are now on the server.

If the server checks your shot against their current position, you always miss by your ping worth of distance. You aim perfectly, the server says "you missed, they moved." Unplayable.

The fix: the server rewinds.

  1. When you fire, the client sends the tick you fired on and your exact aim direction.

  2. The server keeps recent positions of every player in a ring buffer (last ~1 second).

  3. The server rewinds the world to the exact moment you saw when you fired (your tick, offset by your interpolation delay).

  4. The server checks the hit in that rewound world.

  5. If you aimed honestly in your view, the hit registers. Damage applied in the present.

The tradeoff lands on the victim. Scenario: you are being shot at, you dive behind cover, you see yourself safely behind cover for 100ms, then suddenly you die. The shooter fired while you were still exposed in their delayed view of you. The server rewound, saw you exposed from the shooter's perspective, ruled it a hit.

This is "getting shot around a corner." It happens and it is accepted.

Why this trade is made: aiming is an active skill action. Getting shot is passive. Better to make the active thing feel correct, even if the passive thing is occasionally unfair. The alternative (no lag compensation) forces you to lead your shots by your ping, which destroys the game for anyone not on LAN.

The three-timeline mental model

This is the whole system in one paragraph. Hold this in your head.

At any moment in an online game there are three times happening at once:

  • Server time. The authoritative present. The truth.

  • Your local time. Slightly ahead of server time. You predicted, so you are in the future for yourself.

  • Other players' time. Slightly behind server time. You interpolated, so you see them in the past.

You are in the future for yourself. You are in the past for everyone else. Only the server is in "now."

Lag compensation exists to reconcile these three timelines fairly when something time-critical happens (like a shot).

Why each technique exists

Each technique is a direct answer to a problem created by the previous one.

Problem Answer
Cheating Authoritative server
Input feels laggy due to round trip Client-side prediction
Prediction sometimes disagrees with server Server reconciliation
Other players snap between updates Entity interpolation
Shooting misses because target is "in past" Lag compensation

Remove any one of these and the game either cheats, feels laggy, rubber-bands, stutters, or makes shooting feel broken. All four are required.