🌉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()
end
This 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
end
Boss 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
: Triggersqb-bossmenu:client:OpenMenu
.qbx_core
: Usesexports.qbx_management:OpenBossMenu
.es_extended
: Opens the ESX society boss menu viaesx_society:openBossMenu
.
XM.ToggleDuty()
Toggles the player's on-duty/off-duty status:
qb-core
: Calls the standardQBCore:ToggleDuty
server event.qbx_core
: Checks current duty state usingGetPlayerData()
and toggles it using a custom bridge eventxmmx_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-core
andqbx_core
: Reads the player's job status fromGetPlayerData()
.Fallback: Returns
true
if 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
end
Callbacks
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
: UsesQBCore.Functions.TriggerCallback
.qbx_core
: Useslib.callback
.es_extended
: UsesESX.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
: UsesQBCore.Functions.CreateCallback
.qbx_core
: Useslib.callback.register
.es_extended
: UsesESX.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
end
Consumables
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 theXM.Progress
function.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:toggleItem
to 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_status
equivalent).
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:add
for hunger/thirst.Still triggers the same stress relief event.
Returns
true
if the item was successfully consumed and effects applied.nil
if 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
end
DrawText
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 forox
).style
(table, optional): CSS-like styling options (only forox
).
Framework-Specific Behavior:
qb
: Usesqb-core
’sDrawText
with basic positioning.ox
: Useslib.showTextUI
with additional support for icons and styling.esx
: CallsESX.TextUI
with 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 usingqb-core:HideText
.ox
: Callslib.hideTextUI
.esx
: UsesESX.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
end
Hud / 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;false
shows HUD,true
hides it.
tgiann-lumihud
Triggers the event
"tgiann-lumihud:ui"
with atrue
orfalse
value.
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 HUD
This 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
end
Inventory 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) –true
to mark the inventory as busy,false
to re-enable access.
Framework-Specific Behavior
ox_inventory
: UsesLocalPlayer.state.invBusy
andinvHotkeys
to lock/unlock.qb-inventory
/codem-inventory (QB)
: Setsinv_busy
flag viaLocalPlayer.state:set
.qs-inventory
: UsessetInventoryDisabled(true/false)
.codem-inventory (ESX)
: UsesLocalPlayer.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
: Callsox_inventory:closeInventory()
.newQB
,oldQB
,codem
: Executescloseinv
command.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
: Callsox_inventory:GetPlayerItems()
and loops through to find item.Otherwise: Retrieves from
QBCore.Shared.Items
.
qbx_core
: Always usesox_inventory
.es_extended
:Uses appropriate
getInventory()
export based onConfig.Inventory
:ox
,qs
, orcodem
.
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
end
Minigame
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 thexmmx_keysgame
export).keys
(number) – Number of keys the player must press.time
(number) – Total time allowed (in milliseconds or seconds, based onxmmx_keysgame
implementation).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) –true
if the player completed the mini-game successfully,false
if 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.")
end
This 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
end
Player 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"
), ornil
if unavailable.
Framework Support
qb-core
: UsesQBCore.Functions.GetPlayerData()
.qbx_core
: Usesexports.qbx_core:GetPlayerData()
.es_extended
: UsesESX.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) –
true
if the player has one of the specified jobs and is within range of the respective location, otherwisefalse
.
Distance Check
A distance threshold of
100.0
units 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
end
Progress 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:5000
ms).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 isCompleted
loop.
✅ 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
/onCancel
callbacks for result handling.
☑️ custom
Placeholder for custom progress implementation.
❌ Unsupported
Logs an error if
Config.Progress
is not recognized.
Returns
(boolean) –
true
if the progress completed successfully,false
if 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.")
end
This 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
: CallsdisableTargeting(true)
qb-target
: CallsAllowTargeting(false)
qtarget
: Also usesAllowTargeting(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
: CallsdisableTargeting(false)
qb-target
: CallsAllowTargeting(true)
qtarget
: CallsAllowTargeting(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
end
Target 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
nil
if unsuccessful.
Behavior by Target System
✅
ox_target
: Usesox_target:addBoxZone()
with full support for size, rotation, sprite, and interaction options.✅
qb-target
/qtarget
: UsesAddBoxZone()
with a heading and bounding box (minZ
,maxZ
), and adapts the options list:Converts
groups
tojob
field.Converts
onSelect
toaction
.
🗑️ 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
: CallsremoveZone(name)
✅
qb-target
/qtarget
: CallsRemoveZone(name)
Removes the zone from the
TargetZones
registry.
🛑 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 toaction
for 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
groups
tojob
field.Converts
onSelect
toaction
function.Wraps options in a
distance
field and callsAddTargetEntity
.
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
EntityTargets
table 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 theinteract
resource 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
interactionId
for each.Calls
interact:AddModelInteraction
for 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
InteractTargets
for 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
src
does not matchexpected
, 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
Webhook
URL 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
, andqb-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:
AddBank
andRemoveBank
are 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 item
Framework 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 = nil
On 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
true
orfalse
to 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