Eventos de servidor
Cada evento local de servidor que dispara ai-core - personajes, dinero, trabajos, servicio, bandas, metadatos, definiciones, objetos, muertes - con sus argumentos y listeners en TypeScript y Lua.
ai-core dispara estos eventos en el servidor con TriggerEvent (locales: los oyen los demás recursos de servidor, los clientes nunca). El espejo online de la lib y los puentes de ESX / QB / vRP se basan en ellos, así que son la forma más barata de seguir a los jugadores: ni llamadas a exports ni consultas periódicas.
El handler de cada evento se ejecuta de forma síncrona mientras ai-core está en mitad del cambio: mantén los handlers cortos y nunca esperes dentro de ellos. Si necesitas esperar (una escritura en la base de datos), iníciala sin bloquear.
ai-core:playerLoaded
Se cargó el personaje de un jugador y sus datos se enviaron a su cliente. Se dispara una vez por carga de personaje, también tras un cambio de personaje. Con la elección de aparición activada, se dispara antes de que el jugador elija dónde aparecer; ai-core:playerSpawned sigue a la elección.
Lado: Servidor · Constante: CORE.playerLoadedEvent
Argumentos
Prop
Type
Oyente
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})`);
});Los personajes que ya estaban cargados antes de que se iniciara tu recurso nunca te disparan esto. Usa el onCharacter({ loaded }) de la lib (aiLib.onCharacter en Lua), que vuelve a pasártelos.
ai-core:playerSpawned
Se puso al personaje cargado en el mundo. Se dispara justo después de ai-core:playerLoaded, o después de que el jugador elija un punto de aparición cuando el servidor le deja elegir. Úsalo para cosas que necesitan el ped en el mundo (un mensaje de bienvenida, un teletransporte).
Lado: Servidor · Constante: CORE.playerSpawnedEvent
Argumentos
Prop
Type
Oyente
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
Se está soltando a un personaje: el jugador salió del servidor o volvió a la pantalla de personajes. Se dispara antes de que ai-core descarte el personaje, así que los exports de ai-core siguen respondiendo por él dentro de tu handler. Limpia aquí todo lo que guardes por jugador.
Lado: Servidor · Constante: CORE.playerUnloadedEvent
Argumentos
Prop
Type
Oyente
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})`);
});Con reason = "switch" el mismo id de servidor puede cargar otro personaje un momento después. Guarda tus datos por personaje con charId como clave o bórralos aquí; nunca supongas que un id de servidor conserva un mismo personaje.
ai-core:moneyChanged
Cambió el saldo de una cuenta de un personaje cargado. Se dispara después de aplicar el cambio, una vez por cambio, solo cuando el saldo se movió de verdad.
Lado: Servidor · Constante: CORE.moneyChangedEvent
Argumentos
Prop
Type
Oyente
import { CORE } from "@aicore-fivem/shared";
// Marca los pagos grandes en efectivo para el staff.
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
Cambió la lista de trabajos que tiene un personaje cargado: se añadió o quitó un trabajo, o cambió un rango.
Lado: Servidor · Constante: CORE.jobsChangedEvent
Argumentos
Prop
Type
Oyente
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
Un personaje cargado entró de servicio en un trabajo, o salió de servicio. Un jugador está de servicio en como mucho un trabajo a la vez.
Lado: Servidor · Constante: CORE.dutyChangedEvent
Argumentos
Prop
Type
Oyente
import { CORE } from "@aicore-fivem/shared";
on(CORE.dutyChangedEvent, (src: number, job: string | null) => {
console.log(job ? `${src} on duty: ${job}` : `${src} off duty`);
});Para saber cuántos jugadores están de servicio en un trabajo, lee el GlobalState ai:duty:<job> (consulta State bags) en lugar de contar tú estos eventos.
ai-core:gangsChanged
Cambió la lista de bandas a las que pertenece un personaje cargado: se añadió o quitó una banda, o cambió un rango.
Lado: Servidor · Constante: CORE.gangsChangedEvent
Argumentos
Prop
Type
Oyente
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
Un personaje cargado cambió la banda para la que actúa, o ya no actúa para ninguna.
Lado: Servidor · Constante: CORE.activeGangChangedEvent
Argumentos
Prop
Type
Oyente
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
Cambió un valor de metadatos de un personaje cargado. Los metadatos son una bolsa libre de clave / valor guardada con el personaje; los puentes de ESX / QB guardan ahí los metadatos de framework (hambre, sed, estrés, isdead...).
Lado: Servidor · Constante: CORE.metaChangedEvent
Argumentos
Prop
Type
Oyente
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
Se añadió, cambió o borró un trabajo o una banda en el panel de administración. Se dispara una vez por cada trabajo o banda que cambió.
Lado: Servidor · Constante: CORE.definitionsChangedEvent
Argumentos
Prop
Type
Oyente
import { CORE } from "@aicore-fivem/shared";
const labelCache = new Map<string, string>();
// Descarta una etiqueta en caché cuando el panel cambia ese trabajo.
on(CORE.definitionsChangedEvent, (file: "jobs" | "gangs", name: string) => {
if (file === "jobs") labelCache.delete(name);
});ai-core:characterScreen
La pantalla de personajes de un jugador está cargando (tras entrar, o tras volver a ella). ai-core lee por sí mismo los aspectos de las tarjetas; un script de ropa lo escucha para dibujar los retratos de las tarjetas.
Lado: Servidor · Constante: CORE.characterScreenEvent
Argumentos
Prop
Type
Oyente
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
Cambió el inventario que hay detrás de la capa de inventario de ai-core: el inventario elegido se inició o se detuvo, o el dueño eligió otro en el panel. Descarta todo lo que tuvieras en caché del inventario anterior (etiquetas de objetos, definiciones).
Lado: Servidor · Constante: CORE.inventoryChangedEvent
Argumentos
Prop
Type
Oyente
import { CORE } from "@aicore-fivem/shared";
let itemLabels: Record<string, string> | null = null;
on(CORE.inventoryChangedEvent, (resource: string | null) => {
itemLabels = null; // se vuelve a leer del nuevo inventario en el próximo uso
console.log(`inventory is now ${resource ?? "none"}`);
});ai-core:itemUsed
Un jugador usó un objeto. Lleva las necesidades que da el objeto (hambre, sed, estrés), para que un HUD o un script de necesidades las aplique sin conocer el inventario. ai-hud lo escucha.
Lado: Servidor · Constante: CORE.itemUsedEvent
Argumentos
Prop
Type
Oyente
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}`);
});Hoy solo ai-inventory informa a ai-core de los usos de objetos: con otro inventario este evento no se dispara. Escucha este evento, no el evento de uso propio de un inventario, para que tu script funcione cuando ai-inventory es el inventario y siga funcionando cuando se añadan otros.
ai-core:playerDied
Murió un jugador con un personaje cargado. ai-core lo toma del propio aviso de muerte de ped de FXServer (FXServer 38039 o más nuevo), así que no se confía en ningún cliente.
Lado: Servidor · Constante: CORE.playerDiedEvent
Argumentos
Prop
Type
Oyente
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})`);
});Esta es la muerte del juego, no el estado de "caído" del script de muerte: un script de muerte puede mantener vivo a un jugador caído para animarlo. Para saber "si este jugador está caído", usa el medical de la lib de servidor o los exports médicos de servidor de ai-core.
ai-core:vrp:config
El dueño del servidor cambió el mapeo de vRP en el panel de ai-core (pestaña "vRP scripts"). El puente de vRP de ai-core lo escucha; solo lo necesitas si lees tú el mapeo de vRP.
Lado: Servidor · Constante: VRP.configEvent
Argumentos
Prop
Type
Oyente
import { VRP, type VrpConfig } from "@aicore-fivem/shared";
on(VRP.configEvent, (config: VrpConfig) => {
console.log(`${config.permissions.length} vRP permission rule(s)`);
});Eventos de otros scripts ai-*
Estos los disparan scripts ai-*, no ai-core, pero muchos recursos los escuchan. Su referencia completa está en la página para desarrolladores de cada script.
ai-vehicles:owners
Cambiaron los dueños de los vehículos en propiedad que hay en memoria (se cargó un personaje con su garaje, se compró, vendió o borró un vehículo). Se dispara como mucho una vez por tick del servidor con todos los cambios de ese tick. Los scripts de llaves lo usan para mantener un mapa de matrícula a dueño sin preguntar a ai-vehicles cada vez.
Lado: Servidor · Constante: VEHICLES_EVENTS.owners
Argumentos
Prop
Type
Oyente
import { resourceExport } from "@aicore-fivem/lib/server";
import { VEHICLES_EVENTS } from "@aicore-fivem/shared";
const owners = new Map<string, string>();
// Empieza con la lista completa y después sigue los cambios.
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 dispara el clásico evento chatMessage de FiveM antes de entregar el mensaje de un jugador. Llamar a CancelEvent() en tu handler descarta el mensaje.
Lado: Servidor · Constante: ninguna (el propio nombre de FiveM)
Argumentos
Prop
Type
Oyente
on("chatMessage", (source: number, _author: string, text: string) => {
if (text.toLowerCase().includes("discord.gg")) {
CancelEvent();
console.log(`blocked an invite link from ${source}`);
}
});Eventos y estado
Cómo avisa ai-core a otros scripts de que algo cambió - eventos locales, eventos de red, state bags - y cómo escucharlos en TypeScript y Lua.
Eventos de cliente
Cada evento local de cliente que dispara ai-core - el personaje local cargado o descargado, el estado de caído, valores en caché, la visibilidad del HUD, la sincronización del mundo, definiciones de trabajos, ayudas de teclas, cinturón - con sus argumentos y listeners.