🌉Resource Bridge
Installation Guide for the `xmmx_bridge` resource!

Config
In the xmmx_bridge/shared/config.lua you must configure a few basic settings in order to prevent errors in my resources or the bridge itself.
Config.VersionCheck     = true
Config.Debug            = false
Config.Notify           = "qb"      -- "qb", "esx", "ox", "qbx", "custom"         -- edit in shared/notifications.lua
Config.Progress         = "qb"      -- "qb", "esx", "ox", "custom"         -- edit in client/utils/progress.lua
Config.TextUi           = "ox"       -- "ox", "qb", "custom"                -- edit in client/utils/drawtext.lua
-- This option only matters for qb-inventory users. Everyone else ignore.
Config.QBInventory      = "new"     -- "new" for new QB or "old" for older QB.
If using xmmx_bridge in other resources/scripts, you must declare at the XM variable at the top of your script.
Example:
if GetResourceState('xmmx_bridge') == "started" then
    XM = exports.xmmx_bridge:ReturnObject()
endThis will allow use of any my functions found within the bridge resource.
Notifications
in the xmmx_bridge/shared/notifications.lua is where you can configure or customize notifications triggered from my resources. It is pre-configured for "qb", "esx", "ox", and "qbx. Note that iServer is passed as a variable so that you may add your server-sided exports or events for notifications.
XM.Notification = function(isServer, source, msg, _type, time)
    if Config.Notify == "qb" then
        if isServer then 
            if _type == "inform" then 
                QBCore.Functions.Notify(source, msg, "primary", time or 5000)
            else
                QBCore.Functions.Notify(source, msg, _type, time or 5000)
            end  
        else
            if _type == "inform" then 
                QBCore.Functions.Notify(msg, "primary", time or 5000)
            else
                QBCore.Functions.Notify(msg, _type, time or 5000)
            end      
        end  
    elseif Config.Notify == "qbx" then
        if isServer then 
            exports.qbx_core:Notify(source, msg, "inform", time or 5000)
        else
            exports.qbx_core:Notify(msg, "inform", time or 5000)
        end
    elseif Config.Notify == "esx" then
        if isServer then
            if _type == "inform" then 
                TriggerClientEvent('esx:showNotification', source, msg, 'info', time or 5000)
            else
                TriggerClientEvent('esx:showNotification', source, msg, _type, time or 5000)
            end  
        else
            if _type == "inform" then 
                ESX.ShowNotification(msg, 'info', time or 5000)
            else
                ESX.ShowNotification(msg, _type, time or 5000)
            end      
        end         
    elseif Config.Notify == "ox" then
        if isServer then 
            local data = {
                title = '', 
                description = msg, 
                type = _type, 
                duration = time or 5000, 
                style = { 
                    backgroundColor = '#000000a2', 
                    color = '#d6d6d6' 
                }, 
                position = "right-center",
            }
            TriggerClientEvent('ox_lib:notify', source, data)            
        else
            lib.notify({ 
                title = '', 
                description = msg, 
                type = _type, 
                duration = time or 5000, 
                style = { 
                    backgroundColor = '#000000a2', 
                    color = '#d6d6d6' 
                }, 
                position = "right-center", 
            })            
        end  
    elseif Config.Notify == "custom" then        
        -- Configure your notification here:
        if isServer then 
            -- uses source if triggered server-sided
        else
        end 
    end
endBoss Menu & Duty Toggle
This module provides unified support for opening boss menus, toggling duty status, and checking duty status across different popular FiveM frameworks (qb-core, qbx_core, and es_extended). The functions dynamically detect the active framework and execute the appropriate logic, enabling compatibility and flexibility in multi-framework environments.
Located in xmmx_bridge/client/editable/bossmenu.lua:
Functions:
XM.OpenBossMenu(data)
Opens the boss management menu for the player's job, depending on the active framework:
- qb-core: Triggers- qb-bossmenu:client:OpenMenu.
- qbx_core: Uses- exports.qbx_management:OpenBossMenu.
- es_extended: Opens the ESX society boss menu via- esx_society:openBossMenu.
XM.ToggleDuty()
Toggles the player's on-duty/off-duty status:
- qb-core: Calls the standard- QBCore:ToggleDutyserver event.
- qbx_core: Checks current duty state using- GetPlayerData()and toggles it using a custom bridge event- xmmx_bridge:server:qbxduty.
- es_extended: Prints a debug message as duty toggling is not supported by default.
XM.CheckDuty()
Returns a boolean indicating whether the player is currently on duty:
- qb-coreand- qbx_core: Reads the player's job status from- GetPlayerData().
- Fallback: Returns - trueif framework is unsupported or not explicitly handled.
XM.OpenBossMenu = function(data)
	if GetResourceState('qb-core') == "started" then 
		TriggerEvent("qb-bossmenu:client:OpenMenu")
    elseif GetResourceState('qbx_core') == "started" then
        exports.qbx_management:OpenBossMenu('job')
	elseif GetResourceState('es_extended') == "started" then
		TriggerEvent('esx_society:openBossMenu', data.society, function (menu)
			ESX.CloseContext() 
		end, {wash = false}) 
	end
end
XM.ToggleDuty = function()
	if GetResourceState('qb-core') == "started" then 
		TriggerServerEvent("QBCore:ToggleDuty")
    elseif GetResourceState('es_extended') == "started" then
        Print("[XMMX-DEBUG] Not Available by Default in ESX")
    elseif GetResourceState('qbx_core') == "started" then
        local playerData = exports.qbx_core:GetPlayerData()
        if playerData and playerData.job then
            local isOnDuty = playerData.job.onduty
            if isOnDuty then
                TriggerServerEvent("xmmx_bridge:server:qbxduty", false) -- go off duty
            else
                TriggerServerEvent("xmmx_bridge:server:qbxduty", true) -- go on duty
            end
        end        
	end
end
XM.CheckDuty = function()
    if GetResourceState('qb-core') == "started" then 
        local PlayerData = QBCore.Functions.GetPlayerData()
        if PlayerData and PlayerData.job then 
            return PlayerData.job.onduty
        end
        return false
    elseif GetResourceState('qbx_core') == "started" then 
        local PlayerData = exports.qbx_core:GetPlayerData()
        if PlayerData and PlayerData.job then
            return PlayerData.job.onduty
        end
        return false
    end
	return true
endCallbacks
These functions provide a unified abstraction layer for triggering and registering server callbacks across multiple frameworks. By detecting which framework is active (qb-core, qbx_core, or es_extended), the bridge ensures compatibility and reduces the need for conditional logic elsewhere in your codebase.
Here’s a concise documentation description for the two functions found in xmmx_bridge/client/editable/callbacks.lua and xmmx_bridge/server/functions.lua:
Client-Side
XM.TriggerCallback(name, cb, ...)
Triggers a server callback based on the active framework:
- qb-core: Uses- QBCore.Functions.TriggerCallback.
- qbx_core: Uses- lib.callback.
- es_extended: Uses- ESX.TriggerServerCallback.
Parameters:
- name(string) – The name of the callback to trigger.
- cb(function) – The function to execute upon receiving the callback result.
- ...– Additional arguments to pass to the server-side callback.
Server-Side
XM.CreateCallback(name, cb)
Registers a server callback function that can be triggered from the client:
- qb-core: Uses- QBCore.Functions.CreateCallback.
- qbx_core: Uses- lib.callback.register.
- es_extended: Uses- ESX.RegisterServerCallback.
Parameters:
- name(string) – The identifier for the callback.
- cb(function) – The server function to execute when the callback is called.
-- client:
XM.TriggerCallback = function(name, cb, ...)
    if GetResourceState('qb-core') == "started" then
        QBCore.Functions.TriggerCallback(name, cb, ...)
    elseif GetResourceState('qbx_core') == "started" then
        lib.callback(name, cb, ...)
    elseif GetResourceState('es_extended') == "started" then
        ESX.TriggerServerCallback(name, cb, ...)
    end
