Skip to content
Open
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
26 changes: 26 additions & 0 deletions addons/recorder/XEH_preInit.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,33 @@ GVAR(allSettings) = [
false // requires restart to apply
],

/*
CBA Setting: OCAP_settings_excludeVarNameFromRecord
Description:
Array of vehicle variable names (vehicleVarName) that should be excluded from recording. Use single quotes! Default: []

Setting Name:
Variable Names to Exclude

Value Type:
Stringified Array

Example:
> "['hideout_1','cache_west']"
*/
[
QEGVAR(settings,excludeVarNameFromRecord),
"EDITBOX", // setting type
[
"Variable Names to Exclude", // Pretty name shown inside the ingame settings menu. Can be stringtable entry.
"Array of vehicle variable names (vehicleVarName) to exclude from recording. Use single quotes! Default: []"
],
[COMPONENT_NAME, "Exclusions"], // 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
],


// Section: Extra Tracking
Expand Down
22 changes: 19 additions & 3 deletions addons/recorder/fnc_captureLoop.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,16 @@ GVAR(PFHObject) = [
{
private _justInitialized = false;
if !(_x getVariable [QGVARMAIN(isInitialized), false]) then {
if (
_x isKindOf "Logic"
) exitWith {
if (_x isKindOf "Logic") exitWith {
_x setVariable [QGVARMAIN(exclude), true, true];
_x setVariable [QGVARMAIN(isInitialized), true, true];
};
// Check pre-set OCAP_main_exclude variable for per-object exclusion via editor init field
if (_x getVariable [QGVARMAIN(exclude), false]) exitWith {
_x setVariable [QGVARMAIN(isInitialized), true, true];
};
Comment on lines +97 to +99

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Exiting early here for excluded units without sending the :SOLDIER:CREATE: event introduces a critical bug when players are involved.

OCAP's design forces player units to always be tracked (lines 135-139 un-exclude any unit where isPlayer _x is true). If a player unit (or a playable AI unit that a player slots into later) is excluded at initialization, it will be marked as isInitialized = true but :SOLDIER:CREATE: will never be sent. When the player is un-excluded, OCAP will start sending :SOLDIER:STATE: updates for an ID that was never created, leading to database errors or broken AAR playbacks.

To fix this:

  1. Ensure player units are never excluded during initialization by adding !isPlayer _x to the exclusion checks.
  2. For playable AI units that players slot into later, reset isInitialized to false when they are un-excluded so they can be properly initialized on the next frame.

Since lines 135-139 are outside this diff hunk, you should update them manually as follows:

private _isExcluded = _x getVariable [QGVARMAIN(exclude), false];
if (_isExcluded && {isPlayer _x}) then {
  _x setVariable [QGVARMAIN(exclude), false];
  _x setVariable [QGVARMAIN(isInitialized), false, true];
  _isExcluded = true; // Keep it excluded for this frame until initialized on the next frame
};
        if (!isPlayer _x && {_x getVariable [QGVARMAIN(exclude), false]}) exitWith {
          _x setVariable [QGVARMAIN(isInitialized), true, true];
        };

// Check vehicleVarName against centralized exclude list
if (GVAR(excludeVarNameList) isNotEqualTo [] && {vehicleVarName _x in GVAR(excludeVarNameList)}) exitWith {
_x setVariable [QGVARMAIN(exclude), true, true];
_x setVariable [QGVARMAIN(isInitialized), true, true];
};
Comment on lines +101 to 104

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If vehicleVarName _x returns "" (which is the case for almost all objects without an editor-assigned variable name), and GVAR(excludeVarNameList) contains an empty string "" (due to a user typo or empty setting element), then every single unit without a variable name will be excluded from the recording.

Additionally, calling in on an array for every unit initialization when the variable name is empty is an unnecessary performance cost.

We should check _varName isNotEqualTo "" first, and also ensure !isPlayer _x is checked to prevent player exclusion.

        private _varName = vehicleVarName _x;
        if (!isPlayer _x && {_varName isNotEqualTo "" && {GVAR(excludeVarNameList) isNotEqualTo [] && {_varName in GVAR(excludeVarNameList)}}}) exitWith {
          _x setVariable [QGVARMAIN(exclude), true, true];
          _x setVariable [QGVARMAIN(isInitialized), true, true];
        };

Expand Down Expand Up @@ -204,6 +211,15 @@ GVAR(PFHObject) = [
{
private _justInitialized = false;
if !(_x getVariable [QGVARMAIN(isInitialized), false]) then {
// Check pre-set OCAP_main_exclude variable for per-object exclusion via editor init field
if (_x getVariable [QGVARMAIN(exclude), false]) exitWith {
_x setVariable [QGVARMAIN(isInitialized), true, true];
};
// Check vehicleVarName against centralized exclude list
if (GVAR(excludeVarNameList) isNotEqualTo [] && {vehicleVarName _x in GVAR(excludeVarNameList)}) exitWith {
_x setVariable [QGVARMAIN(exclude), true, true];
_x setVariable [QGVARMAIN(isInitialized), true, true];
};
Comment on lines +219 to +222

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Similar to the unit loop, if vehicleVarName _x is "" and GVAR(excludeVarNameList) contains "", all vehicles without a variable name will be excluded.

Checking _varName isNotEqualTo "" first prevents this risk and avoids unnecessary array lookups.

        private _varName = vehicleVarName _x;
        if (_varName isNotEqualTo "" && {GVAR(excludeVarNameList) isNotEqualTo [] && {_varName in GVAR(excludeVarNameList)}}) exitWith {
          _x setVariable [QGVARMAIN(exclude), true, true];
          _x setVariable [QGVARMAIN(isInitialized), true, true];
        };

_vehType = typeOf _x;
_class = _vehType call FUNC(getClass);
private _vic = _x;
Expand Down
6 changes: 6 additions & 0 deletions addons/recorder/fnc_init.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@ GVAR(excludeMarkerList) = if (!isNil QEGVAR(settings,excludeMarkerFromRecord)) t
[]
};

GVAR(excludeVarNameList) = if (!isNil QEGVAR(settings,excludeVarNameFromRecord)) then {
parseSimpleArray EGVAR(settings,excludeVarNameFromRecord)
} else {
[]
};

INFO_4("Settings snapshot — frameCaptureDelay: %1 | autoStart: %2 | minPlayerCount: %3 | minMissionTime: %4",GVAR(frameCaptureDelay),GVAR(autoStart),EGVAR(settings,minPlayerCount),GVAR(minMissionTime));

GVAR(hasACEIsAwake) = !isNil "ace_common_fnc_isAwake";
Expand Down