Multiplayer
Multiplayer adds three new problems to a single-player game: latency (the network), partial information (each client sees a delayed view), and authority (who decides what is real). The architecture choice — peer-to-peer vs authoritative server vs lockstep — sets the answers, and changing it later is expensive.
Authoritative-server netcode with input prediction
EXAMPLE
// Architecture choice cheat sheet
//
// Peer-to-peer: simplest, cheap; cheating-friendly. Pick for co-op only.
// Lockstep: every player runs the same simulation deterministically; RTS classic.
// Sensitive to dropped packets — one slow player slows the world.
// Authoritative srv: server owns state, clients send INPUTS, server broadcasts STATE.
// Modern shooters and MOBAs. Cheaper to write than lockstep, easier
// to secure than P2P.
//
// We sketch the authoritative-server pattern below.
// ===== Wire format =====
// Client -> Server: {tick, inputs: {move, fire, look}}
// Server -> Client: {tick, snapshot: {players: [{id, pos, rot, hp}], events: [...]}}
// 60 Hz simulation, 30 Hz snapshots, delta-encoded.
// ===== Client-side prediction + reconciliation (TypeScript sketch) =====
type Input = { tick: number; move: [number, number]; fire: boolean };
class Client {
// The latest authoritative snapshot we have from the server
authoritative = { tick: 0, pos: { x: 0, y: 0 } };
// Inputs we have sent but not yet had acknowledged
pending: Input[] = [];
// Local visual state — what we DRAW
rendered = { x: 0, y: 0 };
socket = new WebSocket('wss://game.example.test/play');
sendInput(input: Input) {
this.pending.push(input);
this.socket.send(JSON.stringify(input));
// 1) Predict: apply input locally so the player feels responsive
this.rendered = simulate(this.rendered, input);
}
onServerSnapshot(snap: { tick: number; pos: { x: number; y: number } }) {
// 2) Trust the server for the authoritative position
this.authoritative = snap;
// 3) Discard inputs the server has already processed
this.pending = this.pending.filter((i) => i.tick > snap.tick);
// 4) RECONCILE: replay the still-pending inputs on top of the snapshot.
// This way, the predicted local state catches up to the truth and
// the player only sees a snap-back when prediction was wrong.
let pos = { ...snap.pos };
for (const input of this.pending) pos = simulate(pos, input);
this.rendered = pos;
}
// 5) Render with interpolation between recent snapshots for OTHER players
// (this client's own player uses prediction; remote players use a 100 ms
// interpolation buffer to smooth out jitter).
}
function simulate(p: { x: number; y: number }, i: Input) {
return { x: p.x + i.move[0] * 5, y: p.y + i.move[1] * 5 };
}
// ===== Server (authoritative) =====
// - Sim runs at 60 Hz on a fixed step
// - Per-player input buffers — drop the oldest if the buffer overflows
// - Anti-cheat: rate-limit inputs per second, sanity-check magnitudes,
// never trust client position
// - Lag compensation: when validating a 'fire' event, REWIND world state
// to the tick the firing client perceived. Common in shooters; controversial.
// ===== Concrete pitfalls
// 1) Tying simulation to render rate -> physics differs between 60Hz and 144Hz.
// 2) Using TCP for real-time data -> head-of-line blocking on packet loss; use UDP/QUIC.
// 3) Snapshots without delta-compression -> bandwidth scales linearly with player count.
// 4) Trusting client time -> clients lie; derive ticks from server.
// 5) Not designing for disconnects -> 'ghost' players left in the world.
Why it matters
Pick authoritative-server unless you have a specific reason not to. The cost is the server (a few cents per CCU on modern infra); the win is anti-cheat by construction, deterministic dispute resolution, and analytics on actual gameplay — three things every game wishes for after the first cheating incident.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
// Lobbies: WebSocket / Photon / PlayFab. // Realtime: deterministic lockstep (RTS) or client-prediction + server reconciliation (FPS).Try it Yourself »
Discussion
Loading…