Frameworks
Supported frameworks, inventories and how to add your own bridge.
Devices pages
Evolent Devices talks to your framework through one bridge file per framework on each side, and to optional scripts through integrations. Nothing else calls a framework.
Supported Frameworks
| Qbox | QBCore | ESX | |
|---|---|---|---|
| Config value | qbox | qbcore | esx |
| Resource | qbx_core | qb-core | es_extended |
| Character id | citizenid | citizenid | identifier, with the multichar prefix such as char1: |
| Offline lookups | GetOfflinePlayer of qbx_core | the players table | the users table |
| Jobs | job and grade, plus the extra jobs of Qbox | job and grade | job and grade |
| On duty | job.onduty | job.onduty | job.onDuty when ESX has it, else on duty |
| Gangs | Yes | Yes | No |
| Admin check | Aces | Aces, then QBCore permissions | Aces, then ESX groups |
Config.framework = 'auto' takes the first framework that runs: qbx_core, then qb-core, then es_extended. Character ids are stored with up to 60 characters.
ESX has no gangs: the panel greys out the gang line and marks old gang lines, saving a new gang rule is refused and an old one lets nobody in.
Down and restrained
Qbox reads isdead, inlaststand and ishandcuffed of the player metadata and the isDead state bag; QBCore the same metadata. ESX keeps no dead or cuffed state on the server: the client stops device use from esx:onPlayerDeath until esx:onPlayerSpawn and while the ped is cuffed or the isDead or handcuffed state bag is set.
Events
Loaded, logged out and job or gang changes come from QBCore:Server:PlayerLoaded, QBCore:Server:OnPlayerUnload, QBCore:Server:OnJobUpdate, QBCore:Server:OnGangUpdate and QBCore:Server:SetDuty (Qbox and QBCore, Qbox also its own group events) and esx:playerLoaded, esx:playerLogout and esx:setJob (ESX), all as server-only events. When another script makes one of them a network event, a player who fires it can only name themselves.
What a bridge answers about a player (job, gang, duty, home, down) is kept for up to a second and read again at once after one of the events above.
Integrations
| File | Script | What it does |
|---|---|---|
integrations/server/inventory.lua | ox_inventory, qb-inventory, ESX inventory | Picks the inventory: ox_inventory when it runs, else qb-inventory on QBCore or the ESX inventory on ESX. Without any of them players get no device items; everything else works. |
integrations/server/properties.lua | qbx_properties | The "people with keys to this home" rule and homes only placing. Qbox only. Owners and key holders are cached for 30 s. |
integrations/client/target.lua | ox_target | Use, In use and Manage on the device. Without it, or with useTarget = false, a key prompt shows instead. |
integrations/*/weather.lua | renewed-weathersync, qb-weathersync, cd_easytime | The 3D studio holds the weather and time for its user only. With another weather script, change both files. |
integrations/client/hud.lua | Your HUD | Hides the HUD while a device is in use: it sends qbx_hud:client:setHidden and evolent:client:hudHidden. Point it at your own HUD. |
qb-houses, ps-housing and the ESX property scripts are not supported for the home rules; devices placed in their interiors still keep to the routing bucket.
Adding a framework
Each side has one file per framework: bridge/server/qbox.lua, qbcore.lua and esx.lua, and the same names in bridge/client/, plus bridge/server/common.lua for what they share (the aces, the group lists, ox_lib notices). bridge/init.lua lists the functions every bridge must have in Bridge.contract, and the resource stops at start when one is missing.
Write the bridge
Copy the bridge closest to your framework, give it a new name and fill in the same functions. Each file sets its functions on the shared bridge table and steps aside unless its framework is the one in use:
local Bridge = require 'bridge'
if not Bridge.uses('myframework') then return end
function Bridge.getCharacterId(source)
-- return the character id of the player
endLet the bridge be found
Add your framework to Bridge.FRAMEWORKS in bridge/init.lua, with the resource that marks it:
Bridge.FRAMEWORKS = {
{ id = 'qbox', resource = 'qbx_core', label = 'Qbox' },
{ id = 'qbcore', resource = 'qb-core', label = 'QBCore' },
{ id = 'esx', resource = 'es_extended', label = 'ESX' },
{ id = 'myframework', resource = 'my_core', label = 'My framework' },
}Load it
The resource loads its files with require from one entry script per side. Add your files to server/init.lua and client/init.lua next to the other bridges:
require 'bridge.server.esx'
require 'bridge.server.myframework' Integrations work the same way: their functions are set on require 'integrations', and Integrations.contract in integrations/init.lua lists the ones the server needs.