#include "..\script_component.hpp" /* * Author: IDSolutions * Initializes the task store for task entity tracking, participant * contribution tracking, and task outcome application. * * Task metadata is extension-backed but intentionally transient. The * task backend is reset when this store is created so task/catalog/status * state starts clean for each server or mission lifecycle. * * Arguments: * None * * Return Value: * Task store object [HASHMAP OBJECT] * * Example: * call forge_server_task_fnc_initTaskStore * * Public: No */ #pragma hemtt ignore_variables ["_self"] GVAR(TaskStore) = createHashMapObject [[ ["#type", "TaskStore"], ["#create", compileFinal { _self set ["participantRegistry", createHashMap]; _self set ["taskLifecycleRegistry", createHashMap]; _self set ["taskEntityRegistries", createHashMapFromArray [ ["cargo", createHashMap], ["hostages", createHashMap], ["hvts", createHashMap], ["ieds", createHashMap], ["entities", createHashMap], ["shooters", createHashMap], ["targets", createHashMap] ]]; _self call ["resetMissionState", []]; }], ["resetMissionState", compileFinal { _self set ["participantRegistry", createHashMap]; _self set ["taskLifecycleRegistry", createHashMap]; _self set ["taskEntityRegistries", createHashMapFromArray [ ["cargo", createHashMap], ["hostages", createHashMap], ["hvts", createHashMap], ["ieds", createHashMap], ["entities", createHashMap], ["shooters", createHashMap], ["targets", createHashMap] ]]; ["task:reset", []] call EFUNC(extension,extCall) params ["_result", "_isSuccess"]; if ( !_isSuccess || { !(_result isEqualType "") } || { (_result find "Error:") == 0 } ) exitWith { ["WARNING", "Failed to reset task backend state during task store initialization."] call EFUNC(common,log); false }; true }], ["callTaskStateEnvelope", compileFinal { params [["_function", "", [""]], ["_arguments", [], [[]]]]; private _envelope = createHashMapFromArray [ ["success", false], ["error", ""] ]; if (_function isEqualTo "") exitWith { _envelope }; [_function, _arguments] call EFUNC(extension,extCall) params ["_result", "_isSuccess"]; if !_isSuccess exitWith { _envelope set ["error", format ["Task backend call '%1' failed.", _function]]; _envelope }; if !(_result isEqualType "") exitWith { _envelope set ["error", format ["Task backend call '%1' returned an invalid response.", _function]]; _envelope }; if ((_result find "Error:") == 0) exitWith { ["ERROR", format ["Task extension call '%1' failed: %2", _function, _result]] call EFUNC(common,log); _envelope set ["error", _result select [7]]; _envelope }; _envelope set ["success", true]; if (_result isNotEqualTo "") then { _envelope set ["data", fromJSON _result]; }; _envelope }], ["callTaskState", compileFinal { params [["_function", "", [""]], ["_arguments", [], [[]]], ["_fallback", nil]]; private _envelope = _self call ["callTaskStateEnvelope", [_function, _arguments]]; if !(_envelope getOrDefault ["success", false]) exitWith { _fallback }; _envelope getOrDefault ["data", _fallback] }], ["bindTaskOwnership", compileFinal { params [["_taskID", "", [""]], ["_requesterUid", "", [""]]]; private _result = createHashMapFromArray [ ["success", false], ["requesterUid", _requesterUid], ["orgID", "default"], ["message", ""] ]; if (_taskID isEqualTo "") exitWith { _result set ["message", "Missing task ID."]; _result }; private _orgID = "default"; if (_requesterUid isNotEqualTo "") then { private _actor = EGVAR(actor,ActorStore) call ["load", [_requesterUid]]; if (_actor isEqualTo createHashMap) exitWith { _result set ["message", format ["Failed to load actor for %1.", _requesterUid]]; _result }; _orgID = EGVAR(actor,ActorStore) call ["getOrganization", [_requesterUid]]; }; private _context = createHashMapFromArray [ ["requesterUid", _requesterUid], ["orgId", _orgID] ]; private _envelope = _self call [ "callTaskStateEnvelope", [ "task:ownership:bind", [_taskID, toJSON _context] ] ]; if !(_envelope getOrDefault ["success", false]) exitWith { _result set ["message", _envelope getOrDefault ["error", "Failed to bind task ownership."]]; _result }; private _bindResult = _envelope getOrDefault ["data", createHashMap]; _result set ["success", true]; _result set ["message", _bindResult getOrDefault [ "message", ["No requester UID provided. Bound task to default organization.", "Task ownership updated."] select (_requesterUid isNotEqualTo "") ]]; _result set ["orgID", _bindResult getOrDefault ["orgId", _orgID]]; _result }], ["releaseTaskOwnership", compileFinal { params [["_taskID", "", [""]]]; if (_taskID isEqualTo "") exitWith { false }; private _envelope = _self call ["callTaskStateEnvelope", ["task:ownership:release", [_taskID]]]; _envelope getOrDefault ["success", false] }], ["buildTaskLifecycleEventPayload", compileFinal { params [["_taskID", "", [""]], ["_status", "", [""]], ["_extra", createHashMap]]; if !(_extra isEqualType createHashMap) then { _extra = createHashMap; }; private _catalogEntry = _self call ["getTaskCatalogEntry", [_taskID]]; private _lifecycleRegistry = _self getOrDefault ["taskLifecycleRegistry", createHashMap]; private _lifecycle = +(_lifecycleRegistry getOrDefault [_taskID, createHashMap]); private _startedAt = _lifecycle getOrDefault ["startedAt", -1]; private _finishedAt = _lifecycle getOrDefault ["finishedAt", -1]; createHashMapFromArray [ ["taskID", _taskID], ["taskType", _catalogEntry getOrDefault ["type", ""]], ["title", _catalogEntry getOrDefault ["title", _taskID]], ["description", _catalogEntry getOrDefault ["description", ""]], ["position", +(_catalogEntry getOrDefault ["position", []])], ["status", _status], ["source", _catalogEntry getOrDefault ["source", "task"]], ["requesterUid", _catalogEntry getOrDefault ["requesterUid", ""]], ["orgID", _catalogEntry getOrDefault ["orgID", "default"]], ["startedAt", _startedAt], ["finishedAt", _finishedAt], ["duration", if (_startedAt >= 0 && { _finishedAt >= 0 }) then { _finishedAt - _startedAt } else { -1 }], ["failureReason", _extra getOrDefault ["failureReason", ""]], ["participants", _self call ["getTaskParticipantUids", [_taskID]]], ["rewardData", +(_extra getOrDefault ["rewardData", createHashMap])], ["resultSnapshot", +(_extra getOrDefault ["resultSnapshot", createHashMap])], ["catalogEntry", +_catalogEntry] ] }], ["emitTaskLifecycleEvent", compileFinal { params [["_eventName", "", [""]], ["_taskID", "", [""]], ["_status", "", [""]], ["_extra", createHashMap]]; if (_eventName isEqualTo "" || { _taskID isEqualTo "" }) exitWith { createHashMap }; if (isNil QEGVAR(common,EventBus)) exitWith { createHashMap }; EGVAR(common,EventBus) call ["emit", [ _eventName, _self call ["buildTaskLifecycleEventPayload", [_taskID, _status, _extra]], createHashMapFromArray [["source", "task"]] ]] }], ["registerTaskCatalogEntry", compileFinal { params [["_taskID", "", [""]], ["_entry", createHashMap, [createHashMap]]]; if (_taskID isEqualTo "" || { _entry isEqualTo createHashMap }) exitWith { false }; private _envelope = _self call [ "callTaskStateEnvelope", [ "task:catalog:upsert", [_taskID, toJSON _entry] ] ]; private _registered = _envelope getOrDefault ["success", false]; if (_registered) then { private _lifecycleRegistry = _self getOrDefault ["taskLifecycleRegistry", createHashMap]; private _lifecycle = +(_lifecycleRegistry getOrDefault [_taskID, createHashMap]); _lifecycle set ["createdAt", serverTime]; _lifecycleRegistry set [_taskID, _lifecycle]; _self set ["taskLifecycleRegistry", _lifecycleRegistry]; _self call ["emitTaskLifecycleEvent", ["task.created", _taskID, "created", createHashMap]]; }; _registered }], ["getActiveTaskCatalog", compileFinal { private _entries = _self call ["callTaskState", ["task:catalog:active", [], []]]; if !(_entries isEqualType []) exitWith { [] }; _entries }], ["hasTaskCatalogEntry", compileFinal { params [["_taskID", "", [""]]]; if (_taskID isEqualTo "") exitWith { false }; private _entry = _self call ["callTaskState", ["task:catalog:get", [_taskID], objNull]]; _entry isEqualType createHashMap }], ["getTaskCatalogEntry", compileFinal { params [["_taskID", "", [""]]]; if (_taskID isEqualTo "") exitWith { createHashMap }; [(_self call ["callTaskState", ["task:catalog:get", [_taskID], createHashMap]])] params [["_entry", createHashMap, [createHashMap]]]; if !(_entry isEqualType createHashMap) exitWith { createHashMap }; _entry }], ["isTaskAccepted", compileFinal { params [["_taskID", "", [""]]]; if (_taskID isEqualTo "") exitWith { false }; [(_self call ["getTaskCatalogEntry", [_taskID]])] params [["_entry", createHashMap, [createHashMap]]]; if (_entry isEqualTo createHashMap) exitWith { false }; [(_entry getOrDefault ["accepted", false])] params [["_accepted", false, [false]]]; [(_entry getOrDefault ["requesterUid", ""])] params [["_requesterUid", "", [""]]]; _accepted || { _requesterUid isNotEqualTo "" } }], ["acceptTask", compileFinal { params [["_taskID", "", [""]], ["_requesterUid", "", [""]]]; private _result = createHashMapFromArray [ ["success", false], ["message", "Unable to accept task."], ["entry", createHashMap] ]; if (_taskID isEqualTo "" || { _requesterUid isEqualTo "" }) exitWith { _result set ["message", "Missing task ID or requester UID."]; _result }; private _actor = EGVAR(actor,ActorStore) call ["load", [_requesterUid]]; if (_actor isEqualTo createHashMap) exitWith { _result set ["message", format ["Failed to load actor for %1.", _requesterUid]]; _result }; private _orgID = EGVAR(actor,ActorStore) call ["getOrganization", [_requesterUid]]; private _context = createHashMapFromArray [ ["requesterUid", _requesterUid], ["orgId", _orgID] ]; private _envelope = _self call [ "callTaskStateEnvelope", [ "task:ownership:accept", [_taskID, toJSON _context] ] ]; if !(_envelope getOrDefault ["success", false]) exitWith { _result set ["message", _envelope getOrDefault ["error", "Unable to accept task."]]; _result }; private _acceptResult = _envelope getOrDefault ["data", createHashMap]; private _entry = _acceptResult getOrDefault ["entry", createHashMap]; if !(_entry isEqualType createHashMap) then { _entry = createHashMap; }; _result set ["success", true]; _result set ["message", _acceptResult getOrDefault ["message", "Task accepted."]]; _result set ["entry", _entry]; _result }], ["setTaskStatus", compileFinal { params [["_taskID", "", [""]], ["_status", "", [""]]]; if (_taskID isEqualTo "" || { _status isEqualTo "" }) exitWith { false }; private _envelope = _self call ["callTaskStateEnvelope", ["task:status:set", [_taskID, _status]]]; private _statusResult = _envelope getOrDefault ["success", false]; if (_statusResult) then { private _normalizedStatus = toLowerANSI _status; private _lifecycleRegistry = _self getOrDefault ["taskLifecycleRegistry", createHashMap]; private _lifecycle = +(_lifecycleRegistry getOrDefault [_taskID, createHashMap]); private _eventName = ""; switch (_normalizedStatus) do { case "active": { _lifecycle set ["startedAt", serverTime]; _eventName = "task.started"; }; case "succeeded": { _lifecycle set ["finishedAt", serverTime]; _eventName = "task.completed"; }; case "failed": { _lifecycle set ["finishedAt", serverTime]; _eventName = "task.failed"; }; }; _lifecycleRegistry set [_taskID, _lifecycle]; _self set ["taskLifecycleRegistry", _lifecycleRegistry]; if (_eventName isNotEqualTo "") then { _self call ["emitTaskLifecycleEvent", [_eventName, _taskID, _normalizedStatus, createHashMap]]; }; }; _statusResult }], ["getTaskStatus", compileFinal { params [["_taskID", "", [""]]]; if (_taskID isEqualTo "") exitWith { "" }; private _status = _self call ["callTaskState", ["task:status:get", [_taskID], ""]]; if !(_status isEqualType "") exitWith { "" }; _status }], ["clearTaskStatus", compileFinal { params [["_taskID", "", [""]]]; if (_taskID isEqualTo "") exitWith { false }; [(_self call ["callTaskState", ["task:status:clear", [_taskID], false]])] params [["_statusResult", false, [false]]]; _statusResult }], ["registerTaskEntity", compileFinal { params [["_registryKey", "", [""]], ["_taskID", "", [""]], ["_entity", objNull, [objNull]]]; if (_registryKey isEqualTo "" || { _taskID isEqualTo "" } || { isNull _entity }) exitWith { false }; private _taskEntityRegistries = _self getOrDefault ["taskEntityRegistries", createHashMap]; private _registry = +(_taskEntityRegistries getOrDefault [_registryKey, createHashMap]); private _entities = +(_registry getOrDefault [_taskID, []]); _entities pushBackUnique _entity; _registry set [_taskID, _entities]; _taskEntityRegistries set [_registryKey, _registry]; _self set ["taskEntityRegistries", _taskEntityRegistries]; true }], ["getTaskEntities", compileFinal { params [["_registryKey", "", [""]], ["_taskID", "", [""]]]; if (_registryKey isEqualTo "" || { _taskID isEqualTo "" }) exitWith { [] }; private _taskEntityRegistries = _self getOrDefault ["taskEntityRegistries", createHashMap]; private _registry = _taskEntityRegistries getOrDefault [_registryKey, createHashMap]; +(_registry getOrDefault [_taskID, []]) }], ["findTaskEntityOwner", compileFinal { params [["_registryKey", "", [""]], ["_entity", objNull, [objNull]]]; if (_registryKey isEqualTo "" || { isNull _entity }) exitWith { "" }; private _taskEntityRegistries = _self getOrDefault ["taskEntityRegistries", createHashMap]; private _registry = _taskEntityRegistries getOrDefault [_registryKey, createHashMap]; private _resolvedTaskID = ""; { private _taskID = _x; private _entities = _y; if (_entity in _entities) exitWith { _resolvedTaskID = _taskID; }; private _matchingEntity = _entities select { !isNull _x && { (typeOf _x) isEqualTo (typeOf _entity) } && { _x distance _entity < 1 } }; if (_matchingEntity isNotEqualTo []) exitWith { _resolvedTaskID = _taskID; }; } forEach _registry; _resolvedTaskID }], ["clearTaskEntities", compileFinal { params [["_taskID", "", [""]]]; if (_taskID isEqualTo "") exitWith { false }; private _taskEntityRegistries = _self getOrDefault ["taskEntityRegistries", createHashMap]; { private _registry = +_y; _registry deleteAt _taskID; _taskEntityRegistries set [_x, _registry]; } forEach _taskEntityRegistries; _self set ["taskEntityRegistries", _taskEntityRegistries]; true }], ["trackParticipants", compileFinal { params [["_taskID", "", [""]], ["_entities", [], [[]]], ["_marker", "", [""]], ["_radius", 300, [0]]]; if (_taskID isEqualTo "") exitWith { createHashMap }; private _participantRegistry = _self getOrDefault ["participantRegistry", createHashMap]; private _participantSnapshots = +(_participantRegistry getOrDefault [_taskID, createHashMap]); private _activePlayers = allPlayers select { alive _x && { side group _x isEqualTo west } }; if (_marker isNotEqualTo "" && { markerShape _marker in ["RECTANGLE", "ELLIPSE"] }) then { { private _uid = getPlayerUID _x; if (_uid isNotEqualTo "" && { _x inArea _marker }) then { if !(_uid in _participantSnapshots) then { _participantSnapshots set [_uid, createHashMapFromArray [ ["startRating", rating _x] ]]; }; }; } forEach _activePlayers; }; if (_radius > 0 && { _entities isNotEqualTo [] }) then { { private _entity = _x; if (isNull _entity) then { continue; }; { private _uid = getPlayerUID _x; if (_uid isNotEqualTo "" && { (_x distance2D _entity) <= _radius }) then { if !(_uid in _participantSnapshots) then { _participantSnapshots set [_uid, createHashMapFromArray [ ["startRating", rating _x] ]]; }; }; } forEach _activePlayers; } forEach _entities; }; _participantRegistry set [_taskID, _participantSnapshots]; _self set ["participantRegistry", _participantRegistry]; _participantSnapshots }], ["getTaskParticipants", compileFinal { params [["_taskID", "", [""]]]; if (_taskID isEqualTo "") exitWith { createHashMap }; private _participantRegistry = _self getOrDefault ["participantRegistry", createHashMap]; +(_participantRegistry getOrDefault [_taskID, createHashMap]) }], ["getTaskParticipantUids", compileFinal { params [["_taskID", "", [""]]]; if (_taskID isEqualTo "") exitWith { [] }; keys (_self call ["getTaskParticipants", [_taskID]]) }], ["resolveRewardContext", compileFinal { params [["_taskID", "", [""]]]; private _result = createHashMapFromArray [ ["requesterUid", ""], ["orgID", ""], ["memberUids", []] ]; if (_taskID isEqualTo "") exitWith { _result }; private _rewardState = _self call ["callTaskState", ["task:ownership:reward_context", [_taskID], createHashMap]]; if (_rewardState isEqualTo createHashMap) exitWith { _result }; private _requesterUid = _rewardState getOrDefault ["requesterUid", ""]; private _resolvedOrgID = _rewardState getOrDefault ["orgId", ""]; if (_resolvedOrgID isEqualTo "") exitWith { _result }; private _org = EGVAR(org,OrgStore) call ["loadById", [_resolvedOrgID]]; private _memberUids = []; if (_org isNotEqualTo createHashMap) then { private _members = _org getOrDefault ["members", createHashMap]; if (_members isEqualType createHashMap) then { _memberUids = keys _members; }; if (_requesterUid isNotEqualTo "" && { !(_requesterUid in _memberUids) }) then { _memberUids pushBack _requesterUid; }; }; _result set ["requesterUid", _requesterUid]; _result set ["orgID", _resolvedOrgID]; _result set ["memberUids", _memberUids]; _result }], ["incrementDefuseCount", compileFinal { params [["_taskID", "", [""]]]; if (_taskID isEqualTo "") exitWith { 0 }; ["task:defuse:increment", [_taskID]] call EFUNC(extension,extCall) params ["_result", "_isSuccess"]; if !_isSuccess exitWith { 0 }; if !(_result isEqualType "") exitWith { 0 }; if ((_result find "Error:") == 0) exitWith { ["ERROR", format ["Task extension call 'task:defuse:increment' failed: %1", _result]] call EFUNC(common,log); 0 }; parseNumber _result }], ["getDefuseCount", compileFinal { params [["_taskID", "", [""]]]; if (_taskID isEqualTo "") exitWith { 0 }; ["task:defuse:get", [_taskID]] call EFUNC(extension,extCall) params ["_result", "_isSuccess"]; if !_isSuccess exitWith { 0 }; if !(_result isEqualType "") exitWith { 0 }; if ((_result find "Error:") == 0) exitWith { ["ERROR", format ["Task extension call 'task:defuse:get' failed: %1", _result]] call EFUNC(common,log); 0 }; parseNumber _result }], ["notifyParticipants", compileFinal { params [ ["_taskID", "", [""]], ["_type", "info", [""]], ["_title", "Tasks", [""]], ["_message", "", [""]] ]; if (_taskID isEqualTo "" || { _message isEqualTo "" }) exitWith { false }; private _participantRegistry = _self getOrDefault ["participantRegistry", createHashMap]; private _participantSnapshots = +(_participantRegistry getOrDefault [_taskID, createHashMap]); if (_participantSnapshots isEqualTo createHashMap) exitWith { false }; private _participantUids = keys _participantSnapshots; if (_participantUids isEqualTo []) exitWith { false }; if (isNil QEGVAR(common,EventBus)) exitWith { { private _player = [_x] call EFUNC(common,getPlayer); if (isNull _player) then { continue; }; [CRPC(notifications,recieveNotification), [_type, _title, _message], _player] call CFUNC(targetEvent); } forEach _participantUids; true }; EGVAR(common,EventBus) call ["emit", [ "task.notification.requested", createHashMapFromArray [ ["taskID", _taskID], ["notificationType", _type], ["title", _title], ["message", _message], ["participantUids", _participantUids] ], createHashMapFromArray [["source", "task"]] ]]; true }], ["clearTask", compileFinal { params [["_taskID", "", [""]]]; if (_taskID isEqualTo "") exitWith { false }; _self call ["emitTaskLifecycleEvent", ["task.cleared", _taskID, "cleared", createHashMap]]; private _participantRegistry = _self getOrDefault ["participantRegistry", createHashMap]; _participantRegistry deleteAt _taskID; _self set ["participantRegistry", _participantRegistry]; private _lifecycleRegistry = _self getOrDefault ["taskLifecycleRegistry", createHashMap]; _lifecycleRegistry deleteAt _taskID; _self set ["taskLifecycleRegistry", _lifecycleRegistry]; _self call ["callTaskState", ["task:clear", [_taskID], false]]; _self call ["clearTaskEntities", [_taskID]]; true }], ["applyRatingOutcome", compileFinal { params [["_taskID", "", [""]], ["_delta", 0, [0]]]; private _emitRatingEvent = { params [["_eventName", "", [""]], ["_payload", createHashMap, [createHashMap]]]; if (_eventName isEqualTo "" || { isNil QEGVAR(common,EventBus) }) exitWith { createHashMap }; private _eventPayload = +_payload; _eventPayload set ["taskID", _taskID]; _eventPayload set ["ratingDelta", _delta]; EGVAR(common,EventBus) call ["emit", [ _eventName, _eventPayload, createHashMapFromArray [["source", "task"]] ]] }; private _result = createHashMapFromArray [ ["participantUids", []], ["orgIds", []], ["contributions", createHashMap], ["success", true], ["mutationFailures", []], ["persistenceFailures", []], ["message", ""] ]; if (_taskID isEqualTo "" || { _delta isEqualTo 0 }) exitWith { _result }; private _participantRegistry = _self getOrDefault ["participantRegistry", createHashMap]; private _participantSnapshots = +(_participantRegistry getOrDefault [_taskID, createHashMap]); if (_participantSnapshots isEqualTo createHashMap) exitWith { _result }; private _rewardContext = _self call ["resolveRewardContext", [_taskID]]; private _participantUids = keys _participantSnapshots; if (_participantUids isEqualTo [] && { _delta > 0 }) then { private _requesterUid = _rewardContext getOrDefault ["requesterUid", ""]; if (_requesterUid isNotEqualTo "") then { private _requesterPlayer = [_requesterUid] call EFUNC(common,getPlayer); if (!isNull _requesterPlayer) then { _participantUids pushBack _requesterUid; _participantSnapshots set [_requesterUid, createHashMapFromArray [ ["startRating", rating _requesterPlayer] ]]; _participantRegistry set [_taskID, _participantSnapshots]; _self set ["participantRegistry", _participantRegistry]; ["WARNING", format ["Task %1 had no tracked participants at payout time; falling back to requester %2 for personal earnings.", _taskID, _requesterUid]] call EFUNC(common,log); }; }; }; if (_participantUids isEqualTo []) exitWith { _result set ["success", false]; _result set ["message", "No task participants were available for rating outcome."]; ["task.rating.failed", createHashMapFromArray [ ["participantUids", []], ["orgIds", []], ["contributions", createHashMap], ["mutationFailures", []], ["persistenceFailures", []], ["message", _result get "message"] ]] call _emitRatingEvent; _result }; private _orgIds = []; private _contributions = createHashMap; private _totalContribution = 0; private _mutationFailures = []; private _persistenceFailures = []; if (_delta > 0) then { { private _uid = _x; private _player = [_uid] call EFUNC(common,getPlayer); if (isNull _player) then { continue; }; _contributions set [_uid, 1]; _totalContribution = _totalContribution + 1; } forEach _participantUids; }; if (_totalContribution <= 0) exitWith { _result set ["success", false]; _result set ["message", "No eligible participant contribution was available for rating outcome."]; ["task.rating.failed", createHashMapFromArray [ ["participantUids", +_participantUids], ["orgIds", +_orgIds], ["contributions", +_contributions], ["mutationFailures", []], ["persistenceFailures", []], ["message", _result get "message"] ]] call _emitRatingEvent; _self call ["clearTask", [_taskID]]; _result }; { private _uid = _x; private _orgID = EGVAR(actor,ActorStore) call ["getOrganization", [_uid, ""]]; if (_orgID isNotEqualTo "") then { _orgIds pushBackUnique _orgID; }; if (_delta > 0) then { private _contribution = _contributions getOrDefault [_uid, 0]; if (_contribution <= 0) then { continue; }; private _account = EGVAR(bank,BankStore) call ["get", [_uid, ""]]; if (_account isEqualTo createHashMap) then { _account = EGVAR(bank,BankStore) call ["init", [_uid]]; }; if (_account isNotEqualTo createHashMap) then { private _earnings = _account getOrDefault ["earnings", 0]; private _earningsDelta = round ((_delta * _contribution) / _totalContribution); if (_earningsDelta <= 0) then { continue; }; private _patch = EGVAR(bank,BankStore) call [ "mset", [ _uid, createHashMapFromArray [["earnings", (_earnings + _earningsDelta)]], false ] ]; if !(_patch isEqualType createHashMap) then { continue; }; if (_patch isEqualTo createHashMap) then { continue; }; if (isNil QEGVAR(common,EventBus)) then { EGVAR(bank,BankMessenger) call ["sendAccountSync", [_uid, _patch]]; } else { EGVAR(common,EventBus) call ["emit", [ "bank.account.sync.requested", createHashMapFromArray [ ["uid", _uid], ["account", +_patch] ], createHashMapFromArray [["source", "task"]] ]]; }; if ((EGVAR(bank,BankStore) call ["save", [_uid]]) isEqualTo createHashMap) then { _persistenceFailures pushBackUnique format ["bank:%1", _uid]; ["ERROR", format ["Task %1 updated bank earnings for %2, but durable save failed.", _taskID, _uid]] call EFUNC(common,log); }; }; }; } forEach _participantUids; private _ownerOrgID = _rewardContext getOrDefault ["orgID", ""]; if (_ownerOrgID isNotEqualTo "") then { private _org = EGVAR(org,OrgStore) call ["loadById", [_ownerOrgID]]; if (_org isNotEqualTo createHashMap) then { private _reputation = _org getOrDefault ["reputation", 0]; private _nextReputation = round (_reputation + _delta); _org set ["reputation", _nextReputation]; private _updatedOrg = EGVAR(org,OrgStore) call [ "callHotOrg", [ "org:hot:override", [_ownerOrgID, toJSON _org] ] ]; if (_updatedOrg isNotEqualTo createHashMap) then { private _patch = createHashMapFromArray [["reputation", _nextReputation]]; private _memberUids = _rewardContext getOrDefault ["memberUids", []]; if (isNil QEGVAR(common,EventBus)) then { { private _player = [_x] call EFUNC(common,getPlayer); if (isNull _player) then { continue; }; [CRPC(org,responseSyncOrg), [_patch], _player] call CFUNC(targetEvent); } forEach _memberUids; } else { EGVAR(common,EventBus) call ["emit", [ "org.sync.requested", createHashMapFromArray [ ["orgID", _ownerOrgID], ["memberUids", +_memberUids], ["patch", +_patch] ], createHashMapFromArray [["source", "task"]] ]]; }; _orgIds = [_ownerOrgID]; if ((EGVAR(org,OrgStore) call ["saveById", [_ownerOrgID]]) isEqualTo createHashMap) then { _persistenceFailures pushBackUnique format ["organization:%1", _ownerOrgID]; ["ERROR", format ["Task %1 updated reputation for organization %2, but durable save failed.", _taskID, _ownerOrgID]] call EFUNC(common,log); }; } else { ["ERROR", format ["Failed to update organization %1 reputation for task %2.", _ownerOrgID, _taskID]] call EFUNC(common,log); _mutationFailures pushBackUnique format ["organization:%1", _ownerOrgID]; }; }; }; _result set ["participantUids", _participantUids]; _result set ["orgIds", _orgIds]; _result set ["contributions", _contributions]; _result set ["success", (_mutationFailures isEqualTo []) && { _persistenceFailures isEqualTo [] }]; _result set ["mutationFailures", _mutationFailures]; _result set ["persistenceFailures", _persistenceFailures]; if (_mutationFailures isNotEqualTo [] || { _persistenceFailures isNotEqualTo [] }) then { private _messageParts = []; if (_mutationFailures isNotEqualTo []) then { _messageParts pushBack format ["mutation failures: %1", _mutationFailures joinString ", "]; }; if (_persistenceFailures isNotEqualTo []) then { _messageParts pushBack format ["persistence failures: %1", _persistenceFailures joinString ", "]; }; _result set ["message", _messageParts joinString "; "]; }; private _eventName = ["task.rating.failed", "task.rating.applied"] select (_result getOrDefault ["success", false]); [_eventName, createHashMapFromArray [ ["participantUids", +(_result getOrDefault ["participantUids", []])], ["orgIds", +(_result getOrDefault ["orgIds", []])], ["contributions", +(_result getOrDefault ["contributions", createHashMap])], ["mutationFailures", +(_result getOrDefault ["mutationFailures", []])], ["persistenceFailures", +(_result getOrDefault ["persistenceFailures", []])], ["message", _result getOrDefault ["message", ""]] ]] call _emitRatingEvent; _result }] ]]; GVAR(TaskStore)