Refactor code structure for improved readability and maintainability

This commit is contained in:
Jacob Schmidt 2026-04-25 23:59:38 -05:00
parent 63cde7eddb
commit d7018742b5
19 changed files with 4832 additions and 34 deletions

View File

@ -150,7 +150,7 @@ GVAR(GarageActionServiceBaseClass) = compileFinal createHashMapFromArray [
private _hitPointsJson = toJSON (createHashMapFromArray [["names", _rawHitPoints param [0, []]], ["selections", _rawHitPoints param [1, []]], ["values", _rawHitPoints param [2, []]]]);
_self set ["pendingStoreVehicle", _vehicle];
[SRPC(garage,requestStoreVehicle), [getPlayerUID player, typeOf _vehicle, fuel _vehicle, damage _vehicle, _hitPointsJson]] call CFUNC(serverEvent);
[SRPC(garage,requestStoreVehicle), [getPlayerUID player, netId _vehicle, typeOf _vehicle, fuel _vehicle, damage _vehicle, _hitPointsJson]] call CFUNC(serverEvent);
}],
["handleRefuelRequest", compileFinal {
params [["_data", createHashMap, [createHashMap]]];

View File

@ -50,6 +50,12 @@ if (isNil QGVAR(OrgUIBridge)) then { call FUNC(initUIBridge); };
GVAR(OrgUIBridge) call ["handleCreditLineResponse", [_payload]];
}] call CFUNC(addEventHandler);
[QGVAR(responseTreasuryAction), {
params [["_payload", createHashMap, [createHashMap]]];
GVAR(OrgUIBridge) call ["handleTreasuryResponse", [_payload]];
}] call CFUNC(addEventHandler);
[QGVAR(responseInviteOrg), {
params [["_payload", createHashMap, [createHashMap]]];

View File

@ -46,6 +46,12 @@ switch (_event) do {
case "org::credit::request": {
GVAR(OrgUIBridge) call ["requestCreditLine", [_data]];
};
case "org::payroll::request": {
GVAR(OrgUIBridge) call ["requestPayroll", [_data]];
};
case "org::transfer::request": {
GVAR(OrgUIBridge) call ["requestTransferFunds", [_data]];
};
case "org::invite::request": {
GVAR(OrgUIBridge) call ["requestInvite", [_data]];
};

View File

@ -161,6 +161,16 @@ GVAR(OrgUIBridgeBaseClass) = compileFinal createHashMapFromArray [
};
};
}],
["handleTreasuryResponse", compileFinal {
params [["_payload", createHashMap, [createHashMap]]];
private _eventName = [
"org::treasury::failure",
"org::treasury::success"
] select (_payload getOrDefault ["success", false]);
_self call ["sendEvent", [_eventName, _payload]];
}],
["handleInviteResponse", compileFinal {
params [["_payload", createHashMap, [createHashMap]]];
@ -196,6 +206,20 @@ GVAR(OrgUIBridgeBaseClass) = compileFinal createHashMapFromArray [
[SRPC(org,requestAssignCreditLine), [getPlayerUID player, _memberUid, _memberName, _amount]] call CFUNC(serverEvent);
}],
["requestPayroll", compileFinal {
params [["_data", createHashMap, [createHashMap]]];
private _amount = _data getOrDefault ["amount", 0];
[SRPC(org,requestPayroll), [getPlayerUID player, _amount]] call CFUNC(serverEvent);
}],
["requestTransferFunds", compileFinal {
params [["_data", createHashMap, [createHashMap]]];
private _memberUid = _data getOrDefault ["memberUid", ""];
private _memberName = _data getOrDefault ["memberName", ""];
private _amount = _data getOrDefault ["amount", 0];
[SRPC(org,requestTreasuryTransfer), [getPlayerUID player, _memberUid, _memberName, _amount]] call CFUNC(serverEvent);
}],
["requestInvite", compileFinal {
params [["_data", createHashMap, [createHashMap]]];

File diff suppressed because one or more lines are too long

View File

@ -80,6 +80,40 @@
return false;
}
function requestPayroll(payload) {
const sent = sendEvent("org::payroll::request", payload);
if (sent) {
return true;
}
const OrgPortal = window.OrgPortal;
if (OrgPortal && OrgPortal.actions) {
OrgPortal.actions.showTreasuryNotice(
"error",
"Arma payroll bridge is unavailable.",
);
}
return false;
}
function requestTreasuryTransfer(payload) {
const sent = sendEvent("org::transfer::request", payload);
if (sent) {
return true;
}
const OrgPortal = window.OrgPortal;
if (OrgPortal && OrgPortal.actions) {
OrgPortal.actions.showTreasuryNotice(
"error",
"Arma treasury transfer bridge is unavailable.",
);
}
return false;
}
function requestInvitePlayer(payload) {
const sent = sendEvent("org::invite::request", payload);
if (sent) {
@ -179,6 +213,30 @@
}
});
bridge.on("org::treasury::success", (payloadData) => {
const OrgPortal = window.OrgPortal;
if (OrgPortal && OrgPortal.store) {
OrgPortal.store.setModal(null);
}
if (OrgPortal && OrgPortal.actions) {
OrgPortal.actions.showTreasuryNotice(
"success",
payloadData.message || "Treasury action completed.",
);
}
});
bridge.on("org::treasury::failure", (payloadData) => {
const OrgPortal = window.OrgPortal;
if (OrgPortal && OrgPortal.actions) {
OrgPortal.actions.showTreasuryNotice(
"error",
payloadData.message || "Treasury action failed.",
);
}
});
bridge.on("org::invite::success", (payloadData) => {
const OrgPortal = window.OrgPortal;
if (OrgPortal && OrgPortal.store) {
@ -329,6 +387,8 @@
requestDisbandOrg,
requestLeaveOrg,
requestCreditLine,
requestPayroll,
requestTreasuryTransfer,
requestInvitePlayer,
requestAcceptInvite,
requestDeclineInvite,

View File

@ -91,7 +91,7 @@
...memberSelectProps,
},
...members.map((member) =>
h("option", { value: member.name }, member.name),
h("option", { value: member.uid }, member.name),
),
),
),

View File

@ -203,15 +203,24 @@
return false;
}
store.setFunds(funds - total);
this.showTreasuryNotice(
"success",
`Payroll sent to ${members.length} members for ${getters.formatCurrency(total)}.`,
);
return true;
const bridge = window.RegistryApp
? window.RegistryApp.bridge
: null;
if (!bridge || typeof bridge.requestPayroll !== "function") {
this.showTreasuryNotice(
"error",
"Payroll bridge is unavailable.",
);
return false;
}
return bridge.requestPayroll({
amount: amountPerMember,
});
}
sendFundsToMember(memberName, amount) {
sendFundsToMember(memberUid, amount) {
if (!getters.canManageTreasury()) {
this.showTreasuryNotice(
"error",
@ -222,7 +231,7 @@
const funds = store.getFunds();
if (!memberName) {
if (!memberUid) {
this.showTreasuryNotice(
"error",
"Select a member to receive funds.",
@ -246,12 +255,38 @@
return false;
}
store.setFunds(funds - amount);
this.showTreasuryNotice(
"success",
`${getters.formatCurrency(amount)} sent to ${memberName}.`,
);
return true;
const member = store
.getMembers()
.find((entry) => getters.getMemberUid(entry) === memberUid);
const memberName = member ? getters.getMemberName(member) : "";
if (!memberName) {
this.showTreasuryNotice(
"error",
"Selected member was not found in the organization roster.",
);
return false;
}
const bridge = window.RegistryApp
? window.RegistryApp.bridge
: null;
if (
!bridge ||
typeof bridge.requestTreasuryTransfer !== "function"
) {
this.showTreasuryNotice(
"error",
"Treasury transfer bridge is unavailable.",
);
return false;
}
return bridge.requestTreasuryTransfer({
memberUid,
memberName,
amount,
});
}
grantCreditLine(memberUid, amount) {

View File

@ -27,6 +27,7 @@ PREP_RECOMPILE_END;
[QGVAR(requestStoreVehicle), {
params [
["_uid", "", [""]],
["_netId", "", [""]],
["_className", "", [""]],
["_fuel", 0, [0]],
["_damage", 0, [0]],
@ -34,7 +35,7 @@ PREP_RECOMPILE_END;
];
private _player = [_uid] call EFUNC(common,getPlayer);
if (_uid isEqualTo "" || { _className isEqualTo "" } || { _hitPointsJson isEqualTo "" }) exitWith {
if (_uid isEqualTo "" || { _netId isEqualTo "" } || { _className isEqualTo "" } || { _hitPointsJson isEqualTo "" }) exitWith {
[CRPC(garage,responseGarageAction), [createHashMapFromArray [
["action", "store"],
["success", false],
@ -50,14 +51,21 @@ PREP_RECOMPILE_END;
]);
private _garage = GVAR(GarageStore) call ["storeVehicle", [_uid, _payloadJson]];
if (_garage isEqualTo createHashMap) exitWith {
if !(GVAR(GarageStore) call ["didLastCallSucceed", []]) exitWith {
private _message = GVAR(GarageStore) call ["getLastError", []];
if (_message isEqualTo "") then { _message = "Failed to store vehicle."; };
[CRPC(garage,responseGarageAction), [createHashMapFromArray [
["action", "store"],
["success", false],
["message", "Failed to store vehicle."]
["message", _message]
]], _player] call CFUNC(targetEvent);
};
private _vehicle = objectFromNetId _netId;
if !(isNull _vehicle) then {
deleteVehicle _vehicle;
};
[CRPC(garage,responseSyncGarage), [_garage], _player] call CFUNC(targetEvent);
[CRPC(garage,responseGarageAction), [createHashMapFromArray [
["action", "store"],
@ -80,11 +88,13 @@ PREP_RECOMPILE_END;
private _payloadJson = toJSON (createHashMapFromArray [["plate", _plate]]);
private _garage = GVAR(GarageStore) call ["retrieveVehicle", [_uid, _payloadJson]];
if (_garage isEqualTo createHashMap) exitWith {
if !(GVAR(GarageStore) call ["didLastCallSucceed", []]) exitWith {
private _message = GVAR(GarageStore) call ["getLastError", []];
if (_message isEqualTo "") then { _message = "Failed to retrieve vehicle."; };
[CRPC(garage,responseGarageAction), [createHashMapFromArray [
["action", "retrieve"],
["success", false],
["message", "Failed to retrieve vehicle."]
["message", _message]
]], _player] call CFUNC(targetEvent);
};

View File

@ -27,24 +27,50 @@ GVAR(GarageBaseStore) = compileFinal createHashMapFromArray [
["#type", "GarageBaseStore"],
["#create", compileFinal {
["INFO", "Garage Store Initialized!"] call EFUNC(common,log);
_self set ["lastCallSucceeded", false];
_self set ["lastError", ""];
}],
["callHotGarage", compileFinal {
params [["_function", "", [""]], ["_arguments", [], [[]]]];
if (_function isEqualTo "") exitWith { createHashMap };
_self set ["lastCallSucceeded", false];
_self set ["lastError", ""];
if (_function isEqualTo "") exitWith {
_self set ["lastError", "Garage extension function was empty."];
createHashMap
};
[_function, _arguments] call EFUNC(extension,extCall) params ["_result", "_isSuccess"];
if !(_isSuccess) exitWith { createHashMap };
if !(_result isEqualType "") exitWith { createHashMap };
if !(_isSuccess) exitWith {
_self set ["lastError", format ["Garage extension call '%1' did not succeed.", _function]];
createHashMap
};
if !(_result isEqualType "") exitWith {
_self set ["lastError", format ["Garage extension call '%1' returned invalid data.", _function]];
createHashMap
};
if ((_result find "Error:") == 0) exitWith {
_self set ["lastError", _result];
["ERROR", format ["Garage extension call '%1' failed: %2", _function, _result]] call EFUNC(common,log);
createHashMap
};
private _data = fromJSON _result;
if !(_data isEqualType createHashMap) exitWith { createHashMap };
if !(_data isEqualType createHashMap) exitWith {
_self set ["lastError", format ["Garage extension call '%1' returned non-map JSON.", _function]];
createHashMap
};
_self set ["lastCallSucceeded", true];
_data
}],
["didLastCallSucceed", compileFinal {
_self getOrDefault ["lastCallSucceeded", false]
}],
["getLastError", compileFinal {
_self getOrDefault ["lastError", ""]
}],
["loadHotGarage", compileFinal {
params [["_uid", "", [""]], ["_initialize", false, [false]]];

View File

@ -1,3 +1,5 @@
PREP(initStores);
PREP(initValidationHarness);
PREP(playerGroup2Server);
PREP(redirectClient2Server);
PREP(saveHotState);

View File

@ -0,0 +1,10 @@
#include "..\script_component.hpp"
params [["_ip", "127.0.0.1", [""]], ["_port", "2312", [""]], ["_password", "abc", [""]]];
private _units = units group player select { isPlayer _x };
private _machineIDs = _units apply { owner _x };
{
[_ip, _port, _password] remoteExecCall ["forge_server_misc_fnc_redirectClient2Server", _x];
} forEach _machineIDs;

View File

@ -0,0 +1,73 @@
#include "..\script_component.hpp"
#include "\a3\ui_f\hpp\defineResincl.inc"
// Enable Client to Server Travel
if (isServer || !(isRemoteExecuted && remoteExecutedOwner isEqualTo 2)) exitWith { diag_log "Must be remote executed from dedicated server" };
params [["_IP", "127.0.0.1", [""]], ["_PORT", "2302", [""]], ["_PASS", "", [""]], ["_TIMEOUT", 30, [0]]];
_this resize 0;
onEachFrame format [
"
private _allDisplays = allDisplays select [
allDisplays find findDisplay %5,
count allDisplays
];
reverse _allDisplays;
{ _x closeDisplay %4 } forEach _allDisplays;
onEachFrame {
findDisplay %6 closeDisplay %4;
findDisplay %7 closeDisplay %4;
onEachFrame {
ctrlActivate (findDisplay %8 displayCtrl %9);
onEachFrame {
private _ctrlServerAddress = findDisplay %10 displayCtrl 2300;
_ctrlServerAddress controlsGroupCtrl %11 ctrlSetText ""%1"";
_ctrlServerAddress controlsGroupCtrl %12 ctrlSetText ""%2"";
ctrlActivate (_ctrlServerAddress controlsGroupCtrl %14);
onEachFrame {
findDisplay %8 displayCtrl %13 lbData 0 call {
if (diag_tickTime > %18) then {
diag_log ""RCTS Timeout (no server)"";
onEachFrame {};
};
if (_this isEqualTo ""%1:%2"") then {
findDisplay %8 displayCtrl %13 lbSetCurSel 0;
onEachFrame {
ctrlActivate (findDisplay %8 displayCtrl %15);
onEachFrame {
if (diag_tickTime > %18) then {
diag_log ""RCTS Timeout (cannot join)"";
onEachFrame {};
};
if (!isNull findDisplay %16) then {
private _ctrlPassword = findDisplay %16 displayCtrl %17;
_ctrlPassword ctrlSetTextColor [0,0,0,0];
_ctrlPassword ctrlSetText ""%3"";
ctrlActivate (findDisplay %16 displayCtrl %14);
};
if (getClientStateNumber >= 3) then {
diag_log ""RCTS Success"";
onEachFrame {};
};
};
};
};
};
};
};
};
};
", _IP, _PORT, _PASS, IDC_CANCEL, IDD_MISSION, IDD_DEBRIEFING, IDD_MP_SETUP, IDD_MULTIPLAYER,
IDC_MULTI_TAB_DIRECT_CONNECT, IDD_IP_ADDRESS, IDC_IP_ADDRESS, IDC_IP_PORT, IDC_MULTI_SESSIONS,
IDC_OK, IDC_MULTI_JOIN, IDD_PASSWORD, IDC_PASSWORD, diag_tickTime + _TIMEOUT];

View File

@ -85,6 +85,70 @@ PREP_RECOMPILE_END;
]], _requester] call CFUNC(targetEvent);
}] call CFUNC(addEventHandler);
[QGVAR(requestPayroll), {
params [
["_uid", "", [""]],
["_amount", 0, [0]]
];
if (_uid isEqualTo "" || { _amount <= 0 }) exitWith {
diag_log "[FORGE:Server:Org] Invalid payroll request payload!"
};
private _requester = [_uid] call EFUNC(common,getPlayer);
if (_requester isEqualTo objNull) exitWith {};
private _result = GVAR(OrgStore) call ["runPayroll", [_uid, _amount]];
if (_result getOrDefault ["success", false]) then {
{
private _memberPlayer = [_x] call EFUNC(common,getPlayer);
if (_memberPlayer isNotEqualTo objNull) then {
[CRPC(org,responseSyncOrg), [createHashMap], _memberPlayer] call CFUNC(targetEvent);
};
} forEach (_result getOrDefault ["memberUids", []]);
[CRPC(org,responseSyncOrg), [createHashMap], _requester] call CFUNC(targetEvent);
};
[CRPC(org,responseTreasuryAction), [createHashMapFromArray [
["success", _result getOrDefault ["success", false]],
["message", _result getOrDefault ["message", "Unable to run payroll."]]
]], _requester] call CFUNC(targetEvent);
}] call CFUNC(addEventHandler);
[QGVAR(requestTreasuryTransfer), {
params [
["_uid", "", [""]],
["_memberUid", "", [""]],
["_memberName", "", [""]],
["_amount", 0, [0]]
];
if (_uid isEqualTo "" || { _memberUid isEqualTo "" } || { _amount <= 0 }) exitWith {
diag_log "[FORGE:Server:Org] Invalid treasury transfer request payload!"
};
private _requester = [_uid] call EFUNC(common,getPlayer);
if (_requester isEqualTo objNull) exitWith {};
private _result = GVAR(OrgStore) call ["transferFunds", [_uid, _memberUid, _memberName, _amount]];
if (_result getOrDefault ["success", false]) then {
{
private _memberPlayer = [_x] call EFUNC(common,getPlayer);
if (_memberPlayer isNotEqualTo objNull) then {
[CRPC(org,responseSyncOrg), [createHashMap], _memberPlayer] call CFUNC(targetEvent);
};
} forEach (_result getOrDefault ["memberUids", []]);
[CRPC(org,responseSyncOrg), [createHashMap], _requester] call CFUNC(targetEvent);
};
[CRPC(org,responseTreasuryAction), [createHashMapFromArray [
["success", _result getOrDefault ["success", false]],
["message", _result getOrDefault ["message", "Unable to send funds."]]
]], _requester] call CFUNC(targetEvent);
}] call CFUNC(addEventHandler);
[QGVAR(requestInviteOrgMember), {
params [["_uid", "", [""]], ["_targetUid", "", [""]], ["_targetName", "", [""]]];

View File

@ -734,6 +734,194 @@ GVAR(OrgBaseStore) = compileFinal createHashMapFromArray [
_result set ["memberUids", _envelope getOrDefault ["memberUids", []]];
_self call ["persistMutationResult", [_orgID, _result, "Credit line assignment"]]
}],
["creditMemberBank", compileFinal {
params [["_memberUid", "", [""]], ["_amount", 0, [0]], ["_message", "", [""]]];
if (_memberUid isEqualTo "" || { _amount <= 0 }) exitWith { false };
private _account = EGVAR(bank,BankStore) call ["get", [_memberUid, ""]];
if (_account isEqualTo createHashMap) then {
_account = EGVAR(bank,BankStore) call ["init", [_memberUid]];
};
if (_account isEqualTo createHashMap) exitWith { false };
private _currentBank = _account getOrDefault ["bank", 0];
private _patch = EGVAR(bank,BankStore) call ["mset", [_memberUid, createHashMapFromArray [["bank", _currentBank + _amount]], true]];
if (_patch isEqualTo createHashMap) exitWith { false };
EGVAR(bank,BankMessenger) call ["sendAccountSync", [_memberUid, _patch]];
if (_message isNotEqualTo "") then {
EGVAR(bank,BankMessenger) call ["sendNotification", [_memberUid, "info", "Treasury", _message]];
};
true
}],
["updateOrgTreasuryFunds", compileFinal {
params [["_orgID", "", [""]], ["_funds", 0, [0]]];
if (_orgID isEqualTo "") exitWith { createHashMap };
private _org = _self call ["loadById", [_orgID]];
if (_org isEqualTo createHashMap) exitWith { createHashMap };
private _nextOrg = +_org;
_nextOrg set ["funds", _funds];
private _updatedOrg = _self call ["callHotOrg", ["org:hot:override", [_orgID, toJSON _nextOrg]]];
if (_updatedOrg isEqualTo createHashMap) exitWith { createHashMap };
_self call ["saveById", [_orgID]]
}],
["runPayroll", compileFinal {
params [["_requesterUid", "", [""]], ["_amountPerMember", 0, [0]]];
private _result = createHashMapFromArray [
["success", false],
["message", ""],
["memberUids", []]
];
if (_requesterUid isEqualTo "" || { _amountPerMember <= 0 }) exitWith {
_result set ["message", "A valid payroll amount is required."];
_result
};
private _orgID = EGVAR(actor,ActorStore) call ["getOrganization", [_requesterUid]];
private _requesterPlayer = [_requesterUid] call EFUNC(common,getPlayer);
private _requesterIsDefaultOrgCeo = (
_requesterPlayer isNotEqualTo objNull
&& { _orgID isEqualTo "default" }
&& { toLowerANSI (vehicleVarName _requesterPlayer) isEqualTo "ceo" }
);
private _org = _self call ["loadById", [_orgID]];
if (_org isEqualTo createHashMap) exitWith {
_result set ["message", "Organization data could not be loaded."];
_result
};
private _ownerUid = _org getOrDefault ["owner", ""];
private _canManageTreasury = (
_requesterUid isEqualTo _ownerUid
|| { _orgID isEqualTo "default" && { _requesterIsDefaultOrgCeo } }
);
if !(_canManageTreasury) exitWith {
_result set ["message", "Only the organization leader or CEO can manage treasury actions."];
_result
};
private _membersRaw = _org getOrDefault ["members", createHashMap];
private _memberUids = [];
{
private _memberUid = _y getOrDefault ["uid", ""];
if (_memberUid isNotEqualTo "") then {
_memberUids pushBackUnique _memberUid;
};
} forEach _membersRaw;
if (_memberUids isEqualTo []) exitWith {
_result set ["message", "No members available for payroll."];
_result
};
private _total = _amountPerMember * count _memberUids;
private _funds = _org getOrDefault ["funds", 0];
if (_total > _funds) exitWith {
_result set ["message", "Insufficient org funds for payroll."];
_result
};
{
private _memberData = _membersRaw getOrDefault [_x, createHashMap];
private _memberName = _memberData getOrDefault ["name", "a member"];
private _ok = _self call ["creditMemberBank", [_x, _amountPerMember, format ["Received payroll of $%1 from %2.", [_amountPerMember] call EFUNC(common,formatNumber), _org getOrDefault ["name", "the organization"]]]];
if !(_ok) exitWith {
_result set ["message", format ["Failed to credit payroll for %1.", _memberName]];
_result set ["success", false];
};
} forEach _memberUids;
if (_result getOrDefault ["message", ""] isNotEqualTo "") exitWith { _result };
private _savedOrg = _self call ["updateOrgTreasuryFunds", [_orgID, _funds - _total]];
if (_savedOrg isEqualTo createHashMap) exitWith {
_result set ["message", "Payroll was credited, but organization funds could not be updated."];
_result
};
_result set ["success", true];
_result set ["message", format ["Payroll sent to %1 members for $%2.", count _memberUids, [_total] call EFUNC(common,formatNumber)]];
_result set ["memberUids", _memberUids];
_result
}],
["transferFunds", compileFinal {
params [["_requesterUid", "", [""]], ["_memberUid", "", [""]], ["_memberName", "", [""]], ["_amount", 0, [0]]];
private _result = createHashMapFromArray [
["success", false],
["message", ""],
["memberUids", []]
];
if (_requesterUid isEqualTo "" || { _memberUid isEqualTo "" } || { _amount <= 0 }) exitWith {
_result set ["message", "A valid member and transfer amount are required."];
_result
};
private _orgID = EGVAR(actor,ActorStore) call ["getOrganization", [_requesterUid]];
private _requesterPlayer = [_requesterUid] call EFUNC(common,getPlayer);
private _requesterIsDefaultOrgCeo = (
_requesterPlayer isNotEqualTo objNull
&& { _orgID isEqualTo "default" }
&& { toLowerANSI (vehicleVarName _requesterPlayer) isEqualTo "ceo" }
);
private _org = _self call ["loadById", [_orgID]];
if (_org isEqualTo createHashMap) exitWith {
_result set ["message", "Organization data could not be loaded."];
_result
};
private _ownerUid = _org getOrDefault ["owner", ""];
private _canManageTreasury = (
_requesterUid isEqualTo _ownerUid
|| { _orgID isEqualTo "default" && { _requesterIsDefaultOrgCeo } }
);
if !(_canManageTreasury) exitWith {
_result set ["message", "Only the organization leader or CEO can manage treasury actions."];
_result
};
private _membersRaw = _org getOrDefault ["members", createHashMap];
private _memberData = _membersRaw getOrDefault [_memberUid, createHashMap];
if (_memberData isEqualTo createHashMap) exitWith {
_result set ["message", "Selected member was not found in the organization roster."];
_result
};
private _funds = _org getOrDefault ["funds", 0];
if (_amount > _funds) exitWith {
_result set ["message", "Insufficient org funds for this transfer."];
_result
};
private _resolvedMemberName = _memberData getOrDefault ["name", _memberName];
private _ok = _self call ["creditMemberBank", [_memberUid, _amount, format ["Received treasury transfer of $%1 from %2.", [_amount] call EFUNC(common,formatNumber), _org getOrDefault ["name", "the organization"]]]];
if !(_ok) exitWith {
_result set ["message", format ["Failed to transfer funds to %1.", _resolvedMemberName]];
_result
};
private _savedOrg = _self call ["updateOrgTreasuryFunds", [_orgID, _funds - _amount]];
if (_savedOrg isEqualTo createHashMap) exitWith {
_result set ["message", "Transfer was credited, but organization funds could not be updated."];
_result
};
_result set ["success", true];
_result set ["message", format ["$%1 sent to %2.", [_amount] call EFUNC(common,formatNumber), _resolvedMemberName]];
_result set ["memberUids", [_memberUid]];
_result
}],
["repayCreditLine", compileFinal {
params [["_requesterUid", "", [""]], ["_amount", 0, [0]]];

View File

@ -161,8 +161,19 @@ pub(crate) fn add_hot_vehicle(call_context: CallContext, key: String, json_data:
None => return "Error: Missing hit_points".to_string(),
};
match HOT_GARAGE_SERVICE.add_vehicle(resolved_uid, classname, fuel, damage, hit_points_json) {
Ok(garage) => serialize_hot_vehicles(garage),
match HOT_GARAGE_SERVICE.add_vehicle(
resolved_uid.clone(),
classname,
fuel,
damage,
hit_points_json,
) {
Ok(garage) => {
enqueue_persistence_task("garage", move || {
HOT_GARAGE_SERVICE.save_garage(resolved_uid).map(|_| ())
});
serialize_hot_vehicles(garage)
}
Err(error) => format!("Error: {}", error),
}
}
@ -187,8 +198,13 @@ pub(crate) fn remove_hot_vehicle(
None => return "Error: Missing or invalid plate".to_string(),
};
match HOT_GARAGE_SERVICE.remove_vehicle(resolved_uid, plate) {
Ok(garage) => serialize_hot_vehicles(garage),
match HOT_GARAGE_SERVICE.remove_vehicle(resolved_uid.clone(), plate) {
Ok(garage) => {
enqueue_persistence_task("garage", move || {
HOT_GARAGE_SERVICE.save_garage(resolved_uid).map(|_| ())
});
serialize_hot_vehicles(garage)
}
Err(error) => format!("Error: {}", error),
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -241,15 +241,44 @@ impl<R: GarageRepository, H: GarageHotRepository> GarageHotStateService<R, H> {
damage: f64,
hit_points_json: String,
) -> Result<Garage, String> {
let garage =
self.service
.add_vehicle(uid.clone(), classname, fuel, damage, hit_points_json)?;
let mut garage = match self.repository.get(&uid)? {
Some(garage) => garage,
None => match self.service.get_garage(uid.clone()) {
Ok(garage) => garage,
Err(_) => Garage::new().map_err(|e| format!("Failed to create garage: {}", e))?,
},
};
if garage.vehicles.len() >= 5 {
return Err("Garage is full. Maximum of 5 vehicles allowed.".to_string());
}
let plate = Uuid::new_v4().to_string();
let hit_points = HitPoints::from_json_str(&hit_points_json)?;
let new_vehicle = Vehicle::new(plate, classname, fuel, damage, hit_points)
.map_err(|e| format!("Validation failed: {}", e))?;
garage
.add_vehicle(new_vehicle)
.map_err(|e| format!("Failed to add vehicle: {}", e))?;
self.repository.save(&garage, &uid)?;
Ok(garage)
}
pub fn remove_vehicle(&self, uid: String, plate: String) -> Result<Garage, String> {
let garage = self.service.remove_vehicle(uid.clone(), plate)?;
let mut garage = match self.repository.get(&uid)? {
Some(garage) => garage,
None => self
.service
.get_garage(uid.clone())
.map_err(|_| format!("No garage found for player '{}'", uid))?,
};
garage
.remove_vehicle(&plate)
.ok_or_else(|| format!("Vehicle with plate '{}' not found in garage", plate))?;
self.repository.save(&garage, &uid)?;
Ok(garage)
}