Inventory

Server Exports

QBCore, Qbox, ESX, OX

Server Exports

Call these exports from server scripts.

local inventory = exports['tss-inventory']

Arguments and returns

  • playerSource: player server ID.
  • inventoryId: inventory ID, such as player_ABC123.
  • target: player server ID or inventory ID.
  • itemId / slot: an item stack's ID, not a grid position.
  • ?: optional argument.
  • Weights use grams.
  • Grid coordinates start at 1.

Most changes return true or false, errorMessage.

Creation generally returns true, inventory or false, errorMessage.

Getters return copies. Load the character before calling player inventory exports.

Find inventories

ExportPurpose
GetPlayerInventory(playerSource)Get or create the player's inventory.
GetInventory(inventoryId)Get an inventory, or nil.
GetContainer(inventoryId)Get a container, or nil.
GetContainersByOwner(citizenId)Get the character's containers.
GetInventoryType(typeName)Get an inventory type's defaults.

Create and open inventories

ExportPurpose
CreateInventory(inventoryId, typeName, options?)Create an inventory from a type.
CreateInventory(inventoryId, data)Create a stash using QB-style data.
CreateContainer(typeName, options?)Create a container.
OpenInventory(playerSource, inventoryId?, data?)Open an inventory alongside the player's inventory.
CloseInventory(playerSource, inventoryId?)Close one window, or omit the ID to close everything.
DeleteContainer(inventoryId)Delete a container.
RegisterInventoryType(typeName, definition)Set defaults for newly created inventories.
OpenStash(playerSource, stashName)Open a configured fixed stash after access checks.
OpenVehicleInventory(playerSource, networkId, compartment)Open trunk or glovebox.
OpenItemContainer(playerSource, sourceInventoryId, itemId)Open a carried item container. Its source window must already be open.

Container options include:

{
    inventoryId = 'business_storage',
    label = 'Storage',
    size = { x = 8, y = 6 },
    metadata = {},
    playerSource = playerSource,
}

Additional options include owner, coords, whitelist, blacklist and maxWeight.

owner is a character ID. playerSource can resolve the owner through the bridge.

Coordinates alone do not create a target or ped. Authorise access in the calling script before opening custom storage.

local created, container = inventory:CreateContainer('stash', {
    inventoryId = 'business_storage',
    label = 'Storage',
    size = { x = 8, y = 6 },
    playerSource = playerSource,
})

if created then
    inventory:OpenInventory(playerSource, container.id)
end

DeleteContainer excludes player inventories, shops, drops and extra slots.

Temporary loot

local created, container = inventory:CreateContainer('loot', {
    label = 'Loot',
    size = { x = 8 },

    items = {
        plastic = {
            amount = { min = 1, max = 5 },
            chance = 100,
        },

        bandage = {
            amount = 2,
            chance = 30,
        },
    },

    maxItems = { min = 1, max = 2 },
    deleteOnEmpty = true,
    playerSource = playerSource,
})

if created then
    inventory:OpenInventory(playerSource, container.id)
end
  • Omit inventoryId to generate a unique ID.
  • amount accepts a number or {min, max}.
  • chance is a percentage.
  • maxItems caps selected item types, not total item quantity.
  • Chances are independent; a roll may contain fewer types than the cap.
  • An empty roll can return false, 'Loot roll produced no items'.
  • Omit size.y to calculate the required rows.
  • Existing IDs are not rerolled.
  • Loot contents never save to the database.
  • deleteOnEmpty = true removes the container after its last item is taken.

For item-backed loot, deleteOnEmpty also removes the linked item when emptied. Already-opened loot items do not reroll after a restart.

Change inventories

ExportPurpose
ResizeInventory(inventoryId, {x,y}, repack?)Resize; optionally rearrange items to fit.
RepackInventory(inventoryId)Compact items while preserving IDs and metadata.
SetInventoryLabel(inventoryId, label)Set metadata.label; false restores the default.
SetInventoryOwner(inventoryId, citizenId?)Change or clear container ownership.
SetInventoryCoords(inventoryId, coords)Set coordinates; false clears them.
SetInventoryMetadata(inventoryId, metadata)Replace inventory metadata.
SetInventoryRules(inventoryId, rules)Change whitelist, blacklist or maxWeight.
ClearInventory(target, keepItems?)Empty an inventory, optionally keeping item names.
ClearStash(inventoryId)Empty a stash or container.

Resizing fails if the contents cannot fit.

Player and extra-slot ownership cannot be reassigned.

Do not manually change container link fields such as containerId or containerItem.

Check and find items

