iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

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…