Merge development into master: shared Web UI runtime, bridge-driven UIs, and server-authoritative store flow #1

Merged
J.Schmidt92 merged 37 commits from development into master 2026-03-14 20:12:08 -05:00
31 changed files with 688 additions and 512 deletions
Showing only changes of commit 61a9741dc0 - Show all commits

View File

@ -3,6 +3,7 @@ hemtt.exe
.hemtt/missions/~*
.hemttout/
releases/
.hemttprivatekey
# Textures
Exports/

View File

@ -24,28 +24,10 @@ GVAR(ActorClass) = createHashMapObject [[
_self set ["actor", createHashMap];
_self set ["isLoaded", false];
_self set ["lastSave", time];
private _actor = createHashMap;
_actor set ["uid", (getPlayerUID player)];
_actor set ["name", (name player)];
_actor set ["loadout", [[],[],[],["U_BG_Guerrilla_6_1",[]],[],[],"H_Cap_blk_ION","",[],["ItemMap","ItemGPS","ItemRadio","ItemCompass","ItemWatch",""]]];
_actor set ["position", (getPosASL player)];
_actor set ["direction", (getDir player)];
_actor set ["stance", (stance player)];
_actor set ["rank", (rank player)];
_actor set ["state", (lifeState player)];
_actor set ["phone_number", ""];
_actor set ["email", ""];
_actor set ["organization", ""];
_actor set ["holster", true];
_self set ["actor", _actor];
}],
["init", {
private _uid = _self get "uid";
private _actor = _self get "actor";
[SRPC(actor,requestInitActor), [_uid, _actor]] call CFUNC(serverEvent);
[SRPC(actor,requestInitActor), [_uid]] call CFUNC(serverEvent);
systemChat format ["Actor loaded for %1", (name player)];
diag_log "[FORGE:Client:Actor] Actor Class Initialized!";
@ -114,22 +96,18 @@ GVAR(ActorClass) = createHashMapObject [[
}],
["applyDirection", {
private _direction = _self call ["get", ["direction", 0]];
if (GVAR(enableLoc)) then { player setDir _direction; };
}],
["applyStance", {
private _stance = _self call ["get", ["stance", "STAND"]];
if (GVAR(enableLoc)) then { player playAction _stance; };
}],
["applyRank", {
private _rank = _self call ["get", ["rank", "PRIVATE"]];
player setUnitRank _rank;
}],
["applyLoadout", {
private _loadout = _self call ["get", ["loadout", []]];
if (GVAR(enableGear) && count _loadout > 0) then { player setUnitLoadout _loadout; };
}],
["getNearbyActions", {
@ -160,5 +138,4 @@ GVAR(ActorClass) = createHashMapObject [[
}]
]];
SETVAR(player,FORGE_ActorClass,GVAR(ActorClass));
GVAR(ActorClass)

View File

@ -37,7 +37,7 @@ switch (_event) do {
// ========================================================================
case "bank::sync": {
private _org = 0; // TODO: Get org balance
private _players = SREG(bank,NameRegistry);
private _players = SREG(bank,IndexRegistry);
private _accountData = createHashMapFromArray [
["uid", _uid],
["cash", _cash],

View File

@ -27,6 +27,78 @@ diag_log format ["[FORGE:Client:Org] Handling UI event: %1 with data: %2", _even
switch (_event) do {
case "org::close": { _display closeDisplay 1; };
case "org::ready": {
private _orgData = GVAR(OrgClass) get "org";
private _name = _orgData getOrDefault ["name", "Unknown"];
private _id = _orgData getOrDefault ["id", ""];
private _funds = _orgData getOrDefault ["funds", 0];
private _reputation = _orgData getOrDefault ["reputation", 0];
private _membersRaw = _orgData getOrDefault ["members", []];
private _membersList = [];
// Handle members
private _fnc_processMember = {
params ["_mData"];
private _mName = _mData getOrDefault ["name", "Unknown"];
createHashMapFromArray [
["name", _mName],
["rank", "Member"],
["online", true]
]
};
{
_membersList pushBack ([_y] call _fnc_processMember);
} forEach _membersRaw;
private _totalMembers = count _membersList;
// Handle assets
private _assetsRaw = _orgData getOrDefault ["assets", createHashMap];
private _assetsList = [];
private _fnc_processAsset = {
params ["_aData"];
private _aName = _aData getOrDefault ["name", "Unknown Asset"];
private _aLocation = _aData getOrDefault ["location", "Unknown Location"];
private _aIcon = _aData getOrDefault ["icon", "📦"];
createHashMapFromArray [
["name", _aName],
["location", _aLocation],
["icon", _aIcon]
]
};
{
_assetsList pushBack ([_y] call _fnc_processAsset);
} forEach _assetsRaw;
// Construct HashMap payload
private _payload = createHashMapFromArray [
["org", createHashMapFromArray [
["name", _name],
["tag", _id],
["status", "Active"]
]],
["stats", createHashMapFromArray [
["totalMembers", _totalMembers],
["onlineMembers", _totalMembers],
["balance", _funds],
["reputation", _reputation]
]],
["membersOnline", _membersList],
["assets", _assetsList],
["activities", []],
["missions", []]
];
private _json = toJSON _payload;
_control ctrlWebBrowserAction ["ExecJS", format ["updateOrgDashboard(%1)", _json]];
};
default { hint format ["Unhandled UI event: %1", _event]; };
};

View File

@ -72,7 +72,7 @@
</div>
<div class="stat-item">
<span class="stat-label">Reputation</span>
<span class="stat-value">Level 5</span>
<span class="stat-value">200</span>
</div>
</div>
</div>

View File

@ -76,11 +76,160 @@ function updateDashboard(data) {
if (statValues[0]) statValues[0].textContent = data.stats.totalMembers;
if (statValues[1]) statValues[1].textContent = data.stats.onlineMembers;
if (statValues[2]) statValues[2].textContent = `$${data.stats.balance.toLocaleString()}`;
if (statValues[3]) statValues[3].textContent = `Level ${data.stats.reputation}`;
if (statValues[3]) statValues[3].textContent = `${data.stats.reputation}`;
}
// Update Members List
if (data.membersOnline) {
const memberList = document.querySelector('.member-list');
if (memberList) {
memberList.innerHTML = '';
data.membersOnline.forEach(member => {
const item = document.createElement('div');
item.className = 'member-item';
item.innerHTML = `
<div class="member-status ${member.online ? 'online' : 'offline'}"></div>
<div class="member-info">
<span class="member-name">${member.name}</span>
<span class="member-rank">${member.rank}</span>
</div>
`;
memberList.appendChild(item);
});
// Update member count badge
const memberBadge = document.querySelector('.dashboard-card:nth-child(2) .card-badge');
if (memberBadge) memberBadge.textContent = data.membersOnline.length;
}
}
// Update Assets List
if (data.assets) {
const assetList = document.querySelector('.asset-list');
if (assetList) {
assetList.innerHTML = '';
data.assets.forEach(asset => {
const item = document.createElement('div');
item.className = 'asset-item';
item.innerHTML = `
<span class="asset-icon">${asset.icon || '📦'}</span>
<div class="asset-info">
<span class="asset-name">${asset.name}</span>
<span class="asset-location">${asset.location}</span>
</div>
`;
assetList.appendChild(item);
});
}
}
// Update Activities List
if (data.activities) {
const activityList = document.querySelector('.activity-list');
if (activityList) {
activityList.innerHTML = '';
data.activities.forEach(activity => {
const item = document.createElement('div');
item.className = 'activity-item';
item.innerHTML = `
<div class="activity-time">${activity.time}</div>
<div class="activity-text">${activity.text}</div>
`;
activityList.appendChild(item);
});
}
}
// Update Missions List
if (data.missions) {
const missionList = document.querySelector('.mission-list');
if (missionList) {
missionList.innerHTML = '';
data.missions.forEach(mission => {
const item = document.createElement('div');
item.className = 'mission-item';
item.innerHTML = `
<div class="mission-header">
<span class="mission-name">${mission.name}</span>
<span class="mission-priority ${mission.priority}">${mission.priority.charAt(0).toUpperCase() + mission.priority.slice(1)} Priority</span>
</div>
<div class="mission-description">${mission.description}</div>
<div class="mission-progress">
<div class="progress-bar">
<div class="progress-fill" style="width: ${mission.progress}%"></div>
</div>
<span class="progress-text">${mission.progress}%</span>
</div>
`;
missionList.appendChild(item);
});
// Update mission count badge
const missionBadge = document.querySelector('.dashboard-card:last-child .card-badge');
if (missionBadge) missionBadge.textContent = data.missions.length;
}
}
// Re-attach event handlers for new elements if needed
// Note: The original setupEventHandlers attached to querySelectorAll which only finds elements existing at that time.
// We should re-run or use delegation. For simplicity, we can re-attach listeners to the new items.
attachDynamicHandlers(data);
}
// Event handlers
function attachDynamicHandlers(data) {
// Member item clicks
const memberItems = document.querySelectorAll('.member-item');
memberItems.forEach((item, index) => {
item.addEventListener('click', () => {
const memberData = data.membersOnline ? data.membersOnline[index] : null;
if (memberData) {
console.log('Member clicked:', memberData);
if (typeof A3API !== 'undefined') {
A3API.SendAlert(JSON.stringify({
event: 'org::member::view',
data: { member: memberData }
}));
}
}
});
});
// Asset item clicks
const assetItems = document.querySelectorAll('.asset-item');
assetItems.forEach((item, index) => {
item.addEventListener('click', () => {
const assetData = data.assets ? data.assets[index] : null;
if (assetData) {
console.log('Asset clicked:', assetData);
if (typeof A3API !== 'undefined') {
A3API.SendAlert(JSON.stringify({
event: 'org::asset::view',
data: { asset: assetData }
}));
}
}
});
});
// Mission item clicks
const missionItems = document.querySelectorAll('.mission-item');
missionItems.forEach((item, index) => {
item.addEventListener('click', () => {
const missionData = data.missions ? data.missions[index] : null;
if (missionData) {
console.log('Mission clicked:', missionData);
if (typeof A3API !== 'undefined') {
A3API.SendAlert(JSON.stringify({
event: 'org::mission::view',
data: { mission: missionData }
}));
}
}
});
});
}
// Static Event Handlers (Close, Settings, etc.)
function setupEventHandlers() {
// Close button
const closeBtn = document.querySelector('.close-btn');
@ -111,60 +260,26 @@ function setupEventHandlers() {
}
});
}
// Member item clicks
const memberItems = document.querySelectorAll('.member-item');
memberItems.forEach((item, index) => {
item.addEventListener('click', () => {
console.log('Member clicked:', mockData.membersOnline[index]);
if (typeof A3API !== 'undefined') {
A3API.SendAlert(JSON.stringify({
event: 'org::member::view',
data: { member: mockData.membersOnline[index] }
}));
}
});
});
// Asset item clicks
const assetItems = document.querySelectorAll('.asset-item');
assetItems.forEach((item, index) => {
item.addEventListener('click', () => {
console.log('Asset clicked:', mockData.assets[index]);
if (typeof A3API !== 'undefined') {
A3API.SendAlert(JSON.stringify({
event: 'org::asset::view',
data: { asset: mockData.assets[index] }
}));
}
});
});
// Mission item clicks
const missionItems = document.querySelectorAll('.mission-item');
missionItems.forEach((item, index) => {
item.addEventListener('click', () => {
console.log('Mission clicked:', mockData.missions[index]);
if (typeof A3API !== 'undefined') {
A3API.SendAlert(JSON.stringify({
event: 'org::mission::view',
data: { mission: mockData.missions[index] }
}));
}
});
});
}
// Initialize dashboard
function initDashboard() {
console.log('Organization Dashboard initializing...');
// Update with mock data
updateDashboard(mockData);
// Setup event handlers
setupEventHandlers();
// Request live data from Arma
if (typeof A3API !== 'undefined') {
A3API.SendAlert(JSON.stringify({
event: 'org::ready',
data: {}
}));
} else {
// Use mock data for browser testing/development
updateDashboard(mockData);
}
console.log('Organization Dashboard initialized');
}

View File

@ -3,6 +3,7 @@ hemtt.exe
.hemtt/missions/~*
.hemttout/
releases/
.hemttprivatekey
# Textures
Exports/

View File

@ -7,12 +7,10 @@ PREP_RECOMPILE_END;
// private _category = [QUOTE(MOD_NAME), LLSTRING(displayName)];
[QGVAR(requestInitActor), {
params [["_uid", "", [""]], ["_actor", createHashMap, [createHashMap]]];
params [["_uid", "", [""]]];
if (_uid isEqualTo "") exitWith { diag_log "[FORGE:Server:Actor] Empty/Invalid UID!" };
if (_actor isEqualTo createHashMap) exitWith { diag_log "[FORGE:Server:Actor] Empty/Invalid Actor data!" };
GVAR(ActorStore) call ["init", [_uid, _actor]];
GVAR(ActorStore) call ["init", [_uid]];
}] call CFUNC(addEventHandler);
[QGVAR(requestGetActor), {
@ -23,7 +21,10 @@ PREP_RECOMPILE_END;
private _session = GVAR(PlayerSessions) getOrDefault [_uid, nil];
if (isNil "_session") exitWith { diag_log "[FORGE:Server:Actor] Empty/Invalid Session!" };
GVAR(ActorStore) call ["get", [_uid, _sync]];
private _finalData = GVAR(ActorStore) call ["get", [GVAR(ActorRegistry), "actor:get", _uid, _sync]];
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(actor,responseSyncActor), [_finalData], _player] call CFUNC(targetEvent);
}] call CFUNC(addEventHandler);
[QGVAR(requestSetActor), {
@ -34,7 +35,10 @@ PREP_RECOMPILE_END;
private _session = GVAR(PlayerSessions) getOrDefault [_uid, nil];
if (isNil "_session") exitWith { diag_log "[FORGE:Server:Actor] Empty/Invalid Session!" };
GVAR(ActorStore) call ["set", [_uid, _key, _value, _sync]];
private _hashMap = GVAR(ActorStore) call ["set", [GVAR(ActorRegistry), "actor:update", _uid, _key, _value, _sync]];
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(actor,responseSyncActor), [_hashMap], _player] call CFUNC(targetEvent);
}] call CFUNC(addEventHandler);
[QGVAR(requestMSetActor), {
@ -46,7 +50,10 @@ PREP_RECOMPILE_END;
private _session = GVAR(PlayerSessions) getOrDefault [_uid, nil];
if (isNil "_session") exitWith { diag_log "[FORGE:Server:Actor] Empty/Invalid Session!" };
GVAR(ActorStore) call ["mset", [_uid, _fieldValuePairs, _sync]];
private _hashMap = GVAR(ActorStore) call ["mset", [GVAR(ActorRegistry), "actor:update", _uid, _fieldValuePairs, _sync]];
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(actor,responseSyncActor), [_hashMap], _player] call CFUNC(targetEvent);
}] call CFUNC(addEventHandler);
[QGVAR(requestSaveActor), {
@ -57,7 +64,10 @@ PREP_RECOMPILE_END;
private _session = GVAR(PlayerSessions) getOrDefault [_uid, nil];
if (isNil "_session") exitWith { diag_log "[FORGE:Server:Actor] Empty/Invalid Session!" };
GVAR(ActorStore) call ["save", [_uid, _sync]];
private _finalData = GVAR(ActorStore) call ["save", [GVAR(ActorRegistry), "actor:update", _uid, _sync]];
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(actor,responseSyncActor), [_finalData], _player] call CFUNC(targetEvent);
}] call CFUNC(addEventHandler);
[QGVAR(requestRemoveActor), {
@ -65,5 +75,5 @@ PREP_RECOMPILE_END;
if (_uid isEqualTo "") exitWith { diag_log "[FORGE:Server:Actor] Empty/Invalid UID!" };
GVAR(ActorStore) call ["remove", [_uid]];
GVAR(ActorStore) call ["remove", [GVAR(ActorRegistry), _uid]];
}] call CFUNC(addEventHandler);

