Networking · const

PROTOCOL_VERSION

The framing, which is small on purpose.

Explained in Networking and rollback.

const PROTOCOL_VERSION = 1
import { PROTOCOL_VERSION } from '@driftengine/network';

In depth

An input payload is opaque bytes and this file never looks inside one. AGENTS.md: engine APIs take positions, colours, sizes and time and never another game's noun. A wire format that knew a player had a throttle would be a racing engine's wire format.


Fixed widths rather than varints

A varint saves two bytes on a tick number and costs a branch per field and a length that cannot be known before encoding. At sixty inputs a second with a payload of a handful of bytes, the saving is under a kilobyte a minute and the cost is that nothing can be written into a preallocated buffer without measuring first. Fixed widths make an input frame a constant size, which is what lets a session own one buffer for the process.

The widths, and what each one refuses

  • Participant, one byte. 255 participants in a session, and 255 is not a limit anybody is near: lockstep stops being viable in single figures, and an authoritative host with 255 predicting clients has bandwidth problems long before it has an id problem.
  • Tick, four bytes. At 60 Hz an unsigned 32-bit tick counter is 2.2 years of continuous simulation. A session that reaches it has a different problem.
  • Payload length, two bytes. 65,535 bytes, which is far more than an input and far less than a full world. A state message that does not fit is a state message that should have been a delta.

The version is in every join, not in every message

A byte per message to say what the protocol was is a byte per message spent on something that cannot change mid-session. The handshake carries it and a mismatch is refused there, which is the one place a peer can still be told why.