AI Core
Referência da APILib: cliente

Câmera e tempo

ScriptCamera, TickLoop, AreaFollower e ServerClock - câmeras de script, jobs por frame que só rodam quando necessários, informar a área do jogador ao servidor, e o relógio do servidor no cliente.

Uma câmera de script para vitrines e cenas, um job por frame que você liga só enquanto é necessário, a metade do cliente do streaming por área do servidor, e o relógio do servidor para contagens regressivas. Trabalho periódico em geral é every(ms, fn) (veja Lib: compartilhada e fivem); nunca setInterval nem um setTick puro.

ScriptCamera

new ScriptCamera

Uma câmera de script: a vista de vitrine de uma loja, um editor, uma cena, binóculos. start a cria e mostra, os outros métodos a movem e alteram, stop volta suavemente para a câmera do jogo e a destrói. Uma câmera ainda rodando quando o seu recurso para é devolvida na hora, então o jogador nunca fica preso nela.

Lado: Cliente · Espera: não

Signature
new ScriptCamera(type?: string)

Sem equivalente em Lua: recursos Lua usam CreateCam, RenderScriptCams e DestroyCam.

Parâmetros

Prop

Type

CameraView

Para onde uma câmera olha, usado por start, move e glideTo:

Prop

Type

Membros

Prop

Type

Exemplo

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

const camera = new ScriptCamera();
const CAR = { x: -44.4, y: -1097.1, z: 26.4 };

export function openShowroom(): void {
  camera.start({ x: -40.2, y: -1100.5, z: 27.6 }, { pointAt: CAR, fov: 50 }, 800);
}

export function frontView(): void {
  camera.glideTo({ x: -47.5, y: -1093.8, z: 27.2 }, { pointAt: CAR, fov: 45 }, 1200);
}

export function closeShowroom(): void {
  camera.stop(800);
}

camera.start

Cria a câmera (quando ela ainda não existe), a coloca em um ponto e a torna a vista, com transição suave a partir da câmera do jogo.

Lado: Cliente · Espera: não

Signature
camera.start(at: Vec3, view?: CameraView, easeMs?: number): void

Parâmetros

Prop

Type

Retorno

void. Veja o exemplo da classe.

camera.move

Move a câmera, na hora ou deslizando até lá (o jogo interpola). Não faz nada enquanto parada.

Lado: Cliente · Espera: não

Signature
camera.move(at: Vec3, view?: CameraView, ms?: number): void

Parâmetros

Prop

Type

Retorno

void.

Exemplo

camera.move({ x: -42.0, y: -1099.0, z: 28.5 }, { pointAt: CAR }, 600);

camera.glideTo

Faz a transição para um novo plano: uma segunda câmera no novo lugar assume a partir desta, e a antiga é destruída depois da transição. Tremor e desfoque são levados junto. Inicia a câmera quando está parada (ou quando ms é 0).

Lado: Cliente · Espera: não

Signature
camera.glideTo(at: Vec3, view: CameraView, ms: number): void

Parâmetros

Prop

Type

Retorno

void. Veja o exemplo da classe.

camera.attach

Faz a câmera seguir uma entidade com um deslocamento no espaço próprio da entidade.

Lado: Cliente · Espera: não

Signature
camera.attach(entity: number, offset: Vec3, relative?: boolean): void

Parâmetros

Prop

Type

Retorno

void.

Exemplo

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

const chase = new ScriptCamera();
if (cache.vehicle !== false) {
  chase.start({ x: 0, y: 0, z: 0 });
  chase.attach(cache.vehicle, { x: 0, y: -6, z: 2 });
}

camera.pointAt

Faz a câmera continuar olhando para um ponto.

Lado: Cliente · Espera: não

Signature
camera.pointAt(target: Vec3): void

Parâmetros

Prop

Type

Retorno

void.

camera.setFov

Muda o campo de visão (zoom).

Lado: Cliente · Espera: não

Signature
camera.setFov(fov: number): void

Parâmetros

Prop

Type

Retorno

void.

Exemplo

// Binóculos: zoom com a roda do mouse.
let fov = 40;
export function zoom(step: number): void {
  fov = Math.min(70, Math.max(5, fov + step));
  camera.setFov(fov);
}

camera.shake

Adiciona o tremor de câmera do jogo. Amplitude 0 o para.

Lado: Cliente · Espera: não

Signature
camera.shake(type: string, amplitude: number): void

Parâmetros

Prop

Type

Retorno

void.

Exemplo

camera.shake("HAND_SHAKE", 0.3);

camera.blur

Profundidade de campo: nítido entre duas distâncias, desfocado fora delas. Passe null para nenhuma. Precisa de uma native por frame, que só roda enquanto um desfoque está definido.

Lado: Cliente · Espera: não

Signature
camera.blur(dof: CameraBlur | null): void