end
-- server:
XM.CreateCallback = function(name, cb)
    if GetResourceState('qb-core') == "started" then
        QBCore.Functions.CreateCallback(name, cb)
    elseif GetResourceState("qbx_core") == 'started' then
        lib.callback.register(name, cb)
    elseif GetResourceState('es_extended') == "started" then
        ESX.RegisterServerCallback(name, cb)
    end
endConsumables
XM.Consume Function
The XM.Consume function handles consumption logic for items classified as food, drink, or alcohol across different FiveM frameworks (qb-core, qbx_core, and es_extended). It deducts the item from the player’s inventory, displays a progress bar, and applies corresponding effects like hunger, thirst, and stress relief.
Function Signature
XM.Consume(_type, itemName, Label, info, amount, playerId)Parameters
- _type(string) – Type of consumable:- "eat",- "drink", or- "alcohol".
- itemName(string) – The internal name of the item being consumed.
- Label(string) – A readable name displayed during the progress bar animation.
- info(table) – Optional metadata or animation info passed to the- XM.Progressfunction.
- amount(number) – The value to add to hunger/thirst or other needs.
- playerId(number) – Server ID of the player consuming the item.
Behavior
- Item Deduction: Triggers - xmmx_bridge:server:toggleItemto remove 1 unit of the item from the player's inventory.
- Progress Display: Shows a progress animation with a message based on the item type (e.g., "Eating Burger..."). 
- Effect Application: Once progress is complete, the function applies effects based on the active framework: - Food ( - "eat"):- Increases hunger (or - esx_statusequivalent).
 
- Drink / Alcohol ( - "drink"/- "alcohol"):- Increases thirst. 
 
- All types relieve a random amount of stress (2–4). 
 
- Framework Handling: - qb-core/- qbx_core:- Adjusts hunger or thirst using - consumables:server:addHunger/- addThirst.
- Triggers stress relief via - hud:server:RelieveStress.
 
- es_extended:- Uses - esx_status:addfor hunger/thirst.
- Still triggers the same stress relief event. 
 
 
Returns
- trueif the item was successfully consumed and effects applied.
- nilif the progress was interrupted or an unsupported type was passed.
XM.Consume = function(_type, itemName, Label, info, amount, playerId)
    if _type == "eat" then 
        TriggerServerEvent("xmmx_bridge:server:toggleItem", playerId, false, itemName, 1)
        local progDone = XM.Progress("Eating " .. Label .. " . . .", info)
        if progDone then     
            if GetResourceState('qb-core') == "started" then
                
                TriggerServerEvent("consumables:server:addHunger", QBCore.Functions.GetPlayerData().metadata["hunger"] + amount)
                TriggerServerEvent('hud:server:RelieveStress', math.random(2, 4))
            
            elseif GetResourceState('qbx_core') == "started" then
    
                TriggerServerEvent("consumables:server:addHunger", QBCore.Functions.GetPlayerData().metadata["hunger"] + amount)
                TriggerServerEvent('hud:server:RelieveStress', math.random(2, 4))
            
            elseif GetResourceState('es_extended') == "started" then
    
                TriggerEvent('esx_status:add', 'hunger', amount)
                TriggerServerEvent('hud:server:RelieveStress', math.random(2, 4))            
            end
            return true
        end
    elseif _type == "drink" then
        TriggerServerEvent("xmmx_bridge:server:toggleItem", playerId, false, itemName, 1)
        local progDone = XM.Progress("Drinking " .. Label .. " . . .", info)
        if progDone then
            if GetResourceState('qb-core') == "started" then
                TriggerServerEvent("consumables:server:addThirst", QBCore.Functions.GetPlayerData().metadata["thirst"] + amount)
                TriggerServerEvent('hud:server:RelieveStress', math.random(2, 4))
            
            elseif GetResourceState('qbx_core') == "started" then
                TriggerServerEvent("consumables:server:addThirst", QBCore.Functions.GetPlayerData().metadata["thirst"] + amount)
                TriggerServerEvent('hud:server:RelieveStress', math.random(2, 4))
            
            elseif GetResourceState('es_extended') == "started" then
                TriggerEvent('esx_status:add', 'thirst', amount)
                TriggerServerEvent('hud:server:RelieveStress', math.random(2, 4))            
            end
            return true
        end
    elseif _type == "alcohol" then 
        TriggerServerEvent("xmmx_bridge:server:toggleItem", playerId, false, itemName, 1)
        
        local progDone = XM.Progress("Drinking " .. Label .. " . . .", info)
        if progDone then
            if GetResourceState('qb-core') == "started" then
                TriggerServerEvent("consumables:server:addThirst", QBCore.Functions.GetPlayerData().metadata["thirst"] + amount)
                TriggerServerEvent('hud:server:RelieveStress', math.random(2, 4))
            
            elseif GetResourceState('qbx_core') == "started" then
                TriggerServerEvent("consumables:server:addThirst", QBCore.Functions.GetPlayerData().metadata["thirst"] + amount)
                TriggerServerEvent('hud:server:RelieveStress', math.random(2, 4))
            
            elseif GetResourceState('es_extended') == "started" then
                TriggerEvent('esx_status:add', 'thirst', amount)
                TriggerServerEvent('hud:server:RelieveStress', math.random(2, 4))            
            end
            return true
        end
    end
endDrawText
Text UI Display Functions
These functions abstract the process of showing and hiding text-based UI prompts, allowing compatibility with multiple user interface systems (qb-core, ox_lib, es_extended). They provide a framework-agnostic way to display contextual messages on screen.
Function: XM.ShowText(data)
Displays a text-based UI message to the player, using the method defined in Config.TextUi.
Parameters:
- data(table) – Contains the following fields:- text(string, required): The message to display.
- position(string, optional): Screen position (e.g.,- "right",- "right-center"). Defaults vary by system.
- icon(string, optional): Icon to use (only for- ox).
- style(table, optional): CSS-like styling options (only for- ox).
 
Framework-Specific Behavior:
- qb: Uses- qb-core’s- DrawTextwith basic positioning.
- ox: Uses- lib.showTextUIwith additional support for icons and styling.
- esx: Calls- ESX.TextUIwith just the text string.
Function: XM.HideText()
XM.HideText()Hides the currently displayed text UI, based on the configured UI framework.
Framework-Specific Behavior:
- qb: Hides text using- qb-core:HideText.
- ox: Calls- lib.hideTextUI.
- esx: Uses- ESX.HideUI.
These functions make switching between UI libraries seamless and centralized, ideal for projects that want to support multiple frameworks or migrate between them easily.
XM.ShowText = function(data)
    if Config.TextUi == "qb" then 
        exports['qb-core']:DrawText(data.text, data.position or "right")
    elseif Config.TextUi == "ox" then
        lib.showTextUI(data.text, {
            position = data.position or "right-center",
            icon = data.icon,
            style = data.style,
        })
    elseif Config.TextUi == "esx" then
        ESX.TextUI(data.text)
    end
end
XM.HideText = function()
    if Config.TextUi == "qb" then 
        exports['qb-core']:HideText()
    elseif Config.TextUi == "ox" then
        lib.hideTextUI()
    elseif Config.TextUi == "esx" then
        ESX.HideUI() 
    end
endHud / Radar Toggles
Function: XM.ShowHud(bool)
This function is responsible for toggling the visibility of the player HUD (Heads-Up Display) based on the currently active HUD resource. It supports multiple popular HUD systems and includes extension points for custom HUDs.
Parameters
- bool(boolean) –- true: Show the HUD.
- false: Hide the HUD.
 
Framework-Specific Behavior
Depending on which HUD resource is active (i.e., its state is "started"), the function executes the corresponding visibility control:
Supported HUDs:
- 17mov_Hud- ToggleDisplay(true/false): Shows or hides the entire HUD.
- HideRadar(false/true): Shows or hides the minimap.
 
