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.
| Estilo | Lo que ve el jugador |
|---|---|
| Prompt | Una 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. |
| Target | Una 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
new Points()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
points.add(id: string, options: PointOptions): voidpoints: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
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
points.addModel(id: string, options: ModelPointOptions): voidpoints: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
points.addVehicle(id: string, options: VehiclePointOptions): voidpoints: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
points.remove(id: string): voidpoints:remove(id)Parámetros
Prop
Type
Devuelve
void.
Ejemplo
points.remove("shop");points.clear
Elimina todos los puntos del grupo.
Lado: Cliente · Espera: no
points.clear(): voidpoints: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
points.refresh(id?: string): voidpoints:refresh() -- todos los puntos del grupoPará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
points.isInside(id: string): booleanSin 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
points.restyle(): voidSin 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
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
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)
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));El jugador local
El ped, el vehículo, el asiento y el arma en caché, el objeto player (posición, teletransporte, animaciones), fundidos de pantalla, los peds de otros jugadores y el jugador más cercano.
Zonas
Zones - áreas con callbacks de entrada y salida (esfera, cilindro, polígono), comprobadas a su propio intervalo, nunca en cada frame.