Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,5 +97,9 @@ Author:
---------------------------------------------------------------------------- */
```

### Extension Commands

Commands sent to the extension DLL via `callExtension` follow a `:RESOURCE:ACTION:` naming convention. New commands must use this pattern — resource noun first, then verb/qualifier (e.g., `:SOLDIER:CREATE:`, `:EVENT:KILL:`, `:SYS:INIT:`).

### ACE3 Integration
ACE3 support is optional with graceful fallback. `fnc_aceExplosives.sqf` handles placed explosives and detonation tracking.
24 changes: 12 additions & 12 deletions addons/extension/fnc_initSession.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -16,49 +16,49 @@ addMissionEventHandler ["ExtensionCallback", {

TRACE_3("ExtensionCallback",_name,_function,_data);

if (_function isEqualTo ":VERSION:") exitWith {
if (_function isEqualTo ":SYS:VERSION:") exitWith {
// version return is automatic during extension init process
private _ver = _data#0;
GVAR(dllVersion) = _ver;
publicVariable QGVAR(dllVersion);
INFO_1("Extension version: %1",str _ver);
};

if (_function isEqualTo ":GETDIR:ARMA:") exitWith {
if (_function isEqualTo ":SYS:DIR:ARMA:") exitWith {
// arma dir return is automatic during extension init process
private _dir = _data#0;
GVAR(armaDir) = _dir;
INFO_1("Arma directory: %1",_dir);
};

if (_function isEqualTo ":GETDIR:MODULE:") exitWith {
if (_function isEqualTo ":SYS:DIR:MODULE:") exitWith {
// module dir return is automatic during extension init process
private _dir = _data#0;
GVAR(addonDir) = _dir;
INFO_1("Addon directory: %1",_dir);
};

if (_function isEqualTo ":GETDIR:OCAPLOG:") exitWith {
if (_function isEqualTo ":SYS:DIR:LOG:") exitWith {
// logging dir return is automatic during extension init process
private _dir = _data#0;
GVAR(logPath) = _dir;
INFO_1("Extension logging path: %1",_dir);
};

if (_function isEqualTo ":EXT:READY:") exitWith {
if (_function isEqualTo ":SYS:READY:") exitWith {
INFO("Extension ready.");
// extension is ready, send version
[":ADDON:VERSION:", [QUOTE(VERSION_STR)], 'ocap_recorder'] call FUNC(sendData);
[":SYS:ADDON_VERSION:", [QUOTE(VERSION_STR)], 'ocap_recorder'] call FUNC(sendData);

// get arma dir and module dir
[":GETDIR:ARMA:", [], 'ocap_recorder'] call FUNC(sendData);
[":GETDIR:MODULE:", [], 'ocap_recorder'] call FUNC(sendData);
[":SYS:DIR:ARMA:", [], 'ocap_recorder'] call FUNC(sendData);
[":SYS:DIR:MODULE:", [], 'ocap_recorder'] call FUNC(sendData);

// get logging dir
[":GETDIR:OCAPLOG:", [], 'ocap_recorder'] call FUNC(sendData);
[":SYS:DIR:LOG:", [], 'ocap_recorder'] call FUNC(sendData);

INFO("Initializing storage...");
[":INIT:STORAGE:", [], 'ocap_recorder'] call FUNC(sendData);
[":STORAGE:INIT:", [], 'ocap_recorder'] call FUNC(sendData);
};


Expand Down Expand Up @@ -146,7 +146,7 @@ addMissionEventHandler ["ExtensionCallback", {
// Save mission and world context
INFO("Saving mission and world context");
TRACE_2("World and mission context",GVAR(worldContext),GVAR(missionContext));
[":NEW:MISSION:", [GVAR(worldContext), GVAR(missionContext)], 'ocap_recorder'] call FUNC(sendData);
[":MISSION:START:", [GVAR(worldContext), GVAR(missionContext)], 'ocap_recorder'] call FUNC(sendData);
};

if (_function isEqualTo ":MISSION:OK:") exitWith {
Expand All @@ -159,5 +159,5 @@ addMissionEventHandler ["ExtensionCallback", {

INFO("Initializing extension...");
GVAR(initTimer) = diag_tickTime;
[":INIT:", []] call FUNC(sendData);
[":SYS:INIT:", []] call FUNC(sendData);
true
2 changes: 1 addition & 1 deletion addons/extension/fnc_newMission.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ if (isNil QGVAR(worldContext) || isNil QGVAR(missionContext)) exitWith {

INFO("Re-registering new mission with extension");
GVAR(initTimer) = diag_tickTime;
[":NEW:MISSION:", [GVAR(worldContext), GVAR(missionContext)], 'ocap_recorder'] call FUNC(sendData);
[":MISSION:START:", [GVAR(worldContext), GVAR(missionContext)], 'ocap_recorder'] call FUNC(sendData);
2 changes: 1 addition & 1 deletion addons/main/script_macros.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

// MACRO: LOG
// Used for logging messages to the extension (ocap-ext log file).
#define OCAPEXTLOG(_args) [":LOG:", _args] call EFUNC(extension,sendData)
#define OCAPEXTLOG(_args) [":SYS:LOG:", _args] call EFUNC(extension,sendData)

// MACRO: SYSCHAT
// Used for debug purposes to send a string to all clients with interfaces.
Expand Down
4 changes: 2 additions & 2 deletions addons/recorder/fnc_aceExplosives.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ FUNCTION: OCAP_recorder_fnc_aceExplosives

Description:
Integrates ACE3-placed explosives into the placed object pipeline.
Sends :NEW:PLACED: data and attaches lifecycle EHs (HitExplosion, Explode,
Sends :PLACED:CREATE: data and attaches lifecycle EHs (HitExplosion, Explode,
Deleted) identical to vanilla mines in fnc_eh_fired_client.sqf.

Called by <ace_explosives_place> CBA listener.
Expand Down Expand Up @@ -50,7 +50,7 @@ if (_unitOcapId isEqualTo -1) exitWith {};

_explosive setVariable [QGVARMAIN(detonated), false];

// Build :NEW:PLACED: data — same format as vanilla mines in fnc_eh_fired_client.sqf
// Build :PLACED:CREATE: data — same format as vanilla mines in fnc_eh_fired_client.sqf
private _placedData = [
EGVAR(recorder,captureFrameNo), // 0: captureFrameNo
-1, // 1: placedId (assigned by server)
Expand Down
12 changes: 6 additions & 6 deletions addons/recorder/fnc_captureLoop.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ GVAR(PFHObject) = [

[
{missionNamespace getVariable [QEGVAR(extension,sessionReady), false]},
{[":NEW:SOLDIER:", _this] call EFUNC(extension,sendData);},
{[":SOLDIER:CREATE:", _this] call EFUNC(extension,sendData);},
_newUnit,
30
] call CBA_fnc_waitUntilAndExecute;
Expand Down Expand Up @@ -168,7 +168,7 @@ GVAR(PFHObject) = [
];

if (_x getVariable ["unitData", []] isNotEqualTo _unitData) then {
[":NEW:SOLDIER:STATE:", _unitData] call EFUNC(extension,sendData);
[":SOLDIER:STATE:", _unitData] call EFUNC(extension,sendData);
_x setVariable [QGVARMAIN(unitData), _unitData];
};
};
Expand Down Expand Up @@ -217,7 +217,7 @@ GVAR(PFHObject) = [

[
{missionNamespace getVariable [QEGVAR(extension,sessionReady), false]},
{[":NEW:VEHICLE:", _this] call EFUNC(extension,sendData);},
{[":VEHICLE:CREATE:", _this] call EFUNC(extension,sendData);},
_newVehicleData,
30
] call CBA_fnc_waitUntilAndExecute;
Expand Down Expand Up @@ -260,11 +260,11 @@ GVAR(PFHObject) = [
// Stop tracking parachutes/ejection seats that are empty or dead
if ((_x getVariable [QGVARMAIN(vehicleClass), ""]) isEqualTo "parachute" && {!((alive _x) && {_crew isNotEqualTo []})}) then {
_vehicleData set [3, 0];
[":NEW:VEHICLE:STATE:", _vehicleData] call EFUNC(extension,sendData);
[":VEHICLE:STATE:", _vehicleData] call EFUNC(extension,sendData);
_x setVariable [QGVARMAIN(exclude), true, true];
GVAR(trackedVehicles) deleteAt _ocapId;
} else {
[":NEW:VEHICLE:STATE:", _vehicleData] call EFUNC(extension,sendData);
[":VEHICLE:STATE:", _vehicleData] call EFUNC(extension,sendData);
GVAR(trackedVehicles) set [_ocapId, [_x, _pos, round getDir _x, side _x, vectorDir _x, vectorUp _x]];
};
};
Expand All @@ -276,7 +276,7 @@ GVAR(PFHObject) = [
{
(GVAR(trackedVehicles) get _x) params ["_obj", "_lastPos", "_lastDir", "_lastSide", "_lastVectorDir", "_lastVectorUp"];
if (isNull _obj) then {
[":NEW:VEHICLE:STATE:", [
[":VEHICLE:STATE:", [
_x, _lastPos, _lastDir, 0, [], GVAR(captureFrameNo),
0, 1, false, false, _lastSide, _lastVectorDir, _lastVectorUp, 0, 0
]] call EFUNC(extension,sendData);
Expand Down
2 changes: 1 addition & 1 deletion addons/recorder/fnc_eh_connected.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ params ["_id", "_uid", "_name", "_jip", "_owner", "_idstr"];
if (_owner isEqualTo 2) exitWith {};

// log to timeline
[":EVENT:", [
[":EVENT:GENERAL:", [
GVAR(captureFrameNo),
"connected",
_name,
Expand Down
2 changes: 1 addition & 1 deletion addons/recorder/fnc_eh_disconnected.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

params ["_unit", "_id", "_uid", "_name"];

[":EVENT:", [
[":EVENT:GENERAL:", [
GVAR(captureFrameNo),
"disconnected",
_name,
Expand Down
2 changes: 1 addition & 1 deletion addons/recorder/fnc_eh_fired_client.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ _projectile setVariable [QGVARMAIN(projectileData), _data];
if (_weapon == "put") then {
_projectile setVariable [QGVARMAIN(detonated), false];

// Build :NEW:PLACED: data — placedId assigned server-side (GVAR(nextId) only exists there)
// Build :PLACED:CREATE: data — placedId assigned server-side (GVAR(nextId) only exists there)
private _placedData = [
EGVAR(recorder,captureFrameNo), // 0: captureFrameNo
-1, // 1: placedId (assigned by server)
Expand Down
4 changes: 2 additions & 2 deletions addons/recorder/fnc_eh_fired_server.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@
TRACE_1("Sending fired data to extension",_data);
_data spawn {
sleep 2;
[":PROJECTILE:", _this] call EFUNC(extension,sendData);
[":EVENT:PROJECTILE:", _this] call EFUNC(extension,sendData);
};
}] call CBA_fnc_addEventHandler;

Expand All @@ -140,7 +140,7 @@
_data set [1, _placedId];
_projectile setVariable [QGVARMAIN(placedId), _placedId, true];
TRACE_2("Sending placed object data to extension",_placedId,_data);
[":NEW:PLACED:", _data] call EFUNC(extension,sendData);
[":PLACED:CREATE:", _data] call EFUNC(extension,sendData);
}] call CBA_fnc_addEventHandler;

// Handle placed object lifecycle events (detonation, deletion)
Expand Down
2 changes: 1 addition & 1 deletion addons/recorder/fnc_eh_killed.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ if !(_victim getvariable [QGVARMAIN(isKilled),false]) then {
OCAPEXTLOG(ARR4("KILLED EVENT",_killedFrame,_victimId,_killerId));
};

[":KILL:", [
[":EVENT:KILL:", [
_killedFrame,
_victimId,
_killerId,
Expand Down
4 changes: 2 additions & 2 deletions addons/recorder/fnc_exportData.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ if (!isNil QGVAR(PFHObject)) then {
private _winSide = if (isNil "_side") then {""} else {if (_side isEqualTo sideUnknown) then {""} else {str _side}};
private _endMessage = if (isNil "_message") then {if (_winSide == "") then {"Mission ended"} else {""}} else {_message};

[":EVENT:", [
[":EVENT:GENERAL:", [
_endFrameNumber,
"endMission",
"",
Expand All @@ -126,7 +126,7 @@ private _endMessage = if (isNil "_message") then {if (_winSide == "") then {"Mis


private _saveTag = if (!isNil "_tag") then {_tag} else {EGVAR(settings,saveTag)};
[":SAVE:MISSION:", [worldName, GVAR(missionName), getMissionConfigValue ["author", ""], GVAR(frameCaptureDelay), _endFrameNumber, _saveTag]] call EFUNC(extension,sendData);
[":MISSION:SAVE:", [worldName, GVAR(missionName), getMissionConfigValue ["author", ""], GVAR(frameCaptureDelay), _endFrameNumber, _saveTag]] call EFUNC(extension,sendData);
OCAPEXTLOG(ARR4("Saved recording of mission",GVAR(missionName),"with tag",_saveTag));


Expand Down
2 changes: 1 addition & 1 deletion addons/recorder/fnc_handleChatMessage.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ if (parseNumber _strID > 1) then {

private _senderOcapId = _person getVariable [QGVARMAIN(id), -1];

[":CHAT:", [
[":EVENT:CHAT:", [
GVAR(captureFrameNo),
_senderOcapId,
_channel,
Expand Down
2 changes: 1 addition & 1 deletion addons/recorder/fnc_handleCustomEvent.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ params [
["_extraData", createHashMap, [createHashMap, []]]
];

[":EVENT:", [
[":EVENT:GENERAL:", [
GVAR(captureFrameNo),
_eventName,
_eventMessage,
Expand Down
6 changes: 3 additions & 3 deletions addons/recorder/fnc_handleMarkers.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -128,14 +128,14 @@ EGVAR(listener,markers) = [QGVARMAIN(handleMarker), {

private _logParams = (str [_mrk_name, _dir, _type, _text, _captureFrameNo, -1, _mrk_owner, _mrk_color, _size, _sideOfMarker, _pos, _shape, _alpha, _brush]);

[":NEW:MARKER:", [_mrk_name, _dir, _type, _text, _captureFrameNo, -1, _mrk_owner, _mrk_color, _size, _sideOfMarker, _pos, _shape, _alpha, _brush]] call EFUNC(extension,sendData);
[":MARKER:CREATE:", [_mrk_name, _dir, _type, _text, _captureFrameNo, -1, _mrk_owner, _mrk_color, _size, _sideOfMarker, _pos, _shape, _alpha, _brush]] call EFUNC(extension,sendData);
};

case "UPDATED":{

if (_mrk_name in GVAR(trackedMarkers)) then {
if (isNil "_dir") then {_dir = 0};
[":NEW:MARKER:STATE:", [_mrk_name, GVAR(captureFrameNo), _pos, _dir, _alpha]] call EFUNC(extension,sendData);
[":MARKER:STATE:", [_mrk_name, GVAR(captureFrameNo), _pos, _dir, _alpha]] call EFUNC(extension,sendData);
};
};

Expand All @@ -148,7 +148,7 @@ EGVAR(listener,markers) = [QGVARMAIN(handleMarker), {
OCAPEXTLOG(ARR3("MARKER:DELETE: Marker",_mrk_name,"deleted"));
};

[":DELETE:MARKER:", [_mrk_name, GVAR(captureFrameNo)]] call EFUNC(extension,sendData);
[":MARKER:DELETE:", [_mrk_name, GVAR(captureFrameNo)]] call EFUNC(extension,sendData);
GVAR(trackedMarkers) = GVAR(trackedMarkers) - [_mrk_name];
};
};
Expand Down
2 changes: 1 addition & 1 deletion addons/recorder/fnc_init.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ publicVariable QGVARMAIN(version);
Global variable that represents the version of OCAP extension being used [String]
*/
diag_log text "[OCAP] Fetching extension version...";
EGVAR(extension,version) = ([":VERSION:", []] call EFUNC(extension,sendData));
EGVAR(extension,version) = ([":SYS:VERSION:", []] call EFUNC(extension,sendData));
diag_log text format ["[OCAP] Extension version result: %1 (type: %2)", EGVAR(extension,version), typeName EGVAR(extension,version)];
publicVariable QEGVAR(extension,version);

Expand Down
4 changes: 2 additions & 2 deletions addons/recorder/fnc_radioEvent.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ if (_mod isEqualTo "TFAR") then {
) exitWith {};

[
":RADIO:", [
":EVENT:RADIO:", [
GVAR(captureFrameNo),
_ocapId,
_radio,
Expand Down Expand Up @@ -64,7 +64,7 @@ if (_mod isEqualTo "ACRE") then {
) exitWith {};

[
":RADIO:", [
":EVENT:RADIO:", [
GVAR(captureFrameNo),
_ocapId,
_radio,
Expand Down
4 changes: 2 additions & 2 deletions addons/recorder/fnc_telemetryLoop.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ FUNCTION: OCAP_recorder_fnc_telemetryLoop

Description:
Collects server telemetry data every 10 seconds and sends a single
:TELEMETRY: command to the extension. The extension handles routing
:TELEMETRY:FRAME: command to the extension. The extension handles routing
to mission recording (FPS) and InfluxDB (all metrics).

Parameters:
Expand Down Expand Up @@ -102,7 +102,7 @@ Author:
} forEach (allUsers apply {getUserInfo _x});

// Single telemetry call — extension handles routing and formatting
[":TELEMETRY:", [
[":TELEMETRY:FRAME:", [
GVAR(captureFrameNo),
[diag_fps, diag_fpsmin],
_sideData,
Expand Down
2 changes: 1 addition & 1 deletion addons/recorder/fnc_updateTime.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ if (_date isEqualTo []) then {
};
_missionDateFormat append (_date apply {if (_x < 10) then {"0" + str _x} else {str _x}});

[":NEW:TIME:STATE:", [
[":TIME:STATE:", [
GVAR(captureFrameNo),
format _systemTimeFormat,
format _missionDateFormat,
Expand Down