Game Controller Protocol

This page describes the layers that deliver and decode the game state protocol to and from the field. This protocol is partly bidirectional — teams may optionally talk back to the Game Controller to request a keeper change, a timeout, or a substitution.

League Software

There is one piece of league maintained software that manages game state and produces this protocol:

If you’re actively trying to connect to a field, you’ll need to make sure it’s running. Automatic referee implementations are separate, optional software that talk to the Game Controller over the same protocol described below — see the referee protocol page for how their filtered game state gets used.

Transport

A team is never required to reply to the Game Controller. Teams can and do play full matches only receiving game state. The Game Controller talks to teams two ways: a one-way broadcast every team should listen to, and an optional two-way TCP connection only needed if a team wants to actively request something.

Referee Broadcast

The Game Controller publishes overall game state (stage, command, scores, cards) as a one-way UDP multicast stream. The league defines this multicast group as having an address of 224.5.23.1 at port 10003. You join a multicast group just like you connect to any IP address and port combo, though you may need to pass some additional options when binding the socket.

        ---
config:
  layout: elk
  elk:
    nodePlacementStrategy: NETWORK_SIMPLEX
---
flowchart TD
    Team["Team Client<br/>IGMP join only"] -- "IGMP Join<br/>224.5.23.1:10003" --> Net["Switch / Router<br/>duplicates stream"]
    GC["Game Controller"] -- "Referee<br/>UDP multicast, continuous, no ack" --> Net
    Net -- "Referee" --> Team

    classDef purple fill:#faf5ff,stroke:#9333ea,color:#581c87;
    classDef cyan fill:#ecfeff,stroke:#0891b2,color:#164e63;
    classDef gray fill:#f1f5f9,stroke:#64748b,color:#1e293b;
    class Team purple;
    class GC cyan;
    class Net gray;

    

Once you’ve joined, you should expect to receive a Referee packet on a regular interval, independent of any camera framerate. Do not assume the game is running the current command until you’ve received a Referee packet saying so. Field data delivery is not guaranteed here either — a dropped packet is not re-transmitted, and packet loss should be well below 1%.

        %%{init: {"sequence": {"useMaxWidth": false, "actorMargin": 220, "messageMargin": 40}}}%%
sequenceDiagram
    participant Team as Team Client
    participant Net as Switch / Router<br/>(multicast group 224.5.23.1:10003)
    participant GC as Game Controller

    Team->>Net: IGMP Join 224.5.23.1:10003
    Note over Team,GC: No handshake — Team is now another multicast receiver

    GC->>Net: Referee (stage, command, scores)
    Net->>Team: Referee (stage, command, scores)

    GC->>Net: Referee
    Net--xTeam: Referee — dropped
    Note over Team: No retransmission — team just waits for the next packet

    GC->>Net: Referee
    Net->>Team: Referee

    

Remote Control “rcon” Channels (Optional)

If a team’s software/AI wants to request a keeper change, respond to an advantage choice, or request a substitution, it opens a TCP connection to the Game Controller and registers. Again, many of these functions can be done by the human robot handler and physical remote control provided by the event organizer/field. There are three separate rcon channels, each on its own port: one for teams, one for autoRefs, and one for physical remote controls. Registration and signing are described in ssl_gc_rcon.proto; signatures are optional and only needed for secure/verified communication.

Unlike the broadcast channel, opening a TCP connection requires knowing the Game Controller’s actual IP. You don’t need to guess this or hardcode a hostname — read it off the source address field of the IP packets carrying the Referee broadcast you’re already receiving. Whatever machine that traffic comes from is the Game Controller.

        %%{init: {"sequence": {"useMaxWidth": false, "actorMargin": 220, "messageMargin": 40}}}%%
sequenceDiagram
    participant Team as Team Client
    participant GC as Game Controller

    Team->>GC: TCP connect :10008 (or :10108 for TLS)
    Team->>GC: TeamRegistration (team_name[, signature])
    GC->>Team: ControllerReply (status_code=OK, next_token)
    Note over Team,GC: Connection stays open — one registration, then repeated exchanges.<br/>next_token must be echoed back in the next Signature if using secure comms.

    Team->>GC: TeamToController (ping)
    GC->>Team: ControllerToTeam (controller_reply)

    Team->>GC: TeamToController (desired_keeper)
    GC->>Team: ControllerToTeam (controller_reply)

    

The connection stays open — registration happens once, then the team sends further requests and receives replies over the same socket for as long as it stays connected. If a team never connects, it simply never receives a ControllerReply and never gets to make requests; the game continues based on the referee’s broadcast state alone.