View File

@ -1,3 +1,2 @@
#include "script_component.hpp"
#include "XEH_PREP.hpp"

View File

@ -17,69 +17,147 @@
*/
#pragma hemtt ignore_variables ["_self"]
GVAR(ActorStore) = createHashMapObject [[
["#base", EGVAR(common,BaseStore)],
["#type", "IActorStore"],
["#create", {
GVAR(ActorRegistry) = createHashMap;
GVAR(PlayerSessions) = createHashMap;
GVAR(ActorModel) = compileFinal createHashMapObject [[
["#type", "ActorModel"],
["defaults", {
private _actor = createHashMap;
_self set ["_registry", GVAR(ActorRegistry)];
_self set ["_extCallPrefix", "actor"];
_self set ["_readMethod", "get"];
_self set ["_storeName", "Actor"];
_self set ["_syncEventName", CRPC(actor,responseSyncActor)];
_actor set ["uid", ""];
_actor set ["name", ""];
_actor set ["loadout", [[],[],[],["U_BG_Guerrilla_6_1",[]],[],[],"H_Cap_blk_ION","",[],["ItemMap","ItemGPS","ItemRadio","ItemCompass","ItemWatch",""]]];
_actor set ["position", [0,0,0]];
_actor set ["direction", 0];
_actor set ["stance", "STAND"];
_actor set ["rank", "PRIVATE"];
_actor set ["state", "HEALTHY"];
_actor set ["phone_number", ""];
_actor set ["email", ""];
_actor set ["organization", ""];
_actor set ["holster", true];
["INFO", "Actor Store Initialized!", nil, nil] call EFUNC(common,log);
_actor
}],
["generateSessionToken", {
params [["_uid", "", [""]]];
["fromPlayer", {
params [["_player", objNull, [objNull]]];
private _token = format ["%1_%2_%3", _uid, floor(random 999999), time];
private _sessionToken = _token call EFUNC(common,generateHash);
if (_player isEqualTo objNull) exitWith { _self call ["defaults", []] };
private _regEntry = createHashMapFromArray [["sessionToken", _sessionToken]];
GVAR(PlayerSessions) set [_uid, _regEntry];
private _actor = _self call ["defaults", []];
_sessionToken
_actor set ["uid", getPlayerUID _player];
_actor set ["name", name _player];
_actor set ["position", getPosASL _player];
_actor set ["direction", getDir _player];
_actor set ["stance", stance _player];
_actor set ["rank", rank _player];
_actor set ["state", lifeState _player];
_actor
}],
["init", {
params [["_uid", "", [""]], ["_defaultActor", createHashMap, [createHashMap]]];
["migrate", {
params [["_actor", createHashMap, [createHashMap]]];
_self call ["generateSessionToken", [_uid]];
private _finalActor = createHashMap;
private _defaults = _self call ["defaults", []];
["actor:exists", [_uid]] call EFUNC(extension,extCall) params ["_result", "_isSuccess"];
private _exists = _result == "true";
{
if !(_x in _actor) then { _actor set [_x, _y]; };
} forEach _defaults;
if !(_exists) then {
_finalActor = _defaultActor;
_finalActor set ["uid", _uid];
_actor
}],
["validate", {
params [["_actor", createHashMap, [createHashMap]]];
private _json = _self call ["toJSON", [_finalActor]];
["actor:create", [_uid, _json]] call EFUNC(extension,extCall);
private _uid = _actor getOrDefault ["uid", ""];
private _name = _actor getOrDefault ["name", ""];
private _position = _actor getOrDefault ["position", []];
private _direction = _actor getOrDefault ["direction", 0];
private _stance = _actor getOrDefault ["stance", ""];
private _rank = _actor getOrDefault ["rank", ""];
private _state = _actor getOrDefault ["state", ""];
private _phone_number = _actor getOrDefault ["phone_number", ""];
private _email = _actor getOrDefault ["email", ""];
private _organization = _actor getOrDefault ["organization", ""];
private _phone_number = _finalActor getOrDefault ["phone_number", ""];
private _email = _finalActor getOrDefault ["email", ""];
["INFO", format ["New player %1 registered with phone number: %2, email: %3", _uid, _phone_number, _email], nil, nil] call EFUNC(common,log);
} else {
private _existingActor = _self call ["fetch", [_uid]];
_finalActor = _existingActor;
{
if !(_x in _finalActor) then { _finalActor set [_x, _y]; };
} forEach _defaultActor;
[_uid, _name, _position, _direction, _stance, _rank, _state, _phone_number, _email, _organization] try {
if (_uid isEqualTo "" || !(_uid isEqualType "")) then { throw "Invalid UID!"; };
if (_name isEqualTo "" || !(_name isEqualType "")) then { throw "Invalid Name!"; };
if (_position isEqualTo [] || !(_position isEqualType [])) then { throw "Invalid Position!"; };
if (_direction < 0 || !(_direction isEqualType 0)) then { throw "Invalid Direction!"; };
if (_stance isEqualTo "" || !(_stance isEqualType "")) then { throw "Invalid Stance!"; };
if (_rank isEqualTo "" || !(_rank isEqualType "")) then { throw "Invalid Rank!"; };
if (_state isEqualTo "" || !(_state isEqualType "")) then { throw "Invalid State!"; };
if (_phone_number isEqualTo "" || !(_phone_number isEqualType "")) then { throw "Invalid Phone Number!"; };
if (_email isEqualTo "" || !(_email isEqualType "")) then { throw "Invalid Email!"; };
if (_organization isEqualTo "" || !(_organization isEqualType "")) then { throw "Invalid Organization!"; };
} catch {
["ERROR", format ["Failed to validate actor %1!", _exception]] call EFUNC(common,log);
false
};
GVAR(ActorRegistry) set [_uid, _finalActor];
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(actor,responseInitActor), [_finalActor], _player] call CFUNC(targetEvent);
_finalActor
true
}]
]];
GVAR(ActorRepository) = compileFinal createHashMapFromArray [
["#base", EGVAR(common,BaseStore)],
["#type", "ActorRepository"],
["#create", {
GVAR(ActorRegistry) = createHashMap;
["INFO", "Actor Repository Initialized!"] call EFUNC(common,log);
}],
["get", {
params [["_uid", "", [""]]];
private _cached = GVAR(ActorRegistry) getOrDefault [_uid, nil];
if !(isNil { _cached }) exitWith { _cached };
private _player = [_uid] call EFUNC(common,getPlayer);
["actor:exists", [_uid]] call EFUNC(extension,extCall) params ["_result", "_isSuccess"];
if !(_isSuccess) exitWith {
["ERROR", format ["Failed to check if actor %1 exists!", _uid]] call EFUNC(common,log);
createHashMap
};
private _finalActor = createHashMap;
if (_result == "true") then {
_finalActor = _self call ["fetch", ["actor:get", _uid]];
} else {
_finalActor = GVAR(ActorModel) call ["fromPlayer", [_player]];
_finalActor set ["uid", _uid];
private _json = _self call ["toJSON", [_finalActor]];
["actor:create", [_uid, _json]] call EFUNC(extension,extCall) params ["_result", "_isSuccess"];
if !(_isSuccess) exitWith {
["ERROR", format ["Failed to create actor %1!", _uid]] call EFUNC(common,log);
createHashMap
};
};
_finalActor = GVAR(ActorModel) call ["migrate", [_finalActor]];
GVAR(ActorRegistry) set [_uid, _finalActor];
_finalActor
}]
];
GVAR(ActorStore) = createHashMapObject [[
["#base", GVAR(ActorRepository)],
["#type", "IActorStore"],
["#create", {
["INFO", "Actor Store Initialized!"] call EFUNC(common,log);
}],
["init", {
params [["_uid", "", [""]]];
private _actor = _self call ["get", [_uid]];
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(actor,responseInitActor), [_actor], _player] call CFUNC(targetEvent);
_actor
}]
]];
SETMVAR(FORGE_ActorStore,GVAR(ActorStore));
GVAR(ActorStore)

View File

@ -23,7 +23,7 @@ PREP_RECOMPILE_END;
private _session = EGVAR(actor,PlayerSessions) getOrDefault [_uid, nil];
if (isNil "_session") exitWith { diag_log "[FORGE:Server:Bank] Empty/Invalid Session!" };
GVAR(BankStore) call ["get", [_uid, _sync]];
GVAR(BankStore) call ["get", [GVAR(BankRegistry), "bank:get", _uid, _sync]];
}] call CFUNC(addEventHandler);
[QGVAR(requestSetBank), {
@ -34,7 +34,10 @@ PREP_RECOMPILE_END;
private _session = EGVAR(actor,PlayerSessions) getOrDefault [_uid, nil];
if (isNil "_session") exitWith { diag_log "[FORGE:Server:Bank] Empty/Invalid Session!" };
GVAR(BankStore) call ["set", [_uid, _key, _value, _sync]];
private _hashMap = GVAR(BankStore) call ["set", [GVAR(BankRegistry), "bank:update", _uid, _key, _value, _sync]];
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(bank,responseSyncBank), [_hashMap], _player] call CFUNC(targetEvent);
}] call CFUNC(addEventHandler);
[QGVAR(requestMSetBank), {
@ -46,7 +49,10 @@ PREP_RECOMPILE_END;
private _session = EGVAR(actor,PlayerSessions) getOrDefault [_uid, nil];
if (isNil "_session") exitWith { diag_log "[FORGE:Server:Bank] Empty/Invalid Session!" };
GVAR(BankStore) call ["mset", [_uid, _fieldValuePairs, _sync]];
private _hashMap = GVAR(BankStore) call ["mset", [GVAR(BankRegistry), "bank:update", _uid, _fieldValuePairs, _sync]];
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(bank,responseSyncBank), [_hashMap], _player] call CFUNC(targetEvent);
}] call CFUNC(addEventHandler);
[QGVAR(requestSaveBank), {
@ -57,7 +63,10 @@ PREP_RECOMPILE_END;
private _session = EGVAR(actor,PlayerSessions) getOrDefault [_uid, nil];
if (isNil "_session") exitWith { diag_log "[FORGE:Server:Bank] Empty/Invalid Session!" };
GVAR(BankStore) call ["save", [_uid, _sync]];
private _finalData = GVAR(BankStore) call ["save", [GVAR(BankRegistry), "bank:update", _uid, _sync]];
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(bank,responseSyncBank), [_finalData], _player] call CFUNC(targetEvent);
}] call CFUNC(addEventHandler);
[QGVAR(requestRemoveBank), {
@ -65,7 +74,7 @@ PREP_RECOMPILE_END;
if (_uid isEqualTo "") exitWith { diag_log "[FORGE:Server:Bank] Empty/Invalid UID!" };
GVAR(BankStore) call ["remove", [_uid]];
GVAR(BankStore) call ["remove", [GVAR(BankRegistry), _uid]];
}] call CFUNC(addEventHandler);
[QGVAR(requestDeposit), {
@ -79,6 +88,17 @@ PREP_RECOMPILE_END;
GVAR(BankStore) call ["deposit", [_uid, _amount]];
}] call CFUNC(addEventHandler);
[QGVAR(requestPayment), {
params [["_uid", "", [""]], ["_amount", 0, [0]]];
if (_uid isEqualTo "" || _amount isEqualTo 0) exitWith { diag_log "[FORGE:Server:Bank] Empty/Invalid UID or Amount!" };
private _session = EGVAR(actor,PlayerSessions) getOrDefault [_uid, nil];
if (isNil "_session") exitWith { diag_log "[FORGE:Server:Bank] Empty/Invalid Session!" };
GVAR(BankStore) call ["payment", [_uid, _amount]];
}] call CFUNC(addEventHandler);
[QGVAR(requestTransfer), {
params [["_uid", "", [""]], ["_target", "", [""]], ["_from", "", [""]], ["_amount", 0, [0]]];
@ -86,9 +106,9 @@ PREP_RECOMPILE_END;
diag_log "[FORGE:Server:Bank] Empty/Invalid UID, Target, From Account, or Amount!"
};
// Prevent self-transfers (security check)
if (_uid isEqualTo _target) exitWith {
diag_log format ["[FORGE:Server:Bank] SECURITY: Player %1 attempted self-transfer!", _uid];
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(notifications,recieveNotification), ["error", "Bank", "Cannot transfer to yourself!"], _player] call CFUNC(targetEvent);
};

View File

@ -1,3 +1,2 @@
#include "script_component.hpp"
#include "XEH_PREP.hpp"

View File

@ -17,21 +17,9 @@
*/
#pragma hemtt ignore_variables ["_self"]
GVAR(BankStore) = createHashMapObject [[
private _typeBank = compileFinal createHashMapFromArray [
["#base", EGVAR(common,BaseStore)],
["#type", "IBankStore"],
["#create", {
GVAR(BankRegistry) = createHashMap;
GVAR(NameRegistry) = createHashMap;
_self set ["_registry", GVAR(BankRegistry)];
_self set ["_extCallPrefix", "bank"];
_self set ["_readMethod", "get"];
_self set ["_storeName", "Bank"];
_self set ["_syncEventName", CRPC(bank,responseSyncBank)];
["INFO", "Bank Store Initialized!", nil, nil] call EFUNC(common,log);
}],
["#type", "IBaseBank"],
["init", {
params [["_uid", "", [""]], ["_defaultAccount", createHashMap, [createHashMap]]];
@ -49,7 +37,7 @@ GVAR(BankStore) = createHashMapObject [[
["INFO", format ["Created new bank account for %1", _uid], nil, nil] call EFUNC(common,log);
} else {
private _existingAccount = _self call ["fetch", [_uid]];
private _existingAccount = _self call ["fetch", ["bank:get", _uid]];
_finalAccount = _existingAccount;
{
@ -63,10 +51,9 @@ GVAR(BankStore) = createHashMapObject [[
private _player = [_uid] call EFUNC(common,getPlayer);
private _regEntry = createHashMapFromArray [["uid", _uid], ["name", (name _player)]];
GVAR(NameRegistry) set [_uid, _regEntry];
[CRPC(bank,responseInitBank), [_finalAccount], _player] call CFUNC(targetEvent);
_finalAccount
GVAR(IndexRegistry) set [_uid, _regEntry];
[CRPC(bank,responseInitBank), [_finalAccount], _player] call CFUNC(targetEvent);
}],
["deposit", {
params [["_uid", "", [""]], ["_amount", 0, [0]]];
@ -80,15 +67,32 @@ GVAR(BankStore) = createHashMapObject [[
private _cash = _account getOrDefault ["cash", 0];
if (_cash < _amount) exitWith { ["WARNING", "Insufficient Funds!", nil, nil] call EFUNC(common,log); };
private _finalAccount = createHashMapFromArray [
["bank", (_bank + _amount)],
["cash", (_cash - _amount)]
];
private _finalAccount = createHashMapFromArray [["bank", (_bank + _amount)], ["cash", (_cash - _amount)]];
_self call ["mset", [_uid, _finalAccount]];
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(bank,responseSyncBank), [_finalAccount], _player] call CFUNC(targetEvent);
[CRPC(notifications,recieveNotification), ["info", "Bank", format ["Deposited $%1", _amount]], _player] call CFUNC(targetEvent);
}],
["payment", {
params [["_uid", "", [""]], ["_amount", 0, [0]]];
["INFO", format ["Payment %1, for %2", _amount, _uid], nil, nil] call EFUNC(common,log);
private _account = GVAR(BankRegistry) getOrDefault [_uid, nil];
if (isNil "_account") exitWith { ["ERROR", "Empty/Invalid Account!", nil, nil] call EFUNC(common,log); };
private _bank = _account getOrDefault ["bank", 0];
private _finalAccount = createHashMapFromArray [["bank", (_bank + _amount)]];
_self call ["mset", [_uid, _finalAccount]];
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(bank,responseSyncBank), [_finalAccount], _player] call CFUNC(targetEvent);
[CRPC(notifications,recieveNotification), ["info", "Bank", format ["Paid $%1", _amount]], _player] call CFUNC(targetEvent);
}],
["transfer", {
params [["_uid", "", [""]], ["_target", "", [""]], ["_from", "", [""]], ["_amount", 0, [0]]];
@ -115,6 +119,8 @@ GVAR(BankStore) = createHashMapObject [[
private _player = [_uid] call EFUNC(common,getPlayer);
private _targetPlayer = [_target] call EFUNC(common,getPlayer);
[CRPC(bank,responseSyncBank), [_finalAccount], _player] call CFUNC(targetEvent);
[CRPC(bank,responseSyncBank), [_finalTargetBank], _targetPlayer] call CFUNC(targetEvent);
[CRPC(notifications,recieveNotification), ["info", "Bank", format ["Transferred $%1 to %2", _amount, (name _targetPlayer)]], _player] call CFUNC(targetEvent);
[CRPC(notifications,recieveNotification), ["info", "Bank", format ["Received $%1 from %2", _amount, (name _player)]], _targetPlayer] call CFUNC(targetEvent);
}],
@ -130,15 +136,25 @@ GVAR(BankStore) = createHashMapObject [[
private _cash = _account getOrDefault ["cash", 0];
if (_bank < _amount) exitWith { ["WARNING", "Insufficient Funds!", nil, nil] call EFUNC(common,log); };
private _finalAccount = createHashMapFromArray [
["bank", (_bank - _amount)],
["cash", (_cash + _amount)]
];
private _finalAccount = createHashMapFromArray [["bank", (_bank - _amount)], ["cash", (_cash + _amount)]];
_self call ["mset", [_uid, _finalAccount]];
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(bank,responseSyncBank), [_finalAccount], _player] call CFUNC(targetEvent);
[CRPC(notifications,recieveNotification), ["info", "Bank", format ["Withdrew $%1", _amount]], _player] call CFUNC(targetEvent);
}]
];
GVAR(BankStore) = createHashMapObject [[
["#base", _typeBank],
["#type", "IBankStore"],
["#create", {
GVAR(BankRegistry) = createHashMap;
GVAR(IndexRegistry) = createHashMap;
["INFO", "Bank Store Initialized!", nil, nil] call EFUNC(common,log);
}]
]];
SETMVAR(FORGE_BankStore,GVAR(BankStore));

View File

@ -1,7 +1,7 @@
PREP(baseStore);
PREP(formatNumber);
PREP(getPlayer);
PREP(generateHash);
PREP(generateSecureData);
PREP(initBaseStore);
PREP(log);
PREP(timeToSeconds);

View File

@ -1,3 +1,2 @@
#include "script_component.hpp"
#include "XEH_PREP.hpp"

View File

@ -0,0 +1,103 @@
#include "..\script_component.hpp"
/*
* File: fnc_baseStore.sqf
* Author: IDSolutions
* Date: 2026-01-08
* Last Update: 2026-01-10
* Public: No
*
* Description:
* No description added yet.
*
* Parameter(s):
* N/A
*
* Returns:
* Something [BOOL]
*
* Example(s):
* [parameter] call forge_x_component_fnc_myFunction
*/
#pragma hemtt ignore_variables ["_self"]
GVAR(BaseStore) = compileFinal createHashMapFromArray [
["#type", "IBaseStore"],
["fetch", {
params [["_function", "", [""]], ["_uid", "", [""]]];
private _data = createHashMap;
[_function, [_uid]] call EFUNC(extension,extCall) params ["_result", "_isSuccess"];
["INFO", format ["Data: %1", _result], nil, nil] call EFUNC(common,log);
if (count _result > 0) then { _data = _self call ["toHashMap", [_result]] };
_data
}],
["set", {
params [["_registry", createHashMap, [createHashMap]], ["_function", "", [""]], ["_uid", "", [""]], ["_field", "", [""]], ["_value", nil, [0, "", [], false, createHashMap, objNull, grpNull]], ["_sync", false, [false]]];
private _existingData = _registry get _uid;
private _finalData = +_existingData;
private _hashMap = createHashMap;
_finalData set [_field, _value];
_hashMap set [_field, _value];
_registry set [_uid, _finalData];
if (_sync) then {
private _json = _self call ["toJSON", [_hashMap]];
[_function, [_uid, _json]] call EFUNC(extension,extCall);
};
_hashMap
}],
["mset", {
params [["_registry", createHashMap, [createHashMap]], ["_function", "", [""]], ["_uid", "", [""]], ["_fieldValuePairs", createHashMap, [createHashMap]], ["_sync", false, [false]]];
private _existingData = _registry get _uid;
private _finalData = +_existingData;
private _hashMap = createHashMap;
{ _finalData set [_x, _y]; } forEach _fieldValuePairs;
{ _hashMap set [_x, _y]; } forEach _fieldValuePairs;
_registry set [_uid, _finalData];
if (_sync) then {
private _json = _self call ["toJSON", [_hashMap]];
[_function, [_uid, _json]] call EFUNC(extension,extCall);
};
_hashMap
}],
["save", {
params [["_registry", createHashMap, [createHashMap]], ["_function", "", [""]], ["_uid", "", [""]]];
private _existingData = _registry get _uid;
private _finalData = +_existingData;
private _json = _self call ["toJSON", [_finalData]];
[_function, [_uid, _json]] call EFUNC(extension,extCall);
_finalData
}],
["remove", {
params [["_registry", createHashMap, [createHashMap]], ["_uid", "", [""]]];
_registry deleteAt _uid;
}],
["toHashMap", {
params [["_data", "", [""]]];
fromJSON _data
}],
["toJSON", {
params [["_data", createHashMap, [createHashMap]]];
toJSON _data
}]
];
GVAR(BaseStore)

View File

@ -1,154 +0,0 @@
#include "..\script_component.hpp"
/*
* Author: IDSolutions
* Initializes the base store.
*
* Arguments:
* None
*
* Return Value:
* None
*
* Examples:
* [] call forge_server_common_fnc_initBaseStore
*
* Public: Yes
*/
#pragma hemtt ignore_variables ["_self"]
GVAR(BaseStore) = createHashMapObject [[
["#type", "IBaseStore"],
["fetch", {
params [["_uid", "", [""]]];
private _extCallPrefix = _self get "_extCallPrefix";
private _readMethod = _self getOrDefault ["_readMethod", "get"];
private _funcName = format ["%1:%2", _extCallPrefix, _readMethod];
private _store = createHashMap;
[_funcName, [_uid]] call EFUNC(extension,extCall) params ["_result", "_isSuccess"];
["INFO", format ["Data: %1", _result], nil, nil] call EFUNC(common,log);
if (count _result > 0) then { _store = _self call ["toHashMap", [_result]]; };
_store
}],
["get", {
params [["_uid", "", [""]], ["_sync", false, [false]]];
private _finalData = createHashMap;
private _registry = _self get "_registry";
if (_sync) then {
private _existingData = _self call ["fetch", [_uid]];
_finalData = _existingData;
_registry set [_uid, _finalData];
} else {
_finalData = _registry get _uid;
};
_finalData
}],
["set", {
params [["_uid", "", [""]], ["_field", "", [""]], ["_value", nil], ["_sync", false, [false]]];
private _registry = _self get "_registry";
private _existingData = _registry get _uid;
private _finalData = +_existingData;
private _hashMap = createHashMap;
_finalData set [_field, _value];
_hashMap set [_field, _value];
_registry set [_uid, _finalData];
if (_sync) then {
private _extCallPrefix = _self get "_extCallPrefix";
private _funcName = format ["%1:update", _extCallPrefix];
private _json = _self call ["toJSON", [_hashMap]];
[_funcName, [_uid, _json]] call EFUNC(extension,extCall);
};
private _syncEventName = _self getOrDefault ["_syncEventName", ""];
if (_syncEventName isNotEqualTo "") then {
private _player = [_uid] call EFUNC(common,getPlayer);
[_syncEventName, [_hashMap], _player] call CFUNC(targetEvent);
};
_hashMap
}],
["mset", {
params [["_uid", "", [""]], ["_fieldValuePairs", createHashMap, [createHashMap]], ["_sync", false, [false]]];
private _registry = _self get "_registry";
private _existingData = _registry get _uid;
private _finalData = +_existingData;
private _hashMap = createHashMap;
{ _finalData set [_x, _y]; } forEach _fieldValuePairs;
{ _hashMap set [_x, _y]; } forEach _fieldValuePairs;
_registry set [_uid, _finalData];
if (_sync) then {
private _extCallPrefix = _self get "_extCallPrefix";
private _funcName = format ["%1:update", _extCallPrefix];
private _json = _self call ["toJSON", [_hashMap]];
[_funcName, [_uid, _json]] call EFUNC(extension,extCall);
};
private _syncEventName = _self getOrDefault ["_syncEventName", ""];
if (_syncEventName isNotEqualTo "") then {
private _player = [_uid] call EFUNC(common,getPlayer);
[_syncEventName, [_hashMap], _player] call CFUNC(targetEvent);
};
_hashMap
}],
["save", {
params [["_uid", "", [""]], ["_sync", false, [false]]];
private _registry = _self get "_registry";
private _existingData = _registry get _uid;
private _finalData = +_existingData;
private _extCallPrefix = _self get "_extCallPrefix";
private _funcName = format ["%1:update", _extCallPrefix];
private _json = _self call ["toJSON", [_finalData]];
[_funcName, [_uid, _json]] call EFUNC(extension,extCall);
if (_sync) then {
private _syncEventName = _self getOrDefault ["_syncEventName", ""];
if (_syncEventName isNotEqualTo "") then {
private _player = [_uid] call EFUNC(common,getPlayer);
[_syncEventName, [_finalData], _player] call CFUNC(targetEvent);
};
};
_finalData
}],
["remove", {
params [["_uid", "", [""]]];
private _registry = _self get "_registry";
_registry deleteAt _uid;
}],
["toHashMap", {
params [["_data", "", [""]]];
private _hashMap = fromJSON _data;
_hashMap
}],
["toJSON", {
params [["_data", createHashMap, [createHashMap]]];
private _json = toJSON _data;
_json
}]
]];
SETMVAR(FORGE_BaseStore,GVAR(BaseStore));
GVAR(BaseStore)

View File

@ -1,18 +1,3 @@
#include "script_component.hpp"
GVAR(MEconomyStore) call ["init", []];
[QGVAR(onKilled), {
params ["_unit"];
GVAR(MEconomyStore) call ["onKilled", [_unit]];
}] call CFUNC(addEventHandler);
[QGVAR(onRespawn), {
params ["_unit", "_corpse", "_uid"];
GVAR(MEconomyStore) call ["onRespawn", [_unit, _corpse, _uid]];
}] call CFUNC(addEventHandler);
[QGVAR(onHealed), {
params ["_unit"];
GVAR(MEconomyStore) call ["onHealed", [_unit]];
}] call CFUNC(addEventHandler);

View File

@ -27,3 +27,18 @@ if (isNil QGVAR(FEconomyStore)) then { [] call FUNC(initFEconomyStore); };
params ["_source", "_target"];
GVAR(FEconomyStore) call ["stop", [_source, _target]];
}] call CFUNC(addEventHandler);
[QGVAR(onKilled), {
params ["_unit"];
GVAR(MEconomyStore) call ["onKilled", [_unit]];
}] call CFUNC(addEventHandler);
[QGVAR(onRespawn), {
params ["_unit", "_corpse", "_uid"];
GVAR(MEconomyStore) call ["onRespawn", [_unit, _corpse, _uid]];
}] call CFUNC(addEventHandler);
[QGVAR(onHealed), {
params ["_unit"];
GVAR(MEconomyStore) call ["onHealed", [_unit]];
}] call CFUNC(addEventHandler);

View File

@ -1,3 +1,2 @@
#include "script_component.hpp"
#include "XEH_PREP.hpp"

View File

@ -21,7 +21,7 @@ PREP_RECOMPILE_END;
private _session = EGVAR(actor,PlayerSessions) getOrDefault [_uid, nil];
if (isNil "_session") exitWith { diag_log "[FORGE:Server:Garage] Empty/Invalid Session!" };
GVAR(GarageStore) call ["get", [_uid, _sync]];
GVAR(GarageStore) call ["get", [GVAR(GarageRegistry), "garage:get", _uid, _sync]];
}] call CFUNC(addEventHandler);
[QGVAR(requestSetGarage), {
@ -32,7 +32,10 @@ PREP_RECOMPILE_END;
private _session = EGVAR(actor,PlayerSessions) getOrDefault [_uid, nil];
if (isNil "_session") exitWith { diag_log "[FORGE:Server:Garage] Empty/Invalid Session!" };
GVAR(GarageStore) call ["set", [_uid, _key, _value, _sync]];
private _hashMap = GVAR(GarageStore) call ["set", [GVAR(GarageRegistry), "garage:update", _uid, _key, _value, _sync]];
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(garage,responseSyncGarage), [_hashMap], _player] call CFUNC(targetEvent);
}] call CFUNC(addEventHandler);
[QGVAR(requestMSetGarage), {
@ -44,7 +47,10 @@ PREP_RECOMPILE_END;
private _session = EGVAR(actor,PlayerSessions) getOrDefault [_uid, nil];
if (isNil "_session") exitWith { diag_log "[FORGE:Server:Garage] Empty/Invalid Session!" };
GVAR(GarageStore) call ["mset", [_uid, _fieldValuePairs, _sync]];
private _hashMap = GVAR(GarageStore) call ["mset", [GVAR(GarageRegistry), "garage:update", _uid, _fieldValuePairs, _sync]];
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(garage,responseSyncGarage), [_hashMap], _player] call CFUNC(targetEvent);
}] call CFUNC(addEventHandler);
[QGVAR(requestSaveGarage), {
@ -55,7 +61,10 @@ PREP_RECOMPILE_END;
private _session = EGVAR(actor,PlayerSessions) getOrDefault [_uid, nil];
if (isNil "_session") exitWith { diag_log "[FORGE:Server:Garage] Empty/Invalid Session!" };
GVAR(GarageStore) call ["save", [_uid, _sync]];
private _finalData = GVAR(GarageStore) call ["save", [GVAR(GarageRegistry), "garage:update", _uid, _sync]];
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(garage,responseSyncGarage), [_finalData], _player] call CFUNC(targetEvent);
}] call CFUNC(addEventHandler);
[QGVAR(requestRemoveGarage), {
@ -63,7 +72,7 @@ PREP_RECOMPILE_END;
if (_uid isEqualTo "") exitWith { diag_log "[FORGE:Server:Garage] Empty/Invalid UID!" };
GVAR(GarageStore) call ["remove", [_uid]];
GVAR(GarageStore) call ["remove", [GVAR(GarageRegistry), _uid]];
}] call CFUNC(addEventHandler);
[QGVAR(requestInitVG), {
@ -83,7 +92,10 @@ PREP_RECOMPILE_END;
private _session = EGVAR(actor,PlayerSessions) getOrDefault [_uid, nil];
if (isNil "_session") exitWith { diag_log "[FORGE:Server:VGarage] Empty/Invalid Session!" };
GVAR(VGarageStore) call ["get", [_uid, _sync]];
private _hashMap = GVAR(VGarageStore) call ["get", [GVAR(VGarageRegistry), "owned:garage:fetch", _uid, _sync]];
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(garage,responseSyncVG), [_hashMap], _player] call CFUNC(targetEvent);
}] call CFUNC(addEventHandler);
[QGVAR(requestSetVG), {
@ -94,7 +106,10 @@ PREP_RECOMPILE_END;
private _session = EGVAR(actor,PlayerSessions) getOrDefault [_uid, nil];
if (isNil "_session") exitWith { diag_log "[FORGE:Server:VGarage] Empty/Invalid Session!" };
GVAR(VGarageStore) call ["set", [_uid, _key, _value, _sync]];
private _hashMap = GVAR(VGarageStore) call ["set", [GVAR(VGarageRegistry), "", _uid, _key, _value, _sync]];
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(garage,responseSyncVG), [_hashMap], _player] call CFUNC(targetEvent);
}] call CFUNC(addEventHandler);
[QGVAR(requestMSetVG), {
@ -106,7 +121,10 @@ PREP_RECOMPILE_END;
private _session = EGVAR(actor,PlayerSessions) getOrDefault [_uid, nil];
if (isNil "_session") exitWith { diag_log "[FORGE:Server:VGarage] Empty/Invalid Session!" };
GVAR(VGarageStore) call ["mset", [_uid, _fieldValuePairs, _sync]];
private _hashMap = GVAR(VGarageStore) call ["mset", [GVAR(VGarageRegistry), "", _uid, _fieldValuePairs, _sync]];
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(garage,responseSyncVG), [_hashMap], _player] call CFUNC(targetEvent);
}] call CFUNC(addEventHandler);
[QGVAR(requestSaveVG), {
@ -117,7 +135,10 @@ PREP_RECOMPILE_END;
private _session = EGVAR(actor,PlayerSessions) getOrDefault [_uid, nil];
if (isNil "_session") exitWith { diag_log "[FORGE:Server:VGarage] Empty/Invalid Session!" };
GVAR(VGarageStore) call ["save", [_uid, _sync]];
private _finalData = GVAR(VGarageStore) call ["save", [GVAR(VGarageRegistry), "", _uid, _sync]];
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(garage,responseSyncVG), [_finalData], _player] call CFUNC(targetEvent);
}] call CFUNC(addEventHandler);
[QGVAR(requestRemoveVG), {
@ -125,5 +146,5 @@ PREP_RECOMPILE_END;
if (_uid isEqualTo "") exitWith { diag_log "[FORGE:Server:VGarage] Empty/Invalid UID!" };
GVAR(VGarageStore) call ["remove", [_uid]];
GVAR(VGarageStore) call ["remove", [GVAR(VGarageRegistry), _uid]];
}] call CFUNC(addEventHandler);

