AI Core

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.

KindTypeScript (lib)Lua
One GlobalState keynew GlobalKey(key, parse): .get(), .onChange((_, value, old) => ...)GlobalState[key], AddStateBagChangeHandler(key, 'global', fn)
Many GlobalState keys with one prefixnew GlobalGroup(prefix, parse): .get(id), .ids(), .onChange((id, value, old) => ...)GlobalState[prefix .. id]
A player's bagnew PlayerState(key, parse): .get(serverId), .onChange((serverId, value, old) => ...)Player(serverId).state[key], LocalPlayer.state[key] on the client
An entity's bagnew 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.

resource/client/index.ts
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.

KeyConstantOwnerValue
deadPLAYER_BAGS.deadai-deathtrue 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.
cuffedPLAYER_BAGS.cuffedai-policetrue while the player is handcuffed.
proximityPLAYER_BAGS.proximityai-voiceThe voice range, pma-voice's shape: { index, distance, mode }.

Vehicle bags (VEHICLE_BAGS)

Keys on vehicle entities. Constant: VEHICLE_BAGS in @aicore-fivem/shared.

KeyConstantOwnerValue
ai:ownedVEHICLE_BAGS.ownedai-vehiclestrue on a spawned owned vehicle.
ai:vidVEHICLE_BAGS.idai-vehiclesThe vehicle's id in ai-vehicles (number).
ai:propsVEHICLE_BAGS.propsai-vehiclesThe vehicle's look and tuning (VehicleProps). ai-core applies it on the client that owns the entity.
ai:setupVEHICLE_BAGS.setupai-vehiclesA spawn setup (VehicleSetup, for example a color picked at a shop). ai-core applies it once on the owner client.
fuelVEHICLE_BAGS.fuelthe 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

KeyConstantValue
ai:duty:<job>dutyCountKey(job) (prefix DUTY_COUNT_PREFIX)How many players are on duty in that job (number). Counts only, never who.
ai:interactionCORE.interactionStateKey"prompt" or "target": how the lib's Points let players interact (ai-core panel setting).
ai:pvpCORE.pvpStateKeytrue when players can hurt each other (panel setting pvp, command /togglepvp).
ai:inventoryINVENTORY_STATE_KEYResource name of the inventory behind ai-core's inventory layer. Unset while none runs.
ai:vehicleKeysVEHICLE_KEYS_STATE_KEYResource name of the active vehicle key script. Unset while none runs.
ai:appearanceAPPEARANCE_STATE_KEYResource name of the active clothing script. Unset while none runs.
ai:medicalCORE.medicalStateKeyResource name of the active death script.
ai:mdtCORE.mdtStateKeyResource name of the active MDT.
ai:notifyCORE.notifyStateKeyResource name of the notification UI ai-lib's cards go to. Unset: ai-lib draws its own cards.
ai:fuelFUEL_STATE_KEYResource name of the active fuel script. Unset while none runs.
ai:garagesGARAGES_STATE_KEYResource 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.

resource/server/index.ts
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.

KeyWhereOwnerValue
door:<id>GlobalStateai-doorlocktrue while the door is locked.
ai:clockGlobalStateai-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:weatherGlobalStateai-weathersync{ type, blackout }: the current weather.
ai:rweather:<id>GlobalStateai-weathersyncThe current weather of a weather region.
prop:<id>GlobalStateai-propertiestrue when the property has an owner.
rob:<id>GlobalStateai-robberiestrue while a robbery target is emptied and waits for its cooldown.
siren:lxVehicleai-sirensMain siren tone: 0 off, 1-3 a tone.
siren:manuVehicleai-sirensAir horn / manual siren: 0 off, 1 horn, 2 manual, 3 both.
siren:lightbarVehicleai-sirensThe light bar model attached to the vehicle; absent for none.

On this page