Add store DLC source filtering diagnostics

This commit is contained in:
Jacob Schmidt 2026-06-03 23:06:03 -05:00
parent 510c1a77b6
commit 69acbaef4c
3 changed files with 82 additions and 10 deletions

View File

@ -42,12 +42,14 @@ class CfgStore {
patches[] = {"rhs_main", "rhsusf_main"};
addons[] = {"rhs_", "rhsusf_", "rhsgref_", "rhsafrf_"};
prefixes[] = {"rhs_", "rhsusf_", "rhsgref_", "rhsafrf_"};
dlcs[] = {};
};
class ace3 {
patches[] = {"ace_main"};
addons[] = {"ace_"};
prefixes[] = {"ace_"};
dlcs[] = {};
};
};
@ -76,9 +78,10 @@ uses the same prices and descriptions the UI displays.
filtering. `allowlist` only keeps generated entries that match one of the
configured `mods[]`; `denylist` removes matching entries. Each `ModSources`
child can define `patches[]` to detect whether the mod is loaded, `addons[]`
for exact config source addon/source mod names, and `prefixes[]` for classname,
source addon, or source mod prefixes. If a mod source defines no patches, it is
treated as available and only the source/prefix checks are used.
for exact config source addon/source mod names, `prefixes[]` for classname,
source addon, or source mod prefixes, and `dlcs[]` for DLC/source/author labels
used by Creator DLC content. If a mod source defines no patches, it is treated
as available and only the source/prefix/DLC checks are used.
`units[]` follows the same `dynamic`, `allowlist`, and `denylist` behavior as
item and vehicle categories. Unit purchases are immediate spawn grants, not

View File

