State bags
The shared state values ai-core and the ai-* scripts publish - player bags, vehicle bags and GlobalState keys - what each holds, who writes it, and how to read and follow it.
A state bag is a value FiveM keeps in sync for everyone: on GlobalState (one value for the whole server), on a player, or on an entity (a vehicle). Every resource on every side can read it, and it follows changes without any event of your own. ai-core and the ai-* scripts use them for state everyone needs, never for private data.
Read only. Each key below has one owner resource, which is the only one that writes it, always from the server. Never write these keys yourself, from the server or the client: the owner would overwrite you, and other scripts would see wrong state. To change the state, call the owner's export (for example ai-death's revive, ai-core's duty export).
How to read them
The lib has a class per kind. Each one keeps a local copy, so get costs nothing, and onChange runs your listener after a change.
| Kind | TypeScript (lib) | Lua |
|---|---|---|
| One GlobalState key | new GlobalKey(key, parse): .get(), .onChange((_, value, old) => ...) | GlobalState[key], AddStateBagChangeHandler(key, 'global', fn) |
| Many GlobalState keys with one prefix | new GlobalGroup(prefix, parse): .get(id), .ids(), .onChange((id, value, old) => ...) | GlobalState[prefix .. id] |
| A player's bag | new PlayerState(key, parse): .get(serverId), .onChange((serverId, value, old) => ...) | Player(serverId).state[key], LocalPlayer.state[key] on the client |
| An entity's bag | new EntityState(key, parse): .get(entity), .getByNetId(netId), .onChange((netId, value, old) => ...) | Entity(entity).state[key] |
parse checks the raw value: stateNumber, stateBoolean, stateString from the lib, or your own function that returns undefined for a bad value. All of them come from @aicore-fivem/lib/client or @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");
});Player bags (PLAYER_BAGS)
Keys several resources read on a player. Constant: PLAYER_BAGS in @aicore-fivem/shared.
| Key | Constant | Owner | Value |
|---|---|---|---|
dead | PLAYER_BAGS.dead | ai-death | true while the player is down. Absent or false otherwise. With another death script, use the medical layer (IsDead export, lib medical) instead: other death scripts use their own keys. |
cuffed | PLAYER_BAGS.cuffed | ai-police | true while the player is handcuffed. |
proximity | PLAYER_BAGS.proximity | ai-voice | The voice range, pma-voice's shape: { index, distance, mode }. |
Vehicle bags (VEHICLE_BAGS)
Keys on vehicle entities. Constant: VEHICLE_BAGS in @aicore-fivem/shared.
| Key | Constant | Owner | Value |
|---|---|---|---|
ai:owned | VEHICLE_BAGS.owned | ai-vehicles | true on a spawned owned vehicle. |
ai:vid | VEHICLE_BAGS.id | ai-vehicles | The vehicle's id in ai-vehicles (number). |
ai:props | VEHICLE_BAGS.props | ai-vehicles | The vehicle's look and tuning (VehicleProps). ai-core applies it on the client that owns the entity. |
ai:setup | VEHICLE_BAGS.setup | ai-vehicles | A spawn setup (VehicleSetup, for example a color picked at a shop). ai-core applies it once on the owner client. |
fuel | VEHICLE_BAGS.fuel | the fuel script (ai-fuel; ai-core keeps it for client-side fuel scripts) | Fuel level, 0-100. |
To read fuel, use the lib's fuel layer: it works with any fuel script, also those that do not write the fuel bag themselves.
GlobalState keys of ai-core
| Key | Constant | Value |
|---|---|---|
ai:duty:<job> | dutyCountKey(job) (prefix DUTY_COUNT_PREFIX) | How many players are on duty in that job (number). Counts only, never who. |
ai:interaction | CORE.interactionStateKey | "prompt" or "target": how the lib's Points let players interact (ai-core panel setting). |
ai:pvp | CORE.pvpStateKey | true when players can hurt each other (panel setting pvp, command /togglepvp). |
ai:inventory | INVENTORY_STATE_KEY | Resource name of the inventory behind ai-core's inventory layer. Unset while none runs. |
ai:vehicleKeys | VEHICLE_KEYS_STATE_KEY | Resource name of the active vehicle key script. Unset while none runs. |
ai:appearance | APPEARANCE_STATE_KEY | Resource name of the active clothing script. Unset while none runs. |
ai:medical | CORE.medicalStateKey | Resource name of the active death script. |
ai:mdt | CORE.mdtStateKey | Resource name of the active MDT. |
ai:notify | CORE.notifyStateKey | Resource name of the notification UI ai-lib's cards go to. Unset: ai-lib draws its own cards. |
ai:fuel | FUEL_STATE_KEY | Resource name of the active fuel script. Unset while none runs. |
ai:garages | GARAGES_STATE_KEY | Resource name of the active garage script. Unset while none runs. |
The resource name keys tell ai-core's client halves which script to talk to. Read them when you need to know which script runs (for a log line, a hint to the player), not to call that script directly: call ai-core's layer instead.
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"));Keys of other ai-* scripts
Shared state some ai-* scripts publish, for scripts that work with them. Each script's developer page has the details.
| Key | Where | Owner | Value |
|---|---|---|---|
door:<id> | GlobalState | ai-doorlock | true while the door is locked. |
ai:clock | GlobalState | ai-weathersync | { base, at, scale, frozen }: game minutes of the day at server time at (ms), advancing scale game minutes per real minute. Clients run the clock themselves from it. |
ai:weather | GlobalState | ai-weathersync | { type, blackout }: the current weather. |
ai:rweather:<id> | GlobalState | ai-weathersync | The current weather of a weather region. |
prop:<id> | GlobalState | ai-properties | true when the property has an owner. |
rob:<id> | GlobalState | ai-robberies | true while a robbery target is emptied and waits for its cooldown. |
siren:lx | Vehicle | ai-sirens | Main siren tone: 0 off, 1-3 a tone. |
siren:manu | Vehicle | ai-sirens | Air horn / manual siren: 0 off, 1 horn, 2 manual, 3 both. |
siren:lightbar | Vehicle | ai-sirens | The light bar model attached to the vehicle; absent for none. |