AI Core

Items

inventory: give, take and count items, stashes, shops and usable items through whatever inventory the server runs.

TypeScript
import { inventory } from "@aicore-fivem/lib/server";

inventory sends every item call through ai-core's inventory layer: the inventory the server runs (ai-inventory, or another the owner picks in ai-core's panel) answers. Your script never calls an inventory's own exports, so it keeps working when the owner changes inventory.

The inventory argument (inv, type InventoryRef) is a player's server id (a number) or another inventory's id (a string: a stash name, a plate).

Counts are whole numbers of 1 or more; a fraction is rounded down, 0 or a negative count makes the call fail.

While no inventory runs, calls fail quietly: false, 0, an empty list or null. The Lua twins on aiLib.inventory have the same names and argument order.

inventory.addItem

Gives items to an inventory.

Side: Server · Waits: no

Signature
inventory.addItem(inv: InventoryRef, item: string, count?: number, metadata?: ItemMetadata, slot?: number): boolean
Lua
local ok = aiLib.inventory.addItem(inv, item, count, metadata, slot)

Parameters

Prop

Type

Returns

boolean: true when given. false when they do not fit, the item does not exist, an argument is wrong or no inventory runs.

Example

import { inventory } from "@aicore-fivem/lib/server";
import { fail } from "@aicore-fivem/lib/shared";

if (!inventory.addItem(source, "phone", 1, { number: "555-0101" })) return fail("INVENTORY_FULL");

Check canCarryItem first when you take something in exchange (money, another item): take it only after addItem answered true, or give it back.

inventory.removeItem

Takes items from an inventory.

Side: Server · Waits: no

Signature
inventory.removeItem(inv: InventoryRef, item: string, count?: number, metadata?: ItemMetadata, slot?: number): boolean
Lua
local ok = aiLib.inventory.removeItem(inv, item, count, metadata, slot)

Parameters

Prop

Type

Returns

boolean: true when taken. false when there are not enough, an argument is wrong or no inventory runs.

Example

if (!inventory.removeItem(source, "lockpick")) return fail("NO_LOCKPICK");

inventory.getItemCount

How many of an item an inventory holds.

Side: Server · Waits: no

Signature
inventory.getItemCount(inv: InventoryRef, item: string, metadata?: ItemMetadata): number
Lua
local count = aiLib.inventory.getItemCount(inv, item, metadata)

Prop

Type

Returns

number: the total over every stack, 0 when none or no inventory runs.

Example

const bags = inventory.getItemCount(source, "weed_bag");
notify(source, `You have ${bags} bags`);

inventory.hasItem

Whether an inventory holds at least count of an item.

Side: Server · Waits: no

Signature
inventory.hasItem(inv: InventoryRef, item: string, count?: number): boolean
Lua
local has = aiLib.inventory.hasItem(inv, item, count)

Prop

Type

Returns

boolean.

Example

if (!inventory.hasItem(source, "scrap_metal", 10)) return fail("NEED_10_SCRAP");

hasItem is a check, not a hold: between hasItem and removeItem (an await in between) the item can leave. Act on the answer of removeItem.

inventory.canCarryItem

Whether the items would fit (weight and free space).

Side: Server · Waits: no

Signature
inventory.canCarryItem(inv: InventoryRef, item: string, count?: number, metadata?: ItemMetadata): boolean
Lua
local fits = aiLib.inventory.canCarryItem(inv, item, count, metadata)

Prop

Type

Returns

boolean: true when they fit.

Example

if (!inventory.canCarryItem(source, "fish", 5)) return fail("TOO_HEAVY");
inventory.addItem(source, "fish", 5);

inventory.getItems

Every stack of an inventory.

Side: Server · Waits: no

Signature
inventory.getItems(inv: InventoryRef): InventoryStack[]
Lua
local stacks = aiLib.inventory.getItems(inv)

Returns

InventoryStack[]: one { name, label, count, slot, metadata } per stack. Empty when the inventory is empty, unknown or no inventory runs.

Example

const weapons = inventory.getItems(source).filter((stack) => stack.name.startsWith("weapon_"));

inventory.clearInventory

Empties an inventory.

Side: Server · Waits: no

