AI Core
Referencia de la APILib: cliente

Puntos de interacción

Points - cada lugar que usa un jugador (mostradores, tiendas, puertas, NPC, cajeros, maleteros de vehículos) como prompt o como opción de target, con peds, blips y puntos construidos a partir de registros del panel.

Un punto es cualquier lugar que usa un jugador: el mostrador de una tienda, una puerta, un NPC, un sitio de devolución, cada cajero automático, el maletero de cada coche. Lo describes una vez (dónde, qué texto, qué pasa) y la lib lo dibuja de la forma que eligió el dueño del servidor.

Prompt o target

El dueño elige el estilo de interacción en el panel de administración de ai-core (Interaction). El mismo onPressed se ejecuta en ambos casos, así que a tu script nunca le importa cuál está activo.

EstiloLo que ve el jugador
PromptUna caja de "pulsa E" en el lado derecho de la pantalla mientras el jugador está dentro del radio del punto. La tecla es un único keybind reasignable de ai-lib (por defecto E), así que nada sondea las teclas en cada frame.
TargetUna opción en el ojo de target sobre el sitio, el NPC, el objeto o el vehículo. Necesita que esté en marcha uno de los scripts de target para los que la lib tiene un adaptador. Cuando hay varios en marcha, gana el primero en este orden: ai-target, tgiann-radialmenu-target, tgiann-target, sleepless_interact, ox_target, qb-target, interact.

Cuando el dueño eligió target pero no hay ningún script de target en marcha, cada punto es un prompt. Un punto puede anular la elección del dueño: promptOnly mantiene un prompt (cosas que se hacen desde un vehículo: surtidores de combustible, lavaderos de coches), preferTarget usa una opción de target siempre que haya un script de target en marcha (asientos). Cuando un script de target arranca o se detiene, o el dueño cambia el estilo, cada punto se adapta solo.

Solo se ejecuta una acción de punto de tu recurso a la vez. Cuando onPressed devuelve una promise, los demás puntos de tu recurso ignoran las pulsaciones hasta que termina, así que nunca necesitas tu propio indicador busy. El jugador también debe pasar canShow en el momento de la pulsación.

new Points

Crea un grupo de puntos. Crea un grupo por funcionalidad al principio del archivo y añádele puntos.

Lado: Cliente · Espera: no

Firma
new Points()
Lua
local points = aiLib.Points.new()

Devuelve

Un grupo Points con los métodos de abajo.

Ejemplo

import { Points } from "@aicore-fivem/lib/client";

const points = new Points();

points.add

Añade un punto en un lugar, o reemplaza el punto con el mismo id. Un punto puede llevar su propio NPC (ped) y su blip en el mapa (blip).

Lado: Cliente · Espera: no

Firma
points.add(id: string, options: PointOptions): void
Lua
points:add(id, options)

Parámetros

Prop

Type

PointOptions

Prop

Type

PointPed

El campo ped acepta las opciones de LocalPed salvo onSpawn y onDespawn (las usa el punto):

Prop

Type

PointBlip

El campo blip acepta las opciones de blip; coords es por defecto el punto:

Prop

Type

PromptAnchor

Lo que devuelve una función world (PromptAnchor), uno de:

Prop

Type

Devuelve

void.

Ejemplo

resource/client/index.ts
import { callAction, createLocale, hasJob, onMembershipChange, Points } from "@aicore-fivem/lib/client";

const Locale = createLocale<typeof import("../../locales/en.json")>();
const points = new Points();

// El mostrador de una tienda con un tendero y un blip en el mapa.
points.add("shop", {
  coords: { x: 25.7, y: -1347.3, z: 29.5 },
  label: Locale("OPEN_SHOP"),
  icon: "basket-shopping",
  ped: { model: "mp_m_shopkeep_01", coords: { x: 24.5, y: -1346.6, z: 29.5, heading: 270 } },
  blip: { sprite: 52, color: 2, label: Locale("SHOP") },
  onPressed: () => callAction("myshop:open", [], { fallback: "SHOP_FAILED" }),
});

// Un almacén que solo puede abrir la policía; el texto sigue un estado.
let locked = true;
points.add("evidence", {
  coords: { x: 474.9, y: -996.4, z: 26.3 },
  label: () => (locked ? Locale("UNLOCK") : Locale("LOCK")),
  icon: "box-archive",
  canShow: () => hasJob(["police"], 2),
  onPressed: async () => {
    const reply = await callAction("myscript:toggle", [], { fallback: "TOGGLE_FAILED" });
    if (reply) locked = !locked;
    points.refresh("evidence");
  },
});