@ -87,6 +87,28 @@ GVAR(StoreCatalogServiceBaseClass) = compileFinal createHashMapFromArray [
_loaded
}],
["describeMissionStoreModSources", compileFinal {
params [["_mods", [], [[]]]];
_mods apply {
private _modID = _x;
private _patches = _self call ["getMissionStoreModSourceValues", [_modID, "patches"]];
private _addons = _self call ["getMissionStoreModSourceValues", [_modID, "addons"]];
private _prefixes = _self call ["getMissionStoreModSourceValues", [_modID, "prefixes"]];
private _dlcs = _self call ["getMissionStoreModSourceValues", [_modID, "dlcs"]];
private _loaded = _self call ["isMissionStoreModLoaded", [_modID]];
format [
"%1 loaded=%2 patches=%3 addons=%4 prefixes=%5 dlcs=%6",
_modID,
_loaded,
_patches,
_addons,
_prefixes,
_dlcs
]
}
}],
["doesValueMatchAnyPrefix", compileFinal {
params [["_value", "", [""]], ["_prefixes", [], [[]]]];
@ -109,12 +131,19 @@ GVAR(StoreCatalogServiceBaseClass) = compileFinal createHashMapFromArray [
private _className = _item getOrDefault ["className", ""];
private _sourceAddons = (_item getOrDefault ["sourceAddons", []]) apply { toLowerANSI _x };
private _sourceMod = _item getOrDefault ["sourceMod", ""];
private _sourceDLC = _item getOrDefault ["sourceDLC", ""];
private _sourceAuthor = _item getOrDefault ["sourceAuthor", ""];
private _addons = (_self call ["getMissionStoreModSourceValues", [_modID, "addons"]]) apply { toLowerANSI _x };
private _prefixes = (_self call ["getMissionStoreModSourceValues", [_modID, "prefixes"]]) apply { toLowerANSI _x };
private _dlcs = (_self call ["getMissionStoreModSourceValues", [_modID, "dlcs"]]) apply { toLowerANSI _x };
private _matchPrefixes = _addons + _prefixes;
private _sourceModLower = toLowerANSI _sourceMod;
private _sourceDLCLower = toLowerANSI _sourceDLC;
private _sourceAuthorLower = toLowerANSI _sourceAuthor;
if (_sourceModLower in _addons) exitWith { true };
if (_sourceDLCLower in _dlcs) exitWith { true };
if (_sourceAuthorLower in _dlcs) exitWith { true };
private _sourceAddonMatched = false;
{
if (_x in _addons) exitWith { _sourceAddonMatched = true; };
@ -123,6 +152,8 @@ GVAR(StoreCatalogServiceBaseClass) = compileFinal createHashMapFromArray [
if (_sourceAddonMatched) exitWith { true };
if (_self call ["doesValueMatchAnyPrefix", [_className, _matchPrefixes]]) exitWith { true };
if (_self call ["doesValueMatchAnyPrefix", [_sourceMod, _matchPrefixes]]) exitWith { true };
if (_self call ["doesValueMatchAnyPrefix", [_sourceDLC, _dlcs]]) exitWith { true };
if (_self call ["doesValueMatchAnyPrefix", [_sourceAuthor, _dlcs]]) exitWith { true };
false
}],
@ -141,9 +172,18 @@ GVAR(StoreCatalogServiceBaseClass) = compileFinal createHashMapFromArray [
private _mode = _self call ["getMissionStoreModMode", []];
private _mods = _self call ["getMissionStoreModList", []];
if (_mode isEqualTo "dynamic" || { _mods isEqualTo [] }) exitWith { +_items };
private _beforeCount = count _items;
if (_mode isEqualTo "dynamic" || { _mods isEqualTo [] }) exitWith {
["INFO", format [
"Store mod filter skipped. Mode=%1 Mods=%2 Items=%3",
_mode,
_mods,
_beforeCount
]] call EFUNC(common,log);
+_items
};
switch (_mode) do {
private _filteredItems = switch (_mode) do {
case "allowlist": {
_items select { _self call ["doesItemMatchMissionStoreMods", [_x, _mods]] }
};
@ -153,7 +193,18 @@ GVAR(StoreCatalogServiceBaseClass) = compileFinal createHashMapFromArray [
default {
+_items
};
}
};
["INFO", format [
"Store mod filter applied. Mode=%1 Mods=%2 Items=%3 -> %4 Sources=[%5]",
_mode,
_mods,
_beforeCount,
count _filteredItems,
(_self call ["describeMissionStoreModSources", [_mods]]) joinString "; "
]] call EFUNC(common,log);
_filteredItems
}],
["getMissionStoreCategoryList", compileFinal {
params [["_category", "", [""]]];
@ -304,6 +355,8 @@ GVAR(StoreCatalogServiceBaseClass) = compileFinal createHashMapFromArray [
private _displayName = getText (_cfg >> "displayName");
private _sourceAddons = configSourceAddonList _cfg;
private _sourceMod = configSourceMod _cfg;
private _sourceDLC = getText (_cfg >> "DLC");
private _sourceAuthor = getText (_cfg >> "author");
private _picture = getText (_cfg >> _imageField);
if (_picture isEqualTo "" && { _imageField isNotEqualTo "picture" }) then {
_picture = getText (_cfg >> "picture");
@ -321,7 +374,9 @@ GVAR(StoreCatalogServiceBaseClass) = compileFinal createHashMapFromArray [
["image", _picture],
["type", _typeLabel],
["sourceAddons", _sourceAddons],
["sourceMod", _sourceMod]
["sourceMod", _sourceMod],
["sourceDLC", _sourceDLC],
["sourceAuthor", _sourceAuthor]
]
}],
["appendCfgWeaponsByItemInfoType", compileFinal {

View File

@ -42,12 +42,14 @@ class CfgStore {
patches[] = {"rhs_main", "rhsusf_main"};
addons[] = {"rhs_", "rhsusf_", "rhsgref_", "rhsafrf_"};
prefixes[] = {"rhs_", "rhsusf_", "rhsgref_", "rhsafrf_"};
dlcs[] = {};
};
class ace3 {
patches[] = {"ace_main"};
addons[] = {"ace_"};
prefixes[] = {"ace_"};
dlcs[] = {};
};
};
@ -76,9 +78,10 @@ server-side and are used by both the UI payload and checkout validation.
filtering. `allowlist` only keeps generated entries that match one of the
configured `mods[]`; `denylist` removes matching entries. Each `ModSources`
child can define `patches[]` to detect whether the mod is loaded, `addons[]`
for exact config source addon/source mod names, and `prefixes[]` for classname,
source addon, or source mod prefixes. If a mod source defines no patches, it is
treated as available and only the source/prefix checks are used.
for exact config source addon/source mod names, `prefixes[]` for classname,
source addon, or source mod prefixes, and `dlcs[]` for DLC/source/author labels
used by Creator DLC content. If a mod source defines no patches, it is treated
as available and only the source/prefix/DLC checks are used.
For example, to show only RHS-sourced generated inventory:
@ -91,6 +94,17 @@ The matching `class rhs` must exist under `ModSources`. Category `mode` is still
applied afterward, so leave `mode = "dynamic"` if the mod filter should be the
only inventory filter.
For Creator DLCs such as RF or WS, prefer both prefixes and DLC labels:
```cpp
class rf {
patches[] = {};
addons[] = {"lxrf_", "rf_"};
prefixes[] = {"lxrf_", "rf_"};
dlcs[] = {"rf", "reactionforces", "reaction forces"};
};
```
The current filter is global for the mission. Revisit per-store profile support
if individual vendors need different inventories.