AI Core

Items

Add, remove, count and check items in any inventory, register stashes, script shops and usable items, read item definitions and carried weight.

Every item call goes through ai-core, never through an inventory script's own exports. ai-core forwards each call to the active inventory: the one the panel's Inventory script setting picks, or the first one running when it is set to automatic (ai-inventory, ox_inventory, qb-inventory, tgiann-inventory and the others in the compatibility list). When the server owner swaps inventories, your script keeps working unchanged.

What to know:

  • An inventory is named by an InventoryRef: a player's server id (a number) for that player's pockets, or a text id for anything else (a stash name, a trunk plate). See InventoryRef.
  • Item names are the inventory's item names (water, bandage, WEAPON_PISTOL).
  • Metadata is a table of extra values on one stack (a serial number, durability). See ItemMetadata.
  • While no inventory runs, every call answers its "nothing" value: false, 0, an empty list or null.
  • Stashes, shops and usable items you register are kept by ai-core and handed to every inventory that becomes active later, including after an inventory restart. Register them once when your script starts.

AddItem

Gives items to an inventory.

Side: Server · Waits: no · Lib: inventory.addItem

Signature
AddItem(inv: InventoryRef, item: string, count?: number, metadata?: ItemMetadata, slot?: number): boolean
Lua
local ok = exports['ai-core']:AddItem(source, 'water', 2)

Parameters

Prop

Type

Returns

boolean: true when the inventory added the items. false when they do not fit, the item does not exist in the inventory, an argument is wrong (count below 1, empty item name) or no inventory runs.

Example

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

const core = resourceExport("ai-core");
const TAP = { x: 1206.4, y: -3110.2, z: 5.6 };

onClientCallback("myscript:fillBottle", { guards: [near(TAP, 2)], lock: true }, (source) => {
  if (!core.RemoveItem(source, "empty_bottle")) return fail("NO_BOTTLE");
  if (!core.AddItem(source, "water")) {
    core.AddItem(source, "empty_bottle");
    return fail("NO_SPACE");
  }
  return { ok: true };
});

RemoveItem

Takes items from an inventory.

Side: Server · Waits: no · Lib: inventory.removeItem

Signature
RemoveItem(inv: InventoryRef, item: string, count?: number, metadata?: ItemMetadata, slot?: number): boolean
Lua
local ok = exports['ai-core']:RemoveItem(source, 'lockpick', 1)

Parameters

Prop

Type

Returns

boolean: true when the items were taken. false when the inventory holds fewer (none are taken then), an argument is wrong or no inventory runs.

Example

import { onClientCallback, minigameFor, resourceExport } from "@aicore-fivem/lib/server";
import { fail } from "@aicore-fivem/lib/shared";

const core = resourceExport("ai-core");

onClientCallback("myscript:pickLock", { lock: true }, async (source) => {
  if (!core.HasItem(source, "lockpick")) return fail("NO_LOCKPICK");
  const result = await minigameFor(source, { game: "lockpick", minMs: 1500 });
  if (result === "broken") core.RemoveItem(source, "lockpick");
  return result === "won" ? { ok: true } : fail("LOCKPICK_FAILED");
});

GetItemCount

How many of an item an inventory holds.

Side: Server · Waits: no · Lib: inventory.getItemCount

Signature
GetItemCount(inv: InventoryRef, item: string, metadata?: ItemMetadata): number
Lua
local count = exports['ai-core']:GetItemCount(source, 'fish')

Parameters

Prop

Type

Returns

number: the total over every stack. 0 when there is none, an argument is wrong or no inventory runs.

Example

import { onClientCallback, resourceExport } from "@aicore-fivem/lib/server";

const core = resourceExport("ai-core");

// The fish buyer shows how much the player would get.
onClientCallback("myscript:fishQuote", (source) => ({
  ok: true,
  price: core.GetItemCount(source, "fish") * 25,
}));

HasItem

Whether an inventory holds at least a number of an item.

Side: Server · Waits: no · Lib: inventory.hasItem

Signature
HasItem(inv: InventoryRef, item: string, count?: number): boolean
Lua
local has = exports['ai-core']:HasItem(source, 'repairkit')

Parameters

Prop

Type

Returns

boolean: true when the inventory holds count or more. false when it holds fewer, count is below 1, or no inventory runs.

Example

import { onClientCallback, progressFor, resourceExport } from "@aicore-fivem/lib/server";
import { fail } from "@aicore-fivem/lib/shared";
import { Locale } from "common";

