ALGOHOL Docs

Observation envelope

The player observation stream is a WebSocket (see Endpoints). Each player-frame message is a gzip-compressed envelope { "type", "payload", "ts" }; its payload carries two top-level fields:

{
  "state": { ... },
  "observation": { ... }
}

state

Universal across all rulesets. Present on every frame.

Field Type Description
phase string Match phase: "waiting", "live", or "finished"
actionCount number Count of commands resolved so far this session. Increases on resolved commands, not at a fixed rate — do not use it for pacing or timeouts
generation number Arena configuration generation; increments if the arena is reconfigured mid-match
sessionId string Session identifier; join commands must match the current value
acceptingJoins boolean | undefined Whether new players can still join this arena
readyToStart boolean Whether the arena has enough ready players to be, or is, live
rosterReadyAt string | undefined ISO timestamp of when the required roster first became ready, ahead of actually going live
startedAt string | undefined ISO timestamp of when the current match went live
updatedAt string ISO timestamp of the last state change
winnerId string | undefined Winning player or team id. Only set once phase is "finished", and only when there was a winner.
outcome string | undefined Only set once phase is "finished": "winner", "all-eliminated", "timeout-winner", or "timeout-draw"
endReason string | undefined Only set once phase is "finished", and only for these two cases: "preempted" (arena reconfigured mid-match) or "abandoned" (all live participants went inactive)

There is no engine tick counter in state. The engine resolves at 20 Hz internally, but that rate is not exposed as a field — a client that needs to pace or time something (a test move, a timeout) should use wall-clock time (Date.now()), not a field expected to increment once per resolved frame.


observation

The contents of observation are fully ruleset-specific. The keys present, their types, and their meanings depend on the ruleset for the arena.

All rulesets guarantee:

Key Description
arena Arena contract: ruleset, mode, allowed actions, and session parameters
self Authenticated unit state

Additional keys (entity lists, tile visibility, signals, etc.) are defined by the ruleset. See the ruleset documentation for the full observation schema.


Optional detail fields (opt-in)

Two self fields carry extra diagnostic detail and are omitted by default to keep the stream lean. Request them per stream with query parameters. These fields add resolution and contact detail inside the authenticated unit's observation contract.

actionDebug — last command resolution

Append actionDebug=1 to include self.lastActionDebug: a breakdown of how the most recent command resolved (energy cost, per-channel usage, shield allocation, and any blocked or partial outcomes). Useful for tuning and debugging.

wss://{host}/api/arenas/{arenaId}/players/{playerRef}/ws?token={token}&actionDebug=1

contact — physics contact detail

self.lastContactFeedback reports contact and collision detail from the physics step, at one of three levels selected with the contact parameter (default off):

contact self.lastContactFeedback
off (default) not sent
processed compact summary: grounded, blockedDirections (which directions are walled), frictionCoefficient, slip
raw full contact feedback, including every contact normal and recent impact events
wss://{host}/api/arenas/{arenaId}/players/{playerRef}/ws?token={token}&contact=processed

Combining parameters

These combine with each other and with observationDelta, and the HTTP frame endpoint accepts the same parameters (on GET .../frame):

wss://{host}/api/arenas/{arenaId}/players/{playerRef}/ws?token={token}&observationDelta=1&actionDebug=1&contact=processed

Delta transport (optional)

By default the player stream sends the complete observation on every frame. A client can read observation directly as a complete snapshot.

Delta transport is an optional bandwidth mode. With observationDelta=1, the server omits observation families that have not changed since their last transmission, and the client reconstructs them from its own cache. Delta transport preserves the same observation permission boundary as the default complete-frame stream.

The wire default is complete-frame delivery. A client should enable delta transport only when it implements the reconstruction algorithm below.

Opting in

Append observationDelta=1 to the player stream URL:

wss://{host}/api/arenas/{arenaId}/players/{playerRef}/ws?token={token}&observationDelta=1

Without this parameter, every frame contains the full observation.

How omission is described

When delta transport is enabled, each player frame carries three metadata objects describing observation families (named groups of related fields):

Field Meaning
observationFamilyRevisions { familyId: revision } — the revision the client should now hold for each family
observationFamilyIncludes { familyId: boolean } — whether this frame actually carries that family's fields
observationFamilyFields { familyId: string[] } — which observation keys belong to each family

Fields that do not belong to any family (for example fast-moving actors and control state) are always sent in full.

Reconstruction algorithm

For each familyId in observationFamilyRevisions:

  1. If observationFamilyIncludes[familyId] is true, the family's fields are present in observation. Cache them keyed by familyId together with the given revision.
  2. If it is false, the fields are omitted because they are unchanged. Copy them from the client cache for that familyId, provided the cached revision matches observationFamilyRevisions[familyId].
  3. If a family is omitted and the client has no cached copy at that revision (for example after a reconnect), fetch a complete frame over HTTP to resynchronize:
GET /api/arenas/{arenaId}/players/{playerRef}/frame

The HTTP frame endpoint returns a complete observation unless the request explicitly passes known family revisions as query parameters.

Reset the cache whenever state.generation changes; family revisions are scoped to the current session and generation.

Current families

Families are defined per ruleset. The SciFi ruleset currently profiles:

Family Fields Notes
spatialPerception visibleTiles Terrain visibility; refreshed at a lower cadence than the frame rate
objectPerception visibleObjects, visibleCorpses Omitted while unchanged

Other rulesets may define different families. Drive reconstruction from the observationFamily* metadata in the frame.

Tile dictionary (optional)

tileDictionary=1 compacts visibleTiles when observationDelta=1 is enabled. Once a tile's static geometry has been sent, later frames reference it by coordinate instead of resending it, and the frame is marked observationTileEncoding: "dictionary". The wire default sends complete tile data. A client that enables tile dictionaries must cache each tile's geometry by x,y,z, rehydrate referenced tiles from that cache, and reset the cache on state.generation change.