AI Core
Referencia de la APILib: cliente

Cámara y temporización

ScriptCamera, TickLoop, AreaFollower y ServerClock - cámaras con script, tareas por frame que solo se ejecutan cuando hacen falta, informar al servidor del área del jugador y el reloj del servidor en el cliente.

Una cámara con script para exposiciones y escenas, una tarea por frame que activas solo mientras hace falta, la mitad de cliente del streaming por áreas del servidor y el reloj del servidor para cuentas atrás. El trabajo periódico en general es every(ms, fn) (consulta Lib: compartido y fivem); nunca setInterval ni un setTick a secas.

ScriptCamera

new ScriptCamera

Una cámara con script: la vista de exposición de una tienda, un editor, una escena, unos prismáticos. start la crea y la muestra, los demás métodos la mueven y la cambian, stop vuelve suavemente a la cámara del juego y la destruye. Una cámara que sigue en marcha cuando tu recurso se detiene se devuelve al momento, así que el jugador nunca se queda atrapado en ella.

Lado: Cliente · Espera: no

Firma
new ScriptCamera(type?: string)

Sin equivalente en Lua: los recursos Lua usan CreateCam, RenderScriptCams y DestroyCam.

Parámetros

Prop

Type

CameraView

Hacia dónde mira una cámara, usado por start, move y glideTo:

Prop

Type

Miembros

Prop

Type

Ejemplo

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

Crea la cámara (cuando aún no existe), la coloca en un punto y la convierte en la vista, con una transición suave desde la cámara del juego.

Lado: Cliente · Espera: no

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

Parámetros

Prop

Type

Devuelve

void. Consulta el ejemplo de la clase.

camera.move

Mueve la cámara, al momento o deslizándose hasta allí (el juego interpola). No hace nada mientras está detenida.

Lado: Cliente · Espera: no

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

Parámetros

Prop

Type

Devuelve

void.

Ejemplo

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

camera.glideTo

Hace una transición a un nuevo plano: una segunda cámara en el nuevo lugar toma el relevo de esta, y la antigua se destruye después de la transición. La vibración y el desenfoque se mantienen. Inicia la cámara cuando está detenida (o cuando ms es 0).

Lado: Cliente · Espera: no

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

Parámetros

Prop

Type

Devuelve

void. Consulta el ejemplo de la clase.

camera.attach

Hace que la cámara siga a una entidad con un desplazamiento en el espacio propio de la entidad.

Lado: Cliente · Espera: no

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

Parámetros

Prop

Type

Devuelve

void.

Ejemplo

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

Hace que la cámara siga mirando un punto.

Lado: Cliente · Espera: no

Firma
camera.pointAt(target: Vec3): void

Parámetros

Prop

Type

Devuelve

void.

camera.setFov

Cambia el campo de visión (zoom).

Lado: Cliente · Espera: no

Firma
camera.setFov(fov: number): void

Parámetros

Prop

Type

Devuelve

void.

Ejemplo

// Prismáticos: zoom con la rueda del ratón.
let fov = 40;
export function zoom(step: number): void {
  fov = Math.min(70, Math.max(5, fov + step));
  camera.setFov(fov);
}

camera.shake

Añade la vibración de cámara del juego. Una amplitud de 0 la detiene.

Lado: Cliente · Espera: no

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

Parámetros

Prop

Type

Devuelve

void.

Ejemplo

camera.shake("HAND_SHAKE", 0.3);

camera.blur

Profundidad de campo: nítido entre dos distancias, desenfocado fuera. Pasa null para ninguna. Necesita un native por frame, que solo se ejecuta mientras hay un desenfoque fijado.

Lado: Cliente · Espera: no

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

Parámetros

Prop

Type

Devuelve

void.

Ejemplo

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

camera.stop

Devuelve la vista a la cámara del juego (con una transición de easeMs) y destruye la cámara. La vibración y el desenfoque también terminan. No hace nada mientras está detenida.

Lado: Cliente · Espera: no

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

Parámetros

Prop

Type

Devuelve

void. Consulta el ejemplo de la clase.

TickLoop

new TickLoop

Una tarea por frame (every(0, fn) en el único planificador de tu recurso) que está apagada hasta que la enciendes. Úsala para todo lo que deba ejecutarse en cada frame solo a veces: dibujar un marcador mientras estás cerca, una vista previa de colocación, desactivar el disparo mientras apuntas a un amigo.

Lado: Cliente · Espera: no

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

Sin equivalente en Lua: aiLib.every(0, fn, { active = false, name = name }) y job:set(active).

Parámetros

Prop

Type

Miembros

Prop

Type

Ejemplo

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

Cada tarea de tu recurso se ejecuta desde un único setTick que solo existe mientras hay una tarea encendida. Crea el bucle una vez al principio del archivo y conmútalo, en lugar de crear uno nuevo en cada inicio.

AreaFollower

new AreaFollower

La mitad de cliente de un AreaStream de servidor (Streaming por áreas): indica al servidor en qué celda de la cuadrícula está el jugador cada vez que cambia (se comprueba cada 2 segundos mientras está iniciado), para que el servidor envíe solo los objetos del mundo (objetos tirados, plantas, props colocados) alrededor del jugador. Crea uno al principio del archivo.

Lado: Cliente · Espera: no

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

Sin equivalente en Lua.

Parámetros

Prop

Type

Miembros

Prop

Type

Ejemplo

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

// El stream envía (reset, puts, removes): un snapshot con reset en true y después solo cambios.
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);
  },
);

El servidor comprueba una celda informada contra la posición real del jugador (followReported solo acepta celdas a una celda como máximo del ped), así que un tramposo no puede pedir un área lejana.

ServerClock

new ServerClock

El reloj del servidor en un cliente. Los relojes del cliente y del servidor pueden diferir, así que una cuenta atrás hacia una hora del servidor (el cooldown de un robo, el final de una subasta) debe convertirse primero a hora local. Llama a sync con el Date.now() del servidor cada vez que llegue un snapshot o un mensaje de inicio.

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

Firma
new ServerClock()

Sin equivalente en Lua.

Miembros

Prop

Type

Ejemplo

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

El servidor envía la hora de fin una vez; el cliente cuenta hacia atrás con su propio reloj. Nunca envíes el tiempo restante cada segundo.

En esta página