ExportPurpose
HasItem(target, items, amount?)Check all requested items and amounts.
HasItems(target, items, amount?)Same check as HasItem.
GetItemCount(target, items, exactMetadata?)Count matching item names.
GetItemByName(target, itemName)Get the first matching item.
GetItemsByName(target, itemName)Get all matching items.
GetItemBySlot(target, itemId)Get an item by stack ID.
GetItemDefinition(itemName)Get a definition including defaults.
GetItemDefinitions()Get all item definitions.
CanCarryItem(inventoryId, itemName, amount, metadata?)Check available space and weight.
CanAddItem(target, itemName, amount?, metadata?)Carry check accepting a player server ID too.
inventory:HasItem(playerSource, 'bandage', 2)

inventory:HasItems(playerSource, {
    bandage = 2,
    water_bottle = 1,
})

Player HasItem/HasItems checks include the main inventory and enabled extra slots. They do not search nested containers.

Pass a specific inventory ID to check only that inventory.

Item getters provide slot and info as equivalents of id and metadata.

Add, remove and move items

ExportPurpose
AddItem(inventoryId, itemName, amount, metadata?, notification?)Add to an inventory.
AddItem(playerSource, itemName, amount, slot?, info?, reason?)Add using QB-style arguments.
AddItemToSlot(inventoryId, itemName, amount, metadata, itemId)Add to an existing matching stack.
RemoveItem(inventoryId, itemId, amount, notification?)Remove from one stack.
RemoveItem(target, itemName, amount, slot?, reason?)Remove by name or a selected stack.
RemoveItemsByName(inventoryId, itemName, amount, metadataFilter?, itemId?)Remove by name with optional filtering.
MoveItem(fromId, toId, itemId, amount, x, y, rotated?)Move, split, stack or rotate.
SetItemLabel(inventoryId, itemId, label)Rename one stack; false restores the default label.
SetItemMetadata(inventoryId, itemId, metadata)Replace item metadata.
SetItemData(target, itemName, key, value, itemId?)Set one metadata field.

Automatic placement:

inventory:AddItem(playerSource, 'water_bottle', 2, false, {
    quality = 100,
})

Remove by name:

inventory:RemoveItem(playerSource, 'water_bottle', 1, false)

Use an inventory ID and request an item notification:

inventory:AddItem(inventoryId, 'bandage', 1, {}, true)
inventory:RemoveItem(inventoryId, itemId, 1, true)

For inventory-ID forms, notification accepts:

  • true to notify the owning player for their own or extra inventory.
  • A player server ID to notify that player.
  • false or omission for no notification.

A supplied slot must be an existing matching stack. It is not an empty grid cell.

For RemoveItemsByName, a table filter matches supplied metadata fields. A string filter matches metadata.type.

For GetItemCount, exactMetadata must match the complete metadata object.

Using info or metadata as the SetItemData key replaces all metadata.

Labels

inventory:SetItemLabel(inventoryId, itemId, "Jack's Box")
inventory:SetInventoryLabel(inventoryId, "Jack's Storage")

Custom labels are stored in metadata.label and persist when moved or saved.

Labels must be nonempty text up to 100 bytes. Pass false to remove a custom label.

An item ID identifies a stack. Split a stack first to rename just one unit.

A container item's label and its inventory window title are separate.

Usable items

ExportPurpose
RegisterUsableItem(itemName, callback, ownerResource?)Register an item callback.
CreateUsableItem(itemName, callback, ownerResource?)Register with QB-style slot/info fields.
CreateUseableItem(itemName, callback, ownerResource?)Alternative spelling.
GetUsableItem(itemName)Get {func, resource}, or nil.
UseItem(playerSource, itemNameOrItem)Use a carried item normally.
UseItem(itemName, playerSource, item?)Item-name-first form.

Callbacks receive (playerSource, item, inventoryId).

inventory:CreateUsableItem('bandage', function(playerSource, item, inventoryId)
    if not inventory:RemoveItem(inventoryId, item.id, 1) then
        return
    end

    -- Apply the effect here.
end)

Callbacks do not consume items automatically.

With Config.UseItemsFromContainers = true, use the callback's inventory ID to remove the selected item from its carried container.

Start registering scripts after the inventory, and restart them after restarting it.

A framework function forwarding registrations should pass GetInvokingResource() as ownerResource.

Weight and slots

ExportReturns
GetInventoryWeight(inventoryId)Inventory weight.
GetFreeWeight(target)Remaining grams, or math.huge without a limit.
GetTotalWeight(items)Direct weight of a supplied item list.
GetSlots(target)Used cells and free cells.
GetSlotsByItem(items, itemName)Matching item IDs from a supplied list.
GetFirstSlotByItem(items, itemName)First matching item ID, or nil.

Multi-cell items occupy multiple cells.

Dynamic container weight includes carried contents where applicable.

Shops

ExportPurpose
RegisterShop(shopId, definition)Register using the data/shops.lua format.
CreateShop(data)Register a shop from supplied data.
OpenShop(playerSource, shopId)Open a shop alongside the player's inventory.

