forge/docs/LOCKER_USAGE_GUIDE.md
Jacob Schmidt ebfe77a340 feat: implement complete Forge framework with Rust/Redis backend and Arma 3 integration
Implemented features:
- High-performance Rust extension with Redis persistence
- Actor/player management with loadout, position, and state tracking
- Banking system with deposit, withdraw, and transfer operations
- Physical and virtual garage/locker systems for vehicle and equipment storage
- Organization management with member tracking and permissions
- Client-side UI with React-like state management
- Server-side event-driven architecture with CBA Events
- Security: Self-transfer prevention at multiple layers
- Logging system with per-module log files
- ICOM module for inter-server communication

Co-Authored-By: Warp <agent@warp.dev>
2026-01-04 12:52:15 -06:00

5.8 KiB

Locker System Integration Guide

Overview

The locker system provides persistent item storage for Arma 3 players. Each player can store multiple items (weapons, magazines, equipment) with quantity tracking.

Data Storage

  • Each player's locker is stored as a single JSON object (map) at Redis key: locker:{playerUID}
  • The map is keyed by the item's classname (String)
  • Each item tracks: category, classname, and amount
  • Maximum Capacity: 25 unique items per locker
  • Empty lockers are auto-created when a player first fetches their locker if it doesn't exist

Extension Commands

All commands are accessed via the locker group:

Create Locker

Creates a new empty locker for a player. Should be called when initializing a new player if one doesn't exist.

private _result = "forge_server" callExtension ["locker:create", [getPlayerUID player]];
// Returns: {} (empty map) or Error message

Get Locker

Retrieves all items in a player's locker.

private _result = "forge_server" callExtension ["locker:get", [getPlayerUID player]];
private _lockerMap = fromJSON (_result select 0);
// Returns: {"arifle_MX_F": {"classname":"arifle_MX_F","category":"Weapon","amount":1}, ...}

Add Item

Adds a new item to the locker or updates the amount if it already exists. Checks capacity limit (25 items).

private _data = createHashMapFromArray [
    ["classname", "arifle_MX_F"],
    ["category", "Weapon"],
    ["amount", 1]
];

private _result = "forge_server" callExtension ["locker:add", [
    getPlayerUID player,
    toJSON _data
]];

private _updatedLocker = fromJSON (_result select 0);
// Returns updated locker map

Update Locker (Sync)

Updates the entire locker state. Useful for syncing changes made locally (e.g., bulk moves). Replaces the entire locker content.

// _lockerMap is the local HashMap of items
private _result = "forge_server" callExtension ["locker:update", [
    getPlayerUID player,
    toJSON _lockerMap
]];

private _updatedLocker = fromJSON (_result select 0);

Patch Item

Updates specific fields (currently amount) of an existing item without sending the entire locker. Efficient for quantity changes.

private _classname = "arifle_MX_F";
private _data = createHashMapFromArray [
    ["classname", _classname],
    ["amount", 5] // New amount
];

private _result = "forge_server" callExtension ["locker:patch", [
    getPlayerUID player,
    toJSON _data
]];

private _updatedLocker = fromJSON (_result select 0);

Remove Item

Removes a specific item from the locker by classname.

private _classname = "arifle_MX_F";
private _data = createHashMapFromArray [
    ["classname", _classname]
];

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

private _updatedLocker = fromJSON (_result select 0);

Delete Locker

Permanently deletes all items from a player's locker.

private _result = "forge_server" callExtension ["locker:delete", [getPlayerUID player]];
// Returns: "OK" or "Error: ..."

Check Existence

Checks if a player has a locker created.

private _result = "forge_server" callExtension ["locker:exists", [getPlayerUID player]];
private _exists = (_result select 0) == "true";

Complete Integration Example

Storing an Item

fnc_storeCurrentWeapon = {
    private _weapon = currentWeapon player;
    if (_weapon == "") exitWith { hint "No weapon in hand!"; };

    // Create item data
    private _data = createHashMapFromArray [
        ["classname", _weapon],
        ["category", "Weapon"],
        ["amount", 1]
    ];

    // Add to locker
    private _result = "forge_server" callExtension ["locker:add", [
        getPlayerUID player,
        toJSON _data
    ]];

    // Check for error (e.g., full locker)
    if ((_result select 0) find "Error:" == 0) exitWith {
        hint format ["Failed to store item: %1", _result select 0];
        false
    };

    // Remove weapon from player
    player removeWeapon _weapon;
    hint format ["Stored %1 in locker!", _weapon];
    true
};

Retrieving an Item

fnc_retrieveItem = {
    params ["_classname"];

    // Get locker
    private _result = "forge_server" callExtension ["locker:get", [getPlayerUID player]];
    private _locker = fromJSON (_result select 0);

    // Check if item exists
    private _item = _locker getOrDefault [_classname, locationNull];
    if (_item isEqualTo locationNull) exitWith {
        hint "Item not found in locker!";
        false
    };

    // Get amount
    private _amount = _item get "amount";
    if (_amount <= 0) exitWith {
        // Should not happen, but safe to handle
        hint "Item out of stock!";
        false
    };

    // Add to player
    if (player canAdd _classname) then {
        player addItem _classname;

        // Decrement amount or remove if 0
        if (_amount > 1) then {
             private _patchData = createHashMapFromArray [
                ["classname", _classname],
                ["amount", _amount - 1]
            ];
            "forge_server" callExtension ["locker:patch", [getPlayerUID player, toJSON _patchData]];
        } else {
             private _removeData = createHashMapFromArray [
                ["classname", _classname]
            ];
            "forge_server" callExtension ["locker:remove", [getPlayerUID player, toJSON _removeData]];
        };

        hint format ["Retrieved %1 from locker!", _classname];
        true
    } else {
        hint "Not enough space in inventory!";
        false
    };
};

Error Handling

All commands return errors in the format "Error: <message>".

private _result = "forge_server" callExtension ["locker:add", ...];
private _data = _result select 0;

if (_data find "Error:" == 0) then {
    systemChat format ["Locker error: %1", _data];
};