Every message between a game server's plugin and its agent, both ways.
The plugin in each game server streams its gameplay events and status to the node's agent, which stores and uploads the events and acknowledges them, and relays console commands back to the game. The socket listens only on the node's loopback, and the agent image and the CS2 image implement its two ends, so a controller never talks to it. It is here for reference.
Connecting
Each game server's plugin dials its agent on the node's loopback, at the URL its launch gives it in ANKOR_WS_URL. Its events carry the launch's allocation_id, which the launch gives it in ANKOR_ALLOCATION_ID; a plugin without one does nothing.
key is the launch's relay key: 8 random bytes in hex, which the agent makes for each launch. It is in that game's container only, so no game of another slot can connect as it. The agent keeps it in a label of the container and reads it back when it adopts the game after a restart.
The dial sends Ankor-Protocol with the plugin's protocol version.
The agent refuses a dial it cannot accept with an HTTP status:
Status
When
404
The slot is not on the node, or the path is wrong.
401
The key is not the launch's.
426
Ankor-Protocol is missing or has another version.
A slot has one plugin connection. A new one replaces the old.
A binary frame ends the socket, and a frame over 2 MiB closes it with 1009.
The round_backup of a match that sends no statistics, which the plugin sends like phase_change, and the agent forwards as backup. backup holds the complete event, unchanged, as the event stream would carry it.
One sequenced event, which the plugin sends and the agent spools without its type, then uploads as an EventBatchFrame of an event_batch. seq runs from 0 without gaps. The frame names no server, because the connection's key already proves which one it is.
A frame carries at most 2 MiB, which is no more than 2 MiB, so every event the agent accepts fits an upload batch once stored. The plugin drops a larger event before sending it, and the agent ends a socket that sends one.
After a gap past the events it stored, or with more than 512 events or 4 MiB of them waiting to be stored, the agent accepts no more history and ends the socket with code 1000 once the rest is stored. The plugin reconnects and resends from its last ack.
seqEventSeq
The event's position among the events of its server.
The match moved to another phase, which the plugin sends whether or not the match sends statistics, and the agent forwards as phase_change. Like server_status, it is sent once and lost without a connection.
a launch with a restore went here from warmup while the engine loads the backup, and goes to live once the restored round starts. A load that fails leaves the match here, where the plugin reports nothing, until a load is tried again or the server is stopped.
"knife"
the knife round.
"side_choice"
the side choice.
"live"
live play.
"post_live"
after the last round.
Example
{ "type": "phase_change", "phase": "knife"}
quitting
plugin → agent
Tells the agent that the plugin is about to run quit after its match, with every event acknowledged and the demo finished. The agent stops a server that is still running 10 seconds later. Like server_status, it is not resent, so one sent without a connection is lost.
type"quitting"
Example
{ "type": "quitting"}
score
plugin → agent
The match's score changed, which the plugin sends like phase_change, and the agent forwards as score.
A game server's state, which the plugin sends in answer to every get_server_status. The plugin also sends it unasked once when it connects and once when it turns ready.
map_namestring ≤ 64 chars
The map the server is on, up to 64 characters.
matchobject | null
The loaded match and its team state. Null on a server without a match or after a refused config.
match_idMatchId | null
The match_id the server was launched with. Null for a match without one. The launch's config is the controller's to keep, so it is not echoed.
The id of one map's match, which the controller chooses. A series of maps is a grouping that the controller keeps. The id is a lowercase UUID, because demo file names carry it and case matters there.
a launch with a restore went here from warmup while the engine loads the backup, and goes to live once the restored round starts. A load that fails leaves the match here, where the plugin reports nothing, until a load is tried again or the server is stopped.
Why the plugin could not read or use the match config it was launched with, up to 512 characters. Null when the server has no match config or the plugin accepted it.
readyboolean
Whether players can join. When true, the server is logged on to Steam and has loaded the map that its launch asked for, the workshop map when it has one. It stays true once set.
CS2 does not fall back to an anonymous logon when Steam refuses its token, so true also indicates that Steam accepted the GSLT and that its last use can be updated.
server_steam_idSteamId64 | null
The SteamID64 that Steam gave the server when it logged on with its GSLT. Each token keeps one SteamID across logons, so a controller can look the server up in Steam's server list by it. The plugin also adds the allocation_id without its dashes to sv_tags, which that list shows. Null until ready.
What the agent sends a plugin: commands, and an ack once events are stored on the node.
When the agent ends a plugin's socket, it sends a close frame whose reason says why: 1001 when the agent shuts down, and 1000 when the plugin must replay its history, when a newer connection of the same server takes its place, or when the server's launch has ended. The plugin reconnects after each and resends from its last ack.
ack
agent → plugin
Acknowledges that every frame with seq <= to_seq is stored on the node, so the plugin may discard them.
The agent sends it as frames are stored, and on every connect once the server has events on the node, so a reconnecting plugin resends only what follows. An ack past the last frame the plugin sent breaks the stream, and the plugin drops the connection.
An event's position among its server's events, from 0.
integer ≥ 0
Example
{ "type": "ack", "to_seq": 128}
exec
agent → plugin
Runs a server console command. The plugin answers with a command_result once it has handed the command to the engine, or refuses a line that names a command of mp_restartgame, mp_warmup_start, mp_warmup_end, mp_warmup_pausetimer, mp_warmuptime, mp_swapteams, mp_switchteams, mp_scrambleteams, mp_backup_restore_load_file, mp_backup_round_file, mp_backup_round_auto, restart, changelevel, map, host_workshop_map, ds_workshop_changelevel, tv_record, tv_stoprecord and alias while it runs a match.
Loads the server's backup of a round, as restore_round from the controller asks. The plugin runs mp_backup_restore_load_file on the file the engine wrote for it and answers with a command_result.