Bridges
np_phone talks to frameworks and voice resources only through Phone.Framework and Phone.Voice (see Architecture §4–5). Each bridge file calls Phone.Bridge.shouldLoad(kind, name, resource) and returns early unless its resource is started and selected (Config.Framework / Config.Voice, or 'auto'). Files are numbered so auto prefers qbx over qb (qbx also provides qb-core) and pma-voice over the others. Optional exports are called through pcall, so a missing or broken dependency degrades instead of erroring.
bridge/framework/server/0_common.lua holds shared helpers (Phone.BridgeUtil: amount validation, ox_inventory item count, qb vehicle state mapping, pcall wrapper). It doesn't define a bridge.
Framework (server)
| Contract | qbx (qbx_core) | qb (qb-core) | esx (es_extended) |
|---|---|---|---|
| core object | exports.qbx_core | exports['qb-core']:GetCoreObject() | exports.es_extended:getSharedObject() |
getIdentifier | GetPlayer(src).PlayerData.citizenid | QBCore.Functions.GetPlayer(src).PlayerData.citizenid | ESX.GetPlayerFromId(src).identifier |
getName | charinfo.firstname/lastname | charinfo.firstname/lastname | xPlayer.get('firstName'/'lastName'), else xPlayer.getName() |
getJob | job.name/label/grade.level/grade.name/onduty | same as qbx | job.name/label/grade/grade_label/onDuty (missing onDuty = on duty) |
getMoney | PlayerData.money[cash|bank] | same | xPlayer.getAccount('money'|'bank').money (cash → money) |
removeMoney | exports.qbx_core:RemoveMoney(src, type, amount, reason) | Player.Functions.RemoveMoney | balance check, then xPlayer.removeAccountMoney |
addMoney | exports.qbx_core:AddMoney(src, …) | Player.Functions.AddMoney | xPlayer.addAccountMoney |
addMoneyOffline | exports.qbx_core:AddMoney(citizenid, …) (qbx loads offline players itself) | online: GetPlayerByCitizenId; offline: UPDATE players SET money = JSON_SET(…) | online: GetPlayerFromIdentifier; offline: UPDATE users SET accounts = JSON_SET(…) |
getSourceByIdentifier | GetPlayerByCitizenId | QBCore.Functions.GetPlayerByCitizenId | ESX.GetPlayerFromIdentifier(id).source |
hasItem | ox_inventory GetItemCount, else qb-inventory HasItem | ox_inventory, qb-inventory HasItem, else Player.Functions.GetItemByName | ox_inventory, else xPlayer.getInventoryItem(item).count |
getVehicles | player_vehicles (state 0 out / 1 garaged / 2 impounded) | same | owned_vehicles (stored = 1 garaged, pound set = impounded, props JSON for model/fuel/health) |
getCharacterInfo | charinfo + metadata.licences | same | xPlayer.get('firstName','lastName','dateofbirth','sex') + optional user_licenses table |
onPlayerLoaded | QBCore:Server:PlayerLoaded (player) | same | esx:playerLoaded (playerId, xPlayer, isNew) |
onPlayerUnloaded | QBCore:Server:OnPlayerUnload, qbx_core:server:playerLoggedOut | QBCore:Server:OnPlayerUnload (also fired on drop) | esx:playerLogout, esx:playerDropped |
The core also listens to playerDropped itself, so every framework unloads correctly.
Framework (client)
| Contract | qbx | qb | esx |
|---|---|---|---|
isLoaded | LocalPlayer.state.isLoggedIn / load event | same + GetPlayerData().citizenid | ESX.IsPlayerLoaded() |
isDead | metadata.isdead / inlaststand (via exports.qbx_core:GetPlayerData()) | QBCore.Functions.GetPlayerData().metadata | esx:onPlayerDeath / esx:onPlayerSpawn, ESX.GetPlayerData().dead, IsEntityDead |
isCuffed | metadata.ishandcuffed, IsPedCuffed | same | LocalPlayer.state.handcuffed / isCuffed, IsPedCuffed (ESX has no standard flag) |
onLoaded | QBCore:Client:OnPlayerLoaded | same | esx:playerLoaded |
onUnloaded | QBCore:Client:OnPlayerUnload | same | esx:onPlayerLogout |
Voice (server)
| Contract | pma-voice | SaltyChat (saltychat) | YACA (yaca-voice) |
|---|---|---|---|
startCall(callId, sources) | setPlayerCall(src, channel) for each source; string ids are mapped to numeric channels | AddPlayersToCall('np_phone:'..callId, sources) | callPlayer(a, b, true) for every new pair |
endCall(callId, sources) | setPlayerCall(src, 0) | RemovePlayersFromCall('np_phone:'..callId, sources) | callPlayer(src, other, false) for every remaining participant |
setSpeaker(src, on) | no-op (no server export) | SetPhoneSpeaker(src, on) | enablePhoneSpeaker(src, on) |
startCall adds sources to a call (creating it), and endCall removes the given sources. Call endCall with every participant to end the call. With no voice resource, Phone.Voice.name == 'none' and every method is a no-op.
Sources (verified 2026-10-04)
- qbx_core: https://github.com/Qbox-project/qbx_core:
server/functions.lua(GetPlayer, GetPlayerByCitizenId),server/player.lua(AddMoney/RemoveMoney with citizenid → offline player, GetOfflinePlayer, events),server/events.lua(isLoggedInstate bag),client/events.lua,client/functions.lua(GetPlayerData export) - qb-core: https://github.com/qbcore-framework/qb-core:
server/player.lua(Player.Functions method table, AddMoney/RemoveMoney,QBCore:Server:PlayerLoaded,QBCore:Server:OnPlayerUnload),server/events.lua(playerDropped → OnPlayerUnload),server/functions.lua - ESX Legacy: https://github.com/esx-framework/esx_core:
[core]/es_extended/server/classes/player.lua(getAccount, add/removeAccountMoney, getInventoryItem, get, job.onDuty),server/main.lua(esx:playerLoaded,esx:playerDropped,esx:playerLogout),client/modules/events.lua(esx:onPlayerDeath,dead),[SQL]/legacy.sql(owned_vehicles) - ox_inventory: https://github.com/overextended/ox_inventory:
modules/inventory/server.lua(GetItemCount,Search) - qb-inventory: https://github.com/qbcore-framework/qb-inventory:
server/functions.lua(HasItemexport) - pma-voice: https://github.com/AvarianKnight/pma-voice/blob/main/server/module/phone.lua (
setPlayerCallexport) - SaltyChat: https://github.com/saltminede/saltychat-fivem/blob/master/README.md (server exports
AddPlayersToCall,RemovePlayersFromCall,SetPhoneSpeaker) - YACA: https://github.com/yaca-systems/fivem-yaca-typescript/blob/main/README.md (resource
yaca-voice; server exportscallPlayer,enablePhoneSpeaker,muteOnPhone,isPlayerInCall)
Not verified against a running server: the qbx/qb player_vehicles column set (taken from the qb-core schema that qbx_vehicles keeps), ESX user_licenses (esx_license, optional), and handcuff flags of third-party police scripts (ESX).