const core = resourceExport("ai-core");

onClientCallback("myscript:repair", { lock: true }, async (source) => {
  if (!core.HasItem(source, "repairkit")) return fail("NO_KIT");
  if (!(await progressFor(source, { label: Locale("REPAIRING"), duration: 8000 }))) return fail("CANCELLED");
  if (!core.RemoveItem(source, "repairkit")) return fail("NO_KIT");
  return { ok: true };
});

Check again with RemoveItem's answer after anything that waits (a progress bar, a minigame): the player may have dropped the item meanwhile.

CanCarryItem

Whether items would fit in an inventory (weight and slots), without adding them.

Side: Server · Waits: no · Lib: inventory.canCarryItem

Signature
CanCarryItem(inv: InventoryRef, item: string, count?: number, metadata?: ItemMetadata): boolean
Lua
local fits = exports['ai-core']:CanCarryItem(source, 'water', 5)

Parameters

Prop

Type

Returns

boolean: true when they fit. false when they do not, an argument is wrong or no inventory runs.

Example

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

const core = resourceExport("ai-core");

onClientCallback("myscript:buyWater", { lock: true }, (source) => {
  if (!core.CanCarryItem(source, "water", 5)) return fail("NO_SPACE");
  if (!core.RemoveMoney(source, "cash", 50, "shop_water")) return fail("NOT_ENOUGH_MONEY");
  core.AddItem(source, "water", 5);
  return { ok: true };
});

GetItems

Every stack in an inventory, with labels.

Side: Server · Waits: no · Lib: inventory.getItems

Signature
GetItems(inv: InventoryRef): InventoryStack[]
Lua
local stacks = exports['ai-core']:GetItems(source) -- list of tables

Parameters

Prop

Type

Returns

InventoryStack[]: one entry per stack with name, label, count, slot and metadata. See InventoryStack. An empty list for an empty or unknown inventory, a wrong argument or no inventory running.

Example

import { onClientCallback, resourceExport } from "@aicore-fivem/lib/server";

const core = resourceExport("ai-core");

// A pawn shop lists every item the player carries that it buys.
const BUYS: Record<string, number> = { gold_ring: 120, rolex: 400 };

onClientCallback("myscript:pawnList", (source) => ({
  ok: true,
  rows: core.GetItems(source)
    .filter((stack) => BUYS[stack.name] !== undefined)
    .map((stack) => ({ slot: stack.slot, label: stack.label, count: stack.count, price: BUYS[stack.name] })),
}));

ClearInventory

Empties an inventory completely.

Side: Server · Waits: no · Lib: inventory.clearInventory

Signature
ClearInventory(inv: InventoryRef): void
Lua
exports['ai-core']:ClearInventory(source)

Parameters

Prop

Type

Returns

Nothing. A wrong argument or no running inventory does nothing.

Example

import { addCommand, resourceExport } from "@aicore-fivem/lib/server";

const core = resourceExport("ai-core");

addCommand("clearinv", { help: "Empties a player inventory", params: [{ name: "id", type: "playerId" }], restricted: true }, (_source, args) => {
  core.ClearInventory(args.id);
});

This cannot be undone. Keep it behind an admin command or a clear game rule (a prison intake that stores the items first).

RegisterStash

Creates a stash: a storage box players open by its name. ai-core keeps it and registers it again with every inventory that becomes active.

Side: Server · Waits: no · Lib: inventory.registerStash

Signature
RegisterStash(name: string, label: string, slots: number, maxWeight: number, jobs?: string[]): void
Lua
exports['ai-core']:RegisterStash('police_evidence', 'Evidence', 100, 500000, { 'police' })

Parameters

Prop

Type

The defaults apply when a value is missing or wrong.

Returns

Nothing. Without a text name the call does nothing. Registering the same name again replaces the stash.

Example

import { onClientCallback, resourceExport, near } from "@aicore-fivem/lib/server";
import { fail } from "@aicore-fivem/lib/shared";
import { Locale } from "common";

const core = resourceExport("ai-core");
const LOCKER = { x: 474.9, y: -994.7, z: 26.3 };

// Once at start; ai-core hands it to inventories that start later.
core.RegisterStash("police_evidence", Locale("STASH_EVIDENCE"), 100, 500_000, ["police"]);

