forge/arma/server/addons/cad/functions/fnc_initGroupRepository.sqf
Jacob Schmidt 4ea7cf7d05 Add CAD request workflows and focus actions
- Add request hydration, submission, closing, and response handling
- Wire UI events for dispatch orders, support requests, and map focus
- Expand dispatcher layout for alerts, requests, and detail views
2026-03-31 20:14:45 -05:00

342 lines
13 KiB
Plaintext

#include "..\script_component.hpp"
/*
* File: fnc_initGroupRepository.sqf
* Author: IDSolutions
* Date: 2026-03-30
* Public: No
*
* Description:
* Initializes the CAD group repository for live group state, roles,
* and dispatcher/leader-managed group profiles.
*
* Arguments:
* None
*
* Return Value:
* CAD group repository object [HASHMAP OBJECT]
*
* Example:
* call forge_server_cad_fnc_initGroupRepository
*/
#pragma hemtt ignore_variables ["_self"]
GVAR(GroupRepositoryBaseClass) = compileFinal createHashMapFromArray [
["#type", "CadGroupRepositoryBaseClass"],
["#create", compileFinal {
_self set ["groupRegistry", createHashMap];
_self set ["groupProfileRegistry", createHashMap];
_self set ["validStatuses", [
"available",
"en_route",
"on_task",
"holding",
"danger",
"unavailable"
]];
_self set ["validRoles", [
"infantry",
"recon",
"armor",
"air",
"logistics",
"support"
]];
}],
["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
}],
["getCurrentTaskIdForGroup", compileFinal {
params [["_groupID", "", [""]]];
if (_groupID isEqualTo "") exitWith { "" };
private _assignmentRepository = _self getOrDefault ["assignmentRepository", createHashMap];
private _assignmentRegistry = _assignmentRepository getOrDefault ["assignmentRegistry", createHashMap];
private _dispatchOrderRegistry = _assignmentRepository getOrDefault ["dispatchOrderRegistry", createHashMap];
private _taskID = "";
{
if ((_y getOrDefault ["groupId", ""]) isNotEqualTo _groupID) then { continue; };
if !((_y getOrDefault ["state", ""]) in ["assigned", "acknowledged"]) then { continue; };
private _dispatchOrder = +(_dispatchOrderRegistry getOrDefault [_x, createHashMap]);
if (_dispatchOrder isEqualTo createHashMap) then {
if ((EGVAR(task,TaskStore) call ["getTaskStatus", [_x]]) isNotEqualTo "active") then { continue; };
_taskID = _x;
} else {
_taskID = _dispatchOrder getOrDefault ["title", _x];
};
} forEach _assignmentRegistry;
_taskID
}],
["syncGroups", compileFinal {
private _assignmentRepository = _self getOrDefault ["assignmentRepository", createHashMap];
if (_assignmentRepository isNotEqualTo createHashMap) then {
_assignmentRepository call ["restorePersistedState", []];
};
private _liveGroups = [];
{
private _group = _x;
if (side _group isNotEqualTo west) then { continue; };
private _members = allPlayers select { group _x isEqualTo _group };
if (_members isEqualTo []) then { continue; };
private _leader = leader _group;
if (isNull _leader || { !isPlayer _leader }) then {
_leader = _members # 0;
};
private _groupID = _self call ["resolveGroupId", [_group]];
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 _memberUids = [];
private _memberRoster = [];
{
private _memberUid = getPlayerUID _x;
private _memberState = toLowerANSI (lifeState _x);
if (_memberUid isNotEqualTo "") then {
_memberUids pushBack _memberUid;
};
_memberRoster pushBack (createHashMapFromArray [
["uid", _memberUid],
["name", name _x],
["lifeState", _memberState],
["isLeader", _x isEqualTo _leader]
]);
} forEach _members;
_liveGroups pushBack (createHashMapFromArray [
["groupId", _groupID],
["callsign", [groupId _group, _groupID] select ((groupId _group) isEqualTo "")],
["leaderUid", _leaderUid],
["leaderName", name _leader],
["memberUids", _memberUids],
["members", _memberRoster],
["orgId", _orgID],
["role", "infantry"],
["status", "available"],
["position", getPosATL _leader],
["currentTaskId", _self call ["getCurrentTaskIdForGroup", [_groupID]]],
["lastUpdate", serverTime]
]);
} forEach allGroups;
private _mergedGroups = _liveGroups;
private _persistenceService = _self getOrDefault ["persistenceService", createHashMap];
if (_persistenceService isNotEqualTo createHashMap) then {
private _buildResult = _persistenceService call ["buildGroups", [_liveGroups]];
if (_buildResult getOrDefault ["success", false]) then {
_mergedGroups = +(_buildResult getOrDefault ["data", _liveGroups]);
};
};
private _nextRegistry = createHashMap;
private _profileRegistry = createHashMap;
{
if !(_x isEqualType createHashMap) then { continue; };
private _groupID = _x getOrDefault ["groupId", ""];
if (_groupID isEqualTo "") then { continue; };
private _groupRecord = +_x;
_nextRegistry set [_groupID, _groupRecord];
_profileRegistry set [_groupID, createHashMapFromArray [
["groupId", _groupID],
["role", _groupRecord getOrDefault ["role", "infantry"]],
["status", _groupRecord getOrDefault ["status", "available"]]
]];
} forEach _mergedGroups;
_self set ["groupProfileRegistry", _profileRegistry];
_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
}],
["buildGroups", compileFinal {
private _groupRegistry = _self call ["syncGroups", []];
private _groups = [];
{
_groups pushBack +_y;
} forEach _groupRegistry;
_groups
}],
["applyGroupProfileUpdate", compileFinal {
params [
["_requesterUid", "", [""]],
["_groupID", "", [""]],
["_status", "", [""]],
["_role", "", [""]],
["_mode", "profile", [""]]
];
private _result = createHashMapFromArray [
["success", false],
["message", "Unable to update group profile."],
["changed", false],
["group", createHashMap]
];
private _finalStatus = toLowerANSI _status;
private _finalRole = toLowerANSI _role;
private _hasStatus = _finalStatus isNotEqualTo "";
private _hasRole = _finalRole isNotEqualTo "";
if (_mode isEqualTo "status" && !_hasStatus) exitWith {
_result set ["message", "Invalid group status."];
_result
};
if (_mode isEqualTo "role" && !_hasRole) exitWith {
_result set ["message", "Invalid group role."];
_result
};
if (_mode isEqualTo "profile" && !(_hasStatus || _hasRole)) exitWith {
_result set ["message", "No group changes were provided."];
_result
};
if (_hasStatus && !(_finalStatus in (_self getOrDefault ["validStatuses", []]))) exitWith {
_result set ["message", "Invalid group status."];
_result
};
if (_hasRole && !(_finalRole in (_self getOrDefault ["validRoles", []]))) exitWith {
_result set ["message", "Invalid group role."];
_result
};
private _permissionService = _self getOrDefault ["permissionService", createHashMap];
private _isAuthorized = (_self call ["isGroupLeader", [_requesterUid, _groupID]]) || { _permissionService 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
};
private _didChangeStatus = _hasStatus && { (_groupRecord getOrDefault ["status", ""]) isNotEqualTo _finalStatus };
private _didChangeRole = _hasRole && { (_groupRecord getOrDefault ["role", ""]) isNotEqualTo _finalRole };
private _persistenceService = _self getOrDefault ["persistenceService", createHashMap];
if (_persistenceService isEqualTo createHashMap) exitWith {
_result set ["message", "CAD extension state is unavailable."];
_result
};
private _updateContext = createHashMapFromArray [
["groupId", _groupID],
["groupCallsign", _groupRecord getOrDefault ["callsign", _groupID]],
["requesterUid", _requesterUid],
["currentRole", _groupRecord getOrDefault ["role", "infantry"]],
["currentStatus", _groupRecord getOrDefault ["status", "available"]],
["role", [_finalRole, ""] select !_hasRole],
["status", [_finalStatus, ""] select !_hasStatus],
["mode", _mode]
];
private _profileResult = _persistenceService call ["updateGroupProfileFromContext", [_updateContext]];
if !(_profileResult getOrDefault ["success", false]) exitWith {
_result set ["message", "CAD extension rejected the group profile update."];
_result
};
private _profileData = +(_profileResult getOrDefault ["data", createHashMap]);
private _profile = +(_profileData getOrDefault ["profile", createHashMap]);
if (_profile isEqualTo createHashMap) exitWith {
_result set ["message", "CAD extension returned an invalid group profile."];
_result
};
_groupRecord set ["role", _profile getOrDefault ["role", _groupRecord getOrDefault ["role", "infantry"]]];
_groupRecord set ["status", _profile getOrDefault ["status", _groupRecord getOrDefault ["status", "available"]]];
_groupRecord set ["lastUpdate", serverTime];
private _profileRegistry = _self getOrDefault ["groupProfileRegistry", createHashMap];
_groupRegistry set [_groupID, _groupRecord];
_self set ["groupRegistry", _groupRegistry];
_profileRegistry set [_groupID, _profile];
_self set ["groupProfileRegistry", _profileRegistry];
private _activityEntry = +(_profileData getOrDefault ["activity", createHashMap]);
if (_activityEntry isNotEqualTo createHashMap) then {
private _activityRepository = _self getOrDefault ["activityRepository", createHashMap];
_activityRepository call ["appendEntry", [_activityEntry]];
};
_result set ["success", true];
_result set ["message", _profileData getOrDefault ["message", "Group profile updated."]];
_result set ["changed", _profileData getOrDefault ["changed", (_didChangeStatus || _didChangeRole)]];
_result set ["group", _groupRecord];
_result
}],
["updateGroupStatus", compileFinal {
_self call ["applyGroupProfileUpdate", [_this # 0, _this # 1, _this # 2, "", "status"]]
}],
["updateGroupRole", compileFinal {
_self call ["applyGroupProfileUpdate", [_this # 0, _this # 1, "", _this # 2, "role"]]
}],
["updateGroupProfile", compileFinal {
_self call ["applyGroupProfileUpdate", [_this # 0, _this # 1, _this # 2, _this # 3, "profile"]]
}]
];
createHashMapObject [GVAR(GroupRepositoryBaseClass)]