View File

@ -1,3 +1,2 @@
#include "script_component.hpp"
#include "XEH_PREP.hpp"

View File

@ -4,7 +4,7 @@
* File: fnc_initGarageStore.sqf
* Author: IDSolutions
* Date: 2025-12-17
* Last Update: 2026-01-03
* Last Update: 2026-01-10
* Public: No
*
* Description:
@ -22,20 +22,9 @@
*/
#pragma hemtt ignore_variables ["_self"]
GVAR(GarageStore) = createHashMapObject [[
private _typeGarage = compileFinal createHashMapFromArray [
["#base", EGVAR(common,BaseStore)],
["#type", "IGarageStore"],
["#create", {
GVAR(GarageRegistry) = createHashMap;
_self set ["_registry", GVAR(GarageRegistry)];
_self set ["_extCallPrefix", "garage"];
_self set ["_readMethod", "get"];
_self set ["_storeName", "Garage"];
_self set ["_syncEventName", CRPC(garage,responseSyncGarage)];
["INFO", "Garage Store Initialized!", nil, nil] call EFUNC(common,log);
}],
["#type", "IGarageBase"],
["init", {
params [["_uid", "", [""]], ["_defaultGarage", createHashMap, [createHashMap]]];
@ -50,7 +39,7 @@ GVAR(GarageStore) = createHashMapObject [[
["garage:create", [_uid]] call EFUNC(extension,extCall);
["INFO", format ["Created new garage for %1", _uid], nil, nil] call EFUNC(common,log);
} else {
_finalGarage = _self call ["fetch", [_uid]];
_finalGarage = _self call ["fetch", ["garage:get", _uid]];
["INFO", format ["Found garage for %1", _uid], nil, nil] call EFUNC(common,log);
};
@ -60,48 +49,16 @@ GVAR(GarageStore) = createHashMapObject [[
[CRPC(garage,responseInitGarage), [_finalGarage], _player] call CFUNC(targetEvent);
_finalGarage
}],
["set", {
params [["_uid", "", [""]], ["_field", "", [""]], ["_value", nil], ["_sync", false, [false]]];
}]
];
private _existingData = GVAR(GarageRegistry) get _uid;
private _finalData = +_existingData;
private _hashMap = createHashMap;
GVAR(GarageStore) = createHashMapObject [[
["#base", _typeGarage],
["#type", "IGarageStore"],
["#create", {
GVAR(GarageRegistry) = createHashMap;
_finalData set [_field, _value];
_hashMap set [_field, _value];
GVAR(GarageRegistry) set [_uid, _finalData];
if (_sync) then {
private _json = _self call ["toJSON", [_finalData]];
["garage:update", [_uid, _json]] call EFUNC(extension,extCall);
};
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(garage,responseSyncGarage), [_hashMap], _player] call CFUNC(targetEvent);
_hashMap
}],
["mset", {
params [["_uid", "", [""]], ["_fieldValuePairs", createHashMap, [createHashMap]], ["_sync", false, [false]]];
private _existingData = GVAR(GarageRegistry) get _uid;
private _finalData = +_existingData;
private _hashMap = createHashMap;
{ _finalData set [_x, _y]; } forEach _fieldValuePairs;
{ _hashMap set [_x, _y]; } forEach _fieldValuePairs;
GVAR(GarageRegistry) set [_uid, _finalData];
if (_sync) then {
private _json = _self call ["toJSON", [_finalData]];
["garage:update", [_uid, _json]] call EFUNC(extension,extCall);
};
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(garage,responseSyncGarage), [_hashMap], _player] call CFUNC(targetEvent);
_hashMap
["INFO", "Garage Store Initialized!", nil, nil] call EFUNC(common,log);
}]
]];

View File

@ -4,7 +4,7 @@
* File: fnc_initVGStore.sqf
* Author: IDSolutions
* Date: 2025-12-17
* Last Update: 2026-01-03
* Last Update: 2026-01-10
* Public: No
*
* Description:
@ -22,20 +22,9 @@
*/
#pragma hemtt ignore_variables ["_self"]
GVAR(VGarageStore) = createHashMapObject [[
private _typeVGarage = compileFinal createHashMapFromArray [
["#base", EGVAR(common,BaseStore)],
["#type", "IVGarageStore"],
["#create", {
GVAR(VGarageRegistry) = createHashMap;
_self set ["_registry", GVAR(VGarageRegistry)];
_self set ["_extCallPrefix", "owned:garage"];
_self set ["_readMethod", "fetch"];
_self set ["_storeName", "VGarage"];
_self set ["_syncEventName", CRPC(garage,responseSyncVG)];
["INFO", "VGarage Store Initialized!", nil, nil] call EFUNC(common,log);
}],
["#type", "IVGarageBase"],
["init", {
params [["_uid", "", [""]], ["_defaultVGarage", createHashMap, [createHashMap]]];
@ -50,7 +39,7 @@ GVAR(VGarageStore) = createHashMapObject [[
["owned:garage:create", [_uid]] call EFUNC(extension,extCall);
["INFO", format ["Created new VGarage for %1", _uid], nil, nil] call EFUNC(common,log);
} else {
private _existingVGarage = _self call ["fetch", [_uid]];
private _existingVGarage = _self call ["fetch", ["owned:garage:fetch", _uid]];
_finalVGarage = _existingVGarage;
{
@ -65,6 +54,16 @@ GVAR(VGarageStore) = createHashMapObject [[
_finalVGarage
}]
];
GVAR(VGarageStore) = createHashMapObject [[
["#base", _typeVGarage],
["#type", "IVGarageStore"],
["#create", {
GVAR(VGarageRegistry) = createHashMap;
["INFO", "VGarage Store Initialized!", nil, nil] call EFUNC(common,log);
}]
]];
SETMVAR(FORGE_VGarageStore,GVAR(VGarageStore));

View File

@ -21,7 +21,7 @@ PREP_RECOMPILE_END;
private _session = EGVAR(actor,PlayerSessions) getOrDefault [_uid, nil];
if (isNil "_session") exitWith { diag_log "[FORGE:Server:Locker] Empty/Invalid Session!" };
GVAR(LockerStore) call ["get", [_uid, _sync]];
GVAR(LockerStore) call ["get", [GVAR(LockerRegistry), "locker:get", _uid, _sync]];
}] call CFUNC(addEventHandler);
[QGVAR(requestSetLocker), {
@ -32,7 +32,10 @@ PREP_RECOMPILE_END;
private _session = EGVAR(actor,PlayerSessions) getOrDefault [_uid, nil];
if (isNil "_session") exitWith { diag_log "[FORGE:Server:Locker] Empty/Invalid Session!" };
GVAR(LockerStore) call ["set", [_uid, _key, _value, _sync]];
private _hashMap = GVAR(LockerStore) call ["set", [GVAR(LockerRegistry), "locker:update", _uid, _key, _value, _sync]];
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(locker,responseSyncLocker), [_hashMap], _player] call CFUNC(targetEvent);
}] call CFUNC(addEventHandler);
[QGVAR(requestMSetLocker), {
@ -44,7 +47,10 @@ PREP_RECOMPILE_END;
private _session = EGVAR(actor,PlayerSessions) getOrDefault [_uid, nil];
if (isNil "_session") exitWith { diag_log "[FORGE:Server:Locker] Empty/Invalid Session!" };
GVAR(LockerStore) call ["mset", [_uid, _fieldValuePairs, _sync]];
private _hashMap = GVAR(LockerStore) call ["mset", [GVAR(LockerRegistry), "locker:update", _uid, _fieldValuePairs, _sync]];
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(locker,responseSyncLocker), [_hashMap], _player] call CFUNC(targetEvent);
}] call CFUNC(addEventHandler);
[QGVAR(requestSaveLocker), {
@ -55,7 +61,10 @@ PREP_RECOMPILE_END;
private _session = EGVAR(actor,PlayerSessions) getOrDefault [_uid, nil];
if (isNil "_session") exitWith { diag_log "[FORGE:Server:Locker] Empty/Invalid Session!" };
GVAR(LockerStore) call ["save", [_uid, _sync]];
private _finalData = GVAR(LockerStore) call ["save", [GVAR(LockerRegistry), "locker:update", _uid, _sync]];
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(locker,responseSyncLocker), [_finalData], _player] call CFUNC(targetEvent);
}] call CFUNC(addEventHandler);
[QGVAR(requestRemoveLocker), {
@ -83,7 +92,7 @@ PREP_RECOMPILE_END;
private _session = EGVAR(actor,PlayerSessions) getOrDefault [_uid, nil];
if (isNil "_session") exitWith { diag_log "[FORGE:Server:VArsenal] Empty/Invalid Session!" };
GVAR(VArsenalStore) call ["get", [_uid, _sync]];
GVAR(VArsenalStore) call ["get", [GVAR(VArsenalRegistry), "owned:locker:fetch", _uid, _sync]];
}] call CFUNC(addEventHandler);
[QGVAR(requestSetVA), {
@ -94,7 +103,10 @@ PREP_RECOMPILE_END;
private _session = EGVAR(actor,PlayerSessions) getOrDefault [_uid, nil];
if (isNil "_session") exitWith { diag_log "[FORGE:Server:VArsenal] Empty/Invalid Session!" };
GVAR(VArsenalStore) call ["set", [_uid, _key, _value, _sync]];
private _hashMap = GVAR(VArsenalStore) call ["set", [GVAR(VArsenalRegistry), "owned:locker:update", _uid, _key, _value, _sync]];
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(locker,responseSyncVArsenal), [_hashMap], _player] call CFUNC(targetEvent);
}] call CFUNC(addEventHandler);
[QGVAR(requestMSetVA), {
@ -106,7 +118,10 @@ PREP_RECOMPILE_END;
private _session = EGVAR(actor,PlayerSessions) getOrDefault [_uid, nil];
if (isNil "_session") exitWith { diag_log "[FORGE:Server:VArsenal] Empty/Invalid Session!" };
GVAR(VArsenalStore) call ["mset", [_uid, _fieldValuePairs, _sync]];
private _hashMap = GVAR(VArsenalStore) call ["mset", [GVAR(VArsenalRegistry), "owned:locker:update", _uid, _fieldValuePairs, _sync]];
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(locker,responseSyncVArsenal), [_hashMap], _player] call CFUNC(targetEvent);
}] call CFUNC(addEventHandler);
[QGVAR(requestSaveVA), {
@ -117,7 +132,10 @@ PREP_RECOMPILE_END;
private _session = EGVAR(actor,PlayerSessions) getOrDefault [_uid, nil];
if (isNil "_session") exitWith { diag_log "[FORGE:Server:VArsenal] Empty/Invalid Session!" };
GVAR(VArsenalStore) call ["save", [_uid, _sync]];
private _finalData = GVAR(VArsenalStore) call ["save", [GVAR(VArsenalRegistry), "owned:locker:update", _uid, _sync]];
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(locker,responseSyncVArsenal), [_finalData], _player] call CFUNC(targetEvent);
}] call CFUNC(addEventHandler);
[QGVAR(requestRemoveVA), {
@ -125,5 +143,5 @@ PREP_RECOMPILE_END;
if (_uid isEqualTo "") exitWith { diag_log "[FORGE:Server:VArsenal] Empty/Invalid UID!" };
GVAR(VArsenalStore) call ["remove", [_uid]];
GVAR(VArsenalStore) call ["remove", [GVAR(VArsenalRegistry), _uid]];
}] call CFUNC(addEventHandler);

View File

@ -1,3 +1,2 @@
#include "script_component.hpp"
#include "XEH_PREP.hpp"

View File

@ -4,7 +4,7 @@
* File: fnc_initLockerStore.sqf
* Author: IDSolutions
* Date: 2025-12-17
* Last Update: 2026-01-03
* Last Update: 2026-01-10
* Public: No
*
* Description:
@ -22,20 +22,9 @@
*/
#pragma hemtt ignore_variables ["_self"]
GVAR(LockerStore) = createHashMapObject [[
private _typeLocker = compileFinal createHashMapFromArray [
["#base", EGVAR(common,BaseStore)],
["#type", "ILockerStore"],
["#create", {
GVAR(LockerRegistry) = createHashMap;
_self set ["_registry", GVAR(LockerRegistry)];
_self set ["_extCallPrefix", "locker"];
_self set ["_readMethod", "get"];
_self set ["_storeName", "Locker"];
_self set ["_syncEventName", CRPC(locker,responseSyncLocker)];
["INFO", "Locker Store Initialized!", nil, nil] call EFUNC(common,log);
}],
["#type", "ILockerBase"],
["init", {
params [["_uid", "", [""]], ["_defaultLocker", createHashMap, [createHashMap]]];
@ -57,53 +46,19 @@ GVAR(LockerStore) = createHashMapObject [[
GVAR(LockerRegistry) set [_uid, _finalLocker];
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(locker,responseInitLocker), [_finalLocker], _player] call CFUNC(targetEvent);
_finalLocker
}],
["set", {
params [["_uid", "", [""]], ["_field", "", [""]], ["_value", nil], ["_sync", false, [false]]];
}]
];
private _existingData = GVAR(LockerRegistry) get _uid;
private _finalData = +_existingData;
private _hashMap = createHashMap;
GVAR(LockerStore) = createHashMapObject [[
["#base", _typeLocker],
["#type", "ILockerStore"],
["#create", {
GVAR(LockerRegistry) = createHashMap;
_finalData set [_field, _value];
_hashMap set [_field, _value];
GVAR(LockerRegistry) set [_uid, _finalData];
if (_sync) then {
private _json = _self call ["toJSON", [_finalData]];
["locker:update", [_uid, _json]] call EFUNC(extension,extCall);
};
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(locker,responseSyncLocker), [_hashMap], _player] call CFUNC(targetEvent);
_hashMap
}],
["mset", {
params [["_uid", "", [""]], ["_fieldValuePairs", createHashMap, [createHashMap]], ["_sync", false, [false]]];
private _existingData = GVAR(LockerRegistry) get _uid;
private _finalData = +_existingData;
private _hashMap = createHashMap;
{ _finalData set [_x, _y]; } forEach _fieldValuePairs;
{ _hashMap set [_x, _y]; } forEach _fieldValuePairs;
GVAR(LockerRegistry) set [_uid, _finalData];
if (_sync) then {
private _json = _self call ["toJSON", [_finalData]];
["locker:update", [_uid, _json]] call EFUNC(extension,extCall);
};
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(locker,responseSyncLocker), [_hashMap], _player] call CFUNC(targetEvent);
_hashMap
["INFO", "Locker Store Initialized!", nil, nil] call EFUNC(common,log);
}]
]];

View File

@ -4,7 +4,7 @@
* File: fnc_initVAStore.sqf
* Author: IDSolutions
* Date: 2025-12-17
* Last Update: 2026-01-03
* Last Update: 2026-01-10
* Public: No
*
* Description:
@ -22,20 +22,9 @@
*/
#pragma hemtt ignore_variables ["_self"]
GVAR(VArsenalStore) = createHashMapObject [[
private _typeVArsenal = compileFinal createHashMapFromArray [
["#base", EGVAR(common,BaseStore)],
["#type", "IVArsenalStore"],
["#create", {
GVAR(VArsenalRegistry) = createHashMap;
_self set ["_registry", GVAR(VArsenalRegistry)];
_self set ["_extCallPrefix", "owned:locker"];
_self set ["_readMethod", "fetch"];
_self set ["_storeName", "VArsenal"];
_self set ["_syncEventName", CRPC(locker,responseSyncVA)];
["INFO", "VArsenal Store Initialized!", nil, nil] call EFUNC(common,log);
}],
["#type", "IVArsenalBase"],
["init", {
params [["_uid", "", [""]], ["_defaultVArsenal", createHashMap, [createHashMap]]];
@ -65,6 +54,16 @@ GVAR(VArsenalStore) = createHashMapObject [[
_finalVArsenal
}]
];
GVAR(VArsenalStore) = createHashMapObject [[
["#base", _typeVArsenal],
["#type", "IVArsenalStore"],
["#create", {
GVAR(VArsenalRegistry) = createHashMap;
["INFO", "VArsenal Store Initialized!", nil, nil] call EFUNC(common,log);
}]
]];
SETMVAR(FORGE_VArsenalStore,GVAR(VArsenalStore));

View File

@ -17,7 +17,7 @@
*/
// Base
if (isNil QEGVAR(common,BaseStore)) then { [] call EFUNC(common,initBaseStore); };
if (isNil QEGVAR(common,BaseStore)) then { [] call EFUNC(common,baseStore); };
// Actor
if (isNil QEGVAR(actor,ActorStore)) then { [] call EFUNC(actor,initActorStore); };

View File

@ -41,10 +41,6 @@ GVAR(OrgStore) = createHashMapObject [[
private _actor = EGVAR(actor,ActorRegistry) get _uid;
private _orgID = _actor get "organization";
private _assets = createHashMap;
private _organization = createHashMap;
private _members = createHashMap;
["org:exists", [_orgID]] call EFUNC(extension,extCall) params ["_result", "_isSuccess"];
private _exists = _result == "true";
@ -58,13 +54,13 @@ GVAR(OrgStore) = createHashMapObject [[
private _regEntry = createHashMapFromArray [["orgID", _orgID]];
GVAR(IndexRegistry) set [_uid, _regEntry];
_organization = _self call ["fetch", [_uid]];
_members = _self call ["fetchMembers", [_uid]];
// _assets = _self call ["fetchAssets", [_uid]];
private _organization = _self call ["fetch", [_uid]];
private _members = _self call ["fetchMembers", [_uid]];
// private _assets = _self call ["fetchAssets", [_uid]];
private _finalOrg = GVAR(OrgRegistry) getOrDefault [_orgID, _organization];
_finalOrg set ["members", _members];
_finalOrg set ["assets", _assets];
// _finalOrg set ["assets", _assets];
GVAR(OrgRegistry) set [_orgID, _finalOrg, true];
@ -77,13 +73,12 @@ GVAR(OrgStore) = createHashMapObject [[
private _assets = createHashMap;
private _members = createHashMap;
private _organization = createHashMap;
private _member = createHashMapFromArray [["uid", _uid], ["name", _name]];
private _regEntry = createHashMapFromArray [["orgID", "default"]];
GVAR(IndexRegistry) set [_uid, _regEntry];
_organization = _self call ["fetch", ["default"]];
private _organization = _self call ["fetch", ["default"]];
_members set [_uid, _member];
private _finalOrg = GVAR(OrgRegistry) getOrDefault ["default", _organization];

View File

@ -19,11 +19,10 @@
// Locker Registry
[["_SP_PLAYER_",[["30Rnd_65x39_caseless_mag",[["amount",4],["classname","30Rnd_65x39_caseless_mag"],["category","magazine"]]],["arifle_MX_F",[["amount",1],["classname","arifle_MX_F"],["category","weapon"]]],["NVGoggles",[["amount",1],["classname","NVGoggles"],["category","hmd"]]]]]];
// Organization Index Registry
[["_SP_PLAYER_",[["orgID","0160566824"]]]];
// Organization Registry
// Org Registry
[["0160566824",[["assets",[]],["name","Black Rifle Company"],["id","0160566824"],["funds",0],["reputation",0],["owner","_SP_PLAYER_"],["members",[["_SP_PLAYER_",[["name","Jacob Schmidt"],["uid","_SP_PLAYER_"]]]]]]]];
// Org Index Registry
[["_SP_PLAYER_",[["orgID","0160566824"]]]];
// Player Session Registry
[["_SP_PLAYER_",[["sessionToken","855837"]]]];