rps_lib — Full Integration Guide¶
A complete reference for calling rps_lib from another resource: every
exported function, every bridge function on both sides, real signatures
pulled directly from source, and worked examples for each module.
local RPS_Lib = exports['rps_lib']:GetLibObject()
That one line is the entire integration surface. Everything below explains what it gives you and how to use each piece correctly.
Table of contents¶
- How rps_lib exposes itself
- Setup in your resource
- Detected module fields
- Framework & player data (client)
- Framework & player data (server)
- Permissions (server)
- Jobs, gangs & economy (server)
- Vehicle database & plates (server)
- Inventory (client)
- Inventory (server)
- Vehicle keys (client)
- Vehicle keys (server)
- Fuel (client)
- Garage (client)
- Garage (server)
- Target (client)
- Notify, progress, status (client)
- Stress — two APIs, read this carefully
- 3D text & UI helpers (client)
- Banking (server)
- Shared utilities (RPS table)
- Config reference
- Full worked example
- Common mistakes
1. How rps_lib exposes itself¶
rps_lib builds one table per side during its own startup —
framework/client/init.lua builds the client's _Lib, and
framework/server/init.lua builds the server's _Lib (two separate
tables, same variable name).
As of this version, framework-specific code (ESX/QB/QBX) no longer lives inline inside those two loader files — each framework has its own folder:
framework/
├── esx/ client.lua server.lua events.lua
├── qb/ client.lua server.lua events.lua
├── qbx/ client.lua server.lua events.lua
├── client/init.lua ← loader: detects framework, merges in the right folder
└── server/init.lua ← loader: same, server side
Each framework/<name>/client.lua (and server.lua) sets a global slot
when it loads — e.g. _G.RPS_Framework_ESX_Client — containing a table of
that framework's implementations of GetPlayerData, GetJob,
GetIdentifier, etc. FXServer has no conditional script loading, so all
three framework folders load on every server, regardless of which
framework is actually running — but only the active one's functions do
anything meaningful (the other two's core-object lookups simply find
nothing and their functions are never merged in). The loader
(framework/client/init.lua / framework/server/init.lua) reads whichever
slot matches the detected framework and merges only that one into _Lib.
Every other integration file (integration/client/inventory.lua,
integration/server/stress.lua, etc.) then attaches its own functions
directly onto that same _Lib table, so by the time rps_lib finishes
loading, _Lib contains every detected-module field and every bridge
function from every file — framework-specific and backend-agnostic alike.
You never need to look inside the
framework/esx/qb/qbxfolders to userps_lib— this is purely an internal organization detail. Every function name and signature documented in this guide is identical regardless of which framework folder actually implements it underneath.
Three exports give you access to the merged result, declared identically on both sides:
exports {
'GetLibObject', -- returns the whole _Lib table
'GetFramework', -- returns _Lib.Framework as a string
'GetVersion', -- returns the RPS.Version string, e.g. '2.0.0'
}
server_exports {
'GetLibObject',
'GetFramework',
'GetVersion',
}
-- Any of these work, client or server:
local RPS_Lib = exports['rps_lib']:GetLibObject()
local fw = exports['rps_lib']:GetFramework() -- 'esx' | 'qb' | 'qbx' | 'unknown'
local ver = exports['rps_lib']:GetVersion() -- '2.0.0'
In almost every case you want GetLibObject() — it's the only one that
gives you the actual bridge functions.
2. Setup in your resource¶
-- your_script/fxmanifest.lua
fx_version 'cerulean'
game 'gta5'
dependency 'rps_lib'
client_script 'client.lua'
server_script 'server.lua'
# server.cfg
ensure rps_lib
ensure your_script
dependency 'rps_lib' is a hard guarantee enforced by FXServer's resource
graph — rps_lib will have finished its own startup (both
framework/*/init.lua files run synchronously at the top level, no
CreateThread delay for the core fields) before your resource's first
tick. With that declared, this is always safe:
local RPS_Lib = exports['rps_lib']:GetLibObject()
print(RPS_Lib.Framework) -- never nil
If you can't declare the dependency for some reason, guard it instead:
local RPS_Lib
CreateThread(function()
while GetResourceState('rps_lib') ~= 'started' do
Wait(100)
end
RPS_Lib = exports['rps_lib']:GetLibObject()
end)
Store RPS_Lib once in a local at the top of each file — don't call
GetLibObject() repeatedly. It's cheap (just returns a table reference),
but there's no reason to call it more than once per file.
3. Detected module fields¶
Both _Lib tables (client and server) carry these fields, set once at
startup by the Detect* functions in shared/core.lua:
| Field | Possible values |
|---|---|
_Lib.Framework |
'esx' | 'qb' | 'qbx' | 'unknown' |
_Lib.Inventory |
'ox_inventory', 'qb-inventory', 'qs-inventory', 'ps-inventory', 'lj-inventory', 'codem-inventory', 'origen_inventory', 'tgiann-inventory', 'core_inventory', 'jaksam_inventory', 'cheeza_inventory', 'ak47_inventory', 'ak47_qb_inventory', 'qb-inventory-old' |
_Lib.Target |
'ak47_target', 'ox_target', 'qb-target', 'qtarget', 'rps_target' |
_Lib.Fuel |
'LegacyFuel', 'ox_fuel', 'ps-fuel', 'lc_fuel', 'cdn-fuel', 'myFuel' |
_Lib.VehicleKey |
'ak47_vehiclekeys', 'ak47_qb_vehiclekeys', 'tgiann-hotwire', 'wasabi_carlock', 'qs-vehiclekeys', 'cd_garage', 'qb-vehiclekeys', 'qbx_vehiclekeys', 'vehiclekeys', 'rps_vehiclekeys', 'none' |
_Lib.Garage |
'rps_garage', 'jg-advancedgarages', 'cd_garage', 'qb-garages', 'none' |
_Lib.Banking |
'Renewed-Banking', 'okokBanking', 'qb-banking', 'none' |
_Lib.Notify |
'ox', 'esx', 'qb', 'qbx', 'okok', 'pnotify', 'native', 'custom' |
_Lib.Progressbar |
'ox', 'esx', 'qb', 'custom' |
_Lib.Stress |
'jg-stress-addon', 'ps-stress', 'qb', 'ox', 'none' |
⚠️ Important inconsistency to know about: most bridge functions read the field (
_Lib.Inventory,_Lib.VehicleKey, etc.), but a few older functions readConfig.Xdirectly instead (Config.Notify,Config.Progressbar,Config.FuelScript,Config.Stress). After auto-detection runs once at startup, both end up holding the same resolved value, so it doesn't matter which one you read for your own logic — but see §18 for the one place this actually causes a functional split, not just a naming inconsistency.
You don't need to branch on any of these yourself — call the generic
bridge function and rps_lib routes internally. They're exposed mainly so
you can show different UI text or log which backend is active.
4. Framework & player data (client)¶
All functions below are on the client _Lib. Most are implemented per-
framework in framework/<esx|qb|qbx>/client.lua and merged in by
framework/client/init.lua's loader (see §1);
GetTargetMetaValue, AddStress, and RemoveStress are framework-
agnostic and defined directly in the loader itself.
RPS_Lib.GetCoreConfig(key)¶
--- @param key string|nil (Optional, ESX only) specific config key
--- @return table|any
{}
on QBX — there's no GetConfig-style export and QBX's config lives in
files that aren't exposed at runtime. On ESX, returns ESX.GetConfig() (or
just one key if key is passed); on QB, returns QBCore.Config.
RPS_Lib.GetPlayerData()¶
--- @return table
ESX
GetPlayerData(), QBCore.Functions.GetPlayerData(), or
exports.qbx_core:GetPlayerData() depending on framework. Shape differs
per framework; this is the raw table, not normalized.
RPS_Lib.GetJob()¶
--- @return table { name, label, payment, isboss, grade = { name, level } }
{ name = 'unemployed', label = 'Unemployed', payment = 0,
isboss = false, grade = { name = 'none', level = 0 } } if no job data is
found.
local job = RPS_Lib.GetJob()
if job.name == 'police' and job.isboss then
-- boss menu access
end
RPS_Lib.GetIdentifier()¶
--- @return string
identifier on ESX,
citizenid on QB/QBX.
RPS_Lib.GetCharacterName()¶
--- @return string
"Firstname Lastname" for the local player, pulled from
firstName/lastName (ESX) or charinfo.firstname/charinfo.lastname
(QB/QBX).
RPS_Lib.GetTargetMetaValue(targetServerId, metaKey)¶
--- @param targetServerId number
--- @param metaKey string
--- @return any
rps_lib:getTargetMeta callback). Blocks for up to 1 second waiting for
the response, then returns nil if nothing came back. Used internally by
IsDead(target) / IsLastStand(target) in the status module — see
§17.
RPS_Lib.AddStress(amount) / RPS_Lib.RemoveStress(amount)¶
--- @param amount number
integration/client/stress.lua.
They read Config.Stress (not _Lib.Stress) and fire generic
rps_lib:addStress/removeStress events rather than calling
jg-stress-addon exports directly.
5. Framework & player data (server)¶
All functions below are on the server _Lib. Most are implemented per-
framework in framework/<esx|qb|qbx>/server.lua and merged in by
framework/server/init.lua's loader (see §1);
framework-agnostic helpers (GetLicense, GetIdentifierByType,
GetSourceFromIdentifier, HasPermission, GeneratePlate, etc.) are
defined directly in the loader itself. Nearly everything here takes a
source (player server ID) as its first argument.
RPS_Lib.GetPlayer(source)¶
--- @param source number
--- @return table|nil
ESX.GetPlayerFromId(source),
QBCore.Functions.GetPlayer(source), or exports.qbx_core:GetPlayer(source).
Returns nil if the player doesn't exist. Every other server function in
this section calls this internally — if it returns nil, the functions
below it return their documented empty/zero default rather than erroring.
RPS_Lib.GetIdentifier(source)¶
--- @param source number
--- @return string
identifier (ESX) or PlayerData.citizenid (QB/QBX). Empty string
if the player isn't found.
RPS_Lib.GetName(source)¶
--- @param source number
--- @return string
"Firstname Lastname", same normalization as the client's
GetCharacterName.
RPS_Lib.GetPhoneNumber(source)¶
--- @param source number
--- @return string
p.get('phone_number'). QB/QBX: PlayerData.charinfo.phone.
RPS_Lib.GetLicense(source)¶
--- @param source number
--- @return string
GetIdentifierByType(source, 'license').
RPS_Lib.GetIdentifierByType(source, idtype)¶
--- @param source number
--- @param idtype string e.g. 'steam', 'license', 'discord', 'fivem'
--- @return string|nil
GetPlayerIdentifier) for one
matching the given prefix. This does not go through the framework at
all — works regardless of _Lib.Framework.
RPS_Lib.GetSourceFromIdentifier(identifier)¶
--- @param identifier string
--- @return number|nil
GetPlayers()) comparing
GetIdentifier(src) against the given string. O(n) on player count —
fine for admin commands, avoid calling in a hot loop.
RPS_Lib.GetPlayerFromIdentifier(identifier)¶
--- @param identifier string
--- @return table|nil
GetSourceFromIdentifier + GetPlayer combined.
RPS_Lib.GetSource(Player)¶
--- @param Player table a framework player object (from GetPlayer)
--- @return number
GetPlayer — extracts the server ID back out of a player
object you already have.
RPS_Lib.GetNameFromIdentifier(identifier)¶
--- @param identifier string
--- @return string
MySQL.scalar.await) for an offline player's name —
queries the users table (firstname/lastname columns). Works
regardless of framework since it's a raw SQL query, but the table/column
names assume an ESX-style or QB-compatible users schema.
Metadata¶
--- @param source number
--- @param key string
--- @return any
RPS_Lib.GetMetaData(source, key)
--- @param source number
--- @param key string
--- @param value any
RPS_Lib.SetMetaData(source, key, value)
p.get(key) / p.set(key, value). QB/QBX: PlayerData.metadata[key]
/ p.Functions.SetMetaData(key, value).
Offline metadata¶
--- @param identifier string
--- @param key string
--- @return any
RPS_Lib.GetOfflineMetaData(identifier, key)
--- @param identifier string
--- @param key string
--- @param value any
RPS_Lib.SetOfflineMetaData(identifier, key, value)
users.metadata; QB/QBX queries players.metadata. Both
columns are expected to hold JSON.
6. Permissions (server)¶
RPS_Lib.IsAdmin(source)¶
--- @param source number
--- @return boolean
IsPlayerAceAllowed(source, 'command'). Framework-agnostic.
RPS_Lib.HasGroupPermission(source, group)¶
--- @param source number
--- @param group string
--- @return boolean
p.getGroup() == group. QB/QBX: checks
IsPlayerAceAllowed(source, 'group.' .. group) instead — note this means
on QB/QBX you need the matching add_ace group.<group> command allow
(or principal-based group) set up in your server config, not a job/gang
check.
RPS_Lib.HasPermission(source, Admin, notify)¶
--- @param source number
--- @param Admin table { WithAce, WithLicense, WithIdentifier, WithGroup }
--- @param notify boolean|nil log which check passed via RPS.Info
--- @return boolean
true on the first match:
WithAce = true→IsPlayerAceAllowed(source, 'command')WithLicense = { ['license:abc...'] = true, ... }→ checksGetLicense(source)against the table keysWithIdentifier = { ['steam:abc...'] = true, ... }→ checksGetIdentifier(source)against the table keysWithGroup = { admin = true, police = true, ... }→ checksHasGroupPermission(source, group)for each key
local allowed = RPS_Lib.HasPermission(source, {
WithAce = true,
WithGroup = { admin = true, god = true },
}, true) -- true = print which check passed
if not allowed then return end
Any of the four keys can be omitted — only the ones you provide are checked.
7. Jobs, gangs & economy (server)¶
RPS_Lib.GetJob(source) / RPS_Lib.SetJob(source, jobName, grade)¶
--- @param source number
--- @return table { name, label, payment, isboss, grade = { name, level } }
RPS_Lib.GetJob(source)
--- @param source number
--- @param jobName string
--- @param grade number
RPS_Lib.SetJob(source, jobName, grade)
GetJob(). Defaults to the
unemployed table if the player isn't found.
RPS_Lib.GetGang(source) / RPS_Lib.SetGang(source, gangName, grade)¶
--- @param source number
--- @return table { name, label, isboss, grade = { name, level } }
RPS_Lib.GetGang(source)
--- @param source number
--- @param gangName string
--- @param grade number
RPS_Lib.SetGang(source, gangName, grade)
GetGang always returns the neutral
{ name = 'none', label = 'None', isboss = false, grade = {...} } table on
ESX, and SetGang silently does nothing on ESX (the function body checks
if _Lib.Framework ~= 'esx' then ... end).
RPS_Lib.GetJobs()¶
--- @return table
ESX.GetJobs(). QB: QBCore.Shared.Jobs. QBX:
exports.qbx_core:GetJobs().
Money¶
--- @param source number
--- @param account string 'cash' | 'money' | 'bank' | 'black_money' | 'crypto'
--- ('cash' and 'money' are interchangeable — both
--- map to whichever name the active framework uses)
--- @return number
RPS_Lib.GetMoney(source, account)
--- @param source number
--- @param account string
--- @param amount number
RPS_Lib.AddMoney(source, account, amount)
RPS_Lib.RemoveMoney(source, account, amount)
'money'; QB/QBX's is natively named
'cash'. These functions normalize in the correct direction per
framework — pass either 'cash' or 'money' and it resolves to
whichever name the active framework actually expects
(p.getAccount('money')/addAccountMoney/removeAccountMoney on ESX,
p.Functions.GetMoney('cash')/AddMoney/RemoveMoney on QB/QBX). Any
other account name ('bank', 'black_money', 'crypto') passes through
unchanged.
⚠️ Earlier versions of
rps_libnormalized'money'→'cash'unconditionally before checking the framework, which silently broke cash handling on ESX (there is no'cash'account in ESX — callingp.getAccount('cash')returnsnil). Fixed — if you're on an older copy of this file, updateframework/server/init.lua.
Offline money¶
--- @param identifier string
--- @param account string 'cash' | 'money' | 'bank'
--- @return number
RPS_Lib.GetOfflineMoney(identifier, account)
--- @param identifier string
--- @param account string
--- @param amount number
RPS_Lib.AddOfflineMoney(identifier, account, amount)
RPS_Lib.RemoveOfflineMoney(identifier, account, amount) -- just calls AddOfflineMoney with -amount
users — restricted to money and bank only (anything else logs an
RPS.Error and returns 0/no-ops, rather than building a query from an
unchecked column name). QB/QBX queries the JSON money column on
players, so any key works there ('cash', 'bank', 'crypto', custom
keys) since it's just a JSON object lookup, not a SQL column.
RPS_Lib.GetAllOfflinePlayers()¶
--- @return table
SELECT identifier, firstname, lastname, job, job_grade, money, bank FROM
users. QB/QBX: SELECT citizenid, charinfo, job, money FROM players.
No pagination — be mindful on large player tables.
8. Vehicle database & plates (server)¶
RPS_Lib.IsVehicleOwner(source, plate)¶
--- @param source number
--- @param plate string
--- @return boolean
owned_vehicles (ESX) or player_vehicles (QB/QBX) table for
a row where the owner identifier matches GetIdentifier(source).
RPS_Lib.GetVehicleOwner(plate)¶
--- @param plate string
--- @return string|nil
GetSourceFromIdentifier if you need the live source).
RPS_Lib.GeneratePlate(format, prefix)¶
--- @param format string|nil Default 'AAAA 11A' — 'A' = random letter, '1' = random digit, anything else is literal
--- @param prefix string|nil
--- @return string uppercased, truncated to 8 characters
RPS_Lib.GeneratePlate() -- e.g. "XQRT 42B"
RPS_Lib.GeneratePlate('11-AAA-11') -- e.g. "84-QRT-91"
RPS_Lib.GeneratePlate('AAA1111', 'PD') -- prefix is prepended before the pattern is applied
GetVehicleOwner(plate) == nil (or your own
existence query) until it returns one that isn't taken.
RPS_Lib.GiveVehicle(source, model)¶
--- @param source number
--- @param model string|number model name or hash
owned_vehicles (ESX) or player_vehicles
(QB/QBX) for the player, with a freshly generated plate. Does not
spawn the vehicle — this only creates the database/garage entry.
9. Inventory (client)¶
Supports: ox_inventory, qs-inventory, qb-inventory,
qb-inventory-old, ps-inventory, lj-inventory, codem-inventory,
origen_inventory, tgiann-inventory, core_inventory,
jaksam_inventory, cheeza_inventory, ak47_inventory,
ak47_qb_inventory.
Core functions (work on every supported inventory)¶
--- Populates _Lib.Items / _Lib.ItemsByHash. Called automatically on
--- startup — you don't need to call this yourself.
--- @return nil
RPS_Lib.FetchItems()
--- @param hash number result of GetHashKey(itemName)
--- @return string|nil
RPS_Lib.GetWeaponNameFromHash(hash)
--- @return string|nil NUI base path for item images
RPS_Lib.GetInventoryImageLink()
--- @param name string
--- @param format string|nil defaults to '.png'
--- @return string|nil
RPS_Lib.GetItemImageLink(name, format)
--- @param identifier string unique stash ID
--- @param name string display label
--- @param weight number max weight (kg)
--- @param slots number
RPS_Lib.OpenStash(identifier, name, weight, slots)
--- @param targetServerId number search/rob another player's inventory
RPS_Lib.OpenSearchInventory(targetServerId)
--- Closes whatever inventory UI is currently open
RPS_Lib.CloseInventory()
--- @param state boolean lock/unlock the inventory during an action
RPS_Lib.SetInventoryBusy(state)
--- @param item string
--- @param amount number durability reduction — ak47_inventory only, no-op elsewhere
RPS_Lib.RemoveItemQuality(item, amount)
--- Registers item-remove net events for the active inventory/framework.
--- Called automatically on startup.
RPS_Lib.RegisterInventoryEvents()
ox_inventory-exclusive functions¶
These all check _Lib.Inventory == 'ox_inventory' internally and
safely return an empty/zero default on every other inventory — they
won't error if called on a server running qb-inventory, they just won't
do anything useful.
--- @param itemName string
--- @param metadata table|nil
--- @param strict boolean|nil
--- @return number
RPS_Lib.GetItemCount(itemName, metadata, strict)
--- @return table full player inventory contents
RPS_Lib.GetPlayerItems()
--- @return number
RPS_Lib.GetPlayerWeight()
--- @return number
RPS_Lib.GetPlayerMaxWeight()
--- @param search string 'slots' | 'count'
--- @param item string|table
--- @param metadata table|string|nil
--- @return table|number
RPS_Lib.Search(search, item, metadata)
--- @param itemName string
--- @param metadata table|nil
--- @param strict boolean|nil
--- @return number|nil
RPS_Lib.GetSlotIdWithItem(itemName, metadata, strict)
--- @return table|nil all matching slot ids
RPS_Lib.GetSlotIdsWithItem(itemName, metadata, strict)
--- @return table|nil single matching slot data
RPS_Lib.GetSlotWithItem(itemName, metadata, strict)
--- @return table|nil all matching slot data
RPS_Lib.GetSlotsWithItem(itemName, metadata, strict)
--- @return table|nil
RPS_Lib.GetCurrentWeapon()
--- @param data table item data from an item-use callback
--- @param cb function|nil
RPS_Lib.UseItem(data, cb)
--- @param slot number
RPS_Lib.UseSlot(slot)
--- @param id string|number
--- @param owner string|number|nil
RPS_Lib.SetStashTarget(id, owner)
--- @param metadata string|table
--- @param value string|nil
RPS_Lib.DisplayMetadata(metadata, value)
--- @param serverId number give an item to another player
--- @param slotId number
--- @param count number|nil
RPS_Lib.GiveItemToTarget(serverId, slotId, count)
--- @param state boolean enable weapon wheel while disabling inventory weapons
RPS_Lib.WeaponWheel(state)
--- @param value boolean
RPS_Lib.SuppressItemNotifications(value)
--- @return boolean
RPS_Lib.IsInventoryBusy()
--- @return boolean
RPS_Lib.IsInventoryOpen()
-- Example: check before letting a player start an animation that needs both hands free
if RPS_Lib.GetCurrentWeapon() then
RPS_Lib.Notify("Holster your weapon first.", "error")
return
end
10. Inventory (server)¶
Items¶
--- Populates _Lib.Items / _Lib.ItemsByHash. Runs automatically on startup
--- via the inventory auto-detect thread.
RPS_Lib.FetchItems()
--- @return table master item definitions for the active inventory
RPS_Lib.GetItems()
--- @param item string
--- @return string label, or the item name itself if not found
RPS_Lib.GetItemLabel(item)
--- @param hash number
--- @return string|nil
RPS_Lib.GetWeaponNameFromHash(hash)
Add / remove / query items¶
These four work across every supported inventory (the function bodies branch per-system internally):
--- @param inventoryId number|string player source OR stash identifier
--- @param item string
--- @param amount number
--- @param slot number|nil
--- @param meta table|nil
--- @return boolean
RPS_Lib.AddItem(inventoryId, item, amount, slot, meta)
RPS_Lib.RemoveItem(inventoryId, item, amount, slot, meta)
--- @param inventoryId number|string
--- @return table every item currently in that inventory
RPS_Lib.GetInventoryItems(inventoryId)
--- @param inventoryId number|string
--- @param item string
--- @param metadata table|nil
--- @return number count of that item
RPS_Lib.GetInventoryItem(inventoryId, item, metadata)
--- @param inventoryId number|string
--- @param item string
--- @param amount number
--- @return boolean
RPS_Lib.HasEnoughItem(inventoryId, item, amount)
--- @param inventoryId number|string
--- @param item string
--- @param amount number
--- @param metadata table|nil
--- @return boolean whether the inventory has room for this item+amount
RPS_Lib.CanCarryItem(inventoryId, item, amount, metadata)
RegisterNetEvent('your_script:buyItem', function(item, amount)
local src = source
if not RPS_Lib.CanCarryItem(src, item, amount) then
RPS_Lib.Notify(src, "You don't have enough space.", "error")
return
end
RPS_Lib.AddItem(src, item, amount)
end)
ox_inventory-exclusive server functions¶
Same pattern as the client section — these check
_Lib.Inventory == 'ox_inventory' and safely no-op (returning {} / 0 /
false / doing nothing) on every other inventory.
--- @return number
RPS_Lib.CanCarryAmount(inventoryId, item)
--- @return boolean, number can carry, free weight
RPS_Lib.CanCarryWeight(inventoryId, weight)
RPS_Lib.SetMaxWeight(inventoryId, maxWeight)
RPS_Lib.SetSlotCount(inventoryId, slots)
--- @return table|nil
RPS_Lib.GetSlot(inventoryId, slot)
--- @return number|nil
RPS_Lib.GetSlotForItem(inventoryId, itemName, metadata)
RPS_Lib.GetSlotIdWithItem(inventoryId, itemName, metadata, strict)
--- @return table|nil
RPS_Lib.GetSlotIdsWithItem(inventoryId, itemName, metadata, strict)
RPS_Lib.GetSlotWithItem(inventoryId, itemName, metadata, strict)
RPS_Lib.GetSlotsWithItem(inventoryId, itemName, metadata, strict)
--- @return number|nil
RPS_Lib.GetEmptySlot(inventoryId)
--- @return number, number, number used slots, total count, remaining
RPS_Lib.GetItemSlots(inventoryId, item, metadata)
--- @return table|number
RPS_Lib.Search(inventoryId, search, item, metadata)
--- @return table|nil full inventory object
RPS_Lib.GetInventory(inventoryId, owner)
--- @param id string|number
--- @param label string
--- @param slots number
--- @param maxWeight number
--- @param owner string|boolean|nil
--- @param groups table|nil
--- @param coords vector3|nil
RPS_Lib.RegisterStash(id, label, slots, maxWeight, owner, groups, coords)
--- @param properties table
--- @return string|nil inventoryId of the new temp stash
RPS_Lib.CreateTemporaryStash(properties)
--- @param prefix string
--- @param items table
--- @param coords vector3
--- @param slots number|nil
--- @param maxWeight number|nil
--- @param instance string|number|nil
--- @param model number|nil
RPS_Lib.CustomDrop(prefix, items, coords, slots, maxWeight, instance, model)
--- @param playerId number
--- @return string|nil dropId created from the player's inventory contents
RPS_Lib.CreateDropFromPlayer(playerId)
--- @param keep string|string[]|nil items to preserve
RPS_Lib.ClearInventory(inventoryId, keep)
RPS_Lib.RemoveInventory(inventoryId)
--- @param source number confiscate into a stash / return it later
RPS_Lib.ConfiscateInventory(source)
RPS_Lib.ReturnInventory(source)
--- @param target number
--- @param source number let `source` inspect `target`'s inventory read-only
RPS_Lib.InspectInventory(target, source)
--- @param playerId number
--- @param invType string 'player'|'stash'|'container'|'drop'|'glovebox'|'trunk'|'dumpster'
--- @param data number|string|table
RPS_Lib.ForceOpenInventory(playerId, invType, data)
--- @return table|nil
RPS_Lib.GetCurrentWeapon(inventoryId)
RPS_Lib.SetDurability(inventoryId, slot, durability)
RPS_Lib.SetMetadata(inventoryId, slot, metadata)
RPS_Lib.UpdateVehicle(oldPlate, newPlate)
--- @return boolean
RPS_Lib.CanSwapItem(inventoryId, firstItem, firstItemCount, testItem, testItemCount)
--- @return table|nil
RPS_Lib.GetContainerFromSlot(inventoryId, slotId)
--- @param properties table { slots, maxWeight, whitelist?, blacklist? }
RPS_Lib.SetContainerProperties(itemName, properties)
--- @param player table { source, identifier, name, groups?, sex?, dateofbirth? }
--- @param data table|nil
RPS_Lib.SetPlayerInventory(player, data)
Usable items¶
--- @param item string
--- @param cb function(source, itemData)
RPS_Lib.CreateUseableItem(item, cb)
ox_inventory:registerHook, qs-inventory:CreateUseableItem, or
QBCore.Functions.CreateUseableItem (used for both 'qb' and 'qbx'
framework, and for qb-inventory/qb-inventory-old).
RPS_Lib.CreateUseableItem('bandage', function(source, itemData)
RPS_Lib.RemoveItem(source, 'bandage', 1)
-- heal logic
end)
11. Vehicle keys (client)¶
Supports: ak47_vehiclekeys, ak47_qb_vehiclekeys, tgiann-hotwire,
wasabi_carlock, qs-vehiclekeys, cd_garage, qb-vehiclekeys,
qbx_vehiclekeys, vehiclekeys.
--- @param plate string
--- @param vehicle number entity handle
--- @param virtual boolean|nil temporary/virtual keys, where supported
RPS_Lib.GiveVehicleKey(plate, vehicle, virtual)
RPS_Lib.RemoveVehicleKey(plate, vehicle, virtual)
tgiann-hotwire, RemoveVehicleKey has no real equivalent by
design (it's a physical-key simulation) — it falls back to pulling the
key out of the ignition instead, if a vehicle handle is provided.
tgiann-hotwire-exclusive functions¶
All check _Lib.VehicleKey == 'tgiann-hotwire' and no-op (or return
false) on every other vehicle-key system.
--- @param vehicleOrPlate number|string
--- @return boolean
RPS_Lib.HaveVehicleKey(vehicleOrPlate)
--- @param vehicle number
--- @return boolean
RPS_Lib.IsKeyInIgnition(vehicle)
--- @param vehicle number
--- @param state boolean true = insert, false = remove
RPS_Lib.SetKeyInIgnition(vehicle, state)
--- @param vehicle number|nil
--- @param plate string|nil use one or the other — restores ignition state on spawn
RPS_Lib.CheckKeyInIgnitionWhenSpawn(vehicle, plate)
--- @param vehicle number
--- @param state boolean true = lock key in (can't be removed), false = allow removal
RPS_Lib.SetNonRemoveableIgnition(vehicle, state)
--- @param vehicle number
--- @param status number eVehicleLockState enum (0-10) — falls back to
--- SetVehicleDoorsLocked on non-tgiann-hotwire systems
RPS_Lib.SetVehicleLockStatus(vehicle, status)
--- @param state boolean|nil nil = toggle based on current engine state
RPS_Lib.ChangeEngineStateButton(state)
12. Vehicle keys (server)¶
--- @param source number
--- @param plate string
--- @param vehNetId number
--- @param virtual boolean|nil
RPS_Lib.GiveVehicleKey(source, plate, vehNetId, virtual)
RPS_Lib.RemoveVehicleKey(source, plate, vehNetId, virtual)
tgiann-hotwire, these call the real server export
(exports['tgiann-hotwire']:GiveKeyPlate(source, plate, isNew)) directly —
no client round-trip needed. On ak47_vehiclekeys, ak47_qb_vehiclekeys,
cd_garage, qb-vehiclekeys, qbx_vehiclekeys, there's no server export,
so these route through a TriggerClientEvent to the client functions in
§11 instead.
tgiann-hotwire-exclusive server functions¶
--- @param vehNetId number|nil
--- @param entity number|nil use one or the other
--- @return boolean
RPS_Lib.IsKeyInIgnition(vehNetId, entity)
--- @param state boolean
RPS_Lib.SetKeyInIgnition(vehNetId, entity, state)
RPS_Lib.CheckKeyInIgnitionWhenSpawn(vehNetId, entity)
--- @param state boolean
RPS_Lib.SetNonRemoveableIgnition(vehNetId, entity, state)
⚠️
tgiann-hotwire's own docs warn against callingGiveKey*on every pickup. It treats keys as persistent physical objects, not a togglable flag — repeated calls duplicate keys for the player. Only callGiveVehicleKeywhen a player should genuinely receive a new key (a sale, a garage handout, etc.), not every time they get in a vehicle they already have a key for.
13. Fuel (client)¶
Supports: LegacyFuel, ox_fuel, ps-fuel, lc_fuel, rcore_fuel,
rcore_fuel_beta. Falls back to native GetVehicleFuelLevel /
SetVehicleFuelLevel if nothing is detected.
--- @param vehicle number entity handle
--- @return number 0-100
RPS_Lib.GetVehicleFuel(vehicle)
--- @param vehicle number
--- @param amount number 0.0 - 100.0
RPS_Lib.SetVehicleFuel(vehicle, amount)
--- @param vehicle number
--- @param fuelType string|nil 'regular' | 'plus' | 'premium' | 'diesel' | nil (reset)
RPS_Lib.SetVehicleFuelType(vehicle, fuelType) -- lc_fuel only, no-op elsewhere
14. Garage (client)¶
Supports: qb-garages, cd_garage, jg-advancedgarages, rps_garage.
--- @param garageId string
--- @param vehicle number entity handle
--- @param garageVehicleType string|nil 'car' | 'sea' | 'air' (jg-advancedgarages only)
RPS_Lib.StoreVehicleHousing(garageId, vehicle, garageVehicleType)
--- @param garageId string
--- @param vehicleType string|nil 'car' | 'air' | 'sea' (jg-advancedgarages only)
--- @param spawnCoords vector4|nil jg-advancedgarages only
RPS_Lib.OpenGarageHousing(garageId, vehicleType, spawnCoords)
jg-advancedgarages-exclusive functions¶
RPS_Lib.ShowImpoundForm() -- opens the impound UI, if permitted
RPS_Lib.ShowPrivateGaragesDashboard() -- create/edit/delete private garages
RPS_Lib.ShowChangePlateForm(vehicle) -- @param vehicle number|nil
15. Garage (server)¶
--- @return table every registered garage's config (jg-advancedgarages only, else {})
RPS_Lib.GetAllGarages()
--- @param plate string
--- @param netId number vehicle network ID — prevents duplication when
--- another script also spawns from the same garage.
--- jg-advancedgarages v3.2.5+ only.
RPS_Lib.RegisterVehicleOutside(plate, netId)
--- @param plate string deletes a vehicle registered as outside the garage
RPS_Lib.DeleteOutsideVehicle(plate)
16. Target (client)¶
Supports: ak47_target, ox_target, qb-target, qtarget. Every zone /
entity / model / global registration is automatically cleaned up when
the calling resource stops, via GetInvokingResource() tracking and an
internal onResourceStop handler — you don't need to write your own
cleanup for these.
--- @param name string
--- @param center vector3
--- @param length number
--- @param width number
--- @param options table { minZ?, maxZ?, heading?, debugPoly? }
--- @param targetOptions table { options = {...}, distance = number }
--- @return any zone id
RPS_Lib.AddBoxZone(name, center, length, width, options, targetOptions)
--- @param points table array of vector3
--- @param options table { minZ, maxZ, debugPoly }
--- @return any
RPS_Lib.AddPolyZone(name, points, options, targetOptions)
--- @param center vector3
--- @param radius number
--- @return any
RPS_Lib.AddCircleZone(name, center, radius, options, targetOptions)
--- @param id any zone id returned by one of the Add*Zone functions
RPS_Lib.RemoveZone(id)
--- @param bones string|table
RPS_Lib.AddTargetBone(bones, targetOptions)
--- @param entities table|number
RPS_Lib.AddTargetEntity(entities, targetOptions)
RPS_Lib.RemoveTargetEntity(entities, labels)
--- @param models string|number|table
RPS_Lib.AddTargetModel(models, targetOptions)
RPS_Lib.RemoveTargetModel(models, labels)
RPS_Lib.AddGlobalPed(targetOptions)
RPS_Lib.RemoveGlobalPed(labels)
RPS_Lib.AddGlobalVehicle(targetOptions)
RPS_Lib.RemoveGlobalVehicle(labels)
RPS_Lib.AddGlobalObject(targetOptions)
RPS_Lib.RemoveGlobalObject(labels)
RPS_Lib.AddGlobalPlayer(targetOptions)
RPS_Lib.RemoveGlobalPlayer(labels)
targetOptions.options[] entries accept qb-target-style fields
(label, icon, action, job, gang, citizenid, item, event,
type) — these are converted internally into ox_target-style
(onSelect, groups, serverEvent/command, etc.) when an
ak47_target/ox_target backend is active, so you can write one option
table and it works on every supported target system.
RPS_Lib.AddBoxZone('shop_zone', vector3(100.0, 200.0, 30.0), 2.0, 2.0, {
heading = 0.0,
}, {
options = {
{
label = 'Open Shop',
icon = 'fas fa-shopping-cart',
job = 'unemployed', -- works as a single job string...
action = function() TriggerEvent('your_script:openShop') end,
},
},
distance = 2.5,
})
If you want to remove a zone before the resource stops, keep the return
value and call RemoveZone yourself — auto-cleanup only fires on
onResourceStop, not on demand.
17. Notify, progress, status (client)¶
RPS_Lib.Notify(msg, ntype, duration)¶
--- @param msg string
--- @param ntype string 'success' | 'error' | 'info'
--- @param duration number|nil ms, defaults to 5000
Config.Notify: ox → TriggerEvent('ox_lib:notify', ...)
(no lib global needed — ox_lib listens for this event on its own
client script); esx → ESX.ShowNotification(msg); qb →
QBCore.Functions.Notify; qbx → exports.qbx_core:Notify. Anything else
fires a generic rps_lib:notify event you can hook in your own resource.
RPS_Lib.ShowProgress(data, successCb, cancelCb)¶
--- @param data table { label, duration, useWhileDead?, canCancel?, disable?, anim?, prop? }
--- @param successCb function|nil called if the bar completes
--- @param cancelCb function|nil called if the bar is cancelled
--- @return boolean true = completed, false = cancelled
⚠️ The function is
ShowProgress, notProgressbar— there is noRPS_Lib.Progressbar. This exact typo has broken real integrations before; double-check this name if your progress bar isn't appearing.
data follows the ox_lib-style shape regardless of which backend is
active — rps_lib translates internally for ESX's progressBars resource
and QBCore's Functions.Progressbar.
local completed = RPS_Lib.ShowProgress({
label = 'Repairing engine...',
duration = 5000,
canCancel = true,
disable = { move = true, car = true, combat = true },
}, function()
RPS_Lib.Notify('Repair complete.', 'success')
end, function()
RPS_Lib.Notify('Repair cancelled.', 'error')
end)
Status¶
--- @param target number|nil server ID of another player, or nil for self
--- @return boolean
RPS_Lib.IsDead(target)
RPS_Lib.IsLastStand(target)
--- @return boolean IsDead(target) or IsLastStand(target)
RPS_Lib.IsIncapacitated(target)
⚠️ The "downed" check is
IsLastStand, notIsInLastStand. If you just want "is this player out of action for any reason," useIsIncapacitated— it already doesIsDead(target) or IsLastStand(target)for you.
Checking a target other than yourself triggers a server round-trip via
GetTargetMetaValue (see §4), blocking
for up to 1 second.
18. Stress — two APIs, read this carefully¶
rps_lib has two separate, non-interoperable stress implementations.
This is a real inconsistency in the codebase, not a doc simplification —
know which one you're calling.
API A — framework/client/init.lua (older)¶
--- @param amount number
RPS_Lib.AddStress(amount)
RPS_Lib.RemoveStress(amount)
Config.Stress directly. Fires generic events
(rps_lib:addStress / ps-stress:server:addStress /
hud:client:UpdateStress) — it does not call jg-stress-addon
exports even if that's what's detected.
API B — integration/client/stress.lua + integration/server/stress.lua (newer, more complete)¶
-- Client
--- @return number 0-100
RPS_Lib.GetStress()
--- @param amount number
RPS_Lib.GainStress(amount)
RPS_Lib.RelieveStress(amount)
RPS_Lib.ResetStress() -- jg-stress-addon: real export. Others: RelieveStress(100)
RPS_Lib.SetStressLevel(amount) -- jg-stress-addon: real export. Others: computed via Gain/Relieve
--- @return boolean jg-stress-addon only, false elsewhere
RPS_Lib.IsPlayerJobWhitelisted()
-- Server
--- @param source number
--- @return number
RPS_Lib.GetStress(source)
--- @param source number
--- @param amount number
RPS_Lib.GainStress(source, amount)
RPS_Lib.RelieveStress(source, amount)
RPS_Lib.ResetStress(source) -- always calls RelieveStress(source, 100); no native reset export server-side
_Lib.Stress, and does call real jg-stress-addon exports
(getStress, gainStress, relieveStress, resetStress,
setStressLevel, isPlayerJobWhitelisted) when that's the detected
system, with ps-stress/qb metadata fallbacks otherwise.
These are different function names, so both genuinely coexist on
_Libat the same time —AddStress/RemoveStress(API A) andGainStress/RelieveStress(API B) don't collide or overwrite each other. The risk isn't one clobbering the other; it's that calling the wrong one silently gives you the wrong behavior — API A never touchesjg-stress-addoneven when that's the detected system, since it only fires generic events and readsConfig.Stressrather than dispatching to the addon's real exports.Practical takeaway: always use API B (
GainStress,RelieveStress,GetStress,ResetStress,SetStressLevel) for anything you write. Only reach forAddStress/RemoveStressif you specifically need theps-stress/hud:client:UpdateStressevent-firing behavior and don't care aboutjg-stress-addonintegration.
19. 3D text & UI helpers (client)¶
From interface/3dtext.lua:
--- @param msg string
--- @param x number @param y number @param z number
--- @param scale number
--- @param r number @param g number @param b number @param a number
RPS_Lib.Draw3DText(msg, x, y, z, scale, r, g, b, a)
--- @param msg string
--- @param coords vector3
--- @param drawDistance number|nil
RPS_Lib.Show3DTextUI(msg, coords, drawDistance)
RPS_Lib.Hide3DTextUI()
--- @param items table
--- @param title string|nil
RPS_Lib.OpenContextMenu(items, title)
--- @param title string
--- @param rows table
RPS_Lib.InputDialog(title, rows)
--- @param data table
RPS_Lib.AlertDialog(data)
--- @param npcName string
--- @param options table
RPS_Lib.OpenNpcDialogue(npcName, options)
--- @param id string
--- @param title string
--- @param tasks table
RPS_Lib.ShowChecklist(id, title, tasks)
--- @param taskIndex number
--- @param done boolean
RPS_Lib.UpdateChecklistTask(id, taskIndex, done)
RPS_Lib.HideChecklist(id)
--- @param text string
--- @param duration number|nil
RPS_Lib.ShowObjective(text, duration)
RPS_Lib.HideObjective()
--- @param entity number
--- @param cb function
RPS_Lib.UseGizmo(entity, cb)
These are higher-level UI helpers built on top of ox_lib's menu/dialog
primitives where applicable — open interface/3dtext.lua directly if you
need exact parameter shapes for rows, items, or data, since they
mirror ox_lib's own table structures closely.
20. Banking (server)¶
Supports: Renewed-Banking, okokBanking, qb-banking. Falls back to
esx_addonaccount on ESX if none of the three are detected.
--- @param job string
--- @return number
RPS_Lib.GetSocietyMoney(job)
--- @param job string
--- @param amount number
RPS_Lib.AddSocietyMoney(job, amount)
RPS_Lib.RemoveSocietyMoney(job, amount)
RPS_Lib.AddSocietyMoney('police', 500)
local balance = RPS_Lib.GetSocietyMoney('police')
If _Lib.Banking == 'none' and no esx_addonaccount fallback applies,
AddSocietyMoney/RemoveSocietyMoney print an RPS.Error and do nothing;
GetSocietyMoney returns 0.
The exact export names called per backend (verified against each resource's official docs):
Renewed-Banking→getAccountMoney/addAccountMoney/removeAccountMoney(lowercase-first — this resource does not expose theqb-banking-styleGetAccountBalance/AddMoney/RemoveMoneynames some other bridges assume).okokBanking→GetAccount/AddMoney/RemoveMoney.qb-banking→GetAccountBalance/AddMoney/RemoveMoney.
21. Shared utilities (RPS table)¶
These live on the global RPS table (not _Lib) — available to any file
inside rps_lib itself, and technically reachable from outside if you
really need them, though they're meant as internal helpers rather than a
public API surface.
--- @param name string
--- @return boolean
RPS.ResourceStarted(name)
RPS.Debug(...) -- only prints if Config.Debug == true
RPS.Info(msg) -- prints with [rps_lib] tag
RPS.Log = RPS.Info -- alias
RPS.Warn(msg) -- prints with WARN tag
RPS.Error(msg) -- prints with ERROR tag
--- @param orig table
--- @return table
RPS.DeepCopy(orig)
--- @param tbl table @param val any
--- @return boolean
RPS.TableContains(tbl, val)
--- @param target table @param source table
--- @return table target, mutated in place
RPS.MergeTable(target, source)
--- @param tbl table
--- @return number works on non-sequential/mixed tables too
RPS.TableLength(tbl)
--- @param s string
--- @return string
RPS.Trim(s)
--- @param s string @param sep string
--- @return table
RPS.Split(s, sep)
--- @param s string
--- @return string
RPS.Capitalise(s)
The Detect* functions (DetectFramework, DetectInventory,
DetectTarget, DetectFuel, DetectVehicleKeys, DetectGarage,
DetectBanking, DetectNotify, DetectProgressbar, DetectStress) are
also on RPS, but you'll never need to call these yourself — they run
once at startup and their results are already sitting in the _Lib
fields from §3.
22. Config reference¶
rps_lib's own config.lua — you generally don't need to touch this from
your resource, but it's useful to know what each value resolves to and
which functions read Config.X directly instead of _Lib.X.
| Config key | Default | Notes |
|---|---|---|
Config.Framework |
'auto' |
'esx' | 'qb' | 'qbx' |
Config.Notify |
'ox' |
Not 'auto' by default. Read directly by _Lib.Notify (client) and the server _Lib.Notify(source, ...). |
Config.Progressbar |
'ox' |
Not 'auto' by default. Read directly by _Lib.ShowProgress. |
Config.Target |
'auto' |
|
Config.Inventory |
'auto' |
|
Config.VehicleKey |
'auto' |
|
Config.FuelScript |
'auto' |
Read directly by the fuel module (not _Lib.Fuel). |
Config.Garage |
'auto' |
|
Config.Banking |
'auto' |
|
Config.Stress |
'auto' |
Read by API A (AddStress/RemoveStress); API B reads _Lib.Stress instead — see §18. |
Config.Debug |
false |
Gates RPS.Debug(...) output. |
A validation pass runs at resource start and prints a WARN for any
unset or unrecognized value — check your console if you've edited
config.lua and something isn't routing the way you expect.
23. Full worked example¶
A vehicle impound system combining target, vehicle keys, banking, and stress in one realistic flow:
-- client.lua
local RPS_Lib = exports['rps_lib']:GetLibObject()
CreateThread(function()
RPS_Lib.AddGlobalVehicle({
options = {
{
label = 'Impound Vehicle',
icon = 'fas fa-warehouse',
groups = { 'police' },
action = function(entity)
local plate = GetVehicleNumberPlateText(entity)
local netId = NetworkGetNetworkIdFromEntity(entity)
TriggerServerEvent('your_script:impoundVehicle', plate, netId)
end,
},
},
distance = 3.0,
})
end)
-- server.lua
local RPS_Lib = exports['rps_lib']:GetLibObject()
local IMPOUND_FEE = 250
RegisterNetEvent('your_script:impoundVehicle', function(plate, netId)
local source = source
local allowed = RPS_Lib.HasPermission(source, {
WithGroup = { police = true },
})
if not allowed then return end
RPS_Lib.RemoveVehicleKey(source, plate, netId)
RPS_Lib.AddSocietyMoney('police', IMPOUND_FEE)
RPS_Lib.GainStress(source, 5) -- API B, see §18 — not AddStress
RPS_Lib.Notify(source, ('Vehicle %s impounded.'):format(plate), 'success')
print(('^2[your_script]^7 %s impounded by %s, $%d added to police funds')
:format(plate, source, IMPOUND_FEE))
end)
Notice that nothing here checks _Lib.Inventory, _Lib.VehicleKey,
_Lib.Target, _Lib.Banking, or _Lib.Stress — the whole point of going
through rps_lib is that this resource works unmodified across servers
running completely different combinations of those backend systems.
24. Common mistakes¶
- Guessing function names from memory or other libraries' conventions.
It's
ShowProgress, notProgressbar.IsLastStand, notIsInLastStand.GainStress/RelieveStress(API B), notAddStress/RemoveStress(API A) if you wantjg-stress-addonsupport. Open the actualintegration/*.luafile and read the doc-comment before calling — a stray top-level typo in your own file can abort your whole script's parse and present as a confusingrps_lib-side error, when the bug was never inrps_libat all. - Caching a detected field and branching on it yourself. If you find
yourself writing
if RPS_Lib.Inventory == 'ox_inventory' then ... endin your own script, that's a sign the generic function you need either already exists (check §9/§10) or should be added torps_libitself rather than re-implemented per caller. - Calling
GetLibObject()repeatedly. Store it once per file. - Assuming
_Lib.Itemsis populated on tick 0. It's filled by an auto-detect thread that can take a moment. CallRPS_Lib.GetItems()(server) for an on-demand fetch instead of reading the cache early. - Writing your own
onResourceStopcleanup for target zones. Already handled — see §16. A duplicate removal call on an already-cleaned-up zone can error depending on the underlying target resource. - Calling
tgiann-hotwire'sGiveVehicleKeyon every vehicle entry. It duplicates keys — only call it when a player should receive a genuinely new key. - Forgetting ESX has no native gang system.
GetGang/SetGangare effectively QB/QBX-only; on ESX they return a neutral stub and do nothing, respectively.