- 0r-hud-v3- ToggleVisible(true/false): Inverted logic;- falseshows HUD,- truehides it.
 
- tgiann-lumihud- Triggers the event - "tgiann-lumihud:ui"with a- trueor- falsevalue.
 
- your_hud- Placeholder for custom HUD integration. Developers can add the appropriate export or event logic to support additional HUD systems. 
 
Usage Example
XM.ShowHud(true)  -- Show HUD
XM.ShowHud(false) -- Hide HUDThis function simplifies HUD toggling by abstracting resource-specific commands and encouraging modular extension.
XM.ShowHud = function(bool)
    if bool then 
        if GetResourceState("17mov_Hud") == "started" then
            exports["17mov_Hud"]:ToggleDisplay(true) -- should hud be displayed?
            exports["17mov_Hud"]:HideRadar(false) -- should minimap be hidden?
        elseif GetResourceState("0r-hud-v3") == "started" then
            exports['0r-hud-v3']:ToggleVisible(false)
        elseif GetResourceState("tgiann-lumihud") == "started" then
            TriggerEvent("tgiann-lumihud:ui", true)
        elseif GetResourceState("your_hud") == "started" then -- add your hud name here
            -- add your hud export here to show your hud.
        end
    else
        if GetResourceState("17mov_Hud") == "started" then
            exports["17mov_Hud"]:ToggleDisplay(false) -- should hud be displayed?
            exports["17mov_Hud"]:HideRadar(true) -- should minimap be hidden?
        elseif GetResourceState("0r-hud-v3") == "started" then
            exports['0r-hud-v3']:ToggleVisible(true)
        elseif GetResourceState("tgiann-lumihud") == "started" then
            TriggerEvent("tgiann-lumihud:ui", false)
        elseif GetResourceState("your_hud") == "started" then -- add your hud name here
            -- add your hud export here to hide your hud.
            
        end
    end
endInventory Utilities
These functions are part of a cross-framework abstraction layer for managing inventory states, visibility, and item metadata across various supported inventory systems in FiveM.
Function: XM.InventoryBusy(bool)
XM.InventoryBusy(bool)Temporarily enables or disables the player's ability to interact with the inventory UI and hotkeys. This is useful during animations, progress bars, or any scripted events where the inventory should be locked.
Parameters
- bool(boolean) –- trueto mark the inventory as busy,- falseto re-enable access.
Framework-Specific Behavior
- ox_inventory: Uses- LocalPlayer.state.invBusyand- invHotkeysto lock/unlock.
- qb-inventory/- codem-inventory (QB): Sets- inv_busyflag via- LocalPlayer.state:set.
- qs-inventory: Uses- setInventoryDisabled(true/false).
- codem-inventory (ESX): Uses- LocalPlayer.state.invBusy.
Function: XM.CloseInv()
XM.CloseInv()Closes the player's inventory interface, depending on the inventory type defined in Config.Inventory.
Behavior by Config Setting
- ox: Calls- ox_inventory:closeInventory().
- newQB,- oldQB,- codem: Executes- closeinvcommand.
- qs: Stubbed (does not call any close method due to ineffective documentation).
Function: XM.ConsumedItem(itemName)
XM.ConsumedItem(itemName)Fetches the label (display name) of an item by its internal name to be used in UI feedback such as progress bars.
Parameters
- itemName(string) – The internal name of the item to look up.
Returns
- (string) – The label of the item, or - "Something"if not found.
Framework-Specific Behavior
- qb-core:- With - ox_inventory: Calls- ox_inventory:GetPlayerItems()and loops through to find item.
- Otherwise: Retrieves from - QBCore.Shared.Items.
 
- qbx_core: Always uses- ox_inventory.
- es_extended:- Uses appropriate - getInventory()export based on- Config.Inventory:- ox,- qs, or- codem.
 
These functions streamline inventory interactions in multi-framework environments, helping developers write framework-agnostic logic for immersive and safe player interactions.
XM.InventoryBusy = function(bool)
    if bool then 
        if GetResourceState('ox_inventory') == "started"then 
            LocalPlayer.state.invBusy = true
            LocalPlayer.state.invHotkeys = false
        elseif GetResourceState('qb-inventory') == "started" then 
            LocalPlayer.state:set('inv_busy', true, true)
        elseif Config.Inventory == "qs" then 
            exports['qs-inventory']:setInventoryDisabled(true)
        elseif (GetResourceState('codem-inventory') == "started" and GetResourceState("qb-core") == "started") then 
            LocalPlayer.state:set('inv_busy', true, true)
        elseif (GetResourceState('codem-inventory') == "started" and GetResourceState("es_extended") == "started") then 
            LocalPlayer.state.invBusy = true
        end
    else
        if GetResourceState('ox_inventory') == "started"then 
            LocalPlayer.state.invBusy = false
            LocalPlayer.state.invHotkeys = true
        elseif GetResourceState('qb-inventory') == "started" then 
            LocalPlayer.state:set('inv_busy', false, true)
        elseif Config.Inventory == "qs" then 
            exports['qs-inventory']:setInventoryDisabled(false)
        elseif (GetResourceState('codem-inventory') == "started" and GetResourceState("qb-core") == "started") then 
            LocalPlayer.state:set('inv_busy', false, true)
        elseif (GetResourceState('codem-inventory') == "started" and GetResourceState("es_extended") == "started") then 
            LocalPlayer.state.invBusy = false
        end
    end
end
XM.CloseInv = function()
    if Config.Inventory == "ox" then 
        exports.ox_inventory:closeInventory()
    elseif Config.Inventory == "newQB" or Config.Inventory == "oldQB" then 
        ExecuteCommand('closeinv')
    elseif Config.Inventory == "qs" then 
        -- ExecuteCommand('closeinv') -- in their docs but doesn't seem to work.
    elseif Config.Inventory == "codem" then 
        ExecuteCommand('closeinv')
    end
end
XM.ConsumedItem = function(itemName)   -- Function to get the label of item to show in progressbars.
    local itemLabel = "Something"
    if GetResourceState('qb-core') == "started" then
        if Config.Inventory == "ox" then 
            local playerItems = exports.ox_inventory:GetPlayerItems()
            for k, item in pairs(playerItems) do
                if item.name == itemName then
                    itemLabel = item.label
                    break
                end
            end
        else
            local item = QBCore.Shared.Items[itemName]
            if item then
                itemLabel = item.label
            end
        end
    elseif GetResourceState('qbx_core') == "started" then
        local playerItems = exports.ox_inventory:GetPlayerItems()
        for k, item in pairs(playerItems) do
            if item.name == itemName then
                itemLabel = item.label
                break
            end
        end
    elseif GetResourceState('es_extended') == "started" then
        if Config.Inventory == "ox" then 
            local playerItems = exports.ox_inventory:GetPlayerItems()
            for k, item in pairs(playerItems) do
                if item.name == itemName then
                    itemLabel = item.label
                    break
                end
            end
        elseif Config.Inventory == "qs" then 
            local playerItems = exports['qs-inventory']:getUserInventory()
            for k, item in pairs(playerItems) do
                if item.name == itemName then
                    itemLabel = item.label
                    break
                end
            end
        elseif Config.Inventory == "codem" then 
            local playerItems = exports['codem-inventory']:GetClientPlayerInventory()
            for k, item in pairs(playerItems) do
                if item.name == itemName then
                    itemLabel = item.label
                    break
                end
            end
        end
    end
    return itemLabel
