From 58a55313cdc89fb481d9146995312ffa7bb5fd11 Mon Sep 17 00:00:00 2001 From: jaynus Date: Wed, 13 May 2015 17:06:10 -0700 Subject: [PATCH] Changed: Entire frag system re-optimized to a single tracking/GC index-based PFH. Changed: Spalling calculations now throttled across frames and limited; accurate but performant Changed: All lookups are now index-based on a global projectiles array. This reduced runtime dramatically for all fragmentation. --- addons/frag/ACE_Settings.hpp | 24 ++++++++++-- addons/frag/CfgAmmo.hpp | 4 +- addons/frag/CfgAmmoReflections.hpp | 1 - addons/frag/XEH_postInit.sqf | 5 +++ addons/frag/XEH_preInit.sqf | 3 +- addons/frag/functions/fnc_addPfhRound.sqf | 32 ++++++++------- addons/frag/functions/fnc_doSpall.sqf | 4 -- addons/frag/functions/fnc_frago.sqf | 11 ++---- addons/frag/functions/fnc_masterPFH.sqf | 36 +++++++++++------ addons/frag/functions/fnc_pfhRound.sqf | 48 ++++++++++++----------- addons/frag/functions/fnc_spallTrack.sqf | 2 +- addons/frag/stringtable.xml | 22 +++++++++-- 12 files changed, 120 insertions(+), 72 deletions(-) diff --git a/addons/frag/ACE_Settings.hpp b/addons/frag/ACE_Settings.hpp index 6a782de2f9..bbf0398cfb 100644 --- a/addons/frag/ACE_Settings.hpp +++ b/addons/frag/ACE_Settings.hpp @@ -1,15 +1,33 @@ class ACE_Settings { - class GVAR(enabled) { + class GVAR(Enabled) { displayName = "$STR_ACE_frag_EnableFrag"; description = "$STR_ACE_frag_EnableFrag_Desc"; typeName = "BOOL"; value = 1; }; - - class GVAR(spallEnabled) { + class GVAR(SpallEnabled) { displayName = "$STR_ACE_frag_EnableSpall"; description = "$STR_ACE_frag_EnableSpall_Desc"; typeName = "BOOL"; value = 1; }; + class GVAR(maxTrack) { + displayName = "$STR_ACE_frag_MaxTrack"; + description = "$STR_ACE_frag_MaxTrack_Desc"; + typeName = "SCALAR"; + value = 500; + }; + class GVAR(MaxTrackPerFrame) { + displayName = "$STR_ACE_frag_MaxTrackPerFrame"; + description = "$STR_ACE_frag_MaxTrackPerFrame_Desc"; + typeName = "SCALAR"; + value = 50; + }; + + class GVAR(EnableDebugTrace) { + displayName = "$STR_ACE_frag_EnableDebugTrace"; + description = "$STR_ACE_frag_EnableDebugTrace_Desc"; + typeName = "BOOL"; + value = 0; + }; }; diff --git a/addons/frag/CfgAmmo.hpp b/addons/frag/CfgAmmo.hpp index 7f4c4b38b3..41734d2806 100644 --- a/addons/frag/CfgAmmo.hpp +++ b/addons/frag/CfgAmmo.hpp @@ -9,8 +9,6 @@ class CfgAmmo { // GVAR(skip) = 1; //}; - #include "CfgAmmoReflections.hpp" - class Bo_GBU12_LGB; class ACE_GBU12 : Bo_GBU12_LGB { GVAR(enabled) = 1; @@ -473,4 +471,6 @@ class CfgAmmo { class ACE_frag_spall_huge: ACE_frag_huge { timeToLive = 0.3; }; + + #include "CfgAmmoReflections.hpp" }; diff --git a/addons/frag/CfgAmmoReflections.hpp b/addons/frag/CfgAmmoReflections.hpp index 8e481a9cd0..f59d67f89a 100644 --- a/addons/frag/CfgAmmoReflections.hpp +++ b/addons/frag/CfgAmmoReflections.hpp @@ -1,7 +1,6 @@ //CfgAmmoReflections.hpp #define ACE_EXPLOSION_REFLECTION(range, hit) class ace_explosion_reflection_##range##_##hit : ace_explosion_reflection_base { indirectHitRange = range; indirectHit = hit; dangerRadiusHit = range*3; suppressionRadiusHit = range*2; }; -class Sh_120mm_HE; class ace_explosion_reflection_base : Sh_120mm_HE { CraterWaterEffects = ""; CraterEffects = ""; diff --git a/addons/frag/XEH_postInit.sqf b/addons/frag/XEH_postInit.sqf index 0c6a1845b6..95c921df64 100644 --- a/addons/frag/XEH_postInit.sqf +++ b/addons/frag/XEH_postInit.sqf @@ -1,5 +1,10 @@ #include "script_component.hpp" +if(GVAR(EnableDebugTrace) && !isMultiplayer) then { + GVAR(traceFrags) = true; + GVAR(autoTrace) = true; +}; + if(isServer) then { [QGVAR(frag_eh), { _this call FUNC(frago); }] call ace_common_fnc_addEventHandler; }; diff --git a/addons/frag/XEH_preInit.sqf b/addons/frag/XEH_preInit.sqf index a2d1e38c1b..cdd9342ffd 100644 --- a/addons/frag/XEH_preInit.sqf +++ b/addons/frag/XEH_preInit.sqf @@ -15,7 +15,7 @@ GVAR(TOTALFRAGS) = 0; GVAR(spallHPData) = []; GVAR(spallIsTrackingCount) = 0; -GVAR(autoTrace) = true; +GVAR(autoTrace) = false; GVAR(traceID) = -1; GVAR(traces) = []; GVAR(tracesStarted) = false; @@ -43,6 +43,7 @@ PREP(doExplosions); PREP(doReflections); +GVAR(lastIterationIndex) = 0; GVAR(objects) = []; GVAR(objectTypes) = []; GVAR(arguments) = []; diff --git a/addons/frag/functions/fnc_addPfhRound.sqf b/addons/frag/functions/fnc_addPfhRound.sqf index 81454edf97..7530b8f062 100644 --- a/addons/frag/functions/fnc_addPfhRound.sqf +++ b/addons/frag/functions/fnc_addPfhRound.sqf @@ -1,20 +1,21 @@ +//#define DEBUG_MODE_FULL #include "script_component.hpp" -private ["_enabled", "_gun", "_type", "_round", "_doFragTrack", "_doSpall", "_spallTrack", "_spallTrackID"]; +private ["_enabled","_doFragTrack", "_doSpall", "_spallTrack", "_spallTrackID"]; +PARAMS_3(_gun,_type,_round); if (!GVAR(enabled)) exitWith {}; -_gun = _this select 0; -_type = _this select 1; -_round = _this select 2; - -_enabled = getNumber (configFile >> "CfgAmmo" >> _type >> QGVAR(enabled)); -if(_enabled < 1) exitWith {}; +//_enabled = getNumber (configFile >> "CfgAmmo" >> _type >> QGVAR(enabled)); +//if(_enabled < 1) exitWith {}; if(_round in GVAR(blackList)) exitWith { GVAR(blackList) = GVAR(blackList) - [_round]; }; +// Exit on max track +if( (count GVAR(objects)) > GVAR(MaxTrack)) exitWith { }; + _doFragTrack = false; if(_gun == ACE_player) then { _doFragTrack = true; @@ -27,7 +28,7 @@ if(_gun == ACE_player) then { }; }; }; -if(GVAR(spallEnabled)) then { +if(GVAR(SpallEnabled)) then { if(GVAR(spallIsTrackingCount) <= 0) then { GVAR(spallHPData) = []; }; @@ -40,12 +41,15 @@ if(GVAR(spallEnabled)) then { }; // ACE_player sideChat format["c: %1", GVAR(spallIsTrackingCount)]; -#ifdef DEBUG_MODE_FULL -[ACE_player, _round, [1,0,0,1]] call FUNC(addTrack); -#endif +if(GVAR(autoTrace)) then { + [ACE_player, _round, [1,0,0,1]] call FUNC(addTrack); +}; // We only do the single track object check here. -if(_doFragTrack && alive _round && {!(_round in GVAR(objects))} ) then { +// We should do an {!(_round in GVAR(objects))} +// But we leave that out here for optimization. So this cannot be a framework function +// Otherwise, it should only be added once and from the FiredEH +if(_doFragTrack && alive _round) then { _spallTrack = []; _spallTrackID = []; @@ -57,12 +61,12 @@ if(_doFragTrack && alive _round && {!(_round in GVAR(objects))} ) then { (getNumber (configFile >> "CfgAmmo" >> _type >> QGVAR(force))), (getNumber(configFile >> "CfgAmmo" >> _type >> "indirecthit")*(sqrt((getNumber (configFile >> "CfgAmmo" >> _type >> "indirectHitRange"))))) ]; - + TRACE_1("Initializing track", _round); GVAR(objects) pushBack _round; GVAR(arguments) pushBack _args; if(_doSpall) then { - [_round, 2, _spallTrack, _spallTrackID] call FUNC(spallTrack); + [_round, 1, _spallTrack, _spallTrackID] call FUNC(spallTrack); }; // ACE_player sideChat "WTF2"; }; diff --git a/addons/frag/functions/fnc_doSpall.sqf b/addons/frag/functions/fnc_doSpall.sqf index 717b629e53..1e8e87bcb3 100644 --- a/addons/frag/functions/fnc_doSpall.sqf +++ b/addons/frag/functions/fnc_doSpall.sqf @@ -1,14 +1,10 @@ //fnc_doSpall.sqf #include "script_component.hpp" -#ifdef DEBUG_MODE_FULL - GVAR(traceFrags) = true; -#endif // ACE_player sideChat "WAAAAAAAAAAAAAAAAAAAAA"; private ["_params", "_hitData", "_initialData", "_hpData", "_object", "_foundObjects", "_index", "_foundObjecsts", "_roundType", "_round", "_caliber", "_explosive", "_idh", "_alive", "_exit", "_vm", "_velocity", "_oldVelocity", "_curVelocity", "_diff", "_polar", "_unitDir", "_spallPos", "_pos1", "_i", "_pos2", "_blah", "_data", "_spallPolar", "_warn", "_c", "_m", "_k", "_gC", "_fragPower", "_fragTypes", "_spread", "_spallCount", "_elev", "_dir", "_vel", "_spallFragVect", "_fragType", "_fragment", "_pos"]; _params = _this select 0; -[(_this select 1)] call cba_fnc_removePerFrameHandler; _hitData = _params select 0; _initialData = GVAR(spallHPData) select (_hitData select 0); _hpData = (_hitData select 1) select (_params select 1); diff --git a/addons/frag/functions/fnc_frago.sqf b/addons/frag/functions/fnc_frago.sqf index 415b75e790..5b5cf89bbe 100644 --- a/addons/frag/functions/fnc_frago.sqf +++ b/addons/frag/functions/fnc_frago.sqf @@ -163,11 +163,8 @@ if(_isArmed && (count _objects) > 0) then { _fragObj setPosASL _lastPos; _fragObj setVectorDir _vec; _fragObj setVelocity _vel; - #ifdef DEBUG_MODE_FULL - GVAR(TOTALFRAGS) = GVAR(TOTALFRAGS) + 1; - GVAR(traceFrags) = true; - #endif if(GVAR(traceFrags)) then { + GVAR(TOTALFRAGS) = GVAR(TOTALFRAGS) + 1; [ACE_player, _fragObj, [1,0,0,1]] call FUNC(addTrack); }; _fragCount = _fragCount + 1; @@ -200,11 +197,9 @@ if(_isArmed && (count _objects) > 0) then { _fragObj setPosASL _lastPos; _fragObj setVectorDir _vec; _fragObj setVelocity _vel; - #ifdef DEBUG_MODE_FULL - GVAR(TOTALFRAGS) = GVAR(TOTALFRAGS) + 1; - GVAR(traceFrags) = true; - #endif + if(GVAR(traceFrags)) then { + GVAR(TOTALFRAGS) = GVAR(TOTALFRAGS) + 1; [ACE_player, _fragObj, [1,0.5,0,1]] call FUNC(addTrack); }; _fragCount = _fragCount + 1; diff --git a/addons/frag/functions/fnc_masterPFH.sqf b/addons/frag/functions/fnc_masterPFH.sqf index d511325e15..4e81c4c609 100644 --- a/addons/frag/functions/fnc_masterPFH.sqf +++ b/addons/frag/functions/fnc_masterPFH.sqf @@ -9,36 +9,48 @@ * Return Value: * None */ +//#define DEBUG_MODE_FULL #include "script_component.hpp" -PARAMS_2(_pfhArgs,_handle); +//PARAMS_2(_pfhArgs,_handle); if (!GVAR(enabled)) exitWith {}; private["_gcIndex"]; _gcIndex = []; -{ + +_iter = 0; +while { (count GVAR(objects)) > 0 && { _iter < GVAR(MaxTrackPerFrame) } } do { private["_object", "_args"]; - _object = _x; + if(GVAR(lastIterationIndex) >= (count GVAR(objects))) then { + GVAR(lastIterationIndex) = 0; + }; + _object = GVAR(objects) select GVAR(lastIterationIndex); + if(!isNil "_object") then { if(isNull _object) then { - _gcIndex pushBack _forEachIndex; + _gcIndex pushBack GVAR(lastIterationIndex); } else { - _args = GVAR(arguments) select _forEachIndex; + _args = GVAR(arguments) select GVAR(lastIterationIndex); - _args call FUNC(pfhRound); - }; - - if(!alive _object) then { - _gcIndex pushBack _forEachIndex; + if(!(_args call FUNC(pfhRound))) then { + _gcIndex pushBack GVAR(lastIterationIndex); // Add it to the GC if it returns false + }; + // If its not alive anymore, remove it from the queue, it already ran once on dead + if(!alive _object) then { + _gcIndex pushBack GVAR(lastIterationIndex); + }; }; }; -} forEach GVAR(objects); + _iter = _iter + 1; + GVAR(lastIterationIndex) = GVAR(lastIterationIndex) + 1; +}; // clean up dead object references private["_deletionCount", "_deleteIndex"]; _deletionCount = 0; { - _deleteIndex = _gcIndex - _deletionCount; + TRACE_1("GC Projectile", _x); + _deleteIndex = _x - _deletionCount; GVAR(objects) deleteAt _deleteIndex; GVAR(arguments) deleteAt _deleteIndex; diff --git a/addons/frag/functions/fnc_pfhRound.sqf b/addons/frag/functions/fnc_pfhRound.sqf index df6f618ac5..8cc9457842 100644 --- a/addons/frag/functions/fnc_pfhRound.sqf +++ b/addons/frag/functions/fnc_pfhRound.sqf @@ -1,25 +1,28 @@ #include "script_component.hpp" -private ["_params", "_round", "_lastPos", "_lastVel", "_type", "_time", "_doSpall", "_spallTrack", "_foundObjectHPIds", "_skip", "_explosive", "_indirectRange", "_force", "_fragPower"]; -_params = _this select 0; -_round = _params select 0; -_lastPos = _params select 1; -_lastVel = _params select 2; -_type = _params select 3; -_time = _params select 4; -_doSpall = _params select 6; -_spallTrack = _params select 7; -_foundObjectHPIds = _params select 8; -_skip = _params select 9; -_explosive = _params select 10; -_indirectRange = _params select 11; -_force = _params select 12; -_fragPower = _params select 13; +private ["_round", "_lastPos", "_lastVel", "_type", "_time", "_doSpall", "_spallTrack", "_foundObjectHPIds", "_skip", "_explosive", "_indirectRange", "_force", "_fragPower"]; +_round = _this select 0; +_lastPos = _this select 1; +_lastVel = _this select 2; +_type = _this select 3; +_time = _this select 4; +_doSpall = _this select 6; +_spallTrack = _this select 7; +_foundObjectHPIds = _this select 8; +_skip = _this select 9; +_explosive = _this select 10; +_indirectRange = _this select 11; +_force = _this select 12; +_fragPower = _this select 13; + +if(_round in GVAR(blackList)) exitWith { + false +}; if (!alive _round) then { - if(_time != time && {!(_round in GVAR(blackList))}) then { + if(_time != time) then { if(_skip == 0) then { if((_explosive > 0.5 && {_indirectRange >= 4.5} && {_fragPower >= 35}) || {_force == 1} ) then { - [QGVAR(frag_eh), _params] call ace_common_fnc_serverEvent; + [QGVAR(frag_eh), _this] call ace_common_fnc_serverEvent; }; }; }; @@ -33,13 +36,14 @@ if (!alive _round) then { } forEach _spallTrack; }; } else { - if(_round in GVAR(blackList)) exitWith { - [_round] call FUNC(removePfhRound); - }; - + _params set[1, (getPosASL _round)]; _params set[2, (velocity _round)]; if(_doSpall) then { - [_round, 1, _spallTrack, _foundObjectHPIds] call FUNC(spallTrack); + private["_scale"]; + _scale = ( (count GVAR(objects)) / GVAR(MaxTrackPerFrame) ) max 0.1; + [_round, _scale, _spallTrack, _foundObjectHPIds] call FUNC(spallTrack); }; }; + +true \ No newline at end of file diff --git a/addons/frag/functions/fnc_spallTrack.sqf b/addons/frag/functions/fnc_spallTrack.sqf index 4b7a06bc65..afe4bc1931 100644 --- a/addons/frag/functions/fnc_spallTrack.sqf +++ b/addons/frag/functions/fnc_spallTrack.sqf @@ -22,7 +22,7 @@ if (count _intersectsWith > 0) then { if(!(_x in _foundObjects)) then { // diag_log text format["Adding HP: %1", _x]; _index = (count GVAR(spallHPData)); - _hpId = _x addEventHandler ["hitPart", format["[%1, _this] call " + QUOTE(FUNC(spallHP)), _index]]; + _hpId = _x addEventHandler ["hitPart", compile format["[%1, _this] call " + QUOTE(FUNC(spallHP)), _index]]; _foundObjects set[(count _foundObjects), _x]; _foundObjectHPIds set[(count _foundObjectHPIds), _hpId]; _data = [_hpId, _x, typeOf _round, _round, _curPos, _velocity, 0, _foundObjects, _foundObjectHPIds]; diff --git a/addons/frag/stringtable.xml b/addons/frag/stringtable.xml index e267685869..5b49b0e192 100644 --- a/addons/frag/stringtable.xml +++ b/addons/frag/stringtable.xml @@ -3,19 +3,33 @@ Fragmentation Simulation - Enable the ACE Fragmentation Simulation - Spalling Simulation - Enable the ACE Spalling Simulation - + + + Maximum Projectiles Tracked + + + This setting controls the maximum amount of projectiles the fragmentation & spalling system will track at any given time. If more projectiles are fired, they will not be tracked. Lower this setting if you do not want FPS drops at high-count projectile scenarios ( >200 rounds in the air at once) + + + Maximum Projectiles Per Frame + + + The number of spall track calculations to perform in any given frame. This helps spread the FPS impact of tracking spall rounds across multiple frames, limiting its impact even further. + + + (SP Only) Frag/Spall Debug Tracing + + + (SP Only) Requires a mission/editor restart. Enables visual tracing of fragmentation and spalling rounds in SP game mode only.