// canShow lee el trabajo: compruébalo de nuevo cuando cambien los trabajos, el servicio o las bandas.
onMembershipChange(() => points.refresh());

canShow solo decide lo que ve el jugador. El servidor debe comprobarlo de nuevo (trabajo, distancia, stock) en su propio handler. Un tramposo puede llamar a tu evento de servidor sin ningún punto.

points.addModel

Añade un punto en cada objeto del mundo de ciertos modelos (cajeros automáticos, máquinas expendedoras, contenedores, sillas), o reemplaza el punto con el mismo id. En modo target es una opción de target en esos modelos; en modo prompt se muestra un prompt cerca del más cercano. El escaneo del objeto más cercano se ejecuta una sola vez en ai-lib para todos los recursos, dos veces por segundo, y se pausa mientras el jugador está quieto.

Lado: Cliente · Espera: no

Firma
points.addModel(id: string, options: ModelPointOptions): void
Lua
points:addModel(id, options)

Parámetros

Prop

Type

ModelPointOptions

Prop

Type

Devuelve

void.

Ejemplo

import { callAction, createLocale, Points } from "@aicore-fivem/lib/client";

const Locale = createLocale<typeof import("../../locales/en.json")>();
const points = new Points();

points.addModel("atm", {
  models: ["prop_atm_01", "prop_atm_02", "prop_atm_03", "prop_fleeca_atm"],
  label: Locale("USE_ATM"),
  icon: "credit-card",
  onPressed: (atm) => callAction("mybank:atm", [NetworkGetNetworkIdFromEntity(atm)], { fallback: "ATM_FAILED" }),
});

Dos estados de un mismo objeto (amarrar y soltar un barco) son dos puntos de modelo con canShow opuestos, no una sola función de etiqueta. Un punto con más de 6 modelos encuentra sus objetos mediante un índice del pool de objetos, así que cientos de modelos cuestan lo mismo que unos pocos.

points.addVehicle

Añade un punto en cada vehículo en red (maletero, capó, empujar, reparar), o reemplaza el punto con el mismo id. En modo target es la opción global de vehículo del script de target; en modo prompt se muestra un prompt en el vehículo en red más cercano dentro de radius.

Lado: Cliente · Espera: no

Firma
points.addVehicle(id: string, options: VehiclePointOptions): void
Lua
points:addVehicle(id, options)

Parámetros

Prop

Type

Devuelve

void.

Ejemplo

import { cache, createLocale, Points } from "@aicore-fivem/lib/client";

const Locale = createLocale<typeof import("../../locales/en.json")>();
const points = new Points();

points.addVehicle("trunk", {
  label: Locale("OPEN_TRUNK"),
  icon: "box-open",
  radius: 2.5,
  canShow: (vehicle) => vehicle !== 0 && cache.vehicle === false && GetVehicleDoorLockStatus(vehicle) < 2,
  onPressed: (vehicle) => SetVehicleDoorOpen(vehicle, 5, false, false),
});

points.remove

Elimina un punto con su prompt, su opción de target, su NPC y su blip. Funciona con los puntos creados con add, addModel y addVehicle. Un id desconocido no hace nada.

Lado: Cliente · Espera: no

Firma
points.remove(id: string): void
Lua
points:remove(id)

Parámetros

Prop

Type

Devuelve

void.

Ejemplo

points.remove("shop");

points.clear

Elimina todos los puntos del grupo.

Lado: Cliente · Espera: no

Firma
points.clear(): void
Lua
points:clear()

Devuelve

void.

Ejemplo

onServerEvent("myscript:jobEnded", () => points.clear());

Nunca reconstruyas los puntos del panel con clear() + añadirlo todo en cada cambio del panel: con miles de registros, una edición reconstruiría todos en cada cliente. Usa RecordObjects: una edición solo reconstruye su propio registro.

points.refresh

Vuelve a leer canShow y las etiquetas que son funciones. Llámalo cuando cambie algo que leen: el trabajo, el servicio, un vehículo, un estado que envió el servidor. Los prompts se actualizan al momento; las opciones de target leen canShow cuando se abre el ojo, y una etiqueta cambiada se vuelve a poner.

Lado: Cliente · Espera: no

Firma
points.refresh(id?: string): void
Lua
points:refresh() -- todos los puntos del grupo

Parámetros

Prop

Type

Devuelve

void.

Ejemplo

import { EntityState, onCache, onMembershipChange, Points, stateBoolean } from "@aicore-fivem/lib/client";

const points = new Points();
const robbed = new EntityState("robbed", stateBoolean);

