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ó.
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
every(ms: number, fn: () => unknown, options?: EveryOptions): Joblocal job = aiLib.every(ms, fn, options) -- job:set(active), job:stop(), job.runningPará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)
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)
waitFor<T>(check: () => T | undefined, timeoutMs?: number | false, intervalMs?: number): Promise<T>local value = aiLib.waitFor(check, timeout, interval) -- valor, o nil tras el tiempo límite; llamar dentro de un hiloPará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
onStop(fn: () => void): voidLua: sin equivalente; usa AddEventHandler('onResourceStop', function(name) if name == GetCurrentResourceName() then ... end end).
Parámetros
Prop
Type
Devuelve
void.
Ejemplo
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
caller(): stringLua: 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
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
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
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
new Reasons()Lua: sin equivalente.
Métodos
Prop
Type
Ejemplo
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);
});Exports entre recursos
registerExport, resourceExport, optionalExport, callExport, provideExport e isResourceStarted: ofrecer y llamar exports desde TypeScript.
State bags
EntityState, PlayerState, GlobalKey, GlobalGroup y los parsers stateNumber, stateBoolean, stateString: leer valores replicados desde la memoria.