endMinigame
Function: XM.MiniGame(data)
Launches a mini key-press game using the xmmx_keysgame resource, providing a simple and configurable way to add skill-based interactions to your scripts (e.g., lockpicking, hacking, crafting, etc.).
Parameters
- data(table) – Configuration for the mini-game, including:- mode(string) – Game difficulty or mode (as defined by the- xmmx_keysgameexport).
- keys(number) – Number of keys the player must press.
- time(number) – Total time allowed (in milliseconds or seconds, based on- xmmx_keysgameimplementation).
- label(string) – Text displayed during the game.
- color1(string, optional) – Primary color in hex (default:- "#00a79c").
- color2(string, optional) – Secondary color in hex (default:- "#70c0bb").
 
Returns
- success(boolean) –- trueif the player completed the mini-game successfully,- falseif failed or aborted.
Example Usage
local result = XM.MiniGame({
    mode = "arrows",
    keys = 7,
    time = 5000,
    label = "Unlocking...",
    color1 = "#ffcc00",
    color2 = "#ff9900"
})
if result then
    print("Mini-game passed!")
else
    print("Mini-game failed.")
endThis function simplifies integrating interactive mini-games into your gameplay loop using standardized input and visuals.
XM.MiniGame = function(data)
    local success = exports.xmmx_keysgame:StartKeyGame(data.mode, data.keys, data.time, data.label, data.color1 or "#00a79c", data.color2 or"#70c0bb")
    return success
endPlayer Job
These functions provide standardized, framework-agnostic ways to retrieve the player’s job and validate if they are an employee for a given in-world location. This supports dynamic job-based systems such as business management, shop zones, or role-restricted interactions.
Function: XM.EmployeeJob()
XM.EmployeeJob()Returns the current job name of the player across supported frameworks.
Returns
- (string or - nil) – The player’s current job name (e.g.,- "police",- "burgershot"), or- nilif unavailable.
Framework Support
- qb-core: Uses- QBCore.Functions.GetPlayerData().
- qbx_core: Uses- exports.qbx_core:GetPlayerData().
- es_extended: Uses- ESX.GetPlayerData().
Function: XM.IsEmployee(Location)
XM.IsEmployee(Location)Checks if the player is employed at any of the provided job locations within a 100.0 unit radius.
Parameters
- Location(table) – A list of location/job definitions, each containing:- job(string) – The job name to match.
- coords(vector3) – The location to check proximity against.
 
Returns
- (boolean) – - trueif the player has one of the specified jobs and is within range of the respective location, otherwise- false.
Distance Check
- A distance threshold of - 100.0units is used to determine if the player is "at" the location.
Example Location Table Format
Location Table Formatlocal locations = {
    { job = "burgershot", coords = vector3(-1193.0, -892.0, 14.0) },
    { job = "mechanic", coords = vector3(544.0, -195.0, 54.0) }
}These functions are useful for determining job-restricted access to areas, triggering boss menu logic, or controlling role-specific gameplay elements based on proximity and role.
XM.EmployeeJob = function()
    if GetResourceState('qb-core') == "started" then 
        local PlayerData = QBCore.Functions.GetPlayerData()
        return PlayerData.job.name 
    elseif GetResourceState('qbx_core') == "started" then 
        local PlayerData = exports.qbx_core:GetPlayerData()
        return PlayerData.job.name 
    elseif GetResourceState('es_extended') == "started" then
        local playerData = ESX.GetPlayerData()
        if playerData and playerData.job then
            return playerData.job.name
        end
    end
end
XM.IsEmployee = function(Location)
    local hasJob = false
    local playerPed = PlayerPedId()
    local playerCoords = GetEntityCoords(playerPed)
    for _, v in pairs(Location) do
        if v.job and v.coords then
            local distance = #(playerCoords - v.coords)
            local distanceThreshold = 100.0
            if distance <= distanceThreshold then
                if GetResourceState('qb-core') == "started" then 
                    local PlayerData = QBCore.Functions.GetPlayerData()
                    if PlayerData.job.name == v.job then 
                        hasJob = true
                    end
                elseif GetResourceState('qbx_core') == "started" then 
                    local PlayerData = exports.qbx_core:GetPlayerData()
                    if PlayerData.job.name == v.job then
                        hasJob = true
                    end
                elseif GetResourceState('es_extended') == "started" then
                    local playerData = ESX.GetPlayerData()
                    if playerData and playerData.job and playerData.job.name == v.job then 
                        hasJob = true
                    end
                end
            end
        end
    end
    return hasJob
endProgress Bar
Function: XM.Progress(label, info)
Displays a progress bar animation tailored to the active framework (qb, ox, or esx). This function unifies progressbar behavior, including optional animations, props, and player interaction settings. It ensures the inventory is marked as "busy" during interaction to prevent conflicts with item usage.
Parameters
- label(string) The message shown on the progress bar.
- info(table, required) A configuration table containing animation and behavior options:- Time(number) – Duration of the progress (default:- 5000ms).
- Move(boolean) – Whether player movement is allowed (default:- false).
- Dict,- Clip,- Flag(string/number) – Animation dictionary, clip name, and animation flags.
- Prop,- Prop2(string) – Model names for props to attach.
- Bone,- Bone2(number) – Bones to attach props to.
- Coord,- Coord2(vector3) – World offsets for prop attachment.
- Rot,- Rot2(vector3) – Rotation values for props.
 
Supported Frameworks & Behavior
✅ qb-core
- Uses - QBCore.Functions.Progressbar.
- Temporarily disables inventory via - XM.InventoryBusy(true)during progress.
- Supports animations and up to 2 props. 
- Synchronous behavior via - while not isCompletedloop.
✅ ox_lib
- Uses - lib.progressCircle.
- Configurable props, position, and animations. 
- Returns immediately with success state. 
✅ es_extended
- Uses - ESX.Progressbar.
- Supports freezing player and basic animation. 
- Uses - onFinish/- onCancelcallbacks for result handling.
☑️ custom
- Placeholder for custom progress implementation. 
❌ Unsupported
- Logs an error if - Config.Progressis not recognized.
Returns
- (boolean) – - trueif the progress completed successfully,- falseif it failed or was aborted.
Example Usage
local result = XM.Progress("Making coffee...", {
    Time = 4000,
    Move = false,
    Dict = "amb@world_human_drinking@coffee@male@idle_a",
    Clip = "idle_c",
    Flag = 49,
    Prop = "prop_coffee_cup_trailer",
    Bone = 28422
})
if result then
    print("Progress completed!")
else
    print("Progress interrupted.")
