Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Watching a match

How a client is started to watch a match rather than play in it, and how the match reaches it.

In 3.01–3.10

A watching client takes the match over HTTP from a spectator service, not over a game connection.

What marks a watching client

Nothing on the wire does. A client watches because it was started to watch: it is given the word spectator where a player’s client is given its server’s address. Its key can be given as more than 16 characters of base64: the first 24 bytes it encodes, deciphered as Blowfish ECB under the match number written out, give the key as their first 16 bytes.

In 3.01–3.10

The word is followed by the spectator service’s address, with no port of its own, the key, a match number and a platform name; there is no player number. A key is deciphered under the low 32 bits of the match number, written out as a signed decimal.

In 3.01–3.10

The word replay starts a watching client as spectator does.

In 3.10

A player’s key is never base64: one longer than 16 characters is cut to its first 16.

The order of the stream

  1. A client answered on registration sends StreamRequest.

  2. A server sends StreamMetadata, within 30 seconds: until it arrives the client waits.

  3. A server sends StreamChunkRange, with the match’s end left at zero while it runs.

  4. A server sends the chunks, each cut into StreamChunk fragments sent in order and not mixed with another chunk’s. It either sends every chunk from chunk 1 upward, or joins the client late:

    • the chunks of setting up, from 1 to the last of them (the chunk of kind 3), and no chunk after it;
    • then the key frame nearest the present, the first key frame sent on the connection;
    • then the chunks from the one that key frame leads to.

    Either way it skips none after that. A client takes a key frame only where it is the first one sent and arrives before the chunk after the last chunk of setting up; otherwise it keeps it but plays on from that chunk. A server SHOULD join a client late once a match is more than a few minutes in: a client sent every chunk from 1 fails partway through a long catch-up.

  5. As the match ends, a server sends StreamChunkRange again naming its last chunk, then that chunk. Once it has arrived the client takes no more of the stream.

The stream’s chunks run for StreamMetadata’s chunkTimeInterval each and its key frames for its keyFrameTimeInterval, both in milliseconds.

In 3.01–3.10

A watching client asks the spectator service for the match under /observer-mode/rest/consumer/, each request naming the platform and the match number: getGameMetaData for the match’s metadata, getLastChunkInfo for how far the match has come, and getGameDataChunk and getKeyFrame for a chunk or a key frame by number. It gives up on the metadata after a time, fetches the chunks of setting up, then catches up to the last chunk on offer and waits there for the next. Key frames arrive compressed. The metadata gives gameKey.gameId, gameEnded and chunkTimeInterval; the last chunk’s information gives chunkId, nextChunkId, availableSince, nextAvailableChunk, endStartupChunkId and endGameChunkId.

In 3.01–3.10

A watching client first asks the service for its version, and ends by asking it to stop. The metadata also gives keyFrameTimeInterval, a whole multiple of chunkTimeInterval, and clientAddedLag; the last chunk’s information also gives keyFrameId.

In 3.10

A client takes the key frame to fetch from keyFrameId, and chunks arrive compressed too. The metadata request carries a further number where the service’s version is 1.56 or later, and getLastChunkInfo carries one too. The metadata also gives clientBackFetchingEnabled and clientBackFetchingFreq.

What a chunk holds

A chunk is the messages a server sent the players of the match, one record after another.

A client plays records as the stream’s clock reaches their time, records of time zero at once, and the first record with a time above zero sets its clock. It skips a record of command 0 on the events channel.

The chunks of setting up carry what a player’s client is sent from its version answer on: VersionSync first. A client holds the stream back while it loads after VersionSync, and again while it builds the world after SpawnStart, and goes on by itself afterwards.

In 3.10

A client whose own build differs from the one VersionSync names asks its player whether to go on, and leaves where the player declines.

A key frame is laid out as a chunk is, and holds the whole world as it stands at that point. A client joined late goes on after it from the chunk the key frame names, or, where it names none, from the chunk its number implies (see StreamChunk).

Messages

Each message of this system in this book, with each layout it has across the book’s patches and every note its definition carries. A layout is the message’s body, after the header its channel’s family puts in front (see Messages).

StreamMetadata

What a server streaming a match to a watching client sends first, within 30 seconds of the client’s request: how long its chunks and key frames run. A client waits on it, and stops taking the stream’s messages once the last chunk has arrived. The header carries zero.

Definition.

In 3.12–3.15

Command 235 on events, sent by the server, reliable.

FieldTypeWhat it is
unusedu32Unused; a server writes zero.
texttext, sized by remainingA JSON object with integer members chunkTimeInterval and keyFrameTimeInterval, in milliseconds, to the end of the message. A server sends both.
Vectors (1)

one-on-3-15

StreamChunkRange

What a server streaming a match sends to say where the match proper begins in its chunks, and, once known, where it ends. The header carries zero.

Definition.

In 3.12–3.15

Command 236 on events, sent by the server, reliable.

FieldTypeWhat it is
startGameChunku32The chunk the match proper begins with.
endGameChunku32The match’s last chunk, or zero while it runs.
Vectors (2)

another-on-3-15, one-on-3-15

StreamChunk

What a server streaming a match sends to carry one fragment of a chunk or key frame of recorded messages (see Watching a match). A chunk’s facts come from its fragment 0. The fragments of a chunk come in order from 0, and the chunk is complete at index fragments − 1. A new fragment 0 drops an unfinished chunk, and a fragment with no chunk begun has no effect. The header carries zero.

Definition.

In 3.12–3.15

Command 237 on events, sent by the server, reliable.

FieldTypeWhat it is
chunku32The chunk’s id, or the key frame’s. Chunk 0 is dropped; chunks play in order from the one a client starts at, and a missing one after it stalls the stream. Key frames count separately, from 1.
fragmentsu32How many fragments the chunk is cut into.
indexu32This fragment’s place, from 0.
kindu8What the chunk is. Values: 1 ordinary, 2 keyFrame, 3 endOfStartup, 4 gameStart, 5 startup.
sizeu32The whole chunk’s size in bytes.
durationu32Seconds the chunk covers. A client reads it only from fragment 0, and uses it only for the match’s last chunk: the match ends that many seconds after that chunk starts. A value too large holds a client that joins near the end on its loading screen.
nextChunku32For a key frame, the ordinary chunk to go on from. Where zero or less, a client takes key frame interval over chunk interval, times the key frame’s id less one, plus the start-game chunk: the one StreamChunkRange names, or the last chunk of kind 4 to arrive.
databytes, sized by remainingThis fragment’s bytes of the chunk, to the end of the message.
Vectors (2)

another-on-3-15, one-on-3-15

StreamRequest

What a client watching a match streamed over its connection (see Watching a match) sends each time the server answers its registration, asking for the stream from a point. The header carries zero.

Definition.

In every range of this book

Command 234 on requests, sent by the client, reliable.

FieldTypeWhat it is
wantsMetadatau8One: the client wants StreamMetadata.
jumpToLatestu8One where the client has no key frame yet and nothing past the end of the startup chunks: a client that can be joined late (see Watching a match).
fromChunku32The first chunk wanted: one past the highest the client holds, 1 at first.
fromKeyFrameu32The first key frame wanted: one past the latest the client holds, 1 at first.
Vectors (1)

one-on-3-15