-
Notifications
You must be signed in to change notification settings - Fork 762
CSW - Fix AI reload edge cases, code cleanup #11450
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
794f2ac
d391de8
d0ee727
cddf9fd
c5ba0b9
5473bc6
e6931bf
7d24c86
e93fc73
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| #include "..\script_component.hpp" | ||
| /* | ||
| * Author: LinkIsGrim | ||
| * Gets all carry magazines that can be loaded into a CSW, includes weapons added by script. | ||
| * | ||
| * Arguments: | ||
| * 0: CSW <OBJECT> | ||
| * | ||
| * Return Value: | ||
| * Compatible Carry Magazines <HASHMAP> | ||
| * Magazine classname <STRING> | ||
| * true <BOOL> | ||
| * | ||
| * Example: | ||
| * [cursorObject] call ace_csw_fnc_compatibleMagazines | ||
| * | ||
| * Public: Yes | ||
| */ | ||
|
|
||
| params [["_csw", objNull, [objNull]]]; | ||
|
|
||
| // Read from config rather than GVAR(initializedStaticTypes), which is only filled where there is an | ||
| // interface and so is always empty on a dedicated server | ||
| if ((getNumber (configOf _csw >> QUOTE(ADDON) >> "enabled")) != 1) exitWith {createHashMap}; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this blocks all loading on non-enabled static weapons before you could unload and load them when empty |
||
|
|
||
| // Caches are filled here rather than on weapon swap, a CSW without a proxy weapon needs them too | ||
| private _fnc_cacheWeapon = { | ||
| private _weapon = _this; | ||
|
|
||
| GVAR(compatibleCarryMagsCache) getOrDefaultCall [_weapon, { | ||
| // Engine command, not this function | ||
| private _vehicleMags = compatibleMagazines _weapon; | ||
| GVAR(compatibleVehicleMagsCache) set [_weapon, _vehicleMags]; | ||
|
|
||
| // Vehicle magazines without a carry equivalent come back as "", they can't be loaded by hand | ||
| private _carryMags = (_vehicleMags apply {_x call FUNC(getCarryMagazine)}) select {_x != ""}; | ||
|
|
||
| _carryMags createHashMapFromArray (_carryMags apply {true}) | ||
| }, true] | ||
| }; | ||
|
|
||
| private _weapons = []; | ||
| { | ||
| private _turret = _x; | ||
| { | ||
| _weapons pushBackUnique _x; | ||
| } forEach (_csw weaponsTurret _turret); | ||
| } forEach (allTurrets _csw); | ||
|
|
||
| if (_weapons isEqualTo []) exitWith {createHashMap}; | ||
|
|
||
| // Copies, so callers can't edit the cache. Single weapon is by far the most common CSW, skip the merge | ||
| if (count _weapons isEqualTo 1) exitWith {+((_weapons select 0) call _fnc_cacheWeapon)}; | ||
|
|
||
| private _carryMagazines = createHashMap; | ||
| { | ||
| _carryMagazines merge [_x call _fnc_cacheWeapon, true]; | ||
| } forEach _weapons; | ||
|
|
||
| _carryMagazines // return | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,14 +15,16 @@ | |
| * Public: No | ||
| */ | ||
|
|
||
| params ["_vehicleMag"]; | ||
| params [["_vehicleMag", "", [""]]]; | ||
|
|
||
| private _carryMag = GVAR(vehicleMagCache) get _vehicleMag; | ||
| if (isNil "_carryMag") then { | ||
| if (_vehicleMag == "") exitWith {""}; | ||
|
|
||
| // Config lookups are case-insensitive but hashmap keys are not, so normalise before caching. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, but as far as I can tell, all instances of |
||
| // A magazine with no carry equivalent caches "" on purpose, so the miss costs nothing to look up again | ||
| GVAR(vehicleMagCache) getOrDefaultCall [toLowerANSI _vehicleMag, { | ||
| private _groups = "getNumber (_x >> _vehicleMag) == 1 && {isClass (configFile >> 'CfgMagazines' >> configName _x)}" configClasses (configFile >> QGVAR(groups)); | ||
| _carryMag = configName (_groups param [0, configNull]); | ||
| GVAR(vehicleMagCache) set [_vehicleMag, _carryMag]; | ||
| private _carryMag = configName (_groups param [0, configNull]); | ||
| TRACE_2("setting cache",_vehicleMag,_carryMag); | ||
| }; | ||
|
|
||
| _carryMag | ||
| _carryMag | ||
| }, true] // return | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| #include "..\script_component.hpp" | ||
| /* | ||
| * Author: LinkIsGrim | ||
| * Gets available ammo sources for loading a CSW. Units are replaced by their containers, since | ||
| * magazineCargo does not read a unit's inventory. | ||
| * | ||
| * Arguments: | ||
| * 0: Unit or vehicle attempting to load <OBJECT> | ||
| * 1: Skip vehicle sources <BOOL> (default: false) | ||
| * 2: Include crew of the source <BOOL> (default: false) | ||
| * | ||
| * Return Value: | ||
| * Ammo sources <ARRAY of OBJECT> | ||
| * | ||
| * Example: | ||
| * [player] call ace_csw_fnc_getNearbySources | ||
| * | ||
| * Public: No | ||
| */ | ||
|
|
||
| params ["_unit", ["_skipVehicles", false], ["_includeCrew", false]]; | ||
|
|
||
| // Normalised so an omitted default and an explicit one hit the same cache entry | ||
| private _params = [_unit, _skipVehicles, _includeCrew]; | ||
|
|
||
| [ | ||
| _params, | ||
| { | ||
| params ["_unit", "_skipVehicles", "_includeCrew"]; | ||
|
|
||
| // group is grpNull on a vehicle, so a CSW passed straight in has to be asked directly | ||
| private _side = if (_unit isKindOf "CAManBase") then {side group _unit} else {side _unit}; | ||
|
|
||
| // group is also grpNull on crates and weapon holders, which is what lets them through | ||
| private _nearSupplies = (_unit nearSupplies DISTANCE_SEARCH_RADIUS) select { | ||
| isNull (group _x) || | ||
| {!([_x] call EFUNC(common,isPlayer)) && {[_side, side group _x] call BIS_fnc_sideIsFriendly}} | ||
| }; | ||
|
|
||
| if (_includeCrew) then { | ||
| _nearSupplies append (crew _unit); | ||
| }; | ||
|
|
||
| if (_skipVehicles) then { | ||
| _nearSupplies = _nearSupplies select { | ||
| private _source = _x; | ||
| (["Ship", "Car", "Air", "Tank"] findIf {_source isKindOf _x}) == -1 | ||
| }; | ||
| }; | ||
|
|
||
| _nearSupplies pushBackUnique _unit; | ||
|
|
||
| // Built into a second array rather than appended in place, forEach over an array that is | ||
| // growing underneath it has no defined behaviour | ||
| private _sources = []; | ||
| { | ||
| // magazineCargo does not read a unit's inventory, only their containers do | ||
| if (_x isKindOf "CAManBase") then { | ||
| { | ||
| _sources pushBackUnique _x; | ||
| } forEach [uniformContainer _x, vestContainer _x, backpackContainer _x]; | ||
| continue; | ||
| }; | ||
|
|
||
| _sources pushBackUnique _x; | ||
|
|
||
| { | ||
| _x params ["", "_container"]; | ||
| _sources pushBackUnique _container; | ||
| } forEach (everyContainer _x); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't handle recursive containers - tbf, I don't know how necessary that is though.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. gotta stop the rabbit hole somewhere IMO besides being able to load from a vehicle is believe being able to load from a backpack inside one, ehhhhh |
||
| } forEach _nearSupplies; | ||
|
|
||
| // A unit with no vest or backpack gives objNull back | ||
| _sources select {!isNull _x} // return | ||
| }, | ||
| _unit, | ||
| // The uid has to cover every argument, cachedCall hands it to setVariable so it must be a string | ||
| format [QGVAR(nearbySourcesCache_%1), hashValue _params], | ||
| NEARBY_SOURCES_CACHE_EXPIRY, | ||
| QGVAR(clearNearbySourcesCache) | ||
| ] call EFUNC(common,cachedCall) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This uses cached stuff if I've understood correctly. If the best source were to be deleted before the cache expires (5 seconds), line 44 would fail, yet the weapon would be reloaded - right? Or am I missing something?