Gameplay Sessions Technical Reference
Although developers on Regression Games will often interact with the Gameplay Sessions through the web interface or within the SDK itself, you may be interested in viewing and understanding the data directly. This document provides a technical overview of the Gameplay Sessions system, as well as more technical details and FAQ.
Overview of the Schema
Folder and File Structure
When a Gameplay Session is recorded, all data is stored on disk within two folders:
~/unity_videos/{Application.productName}/recording_{date}_{time}_{sessionId}/screenshots
- A folder with screenshots for each recorded tick of the session. Each screenshot is named with the format{tick#}.jpg
, wheretick#
is the in-game tick from the start of the session.~/unity_videos/{Application.productName}/recording_{date}_{time}_{sessionId}/data
- A folder with the state and input data for each recorded tick of the session. Each tick is stored in a JSON file named with the format{tick#}.json
.
After a recording is finished, you will not see these folders, because they will be compressed into zip files
(bot_segments.zip
, data.zip
, and screenshots.zip
within the recording_{date}_{time}_{sessionId}
folder).
Additionally, there is a thumbnail.jpg
file stored in this sessionDirectory
, which is the screenshot from the middle of
your Gameplay Session.
Structure of {tick#}.json Files
Each {tick#}.json
file contains the following information:
- Timing information (e.g. tick number, time, time scale)
- Screen size information
- Information about the state of the game (i.e. the game objects / entities within the game on that tick)
- Information about inputs on that tick (i.e. keyboard, mouse)
- Key frames on this tick (explained below)
Game Object State
Within the state
field, an array of objects represents the state of game objects on this tick. Depending on the
options you have configured for recording, some objects
and state in your scene may not be present in this list.
Key Frames
Key frames is how the SDK marks important moments in your gameplay session. They are represented as an array of strings
in the keyFrame
field of the {tick#}.json
file. The possible key frames are:
FIRST_FRAME
- Indicates that this tick is the first tick of the gameplay session.SCENE
- Indicates that the scenes visible in this tick are different from the scenes visible in the previous tick.GAME_ELEMENT
- Indicates that a game element became visible to the camera or went off camera this tick. This could be from spawning, de-spawning, movement, or camera rotation/movement.GAME_ELEMENT_RENDERER_COUNT
- Indicates that a visible game element changed its number of renderers this tick.UI_ELEMENT
- Indicates that a visible UI element became visible to the camera or went off camera this tick. This could be from spawning, de-spawning, or UI component or canvas group visibility changes.UI_PIXELHASH
- Indicates that the screen pixels of a UI component changed this tick. This value is only relevant when using 3rd party UI system like Coherent GameFace.
Any time one of these events occurs on a tick, the corresponding key frame will be added to the keyFrame
array.
Example of a Tick JSON File
{
"tickNumber": 2,
"keyFrame": [
"UI_ELEMENT"
],
"time": 8.4254524,
"timeScale": 1,
"screenSize": {
"x": 2078,
"y": 1137
},
"performance": {
"previousTickTime": 8.4254524,
"framesSincePreviousTick": 0,
"fps": 0,
"engineStats": {
"frameTime": 0.0047242,
"renderTime": 0.0035487,
"triangles": 13910,
"vertices": 19124,
"setPassCalls": 22,
"drawCalls": 110,
"dynamicBatchedDrawCalls": 2,
"staticBatchedDrawCalls": 2,
"instancedBatchedDrawCalls": 0,
"batches": 110,
"dynamicBatches": 2,
"staticBatches": 1,
"instancedBatches": 0
}
},
"state": [
{
"id": -13744,
"path": "UI Canvas/LobbyPopup/Tabs/LobbyCreationUI/Lobby Name Input Field",
"scene": "MainMenu",
"tag": "Untagged",
"layer": "UI",
"rendererCount": 4,
"screenSpaceBounds": {
"center": {
"x": 1038.0159912,
"y": 556.3427734,
"z": 0
},
"extents": {
"x": 320.1767578,
"y": 32.0177001,
"z": 0.05
}
},
"worldSpaceBounds": null,
"position": {
"x": 1038.0159912,
"y": 556.3427734,
"z": 0
},
"rotation": {
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"rigidbodies": [],
"colliders": [],
"behaviours": [
{
"name": "UnityEngine.UI.Image",
"path": "UI Canvas/LobbyPopup/Tabs/LobbyCreationUI/Lobby Name Input Field",
"state": {
"sourceImage": "inputfield_Blank",
"color": {
"r": 1,
"g": 1,
"b": 1,
"a": 1
},
"material": "Default UI Material",
"raycastTarget": true,
"preserveAspect": false
}
},
{
"name": "UnityEngine.UI.InputField",
"path": "UI Canvas/LobbyPopup/Tabs/LobbyCreationUI/Lobby Name Input Field",
"state": {}
},
{
"name": "UnityEngine.UI.LayoutElement",
"path": "UI Canvas/LobbyPopup/Tabs/LobbyCreationUI/Lobby Name Input Field/Lobby Name Input Field Input Caret",
"state": {}
},
{
"name": "UnityEngine.UI.Text",
"path": "UI Canvas/LobbyPopup/Tabs/LobbyCreationUI/Lobby Name Input Field/InputBox",
"state": {
"text": "Enter your lobby name...",
"font": "Arial",
"fontStyle": "BoldAndItalic",
"fontSize": 50,
"color": {
"r": 0.9215687,
"g": 0.8196079,
"b": 0.2470588,
"a": 0.5
},
"raycastTarget": true
}
},
{
"name": "UnityEngine.UI.Text",
"path": "UI Canvas/LobbyPopup/Tabs/LobbyCreationUI/Lobby Name Input Field/InputText",
"state": {
"text": "",
"font": "Arial",
"fontStyle": "Bold",
"fontSize": 50,
"color": {
"r": 0.9215687,
"g": 0.8196079,
"b": 0.2470588,
"a": 1
},
"raycastTarget": true
}
}
]
}
],
"inputs": {
"keyboard": [],
"mouse": [
{
"startTime": 6.9127706,
"position": {
"x": -1,
"y": 0
},
"worldPosition": null,
"leftButton": false,
"middleButton": false,
"rightButton": false,
"forwardButton": false,
"backButton": false,
"scroll": {
"x": 0,
"y": 0
},
"clickedObjectIds": []
}
]
}
}
How performance information is scraped
Performance information, such as fps, render time, and object stats are either calculated frame-by-frame, or use
the UnityStats class. Since
UnityStats is an editor-only feature, some performance information, specifically that of engineStats
, is only
available when running in the Unity Editor.
Performance information like fps
is calculated tick by tick.
Performance information like cpuTimeSincePreviousTick
, memory
, and gcMemory
are captured using Unity ProfilerRecorder.
Performance information like render time object stats are captured using the UnityStats class.
Since UnityStats is an editor-only feature, some performance information, specifically the engineStats
section of the state, is only available when running in the Unity Editor.
RGTestUtils class
The RGTestUtils
class is a utility class that provides methods for loading and playing back recordings in Unity
Play Mode tests. This class is included in the SDK and can be used to automate the testing of your game.
To use this class, first add RegressionGames
and RegressionGames.TestFramework
as references to your test assembly:
API
namespace RegressionGames
{
/// <summary>
/// Utilities for running tests within the Unity Test Runner using Regression Games features.
/// </summary>
public class RGTestUtils
{
/// <summary>
/// Waits until a specific scene has been loaded, and asserts that it has been loaded
/// </summary>
/// <param name="sceneName">The name of the scene to wait for</param>
/// <param name="timeout">The maximum time to wait for the scene to load (in seconds). Defaults to 5.</param>
public static IEnumerator WaitForScene(string sceneName, int timeout = 5)
/// <summary>
/// Plays back an existing recording, and then returns the save location of the recording.
/// </summary>
/// <param name="recordingPath">The path to the recording to play back (the full bot_segments.zip file path)</param>
/// <param name="setPlaybackResult">A callback that will be called with the results of this playback</param>
public static IEnumerator StartPlaybackFromFile(string recordingPath, Action<PlaybackResult> setPlaybackResult)
}
}
Additionally, the PlaybackResult
class contains information about the recording playback results, such as the location
of the new recording.
namespace RegressionGames.Types
{
[Serializable]
public class PlaybackResult
{
/// <summary>
/// The location that the playback recording is saved to on disk.
/// </summary>
public string saveLocation;
}
}