endThis function enables immersive, framework-aware progress feedback for any interaction scenario.
XM.Progress = function(label, info)
    XM.TargetInactive()
    local success = false
    local isCompleted = false
    if not info or type(info) ~= "table" then
        print("^1[ERROR] Invalid info table passed to Progress function!^0")
        return false
    end
    local time = info.Time or 5000
    local move = info.Move or false
    if not Config or not Config.Progress then
        print("^1[ERROR] Config.Progress is nil!^0")
        return false
    end
    if Config.Progress == "qb" then
        XM.InventoryBusy(true)
        if not QBCore or not QBCore.Functions or not QBCore.Functions.Progressbar then
            print("^1[ERROR] QBCore Progressbar function is missing!^0")
            return false
        end
        QBCore.Functions.Progressbar("doing_bites", label, time, false, false, { 
            disableMovement = move, 
            disableCarMovement = false, 
            disableMouse = false, 
            disableCombat = false, 
        }, {
            animDict = info.Dict or "", 
            anim = info.Clip or "", 
            flags = info.Flag or 0, 
        }, {
            model = info.Prop or nil,
            bone = info.Bone or 0,
            coords = info.Coord and { 
                x = info.Coord.x or 0.0, 
                y = info.Coord.y or 0.0, 
                z = info.Coord.z or 0.0 
            } or nil,
            rotation = info.Rot and {
                x = info.Rot.x or 0.0,
                y = info.Rot.y or 0.0,
                z = info.Rot.z or 0.0
            } or nil,
        }, {
            model = info.Prop2 or nil,
            bone = info.Bone2 or 0,
            coords = info.Coord2 and { 
                x = info.Coord2.x or 0.0, 
                y = info.Coord2.y or 0.0, 
                z = info.Coord2.z or 0.0 
            } or nil,
            rotation = info.Rot2 and {
                x = info.Rot2.x or 0.0,
                y = info.Rot2.y or 0.0,
                z = info.Rot2.z or 0.0
            } or nil,
        }, function()
            success = true
            isCompleted = true
            XM.InventoryBusy(false)
        end) 
        while not isCompleted do
            Citizen.Wait(100)
        end
    elseif Config.Progress == "ox" then
        -- Ensure lib.progressCircle exists
        if not lib or not lib.progressCircle then
            print("^1[ERROR] lib.progressCircle function is missing!^0")
            return false
        end
        local options = {}
        if info.Prop then 
            table.insert(options, {
                model = info.Prop,
                bone = info.Bone or 0,
                pos = info.Coord or vector3(0.0, 0.0, 0.0),
                rot = info.Rot or vector3(0.0, 0.0, 0.0)
            })
        end
        if info.Prop2 then 
            table.insert(options, {
                model = info.Prop2,
                bone = info.Bone2 or 0,
                pos = info.Coord2 or vector3(0.0, 0.0, 0.0),
                rot = info.Rot2 or vector3(0.0, 0.0, 0.0)
            })
        end
        success = lib.progressCircle({
            duration = time,
            position = 'bottom',
            label = label,
            useWhileDead = false,
            canCancel = false,
            disable = {
                car = false,
                move = move,
            },
            anim = {
                dict = info.Dict or "",
                clip = info.Clip or "", 
                flag = info.Flag or 0,
                lockX = false,
                lockY = false,
                lockZ = false,
            },
            prop = options,
        }) 
    elseif Config.Progress == "esx" then
        if not ESX or not ESX.Progressbar then
            print("^1[ERROR] ESX.Progressbar function is missing!^0")
            return false
        end
    
        local animDict = info.Dict or ""
        local animClip = info.Clip or ""
        local freeze   = not (info.Move or false)
    
        ESX.Progressbar(label, time, {
            FreezePlayer = freeze,
            animation = {
                type = 'anim',
                dict = animDict,
                lib = animClip
            },
            onFinish = function()
                success = true
            end,
            onCancel = function()
                success = false
            end
        })
    
        while success == nil do
            Wait(100)
        end
    elseif Config.Progress == "custom" then
        -- add your custom progressbar here
    else
        print("^1[ERROR] Unsupported Progress Type: " .. tostring(Config.Progress) .. "^0")
    end  
    XM.TargetActive()
    return success
end
Targeting Controls
These functions enable or disable interaction targeting systems during scripted events, such as progress bars, animations, or menus—where interaction interruptions must be prevented. They support several popular targeting frameworks.
Function: XM.TargetInactive()
XM.TargetInactive()Disables player targeting temporarily by detecting the active targeting resource and calling its appropriate method.
Supported Frameworks & Behavior
- ox_target: Calls- disableTargeting(true)
- qb-target: Calls- AllowTargeting(false)
- qtarget: Also uses- AllowTargeting(false)(likely interchangeable export name)
Function: XM.TargetActive()
XM.TargetActive()Re-enables player targeting after it has been disabled. Intended to be used following XM.TargetInactive() once the task (e.g., progress bar) is complete.
Supported Frameworks & Behavior
- ox_target: Calls- disableTargeting(false)
- qb-target: Calls- AllowTargeting(true)
- qtarget: Calls- AllowTargeting(true)
Use Case Example
Used alongside other functions (e.g., XM.Progress) to prevent interaction conflicts:
XM.TargetInactive()
-- show a progress bar, animation, etc.
XM.TargetActive()These utilities provide seamless and framework-aware control over player interaction targeting to maintain immersion and prevent unintended interruptions.
XM.TargetInactive = function()
    if GetResourceState('ox_target') == 'started' then
        exports.ox_target:disableTargeting(true) 
    elseif GetResourceState('qb-target') == 'started' then 
        exports['qb-target']:AllowTargeting(false) 
    elseif GetResourceState('qtarget') == 'started' then 
        exports['qb-target']:AllowTargeting(false) 
    end
end
XM.TargetActive = function()
    if GetResourceState('ox_target') == 'started' then
        exports.ox_target:disableTargeting(false) 
    elseif GetResourceState('qb-target') == 'started' then 
        exports['qb-target']:AllowTargeting(true) 
    elseif GetResourceState('qtarget') == 'started' then 
        exports['qtarget']:AllowTargeting(true) 
    end
endTarget Box Zones
This system abstracts and standardizes interaction zones ("target zones") using popular target libraries in FiveM: ox_target, qb-target, and qtarget. It supports dynamic creation and removal of box-style target zones with custom options.
🔄 Initialization
CreateThread(function()
    -- Detect active target system
end)Upon script startup, it detects the first available and supported target system (ox_target, qb-target, qtarget) and sets TargetSystem accordingly. If no target system is found, it logs a warning.
🔧 Function: XM.AddTargetZone(data)
XM.AddTargetZone(data)Creates a new box-style interaction zone using the active target system.
Parameters
- data(table) – Zone configuration:- name(string) – Unique identifier for the zone (required).
- coords(vector3) – Zone center coordinates.
- size(vector2) – Zone dimensions (x, y).
- rotation(number) – Rotation angle in degrees.
- debug(boolean) – Optional debug drawing.
- drawSprite(boolean) – OX-specific: show sprite marker (default:- true).
- options(table) – List of target interaction options.
- distance(number) – Interaction distance (for qb/qtarget only).
 
Returns
- (string) – The name of the zone added, or - nilif unsuccessful.
Behavior by Target System
- ✅ - ox_target: Uses- ox_target:addBoxZone()with full support for size, rotation, sprite, and interaction options.
- ✅ - qb-target/- qtarget: Uses- AddBoxZone()with a heading and bounding box (- minZ,- maxZ), and adapts the options list:- Converts - groupsto- jobfield.
- Converts - onSelectto- action.
 
🗑️ Function: XM.RemoveTargetZone(name)
XM.RemoveTargetZone(name)Removes a previously added target zone from the active target system.
Parameters
- name(string) – The name of the zone to remove.
Behavior
- ✅ - ox_target: Calls- removeZone(name)
- ✅ - qb-target/- qtarget: Calls- RemoveZone(name)
- Removes the zone from the - TargetZonesregistry.
🛑 Event Cleanup: onResourceStop
Automatically removes all registered target zones when the resource stops, ensuring no orphaned zones are left behind.
AddEventHandler("onResourceStop", function(resource)
    -- Clean up all active zones
end)✅ Example Usage
XM.AddTargetZone({
    name = "coffeeshop_register",
    coords = vector3(-1193.0, -892.0, 14.0),
    size = vector2(1.5, 1.5),
    rotation = 180.0,
    debug = true,
    options = {
        {
            icon = "fa-solid fa-mug-hot",
            label = "Order Coffee",
            onSelect = function() print("Coffee ordered!") end
        }
    }
})Located in xmmx_bridge/client/targets/boxzones.lua:
local TargetZones = {}
local TargetSystem = nil
CreateThread(function()
    if GetResourceState("ox_target") == "started" then
        TargetSystem = "ox_target"
    elseif GetResourceState("qb-target") == "started" then
        TargetSystem = "qb-target"
    elseif GetResourceState("qtarget") == "started" then
        TargetSystem = "qtarget"
    else
        print("^1[XM][Target]^0 No supported target system found.")
    end
end)
XM.AddTargetZone = function(data)
    if not data or not data.name then return nil end
    if not TargetSystem then return nil end
    TargetZones[data.name] = true
    if TargetSystem == "ox_target" then
        exports.ox_target:addBoxZone({
            name       = data.name,
            coords     = data.coords,
            size       = data.size,
            rotation   = data.rotation,
            debug      = data.debug or false,
            drawSprite = data.drawSprite or true,
            options    = data.options or {}
        })
    elseif TargetSystem == "qb-target" or TargetSystem == "qtarget" then
        local options = {}
        for _, option in pairs(data.options or {}) do
            if option.groups then
                option.job = next(option.groups)
                option.groups = nil
            end
            if option.onSelect and not option.action then
                local callback = option.onSelect
                option.action = function(entity)
                    callback(option)
                end
                option.onSelect = nil
            end
            table.insert(options, option)
        end
        exports[TargetSystem]:AddBoxZone(data.name, data.coords, data.size.y, data.size.x, {
            name = data.name,
            heading = data.rotation,
            debugPoly = data.debug or false,
            minZ = data.coords.z - 1.25,
            maxZ = data.coords.z + 0.25
        }, {
            options = options,
            distance = data.distance or 2.0
        })
    end
    return data.name
