AI Core
API-ReferenzEvents und Zustand

Server-Events

Jedes lokale Server-Event, das ai-core auslöst - Charaktere, Geld, Jobs, Dienst, Gangs, Metadaten, Definitionen, Items, Tode - mit Argumenten und Listenern in TypeScript und Lua.

ai-core löst diese Events auf dem Server mit TriggerEvent aus (lokal: andere Server-Ressourcen hören sie, Clients nie). Der online-Spiegel der Lib und die ESX- / QB- / vRP-Brücken bauen darauf auf, deshalb sind sie der günstigste Weg, Spielern zu folgen: kein Export-Aufruf, kein Polling.

Der Handler jedes Events läuft synchron, während ai-core mitten in der Änderung ist: Halte Handler kurz und warte nie darin. Wenn du warten musst (ein Schreiben in die Datenbank), starte es, ohne zu blockieren.

ai-core:playerLoaded

Der Charakter eines Spielers wurde geladen und seine Daten an seinen Client gesendet. Wird einmal pro Laden eines Charakters ausgelöst, auch nach einem Charakterwechsel. Mit aktiver Spawn-Wahl wird es ausgelöst, bevor der Spieler wählt, wo er erscheint; ai-core:playerSpawned folgt auf die Wahl.

Seite: Server · Konstante: CORE.playerLoadedEvent

Argumente

Prop

Type

Listener

resource/server/index.ts
import { CORE, type CharacterInfo } from "@aicore-fivem/shared";

on(CORE.playerLoadedEvent, (src: number, character: CharacterInfo) => {
  console.log(`#${character.id} ${character.firstname} ${character.lastname} loaded (src ${src})`);
});

Für Charaktere, die bereits geladen waren, bevor deine Ressource gestartet ist, wird dies für dich nie ausgelöst. Nutze onCharacter({ loaded }) der Lib (aiLib.onCharacter in Lua), das sie nachspielt.

ai-core:playerSpawned

Der geladene Charakter wurde in die Welt gesetzt. Wird direkt nach ai-core:playerLoaded ausgelöst oder nachdem der Spieler einen Spawnpunkt gewählt hat, wenn der Server ihn wählen lässt. Nutze es für Dinge, die den Ped in der Welt brauchen (eine Willkommensnachricht, ein Teleport).

Seite: Server · Konstante: CORE.playerSpawnedEvent

Argumente

Prop

Type

Listener

resource/server/index.ts
import { notify } from "@aicore-fivem/lib/server";
import { CORE } from "@aicore-fivem/shared";
import { Locale } from "common";

on(CORE.playerSpawnedEvent, (src: number, _charId: number) => {
  notify(src, Locale("WELCOME_BACK"), "info");
});

ai-core:playerUnloaded

Ein Charakter wird losgelassen: Der Spieler hat den Server verlassen oder ist zum Charakterbildschirm zurückgekehrt. Wird ausgelöst, bevor ai-core den Charakter verwirft, sodass die Exports von ai-core in deinem Handler noch für ihn antworten. Räume hier alles auf, was du pro Spieler hältst.

Seite: Server · Konstante: CORE.playerUnloadedEvent

Argumente

Prop

Type

Listener

resource/server/index.ts
import { CORE } from "@aicore-fivem/shared";

const activeJobs = new Map<number, string>();

on(CORE.playerUnloadedEvent, (src: number, _charId: number, reason: "dropped" | "switch") => {
  activeJobs.delete(src);
  console.log(`${src} unloaded (${reason})`);
});

Mit reason = "switch" kann dieselbe Server-ID einen Moment später einen anderen Charakter laden. Schlüssele deine Daten pro Charakter über charId oder lösche sie hier; nimm nie an, dass eine Server-ID bei einem Charakter bleibt.

ai-core:moneyChanged

Ein Kontostand eines geladenen Charakters hat sich geändert. Wird ausgelöst, nachdem die Änderung angewendet wurde, einmal pro Änderung, nur wenn sich der Kontostand wirklich bewegt hat.

Seite: Server · Konstante: CORE.moneyChangedEvent

Argumente

Prop

Type

Listener

resource/server/index.ts
import { CORE } from "@aicore-fivem/shared";

// Markiert große Bargeldzahlungen für das Team.
on(CORE.moneyChangedEvent, (src: number, account: string, balance: number, delta: number, reason: string) => {
  if (account === "cash" && delta >= 100_000)
    console.log(`${src} got $${delta} cash (${reason}), now $${balance}`);
});

ai-core:jobsChanged

Die Liste der Jobs, die ein geladener Charakter hat, hat sich geändert: ein Job hinzugefügt oder entfernt oder ein Rang geändert.

Seite: Server · Konstante: CORE.jobsChangedEvent

Argumente

Prop

Type

Listener

resource/server/index.ts
import { CORE, type JobMembership } from "@aicore-fivem/shared";

