Enable vehicle checkout grants and garage/org sync updates

- Wire store checkout to grant purchased vehicles via virtual garage
- Add org fleet updates for org-funded vehicle purchases and sync to members
- Simplify client garage sync to always apply incoming category patches
This commit is contained in:
Jacob Schmidt 2026-03-12 22:20:21 -05:00
parent 6dda184d54
commit 7a214d835d
5 changed files with 186 additions and 43 deletions

View File

@ -10,13 +10,13 @@ if (isNil QGVAR(VGClass)) then { call FUNC(initVGClass); };
[QGVAR(responseInitGarage), {
params [["_data", createHashMap, [createHashMap]]];
GVAR(GarageClass) call ["sync", [_data, true]];
GVAR(GarageClass) call ["sync", [_data]];
}] call CFUNC(addEventHandler);
[QGVAR(responseSyncGarage), {
params [["_data", createHashMap, [createHashMap, []]], ["_jip", false, [false]]];
params [["_data", createHashMap, [createHashMap, []]]];
GVAR(GarageClass) call ["sync", [_data, _jip]];
GVAR(GarageClass) call ["sync", [_data]];
}] call CFUNC(addEventHandler);
[QGVAR(initVG), {
@ -26,13 +26,13 @@ if (isNil QGVAR(VGClass)) then { call FUNC(initVGClass); };
[QGVAR(responseInitVG), {
params [["_data", createHashMap, [createHashMap]]];
GVAR(VGClass) call ["sync", [_data, true]];
GVAR(VGClass) call ["sync", [_data]];
}] call CFUNC(addEventHandler);
[QGVAR(responseSyncVG), {
params [["_data", createHashMap, [createHashMap, []]], ["_jip", false, [false]]];
params [["_data", createHashMap, [createHashMap, []]]];
GVAR(VGClass) call ["sync", [_data, _jip]];
GVAR(VGClass) call ["sync", [_data]];
}] call CFUNC(addEventHandler);
[{

View File

@ -48,7 +48,7 @@ GVAR(VGBaseClass) = compileFinal createHashMapFromArray [
_self set ["lastSave", time];
}],
["sync", compileFinal {
params [["_data", createHashMap, [createHashMap]], ["_jip", false, [false]]];
params [["_data", createHashMap, [createHashMap]]];
private _vGarage = _self get "vGarage";
private _isLoaded = _self get "isLoaded";
@ -56,16 +56,14 @@ GVAR(VGBaseClass) = compileFinal createHashMapFromArray [
{
_vGarage set [_x, _y];
if (_jip) then {
switch (_x) do {
case "cars": { _self call ["apply", ["cars"]]; };
case "armor": { _self call ["apply", ["armor"]]; };
case "helis": { _self call ["apply", ["helis"]]; };
case "planes": { _self call ["apply", ["planes"]]; };
case "naval": { _self call ["apply", ["naval"]]; };
case "other": { _self call ["apply", ["other"]]; };
default {};
};
switch (_x) do {
case "cars": { _self call ["apply", ["cars"]]; };
case "armor": { _self call ["apply", ["armor"]]; };
case "helis": { _self call ["apply", ["helis"]]; };
case "planes": { _self call ["apply", ["planes"]]; };
case "naval": { _self call ["apply", ["naval"]]; };
case "other": { _self call ["apply", ["other"]]; };
default {};
};
} forEach _data;
@ -84,19 +82,21 @@ GVAR(VGBaseClass) = compileFinal createHashMapFromArray [
params [["_key", "", [""]]];
private _vehicles = _self call ["get", [_key, []]];
private _array = switch (_key) do {
case "cars": { GVAR(Cars) };
case "armor": { GVAR(Armor) };
case "helis": { GVAR(Helis) };
case "planes": { GVAR(Planes) };
case "naval": { GVAR(Naval) };
case "other": { GVAR(Other) };
default { [] };
};
private _appliedVehicles = [];
{
_array append [getText (configFile >> "CfgVehicles" >> _x >> "model"), [configFile >> "CfgVehicles" >> _x]];
_appliedVehicles append [getText (configFile >> "CfgVehicles" >> _x >> "model"), [configFile >> "CfgVehicles" >> _x]];
} forEach _vehicles;
switch (_key) do {
case "cars": { GVAR(Cars) = _appliedVehicles; };
case "armor": { GVAR(Armor) = _appliedVehicles; };
case "helis": { GVAR(Helis) = _appliedVehicles; };
case "planes": { GVAR(Planes) = _appliedVehicles; };
case "naval": { GVAR(Naval) = _appliedVehicles; };
case "other": { GVAR(Other) = _appliedVehicles; };
default {};
};
}]
];

View File

@ -91,6 +91,59 @@ GVAR(VGBaseStore) = compileFinal createHashMapFromArray [
[CRPC(garage,responseInitVG), [_finalVGarage], _player] call CFUNC(targetEvent);
_finalVGarage
}],
["grantVehicles", compileFinal {
params [["_uid", "", [""]], ["_vehicles", [], [[]]], ["_commit", false, [false]]];
private _result = createHashMapFromArray [
["success", false],
["message", "Virtual garage grant failed."],
["patch", createHashMap],
["granted", []],
["garage", createHashMap]
];
private _defaultGarage = GVAR(VGarageModel) call ["defaults", []];
private _garage = +(GVAR(VGRegistry) getOrDefault [_uid, _defaultGarage]);
private _patch = createHashMap;
private _granted = [];
private _categoriesToSync = [];
{
private _className = _x getOrDefault ["classname", ""];
private _category = toLowerANSI (_x getOrDefault ["category", ""]);
if (_className isEqualTo "") exitWith {
_result set ["message", "Vehicle checkout entry was missing a classname."];
};
if !(_category in ["cars", "armor", "helis", "planes", "naval", "other"]) exitWith {
_result set ["message", format ["Vehicle category '%1' is unsupported.", _category]];
};
private _categoryUnlocks = +(_garage getOrDefault [_category, []]);
_categoryUnlocks pushBackUnique _className;
_garage set [_category, _categoryUnlocks];
_categoriesToSync pushBackUnique _category;
_granted pushBack (createHashMapFromArray [
["classname", _className],
["category", _category]
]);
} forEach _vehicles;
{
private _category = _x;
_patch set [_category, _garage getOrDefault [_category, []]];
} forEach _categoriesToSync;
if (_commit) then { GVAR(VGRegistry) set [_uid, _garage]; };
_result set ["success", true];
_result set ["message", ""];
_result set ["patch", _patch];
_result set ["granted", _granted];
_result set ["garage", _garage];
_result
}]
];

View File

@ -173,6 +173,73 @@ GVAR(OrgBaseStore) = compileFinal createHashMapFromArray [
["chargeCheckout", compileFinal {
GVAR(OrgTreasuryService) call ["chargeCheckout", _this]
}],
["addFleetVehicles", compileFinal {
params [["_requesterUid", "", [""]], ["_vehicles", [], [[]]], ["_commit", false, [false]]];
private _result = createHashMapFromArray [
["success", false],
["message", "Unable to update organization fleet."],
["patch", createHashMap],
["memberUids", []]
];
if (_requesterUid isEqualTo "" || { _vehicles isEqualTo [] }) exitWith {
_result set ["success", true];
_result set ["message", ""];
_result
};
private _requesterActor = EGVAR(actor,Registry) getOrDefault [_requesterUid, createHashMap];
private _orgID = _requesterActor getOrDefault ["organization", "default"];
if (_orgID isEqualTo "") then { _orgID = "default"; };
private _org = GVAR(Registry) getOrDefault [_orgID, createHashMap];
if (_org isEqualTo createHashMap) exitWith {
_result set ["message", "Organization data is unavailable for fleet updates."];
_result
};
private _fleet = +(_org getOrDefault ["fleet", createHashMap]);
private _fleetIndex = count (keys _fleet);
{
private _className = _x getOrDefault ["classname", ""];
private _category = toLowerANSI (_x getOrDefault ["category", "other"]);
if (_className isEqualTo "") exitWith {
_result set ["message", "Vehicle fleet entry was missing a classname."];
};
private _fleetKey = format ["%1_%2", _className, _fleetIndex];
while { _fleetKey in (keys _fleet) } do {
_fleetIndex = _fleetIndex + 1;
_fleetKey = format ["%1_%2", _className, _fleetIndex];
};
private _displayName = getText (configFile >> "CfgVehicles" >> _className >> "displayName");
if (_displayName isEqualTo "") then { _displayName = _className; };
_fleet set [_fleetKey, createHashMapFromArray [
["classname", _className],
["name", _displayName],
["type", _category],
["status", "Ready"],
["damage", "0%"]
]];
_fleetIndex = _fleetIndex + 1;
} forEach _vehicles;
private _patch = createHashMapFromArray [["fleet", _fleet]];
if (_commit) then {
_patch = _self call ["mset", [GVAR(Registry), "org:update", _orgID, _patch, false]];
};
_result set ["success", true];
_result set ["message", ""];
_result set ["patch", _patch];
_result set ["memberUids", GVAR(OrgTreasuryService) call ["resolveOrgMemberUids", [_org, _requesterUid]]];
_result
}],
["loadById", compileFinal {
params [["_orgID", "", [""]]];

View File

@ -26,7 +26,7 @@ GVAR(StoreBaseStore) = compileFinal createHashMapFromArray [
["paymentMethod", _paymentMethod],
["chargedTotal", 0],
["lockerGranted", []],
["unsupportedLines", []],
["vehicleGranted", []],
["bankPatch", createHashMap],
["orgPatch", createHashMap],
["orgTargetUids", []]
@ -95,18 +95,6 @@ GVAR(StoreBaseStore) = compileFinal createHashMapFromArray [
_result
};
if (_vehicles isNotEqualTo []) exitWith {
_result set ["unsupportedLines", _vehicles apply {
createHashMapFromArray [
["classname", _x getOrDefault ["classname", ""]],
["category", _x getOrDefault ["category", "vehicle"]],
["reason", "Vehicles are handled through the virtual garage flow."]
]
}];
_result set ["message", "Vehicle purchases are not wired yet."];
_result
};
if (_totalPrice <= 0) exitWith {
_result set ["message", "Checkout total must be greater than zero."];
_result
@ -124,7 +112,23 @@ GVAR(StoreBaseStore) = compileFinal createHashMapFromArray [
_result
};
private _vgPreview = EGVAR(garage,VGarageStore) call ["grantVehicles", [_uid, _vehicles, false]];
if !(_vgPreview getOrDefault ["success", false]) exitWith {
_result set ["message", _vgPreview getOrDefault ["message", "Vehicle unlock failed."]];
_result
};
private _orgFleetPreview = createHashMapFromArray [["success", true], ["message", ""], ["patch", createHashMap], ["memberUids", []]];
if (_paymentMethod isEqualTo "org_funds" && { _vehicles isNotEqualTo [] }) then {
_orgFleetPreview = EGVAR(org,OrgStore) call ["addFleetVehicles", [_uid, _vehicles, false]];
if !(_orgFleetPreview getOrDefault ["success", false]) exitWith {
_result set ["message", _orgFleetPreview getOrDefault ["message", "Organization fleet update failed."]];
_result
};
};
_result set ["lockerGranted", _lockerPreview getOrDefault ["granted", []]];
_result set ["vehicleGranted", _vgPreview getOrDefault ["granted", []]];
private _paymentPreview = _self call ["applyPaymentPatch", [_uid, _player, _paymentMethod, _totalPrice, false]];
if !(_paymentPreview getOrDefault ["success", false]) exitWith {
@ -135,31 +139,50 @@ GVAR(StoreBaseStore) = compileFinal createHashMapFromArray [
private _payment = _self call ["applyPaymentPatch", [_uid, _player, _paymentMethod, _totalPrice, true]];
private _lockerResult = EGVAR(locker,LockerStore) call ["grantItems", [_uid, _items, true]];
private _vaResult = EGVAR(locker,VAStore) call ["unlockItems", [_uid, _items, true]];
private _vgResult = EGVAR(garage,VGarageStore) call ["grantVehicles", [_uid, _vehicles, true]];
private _orgFleetResult = createHashMapFromArray [["success", true], ["message", ""], ["patch", createHashMap], ["memberUids", []]];
if (_paymentMethod isEqualTo "org_funds" && { _vehicles isNotEqualTo [] }) then {
_orgFleetResult = EGVAR(org,OrgStore) call ["addFleetVehicles", [_uid, _vehicles, true]];
};
private _lockerPatch = _lockerResult getOrDefault ["patch", createHashMap];
private _vaPatch = _vaResult getOrDefault ["patch", createHashMap];
private _vgPatch = _vgResult getOrDefault ["patch", createHashMap];
if (keys _lockerPatch isNotEqualTo []) then { [CRPC(locker,responseSyncLocker), [_lockerPatch], _player] call CFUNC(targetEvent); };
if (keys _vaPatch isNotEqualTo []) then { [CRPC(locker,responseSyncVA), [_vaPatch], _player] call CFUNC(targetEvent); };
if (keys _vgPatch isNotEqualTo []) then { [CRPC(garage,responseSyncVG), [_vgPatch], _player] call CFUNC(targetEvent); };
private _bankPatch = _payment getOrDefault ["bankPatch", createHashMap];
if (keys _bankPatch isNotEqualTo []) then { [CRPC(bank,responseSyncBank), [_bankPatch], _player] call CFUNC(targetEvent); };
private _orgPatch = _payment getOrDefault ["orgPatch", createHashMap];
private _orgFleetPatch = _orgFleetResult getOrDefault ["patch", createHashMap];
if (keys _orgFleetPatch isNotEqualTo []) then {
{ _orgPatch set [_x, _y]; } forEach _orgFleetPatch;
};
if (keys _orgPatch isNotEqualTo []) then {
private _orgTargetUids = _payment getOrDefault ["orgTargetUids", []];
{
if !(_x in _orgTargetUids) then { _orgTargetUids pushBack _x; };
} forEach (_orgFleetResult getOrDefault ["memberUids", []]);
{
private _memberPlayer = [_x] call EFUNC(common,getPlayer);
if (_memberPlayer isNotEqualTo objNull) then {
[CRPC(org,responseSyncOrg), [_orgPatch], _memberPlayer] call CFUNC(targetEvent);
};
} forEach (_payment getOrDefault ["orgTargetUids", []]);
} forEach _orgTargetUids;
};
_result set ["success", true];
_result set ["message", format [
"Checkout completed. %1 charged, %2 locker grant(s).",
"Checkout completed. %1 charged, %2 locker grant(s), %3 vehicle unlock(s).",
_self call ["formatCurrency", [_totalPrice]],
count (_lockerResult getOrDefault ["granted", []])
count (_lockerResult getOrDefault ["granted", []]),
count (_vgResult getOrDefault ["granted", []])
]];
_result set ["lockerGranted", _lockerResult getOrDefault ["granted", []]];
_result set ["vehicleGranted", _vgResult getOrDefault ["granted", []]];
_result
}]
];