213 lines
6.3 KiB
Markdown
213 lines
6.3 KiB
Markdown
# 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.
|
|
|
|
```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.
|