AI Core
Referencia de la APILib: compartido y fivem

Planificación y ciclo de vida

every, onStop, caller, ByResource, Reasons, sleep y waitFor: trabajo periódico, esperas y datos que pertenecen al recurso que los registró.

TypeScript
import { every, onStop, caller, ByResource, Reasons } from "@aicore-fivem/lib/fivem";
import { sleep, waitFor } from "@aicore-fivem/lib/shared";

Trabajo periódico

every

Ejecuta una función cada ms milisegundos (0 = cada frame) desde el único planificador de tu recurso. Úsalo en lugar de setInterval, setTick o un bucle CreateThread con Wait: todas las tareas de un recurso comparten un tick, y ese tick solo existe mientras haya al menos una tarea encendida, así que un recurso inactivo no cuesta nada en resmon.

Lado: Cliente y servidor · Espera: no

Firma
every(ms: number, fn: () => unknown, options?: EveryOptions): Job
Lua
local job = aiLib.every(ms, fn, options) -- job:set(active), job:stop(), job.running

Parámetros

Prop

Type

EveryOptions

Prop

Type

Devuelve

Job: un handle para encender y apagar la tarea.

Prop

Type

Ejemplo

Una tarea por frame que solo se ejecuta mientras tiene algo que hacer:

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

// Oculta la mira en cada frame, pero solo mientras hay un arma en la mano.
const hideCrosshair = every(0, () => HideHudComponentThisFrame(14), {
  active: cache.weapon !== false,
  name: "hide crosshair",
});

onCache("weapon", (weapon) => hideCrosshair.set(weapon !== false));

Una tarea nunca debe esperar: nada de Wait en Lua, ni una cadena larga de await que esperas que termine antes de la siguiente ejecución en TypeScript. En Lua, un Wait dentro de una tarea retiene todas las demás tareas del recurso; para eso, inicia un hilo desde la tarea. Una tarea que falla se registra en el log como máximo una vez cada 10 segundos (los errores intermedios se cuentan en la siguiente línea).

Esperas

sleep

Espera ms milisegundos.

Lado: Cliente, servidor y NUI · Espera: sí (Promise)

Firma
sleep(ms: number): Promise<void>

Lua: sin equivalente; usa Wait(ms) dentro de un hilo.

Parámetros

Prop

Type

Devuelve

Promise<void> que se resuelve después de ms milisegundos.

Ejemplo

import { sleep } from "@aicore-fivem/lib/shared";
import { fadeOut, fadeIn } from "@aicore-fivem/lib/client";

async function blink(): Promise<void> {
  await fadeOut(300);
  await sleep(1000);
  await fadeIn(300);
}

waitFor

Comprueba una condición hasta que da un valor, y luego devuelve ese valor. Úsalo para esperar algo que el juego hace a su ritmo: que exista una entidad, que cargue un modelo, que llegue un valor.

Lado: Cliente, servidor y NUI · Espera: sí (Promise en TypeScript, cede el hilo en Lua)

Firma
waitFor<T>(check: () => T | undefined, timeoutMs?: number | false, intervalMs?: number): Promise<T>
Lua
local value = aiLib.waitFor(check, timeout, interval) -- valor, o nil tras el tiempo límite; llamar dentro de un hilo

Parámetros

Prop

Type

Devuelve

TypeScript: Promise<T> que se resuelve con el primer valor devuelto por check que no fue undefined. Se rechaza con Error("waitFor timed out after <ms> ms") tras el tiempo límite.

Lua: el valor, o nil tras el tiempo límite (no lanza errores).

Ejemplo

import { waitFor } from "@aicore-fivem/lib/shared";

async function vehicleFromNet(netId: number): Promise<number | null> {
  try {
    return await waitFor(() => {
      const vehicle = NetworkGetEntityFromNetworkId(netId);
      return DoesEntityExist(vehicle) ? vehicle : undefined;
    }, 5000);
  } catch {
    return null; // no se cargó en 5 segundos
  }
}

En TypeScript, gestiona siempre el rechazo (try / catch o .catch()), o pasa false como tiempo límite. En Lua, waitFor solo funciona dentro de un hilo.

