AI Core

Shared UI

notify, progress, menu, input, prompts, skillCheck, lockpick and itemPicker - the player UI ai-lib draws for every resource.

ai-lib draws one shared UI for every resource: notification cards, the progress bar, the "press E" prompts, menus, input dialogs and minigames. Your script only asks for them, so every script on the server looks the same and you write no NUI for these. The item picker is drawn by ai-core.

Texts you pass are shown as they are: translate them first (Locale("KEY") in TypeScript, t('KEY') in Lua).

Notifications

notify

Shows a notification card on this player's screen.

Side: Client · Waits: no

Signature
notify(text: string, kind?: NotificationKind, duration?: number): void
Lua
aiLib.notify(text, kind, duration)

Parameters

Prop

Type

The kind type is NotificationKind. To notify a player from the server, use the server notify(source, text, kind).

Returns

void.

Example

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

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

notify(Locale("WELCOME"));
notify(Locale("NO_MONEY"), "error");
notify(Locale("SAVED"), "success", 2000);

Progress bar

progress

Runs a timed action with ai-lib's progress bar and an optional animation or scenario, and waits until it ends. It ends early (cancelled) when the player dies, gets into a vehicle, presses ai-lib's cancel key (default Backspace, only with canCancel), or your script calls cancelProgress(). One progress per resource at a time.

Side: Client · Waits: yes (Promise in TypeScript, yields the thread in Lua)

Signature
progress(options: ProgressOptions): Promise<boolean>
Lua
local finished = aiLib.progress(options) -- boolean, call inside a thread

Parameters

Prop

Type

ProgressOptions

Prop

Type

Returns

Promise<boolean>: true when the bar ran out; false when it was cancelled, or at once when another progress of your resource is still running. Lua returns the same boolean.

Example

import { callAction, createLocale, nearestVehicle, notify, progress } from "@aicore-fivem/lib/client";

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

export async function repair(): Promise<void> {
  const vehicle = nearestVehicle(4, { notOwn: true });
  if (!vehicle) return notify(Locale("NO_VEHICLE"), "error");
  const [x = 0, y = 0, z = 0] = GetEntityCoords(vehicle, false);
  const done = await progress({
    label: Locale("REPAIRING"),
    duration: 8000,
    face: { x, y, z },
    anim: { dict: "mini@repair", clip: "fixing_a_player" },
    canCancel: true,
    disable: { move: true, combat: true },
  });
  if (!done) return notify(Locale("CANCELLED"), "error");
  await callAction("mymech:repair", [NetworkGetNetworkIdFromEntity(vehicle)], { fallback: "REPAIR_FAILED" });
}

The result is the client's word: a cheater can skip the bar. When the server pays for the action (items, money, a repair), run the bar from the server with progressFor(source, options) (Client input): it only answers true when enough time passed on the server too.

cancelProgress

Cancels your resource's running progress, whether or not the player may cancel it. The progress call then resolves false. Nothing happens when no progress runs.

Side: Client · Waits: no

Signature
cancelProgress(): void
Lua
aiLib.progress.cancel()

Returns

void.

Example

import { cancelProgress, onServerEvent } from "@aicore-fivem/lib/client";

// The server says the target was robbed by someone else.
onServerEvent("myrob:taken", () => cancelProgress());

isProgressRunning

Whether a progress of your resource is running now.

Side: Client · Waits: no

Signature
isProgressRunning(): boolean
Lua
local running = aiLib.progress.isRunning()

Returns

boolean: true while your resource's bar runs. Other resources' bars do not count.

Example

import { isProgressRunning, menu } from "@aicore-fivem/lib/client";

export async function openMenu(): Promise<void> {
  if (isProgressRunning()) return; // busy
  await menu({ title: "Actions", items: [{ id: "a", label: "Action" }] });
}

Shows ai-lib's menu and waits for the player's pick. Arrow keys move, Enter picks. Items with checked are switch rows that flip in place without closing the menu. In a sub menu (back: true), a short Escape resolves MENU_BACK so you can open the menu before; holding Escape closes.

Side: Client · Waits: yes (Promise in TypeScript, yields the thread in Lua)