end
XM.RemoveTargetZone = function(name)
    if not TargetZones[name] then return end
    if TargetSystem == "ox_target" then
        exports.ox_target:removeZone(name)
    elseif TargetSystem == "qb-target" or TargetSystem == "qtarget" then
        exports[TargetSystem]:RemoveZone(name)
    end
    TargetZones[name] = nil
end
AddEventHandler("onResourceStop", function(resource)
    if resource ~= GetCurrentResourceName() then return end
    for zone in pairs(TargetZones) do
        XM.RemoveTargetZone(zone)
    end
end)Target Entities
This system allows you to dynamically assign interactive target options to entities (peds, vehicles, props, etc.) across supported target frameworks: ox_target, qb-target, and qtarget. It ensures clean initialization, unified behavior, and proper cleanup.
🔄 Initialization
CreateThread(function()
    -- Detect and set the first available supported target system
end)When the script starts, it automatically sets TargetSystem based on which target resource is active. If none are found, a warning is printed to the console.
✅ Function: XM.AddTargetEntity(entity, options)
Adds interactive targeting options to a specific entity (e.g., ped, object, or vehicle).
Parameters
- entity(Entity handle) – The in-game entity to target (must exist).
- options(table) – A list of targeting options:- label(string) – Text shown when aiming at the entity.
- icon(string) – Icon shown in the target UI.
- onSelect(function) – Callback triggered on selection (auto-converted to- actionfor qb/qtarget).
- groups(table, optional) – Jobs allowed to see this option.
- distance(number) – Optional interaction distance (defaults to 2.0).
 
Behavior by Target System
- ✅ - ox_target:- Calls - ox_target:addLocalEntity(entity, options)directly.
 
- ✅ - qb-target/- qtarget:- Converts - groupsto- jobfield.
- Converts - onSelectto- actionfunction.
- Wraps options in a - distancefield and calls- AddTargetEntity.
 
Example Usage
XM.AddTargetEntity(vehicle, {
    {
        icon = "fa-solid fa-key",
        label = "Unlock Car",
        distance = 2.0,
        onSelect = function()
            print("Car unlocked!")
        end
    }
})
Function: XM.RemoveTargetEntity(entity)
Removes an entity's targeting options if they were previously registered.
Parameters
- entity(Entity handle) – The entity to deregister.
Behavior
- Calls: - ox_target:removeLocalEntity(entity)
- or - qb-target/- qtarget:RemoveTargetEntity(entity)
 
- Cleans up - EntityTargetstable entry.
🧼 Resource Cleanup: onResourceStop
Automatically removes all entity targets registered during the resource's lifecycle when the script stops:
AddEventHandler("onResourceStop", function(resource)
    -- Remove all entity targets added by this script
end)🗂️ Internals
- EntityTargets(table) – Tracks all added entities for cleanup.
- TargetSystem(string) – Holds the name of the active target resource (- ox_target,- qb-target,- qtarget).
This system enables framework-agnostic entity targeting and maintains clean behavior through proper conversion and lifecycle handling. Located in xmmx_bridge/client/targets/targetentity.lua:
local EntityTargets = {}
local TargetSystem = nil
CreateThread(function()
    if GetResourceState("ox_target") == "started" then
        TargetSystem = "ox_target"
    elseif GetResourceState("qb-target") == "started" then
        TargetSystem = "qb-target"
    elseif GetResourceState("qtarget") == "started" then
        TargetSystem = "qtarget"
    else
        print("^1[XMMX-BRIDGE][Target]^0 No supported target system found.")
    end
end)
XM.AddTargetEntity = function(entity, options)
    if not entity or not DoesEntityExist(entity) or not options then return end
    local system = TargetSystem
    if not system then return end
    EntityTargets[entity] = true
    if system == "ox_target" then
        exports.ox_target:addLocalEntity(entity, options)
    elseif system == "qb-target" or system == "qtarget" then
        local parsedOptions = {}
        for _, option in ipairs(options) do
            if option.groups then
                option.job = next(option.groups)
                option.groups = nil
            end
            -- Convert onSelect to action for qb/qtarget
            if option.onSelect and not option.action then
                option.action = option.onSelect
                option.onSelect = nil
            end
            table.insert(parsedOptions, option)
        end
        exports[system]:AddTargetEntity(entity, {
            options = parsedOptions,
            distance = options[1] and options[1].distance or 2.0
        })
    end
end
XM.RemoveTargetEntity = function(entity)
    if not entity or not EntityTargets[entity] then return end
    local system = TargetSystem
    if not system then return end
    if system == "ox_target" then
        exports.ox_target:removeLocalEntity(entity)
    elseif system == "qb-target" or system == "qtarget" then
        exports[system]:RemoveTargetEntity(entity)
    end
    EntityTargets[entity] = nil
end
AddEventHandler("onResourceStop", function(resource)
    if resource ~= GetCurrentResourceName() then return end
    for ent in pairs(EntityTargets) do
        XM.RemoveTargetEntity(ent)
    end
end)
Interact
This module integrates with the interact resource to support model- and entity-based interaction zones in a structured and maintainable way. It allows defining interaction prompts tied to in-game models or entities and ensures automatic cleanup when the resource stops.
🧠 Internal State
- InteractReady: Boolean flag to confirm the- interactresource is active.
- InteractTargets: Tracks registered interactions (model or entity) for cleanup.
🔁 Initialization
CreateThread(function()
    if GetResourceState("interact") == "started" then
        InteractReady = true
    else
        print("[XMMX-BRIDGE][INTERACT] 'interact' system not found or not started.")
    end
end)Checks for interact resource availability and enables interaction functionality accordingly.
Function XM.AddInteractModel(data)
Registers an interaction target for one or more models.
Parameters
- data(table) – Interaction configuration:- model(string or table) – One or more model names.
- options(table) – List of interaction options (icon, label,- onSelect, etc.).
- offset,- bone,- distance,- interactDst,- groups,- name,- id(optional) – Additional interaction parameters.
 
Behavior
- Iterates through all provided model names. 
- Generates a unique or custom - interactionIdfor each.
- Calls - interact:AddModelInteractionfor each model.
Function XM.AddInteractEntity(entity, data)
Registers an interaction for a specific game entity.
Parameters
- entity(entity handle) – The in-game entity (ped, vehicle, prop, etc.).
- data(table) – Includes:- options,- distance,- interactDst,- name,- offset,- bone,- ignoreLos,- groups,- id(optional)
 