Parâmetros

Prop

Type

Retorno

void.

Exemplo

camera.blur({ near: 2, far: 8, strength: 0.8 });

camera.stop

Devolve a vista para a câmera do jogo (com transição ao longo de easeMs) e destrói a câmera. Tremor e desfoque também terminam. Não faz nada enquanto parada.

Lado: Cliente · Espera: não

Signature
camera.stop(easeMs?: number): void

Parâmetros

Prop

Type

Retorno

void. Veja o exemplo da classe.

TickLoop

new TickLoop

Um job por frame (every(0, fn) no único agendador do seu recurso) que fica desligado até você ligá-lo. Use para qualquer coisa que precisa rodar a cada frame só às vezes: desenhar um marcador enquanto está perto, uma prévia de posicionamento, desativar o tiro enquanto mira em um amigo.

Lado: Cliente · Espera: não

Signature
new TickLoop(onFrame: () => void, name?: string)

Sem equivalente em Lua: aiLib.every(0, fn, { active = false, name = name }) e job:set(active).

Parâmetros

Prop

Type

Membros

Prop

Type

Exemplo

import { TickLoop, Zones } from "@aicore-fivem/lib/client";

const SPOT = { x: 215.8, y: -810.1, z: 30.7 };
const light = new TickLoop(() => {
  DrawLightWithRange(SPOT.x, SPOT.y, SPOT.z + 2, 61, 247, 158, 8, 4);
}, "garageLight");

const zones = new Zones();
zones.add("garage", {
  shape: { type: "sphere", center: SPOT, radius: 25 },
  onEnter: () => light.set(true),
  onExit: () => light.set(false),
});

Todo job do seu recurso roda a partir de um único setTick que só existe enquanto algum job está ligado. Crie o loop uma vez no topo do arquivo e ligue-o e desligue-o, em vez de criar um novo a cada início.

AreaFollower

new AreaFollower

A metade do cliente de um AreaStream do servidor (Streaming por área): ele informa ao servidor em qual célula da grade o jogador está sempre que ela muda (verificado a cada 2 segundos enquanto iniciado), para que o servidor envie só os objetos do mundo (drops, plantas, props colocados) ao redor do jogador. Crie um no topo do arquivo.

Lado: Cliente · Espera: não

Signature
new AreaFollower(event: string, cellSize?: number)

Sem equivalente em Lua.

Parâmetros

Prop

Type

Membros

Prop

Type

Exemplo

resource/client/index.ts
import { AreaFollower, onServerEvent } from "@aicore-fivem/lib/client";

const follower = new AreaFollower("myplants:cell");
follower.start();

const plants = new Map<number, unknown>();

// O stream envia (reset, puts, removes): um snapshot com reset true, depois só mudanças.
onServerEvent(
  "myplants:area",
  {
    args: ([reset, puts, removes]) =>
      typeof reset === "boolean" && Array.isArray(puts) && Array.isArray(removes)
        ? ([reset, puts, removes] as const)
        : null,
  },
  (reset, puts, removes) => {
    if (reset) plants.clear();
    for (const plant of puts as Array<{ id?: unknown } | null>)
      if (typeof plant?.id === "number") plants.set(plant.id, plant);
    for (const id of removes) if (typeof id === "number") plants.delete(id);
  },
);

O servidor verifica uma célula informada contra a posição real do jogador (followReported só aceita células a até uma célula do ped), então um trapaceiro não consegue pedir uma área distante.

ServerClock

new ServerClock

O relógio do servidor em um cliente. Os relógios do cliente e do servidor podem diferir, então uma contagem regressiva até um horário do servidor (o cooldown de um roubo, o fim de um leilão) precisa ser convertida para o horário local primeiro. Chame sync com o Date.now() do servidor sempre que chegar um snapshot ou uma mensagem de início.

Lado: Cliente (de @aicore-fivem/lib/shared) · Espera: não

Signature
new ServerClock()

Sem equivalente em Lua.

Membros

Prop

Type

Exemplo

resource/client/index.ts
import { every, onServerEvent } from "@aicore-fivem/lib/client";
import { ServerClock } from "@aicore-fivem/lib/shared";

const clock = new ServerClock();
let endsAt = 0; // horário local

onServerEvent(
  "myauction:state",
  { args: ([now, ends]) => (typeof now === "number" && typeof ends === "number" ? [now, ends] : null) },
  (now, ends) => {
    clock.sync(now);
    endsAt = clock.toLocal(ends);
  },
);

every(1000, () => {
  const left = Math.max(0, Math.round((endsAt - Date.now()) / 1000));
  SendNUIMessage({ action: "countdown", data: left });
});

O servidor envia o horário de fim uma vez; o cliente faz a contagem regressiva no próprio relógio. Nunca envie o tempo restante a cada segundo.

Nesta página