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 ornull. - 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
AddItem(inv: InventoryRef, item: string, count?: number, metadata?: ItemMetadata, slot?: number): booleanlocal 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
RemoveItem(inv: InventoryRef, item: string, count?: number, metadata?: ItemMetadata, slot?: number): booleanlocal 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
GetItemCount(inv: InventoryRef, item: string, metadata?: ItemMetadata): numberlocal 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
HasItem(inv: InventoryRef, item: string, count?: number): booleanlocal 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
CanCarryItem(inv: InventoryRef, item: string, count?: number, metadata?: ItemMetadata): booleanlocal 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
GetItems(inv: InventoryRef): InventoryStack[]local stacks = exports['ai-core']:GetItems(source) -- list of tablesParameters
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
ClearInventory(inv: InventoryRef): voidexports['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
RegisterStash(name: string, label: string, slots: number, maxWeight: number, jobs?: string[]): voidexports['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
OpenInventory(source: number, inv: InventoryRef): booleanlocal 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
RegisterShop(name: string, label: string, items: ShopProduct[]): voidexports['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
OpenShop(source: number, name: string): booleanlocal 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
RegisterUsableItem(name: string, handler: UsableItemHandler): void
// UsableItemHandler = (source: number, item: UsedItem) => unknownexports['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
GetItemDefinition(name: string): ItemDefinition | nulllocal def = exports['ai-core']:GetItemDefinition('water') -- table or nilParameters
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
GetItemDefinitions(): Record<string, ItemDefinition>local items = exports['ai-core']:GetItemDefinitions() -- table keyed by item nameParameters
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
GetInventoryWeight(source: number): { weight: number; maxWeight: number } | nulllocal w = exports['ai-core']:GetInventoryWeight(source) -- { weight, maxWeight } or nilParameters
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)
UseItem(source: number, name: string, item?: unknown): unknownlocal 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)
IsUsableItem(name: string): booleanlocal 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);
}