State bag
Общие значения состояния, которые публикуют ai-core и скрипты ai-* - bag игроков, bag транспорта и ключи GlobalState - что хранит каждый, кто его пишет и как его читать и следить за ним.
State bag - это значение, которое FiveM синхронизирует для всех: в GlobalState (одно значение на весь сервер), у игрока или у сущности (транспорта). Каждый ресурс на любой стороне может его читать, и оно следует за изменениями без каких-либо ваших событий. ai-core и скрипты ai-* используют их для состояния, которое нужно всем, и никогда для приватных данных.
Только чтение. У каждого ключа ниже есть один ресурс-владелец, и только он его пишет, всегда с сервера. Никогда не пишите эти ключи сами, ни с сервера, ни с клиента: владелец перезапишет вас, а другие скрипты увидят неверное состояние. Чтобы изменить состояние, вызовите экспорт владельца (например, реанимацию ai-death, экспорт дежурства ai-core).
Как их читать
В библиотеке есть класс на каждый вид. Каждый хранит локальную копию, поэтому get ничего не стоит, а onChange вызывает ваш обработчик после изменения.
| Вид | TypeScript (библиотека) | Lua |
|---|---|---|
| Один ключ GlobalState | new GlobalKey(key, parse): .get(), .onChange((_, value, old) => ...) | GlobalState[key], AddStateBagChangeHandler(key, 'global', fn) |
| Много ключей GlobalState с одним префиксом | new GlobalGroup(prefix, parse): .get(id), .ids(), .onChange((id, value, old) => ...) | GlobalState[prefix .. id] |
| Bag игрока | new PlayerState(key, parse): .get(serverId), .onChange((serverId, value, old) => ...) | Player(serverId).state[key], LocalPlayer.state[key] на клиенте |
| Bag сущности | new EntityState(key, parse): .get(entity), .getByNetId(netId), .onChange((netId, value, old) => ...) | Entity(entity).state[key] |
parse проверяет сырое значение: stateNumber, stateBoolean, stateString из библиотеки или ваша собственная функция, которая возвращает undefined для плохого значения. Все они берутся из @aicore-fivem/lib/client или @aicore-fivem/lib/server.
import { cache, GlobalKey, PlayerState, stateBoolean, stateNumber } from "@aicore-fivem/lib/client";
import { dutyCountKey, PLAYER_BAGS } from "@aicore-fivem/shared";
const policeOnDuty = new GlobalKey(dutyCountKey("police"), stateNumber);
const cuffed = new PlayerState(PLAYER_BAGS.cuffed, stateBoolean);
console.log(`police on duty: ${policeOnDuty.get() ?? 0}`);
policeOnDuty.onChange((_, count) => console.log(`police on duty now: ${count ?? 0}`));
cuffed.onChange((serverId, value) => {
if (serverId === cache.serverId) console.log(value ? "you are cuffed" : "you are free");
});Bag игроков (PLAYER_BAGS)
Ключи у игрока, которые читают несколько ресурсов. Константа: PLAYER_BAGS в @aicore-fivem/shared.
| Ключ | Константа | Владелец | Значение |
|---|---|---|---|
dead | PLAYER_BAGS.dead | ai-death | true, пока игрок лежит. Иначе отсутствует или false. С другим скриптом смерти используйте медицинский слой (экспорт IsDead, medical из библиотеки): другие скрипты смерти используют свои ключи. |
cuffed | PLAYER_BAGS.cuffed | ai-police | true, пока игрок в наручниках. |
proximity | PLAYER_BAGS.proximity | ai-voice | Дальность голоса в формате pma-voice: { index, distance, mode }. |
Bag транспорта (VEHICLE_BAGS)
Ключи у сущностей транспорта. Константа: VEHICLE_BAGS в @aicore-fivem/shared.
| Ключ | Константа | Владелец | Значение |
|---|---|---|---|
ai:owned | VEHICLE_BAGS.owned | ai-vehicles | true у заспавненного личного транспорта. |
ai:vid | VEHICLE_BAGS.id | ai-vehicles | Id транспорта в ai-vehicles (число). |
ai:props | VEHICLE_BAGS.props | ai-vehicles | Внешний вид и тюнинг транспорта (VehicleProps). ai-core применяет его на клиенте, который владеет сущностью. |
ai:setup | VEHICLE_BAGS.setup | ai-vehicles | Настройка при спавне (VehicleSetup, например цвет, выбранный в магазине). ai-core применяет её один раз на клиенте-владельце. |
fuel | VEHICLE_BAGS.fuel | скрипт топлива (ai-fuel; ai-core ведёт его для клиентских скриптов топлива) | Уровень топлива, 0-100. |
Чтобы прочитать топливо, используйте слой fuel из библиотеки: он работает с любым скриптом топлива, в том числе с теми, которые сами не пишут bag fuel.
Ключи GlobalState в ai-core
| Ключ | Константа | Значение |
|---|---|---|
ai:duty:<job> | dutyCountKey(job) (префикс DUTY_COUNT_PREFIX) | Сколько игроков на дежурстве по этой работе (число). Только количество, никогда не кто именно. |
ai:interaction | CORE.interactionStateKey | "prompt" или "target": как Points из библиотеки дают игрокам взаимодействовать (настройка панели ai-core). |
ai:pvp | CORE.pvpStateKey | true, когда игроки могут ранить друг друга (настройка панели pvp, команда /togglepvp). |
ai:inventory | INVENTORY_STATE_KEY | Имя ресурса инвентаря за слоем инвентаря ai-core. Не задано, пока ни один не работает. |
ai:vehicleKeys | VEHICLE_KEYS_STATE_KEY | Имя ресурса активного скрипта ключей от транспорта. Не задано, пока ни один не работает. |
ai:appearance | APPEARANCE_STATE_KEY | Имя ресурса активного скрипта одежды. Не задано, пока ни один не работает. |
ai:medical | CORE.medicalStateKey | Имя ресурса активного скрипта смерти. |
ai:mdt | CORE.mdtStateKey | Имя ресурса активного MDT. |
ai:notify | CORE.notifyStateKey | Имя ресурса интерфейса уведомлений, куда идут карточки ai-lib. Не задано: ai-lib рисует собственные карточки. |
ai:fuel | FUEL_STATE_KEY | Имя ресурса активного скрипта топлива. Не задано, пока ни один не работает. |
ai:garages | GARAGES_STATE_KEY | Имя ресурса активного скрипта гаражей. Не задано, пока ни один не работает. |
Ключи с именами ресурсов сообщают клиентским частям ai-core, с каким скриптом говорить. Читайте их, когда нужно знать, какой скрипт работает (для строки лога, подсказки игроку), а не чтобы вызвать этот скрипт напрямую: вместо этого вызывайте слой ai-core.
import { GlobalKey, stateBoolean } from "@aicore-fivem/lib/server";
import { CORE } from "@aicore-fivem/shared";
const pvp = new GlobalKey(CORE.pvpStateKey, stateBoolean);
pvp.onChange((_, on) => console.log(on ? "PvP is on" : "PvP is off"));Ключи других скриптов ai-*
Общее состояние, которое публикуют некоторые скрипты ai-*, для скриптов, работающих с ними. Подробности на странице разработчика каждого скрипта.
| Ключ | Где | Владелец | Значение |
|---|---|---|---|
door:<id> | GlobalState | ai-doorlock | true, пока дверь заперта. |
ai:clock | GlobalState | ai-weathersync | { base, at, scale, frozen }: игровые минуты дня на серверное время at (мс), продвигаются на scale игровых минут за реальную минуту. Клиенты сами ведут часы по этому значению. |
ai:weather | GlobalState | ai-weathersync | { type, blackout }: текущая погода. |
ai:rweather:<id> | GlobalState | ai-weathersync | Текущая погода погодного региона. |
prop:<id> | GlobalState | ai-properties | true, когда у недвижимости есть владелец. |
rob:<id> | GlobalState | ai-robberies | true, пока цель ограбления опустошена и ждёт окончания задержки. |
siren:lx | Транспорт | ai-sirens | Основной тон сирены: 0 выкл., 1-3 тон. |
siren:manu | Транспорт | ai-sirens | Воздушный гудок / ручная сирена: 0 выкл., 1 гудок, 2 ручная, 3 обе. |
siren:lightbar | Транспорт | ai-sirens | Модель световой балки на транспорте; отсутствует, если её нет. |
События интерфейса ai-lib
Клиентские события, которые отправляет ai-lib, когда игрок отвечает в меню, диалоге ввода, выборе предметов, мини-игре или подсказке или отменяет полосу прогресса - для скриптов, которые сами вызывают экспорты ai-lib.
События моста фреймворков
События ESX, QB / Qbox и vRP, которые отправляет ai-core, чтобы скрипты, написанные под эти фреймворки, продолжали работать, с их точными аргументами, и события фреймворков, на которые отвечает ai-core.