Signature
menu(request: MenuRequest, listeners?: ((item: string) => void) | MenuListeners): Promise<string | null>
Lua
local picked = aiLib.menu.show(request, listeners) -- string or nil, call inside a thread

Parameters

Prop

Type

Prop

Type

Prop

Type

The types are MenuRequest and MenuItem.

Prop

Type

Returns

Promise<string | null>: the picked item id; "__back" (MENU_BACK from @aicore-fivem/shared) after a short Escape in a sub menu; null when the player closed the menu. Lua returns the same, nil for closed.

Example

import { callAction, createLocale, menu } from "@aicore-fivem/lib/client";
import { MENU_BACK } from "@aicore-fivem/shared";

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

export async function vehicleMenu(vehicle: number): Promise<void> {
  const pick = await menu({
    title: Locale("VEHICLE"),
    items: [
      { id: "doors", label: Locale("DOORS"), icon: "door-open" },
      { id: "engine", label: Locale("ENGINE"), icon: "power-off", checked: engineOn },
    ],
  }, {
    onToggle: (item, checked) => {
      if (item !== "engine") return;
      engineOn = checked;
      SetVehicleEngineOn(vehicle, checked, false, true);
    },
  });
  if (pick === "doors") await doorsMenu(vehicle);
}

async function doorsMenu(vehicle: number): Promise<void> {
  const pick = await menu({
    title: Locale("DOORS"),
    back: true,
    items: [0, 1, 2, 3].map((door) => ({ id: String(door), label: Locale("DOOR", door + 1) })),
  });
  if (pick === MENU_BACK) return vehicleMenu(vehicle);
  if (pick !== null) SetVehicleDoorOpen(vehicle, Number(pick), false, false);
}

The picked id comes from the player's client: the server must check that it is a valid choice.

input

Shows ai-lib's input dialog and waits for the values. Each field is a number box or a text box.

Side: Client · Waits: yes (Promise in TypeScript, yields the thread in Lua)

Signature
input(request: InputRequest): Promise<Record<string, string | number> | null>
Lua
local values = aiLib.input(request) -- table or nil, call inside a thread

Parameters

Prop

Type

InputRequest

Prop

Type

InputField: number

Prop

Type

InputField: text

Prop

Type

The types are InputRequest and InputField.

Returns

Promise<Record<string, string | number> | null>: the entered values by field name when the player confirmed; null when they closed the dialog. Values that are neither a string nor a number are left out. Lua returns the table or nil.

Example

import { callAction, createLocale, input } from "@aicore-fivem/lib/client";

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

export async function sendBill(target: number): Promise<void> {
  const values = await input({
    title: Locale("BILL"),
    confirm: Locale("SEND"),
    fields: [
      { name: "amount", label: Locale("AMOUNT"), type: "number", min: 1, max: 100000 },
      { name: "reason", label: Locale("REASON"), type: "text", maxLength: 80 },
    ],
  });
  if (!values) return;
  await callAction("mybill:send", [target, values.amount, values.reason], { fallback: "BILL_FAILED" });
}

min, max and maxLength only guide the player. The server must check every value again (readInt, readText in the server handler).

itemPicker

Admin tools: shows ai-core's item picker. It lists every item of the active inventory with its picture and a search; clicks fill a list on the right (1 per click, 10 with Ctrl, 100 with Shift) that stops at the target's weight limit. The item list is only sent to admins.

Side: Client · Waits: yes (Promise in TypeScript, yields the thread in Lua)

Signature
itemPicker(request: ItemPickerRequest): Promise<PickedItem[] | null>
Lua
local list = aiLib.itemPicker(request) -- table or nil, call inside a thread

Parameters

Prop

Type

ItemPickerRequest

Prop

Type

Returns

Promise<PickedItem[] | null>: the list the admin took, each row { name: string; count: number } (count a whole number above 0); null when the picker was closed. Lua returns the list or nil. The types are ItemPickerRequest and PickedItem.

Example

import { callAction, itemPicker } from "@aicore-fivem/lib/client";

export async function giveItems(target: number): Promise<void> {
  const list = await itemPicker({ title: "Give items", target });
  if (!list || list.length === 0) return;
  await callAction("myadmin:give", [target, list], { fallback: "GIVE_FAILED" });
}

