Pontos de interação
Points - todo lugar que um jogador usa (balcões, lojas, portas, NPCs, caixas eletrônicos, porta-malas de veículos) como prompt ou opção de target, com peds, blips e pontos construídos a partir de registros do painel.
Um ponto é qualquer lugar que um jogador usa: o balcão de uma loja, uma porta, um NPC, um local de devolução, todo caixa eletrônico, o porta-malas de todo carro. Você o descreve uma vez (onde, qual texto, o que acontece) e a lib o desenha do jeito que o dono do servidor escolheu.
Prompt ou target
O dono escolhe o estilo de interação no painel de administração do ai-core (Interaction). O mesmo onPressed roda de qualquer forma, então o seu script nunca se importa com qual está ativo.
| Estilo | O que o jogador vê |
|---|---|
| Prompt | Uma caixa "aperte E" no lado direito da tela enquanto o jogador está dentro do raio do ponto. A tecla é um único keybind reconfigurável no ai-lib (padrão E), então nada verifica teclas a cada frame. |
| Target | Uma opção no olho de target no local, no NPC, no objeto ou no veículo. Precisa que esteja rodando um dos scripts de target para os quais a lib tem adaptador. Quando vários rodam, vence o primeiro nesta ordem: ai-target, tgiann-radialmenu-target, tgiann-target, sleepless_interact, ox_target, qb-target, interact. |
Quando o dono escolheu target mas nenhum script de target está rodando, todo ponto é um prompt. Um ponto pode sobrepor a escolha do dono: promptOnly mantém um prompt (coisas feitas de dentro de um veículo: bombas de combustível, lava-rápidos), preferTarget usa uma opção de target sempre que um script de target roda (assentos). Quando um script de target inicia ou para, ou o dono troca o estilo, todo ponto muda sozinho.
Só uma ação de ponto do seu recurso roda por vez. Quando onPressed retorna uma promise, os outros pontos do seu recurso ignoram os apertos até ela terminar, então você nunca precisa da sua própria flag busy. O jogador também precisa passar em canShow no momento do aperto.
new Points
Cria um grupo de pontos. Faça um grupo por funcionalidade no topo do arquivo e adicione pontos a ele.
Lado: Cliente · Espera: não
new Points()local points = aiLib.Points.new()Retorno
Um grupo Points com os métodos abaixo.
Exemplo
import { Points } from "@aicore-fivem/lib/client";
const points = new Points();points.add
Adiciona um ponto em um lugar, ou substitui o ponto com o mesmo id. Um ponto pode ter o próprio NPC (ped) e blip no mapa (blip).
Lado: Cliente · Espera: não
points.add(id: string, options: PointOptions): voidpoints:add(id, options)Parâmetros
Prop
Type
PointOptions
Prop
Type
PointPed
O campo ped aceita as opções de LocalPed, exceto onSpawn e onDespawn (o ponto as usa):
Prop
Type
PointBlip
O campo blip aceita as opções de blip; coords tem como padrão o ponto:
Prop
Type
PromptAnchor
O que uma função world retorna (PromptAnchor), um destes:
Prop
Type
Retorno
void.
Exemplo
import { callAction, createLocale, hasJob, onMembershipChange, Points } from "@aicore-fivem/lib/client";
const Locale = createLocale<typeof import("../../locales/en.json")>();
const points = new Points();
// O balcão de uma loja com um lojista e um blip no 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" }),
});
// Um baú que só a polícia pode abrir; o texto acompanha um 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 lê o emprego: verifique de novo quando empregos, serviço ou gangues mudarem.
onMembershipChange(() => points.refresh());canShow decide só o que o jogador vê. O servidor precisa verificar de novo (emprego, distância, estoque) no próprio handler. Um trapaceiro pode chamar o seu evento de servidor sem nenhum ponto.
points.addModel
Adiciona um ponto em todo objeto do mundo de alguns modelos (caixas eletrônicos, máquinas de venda, caçambas, cadeiras), ou substitui o ponto com o mesmo id. No modo target é uma opção de target nesses modelos; no modo prompt um prompt aparece perto do mais próximo. A varredura pelo objeto mais próximo roda uma vez no ai-lib para todos os recursos, duas vezes por segundo, e pausa enquanto o jogador está parado.
Lado: Cliente · Espera: não
points.addModel(id: string, options: ModelPointOptions): voidpoints:addModel(id, options)Parâmetros
Prop
Type
ModelPointOptions
Prop
Type
Retorno
void.
Exemplo
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" }),
});Dois estados de um objeto (amarrar e desamarrar um barco) são dois pontos de modelo com canShow opostos, não uma função de rótulo. Um ponto com mais de 6 modelos encontra os objetos por um índice do pool de objetos, então centenas de modelos custam o mesmo que alguns.
points.addVehicle
Adiciona um ponto em todo veículo em rede (porta-malas, capô, empurrar, consertar), ou substitui o ponto com o mesmo id. No modo target é a opção global de veículo do script de target; no modo prompt um prompt aparece no veículo em rede mais próximo dentro de radius.
Lado: Cliente · Espera: não
points.addVehicle(id: string, options: VehiclePointOptions): voidpoints:addVehicle(id, options)Parâmetros
Prop
Type
Retorno
void.
Exemplo
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
Remove um ponto com o prompt, a opção de target, o NPC e o blip dele. Funciona para pontos feitos com add, addModel e addVehicle. Um id desconhecido não faz nada.
Lado: Cliente · Espera: não
points.remove(id: string): voidpoints:remove(id)Parâmetros
Prop
Type
Retorno
void.
Exemplo
points.remove("shop");points.clear
Remove todos os pontos do grupo.
Lado: Cliente · Espera: não
points.clear(): voidpoints:clear()Retorno
void.
Exemplo
onServerEvent("myscript:jobEnded", () => points.clear());Nunca reconstrua pontos do painel com clear() + adicionar tudo a cada mudança no painel: com milhares de registros uma edição reconstruiria todos eles em todos os clientes. Use RecordObjects: uma edição reconstrói só o próprio registro.
points.refresh
Lê de novo canShow e os rótulos que são funções. Chame quando algo que eles leem mudou: o emprego, o serviço, um veículo, um estado que o servidor enviou. Os prompts se atualizam na hora; as opções de target leem canShow quando o olho abre, e um rótulo alterado é colocado de novo.
Lado: Cliente · Espera: não
points.refresh(id?: string): voidpoints:refresh() -- todos os pontos do grupoParâmetros
Prop
Type
Retorno
void.
Exemplo
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());
// Um caixa mudou: atualize só o ponto dele.
robbed.onChange((netId) => points.refresh(`register:${netId}`));Dentro de um AddStateBagChangeHandler puro o novo valor ainda não pode ser lido: chame refresh em um setTimeout(..., 0) ali. As classes de estado da lib (EntityState.onChange) já dão o novo valor.
points.isInside
Se o jogador está dentro do raio de um ponto agora (pontos feitos com add).
Lado: Cliente · Espera: não
points.isInside(id: string): booleanSem equivalente em Lua.
Parâmetros
Prop
Type
Retorno
boolean: true enquanto o jogador está dentro; false fora, ou para um id desconhecido ou um ponto de modelo.
Exemplo
if (points.isInside("garage")) notify(Locale("PARK_HERE"), "info");points.restyle
Coloca todos os pontos do grupo no estilo de interação atual. A lib o chama sozinha quando o dono troca o estilo ou um script de target inicia ou para; você nunca precisa dele.
Lado: Cliente · Espera: não
points.restyle(): voidSem equivalente em Lua (Lua também troca o estilo sozinho).
Retorno
void.
Pontos a partir de registros do painel
A maioria dos pontos vem de um arquivo de records do painel de administração do seu script (lojas, garagens, balcões de aluguel). Espelhe o arquivo no cliente com AdminWorld, depois construa os pontos de cada registro com RecordObjects: um registro editado reconstrói só os próprios pontos, um apagado os remove.
new RecordObjects
Mantém os objetos do mundo de um arquivo de records (pontos, blips, peds, zonas) em sincronia com o arquivo, um registro por vez. build(key, record) cria os objetos de um registro e retorna como removê-los. Ele constrói todos os registros no construtor.
Lado: Cliente e servidor (de @aicore-fivem/lib/shared) · Espera: não
new RecordObjects<T>(
source: RecordSource,
file: string,
records: RecordReader<T> | ReadonlyMap<string, T>,
build: (key: string, record: T) => (() => void) | void,
)Sem equivalente em Lua.
Parâmetros
Prop
Type
Membros
Prop
Type
Exemplo
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);
});
// Uma configuração que toda loja lê mudou: reconstrua todas.
world.onChange("settings", () => shops.rebuildAll());RecordObjects constrói no construtor. Crie-o depois de tudo o que build lê, e dentro de build use o argumento record: um campo de classe que guarda o RecordObjects ainda não foi atribuído durante essa primeira construção.
new AdminWorld
A cópia no cliente dos arquivos de mundo do painel do seu script (os arquivos cujo schema diz sync: "all", veja Painel de administração). Ela lê a cópia que o FiveM guardou em cache na inicialização, pergunta ao servidor uma vez pelos registros alterados desde então, e depois acompanha as mudanças ao vivo. Nunca fica consultando.
Lado: Cliente · Espera: não (a promise ready avisa quando as mudanças desde a inicialização chegaram)
new AdminWorld(files: string[])Sem equivalente em Lua.
Parâmetros
Prop
Type
Membros
Prop
Type
Exemplo
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));O jogador local
O ped, o veículo, o assento e a arma em cache, o objeto player (posição, teleporte, animações), fades de tela, os peds de outros jogadores e o jogador mais próximo.
Zonas
Zones - áreas com callbacks de entrada e saída (esfera, cilindro, polígono), verificadas no próprio intervalo, nunca a cada frame.