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>
219 lines
5.8 KiB
Markdown
219 lines
5.8 KiB
Markdown
# 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.
|
|
|
|
```sqf
|
|
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.
|
|
|
|
```sqf
|
|
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).**
|
|
|
|
```sqf
|
|
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.**
|
|
|
|
```sqf
|
|
// _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.**
|
|
|
|
```sqf
|
|
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.
|
|
|
|
```sqf
|
|
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.
|
|
|
|
```sqf
|
|
private _result = "forge_server" callExtension ["locker:delete", [getPlayerUID player]];
|
|
// Returns: "OK" or "Error: ..."
|
|
```
|
|
|
|
### Check Existence
|
|
Checks if a player has a locker created.
|
|
|
|
```sqf
|
|
private _result = "forge_server" callExtension ["locker:exists", [getPlayerUID player]];
|
|
private _exists = (_result select 0) == "true";
|
|
```
|
|
|
|
## Complete Integration Example
|
|
|
|
### Storing an Item
|
|
|
|
```sqf
|
|
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
|
|
|
|
```sqf
|
|
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>"`.
|
|
|
|
```sqf
|
|
private _result = "forge_server" callExtension ["locker:add", ...];
|
|
private _data = _result select 0;
|
|
|
|
if (_data find "Error:" == 0) then {
|
|
systemChat format ["Locker error: %1", _data];
|
|
};
|
|
```
|