From 5606d06912383221d01bf331455927b3c2507973 Mon Sep 17 00:00:00 2001 From: IndigoFox Date: Mon, 28 Mar 2022 02:07:11 -0400 Subject: [PATCH] bunch more changes --- x/ocap2/addons/main/XEH_postInit.sqf | 2 +- x/ocap2/addons/main/XEH_preInit.sqf | 197 +--------------- x/ocap2/addons/main/script_macros.hpp | 5 +- x/ocap2/addons/mod.cpp | 6 +- x/ocap2/addons/recorder/XEH_postInit.sqf | 6 +- x/ocap2/addons/recorder/XEH_preInit.sqf | 220 +++++++++++++++++- x/ocap2/addons/recorder/XEH_prep.sqf | 1 + x/ocap2/addons/recorder/fnc_aceExplosives.sqf | 48 ++-- x/ocap2/addons/recorder/fnc_aceThrowing.sqf | 18 +- .../addons/recorder/fnc_addEventMission.sqf | 15 +- .../recorder/fnc_addUnitEventHandlers.sqf | 23 +- x/ocap2/addons/recorder/fnc_captureLoop.sqf | 36 +-- x/ocap2/addons/recorder/fnc_eh_firedMan.sqf | 217 +++++++---------- x/ocap2/addons/recorder/fnc_eh_hit.sqf | 17 +- x/ocap2/addons/recorder/fnc_eh_killed.sqf | 13 +- x/ocap2/addons/recorder/fnc_exportData.sqf | 37 ++- x/ocap2/addons/recorder/fnc_getAmmoData.sqf | 62 +++++ x/ocap2/addons/recorder/fnc_getDelay.sqf | 4 +- .../recorder/fnc_getEventWeaponText.sqf | 9 +- .../addons/recorder/fnc_handleCustomEvent.sqf | 2 + x/ocap2/addons/recorder/fnc_handleMarkers.sqf | 21 +- x/ocap2/addons/recorder/fnc_init.sqf | 107 ++++++++- .../addons/recorder/fnc_startRecording.sqf | 16 +- 23 files changed, 649 insertions(+), 433 deletions(-) create mode 100644 x/ocap2/addons/recorder/fnc_getAmmoData.sqf diff --git a/x/ocap2/addons/main/XEH_postInit.sqf b/x/ocap2/addons/main/XEH_postInit.sqf index e3eaf9a..b123aab 100644 --- a/x/ocap2/addons/main/XEH_postInit.sqf +++ b/x/ocap2/addons/main/XEH_postInit.sqf @@ -3,7 +3,7 @@ // During postInit, we'll remoteExec these settings onto clients so vars are synchronized and modifiable during a mission. { _x remoteExec ["CBA_fnc_addSetting", [0, -2] select isDedicated, true]; -} forEach GVARMAIN(allSettings); +} forEach GVAR(allSettings); ADDON = true; diff --git a/x/ocap2/addons/main/XEH_preInit.sqf b/x/ocap2/addons/main/XEH_preInit.sqf index 1a46b65..5de52f5 100644 --- a/x/ocap2/addons/main/XEH_preInit.sqf +++ b/x/ocap2/addons/main/XEH_preInit.sqf @@ -4,201 +4,14 @@ // This PreInit creates the settings on the server, only so that the global vars will be registered and synchronized with clients. -GVARMAIN(allSettings) = [ - // AUTO START SETTINGS - [ - QEGVAR(settings,autoStart), - "CHECKBOX", // setting type - [ - "Auto Start Recording", // Pretty name shown inside the ingame settings menu. Can be stringtable entry. - "Automatically start OCAP recordings at session start. Default: true" - ], - [COMPONENT_NAME, "Auto-start Settings"], // Pretty name of the category where the setting can be found. Can be stringtable entry. - true, // default enabled - true, // "_isGlobal" flag. Set this to true to always have this setting synchronized between all clients in multiplayer - {}, // function that will be executed once on mission start and every time the setting is changed. - true // requires restart to apply - ], - - [ - QEGVAR(settings,minPlayerCount), - "SLIDER", // setting type - [ - "Minimum Player Count", // Pretty name shown inside the ingame settings menu. Can be stringtable entry. - "Auto-start will begin once this player count is reached. Default: 15" - ], - [COMPONENT_NAME, "Auto-start Settings"], // Pretty name of the category where the setting can be found. Can be stringtable entry. - [ - 1, // min - 150, // max - 15, // default - 0, // trailing decimals - false // percentage - ], // data for this setting: [min, max, default, number of shown trailing decimals] - true, // "_isGlobal" flag. Set this to true to always have this setting synchronized between all clients in multiplayer - {}, // function that will be executed once on mission start and every time the setting is changed. - true // requires restart to apply - ], - - - - // RECORDING SETTINGS - [ - QEGVAR(settings,frameCaptureDelay), - "SLIDER", // setting type - [ - "Frame Capture Delay", // Pretty name shown inside the ingame settings menu. Can be stringtable entry. - "Positioning, medical status, and crew states of units and vehicles will be captured every X amount of seconds. Default: 1" - ], - [COMPONENT_NAME, "Recording Settings"], // Pretty name of the category where the setting can be found. Can be stringtable entry. - [ - 0.25, // min - 10, // max - 1, // default - 0, // trailing decimals - false // percentage - ], // data for this setting: [min, max, default, number of shown trailing decimals] - true, // "_isGlobal" flag. Set this to true to always have this setting synchronized between all clients in multiplayer - {}, // function that will be executed once on mission start and every time the setting is changed. - false // requires restart to apply - ], - - [ - QEGVAR(settings,minMissionTime), - "SLIDER", // setting type - [ - "Required Duration to Save", // Pretty name shown inside the ingame settings menu. Can be stringtable entry. - "A recording must be at least this long (in minutes) to save. Default: 20" - ], - [COMPONENT_NAME, "Recording Settings"], // Pretty name of the category where the setting can be found. Can be stringtable entry. - [ - 1, // min - 120, // max - 20, // default - 0, // trailing decimals - false // percentage - ], // data for this setting: [min, max, default, number of shown trailing decimals] - true, // "_isGlobal" flag. Set this to true to always have this setting synchronized between all clients in multiplayer - {}, // function that will be executed once on mission start and every time the setting is changed. - false // requires restart to apply - ], - - [ - QEGVAR(settings,preferACEUnconscious), - "CHECKBOX", // setting type - [ - "Use ACE3 Medical", // Pretty name shown inside the ingame settings menu. Can be stringtable entry. - "If true, will check ACE3 medical status on units. If false, or ACE3 isn't loaded, fall back to vanilla. Default: true" - ], - [COMPONENT_NAME, "Recording Settings"], // Pretty name of the category where the setting can be found. Can be stringtable entry. - true, // default enabled - true, // "_isGlobal" flag. Set this to true to always have this setting synchronized between all clients in multiplayer - {}, // function that will be executed once on mission start and every time the setting is changed. - false // requires restart to apply - ], - - [ - QEGVAR(settings,excludeClassFromRecord), - "EDITBOX", // setting type - [ - "Classnames to Exclude", // Pretty name shown inside the ingame settings menu. Can be stringtable entry. - "Array of object classnames that should be excluded from recording. Use single quotes! Default: ['ACE_friesAnchorBar', 'GroundWeaponHolder', 'WeaponHolderSimulated']" - ], - [COMPONENT_NAME, "Recording Settings"], // Pretty name of the category where the setting can be found. Can be stringtable entry. - "['ACE_friesAnchorBar', 'GroundWeaponHolder', 'WeaponHolderSimulated']", // default string value - true, // "_isGlobal" flag. Set this to true to always have this setting synchronized between all clients in multiplayer - {}, // function that will be executed once on mission start and every time the setting is changed. - false // requires restart to apply - ], - - [ - QEGVAR(settings,excludeKindFromRecord), - "EDITBOX", // setting type - [ - "Object KindOfs to Exclude", // Pretty name shown inside the ingame settings menu. Can be stringtable entry. - "Array of classnames which, along with all child classes, should be excluded from recording. Use single quotes! Default: []" - ], - [COMPONENT_NAME, "Recording Settings"], // Pretty name of the category where the setting can be found. Can be stringtable entry. - "[]", // default string value - true, // "_isGlobal" flag. Set this to true to always have this setting synchronized between all clients in multiplayer - {}, // function that will be executed once on mission start and every time the setting is changed. - false // requires restart to apply - ], - - [ - QEGVAR(settings,excludeMarkerFromRecord), - "EDITBOX", // setting type - [ - "Marker Prefixes to Exclude", // Pretty name shown inside the ingame settings menu. Can be stringtable entry. - "Array of prefixes - any markers matching these prefixes will be excluded from recording. Use single quotes! Default: ['SystemMarker_']" - ], - [COMPONENT_NAME, "Recording Settings"], // Pretty name of the category where the setting can be found. Can be stringtable entry. - "['SystemMarker_']", // default string value - true, // "_isGlobal" flag. Set this to true to always have this setting synchronized between all clients in multiplayer - {}, // function that will be executed once on mission start and every time the setting is changed. - false // requires restart to apply - ], - - [ - QEGVAR(settings,trackTimes), - "CHECKBOX", // setting type - [ - "Enable Mission Time Tracking", // Pretty name shown inside the ingame settings menu. Can be stringtable entry. - "Will continuously track in-game world time during a mission. Useful for accelerated/skipped time scenarios. Default: false" - ], - [COMPONENT_NAME, "Recording Settings"], // Pretty name of the category where the setting can be found. Can be stringtable entry. - false, // default enabled - true, // "_isGlobal" flag. Set this to true to always have this setting synchronized between all clients in multiplayer - {}, // function that will be executed once on mission start and every time the setting is changed. - false // requires restart to apply - ], - - [ - QEGVAR(settings,trackTimeInterval), - "SLIDER", // setting type - [ - "Mission Time Tracking Interval", // Pretty name shown inside the ingame settings menu. Can be stringtable entry. - "If time tracking is enabled, it will be checked every X capture frames. Default: 10" - ], - [COMPONENT_NAME, "Recording Settings"], // Pretty name of the category where the setting can be found. Can be stringtable entry. - [ - 5, // min - 25, // max - 10, // default - 0, // trailing decimals - false // percentage - ], // data for this setting: [min, max, default, number of shown trailing decimals] - true, // "_isGlobal" flag. Set this to true to always have this setting synchronized between all clients in multiplayer - {}, // function that will be executed once on mission start and every time the setting is changed. - false // requires restart to apply - ], - - - - // SAVING SETTINGS - [ - QEGVAR(settings,saveMissionEnded), - "CHECKBOX", // setting type - [ - "Auto-save on MPEnded Event", // Pretty name shown inside the ingame settings menu. Can be stringtable entry. - "If true, automatically save and export the mission when the MPEnded event fires. Default: true" - ], - [COMPONENT_NAME, "Save/Export Settings"], // Pretty name of the category where the setting can be found. Can be stringtable entry. - true, // default enabled - true, // "_isGlobal" flag. Set this to true to always have this setting synchronized between all clients in multiplayer - {}, // function that will be executed once on mission start and every time the setting is changed. - false // requires restart to apply - ], - - - - // DEBUG +GVAR(allSettings) = [ + // Core [ QGVARMAIN(enabled), "CHECKBOX", // setting type [ "Recording Enabled", // Pretty name shown inside the ingame settings menu. Can be stringtable entry. - "Turns on or off all recording functionality. Will not reset anything from existing session, will just stop recording any new data. Default: true" + "Turns on or off most recording functionality. Will not reset anything from existing session, will just stop recording most new data. Note: For record/pause switching, use the CBA events! Default: true" ], [COMPONENT_NAME, "Core"], // Pretty name of the category where the setting can be found. Can be stringtable entry. true, // default enabled @@ -206,7 +19,7 @@ GVARMAIN(allSettings) = [ { params ["_value"]; if (!isServer) exitWith {}; - EFUNC(recorder,init); + if (_value) then {call EFUNC(recorder,init)}; }, // function that will be executed once on mission start and every time the setting is changed. false // requires restart to apply ], @@ -230,6 +43,6 @@ GVARMAIN(allSettings) = [ { _x call CBA_fnc_addSetting; -} forEach GVARMAIN(allSettings); +} forEach GVAR(allSettings); ADDON = true; diff --git a/x/ocap2/addons/main/script_macros.hpp b/x/ocap2/addons/main/script_macros.hpp index 7adcccc..c40eb31 100644 --- a/x/ocap2/addons/main/script_macros.hpp +++ b/x/ocap2/addons/main/script_macros.hpp @@ -36,7 +36,8 @@ #define ARR6(_arg1, _arg2, _arg3, _arg4, _arg5, _arg6) [_arg1, _arg2, _arg3, _arg4, _arg5, _arg6] - - #include "\x\cba\addons\main\script_macros_common.hpp" #include "\x\cba\addons\xeh\script_xeh.hpp" + +#define SHOULDSAVEEVENTS ((missionNamespace getVariable [QGVAR(recording), false]) && missionNamespace getVariable [QGVAR(startTime), -1] > -1) + diff --git a/x/ocap2/addons/mod.cpp b/x/ocap2/addons/mod.cpp index 4a2a884..6a65751 100644 --- a/x/ocap2/addons/mod.cpp +++ b/x/ocap2/addons/mod.cpp @@ -1,11 +1,11 @@ -name = "OCAP"; // Name of your mod +name = "OCAP2"; // Name of your mod picture = "logo_ocap.paa"; // Picture displayed from the expansions menu. Optimal size is 2048x1024 //logoSmall = "\Samples_F\Data_01\Logos\logo_small.paa"; // Display next to the item added by the mod //logo = "\Samples_F\Data_01\Logos\logo.paa"; // Logo displayed in the main menu //logoOver = "\Samples_F\Data_01\Logos\logoOver.paa"; // When the mouse is over, in the main menu actionName = "Github"; // Text displayed on the "website" button -action = "https://github.com/OCAPv2"; // Website URL, that can accessed from the expansions menu -tooltipOwned = "Operation Capture and Playback v2"; // Tool tip displayed when the mouse is left over, in the main menu +action = "https://github.com/OCAP2/OCAP"; // Website URL, that can accessed from the expansions menu +tooltipOwned = "Operation Capture and Playback 2"; // Tool tip displayed when the mouse is left over, in the main menu // Color used for DLC stripes and backgrounds (RGBA) dlcColor[] = diff --git a/x/ocap2/addons/recorder/XEH_postInit.sqf b/x/ocap2/addons/recorder/XEH_postInit.sqf index 521017f..36b9004 100644 --- a/x/ocap2/addons/recorder/XEH_postInit.sqf +++ b/x/ocap2/addons/recorder/XEH_postInit.sqf @@ -1,8 +1,8 @@ #include "script_component.hpp" #include "XEH_prep.sqf" -if (!EGVAR(settings,autoStart)) then { - call FUNC(init); -}; +{ + _x remoteExec ["CBA_fnc_addSetting", [0, -2] select isDedicated, true]; +} forEach GVAR(allSettings); ADDON = true; diff --git a/x/ocap2/addons/recorder/XEH_preInit.sqf b/x/ocap2/addons/recorder/XEH_preInit.sqf index d9174b5..d73a536 100644 --- a/x/ocap2/addons/recorder/XEH_preInit.sqf +++ b/x/ocap2/addons/recorder/XEH_preInit.sqf @@ -1,7 +1,225 @@ #include "script_component.hpp" #include "XEH_prep.sqf" -if (EGVAR(settings,autoStart) && !is3DEN) then { +GVAR(allSettings) = [ + // AUTO START SETTINGS + [ + QEGVAR(settings,autoStart), + "CHECKBOX", // setting type + [ + "Auto Start Recording", // Pretty name shown inside the ingame settings menu. Can be stringtable entry. + "Automatically start OCAP recordings at session start. Default: true" + ], + [COMPONENT_NAME, "Auto-start Settings"], // Pretty name of the category where the setting can be found. Can be stringtable entry. + true, // default enabled + true, // "_isGlobal" flag. Set this to true to always have this setting synchronized between all clients in multiplayer + {}, // function that will be executed once on mission start and every time the setting is changed. + true // requires restart to apply + ], + + [ + QEGVAR(settings,minPlayerCount), + "SLIDER", // setting type + [ + "Minimum Player Count", // Pretty name shown inside the ingame settings menu. Can be stringtable entry. + "Auto-start will begin once this player count is reached. Default: 15" + ], + [COMPONENT_NAME, "Auto-start Settings"], // Pretty name of the category where the setting can be found. Can be stringtable entry. + [ + 1, // min + 150, // max + 15, // default + 0, // trailing decimals + false // percentage + ], // data for this setting: [min, max, default, number of shown trailing decimals] + true, // "_isGlobal" flag. Set this to true to always have this setting synchronized between all clients in multiplayer + {}, // function that will be executed once on mission start and every time the setting is changed. + false // requires restart to apply + ], + + + // RECORDING SETTINGS + [ + QEGVAR(settings,frameCaptureDelay), + "SLIDER", // setting type + [ + "Frame Capture Delay", // Pretty name shown inside the ingame settings menu. Can be stringtable entry. + "Positioning, medical status, and crew states of units and vehicles will be captured every X amount of seconds. Default: 1" + ], + [COMPONENT_NAME, "Recording Settings"], // Pretty name of the category where the setting can be found. Can be stringtable entry. + [ + 0.25, // min + 10, // max + 1, // default + 0, // trailing decimals + false // percentage + ], // data for this setting: [min, max, default, number of shown trailing decimals] + true, // "_isGlobal" flag. Set this to true to always have this setting synchronized between all clients in multiplayer + {}, // function that will be executed once on mission start and every time the setting is changed. + true // requires restart to apply + ], + + [ + QEGVAR(settings,preferACEUnconscious), + "CHECKBOX", // setting type + [ + "Use ACE3 Medical", // Pretty name shown inside the ingame settings menu. Can be stringtable entry. + "If true, will check ACE3 medical status on units. If false, or ACE3 isn't loaded, fall back to vanilla. Default: true" + ], + [COMPONENT_NAME, "Recording Settings"], // Pretty name of the category where the setting can be found. Can be stringtable entry. + true, // default enabled + true, // "_isGlobal" flag. Set this to true to always have this setting synchronized between all clients in multiplayer + {}, // function that will be executed once on mission start and every time the setting is changed. + false // requires restart to apply + ], + + [ + QEGVAR(settings,excludeClassFromRecord), + "EDITBOX", // setting type + [ + "Classnames to Exclude", // Pretty name shown inside the ingame settings menu. Can be stringtable entry. + "Array of object classnames that should be excluded from recording. Use single quotes! Default: ['ACE_friesAnchorBar', 'GroundWeaponHolder', 'WeaponHolderSimulated']" + ], + [COMPONENT_NAME, "Recording Settings"], // Pretty name of the category where the setting can be found. Can be stringtable entry. + "['ACE_friesAnchorBar', 'GroundWeaponHolder', 'WeaponHolderSimulated']", // default string value + true, // "_isGlobal" flag. Set this to true to always have this setting synchronized between all clients in multiplayer + {}, // function that will be executed once on mission start and every time the setting is changed. + false // requires restart to apply + ], + + [ + QEGVAR(settings,excludeKindFromRecord), + "EDITBOX", // setting type + [ + "Object KindOfs to Exclude", // Pretty name shown inside the ingame settings menu. Can be stringtable entry. + "Array of classnames which, along with all child classes, should be excluded from recording. Use single quotes! Default: []" + ], + [COMPONENT_NAME, "Recording Settings"], // Pretty name of the category where the setting can be found. Can be stringtable entry. + "[]", // default string value + true, // "_isGlobal" flag. Set this to true to always have this setting synchronized between all clients in multiplayer + {}, // function that will be executed once on mission start and every time the setting is changed. + false // requires restart to apply + ], + + [ + QEGVAR(settings,excludeMarkerFromRecord), + "EDITBOX", // setting type + [ + "Marker Prefixes to Exclude", // Pretty name shown inside the ingame settings menu. Can be stringtable entry. + "Array of prefixes - any markers matching these prefixes will be excluded from recording. Use single quotes! Default: ['SystemMarker_']" + ], + [COMPONENT_NAME, "Recording Settings"], // Pretty name of the category where the setting can be found. Can be stringtable entry. + "['SystemMarker_']", // default string value + true, // "_isGlobal" flag. Set this to true to always have this setting synchronized between all clients in multiplayer + {}, // function that will be executed once on mission start and every time the setting is changed. + false // requires restart to apply + ], + + [ + QEGVAR(settings,pauseOnEmpty), + "CHECKBOX", // setting type + [ + "Auto-Save When No Players", // Pretty name shown inside the ingame settings menu. Can be stringtable entry. + "Will automatically save recording when there are 0 players on the server and existing data accounts for more time than the minumum save duration setting. Default: true" + ], + [COMPONENT_NAME, "Recording Settings"], // Pretty name of the category where the setting can be found. Can be stringtable entry. + true, // default enabled + true, // "_isGlobal" flag. Set this to true to always have this setting synchronized between all clients in multiplayer + {}, // function that will be executed once on mission start and every time the setting is changed. + false // requires restart to apply + ], + + [ + QEGVAR(settings,trackTimes), + "CHECKBOX", // setting type + [ + "Enable Mission Time Tracking", // Pretty name shown inside the ingame settings menu. Can be stringtable entry. + "Will continuously track in-game world time during a mission. Useful for accelerated/skipped time scenarios. Default: false" + ], + [COMPONENT_NAME, "Recording Settings"], // Pretty name of the category where the setting can be found. Can be stringtable entry. + false, // default enabled + true, // "_isGlobal" flag. Set this to true to always have this setting synchronized between all clients in multiplayer + {}, // function that will be executed once on mission start and every time the setting is changed. + false // requires restart to apply + ], + + [ + QEGVAR(settings,trackTimeInterval), + "SLIDER", // setting type + [ + "Mission Time Tracking Interval", // Pretty name shown inside the ingame settings menu. Can be stringtable entry. + "If time tracking is enabled, it will be checked every X capture frames. Default: 10" + ], + [COMPONENT_NAME, "Recording Settings"], // Pretty name of the category where the setting can be found. Can be stringtable entry. + [ + 5, // min + 25, // max + 10, // default + 0, // trailing decimals + false // percentage + ], // data for this setting: [min, max, default, number of shown trailing decimals] + true, // "_isGlobal" flag. Set this to true to always have this setting synchronized between all clients in multiplayer + {}, // function that will be executed once on mission start and every time the setting is changed. + false // requires restart to apply + ], + + + + // SAVING SETTINGS + [ + QEGVAR(settings,saveTag), + "EDITBOX", // setting type + [ + "Mission Type Tag", // Pretty name shown inside the ingame settings menu. Can be stringtable entry. + "If not overriden by the exportData CBA event or if a mission is auto-saved, this will be used to categorize and filter the recording in the database and web list of missions." + ], + [COMPONENT_NAME, "Save/Export Settings"], // Pretty name of the category where the setting can be found. Can be stringtable entry. + "TvT", // default string value + true, // "_isGlobal" flag. Set this to true to always have this setting synchronized between all clients in multiplayer + {}, // function that will be executed once on mission start and every time the setting is changed. + false // requires restart to apply + ], + + [ + QEGVAR(settings,saveMissionEnded), + "CHECKBOX", // setting type + [ + "Auto-save on MPEnded Event", // Pretty name shown inside the ingame settings menu. Can be stringtable entry. + "If true, automatically save and export the mission when the MPEnded event fires. Default: true" + ], + [COMPONENT_NAME, "Save/Export Settings"], // Pretty name of the category where the setting can be found. Can be stringtable entry. + true, // default enabled + true, // "_isGlobal" flag. Set this to true to always have this setting synchronized between all clients in multiplayer + {}, // function that will be executed once on mission start and every time the setting is changed. + false // requires restart to apply + ], + + [ + QEGVAR(settings,minMissionTime), + "SLIDER", // setting type + [ + "Required Duration to Save", // Pretty name shown inside the ingame settings menu. Can be stringtable entry. + "A recording must be at least this long (in minutes) to auto-save. Calling an 'ocap_exportData' CBA server event will override this restriction. Default: 20" + ], + [COMPONENT_NAME, "Save/Export Settings"], // Pretty name of the category where the setting can be found. Can be stringtable entry. + [ + 1, // min + 120, // max + 20, // default + 0, // trailing decimals + false // percentage + ], // data for this setting: [min, max, default, number of shown trailing decimals] + true, // "_isGlobal" flag. Set this to true to always have this setting synchronized between all clients in multiplayer + {}, // function that will be executed once on mission start and every time the setting is changed. + true // requires restart to apply + ] +]; + +{ + _x call CBA_fnc_addSetting; +} forEach GVAR(allSettings); + +if (!is3DEN) then { call FUNC(init); }; diff --git a/x/ocap2/addons/recorder/XEH_prep.sqf b/x/ocap2/addons/recorder/XEH_prep.sqf index 461c888..a7afbb9 100644 --- a/x/ocap2/addons/recorder/XEH_prep.sqf +++ b/x/ocap2/addons/recorder/XEH_prep.sqf @@ -23,6 +23,7 @@ PREP(eh_hit); PREP(eh_killed); PREP(getInstigator); PREP(getEventWeaponText); +PREP(getAmmoData); PREP(aceThrowing); PREP(aceExplosives); diff --git a/x/ocap2/addons/recorder/fnc_aceExplosives.sqf b/x/ocap2/addons/recorder/fnc_aceExplosives.sqf index 12be079..cdb1af0 100644 --- a/x/ocap2/addons/recorder/fnc_aceExplosives.sqf +++ b/x/ocap2/addons/recorder/fnc_aceExplosives.sqf @@ -31,7 +31,10 @@ Author: #include "script_component.hpp" EGVAR(listener,aceExplosives) = ["ace_explosives_place", { - params [_explosive, _dir, _pitch, _unit]; + + if (!SHOULDSAVEEVENTS) exitWith {}; + + params ["_explosive", "_dir", "_pitch", "_unit"]; private _int = random(2000); @@ -47,50 +50,57 @@ EGVAR(listener,aceExplosives) = ["ace_explosives_place", { _markColor = "ColorRed"; _markerType = "Minefield"; + if (GVARMAIN(isDebug)) then { + format["Created explosive placed marker, %1, %2", _markName, _explosiveDisp] SYSCHAT; + OCAPEXTLOG(ARR3("Created explosive placed marker", _markName, _explosiveDisp)); + }; + [QGVARMAIN(handleMarker), [ "CREATED", _markName, _unit, _placedPos, _markerType, "ICON", [1,1], 0, "Solid", "ColorRed", 1, _markTextLocal, true ]] call CBA_fnc_localEvent; - TRACE_2("Created explosive placed marker ", _markName); - if (GVARMAIN(isDebug)) then { - ("Created explosive placed marker " + _markName) SYSCHAT; - }; - [{isNull (_this#0)}, { // wait until the mine is null (exploded), and mark this for playback params ["_explosive", "_explosiveDisp", "_unit", "_placedPos", "_markName", "_int"]; - // remove previous marker - ["ocap_handleMarker", ["DELETED", _markName]] call CBA_fnc_localEvent; + // set unit who placed's lastFired var as the explosive so kills are registered to the explosive + _unit setVariable [ + QGVARMAIN(lastFired), + _explosiveDisp + ]; - TRACE_2("Removed explosive placed marker ", _markName); + // remove previous marker if (GVARMAIN(isDebug)) then { - ("Removed explosive placed marker " + _markName) SYSCHAT; + format["Removed explosive placed marker, %1, %2", _markName, _explosiveDisp] SYSCHAT; + OCAPEXTLOG(ARR3("Removed explosive placed marker", _markName, _explosiveDisp)); }; + [QGVARMAIN(handleMarker), ["DELETED", _markName]] call CBA_fnc_localEvent; + _markTextLocal = format["%1", _explosiveDisp]; _markName = format["Detonation#%1", _int]; _markColor = "ColorRed"; _markerType = "waypoint"; + if (GVARMAIN(isDebug)) then { + format["Created explosive explosion marker, %1, %2", _markName, _explosiveDisp] SYSCHAT; + OCAPEXTLOG(ARR3("Created explosive explosion marker", _markName, _explosiveDisp)); + }; + [QGVARMAIN(handleMarker), [ "CREATED", _markName, _unit, _placedPos, _markerType, "ICON", [1,1], 0, "Solid", "ColorRed", 1, _markTextLocal, true ]] call CBA_fnc_localEvent; - TRACE_2("Created explosive explosion marker ", _markName); - if (GVARMAIN(isDebug)) then { - ("Created explosive explosion " + _markName) SYSCHAT; - }; [{ - params ["_markName"]; - [QGVARMAIN(handleMarker), ["DELETED", _markName]] call CBA_fnc_localEvent; - TRACE_2("Removed explosive explosion marker ", _markName); + params ["_markName", "_explosiveDisp"]; if (GVARMAIN(isDebug)) then { - ("Removed explosive explosion marker " + _markName) SYSCHAT; + format["Removed explosive explosion marker, %1, %2", _markName, _explosiveDisp] SYSCHAT; + OCAPEXTLOG(ARR3("Removed explosive explosion marker", _markName, _explosiveDisp)); }; - }, [_markName], 10] call CBA_fnc_waitAndExecute; + [QGVARMAIN(handleMarker), ["DELETED", _markName]] call CBA_fnc_localEvent; + }, [_markName, _explosiveDisp], 10] call CBA_fnc_waitAndExecute; }, [_explosive, _explosiveDisp, _unit, _placedPos, _markName, _int]] call CBA_fnc_waitUntilAndExecute; diff --git a/x/ocap2/addons/recorder/fnc_aceThrowing.sqf b/x/ocap2/addons/recorder/fnc_aceThrowing.sqf index ce805e3..4fddecd 100644 --- a/x/ocap2/addons/recorder/fnc_aceThrowing.sqf +++ b/x/ocap2/addons/recorder/fnc_aceThrowing.sqf @@ -25,6 +25,8 @@ Author: EGVAR(listener,aceThrowing) = ["ace_throwableThrown", { + if (!SHOULDSAVEEVENTS) exitWith {}; + _this spawn { params["_unit", "_projectile"]; @@ -43,9 +45,9 @@ EGVAR(listener,aceThrowing) = ["ace_throwableThrown", { _projConfig = configOf _projectile; _projName = getText(configFile >> "CfgAmmo" >> _projType >> "displayName"); - TRACE_2("Detected ACE throwing of ", _projName); if (GVARMAIN(isDebug)) then { - ("Detected ACE throwing of " + _projName) SYSCHAT; + format["Detected ACE throwing of %1", _projName] SYSCHAT; + OCAPEXTLOG(ARR2("Detected ACE throwing of ", _projName)); }; // systemChat format["Config name: %1", configOf _projectile]; @@ -135,12 +137,20 @@ EGVAR(listener,aceThrowing) = ["ace_throwableThrown", { [QGVARMAIN(handleMarker), ["UPDATED", _markName, _unit, _pos, "", "", "", 0, "", "", 1]] call CBA_fnc_serverEvent; // here, monitor fast moving missiles/rockets/shells every 0.3 seconds. monitor smokes, grenades, flares, mines in line with the configured frame capture delay - sleep ([0.3, EGVAR(settings,frameCaptureDelay)] select {_ammoSimType in ["ShotSmokeX","ShotGrenade","ShotIlluminating","ShotMine"]}); + sleep (([0.3, GVAR(frameCaptureDelay)] select {_ammoSimType in ["ShotSmokeX","ShotGrenade","ShotIlluminating","ShotMine"]})#0); false; }; if !((count _lastPos) isEqualTo 0) then { - // if (count _lastPos == 3) then { + isNil { + // for non-bullets, set the last fired variable of the soldier so hits/kills are recorded accurately + if (_ammoSimType == "shotGrenade") then { + _unit setVariable [ + QGVARMAIN(lastFired), + _projName + ]; + }; + }; [QGVARMAIN(handleMarker), ["UPDATED", _markName, _unit, _lastPos, "", "", "", 0, "", "", 1]] call CBA_fnc_serverEvent; }; diff --git a/x/ocap2/addons/recorder/fnc_addEventMission.sqf b/x/ocap2/addons/recorder/fnc_addEventMission.sqf index 194a10d..f837861 100644 --- a/x/ocap2/addons/recorder/fnc_addEventMission.sqf +++ b/x/ocap2/addons/recorder/fnc_addEventMission.sqf @@ -51,12 +51,24 @@ addMissionEventHandler ["EntityRespawned", { }; }]; +// Listen for global ACE Explosive placement events if (isClass (configFile >> "CfgPatches" >> "ace_explosives")) then { call FUNC(aceExplosives); }; +// Listen for local ACE Throwing events, for any units owned by the server +if (isClass (configFile >> "CfgPatches" >> "ace_advanced_throwing")) then { + call FUNC(aceThrowing); +}; + addMissionEventHandler ["MPEnded", { - if (EGVAR(settings,saveMissionEnded)) then { + if (EGVAR(settings,saveMissionEnded) && (GVAR(captureFrameNo) * GVAR(frameCaptureDelay)) >= GVAR(minMissionTime)) then { + ["Mission ended automatically"] call FUNC(exportData); + }; +}]; + +addMissionEventHandler ["Ended", { + if (EGVAR(settings,saveMissionEnded) && (GVAR(captureFrameNo) * GVAR(frameCaptureDelay)) >= GVAR(minMissionTime)) then { ["Mission ended automatically"] call FUNC(exportData); }; }]; @@ -80,6 +92,7 @@ EGVAR(listener,exportData) = [QGVARMAIN(record), { // This will PAUSE recording EGVAR(listener,exportData) = [QGVARMAIN(pause), { GVAR(recording) = false; + publicVariable QGVAR(recording); }] call CBA_fnc_addEventHandler; // Custom event handler with key "ocap2_exportData" diff --git a/x/ocap2/addons/recorder/fnc_addUnitEventHandlers.sqf b/x/ocap2/addons/recorder/fnc_addUnitEventHandlers.sqf index 467a828..bd28b62 100644 --- a/x/ocap2/addons/recorder/fnc_addUnitEventHandlers.sqf +++ b/x/ocap2/addons/recorder/fnc_addUnitEventHandlers.sqf @@ -28,17 +28,32 @@ Author: params ["_entity", ["_respawn", false]]; + +// FIREDMAN if ((_entity call BIS_fnc_objectType) # 0 == "Soldier") then { - _entity addEventHandler ["FiredMan", { _this spawn FUNC(eh_firedMan); }]; + _entity addEventHandler ["FiredMan", { _this call FUNC(eh_firedMan); }]; }; + +// MPHIT _entity addMPEventHandler ["MPHit", { _this spawn FUNC(eh_hit); }]; +private _ownerId = owner _entity; if ( - !_respawn && + !_respawn && // exclude re-adding on respawn, as the CBA listener will already be present on the owner's machine (_entity call BIS_fnc_objectType) # 0 == "Soldier" && + _ownerId != 2 && // only add to entities not owned by server, as otherwise server will receive local events already isClass (configFile >> "CfgPatches" >> "ace_advanced_throwing") ) then { // here, we must place a local listener of ACE throw events on the owner of the entity - // the client will then notify the server when such an event happens - FUNC(aceThrowing) remoteExec ["call", _entity]; + // the client will then notify the server when these local events happen + // we'll wait a max of 15 secs until that owner is at least to briefing stage, has completed PostInit, before sending + [ + {(getUserInfo (_this#0)) select 6 > 8}, + { + FUNC(aceThrowing) remoteExec ["call", _this#1]; + OCAPEXTLOG(ARR3("ADD ACE THROWING LISTENER", _this#0, _this#1)); + }, + [_ownerId, _entity], + 15 + ] call CBA_fnc_waitUntilAndExecute; }; diff --git a/x/ocap2/addons/recorder/fnc_captureLoop.sqf b/x/ocap2/addons/recorder/fnc_captureLoop.sqf index d812cf1..a827f20 100644 --- a/x/ocap2/addons/recorder/fnc_captureLoop.sqf +++ b/x/ocap2/addons/recorder/fnc_captureLoop.sqf @@ -34,35 +34,27 @@ if (!isNil QGVAR(PFHObject)) then { }; if (isNil QGVAR(startTime)) then { GVAR(startTime) = time; + OCAPEXTLOG(ARR3(__FILE__, QGVAR(recording) + " started, time:", GVAR(startTime))); LOG(ARR3(__FILE__, QGVAR(recording) + " started, time:", GVAR(startTime))); }; GVAR(PFHObject) = [ { - if (!isNil {_private#0}) then { - if (EGVAR(settings,frameCaptureDelay) != _private#0) exitWith { - OCAPEXTLOG(ARR_3("Frame capture delay changed", _private#0, EGVAR(settings,frameCaptureDelay))); - TRACE_3("Frame capture delay changed", _private#0, EGVAR(settings,frameCaptureDelay)); - GVAR(recording) = false; - [{call FUNC(startCaptureLoop)}, [], EGVAR(settings,frameCaptureDelay) + _private#0] call CBA_fnc_waitAndExecute; - }; - }; - _frameCaptureDelay = EGVAR(settings,frameCaptureDelay); + private _loopStart = diag_tickTime; - TRACE_2("Frame", _frameCaptureDelay); if (GVAR(captureFrameNo) == 10 || (GVAR(captureFrameNo) > 10 && EGVAR(settings,trackTimes) && GVAR(captureFrameNo) % EGVAR(settings,trackTimeInterval) == 0)) then { [] call FUNC(updateTime); }; // update diary record every 320 frames - if (GVAR(captureFrameNo) % (320 / EGVAR(settings,frameCaptureDelay)) == 0) then { + if (GVAR(captureFrameNo) % (320 / GVAR(frameCaptureDelay)) == 0) then { publicVariable QGVAR(captureFrameNo); { player createDiaryRecord [ "OCAP2Info", [ "Status", - ("Capture frame: " + QGVAR(captureFrameNo) + "") + ("Capture frame: " + str (missionNamespace getVariable [QGVAR(captureFrameNo), "[not yet received]"]) + "") ] ]; } remoteExecCall ["call", 0, false]; @@ -138,15 +130,15 @@ GVAR(PFHObject) = [ _x setVariable [QGVARMAIN(exclude), true]; }; - _x setVariable [QGVARMAIN(id), _id]; + _x setVariable [QGVARMAIN(id), GVAR(nextId)]; [":NEW:VEH:", [ GVAR(captureFrameNo), //1 - _id, //2 + GVAR(nextId), //2 _class, //3 getText (configFile >> "CfgVehicles" >> _vehType >> "displayName") //4 ]] call EFUNC(extension,sendData); [_x] spawn FUNC(addUnitEventHandlers); - _id = _id + 1; + GVAR(nextId) = GVAR(nextId) + 1; _x setVariable [QGVARMAIN(isInitialized), true]; }; if !(_x getVariable [QGVARMAIN(exclude), false]) then { @@ -170,11 +162,19 @@ GVAR(PFHObject) = [ } count vehicles; GVAR(captureFrameNo) = GVAR(captureFrameNo) + 1; + publicVariable QGVAR(captureFrameNo); + + if (GVARMAIN(isDebug)) then { + private _logStr = format["Frame %1 processed in %2ms", GVAR(captureFrameNo), diag_tickTime - _loopStart]; + OCAPEXTLOG([_logStr]); + _logStr SYSCHAT; + }; }, - EGVAR(settings,frameCaptureDelay), // delay + GVAR(frameCaptureDelay), // delay [], // args { GVAR(recording) = true; + publicVariable QGVAR(recording); { // add diary entry for clients on recording start [{!isNull player}, { @@ -194,6 +194,7 @@ GVAR(PFHObject) = [ }, // code, executed when added { GVAR(recording) = false; + publicVariable QGVAR(recording); { // add diary entry for clients on recording start [{!isNull player}, { @@ -212,6 +213,5 @@ GVAR(PFHObject) = [ } remoteExecCall ["call", 0, true]; }, // code, executed when removed {GVAR(recording)}, // if true, execute PFH cycle - {!GVAR(recording) || !GVARMAIN(enabled)}, // if true, delete object - ["_frameCaptureDelay"] + {!GVAR(recording) || !GVARMAIN(enabled)} // if true, delete object ] call CBA_fnc_createPerFrameHandlerObject; diff --git a/x/ocap2/addons/recorder/fnc_eh_firedMan.sqf b/x/ocap2/addons/recorder/fnc_eh_firedMan.sqf index 85ac8e1..690efa8 100644 --- a/x/ocap2/addons/recorder/fnc_eh_firedMan.sqf +++ b/x/ocap2/addons/recorder/fnc_eh_firedMan.sqf @@ -29,154 +29,111 @@ Author: ---------------------------------------------------------------------------- */ #include "script_component.hpp" -params ["_firer", "_weapon", "_muzzle", "_mode", "_ammo", "_magazine", "_projectile", "_vehicle"]; +if (!SHOULDSAVEEVENTS) exitWith {}; -_frame = GVAR(captureFrameNo); +params ["_firer", "_weapon", "_muzzle", "_mode", "_ammo", "_magazine", "_projectile", "_vehicle"]; -_firer setVariable [QGVARMAIN(lastFired), currentWeapon _firer]; +private _frame = GVAR(captureFrameNo); + +private _firerId = (_firer getVariable [QGVARMAIN(id), -1]); +if (_firerId == -1) exitWith {}; + +// set the firer's lastFired var as this weapon, so subsequent kills are logged accurately +isNil { + _firer setVariable [ + QGVARMAIN(lastFired), + format[ + "%1 [%2]", + getText (configFile >> "CfgWeapons" >> _weapon >> "displayName"), + getText (configFile >> "CfgWeapons" >> _muzzle >> "displayName") + ] + ]; +}; _ammoSimType = getText(configFile >> "CfgAmmo" >> _ammo >> "simulation"); - -// bullet handling, cut short -if (_ammoSimType isEqualTo "shotBullet") then { - [_projectile, _firer, _frame, _ammoSimType, _ammo] spawn { - params["_projectile", "_firer", "_frame", "_ammoSimType", "_ammo"]; +// _ammoSimType +// "ShotGrenade" // M67 +// "ShotRocket" // S-8 +// "ShotMissile" // R-27 +// "ShotShell" // VOG-17M, HE40mm +// "ShotMine" // Satchel charge +// "ShotIlluminating" // 40mm_green Flare +// "ShotSmokeX"; // M18 Smoke + + +switch (_ammoSimType) do { + case (_ammoSimType isEqualTo "shotBullet"): { + // [_projectile, _firer, _frame, _ammoSimType, _ammo] spawn { + // params["_projectile", "_firer", "_frame", "_ammoSimType", "_ammo"]; if (isNull _projectile) then { _projectile = nearestObject [_firer, _ammo]; }; - private _lastPos = []; - waitUntil { - _pos = getPosASL _projectile; - if (((_pos select 0) isEqualTo 0) || isNull _projectile) exitWith { - true - }; - _lastPos = _pos; - false; - }; - - if !((count _lastPos) isEqualTo 0) then { - [":FIRED:", [ - (_firer getVariable QGVARMAIN(id)), - _frame, - _lastPos - ]] call EFUNC(extension,sendData); - }; + GVAR(liveBullets) pushBack [_projectile, _firerId, _frame, getPosASL _projectile]; }; -} else { - // _ammoSimType - // simulation == "ShotSmokeX"; // M18 Smoke - // "ShotGrenade" // M67 - // "ShotRocket" // S-8 - // "ShotMissile" // R-27 - // "ShotShell" // VOG-17M, HE40mm - // "ShotIlluminating" // 40mm_green Flare - // "ShotMine" // Satchel remote - - _int = random 2000; - _muzzleDisp = getText(configFile >> "CfgWeapons" >> _weapon >> _muzzle >> "displayName"); - if (_muzzleDisp == "") then {_muzzleDisp = getText(configFile >> "CfgWeapons" >> _weapon >> "displayNameShort")}; - if (_muzzleDisp == "") then {_muzzleDisp = getText(configFile >> "CfgWeapons" >> _weapon >> "displayName")}; - _magDisp = getText(configFile >> "CfgMagazines" >> _magazine >> "displayNameShort"); - if (_magDisp == "") then {_magDisp = getText(configFile >> "CfgMagazines" >> _magazine >> "displayName")}; - if (_magDisp == "") then {_magDisp = getText(configFile >> "CfgAmmo" >> _ammo >> "displayNameShort")}; - if (_magDisp == "") then {_magDisp = getText(configFile >> "CfgAmmo" >> _ammo >> "displayName")}; - - // non-bullet handling - private ["_markTextLocal"]; - if (!isNull _vehicle) then { - _markTextLocal = format["[%3] %1 - %2", _muzzleDisp, _magDisp, ([configOf _vehicle] call BIS_fnc_displayName)]; - } else { - if (_ammoSimType isEqualTo "shotGrenade") then { - _markTextLocal = format["%1", _magDisp]; - } else { - _markTextLocal = format["%1 - %2", _muzzleDisp, _magDisp]; - }; - }; - - _markName = format["Projectile#%1", _int]; - _markColor = "ColorRed"; - _markerType = ""; - _magPic = (getText(configfile >> "CfgMagazines" >> _magazine >> "picture")); - if (_magPic == "") then { - _markerType = "mil_triangle"; - } else { - _magPicSplit = _magPic splitString "\"; - _magPic = _magPicSplit # ((count _magPicSplit) -1); - _markerType = format["magIcons/%1", _magPic]; - _markColor = "ColorWhite"; - }; - - - // _markStr = format["|%1|%2|%3|%4|%5|%6|%7|%8|%9|%10", - // _markName, - // getPos _firer, - // "mil_triangle", - // "ICON", - // [1, 1], - // 0, - // "Solid", - // "ColorRed", - // 1, - // _markTextLocal - // ]; - - // _markStr call BIS_fnc_stringToMarkerLocal; - // diag_log text format["detected grenade, created marker %1", _markStr]; + case (_ammoSimType isNotEqualTo "shotSubmunitions"): { - // _markStr = str _mark; - // _mark = createMarkerLocal [format["Projectile%1", _int],_projectile]; - // _mark setMarkerColorLocal "ColorRed"; - // _mark setMarkerTypeLocal "selector_selectable"; - // _mark setMarkerShapeLocal "ICON"; - // _mark setMarkerTextLocal format["%1 - %2", _firer, _markTextLocal]; + // MAKE MARKER FOR PLAYBACK + _firerPos = getPosASL _firer; + [QGVARMAIN(handleMarker), ["CREATED", _markName, _firer, _firerPos, _markerType, "ICON", [1,1], getDirVisual _firer, "Solid", _markColor, 1, _markTextLocal, true]] call CBA_fnc_localEvent; - _firerPos = getPosASL _firer; - [QGVARMAIN(handleMarker), ["CREATED", _markName, _firer, _firerPos, _markerType, "ICON", [1,1], getDirVisual _firer, "Solid", _markColor, 1, _markTextLocal, true]] call CBA_fnc_localEvent; - - if (_ammoSimType isEqualTo "shotSubmunitions") then { - private _subTypes = ((configFile >> "CfgAmmo" >> _ammo >> "submunitionAmmo") call BIS_fnc_getCfgDataArray) select {_x isEqualType ""}; - if (count _subTypes > 1) then { - waitUntil {isNull _projectile}; - }; - while {isNull _projectile} do { - { - _projSearch = nearestObject [_firer, _x]; - if !(isNull _projSearch) exitWith {_projectile = _projSearch}; - } forEach _subTypes; - }; - } else { if (isNull _projectile) then { _projectile = nearestObject [_firer, _ammo]; }; - }; - private _lastPos = []; - private _lastDir = 0; - waitUntil { - _pos = getPosASL _projectile; - _dir = getDirVisual _projectile; - if (((_pos select 0) isEqualTo 0) || isNull _projectile) exitWith { - true + switch (true) do { + case (_ammoSimType isEqualTo "shotBullet"): { + GVAR(liveBullets) pushBack [_projectile, _firerId, _frame, getPosASL _projectile]; + }; + case (_ammoSimType in ["shotMissile", "shotRocket", "shotShell"]): { + GVAR(liveMissiles) pushBack [_projectile, _magazine, _firer, getPosASL _projectile, _markName]; + }; + case (_ammoSimType in ["shotGrenade", "shotIlluminating", "shotMine", "shotSmokeX"]): { + GVAR(liveGrenades) pushBack [_projectile, _magazine, _firer, getPosASL _projectile, _markName, _ammoSimType]; + }; + default {OCAPEXTLOG(ARR3("Invalid ammo sim type, check it", _projectile, _newAmmoSimType))}; }; - _lastPos = _pos; - _lastDir = _dir; - // params["_eventType", "_mrk_name", "_mrk_owner", "_pos", "_type", "_shape", "_size", "_dir", "_brush", "_color", "_alpha", "_text", "_forceGlobal"]; - [QGVARMAIN(handleMarker), ["UPDATED", _markName, _firer, _pos, "", "", "", _dir, "", "", 1]] call CBA_fnc_localEvent; - - // here, monitor fast moving missiles/rockets/shells every 0.3 seconds. monitor smokes, grenades, flares, mines in line with the configured frame capture delay - sleep ([0.3, EGVAR(settings,frameCaptureDelay)] select {_ammoSimType in ["ShotSmokeX","ShotGrenade","ShotIlluminating","ShotMine"]}); - false; }; - if !((count _lastPos) isEqualTo 0) then { - // if (count _lastPos == 3) then { - // params["_eventType", "_mrk_name", "_mrk_owner", "_pos", "_type", "_shape", "_size", "_dir", "_brush", "_color", "_alpha", "_text", "_forceGlobal"]; - [QGVARMAIN(handleMarker), ["UPDATED", _markName, _firer, _lastPos, "", "", "", _lastDir, "", "", 1]] call CBA_fnc_localEvent; + + case (_ammoSimType isEqualTo "shotSubmunitions"): { + + // for submunitions, we first look at the original ammo and find the classnames of submunition ammo its rounds will turn into + // these are done in a staggered array in format ["classname1", probability of spawn, "classname2", probability of spawn] + // this is usually for vehicles with guns that fire mixed ammo, or for cluster munitions + // we'll wait for the simStep to have elapsed, then start checking for the resulting submunition nearby + // once we have that, we'll add it to the bullet tracking array for positions so a fireline is drawn in playback + private _simDelay = (configFile >> "CfgAmmo" >> _ammo >> "simulationStep") call BIS_fnc_getCfgData; + private _subTypes = ((configFile >> "CfgAmmo" >> _ammo >> "submunitionAmmo") call BIS_fnc_getCfgDataArray) select {_x isEqualType ""}; + [{ + params ["_EHData", "_subTypes", "_magazine", "_firer", "_firerId", "_firerPos", "_frame"]; + private _projectile = objNull; + while {isNull _projectile} do { + { + _projSearch = nearestObject [_firer, _x]; + if !(isNull _projSearch) exitWith {_projectile = _projSearch}; + } forEach _subTypes; + }; + + // get marker details based on original EH data + (_EHData call FUNC(getAmmoData)) params ["_markTextLocal","_markName","_markColor","_markerType"]; + // create our marker record in the timeline + [QGVARMAIN(handleMarker), ["CREATED", _markName, _firer, getPosASL _firer, _markerType, "ICON", [1,1], getDir _firer, "Solid", _markColor, 1, _markTextLocal, true]] call CBA_fnc_localEvent; + + private _newAmmoSimType = getText(configFile >> "CfgAmmo" >> _projectile >> "simulation"); + switch (true) do { + case (_newAmmoSimType isEqualTo "shotBullet"): { + GVAR(liveBullets) pushBack [_projectile, _firerId, _frame, getPosASL _projectile]; + }; + case (_newAmmoSimType in ["shotMissile", "shotRocket", "shotShell"]): { + GVAR(liveMissiles) pushBack [_projectile, _magazine, _firer, getPosASL _projectile, _markName]; + }; + case (_newAmmoSimType in ["shotGrenade", "shotIlluminating", "shotMine", "shotSmokeX"]): { + GVAR(liveGrenades) pushBack [_projectile, _magazine, _firer, getPosASL _projectile, _markName, _newAmmoSimType]; + }; + default {OCAPEXTLOG(ARR3("Invalid ammo sim type, check it", _projectile, _newAmmoSimType))}; + }; + }, [_this, _subTypes, _magazine, _firer, _firerId, _firerPos, _frame], _simDelay] call CBA_fnc_waitAndExecute; }; - sleep 10; - // deleteMarkerLocal _markName; - // }; - [QGVARMAIN(handleMarker), ["DELETED", _markName]] call CBA_fnc_localEvent; }; diff --git a/x/ocap2/addons/recorder/fnc_eh_hit.sqf b/x/ocap2/addons/recorder/fnc_eh_hit.sqf index 981d0fd..8ba40b4 100644 --- a/x/ocap2/addons/recorder/fnc_eh_hit.sqf +++ b/x/ocap2/addons/recorder/fnc_eh_hit.sqf @@ -25,6 +25,8 @@ Author: ---------------------------------------------------------------------------- */ #include "script_component.hpp" +if (!SHOULDSAVEEVENTS) exitWith {}; + params ["_unit", "_causedBy", "_damage", "_instigator"]; [_unit, _causedBy, _instigator] spawn { @@ -34,9 +36,11 @@ params ["_unit", "_causedBy", "_damage", "_instigator"]; _instigator = [_unit, _causedBy] call FUNC(getInstigator); }; + private _hitFrame = GVAR(captureFrameNo); + _unitID = _unit getVariable [QGVARMAIN(id), -1]; if (_unitID == -1) exitWith {}; - private _eventData = [GVAR(captureFrameNo), "hit", _unitID, ["null"], -1]; + private _eventData = [_hitFrame, "hit", _unitID, ["null"], -1]; if (!isNull _instigator) then { _causedById = _causedBy getVariable [QGVARMAIN(id), -1]; @@ -50,6 +54,10 @@ params ["_unit", "_causedBy", "_damage", "_instigator"]; ([_causedBy] call FUNC(getEventWeaponText)) ]; _distanceInfo = round (_unit distance _causedBy); + + if (GVARMAIN(isDebug)) then { + OCAPEXTLOG(ARR4("HIT EVENT", _hitFrame, _unitID, _causedById)); + }; } else { if (!isNull _instigator && _causedBy != _instigator && _instigator isKindOf "CAManBase" && _instigatorId > -1) then { _causedByInfo = [ @@ -57,13 +65,17 @@ params ["_unit", "_causedBy", "_damage", "_instigator"]; ([_instigator] call FUNC(getEventWeaponText)) ]; _distanceInfo = round (_unit distance _instigator); + + if (GVARMAIN(isDebug)) then { + OCAPEXTLOG(ARR4("HIT EVENT", _hitFrame, _unitID, _instigatorId)); + }; } else { _causedByInfo = [_causedById]; _distanceInfo = round (_unit distance _causedBy); }; }; _eventData = [ - GVAR(captureFrameNo), + _hitFrame, "hit", _unitID, _causedByInfo, @@ -71,6 +83,5 @@ params ["_unit", "_causedBy", "_damage", "_instigator"]; ]; }; - OCAPEXTLOG(_eventData); [":EVENT:", _eventData] call EFUNC(extension,sendData); }; diff --git a/x/ocap2/addons/recorder/fnc_eh_killed.sqf b/x/ocap2/addons/recorder/fnc_eh_killed.sqf index 8868ee5..42aff77 100644 --- a/x/ocap2/addons/recorder/fnc_eh_killed.sqf +++ b/x/ocap2/addons/recorder/fnc_eh_killed.sqf @@ -25,7 +25,10 @@ Author: ---------------------------------------------------------------------------- */ #include "script_component.hpp" +if (!SHOULDSAVEEVENTS) exitWith {}; + params ["_victim", "_killer", "_instigator"]; + if !(_victim getvariable [QGVARMAIN(isKilled),false]) then { _victim setvariable [QGVARMAIN(isKilled),true]; @@ -34,7 +37,7 @@ if !(_victim getvariable [QGVARMAIN(isKilled),false]) then { private _killedFrame = GVAR(captureFrameNo); - if (_killer == _victim) then { + if (_killer == _victim && owner _victim != 2 && EGVAR(settings,preferACEUnconscious) && isClass(configFile >> "CfgPatches" >> "ace_medical_status")) then { private _time = diag_tickTime; [_victim, { _this setVariable ["ace_medical_lastDamageSource", (_this getVariable "ace_medical_lastDamageSource"), 2]; @@ -75,12 +78,14 @@ if !(_victim getvariable [QGVARMAIN(isKilled),false]) then { _killerInfo, round(_instigator distance _victim) ]; - }; - if (GVARMAIN(isDebug)) then { - OCAPEXTLOG(_eventData); + if (GVARMAIN(isDebug)) then { + OCAPEXTLOG(ARR4("KILLED EVENT", _killedFrame, _victimId, _killerId)); + }; }; + + [":EVENT:", _eventData] call EFUNC(extension,sendData); }; }; diff --git a/x/ocap2/addons/recorder/fnc_exportData.sqf b/x/ocap2/addons/recorder/fnc_exportData.sqf index 80a3cf1..2987ed1 100644 --- a/x/ocap2/addons/recorder/fnc_exportData.sqf +++ b/x/ocap2/addons/recorder/fnc_exportData.sqf @@ -65,11 +65,11 @@ if (isNil QGVAR(startTime)) exitWith { _elapsedTime = time - GVAR(startTime); -_frameTimeDuration = EGVAR(settings,frameCaptureDelay) * GVAR(captureFrameNo); +_frameTimeDuration = GVAR(frameCaptureDelay) * GVAR(captureFrameNo); TRACE_7("Save attempted. Elapsed Time =", _elapsedTime," Frame Count * Delay Duration =", _frameTimeDuration," delta =", _elapsedTime - _frameTimeDuration); -if (_frameTimeDuration < EGVAR(settings,minMissionTime) && !_overrideLimits) exitWith { +if (_frameTimeDuration < GVAR(minMissionTime) && !_overrideLimits) exitWith { // if the total duration in minutes is not met based on how many frames have been recorded & the frame capture delay, // then we won't save, but will continue recording in case admins want to save once that threshold is met. // allow this restriction to be overriden @@ -92,32 +92,31 @@ if (_frameTimeDuration < EGVAR(settings,minMissionTime) && !_overrideLimits) exi }; GVAR(recording) = false; +publicVariable QGVAR(recording); GVAR(endFrameNumber) = GVAR(captureFrameNo); publicVariable QGVAR(endFrameNumber); -switch (count _this) do { - case 0: { - [":EVENT:", [GVAR(endFrameNumber), "endMission", ["", "Mission ended"]]] call EFUNC(extension,sendData); - }; - case 1: { - [":EVENT:", [GVAR(endFrameNumber), "endMission", ["", _side]]] call EFUNC(extension,sendData); - }; - default { - private _sideString = str(_side); - if (_side == sideUnknown) then { _sideString = "" }; - [":EVENT:", [GVAR(endFrameNumber), "endMission", [_sideString, _message]]] call EFUNC(extension,sendData); - }; +if (isNil "_side") then { + [":EVENT:", [GVAR(endFrameNumber), "endMission", ["", "Mission ended"]]] call EFUNC(extension,sendData); +}; +if (!isNil "_side" && isNil "_message") then { + [":EVENT:", [GVAR(endFrameNumber), "endMission", ["", _side]]] call EFUNC(extension,sendData); +}; +if (!isNil "_side" && !isNil "_message") then { + private _sideString = str(_side); + if (_side == sideUnknown) then { _sideString = "" }; + [":EVENT:", [GVAR(endFrameNumber), "endMission", [_sideString, _message]]] call EFUNC(extension,sendData); }; if (!isNil "_tag") then { - [":SAVE:", [worldName, GVAR(missionName), getMissionConfigValue ["author", ""], EGVAR(settings,frameCaptureDelay), GVAR(endFrameNumber), _tag]] call EFUNC(extension,sendData); - LOG(ARR4("Saved recording of mission", GVAR(missionName), "with tag", _tag)); -} else { - [":SAVE:", [worldName, GVAR(missionName), getMissionConfigValue ["author", ""], EGVAR(settings,frameCaptureDelay), GVAR(endFrameNumber)]] call EFUNC(extension,sendData); - LOG(ARR3("Saved recording of mission", GVAR(missionName), "with default tag")); + [":SAVE:", [worldName, GVAR(missionName), getMissionConfigValue ["author", ""], GVAR(frameCaptureDelay), GVAR(endFrameNumber), _tag]] call EFUNC(extension,sendData); + OCAPEXTLOG(ARR4("Saved recording of mission", GVAR(missionName), "with tag", _tag)); +} else {// default tag to configured setting + [":SAVE:", [worldName, GVAR(missionName), getMissionConfigValue ["author", ""], GVAR(frameCaptureDelay), GVAR(endFrameNumber), EGVAR(settings,saveTag)]] call EFUNC(extension,sendData); + OCAPEXTLOG(ARR3("Saved recording of mission", GVAR(missionName), "with default tag")); }; // briefingName is used here, no need for publicVariable for a simple confirmation log. diff --git a/x/ocap2/addons/recorder/fnc_getAmmoData.sqf b/x/ocap2/addons/recorder/fnc_getAmmoData.sqf new file mode 100644 index 0000000..e22ff7b --- /dev/null +++ b/x/ocap2/addons/recorder/fnc_getAmmoData.sqf @@ -0,0 +1,62 @@ +params ["_firer", "_weapon", "_muzzle", "_mode", "_ammo", "_magazine", "_projectile", "_vehicle"]; + +_int = random 2000; +_muzzleDisp = getText(configFile >> "CfgWeapons" >> _weapon >> _muzzle >> "displayName"); +if (_muzzleDisp == "") then {_muzzleDisp = getText(configFile >> "CfgWeapons" >> _weapon >> "displayNameShort")}; +if (_muzzleDisp == "") then {_muzzleDisp = getText(configFile >> "CfgWeapons" >> _weapon >> "displayName")}; +_magDisp = getText(configFile >> "CfgMagazines" >> _magazine >> "displayNameShort"); +if (_magDisp == "") then {_magDisp = getText(configFile >> "CfgMagazines" >> _magazine >> "displayName")}; +if (_magDisp == "") then {_magDisp = getText(configFile >> "CfgAmmo" >> _ammo >> "displayNameShort")}; +if (_magDisp == "") then {_magDisp = getText(configFile >> "CfgAmmo" >> _ammo >> "displayName")}; + +// non-bullet handling +private ["_markTextLocal"]; +if (!isNull _vehicle) then { + _markTextLocal = format["[%3] %1 - %2", _muzzleDisp, _magDisp, ([configOf _vehicle] call BIS_fnc_displayName)]; +} else { + if (_ammoSimType isEqualTo "shotGrenade") then { + _markTextLocal = format["%1", _magDisp]; + } else { + _markTextLocal = format["%1 - %2", _muzzleDisp, _magDisp]; + }; +}; + +_markName = format["Projectile#%1", _int]; +_markColor = "ColorRed"; +_markerType = ""; +_magPic = (getText(configfile >> "CfgMagazines" >> _magazine >> "picture")); +if (_magPic == "") then { + _markerType = "mil_triangle"; +} else { + _magPicSplit = _magPic splitString "\"; + _magPic = _magPicSplit # ((count _magPicSplit) -1); + _markerType = format["magIcons/%1", _magPic]; + _markColor = "ColorWhite"; +}; + +[_markTextLocal,_markName,_markColor,_markerType]; + + + // _markStr = format["|%1|%2|%3|%4|%5|%6|%7|%8|%9|%10", + // _markName, + // getPos _firer, + // "mil_triangle", + // "ICON", + // [1, 1], + // 0, + // "Solid", + // "ColorRed", + // 1, + // _markTextLocal + // ]; + + // _markStr call BIS_fnc_stringToMarkerLocal; + + // diag_log text format["detected grenade, created marker %1", _markStr]; + + // _markStr = str _mark; + // _mark = createMarkerLocal [format["Projectile%1", _int],_projectile]; + // _mark setMarkerColorLocal "ColorRed"; + // _mark setMarkerTypeLocal "selector_selectable"; + // _mark setMarkerShapeLocal "ICON"; + // _mark setMarkerTextLocal format["%1 - %2", _firer, _markTextLocal]; diff --git a/x/ocap2/addons/recorder/fnc_getDelay.sqf b/x/ocap2/addons/recorder/fnc_getDelay.sqf index 9b151c2..26e8143 100644 --- a/x/ocap2/addons/recorder/fnc_getDelay.sqf +++ b/x/ocap2/addons/recorder/fnc_getDelay.sqf @@ -28,10 +28,10 @@ Author: private "_sleep"; isNil { _elapsedTime = time - GVAR(startTime); - _sleep = (GVAR(captureFrameNo) + 1) * EGVAR(settings,frameCaptureDelay) - _elapsedTime; + _sleep = (GVAR(captureFrameNo) + 1) * GVAR(frameCaptureDelay) - _elapsedTime; if ((GVAR(captureFrameNo) % 10) isEqualTo 0) then { - LOG(ARR4("DEBUG: Frame", GVAR(captureFrameNo), "is created in ~", EGVAR(settings,frameCaptureDelay) - _sleep)); + LOG(ARR4("DEBUG: Frame", GVAR(captureFrameNo), "is created in ~", GVAR(frameCaptureDelay) - _sleep)); }; if (_sleep < 0) then { LOG(ARR3("ERROR: Frame delay is negative", GVAR(captureFrameNo), _sleep)); diff --git a/x/ocap2/addons/recorder/fnc_getEventWeaponText.sqf b/x/ocap2/addons/recorder/fnc_getEventWeaponText.sqf index 53380d9..04dbc45 100644 --- a/x/ocap2/addons/recorder/fnc_getEventWeaponText.sqf +++ b/x/ocap2/addons/recorder/fnc_getEventWeaponText.sqf @@ -28,7 +28,14 @@ Author: params ["_instigator"]; if (vehicle _instigator isEqualTo _instigator) exitWith { - _instigator getVariable [QGVARMAIN(lastFired), getText (configFile >> "CfgWeapons" >> currentWeapon _instigator >> "displayName")]; + _instigator getVariable [ + QGVARMAIN(lastFired), + format[ + "%1 [%2]", + getText (configFile >> "CfgWeapons" >> currentWeapon _instigator >> "displayName"), + getText (configFile >> "CfgWeapons" >> currentMuzzle _instigator >> "displayName") + ] + ] }; // pilot/driver doesn't return a value, so check for this diff --git a/x/ocap2/addons/recorder/fnc_handleCustomEvent.sqf b/x/ocap2/addons/recorder/fnc_handleCustomEvent.sqf index 7efc0b1..278231e 100644 --- a/x/ocap2/addons/recorder/fnc_handleCustomEvent.sqf +++ b/x/ocap2/addons/recorder/fnc_handleCustomEvent.sqf @@ -48,6 +48,8 @@ Author: ---------------------------------------------------------------------------- */ #include "script_component.hpp" +if (!SHOULDSAVEEVENTS) exitWith {}; + params ["_eventName", "_eventMessage"]; [":EVENT:", [GVAR(captureFrameNo), _eventName, _eventMessage] diff --git a/x/ocap2/addons/recorder/fnc_handleMarkers.sqf b/x/ocap2/addons/recorder/fnc_handleMarkers.sqf index 2983214..012f185 100644 --- a/x/ocap2/addons/recorder/fnc_handleMarkers.sqf +++ b/x/ocap2/addons/recorder/fnc_handleMarkers.sqf @@ -63,6 +63,9 @@ GVAR(trackedMarkers) = []; // Markers which we saves into replay // create CBA event handler to be called on server with key "ocap2_handleMarker" EGVAR(listener,markers) = [QGVARMAIN(handleMarker), { + + if (!SHOULDSAVEEVENTS) exitWith {}; + params["_eventType", "_mrk_name", "_mrk_owner", "_pos", "_type", "_shape", "_size", "_dir", "_brush", "_color", "_alpha", "_text", ["_forceGlobal", false], ["_creationTime", 0]]; switch (_eventType) do { @@ -70,7 +73,7 @@ EGVAR(listener,markers) = [QGVARMAIN(handleMarker), { case "CREATED":{ if (GVARMAIN(isDebug)) then { - OCAPEXTLOG(ARR2("MARKER:CREATE: Processing marker data -- ", _this)); + OCAPEXTLOG(ARR2("MARKER:CREATE: Processing marker data -- ", _mrk_name)); }; if (_mrk_name in GVAR(trackedMarkers)) exitWith { @@ -80,7 +83,8 @@ EGVAR(listener,markers) = [QGVARMAIN(handleMarker), { }; if (GVARMAIN(isDebug)) then { - OCAPEXTLOG(ARR4("MARKER:CREATE: Valid CREATED process of marker from", _mrk_owner, "for", _mrk_name)); + format["CREATE:MARKER: Valid CREATED process of %1, sending to extension", _mrk_name] SYSCHAT; + OCAPEXTLOG(ARR3("CREATE:MARKER: Valid CREATED process of", _mrk_name, ", sending to extension")); }; if (_type isEqualTo "") then {_type = "mil_dot"}; @@ -128,9 +132,9 @@ EGVAR(listener,markers) = [QGVARMAIN(handleMarker), { private _captureFrameNo = GVAR(captureFrameNo); if (_creationTime > 0) then { private _delta = time - _creationTime; - private _lastFrameTime = (GVAR(captureFrameNo) * EGVAR(settings,frameCaptureDelay)) + GVAR(startTime); + private _lastFrameTime = (GVAR(captureFrameNo) * GVAR(frameCaptureDelay)) + GVAR(startTime); if (_delta > (time - _lastFrameTime)) then { // marker was initially created in some frame(s) before - _captureFrameNo = ceil _lastFrameTime - (_delta / EGVAR(settings,frameCaptureDelay)); + _captureFrameNo = ceil _lastFrameTime - (_delta / GVAR(frameCaptureDelay)); private _logParams = (str [GVAR(captureFrameNo), time, _creationTime, _delta, _lastFrameTime, _captureFrameNo]); if (GVARMAIN(isDebug)) then { @@ -141,11 +145,6 @@ 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]); - if (GVARMAIN(isDebug)) then { - str ["CREATE:MARKER: Valid CREATED process of", _mrk_name, ", sending to extension -- ", _logParams select [0, 5]] remoteExec ["systemChat", [0, -2] select isDedicated]; - OCAPEXTLOG(ARR4("CREATE:MARKER: Valid CREATED process of", _mrk_name, ", sending to extension -- ", _logParams)); - }; - [":MARKER:CREATE:", [_mrk_name, _dir, _type, _text, _captureFrameNo, -1, _mrk_owner, _mrk_color, _size, _sideOfMarker, _pos, _shape, _alpha, _brush]] call EFUNC(extension,sendData); }; @@ -162,7 +161,7 @@ EGVAR(listener,markers) = [QGVARMAIN(handleMarker), { if (_mrk_name in GVAR(trackedMarkers)) then { if (GVARMAIN(isDebug)) then { - str ["MARKER:DELETE: Marker", _mrk_name, "deleted"] remoteExec ["systemChat", [0, -2] select isDedicated]; + format["MARKER:DELETE: Marker %1", _mrk_name] SYSCHAT; OCAPEXTLOG(ARR3("MARKER:DELETE: Marker", _mrk_name, "deleted")); }; @@ -268,7 +267,7 @@ EGVAR(listener,markers) = [QGVARMAIN(handleMarker), { // collect all initial markers & add event handlers to clients [ - {getClientState > 8 && !isNil QGVAR(startTime)}, + {getClientStateNumber > 8 && !isNil QGVAR(startTime)}, { { private _marker = _x; diff --git a/x/ocap2/addons/recorder/fnc_init.sqf b/x/ocap2/addons/recorder/fnc_init.sqf index 5e900f0..2771aae 100644 --- a/x/ocap2/addons/recorder/fnc_init.sqf +++ b/x/ocap2/addons/recorder/fnc_init.sqf @@ -25,12 +25,24 @@ Author: #include "script_component.hpp" +// exit if in 3DEN editor (when loaded in PreInit XEH +if (is3DEN) exitWith {}; +// if OCAP is disabled do nothing +if (!GVARMAIN(enabled)) exitWith {}; +// if recording has already initialized this session then just start recording, don't re-init +if (!isNil QGVAR(startTime)) exitWith {call FUNC(startRecording)}; + // bool: GVAR(recording) GVAR(recording) = false; +publicVariable QGVAR(recording); // int: GVAR(captureFrameNo) GVAR(captureFrameNo) = 0; -// bool: GVAR(shouldSave) -GVAR(shouldSave) = false; +publicVariable QGVAR(captureFrameNo); + +// save static setting values so changes during a mission don't interrupt timeline +GVAR(frameCaptureDelay) = EGVAR(settings,frameCaptureDelay); +GVAR(autoStart) = EGVAR(settings,autoStart); +GVAR(minMissionTime) = EGVAR(settings,minMissionTime); // macro: GVARMAIN(version)SION GVARMAIN(version) = QUOTE(VERSION_STR); @@ -84,15 +96,96 @@ if (GVAR(missionName) == "") then { GVAR(missionName) = briefingName; }; - - /* Conditional Start Recording We'll wait to see if auto-start is enabled and minPlayercount setting is met. This covers scenarios where someone changes the autostart setting during the mission as well, and excludes cases where autostart is disabled. - On execution, we'll also check if recording has already started by other means via whether GVAR(startTime) has been declared or not. If recording hasn't started already, we'll initialize it here assuming the above conditions are met. + The startRecording function checks internally if recording has already started by other means via whether GVAR(startTime) has been declared or not. */ [ - {((count allPlayers) >= EGVAR(settings,minPlayerCount) && EGVAR(settings,autoStart)) || !isNil QGVAR(startTime)}, - {call FUNC(startRecording)}, + {((count allPlayers) >= EGVAR(settings,minPlayerCount) && GVAR(autoStart)) || !isNil QGVAR(startTime)}, + {call FUNC(startRecording)} ] call CBA_fnc_waitUntilAndExecute; + +// When the server progresses past briefing and enters the mission, save an event to the timeline if recording +[{getClientStateNumber > 9}, { + if (!SHOULDSAVEEVENTS) exitWith {}; + [QGVARMAIN(customEvent), ["generalEvent", "Mission has started!"]] call CBA_fnc_serverEvent; +}] call CBA_fnc_waitUntilAndExecute; + + + +// PFH to track bullets +[{ + { + if (isNull (_x#0)) then { + _x params ["_obj", "_firerId", "_frame", "_pos"]; + [":FIRED:", [ + _firerId, + _frame, + _pos + ]] call EFUNC(extension,sendData); + + if (GVARMAIN(isDebug)) then { + OCAPEXTLOG(ARR4("FIRED EVENT: BULLET", _frame, _firerId, str _pos)); + }; + GVAR(liveBullets) = GVAR(liveBullets) - [_x]; + } else { + _x set [3, getPosASL (_x#0)]; + }; + } forEach GVAR(liveBullets); +}] call CBA_fnc_addPerFrameHandler; + +// PFH to track missiles, rockets, shells +[{ + { + _x params ["_obj", "_magazine", "_firer", "_pos", "_markName"]; + if (isNull (_x#0)) then { + + _firer setVariable [ + QGVARMAIN(lastFired), + getText(configFile >> "CfgMagazines" >> _magazine >> "displayName") + ]; + + if (GVARMAIN(isDebug)) then { + OCAPEXTLOG(ARR4("FIRED EVENT: SHELL-ROCKET-MISSILE", _frame, _firerId, str _pos)); + }; + + [{[QGVARMAIN(handleMarker), ["DELETED", _this]] call CBA_fnc_localEvent}, _markName, 10] call CBA_fnc_waitAndExecute; + GVAR(liveMissiles) = GVAR(liveMissiles) - [_x]; + + } else { + _nowPos = getPosASL (_x#0); + _x set [3, _nowPos]; + [QGVARMAIN(handleMarker), ["UPDATED", _markName, _firer, _nowPos, "", "", "", getDir (_x#0), "", "", 1]] call CBA_fnc_localEvent; + }; + } forEach GVAR(liveMissiles); +}, GVAR(frameCaptureDelay) * 0.3] call CBA_fnc_addPerFrameHandler; + +// PFH to track grenades, flares, thrown charges +[{ + { + _x params ["_obj", "_magazine", "_firer", "_pos", "_markName", "_ammoSimType"]; + if (isNull (_x#0)) then { + + if !(_ammoSimType in ["shotSmokeX", "shotIlluminating"]) then { + _firer setVariable [ + QGVARMAIN(lastFired), + getText(configFile >> "CfgMagazines" >> _magazine >> "displayName") + ]; + }; + + if (GVARMAIN(isDebug)) then { + OCAPEXTLOG(ARR4("FIRED EVENT: GRENADE-FLARE-SMOKE", _frame, _firerId, str _pos)); + }; + + [{[QGVARMAIN(handleMarker), ["DELETED", _this]] call CBA_fnc_localEvent}, _markName, 10] call CBA_fnc_waitAndExecute; + GVAR(liveGrenades) = GVAR(liveGrenades) - [_x]; + + } else { + _nowPos = getPosASL (_x#0); + _x set [3, _nowPos]; + [QGVARMAIN(handleMarker), ["UPDATED", _markName, _firer, _nowPos, "", "", "", getDir (_x#0), "", "", 1]] call CBA_fnc_localEvent; + }; + } forEach GVAR(liveGrenades); +}, GVAR(frameCaptureDelay)] call CBA_fnc_addPerFrameHandler; diff --git a/x/ocap2/addons/recorder/fnc_startRecording.sqf b/x/ocap2/addons/recorder/fnc_startRecording.sqf index 0f3a9cc..2922dff 100644 --- a/x/ocap2/addons/recorder/fnc_startRecording.sqf +++ b/x/ocap2/addons/recorder/fnc_startRecording.sqf @@ -9,17 +9,17 @@ if (!GVARMAIN(enabled)) exitWith {}; // if recording started earlier and startTime has been noted, only restart the capture loop with any updated settings. -if (!isNil QGVAR(startTime)) then { - if (GVAR(recording)) exitWith { - OCAPEXTLOG(["OCAP2 was asked to record and is already recording!"]); - }; - if (!GVAR(recording)) exitWith { - call FUNC(captureLoop); - }; +if (!isNil QGVAR(startTime) && GVAR(recording)) exitWith { + OCAPEXTLOG(["OCAP2 was asked to record and is already recording!"]); +}; +if (!isNil QGVAR(startTime) && !GVAR(recording)) exitWith { + call FUNC(captureLoop); }; -[":START:", [worldName, GVAR(missionName), getMissionConfigValue ["author", ""], EGVAR(settings,frameCaptureDelay)]] call EFUNC(extension,sendData); +// Notify the extension +[":START:", [worldName, GVAR(missionName), getMissionConfigValue ["author", ""], GVAR(frameCaptureDelay)]] call EFUNC(extension,sendData); [":SET:VERSION:", [GVARMAIN(version)]] call EFUNC(extension,sendData); + // Add mission event handlers call FUNC(addEventMission); // Track initial times