Table of Contents

Wire Protocol & Catalog

A compact binary stream a client decodes from a catalog it is sent, not from the server's types.

Status: โœ… Implemented ยท Visibility: Public ยท Level: ๐ŸŸฃ Advanced ยท Category: Subscriptions

๐ŸŽฏ What it solves

Replication bandwidth is the product's ceiling, and clients live in other languages and ship on other schedules. The wire must be dense, self-describing, versioned independently of the server's code, and exact across languages.

โš™๏ธ How it works (in brief)

Messages โ€” one WebSocket binary message, or u32 len | message on TCP after a TYP2 preamble; the first byte is the type:

Message Direction Carries
HELLO client โ†’ server version, capabilities, kind, token (โ‰ค 8 KiB), known catalog hash, payload (โ‰ค 256 B) โ€” within 5 s
WELCOME server โ†’ client granted capabilities, session id, tick, tick period, catalog hash, the catalog (omitted when the client already has it)
TICK server โ†’ client tick number, flags (VIEW_COMPLETE, RESET, OVERLOAD, PERIOD), blocks
COMMANDS client โ†’ server client tick, then typed commands with a u16 sequence each
PING / PONG both client clock and last applied tick (mandatory, 4 Hz) / server tick
KICK / BYE server โ†’ client / client โ†’ server a close code and reason / a clean leave

Blocks inside a TICK, each length-prefixed so an unknown one is skipped: ENTITIES (one archetype's enters, updates, leaves), EVENTS, SELF, AGG, STATS, DEBUG, ACKS, EXT.

The catalog is canonical JSON โ€” archetypes with their position and fields (codec, group, section), commands with their rate and roles, events, metrics, limits, the tick rate โ€” sorted so the same declarations in any order produce the same bytes and the same hash. Built-in commands, events and metrics sit at reserved indices, so enabling one never moves an application index.

Codecs โ€” integers, varu/vari, f16/f32, quantizers over a range, normalized values, angles, packed bits (โ‰ค 24 in a section's pack), positions (24 bits per axis over the world bounds), velocities (displacement per tick in 1/16 position quanta), entity references (netIds), text, blobs, lists, quaternions, tick offsets. The arithmetic is specified exactly and implemented identically in C# and TypeScript.

Close codes:

Code Meaning SDK reconnects
1000 / 1001 normal / server going away app decides / yes
1002 / 1007 / 1009 protocol error / malformed payload / message too big no
1008 policy violation: sustained refused commands yes, backoff
1011 internal error (a flush failure closes every session) yes
1013 try later: server full, or lagging yes, backoff
4001 / 4002 / 4003 no acknowledgement / HELLO timeout / admission rejected yes / yes / no
4100โ€“4999 application (Kick, Admission.Reject) app-declared

โš ๏ธ Guarantees & limits

  • Versioned: typhon.2 + a minor + capability bits; a client ignores unknown blocks and unknown fixed-size fields.
  • No 64-bit integer on the wire implicitly; strings and blobs are length-capped by the catalog.
  • Records are absolute: a frame never depends on a frame the client might have missed.
  • resumeToken is always 0 until resume is built.

๐Ÿงช Tests