AI Core

Layers through ai-core

medical, appearance, gestures, seatbelt, fuel, mdt, radial, world and inventory - client calls that reach whatever death, clothing, emote, belt, fuel, MDT, radial, weather or inventory script the server runs.

These objects never talk to a specific script. They ask ai-core, and ai-core forwards to whichever script the server runs for that job: ai-death or another death script, ai-appearance or tgiann-clothing, any supported emote or radial script. Your script keeps working when the owner swaps one. How the layers work is on Layers and the bridge.

When no script of that kind runs, the calls answer false, null or the game's own value, as each entry says.

medical

medical.isDead

Whether the local player is down (dead or in last stand), in whatever death script runs. Death scripts keep a downed ped alive to animate it, so IsEntityDead alone misses them. A memory read after the first call.

Side: Client · Waits: no

Signature
medical.isDead(): boolean

No Lua twin: call exports['ai-core']:IsDead() and listen to the local event ai-core:client:dead (dead).

Returns

boolean: true when ai-core's medical layer says the player is down, or the ped is dead for the game.

Example

import { medical, notify } from "@aicore-fivem/lib/client";

RegisterCommand(
  "phone",
  () => {
    if (medical.isDead()) return notify("You cannot use the phone now", "error");
    SetNuiFocus(true, true);
  },
  false,
);

medical.onChange

Runs a handler when the local player goes down or gets up.

Side: Client · Waits: no

Signature
medical.onChange(fn: (dead: boolean) => void): void

No Lua twin: AddEventHandler('ai-core:client:dead', function(dead) end).

Parameters

Prop

Type

Returns

void.

Example

import { medical, Points } from "@aicore-fivem/lib/client";

const points = new Points();
medical.onChange(() => points.refresh()); // points whose canShow reads medical.isDead()

appearance

Looks on peds through ai-core's appearance layer, whatever clothing script runs.

appearance.apply

Puts a stored look on a ped of the look's model. Get the look on the server with appearance.get(charId), create the ped with look.model, then apply. On the player's own ped it changes their clothes.

Side: Client · Waits: no

Signature
appearance.apply(ped: number, look: CharacterAppearance): boolean
Lua
local ok = aiLib.appearance.apply(ped, look)

Parameters

Prop

Type

The type is CharacterAppearance.

Returns

boolean: false when the ped is gone, the model differs, or no clothing script runs.

Example

import { appearance, LocalPed, triggerServerCallback } from "@aicore-fivem/lib/client";
import type { CharacterAppearance } from "@aicore-fivem/shared";

// A sleeping copy of a character, dressed like them.
export async function showSleeper(charId: number): Promise<void> {
  const look = (await triggerServerCallback("mysleep:look", [charId]).catch(() => null)) as CharacterAppearance | null;
  if (!look) return;
  new LocalPed({
    model: look.model,
    coords: { x: 151.2, y: -1004.6, z: 29.4, heading: 90 },
    onSpawn: (ped) => appearance.apply(ped, look),
  });
}

Check what the server sends before you cast it. A ped created with another model than look.model cannot take the look: apply answers false.

appearance.read

The look a ped wears now.

Side: Client · Waits: no

Signature
appearance.read(ped: number): CharacterAppearance | null
Lua
local look = aiLib.appearance.read(ped) -- table or nil

Parameters

Prop

Type

Returns

CharacterAppearance | null: the look, or null (nil in Lua) when the clothing script cannot tell or none runs.

Example

import { appearance, cache } from "@aicore-fivem/lib/client";

const before = appearance.read(cache.ped); // put it back later with appearance.apply

appearance.openMenu

Opens the clothing script's clothing shop, barber or saved outfits for the player.

Side: Client · Waits: no

Signature
appearance.openMenu(menu: ClothingMenu): boolean
Lua
local ok = aiLib.appearance.openMenu(menu)

Parameters

Prop

Type

The type is ClothingMenu.

Returns

boolean: false when the clothing script has no such menu or none runs.

Example

import { appearance, Points } from "@aicore-fivem/lib/client";

const points = new Points();
points.add("barber", {
  coords: { x: -814.3, y: -183.8, z: 37.6 },
  label: "Barber",
  onPressed: () => appearance.openMenu("barber"),
});

appearance.wearOutfit

Puts a job outfit (a uniform) on the player until reloadSkin. It is not saved: a reconnect or reloadSkin gives the player's own clothes back. Only the listed pieces change.

Side: Client · Waits: no

Signature
appearance.wearOutfit(outfit: JobOutfit): boolean
Lua
local ok = aiLib.appearance.wearOutfit(outfit)

Parameters

Prop

Type

The types are JobOutfit and OutfitPiece.

Returns

boolean: false when it cannot (no clothing script, a model it does not support).

Example

import { appearance } from "@aicore-fivem/lib/client";

appearance.wearOutfit({
  components: [
    { id: 11, collection: "", index: 55, texture: 0 },
    { id: 4, collection: "", index: 35, texture: 0 },
  ],
  props: [{ id: 0, collection: "", index: -1, texture: 0 }],
});

