Class RemoteControl
Bridges a TCP connection to Unity's event system, letting a remote study operator trigger predefined scene actions during a live session without physical access to the machine.
[RequireComponent(typeof(TCPServer))]
public class RemoteControl : MonoBehaviour, IDataLoggable
Inheritance
Implements
Examples
Inspector setup
- Create signal assets: right-click in the Project window and choose
ScriptableObject → Configuration Assets → Remote Control Button Configuration. Give each a human-readableName(e.g.,"StartScenario") and optionalTextandTags. TheID(GUID) field is auto-populated. - On the RemoteControl component, add entries to
MessageDictionary: drag each signal asset into the key slot and wire
the corresponding UnityEvent (e.g.,
ScenarioManager.StartScenario()).
Wire framing
Every TCP message in both directions is wrapped in a netstring:
:,
The numeric prefix is the exact byte length of the payload (ASCII encoding). TCPServer handles all netstring encoding on outgoing messages and decoding on incoming messages automatically — see its documentation for full details. Messages that do not conform to this format are silently discarded by TCPServer. The framing examples below show what the remote client must send and receive on the wire.
Manifest sent to the remote client on connection (Unity → Client)
Immediately after TCP connection is established, RemoteControl sends a netstring whose payload is a JSON array of all registered signals. Each element is a RemoteControlSignalDTO:
264:[{"ID":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","Name":"StartScenario","Text":"Begin the main driving scenario.","Tags":["scenario","start"]},{"ID":"b2c3d4e5-f6a7-8901-bcde-f12345678901","Name":"AbortScenario","Text":"Abort the current scenario.","Tags":["scenario","abort"]}],
Command sent from the remote client to trigger an action (Client → Unity)
To fire a registered UnityEvent, the client sends the signal's ID string wrapped
in a netstring. The payload is just the raw GUID — no JSON wrapper:
36:a1b2c3d4-e5f6-7890-abcd-ef1234567890,
Any message whose payload does not exactly match a registered ID is silently ignored.
Minimal Python client
import socket, json
def to_netstring(s):
payload = s.encode("ascii")
return f"{len(payload)}:".encode("ascii") + payload + b","
def from_netstring(data):
raw = data.decode("ascii")
colon = raw.index(":")
length = int(raw[:colon])
return raw[colon + 1 : colon + 1 + length]
with socket.create_connection(("192.168.1.100", 5000)) as sock:
# Receive the manifest netstring and decode it
signals = json.loads(from_netstring(sock.recv(4096)))
target_id = next(s["ID"] for s in signals if s["Name"] == "StartScenario")
# Send the ID wrapped in a netstring to trigger the corresponding UnityEvent
sock.sendall(to_netstring(target_id))
Remarks
The simulation machine may be inside a driving simulator cab that is physically inaccessible once a participant is seated. A researcher at a control desk connects over TCP, selects a labelled action (e.g., "start scenario", "abort", "go to next waypoint"), and the corresponding UnityEvent fires on the simulation machine — all without interrupting the session.
The MessageDictionary maps RemoteControlSignal assets (which carry a human-readable name and a stable string ID) to UnityEvents, so the operator tool receives a self-describing JSON manifest on connection and can show a labelled button panel without hard-coding signal IDs.
This component is excluded from WebGL builds (#if !UNITY_WEBGL) because TCP
sockets are not available in browser sandboxes; WebGL deployments use URL parameters
and the PHP backend for equivalent operator control.
Methods
Collect()
Returns a RemoteControlSystemDataLog containing all accumulated action
timestamps and clears the cache, or returns null if no actions were triggered.
public DataLog Collect()
Returns
DataLog — A snapshot of all remote control actions, or null if none occurred.
Remarks
Returning null for an empty log suppresses an unnecessary allocation; the
analysis pipeline treats null as "no data this session" and skips the record.
On WebGL builds where TCP is unavailable the method always returns null.