onCache("vehicle", () => points.refresh());
onMembershipChange(() => points.refresh());
// Cambió una caja registradora: refresca solo su punto.
robbed.onChange((netId) => points.refresh(`register:${netId}`));

Dentro de un AddStateBagChangeHandler a secas, el nuevo valor aún no se puede leer: llama ahí a refresh en un setTimeout(..., 0). Las clases de estado de la lib (EntityState.onChange) ya te dan el nuevo valor.

points.isInside

Si el jugador está ahora dentro del radio de un punto (puntos creados con add).

Lado: Cliente · Espera: no

Firma
points.isInside(id: string): boolean

Sin equivalente en Lua.

Parámetros

Prop

Type

Devuelve

boolean: true mientras el jugador está dentro; false fuera, o para un id desconocido o un punto de modelo.

Ejemplo

if (points.isInside("garage")) notify(Locale("PARK_HERE"), "info");

points.restyle

Pone todos los puntos del grupo en el estilo de interacción actual. La lib lo llama por sí misma cuando el dueño cambia el estilo o un script de target arranca o se detiene; nunca lo necesitas.

Lado: Cliente · Espera: no

Firma
points.restyle(): void

Sin equivalente en Lua (Lua también cambia de estilo por sí mismo).

Devuelve

void.

Puntos a partir de registros del panel

La mayoría de los puntos vienen de un archivo de registros del panel de administración de tu script (tiendas, garajes, mostradores de alquiler). Refleja el archivo en el cliente con AdminWorld y luego construye los puntos de cada registro con RecordObjects: un registro editado reconstruye solo sus propios puntos, y uno eliminado los quita.

new RecordObjects

Mantiene los objetos del mundo de un archivo de registros (puntos, blips, peds, zonas) al día con el archivo, registro a registro. build(key, record) crea los objetos de un registro y devuelve cómo quitarlos. Construye todos los registros en su constructor.

Lado: Cliente y servidor (desde @aicore-fivem/lib/shared) · Espera: no

Firma
new RecordObjects<T>(
  source: RecordSource,
  file: string,
  records: RecordReader<T> | ReadonlyMap<string, T>,
  build: (key: string, record: T) => (() => void) | void,
)

Sin equivalente en Lua.

Parámetros

Prop

Type

Miembros

Prop

Type

Ejemplo

resource/client/index.ts
import { AdminWorld, callAction, createLocale, Points } from "@aicore-fivem/lib/client";
import { readVec3, RecordObjects, str } from "@aicore-fivem/lib/shared";

const Locale = createLocale<typeof import("../../locales/en.json")>();
const world = new AdminWorld(["settings", "shops"]);
const points = new Points();

interface Shop { label: string; coords: { x: number; y: number; z: number } }
const readShop = (_key: string, raw: Record<string, unknown>): Shop | null => {
  const coords = readVec3(raw.coords);
  return coords ? { label: str(raw.label, "Shop"), coords } : null;
};

const shops = new RecordObjects(world, "shops", readShop, (id, shop) => {
  points.add(id, {
    coords: shop.coords,
    label: Locale("OPEN_SHOP", shop.label),
    onPressed: () => callAction("myshop:open", [id], { fallback: "SHOP_FAILED" }),
  });
  return () => points.remove(id);
});

// Cambió un ajuste que leen todas las tiendas: reconstrúyelas todas.
world.onChange("settings", () => shops.rebuildAll());

RecordObjects construye en su constructor. Créalo después de todo lo que lee build, y dentro de build usa el argumento record: un campo de clase que guarda el RecordObjects aún no está asignado durante esa primera construcción.

new AdminWorld

La copia en el cliente de los archivos de mundo del panel de tu script (los archivos cuyo esquema dice sync: "all", consulta Panel de administración). Lee la copia que FiveM guardó en caché al arrancar, pregunta una vez al servidor por los registros cambiados desde entonces y luego sigue los cambios en vivo. Nunca sondea.

Lado: Cliente · Espera: no (la promise ready indica cuándo llegaron los cambios desde el arranque)

Firma
new AdminWorld(files: string[])

Sin equivalente en Lua.

Parámetros

Prop

Type

Miembros

Prop

Type

Ejemplo

import { AdminWorld } from "@aicore-fivem/lib/client";
import { num, record } from "@aicore-fivem/lib/shared";

const world = new AdminWorld(["settings"]);
const settings = world.view("settings", (raw) => ({
  radius: num(record(raw).radius, 2),
}));

world.onChange("settings", () => console.log("new radius", settings.value.radius));

En esta página