Connections Table

The following table contains connection information for the broadcast channel and the team/remote-control rcon channels. AutoRef connections use the same rcon flow but are documented on the referee protocol page instead, alongside the rest of the autoRef-specific content.

Protocol

Protobuf

Type

Address

Port

SSL-Game-Controller (GC)

Referee

UDP Multicast

224.5.23.1

10003

Team -> GC

Team

TCP

GC

10008

Team -> GC

Team

TCP + SSL

GC

10108

Remote Control -> GC

Remote Control

TCP

GC

10011

Remote Control -> GC

Remote Control

TCP + SSL

GC

10111

Message Format

The league uses google protobuf to define the data format for this protocol too. The interface definitions are in the same league protobuf repository used for vision. The image below shows the hierarchy of the broadcast Referee message — the one every team decodes, whether or not it ever opens an rcon connection.

        ---
config:
  layout: elk
  elk:
    nodePlacementStrategy: NETWORK_SIMPLEX
---
flowchart TD
    Referee["Referee<br/>one packet per broadcast"]
    Referee --> Stage["stage, command,<br/>packet_timestamp"]
    Referee --> Yellow["yellow<br/>Referee.TeamInfo"]
    Referee --> Blue["blue<br/>Referee.TeamInfo"]
    Referee --> Pos["designated_position<br/>Referee.Point"]
    Referee --> Events["game_events[]<br/>GameEvent"]
    Referee --> Proposals["game_event_proposals[]<br/>GameEventProposalGroup"]

    classDef slate fill:#f8fafc,stroke:#475569,color:#0f172a;
    classDef cyan fill:#ecfeff,stroke:#0891b2,color:#164e63;
    classDef purple fill:#faf5ff,stroke:#9333ea,color:#581c87;
    classDef amber fill:#fffbeb,stroke:#d97706,color:#78350f;
    class Referee slate;
    class Stage cyan;
    class Yellow,Blue purple;
    class Pos,Events,Proposals amber;

    

Referee is the single top level structure sent on the broadcast channel. It carries the coarse game stage and fine-grained command teams must obey, a Referee.TeamInfo for each of yellow and blue (score, cards, timeouts, keeper id), an optional designated_position for ball placement, and any game_events/game_event_proposals the active autoRef has reported.

The table below contains links to the specific proto files needed to decode the broadcast message and the three rcon channels. It’s recommended you include the entire ssl-protocol-defs repository as a submodule in your code, rather than copying the files directly.

Message

Proto File

Referee, Referee.TeamInfo, Referee.Point

ssl_gc_referee_message.proto

GameEvent, GameEventProposalGroup

ssl_gc_game_event.proto

ControllerReply, Signature

ssl_gc_rcon.proto

TeamRegistration, TeamToController, ControllerToTeam

ssl_gc_rcon_team.proto

AutoRefRegistration, AutoRefToController, ControllerToAutoRef

ssl_gc_rcon_autoref.proto

RemoteControlRegistration, RemoteControlToController, ControllerToRemoteControl, RemoteControlTeamState

ssl_gc_rcon_remotecontrol.proto

Team, RobotId, Division

ssl_gc_common.proto

Team Sides

This protocol shares its coordinate frame and units with the vision protocol — see vision’s coordinate system for the full breakdown (mm, radians, CCW from +X). The only game-controller-specific piece is blue_team_on_positive_half, which tells you which side of the field’s +X axis the blue team currently defends. This flips between halves — do not hardcode a side. designated_position (used for ball placement) is a Referee.Point in the same field frame.

Registration Channels

The Game Controller’s rcon interface is split into three independent TCP channels — team, autoRef, and remote control — each on its own port, each with its own registration message and message types. This means if your software wants to act as more than one role (for example, a team client that is also a remote control), it needs a separate TCP connection and registration per role; they are not multiplexed over one socket.

The referee protocol page documents how teams can use the game_events an automatic referee reports over this protocol.

Network Flow

The diagram below is the same competition network fan-out shown in the field network documentation, with the machines involved in the game controller protocol highlighted and the vision-only machines (cameras, Truss NUC, Vision Computer) muted. The Game Controller publishes the 224.5.23.1:10003 broadcast and serves the three rcon channels; team PCs, remotes, the status board, and the officiating/broadcast machines that read referee state all consume it. The router and switch are highlighted too — they maintain the multicast group and carry the rcon TCP connections.

SSL field network fan-out diagram with game-controller-producing and game-controller-consuming machines highlighted, vision-only machines muted SSL field network fan-out diagram with game-controller-producing and game-controller-consuming machines highlighted, vision-only machines muted