Lua-only helpers
aiLib.playerData, aiLib.online, aiLib.isAdmin and the aiLib.menu table: the aiLib functions whose Lua form differs from the TypeScript lib.
Most aiLib functions are the Lua twin of a TypeScript function and are documented next to it, with a Lua tab (see Every aiLib function). The ones on this page have a different name, shape or behaviour in Lua, so they are documented here.
Client: player data
aiLib.playerData.get
The last value ai-core sent for one key of the local player's data. When nothing has arrived since your resource started, it asks ai-core once (GetPlayerData) and keeps the answer.
Side: Client · Waits: no
local value = aiLib.playerData.get(key)TypeScript: the same data through getPlayerData(key) (see Membership and player data).
Parameters
Prop
Type
Returns
The value: a table for character, money ({ cash = 500, bank = 5000 }), jobs, job, gangs and metadata; a string or nil for duty and activeGang. nil while no character is loaded or ai-core is not running.
Example
RegisterCommand('cash', function()
local money = aiLib.playerData.get('money') or {}
aiLib.notify(('Cash: $%s'):format(aiLib.numbers.groupDigits(money.cash or 0)), 'info')
end, false)aiLib.playerData.onChange
Runs a function each time ai-core pushes a new value of one key for the local player (a job change, money, going on duty). For money and metadata, ai-core sends only the changed entries; aiLib merges them, so your handler always gets the whole table.
Side: Client · Waits: no
aiLib.playerData.onChange(key, function(value) end)TypeScript: onPlayerData(key, handler) (see Membership and player data).
Parameters
Prop
Type
Returns
Nothing. There is no way to remove the handler; it goes away with your resource.
Example
aiLib.playerData.onChange('duty', function(job)
if job == 'police' then
aiLib.notify('You are now on duty', 'success')
end
end)Server: online players
aiLib.online reads loaded players through ai-core's exports, one export call per read. It is meant for lookups when an action happens (a command, a callback), not for every tick. The TypeScript online keeps a local mirror with more readers and different return shapes (see Players).
aiLib.online.character
The loaded character of a player.
Side: Server · Waits: no
local character = aiLib.online.character(src)Parameters
Prop
Type
Returns
A CharacterInfo table (id, citizenid, firstname, lastname, birthdate, sex, nationality...), or nil when the player has no character loaded.
Example
aiLib.addCommand('whoami', { help = 'Shows your character id' }, function(source)
local character = aiLib.online.character(source)
if not character then return end
aiLib.notify(source, ('Character #%d (%s)'):format(character.id, character.citizenid), 'info')
end)aiLib.online.name
The character's "Firstname Lastname", else the player's FiveM name.
Side: Server · Waits: no
local name = aiLib.online.name(src, fallback)TypeScript: online.name(source, { fallback }) takes an options table instead of a boolean.
Parameters
Prop
Type
Returns
string: the character name, else the FiveM name (or "" with fallback = false, or when the player is gone).
Example
print(('%s opened the shop'):format(aiLib.online.name(source)))aiLib.online.jobs
Every job of a player, on duty or not.
Side: Server · Waits: no
local jobs = aiLib.online.jobs(src)TypeScript: online.jobs(source) returns only the job names; Lua returns the membership tables.
Parameters
Prop
Type
Returns
A list of JobMembership tables ({ job = 'police', grade = 2 }). An empty list when the player has none or no character.
Example
for _, membership in ipairs(aiLib.online.jobs(source)) do
print(membership.job, membership.grade)
endaiLib.online.gangs
Every gang of a player.
Side: Server · Waits: no
local gangs = aiLib.online.gangs(src)TypeScript: online.gangs(source) returns only the gang names.
Parameters
Prop
Type
Returns
A list of GangMembership tables ({ gang = 'ballas', grade = 0 }), or an empty list.
Example
local inAGang = #aiLib.online.gangs(source) > 0aiLib.online.jobGrade
A player's grade in one job.
Side: Server · Waits: no
local grade = aiLib.online.jobGrade(src, job)Parameters
Prop
Type
Returns
integer (0 = the lowest grade), or nil when the player is not in that job.
Example
local grade = aiLib.online.jobGrade(source, 'police')
if not grade or grade < 2 then return aiLib.fail('NOT_ALLOWED') endaiLib.online.gangGrade
A player's grade in one gang.
Side: Server · Waits: no
local grade = aiLib.online.gangGrade(src, gang)Parameters
Prop
Type
Returns
integer, or nil when the player is not in that gang.
Example
local isBoss = (aiLib.online.gangGrade(source, 'ballas') or -1) >= 3aiLib.online.dutyJob
The job a player is on duty for.
Side: Server · Waits: no
local job = aiLib.online.dutyJob(src)Parameters
Prop
Type
Returns
The job name, or nil when off duty.
Example
if aiLib.online.dutyJob(source) ~= 'police' then return aiLib.fail('NOT_ON_DUTY') endaiLib.online.sources
The server ids of every player with a loaded character.
Side: Server · Waits: no
local players = aiLib.online.sources()Returns
A list of server ids (empty when nobody is loaded or ai-core is not running).
Example
for _, src in ipairs(aiLib.online.sources()) do
if aiLib.online.dutyJob(src) == 'police' then
aiLib.notify(src, 'Robbery in progress', 'warning')
end
endEach call is an export call to ai-core. In a loop over every player, read what you need once per player, and never run it every frame. For "how many on duty", read the ai:duty:<job> global state (GlobalState['ai:duty:police']) instead.
Server: permissions
aiLib.isAdmin
Whether a player is an ai-core admin (ACE ai.admin), or has the ACE you name.
Side: Server · Waits: no
local allowed = aiLib.isAdmin(src, ace)TypeScript: isAdmin(ace?) is a guard for onClientCallback / onClientEvent instead (see Client input). In Lua, gate a callback with its ace option, or call aiLib.isAdmin yourself.
Parameters
Prop
Type
Returns
true when the player has the ACE, else false.
Example
RegisterCommand('fixall', function(source)
if not aiLib.isAdmin(source) then return end
-- admin-only work here
end, false)Client: the menu table
aiLib.menu
The dialogs live on one table. The top-level names are the same functions, kept for short calls:
On aiLib.menu | Same as | Waits | Answers |
|---|---|---|---|
menu.show(request, listeners?) | (only here) | yes | The picked item id, '__back' for a sub menu's back, or nil when closed. |
menu.input(request) | aiLib.input(request) | yes | A table of the values by field name, or nil when closed. |
menu.itemPicker(request) | aiLib.itemPicker(request) | yes | A list of { name, count }, or nil. Admin tools only. |
menu.skillCheck(difficulty, keys?) | aiLib.skillCheck(difficulty, keys?) | yes | true when every stage was hit. |
menu.lockpick(options?) | aiLib.lockpick(options?) | yes | 'opened', 'broken' or 'cancelled'. |
The request shapes are MenuRequest, InputRequest, ItemPickerRequest and SkillDifficulty. Every option and listener is documented with the TypeScript twins on Shared UI.
RegisterCommand('fine', function()
local values = aiLib.input({
title = 'Write a fine',
confirm = 'Send',
fields = {
{ name = 'amount', label = 'Amount', type = 'number', min = 1, max = 10000 },
{ name = 'reason', label = 'Reason', type = 'text', maxLength = 80 },
},
})
if values then aiLib.callAction('mypolice:fine', { values.amount, values.reason }, { fallback = 'FINE_FAILED' }) end
end, false)