From aef7f9ae48a354b914ead53b427115c994cb40f2 Mon Sep 17 00:00:00 2001 From: Jacob Schmidt Date: Fri, 30 Jan 2026 20:19:29 -0600 Subject: [PATCH] feat: Implement core game systems for actor, garage, organization, bank, locker, and notifications with client-side UI and server-side data stores. --- .../addons/actor/XEH_postInitClient.sqf | 2 +- .../actor/functions/fnc_handleUIEvents.sqf | 21 +- .../actor/functions/fnc_initActorClass.sqf | 6 +- .../addons/actor/functions/fnc_openUI.sqf | 8 +- arma/client/addons/actor/ui/_site/script.js | 14 +- .../client/addons/bank/XEH_postInitClient.sqf | 2 +- .../bank/functions/fnc_handleUIEvents.sqf | 4 +- .../bank/functions/fnc_initBankClass.sqf | 4 +- .../addons/bank/functions/fnc_openUI.sqf | 6 +- .../addons/garage/XEH_postInitClient.sqf | 4 +- .../garage/functions/fnc_handleUIEvents.sqf | 4 +- .../garage/functions/fnc_initGarageClass.sqf | 4 +- .../garage/functions/fnc_initVGClass.sqf | 4 +- .../addons/garage/functions/fnc_openUI.sqf | 4 +- .../addons/garage/functions/fnc_openVG.sqf | 4 +- .../addons/locker/XEH_postInitClient.sqf | 4 +- .../locker/functions/fnc_handleUIEvents.sqf | 23 -- .../locker/functions/fnc_initLockerClass.sqf | 270 ++++++++++++++++-- .../locker/functions/fnc_initVAClass.sqf | 7 +- .../addons/locker/functions/fnc_openUI.sqf | 21 -- .../notifications/XEH_postInitClient.sqf | 4 +- .../functions/fnc_handleUIEvents.sqf | 4 +- .../functions/fnc_initNotificationClass.sqf | 4 +- .../notifications/functions/fnc_openUI.sqf | 4 +- arma/client/addons/org/XEH_postInitClient.sqf | 2 +- .../org/functions/fnc_handleUIEvents.sqf | 2 +- .../addons/org/functions/fnc_initOrgClass.sqf | 2 +- .../addons/org/functions/fnc_openUI.sqf | 6 +- .../example_addon/functions/fnc_empty.sqf | 2 +- .../actor/functions/fnc_initActorStore.sqf | 4 +- .../bank/functions/fnc_initBankStore.sqf | 4 +- .../addons/common/functions/fnc_baseStore.sqf | 4 +- arma/server/addons/economy/XEH_preInit.sqf | 6 +- arma/server/addons/extension/XEH_preStart.sqf | 1 - arma/server/addons/garage/XEH_postInit.sqf | 2 +- arma/server/addons/garage/XEH_preInit.sqf | 10 +- .../garage/functions/fnc_initGarage.sqf | 4 +- .../garage/functions/fnc_initGarageStore.sqf | 4 +- .../garage/functions/fnc_initVGStore.sqf | 4 +- arma/server/addons/locker/XEH_postInit.sqf | 2 +- arma/server/addons/locker/XEH_preInit.sqf | 33 +-- .../locker/functions/fnc_initLocker.sqf | 74 +---- .../locker/functions/fnc_initLockerStore.sqf | 4 +- .../locker/functions/fnc_initVAStore.sqf | 4 +- arma/server/addons/main/XEH_postInit.sqf | 2 +- .../addons/main/functions/fnc_initStores.sqf | 18 +- .../addons/org/functions/fnc_initOrgStore.sqf | 4 +- lib/models/src/v_garage.rs | 4 + lib/models/src/v_locker.rs | 4 + 49 files changed, 384 insertions(+), 254 deletions(-) delete mode 100644 arma/client/addons/locker/functions/fnc_handleUIEvents.sqf delete mode 100644 arma/client/addons/locker/functions/fnc_openUI.sqf diff --git a/arma/client/addons/actor/XEH_postInitClient.sqf b/arma/client/addons/actor/XEH_postInitClient.sqf index df53600..12c69b1 100644 --- a/arma/client/addons/actor/XEH_postInitClient.sqf +++ b/arma/client/addons/actor/XEH_postInitClient.sqf @@ -23,7 +23,7 @@ player addEventHandler ["Respawn", { [SRPC(economy,onRespawn), [_unit, _corpse, _uid]] call CFUNC(serverEvent); }]; -if (isNil QGVAR(ActorClass)) then { [] call FUNC(initActorClass); }; +if (isNil QGVAR(ActorClass)) then { call FUNC(initActorClass); }; [QGVAR(initActor), { GVAR(ActorClass) call ["init", []]; diff --git a/arma/client/addons/actor/functions/fnc_handleUIEvents.sqf b/arma/client/addons/actor/functions/fnc_handleUIEvents.sqf index 6806bd3..419a8ab 100644 --- a/arma/client/addons/actor/functions/fnc_handleUIEvents.sqf +++ b/arma/client/addons/actor/functions/fnc_handleUIEvents.sqf @@ -4,7 +4,7 @@ * File: fnc_handleUIEvents.sqf * Author: IDSolutions * Date: 2026-01-28 - * Last Update: 2026-01-28 + * Last Update: 2026-01-30 * Public: No * * Description: @@ -19,7 +19,7 @@ * UI events handled [BOOL] * * Example: - * [] call forge_client_actor_fnc_handleUIEvents; + * call forge_client_actor_fnc_handleUIEvents; */ params ["_control", "_isConfirmDialog", "_message"]; @@ -27,7 +27,7 @@ params ["_control", "_isConfirmDialog", "_message"]; private _alert = fromJSON _message; private _event = _alert get "event"; private _data = _alert get "data"; -private _display = displayChild findDisplay 46; +// private _display = displayChild findDisplay 46; diag_log format ["[FORGE:Client:Actor] Handling UI event: %1 with data: %2", _event, _data]; @@ -35,19 +35,20 @@ switch (_event) do { case "actor::get::actions": { GVAR(ActorClass) call ["getNearbyActions", [_control]]; }; case "actor::open::atm": { [true] spawn EFUNC(bank,openUI); }; case "actor::open::bank": { [] spawn EFUNC(bank,openUI); }; - case "actor::open::device": { hint "Device interaction is not yet implemented."; }; // TODO: Implement device interaction - case "actor::open::garage": { hint "Garage interaction is not yet implemented."; }; // TODO: Implement garage interaction + case "actor::open::device": { hint "Device interaction is not yet implemented."; }; + case "actor::open::garage": { hint "Garage interaction is not yet implemented."; }; case "actor::open::vgarage": { [] spawn EFUNC(garage,openVG); }; case "actor::open::org": { [] spawn EFUNC(org,openUI); }; - case "actor::open::locker": { hint "Locker interaction is not yet implemented."; }; // TODO: Implement locker interaction + // case "actor::open::locker": { hint "Locker interaction is not yet implemented."; }; case "actor::open::vlocker": { ["Open", [false, FORGE_Locker_Box, player]] spawn BFUNC(arsenal) }; // case "actor::open::phone": { [] spawn EFUNC(phone,openUI) }; - case "actor::open::phone": { hint "Phone interaction is not yet implemented."; }; // TODO: Implement phone interaction - case "actor::open::iplayer": { hint "Player interaction is not yet implemented." }; // TODO: Implement player interaction - case "actor::open::store": { hint "Store interaction is not yet implemented."; }; // TODO: Implement store interaction + case "actor::open::phone": { hint "Phone interaction is not yet implemented."; }; + case "actor::open::iplayer": { hint "Player interaction is not yet implemented." }; + case "actor::open::store": { hint "Store interaction is not yet implemented."; }; default { hint format ["Unhandled UI event: %1", _event]; }; }; -if (_event isNotEqualTo "actor::get::actions") then { _display closeDisplay 1; }; +// if (_event isNotEqualTo "actor::get::actions") then { _display closeDisplay 1; }; +if (_event isNotEqualTo "actor::get::actions") then { closeDialog 1; }; true; diff --git a/arma/client/addons/actor/functions/fnc_initActorClass.sqf b/arma/client/addons/actor/functions/fnc_initActorClass.sqf index bda2d1a..3eb641c 100644 --- a/arma/client/addons/actor/functions/fnc_initActorClass.sqf +++ b/arma/client/addons/actor/functions/fnc_initActorClass.sqf @@ -4,7 +4,7 @@ * File: fnc_initActorClass.sqf * Author: IDSolutions * Date: 2026-01-28 - * Last Update: 2026-01-28 + * Last Update: 2026-01-30 * Public: Yes * * Description: @@ -18,7 +18,7 @@ * Actor class object [HASHMAP OBJECT] * * Example: - * [] call forge_client_actor_fnc_initActorClass + * call forge_client_actor_fnc_initActorClass */ #pragma hemtt ignore_variables ["_self"] @@ -131,7 +131,7 @@ GVAR(ActorClass) = createHashMapObject [[ if (_storeType isNotEqualTo "") then { _nearbyActions pushBack ["store", _storeType]; }; if (_isBank) then { _nearbyActions pushBack ["bank", true]; }; - if (_isLocker) then { _nearbyActions pushBack ["locker", true]; }; + // if (_isLocker) then { _nearbyActions pushBack ["locker", true]; }; if (_isLocker && GVAR(enableVA)) then { _nearbyActions pushBack ["va", true]; }; if (_isGarage) then { _nearbyActions pushBack ["garage", _garageType]; }; if (_isGarage && GVAR(enableVG)) then { _nearbyActions pushBack ["vg", true]; }; diff --git a/arma/client/addons/actor/functions/fnc_openUI.sqf b/arma/client/addons/actor/functions/fnc_openUI.sqf index ce70ed1..ad36acf 100644 --- a/arma/client/addons/actor/functions/fnc_openUI.sqf +++ b/arma/client/addons/actor/functions/fnc_openUI.sqf @@ -4,7 +4,7 @@ * File: fnc_openUI.sqf * Author: IDSolutions * Date: 2026-01-28 - * Last Update: 2026-01-28 + * Last Update: 2026-01-30 * Public: No * * Description: @@ -17,11 +17,11 @@ * UI opened [BOOL] * * Example: - * [] call forge_client_actor_fnc_openUI; + * call forge_client_actor_fnc_openUI; */ -private _display = (findDisplay 46) createDisplay "RscActorMenu"; -private _ctrl = (_display displayCtrl 1001); +private _display = createDialog ["RscActorMenu", true]; +private _ctrl = _display displayCtrl 1001; _ctrl ctrlAddEventHandler ["JSDialog", { params ["_control", "_isConfirmDialog", "_message"]; diff --git a/arma/client/addons/actor/ui/_site/script.js b/arma/client/addons/actor/ui/_site/script.js index 88b4334..7c2bf9c 100644 --- a/arma/client/addons/actor/ui/_site/script.js +++ b/arma/client/addons/actor/ui/_site/script.js @@ -92,13 +92,13 @@ const actionDefinitions = { icon: "", action: "actor::open::garage", }, - locker: { - id: "locker", - title: "Locker", - description: "Access your personal locker for storage", - icon: "", - action: "actor::open::locker", - }, + // locker: { + // id: "locker", + // title: "Locker", + // description: "Access your personal locker for storage", + // icon: "", + // action: "actor::open::locker", + // }, player: { id: "player", title: "Player Interaction", diff --git a/arma/client/addons/bank/XEH_postInitClient.sqf b/arma/client/addons/bank/XEH_postInitClient.sqf index ee3a2c2..2c874f5 100644 --- a/arma/client/addons/bank/XEH_postInitClient.sqf +++ b/arma/client/addons/bank/XEH_postInitClient.sqf @@ -1,6 +1,6 @@ #include "script_component.hpp" -if (isNil QGVAR(BankClass)) then { [] call FUNC(initBankClass); }; +if (isNil QGVAR(BankClass)) then { call FUNC(initBankClass); }; [QGVAR(initBank), { GVAR(BankClass) call ["init", []]; diff --git a/arma/client/addons/bank/functions/fnc_handleUIEvents.sqf b/arma/client/addons/bank/functions/fnc_handleUIEvents.sqf index 6cb40ab..09a2d15 100644 --- a/arma/client/addons/bank/functions/fnc_handleUIEvents.sqf +++ b/arma/client/addons/bank/functions/fnc_handleUIEvents.sqf @@ -4,7 +4,7 @@ * File: fnc_handleUIEvents.sqf * Author: IDSolutions * Date: 2025-12-16 - * Last Update: 2026-01-28 + * Last Update: 2026-01-30 * Public: No * * Description: @@ -19,7 +19,7 @@ * UI events handled [BOOL] * * Example: - * [] call forge_client_bank_fnc_handleUIEvents; + * call forge_client_bank_fnc_handleUIEvents; */ params ["_control", "_isConfirmDialog", "_message"]; diff --git a/arma/client/addons/bank/functions/fnc_initBankClass.sqf b/arma/client/addons/bank/functions/fnc_initBankClass.sqf index 432d4fa..8f47297 100644 --- a/arma/client/addons/bank/functions/fnc_initBankClass.sqf +++ b/arma/client/addons/bank/functions/fnc_initBankClass.sqf @@ -4,7 +4,7 @@ * File: fnc_initBankClass.sqf * Author: IDSolutions * Date: 2025-12-16 - * Last Update: 2026-01-28 + * Last Update: 2026-01-30 * Public: No * * Description: @@ -17,7 +17,7 @@ * Bank class object [HASHMAP OBJECT] * * Example: - * [] call forge_client_bank_fnc_initBankClass + * call forge_client_bank_fnc_initBankClass */ #pragma hemtt ignore_variables ["_self"] diff --git a/arma/client/addons/bank/functions/fnc_openUI.sqf b/arma/client/addons/bank/functions/fnc_openUI.sqf index 65086a8..bfce578 100644 --- a/arma/client/addons/bank/functions/fnc_openUI.sqf +++ b/arma/client/addons/bank/functions/fnc_openUI.sqf @@ -4,7 +4,7 @@ * File: fnc_openUI.sqf * Author: IDSolutions * Date: 2026-01-28 - * Last Update: 2026-01-28 + * Last Update: 2026-01-30 * Public: No * * Description: @@ -22,8 +22,8 @@ params [["_isATM", false, [false]]]; -private _display = (findDisplay 46) createDisplay "RscBank"; -private _ctrl = (_display displayCtrl 1002); +private _display = createDialog ["RscBank", true]; +private _ctrl = _display displayCtrl 1002; _ctrl ctrlAddEventHandler ["JSDialog", { params ["_control", "_isConfirmDialog", "_message"]; diff --git a/arma/client/addons/garage/XEH_postInitClient.sqf b/arma/client/addons/garage/XEH_postInitClient.sqf index d678a9b..536df61 100644 --- a/arma/client/addons/garage/XEH_postInitClient.sqf +++ b/arma/client/addons/garage/XEH_postInitClient.sqf @@ -1,7 +1,7 @@ #include "script_component.hpp" -if (isNil QGVAR(GarageClass)) then { [] call FUNC(initGarageClass); }; -if (isNil QGVAR(VGarageClass)) then { [] call FUNC(initVGClass); }; +if (isNil QGVAR(GarageClass)) then { call FUNC(initGarageClass); }; +if (isNil QGVAR(VGarageClass)) then { call FUNC(initVGClass); }; [QGVAR(initGarage), { GVAR(GarageClass) call ["init", []]; diff --git a/arma/client/addons/garage/functions/fnc_handleUIEvents.sqf b/arma/client/addons/garage/functions/fnc_handleUIEvents.sqf index 6347852..2fe5dfb 100644 --- a/arma/client/addons/garage/functions/fnc_handleUIEvents.sqf +++ b/arma/client/addons/garage/functions/fnc_handleUIEvents.sqf @@ -4,7 +4,7 @@ * File: fnc_handleUIEvents.sqf * Author: IDSolutions * Date: 2025-12-16 - * Last Update: 2026-01-28 + * Last Update: 2026-01-30 * Public: No * * Description: @@ -19,5 +19,5 @@ * UI events handled [BOOL] * * Example: - * [] call forge_client_garage_fnc_handleUIEvents; + * call forge_client_garage_fnc_handleUIEvents; */ diff --git a/arma/client/addons/garage/functions/fnc_initGarageClass.sqf b/arma/client/addons/garage/functions/fnc_initGarageClass.sqf index 9497ea5..6ebee5c 100644 --- a/arma/client/addons/garage/functions/fnc_initGarageClass.sqf +++ b/arma/client/addons/garage/functions/fnc_initGarageClass.sqf @@ -4,7 +4,7 @@ * File: fnc_initGarageClass.sqf * Author: IDSolutions * Date: 2025-12-17 - * Last Update: 2026-01-28 + * Last Update: 2026-01-30 * Public: No * * Description: @@ -18,7 +18,7 @@ * Garage class object [HASHMAP OBJECT] * * Example: - * [] call forge_client_garage_fnc_initGarageClass + * call forge_client_garage_fnc_initGarageClass */ #pragma hemtt ignore_variables ["_self"] diff --git a/arma/client/addons/garage/functions/fnc_initVGClass.sqf b/arma/client/addons/garage/functions/fnc_initVGClass.sqf index 72d422f..3264afa 100644 --- a/arma/client/addons/garage/functions/fnc_initVGClass.sqf +++ b/arma/client/addons/garage/functions/fnc_initVGClass.sqf @@ -4,7 +4,7 @@ * File: fnc_initVGClass.sqf * Author: IDSolutions * Date: 2025-12-16 - * Last Update: 2026-01-28 + * Last Update: 2026-01-30 * Public: No * * Description: @@ -18,7 +18,7 @@ * vGarage class object [HASHMAP OBJECT] * * Example: - * [] call forge_client_garage_fnc_initVGClass; + * call forge_client_garage_fnc_initVGClass; */ #pragma hemtt ignore_variables ["_self"] diff --git a/arma/client/addons/garage/functions/fnc_openUI.sqf b/arma/client/addons/garage/functions/fnc_openUI.sqf index c6f42c2..84678e0 100644 --- a/arma/client/addons/garage/functions/fnc_openUI.sqf +++ b/arma/client/addons/garage/functions/fnc_openUI.sqf @@ -4,7 +4,7 @@ * File: fnc_openUI.sqf * Author: IDSolutions * Date: 2025-12-16 - * Last Update: 2026-01-28 + * Last Update: 2026-01-30 * Public: No * * Description: @@ -17,5 +17,5 @@ * UI opened [BOOL] * * Example: - * [] call forge_client_garage_fnc_openUI; + * call forge_client_garage_fnc_openUI; */ diff --git a/arma/client/addons/garage/functions/fnc_openVG.sqf b/arma/client/addons/garage/functions/fnc_openVG.sqf index c6a0e18..bca0cb8 100644 --- a/arma/client/addons/garage/functions/fnc_openVG.sqf +++ b/arma/client/addons/garage/functions/fnc_openVG.sqf @@ -4,7 +4,7 @@ * File: fnc_openVG.sqf * Author: IDSolutions * Date: 2025-12-16 - * Last Update: 2026-01-28 + * Last Update: 2026-01-30 * Public: No * * Description: @@ -17,7 +17,7 @@ * None * * Example: - * [] call forge_client_garage_fnc_openVG + * call forge_client_garage_fnc_openVG */ private _locations = (missionConfigFile >> "FORGE_CfgGarages" >> "locations") call BFUNC(getCfgData); diff --git a/arma/client/addons/locker/XEH_postInitClient.sqf b/arma/client/addons/locker/XEH_postInitClient.sqf index 9e97a3b..9d0d346 100644 --- a/arma/client/addons/locker/XEH_postInitClient.sqf +++ b/arma/client/addons/locker/XEH_postInitClient.sqf @@ -1,7 +1,7 @@ #include "script_component.hpp" -if (isNil QGVAR(LockerClass)) then { [] call FUNC(initLockerClass); }; -if (isNil QGVAR(VArsenalClass)) then { [] call FUNC(initVAClass); }; +if (isNil QGVAR(LockerClass)) then { call FUNC(initLockerClass); }; +if (isNil QGVAR(VArsenalClass)) then { call FUNC(initVAClass); }; [QGVAR(initLocker), { GVAR(LockerClass) call ["init", []]; diff --git a/arma/client/addons/locker/functions/fnc_handleUIEvents.sqf b/arma/client/addons/locker/functions/fnc_handleUIEvents.sqf deleted file mode 100644 index 9cb8f26..0000000 --- a/arma/client/addons/locker/functions/fnc_handleUIEvents.sqf +++ /dev/null @@ -1,23 +0,0 @@ -#include "..\script_component.hpp" - -/* - * File: fnc_handleUIEvents.sqf - * Author: IDSolutions - * Date: 2026-01-28 - * Last Update: 2026-01-28 - * Public: No - * - * Description: - * Handles the UI events. - * - * Arguments: - * 0: [CONTROL] - The control that triggered the event - * 1: [BOOL] - Whether the event is from a confirm dialog - * 2: [STRING] - The message containing the event data - * - * Return Value: - * UI events handled [BOOL] - * - * Example: - * [] call forge_client_locker_fnc_handleUIEvents; - */ diff --git a/arma/client/addons/locker/functions/fnc_initLockerClass.sqf b/arma/client/addons/locker/functions/fnc_initLockerClass.sqf index 4d0e87c..cdcf28f 100644 --- a/arma/client/addons/locker/functions/fnc_initLockerClass.sqf +++ b/arma/client/addons/locker/functions/fnc_initLockerClass.sqf @@ -4,7 +4,7 @@ * File: fnc_initLockerClass.sqf * Author: IDSolutions * Date: 2025-12-17 - * Last Update: 2026-01-28 + * Last Update: 2026-01-30 * Public: No * * Description: @@ -18,26 +18,164 @@ * Locker class object [HASHMAP OBJECT] * * Example: - * [] call forge_client_locker_fnc_initLockerClass + * call forge_client_locker_fnc_initLockerClass */ #pragma hemtt ignore_variables ["_self"] -GVAR(LockerClass) = createHashMapObject [[ - ["#type", "ILockerClass"], - ["#create", { - _self set ["uid", (getPlayerUID player)]; - _self set ["locker", createHashMap]; - _self set ["isLoaded", false]; - _self set ["lastSave", time]; - }], - ["init", { - private _uid = _self get "uid"; +GVAR(LockerRepository) = compileFinal createHashMapFromArray [ + ["#type", "LockerRepository"], + ["get", { + params [["_key", "", [""]], ["_default", nil, [[], "", 0, false, createHashMap]]]; + private _locker = _self get "locker"; + _locker getOrDefault [_key, _default]; + }], + ["getCargo", { + params [["_container", objNull, [objNull]], ["_locker", createHashMap, [createHashMap]]]; - [SRPC(locker,requestInitLocker), [_uid, _locker]] call CFUNC(serverEvent); + private _cargoData = [ + ["item", getItemCargo _container], + ["weapon", getWeaponCargo _container], + ["magazine", getMagazineCargo _container], + ["backpack", getBackpackCargo _container] + ]; - systemChat format ["Locker loaded for %1", (name player)]; - diag_log "[FORGE:Client:Locker] Locker Class Initialized!"; + { + _x params ["_category", "_data"]; + _data params ["_classes", "_counts"]; + + { + private _class = _x; + private _count = _counts select _forEachIndex; + + _locker set [_class, createHashMapFromArray [ + ["amount", _count], + ["classname", _class], + ["category", _category] + ]]; + } forEach _classes; + } forEach _cargoData; + + _locker + }], + ["getContainerItems", { + params [["_container", objNull, [objNull]], ["_locker", createHashMap, [createHashMap]]]; + + private _allContainers = everyContainer _container; + { + _x params ["_containerClass", "_containerObj"]; + + private _isBackpack = isClass (configFile >> "CfgVehicles" >> _containerClass); + private _cfgWeapons = configFile >> "CfgWeapons" >> _containerClass; + private _itemInfoType = getNumber (_cfgWeapons >> "ItemInfo" >> "type"); + private _isVest = isClass _cfgWeapons && {_itemInfoType == 701}; + private _isUniform = isClass _cfgWeapons && {_itemInfoType == 801}; + + if (!_isBackpack && !_isVest && !_isUniform) then { continue; }; + + private _containerItems = getItemCargo _containerObj; + _containerItems params ["_classes", "_counts"]; + { + private _class = _x; + private _count = _counts select _forEachIndex; + private _existing = _locker getOrDefault [_class, createHashMap]; + private _existingCount = _existing getOrDefault ["amount", 0]; + + _locker set [_class, createHashMapFromArray [ + ["amount", _existingCount + _count], + ["classname", _class], + ["category", "item"] + ]]; + } forEach _classes; + + private _containerMags = getMagazineCargo _containerObj; + _containerMags params ["_classes", "_counts"]; + { + private _class = _x; + private _count = _counts select _forEachIndex; + private _existing = _locker getOrDefault [_class, createHashMap]; + private _existingCount = _existing getOrDefault ["amount", 0]; + + _locker set [_class, createHashMapFromArray [ + ["amount", _existingCount + _count], + ["classname", _class], + ["category", "magazine"] + ]]; + } forEach _classes; + + private _containerWeapons = getWeaponCargo _containerObj; + _containerWeapons params ["_classes", "_counts"]; + { + private _class = _x; + private _count = _counts select _forEachIndex; + private _existing = _locker getOrDefault [_class, createHashMap]; + private _existingCount = _existing getOrDefault ["amount", 0]; + + _locker set [_class, createHashMapFromArray [ + ["amount", _existingCount + _count], + ["classname", _class], + ["category", "weapon"] + ]]; + } forEach _classes; + } forEach _allContainers; + + _locker + }], + ["getAttachments", { + params [["_container", objNull, [objNull]], ["_locker", createHashMap, [createHashMap]]]; + + private _weaponItems = weaponsItemsCargo _container; + { + // private _weapon = _x param [0, ""]; + private _muzzle = _x param [1, ""]; + private _pointer = _x param [2, ""]; + private _optic = _x param [3, ""]; + private _primaryMag = _x param [4, ["", 0]]; + private _underbarrel = _x param [5, ""]; + private _bipod = _x param [6, ""]; + private _secondaryMag = _x param [7, ["", 0]]; + private _attachments = [_muzzle, _pointer, _optic, _underbarrel, _bipod] select {(_x isEqualType "") && {_x != ""}}; + { + private _existing = _locker getOrDefault [_x, createHashMap]; + private _existingCount = _existing getOrDefault ["amount", 0]; + + _locker set [_x, createHashMapFromArray [ + ["amount", _existingCount + 1], + ["classname", _x], + ["category", "item"] + ]]; + } forEach _attachments; + + if (_primaryMag isNotEqualTo ["", 0]) then { + _primaryMag params ["_magClass", "_ammoCount"]; + if (_magClass != "") then { + private _existing = _locker getOrDefault [_magClass, createHashMap]; + private _existingCount = _existing getOrDefault ["amount", 0]; + + _locker set [_magClass, createHashMapFromArray [ + ["amount", _existingCount + 1], + ["classname", _magClass], + ["category", "magazine"] + ]]; + }; + }; + + if (_secondaryMag isNotEqualTo ["", 0]) then { + _secondaryMag params ["_magClass", "_ammoCount"]; + if (_magClass != "") then { + private _existing = _locker getOrDefault [_magClass, createHashMap]; + private _existingCount = _existing getOrDefault ["amount", 0]; + + _locker set [_magClass, createHashMapFromArray [ + ["amount", _existingCount + 1], + ["classname", _magClass], + ["category", "magazine"] + ]]; + }; + }; + } forEach _weaponItems; + + _locker }], ["save", { private _uid = _self get "uid"; @@ -45,25 +183,109 @@ GVAR(LockerClass) = createHashMapObject [[ _self set ["lastSave", time]; }], + ["setEventHandlers", { + params [["_locker", objNull, [objNull]]]; + + _locker addEventHandler ["ContainerOpened", { + params ["_container", "_unit"]; + + private _index = GVAR(LockerClass) get "locker"; + + clearBackpackCargo _container; + clearItemCargo _container; + clearMagazineCargo _container; + clearWeaponCargo _container; + + { + private _amount = _y get "amount"; + private _category = _y get "category"; + private _className = _y get "classname"; + + switch (_category) do { + case "backpack": { _container addBackpackCargo [_className, _amount]; }; + case "item": { _container addItemCargo [_className, _amount]; }; + case "magazine": { _container addMagazineCargo [_className, _amount]; }; + case "weapon": { _container addWeaponCargo [_className, _amount]; }; + default { _container addItemCargo [_className, _amount]; }; + }; + } forEach _index; + }]; + + _locker addEventHandler ["ContainerClosed", { + params ["_container", "_unit"]; + + private _newLocker = createHashMap; + _newLocker = GVAR(LockerClass) call ["getCargo", [_container, _newLocker]]; + _newLocker = GVAR(LockerClass) call ["getContainerItems", [_container, _newLocker]]; + _newLocker = GVAR(LockerClass) call ["getAttachments", [_container, _newLocker]]; + + private _uid = getPlayerUID _unit; + [SRPC(locker,requestOverrideLocker), [_uid, _newLocker]] call CFUNC(serverEvent); + GVAR(LockerClass) set ["locker", _newLocker]; + }]; + }], + ["setup", { + private _lockers = (allVariables missionNamespace) select { + private _var = missionNamespace getVariable _x; + ("locker" in _x) && { _var isEqualType objNull } && { !isNull _var } && { _x isNotEqualTo "forge_locker_box" } + }; + + if (_lockers isEqualTo []) exitWith { diag_log "[FORGE:Client:Locker] No lockers found in missionNamespace."; }; + + { + private _globalLocker = missionNamespace getVariable _x; + private _pos = getPosASL _globalLocker; + private _vDir = vectorDir _globalLocker; + private _vUp = vectorUp _globalLocker; + + private _localLocker = createVehicleLocal ["Box_NATO_Equip_F", [0, 0, 0]]; + _localLocker setPosASL _pos; + _localLocker setVectorDirAndUp [_vDir, _vUp]; + _localLocker allowDamage false; + _localLocker setVariable ["isLocker", true]; + + clearBackpackCargo _localLocker; + clearItemCargo _localLocker; + clearMagazineCargo _localLocker; + clearWeaponCargo _localLocker; + + private _localVarName = format ["FORGE_Locker_Local_%1", _forEachIndex]; + _localLocker setVehicleVarName _localVarName; + missionNamespace setVariable [_localVarName, _localLocker]; + + _self call ["setEventHandlers", [_localLocker]]; + } forEach _lockers; + }], ["sync", { params [["_data", createHashMap, [createHashMap]]]; - private _locker = _self get "locker"; private _isLoaded = _self get "isLoaded"; + private _locker = _self get "locker"; if (_data isEqualTo createHashMap) exitWith { diag_log "[FORGE:Client:Locker] Empty data received for sync, skipping."; }; { _locker set [_x, _y]; } forEach _data; - _self set ["locker", _locker]; - - if !(_isLoaded) then { _self set ["isLoaded", true]; }; + if !(_isLoaded) then { _self set ["isLoaded", true]; _self call ["setup", []]; }; diag_log "[FORGE:Client:Locker] Sync completed"; - }], - ["get", { - params [["_key", "", [""]], ["_default", nil, [[], "", 0, false, createHashMap]]]; + }] +]; - private _locker = _self get "locker"; - _locker getOrDefault [_key, _default]; +GVAR(LockerClass) = createHashMapObject [[ + ["#base", GVAR(LockerRepository)], + ["#type", "ILockerClass"], + ["#create", { + _self set ["uid", (getPlayerUID player)]; + _self set ["isLoaded", false]; + _self set ["lastSave", time]; + _self set ["locker", createHashMap]; + }], + ["init", { + private _uid = _self get "uid"; + + [SRPC(locker,requestInitLocker), [_uid]] call CFUNC(serverEvent); + + systemChat format ["Locker loaded for %1", (name player)]; + diag_log "[FORGE:Client:Locker] Locker Class Initialized!"; }] ]]; diff --git a/arma/client/addons/locker/functions/fnc_initVAClass.sqf b/arma/client/addons/locker/functions/fnc_initVAClass.sqf index 264b3ee..81f28a8 100644 --- a/arma/client/addons/locker/functions/fnc_initVAClass.sqf +++ b/arma/client/addons/locker/functions/fnc_initVAClass.sqf @@ -4,7 +4,7 @@ * File: fnc_initVAClass.sqf * Author: IDSolutions * Date: 2025-12-16 - * Last Update: 2026-01-28 + * Last Update: 2026-01-30 * Public: No * * Description: @@ -18,7 +18,7 @@ * vArsenal class object [HASHMAP OBJECT] * * Example: - * [] call forge_client_locker_fnc_initVAClass; + * call forge_client_locker_fnc_initVAClass; */ #pragma hemtt ignore_variables ["_self"] @@ -32,9 +32,8 @@ GVAR(VArsenalClass) = createHashMapObject [[ }], ["init", { private _uid = _self get "uid"; - private _vArsenal = _self get "vArsenal"; - [SRPC(locker,requestInitVA), [_uid, _vArsenal]] call CFUNC(serverEvent); + [SRPC(locker,requestInitVA), [_uid]] call CFUNC(serverEvent); FORGE_Locker_Box = "ReammoBox_F" createVehicleLocal [0, 0, -999]; systemChat format ["VArsenal loaded for %1", (name player)]; diff --git a/arma/client/addons/locker/functions/fnc_openUI.sqf b/arma/client/addons/locker/functions/fnc_openUI.sqf deleted file mode 100644 index d779239..0000000 --- a/arma/client/addons/locker/functions/fnc_openUI.sqf +++ /dev/null @@ -1,21 +0,0 @@ -#include "..\script_component.hpp" - -/* - * File: fnc_openUI.sqf - * Author: IDSolutions - * Date: 2026-01-28 - * Last Update: 2026-01-28 - * Public: No - * - * Description: - * Opens the player locker interaction interface. - * - * Arguments: - * None - * - * Return Value: - * UI opened [BOOL] - * - * Example: - * [] call forge_client_locker_fnc_openUI; - */ diff --git a/arma/client/addons/notifications/XEH_postInitClient.sqf b/arma/client/addons/notifications/XEH_postInitClient.sqf index 6dc4bcd..072b241 100644 --- a/arma/client/addons/notifications/XEH_postInitClient.sqf +++ b/arma/client/addons/notifications/XEH_postInitClient.sqf @@ -4,8 +4,8 @@ EGVAR(actor,ActorClass) get "isLoaded"; }, { ("NotificationHudLayer" call BFUNC(rscLayer)) cutRsc ["RscNotifications", "PLAIN"]; - [] call FUNC(openUI); - if (isNil QGVAR(NotificationClass)) then { [] call FUNC(initNotificationClass); }; + call FUNC(openUI); + if (isNil QGVAR(NotificationClass)) then { call FUNC(initNotificationClass); }; }] call CFUNC(waitUntilAndExecute); [QGVAR(recieveNotification), { diff --git a/arma/client/addons/notifications/functions/fnc_handleUIEvents.sqf b/arma/client/addons/notifications/functions/fnc_handleUIEvents.sqf index d206206..7c84d95 100644 --- a/arma/client/addons/notifications/functions/fnc_handleUIEvents.sqf +++ b/arma/client/addons/notifications/functions/fnc_handleUIEvents.sqf @@ -4,7 +4,7 @@ * File: fnc_handleUIEvents.sqf * Author: IDSolutions * Date: 2026-01-28 - * Last Update: 2026-01-28 + * Last Update: 2026-01-30 * Public: No * * Description: @@ -19,7 +19,7 @@ * UI events handled [BOOL] * * Example: - * [] call forge_client_notifications_fnc_handleUIEvents; + * call forge_client_notifications_fnc_handleUIEvents; */ params ["_control", "_isConfirmDialog", "_message"]; diff --git a/arma/client/addons/notifications/functions/fnc_initNotificationClass.sqf b/arma/client/addons/notifications/functions/fnc_initNotificationClass.sqf index e72601e..06ed9cc 100644 --- a/arma/client/addons/notifications/functions/fnc_initNotificationClass.sqf +++ b/arma/client/addons/notifications/functions/fnc_initNotificationClass.sqf @@ -4,7 +4,7 @@ * File: fnc_initNotificationClass.sqf * Author: IDSolutions * Date: 2026-01-28 - * Last Update: 2026-01-28 + * Last Update: 2026-01-30 * Public: No * * Description: @@ -18,7 +18,7 @@ * Notification class object [HASHMAP OBJECT] * * Example: - * [] call forge_client_notifications_fnc_initNotificationClass + * call forge_client_notifications_fnc_initNotificationClass */ #pragma hemtt ignore_variables ["_self"] diff --git a/arma/client/addons/notifications/functions/fnc_openUI.sqf b/arma/client/addons/notifications/functions/fnc_openUI.sqf index 0a4350b..f3af405 100644 --- a/arma/client/addons/notifications/functions/fnc_openUI.sqf +++ b/arma/client/addons/notifications/functions/fnc_openUI.sqf @@ -4,7 +4,7 @@ * File: fnc_openUI.sqf * Author: IDSolutions * Date: 2026-01-28 - * Last Update: 2026-01-28 + * Last Update: 2026-01-30 * Public: No * * Description: @@ -17,7 +17,7 @@ * UI opened [BOOL] * * Example: - * [] call forge_client_notifications_fnc_openUI; + * call forge_client_notifications_fnc_openUI; */ private _display = uiNamespace getVariable ["RscNotifications", nil]; diff --git a/arma/client/addons/org/XEH_postInitClient.sqf b/arma/client/addons/org/XEH_postInitClient.sqf index e6c9147..7ba023a 100644 --- a/arma/client/addons/org/XEH_postInitClient.sqf +++ b/arma/client/addons/org/XEH_postInitClient.sqf @@ -1,6 +1,6 @@ #include "script_component.hpp" -if (isNil QGVAR(OrgClass)) then { [] call FUNC(initOrgClass); }; +if (isNil QGVAR(OrgClass)) then { call FUNC(initOrgClass); }; [QGVAR(initOrg), { GVAR(OrgClass) call ["init", []]; diff --git a/arma/client/addons/org/functions/fnc_handleUIEvents.sqf b/arma/client/addons/org/functions/fnc_handleUIEvents.sqf index 89ac8f8..170b54c 100644 --- a/arma/client/addons/org/functions/fnc_handleUIEvents.sqf +++ b/arma/client/addons/org/functions/fnc_handleUIEvents.sqf @@ -11,7 +11,7 @@ * None * * Example: - * [] call forge_client_org_fnc_handleUIEvents; + * call forge_client_org_fnc_handleUIEvents; * * Public: No */ diff --git a/arma/client/addons/org/functions/fnc_initOrgClass.sqf b/arma/client/addons/org/functions/fnc_initOrgClass.sqf index df7d6f1..3fb8179 100644 --- a/arma/client/addons/org/functions/fnc_initOrgClass.sqf +++ b/arma/client/addons/org/functions/fnc_initOrgClass.sqf @@ -11,7 +11,7 @@ * None * * Examples: - * [] call forge_client_org_fnc_initOrgClass + * call forge_client_org_fnc_initOrgClass * * Public: Yes */ diff --git a/arma/client/addons/org/functions/fnc_openUI.sqf b/arma/client/addons/org/functions/fnc_openUI.sqf index f36395d..7506dd4 100644 --- a/arma/client/addons/org/functions/fnc_openUI.sqf +++ b/arma/client/addons/org/functions/fnc_openUI.sqf @@ -11,13 +11,13 @@ * None * * Example: - * [] call forge_client_org_fnc_openUI; + * call forge_client_org_fnc_openUI; * * Public: No */ -private _display = (findDisplay 46) createDisplay "RscOrg"; -private _ctrl = (_display displayCtrl 1003); +private _display = createDialog ["RscOrg", true]; +private _ctrl = _display displayCtrl 1003; _ctrl ctrlAddEventHandler ["JSDialog", { params ["_control", "_isConfirmDialog", "_message"]; diff --git a/arma/client/extra/example_addon/functions/fnc_empty.sqf b/arma/client/extra/example_addon/functions/fnc_empty.sqf index 07b0282..73c0a37 100644 --- a/arma/client/extra/example_addon/functions/fnc_empty.sqf +++ b/arma/client/extra/example_addon/functions/fnc_empty.sqf @@ -10,7 +10,7 @@ * None * * Example: - * [] call forge_client_addonName_fnc_empty; + * call forge_client_addonName_fnc_empty; * * Public: No */ diff --git a/arma/server/addons/actor/functions/fnc_initActorStore.sqf b/arma/server/addons/actor/functions/fnc_initActorStore.sqf index de6e2e9..94b527a 100644 --- a/arma/server/addons/actor/functions/fnc_initActorStore.sqf +++ b/arma/server/addons/actor/functions/fnc_initActorStore.sqf @@ -4,7 +4,7 @@ * File: fnc_initActorStore.sqf * Author: IDSolutions * Date: 2025-12-17 - * Last Update: 2026-01-28 + * Last Update: 2026-01-30 * Public: Yes * * Description: @@ -18,7 +18,7 @@ * Actor store object [HASHMAP OBJECT] * * Example: - * [] call forge_server_actor_fnc_initActorStore + * call forge_server_actor_fnc_initActorStore */ #pragma hemtt ignore_variables ["_self"] diff --git a/arma/server/addons/bank/functions/fnc_initBankStore.sqf b/arma/server/addons/bank/functions/fnc_initBankStore.sqf index 58aea83..2472bfe 100644 --- a/arma/server/addons/bank/functions/fnc_initBankStore.sqf +++ b/arma/server/addons/bank/functions/fnc_initBankStore.sqf @@ -4,7 +4,7 @@ * File: fnc_initBankStore.sqf * Author: IDSolutions * Date: 2025-12-17 - * Last Update: 2026-01-28 + * Last Update: 2026-01-30 * Public: Yes * * Description: @@ -18,7 +18,7 @@ * Bank store object [HASHMAP OBJECT] * * Example: - * [] call forge_server_bank_fnc_initBankStore + * call forge_server_bank_fnc_initBankStore */ #pragma hemtt ignore_variables ["_self"] diff --git a/arma/server/addons/common/functions/fnc_baseStore.sqf b/arma/server/addons/common/functions/fnc_baseStore.sqf index 67328d9..b4811f3 100644 --- a/arma/server/addons/common/functions/fnc_baseStore.sqf +++ b/arma/server/addons/common/functions/fnc_baseStore.sqf @@ -4,7 +4,7 @@ * File: fnc_baseStore.sqf * Author: IDSolutions * Date: 2026-01-08 - * Last Update: 2026-01-28 + * Last Update: 2026-01-30 * Public: No * * Description: @@ -17,7 +17,7 @@ * Base store [HASHMAP] * * Example: - * [] call forge_x_component_fnc_myFunction + * call forge_x_component_fnc_myFunction */ #pragma hemtt ignore_variables ["_self"] diff --git a/arma/server/addons/economy/XEH_preInit.sqf b/arma/server/addons/economy/XEH_preInit.sqf index d07df45..8a385c3 100644 --- a/arma/server/addons/economy/XEH_preInit.sqf +++ b/arma/server/addons/economy/XEH_preInit.sqf @@ -6,9 +6,9 @@ PREP_RECOMPILE_END; // private _category = [QUOTE(MOD_NAME), LLSTRING(displayName)]; -if (isNil QGVAR(MEconomyStore)) then { [] call FUNC(initMEconomyStore); }; -if (isNil QGVAR(FEconomyStore)) then { [] call FUNC(initFEconomyStore); }; -// if (isNil QGVAR(SEconomyStore)) then { [] call FUNC(initSEconomyStore); }; +if (isNil QGVAR(MEconomyStore)) then { call FUNC(initMEconomyStore); }; +if (isNil QGVAR(FEconomyStore)) then { call FUNC(initFEconomyStore); }; +// if (isNil QGVAR(SEconomyStore)) then { call FUNC(initSEconomyStore); }; [QGVAR(FuelStart), { params ["_source", "_target", "_unit"]; diff --git a/arma/server/addons/extension/XEH_preStart.sqf b/arma/server/addons/extension/XEH_preStart.sqf index 0228885..a51262a 100644 --- a/arma/server/addons/extension/XEH_preStart.sqf +++ b/arma/server/addons/extension/XEH_preStart.sqf @@ -1,3 +1,2 @@ #include "script_component.hpp" - #include "XEH_PREP.hpp" diff --git a/arma/server/addons/garage/XEH_postInit.sqf b/arma/server/addons/garage/XEH_postInit.sqf index 13676d7..c45c803 100644 --- a/arma/server/addons/garage/XEH_postInit.sqf +++ b/arma/server/addons/garage/XEH_postInit.sqf @@ -1,3 +1,3 @@ #include "script_component.hpp" -[] call FUNC(initGarage); +call FUNC(initGarage); diff --git a/arma/server/addons/garage/XEH_preInit.sqf b/arma/server/addons/garage/XEH_preInit.sqf index a9fecfe..ea3c7a5 100644 --- a/arma/server/addons/garage/XEH_preInit.sqf +++ b/arma/server/addons/garage/XEH_preInit.sqf @@ -7,10 +7,10 @@ PREP_RECOMPILE_END; // private _category = [QUOTE(MOD_NAME), LLSTRING(displayName)]; [QGVAR(requestInitGarage), { - params [["_uid", "", [""]], ["_garage", createHashMap, [createHashMap]]]; + params [["_uid", "", [""]]]; if (_uid isEqualTo "") exitWith { diag_log "[FORGE:Server:Garage] Empty/Invalid UID!" }; - GVAR(GarageStore) call ["init", [_uid, _garage]]; + GVAR(GarageStore) call ["init", [_uid]]; }] call CFUNC(addEventHandler); [QGVAR(requestGetGarage), { @@ -62,12 +62,10 @@ PREP_RECOMPILE_END; }] call CFUNC(addEventHandler); [QGVAR(requestInitVG), { - params [["_uid", "", [""]], ["_vGarage", createHashMap, [createHashMap]]]; + params [["_uid", "", [""]]]; if (_uid isEqualTo "") exitWith { diag_log "[FORGE:Server:VGarage] Empty/Invalid UID!" }; - if (_vGarage isEqualTo createHashMap) exitWith { diag_log "[FORGE:Server:VGarage] Empty/Invalid VGarage data!" }; - - GVAR(VGarageStore) call ["init", [_uid, _vGarage]]; + GVAR(VGarageStore) call ["init", [_uid]]; }] call CFUNC(addEventHandler); [QGVAR(requestGetVG), { diff --git a/arma/server/addons/garage/functions/fnc_initGarage.sqf b/arma/server/addons/garage/functions/fnc_initGarage.sqf index a1e5596..66d0210 100644 --- a/arma/server/addons/garage/functions/fnc_initGarage.sqf +++ b/arma/server/addons/garage/functions/fnc_initGarage.sqf @@ -4,7 +4,7 @@ * File: fnc_initGarage.sqf * Author: IDSolutions * Date: 2025-12-17 - * Last Update: 2026-01-28 + * Last Update: 2026-01-30 * Public: No * * Description: @@ -17,7 +17,7 @@ * None * * Example: - * [] call forge_server_garage_fnc_initGarage + * call forge_server_garage_fnc_initGarage */ // TODO: Refactor to read from placed objects and their variables instead of missionConfig entries. diff --git a/arma/server/addons/garage/functions/fnc_initGarageStore.sqf b/arma/server/addons/garage/functions/fnc_initGarageStore.sqf index b46fbf6..d8eb769 100644 --- a/arma/server/addons/garage/functions/fnc_initGarageStore.sqf +++ b/arma/server/addons/garage/functions/fnc_initGarageStore.sqf @@ -4,7 +4,7 @@ * File: fnc_initGarageStore.sqf * Author: IDSolutions * Date: 2025-12-17 - * Last Update: 2026-01-28 + * Last Update: 2026-01-30 * Public: No * * Description: @@ -18,7 +18,7 @@ * Garage store object [HASHMAP OBJECT] * * Example: - * [] call forge_server_garage_fnc_initGarageStore + * call forge_server_garage_fnc_initGarageStore */ #pragma hemtt ignore_variables ["_self"] diff --git a/arma/server/addons/garage/functions/fnc_initVGStore.sqf b/arma/server/addons/garage/functions/fnc_initVGStore.sqf index d7fe923..2197d21 100644 --- a/arma/server/addons/garage/functions/fnc_initVGStore.sqf +++ b/arma/server/addons/garage/functions/fnc_initVGStore.sqf @@ -4,7 +4,7 @@ * File: fnc_initVGStore.sqf * Author: IDSolutions * Date: 2025-12-17 - * Last Update: 2026-01-28 + * Last Update: 2026-01-30 * Public: No * * Description: @@ -18,7 +18,7 @@ * VG store object [HASHMAP OBJECT] * * Example: - * [] call forge_server_garage_fnc_initVGStore + * call forge_server_garage_fnc_initVGStore */ #pragma hemtt ignore_variables ["_self"] diff --git a/arma/server/addons/locker/XEH_postInit.sqf b/arma/server/addons/locker/XEH_postInit.sqf index 9571a80..4125916 100644 --- a/arma/server/addons/locker/XEH_postInit.sqf +++ b/arma/server/addons/locker/XEH_postInit.sqf @@ -1,3 +1,3 @@ #include "script_component.hpp" -[] call FUNC(initLocker); +call FUNC(initLocker); diff --git a/arma/server/addons/locker/XEH_preInit.sqf b/arma/server/addons/locker/XEH_preInit.sqf index 13cc7a7..bf69209 100644 --- a/arma/server/addons/locker/XEH_preInit.sqf +++ b/arma/server/addons/locker/XEH_preInit.sqf @@ -7,10 +7,10 @@ PREP_RECOMPILE_END; // private _category = [QUOTE(MOD_NAME), LLSTRING(displayName)]; [QGVAR(requestInitLocker), { - params [["_uid", "", [""]], ["_locker", createHashMap, [createHashMap]]]; + params [["_uid", "", [""]]]; if (_uid isEqualTo "") exitWith { diag_log "[FORGE:Server:Locker] Empty/Invalid UID!" }; - GVAR(LockerStore) call ["init", [_uid, _locker]]; + GVAR(LockerStore) call ["init", [_uid]]; }] call CFUNC(addEventHandler); [QGVAR(requestGetLocker), { @@ -54,6 +54,16 @@ PREP_RECOMPILE_END; [CRPC(locker,responseSyncLocker), [_finalData], _player] call CFUNC(targetEvent); }] call CFUNC(addEventHandler); +[QGVAR(requestOverrideLocker), { + params [["_uid", "", [""]], ["_data", createHashMap, [createHashMap]]]; + + if (_uid isEqualTo "") exitWith { diag_log "[FORGE:Server:Locker] Empty/Invalid UID!" }; + GVAR(LockerRegistry) set [_uid, _data]; + + private _player = [_uid] call EFUNC(common,getPlayer); + [CRPC(locker,responseSyncLocker), [_data], _player] call CFUNC(targetEvent); +}] call CFUNC(addEventHandler); + [QGVAR(requestRemoveLocker), { params [["_uid", "", [""]]]; @@ -62,22 +72,16 @@ PREP_RECOMPILE_END; }] call CFUNC(addEventHandler); [QGVAR(requestInitVA), { - params [["_uid", "", [""]], ["_vArsenal", createHashMap, [createHashMap]]]; + params [["_uid", "", [""]]]; if (_uid isEqualTo "") exitWith { diag_log "[FORGE:Server:VArsenal] Empty/Invalid UID!" }; - if (_vArsenal isEqualTo createHashMap) exitWith { diag_log "[FORGE:Server:VArsenal] Empty/Invalid VArsenal data!" }; - - GVAR(VArsenalStore) call ["init", [_uid, _vArsenal]]; + GVAR(VArsenalStore) call ["init", [_uid]]; }] call CFUNC(addEventHandler); [QGVAR(requestGetVA), { params [["_uid", "", [""]]]; if (_uid isEqualTo "") exitWith { diag_log "[FORGE:Server:VArsenal] Empty/Invalid UID!" }; - - private _session = EGVAR(actor,PlayerSessions) getOrDefault [_uid, nil]; - if (isNil "_session") exitWith { diag_log "[FORGE:Server:VArsenal] Empty/Invalid Session!" }; - GVAR(VArsenalStore) call ["get", [GVAR(VArsenalRegistry), "owned:locker:fetch", _uid]]; }] call CFUNC(addEventHandler); @@ -86,9 +90,6 @@ PREP_RECOMPILE_END; if (_uid isEqualTo "" || _key isEqualTo "") exitWith { diag_log "[FORGE:Server:VArsenal] Empty/Invalid UID or Key!" }; - private _session = EGVAR(actor,PlayerSessions) getOrDefault [_uid, nil]; - if (isNil "_session") exitWith { diag_log "[FORGE:Server:VArsenal] Empty/Invalid Session!" }; - private _hashMap = GVAR(VArsenalStore) call ["set", [GVAR(VArsenalRegistry), "owned:locker:update", _uid, _key, _value, _sync]]; private _player = [_uid] call EFUNC(common,getPlayer); @@ -101,9 +102,6 @@ PREP_RECOMPILE_END; if (_uid isEqualTo "") exitWith { diag_log "[FORGE:Server:VArsenal] Empty/Invalid UID!" }; if ((_fieldValuePairs isEqualTo createHashMap) || !(_fieldValuePairs isEqualType createHashMap)) exitWith { diag_log "[FORGE:Server:VArsenal] Empty/Invalid field pairs!" }; - private _session = EGVAR(actor,PlayerSessions) getOrDefault [_uid, nil]; - if (isNil "_session") exitWith { diag_log "[FORGE:Server:VArsenal] Empty/Invalid Session!" }; - private _hashMap = GVAR(VArsenalStore) call ["mset", [GVAR(VArsenalRegistry), "owned:locker:update", _uid, _fieldValuePairs, _sync]]; private _player = [_uid] call EFUNC(common,getPlayer); @@ -115,9 +113,6 @@ PREP_RECOMPILE_END; if (_uid isEqualTo "") exitWith { diag_log "[FORGE:Server:VArsenal] Empty/Invalid UID!" }; - private _session = EGVAR(actor,PlayerSessions) getOrDefault [_uid, nil]; - if (isNil "_session") exitWith { diag_log "[FORGE:Server:VArsenal] Empty/Invalid Session!" }; - private _finalData = GVAR(VArsenalStore) call ["save", [GVAR(VArsenalRegistry), "owned:locker:update", _uid]]; private _player = [_uid] call EFUNC(common,getPlayer); diff --git a/arma/server/addons/locker/functions/fnc_initLocker.sqf b/arma/server/addons/locker/functions/fnc_initLocker.sqf index bdd2a76..fc81532 100644 --- a/arma/server/addons/locker/functions/fnc_initLocker.sqf +++ b/arma/server/addons/locker/functions/fnc_initLocker.sqf @@ -4,11 +4,12 @@ * File: fnc_initLocker.sqf * Author: IDSolutions * Date: 2025-12-17 - * Last Update: 2026-01-28 + * Last Update: 2026-01-30 * Public: No * * Description: - * Initializes all lockers defined in the mission configuration. + * Initializes lockers by hiding editor-placed global locker objects. + * Each client will create their own local instance. * * Arguments: * None @@ -17,69 +18,20 @@ * None * * Example: - * [] call forge_server_locker_fnc_initLocker + * call forge_server_locker_fnc_initLocker */ -// TODO: Refactor to read from placed objects and their variables instead of missionConfig entries. +private _lockers = (allVariables missionNamespace) select { + private _var = missionNamespace getVariable _x; + ("locker" in _x) && { _var isEqualType objNull } && { !isNull _var } && { _x isNotEqualTo "forge_locker_box" } +}; -private _mC = "FORGE_CfgLockers"; -private _lockers = "true" configClasses (missionConfigFile >> "FORGE_CfgLockers" >> "lockers"); +if (_lockers isEqualTo []) exitWith { diag_log "[FORGE:Server:Locker] No editor-placed lockers found."; }; +diag_log format ["[FORGE:Server:Locker] Found %1 editor-placed locker(s), hiding globally", count _lockers]; { - private _configName = configName(_x); - private _className = (missionConfigFile >> _mC >> "lockers" >> _configName >> "className") call BFUNC(getCfgData); - private _pos = (missionConfigFile >> _mC >> "lockers" >> _configName >> "pos") call BFUNC(getCfgData); - private _dir = (missionConfigFile >> _mC >> "lockers" >> _configName >> "dir") call BFUNC(getCfgData); + private _locker = missionNamespace getVariable _x; + _locker hideObjectGlobal true; - private _locker = createVehicle [_className, [0, 0, 0]]; - // private _prefix = "FORGE_Locker"; - // private _varName = format ["%1_%2", _prefix, _forEachIndex]; - - _locker setPosATL _pos; - _locker setDir _dir; - _locker allowDamage false; - _locker setVariable ["isLocker", true, true]; - - clearBackpackCargoGlobal _locker; - clearItemCargoGlobal _locker; - clearMagazineCargoGlobal _locker; - clearWeaponCargoGlobal _locker; - - // private _pLocker = vehicle _locker; - // _pLocker setVehicleVarName _varName; - // missionNamespace setVariable [_varName, _pLocker, true]; - - // _locker addEventHandler ["ContainerOpened", { - // params ["_container", "_unit"]; - - // private _uid = getPlayerUID _unit; - // private _pLocker = GVAR(LockerRegistry) get _uid; - - // diag_log text format ["[FORGE] (locker) INFO: Container opened, refreshing inventory: %1 w/ %2", _container, _pLocker]; - - // // Clear existing cargo - // clearBackpackCargo _container; - // clearItemCargo _container; - // clearMagazineCargo _container; - // clearWeaponCargo _container; - - // // Repopulate with current locker items - // { - // private _amount = _y get "amount"; - // private _category = _y get "category"; - // private _className = _y get "classname"; - - // switch (_category) do { - // case "backpack": { _container addBackpackCargo [_className, _amount]; }; - // case "item": { _container addItemCargo [_className, _amount]; }; - // case "magazine": { _container addMagazineCargo [_className, _amount]; }; - // case "weapon": { _container addWeaponCargo [_className, _amount]; }; - // default { _container addItemCargo [_className, _amount]; }; - // }; - // } forEach _pLocker; - - // diag_log text format ["[FORGE] (locker) INFO: Inventory refreshed"]; - // }]; - - diag_log format ["[FORGE:Server:Locker] ClassName: %1 Pos: %2 Dir: %3", _className, _pos, _dir]; + diag_log format ["[FORGE:Server:Locker] Hidden locker: %1 at position %2", _x, getPosASL _locker]; } forEach _lockers; diff --git a/arma/server/addons/locker/functions/fnc_initLockerStore.sqf b/arma/server/addons/locker/functions/fnc_initLockerStore.sqf index 53cdd5f..7bde051 100644 --- a/arma/server/addons/locker/functions/fnc_initLockerStore.sqf +++ b/arma/server/addons/locker/functions/fnc_initLockerStore.sqf @@ -4,7 +4,7 @@ * File: fnc_initLockerStore.sqf * Author: IDSolutions * Date: 2025-12-17 - * Last Update: 2026-01-28 + * Last Update: 2026-01-30 * Public: No * * Description: @@ -18,7 +18,7 @@ * Locker store object [HASHMAP OBJECT] * * Example: - * [] call forge_server_locker_fnc_initLockerStore + * call forge_server_locker_fnc_initLockerStore */ #pragma hemtt ignore_variables ["_self"] diff --git a/arma/server/addons/locker/functions/fnc_initVAStore.sqf b/arma/server/addons/locker/functions/fnc_initVAStore.sqf index 7460a19..2ae16d3 100644 --- a/arma/server/addons/locker/functions/fnc_initVAStore.sqf +++ b/arma/server/addons/locker/functions/fnc_initVAStore.sqf @@ -4,7 +4,7 @@ * File: fnc_initVAStore.sqf * Author: IDSolutions * Date: 2025-12-17 - * Last Update: 2026-01-28 + * Last Update: 2026-01-30 * Public: No * * Description: @@ -18,7 +18,7 @@ * VA store object [HASHMAP OBJECT] * * Example: - * [] call forge_server_locker_fnc_initVAStore + * call forge_server_locker_fnc_initVAStore */ #pragma hemtt ignore_variables ["_self"] diff --git a/arma/server/addons/main/XEH_postInit.sqf b/arma/server/addons/main/XEH_postInit.sqf index 23ac945..1b295d1 100644 --- a/arma/server/addons/main/XEH_postInit.sqf +++ b/arma/server/addons/main/XEH_postInit.sqf @@ -1,3 +1,3 @@ #include "script_component.hpp" -[] call FUNC(initStores); +call FUNC(initStores); diff --git a/arma/server/addons/main/functions/fnc_initStores.sqf b/arma/server/addons/main/functions/fnc_initStores.sqf index 6047574..275ffcc 100644 --- a/arma/server/addons/main/functions/fnc_initStores.sqf +++ b/arma/server/addons/main/functions/fnc_initStores.sqf @@ -11,31 +11,31 @@ * None * * Example: - * [] call forge_server_main_fnc_initStores; + * call forge_server_main_fnc_initStores; * * Public: No */ // Base -if (isNil QEGVAR(common,BaseStore)) then { [] call EFUNC(common,baseStore); }; +if (isNil QEGVAR(common,BaseStore)) then { call EFUNC(common,baseStore); }; // Actor -if (isNil QEGVAR(actor,ActorStore)) then { [] call EFUNC(actor,initActorStore); }; +if (isNil QEGVAR(actor,ActorStore)) then { call EFUNC(actor,initActorStore); }; // Bank -if (isNil QEGVAR(bank,BankStore)) then { [] call EFUNC(bank,initBankStore); }; +if (isNil QEGVAR(bank,BankStore)) then { call EFUNC(bank,initBankStore); }; // Garage -if (isNil QEGVAR(garage,GarageStore)) then { [] call EFUNC(garage,initGarageStore); }; +if (isNil QEGVAR(garage,GarageStore)) then { call EFUNC(garage,initGarageStore); }; // VGarage -if (isNil QEGVAR(garage,VGarageStore)) then { [] call EFUNC(garage,initVGStore); }; +if (isNil QEGVAR(garage,VGarageStore)) then { call EFUNC(garage,initVGStore); }; // Locker -if (isNil QEGVAR(locker,LockerStore)) then { [] call EFUNC(locker,initLockerStore); }; +if (isNil QEGVAR(locker,LockerStore)) then { call EFUNC(locker,initLockerStore); }; // VArsenal -if (isNil QEGVAR(locker,VArsenalStore)) then { [] call EFUNC(locker,initVAStore); }; +if (isNil QEGVAR(locker,VArsenalStore)) then { call EFUNC(locker,initVAStore); }; // Org -if (isNil QEGVAR(org,OrgStore)) then { [] call EFUNC(org,initOrgStore); }; +if (isNil QEGVAR(org,OrgStore)) then { call EFUNC(org,initOrgStore); }; diff --git a/arma/server/addons/org/functions/fnc_initOrgStore.sqf b/arma/server/addons/org/functions/fnc_initOrgStore.sqf index 7c2a671..30ebbd9 100644 --- a/arma/server/addons/org/functions/fnc_initOrgStore.sqf +++ b/arma/server/addons/org/functions/fnc_initOrgStore.sqf @@ -11,7 +11,7 @@ * None * * Examples: - * [] call forge_server_org_fnc_initOrgStore + * call forge_server_org_fnc_initOrgStore * * Public: Yes */ @@ -63,9 +63,9 @@ GVAR(OrgStore) = createHashMapObject [[ // _finalOrg set ["assets", _assets]; GVAR(OrgRegistry) set [_orgID, _finalOrg, true]; - [CRPC(org,responseInitOrg), [_finalOrg], _player] call CFUNC(targetEvent); + ["INFO", format ["Found org for %1", _uid], nil, nil] call EFUNC(common,log); _finalOrg }], ["default", { diff --git a/lib/models/src/v_garage.rs b/lib/models/src/v_garage.rs index a080d33..6e54df9 100644 --- a/lib/models/src/v_garage.rs +++ b/lib/models/src/v_garage.rs @@ -23,6 +23,10 @@ pub struct VGarage { impl VGarage { pub fn new() -> Self { + Self::default_unlocks() + } + + fn default_unlocks() -> Self { Self { cars: vec!["B_Quadbike_01_F".to_string()], armor: Vec::new(), diff --git a/lib/models/src/v_locker.rs b/lib/models/src/v_locker.rs index ae204ba..4ad24e4 100644 --- a/lib/models/src/v_locker.rs +++ b/lib/models/src/v_locker.rs @@ -19,6 +19,10 @@ pub struct VLocker { impl VLocker { pub fn new() -> Self { + Self::default_unlocks() + } + + fn default_unlocks() -> Self { Self { items: vec![ "FirstAidKit".to_string(),