onClientCallback("myscript:openEvidence", { guards: [near(LOCKER, 2)] }, (source) => {
  if (core.GetDutyJob(source) !== "police") return fail("NOT_POLICE");
  return core.OpenInventory(source, "police_evidence") ? { ok: true } : fail("STASH_FAILED");
});

OpenInventory

Opens a stash, a trunk or another player's inventory on a player's screen, next to their own.

Side: Server · Waits: no · Lib: inventory.openInventory

Signature
OpenInventory(source: number, inv: InventoryRef): boolean
Lua
local opened = exports['ai-core']:OpenInventory(source, 'police_evidence')

Parameters

Prop

Type

Returns

boolean: true when the inventory opened the screen. false when it could not (unknown stash, the player has no inventory), an argument is wrong or no inventory runs.

Example

import { onClientCallback, isNear, coordsOf, resourceExport } from "@aicore-fivem/lib/server";
import { fail, oneArg, readId } from "@aicore-fivem/lib/shared";

const core = resourceExport("ai-core");

// Police search a handcuffed player standing next to them.
onClientCallback("myscript:search", { args: oneArg(readId) }, (source, target) => {
  if (core.GetDutyJob(source) !== "police") return fail("NOT_POLICE");
  if (target === source || !isNear(target, coordsOf(source), 2)) return fail("TOO_FAR");
  return core.OpenInventory(source, target) ? { ok: true } : fail("SEARCH_FAILED");
});

The inventory does no range or permission check here. Check the job, the distance and the target's state yourself before you call it.

RegisterShop

Creates a script shop: a list of items with prices that your script opens for a player (an armory, a vending machine). The inventory draws the shop and takes the payment its own way (cash, then bank). ai-core keeps it and hands it to every inventory that becomes active.

Side: Server · Waits: no · Lib: inventory.registerShop

Signature
RegisterShop(name: string, label: string, items: ShopProduct[]): void
Lua
exports['ai-core']:RegisterShop('police_armoury', 'Armoury', { { name = 'bandage', price = 0 } })

Parameters

Prop

Type

See ShopProduct.

Returns

Nothing. Without a text name or with no valid product the call does nothing. Registering the same name again replaces the shop.

Example

import { onClientCallback, resourceExport, near } from "@aicore-fivem/lib/server";
import { fail } from "@aicore-fivem/lib/shared";
import { Locale } from "common";

const core = resourceExport("ai-core");
const ARMOURY = { x: 482.6, y: -995.2, z: 30.7 };

core.RegisterShop("police_armoury", Locale("SHOP_ARMOURY"), [
  { name: "WEAPON_STUNGUN", price: 0 },
  { name: "bandage", price: 10 },
]);

onClientCallback("myscript:armoury", { guards: [near(ARMOURY, 2)] }, (source) => {
  if (core.GetDutyJob(source) !== "police") return fail("NOT_POLICE");
  return core.OpenShop(source, "police_armoury") ? { ok: true } : fail("SHOP_FAILED");
});

OpenShop

Opens a shop registered with RegisterShop on a player's screen.

Side: Server · Waits: no · Lib: inventory.openShop

Signature
OpenShop(source: number, name: string): boolean
Lua
local opened = exports['ai-core']:OpenShop(source, 'police_armoury')

Parameters

Prop

Type

Returns

boolean: true when the shop opened. false when no shop has that name, the active inventory has no script shops, it could not open, or no inventory runs.

Example

See the RegisterShop example above: register once at start, then open after your own job and distance checks.

Like OpenInventory, this does no range or access check. Check them first.

RegisterUsableItem

Makes an item usable: when a player uses it in the inventory, your function runs. ai-core keeps the function, so it works with inventories that start later and survives an inventory restart.

Side: Server · Waits: no · Lib: inventory.registerUsableItem

Signature
RegisterUsableItem(name: string, handler: UsableItemHandler): void
// UsableItemHandler = (source: number, item: UsedItem) => unknown
Lua
exports['ai-core']:RegisterUsableItem('bandage', function(source, item) end)

Parameters

Prop

Type

See UsableItemHandler and UsedItem.

Returns

Nothing. Without a text name or a function the call does nothing. A second call for the same item replaces the handler.

