This is the GameController software for robot soccer games in the RoboCup Humanoid Soccer League.
- Rust and other platform-specific tauri dependencies as listed here
- nodejs and npm (or a compatible package manager)
- libclang (for bindgen)
- On Windows:
winget install LLVM set LIBCLANG_PATH 'C:\Program Files\LLVM\bin\'
First, the frontend must be compiled:
cd frontend
npm ci
npm run buildThe Rust code is compiled with cargo:
cargo build [-r]First, thank you for contributing to development.
This will install the tauri CLI:
cargo install tauri-cliThis will start the frontend and backend in dev mode:
cargo tauri devFor Linux, macOS and Windows, there are scripts in the directory dist/ to create binary distributions.
dist/mkdist [<target>] (dist/mkdist.ps1 on Windows) builds archives of all products in one go (named after the version in Cargo.toml):
the application (app), the C API (api) and the log analysis tool (logs).
--only app,api,logs selects products, and --stage-only only creates the directories that the archives are made from.
The target is optional (otherwise the host target is assumed on Linux and Windows, while macOS creates Universal binaries).
They build a special profile called release-dist which mainly tries to create a small binary.
It is recommended to run the scripts only on a clean working tree.
Configuration files that are read at runtime are located in a configuration directory.
It is the first of the following directories that contains a teams.yaml:
- The directory given with
--config-dir(or the environment variableGAMECONTROLLER_CONFIG). If this option is used, no other directory is tried. - The
configdirectory in the user's directory ($XDG_CONFIG_HOME/GameControlleror~/.config/GameControlleron Linux,~/Library/Application Support/GameControlleron macOS,%LOCALAPPDATA%\GameControlleron Windows). - The configuration that is shipped with the application (
<prefix>/share/GameController/configon Linux, inside the app bundle on macOS,confignext to the program on Windows). configin the root of a source checkout (this is what is used forcargo run).
Directories are never combined, i.e. a user directory has to contain all files.
The directory that is used is printed to the standard error output on start, --show-paths lists all candidates, and an error lists the directories that were tried.
--install-config copies the shipped configuration to the user's config directory so that it can be edited.
Because it is not updated together with the application, a warning is printed when the user's configuration was created by another version.
The global teams.yaml is a list of all teams in the HSL, their names, and their available jersey colors both for field players and goalkeepers.
Each (sub)competition has a subdirectory with two files:
params.yaml corresponds to the Rust struct game_controller_core::types::CompetitionParams and sets (mostly numeric) constants for the competition.
teams.yaml is a list of team numbers of the teams that participate in the competition.
Only those teams can be selected when playing in this competition.
Therefore, for a new team to appear in the UI, an entry must be added both to the global teams.yaml (with an unused team number) and in the competition's teams.yaml (referencing the team number).
Currently, all network communication with the GameController uses IPv4, although most parts of the code can also handle IPv6.
The GameController communicates with robot players via three channels:
- It sends control messages at a rate of 2 hertz (UDP broadcast on port 3838, format specified in the struct
RoboCupGameControlDataingame_controller_msgs/headers/RoboCupGameControlData.h). These control messages do not always represent the true game state, specifically after a transition to theplayingstate. After these events, they continue to maintain the state before the event for up to 10 seconds, or until another event happens that could not have happened in this "fake" state. A control message is sent immediately and the rate is temporarily increased to 5 hertz when play is stopped. - It receives status messages from the robot players which must send them at a rate between 0.5 hertz and 2 hertz (UDP unicast on port 3939, format specified in the struct
RoboCupGameControlReturnDataingame_controller_msgs/headers/RoboCupGameControlData.h). - It receives team messages from the robot players (UDP broadcast on port 10000 + team number, up to 512 bytes of payload with arbitrary format).
In addition, the GameController offers an interface for monitor applications (such as the TeamCommunicationMonitor or the EventRecorder):
- It receives monitor requests (UDP unicast on port 3636, 4 bytes header magic
RGTr+ 1 byte version number0). It refuses to accept monitor requests from hosts that have previously sent status messages, as those are presumed to be robot players which should not get true data. Similarly, if a host that had previously sent a monitor request sends a status message, it will not receive monitor data anymore. - Each registered monitor host will get:
- control messages with the true game state at a rate of 2 hertz (UDP unicast on port 3838, with the same format as regular control messages, but with the header magic
RGTD). - forwarded status messages (UDP unicast on port 3940, prefixed by the IPv4 address of the original sender). The forwarded payload has not been validated.
- control messages with the true game state at a rate of 2 hertz (UDP unicast on port 3838, with the same format as regular control messages, but with the header magic
The user must ensure that all of the aforementioned network communication channels are allowed to be used by the firewall.
The GameController runs on a specific network interface, which generally specifies where packets are sent and from where they are received.
The exceptions are that control messages can be configured to be sent to the limited broadcast address (255.255.255.255) instead of the interface's broadcast address, and that monitor requests and team messages are received from any address.
The binary distributions are on the GitHub releases page.
- Linux: Unpack the archive and run
./install(installs to~/.local, or use--prefix /usr/localetc.). This addsGameControllertobin/and the GameController to the application menu. To update, run./installof the new version; to remove, run<prefix>/share/GameController/uninstall(--purgealso removes configuration and logs). The unpacked directory can also be run in place (bin/GameController). - macOS: Open the disk image and drag
GameController.appto/Applications, then start it from there. The app is not notarized by Apple, so macOS refuses to open it the first time ("cannot be checked for malware"). Open System Settings → Privacy & Security and click "Open Anyway" at the message about the GameController (or runxattr -dr com.apple.quarantine /Applications/GameController.appbefore the first start). This has to be repeated after each update. When the first broadcast packet from a robot arrives (e.g. a team message), macOS asks whether the GameController may use the local network; allow it. If the firewall is enabled, it asks to allow incoming connections as well. To allow it beforehand (e.g. before an event), run/Applications/GameController.app/Contents/Resources/allow-firewall. To update, replace the app; to remove, move it to the trash (and~/Library/Application Support/GameControllerif you want to remove configuration and logs). - Windows: Unpack the archive and run
install.ps1(right-click, Run with PowerShell) to install for the current user with a Start menu entry.uninstall.ps1(or Apps & Features) removes it. Installing over an existing installation updates it. The unpacked directory can also be run in place (GameController.exe).
Options that should apply on every start (e.g. --interface en0 or --sync) can be written to the file args in the user's directory (next to config; --install-config creates a template).
Options on the command line take precedence.
If the GameController should be run from the source code, the most convenient way to do it is by executing
cargo run [-r]from a command line within any directory of this workspace.
The program accepts command line arguments which can be passed to cargo after --.
They override the defaults of the launcher.
A list of arguments (that is always up to date, in contrast to what would be written here) can be obtained by running with the -h option:
cargo run -- -hNote that release builds on Windows do not output any text.
When the GameController is started, a launcher is shown first. Some fields will be pre-filled by command line arguments, if they were specified.
The following settings are exposed via the launcher:
- Competition: This box selects the competition type of the game. It influences the behavior and constants of the GameController and narrows down the set of teams that can be selected.
- Home / Away Team:
- The main box selects the team on the respective side.
- Field Player Color and Goalkeeper Color: These boxes select the jersey colors of the team.
- Kick-off: This radio button selects which team has the first kick-off, as a result of the coin tosses before the game.
- Mirror (between the team boxes): This checkbox selects if the home (first on the schedule) team defends the right side (from the GameController's perspective) instead of the left side, as a result of the coin tosses before the game. The team boxes swap their places accordingly.
- Network Interface: This box selects the network interface to run on (see above). Not all interfaces that are listed will necessarily work.
- Fullscreen: This checkbox selects if the window should be switched to fullscreen mode when started.
- Casting (Advanced):
- Broadcast: This checkbox selects if control messages are sent to the limited broadcast address (
255.255.255.255) instead of the interface's broadcast address. Should only be used when it is required that those messages are sent on all interfaces. - Multicast: This checkbox selects whether team communication is also received from a certain multicast group. Should only be used for simulated games, never for real competition games.
- Broadcast: This checkbox selects if control messages are sent to the limited broadcast address (
- Testing:
- No Delay: This checkbox disables the delay of game state transitions.
- Penalty Shoot-out: This checkbox allows to start/continue a penalty shoot-out even though the game is actually decided.
The launcher allows to start a game only if the two teams are distinct and their jersey colors don't conflict, i.e. the field player colors must be different from each other and from the opponent's goalkeeper color. Otherwise, the Start button is disabled and the boxes that need to be changed are outlined in red. Note that changing the sides or the kick-off team is not possible afterwards, so the switch to the main interface can only be done after the coin tosses.
The team panels (i.e. the left and right columns of the layout) should be aligned with the goals the teams are defending (from the perspective of the GameController operator). That is, the GameController operator's view defines what the left and the right team is, as it has been selected in the launcher.
The main interface is sometimes context-sensitive, i.e. some buttons only appear when they are useful in the current state of the game. However, it is generally avoided that the layout or meaning of buttons changes without user interaction (because it would be bad if a button which the user is about to press changed its meaning in that instant).
Penalties are applied by clicking the button labeled with the penalty call first and then clicking the button of the penalized player. The name of the penalty will appear below the player's color, but no timer appears yet. Once the player is returned / placed by the robot handler, the player button is clicked again. This will start a timer. Clicking the player while the timer is counting down will unset the timer (i.e. reset everything to the state immediately after penalizing the player). This should be done in case the robot handler wants to do something with the robot again. Once there are only 10 seconds remaining, the player's button starts flashing. Players are not unpenalized automatically. Instead they must be unpenalized by clicking their button once their penalty time is over. If a player has been penalized by mistake, and some actions have followed so that it cannot be simply undone, penalties can be removed early by pressing the Shift key while clicking the player. This will, however, not remove any effects on the team's penalty counter and the penalty times of other players that have been penalized later.
Some penalties are special:
- The Motion in Set penalty can be applied to multiple players without selecting it, accommodating the case that multiple players respond at once to a wrong whistle. Furthermore, players are unpenalized automatically when the timer has elapsed, since they are never removed from the field.
- When the Request for Pick-up penalty is applied during the Initial state or a Timeout, clicking the player again will unpenalize it immediately without starting a timer.
As per the rule book, team messages are counted (based on the port that they are sent on) during the Ready, Set, and Playing states (but not in penalty shoot-outs). When a team message arrives that is either too large or beyond the team's message budget, the score resets to 0 and future goals will not be counted. The score and the message counter change to a different color then.
The Stop Play button activates the stopped state and causes sending a control message immediately (cf. Network Communication). Currently there is no protection against hitting resume immediately after, i.e. double clicking resumes play immediately. The stop action can also be invoked by pressing the Space bar. However, play can only be resumed by pressing the button. The stop feature is orthogonal to the undo history, i.e. the Stop/Resume Play actions do not appear in the history, and the stopped state is not affected by going back to a previous state.
A timeout can be taken both by the teams and by the referee. When a timeout is taken during the Ready or Set state, the clock is reset to the beginning of the stoppage of play, but not the message budget.
When a timeout is taken while the half-time break timer counts down, the timer is adjusted by the duration of a timeout. This can cause confusion in so-called interleaved games because the half-time break is often longer than usual, so that even after taking a timeout that half-time break timer can still be negative.
A minute of additional time can be added by pressing the "+" button next to the main clock. This button becomes available during stoppages of play once a minute of play has elapsed in the half. Adding a minute of additional time also increases the message budget for both teams, unless a team had communicated illegally before.
To substitute players, first click the "Substitute" button on the team's side. Then, click the player which should be removed from play. The list of players will now change to the list of available substitutes (note that this list is scrollable). From this list, the player that shall replace the previously selected player is clicked. Depending on the game state, the new player gets a penalty or inherits the penalty of the substituted player. The goalkeeper property is transferred to the substitute, i.e. when the goalkeeper is substituted, the substitute is expected to wear a goalkeeper jersey and inherits the privileges of the goalkeeper. This feature must also be used before the start of a half in order to match the set of players in the GameController to the players that are actually on the field.
The goalkeeper can also be set by pressing the Shift key, which turns the "Substitute" button into a "Select" button. Afterwards, the player which should become goalkeeper can be selected (Shift can already be released). This is needed when, e.g. the goalkeeper has been sent off (because that player can't be substituted anymore), or before the start of a half, when the goalkeeper is not wearing the jersey number 1.
Extra time can be started after two halves have been played and the score is equal.
The message budget is increased.
Extra time can be skipped by removing the extraHalfDuration parameter from the competition configuration.
If the score is still equal after extra time (or regular time, if extra time has been disabled), a penalty shoot-out can be started. First, the goal that is used must be selected. Then (in the Initial state), a timeout can be taken (this is not possible in the Finished state before).
The Playing state can be entered once players on both sides are selected. This is done by clicking the "Select" button (in place of the "Substitute" button). First, the color of the selected player must be selected. This is because in a penalty shoot-out, the jersey color does not necessarily match the designation as goalkeeper or kicker, and the GameController cannot know which players are wearing which jersey. After the color has been selected, a scrollable list of players appears (similar to substitution).
At the bottom of the window, a timeline of the last five actions applied by the user is filled from right to left. Clicking on one of the actions there restores the entire game to the state immediately before that action was applied. It is not possible to undo individual actions that have been followed by other actions. The undo history is actually not limited to the last five actions, i.e. previous actions appear once some actions are undone.
Actions that were applied automatically (e.g. because a timer elapsed) do not appear in the undo history. This is because they would be applied again immediately if they were undone.
The GameController writes log files to a directory in the user's data directory, so they are kept when an installation is removed or replaced:
- Linux:
~/.local/share/GameController/logs(or$XDG_DATA_HOME/GameController/logs) - macOS:
~/Library/Application Support/GameController/logs - Windows:
%LOCALAPPDATA%\GameController\logs
They can get quite large because they are YAML. The main reason for YAML is that it is human-readable and can be appended (in contrast to JSON which requires a closing bracket in the end to be well-formed).
These log files can be analyzed by the programs from the game_controller_logs package or replayed using the TeamCommunicationMonitor.