Arsenal - Improved sorting, insignia detection, identity info verification and minor cleanup (#9795)

* Changed sorting + minor cleanup

* Update addons/arsenal/functions/fnc_fillLeftPanel.sqf

Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com>

* check and log missing extended info

* fix extended loadout logging

* Made voice stuff config case

* use lowercase voice everywhere

* check loadout voice against configCase

* Update fnc_verifyLoadout.sqf

* Update addons/arsenal/functions/fnc_verifyLoadout.sqf

Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com>

* Update addons/arsenal/functions/fnc_verifyLoadout.sqf

Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com>

* Update addons/arsenal/functions/fnc_verifyLoadout.sqf

---------

Co-authored-by: LinkIsGrim <salluci.lovi@gmail.com>
Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com>
This commit is contained in:
johnb432 2024-02-13 20:22:27 +01:00 committed by GitHub
parent a0f3933bf0
commit fd5e56ffbc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 102 additions and 73 deletions

View File

@ -108,24 +108,16 @@ GVAR(lastSortDirectionRight) = DESCENDING;
private _face = _extendedInfo getOrDefault [QGVAR(face), ""];
if (_face != "") then {
if (isMultiplayer) then {
private _id = [QGVAR(broadcastFace), [_unit, _face], QGVAR(centerFace_) + netId _unit] call CBA_fnc_globalEventJIP;
[_id, _unit] call CBA_fnc_removeGlobalEventJIP;
} else {
_unit setFace _face;
};
private _id = [QGVAR(broadcastFace), [_unit, _face], QGVAR(centerFace_) + hashValue _unit] call CBA_fnc_globalEventJIP;
[_id, _unit] call CBA_fnc_removeGlobalEventJIP;
};
// Set voice
private _voice = _extendedInfo getOrDefault [QGVAR(voice), ""];
if (_voice != "") then {
if (isMultiplayer) then {
private _id = [QGVAR(broadcastVoice), [_unit, _voice], QGVAR(centerVoice_) + netId _unit] call CBA_fnc_globalEventJIP;
[_id, _unit] call CBA_fnc_removeGlobalEventJIP;
} else {
_unit setSpeaker _voice;
};
private _id = [QGVAR(broadcastVoice), [_unit, _voice], QGVAR(centerVoice_) + hashValue _unit] call CBA_fnc_globalEventJIP;
[_id, _unit] call CBA_fnc_removeGlobalEventJIP;
};
// Set insignia
@ -147,7 +139,7 @@ GVAR(lastSortDirectionRight) = DESCENDING;
// Set voice if enabled
if (GVAR(loadoutsSaveVoice)) then {
_extendedInfo set [QGVAR(voice), speaker _unit];
_extendedInfo set [QGVAR(voice), (speaker _unit) call EFUNC(common,getConfigName)];
};
// Set insignia if enabled

View File

@ -91,5 +91,4 @@ private _insigniaCondition = toString {
GVAR(insigniaCache) set [_x, 2];
} forEach (_insigniaCondition configClasses (missionConfigFile >> "CfgUnitInsignia"));
ADDON = true;

View File

@ -6,7 +6,7 @@
*
* Arguments:
* 0: Config category, must be "CfgWeapons", "CfgVehicles", "CfgMagazines", "CfgVoice" or "CfgUnitInsignia" <STRING>
* 1: Classname <STRING>
* 1: Classname (must be in config case) <STRING>
* 2: Panel control <CONTROL>
* 3: Name of the picture entry in that Cfg class <STRING> (default: "picture")
* 4: Config root <NUMBER> (default: 0 -> configFile)
@ -42,7 +42,7 @@ if (_skip) then {
if (_skip) exitWith {};
// Sanitise key, as it's public; If not in cache, find info and cache it for later use
// If not in cache, find info and cache it for later use
((uiNamespace getVariable QGVAR(addListBoxItemCache)) getOrDefaultCall [_configCategory + _className + str _configRoot, {
// Get classname (config case), display name, picture and DLC
private _configPath = ([configFile, campaignConfigFile, missionConfigFile] select _configRoot) >> _configCategory >> _className;

View File

@ -71,15 +71,16 @@ if (GVAR(currentLoadoutsTab) != IDC_buttonSharedLoadouts) then {
_loadoutCachedInfo = [_loadoutData] call FUNC(verifyLoadout);
_contentPanelCtrl setVariable [_loadoutNameAndTab, _loadoutCachedInfo];
_loadoutCachedInfo params ["", "_nullItemsList", "_unavailableItemsList"];
_loadoutCachedInfo params ["", "_nullItemsList", "_unavailableItemsList", "_missingExtendedInfo"];
// Log missing / nil items to RPT (only once per arsenal session)
if (GVAR(EnableRPTLog) && {(_nullItemsList isNotEqualTo []) || {_unavailableItemsList isNotEqualTo []}}) then {
if (GVAR(EnableRPTLog) && {(_nullItemsList isNotEqualTo []) || {_unavailableItemsList isNotEqualTo [] || {_missingExtendedInfo isNotEqualTo []}}}) then {
private _printComponent = "ACE_Arsenal - Loadout:";
private _printNullItemsList = ["Missing items:", str _nullItemsList] joinString " ";
private _printUnavailableItemsList = ["Unavailable items:", str _unavailableItemsList] joinString " ";
private _printMissingExtendedInfo = ["Missing extended loadout:", str _missingExtendedInfo] joinString " ";
diag_log text (format ["%1%5 %2%5 %3%5 %4", _printComponent, "Name: " + _loadoutName, _printNullItemsList, _printUnavailableItemsList, endl]);
diag_log text (format ["%1%6 %2%6 %3%6 %4%6 %5", _printComponent, "Name: " + _loadoutName, _printNullItemsList, _printUnavailableItemsList, _printMissingExtendedInfo, endl]);
};
};

View File

@ -68,7 +68,7 @@ if (isNil QGVAR(virtualItems)) then {
GVAR(virtualItemsFlatAll) = +GVAR(virtualItemsFlat);
GVAR(currentFace) = face GVAR(center);
GVAR(currentVoice) = speaker GVAR(center);
GVAR(currentVoice) = (speaker GVAR(center)) call EFUNC(common,getConfigName);
GVAR(currentInsignia) = GVAR(center) call BIS_fnc_getUnitInsignia;
GVAR(currentAction) = "Stand";

View File

@ -683,14 +683,19 @@ switch (GVAR(currentLeftPanel)) do {
TOGGLE_RIGHT_PANEL_HIDE
private _unitInsigniaConfig = configFile >> "CfgUnitInsignia" >> _item;
// Check for correct config: First mission, then campaign and finally regular config
private _itemCfg = missionConfigFile >> "CfgUnitInsignia" >> _item;
if (isNull _itemCfg) then {
_itemCfg = campaignConfigFile >> "CfgUnitInsignia" >> _item;
};
if (isNull _itemCfg) then {
_itemCfg = configFile >> "CfgUnitInsignia" >> _item;
};
// Display new items's info on the bottom right
if (isNull _unitInsigniaConfig) then {
[_display, _control, _curSel, missionConfigFile >> "CfgUnitInsignia" >> _item] call FUNC(itemInfo);
} else {
[_display, _control, _curSel, _unitInsigniaConfig] call FUNC(itemInfo);
};
[_display, _control, _curSel, _itemCfg] call FUNC(itemInfo);
};
};

View File

@ -15,6 +15,10 @@
params ["_control"];
// https://community.bistudio.com/wiki/toString, see comment
// However, using 55295 did not work as expected, 55291 was found by trial and error
#define HIGHEST_VALUE_CHAR 55291
// When filling the sorting panel, FUNC(sortPanel) is called twice, so ignore first call
if (GVAR(ignoreFirstSortPanelCall)) exitWith {
GVAR(ignoreFirstSortPanelCall) = false;
@ -29,6 +33,7 @@ private _sortDirectionCtrl = _display displayCtrl ([IDC_sortLeftTabDirection, ID
private _cfgMagazines = configFile >> "CfgMagazines";
private _cfgFaces = configFile >> "CfgFaces";
private _cfgUnitInsignia = configFile >> "CfgUnitInsignia";
private _cfgUnitInsigniaCampaign = campaignConfigFile >> "CfgUnitInsignia";
private _cfgUnitInsigniaMission = missionConfigFile >> "CfgUnitInsignia";
if (_rightSort) then {
@ -126,7 +131,6 @@ private _selected = if (_right) then {
_panel lbData _curSel
};
private _originalNames = createHashMap;
private _item = "";
private _quantity = "";
private _itemCfg = configNull;
@ -136,12 +140,8 @@ private _fillerChar = toString [1];
private _magazineMiscItems = uiNamespace getVariable QGVAR(magazineMiscItems);
private _sortCache = uiNamespace getVariable QGVAR(sortCache);
private _faceCache = if (_cfgClass == _cfgFaces) then {
uiNamespace getVariable [QGVAR(faceCache), createHashMap]
} else {
createHashMap
};
private _faceCache = uiNamespace getVariable QGVAR(faceCache);
private _insigniaCache = uiNamespace getVariable QGVAR(insigniaCache);
private _countColumns = if (_right) then {
count lnbGetColumnsPosition _panel
@ -150,9 +150,9 @@ private _countColumns = if (_right) then {
};
private _for = if (_right) then {
for '_i' from 0 to (lnbSize _panel select 0) - 1
for "_i" from 0 to (lnbSize _panel select 0) - 1
} else {
for '_i' from 0 to (lbSize _panel) - 1
for "_i" from 0 to (lbSize _panel) - 1
};
_for do {
@ -163,6 +163,14 @@ _for do {
_panel lbData _i
};
// Check if entry is "Empty"
if (!_right && {(_panel lbValue _i) == -1}) then {
// Set to lowest/highest lexicographical value, so that "Empty" is always at the top
_panel lbSetTextRight [_i, ["", toString [HIGHEST_VALUE_CHAR, HIGHEST_VALUE_CHAR, HIGHEST_VALUE_CHAR, HIGHEST_VALUE_CHAR, HIGHEST_VALUE_CHAR]] select (_sortDirection == ASCENDING)];
continue;
};
// Get item's count
_quantity = if (_right) then {
parseNumber (_panel lnbText [_i, 2])
@ -179,18 +187,22 @@ _for do {
_itemCfg = if !(_cfgClass in [_cfgFaces, _cfgUnitInsignia]) then {
_cfgClass >> _item
} else {
// If insignia, check both config and mission file
// If insignia, check for correct config: First mission, then campaign and finally regular config
if (_cfgClass == _cfgUnitInsignia) then {
_itemCfg = _cfgClass >> _item;
_itemCfg = _cfgUnitInsigniaMission >> _item;
if (isNull _itemCfg) then {
_itemCfg = _cfgUnitInsigniaMission >> _item;
_itemCfg = _cfgUnitInsigniaCampaign >> _item;
};
if (isNull _itemCfg) then {
_itemCfg = _cfgUnitInsignia >> _item;
};
_itemCfg
} else {
// If face, check correct category
_cfgClass >> (_faceCache get _item) param [2, "Man_A3"] >> _item
_cfgClass >> (_faceCache getOrDefault [_item, []]) param [2, "Man_A3"] >> _item
};
};
@ -216,37 +228,29 @@ _for do {
_value
}, true];
// Save the current row's item's name in a cache and set text to it's sorting value
// Set the right text temporarily, so it can be used for sorting
if (_right) then {
_name = _panel lnbText [_i, 1];
_originalNames set [_item, _name];
// Use value, display name and classname to sort, which means a fixed alphabetical order is guaranteed
// Filler char has lowest lexicographical order possible
_panel lnbSetText [[_i, 1], format ["%1%2%4%3", _value, _name, _item, _fillerChar]];
// Filler char has lowest lexicographical value possible
_panel lnbSetTextRight [[_i, 1], format ["%1%2%4%3", _value, _panel lnbText [_i, 1], _item, _fillerChar]];
} else {
if (_item != "") then {
_name = _panel lbText _i;
_originalNames set [_item, _name];
// Use value, display name and classname to sort, which means a fixed alphabetical order is guaranteed
// Filler char has lowest lexicographical order possible
_panel lbSetText [_i, format ["%1%2%4%3", _value, _name, _item, _fillerChar]];
// Filler char has lowest lexicographical value possible
_panel lbSetTextRight [_i, format ["%1%2%4%3", _value, _panel lbText _i, _item, _fillerChar]];
};
};
};
// Sort alphabetically, find the previously selected item, select it again and reset text to original text
// Sort alphabetically, find the previously selected item and select it again
if (_right) then {
_panel lnbSort [1, _sortDirection == ASCENDING];
[_panel, 1] lnbSortBy ["TEXT", _sortDirection == ASCENDING, false, true, false];
_for do {
_item = _panel lnbData [_i, 0];
// Remove sorting text, as it blocks the item name otherwise
_panel lnbSetTextRight [[_i, 1], ""];
_panel lnbSetText [[_i, 1], _originalNames get _item];
// Set selection after text, otherwise item info box on the right side shows invalid name
if (_curSel != -1 && {_item == _selected}) then {
if (_curSel != -1 && {(_panel lnbData [_i, 0]) == _selected}) then {
_panel lnbSetCurSelRow _i;
// To avoid unnecessary checks after previsouly selected item was found
@ -254,17 +258,17 @@ if (_right) then {
};
};
} else {
lbSort [_panel, ["DESC", "ASC"] select _sortDirection];
_panel lbSortBy ["TEXT", _sortDirection == ASCENDING, false, true, false];
_for do {
_item = _panel lbData _i;
// Check if valid item (problems can be caused when searching)
if (_item != "") then {
_panel lbSetText [_i, _originalNames get _item];
// Remove sorting text, as it blocks the item name otherwise
_panel lbSetTextRight [_i, ""];
};
// Set selection after text, otherwise item info box on the right side shows invalid name
if (_curSel != -1 && {_item == _selected}) then {
_panel lbSetCurSel _i;

View File

@ -27,6 +27,7 @@ private _name = "";
private _itemArray = [];
private _nullItemsList = [];
private _unavailableItemsList = [];
private _missingExtendedInfo = [];
// Search for all items and check their availability
private _fnc_filterLoadout = {
@ -70,7 +71,22 @@ private _fnc_filterLoadout = {
// Loadout might come from a different modpack, which might have different config naming
_loadout = _loadout call _fnc_filterLoadout;
// Raise event for 3rd party: mostly for handling extended info
[QGVAR(loadoutVerified), [_loadout, _extendedInfo]] call CBA_fnc_localEvent;
{
private _class = _extendedInfo getOrDefault [_x, ""];
private _cache = missionNamespace getVariable (_x + "Cache");
[[_loadout, _extendedInfo], _nullItemsList arrayIntersect _nullItemsList, _unavailableItemsList arrayIntersect _unavailableItemsList]
// Previously voices were stored in lower case (speaker command returns lower case), so this is to make old loadouts compatible
if (_class != "" && {_x == QGVAR(voice)}) then {
_class = _class call EFUNC(common,getConfigName);
};
if (_class != "" && {!(_class in _cache)}) then {
_missingExtendedInfo pushBack [_x, _class];
_extendedInfo deleteAt _x;
};
} forEach [QGVAR(insignia), QGVAR(face), QGVAR(voice)];
// Raise event for 3rd party: mostly for handling extended info
// Pass all items, including duplicates
[QGVAR(loadoutVerified), [_loadout, _extendedInfo, _nullItemsList, _unavailableItemsList, _missingExtendedInfo]] call CBA_fnc_localEvent;
[[_loadout, _extendedInfo], _nullItemsList arrayIntersect _nullItemsList, _unavailableItemsList arrayIntersect _unavailableItemsList, _missingExtendedInfo]

View File

@ -564,6 +564,7 @@ class GVAR(display) {
colorSelect[] = {1,1,1,1};
colorSelect2[] = {1,1,1,1};
colorPictureRightSelected[] = {1,1,1,1};
colorTextRight[] = {0.5, 0.5, 0.5, 0};
onLBSelChanged = QUOTE(_this call FUNC(onSelChangedLeft));
onLBDblClick = QUOTE(_this call FUNC(onPanelDblClick));
onSetFocus = QUOTE(GVAR(leftTabFocus) = true);
@ -594,6 +595,7 @@ class GVAR(display) {
colorSelect[] = {1,1,1,1};
colorSelect2[] = {1,1,1,1};
colorPictureRightSelected[] = {1,1,1,1};
colorTextRight[] = {0.5, 0.5, 0.5, 0};
columns[] = {0.07, 0.15, 0.75};
idcLeft = IDC_arrowMinus;
idcRIght = IDC_arrowPlus;

View File

@ -1 +0,0 @@
#include "..\script_component.hpp"

View File

@ -17,7 +17,7 @@
params ["_className"];
(uiNamespace getVariable QGVAR(configNames)) getOrDefaultCall [toLower _className, {
(uiNamespace getVariable QGVAR(configNames)) getOrDefaultCall [toLowerANSI _className, {
private _config = configNull;
{

View File

@ -27,23 +27,34 @@ PREP_RECOMPILE_END;
}] call CBA_fnc_addClassEventHandler;
[QEGVAR(arsenal,loadoutVerified), {
params ["_loadout", "_extendedInfo"];
params ["_loadout", "_extendedInfo", "", "", "_missingExtendedInfo"];
private _gunbagInfo = _extendedInfo getOrDefault [QGVAR(gunbagWeapon), []];
if (_gunbagInfo isEqualTo []) exitWith {};
private _weapon = (_gunbagInfo select 0) call EFUNC(arsenal,baseWeapon);
if !(_weapon in EGVAR(arsenal,virtualItemsFlat)) exitWith {
INFO_1("removing [%1] from loadout",_gunbagInfo);
_missingExtendedInfo pushBack [QGVAR(gunbagWeapon), _weapon];
_extendedInfo deleteAt QGVAR(gunbagWeapon);
};
private _missingItems = [];
private _attachments = _gunbagInfo select 1;
{
if (_x != "" && {!(_x call EFUNC(arsenal,baseWeapon) in EGVAR(arsenal,virtualItemsFlat))}) then {
_missingItems pushBack _x;
_attachments set [_forEachIndex, ""];
};
} forEach _attachments;
private _magazines = _gunbagInfo select 2;
{
private _class = _x param [0, ""];
private _defaultValue = ["", []] select {_x isEqualType []};
if (_class != "" && {!(_class in EGVAR(arsenal,virtualItemsFlat))}) then {
INFO_1("removing [%1] from loadout",_x);
_gunbagInfo set [_forEachIndex + 1, _defaultValue];
if !(_class != "" && {_class in EGVAR(arsenal,virtualItemsFlat)}) then {
_missingItems pushBack _class;
_magazines set [_forEachIndex, ["", 0]];
};
} forEach (_gunbagInfo select [1]); // weapon was verified above
} forEach _magazines;
if (_missingItems isNotEqualTo []) then {
_missingExtendedInfo pushBack [QGVAR(gunbagWeapon), _missingItems];
};
}] call CBA_fnc_addEventHandler;
["CBA_loadoutSet", {

View File

@ -511,7 +511,7 @@ All are local.
| ace_arsenal_loadoutsDisplayClosed | None | 3.12.3 |
| ace_arsenal_loadoutsTabChanged | loadouts screen display (DISPLAY), tab control (CONTROL) | 3.12.3 |
| ace_arsenal_loadoutsListFilled | loadouts screen display (DISPLAY), tab control (CONTROL) | 3.12.3 |
| ace_arsenal_loadoutVerified | loadout data (ARRAY), loadout CBA extended data (HASHMAP) | 3.17.0 |
| ace_arsenal_loadoutVerified | loadout data (ARRAY), loadout CBA extended data (HASHMAP), null items (ARRAY), unavailable items (ARRAY), unavailable extended data (ARRAY) | 3.17.0 |
| ace_arsenal_weaponItemChanged | weapon classname (STRING), item classname (STRING), item index (NUMBER, 0-5: muzzle, side, optic, bipod, magazine, underbarrel) | 3.16.0 |
## 9. Custom sub item categories