Qbox Structure and Core Exports
Qbox keeps QBCore’s data vocabulary but drops the shared core object. Everything
goes through exports on qbx_core.
No core object
-- QBCore
local QBCore = exports['qb-core']:GetCoreObject()
local Player = QBCore.Functions.GetPlayer(source)
-- Qbox
local player = exports.qbx_core:GetPlayer(source)There is no GetCoreObject() in Qbox. Calling exports directly means no
startup ordering problem and no stale shared table, which is the main reason
the fork made this change.
Qbox also exposes an ox_lib-style require for its shared modules:
local config = require '@qbx_core.config.shared'Player data
PlayerData extends a PlayerEntity persisted to the database:
local player = exports.qbx_core:GetPlayer(source)
player.PlayerData = {
source = 1,
citizenid = 'ABC12345',
license = 'license:...',
name = 'John Doe',
money = { cash = 500, bank = 5000, crypto = 0 },
charinfo = {
firstname = 'John', lastname = 'Doe', birthdate = '1990-01-01',
gender = 0, nationality = 'USA', phone = '555-0123',
account = 'US00QBX...', cid = 1,
},
job = { name = 'police', label = 'Police', type = 'leo', onduty = true,
isboss = false, grade = { name = 'Officer', level = 1, payment = 100 } },
jobs = { police = 1 },
gang = { name = 'none', label = 'No Gang', grade = { name = 'none', level = 0 } },
gangs = {},
position = vec4(0.0, 0.0, 0.0, 0.0),
metadata = { health = 200, armor = 0, hunger = 100, thirst = 100,
stress = 0, isdead = false, licences = {}, phone = {} },
}The jobs and gangs tables are the multi-job feature: they map a job name to
the grade level the player holds. Unemployed and gangless are not listed.
PlayerData.items and player.Functions exist but are deprecated. Items live
in ox_inventory; use its exports, not the player object.
Jobs and groups
Job and gang grades are numbers in Qbox, where QBCore used strings. This is the conversion bug that bites everyone.
-- qbx_core/shared/jobs.lua
police = {
label = 'Police',
type = 'leo',
defaultDuty = true,
grades = {
[0] = { name = 'Recruit', payment = 50 },
[1] = { name = 'Officer', payment = 75 },
},
},Runtime management goes through exports, and does not persist across a restart:
exports.qbx_core:CreateJob('mechanic', jobTable)
exports.qbx_core:AddPlayerToJob(citizenid, 'mechanic', 1)
exports.qbx_core:RemoveJob('mechanic')
local hasGroup = exports.qbx_core:HasGroup(source, 'police')
local isBoss = exports.qbx_core:IsGradeBoss('police', 4)Multi-job and multi-gang membership is stored in the player_groups table.
Do not install external multijob resources — they write to the same tables and
will corrupt data.
Common server calls
-- Players
local player = exports.qbx_core:GetPlayer(source)
local player = exports.qbx_core:GetPlayerByCitizenId('ABC12345')
local players = exports.qbx_core:GetQBPlayers()
-- Money
exports.qbx_core:AddMoney(source, 'cash', 100, 'paycheck')
local cash = exports.qbx_core:GetMoney(source, 'cash')
-- Metadata and permissions
local meta = exports.qbx_core:GetMetadata(source, 'stress')
local ok = exports.qbx_core:HasPermission(source, 'admin')
-- Items
exports.qbx_core:CreateUseableItem('lockpick', function(source, item) end)Server exports → · Client exports →
Events
Qbox deliberately keeps QBCore’s event names so that ported scripts keep working:
| Event | Fires when |
|---|---|
QBCore:Server:OnPlayerLoaded | A character finishes loading |
QBCore:Server:OnPlayerUnload | A character logs out |
QBCore:Server:OnJobUpdate | A player’s job changes |
QBCore:Server:OnGangUpdate | A player’s gang changes |
QBCore:Server:OnMoneyChange | A money account changes |
QBCore:Server:OnPermissionUpdate | A player’s permissions change |
qbx_core:server:onGroupUpdate | Multi-job or multi-gang membership changes |
qbx_core:server:onSetMetaData | A metadata key is written |
The two qbx_core:-prefixed events are Qbox-only. Anything reading them will not
run on QBCore.
Next steps
- Qbox installation
- ox_lib — the library Qbox is built on
- Converting from QBCore →