Cube Scripts

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.

FolderBridges
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.luaoxmysql, mysql-async, ghmattimysql

How detection works#

On 'auto', Cube Gang checks which resources are started, in this order:

OptionDetection order
Config.Frameworkqbx_core, es_extended, qb-core, then standalone
Config.Targetox_target, qb-target, then the built-in [E] interaction
Config.Inventoryox_inventory, qs-inventory, codem-inventory, tgiann-inventory, core_inventory, mf-inventory, inventory (Chezza), qb-inventory, ps-inventory, lj-inventory, then the framework
Config.Dispatchcd_dispatch, ps-dispatch, qs-dispatch, core_dispatch, rcore_dispatch, codem-dispatch, origen_police, lb-tablet, then the built-in dispatch
Config.Databaseoxmysql, mysql-async, ghmattimysql

Each bridge guards itself on its first line, so only one of each kind loads:

server/inventory/ox_inventory.luaLua
if Config.Inventory ~= 'ox_inventory' then return end
Warning

Start 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:

JSON
{ "gang": 3, "grade": 4 }

The table, the identifier column and the character name come from the framework bridge:

server/framework/esx.luaLua
Bridge.Storage = {
    table = 'users',
    identifier = 'identifier',
    columns = { 'firstname', 'lastname' },
}

function Bridge.FormatName(row)
    return ('%s %s'):format(row.firstname, row.lastname)
end

If your characters live elsewhere, override it from the config instead of editing the bridge:

config.luaLua
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:

FunctionReturns
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.

SideFunctionPurpose
ServerInventory.GetItemCount(source, item)Drug selling
ServerInventory.AddItem(source, item, count, metadata)Dirty money item
ServerInventory.RemoveItem(source, item, count)Drug selling
ServerInventory.GetItemLabel(item)Notifications, drug demand
ServerInventory.RegisterStash(id, label, slots, weight)Gang stash
ServerInventory.OpenStash(source, id, label, slots, weight)Gang stash
ClientInventory.GetItemCount(item)Show the sell option only with drugs
ClientInventory.OpenStash(id, label, slots, weight)Gang stash

Then set it explicitly:

config.luaLua
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:

client/dispatch/my_dispatch.luaLua
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,
    })
end

Add 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:

server/database/bridge.luaLua
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,
}