CreateShop accepts:

{
    name = 'trade_counter',
    label = 'Trade Counter',
    coords = vector4(24.47, -1346.62, 28.50, 266.0),
    size = { x = 8 },

    items = {
        {
            name = 'plastic',
            buyPrice = 5,
            sellPrice = 2,
            amount = 100,
        },
    },
}

Coordinates are required. Product names must be unique.

Products support buyPrice, sellPrice, buy, sell, amount and metadata. Legacy price, count and info are also accepted.

Shop height is calculated automatically, with a minimum of two rows. Use amount = false for unlimited stock.

World drops

ExportPurpose
DropItem(playerSource, itemId, amount, rotated?)Drop from the personal inventory.
CreateDrop(options)Create a temporary drop.
GetDrops()List current drops.
RemoveDrop(dropInventoryId)Remove a drop and its contents.

CreateDrop requires coordinates and an item list:

inventory:CreateDrop({
    coords = { x = 24.47, y = -1346.62, z = 28.5 },

    items = {
        {
            name = 'bandage',
            amount = 2,
            metadata = {},
        },
    },
})

Optional fields include size, label, metadata and bucket.

World drops never save to the database.

When world drops are disabled, DropItem deletes the items instead.

Extra inventories

ExportPurpose
RegisterExtraInventory(slotName, definition)Register defaults until restart.
GetExtraInventoryDefinitions(playerSource?)Get defaults or a player's enabled definitions.
CreateExtraInventory(playerSource, slotName, definition?)Create, update or re-enable a slot.
GetExtraInventory(playerSource, slotName)Get or create an enabled slot.
GetExtraInventories(playerSource)Get enabled slots.
UpdateExtraInventory(playerSource, slotName, changes, repack?)Update supplied fields.
ResizeExtraInventory(playerSource, slotName, {x,y}, repack?)Resize a slot.
RemoveExtraInventory(playerSource, slotName)Disable an empty slot.
OpenExtraInventory(playerSource, slotName)Open the slot and personal inventory.

Definitions accept label, size, metadata, whitelist, blacklist and maxWeight.

inventory:CreateExtraInventory(playerSource, 'wallet_slot', {
    label = 'Wallet',
    size = { x = 1, y = 1 },
    whitelist = { 'wallet' },
})

Use the returned inventory ID with normal item exports.

Slot names allow 1–64 letters, numbers, underscores or hyphens. Each character can have up to 32 definitions.

Window settings

ExportPurpose
GetInventorySettings(inventoryId, citizenId)Get saved window settings.
SetInventorySettings(inventoryId, citizenId, settings)Set position and docking settings.

Settings use:

{
    x = 100,
    y = 100,
    dock = false,
    minimised = false,
    active = true,
}

Dock positions:

  • left-top
  • left-bottom
  • right-top
  • right-bottom
  • top-left
  • top-right
  • bottom-left
  • bottom-right

Item notifications

inventory:ItemBox(playerSource, 'bandage', 'added', 1)
inventory:ItemBox(playerSource, 'bandage', 'removed', 1)

Notifications do not add or remove items.

Players control their visibility, duration and position through /inventorysettings.

Weapons

Requires Config.EnableWeaponSystem = true.

ExportPurpose
GetEquippedWeapon(playerSource)Get equipped weapon state, or nil.
UnequipWeapon(playerSource)Holster the managed weapon.
OpenWeaponAttachments(playerSource, inventoryId, itemId)Open the 3D attachment view.
GetWeaponAttachmentDefinitions()Get attachment and tint definitions.

Use UseItem to equip or toggle a carried weapon.

Loaded ammunition is stored in metadata.ammo. Installed attachments are stored in metadata.attachments.

Clothing

These exports are registered when Config.EnableClothingSystem = true.

local clothing = inventory:GetEquippedClothing(playerSource)

local success, errorMessage = inventory:EquipClothing(
    playerSource,
    inventoryId,
    itemId
)

local success, errorMessage = inventory:UnequipClothing(
    playerSource,
    'top'
)

clothing.inventory.items contains worn items. clothing.slots lists equipment slots.

Replaced or unequipped clothing returns to the main inventory. Changes fail if the returned item cannot fit.

Cash items

With Config.MoneyAsItem = true, carried cash items synchronise with the player's cash account.

This includes enabled extra slots and linked nested containers.

Moving cash within carried storage does not change the balance. Moving cash or a funded container outside carried storage debits it; moving it back credits it.

Use one cash operation in payment scripts. Synchronisation handles the matching account or item change.

Cash edits to offline player inventories are refused.

Unsupported QB calls

Use GetPlayerInventory instead of LoadInventory.

TSS saves changes automatically, so SaveInventory is not required.

SetInventory, RemoveInventory, OpenInventoryById and QB hook/listener exports are not provided.