Jacob Schmidt a4d5c2fd4d Enhance documentation structure and content across multiple guides
- 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.
2026-05-16 10:33:17 -05:00

5.3 KiB

title, description
title description
Locker Usage Guide 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.

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

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.

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.

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.

private _result = "forge_server" callExtension ["locker:remove", [
    getPlayerUID player,
    "arifle_MX_F"
]];

Retrieve an Item

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.

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.