diff --git a/addons/recorder/fnc_aceExplosives.sqf b/addons/recorder/fnc_aceExplosives.sqf index 7e37045..465cb2a 100644 --- a/addons/recorder/fnc_aceExplosives.sqf +++ b/addons/recorder/fnc_aceExplosives.sqf @@ -4,13 +4,17 @@ FILE: fnc_aceExplosives.sqf FUNCTION: OCAP_recorder_fnc_aceExplosives Description: - Adds marker on the mine's position to the recording timeline. - Uses Explode event handler to detect detonation and indicates it with a 10-frame long red X before removing the marker. + Integrates ACE3-placed explosives into the placed object pipeline. + Sends :NEW:PLACED: data and attaches lifecycle EHs (HitExplosion, Explode, + Deleted) identical to vanilla mines in fnc_eh_fired_client.sqf. Called by CBA listener. Parameters: - None + _explosive - Object: the placed explosive + _dir - Number: direction + _pitch - Number: pitch + _unit - Object: the unit that placed the explosive Returns: Nothing @@ -34,68 +38,76 @@ if (!SHOULDSAVEEVENTS) exitWith {}; params ["_explosive", "_dir", "_pitch", "_unit"]; -private _int = random(2000); - +// Resolve explosive metadata from config private _explType = typeOf _explosive; private _explosiveMag = getText(configFile >> "CfgAmmo" >> _explType >> "defaultMagazine"); private _explosiveDisp = getText(configFile >> "CfgMagazines" >> _explosiveMag >> "displayName"); private _explosivePic = getText(configFile >> "CfgMagazines" >> _explosiveMag >> "picture"); -private _placedPos = getPosASL _explosive; -_unit addOwnedMine _explosive; - -private _markTextLocal = format["%1", _explosiveDisp]; -private _markName = format["%1#%2/%3", QGVARMAIN(mine), _int, _placedPos]; - -// Signals creation of a Minefield (triangle) marker on the timeline at the location the explosive was armed. -[QGVARMAIN(handleMarker), [ - "CREATED", _markName, _unit, _placedPos, "Minefield", "ICON", [1,1], 0, "Solid", "ColorRed", 1, _markTextLocal, true -]] call CBA_fnc_localEvent; - -if (GVARMAIN(isDebug)) then { - private _debugArr = [_explosive, _explosivePic, format["%1 %2 - %3", str side group _unit, name _unit, _markTextLocal], [side group _unit] call BIS_fnc_sideColor]; - GVAR(liveDebugMagIcons) pushBack _debugArr; - publicVariable QGVAR(liveDebugMagIcons); -}; +// Get placer's OCAP ID +private _unitOcapId = _unit getVariable [QGVARMAIN(id), -1]; +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 +private _placedData = [ + EGVAR(recorder,captureFrameNo), // 0: captureFrameNo + -1, // 1: placedId (assigned by server) + _explType, // 2: className + _explosiveDisp, // 3: displayName + (getPosASL _explosive) joinString ",", // 4: position + _unitOcapId, // 5: firerOcapId + str (side group _unit), // 6: side + "put", // 7: weapon + _explosivePic // 8: magazineIcon +]; + +[QGVARMAIN(handlePlacedData), [_placedData, _explosive]] call CBA_fnc_serverEvent; + +// Attach lifecycle EHs — identical to vanilla path in fnc_eh_fired_client.sqf +_explosive addEventHandler ["HitExplosion", { + params ["_explosive", "_hitEntity", "_explosiveOwner", "_hitThings"]; + if (isNull _hitEntity) exitWith {}; + if (count _hitThings isEqualTo 0) exitWith {}; + private _hitOcapId = _hitEntity getVariable [QGVARMAIN(id), -1]; + if (_hitOcapId isEqualTo -1) exitWith {}; + private _placedId = _explosive getVariable [QGVARMAIN(placedId), -1]; + private _eventData = [ + EGVAR(recorder,captureFrameNo), // 0: captureFrameNo + _placedId, // 1: placedId + "hit", // 2: eventType + (getPosASL _hitEntity) joinString ",", // 3: position (victim pos) + _hitOcapId // 4: hitEntityOcapId + ]; + [QGVARMAIN(handlePlacedEvent), [_eventData]] call CBA_fnc_serverEvent; +}]; -// Use Explode event handler instead of polling for null _explosive addEventHandler ["Explode", { - params ["_explosive", "_damage", "_source", "_instigator"]; - - private _data = _explosive getVariable [QGVAR(explosiveData), []]; - if (_data isEqualTo []) exitWith {}; - - _data params ["_explosiveDisp", "_unit", "_placedPos", "_markName", "_int"]; - - if (GVARMAIN(isDebug)) then { - format["Removed explosive placed marker, %1, %2", _markName, _explosiveDisp] SYSCHAT; - OCAPEXTLOG(ARR3("Removed explosive placed marker",_markName,_explosiveDisp)); - }; - - // Signals removal of the Minefield (triangle) marker when the explosive detonates - [QGVARMAIN(handleMarker), ["DELETED", _markName]] call CBA_fnc_localEvent; - - private _detonationMarkName = format["Detonation#%1", _int]; - - if (GVARMAIN(isDebug)) then { - format["Created explosive explosion marker, %1, %2", _detonationMarkName, _explosiveDisp] SYSCHAT; - OCAPEXTLOG(ARR3("Created explosive explosion marker",_detonationMarkName,_explosiveDisp)); - }; - - // Signals creation of a Waypoint (X) marker on the timeline at the location the explosive detonated - [QGVARMAIN(handleMarker), [ - "CREATED", _detonationMarkName, _unit, _placedPos, "waypoint", "ICON", [1,1], 0, "Solid", "ColorRed", 1, format["%1", _explosiveDisp], true - ]] call CBA_fnc_localEvent; - - [{ - params ["_markName", "_explosiveDisp"]; - if (GVARMAIN(isDebug)) then { - format["Removed explosive explosion marker, %1, %2", _markName, _explosiveDisp] SYSCHAT; - OCAPEXTLOG(ARR3("Removed explosive explosion marker",_markName,_explosiveDisp)); - }; - [QGVARMAIN(handleMarker), ["DELETED", _markName]] call CBA_fnc_localEvent; - }, [_detonationMarkName, _explosiveDisp], GVAR(captureFrameNo) * 10] call CBA_fnc_waitAndExecute; + params ["_explosive", "_pos", "_velocity"]; + if (_explosive getVariable [QGVARMAIN(detonated), true]) exitWith {}; + _explosive setVariable [QGVARMAIN(detonated), true]; + private _placedId = _explosive getVariable [QGVARMAIN(placedId), -1]; + private _eventData = [ + EGVAR(recorder,captureFrameNo), // 0: captureFrameNo + _placedId, // 1: placedId + "detonated", // 2: eventType + _pos joinString "," // 3: position + ]; + [QGVARMAIN(handlePlacedEvent), [_eventData]] call CBA_fnc_serverEvent; }]; -// Store data on the explosive for retrieval in the event handler -_explosive setVariable [QGVAR(explosiveData), [_explosiveDisp, _unit, _placedPos, _markName, _int]]; +_explosive addEventHandler ["Deleted", { + params ["_explosive"]; + // Only send "deleted" if not already detonated (avoid double-send) + if (_explosive getVariable [QGVARMAIN(detonated), true]) exitWith {}; + _explosive setVariable [QGVARMAIN(detonated), true]; + private _placedId = _explosive getVariable [QGVARMAIN(placedId), -1]; + private _eventData = [ + EGVAR(recorder,captureFrameNo), // 0: captureFrameNo + _placedId, // 1: placedId + "deleted", // 2: eventType + (getPosASL _explosive) joinString "," // 3: position + ]; + [QGVARMAIN(handlePlacedEvent), [_eventData]] call CBA_fnc_serverEvent; +}]; diff --git a/addons/recorder/fnc_eh_fired_client.sqf b/addons/recorder/fnc_eh_fired_client.sqf index f4faa75..46fee20 100644 --- a/addons/recorder/fnc_eh_fired_client.sqf +++ b/addons/recorder/fnc_eh_fired_client.sqf @@ -109,25 +109,92 @@ private _data = [ _projectile setVariable [QGVARMAIN(projectileData), _data]; -// carryover variables to submunitions -if ((_data select 17) isEqualTo "shotSubmunitions") then { - _projectile addEventHandler ["SubmunitionCreated", { - params ["_projectile", "_submunitionProjectile"]; - private _data = +(_projectile getVariable QGVARMAIN(projectileData)); - _data set [17, getText(configOf _submunitionProjectile >> "simulation")]; // actual sim type - _data set [18, true]; // isSub = true - (_data select 14) pushBack [ - diag_tickTime, - EGVAR(recorder,captureFrameNo), - (getPosASL _submunitionProjectile) joinString "," +// Handle placed objects (mines, explosives) — separate lifecycle from projectiles +if (_weapon == "put") then { + _projectile setVariable [QGVARMAIN(detonated), false]; + + // Build :NEW:PLACED: data — placedId assigned server-side (GVAR(nextId) only exists there) + private _placedData = [ + EGVAR(recorder,captureFrameNo), // 0: captureFrameNo + -1, // 1: placedId (assigned by server) + typeOf _projectile, // 2: className + _data select 11, // 3: displayName (magazineDisplay) + (getPosASL _projectile) joinString ",", // 4: position + _firerOcapId, // 5: firerOcapId + str (side group _firer), // 6: side + _weapon, // 7: weapon + _data select 19 // 8: magazineIcon + ]; + + [QGVARMAIN(handlePlacedData), [_placedData, _projectile]] call CBA_fnc_serverEvent; + + // Attach simplified EHs for placed object lifecycle + _projectile addEventHandler ["HitExplosion", { + params ["_projectile", "_hitEntity", "_projectileOwner", "_hitThings"]; + if (isNull _hitEntity) exitWith {}; + if (count _hitThings isEqualTo 0) exitWith {}; + private _hitOcapId = _hitEntity getVariable [QGVARMAIN(id), -1]; + if (_hitOcapId isEqualTo -1) exitWith {}; + private _placedId = _projectile getVariable [QGVARMAIN(placedId), -1]; + private _eventData = [ + EGVAR(recorder,captureFrameNo), // 0: captureFrameNo + _placedId, // 1: placedId + "hit", // 2: eventType + (getPosASL _hitEntity) joinString ",", // 3: position (victim pos) + _hitOcapId // 4: hitEntityOcapId ]; - _submunitionProjectile setVariable [QGVARMAIN(projectileData), _data]; - // add the rest of EHs to submunition - [_submunitionProjectile] call FUNC(eh_fired_clientBullet); + [QGVARMAIN(handlePlacedEvent), [_eventData]] call CBA_fnc_serverEvent; + }]; + + _projectile addEventHandler ["Explode", { + params ["_projectile", "_pos", "_velocity"]; + if (_projectile getVariable [QGVARMAIN(detonated), true]) exitWith {}; + _projectile setVariable [QGVARMAIN(detonated), true]; + private _placedId = _projectile getVariable [QGVARMAIN(placedId), -1]; + private _eventData = [ + EGVAR(recorder,captureFrameNo), // 0: captureFrameNo + _placedId, // 1: placedId + "detonated", // 2: eventType + _pos joinString "," // 3: position + ]; + [QGVARMAIN(handlePlacedEvent), [_eventData]] call CBA_fnc_serverEvent; + }]; + + _projectile addEventHandler ["Deleted", { + params ["_projectile"]; + // Only send "deleted" if not already detonated (avoid double-send) + if (_projectile getVariable [QGVARMAIN(detonated), true]) exitWith {}; + _projectile setVariable [QGVARMAIN(detonated), true]; + private _placedId = _projectile getVariable [QGVARMAIN(placedId), -1]; + private _eventData = [ + EGVAR(recorder,captureFrameNo), // 0: captureFrameNo + _placedId, // 1: placedId + "deleted", // 2: eventType + (getPosASL _projectile) joinString "," // 3: position + ]; + [QGVARMAIN(handlePlacedEvent), [_eventData]] call CBA_fnc_serverEvent; }]; } else { - // add the rest of EHs to projectile - [_projectile] call FUNC(eh_fired_clientBullet); + // carryover variables to submunitions + if ((_data select 17) isEqualTo "shotSubmunitions") then { + _projectile addEventHandler ["SubmunitionCreated", { + params ["_projectile", "_submunitionProjectile"]; + private _data = +(_projectile getVariable QGVARMAIN(projectileData)); + _data set [17, getText(configOf _submunitionProjectile >> "simulation")]; // actual sim type + _data set [18, true]; // isSub = true + (_data select 14) pushBack [ + diag_tickTime, + EGVAR(recorder,captureFrameNo), + (getPosASL _submunitionProjectile) joinString "," + ]; + _submunitionProjectile setVariable [QGVARMAIN(projectileData), _data]; + // add the rest of EHs to submunition + [_submunitionProjectile] call FUNC(eh_fired_clientBullet); + }]; + } else { + // add the rest of EHs to projectile + [_projectile] call FUNC(eh_fired_clientBullet); + }; }; true; diff --git a/addons/recorder/fnc_eh_fired_server.sqf b/addons/recorder/fnc_eh_fired_server.sqf index c19505b..b45727c 100644 --- a/addons/recorder/fnc_eh_fired_server.sqf +++ b/addons/recorder/fnc_eh_fired_server.sqf @@ -130,3 +130,22 @@ [":PROJECTILE:", _this] call EFUNC(extension,sendData); }; }] call CBA_fnc_addEventHandler; + +// Handle placed object creation events (mines, explosives) +// ID assignment happens here because GVAR(nextId) only exists on the server +[QGVARMAIN(handlePlacedData), { + params ["_data", "_projectile"]; + private _placedId = GVAR(nextId); + GVAR(nextId) = GVAR(nextId) + 1; + _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); +}] call CBA_fnc_addEventHandler; + +// Handle placed object lifecycle events (detonation, deletion) +[QGVARMAIN(handlePlacedEvent), { + params ["_data"]; + TRACE_1("Sending placed event data to extension",_data); + [":PLACED:EVENT:", _data] call EFUNC(extension,sendData); +}] call CBA_fnc_addEventHandler;