0002 · Authoritative world in a single goroutine

  • Status: accepted (2026-09-29)

#Context

Positions, collisions, room permissions and conversation membership must be trustworthy. Clients cannot decide where they are.

#Decision

  • Each office has one World that owns all of its state in a single goroutine. Connections talk to it only through an event queue, so the hot path takes no locks.
  • The client sends intent (a direction), never a position. The server integrates movement using the configured speed and the map collisions.
  • The client predicts locally and the server sends acknowledgements with the authoritative position; small differences are smoothed, large ones are snapped.
  • Simulation and send rate: 15 Hz by default (TILEWORK_TICK_HZ, 5 to 30). Events are never sent per frame.
  • A spatial grid (128 px cells) with areas of interest: each player only receives entities from nearby cells (radius of 2 cells by default). Entering or leaving the area produces incremental events.
  • Global presence (people list, status) travels in separate, summarised messages without positions.
  • Pending positions are coalesced per client: when a client's queue is more than half full, sending is deferred and the newest position overwrites the stale one. Reliable messages (chat, control) are never dropped; if their queue overflows, the connection is closed (the client reconnects and resyncs).
  • Movement is never written to the database. Only the last position is saved, when a player leaves.

#Consequences

  • A very large office is limited by one goroutine's core. The real limit depends on measurement (benchmarks pending).
  • State lives in memory, so restarting the process drops connections; clients reconnect and the server restores the map and last position from SQLite.

Edit this page on GitHub