Skip to main content
Server Client Proxied to ug-core. ug-core owns every inventory: contents, rules, persistence and the callbacks clients use. It has no UI. An inventory resource such as ug-inventory shows the items and calls the client functions below. Owners can swap the UI without weakening security.
This page covers player inventories. Stashes, vehicle inventories and ground drops come next.

Concepts

  • Slots and weight. Each inventory has a number of slots and a maximum weight in grams. Each slot holds one stack. Player inventories use playerSlots and playerWeight from config/inventory.lua.
  • All or nothing. Every change either applies fully or not at all. Adding 12 water that only fits 10 adds none and returns cannot_carry.
  • Stacking. Units stack up to the item’s maxStack, only with the same name and equal metadata. Existing stacks fill first, then empty slots, lowest slot first.
  • Targets. target is a player source, for that player’s inventory, or an inventory id. Player inventories are player:<characterId> and exist while the character is loaded.
  • Audit log. Every change writes a row to ug_item_logs, in the same database transaction as the inventory. See GetLog.

Adding and removing

AddItem

integer
required
1 to 1,000,000.
table
Checked by the item’s rule.
string
Up to 128 characters, stored in the audit log.

RemoveItem

Removes from the lowest slots first. With metadata, only stacks whose metadata has those keys and values count.

RemoveFromSlot

count defaults to the whole stack.

SetMetadata

Replaces the metadata of a whole slot. The audit log records it with an amount of 0.

Clear

Moving

Moves units between slots of one or two inventories: Between two inventories, the target’s weight is checked, and both sides get an audit row pointing to the other.

Reading

table
A copy.
Unknown or unloaded inventories read as empty. GetSource returns the player who owns an inventory id, or nil.

Use

Uses the item in a slot of the player’s inventory, in this order:
  1. The slot has an item with a use handler. Otherwise not_found or invalid_args.
  2. The player is alive, unless the handler allows otherwise. Otherwise no_permission.
  3. The item’s cooldown passed. Otherwise rate_limited.
  4. Items:BeforeUse allows it. Otherwise no_permission.
  5. The handler runs. Returning false refuses the use with no_permission. An error returns internal_error.
  6. consume units leave the slot, and ug-core:Items:Used fires.

GetLog

MUST run in a thread. Saves the inventory first, then returns the latest audit rows, newest first.
integer
default:"25"
1 to 100.
UgItemLogEntry[]
Inventories are saved by a write-behind cache: every 30 seconds, on character unload, on player drop and on resource stop. Audit rows are written in the same transaction, so the log never shows a change the inventory lost. A failed write keeps both and retries.

Client

The player’s own inventory, sent by the server to that player only. Reads are local:
Actions ask the server, which checks everything again. They MUST run in a thread and return ok, errorCode:
Give needs the other player within giveDistance meters, measured on the server.

Build an inventory UI

client.lua
ug-core:Inventory:Changed is a client event: nil after a full sync, or the list of changed slots.

Security

Clients send slots and counts, never items, metadata or inventory ids. Their own inventory is the reference player. Each replies true or an error code. The client functions above call them for you.

Errors

Wrong argument types, counts out of range and long reasons raise.

Events

Use GetSource(inventoryId) to find the player of a player inventory.

Hooks

They allow or cancel. Changes to the payload are ignored.

Death

Items stay when a player dies. With clearOnRespawn = true in config/inventory.lua, respawning empties the inventory, except items with keepOnRespawn. Inventory:BeforeClearOnRespawn can cancel it, for example in an arena.

Player object

Player objects have shortcuts: player:AddItem, RemoveItem, GetItemCount, HasItem, CanCarry, GetItems, UseItem.