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

Планирование и жизненный цикл

every, onStop, caller, ByResource, Reasons, sleep и waitFor: периодическая работа, ожидание и данные, принадлежащие ресурсу, который их зарегистрировал.

TypeScript
import { every, onStop, caller, ByResource, Reasons } from "@aicore-fivem/lib/fivem";
import { sleep, waitFor } from "@aicore-fivem/lib/shared";

Периодическая работа

every

Выполняет функцию каждые ms миллисекунд (0 = каждый кадр) из единого планировщика вашего ресурса. Используйте вместо setInterval, setTick или цикла CreateThread с Wait: все задачи ресурса делят один тик, и этот тик существует, только пока включена хотя бы одна задача, поэтому простаивающий ресурс ничего не стоит в resmon.

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

Сигнатура
every(ms: number, fn: () => unknown, options?: EveryOptions): Job
Lua
local job = aiLib.every(ms, fn, options) -- job:set(active), job:stop(), job.running

Параметры

Prop

Type

EveryOptions

Prop

Type

Возвращает

Job: дескриптор для включения и выключения задачи.

Prop

Type

Пример

Покадровая задача, которая работает, только пока ей есть что делать:

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

// Скрывает прицел каждый кадр, но только пока в руках оружие.
const hideCrosshair = every(0, () => HideHudComponentThisFrame(14), {
  active: cache.weapon !== false,
  name: "hide crosshair",
});

onCache("weapon", (weapon) => hideCrosshair.set(weapon !== false));

Задача никогда не должна ждать: никакого Wait в Lua, никакой длинной цепочки await в TypeScript, которая должна завершиться до следующего запуска. В Lua Wait внутри задачи задерживает все остальные задачи ресурса; для этого запустите поток из задачи. Сбойная задача логируется не чаще раза в 10 секунд (ошибки в промежутке подсчитываются в следующую строку).

Ожидание

sleep

Ждёт ms миллисекунд.

Сторона: Клиент, сервер и NUI · Ждёт: да (Promise)

Сигнатура
sleep(ms: number): Promise<void>

Lua: аналога нет; используйте Wait(ms) внутри потока.

Параметры

Prop

Type

Возвращает

Promise<void>, который выполняется через ms миллисекунд.

Пример

import { sleep } from "@aicore-fivem/lib/shared";
import { fadeOut, fadeIn } from "@aicore-fivem/lib/client";

async function blink(): Promise<void> {
  await fadeOut(300);
  await sleep(1000);
  await fadeIn(300);
}

waitFor

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

Сторона: Клиент, сервер и NUI · Ждёт: да (Promise в TypeScript, в Lua приостанавливает поток)

Сигнатура
waitFor<T>(check: () => T | undefined, timeoutMs?: number | false, intervalMs?: number): Promise<T>
Lua
local value = aiLib.waitFor(check, timeout, interval) -- значение или nil после тайм-аута; вызывайте внутри потока

Параметры

Prop

Type

Возвращает

TypeScript: Promise<T>, который выполняется с первым значением, которое вернула check и которое не было undefined. После тайм-аута он отклоняется с Error("waitFor timed out after <ms> ms").

Lua: значение или nil после тайм-аута (исключение не выбрасывается).

Пример

import { waitFor } from "@aicore-fivem/lib/shared";

async function vehicleFromNet(netId: number): Promise<number | null> {
  try {
    return await waitFor(() => {
      const vehicle = NetworkGetEntityFromNetworkId(netId);
      return DoesEntityExist(vehicle) ? vehicle : undefined;
    }, 5000);
  } catch {
    return null; // не подгрузилась за 5 секунд
  }
}

В TypeScript всегда обрабатывайте отклонение (try / catch или .catch()) либо передавайте false как тайм-аут. В Lua waitFor работает только внутри потока.

Жизненный цикл ресурса

onStop

