- Added frontmatter to various markdown files for better metadata handling. - Updated site URLs in configuration files for consistency. - Improved content organization and clarity in getting started, server extension, and client addon guides.
203 lines
5.3 KiB
Markdown
203 lines
5.3 KiB
Markdown
---
|
|
title: "Locker Usage Guide"
|
|
description: "The locker module stores physical player inventory items by classname. It is separate from the virtual arsenal unlock module documented in [Owned Storage Usage Guide](/server-modules/owned-storage)."
|
|
---
|
|
|
|
## Storage Model
|
|
|
|
Locker data is persisted through SurrealDB by the server extension.
|
|
|
|
```json
|
|
{
|
|
"arifle_MX_F": {
|
|
"category": "weapon",
|
|
"classname": "arifle_MX_F",
|
|
"amount": 1
|
|
}
|
|
}
|
|
```
|
|
|
|
Rules validated by the Rust service:
|
|
|
|
- A locker can contain up to 25 unique classnames.
|
|
- `category` and `classname` cannot be empty.
|
|
- `amount` must be greater than `0`.
|
|
- `locker:add` creates an empty locker automatically when one does not exist.
|
|
- `locker:get`, `locker:patch`, and `locker:remove` require an existing locker.
|
|
- `locker:remove` takes the classname directly, not a JSON object.
|
|
|
|
## Commands
|
|
|
|
All commands are called on the `locker` group.
|
|
|
|
| Command | Arguments | Returns |
|
|
| --- | --- | --- |
|
|
| `locker:create` | `uid` | Empty item map as JSON. |
|
|
| `locker:get` | `uid` | Item map as JSON. |
|
|
| `locker:add` | `uid`, `item_json` | Updated item map as JSON. |
|
|
| `locker:update` | `uid`, `items_json` | Replaced item map as JSON. |
|
|
| `locker:patch` | `uid`, `patch_json` | Updated item map as JSON. |
|
|
| `locker:remove` | `uid`, `classname` | Updated item map as JSON. |
|
|
| `locker:delete` | `uid` | `OK`. |
|
|
| `locker: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 ["locker:get", [getPlayerUID player]];
|
|
private _payload = _result select 0;
|
|
|
|
if (_payload find "Error:" == 0) exitWith {
|
|
systemChat format ["Locker error: %1", _payload];
|
|
};
|
|
|
|
private _locker = fromJSON _payload;
|
|
```
|
|
|
|
## Add an Item
|
|
|
|
`locker:add` creates or overwrites one classname entry.
|
|
|
|
```sqf
|
|
private _item = createHashMapFromArray [
|
|
["category", "weapon"],
|
|
["classname", "arifle_MX_F"],
|
|
["amount", 1]
|
|
];
|
|
|
|
private _result = "forge_server" callExtension ["locker:add", [
|
|
getPlayerUID player,
|
|
toJSON _item
|
|
]];
|
|
|
|
private _payload = _result select 0;
|
|
if (_payload find "Error:" == 0) exitWith {
|
|
hint format ["Failed to store item: %1", _payload];
|
|
};
|
|
|
|
private _locker = fromJSON _payload;
|
|
```
|
|
|
|
## Patch an Amount
|
|
|
|
`locker:patch` currently patches the `amount` field for an existing classname.
|
|
|
|
```sqf
|
|
private _patch = createHashMapFromArray [
|
|
["classname", "arifle_MX_F"],
|
|
["amount", 5]
|
|
];
|
|
|
|
private _result = "forge_server" callExtension ["locker:patch", [
|
|
getPlayerUID player,
|
|
toJSON _patch
|
|
]];
|
|
```
|
|
|
|
## Remove an Item
|
|
|
|
`locker:remove` takes the classname as the second argument.
|
|
|
|
```sqf
|
|
private _result = "forge_server" callExtension ["locker:remove", [
|
|
getPlayerUID player,
|
|
"arifle_MX_F"
|
|
]];
|
|
```
|
|
|
|
## Retrieve an Item
|
|
|
|
```sqf
|
|
fnc_retrieveLockerItem = {
|
|
params ["_classname"];
|
|
|
|
private _result = "forge_server" callExtension ["locker:get", [getPlayerUID player]];
|
|
private _payload = _result select 0;
|
|
|
|
if (_payload find "Error:" == 0) exitWith {
|
|
hint format ["Failed to load locker: %1", _payload];
|
|
false
|
|
};
|
|
|
|
private _locker = fromJSON _payload;
|
|
private _item = _locker getOrDefault [_classname, createHashMap];
|
|
if (_item isEqualTo createHashMap) exitWith {
|
|
hint "Item was not found in your locker.";
|
|
false
|
|
};
|
|
|
|
private _amount = _item getOrDefault ["amount", 0];
|
|
if (_amount <= 0) exitWith {
|
|
hint "Item is out of stock.";
|
|
false
|
|
};
|
|
|
|
if !(player canAdd _classname) exitWith {
|
|
hint "Not enough inventory space.";
|
|
false
|
|
};
|
|
|
|
player addItem _classname;
|
|
|
|
if (_amount > 1) then {
|
|
private _patch = createHashMapFromArray [
|
|
["classname", _classname],
|
|
["amount", _amount - 1]
|
|
];
|
|
"forge_server" callExtension ["locker:patch", [getPlayerUID player, toJSON _patch]];
|
|
} else {
|
|
"forge_server" callExtension ["locker:remove", [getPlayerUID player, _classname]];
|
|
};
|
|
|
|
true
|
|
};
|
|
```
|
|
|
|
## Replace the Whole Locker
|
|
|
|
`locker:update` replaces the whole item map. Use it for explicit bulk syncs,
|
|
not single-item changes.
|
|
|
|
```sqf
|
|
private _items = createHashMapFromArray [
|
|
["arifle_MX_F", createHashMapFromArray [
|
|
["category", "weapon"],
|
|
["classname", "arifle_MX_F"],
|
|
["amount", 1]
|
|
]]
|
|
];
|
|
|
|
private _result = "forge_server" callExtension ["locker:update", [
|
|
getPlayerUID player,
|
|
toJSON _items
|
|
]];
|
|
```
|
|
|
|
## Hot State
|
|
|
|
The `locker:hot:*` commands keep a runtime copy of a player's locker and write
|
|
it back only when `locker:hot:save` runs.
|
|
|
|
| Command | Arguments | Returns |
|
|
| --- | --- | --- |
|
|
| `locker:hot:init` | `uid` | Item map as JSON. |
|
|
| `locker:hot:get` | `uid` | Item map as JSON. |
|
|
| `locker:hot:override` | `uid`, `items_json` | Item map as JSON. |
|
|
| `locker:hot:save` | `uid` | Current hot item map as JSON. |
|
|
| `locker:hot:remove` | `uid` | `OK`. |
|
|
|
|
Use hot state for session-heavy locker workflows. Use the durable commands for
|
|
simple item deposits and withdrawals.
|
|
|
|
## Best Practices
|
|
|
|
- Keep categories normalized, for example `weapon`, `magazine`, `item`, or
|
|
`backpack`.
|
|
- Use `locker:patch` for quantity changes.
|
|
- Use `locker:remove` when quantity reaches zero.
|
|
- Treat the locker response as a hash map keyed by classname.
|
|
- Check capacity before bulk operations that may exceed 25 unique items.
|