Frameworks & bridges
How detection works, and how to plug in an unsupported framework, inventory, dispatch or database.
Every bridge is listed in escrow_ignore, so you can read and edit all of them.
| Folder | Bridges |
|---|---|
client/framework/, server/framework/ | esx, qbcore, qbox, standalone |
client/inventory/, server/inventory/ | One file per supported inventory |
client/dispatch/, server/dispatch/ | One file per supported dispatch |
server/database/bridge.lua | oxmysql, mysql-async, ghmattimysql |
How detection works#
On 'auto', Cube Gang checks which resources are started, in this order:
| Option | Detection order |
|---|---|
Config.Framework | qbx_core, es_extended, qb-core, then standalone |
Config.Target | ox_target, qb-target, then the built-in [E] interaction |
Config.Inventory | ox_inventory, qs-inventory, codem-inventory, tgiann-inventory, core_inventory, mf-inventory, inventory (Chezza), qb-inventory, ps-inventory, lj-inventory, then the framework |
Config.Dispatch | cd_dispatch, ps-dispatch, qs-dispatch, core_dispatch, rcore_dispatch, codem-dispatch, origen_police, lb-tablet, then the built-in dispatch |
Config.Database | oxmysql, mysql-async, ghmattimysql |
Each bridge guards itself on its first line, so only one of each kind loads:
if Config.Inventory ~= 'ox_inventory' then return endStart Cube Gang after these resources in your server.cfg. A resource that is still stopped when Cube Gang starts cannot be detected.
Player storage#
The gang of each character is saved in a JSON column of your player table, the same way your framework saves the job:
{ "gang": 3, "grade": 4 }The table, the identifier column and the character name come from the framework bridge:
Bridge.Storage = {
table = 'users',
identifier = 'identifier',
columns = { 'firstname', 'lastname' },
}
function Bridge.FormatName(row)
return ('%s %s'):format(row.firstname, row.lastname)
endIf your characters live elsewhere, override it from the config instead of editing the bridge:
Config.PlayerTable = {
table = 'characters',
identifier = 'charid',
column = 'cube_gang',
}Adding a framework#
Copy server/framework/standalone.lua and client/framework/standalone.lua, rename them, and change the guard on the first line. A server bridge must provide:
| Function | Returns |
|---|---|
Bridge.GetPlayer(source) | player object or nil |
Bridge.GetIdentifier(source) | string - character identifier |
Bridge.GetName(source) | string - character name |
Bridge.IsAdmin(source) | boolean |
Bridge.GetJob(source) | { name, grade, onDuty } or nil |
Bridge.GetMoney(source, account) | number |
Bridge.AddMoney(source, account, amount) | boolean |
Bridge.RemoveMoney(source, account, amount) | boolean |
Bridge.Storage / Bridge.FormatName(row) | see Player storage |
It must also trigger cube_gang:playerLoaded and cube_gang:playerUnloaded with the player's server id when a character is loaded and unloaded.
Adding an inventory#
Copy the closest inventory bridge on both sides and rename it.
| Side | Function | Purpose |
|---|---|---|
| Server | Inventory.GetItemCount(source, item) | Drug selling |
| Server | Inventory.AddItem(source, item, count, metadata) | Dirty money item |
| Server | Inventory.RemoveItem(source, item, count) | Drug selling |
| Server | Inventory.GetItemLabel(item) | Notifications, drug demand |
| Server | Inventory.RegisterStash(id, label, slots, weight) | Gang stash |
| Server | Inventory.OpenStash(source, id, label, slots, weight) | Gang stash |
| Client | Inventory.GetItemCount(item) | Show the sell option only with drugs |
| Client | Inventory.OpenStash(id, label, slots, weight) | Gang stash |
Then set it explicitly:
Config.Inventory = 'my-inventory'Adding a dispatch#
Dispatch alerts are sent when a ped reports a drug sale. Copy client/dispatch/cd_dispatch.lua, rename it, and adapt Dispatch.Send:
if Config.Dispatch ~= 'my_dispatch' then return end
Dispatch = {}
function Dispatch.Send(alert)
-- alert.code, alert.title, alert.message, alert.jobs,
-- alert.coords, alert.duration, alert.blip
exports['my_dispatch']:SendAlert({
title = alert.title,
message = alert.message,
coords = alert.coords,
jobs = alert.jobs,
})
endAdd its name to the client dispatch list at the top of server/dispatch/client.lua so the server forwards alerts to the client.
Database#
server/database/bridge.lua holds one small driver per database resource. Every query uses named parameters (@name), which all three resources understand. To support another resource, add a driver with the same six functions:
drivers['my-sql'] = {
query = function(query, params, cb) exports['my-sql']:fetchAll(query, params, cb) end,
single = function(query, params, cb) ... end,
scalar = function(query, params, cb) ... end,
insert = function(query, params, cb) ... end,
update = function(query, params, cb) ... end,
transaction = function(queries, params, cb) ... end,
}