on(CORE.jobsChangedEvent, (src: number, jobs: JobMembership[]) => {
  const police = jobs.find((m) => m.job === "police");
  console.log(police ? `${src} is police grade ${police.grade}` : `${src} is not police`);
});

ai-core:dutyChanged

Ein geladener Charakter ist in einem Job in den Dienst gegangen oder außer Dienst. Ein Spieler ist höchstens in einem Job gleichzeitig im Dienst.

Seite: Server · Konstante: CORE.dutyChangedEvent

Argumente

Prop

Type

Listener

resource/server/index.ts
import { CORE } from "@aicore-fivem/shared";

on(CORE.dutyChangedEvent, (src: number, job: string | null) => {
  console.log(job ? `${src} on duty: ${job}` : `${src} off duty`);
});

Um zu wissen, wie viele Spieler in einem Job im Dienst sind, lies den GlobalState ai:duty:<job> (siehe State Bags), statt diese Events selbst zu zählen.

ai-core:gangsChanged

Die Liste der Gangs, zu denen ein geladener Charakter gehört, hat sich geändert: eine Gang hinzugefügt oder entfernt oder ein Rang geändert.

Seite: Server · Konstante: CORE.gangsChangedEvent

Argumente

Prop

Type

Listener

resource/server/index.ts
import { CORE, type GangMembership } from "@aicore-fivem/shared";

on(CORE.gangsChangedEvent, (src: number, gangs: GangMembership[]) => {
  console.log(`${src} is in ${gangs.length} gang(s)`);
});

ai-core:activeGangChanged

Ein geladener Charakter hat die Gang gewechselt, für die er handelt, oder handelt jetzt für keine.

Seite: Server · Konstante: CORE.activeGangChangedEvent

Argumente

Prop

Type

Listener

resource/server/index.ts
import { CORE } from "@aicore-fivem/shared";

on(CORE.activeGangChangedEvent, (src: number, gang: string | null) => {
  console.log(`${src} now acts for ${gang ?? "no gang"}`);
});

ai-core:metaChanged

Ein Metadatenwert eines geladenen Charakters hat sich geändert. Metadaten sind ein freier Schlüssel-/Wert-Beutel, der mit dem Charakter gespeichert wird; die ESX- / QB-Brücken legen dort Framework-Metadaten ab (hunger, thirst, stress, isdead...).

Seite: Server · Konstante: CORE.metaChangedEvent

Argumente

Prop

Type

Listener

resource/server/index.ts
import { CORE } from "@aicore-fivem/shared";

on(CORE.metaChangedEvent, (src: number, key: string, value: unknown) => {
  if (key === "stress" && typeof value === "number" && value >= 90)
    console.log(`${src} is very stressed`);
});

ai-core:definitionsChanged

Ein Job oder eine Gang wurde im Admin-Panel hinzugefügt, geändert oder gelöscht. Wird einmal pro geändertem Job oder geänderter Gang ausgelöst.

Seite: Server · Konstante: CORE.definitionsChangedEvent

Argumente

Prop

Type

Listener

resource/server/index.ts
import { CORE } from "@aicore-fivem/shared";

const labelCache = new Map<string, string>();

// Ein gecachtes Label verwerfen, wenn das Panel diesen Job ändert.
on(CORE.definitionsChangedEvent, (file: "jobs" | "gangs", name: string) => {
  if (file === "jobs") labelCache.delete(name);
});

ai-core:characterScreen

Der Charakterbildschirm eines Spielers lädt (nach dem Beitreten oder nach der Rückkehr dorthin). ai-core liest das Aussehen der Karten selbst; ein Kleidungs-Skript hört darauf, um Porträts für die Karten zu zeichnen.

Seite: Server · Konstante: CORE.characterScreenEvent

Argumente

Prop

Type

Listener

resource/server/index.ts
import { CORE } from "@aicore-fivem/shared";

on(CORE.characterScreenEvent, (src: number, charIds: number[]) => {
  console.log(`${src} sees ${charIds.length} character card(s)`);
});

ai-core:inventoryChanged

Das Inventar hinter der Inventar-Ebene von ai-core hat sich geändert: Das gewählte Inventar ist gestartet oder gestoppt, oder der Besitzer hat im Panel ein anderes gewählt. Verwirf alles, was du aus dem alten Inventar gecacht hast (Item-Labels, Definitionen).

Seite: Server · Konstante: CORE.inventoryChangedEvent

Argumente

Prop

Type

Listener

resource/server/index.ts
import { CORE } from "@aicore-fivem/shared";

let itemLabels: Record<string, string> | null = null;

on(CORE.inventoryChangedEvent, (resource: string | null) => {
  itemLabels = null; // bei der nächsten Nutzung erneut aus dem neuen Inventar lesen
  console.log(`inventory is now ${resource ?? "none"}`);
});

ai-core:itemUsed

