Gemeinsame UI
notify, progress, menu, input, Prompts, skillCheck, lockpick und itemPicker - die Spieler-UI, die ai-lib für jede Ressource zeichnet.
ai-lib zeichnet eine gemeinsame UI für jede Ressource: Benachrichtigungskarten, den Fortschrittsbalken, die „Drücke E“-Prompts, Menüs, Eingabedialoge und Minispiele. Dein Skript fordert sie nur an, daher sieht jedes Skript auf dem Server gleich aus, und du schreibst dafür keine NUI. Die Item-Auswahl zeichnet ai-core.
Texte, die du übergibst, werden so angezeigt, wie sie sind: Übersetze sie zuerst (Locale("KEY") in TypeScript, t('KEY') in Lua).
Benachrichtigungen
notify
Zeigt eine Benachrichtigungskarte auf dem Bildschirm dieses Spielers.
Seite: Client · Wartet: nein
notify(text: string, kind?: NotificationKind, duration?: number): voidaiLib.notify(text, kind, duration)Parameter
Prop
Type
Der Typ von kind ist NotificationKind. Um einen Spieler vom Server aus zu benachrichtigen, nutze das Server-notify(source, text, kind).
Rückgabewert
void.
Beispiel
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);Fortschrittsbalken
progress
Führt eine zeitgesteuerte Aktion mit dem Fortschrittsbalken von ai-lib und einer optionalen Animation oder einem Szenario aus und wartet, bis sie endet. Sie endet vorzeitig (abgebrochen), wenn der Spieler stirbt, in ein Fahrzeug steigt, die Abbruchtaste von ai-lib drückt (Standard Backspace, nur mit canCancel) oder dein Skript cancelProgress() aufruft. Ein Fortschritt pro Ressource zur Zeit.
Seite: Client · Wartet: ja (Promise in TypeScript, hält in Lua den Thread an)
progress(options: ProgressOptions): Promise<boolean>local finished = aiLib.progress(options) -- boolean, innerhalb eines Threads aufrufenParameter
Prop
Type
ProgressOptions
Prop
Type
Rückgabewert
Promise<boolean>: true, wenn der Balken abgelaufen ist; false, wenn er abgebrochen wurde, oder sofort, wenn noch ein anderer Fortschritt deiner Ressource läuft. Lua gibt denselben Boolean zurück.
Beispiel
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" });
}Das Ergebnis ist das Wort des Clients: Ein Cheater kann den Balken überspringen. Wenn der Server für die Aktion bezahlt (Items, Geld, eine Reparatur), starte den Balken vom Server mit progressFor(source, options) (Client-Eingaben): Es antwortet nur mit true, wenn auch auf dem Server genug Zeit vergangen ist.
cancelProgress
Bricht den laufenden Fortschritt deiner Ressource ab, egal ob der Spieler ihn abbrechen darf. Der progress-Aufruf wird dann mit false erfüllt. Es passiert nichts, wenn kein Fortschritt läuft.
Seite: Client · Wartet: nein
cancelProgress(): voidaiLib.progress.cancel()Rückgabewert
void.
Beispiel
import { cancelProgress, onServerEvent } from "@aicore-fivem/lib/client";
// Der Server sagt, das Ziel wurde von jemand anderem ausgeraubt.
onServerEvent("myrob:taken", () => cancelProgress());isProgressRunning
Ob gerade ein Fortschritt deiner Ressource läuft.
Seite: Client · Wartet: nein
isProgressRunning(): booleanlocal running = aiLib.progress.isRunning()Rückgabewert
boolean: true, solange der Balken deiner Ressource läuft. Balken anderer Ressourcen zählen nicht.
Beispiel
import { isProgressRunning, menu } from "@aicore-fivem/lib/client";
export async function openMenu(): Promise<void> {
if (isProgressRunning()) return; // beschäftigt
await menu({ title: "Actions", items: [{ id: "a", label: "Action" }] });
}Menüs und Dialoge
menu
Zeigt das Menü von ai-lib und wartet auf die Wahl des Spielers. Pfeiltasten bewegen, Enter wählt. Einträge mit checked sind Schalterzeilen, die an Ort und Stelle umschalten, ohne das Menü zu schließen. In einem Untermenü (back: true) ergibt ein kurzes Escape MENU_BACK, damit du das vorherige Menü öffnen kannst; Escape gedrückt halten schließt.
Seite: Client · Wartet: ja (Promise in TypeScript, hält in Lua den Thread an)
menu(request: MenuRequest, listeners?: ((item: string) => void) | MenuListeners): Promise<string | null>local picked = aiLib.menu.show(request, listeners) -- string oder nil, innerhalb eines Threads aufrufenParameter
Prop
Type
MenuRequest
Prop
Type
MenuItem
Prop
Type
Die Typen sind MenuRequest und MenuItem.
MenuListeners
Prop
Type
Rückgabewert
Promise<string | null>: die gewählte Eintrags-ID; "__back" (MENU_BACK aus @aicore-fivem/shared) nach einem kurzen Escape in einem Untermenü; null, wenn der Spieler das Menü geschlossen hat. Lua gibt dasselbe zurück, nil für geschlossen.
Beispiel
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);
}Die gewählte ID kommt vom Client des Spielers: Der Server muss prüfen, dass sie eine gültige Wahl ist.
input
Zeigt den Eingabedialog von ai-lib und wartet auf die Werte. Jedes Feld ist ein Zahlenfeld oder ein Textfeld.
Seite: Client · Wartet: ja (Promise in TypeScript, hält in Lua den Thread an)
input(request: InputRequest): Promise<Record<string, string | number> | null>local values = aiLib.input(request) -- table oder nil, innerhalb eines Threads aufrufenParameter
Prop
Type
InputRequest
Prop
Type
InputField: number
Prop
Type
InputField: text
Prop
Type
Die Typen sind InputRequest und InputField.
Rückgabewert
Promise<Record<string, string | number> | null>: die eingegebenen Werte nach Feld-name, wenn der Spieler bestätigt hat; null, wenn er den Dialog geschlossen hat. Werte, die weder String noch Zahl sind, werden weggelassen. Lua gibt die Tabelle oder nil zurück.
Beispiel
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 und maxLength leiten den Spieler nur. Der Server muss jeden Wert erneut prüfen (readInt, readText im Server-Handler).
itemPicker
Admin-Werkzeuge: zeigt die Item-Auswahl von ai-core. Sie listet jedes Item des aktiven Inventars mit Bild und einer Suche; Klicks füllen eine Liste rechts (1 pro Klick, 10 mit Strg, 100 mit Shift), die am Gewichtslimit des Ziels stoppt. Die Item-Liste wird nur an Admins gesendet.
Seite: Client · Wartet: ja (Promise in TypeScript, hält in Lua den Thread an)
itemPicker(request: ItemPickerRequest): Promise<PickedItem[] | null>local list = aiLib.itemPicker(request) -- table oder nil, innerhalb eines Threads aufrufenParameter
Prop
Type
ItemPickerRequest
Prop
Type
Rückgabewert
Promise<PickedItem[] | null>: die Liste, die der Admin genommen hat, jede Zeile { name: string; count: number } (count eine ganze Zahl über 0); null, wenn die Auswahl geschlossen wurde. Lua gibt die Liste oder nil zurück. Die Typen sind ItemPickerRequest und PickedItem.
Beispiel
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" });
}Dein Server-Handler gibt die Items: Prüfe, dass der Aufrufer ein Admin ist (Guard isAdmin), und prüfe jeden Namen und jede Anzahl erneut. Die Auswahl gibt nie selbst etwas.
Prompts von Hand
Punkte zeigen und verbergen Prompts für dich. Nutze diese nur für einen Prompt, der nicht an einen Ort gebunden ist.
showPrompt
Zeigt einen der Prompts deiner Ressource an (oder ändert seinen Text): das „Drücke E“-Feld rechts auf dem Bildschirm. Mit at schwebt der Prompt stattdessen über einem Weltpunkt oder einer Stelle an einer Entity.
Seite: Client · Wartet: nein
showPrompt(id: string, text: string, at?: PromptAnchor): voidaiLib.showPrompt(id, text) -- in Lua kein WeltankerParameter
Prop
Type
Rückgabewert
void.
Beispiel
Siehe onPromptPressed.
hidePrompt
Verbirgt einen der Prompts deiner Ressource. Eine ID, die nicht angezeigt wird, tut nichts.
Seite: Client · Wartet: nein
hidePrompt(id: string): voidaiLib.hidePrompt(id)Parameter
Prop
Type
Rückgabewert
void.
onPromptPressed
Führt einen Handler aus, wenn der Spieler die Interaktionstaste drückt (Standard E), während einer der Prompts deiner Ressource der oberste ist.
Seite: Client · Wartet: nein
onPromptPressed(handler: (id: string) => void): voidaiLib.onPromptPressed(function(id) end)Parameter
Prop
Type
Rückgabewert
void.
Beispiel
import { createLocale, hidePrompt, onCache, onPromptPressed, showPrompt } from "@aicore-fivem/lib/client";
const Locale = createLocale<typeof import("../../locales/en.json")>();
// „Drücke E zum Hinauswerfen“, während man auf dem Beifahrersitz sitzt.
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);
});Minispiele
skillCheck
Der Skill-Check von ai-lib: Eine Nadel läuft pro Stufe einmal um einen Ring, und der Spieler drückt die angezeigte Taste, während sie im grünen Bogen ist. Er hat die übliche FiveM-Skill-Check-Form ("easy" | "medium" | "hard" oder { areaSize, speedMultiplier }), daher funktioniert Code, der für den Skill-Check von ox_lib geschrieben wurde, genauso.
Seite: Client · Wartet: ja (Promise in TypeScript, hält in Lua den Thread an)
skillCheck(difficulty: SkillDifficulty | SkillDifficulty[], keys?: string[]): Promise<boolean>local passed = aiLib.skillCheck(difficulty, keys) -- boolean, innerhalb eines Threads aufrufenParameter
Prop
Type
SkillDifficulty
SkillDifficulty ist eines von:
Prop
Type
Rückgabewert
Promise<boolean>: true, wenn jede Stufe getroffen wurde; false bei einem Fehlschlag, einer falschen Taste oder Escape.
Beispiel
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" });
}Das Ergebnis ist das Wort des Clients. Wenn das Minispiel etwas einbringt (ein Auto, ein Raub), spiele es vom Server mit minigameFor(source, { game: "skillCheck", ... }), das außerdem einen Sieg ablehnt, der schneller ist als ein echtes Spiel (Client-Eingaben).
lockpick
Das Schlossknacken von ai-lib: Der Spieler bewegt den Dietrich mit A / D (oder den Pfeiltasten) und hält W, um das Schloss zu drehen. Das Schloss dreht sich umso weiter, je näher der Dietrich am versteckten Sweet Spot ist; Gewalt nutzt den Dietrich ab.
Seite: Client · Wartet: ja (Promise in TypeScript, hält in Lua den Thread an)
lockpick(options?: LockpickOptions): Promise<LockpickResult>local result = aiLib.lockpick(options) -- 'opened' | 'broken' | 'cancelled', innerhalb eines Threads aufrufenParameter
Prop
Type
LockpickOptions
Prop
Type
Rückgabewert
Promise<LockpickResult> (LockpickResult): "opened", wenn jeder Stift gedreht wurde; "broken", wenn der letzte Dietrich zerbrochen ist (nimm das Dietrich-Item weg); "cancelled", wenn der Spieler Escape gedrückt hat.
Beispiel
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" });
}Peds, Blips und Props
LocalPed, Blips, createBlip, attachProp, PreviewVehicle und player.holdAnim - lokale NPCs, Karten-Blips, gehaltene Props, Ausstellungsfahrzeuge und gehaltene Animationen.
Bildschirme und Steuerung
NuiScreen, hud, keyHints und controls - deine eigene Vollbild-NUI, jedes HUD ausblenden, Tastenhilfe-Zeilen und deaktivierte Steuerungen.