WebSocket API Reference
The WebPlatform exposes two WebSocket servers and maintains one outbound WebSocket connection. All messages are JSON-encoded strings.
Ports summary
| Port (default) | Env var | Direction | Purpose |
|---|---|---|---|
8001 | MONITOR_WS_PORT | Frontend ↔ WebPlatform | Admin UI control and state updates |
8080 | HEADSET_WS_PORT | Headset ↔ WebPlatform | Player connection and simulation data |
1000 | GAMA_WS_PORT | WebPlatform → GAMA | GAMA server protocol (outbound client) |
Monitor WebSocket (MONITOR_WS_PORT)
The admin UI (browser frontend) connects to this port. The server broadcasts state updates to all connected monitor clients and sends targeted responses to the requesting client.
Messages: Frontend → WebPlatform
launch_experiment
Start the currently selected simulation in GAMA.
{ "type": "launch_experiment" }
stop_experiment
Stop the running simulation. All headsets are removed from the simulation.
{ "type": "stop_experiment" }
pause_experiment
Pause the running simulation. Headsets stay connected.
{ "type": "pause_experiment" }
resume_experiment
Resume a paused simulation.
{ "type": "resume_experiment" }
get_simulation_informations
Request the full catalog of available Virtual Universes. The server responds with the catalog structure read from the learning-packages directories.
{ "type": "get_simulation_informations" }
get_simulation_by_index
Select a specific Virtual Universe by its index in the flat model list and receive its settings.
{
"type": "get_simulation_by_index",
"simulationIndex": 0
}
simulationIndex is a 0-based integer index into the list returned by get_simulation_informations.
send_simulation
Alternative to get_simulation_by_index. Select a simulation using the model_index field embedded in a previously received simulation object.
{
"type": "send_simulation",
"simulation": { "model_index": 2 }
}
add_player_headset
Manually add a connected headset to the running simulation. Normally headsets are added automatically on experiment launch.
{
"type": "add_player_headset",
"id": "player-ip-or-id"
}
remove_player_headset
Remove a headset from the simulation and disconnect it.
{
"type": "remove_player_headset",
"id": "player-id"
}
id must match the player's id field (set by the headset on connection), not the internal IP key.
screen_control
Switch the display mode shown on all monitor clients.
{
"type": "screen_control",
"display_type": "stream"
}
try_connection
No-op in normal mode. Sent by the frontend to check whether GAMA is reachable. The GamaConnector manages its own reconnection independently.
{ "type": "try_connection" }
Messages: WebPlatform → Frontend
json_state
Broadcast to all connected monitor clients whenever GAMA or player state changes.
{
"type": "json_state",
"gama": {
"connected": true,
"experiment_state": "RUNNING",
"loading": false,
"content_error": "",
"experiment_id": "abc123",
"experiment_name": "My Simulation"
},
"player": {
"PlayerA": {
"id": "PlayerA",
"connected": true,
"in_game": true,
"date_connection": "14:32"
}
}
}
gama.experiment_state values:
| Value | Meaning |
|---|---|
NONE | No experiment loaded |
NOTREADY | Experiment loading |
RUNNING | Experiment running |
PAUSED | Experiment paused |
In GAMALESS mode (ENV_GAMALESS=true), gama is an empty object {}.
get_simulation_by_index
Response to a get_simulation_by_index or send_simulation request. Sent only to the requesting client.
{
"type": "get_simulation_by_index",
"simulation": {
"type": "json_settings",
"name": "Flood Model",
"splashscreen": "./splash.png",
"model_file_path": "/absolute/path/to/model.gaml",
"experiment_name": "Launch",
"minimal_players": "1",
"maximal_players": "6",
"model_index": 0
}
}
Catalog response (to get_simulation_informations)
The server sends the raw JSON string of the nested catalog structure. Each entry is either a json_settings leaf or a catalog node:
[
{
"type": "json_settings",
"name": "Single-player demo",
"splashscreen": "./splash.png",
"model_index": 0
},
{
"type": "catalog",
"name": "Flood scenarios",
"entries": [
{ "type": "json_settings", "name": "Quang Binh", "model_index": 1 },
{ "type": "json_settings", "name": "Mekong Delta", "model_index": 2 }
]
}
]
screen_control
Forwarded to all monitor clients when the display mode changes.
{
"type": "screen_control",
"display_type": "stream"
}
Headset WebSocket (HEADSET_WS_PORT)
VR headsets (running the Unity app) connect to this port. The server uses each headset's IP address as its internal key.
Messages: Headset → WebPlatform
connection
First message sent by a headset after establishing the WebSocket connection. Registers the headset in the player list.
{
"type": "connection",
"id": "PlayerA",
"heartbeat": 5000
}
| Field | Type | Description |
|---|---|---|
id | string | Human-readable player identifier (set in the Unity app, typically the headset color name) |
heartbeat | number | Desired ping interval in milliseconds. Defaults to 5000 if omitted. |
ping
Sent by a headset to verify its connection is alive. The WebPlatform responds with pong.
{
"type": "ping",
"id": "PlayerA"
}
pong
Response to a heartbeat ping sent by the WebPlatform.
{ "type": "pong" }
expression
Send a GAML expression to be evaluated in the running GAMA simulation on behalf of this player. The literal string $id in expr is replaced with the player's id before being forwarded to GAMA.
{
"type": "expression",
"expr": "do my_action(player: $id);"
}
ask
Send a GAML ask statement to GAMA on behalf of this player.
{
"type": "ask",
"action": "my_action",
"args": "{\"key\": \"value\"}",
"agent": "unity_linker[0]"
}
disconnect_properly
Request a clean disconnection. The WebPlatform removes the player from GAMA and closes the WebSocket with code 1000.
{ "type": "disconnect_properly" }
Messages: WebPlatform → Headset
ping
Heartbeat sent by the WebPlatform at the interval negotiated during connection. The headset must respond with pong. If no response is received before the next ping, the connection is considered dead and terminated.
{ "type": "ping" }
pong
Response to a headset-initiated ping.
{
"type": "pong",
"id": "PlayerA"
}
json_state
Sent to a headset whenever its state changes (connection, in-game status). Contains all player fields except the internal WebSocket handle and timer.
{
"type": "json_state",
"id_player": "PlayerA",
"id": "PlayerA",
"connected": true,
"in_game": false,
"date_connection": "14:32"
}
json_output
Simulation data from GAMA, targeted at this specific player. The contents field is the raw payload produced by the GAML model's send_world or send_geometries actions, filtered to only include entries addressed to this player's id.
{
"type": "json_output",
"contents": [
{ "key": "value" }
]
}
GAMA WebSocket (outbound client)
The WebPlatform connects as a WebSocket client to the GAMA server at ws://<GAMA_IP_ADDRESS>:<GAMA_WS_PORT>.
Messages: WebPlatform → GAMA
Load experiment
{
"type": "load",
"model": "/absolute/path/to/model.gaml",
"experiment": "ExperimentName"
}
Control experiment
{
"type": "play" | "pause" | "stop",
"exp_id": "<experiment-id>"
}
Send expression (player action or ask)
{
"type": "expression",
"exp_id": "<experiment-id>",
"expr": "do create_player(\"PlayerA\");"
}
Messages: GAMA → WebPlatform
type | Description |
|---|---|
ConnectionSuccessful | GAMA accepted the WebSocket connection |
SimulationStatus | Experiment state changed; content holds the new state string |
SimulationOutput | JSON-encoded simulation output (content field); forwarded to headsets |
CommandExecutedSuccessfully | A command was accepted; command.type === "load" carries the experiment name |
SimulationStatusError | Simulation state error |
SimulationErrorDialog | GAMA displayed an error dialog |
SimulationError | Generic simulation error |
RuntimeError | GAMA runtime error |
GamaServerError | GAMA server-level error |
MalformedRequest | Sent message was not valid |
UnableToExecuteRequest | GAMA could not execute the request |
On any error type, the WebPlatform logs the error and sets content_error in the state broadcast to the admin UI.
On abnormal socket closure, the WebPlatform waits 5 seconds and attempts to reconnect automatically.