Ein Spieler hat ein Item benutzt. Trägt die Bedürfnisse, die das Item gibt (Hunger, Durst, Stress), sodass ein HUD oder Bedürfnis-Skript sie anwendet, ohne das Inventar zu kennen. ai-hud hört darauf.

Seite: Server · Konstante: CORE.itemUsedEvent

Argumente

Prop

Type

Listener

resource/server/needs.ts
import { CORE } from "@aicore-fivem/shared";

on(CORE.itemUsedEvent, (src: number, name: string, status: Record<string, number> | null) => {
  if (!status) return;
  for (const [need, amount] of Object.entries(status))
    console.log(`${src} used ${name}: ${need} ${amount > 0 ? "+" : ""}${amount}`);
});

Derzeit meldet nur ai-inventory Item-Benutzungen an ai-core: Mit einem anderen Inventar wird dieses Event nicht ausgelöst. Höre auf dieses Event, nicht auf das eigene Benutzungs-Event eines Inventars, damit dein Skript funktioniert, wenn ai-inventory das Inventar ist, und weiter funktioniert, wenn andere hinzukommen.

ai-core:playerDied

Ein Spieler mit geladenem Charakter ist gestorben. ai-core übernimmt das aus der eigenen Ped-Todesmeldung von FXServer (FXServer 38039 oder neuer), sodass keinem Client vertraut wird.

Seite: Server · Konstante: CORE.playerDiedEvent

Argumente

Prop

Type

Listener

resource/server/killfeed.ts
import { CORE } from "@aicore-fivem/shared";

on(CORE.playerDiedEvent, (src: number, killer: number | null, weaponHash: number) => {
  if (killer !== null && killer !== src)
    console.log(`${GetPlayerName(String(killer))} killed ${GetPlayerName(String(src))} (weapon ${weaponHash})`);
});

Das ist der Tod im Spiel, nicht der Zustand „am Boden“ des Tod-Skripts: Ein Tod-Skript kann einen Spieler am Boden am Leben halten, um ihn zu animieren. Für „ist dieser Spieler am Boden“ nutze medical der Server-Lib oder die Medizin-Exports des Servers von ai-core.

ai-core:vrp:config

Der Serverbesitzer hat die vRP-Zuordnung im Panel von ai-core geändert (Tab "vRP scripts", vRP-Skripte). Die vRP-Brücke von ai-core hört darauf; du brauchst es nur, wenn du die vRP-Zuordnung selbst liest.

Seite: Server · Konstante: VRP.configEvent

Argumente

Prop

Type

Listener

resource/server/index.ts
import { VRP, type VrpConfig } from "@aicore-fivem/shared";

on(VRP.configEvent, (config: VrpConfig) => {
  console.log(`${config.permissions.length} vRP permission rule(s)`);
});

Events anderer ai-*-Skripte

Diese werden von ai-*-Skripten ausgelöst, nicht von ai-core, aber viele Ressourcen hören darauf. Ihre vollständige Referenz steht auf der Developer-Seite jedes Skripts.

ai-vehicles:owners

Die Besitzer der Fahrzeuge mit Besitzer im Speicher haben sich geändert (ein Charakter wurde mit seiner Garage geladen, ein Fahrzeug gekauft, verkauft oder gelöscht). Wird höchstens einmal pro Server-Tick mit jeder Änderung dieses Ticks ausgelöst. Schlüssel-Skripte nutzen es, um eine Zuordnung von Kennzeichen zu Besitzer zu führen, ohne ai-vehicles jedes Mal zu fragen.

Seite: Server · Konstante: VEHICLES_EVENTS.owners

Argumente

Prop

Type

Listener

resource/server/owners.ts
import { resourceExport } from "@aicore-fivem/lib/server";
import { VEHICLES_EVENTS } from "@aicore-fivem/shared";

const owners = new Map<string, string>();

// Mit der vollständigen Liste beginnen, dann den Änderungen folgen.
for (const [plate, type, id] of resourceExport("ai-vehicles").GetPlateOwners()) owners.set(plate, `${type}:${id}`);

on(VEHICLES_EVENTS.owners, (puts: Array<[string, string, string]>, removes: string[]) => {
  for (const [plate, type, id] of puts) owners.set(plate, `${type}:${id}`);
  for (const plate of removes) owners.delete(plate);
});

chatMessage

ai-chat löst das klassische FiveM-Event chatMessage aus, bevor es die Nachricht eines Spielers zustellt. CancelEvent() in deinem Handler aufzurufen verwirft die Nachricht.

Seite: Server · Konstante: keine (der eigene Name von FiveM)

Argumente

Prop

Type

Listener

resource/server/filter.ts
on("chatMessage", (source: number, _author: string, text: string) => {
  if (text.toLowerCase().includes("discord.gg")) {
    CancelEvent();
    console.log(`blocked an invite link from ${source}`);
  }
});

Auf dieser Seite