AI Core
Справочник APILib: общее и fivem

State bags

EntityState, PlayerState, GlobalKey, GlobalGroup и парсеры stateNumber, stateBoolean, stateString: чтение реплицируемых значений из памяти.

State bag это значение, которое FiveM копирует с сервера на клиенты, которым оно нужно: топливо транспорта (Entity(vehicle).state.fuel), лежит ли игрок без сознания (Player(id).state.dead), флаг на весь сервер (GlobalState["ai:pvp"]).

Прямое чтение bag медленное: каждое чтение создаёт прокси, вызывает несколько нативов и заново декодирует значение. Эти классы держат один обработчик изменений на ключ и копию каждого значения в памяти, поэтому чтение сводится к поиску в Map. Используйте их для любого bag, который читаете больше одного раза.

Файл клиента: версии только для чтения (get, onChange)
import { EntityState, PlayerState, GlobalKey, GlobalGroup, stateNumber, stateBoolean, stateString } from "@aicore-fivem/lib/client";
Файл сервера: те же классы плюс set(...)
import { EntityState, PlayerState, GlobalKey, GlobalGroup, stateNumber, stateBoolean, stateString } from "@aicore-fivem/lib/server";

Этих классов нет в @aicore-fivem/lib/fivem: импортируйте их из точки входа клиента или сервера. State bags пишет только сервер (sv_stateBagStrictMode); клиент просит сервер через колбэк, и сервер задаёт значение. Серверные методы set описаны на странице Lib: сервер, State bags.

Lua: ни у одного из них нет Lua-аналога. Lua сам читает bags (Entity(vehicle).state.fuel, Player(id).state.dead, GlobalState['ai:pvp']) и слушает их через AddStateBagChangeHandler.

Ключи, которые используют ai-core и скрипты ai-*, перечислены на странице События и состояние.

Парсеры

Каждый класс принимает парсер: функцию, которая превращает сырое реплицированное значение в ваш тип или в undefined, если значение неверное. Тип: StateParse<T> = (value: unknown) => T | undefined. Очищенный bag (null) всегда читается как undefined; парсер его не видит.

stateNumber

Принимает конечное число; всё остальное (текст, NaN, Infinity) читается как undefined.

Сторона: Клиент и сервер · Ждёт: нет

Сигнатура
stateNumber: StateParse<number>

Пример

import { EntityState, stateNumber } from "@aicore-fivem/lib/client";

const fuel = new EntityState("fuel", stateNumber); // 0-100, задаёт скрипт топлива

stateBoolean

Принимает true или false; всё остальное читается как undefined.

Сторона: Клиент и сервер · Ждёт: нет

Сигнатура
stateBoolean: StateParse<boolean>

Пример

import { PlayerState, stateBoolean } from "@aicore-fivem/lib/client";

const dead = new PlayerState("dead", stateBoolean); // true, пока игрок без сознания (ai-death)

stateString

Принимает строку; всё остальное читается как undefined.

Сторона: Клиент и сервер · Ждёт: нет

Сигнатура
stateString: StateParse<string>

Пример

import { GlobalKey, stateString } from "@aicore-fivem/lib/client";

const inventoryScript = new GlobalKey("ai:inventory", stateString); // имя ресурса активного инвентаря

Для значения-объекта напишите собственный парсер, который проверяет каждое поле и возвращает undefined для неверного значения:

import { PlayerState, type StateParse } from "@aicore-fivem/lib/client";

type Proximity = { index: number; distance: number; mode: string };
const proximity: StateParse<Proximity> = (v) => {
  if (typeof v !== "object" || v === null) return undefined;
  const { index, distance, mode } = v as Record<string, unknown>;
  return typeof index === "number" && typeof distance === "number" && typeof mode === "string"
    ? { index, distance, mode }
    : undefined;
};
const voiceRange = new PlayerState("proximity", proximity); // дальность pma-voice, которую записывает ai-voice

Классы

EntityState

Один ключ state bags сущностей (fuel, ai:owned...) для каждой сетевой сущности. Значения хранятся по сетевому id; чтение принимает хэндл сущности.

Сторона: Клиент и сервер · Ждёт: нет

Сигнатура
new EntityState<T>(key: string, parse: StateParse<T>)

Параметры

Prop

Type

Методы

Prop

Type

Пример

resource/client/index.ts
import { EntityState, stateNumber, cache, every } from "@aicore-fivem/lib/client";

const fuel = new EntityState("fuel", stateNumber);

every(1000, () => {
  if (cache.vehicle === false) return;
  SendNUIMessage({ action: "fuel", value: fuel.get(cache.vehicle) ?? 100 });
});

Память сама остаётся небольшой: сервер забывает сущность, когда её удаляют, а клиент каждые 30 секунд отбрасывает сущности, которые вышли из его зоны видимости. Сетевой id, заново занятый новой сущностью, читается заново.

PlayerState

Один ключ state bags игроков (dead, cuffed, proximity из pma-voice...) по серверному id.

Сторона: Клиент и сервер · Ждёт: нет

Сигнатура
new PlayerState<T>(key: string, parse: StateParse<T>)

Параметры

Prop

Type

Методы

Prop

Type

Пример

resource/server/index.ts
import { PlayerState, stateBoolean, onClientCallback } from "@aicore-fivem/lib/server";
import { fail } from "@aicore-fivem/lib/shared";

const dead = new PlayerState("dead", stateBoolean);
const cuffed = new PlayerState("cuffed", stateBoolean);

onClientCallback("my-shop:open", (source) => {
  if (dead.get(source) || cuffed.get(source)) return fail("CANNOT_NOW");
  return { ok: true };
});

На сервере игрок, который вышел, забывается во всех PlayerState вашего ресурса (один общий обработчик playerDropped).

GlobalKey

Один ключ GlobalState: значение, которое нужно каждому игроку (переключатель PvP, активный инвентарь). Читается один раз при старте, затем поддерживается в актуальном виде обработчиком изменений.

Сторона: Клиент и сервер · Ждёт: нет

Сигнатура
new GlobalKey<T>(key: string, parse: StateParse<T>)

Параметры

Prop

Type

Методы

Prop

Type

Пример

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

const pvp = new GlobalKey("ai:pvp", stateBoolean);

pvp.onChange((_id, on) => SendNUIMessage({ action: "pvp", value: on === true }));

GlobalGroup

Много ключей GlobalState с общим префиксом (ai:duty:police, ai:duty:ambulance), которые читаются по части после префикса. Все группы ресурса делят один обработчик.

Сторона: Клиент и сервер · Ждёт: нет

Сигнатура
new GlobalGroup<T>(prefix: string, parse: StateParse<T>)

Параметры

Prop

Type

Методы

Prop

Type

Пример

ai-core публикует, сколько игроков на дежурстве в каждой работе, под ключом ai:duty:<job>:

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

const onDuty = new GlobalGroup("ai:duty:", stateNumber);

function policeOnline(): number {
  return onDuty.get("police") ?? 0;
}

Создавайте каждый класс один раз на ключ, в начале файла, и никогда внутри часто вызываемой функции: каждый экземпляр добавляет обработчик изменений. GlobalState отправляется каждому игроку, поэтому кладите туда только значения, которые нужны каждому игроку.

На этой странице