What happens to the item after use depends on the inventory: inventories that take a used item themselves (ai-inventory takes the item's consume amount) keep it when your handler returns false; other inventories follow their own item settings, so remove the item yourself there when needed.

Example

import { progressFor, resourceExport } from "@aicore-fivem/lib/server";
import { Locale } from "common";

const core = resourceExport("ai-core");

core.RegisterUsableItem("bandage", (source) => {
  // The handler must answer at once; the timed part runs on its own.
  void (async () => {
    if (!(await progressFor(source, { label: Locale("BANDAGING"), duration: 4000 }))) return;
    if (!core.RemoveItem(source, "bandage")) return;
    emitNet("myscript:client:heal", source, 25); // your client script adds the health
  })();
  return false; // keep it: it is removed above once the bar finished
});

A use also fires the server event ai-core:itemUsed (src, name, status), which item effects like hunger and thirst follow. See Events and state.

GetItemDefinition

One item as the active inventory defines it: label, weight, whether it stacks, picture.

Side: Server · Waits: no · Lib: inventory.getItemDefinition

Signature
GetItemDefinition(name: string): ItemDefinition | null
Lua
local def = exports['ai-core']:GetItemDefinition('water') -- table or nil

Parameters

Prop

Type

Returns

ItemDefinition | null: the item with name, label, weight, unique, close, description and image when the inventory has one. See ItemDefinition. null for an unknown item, an empty name or no running inventory.

Example

import { notify, resourceExport } from "@aicore-fivem/lib/server";
import { Locale } from "common";

const core = resourceExport("ai-core");

/** "You received 2x Water" with the inventory's own label. */
export function giveWithNotice(source: number, item: string, count: number): void {
  if (!core.AddItem(source, item, count)) return;
  const label = core.GetItemDefinition(item)?.label ?? item;
  notify(source, Locale("NOTIFY_RECEIVED", count, label), "success");
}

GetItemDefinitions

Every item the active inventory defines, keyed by name. Use it rarely (building a list once); for one item use GetItemDefinition.

Side: Server · Waits: no · Lib: none

Signature
GetItemDefinitions(): Record<string, ItemDefinition>
Lua
local items = exports['ai-core']:GetItemDefinitions() -- table keyed by item name

Parameters

None.

Returns

Record<string, ItemDefinition>: every item. An empty table while no inventory runs.

Example

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

const core = resourceExport("ai-core");

/** Warns at start about items in your config that the inventory does not know. */
export function checkItems(names: string[]): void {
  const known = core.GetItemDefinitions();
  for (const name of names) if (!known[name]) console.log(`unknown item: ${name}`);
}

Run such a check after the inventory started: right after a server start the inventory may not be running yet and the table is empty.

GetInventoryWeight

What a player carries and can carry, by weight.

Side: Server · Waits: no · Lib: none

Signature
GetInventoryWeight(source: number): { weight: number; maxWeight: number } | null
Lua
local w = exports['ai-core']:GetInventoryWeight(source) -- { weight, maxWeight } or nil

Parameters

Prop

Type

Returns

{ weight, maxWeight } | null: carried weight and the limit, in grams. null when the active inventory does not tell them, the player has no inventory loaded or no inventory runs.

Example

import { onClientCallback, resourceExport } from "@aicore-fivem/lib/server";

const core = resourceExport("ai-core");

onClientCallback("myscript:weight", (source) => {
  const w = core.GetInventoryWeight(source);
  return { ok: true, free: w ? w.maxWeight - w.weight : null };
});

UseItem

Runs the handler registered for an item, as if the player used it. ai-core's ESX / QB bridge calls it (from ESX.UseItem and QB's CanUseItem); a normal script has no reason to.

Side: Server · Waits: no · Lib: none (bridge only)

Signature
UseItem(source: number, name: string, item?: unknown): unknown
Lua
local result = exports['ai-core']:UseItem(source, 'bandage', stack)

Parameters

Prop

Type

Returns

unknown: what the handler returned. false when no handler is registered, the arguments are wrong or the handler threw (it is logged).

Example

No example: inventories and the bridge call it. To react to a use, register the item with RegisterUsableItem.

IsUsableItem

Whether a handler is registered for an item. ai-core's bridge uses it.

Side: Server · Waits: no · Lib: none (bridge only)

Signature
IsUsableItem(name: string): boolean
Lua
local usable = exports['ai-core']:IsUsableItem('bandage')

Parameters

Prop

Type

Returns

boolean: true when some resource registered the item with RegisterUsableItem. false otherwise.

Example

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

const core = resourceExport("ai-core");

/** Item tooltips show "Use" only for usable items. */
export function canUse(item: string): boolean {
  return core.IsUsableItem(item);
}

On this page