Ciclo de vida del recurso

onStop

Ejecuta una función cuando tu recurso se detiene (en el lado en el que se ejecuta el código). Úsalo para eliminar lo que crearon los natives y nada más quita: entidades que hiciste aparecer, cámaras, un foco NUI.

Lado: Cliente y servidor · Espera: no

Firma
onStop(fn: () => void): void

Lua: sin equivalente; usa AddEventHandler('onResourceStop', function(name) if name == GetCurrentResourceName() then ... end end).

Parámetros

Prop

Type

Devuelve

void.

Ejemplo

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

const spawned = new Set<number>();

onStop(() => {
  for (const entity of spawned) if (DoesEntityExist(entity)) DeleteEntity(entity);
});

Todos los onStop, ByResource y Reasons de un recurso comparten un único listener de detención, así que añadir muchos no cuesta nada extra.

caller

El nombre del recurso que llamó al export que se está ejecutando ahora. Dentro de tu propio código (no en una llamada a un export) es el nombre de tu recurso.

Lado: Cliente y servidor · Espera: no

Firma
caller(): string

Lua: sin equivalente; usa GetInvokingResource() or GetCurrentResourceName().

Devuelve

string: el nombre del recurso que llama, o el nombre de este recurso cuando no llama ningún otro.

Ejemplo

resource/server/index.ts
import { registerExport, caller } from "@aicore-fivem/lib/server";

registerExport("Ping", () => {
  console.log(`${caller()} asked for a ping`);
  return true;
});

ByResource

Un mapa cuyas entradas pertenecen al recurso que las fijó. Cuando ese recurso se detiene, sus entradas se eliminan al momento (y onDrop se ejecuta para cada una). Úsalo para las cosas que otros recursos registran mediante tus exports: hooks, prompts, objetos, entradas de menú.

Lado: Cliente y servidor · Espera: no

Firma
new ByResource<K, V>(options?: { onDrop?: (resource: string, key: K, value: V) => void })

Lua: sin equivalente.

Parámetros

Prop

Type

Métodos

Prop

Type

Ejemplo

resource/server/index.ts
import { ByResource, registerExport } from "@aicore-fivem/lib/server";
import { readText } from "@aicore-fivem/lib/shared";

type Hook = (source: number, text: string) => boolean;
const hooks = new ByResource<string, Hook>({
  onDrop: (resource, id) => console.log(`${resource} stopped: hook ${id} removed`),
});

// Otro recurso: exports["my-chat"].AddHook("swear-filter", (source, text) => ...)
registerExport("AddHook", (id: unknown, hook: unknown) => {
  const name = readText(id, 64);
  if (name === null || typeof hook !== "function") return false;
  hooks.set(name, hook as Hook); // owner = el recurso que llama a AddHook
  return true;
});

export function allowed(source: number, text: string): boolean {
  for (const hook of hooks.values()) if (!hook(source, text)) return false;
  return true;
}

Reasons

Un interruptor que está encendido mientras haya al menos un motivo fijado. Cada recurso fija sus propios motivos con nombre, y los motivos de un recurso que se detiene se borran. Úsalo para "ocultar el HUD", "pausar la sincronización", "bloquear el menú": varios scripts pueden pedirlo a la vez, y el estado solo vuelve atrás cuando el último lo suelta.

Lado: Cliente y servidor · Espera: no

Firma
new Reasons()

Lua: sin equivalente.

Métodos

Prop

Type

Ejemplo

resource/client/index.ts
import { Reasons, registerExport } from "@aicore-fivem/lib/client";
import { readText } from "@aicore-fivem/lib/shared";

const hidden = new Reasons();
hidden.onChange((any) => SendNUIMessage({ action: "visible", value: !any }));

// Otros recursos: exports["my-hud"].Hide("cutscene") y exports["my-hud"].Show("cutscene")
registerExport("Hide", (reason: unknown) => {
  const name = readText(reason, 64);
  if (name !== null) hidden.set(name, true);
});
registerExport("Show", (reason: unknown) => {
  const name = readText(reason, 64);
  if (name !== null) hidden.set(name, false);
});

En esta página