AI Core
Referência da APILib: cliente

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.

EstiloO que o jogador vê
PromptUma 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.
TargetUma 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

Signature
new Points()
Lua
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

Signature
points.add(id: string, options: PointOptions): void
Lua
points: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

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();

// 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

Signature
points.addModel(id: string, options: ModelPointOptions): void
Lua
points: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

Signature
points.addVehicle(id: string, options: VehiclePointOptions): void
Lua
points: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

Signature
points.remove(id: string): void
Lua
points: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

Signature
points.clear(): void
Lua
points: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

Signature
points.refresh(id?: string): void
Lua
points:refresh() -- todos os pontos do grupo

Parâ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

Signature
points.isInside(id: string): boolean

Sem 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

Signature
points.restyle(): void

Sem 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

Signature
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

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);
});

// 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)

Signature
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));

Nesta página