Your server handler gives the items: check that the caller is an admin (isAdmin guard) and check every name and count again. The picker never gives anything by itself.

Prompts by hand

Points show and hide prompts for you. Use these only for a prompt that is not tied to a place.

showPrompt

Shows (or changes the text of) one of your resource's prompts: the "press E" box on the right of the screen. With at, the prompt floats over a world point or an entity spot instead.

Side: Client · Waits: no

Signature
showPrompt(id: string, text: string, at?: PromptAnchor): void
Lua
aiLib.showPrompt(id, text) -- no world anchor in Lua

Parameters

Prop

Type

Returns

void.

Example

See onPromptPressed.

hidePrompt

Hides one of your resource's prompts. An id that is not shown does nothing.

Side: Client · Waits: no

Signature
hidePrompt(id: string): void
Lua
aiLib.hidePrompt(id)

Parameters

Prop

Type

Returns

void.

onPromptPressed

Runs a handler when the player presses the interaction key (default E) while one of your resource's prompts is the one on top.

Side: Client · Waits: no

Signature
onPromptPressed(handler: (id: string) => void): void
Lua
aiLib.onPromptPressed(function(id) end)

Parameters

Prop

Type

Returns

void.

Example

import { createLocale, hidePrompt, onCache, onPromptPressed, showPrompt } from "@aicore-fivem/lib/client";

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

// "Press E to eject" while sitting in the passenger seat.
onCache("seat", (seat) => {
  if (seat === 0) showPrompt("eject", Locale("EJECT"));
  else hidePrompt("eject");
});

onPromptPressed((id) => {
  if (id !== "eject") return;
  TaskLeaveVehicle(PlayerPedId(), GetVehiclePedIsIn(PlayerPedId(), false), 4160);
});

Minigames

skillCheck

ai-lib's skill check: a needle runs around a ring once per stage, and the player presses the shown key while it is on the green arc. It has the common FiveM skill check shape ("easy" | "medium" | "hard" or { areaSize, speedMultiplier }), so code written for ox_lib's skill check works the same.

Side: Client · Waits: yes (Promise in TypeScript, yields the thread in Lua)

Signature
skillCheck(difficulty: SkillDifficulty | SkillDifficulty[], keys?: string[]): Promise<boolean>
Lua
local passed = aiLib.skillCheck(difficulty, keys) -- boolean, call inside a thread

Parameters

Prop

Type

SkillDifficulty

SkillDifficulty is one of:

Prop

Type

Returns

Promise<boolean>: true when every stage was hit; false on a miss, a wrong key or Escape.

Example

import { callAction, skillCheck } from "@aicore-fivem/lib/client";

export async function hotwire(netId: number): Promise<void> {
  const passed = await skillCheck(["easy", "easy", "medium", { areaSize: 30, speedMultiplier: 1.5 }], ["w", "a", "s", "d"]);
  await callAction("mykeys:hotwire", [netId, passed], { fallback: "HOTWIRE_FAILED" });
}

The result is the client's word. When the minigame pays (a car, a robbery), play it from the server with minigameFor(source, { game: "skillCheck", ... }), which also refuses a win faster than a real play (Client input).

lockpick

ai-lib's lockpick: the player moves the pick with A / D (or the arrows) and holds W to turn the lock. The lock turns further the closer the pick is to the hidden sweet spot; forcing it wears the pick down.

Side: Client · Waits: yes (Promise in TypeScript, yields the thread in Lua)

Signature
lockpick(options?: LockpickOptions): Promise<LockpickResult>
Lua
local result = aiLib.lockpick(options) -- 'opened' | 'broken' | 'cancelled', call inside a thread

Parameters

Prop

Type

LockpickOptions

Prop

Type

Returns

Promise<LockpickResult> (LockpickResult): "opened" when every pin turned; "broken" when the last pick broke (take the lockpick item); "cancelled" when the player pressed Escape.

Example

import { callAction, lockpick } from "@aicore-fivem/lib/client";

export async function pickDoor(doorId: string): Promise<void> {
  const result = await lockpick({ difficulty: "hard", pins: 3, picks: 2 });
  if (result === "cancelled") return;
  await callAction("mydoors:picked", [doorId, result], { fallback: "PICK_FAILED" });
}

On this page