Game integration API

Overview

Game integrations communicate with the web instance using HTTP endpoints under /api/game controlled by App\Controllers\GameIntegrationController, hereinafter referred to as the web API.

Integrations communicate by

  • periodically sending connecting and connected players' identifiers and polling for incoming actions from the POST /api/game/poll route.
  • responding to game events (e.g. bans and group changes) by sending requests to the web API.

Authentication

Game integrations authenticate every request using a server token in the Authorization header (Authorization: Bearer: <token>).

Initialization

Settings are be obtained with the GET /api/game/meta?actions[]=settings request (under the actions key of the JSON response).

Polling

Further actions (possibly including changes to settings) are received by calling the /api/game/poll endpoint at intervals specified by its X-RateLimit-Reset response header.

Endpoints

MethodRouteParametersNote
GET/api/game/metaactionsReturns actions
POST/api/game/pollplayersReturns actions
PATCH/api/game/actions/executions/{execution_id}/finisherror
POST/api/game/players/{source_id}/{account_id}/bansadmin_{source_id}_account_id, duration_minutes, reason, scope
DELETE/api/game/players/{source_id}/{account_id}/bans
POST/api/game/players/{source_id}/{account_id}/rolesnameMulti-role games
DELETE/api/game/players/{source_id}/{account_id}/roles/{role_ingame_equivalent}Multi-role games
GET/api/game/players/{source_id}/{account_id}/primaryroleSingle-role games
POST/api/game/players/{source_id}/{account_id}/primaryrolenameSingle-role games
POST/api/game/players/{source_id}/{account_id}/linktokenAuth providerless games

Placeholder definitions

  • {source_id}: abbreviated from external_account_source_id; refers to an external account source (which may correspond to an OAuth provider).
  • {account_id}: abbreviated from external_account_id; refers to the player's external account identifier from the given source.

Example requests

  • URL: /api/game/poll
    • Body: players[steam][connecting][ids]=76561198131926932
  • URL: /api/game/players/steam/76561198131926932/roles
    • Body: name=admin
  • URL: /api/game/players/steam/76561198131926932/bans
    • Body: admin_steam_account_id=76561198131926932&scope=global

Action types

Below is a partial overview of the actions types available.

Code action

Code to be compiled and executed, specified by payload.

Command action

A console command to be executed, specified by payload.

Roles action

Actions of type roles concern a single player identified by payload.player_{source_id}_account_id.

Exhaustive

  • Dispatched only when role sync is configured to send roles to the game server.
  • Dispatched only when the player is connecting.
  • payload.exhaustive is set to true.
  • payload.grant and payload.revoke contain all of the associated user's roles and (prior) revoked roles, respectively.

Partial

  • Dispatched from store package actions and role sync.
  • May be dispatched even when the player is not present.
  • payload.exhaustive is set to false.
  • payload.grant and payload.revoke contain some or all of the associated user's roles and (prior) revoked roles, respectively.

Settings action

Settings for the integration (configured from the server manager in the web UI).

E.g. payload.role_sync specifies if and how roles should be synchronized.

Implementation

Adding a game to the backend

  • Implement a game class (see the abstract class App\Models\Games\Game for available member variables and methods).
  • In a module service provider's boot method, call the App\Models\Server::setGame method supplying a key and a game class.

Example game

Class GarrysMod.php
namespace Modules\Example\Games;

use App\Models\User;

class GarrysMod extends SteamGame
{
    protected static string $name = 'Garry\'s Mod';
    protected static int $steamAppId = 4000;

    protected static bool $integration = true;

    public static function getConsoleCommands(): array
    {
        return [
            'kick' => static fn (User $user, string $reason) => "kickid {$user->steamid2} \"{$reason}\"",
        ];
    }
}
Registration
Server::setGame('gmod', GarrysMod::class);

Writing an integration

Refer to the game's (or a modding framework's) documentation and implement the web API as a plugin.

Implementation notes

Actions
  • The PATCH /api/game/actions/executions/{execution_id}/finish endpoint should be called for actions which specify payload.execution_id (with the body containing an error string on failure).
  • Applicability is game-specific, thus actions may be ignored.
  • Unrecognized action types must be handled gracefully.
Roles

WARNING

Games which only support a single role per player

The GET/POST primary role endpoint at /api/game/players/{source_id}/{account_id}/primaryrole must be used when handling roles actions.

Setting the user's primary role implicitly revokes roles lower in hierarchy.

Desired behavior depends on the role sync configuration of the server.

Receive from web API (role_sync.receive set to true)

For exhaustive actions it's safe to grant payload.grant[0] (as the order is hierarchial). If grants are empty, the player's current role (if any) must be revoked if it corresponds to a role in payload.revoke. If it does not and role_sync.send is set to true, the player's current role should be sent to the web API (to handle initial synchronization).

If a partial revoke contains the player's current role, the GET primary role endpoint must be used to determine whether the corresponding user retains another role (which, if any, should be granted to the player).

Send to web API (role_sync.send set to true)

If role_sync.receive is set to

  • true, when handling partial actions avoid inadvertently revoking roles (implicitly) by GETting the player's primary role.
  • false, exhaustive actions are to be handled by POSTing the player's current role if it is not already present in payload.grant.