forge/docs/GARAGE_USAGE_GUIDE.md
2026-05-23 09:23:12 -05:00

6.3 KiB

Garage Usage Guide

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.

{
  "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.

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.

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.

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.

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.

private _remove = createHashMapFromArray [
    ["plate", _plate]
];

private _result = "forge_server" callExtension ["garage:remove", [
    getPlayerUID player,
    toJSON _remove
]];

Spawn a Stored Vehicle

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.