appearance.reloadSkin

Puts the player's saved look back on (takes a job outfit off).

Side: Client · Waits: no

Signature
appearance.reloadSkin(): boolean
Lua
local ok = aiLib.appearance.reloadSkin()

Returns

boolean: false without a clothing script.

Example

import { appearance } from "@aicore-fivem/lib/client";

RegisterCommand("offduty", () => appearance.reloadSkin(), false);

gestures

Hands up, pointing and emotes of whatever emote script runs, through ai-core.

gestures.isHandsUp

Whether the local player has the hands up.

Side: Client · Waits: no

Signature
gestures.isHandsUp(): boolean
Lua
local up = aiLib.gestures.isHandsUp()

Returns

boolean: true while the hands are up in the running emote script.

Example

import { gestures, onServerCallback } from "@aicore-fivem/lib/client";

// The server asks before a robbery whether the victim surrendered.
onServerCallback("myrob:surrendered", () => gestures.isHandsUp());

gestures.isPointing

Whether the local player is pointing.

Side: Client · Waits: no

Signature
gestures.isPointing(): boolean
Lua
local pointing = aiLib.gestures.isPointing()

Returns

boolean: true while pointing.

Example

if (gestures.isPointing()) return; // do not start an emote over pointing

gestures.provider

The emote script that answers hands up and pointing.

Side: Client · Waits: no

Signature
gestures.provider(): string | null
Lua
local name = aiLib.gestures.provider()

Returns

string | null: its resource name, or null (nil) when none runs.

Example

console.log(`hands up from ${gestures.provider() ?? "nothing"}`);

gestures.playEmote

Plays an emote by its command name (what players type after e) in the running emote script.

Side: Client · Waits: no

Signature
gestures.playEmote(name: string): boolean
Lua
local ok = aiLib.gestures.playEmote(name)

Parameters

Prop

Type

Returns

boolean: false without an emote script.

Example

import { gestures } from "@aicore-fivem/lib/client";

RegisterCommand("hi", () => gestures.playEmote("wave"), false);

gestures.cancelEmote

Stops the emote the player plays (cuffed, knocked down).

Side: Client · Waits: no

Signature
gestures.cancelEmote(): boolean
Lua
local ok = aiLib.gestures.cancelEmote()

Returns

boolean: false without an emote script.

Example

onServerEvent("mypolice:cuffed", () => gestures.cancelEmote());

gestures.emoteProvider

The emote script that plays emotes (it may differ from the one answering hands up).

Side: Client · Waits: no

Signature
gestures.emoteProvider(): string | null
Lua
local name = aiLib.gestures.emoteProvider()

Returns

string | null: its resource name, or null (nil) when none runs.

Example

if (gestures.emoteProvider() === null) console.log("no emote script: skipping the emote");

seatbelt

The local player's seat belt through ai-core, whatever seat belt script runs.

seatbelt.isOn

Whether the belt is on. Ask on demand, not every frame.

Side: Client · Waits: no

Signature
seatbelt.isOn(): boolean | null
Lua
local worn = aiLib.seatbelt.isOn() -- boolean or nil

Returns

boolean | null: true or false; null (nil) when no seat belt script answers.

Example

import { cache, notify, onCache, seatbelt } from "@aicore-fivem/lib/client";

onCache("vehicle", (vehicle) => {
  if (vehicle !== false && seatbelt.isOn() === false) notify("Buckle up", "warning");
});

seatbelt.onChange

Runs a handler when the belt changes. Only seat belt scripts that report changes trigger it.

Side: Client · Waits: no

Signature
seatbelt.onChange(fn: (worn: boolean | null) => void): void
Lua
aiLib.seatbelt.onChange(function(worn) end)

Parameters

Prop

Type

Returns

void.

Example

seatbelt.onChange((worn) => SendNUIMessage({ action: "belt", data: worn === true }));

seatbelt.provider

The seat belt script that answers.

Side: Client · Waits: no

Signature
seatbelt.provider(): string | null
Lua
local name = aiLib.seatbelt.provider()

Returns

string | null: its resource name, or null (nil) when none answers.

Example

if (seatbelt.provider() === null) console.log("no seat belt script runs");

fuel

fuel.get

A vehicle's fuel level. The server keeps a fuel state bag for every vehicle whatever fuel script runs, so this is a memory read; without that bag it is the game's tank level.

Side: Client · Waits: no

Signature
fuel.get(vehicle: number): number

No Lua twin: read Entity(vehicle).state.fuel. Setting fuel is server-only (fuel.set on Vehicles).

Parameters

Prop

Type

Returns

number: 0-100.

Example

import { cache, every, fuel } from "@aicore-fivem/lib/client";

every(1000, () => {
  if (cache.vehicle !== false) SendNUIMessage({ action: "fuel", data: Math.round(fuel.get(cache.vehicle)) });
});

mdt

mdt.open

Opens the active police MDT for the local player. The MDT checks the job itself.

Side: Client · Waits: no

Signature
mdt.open(): boolean
Lua
local ok = aiLib.mdt.open()

