Counter-Strike: Global Offensive Game State Integration

From Valve Developer Community
Jump to: navigation, search
This page outlines the basics of setting up game state integration with a running Counter-Strike: Global Offensive game.
Counter-Strike: Global Offensive

There are many ways for third parties to integrate their services with the game: activate stage lighting and pyrotechnics during a competitive match, activate lighting or haptic elements in peripherals connected to the player's PC during the game, complement streaming overlay with custom interactive graphics synchronized with game state, collect all game state changes to annotate recorded VODs, etc.

The game client by default can expose all game state, and send an update notification as soon as the client game state changes, to any local or remote HTTP POST endpoint using JSON as the game state structure. It just needs to know where the player wants to submit game state and what notifications to relay. This document will help third parties develop their tools and processes integrating with CS:GO game state.


Locating CS:GO Install Directory

The CS:GO client needs to read endpoint configuration files in order to find out the destination and game state components to send to the endpoint. System administrators at a competitive event know where the game client is installed on tournament players computers at the time when they image drives for the players, so no install directory discovery process is required. Keyboard or headset drivers that implement HTTP POST endpoint for activating peripherals integration may prompt the user to manually locate an existing CS:GO install directory, or may attempt to automatically locate it using the following approach.

The Steam install directory on Windows can be found in registry under the key HKEY_CURRENT_USER\Software\Valve\Steam, value "SteamPath" contains a string naming the Steam install directory. If Steam is installed into D:\Steam then Steam library folders will be listed in D:\Steam\steamapps\libraryfolders.vdf.

On OSX Steam library folders file in most cases will be found at ~/Library/Application Support/Steam/steamapps/libraryfolders.vdf.

On Linux Steam library folders file in most cases will be found at ~/.local/share/Steam/SteamApps/libraryfolders.vdf.

An automatic process locating CS:GO install directory can now iterate all user's Steam Library Folders found in libraryfolders.vdf, including the location of libraryfolders.vdf itself looking for the common CS:GO installation.

If Steam is installed into D:\Steam and CS:GO is installed directly under Steam installation directory then the location of CS:GO configuration files will be "D:\Steam\steamapps\common\Counter-Strike Global Offensive\csgo\cfg".

For game state integration to work with your service you will need to place a text file named gamestate_integration_yourservicenamehere.cfg into the csgo/cfg directory, CS:GO will pick it up next time the game launches. Different services can place their own game state integration files in csgo/cfg directory, and the game client will relay information to all registered service configurations.

For example, my sample service would place the configuration file here:

D:\Steam\steamapps\common\Counter-Strike Global Offensive\csgo\cfg\gamestate_integration_consolesample.cfg

Sample Configuration File

Here's a sample configuration file for integrating the player's own gameplay experience gamestate_integration_consolesample.cfg:

"Console Sample v.1"
{
 "uri" "http://127.0.0.1:3000"
 "timeout" "5.0"
 "buffer"  "0.1"
 "throttle" "0.5"
 "heartbeat" "60.0"
 "auth"
 {
   "token" "CCWJu64ZV3JHDT8hZc"
 }
 "data"
 {
   "provider"            "1"      // general info about client being listened to: game name, appid, client steamid, etc.
   "map"                 "1"      // map, gamemode, and current match phase ('warmup', 'intermission', 'gameover', 'live') and current score
   "round"               "1"      // round phase ('freezetime', 'over', 'live'), bomb state ('planted', 'exploded', 'defused'), and round winner (if any)
   "player_id"           "1"      // player name, clan tag, observer slot (ie key to press to observe this player) and team
   "player_state"        "1"      // player state for this current round such as health, armor, kills this round, etc.
   "player_weapons"      "1"      // output equipped weapons.
   "player_match_stats"  "1"      // player stats this match such as kill, assists, score, deaths and MVPs
 }
}

Here's a sample configuration file for stage lighting driven from a tournament observer's machine connected to team spectator gamestate_integration_observerspectator.cfg:

"Observer All Players v.1"
{
 "uri" "http://10.0.1.3:8080"
 "timeout" "5.0"
 "buffer"  "0.1"
 "throttle" "0.1"
 "heartbeat" "30.0"
 "auth"
 {
   "token" "Q79v5tcxVQ8u"
 }
 "data"
 {
   "provider"            "1"
   "map"                 "1"
   "round"               "1"
   "player_id"           "1"
   "allplayers_id"       "1"      // Same as 'player_id' but for all players. 'allplayers' versions are only valid for HLTV and observers
   "player_state"        "1"      
   "allplayers_state"    "1"      
   "allplayers_match_stats"  "1"  
   "allplayers_weapons"  "1"      
   "allplayers_position" "1"      // output the player world positions, only valid for HLTV or spectators. 
   "phase_countdowns"    "1"      // countdowns of each second remaining for game phases, eg round time left, time until bomb explode, freezetime. Only valid for HLTV or spectators. 
 }
}

