--- title: "Garage Usage Guide" description: "The garage module stores physical player vehicles. Each record keeps the vehicle classname, generated plate UUID, fuel, overall damage, and detailed hit point damage." --- ## Storage Model Garage data is persisted through SurrealDB by the server extension. ```json { "plate-uuid": { "plate": "plate-uuid", "classname": "B_Quadbike_01_F", "fuel": 1.0, "damage": 0.0, "hit_points": { "names": ["hitengine"], "selections": ["engine_hitpoint"], "values": [0.0] } } } ``` Rules validated by the Rust service: - A player garage can contain up to 5 vehicles. - `garage:add` generates a UUID plate automatically. - `fuel`, `damage`, and every hit point value must be between `0.0` and `1.0`. - `hit_points.names`, `hit_points.selections`, and `hit_points.values` must have the same length. - `garage:get`, `garage:patch`, and `garage:remove` require an existing garage. - `garage:add` creates an empty garage automatically when one does not exist. ## Commands All commands are called on the `garage` group. | Command | Arguments | Returns | | --- | --- | --- | | `garage:create` | `uid` | Empty vehicle map as JSON. | | `garage:get` | `uid` | Vehicle map as JSON. | | `garage:add` | `uid`, `vehicle_json` | Updated vehicle map as JSON. | | `garage:update` | `uid`, `vehicles_json` | Replaced vehicle map as JSON. | | `garage:patch` | `uid`, `patch_json` | Updated vehicle map as JSON. | | `garage:remove` | `uid`, `remove_json` | Updated vehicle map as JSON. | | `garage:delete` | `uid` | `OK`. | | `garage:exists` | `uid` | `true` or `false`. | ## Error Handling Every command returns a string payload. Always check for the `Error:` prefix before parsing JSON. ```sqf private _result = "forge_server" callExtension ["garage:get", [getPlayerUID player]]; private _payload = _result select 0; if (_payload find "Error:" == 0) exitWith { systemChat format ["Garage error: %1", _payload]; }; private _garage = fromJSON _payload; ``` ## Add a Vehicle `garage:add` requires `classname`, `fuel`, `damage`, and `hit_points`. ```sqf private _hitPointData = getAllHitPointsDamage _vehicle; private _hitPoints = createHashMapFromArray [ ["names", _hitPointData select 0], ["selections", _hitPointData select 1], ["values", _hitPointData select 2] ]; private _vehicleData = createHashMapFromArray [ ["classname", typeOf _vehicle], ["fuel", fuel _vehicle], ["damage", damage _vehicle], ["hit_points", _hitPoints] ]; private _result = "forge_server" callExtension ["garage:add", [ getPlayerUID player, toJSON _vehicleData ]]; private _payload = _result select 0; if (_payload find "Error:" == 0) exitWith { hint format ["Failed to store vehicle: %1", _payload]; }; private _garage = fromJSON _payload; ``` The returned value is a hash map keyed by generated plate. To find the newly stored vehicle, compare returned keys before and after the add, or search by classname if your workflow guarantees a unique pending vehicle. ```sqf private _storedPlate = ""; { private _vehicleRecord = _garage get _x; if ((_vehicleRecord get "classname") == typeOf _vehicle) then { _storedPlate = _x; }; } forEach keys _garage; ``` ## Patch a Vehicle `garage:patch` updates selected fields for one plate. The `plate` field is required. `fuel`, `damage`, and `hit_points` are optional. ```sqf private _patch = createHashMapFromArray [ ["plate", _vehicle getVariable ["forge_garage_plate", ""]], ["fuel", fuel _vehicle], ["damage", damage _vehicle] ]; private _result = "forge_server" callExtension ["garage:patch", [ getPlayerUID player, toJSON _patch ]]; ``` ## Remove a Vehicle `garage:remove` expects JSON with a `plate` field. ```sqf private _remove = createHashMapFromArray [ ["plate", _plate] ]; private _result = "forge_server" callExtension ["garage:remove", [ getPlayerUID player, toJSON _remove ]]; ``` ## Spawn a Stored Vehicle ```sqf fnc_spawnGarageVehicle = { params ["_plate"]; private _result = "forge_server" callExtension ["garage:get", [getPlayerUID player]]; private _payload = _result select 0; if (_payload find "Error:" == 0) exitWith { hint format ["Failed to load garage: %1", _payload]; objNull }; private _garage = fromJSON _payload; private _vehicleData = _garage getOrDefault [_plate, createHashMap]; if (_vehicleData isEqualTo createHashMap) exitWith { hint "Vehicle plate was not found in your garage."; objNull }; private _vehicle = (_vehicleData get "classname") createVehicle (player getPos [10, getDir player]); _vehicle setFuel (_vehicleData getOrDefault ["fuel", 1]); _vehicle setDamage (_vehicleData getOrDefault ["damage", 0]); _vehicle setVariable ["forge_garage_plate", _plate, true]; private _hitPoints = _vehicleData getOrDefault ["hit_points", createHashMap]; private _names = _hitPoints getOrDefault ["names", []]; private _values = _hitPoints getOrDefault ["values", []]; { _vehicle setHitPointDamage [_x, _values select _forEachIndex]; } forEach _names; private _remove = createHashMapFromArray [["plate", _plate]]; "forge_server" callExtension ["garage:remove", [getPlayerUID player, toJSON _remove]]; _vehicle }; ``` ## Hot State The `garage:hot:*` commands keep a runtime copy of a player's garage and write it back only when `garage:hot:save` runs. | Command | Arguments | Returns | | --- | --- | --- | | `garage:hot:init` | `uid` | Vehicle map as JSON. | | `garage:hot:get` | `uid` | Vehicle map as JSON. | | `garage:hot:override` | `uid`, `vehicles_json` | Vehicle map as JSON. | | `garage:hot:add` | `uid`, `vehicle_json` | Vehicle map as JSON. | | `garage:hot:remove_vehicle` | `uid`, `remove_json` | Vehicle map as JSON. | | `garage:hot:save` | `uid` | Current hot vehicle map as JSON. | | `garage:hot:remove` | `uid` | `OK`. | Use hot state for session-heavy vehicle workflows. Use the durable commands for simple store/retrieve operations. ## Best Practices - Store the generated plate on spawned vehicles with `setVariable`. - Use `garage:patch` for frequent fuel and damage syncs. - Use `garage:update` only when replacing the whole vehicle map intentionally. - Do not delete the world vehicle until `garage:add` succeeds. - Treat vehicle maps as hash maps keyed by plate, not arrays.