Выполняет функцию, когда ваш ресурс останавливается (на той стороне, где выполняется код). Используйте, чтобы удалить то, что создали нативы и что больше ничто не удалит: созданные вами сущности, камеры, фокус NUI.

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

Сигнатура
onStop(fn: () => void): void

Lua: аналога нет; используйте AddEventHandler('onResourceStop', function(name) if name == GetCurrentResourceName() then ... end end).

Параметры

Prop

Type

Возвращает

void.

Пример

resource/server/index.ts
import { onStop } from "@aicore-fivem/lib/server";

const spawned = new Set<number>();

onStop(() => {
  for (const entity of spawned) if (DoesEntityExist(entity)) DeleteEntity(entity);
});

Все onStop, ByResource и Reasons ресурса делят один обработчик остановки, поэтому добавление многих ничего не стоит.

caller

Имя ресурса, который вызвал выполняемый сейчас экспорт. Внутри вашего собственного кода (не в вызове экспорта) это имя вашего ресурса.

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

Сигнатура
caller(): string

Lua: аналога нет; используйте GetInvokingResource() or GetCurrentResourceName().

Возвращает

string: имя вызывающего ресурса или имя этого ресурса, если никакой другой ресурс его не вызывает.

Пример

resource/server/index.ts
import { registerExport, caller } from "@aicore-fivem/lib/server";

registerExport("Ping", () => {
  console.log(`${caller()} asked for a ping`);
  return true;
});

ByResource

Map, записи которого принадлежат ресурсу, который их задал. Когда этот ресурс останавливается, его записи сразу удаляются (и для каждой выполняется onDrop). Используйте для того, что другие ресурсы регистрируют через ваши экспорты: хуки, подсказки, предметы, пункты меню.

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

Сигнатура
new ByResource<K, V>(options?: { onDrop?: (resource: string, key: K, value: V) => void })

Lua: аналога нет.

Параметры

Prop

Type

Методы

Prop

Type

Пример

resource/server/index.ts
import { ByResource, registerExport } from "@aicore-fivem/lib/server";
import { readText } from "@aicore-fivem/lib/shared";

type Hook = (source: number, text: string) => boolean;
const hooks = new ByResource<string, Hook>({
  onDrop: (resource, id) => console.log(`${resource} stopped: hook ${id} removed`),
});

// Другой ресурс: exports["my-chat"].AddHook("swear-filter", (source, text) => ...)
registerExport("AddHook", (id: unknown, hook: unknown) => {
  const name = readText(id, 64);
  if (name === null || typeof hook !== "function") return false;
  hooks.set(name, hook as Hook); // owner = ресурс, вызывающий AddHook
  return true;
});

export function allowed(source: number, text: string): boolean {
  for (const hook of hooks.values()) if (!hook(source, text)) return false;
  return true;
}

Reasons

Переключатель, который включён, пока задана хотя бы одна причина. Каждый ресурс задаёт свои именованные причины, а причины останавливающегося ресурса сбрасываются. Используйте для «скрыть HUD», «приостановить синхронизацию», «заблокировать меню»: несколько скриптов могут попросить одновременно, а состояние возвращается обратно, только когда отпустит последний.

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

Сигнатура
new Reasons()

Lua: аналога нет.

Методы

Prop

Type

Пример

resource/client/index.ts
import { Reasons, registerExport } from "@aicore-fivem/lib/client";
import { readText } from "@aicore-fivem/lib/shared";

const hidden = new Reasons();
hidden.onChange((any) => SendNUIMessage({ action: "visible", value: !any }));

// Другие ресурсы: exports["my-hud"].Hide("cutscene") и exports["my-hud"].Show("cutscene")
registerExport("Hide", (reason: unknown) => {
  const name = readText(reason, 64);
  if (name !== null) hidden.set(name, true);
});
registerExport("Show", (reason: unknown) => {
  const name = readText(reason, 64);
  if (name !== null) hidden.set(name, false);
});

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