Behavior
- Builds an interaction configuration and calls - interact:AddLocalEntityInteraction.
- Stores reference in - InteractTargetsfor later cleanup.
Function XM.RemoveInteract(id)
Removes a previously registered model or entity interaction.
Parameters
- id(string) – The unique interaction ID to remove.
Behavior
- If it was a model-based interaction: calls - RemoveModelInteraction.
- If it was entity-based: calls - RemoveLocalEntityInteraction.
🧼 Event Handler onResourceStop Cleanup
Ensures all interact targets are properly removed if the resource is stopped:
AddEventHandler("onResourceStop", function(resource)
    for id in pairs(InteractTargets) do
        XM.RemoveInteract(id)
    end
end)🧪 Example: Add Interaction to Trash Can Model
XM.AddInteractModel({
    model = "prop_bin_05a",
    name = "trash_interact",
    options = {
        {
            icon = "fas fa-trash",
            label = "Search Trash",
            onSelect = function()
                print("Searching the bin...")
            end
        }
    }
})
This integration provides a modular, extensible, and resource-safe method of handling interactions via the interact resource, promoting consistency and ease of use across your server scripts.
Located in xmmx_bridge/client/target/interact.lua:
if GetResourceState("interact") ~= "started" then return end
local InteractTargets = {}
local InteractReady = false
CreateThread(function()
    if GetResourceState("interact") == "started" then
        InteractReady = true
    else
        print("^1[XMMX-BRIDGE][INTERACT]^0 'interact' system not found or not started.")
    end
end)
---@param data table
---@param data.model can be a string or array of strings (model names)
---@param data.options = table of interaction options
---@param data.offset, distance, interactDst, name, id, etc. are optional
XM.AddInteractModel = function(data)
    if not InteractReady or not data or not data.model or not data.options then return end
    local models = type(data.model) == "table" and data.model or { data.model }
    for _, model in pairs(models) do
        local interactionId = data.id or ('XM_INTERACT_' .. model .. '_' .. tostring(math.random(1111, 9999)))
        InteractTargets[interactionId] = { type = "model", model = model }
        exports.interact:AddModelInteraction({
            model = model,
            offset = data.offset or vec3(0, 0, 0),
            bone = data.bone,
            name = data.name or interactionId,
            id = interactionId,
            distance = data.distance or 5.0,
            interactDst = data.interactDst or 2.0,
            groups = data.groups,
            options = data.options
        })
    end
end
XM.AddInteractEntity = function(entity, data)
    if not InteractReady or not entity or not data or not data.options then return end
    local interactionId = data.id or ('XM_ENTITY_INTERACT_' .. entity)
    InteractTargets[interactionId] = { type = "entity", entity = entity }
    exports.interact:AddLocalEntityInteraction({
        entity = entity,
        id = interactionId,
        name = data.name or interactionId,
        distance = data.distance or 5.0,
        interactDst = data.interactDst or 2.0,
        ignoreLos = data.ignoreLos or false,
        offset = data.offset or vec3(0, 0, 0),
        bone = data.bone,
        groups = data.groups,
        options = data.options
    })
end
XM.RemoveInteract = function(id)
    if not InteractTargets[id] then return end
    local target = InteractTargets[id]
    if target.type == "model" then
        exports.interact:RemoveModelInteraction(target.model, id)
    elseif target.type == "entity" then
        exports.interact:RemoveLocalEntityInteraction(target.entity, id)
    end
    InteractTargets[id] = nil
end
AddEventHandler("onResourceStop", function(resource)
    if resource ~= GetCurrentResourceName() then return end
    for id in pairs(InteractTargets) do
        XM.RemoveInteract(id)
    end
end)
Society Funds
These functions provide a unified way to add to or remove from a job/society’s shared account across various banking systems used in FiveM (qb, esx, okok, Renewed, etc.). This abstraction allows for compatibility across different frameworks without needing to change the business logic.
Function: XM.AddSocietyMoney(src, society, amount)
XM.AddSocietyMoney(src, society, amount)Adds funds to a society or job’s shared account.
Parameters
- src(number) – Player source (unused in current logic, but may be useful for auditing or custom implementation).
- society(string) – Name of the society or job (e.g.,- "police").
- amount(number) – Amount of money to add.
Supported Banking Resources
- qb-banking:- AddMoney(society, amount)
- fd_banking:- AddMoney(society, amount)
- Renewed-Banking:- addAccountMoney(society, amount)
- esx_society:- esx_addonaccount:getSharedAccount("society_<name>")→- addMoney(amount)
- okokbanking:- AddMoney(society, amount)
- your_society: Placeholder for custom implementation
Function: XM.RemoveSocietyMoney(society, amount, reason)
XM.RemoveSocietyMoney(society, amount, reason)Removes funds from a society’s shared account.
Parameters
- society(string) – Society or job name.
- amount(number) – Amount to remove.
- reason(string) – Reason for the deduction (used in some banking systems).
Supported Banking Resources
- qb-banking:- RemoveMoney(society, amount, reason)
- fd_banking:- RemoveMoney(society, amount, reason)
- Renewed-Banking:- RemoveAccountMoney(society, amount)
- esx_society:- esx_addonaccount:getSharedAccount("society_<name>")→- removeMoney(amount)
- okokbanking:- RemoveMoney(society, amount)
- your_society: Placeholder for custom removal logic
🧪 Example Usage
XM.AddSocietyMoney(source, "mechanic", 500)
XM.RemoveSocietyMoney("mechanic", 250, "Parts Purchased")These functions allow seamless switching or support for multiple banking frameworks without modifying core game logic. Let me know if you'd like helper logging or Discord webhooks added for auditing transactions! Located in xmmx_bridge/server/societies/society.lua:
XM.AddSocietyMoney = function(src, society, amount)
    if GetResourceState("qb-banking") == 'started' then            
        exports['qb-banking']:AddMoney(society, amount)
    elseif GetResourceState("fd_banking") == 'started' then            
        exports.fd_banking:AddMoney(society, amount)
    elseif GetResourceState("Renewed-Banking") == 'started' then            
        exports['Renewed-Banking']:addAccountMoney(society, amount)
    elseif GetResourceState("esx_society") == 'started' then       
        TriggerEvent('esx_addonaccount:getSharedAccount', 'society_'..society, function(account)
            if account then account.addMoney(amount) end
		end)
    elseif GetResourceState("okokbanking") == 'started' then
        exports['okokBanking']:AddMoney(society, amount)
    elseif GetResourceState("your_society") == 'started' then -- Add your society/banking script name here
        -- add your society Add Money export here.
    end
end
XM.RemoveSocietyMoney = function(society, amount, reason)
    if GetResourceState("qb-banking") == 'started' then            
        exports['qb-banking']:RemoveMoney(society, amount, reason)
    elseif GetResourceState("fd_banking") == 'started' then            
        exports.fd_banking:RemoveMoney(society, amount, reason)
    elseif GetResourceState("Renewed-Banking") == 'started' then            
        exports['Renewed-Banking']:RemoveAccountMoney(society, amount)
    elseif GetResourceState("esx_society") == 'started' then            
        TriggerEvent('esx_addonaccount:getSharedAccount', 'society_'..society, function(account)
            if account then account.removeMoney(amount) end
		end)
    elseif GetResourceState("okokbanking") == 'started' then
        exports['okokBanking']:RemoveMoney(society, amount)
    elseif GetResourceState("your_society") == 'started' then -- Add your society/banking script name here
        -- add your society Remove Money export here.
    end