Note: allplayers_weapons payload became available starting from game update 1.35.4.1, it is recommended to be used for LAN heartbeat endpoints only as the payload size and frequency is significantly increased when it is enabled.

Important: Make sure the configuration-file has no UTF8-BOM , or else the configuration-file won't load. You can see if a file was successfully loaded by the output of the console after you start CS:GO.

Endpoint Section Settings

  • uri: Game will be making POST requests to this uri. If the endpoint needs traffic to be encrypted in flight then it is recommended to specify a secure uri and use SSL on the service end. Steam client will automatically use SSL and validate endpoint certificate for https destinations.
  • timeout: Game expects an HTTP 2XX response code from its HTTP POST request, and game will not attempt submitting the next HTTP POST request while a previous request is still in flight. The game will consider the request as timed out if a response is not received within so many seconds, and will re-heartbeat next time with full state omitting any delta-computation. If the setting is not specified then default short timeout of 1.1 sec will be used.
Note:If your endpoint is never receiving JSON payload blocks named "previously" or "added" then this may be an indication that the game client is never getting HTTP 2XX response and always considers the request as failed.
  • buffer: Because multiple game events tend to occur one after another very quickly, it is recommended to specify a non-zero buffer. When buffering is enabled, the game will collect events for so many seconds to report a bigger delta. For localhost service integration this is less of an issue and can be tuned to match the needs of the service or set to 0.0 to disable buffering completely. If the setting is not specified then default buffer of 0.1 sec will be used.
  • throttle: For high-traffic endpoints this setting will make the game client not send another request for at least this many seconds after receiving previous HTTP 2XX response to avoid notifying the service when game state changes too frequently. If the setting is not specified then default throttle of 1.0 sec will be used.
  • heartbeat: Even if no game state change occurs, this setting instructs the game to send a request so many seconds after receiving previous HTTP 2XX response. The service can be configured to consider game as offline or disconnected if it didn't get a notification for a significant period of time exceeding the heartbeat interval.

Game Client Authentication

Both sample cfg files provided in this document contain an optional "auth" configuration section. In most localhost or even LAN integration scenarios this section can be completely omitted, but when it is present, fields in this section will be transmitted as JSON string fields to the endpoint to authenticate the payload. It is recommended for the endpoint to also use SSL to protect the in flight payload containing an authentication block.

Game State Components

All game state is separated into independent blocks that the service can be independently subscribed to. For example a service providing haptic feedback for every bullet fired might be interested in getting the "player_weapons" payload and any changes in weapons and ammo data, while a service annotating a video stream might only subscribe to the "map" component to keep track of the map name and round wins scored.

When developing your service it is recommended to use the sample console program provided below to output the JSON payload sent by the game and eliminate unnecessary components that aren't needed for the service operation.

When any data of a reported component changes, the game client will start the buffer timer, and after it elapses, or immediately if buffering is disabled, will report the new full game state, and delta states computed from payload with last successful HTTP 2XX response from the endpoint. For data that changed from the previous report a global block "previously" will contain old state of the changed game state, whereas for new data a global block "added" will contain the root JSON fields that are present in the new game state, but were absent in the old game state.

Sample HTTP POST Endpoint Server

An example HTTP POST server implementation printing the game payload to console is provided here using https://nodejs.org framework. You can save the provided script as mysample.js and execute node mysample.js to launch an HTTP POST server on your localhost port 3000.

http = require('http');
fs = require('fs');
 
port = 3000;
host = '127.0.0.1';
 
server = http.createServer( function(req, res) {
 
    if (req.method == 'POST') {
        console.log("Handling POST request...");
        res.writeHead(200, {'Content-Type': 'text/html'});
 
        var body = '';
        req.on('data', function (data) {
            body += data;
        });
        req.on('end', function () {
            console.log("POST payload: " + body);
        	res.end( '' );
        });
    }
    else
    {
        console.log("Not expecting other request types...");
        res.writeHead(200, {'Content-Type': 'text/html'});
		var html = '<html><body>HTTP Server at http://' + host + ':' + port + '</body></html>';
        res.end(html);
    }
 
});
 
server.listen(port, host);
console.log('Listening at http://' + host + ':' + port);

External links