Signature
inventory.clearInventory(inv: InventoryRef): void
Lua
aiLib.inventory.clearInventory(inv)

Returns

void.

Example

inventory.clearInventory("evidence_locker_12");

inventory.registerStash

Registers a stash (a storage box, a locker). ai-core remembers it and registers it again with any inventory that starts later, so call it once when your script starts.

Side: Server · Waits: no

Signature
inventory.registerStash(name: string, label: string, slots: number, maxWeight: number, jobs?: string[]): void
Lua
aiLib.inventory.registerStash(name, label, slots, maxWeight, jobs)

Parameters

Prop

Type

Returns

void.

Example

inventory.registerStash("police_armory", "Armory", 50, 200_000, ["police"]);

inventory.openInventory

Opens a stash or another player's inventory on a player's screen.

Side: Server · Waits: no

Signature
inventory.openInventory(source: number, inv: InventoryRef): boolean
Lua
local ok = aiLib.inventory.openInventory(source, inv)

Prop

Type

Returns

boolean: true when the inventory opened it.

Example

import { onClientCallback, near, online, inventory } from "@aicore-fivem/lib/server";
import { fail } from "@aicore-fivem/lib/shared";

const ARMORY = { x: 452.3, y: -980.0, z: 30.7 };

onClientCallback(
  "my-police:armory",
  (source) => {
    if (!online.onDutyIn(source, ["police"])) return fail("NOT_ON_DUTY");
    return { ok: inventory.openInventory(source, "police_armory") };
  },
  { guards: [near(ARMORY, 3)] },
);

No range or access check happens here: check distance, job and ownership before you call it.

inventory.registerUsableItem

Runs your handler when a player uses an item. ai-core keeps the handler for inventories that start later and across inventory restarts, so register once when your script starts.

Side: Server · Waits: no

Signature
inventory.registerUsableItem(name: string, handler: UsableItemHandler): void
Lua
aiLib.inventory.registerUsableItem(name, handler) -- handler(source, item)

Parameters

The used stack is a UsedItem.

Inventories that take a used item themselves (ai-inventory) take it as soon as the handler returns anything but false. When your handler waits (a progress bar) and removes the item itself, return false at once, or the item is taken twice.

Returns

void.

Example

import { inventory, progressFor, medical, createLocale } from "@aicore-fivem/lib/server";

const Locale = createLocale();

async function bandage(source: number) {
  const done = await progressFor(source, { label: Locale("BANDAGING"), duration: 4000, canCancel: true });
  if (done && inventory.removeItem(source, "bandage")) medical.heal(source);
}

inventory.registerUsableItem("bandage", (source) => {
  void bandage(source);
  return false; // keep the item now: bandage() takes it after the bar
});

inventory.getItemDefinition

An item's label, weight and flags.

Side: Server · Waits: no

Signature
inventory.getItemDefinition(name: string): ItemDefinition | null
Lua
local def = aiLib.inventory.getItemDefinition(name)

Returns

ItemDefinition (name, label, weight, unique, close, description, image?), or null when the inventory does not know the item.

Example

const label = inventory.getItemDefinition("water")?.label ?? "water";
notify(source, `You bought ${label}`, "success");

inventory.registerShop

Registers a shop the server opens for a player (it has no place of its own). ai-core registers it again with any inventory that starts later; call it once at start.

Side: Server · Waits: no

Signature
inventory.registerShop(name: string, label: string, items: ShopProduct[]): void
Lua
aiLib.inventory.registerShop(name, label, items)

Prop

Type

Returns

void.

Example

inventory.registerShop("police_shop", "Police supplies", [
  { name: "handcuffs", price: 0 },
  { name: "radio", price: 50 },
]);

inventory.openShop

Opens a registered shop on a player's screen.

Side: Server · Waits: no

Signature
inventory.openShop(source: number, name: string): boolean
Lua
local ok = aiLib.inventory.openShop(source, name)

Returns

boolean: true when it opened.

Example

onClientCallback("my-police:shop", (source) => {
  if (!online.onDutyIn(source, ["police"])) return fail("NOT_ON_DUTY");
  return { ok: inventory.openShop(source, "police_shop") };
});

No range or access check happens here: check them before you call it.

On this page