end🛡️Anti-Cheat
Function XM.ValidateCaller(expected, src, actionLabel)
This function serves as a security utility to validate that a triggering source (src) matches the expected source (expected). It's designed to prevent unauthorized or spoofed event usage, acting as a lightweight anti-cheat mechanism.
✅ Purpose
Ensures that sensitive server-side events are only executed by their rightful triggering client (e.g., validating a player's own action). If the validation fails, the player can be optionally dropped from the server, and a Discord webhook notification can be sent for admin review.
🔧 Parameters
expected
number
The expected player source ID (usually the one originally associated with the action).
src
number
The actual player source that triggered the server event.
actionLabel
string
A label or name of the action being validated (used in logs/webhook).
🔁 Behavior
- Mismatch Detection If - srcdoes not match- expected, an anti-cheat alert is triggered.
- Logging & Punishment - Prints a message to the server console. 
- Optionally drops the player from the server using - DropPlayer.
- Sends a Discord webhook alert if a valid - WebhookURL is defined.
 
- Webhook Payload Structure - Player name, source ID, attempted event/action, and the expected source. 
- Timestamped for log tracking. 
 
💬 Example Use
RegisterNetEvent("xmmx:secureAction", function(targetId)
    local src = source
    if not XM.ValidateCaller(targetId, src, "Secure Action Attempt") then return end
    -- Proceed with secure logic...
end)🔒 Security Notes
- Always use this check for sensitive actions triggered by the client (e.g., money handling, item giving, job switching). 
- Be cautious with - DropPlayer()usage in development environments.
🧪 Optional Webhook Setup
To enable Discord alerts, configure the global Webhook variable:
local Webhook = "https://discord.com/api/webhooks/your_webhook_url"Located in xmmx_bridge/server/anticheat/anticheat.lua:
local Webhook = ''
XM.ValidateCaller = function(expected, src, actionLabel)
    if expected ~= src then
        local playerName = GetPlayerName(src) or "unknown"
        local msg = ("^1[ANTI-CHEAT] ^3%s (%s) attempted unauthorized access to '%s'. Expected Source ID: (%s)^0"):format(playerName, src, actionLabel, expected)
        
        print(msg)
        DropPlayer(src, "[Anti-Cheat] Unauthorized server event usage detected.") -- drops player from server, remove if not needed!!!
        if Webhook and Webhook ~= '' then
            local payload = {
                username = "Anti-Cheat Logger",
                embeds = {{
                    title = "Unauthorized Server Event Usage",
                    color = 16711680,
                    fields = {
                        { name = "Player Name", value = playerName, inline = true },
                        { name = "Source", value = tostring(src), inline = true },
                        { name = "Event", value = actionLabel, inline = false },
                        { name = "Expected", value = tostring(expected), inline = true },
                    },
                    footer = { text = "XMMX Security" },
                    timestamp = os.date("!%Y-%m-%dT%H:%M:%SZ")
                }}
            }
            PerformHttpRequest(Webhook, function() end, "POST", json.encode(payload), {
                ["Content-Type"] = "application/json"
            })
        end
        return false
    end
    return true
end
Framework Functions
🧰 XM Server-Side Framework Utilities
These functions abstract common player-related actions across multiple popular FiveM frameworks—QBCore, ESX, and QB-X—providing a consistent interface for:
- Cash and bank transactions 
- Inventory item management 
- Meta item support 
- Toggling items 
- Duty toggling (for - qbx_core)
Each framework implementation is conditionally loaded depending on the active resources.
🧾 Common Function Definitions
Each framework implements these shared utility functions:
Function XM.AddMoney(src, amount, reason)
XM.AddMoney(src, amount, reason)Adds money to the player’s cash wallet.
Function XM.RemoveMoney(src, amount, reason)
XM.RemoveMoney(src, amount, reason)Removes money from the player’s wallet.
Function XM.AddBank(src, amount, reason)
XM.AddBank(src, amount, reason)Adds money to the player’s bank account.
Function XM.RemoveBank(src, amount, reason)
XM.RemoveBank(src, amount, reason)Removes money from the player’s bank account.
Function XM.AddItem(src, item, amount)
XM.AddItem(src, item, amount)Gives the player a specific item.
Function XM.RemoveItem(src, item, amount)
XM.RemoveItem(src, item, amount)Removes an item from the player's inventory.
Function XM.AddMetaItem(src, item, amount, meta)
XM.AddMetaItem(src, item, amount, meta)Adds an item with metadata (supports various inventories like ox, qs, codem).
Function XM.ToggleItem(src, bool, item, amount)
XM.ToggleItem(src, bool, item, amount)Adds or removes an item based on the bool value.
🔷 QBCore Implementation
- Framework: - qb-core
- Inventory support check: - qb-inventory(for item box animation)
- Meta item support: Handles - ox_inventory,- qs,- codem,- ak47, and- qb-inventory
- Uses - QBCore.Functions.GetPlayer(src)
-- Add money
Player.Functions.AddMoney('cash', amount, reason)
-- Add item
Player.Functions.AddItem(item, amount)
-- Show item box (client)
TriggerClientEvent('qb-inventory:client:ItemBox', ...)🔶 ESX Implementation
- Framework: - es_extended
- Uses - ESX.GetPlayerFromId(src)
- Meta item support includes: - ox_inventory,- qs,- codem,- ak47_inventory
Player.addAccountMoney('money', amount)
Player.addInventoryItem(item, amount)🔷 QBX (QBCore Extended) Implementation
- Framework: - qbx_core
- Uses - exports.qbx_core:*
- Inventory: Primarily relies on - ox_inventory
- Duty toggle supported via: - exports.qbx_core:SetJobDuty(src, bool)
❗ Note:
- AddBankand- RemoveBankare placeholders and need implementation based on your banking system.
🧪 Example Usage
XM.AddMoney(playerSrc, 500, "Mission Complete")
XM.RemoveItem(playerSrc, "lockpick", 1)
XM.AddMetaItem(playerSrc, "document", 1, { owner = "John Doe" })
XM.ToggleItem(playerSrc, true, "sandwich", 2) -- add itemFramework Bridge
This script enables a unified server-side interface to handle player-related logic like money, items, job checks, and usable items across QBCore, QB-X, and ESX frameworks. It allows modular and framework-agnostic scripting.
🔍 Framework Detection
local framework = nilOn resource load, it sets the framework variable based on what’s running:
- "qb-core"
- "qbx_core"
- "es_extended"
🧰 XM Utility Functions
✅ Function XM.GetPlayer(src)
XM.GetPlayer(src)Returns the player object from the active framework.
✅ Function XM.GetPlayerCash(src)
XM.GetPlayerCash(src)Gets the player's current cash amount.
✅ Function XM.GetPlayerBank(src)
XM.GetPlayerBank(src)Gets the player's bank account balance.
🧩 Function XM.CreateCallback(name, cb)
XM.CreateCallback(name, cb)Registers a server callback compatible with the active framework:
- QBCore.Functions.CreateCallback
- lib.callback.register
- ESX.RegisterServerCallback
🧪 Function XM.RegisterItemUseable(itemName, eventName)
XM.RegisterItemUseable(itemName, eventName)Registers a usable item that triggers a client event.
- Framework-specific registration: - QBCore.Functions.CreateUseableItem
- exports.qbx_core:CreateUseableItem
- ESX.RegisterUsableItem
 
👥 Function XM.GetPlayersNotInJobs(excludedJobs)
XM.GetPlayersNotInJobs(excludedJobs)Returns a list of player IDs who are not in any of the specified jobs.
- Useful for excluding certain roles (e.g., police or EMS) from missions. 
👮 Function XM.PoliceCheck(jobs, count)
XM.PoliceCheck(jobs, count)Registers a server callback xmmx_moneyruns:server:GetCopCount to verify if there are enough on-duty police (or specified jobs) on the server.
- Works differently per framework, respecting each framework's job/duty system. 
- Returns - trueor- falseto the client via callback.
🔄 Inventory Toggle Handler
RegisterServerEvent("xmmx_bridge:server:toggleItem")Server event used to add or remove an item from a player's inventory:
- Performs anti-cheat validation with - XM.ValidateCaller
- Calls - XM.ToggleItem()to process the item change
🛡️ Security Reminder
All sensitive server events like toggleItem are protected by XM.ValidateCaller, which ensures only the legitimate player can trigger the event.
✅ Example Usages
-- Add usable item
XM.RegisterItemUseable("medkit", "my_script:useMedkit")
-- Get player balance
local cash = XM.GetPlayerCash(src)
-- Trigger item toggle (server-side)
TriggerEvent("xmmx_bridge:server:toggleItem", src, true, "lockpick", 1)
-- Register server-side callback
XM.CreateCallback("my_script:getBalance", function(src, cb)
    cb(XM.GetPlayerBank(src))
end)Last updated
