forge/arma/server/addons/cad/functions/fnc_initCadStore.sqf
Jacob Schmidt 0e9d0d3dc4 Refactor CAD sidepanel to hydrate board data
- Replace task-only refresh flow with hydrate/assignment/group events
- Add contracts, groups, and activity tabs to the client sidepanel
- Introduce server-side CAD store and request handlers
2026-03-29 22:17:07 -05:00

499 lines
18 KiB
Plaintext

#include "..\script_component.hpp"
/*
* File: fnc_initCadStore.sqf
* Author: IDSolutions
* Date: 2026-03-29
* Public: Yes
*
* Description:
* Initializes the CAD store for group tracking, assignment state,
* activity history, and CAD hydrate payloads.
*
* Arguments:
* None
*
* Return Value:
* CAD store object [HASHMAP OBJECT]
*
* Example:
* call forge_server_cad_fnc_initCadStore
*/
#pragma hemtt ignore_variables ["_self"]
GVAR(CadStoreBaseClass) = compileFinal createHashMapFromArray [
["#type", "CadStoreBaseClass"],
["#create", compileFinal {
_self set ["groupRegistry", createHashMap];
_self set ["assignmentRegistry", createHashMap];
_self set ["activityRegistry", []];
_self set ["validStatuses", [
"available",
"en_route",
"on_task",
"holding",
"danger",
"refit",
"offline"
]];
["INFO", "CAD Store Initialized!"] call EFUNC(common,log);
}],
["appendActivity", compileFinal {
params [
["_type", "", [""]],
["_message", "", [""]],
["_taskID", "", [""]],
["_groupID", "", [""]],
["_actorUid", "", [""]]
];
if (_type isEqualTo "" || { _message isEqualTo "" }) exitWith { false };
private _activityRegistry = +(_self getOrDefault ["activityRegistry", []]);
_activityRegistry pushBack createHashMapFromArray [
["type", _type],
["message", _message],
["timestamp", serverTime],
["taskId", _taskID],
["groupId", _groupID],
["actorUid", _actorUid]
];
if ((count _activityRegistry) > 50) then {
_activityRegistry deleteRange [0, (count _activityRegistry) - 50];
};
_self set ["activityRegistry", _activityRegistry];
true
}],
["resolveGroupId", compileFinal {
params [["_group", grpNull, [grpNull]]];
if (isNull _group) exitWith { "" };
private _leader = leader _group;
private _leaderUid = if (isNull _leader) then { "" } else { getPlayerUID _leader };
if (_leaderUid isNotEqualTo "") exitWith { format ["group:%1", _leaderUid] };
private _groupLabel = groupId _group;
if (_groupLabel isNotEqualTo "") exitWith { format ["group:%1", _groupLabel] };
str _group
}],
["canDispatch", compileFinal {
params [["_uid", "", [""]]];
if (_uid isEqualTo "") exitWith { false };
private _actor = EGVAR(actor,Registry) getOrDefault [_uid, createHashMap];
if (_actor isEqualTo createHashMap) then {
_actor = EGVAR(actor,ActorStore) call ["init", [_uid]];
};
private _orgID = _actor getOrDefault ["organization", "default"];
private _org = EGVAR(org,Registry) getOrDefault [_orgID, createHashMap];
if (_org isEqualTo createHashMap) then {
_org = EGVAR(org,OrgStore) call ["loadById", [_orgID]];
};
if (_org getOrDefault ["owner", ""] isEqualTo _uid) exitWith { true };
private _player = [_uid] call EFUNC(common,getPlayer);
if (_player isEqualTo objNull) exitWith { false };
(_orgID isEqualTo "default") && { vehicleVarName _player isEqualTo "ceo" }
}],
["getCurrentTaskIdForGroup", compileFinal {
params [["_groupID", "", [""]]];
if (_groupID isEqualTo "") exitWith { "" };
private _assignmentRegistry = _self getOrDefault ["assignmentRegistry", createHashMap];
private _taskID = "";
{
if ((_y getOrDefault ["groupId", ""]) isNotEqualTo _groupID) then { continue; };
if !((_y getOrDefault ["state", ""]) in ["assigned", "acknowledged"]) then { continue; };
if ((EGVAR(task,TaskStore) call ["getTaskStatus", [_x]]) isNotEqualTo "active") then { continue; };
_taskID = _x;
} forEach _assignmentRegistry;
_taskID
}],
["syncGroups", compileFinal {
private _previousRegistry = _self getOrDefault ["groupRegistry", createHashMap];
private _nextRegistry = createHashMap;
{
if (side _x isNotEqualTo west) then { continue; };
private _members = (units _x) select { isPlayer _x };
if (_members isEqualTo []) then { continue; };
private _leader = leader _x;
if (isNull _leader || { !isPlayer _leader }) then {
_leader = _members # 0;
};
private _groupID = _self call ["resolveGroupId", [_x]];
if (_groupID isEqualTo "") then { continue; };
private _leaderUid = getPlayerUID _leader;
private _actor = EGVAR(actor,Registry) getOrDefault [_leaderUid, createHashMap];
if (_actor isEqualTo createHashMap && { _leaderUid isNotEqualTo "" }) then {
_actor = EGVAR(actor,ActorStore) call ["init", [_leaderUid]];
};
private _orgID = _actor getOrDefault ["organization", "default"];
if (_orgID isEqualTo "") then { _orgID = "default"; };
private _existingRecord = +(_previousRegistry getOrDefault [_groupID, createHashMap]);
private _memberUids = [];
{
private _memberUid = getPlayerUID _x;
if (_memberUid isNotEqualTo "") then {
_memberUids pushBack _memberUid;
};
} forEach _members;
private _record = createHashMapFromArray [
["groupId", _groupID],
["callsign", [groupId _x, _groupID] select ((groupId _x) isEqualTo "")],
["leaderUid", _leaderUid],
["leaderName", name _leader],
["memberUids", _memberUids],
["orgId", _orgID],
["role", _existingRecord getOrDefault ["role", "infantry"]],
["status", _existingRecord getOrDefault ["status", "available"]],
["position", getPosATL _leader],
["currentTaskId", _self call ["getCurrentTaskIdForGroup", [_groupID]]],
["lastUpdate", serverTime]
];
_nextRegistry set [_groupID, _record];
} forEach allGroups;
_self set ["groupRegistry", _nextRegistry];
_nextRegistry
}],
["getGroupRecord", compileFinal {
params [["_groupID", "", [""]]];
if (_groupID isEqualTo "") exitWith { createHashMap };
private _groupRegistry = _self call ["syncGroups", []];
+(_groupRegistry getOrDefault [_groupID, createHashMap])
}],
["getPlayerGroupId", compileFinal {
params [["_uid", "", [""]]];
if (_uid isEqualTo "") exitWith { "" };
private _player = [_uid] call EFUNC(common,getPlayer);
if (_player isEqualTo objNull) exitWith { "" };
_self call ["resolveGroupId", [group _player]]
}],
["isGroupLeader", compileFinal {
params [["_uid", "", [""]], ["_groupID", "", [""]]];
if (_uid isEqualTo "" || { _groupID isEqualTo "" }) exitWith { false };
private _groupRecord = _self call ["getGroupRecord", [_groupID]];
(_groupRecord getOrDefault ["leaderUid", ""]) isEqualTo _uid
}],
["pruneAssignments", compileFinal {
private _assignmentRegistry = _self getOrDefault ["assignmentRegistry", createHashMap];
private _keysToRemove = [];
{
private _status = EGVAR(task,TaskStore) call ["getTaskStatus", [_x]];
if !(_status in ["active", ""]) then {
_keysToRemove pushBack _x;
};
} forEach _assignmentRegistry;
{
_assignmentRegistry deleteAt _x;
} forEach _keysToRemove;
_self set ["assignmentRegistry", _assignmentRegistry];
count _keysToRemove
}],
["buildContracts", compileFinal {
_self call ["pruneAssignments", []];
private _assignmentRegistry = _self getOrDefault ["assignmentRegistry", createHashMap];
private _contracts = [];
{
private _taskID = _x getOrDefault ["taskID", ""];
if (_taskID isEqualTo "") then { continue; };
private _assignment = _assignmentRegistry getOrDefault [_taskID, createHashMap];
private _entry = +_x;
_entry set ["taskId", _taskID];
_entry set ["assignedGroupId", _assignment getOrDefault ["groupId", ""]];
_entry set ["assignmentState", [_assignment getOrDefault ["state", ""], "unassigned"] select (_assignment isEqualTo createHashMap)];
_contracts pushBack _entry;
} forEach (EGVAR(task,TaskStore) call ["getActiveTaskCatalog", []]);
_contracts
}],
["buildGroups", compileFinal {
private _groupRegistry = _self call ["syncGroups", []];
private _groups = [];
{
_groups pushBack +_y;
} forEach _groupRegistry;
_groups
}],
["buildHydratePayload", compileFinal {
params [["_uid", "", [""]]];
private _activity = +(_self getOrDefault ["activityRegistry", []]);
private _actor = EGVAR(actor,Registry) getOrDefault [_uid, createHashMap];
if (_actor isEqualTo createHashMap && { _uid isNotEqualTo "" }) then {
_actor = EGVAR(actor,ActorStore) call ["init", [_uid]];
};
createHashMapFromArray [
["groups", _self call ["buildGroups", []]],
["contracts", _self call ["buildContracts", []]],
["assignments", values (_self getOrDefault ["assignmentRegistry", createHashMap])],
["activity", _activity],
["session", createHashMapFromArray [
["uid", _uid],
["orgId", _actor getOrDefault ["organization", "default"]],
["isDispatcher", _self call ["canDispatch", [_uid]]],
["groupId", _self call ["getPlayerGroupId", [_uid]]],
["isLeader", _self call ["isGroupLeader", [_uid, _self call ["getPlayerGroupId", [_uid]]]]]
]]
]
}],
["notifyPlayer", compileFinal {
params [
["_uid", "", [""]],
["_type", "info", [""]],
["_title", "CAD", [""]],
["_message", "", [""]]
];
if (_uid isEqualTo "" || { _message isEqualTo "" }) exitWith { false };
private _player = [_uid] call EFUNC(common,getPlayer);
if (_player isEqualTo objNull) exitWith { false };
[CRPC(notifications,recieveNotification), [_type, _title, _message], _player] call CFUNC(targetEvent);
true
}],
["assignTaskToGroup", compileFinal {
params [
["_requesterUid", "", [""]],
["_taskID", "", [""]],
["_groupID", "", [""]],
["_note", "", [""]]
];
private _result = createHashMapFromArray [
["success", false],
["message", "Unable to assign task."],
["assignment", createHashMap]
];
if !(_self call ["canDispatch", [_requesterUid]]) exitWith {
_result set ["message", "You are not authorized to assign contracts."];
_result
};
if ((EGVAR(task,TaskStore) call ["getTaskStatus", [_taskID]]) isNotEqualTo "active") exitWith {
_result set ["message", "Task is no longer active."];
_result
};
private _groupRecord = _self call ["getGroupRecord", [_groupID]];
if (_groupRecord isEqualTo createHashMap) exitWith {
_result set ["message", "Selected group is unavailable."];
_result
};
private _leaderUid = _groupRecord getOrDefault ["leaderUid", ""];
if (_leaderUid isEqualTo "") exitWith {
_result set ["message", "Selected group has no online leader."];
_result
};
private _requesterPlayer = [_requesterUid] call EFUNC(common,getPlayer);
private _assignmentRegistry = _self getOrDefault ["assignmentRegistry", createHashMap];
private _assignment = createHashMapFromArray [
["taskId", _taskID],
["groupId", _groupID],
["assignedByUid", _requesterUid],
["assignedByName", ["Dispatcher", name _requesterPlayer] select (_requesterPlayer isNotEqualTo objNull)],
["assignedAt", serverTime],
["state", "assigned"],
["note", _note]
];
_assignmentRegistry set [_taskID, _assignment];
_self set ["assignmentRegistry", _assignmentRegistry];
_self call ["appendActivity", [
"task_assigned",
format ["%1 assigned %2 to %3.", _assignment get "assignedByName", _taskID, _groupRecord getOrDefault ["callsign", _groupID]],
_taskID,
_groupID,
_requesterUid
]];
_self call ["notifyPlayer", [
_leaderUid,
"info",
"Tasks",
format ["Contract assigned: %1. Open CAD to review and acknowledge.", _taskID]
]];
_result set ["success", true];
_result set ["message", "Task assigned."];
_result set ["assignment", _assignment];
_result
}],
["acknowledgeTask", compileFinal {
params [["_requesterUid", "", [""]], ["_taskID", "", [""]]];
private _result = createHashMapFromArray [
["success", false],
["message", "Unable to acknowledge task."],
["assignment", createHashMap]
];
private _assignmentRegistry = _self getOrDefault ["assignmentRegistry", createHashMap];
private _assignment = +(_assignmentRegistry getOrDefault [_taskID, createHashMap]);
if (_assignment isEqualTo createHashMap) exitWith {
_result set ["message", "Task is not assigned."];
_result
};
private _groupID = _assignment getOrDefault ["groupId", ""];
if !(_self call ["isGroupLeader", [_requesterUid, _groupID]]) exitWith {
_result set ["message", "Only the assigned group leader can acknowledge this task."];
_result
};
private _bindResult = EGVAR(task,TaskStore) call ["bindTaskOwnership", [_taskID, _requesterUid]];
if !(_bindResult getOrDefault ["success", false]) exitWith {
_result set ["message", _bindResult getOrDefault ["message", "Failed to bind task ownership."]];
_result
};
_assignment set ["state", "acknowledged"];
_assignment set ["acknowledgedAt", serverTime];
_assignmentRegistry set [_taskID, _assignment];
_self set ["assignmentRegistry", _assignmentRegistry];
_self call ["appendActivity", [
"task_acknowledged",
format ["%1 acknowledged %2.", _requesterUid, _taskID],
_taskID,
_groupID,
_requesterUid
]];
_result set ["success", true];
_result set ["message", "Task acknowledged."];
_result set ["assignment", _assignment];
_result
}],
["declineTask", compileFinal {
params [["_requesterUid", "", [""]], ["_taskID", "", [""]]];
private _result = createHashMapFromArray [
["success", false],
["message", "Unable to decline task."],
["assignment", createHashMap]
];
private _assignmentRegistry = _self getOrDefault ["assignmentRegistry", createHashMap];
private _assignment = +(_assignmentRegistry getOrDefault [_taskID, createHashMap]);
if (_assignment isEqualTo createHashMap) exitWith {
_result set ["message", "Task is not assigned."];
_result
};
private _groupID = _assignment getOrDefault ["groupId", ""];
if !(_self call ["isGroupLeader", [_requesterUid, _groupID]]) exitWith {
_result set ["message", "Only the assigned group leader can decline this task."];
_result
};
_assignment set ["state", "declined"];
_assignment set ["declinedAt", serverTime];
_assignmentRegistry set [_taskID, _assignment];
_self set ["assignmentRegistry", _assignmentRegistry];
_self call ["appendActivity", [
"task_declined",
format ["%1 declined %2.", _requesterUid, _taskID],
_taskID,
_groupID,
_requesterUid
]];
_result set ["success", true];
_result set ["message", "Task declined."];
_result set ["assignment", _assignment];
_result
}],
["updateGroupStatus", compileFinal {
params [["_requesterUid", "", [""]], ["_groupID", "", [""]], ["_status", "", [""]]];
private _result = createHashMapFromArray [
["success", false],
["message", "Unable to update group status."],
["group", createHashMap]
];
private _finalStatus = toLowerANSI _status;
if !(_finalStatus in (_self getOrDefault ["validStatuses", []])) exitWith {
_result set ["message", "Invalid group status."];
_result
};
private _isAuthorized = (_self call ["isGroupLeader", [_requesterUid, _groupID]]) || { _self call ["canDispatch", [_requesterUid]] };
if !_isAuthorized exitWith {
_result set ["message", "You are not authorized to update that group."];
_result
};
private _groupRegistry = _self call ["syncGroups", []];
private _groupRecord = +(_groupRegistry getOrDefault [_groupID, createHashMap]);
if (_groupRecord isEqualTo createHashMap) exitWith {
_result set ["message", "Group could not be resolved."];
_result
};
_groupRecord set ["status", _finalStatus];
_groupRecord set ["lastUpdate", serverTime];
_groupRegistry set [_groupID, _groupRecord];
_self set ["groupRegistry", _groupRegistry];
_self call ["appendActivity", [
"group_status",
format ["%1 updated %2 to %3.", _requesterUid, _groupRecord getOrDefault ["callsign", _groupID], _finalStatus],
"",
_groupID,
_requesterUid
]];
_result set ["success", true];
_result set ["message", "Group status updated."];
_result set ["group", _groupRecord];
_result
}]
];
GVAR(CadStore) = createHashMapObject [GVAR(CadStoreBaseClass)];
GVAR(CadStore)