Watching a match
How a client is started to watch a match rather than play in it, and how the match reaches it.
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.
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.
The word replay starts a watching client as spectator does.
The order of the stream
-
A client answered on registration sends
StreamRequest. -
A server sends
StreamMetadata, within 30 seconds: until it arrives the client waits. -
A server sends
StreamChunkRange, with the match’s end left at zero while it runs. -
A server sends the chunks, each cut into
StreamChunkfragments 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.
-
As the match ends, a server sends
StreamChunkRangeagain 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.
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 1.0.0.130–1.0.0.140
A client asks
getLastKeyFrameInfofor the last key frame.
In 1.0.0.140–3.1.0.0
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 ofchunkTimeInterval, andclientAddedLag; the last chunk’s information also giveskeyFrameId.
In 1.0.0.140
A client fetches the first key frame’s information after the chunks of setting up. The last chunk’s information also gives
durationandstartGameChunkId.
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.
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).
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.
In 1.0.0.141–3.1.0.0
Carried on requests, sent by the client, reliable, under these commands:
| Builds | Command |
|---|---|
| 1.0.0.141–1.0.0.142 | 248 |
| 1.0.0.143 | 247 |
| 1.0.0.144–1.0.0.149 | 234 |
| 1.0.0.150–3.1.0.0 | 231 |
| Field | Type | What it is |
|---|---|---|
| wantsMetadata | u8 | One: the client wants StreamMetadata. |
| jumpToLatest | u8 | One 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). |
| fromChunk | u32 | The first chunk wanted: one past the highest the client holds, 1 at first. |
| fromKeyFrame | u32 | The first key frame wanted: one past the latest the client holds, 1 at first. |
Vectors (4)
one-on-1-0-0-142, one-on-1-0-0-143, one-on-1-0-0-149, one-on-1-0-0-154