diff --git a/arma/client/addons/actor/XEH_PREP.hpp b/arma/client/addons/actor/XEH_PREP.hpp index 0dcc312..97e1950 100644 --- a/arma/client/addons/actor/XEH_PREP.hpp +++ b/arma/client/addons/actor/XEH_PREP.hpp @@ -1,3 +1,3 @@ PREP(handleUIEvents); -PREP(initActorClass); +PREP(initRepository); PREP(openUI); diff --git a/arma/client/addons/actor/XEH_postInitClient.sqf b/arma/client/addons/actor/XEH_postInitClient.sqf index 12c69b1..483c48c 100644 --- a/arma/client/addons/actor/XEH_postInitClient.sqf +++ b/arma/client/addons/actor/XEH_postInitClient.sqf @@ -23,17 +23,17 @@ player addEventHandler ["Respawn", { [SRPC(economy,onRespawn), [_unit, _corpse, _uid]] call CFUNC(serverEvent); }]; -if (isNil QGVAR(ActorClass)) then { call FUNC(initActorClass); }; +if (isNil QGVAR(ActorRepository)) then { call FUNC(initRepository); }; [QGVAR(initActor), { - GVAR(ActorClass) call ["init", []]; + GVAR(ActorRepository) call ["init", []]; }] call CFUNC(addEventHandler); [QGVAR(onActorRespawn), { params [["_loadout", [], [[]]], ["_medSpawnPos", [0,0,0], [[]]], ["_medSpawnDir", 0, [0]]]; private _message = ["warning", "Medical Alert", "You have been revived at a medical facility.", 5000]; - EGVAR(notifications,NotificationClass) call ["create", _message]; + EGVAR(notifications,NotificationService) call ["create", _message]; player setUnitLoadout _loadout; player setPosATL _medSpawnPos; @@ -53,14 +53,14 @@ if (isNil QGVAR(ActorClass)) then { call FUNC(initActorClass); }; [QGVAR(responseInitActor), { params [["_data", createHashMap, [createHashMap]]]; - GVAR(ActorClass) call ["sync", [_data, true]]; + GVAR(ActorRepository) call ["sync", [_data, true]]; cutText ["", "PLAIN", 1]; }] call CFUNC(addEventHandler); [QGVAR(responseSyncActor), { params [["_data", createHashMap, [createHashMap]], ["_jip", false, [false]]]; - GVAR(ActorClass) call ["sync", [_data, _jip]]; + GVAR(ActorRepository) call ["sync", [_data, _jip]]; }] call CFUNC(addEventHandler); [QGVAR(initActor), []] call CFUNC(localEvent); @@ -68,6 +68,6 @@ if (isNil QGVAR(ActorClass)) then { call FUNC(initActorClass); }; [{ GETVAR(player,FORGE_isLoaded,false) }, { - private _holster = GVAR(ActorClass) call ["get", ["holster", true]]; + private _holster = GVAR(ActorRepository) call ["get", ["holster", true]]; if (_holster) then { [player] call AFUNC(weaponselect,putWeaponAway); }; }] call CFUNC(waitUntilAndExecute); diff --git a/arma/client/addons/actor/functions/fnc_handleUIEvents.sqf b/arma/client/addons/actor/functions/fnc_handleUIEvents.sqf index 869b624..9894313 100644 --- a/arma/client/addons/actor/functions/fnc_handleUIEvents.sqf +++ b/arma/client/addons/actor/functions/fnc_handleUIEvents.sqf @@ -31,7 +31,7 @@ private _data = _alert get "data"; diag_log format ["[FORGE:Client:Actor] Handling UI event: %1 with data: %2", _event, _data]; switch (_event) do { - case "actor::get::actions": { GVAR(ActorClass) call ["getNearbyActions", [_control]]; }; + case "actor::get::actions": { GVAR(ActorRepository) call ["getNearbyActions", [_control]]; }; case "actor::close::menu": { closeDialog 1; }; case "actor::open::atm": { [true] spawn EFUNC(bank,openUI); }; case "actor::open::bank": { [] spawn EFUNC(bank,openUI); }; diff --git a/arma/client/addons/actor/functions/fnc_initActorClass.sqf b/arma/client/addons/actor/functions/fnc_initRepository.sqf similarity index 88% rename from arma/client/addons/actor/functions/fnc_initActorClass.sqf rename to arma/client/addons/actor/functions/fnc_initRepository.sqf index 294d20f..71cdd8a 100644 --- a/arma/client/addons/actor/functions/fnc_initActorClass.sqf +++ b/arma/client/addons/actor/functions/fnc_initRepository.sqf @@ -1,29 +1,27 @@ #include "..\script_component.hpp" /* - * File: fnc_initActorClass.sqf + * File: fnc_initRepository.sqf * Author: IDSolutions - * Date: 2026-01-28 - * Last Update: 2026-03-25 - * Public: Yes + * Date: 2026-03-27 + * Public: No * * Description: - * Initializes the actor class for managing player data. - * Provides methods for saving, loading, and applying actor data. + * Initializes the actor repository for managing player actor data. * * Arguments: * None * * Return Value: - * Actor class object [HASHMAP OBJECT] + * Actor repository object [HASHMAP OBJECT] * * Example: - * call forge_client_actor_fnc_initActorClass + * call forge_client_actor_fnc_initRepository; */ #pragma hemtt ignore_variables ["_self"] -GVAR(ActorBaseClass) = compileFinal createHashMapFromArray [ - ["#type", "ActorBaseClass"], +GVAR(ActorRepositoryBaseClass) = compileFinal createHashMapFromArray [ + ["#type", "ActorRepositoryBaseClass"], ["#create", compileFinal { _self set ["uid", getPlayerUID player]; _self set ["actor", createHashMap]; @@ -35,8 +33,8 @@ GVAR(ActorBaseClass) = compileFinal createHashMapFromArray [ [SRPC(actor,requestInitActor), [_uid]] call CFUNC(serverEvent); _self set ["lastSave", time]; - systemChat format ["Actor loaded for %1", (name player)]; - diag_log "[FORGE:Client:Actor] Actor Class Initialized!"; + systemChat format ["Actor loaded for %1", name player]; + diag_log "[FORGE:Client:Actor] Actor Repository Initialized!"; }], ["save", compileFinal { params [["_sync", false, [false]]]; @@ -69,29 +67,23 @@ GVAR(ActorBaseClass) = compileFinal createHashMapFromArray [ _self set ["actor", _actor]; SETPVAR(player,FORGE_isLoaded,true); - if !(_isLoaded) then { _self set ["isLoaded", true]; }; diag_log "[FORGE:Client:Actor] Sync completed"; }], ["get", compileFinal { params [["_key", "", [""]], ["_default", nil, [[], "", 0, false, createHashMap]]]; - private _actor = _self get "actor"; _actor getOrDefault [_key, _default]; }], ["applyPosition", compileFinal { private _position = _self call ["get", ["position", [0, 0, 0]]]; - if (GVAR(enableLoc)) then { player setPosASL _position; - private _pAlt = ((getPosATLVisual player) select 2); private _pVelZ = ((velocity player) select 2); - if (_pAlt > 5 && _pVelZ < 0) then { player setVelocity [0, 0, 0]; player setPosATL [((getPosATLVisual player) select 0), ((getPosATLVisual player) select 1), 1]; - hint "You logged off mid air. You were moved to a safe position on the ground"; }; }; @@ -114,9 +106,7 @@ GVAR(ActorBaseClass) = compileFinal createHashMapFromArray [ }], ["getNearbyActions", compileFinal { params [["_control", controlNull, [controlNull]]]; - private _nearbyActions = []; - { private _storeType = _x getVariable ["storeType", ""]; private _isAtm = _x getVariable ["isAtm", false]; @@ -141,5 +131,5 @@ GVAR(ActorBaseClass) = compileFinal createHashMapFromArray [ }] ]; -GVAR(ActorClass) = createHashMapObject [GVAR(ActorBaseClass)]; -GVAR(ActorClass) +GVAR(ActorRepository) = createHashMapObject [GVAR(ActorRepositoryBaseClass)]; +GVAR(ActorRepository) diff --git a/arma/client/addons/bank/XEH_PREP.hpp b/arma/client/addons/bank/XEH_PREP.hpp index 7d71bae..fb83b48 100644 --- a/arma/client/addons/bank/XEH_PREP.hpp +++ b/arma/client/addons/bank/XEH_PREP.hpp @@ -1,4 +1,4 @@ PREP(handleUIEvents); -PREP(initClass); +PREP(initRepository); PREP(initUIBridge); PREP(openUI); diff --git a/arma/client/addons/bank/XEH_postInitClient.sqf b/arma/client/addons/bank/XEH_postInitClient.sqf index 5eb9fc0..3ec1fc8 100644 --- a/arma/client/addons/bank/XEH_postInitClient.sqf +++ b/arma/client/addons/bank/XEH_postInitClient.sqf @@ -1,16 +1,16 @@ #include "script_component.hpp" -if (isNil QGVAR(BankClass)) then { call FUNC(initClass); }; +if (isNil QGVAR(BankRepository)) then { call FUNC(initRepository); }; if (isNil QGVAR(BankUIBridge)) then { call FUNC(initUIBridge); }; [QGVAR(initBank), { - GVAR(BankClass) call ["init", []]; + GVAR(BankRepository) call ["init", []]; }] call CFUNC(addEventHandler); [QGVAR(responseInitBank), { params [["_data", createHashMap, [createHashMap]]]; - GVAR(BankClass) call ["markLoaded", []]; + GVAR(BankRepository) call ["markLoaded", []]; if !(isNil QGVAR(BankUIBridge)) then { GVAR(BankUIBridge) call ["refreshSession", []]; }; @@ -19,7 +19,7 @@ if (isNil QGVAR(BankUIBridge)) then { call FUNC(initUIBridge); }; [QGVAR(responseSyncBank), { params [["_data", createHashMap, [createHashMap]], ["_jip", false, [false]]]; - GVAR(BankClass) call ["markLoaded", []]; + GVAR(BankRepository) call ["markLoaded", []]; if !(isNil QGVAR(BankUIBridge)) then { GVAR(BankUIBridge) call ["refreshSession", []]; }; @@ -42,7 +42,7 @@ if (isNil QGVAR(BankUIBridge)) then { call FUNC(initUIBridge); }; }] call CFUNC(addEventHandler); [{ - EGVAR(actor,ActorClass) get "isLoaded"; + EGVAR(actor,ActorRepository) get "isLoaded"; }, { [QGVAR(initBank), []] call CFUNC(localEvent); }] call CFUNC(waitUntilAndExecute); diff --git a/arma/client/addons/bank/functions/fnc_initClass.sqf b/arma/client/addons/bank/functions/fnc_initRepository.sqf similarity index 55% rename from arma/client/addons/bank/functions/fnc_initClass.sqf rename to arma/client/addons/bank/functions/fnc_initRepository.sqf index 1643c0d..c91ecf2 100644 --- a/arma/client/addons/bank/functions/fnc_initClass.sqf +++ b/arma/client/addons/bank/functions/fnc_initRepository.sqf @@ -1,17 +1,27 @@ #include "..\script_component.hpp" /* - * File: fnc_initClass.sqf + * File: fnc_initRepository.sqf * Author: IDSolutions + * Date: 2026-03-27 * Public: No * * Description: - * Initializes the bank class for lifecycle and save helpers. + * Initializes the bank repository for client bank lifecycle state. + * + * Arguments: + * None + * + * Return Value: + * Bank repository object [HASHMAP OBJECT] + * + * Example: + * call forge_client_bank_fnc_initRepository; */ #pragma hemtt ignore_variables ["_self"] -GVAR(BankBaseClass) = compileFinal createHashMapFromArray [ - ["#type", "BankBaseClass"], +GVAR(BankRepositoryBaseClass) = compileFinal createHashMapFromArray [ + ["#type", "BankRepositoryBaseClass"], ["#create", compileFinal { _self set ["uid", getPlayerUID player]; _self set ["isLoaded", false]; @@ -21,12 +31,11 @@ GVAR(BankBaseClass) = compileFinal createHashMapFromArray [ [SRPC(bank,requestInitBank), [getPlayerUID player]] call CFUNC(serverEvent); _self set ["lastSave", time]; - systemChat format ["Bank loaded for %1", (name player)]; - diag_log "[FORGE:Client:Bank] Bank Class Initialized!"; + systemChat format ["Bank loaded for %1", name player]; + diag_log "[FORGE:Client:Bank] Bank Repository Initialized!"; }], ["markLoaded", compileFinal { if !(_self getOrDefault ["isLoaded", false]) then { _self set ["isLoaded", true]; }; - true }], ["save", compileFinal { @@ -35,5 +44,5 @@ GVAR(BankBaseClass) = compileFinal createHashMapFromArray [ }] ]; -GVAR(BankClass) = createHashMapObject [GVAR(BankBaseClass)]; -GVAR(BankClass) +GVAR(BankRepository) = createHashMapObject [GVAR(BankRepositoryBaseClass)]; +GVAR(BankRepository) diff --git a/arma/client/addons/bank/functions/fnc_initUIBridge.sqf b/arma/client/addons/bank/functions/fnc_initUIBridge.sqf index 4d82ee9..9788f08 100644 --- a/arma/client/addons/bank/functions/fnc_initUIBridge.sqf +++ b/arma/client/addons/bank/functions/fnc_initUIBridge.sqf @@ -3,10 +3,20 @@ /* * File: fnc_initUIBridge.sqf * Author: IDSolutions + * Date: 2026-03-27 * Public: No * * Description: - * Initializes the bank web UI bridge. + * Initializes the bank UI bridge for browser control state and bank UI events. + * + * Arguments: + * None + * + * Return Value: + * Bank UI bridge object [HASHMAP OBJECT] + * + * Example: + * call forge_client_bank_fnc_initUIBridge; */ #pragma hemtt ignore_variables ["_self"] diff --git a/arma/client/addons/garage/XEH_PREP.hpp b/arma/client/addons/garage/XEH_PREP.hpp index 9db23f1..f39faee 100644 --- a/arma/client/addons/garage/XEH_PREP.hpp +++ b/arma/client/addons/garage/XEH_PREP.hpp @@ -1,8 +1,10 @@ PREP(handleUIEvents); -PREP(initCatalogService); -PREP(initClass); -PREP(initSessionService); +PREP(initActionService); +PREP(initContextService); +PREP(initHelperService); +PREP(initPayloadService); +PREP(initRepository); PREP(initUIBridge); -PREP(initVGClass); +PREP(initVGRepository); PREP(openUI); PREP(openVG); diff --git a/arma/client/addons/garage/XEH_postInitClient.sqf b/arma/client/addons/garage/XEH_postInitClient.sqf index 7d53dc5..76cd623 100644 --- a/arma/client/addons/garage/XEH_postInitClient.sqf +++ b/arma/client/addons/garage/XEH_postInitClient.sqf @@ -1,19 +1,21 @@ #include "script_component.hpp" -if (isNil QGVAR(GarageCatalogService)) then { call FUNC(initCatalogService); }; -if (isNil QGVAR(GarageClass)) then { call FUNC(initClass); }; -if (isNil QGVAR(GarageSessionService)) then { call FUNC(initSessionService); }; +if (isNil QGVAR(GarageHelperService)) then { call FUNC(initHelperService); }; +if (isNil QGVAR(GarageRepository)) then { call FUNC(initRepository); }; +if (isNil QGVAR(GarageContextService)) then { call FUNC(initContextService); }; +if (isNil QGVAR(GaragePayloadService)) then { call FUNC(initPayloadService); }; +if (isNil QGVAR(GarageActionService)) then { call FUNC(initActionService); }; if (isNil QGVAR(GarageUIBridge)) then { call FUNC(initUIBridge); }; -if (isNil QGVAR(VGClass)) then { call FUNC(initVGClass); }; +if (isNil QGVAR(VGRepository)) then { call FUNC(initVGRepository); }; [QGVAR(initGarage), { - GVAR(GarageClass) call ["init", []]; + GVAR(GarageRepository) call ["init", []]; }] call CFUNC(addEventHandler); [QGVAR(responseInitGarage), { params [["_data", createHashMap, [createHashMap]]]; - GVAR(GarageClass) call ["sync", [_data]]; + GVAR(GarageRepository) call ["sync", [_data]]; if !(isNil QGVAR(GarageUIBridge)) then { GVAR(GarageUIBridge) call ["refreshGarage", []]; }; @@ -22,7 +24,7 @@ if (isNil QGVAR(VGClass)) then { call FUNC(initVGClass); }; [QGVAR(responseSyncGarage), { params [["_data", createHashMap, [createHashMap, []]]]; - GVAR(GarageClass) call ["sync", [_data]]; + GVAR(GarageRepository) call ["sync", [_data]]; if !(isNil QGVAR(GarageUIBridge)) then { GVAR(GarageUIBridge) call ["refreshGarage", []]; }; @@ -31,35 +33,35 @@ if (isNil QGVAR(VGClass)) then { call FUNC(initVGClass); }; [QGVAR(responseGarageAction), { params [["_payload", createHashMap, [createHashMap]]]; - if !(isNil QGVAR(GarageUIBridge)) then { - GVAR(GarageUIBridge) call ["handleActionResponse", [_payload]]; + if !(isNil QGVAR(GarageActionService)) then { + GVAR(GarageActionService) call ["handleActionResponse", [_payload]]; }; }] call CFUNC(addEventHandler); [QGVAR(initVG), { - GVAR(VGClass) call ["init", []]; + GVAR(VGRepository) call ["init", []]; }] call CFUNC(addEventHandler); [QGVAR(responseInitVG), { params [["_data", createHashMap, [createHashMap]]]; - GVAR(VGClass) call ["sync", [_data]]; + GVAR(VGRepository) call ["sync", [_data]]; }] call CFUNC(addEventHandler); [QGVAR(responseSyncVG), { params [["_data", createHashMap, [createHashMap, []]]]; - GVAR(VGClass) call ["sync", [_data]]; + GVAR(VGRepository) call ["sync", [_data]]; }] call CFUNC(addEventHandler); [{ - EGVAR(bank,BankClass) get "isLoaded"; + EGVAR(bank,BankRepository) get "isLoaded"; }, { [QGVAR(initGarage), []] call CFUNC(localEvent); }] call CFUNC(waitUntilAndExecute); [{ - GVAR(GarageClass) get "isLoaded"; + GVAR(GarageRepository) get "isLoaded"; }, { [QGVAR(initVG), []] call CFUNC(localEvent); }] call CFUNC(waitUntilAndExecute); diff --git a/arma/client/addons/garage/functions/fnc_handleUIEvents.sqf b/arma/client/addons/garage/functions/fnc_handleUIEvents.sqf index ae6ee6e..94c1ad1 100644 --- a/arma/client/addons/garage/functions/fnc_handleUIEvents.sqf +++ b/arma/client/addons/garage/functions/fnc_handleUIEvents.sqf @@ -44,13 +44,13 @@ switch (_event) do { }; }; case "garage::vehicle::retrieve::request": { - if !(isNil QGVAR(GarageUIBridge)) then { - GVAR(GarageUIBridge) call ["handleRetrieveRequest", [_data]]; + if !(isNil QGVAR(GarageActionService)) then { + GVAR(GarageActionService) call ["handleRetrieveRequest", [_data]]; }; }; case "garage::vehicle::store::request": { - if !(isNil QGVAR(GarageUIBridge)) then { - GVAR(GarageUIBridge) call ["handleStoreRequest", [_data]]; + if !(isNil QGVAR(GarageActionService)) then { + GVAR(GarageActionService) call ["handleStoreRequest", [_data]]; }; }; case "garage::refresh": { diff --git a/arma/client/addons/garage/functions/fnc_initActionService.sqf b/arma/client/addons/garage/functions/fnc_initActionService.sqf new file mode 100644 index 0000000..408d5a8 --- /dev/null +++ b/arma/client/addons/garage/functions/fnc_initActionService.sqf @@ -0,0 +1,133 @@ +#include "..\script_component.hpp" + +/* + * File: fnc_initActionService.sqf + * Author: IDSolutions + * Date: 2026-03-27 + * Public: No + * + * Description: + * Initializes the garage action service for retrieve and store world actions. + * + * Arguments: + * None + * + * Return Value: + * Garage action service object [HASHMAP OBJECT] + * + * Example: + * call forge_client_garage_fnc_initActionService; + */ + +#pragma hemtt ignore_variables ["_self"] +GVAR(GarageActionServiceBaseClass) = compileFinal createHashMapFromArray [ + ["#type", "GarageActionServiceBaseClass"], + ["#create", compileFinal { + _self set ["pendingStoreVehicle", objNull]; + _self set ["pendingRetrieve", createHashMap]; + }], + ["handleRetrieveRequest", compileFinal { + params [["_data", createHashMap, [createHashMap]]]; + + private _plate = _data getOrDefault ["plate", ""]; + if (_plate isEqualTo "") exitWith { + GVAR(GarageUIBridge) call ["sendEvent", ["garage::retrieve::failure", createHashMapFromArray [["message", "Select a stored vehicle to retrieve."]]]]; + }; + + private _garageMap = if (isNil QGVAR(GarageRepository)) then { createHashMap } else { GVAR(GarageRepository) call ["getState", []] }; + private _vehicleData = _garageMap getOrDefault [_plate, createHashMap]; + if (_vehicleData isEqualTo createHashMap) exitWith { + GVAR(GarageUIBridge) call ["sendEvent", ["garage::retrieve::failure", createHashMapFromArray [["message", "Stored vehicle record could not be found."]]]]; + }; + + private _context = GVAR(GarageContextService) call ["getContext", []]; + private _spawnPosition = _context getOrDefault ["spawnPosition", getPosATL player]; + private _spawnHeading = _context getOrDefault ["spawnHeading", getDir player]; + private _spawnRadius = _context getOrDefault ["spawnRadius", 6]; + private _blockingVehicles = []; + { _blockingVehicles pushBackUnique _x; } forEach (_spawnPosition nearEntities [["Car", "Tank", "Air", "Ship"], _spawnRadius]); + { _blockingVehicles pushBackUnique _x; } forEach (nearestObjects [_spawnPosition, ["Car", "Tank", "Air", "Ship"], _spawnRadius]); + if (_blockingVehicles isNotEqualTo []) exitWith { + GVAR(GarageUIBridge) call ["sendEvent", ["garage::retrieve::failure", createHashMapFromArray [["message", "The garage spawn area is blocked."]]]]; + }; + + private _className = _vehicleData getOrDefault ["classname", ""]; + if (_className isEqualTo "") exitWith { + GVAR(GarageUIBridge) call ["sendEvent", ["garage::retrieve::failure", createHashMapFromArray [["message", "Stored vehicle record is missing a classname."]]]]; + }; + + private _vehicle = createVehicle [_className, _spawnPosition, [], 0, "CAN_COLLIDE"]; + _vehicle setDir _spawnHeading; + _vehicle setFuel (_vehicleData getOrDefault ["fuel", 0]); + _vehicle setDamage (_vehicleData getOrDefault ["damage", 0]); + + private _hitPoints = _vehicleData getOrDefault ["hit_points", createHashMap]; + private _hitPointNames = _hitPoints getOrDefault ["names", []]; + private _hitPointValues = _hitPoints getOrDefault ["values", []]; + for "_index" from 0 to ((count _hitPointNames) - 1) do { + _vehicle setHitPointDamage [_hitPointNames param [_index, ""], _hitPointValues param [_index, 0]]; + }; + + _vehicle setVariable ["forge_garage_plate", _plate, true]; + _vehicle setVariable ["forge_garage_owner_uid", getPlayerUID player, true]; + + _self set ["pendingRetrieve", createHashMapFromArray [["plate", _plate], ["vehicle", _vehicle]]]; + [SRPC(garage,requestRetrieveVehicle), [getPlayerUID player, _plate]] call CFUNC(serverEvent); + }], + ["handleStoreRequest", compileFinal { + params [["_data", createHashMap, [createHashMap]]]; + + private _netId = _data getOrDefault ["netId", ""]; + if (_netId isEqualTo "") exitWith { + GVAR(GarageUIBridge) call ["sendEvent", ["garage::store::failure", createHashMapFromArray [["message", "Select a nearby vehicle to store."]]]]; + }; + + private _vehicle = objectFromNetId _netId; + if (isNull _vehicle) exitWith { + GVAR(GarageUIBridge) call ["sendEvent", ["garage::store::failure", createHashMapFromArray [["message", "The selected vehicle is no longer available."]]]]; + }; + + if (crew _vehicle isNotEqualTo []) exitWith { + GVAR(GarageUIBridge) call ["sendEvent", ["garage::store::failure", createHashMapFromArray [["message", "All crew must exit the vehicle before storing it."]]]]; + }; + + private _rawHitPoints = getAllHitPointsDamage _vehicle; + private _hitPointsJson = toJSON (createHashMapFromArray [["names", _rawHitPoints param [0, []]], ["selections", _rawHitPoints param [1, []]], ["values", _rawHitPoints param [2, []]]]); + + _self set ["pendingStoreVehicle", _vehicle]; + [SRPC(garage,requestStoreVehicle), [getPlayerUID player, typeOf _vehicle, fuel _vehicle, damage _vehicle, _hitPointsJson]] call CFUNC(serverEvent); + }], + ["handleActionResponse", compileFinal { + params [["_payload", createHashMap, [createHashMap]]]; + + private _action = _payload getOrDefault ["action", ""]; + private _success = _payload getOrDefault ["success", false]; + private _message = _payload getOrDefault ["message", "Garage action failed."]; + + switch (_action) do { + case "retrieve": { + private _pendingRetrieve = _self getOrDefault ["pendingRetrieve", createHashMap]; + private _vehicle = _pendingRetrieve getOrDefault ["vehicle", objNull]; + if (!_success && { !isNull _vehicle }) then { deleteVehicle _vehicle; }; + _self set ["pendingRetrieve", createHashMap]; + GVAR(GarageUIBridge) call ["sendEvent", [[ "garage::retrieve::failure", "garage::retrieve::success" ] select _success, createHashMapFromArray [["message", _message]]]]; + }; + case "store": { + private _vehicle = _self getOrDefault ["pendingStoreVehicle", objNull]; + if (_success && { !isNull _vehicle }) then { deleteVehicle _vehicle; }; + _self set ["pendingStoreVehicle", objNull]; + GVAR(GarageUIBridge) call ["sendEvent", [[ "garage::store::failure", "garage::store::success" ] select _success, createHashMapFromArray [["message", _message]]]]; + }; + }; + + [] spawn { + sleep 0.05; + if !(isNil QGVAR(GarageUIBridge)) then { + GVAR(GarageUIBridge) call ["refreshGarage", []]; + }; + }; + }] +]; + +GVAR(GarageActionService) = createHashMapObject [GVAR(GarageActionServiceBaseClass)]; +GVAR(GarageActionService) diff --git a/arma/client/addons/garage/functions/fnc_initContextService.sqf b/arma/client/addons/garage/functions/fnc_initContextService.sqf new file mode 100644 index 0000000..45da63e --- /dev/null +++ b/arma/client/addons/garage/functions/fnc_initContextService.sqf @@ -0,0 +1,146 @@ +#include "..\script_component.hpp" + +/* + * File: fnc_initContextService.sqf + * Author: IDSolutions + * Date: 2026-03-27 + * Public: No + * + * Description: + * Initializes the garage context service for local garage context and nearby state. + * + * Arguments: + * None + * + * Return Value: + * Garage context service object [HASHMAP OBJECT] + * + * Example: + * call forge_client_garage_fnc_initContextService; + */ + +#pragma hemtt ignore_variables ["_self"] +GVAR(GarageContextServiceBaseClass) = compileFinal createHashMapFromArray [ + ["#type", "GarageContextServiceBaseClass"], + ["#create", compileFinal { _self set ["lastContext", createHashMap]; }], + ["#delete", compileFinal { _self set ["lastContext", createHashMap]; }], + ["createDefaultContext", compileFinal { + createHashMapFromArray [ + ["name", "Vehicle Garage"], + ["anchorPosition", getPosATL player], + ["sourceObject", objNull], + ["spawnHeading", getDir player], + ["spawnPosition", player getPos [8, getDir player]], + ["spawnRadius", 6], + ["nearbyRadius", 30] + ] + }], + ["scanEntryValues", compileFinal { + params [["_values", [], [[]]], ["_state", createHashMap, [createHashMap]]]; + { + if (_x isEqualType "" && { (_state getOrDefault ["name", "Vehicle Garage"]) isEqualTo "Vehicle Garage" }) then { _state set ["name", _x]; }; + if (_x isEqualType "") then { + private _resolvedObject = _state getOrDefault ["sourceObject", objNull]; + if (isNull _resolvedObject) then { + private _namedObject = missionNamespace getVariable [_x, objNull]; + if (!isNull _namedObject) then { _state set ["sourceObject", _namedObject]; }; + }; + if ((_state getOrDefault ["anchorPosition", []]) isEqualTo [] && { _x in allMapMarkers }) then { _state set ["anchorPosition", markerPos _x]; }; + continue; + }; + if (_x isEqualType objNull && { isNull (_state getOrDefault ["sourceObject", objNull]) }) then { + _state set ["sourceObject", _x]; + if ((_state getOrDefault ["anchorPosition", []]) isEqualTo []) then { _state set ["anchorPosition", getPosATL _x]; }; + continue; + }; + if (_x isEqualType 0 && { (_state getOrDefault ["spawnHeading", -1]) < 0 }) then { _state set ["spawnHeading", _x]; continue; }; + if (_x isEqualType [] && { count _x > 0 }) then { + if ({ _x isEqualType 0 } count _x >= 2 && { ((_state getOrDefault ["offset", []]) isEqualTo []) || ((_state getOrDefault ["anchorPosition", []]) isEqualTo []) }) then { + if ((_state getOrDefault ["anchorPosition", []]) isEqualTo []) then { _state set ["anchorPosition", _x]; } else { _state set ["offset", _x]; }; + continue; + }; + _self call ["scanEntryValues", [_x, _state]]; + }; + } forEach _values; + _state + }], + ["resolveEntry", compileFinal { + params [["_entry", [], [[]]]]; + private _state = createHashMapFromArray [["name", "Vehicle Garage"], ["anchorPosition", []], ["sourceObject", objNull], ["offset", []], ["spawnHeading", -1]]; + _self call ["scanEntryValues", [_entry, _state]]; + private _anchorPosition = _state getOrDefault ["anchorPosition", []]; + private _offset = _state getOrDefault ["offset", []]; + private _spawnPosition = if (_anchorPosition isEqualTo []) then { [] } else { if (_offset isEqualTo []) then { _anchorPosition } else { _anchorPosition vectorAdd _offset } }; + createHashMapFromArray [["name", _state getOrDefault ["name", "Vehicle Garage"]], ["anchorPosition", _anchorPosition], ["sourceObject", _state getOrDefault ["sourceObject", objNull]], ["spawnHeading", _state getOrDefault ["spawnHeading", -1]], ["spawnPosition", _spawnPosition]] + }], + ["resolveContext", compileFinal { + private _context = _self call ["createDefaultContext", []]; + private _locations = (missionConfigFile >> "FORGE_CfgGarages" >> "locations") call BFUNC(getCfgData); + if !(_locations isEqualType []) exitWith { _self set ["lastContext", _context]; _context }; + + private _nearestEntry = []; + private _nearestDistance = 1e10; + { + private _entry = _self call ["resolveEntry", [_x]]; + private _anchorPosition = _entry getOrDefault ["anchorPosition", []]; + if (_anchorPosition isEqualTo []) then { continue; }; + private _distance = player distance2D _anchorPosition; + if (_distance < _nearestDistance) then { _nearestDistance = _distance; _nearestEntry = _entry; }; + } forEach _locations; + + if (_nearestEntry isEqualTo []) exitWith { _self set ["lastContext", _context]; _context }; + + private _anchorPosition = _nearestEntry getOrDefault ["anchorPosition", []]; + private _garageObject = _nearestEntry getOrDefault ["sourceObject", objNull]; + private _garageName = _nearestEntry getOrDefault ["name", "Vehicle Garage"]; + private _spawnHeading = _nearestEntry getOrDefault ["spawnHeading", getDir player]; + if (_spawnHeading < 0) then { _spawnHeading = if (!isNull _garageObject) then { getDir _garageObject } else { getDir player }; }; + + private _spawnPosition = _nearestEntry getOrDefault ["spawnPosition", []]; + if (_spawnPosition isEqualTo []) then { _spawnPosition = if (_anchorPosition isEqualTo []) then { player getPos [8, _spawnHeading] } else { _anchorPosition }; }; + + _context set ["name", _garageName]; + _context set ["anchorPosition", _anchorPosition]; + _context set ["sourceObject", _garageObject]; + _context set ["spawnHeading", _spawnHeading]; + _context set ["spawnPosition", _spawnPosition]; + _self set ["lastContext", _context]; + _context + }], + ["getContext", compileFinal { _self call ["resolveContext", []] }], + ["buildNearbyState", compileFinal { + private _context = _self call ["getContext", []]; + private _anchorPosition = _context getOrDefault ["anchorPosition", []]; + private _spawnPosition = _context getOrDefault ["spawnPosition", getPosATL player]; + private _spawnRadius = _context getOrDefault ["spawnRadius", 6]; + private _nearbyRadius = _context getOrDefault ["nearbyRadius", 30]; + private _nearbyOrigin = [_anchorPosition, _spawnPosition] select (_anchorPosition isEqualTo []); + private _nearbyVehicles = []; + private _nearbyEntities = []; + private _candidateVehicles = []; + { _candidateVehicles pushBackUnique _x; } forEach (_nearbyOrigin nearEntities [["Car", "Tank", "Air", "Ship"], _nearbyRadius]); + { _candidateVehicles pushBackUnique _x; } forEach ((getPosATL player) nearEntities [["Car", "Tank", "Air", "Ship"], _nearbyRadius]); + { _candidateVehicles pushBackUnique _x; } forEach (nearestObjects [_nearbyOrigin, ["AllVehicles"], _nearbyRadius]); + { _candidateVehicles pushBackUnique _x; } forEach (nearestObjects [getPosATL player, ["AllVehicles"], _nearbyRadius]); + { + if (isNull _x) then { continue; }; + if (_x isKindOf "CAManBase") then { continue; }; + if !(_x isKindOf "Car" || _x isKindOf "Tank" || _x isKindOf "Air" || _x isKindOf "Ship") then { continue; }; + _nearbyEntities pushBackUnique _x; + } forEach _candidateVehicles; + { + if (isNull _x) then { continue; }; + private _builtVehicle = GVAR(GarageHelperService) call ["buildNearbyVehicle", [_x, _nearbyOrigin]]; + if (_builtVehicle isEqualTo createHashMap) then { continue; }; + _nearbyVehicles pushBack _builtVehicle; + } forEach _nearbyEntities; + private _nearbyVehiclePairs = _nearbyVehicles apply { [_x getOrDefault ["distance", 0], _x] }; + _nearbyVehiclePairs sort true; + _nearbyVehicles = _nearbyVehiclePairs apply { _x param [1, createHashMap] }; + private _spawnBlocked = ((_spawnPosition nearEntities [["Car", "Tank", "Air", "Ship"], _spawnRadius]) + (nearestObjects [_spawnPosition, ["Car", "Tank", "Air", "Ship"], _spawnRadius])) isNotEqualTo []; + createHashMapFromArray [["session", createHashMapFromArray [["garageName", _context getOrDefault ["name", "Vehicle Garage"]], ["nearbyCount", count _nearbyVehicles], ["spawnBlocked", _spawnBlocked], ["spawnStatus", ["Ready", "Blocked"] select _spawnBlocked]]], ["nearby", createHashMapFromArray [["vehicles", _nearbyVehicles]]]] + }] +]; + +GVAR(GarageContextService) = createHashMapObject [GVAR(GarageContextServiceBaseClass)]; +GVAR(GarageContextService) diff --git a/arma/client/addons/garage/functions/fnc_initCatalogService.sqf b/arma/client/addons/garage/functions/fnc_initHelperService.sqf similarity index 91% rename from arma/client/addons/garage/functions/fnc_initCatalogService.sqf rename to arma/client/addons/garage/functions/fnc_initHelperService.sqf index 748b5e4..714d2a2 100644 --- a/arma/client/addons/garage/functions/fnc_initCatalogService.sqf +++ b/arma/client/addons/garage/functions/fnc_initHelperService.sqf @@ -1,18 +1,27 @@ #include "..\script_component.hpp" /* - * File: fnc_initCatalogService.sqf + * File: fnc_initHelperService.sqf * Author: IDSolutions - * Date: 2026-03-14 + * Date: 2026-03-27 * Public: No * * Description: - * Initializes the garage catalog service for vehicle metadata and UI-friendly shaping. + * Initializes the garage helper service for vehicle metadata and UI-friendly shaping. + * + * Arguments: + * None + * + * Return Value: + * Garage helper service object [HASHMAP OBJECT] + * + * Example: + * call forge_client_garage_fnc_initHelperService; */ #pragma hemtt ignore_variables ["_self"] -GVAR(GarageCatalogServiceBaseClass) = compileFinal createHashMapFromArray [ - ["#type", "GarageCatalogServiceBaseClass"], +GVAR(GarageHelperServiceBaseClass) = compileFinal createHashMapFromArray [ + ["#type", "GarageHelperServiceBaseClass"], ["resolveCategory", compileFinal { params [["_className", "", [""]]]; @@ -156,5 +165,5 @@ GVAR(GarageCatalogServiceBaseClass) = compileFinal createHashMapFromArray [ }] ]; -GVAR(GarageCatalogService) = createHashMapObject [GVAR(GarageCatalogServiceBaseClass)]; -GVAR(GarageCatalogService) +GVAR(GarageHelperService) = createHashMapObject [GVAR(GarageHelperServiceBaseClass)]; +GVAR(GarageHelperService) diff --git a/arma/client/addons/garage/functions/fnc_initPayloadService.sqf b/arma/client/addons/garage/functions/fnc_initPayloadService.sqf new file mode 100644 index 0000000..184065e --- /dev/null +++ b/arma/client/addons/garage/functions/fnc_initPayloadService.sqf @@ -0,0 +1,44 @@ +#include "..\script_component.hpp" + +/* + * File: fnc_initPayloadService.sqf + * Author: IDSolutions + * Date: 2026-03-27 + * Public: No + * + * Description: + * Initializes the garage payload service for browser hydrate payload composition. + * + * Arguments: + * None + * + * Return Value: + * Garage payload service object [HASHMAP OBJECT] + * + * Example: + * call forge_client_garage_fnc_initPayloadService; + */ + +#pragma hemtt ignore_variables ["_self"] +GVAR(GaragePayloadServiceBaseClass) = compileFinal createHashMapFromArray [ + ["#type", "GaragePayloadServiceBaseClass"], + ["buildStoredVehicles", compileFinal { + private _garageMap = if (isNil QGVAR(GarageRepository)) then { createHashMap } else { GVAR(GarageRepository) call ["getState", []] }; + private _storedVehicles = []; + { _storedVehicles pushBack (GVAR(GarageHelperService) call ["buildStoredVehicle", [_x, _y]]); } forEach _garageMap; + private _storedVehiclePairs = _storedVehicles apply { [toLowerANSI (_x getOrDefault ["displayName", ""]), _x] }; + _storedVehiclePairs sort true; + _storedVehiclePairs apply { _x param [1, createHashMap] } + }], + ["buildPayload", compileFinal { + private _localState = GVAR(GarageContextService) call ["buildNearbyState", []]; + private _storedVehicles = _self call ["buildStoredVehicles", []]; + private _session = +(_localState getOrDefault ["session", createHashMap]); + _session set ["capacityUsed", count _storedVehicles]; + _session set ["capacityMax", 5]; + createHashMapFromArray [["session", _session], ["garage", createHashMapFromArray [["vehicles", _storedVehicles]]], ["nearby", +(_localState getOrDefault ["nearby", createHashMap])]] + }] +]; + +GVAR(GaragePayloadService) = createHashMapObject [GVAR(GaragePayloadServiceBaseClass)]; +GVAR(GaragePayloadService) diff --git a/arma/client/addons/garage/functions/fnc_initClass.sqf b/arma/client/addons/garage/functions/fnc_initRepository.sqf similarity index 59% rename from arma/client/addons/garage/functions/fnc_initClass.sqf rename to arma/client/addons/garage/functions/fnc_initRepository.sqf index 6bb114e..5129610 100644 --- a/arma/client/addons/garage/functions/fnc_initClass.sqf +++ b/arma/client/addons/garage/functions/fnc_initRepository.sqf @@ -1,49 +1,44 @@ #include "..\script_component.hpp" /* - * File: fnc_initClass.sqf + * File: fnc_initRepository.sqf * Author: IDSolutions - * Date: 2025-12-17 - * Last Update: 2026-03-25 + * Date: 2026-03-27 * Public: No * * Description: - * Initializes the Garage class for managing player vehicles. - * Provides methods for syncing, saving, and applying vehicles to the player's garage. + * Initializes the garage repository for persisted stored vehicle records. * * Arguments: * None * * Return Value: - * Garage class object [HASHMAP OBJECT] + * Garage repository object [HASHMAP OBJECT] * * Example: - * call forge_client_garage_fnc_initClass + * call forge_client_garage_fnc_initRepository; */ #pragma hemtt ignore_variables ["_self"] -GVAR(GarageBaseClass) = compileFinal createHashMapFromArray [ - ["#type", "GarageBaseClass"], +GVAR(GarageRepositoryBaseClass) = compileFinal createHashMapFromArray [ + ["#type", "GarageRepositoryBaseClass"], ["#create", compileFinal { - _self set ["uid", (getPlayerUID player)]; + _self set ["uid", getPlayerUID player]; _self set ["garage", createHashMap]; _self set ["isLoaded", false]; _self set ["lastSave", time]; }], ["init", compileFinal { private _uid = _self get "uid"; - private _garage = _self get "garage"; - - [SRPC(garage,requestInitGarage), [_uid, _garage]] call CFUNC(serverEvent); + [SRPC(garage,requestInitGarage), [_uid]] call CFUNC(serverEvent); _self set ["lastSave", time]; - systemChat format ["Garage loaded for %1", (name player)]; - diag_log "[FORGE:Client:Garage] Garage Class Initialized!"; + systemChat format ["Garage loaded for %1", name player]; + diag_log "[FORGE:Client:Garage] Garage Repository Initialized!"; }], ["save", compileFinal { private _uid = _self get "uid"; [SRPC(garage,requestSaveGarage), [_uid]] call CFUNC(serverEvent); - _self set ["lastSave", time]; }], ["sync", compileFinal { @@ -51,14 +46,13 @@ GVAR(GarageBaseClass) = compileFinal createHashMapFromArray [ private _isLoaded = _self get "isLoaded"; private _garage = createHashMap; - { _garage set [_x, _y]; } forEach _data; _self set ["garage", _garage]; if !(_isLoaded) then { _self set ["isLoaded", true]; }; - diag_log "[FORGE:Client:Garage] Sync completed"; + diag_log "[FORGE:Client:Garage] Repository sync completed"; }], - ["getGarageState", compileFinal { + ["getState", compileFinal { _self getOrDefault ["garage", createHashMap] }], ["get", compileFinal { @@ -69,5 +63,5 @@ GVAR(GarageBaseClass) = compileFinal createHashMapFromArray [ }] ]; -GVAR(GarageClass) = createHashMapObject [GVAR(GarageBaseClass)]; -GVAR(GarageClass) +GVAR(GarageRepository) = createHashMapObject [GVAR(GarageRepositoryBaseClass)]; +GVAR(GarageRepository) diff --git a/arma/client/addons/garage/functions/fnc_initSessionService.sqf b/arma/client/addons/garage/functions/fnc_initSessionService.sqf deleted file mode 100644 index 7fe871b..0000000 --- a/arma/client/addons/garage/functions/fnc_initSessionService.sqf +++ /dev/null @@ -1,298 +0,0 @@ -#include "..\script_component.hpp" - -/* - * File: fnc_initSessionService.sqf - * Author: IDSolutions - * Date: 2026-03-14 - * Public: No - * - * Description: - * Initializes the typed garage session service responsible for resolving the - * active garage context and building the browser hydrate payload. - */ - -#pragma hemtt ignore_variables ["_self"] - -GVAR(GarageSessionServiceBaseClass) = compileFinal createHashMapFromArray [ - ["#type", "GarageSessionServiceBaseClass"], - ["#create", compileFinal { - _self set ["lastContext", createHashMap]; - }], - ["#delete", compileFinal { - _self set ["lastContext", createHashMap]; - }], - ["createDefaultContext", compileFinal { - createHashMapFromArray [ - ["name", "Vehicle Garage"], - ["anchorPosition", getPosATL player], - ["sourceObject", objNull], - ["spawnHeading", getDir player], - ["spawnPosition", player getPos [8, getDir player]], - ["spawnRadius", 6], - ["nearbyRadius", 30] - ] - }], - ["scanEntryValues", compileFinal { - params [ - ["_values", [], [[]]], - ["_state", createHashMap, [createHashMap]] - ]; - - { - if (_x isEqualType "" && { (_state getOrDefault ["name", "Vehicle Garage"]) isEqualTo "Vehicle Garage" }) then { - _state set ["name", _x]; - }; - - if (_x isEqualType "") then { - private _resolvedObject = _state getOrDefault ["sourceObject", objNull]; - if (isNull _resolvedObject) then { - private _namedObject = missionNamespace getVariable [_x, objNull]; - if (!isNull _namedObject) then { - _state set ["sourceObject", _namedObject]; - }; - }; - - if ((_state getOrDefault ["anchorPosition", []]) isEqualTo [] && { _x in allMapMarkers }) then { - _state set ["anchorPosition", markerPos _x]; - }; - - continue; - }; - - if (_x isEqualType objNull && { isNull (_state getOrDefault ["sourceObject", objNull]) }) then { - _state set ["sourceObject", _x]; - if ((_state getOrDefault ["anchorPosition", []]) isEqualTo []) then { - _state set ["anchorPosition", getPosATL _x]; - }; - continue; - }; - - if (_x isEqualType 0 && { (_state getOrDefault ["spawnHeading", -1]) < 0 }) then { - _state set ["spawnHeading", _x]; - continue; - }; - - if (_x isEqualType [] && { count _x > 0 }) then { - if ( - { _x isEqualType 0 } count _x >= 2 && - { - ((_state getOrDefault ["offset", []]) isEqualTo []) || - ((_state getOrDefault ["anchorPosition", []]) isEqualTo []) - } - ) then { - if ((_state getOrDefault ["anchorPosition", []]) isEqualTo []) then { - _state set ["anchorPosition", _x]; - } else { - _state set ["offset", _x]; - }; - continue; - }; - - _self call ["scanEntryValues", [_x, _state]]; - }; - } forEach _values; - - _state - }], - ["resolveEntry", compileFinal { - params [["_entry", [], [[]]]]; - - private _state = createHashMapFromArray [ - ["name", "Vehicle Garage"], - ["anchorPosition", []], - ["sourceObject", objNull], - ["offset", []], - ["spawnHeading", -1] - ]; - - _self call ["scanEntryValues", [_entry, _state]]; - - private _anchorPosition = _state getOrDefault ["anchorPosition", []]; - private _offset = _state getOrDefault ["offset", []]; - private _spawnPosition = if (_anchorPosition isEqualTo []) then { - [] - } else { - if (_offset isEqualTo []) then { - _anchorPosition - } else { - _anchorPosition vectorAdd _offset - } - }; - - createHashMapFromArray [ - ["name", _state getOrDefault ["name", "Vehicle Garage"]], - ["anchorPosition", _anchorPosition], - ["sourceObject", _state getOrDefault ["sourceObject", objNull]], - ["spawnHeading", _state getOrDefault ["spawnHeading", -1]], - ["spawnPosition", _spawnPosition] - ] - }], - ["resolveContext", compileFinal { - private _context = _self call ["createDefaultContext", []]; - private _locations = (missionConfigFile >> "FORGE_CfgGarages" >> "locations") call BFUNC(getCfgData); - if !(_locations isEqualType []) exitWith { - _self set ["lastContext", _context]; - _context - }; - - private _nearestEntry = []; - private _nearestDistance = 1e10; - - { - private _entry = _self call ["resolveEntry", [_x]]; - private _anchorPosition = _entry getOrDefault ["anchorPosition", []]; - if (_anchorPosition isEqualTo []) then { - continue; - }; - - private _distance = player distance2D _anchorPosition; - if (_distance < _nearestDistance) then { - _nearestDistance = _distance; - _nearestEntry = _entry; - }; - } forEach _locations; - - if (_nearestEntry isEqualTo []) exitWith { - _self set ["lastContext", _context]; - _context - }; - - private _anchorPosition = _nearestEntry getOrDefault ["anchorPosition", []]; - private _garageObject = _nearestEntry getOrDefault ["sourceObject", objNull]; - private _garageName = _nearestEntry getOrDefault ["name", "Vehicle Garage"]; - private _spawnHeading = _nearestEntry getOrDefault ["spawnHeading", getDir player]; - if (_spawnHeading < 0) then { - _spawnHeading = if (!isNull _garageObject) then { getDir _garageObject } else { getDir player }; - }; - - private _spawnPosition = _nearestEntry getOrDefault ["spawnPosition", []]; - if (_spawnPosition isEqualTo []) then { - _spawnPosition = if (_anchorPosition isEqualTo []) then { - player getPos [8, _spawnHeading] - } else { - _anchorPosition - }; - }; - - _context set ["name", _garageName]; - _context set ["anchorPosition", _anchorPosition]; - _context set ["sourceObject", _garageObject]; - _context set ["spawnHeading", _spawnHeading]; - _context set ["spawnPosition", _spawnPosition]; - - _self set ["lastContext", _context]; - _context - }], - ["getContext", compileFinal { - _self call ["resolveContext", []] - }], - ["buildPayload", compileFinal { - private _context = _self call ["getContext", []]; - private _garageMap = if (isNil QGVAR(GarageClass)) then { - createHashMap - } else { - GVAR(GarageClass) call ["getGarageState", []] - }; - - private _anchorPosition = _context getOrDefault ["anchorPosition", []]; - private _spawnPosition = _context getOrDefault ["spawnPosition", getPosATL player]; - private _spawnRadius = _context getOrDefault ["spawnRadius", 6]; - private _nearbyRadius = _context getOrDefault ["nearbyRadius", 30]; - private _nearbyOrigin = [_anchorPosition, _spawnPosition] select (_anchorPosition isEqualTo []); - - private _storedVehicles = []; - private _nearbyVehicles = []; - private _nearbyEntities = []; - private _candidateVehicles = []; - - { - _candidateVehicles pushBackUnique _x; - } forEach (_nearbyOrigin nearEntities [["Car", "Tank", "Air", "Ship"], _nearbyRadius]); - { - _candidateVehicles pushBackUnique _x; - } forEach ((getPosATL player) nearEntities [["Car", "Tank", "Air", "Ship"], _nearbyRadius]); - { - _candidateVehicles pushBackUnique _x; - } forEach (nearestObjects [_nearbyOrigin, ["AllVehicles"], _nearbyRadius]); - { - _candidateVehicles pushBackUnique _x; - } forEach (nearestObjects [getPosATL player, ["AllVehicles"], _nearbyRadius]); - - { - if (isNull _x) then { - continue; - }; - - if (_x isKindOf "CAManBase") then { - continue; - }; - - if !( - _x isKindOf "Car" || - _x isKindOf "Tank" || - _x isKindOf "Air" || - _x isKindOf "Ship" - ) then { - continue; - }; - - _nearbyEntities pushBackUnique _x; - } forEach _candidateVehicles; - - { - _storedVehicles pushBack ( - GVAR(GarageCatalogService) call ["buildStoredVehicle", [_x, _y]] - ); - } forEach _garageMap; - - private _storedVehiclePairs = _storedVehicles apply { - [toLowerANSI (_x getOrDefault ["displayName", ""]), _x] - }; - _storedVehiclePairs sort true; - _storedVehicles = _storedVehiclePairs apply { _x param [1, createHashMap] }; - - { - if (isNull _x) then { - continue; - }; - - private _builtVehicle = GVAR(GarageCatalogService) call ["buildNearbyVehicle", [_x, _nearbyOrigin]]; - if (_builtVehicle isEqualTo createHashMap) then { - continue; - }; - - _nearbyVehicles pushBack _builtVehicle; - } forEach _nearbyEntities; - - private _nearbyVehiclePairs = _nearbyVehicles apply { - [_x getOrDefault ["distance", 0], _x] - }; - _nearbyVehiclePairs sort true; - _nearbyVehicles = _nearbyVehiclePairs apply { _x param [1, createHashMap] }; - - private _spawnBlocked = ( - (_spawnPosition nearEntities [["Car", "Tank", "Air", "Ship"], _spawnRadius]) + - (nearestObjects [_spawnPosition, ["Car", "Tank", "Air", "Ship"], _spawnRadius]) - ) isNotEqualTo []; - - createHashMapFromArray [ - ["session", createHashMapFromArray [ - ["garageName", _context getOrDefault ["name", "Vehicle Garage"]], - ["capacityUsed", count _storedVehicles], - ["capacityMax", 5], - ["nearbyCount", count _nearbyVehicles], - ["spawnBlocked", _spawnBlocked], - ["spawnStatus", ["Ready", "Blocked"] select _spawnBlocked] - ]], - ["garage", createHashMapFromArray [ - ["vehicles", _storedVehicles] - ]], - ["nearby", createHashMapFromArray [ - ["vehicles", _nearbyVehicles] - ]] - ] - }] -]; - -GVAR(GarageSessionService) = createHashMapObject [GVAR(GarageSessionServiceBaseClass)]; -GVAR(GarageSessionService) diff --git a/arma/client/addons/garage/functions/fnc_initUIBridge.sqf b/arma/client/addons/garage/functions/fnc_initUIBridge.sqf index ec15d50..ee20a28 100644 --- a/arma/client/addons/garage/functions/fnc_initUIBridge.sqf +++ b/arma/client/addons/garage/functions/fnc_initUIBridge.sqf @@ -3,11 +3,20 @@ /* * File: fnc_initUIBridge.sqf * Author: IDSolutions - * Date: 2026-03-14 + * Date: 2026-03-27 * Public: No * * Description: - * Initializes the garage UI bridge for browser control state and retrieve/store actions. + * Initializes the garage UI bridge for browser control state and UI events. + * + * Arguments: + * None + * + * Return Value: + * Garage UI bridge object [HASHMAP OBJECT] + * + * Example: + * call forge_client_garage_fnc_initUIBridge; */ #pragma hemtt ignore_variables ["_self"] @@ -17,10 +26,6 @@ private _webUIBridgeDeclaration = _webUIDeclarations get "bridgeDeclaration"; GVAR(GarageUIBridgeBaseClass) = compileFinal createHashMapFromArray [ ["#base", _webUIBridgeDeclaration], ["#type", "GarageUIBridgeBaseClass"], - ["#create", compileFinal { - _self set ["pendingStoreVehicle", objNull]; - _self set ["pendingRetrieve", createHashMap]; - }], ["getActiveBrowserControl", compileFinal { private _display = uiNamespace getVariable ["RscGarage", displayNull]; if (isNull _display) exitWith { @@ -40,164 +45,13 @@ GVAR(GarageUIBridgeBaseClass) = compileFinal createHashMapFromArray [ _screen call ["markReady", [true]]; _self call ["flushPendingEvents", []]; - _self call ["sendEvent", ["garage::hydrate", GVAR(GarageSessionService) call ["buildPayload", []], _control]]; + _self call ["sendEvent", ["garage::hydrate", GVAR(GaragePayloadService) call ["buildPayload", []], _control]]; }], ["refreshGarage", compileFinal { private _control = _self call ["getActiveBrowserControl", []]; if (isNull _control) exitWith { false }; - _self call ["sendEvent", ["garage::sync", GVAR(GarageSessionService) call ["buildPayload", []], _control]] - }], - ["handleRetrieveRequest", compileFinal { - params [["_data", createHashMap, [createHashMap]]]; - - private _plate = _data getOrDefault ["plate", ""]; - if (_plate isEqualTo "") exitWith { - _self call ["sendEvent", ["garage::retrieve::failure", createHashMapFromArray [ - ["message", "Select a stored vehicle to retrieve."] - ]]]; - }; - - private _garageMap = if (isNil QGVAR(GarageClass)) then { - createHashMap - } else { - GVAR(GarageClass) call ["getGarageState", []] - }; - private _vehicleData = _garageMap getOrDefault [_plate, createHashMap]; - if (_vehicleData isEqualTo createHashMap) exitWith { - _self call ["sendEvent", ["garage::retrieve::failure", createHashMapFromArray [ - ["message", "Stored vehicle record could not be found."] - ]]]; - }; - - private _context = GVAR(GarageSessionService) call ["getContext", []]; - private _spawnPosition = _context getOrDefault ["spawnPosition", getPosATL player]; - private _spawnHeading = _context getOrDefault ["spawnHeading", getDir player]; - private _spawnRadius = _context getOrDefault ["spawnRadius", 6]; - private _blockingVehicles = []; - { - _blockingVehicles pushBackUnique _x; - } forEach (_spawnPosition nearEntities [["Car", "Tank", "Air", "Ship"], _spawnRadius]); - { - _blockingVehicles pushBackUnique _x; - } forEach (nearestObjects [_spawnPosition, ["Car", "Tank", "Air", "Ship"], _spawnRadius]); - if (_blockingVehicles isNotEqualTo []) exitWith { - _self call ["sendEvent", ["garage::retrieve::failure", createHashMapFromArray [ - ["message", "The garage spawn area is blocked."] - ]]]; - }; - - private _className = _vehicleData getOrDefault ["classname", ""]; - if (_className isEqualTo "") exitWith { - _self call ["sendEvent", ["garage::retrieve::failure", createHashMapFromArray [ - ["message", "Stored vehicle record is missing a classname."] - ]]]; - }; - - private _vehicle = createVehicle [_className, _spawnPosition, [], 0, "CAN_COLLIDE"]; - _vehicle setDir _spawnHeading; - _vehicle setFuel (_vehicleData getOrDefault ["fuel", 0]); - _vehicle setDamage (_vehicleData getOrDefault ["damage", 0]); - - private _hitPoints = _vehicleData getOrDefault ["hit_points", createHashMap]; - private _hitPointNames = _hitPoints getOrDefault ["names", []]; - private _hitPointValues = _hitPoints getOrDefault ["values", []]; - for "_index" from 0 to ((count _hitPointNames) - 1) do { - _vehicle setHitPointDamage [_hitPointNames param [_index, ""], _hitPointValues param [_index, 0]]; - }; - - _vehicle setVariable ["forge_garage_plate", _plate, true]; - _vehicle setVariable ["forge_garage_owner_uid", getPlayerUID player, true]; - - _self set ["pendingRetrieve", createHashMapFromArray [ - ["plate", _plate], - ["vehicle", _vehicle] - ]]; - - [SRPC(garage,requestRetrieveVehicle), [getPlayerUID player, _plate]] call CFUNC(serverEvent); - }], - ["handleStoreRequest", compileFinal { - params [["_data", createHashMap, [createHashMap]]]; - - private _netId = _data getOrDefault ["netId", ""]; - if (_netId isEqualTo "") exitWith { - _self call ["sendEvent", ["garage::store::failure", createHashMapFromArray [ - ["message", "Select a nearby vehicle to store."] - ]]]; - }; - - private _vehicle = objectFromNetId _netId; - if (isNull _vehicle) exitWith { - _self call ["sendEvent", ["garage::store::failure", createHashMapFromArray [ - ["message", "The selected vehicle is no longer available."] - ]]]; - }; - - if (crew _vehicle isNotEqualTo []) exitWith { - _self call ["sendEvent", ["garage::store::failure", createHashMapFromArray [ - ["message", "All crew must exit the vehicle before storing it."] - ]]]; - }; - - private _rawHitPoints = getAllHitPointsDamage _vehicle; - private _hitPointsJson = toJSON (createHashMapFromArray [ - ["names", _rawHitPoints param [0, []]], - ["selections", _rawHitPoints param [1, []]], - ["values", _rawHitPoints param [2, []]] - ]); - - _self set ["pendingStoreVehicle", _vehicle]; - [SRPC(garage,requestStoreVehicle), [ - getPlayerUID player, - typeOf _vehicle, - fuel _vehicle, - damage _vehicle, - _hitPointsJson - ]] call CFUNC(serverEvent); - }], - ["handleActionResponse", compileFinal { - params [["_payload", createHashMap, [createHashMap]]]; - - private _action = _payload getOrDefault ["action", ""]; - private _success = _payload getOrDefault ["success", false]; - private _message = _payload getOrDefault ["message", "Garage action failed."]; - - switch (_action) do { - case "retrieve": { - private _pendingRetrieve = _self getOrDefault ["pendingRetrieve", createHashMap]; - private _vehicle = _pendingRetrieve getOrDefault ["vehicle", objNull]; - - if (!_success && { !isNull _vehicle }) then { - deleteVehicle _vehicle; - }; - - _self set ["pendingRetrieve", createHashMap]; - _self call ["sendEvent", [[ - "garage::retrieve::failure", - "garage::retrieve::success" - ] select _success, createHashMapFromArray [["message", _message]]]]; - }; - case "store": { - private _vehicle = _self getOrDefault ["pendingStoreVehicle", objNull]; - - if (_success && { !isNull _vehicle }) then { - deleteVehicle _vehicle; - }; - - _self set ["pendingStoreVehicle", objNull]; - _self call ["sendEvent", [[ - "garage::store::failure", - "garage::store::success" - ] select _success, createHashMapFromArray [["message", _message]]]]; - }; - }; - - [] spawn { - sleep 0.05; - if !(isNil QGVAR(GarageUIBridge)) then { - GVAR(GarageUIBridge) call ["refreshGarage", []]; - }; - }; + _self call ["sendEvent", ["garage::sync", GVAR(GaragePayloadService) call ["buildPayload", []], _control]] }] ]; diff --git a/arma/client/addons/garage/functions/fnc_initVGClass.sqf b/arma/client/addons/garage/functions/fnc_initVGRepository.sqf similarity index 74% rename from arma/client/addons/garage/functions/fnc_initVGClass.sqf rename to arma/client/addons/garage/functions/fnc_initVGRepository.sqf index e5370d7..4e99a8a 100644 --- a/arma/client/addons/garage/functions/fnc_initVGClass.sqf +++ b/arma/client/addons/garage/functions/fnc_initVGRepository.sqf @@ -1,51 +1,45 @@ #include "..\script_component.hpp" /* - * File: fnc_initVGClass.sqf + * File: fnc_initVGRepository.sqf * Author: IDSolutions - * Date: 2025-12-16 - * Last Update: 2026-03-25 + * Date: 2026-03-27 * Public: No * * Description: - * Initializes the Virtual Garage class for managing player garage unlocks. - * Provides methods for syncing, saving, and applying virtual items to BIS Garage. + * Initializes the virtual garage repository for BIS virtual garage state. * * Arguments: * None * * Return Value: - * vGarage class object [HASHMAP OBJECT] + * Virtual garage repository object [HASHMAP OBJECT] * * Example: - * call forge_client_garage_fnc_initVGClass; + * call forge_client_garage_fnc_initVGRepository; */ #pragma hemtt ignore_variables ["_self"] -GVAR(VGBaseClass) = compileFinal createHashMapFromArray [ - ["#type", "VGBaseClass"], +GVAR(VGRepositoryBaseClass) = compileFinal createHashMapFromArray [ + ["#type", "VGRepositoryBaseClass"], ["#create", compileFinal { GVAR(isPreLoaded) = false; - - _self set ["uid", (getPlayerUID player)]; + _self set ["uid", getPlayerUID player]; _self set ["vGarage", createHashMap]; _self set ["isLoaded", false]; _self set ["lastSave", time]; }], ["init", compileFinal { private _uid = _self get "uid"; - private _vGarage = _self get "vGarage"; - - [SRPC(garage,requestInitVG), [_uid, _vGarage]] call CFUNC(serverEvent); + [SRPC(garage,requestInitVG), [_uid]] call CFUNC(serverEvent); _self set ["lastSave", time]; - systemChat format ["VGarage loaded for %1", (name player)]; - diag_log "[FORGE:Client:VGarage] VGarage Class Initialized!"; + systemChat format ["VGarage loaded for %1", name player]; + diag_log "[FORGE:Client:VGarage] Repository Initialized!"; }], ["save", compileFinal { private _uid = _self get "uid"; [SRPC(garage,requestSaveVG), [_uid]] call CFUNC(serverEvent); - _self set ["lastSave", time]; }], ["sync", compileFinal { @@ -56,7 +50,6 @@ GVAR(VGBaseClass) = compileFinal createHashMapFromArray [ { _vGarage set [_x, _y]; - switch (_x) do { case "cars": { _self call ["apply", ["cars"]]; }; case "armor": { _self call ["apply", ["armor"]]; }; @@ -69,9 +62,8 @@ GVAR(VGBaseClass) = compileFinal createHashMapFromArray [ } forEach _data; _self set ["vGarage", _vGarage]; - if !(_isLoaded) then { _self set ["isLoaded", true]; }; - diag_log "[FORGE:Client:VGarage] Sync completed"; + diag_log "[FORGE:Client:VGarage] Repository sync completed"; }], ["get", compileFinal { params [["_key", "", [""]], ["_default", nil, [[], "", 0, false, createHashMap]]]; @@ -84,7 +76,6 @@ GVAR(VGBaseClass) = compileFinal createHashMapFromArray [ private _vehicles = _self call ["get", [_key, []]]; private _appliedVehicles = []; - { _appliedVehicles append [getText (configFile >> "CfgVehicles" >> _x >> "model"), [configFile >> "CfgVehicles" >> _x]]; } forEach _vehicles; @@ -101,5 +92,5 @@ GVAR(VGBaseClass) = compileFinal createHashMapFromArray [ }] ]; -GVAR(VGClass) = createHashMapObject [GVAR(VGBaseClass)]; -GVAR(VGClass) +GVAR(VGRepository) = createHashMapObject [GVAR(VGRepositoryBaseClass)]; +GVAR(VGRepository) diff --git a/arma/client/addons/garage/functions/fnc_openVG.sqf b/arma/client/addons/garage/functions/fnc_openVG.sqf index ddc3d6b..70c3518 100644 --- a/arma/client/addons/garage/functions/fnc_openVG.sqf +++ b/arma/client/addons/garage/functions/fnc_openVG.sqf @@ -89,7 +89,7 @@ if !(GVAR(isPreLoaded)) then { private _nearVehicles = FORGE_VehSpawnPos nearEntities [["Car", "Tank", "Air", "Ship"], 5]; if (_nearVehicles isNotEqualTo []) exitWith { private _params = ["warning", "Virtual Garage", "Vehicle spawn position is blocked. Please move the vehicle before accessing the garage.", 3000]; - EGVAR(notifications,NotificationClass) call ["create", _params]; + EGVAR(notifications,NotificationService) call ["create", _params]; }; ["Open", true] call BFUNC(garage); diff --git a/arma/client/addons/locker/XEH_PREP.hpp b/arma/client/addons/locker/XEH_PREP.hpp index f3e1d08..b979dfe 100644 --- a/arma/client/addons/locker/XEH_PREP.hpp +++ b/arma/client/addons/locker/XEH_PREP.hpp @@ -1,2 +1,2 @@ -PREP(initLockerClass); -PREP(initVAClass); +PREP(initRepository); +PREP(initVARepository); diff --git a/arma/client/addons/locker/XEH_postInitClient.sqf b/arma/client/addons/locker/XEH_postInitClient.sqf index d4baf95..20123fa 100644 --- a/arma/client/addons/locker/XEH_postInitClient.sqf +++ b/arma/client/addons/locker/XEH_postInitClient.sqf @@ -1,48 +1,48 @@ #include "script_component.hpp" -if (isNil QGVAR(LockerClass)) then { call FUNC(initLockerClass); }; -if (isNil QGVAR(VAClass)) then { call FUNC(initVAClass); }; +if (isNil QGVAR(LockerRepository)) then { call FUNC(initRepository); }; +if (isNil QGVAR(VARepository)) then { call FUNC(initVARepository); }; [QGVAR(initLocker), { - GVAR(LockerClass) call ["init", []]; + GVAR(LockerRepository) call ["init", []]; }] call CFUNC(addEventHandler); [QGVAR(responseInitLocker), { params [["_data", createHashMap, [createHashMap]]]; - GVAR(LockerClass) call ["sync", [_data]]; + GVAR(LockerRepository) call ["sync", [_data]]; }] call CFUNC(addEventHandler); [QGVAR(responseSyncLocker), { params [["_data", createHashMap, [createHashMap, []]], ["_jip", false, [false]]]; - GVAR(LockerClass) call ["sync", [_data, _jip]]; + GVAR(LockerRepository) call ["sync", [_data, _jip]]; }] call CFUNC(addEventHandler); [QGVAR(initVA), { - GVAR(VAClass) call ["init", []]; + GVAR(VARepository) call ["init", []]; }] call CFUNC(addEventHandler); [QGVAR(responseInitVA), { params [["_data", createHashMap, [createHashMap]]]; - GVAR(VAClass) call ["sync", [_data]]; + GVAR(VARepository) call ["sync", [_data]]; }] call CFUNC(addEventHandler); [QGVAR(responseSyncVA), { params [["_data", createHashMap, [createHashMap, []]], ["_jip", false, [false]]]; - GVAR(VAClass) call ["sync", [_data, _jip]]; + GVAR(VARepository) call ["sync", [_data, _jip]]; }] call CFUNC(addEventHandler); [{ - EGVAR(garage,GarageClass) get "isLoaded"; + EGVAR(garage,GarageRepository) get "isLoaded"; }, { [QGVAR(initLocker), []] call CFUNC(localEvent); }] call CFUNC(waitUntilAndExecute); [{ - GVAR(LockerClass) get "isLoaded"; + GVAR(LockerRepository) get "isLoaded"; }, { [QGVAR(initVA), []] call CFUNC(localEvent); }] call CFUNC(waitUntilAndExecute); diff --git a/arma/client/addons/locker/functions/fnc_initLockerClass.sqf b/arma/client/addons/locker/functions/fnc_initRepository.sqf similarity index 86% rename from arma/client/addons/locker/functions/fnc_initLockerClass.sqf rename to arma/client/addons/locker/functions/fnc_initRepository.sqf index 4012c52..e67157e 100644 --- a/arma/client/addons/locker/functions/fnc_initLockerClass.sqf +++ b/arma/client/addons/locker/functions/fnc_initRepository.sqf @@ -1,31 +1,29 @@ #include "..\script_component.hpp" /* - * File: fnc_initLockerClass.sqf + * File: fnc_initRepository.sqf * Author: IDSolutions - * Date: 2025-12-17 - * Last Update: 2026-03-25 + * Date: 2026-03-27 * Public: No * * Description: - * Initializes the Locker class for managing player locker items. - * Provides methods for syncing, saving, and applying locker items to the player's locker. + * Initializes the locker repository for managing player locker items. * * Arguments: * None * * Return Value: - * Locker class object [HASHMAP OBJECT] + * Locker repository object [HASHMAP OBJECT] * * Example: - * call forge_client_locker_fnc_initLockerClass + * call forge_client_locker_fnc_initRepository; */ #pragma hemtt ignore_variables ["_self"] -GVAR(LockerBaseClass) = compileFinal createHashMapFromArray [ - ["#type", "LockerBaseClass"], +GVAR(LockerRepositoryBaseClass) = compileFinal createHashMapFromArray [ + ["#type", "LockerRepositoryBaseClass"], ["#create", compileFinal { - _self set ["uid", (getPlayerUID player)]; + _self set ["uid", getPlayerUID player]; _self set ["isLoaded", false]; _self set ["lastSave", time]; _self set ["locker", createHashMap]; @@ -36,8 +34,8 @@ GVAR(LockerBaseClass) = compileFinal createHashMapFromArray [ [SRPC(locker,requestInitLocker), [_uid]] call CFUNC(serverEvent); _self set ["lastSave", time]; - systemChat format ["Locker loaded for %1", (name player)]; - diag_log "[FORGE:Client:Locker] Locker Class Initialized!"; + systemChat format ["Locker loaded for %1", name player]; + diag_log "[FORGE:Client:Locker] Locker Repository Initialized!"; }], ["get", compileFinal { params [["_key", "", [""]], ["_default", nil, [[], "", 0, false, createHashMap]]]; @@ -84,8 +82,8 @@ GVAR(LockerBaseClass) = compileFinal createHashMapFromArray [ private _cfgWeapons = configFile >> "CfgWeapons" >> _containerClass; private _itemInfoType = getNumber (_cfgWeapons >> "ItemInfo" >> "type"); private _isBackpack = isClass _cfgVehicles; - private _isUniform = isClass _cfgWeapons && {_itemInfoType == TYPE_UNIFORM}; - private _isVest = isClass _cfgWeapons && {_itemInfoType == TYPE_VEST}; + private _isUniform = isClass _cfgWeapons && { _itemInfoType == TYPE_UNIFORM }; + private _isVest = isClass _cfgWeapons && { _itemInfoType == TYPE_VEST }; if (!_isBackpack && !_isVest && !_isUniform) then { continue; }; @@ -142,7 +140,6 @@ GVAR(LockerBaseClass) = compileFinal createHashMapFromArray [ private _weaponItems = weaponsItemsCargo _container; { - // private _weapon = _x param [0, ""]; private _muzzle = _x param [1, ""]; private _pointer = _x param [2, ""]; private _optic = _x param [3, ""]; @@ -150,7 +147,7 @@ GVAR(LockerBaseClass) = compileFinal createHashMapFromArray [ 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 _attachments = [_muzzle, _pointer, _optic, _underbarrel, _bipod] select { (_x isEqualType "") && { _x != "" } }; { private _existing = _locker getOrDefault [_x, createHashMap]; private _existingCount = _existing getOrDefault ["amount", 0]; @@ -163,7 +160,7 @@ GVAR(LockerBaseClass) = compileFinal createHashMapFromArray [ } forEach _attachments; if (_primaryMag isNotEqualTo ["", 0]) then { - _primaryMag params ["_magClass", "_ammoCount"]; // TODO: Add ammo count to locker + _primaryMag params ["_magClass", "_ammoCount"]; if (_magClass != "") then { private _existing = _locker getOrDefault [_magClass, createHashMap]; private _existingCount = _existing getOrDefault ["amount", 0]; @@ -177,7 +174,7 @@ GVAR(LockerBaseClass) = compileFinal createHashMapFromArray [ }; if (_secondaryMag isNotEqualTo ["", 0]) then { - _secondaryMag params ["_magClass", "_ammoCount"]; // TODO: Add ammo count to locker + _secondaryMag params ["_magClass", "_ammoCount"]; if (_magClass != "") then { private _existing = _locker getOrDefault [_magClass, createHashMap]; private _existingCount = _existing getOrDefault ["amount", 0]; @@ -205,7 +202,7 @@ GVAR(LockerBaseClass) = compileFinal createHashMapFromArray [ _locker addEventHandler ["ContainerOpened", { params ["_container", "_unit"]; - private _index = GVAR(LockerClass) get "locker"; + private _index = GVAR(LockerRepository) get "locker"; clearBackpackCargo _container; clearItemCargo _container; @@ -228,7 +225,7 @@ GVAR(LockerBaseClass) = compileFinal createHashMapFromArray [ if (count _index > 25) then { private _params = ["warning", "Over Capacity", "Locker has more then 25 items, please remove some items", 3000]; - GVAR(NotificationClass) call ["create", _params]; + GVAR(NotificationService) call ["create", _params]; }; }]; @@ -236,17 +233,17 @@ GVAR(LockerBaseClass) = compileFinal createHashMapFromArray [ 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]]; + _newLocker = GVAR(LockerRepository) call ["getCargo", [_container, _newLocker]]; + _newLocker = GVAR(LockerRepository) call ["getContainerItems", [_container, _newLocker]]; + _newLocker = GVAR(LockerRepository) call ["getAttachments", [_container, _newLocker]]; private _uid = getPlayerUID _unit; [SRPC(locker,requestOverrideLocker), [_uid, _newLocker]] call CFUNC(serverEvent); - GVAR(LockerClass) set ["locker", _newLocker]; + GVAR(LockerRepository) set ["locker", _newLocker]; if (count _newLocker > 25) then { private _params = ["warning", "Over Capacity", "Locker has more then 25 items, please remove some items", 3000]; - GVAR(NotificationClass) call ["create", _params]; + GVAR(NotificationService) call ["create", _params]; }; }]; }], @@ -296,5 +293,5 @@ GVAR(LockerBaseClass) = compileFinal createHashMapFromArray [ }] ]; -GVAR(LockerClass) = createHashMapObject [GVAR(LockerBaseClass)]; -GVAR(LockerClass) +GVAR(LockerRepository) = createHashMapObject [GVAR(LockerRepositoryBaseClass)]; +GVAR(LockerRepository) diff --git a/arma/client/addons/locker/functions/fnc_initVAClass.sqf b/arma/client/addons/locker/functions/fnc_initVARepository.sqf similarity index 79% rename from arma/client/addons/locker/functions/fnc_initVAClass.sqf rename to arma/client/addons/locker/functions/fnc_initVARepository.sqf index d6c0749..d4aa4b9 100644 --- a/arma/client/addons/locker/functions/fnc_initVAClass.sqf +++ b/arma/client/addons/locker/functions/fnc_initVARepository.sqf @@ -1,31 +1,29 @@ #include "..\script_component.hpp" /* - * File: fnc_init.sqf + * File: fnc_initVARepository.sqf * Author: IDSolutions - * Date: 2025-12-16 - * Last Update: 2026-03-25 + * Date: 2026-03-27 * Public: No * * Description: - * Initializes the Virtual Arsenal class for managing player arsenal unlocks. - * Provides methods for syncing, saving, and applying virtual items to BIS Arsenal. + * Initializes the virtual arsenal repository for managing player arsenal unlocks. * * Arguments: * None * * Return Value: - * vArsenal class object [HASHMAP OBJECT] + * Virtual arsenal repository object [HASHMAP OBJECT] * * Example: - * call forge_client_locker_fnc_init; + * call forge_client_locker_fnc_initVARepository; */ #pragma hemtt ignore_variables ["_self"] -GVAR(VABaseClass) = compileFinal createHashMapFromArray [ - ["#type", "VABaseClass"], +GVAR(VARepositoryBaseClass) = compileFinal createHashMapFromArray [ + ["#type", "VARepositoryBaseClass"], ["#create", compileFinal { - _self set ["uid", (getPlayerUID player)]; + _self set ["uid", getPlayerUID player]; _self set ["vArsenal", createHashMap]; _self set ["isLoaded", false]; _self set ["lastSave", time]; @@ -36,8 +34,8 @@ GVAR(VABaseClass) = compileFinal createHashMapFromArray [ [SRPC(locker,requestInitVA), [_uid]] call CFUNC(serverEvent); _self set ["lastSave", time]; - systemChat format ["VArsenal loaded for %1", (name player)]; - diag_log "[FORGE:Client:VArsenal] VArsenal Class Initialized!"; + systemChat format ["VArsenal loaded for %1", name player]; + diag_log "[FORGE:Client:VArsenal] Repository Initialized!"; }], ["save", compileFinal { private _uid = _self get "uid"; @@ -92,5 +90,5 @@ GVAR(VABaseClass) = compileFinal createHashMapFromArray [ }] ]; -GVAR(VAClass) = createHashMapObject [GVAR(VABaseClass)]; -GVAR(VAClass) +GVAR(VARepository) = createHashMapObject [GVAR(VARepositoryBaseClass)]; +GVAR(VARepository) diff --git a/arma/client/addons/notifications/XEH_PREP.hpp b/arma/client/addons/notifications/XEH_PREP.hpp index c0e2dad..e3b9ad1 100644 --- a/arma/client/addons/notifications/XEH_PREP.hpp +++ b/arma/client/addons/notifications/XEH_PREP.hpp @@ -1,3 +1,3 @@ PREP(handleUIEvents); -PREP(initNotificationClass); +PREP(initService); PREP(openUI); diff --git a/arma/client/addons/notifications/XEH_postInitClient.sqf b/arma/client/addons/notifications/XEH_postInitClient.sqf index 9981181..6504295 100644 --- a/arma/client/addons/notifications/XEH_postInitClient.sqf +++ b/arma/client/addons/notifications/XEH_postInitClient.sqf @@ -1,16 +1,16 @@ #include "script_component.hpp" [{ - EGVAR(locker,VAClass) get "isLoaded"; + EGVAR(locker,VARepository) get "isLoaded"; }, { ("NotificationHudLayer" call BFUNC(rscLayer)) cutRsc ["RscNotifications", "PLAIN"]; call FUNC(openUI); - if (isNil QGVAR(NotificationClass)) then { call FUNC(initNotificationClass); }; + if (isNil QGVAR(NotificationService)) then { call FUNC(initService); }; }] call CFUNC(waitUntilAndExecute); [QGVAR(recieveNotification), { params [["_type", "", [""]], ["_title", "", [""]], ["_content", "", [""]], ["_duration", 4000, [4000]]]; playSound QGVAR(notify); - GVAR(NotificationClass) call ["create", [_type, _title, _content, _duration]]; + GVAR(NotificationService) call ["create", [_type, _title, _content, _duration]]; }] call CFUNC(addEventHandler); diff --git a/arma/client/addons/notifications/functions/fnc_handleUIEvents.sqf b/arma/client/addons/notifications/functions/fnc_handleUIEvents.sqf index 7c84d95..287842c 100644 --- a/arma/client/addons/notifications/functions/fnc_handleUIEvents.sqf +++ b/arma/client/addons/notifications/functions/fnc_handleUIEvents.sqf @@ -32,7 +32,7 @@ diag_log format ["[FORGE:Client:Notifications] Handling UI event: %1 with data: switch (_event) do { case "notifications::ready": { - GVAR(NotificationClass) call ["init", []]; + GVAR(NotificationService) call ["init", []]; }; default { hint format ["[FORGE:Client:Notifications] Unhandled event: %1", _event]; }; }; diff --git a/arma/client/addons/notifications/functions/fnc_initNotificationClass.sqf b/arma/client/addons/notifications/functions/fnc_initService.sqf similarity index 66% rename from arma/client/addons/notifications/functions/fnc_initNotificationClass.sqf rename to arma/client/addons/notifications/functions/fnc_initService.sqf index 06ed9cc..cfdb3ce 100644 --- a/arma/client/addons/notifications/functions/fnc_initNotificationClass.sqf +++ b/arma/client/addons/notifications/functions/fnc_initService.sqf @@ -1,29 +1,27 @@ #include "..\script_component.hpp" /* - * File: fnc_initNotificationClass.sqf + * File: fnc_initService.sqf * Author: IDSolutions - * Date: 2026-01-28 - * Last Update: 2026-01-30 + * Date: 2026-03-27 * Public: No * * Description: - * Initializes the notification class for managing player notifications. - * Provides methods for creating and displaying notifications. + * Initializes the notification service for client notification display. * * Arguments: * None * * Return Value: - * Notification class object [HASHMAP OBJECT] + * Notification service object [HASHMAP OBJECT] * * Example: - * call forge_client_notifications_fnc_initNotificationClass + * call forge_client_notifications_fnc_initService; */ #pragma hemtt ignore_variables ["_self"] -GVAR(NotificationClass) = createHashMapObject [[ - ["#type", "INotificationClass"], +GVAR(NotificationService) = createHashMapObject [[ + ["#type", "INotificationService"], ["#create", { private _display = uiNamespace getVariable ["RscNotifications", nil]; private _control = _display displayCtrl 1004; @@ -37,8 +35,8 @@ GVAR(NotificationClass) = createHashMapObject [[ _self call ["create", _params]; _self set ["isLoaded", true]; - systemChat format ["Notifications loaded for %1", (name player)]; - diag_log "[FORGE:Client:Notifications] Notification Class Initialized!"; + systemChat format ["Notifications loaded for %1", name player]; + diag_log "[FORGE:Client:Notifications] Notification Service Initialized!"; }], ["create", { params [["_type", "", ["info"]], ["_title", "", [""]], ["_content", "", [""]], ["_duration", 4000]]; @@ -55,4 +53,4 @@ GVAR(NotificationClass) = createHashMapObject [[ }] ]]; -GVAR(NotificationClass) +GVAR(NotificationService) diff --git a/arma/client/addons/org/XEH_PREP.hpp b/arma/client/addons/org/XEH_PREP.hpp index 7d71bae..fb83b48 100644 --- a/arma/client/addons/org/XEH_PREP.hpp +++ b/arma/client/addons/org/XEH_PREP.hpp @@ -1,4 +1,4 @@ PREP(handleUIEvents); -PREP(initClass); +PREP(initRepository); PREP(initUIBridge); PREP(openUI); diff --git a/arma/client/addons/org/XEH_postInitClient.sqf b/arma/client/addons/org/XEH_postInitClient.sqf index 1d0d2c2..870a9fc 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(initClass); }; +if (isNil QGVAR(OrgRepository)) then { call FUNC(initRepository); }; if (isNil QGVAR(OrgUIBridge)) then { call FUNC(initUIBridge); }; [QGVAR(responseInitOrg), { @@ -46,7 +46,7 @@ if (isNil QGVAR(OrgUIBridge)) then { call FUNC(initUIBridge); }; }] call CFUNC(addEventHandler); [{ - EGVAR(locker,VAClass) get "isLoaded"; + EGVAR(locker,VARepository) get "isLoaded"; }, { [QGVAR(initOrg), []] call CFUNC(localEvent); }] call CFUNC(waitUntilAndExecute); diff --git a/arma/client/addons/org/functions/fnc_handleUIEvents.sqf b/arma/client/addons/org/functions/fnc_handleUIEvents.sqf index a9657c3..6563ac6 100644 --- a/arma/client/addons/org/functions/fnc_handleUIEvents.sqf +++ b/arma/client/addons/org/functions/fnc_handleUIEvents.sqf @@ -1,19 +1,24 @@ #include "..\script_component.hpp" /* + * File: fnc_handleUIEvents.sqf * Author: IDSolutions - * Handles the UI events. + * Date: 2026-03-27 + * Public: No + * + * Description: + * Handles the org UI events. * * Arguments: - * None + * 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: - * None + * UI events handled [BOOL] * * Example: * call forge_client_org_fnc_handleUIEvents; - * - * Public: No */ params ["_control", "_isConfirmDialog", "_message"]; diff --git a/arma/client/addons/org/functions/fnc_initClass.sqf b/arma/client/addons/org/functions/fnc_initRepository.sqf similarity index 57% rename from arma/client/addons/org/functions/fnc_initClass.sqf rename to arma/client/addons/org/functions/fnc_initRepository.sqf index 52695a5..ac50b8e 100644 --- a/arma/client/addons/org/functions/fnc_initClass.sqf +++ b/arma/client/addons/org/functions/fnc_initRepository.sqf @@ -1,28 +1,27 @@ #include "..\script_component.hpp" /* - * File: fnc_initClass.sqf + * File: fnc_initRepository.sqf * Author: IDSolutions - * Date: 2026-03-25 - * Last Update: 2026-03-25 + * Date: 2026-03-27 * Public: No * * Description: - * No description added yet. + * Initializes the org repository for client org lifecycle state. * - * Parameter(s): - * N/A + * Arguments: + * None * - * Returns: - * Something [BOOL] + * Return Value: + * Org repository object [HASHMAP OBJECT] * - * Example(s): - * [parameter] call forge_x_component_fnc_myFunction + * Example: + * call forge_client_org_fnc_initRepository; */ #pragma hemtt ignore_variables ["_self"] -GVAR(OrgBaseClass) = compileFinal createHashMapFromArray [ - ["#type", "OrgBaseClass"], +GVAR(OrgRepositoryBaseClass) = compileFinal createHashMapFromArray [ + ["#type", "OrgRepositoryBaseClass"], ["#create", compileFinal { _self set ["uid", getPlayerUID player]; _self set ["isLoaded", false]; @@ -32,12 +31,11 @@ GVAR(OrgBaseClass) = compileFinal createHashMapFromArray [ [SRPC(org,requestInitOrg), [getPlayerUID player]] call CFUNC(serverEvent); _self set ["lastSave", time]; - systemChat format ["Org loaded for %1", (name player)]; - diag_log "[FORGE:Client:Org] Org Class Initialized!"; + systemChat format ["Org loaded for %1", name player]; + diag_log "[FORGE:Client:Org] Org Repository Initialized!"; }], ["markLoaded", compileFinal { if !(_self getOrDefault ["isLoaded", false]) then { _self set ["isLoaded", true]; }; - true }], ["save", compileFinal { @@ -46,5 +44,5 @@ GVAR(OrgBaseClass) = compileFinal createHashMapFromArray [ }] ]; -GVAR(OrgClass) = createHashMapObject [GVAR(OrgBaseClass)]; -GVAR(OrgClass) +GVAR(OrgRepository) = createHashMapObject [GVAR(OrgRepositoryBaseClass)]; +GVAR(OrgRepository) diff --git a/arma/client/addons/org/functions/fnc_openUI.sqf b/arma/client/addons/org/functions/fnc_openUI.sqf index 7506dd4..e146d45 100644 --- a/arma/client/addons/org/functions/fnc_openUI.sqf +++ b/arma/client/addons/org/functions/fnc_openUI.sqf @@ -1,19 +1,22 @@ #include "..\script_component.hpp" /* + * File: fnc_openUI.sqf * Author: IDSolutions - * Opens the player interaction interface. + * Date: 2026-03-27 + * Public: No + * + * Description: + * Opens the org UI. * * Arguments: * None * * Return Value: - * None + * UI opened [BOOL] * * Example: * call forge_client_org_fnc_openUI; - * - * Public: No */ private _display = createDialog ["RscOrg", true]; diff --git a/arma/client/addons/store/functions/fnc_initUIBridge.sqf b/arma/client/addons/store/functions/fnc_initUIBridge.sqf index e4a1b3c..e2e7b47 100644 --- a/arma/client/addons/store/functions/fnc_initUIBridge.sqf +++ b/arma/client/addons/store/functions/fnc_initUIBridge.sqf @@ -3,12 +3,20 @@ /* * File: fnc_initUIBridge.sqf * Author: IDSolutions - * Date: 2026-03-10 - * Last Update: 2026-03-25 + * Date: 2026-03-27 * Public: No * * Description: - * Initializes the store UI bridge for browser control state, event routing, and catalog queries. + * Initializes the store UI bridge for browser control state and store UI events. + * + * Arguments: + * None + * + * Return Value: + * Store UI bridge object [HASHMAP OBJECT] + * + * Example: + * call forge_client_store_fnc_initUIBridge; */ #pragma hemtt ignore_variables ["_self"] diff --git a/arma/server/addons/org/functions/fnc_initOrgStore.sqf b/arma/server/addons/org/functions/fnc_initOrgStore.sqf index cd01078..b55cf35 100644 --- a/arma/server/addons/org/functions/fnc_initOrgStore.sqf +++ b/arma/server/addons/org/functions/fnc_initOrgStore.sqf @@ -185,6 +185,12 @@ GVAR(OrgBaseStore) = compileFinal createHashMapFromArray [ }; if (_org isEqualTo createHashMap) exitWith { createHashMap }; + // Ensure the requesting player's membership is present in the cached roster + // before shaping the portal payload. This prevents stale org caches from + // omitting the current member while still resolving owner metadata. + _org = _self call ["verifyMember", [_org, _orgID, _uid, _player, _actor]]; + GVAR(Registry) set [_orgID, _org, true]; + private _name = _org getOrDefault ["name", ""]; private _id = _org getOrDefault ["id", _orgID]; private _ownerUid = _org getOrDefault ["owner", ""]; diff --git a/build-arma.ps1 b/build-arma.ps1 index d7b67c3..612f650 100644 --- a/build-arma.ps1 +++ b/build-arma.ps1 @@ -10,6 +10,9 @@ .PARAMETER Target Specify which target to build: 'client', 'server', or 'both' (default) +.PARAMETER BuildUI + Rebuild the web UI bundles before running the client build. + .EXAMPLE .\build-arma.ps1 Builds both client and server @@ -17,12 +20,19 @@ .EXAMPLE .\build-arma.ps1 -Target client Builds only the client + +.EXAMPLE + .\build-arma.ps1 -Target client -BuildUI + Rebuilds web UI bundles and then builds the client #> param( [Parameter(Mandatory=$false)] [ValidateSet('client', 'server', 'both')] - [string]$Target = 'both' + [string]$Target = 'both', + + [Parameter(Mandatory=$false)] + [switch]$BuildUI ) $ErrorActionPreference = "Stop" @@ -70,7 +80,9 @@ $serverPath = Join-Path $scriptDir "arma\server" try { if ($Target -eq 'client' -or $Target -eq 'both') { - Build-WebUIAssets + if ($BuildUI) { + Build-WebUIAssets + } Build-HemttProject -ProjectPath $clientPath -ProjectName "Client" }