Returns

boolean: false when no MDT runs or it cannot be opened from outside.

Example

import { mdt, notify } from "@aicore-fivem/lib/client";

RegisterCommand("mdt", () => {
  if (!mdt.open()) notify("No MDT available", "error");
}, false);

radial

Items on whichever radial menu runs (ai-radialmenu, or another through ai-core's radial layer). ai-core keeps them across radial restarts and drops them when your resource stops: add once at start.

radial.add

Adds an item to the wheel, or replaces the item with the same id.

Side: Client · Waits: no

Signature
radial.add(item: RadialItem): void
Lua
aiLib.radial.add(item)

Parameters

Prop

Type

RadialItem

Prop

Type

The type is RadialItem.

Returns

void.

Example

import { cache, createLocale, hasJob, radial } from "@aicore-fivem/lib/client";
import { RADIAL_VEHICLE } from "@aicore-fivem/shared";

const Locale = createLocale<typeof import("../../locales/en.json")>();

radial.add({
  id: "myscript:engine",
  label: Locale("ENGINE"),
  icon: "power-off",
  parent: RADIAL_VEHICLE,
  keepOpen: true,
  canShow: () => cache.seat === -1,
  onPressed: () => {
    if (cache.vehicle === false) return;
    SetVehicleEngineOn(cache.vehicle, !GetIsVehicleEngineRunning(cache.vehicle), false, true);
  },
});

radial.add({
  id: "myscript:police",
  label: Locale("POLICE"),
  icon: "shield-halved",
  canShow: () => hasJob(["police"]),
  items: [
    { id: "myscript:cuff", label: Locale("CUFF"), icon: "handcuffs", onPressed: () => emitNet("mypolice:cuff") },
  ],
});

radial.remove

Removes one of your items. An unknown id does nothing.

Side: Client · Waits: no

Signature
radial.remove(id: string): void
Lua
aiLib.radial.remove(id)

Parameters

Prop

Type

Returns

void.

Example

radial.remove("myscript:engine");

radial.refresh

Reads every canShow of an open wheel again. Call it after something they read changed while the wheel may be open.

Side: Client · Waits: no

Signature
radial.refresh(): void
Lua
aiLib.radial.refresh()

Returns

void.

Example

onMembershipChange(() => radial.refresh());

world

The weather and time sync of whatever weather script runs, paused while a reason holds.

world.pauseSync

Pauses the weather and time sync for a reason: inside an interior, during a scene, or while your script sets its own weather.

Side: Client · Waits: no

Signature
world.pauseSync(reason: string): void
Lua
aiLib.world.pauseSync(reason)

Parameters

Prop

Type

Returns

void.

Example

import { world } from "@aicore-fivem/lib/client";

export function enterApartment(): void {
  world.pauseSync("apartment");
  NetworkOverrideClockTime(12, 0, 0);
  SetWeatherTypeNowPersist("EXTRASUNNY");
}

export function leaveApartment(): void {
  world.resumeSync("apartment");
}

world.resumeSync

Removes one pause reason; the sync runs again when no reason is left.

Side: Client · Waits: no

Signature
world.resumeSync(reason: string): void
Lua
aiLib.world.resumeSync(reason)

Parameters

Prop

Type

Returns

void. See the world.pauseSync example.

inventory

The local player's inventory through ai-core's inventory layer: the inventory the server picked answers. Giving and taking items is server-only (Items).

inventory.openInventory

Opens the player's own inventory screen.

Side: Client · Waits: no

Signature
inventory.openInventory(): void
Lua
aiLib.inventory.openInventory()

Returns

void.

Example

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

RegisterCommand("bag", () => inventory.openInventory(), false);

inventory.hasItem

Whether the player holds at least count of an item. Use it in canShow so the player only sees what they can do; the server checks again.

Side: Client · Waits: no

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

Parameters

Prop

Type

Returns

boolean: true when the player has enough.

Example

import { inventory, Points } from "@aicore-fivem/lib/client";

const points = new Points();
points.addVehicle("lockpick", {
  label: "Lockpick",
  icon: "unlock",
  canShow: (vehicle) => GetVehicleDoorLockStatus(vehicle) >= 2 && inventory.hasItem("lockpick"),
  onPressed: (vehicle) => emitNet("mykeys:lockpick", NetworkGetNetworkIdFromEntity(vehicle)),
});

inventory.currentWeapon

The weapon item in the player's hand: its name, label and picture.

Side: Client · Waits: no

Signature
inventory.currentWeapon(): HeldWeapon | null
Lua
local weapon = aiLib.inventory.currentWeapon() -- table or nil

Returns

HeldWeapon { name: string; label: string; image?: string } (name like WEAPON_PISTOL, image a nui:// url when the inventory has one), or null (nil) when the hand is empty.

Example

import { inventory, onCache } from "@aicore-fivem/lib/client";

// Read it when the weapon changes, never every frame.
onCache("weapon", () => SendNUIMessage({ action: "weapon", data: inventory.currentWeapon() }));

On this page