Ownership & the ladder

Every entity has exactly one owner. The owner is the only party whose writes are accepted; everyone else receives it read-only. Owners come in two kinds:

  • A client — cheap, low-latency, good for cosmetic or self-reported state (your position, your cursor, your chat message).
  • The server — authoritative, good for anything that decides the game (score, loot, whose turn it is, hit detection).

Assigning an owner

Set it when you create the entity, usually in onJoin:

onJoin(state, ctx) {
  state.players[ctx.clientId] = { x: 0, y: 0, owner: ctx.clientId };
}

Hand it to the server by marking the entity serverOwned in the schema, or by setting owner: SERVER at creation:

import { SERVER } from '@irtio/room';

state.match = { phase: 'lobby', round: 0, owner: SERVER };

The ladder, one rung at a time

You don’t pick an architecture up front. You climb only when a feature demands it, and each rung is a local edit:

  1. Relay — no room deployed; clients just fan messages out.
  2. Owner-write sync — assign client owners; state syncs automatically.
  3. Validators — keep client ownership but add a validate to clamp writes.
  4. Server-owned + RPCs — move the decision server-side, expose it as an RPC.
  5. Server tick — the server simulates continuously in tick(state, dt).

Rule of thumb: if a lie about this value would ruin the game, the server owns it. Everything else can stay on the client.

Transferring ownership

Ownership can move at runtime — handing a dragged object between players, or pulling a contested entity to the server to resolve a conflict:

state.pieces[id].owner = ctx.clientId; // pick up
state.pieces[id].owner = SERVER;       // let the server settle it

Next steps

Placeholder content.