2025-03-08 13:44:05 +00:00
--[[
Usable Items & Inventory Utilities Module
-------------------------------------------
This module provides functions for :
• Registering items as usable across different inventory systems ( ESX , QBcore , QBX ) .
• Retrieving an item ' s image as a NUI link.
• Adding and removing items from a player ' s inventory.
• Toggling items in inventory ( with server event for exploit protection ) .
• Checking for item duplication exploits .
• Handling tool durability mechanics .
• Checking item availability and retrieving inventory .
• Granting random rewards from a reward pool .
• Checking if a player can carry specific items based on weight .
] ]
2025-03-26 21:43:48 +00:00
validTokens = { }
2025-03-08 13:44:05 +00:00
-------------------------------------------------------------
-- Registering Usable Items
-------------------------------------------------------------
--- Registers an item as usable for ESX, QBcore, or QBX.
---
--- @param item string The name of the item.
--- @param funct function The function to execute when the item is used.
2025-03-01 12:58:43 +00:00
---
2025-03-08 13:44:05 +00:00
--- @usage
2025-03-01 12:58:43 +00:00
--- ```lua
--- createUseableItem("health_potion", function(source)
--- -- Code to consume the health potion
--- end)
--- ```
function createUseableItem ( item , funct )
if isStarted ( ESXExport ) then
2025-05-01 17:49:37 +01:00
debugPrint ( " ^6Bridge^7: ^2Registering item as ^3Usable^2 with ^7es_extended^7 " , item )
2025-03-01 12:58:43 +00:00
while not ESX do Wait ( 0 ) end
ESX.RegisterUsableItem ( item , funct )
2025-05-01 17:49:37 +01:00
2025-03-01 12:58:43 +00:00
elseif isStarted ( QBExport ) and not isStarted ( QBXExport ) then
2025-05-01 17:49:37 +01:00
debugPrint ( " ^6Bridge^7: ^2Registering item as ^3Usable^2 with ^7qb-core^7 " , item )
2025-03-01 12:58:43 +00:00
Core.Functions . CreateUseableItem ( item , funct )
2025-05-01 17:49:37 +01:00
2025-03-01 12:58:43 +00:00
elseif isStarted ( QBXExport ) then
2025-05-01 17:49:37 +01:00
debugPrint ( " ^6Bridge^7: ^2Registering item as ^3Usable^2 with ^7qbx_core^7 " , item )
2025-03-01 12:58:43 +00:00
exports [ QBXExport ] : CreateUseableItem ( item , funct )
2025-05-01 17:49:37 +01:00
elseif isStarted ( RSGExport ) then
debugPrint ( " ^6Bridge^7: ^2Registering item as ^3Usable^2 with ^1rsg-core^7 " , item )
Core.Functions . CreateUseableItem ( item , funct )
2025-03-08 13:44:05 +00:00
else
print ( " ^4ERROR^7: No supported framework detected for registering usable item: ^3 " .. item .. " ^7 " )
2025-03-01 12:58:43 +00:00
end
end
2025-03-08 13:44:05 +00:00
-------------------------------------------------------------
-- Item Image Retrieval
-------------------------------------------------------------
--- Retrieves the NUI link for an item's image from the active inventory system.
2025-03-01 12:58:43 +00:00
---
2025-03-08 13:44:05 +00:00
--- @param item string The item name.
--- @return string string A `nui://` link to the item's image, or an empty string if not found.
2025-03-01 12:58:43 +00:00
---
2025-03-08 13:44:05 +00:00
--- @usage
2025-03-01 12:58:43 +00:00
--- ```lua
--- local imageLink = invImg("health_potion")
2025-03-08 13:44:05 +00:00
--- if imageLink ~= "" then print(imageLink) end
2025-03-01 12:58:43 +00:00
--- ```
function invImg ( item )
local imgLink = " "
if item ~= " " and Items [ item ] then
if isStarted ( OXInv ) then
imgLink = " nui:// " .. OXInv .. " /web/images/ " .. ( Items [ item ] . image or " " )
2025-04-30 17:53:26 +01:00
2025-03-01 12:58:43 +00:00
elseif isStarted ( QSInv ) then
imgLink = " nui:// " .. QSInv .. " /html/images/ " .. ( Items [ item ] . image or " " )
2025-04-30 17:53:26 +01:00
2025-03-01 12:58:43 +00:00
elseif isStarted ( CoreInv ) then
imgLink = " nui:// " .. CoreInv .. " /html/img/ " .. ( Items [ item ] . image or " " )
2025-04-30 17:53:26 +01:00
2025-03-08 13:44:05 +00:00
elseif isStarted ( CodeMInv ) then
imgLink = " nui:// " .. CodeMInv .. " /html/itemimages/ " .. ( Items [ item ] . image or " " )
2025-04-30 17:53:26 +01:00
2025-03-01 12:58:43 +00:00
elseif isStarted ( OrigenInv ) then
imgLink = " nui:// " .. OrigenInv .. " /html/img/ " .. ( Items [ item ] . image or " " )
2025-04-30 17:53:26 +01:00
2025-03-01 12:58:43 +00:00
elseif isStarted ( QBInv ) then
imgLink = " nui:// " .. QBInv .. " /html/images/ " .. ( Items [ item ] . image or " " )
2025-04-30 17:53:26 +01:00
elseif isStarted ( TgiannInv ) then
imgLink = " nui://inventory_images/images/ " .. ( Items [ item ] . image or " " )
2025-04-07 20:52:59 +01:00
elseif isStarted ( RSGInv ) then
imgLink = " nui:// " .. RSGInv .. " /html/images/ " .. ( Items [ item ] . image or " " )
2025-04-30 17:53:26 +01:00
2025-03-01 12:58:43 +00:00
else
2025-03-26 21:43:48 +00:00
print ( " ^4ERROR^7: ^2No Inventory detected for invImg - Check starter.lua " )
2025-03-01 12:58:43 +00:00
end
end
return imgLink
end
2025-03-08 13:44:05 +00:00
-------------------------------------------------------------
-- Adding and Removing Items
-------------------------------------------------------------
2025-03-01 12:58:43 +00:00
--- Adds an item to a player's inventory.
---
2025-03-08 13:44:05 +00:00
--- Triggers a server event (or local event) to add the specified item.
2025-03-01 12:58:43 +00:00
---
2025-03-08 13:44:05 +00:00
--- @param item string The item name.
--- @param amount number The quantity to add.
--- @param info table|nil Additional metadata for the item.
--- @param src number|nil Optional player source; if nil, defaults to the caller.
2025-03-01 12:58:43 +00:00
---
2025-03-08 13:44:05 +00:00
--- @usage
2025-03-01 12:58:43 +00:00
--- ```lua
--- addItem("health_potion", 2, { quality = "high" })
--- ```
function addItem ( item , amount , info , src )
2025-04-07 20:52:59 +01:00
if not Items [ item ] then
print ( " ^6Bridge^7: ^1Error^7 - ^2Tried to give ^7'^3 " .. item .. " ^7'^2 but it doesn't exist " )
return
end
2025-03-08 13:44:05 +00:00
2025-03-01 12:58:43 +00:00
if src then
TriggerEvent ( getScript ( ) .. " :server:toggleItem " , true , item , amount , src , info )
else
2025-04-07 20:52:59 +01:00
TriggerServerEvent ( getScript ( ) .. " :server:toggleItem " , true , item , amount , nil , info , nil , currentToken )
2025-03-26 21:43:48 +00:00
currentToken = nil -- clear client cached token
2025-03-01 12:58:43 +00:00
end
end
--- Removes an item from a player's inventory.
---
2025-03-08 13:44:05 +00:00
--- Triggers a server event (or local event) to remove the specified item.
2025-03-01 12:58:43 +00:00
---
2025-03-08 13:44:05 +00:00
--- @param item string The item name.
--- @param amount number The quantity to remove.
--- @param src number|nil Optional player source.
--- @param slot number|nil Optional inventory slot.
2025-03-01 12:58:43 +00:00
---
2025-03-08 13:44:05 +00:00
--- @usage
2025-03-01 12:58:43 +00:00
--- ```lua
--- removeItem("health_potion", 1)
--- ```
2025-03-06 23:49:07 +00:00
function removeItem ( item , amount , src , slot )
2025-03-08 13:44:05 +00:00
if not Items [ item ] then
print ( " ^6Bridge^7: ^1Error^7 - ^2Tried to remove ^7'^3 " .. item .. " ^7'^2 but it doesn't exist " )
return
end
2025-03-01 12:58:43 +00:00
if src then
2025-04-07 20:52:59 +01:00
debugPrint ( src )
2025-03-06 23:49:07 +00:00
TriggerEvent ( getScript ( ) .. " :server:toggleItem " , false , item , amount , src , nil , slot )
2025-03-01 12:58:43 +00:00
else
2025-03-06 23:49:07 +00:00
TriggerServerEvent ( getScript ( ) .. " :server:toggleItem " , false , item , amount , nil , nil , slot )
2025-03-01 12:58:43 +00:00
end
end
2025-03-08 13:44:05 +00:00
-------------------------------------------------------------
-- Toggle Items (Server Event)
-------------------------------------------------------------
--- Server event handler to toggle (add or remove) an item from a player's inventory.
2025-03-01 12:58:43 +00:00
---
2025-03-08 13:44:05 +00:00
--- This function validates the item, then calls the appropriate export functions based on the active inventory system.
--- It also includes exploit protection via the dupeWarn function.
2025-03-01 12:58:43 +00:00
---
2025-03-08 13:44:05 +00:00
--- @param give boolean True to add the item, false to remove.
--- @param item string The item name.
--- @param amount number The quantity.
--- @param newsrc number|nil The player source; defaults to event source.
--- @param info table|nil Additional metadata.
--- @param slot number|nil Optional inventory slot.
2025-03-01 12:58:43 +00:00
---
2025-03-08 13:44:05 +00:00
--- @usage
2025-03-01 12:58:43 +00:00
--- ```lua
2025-03-08 13:44:05 +00:00
--- TriggerServerEvent(getScript()..":server:toggleItem", true, "health_potion", 1)
2025-03-01 12:58:43 +00:00
--- ```
2025-04-07 20:52:59 +01:00
RegisterNetEvent ( getScript ( ) .. " :server:toggleItem " , function ( give , item , amount , newsrc , info , slot , token )
debugPrint ( GetInvokingResource ( ) )
if GetInvokingResource ( ) and GetInvokingResource ( ) ~= getScript ( ) and GetInvokingResource ( ) ~= " qb-core " then
debugPrint ( " ^1Error^7: ^1Possible exploit^7, ^1vital function was called from an external resource^7 " )
return
end
2025-03-08 13:44:05 +00:00
if not Items [ item ] then
print ( " ^6Bridge^7: ^1Error^7 - ^2Tried to " .. ( tostring ( give ) == " true " and " add " or " remove " ) .. " '^3 " .. item .. " ^7' but it doesn't exist " )
return
end
2025-04-07 20:52:59 +01:00
local src = newsrc or source
2025-03-26 21:43:48 +00:00
if ( give == true or give == 1 ) then
if newsrc == nil then -- must be coming from client this would be blank
2025-04-07 20:52:59 +01:00
if token == nil then
debugPrint ( " ^1Auth^7: ^1No token recieved^7 " )
dupeWarn ( src , item , " Auth: Player " .. src .. " attempted to spawn " .. item .. " without an auth token " )
else
if type ( token ) ~= " number " then -- checks if the newsrc is a source or token, if number its coming form the server itself
debugPrint ( " ^1Auth^7: ^2Auth token received^7, ^2checking against server cache^7.. " )
if token ~= validTokens [ src ] then
debugPrint ( " ^1Auth^7: ^1Tokens don't match! ^7 " , token , validTokens [ src ] )
dupeWarn ( src , item , " Auth: " .. src .. " attempted to spawn " .. item .. " with an incorrect auth token " )
else
debugPrint ( " ^1Auth^7: ^2Client and Server Auth tokens match^7! " , token , validTokens [ src ] )
validTokens [ src ] = nil
end
2025-03-26 21:43:48 +00:00
end
end
end
end
2025-03-08 13:44:05 +00:00
local action = ( tostring ( give ) == " true " and " addItem " or " removeItem " )
local remamount = amount or 1
2025-03-01 12:58:43 +00:00
if item == nil then return end
2025-03-08 13:44:05 +00:00
-- Grab the current inventory (you can expand usage of 'inv' if needed)
local invName = " "
2025-03-01 12:58:43 +00:00
if give == 0 or give == false then
2025-03-08 13:44:05 +00:00
if not hasItem ( item , amount or 1 , src ) then
dupeWarn ( src , item , amount )
else
if isStarted ( OXInv ) then invName = OXInv
exports [ OXInv ] : RemoveItem ( src , item , remamount , nil )
elseif isStarted ( QSInv ) then invName = QSInv
exports [ QSInv ] : RemoveItem ( src , item , remamount )
elseif isStarted ( CoreInv ) then invName = CoreInv
exports [ CoreInv ] : removeItem ( src , item , remamount )
2025-03-01 12:58:43 +00:00
2025-03-08 13:44:05 +00:00
elseif isStarted ( OrigenInv ) then invName = OrigenInv
exports [ OrigenInv ] : removeItem ( src , item , remamount )
2025-03-01 12:58:43 +00:00
2025-03-08 13:44:05 +00:00
elseif isStarted ( CodeMInv ) then invName = CodeMInv
exports [ CodeMInv ] : RemoveItem ( src , item , remamount )
2025-03-01 12:58:43 +00:00
2025-04-30 17:53:26 +01:00
elseif isStarted ( TgiannInv ) then invName = TgiannInv
exports [ TgiannInv ] : RemoveItem ( src , item , remamount )
2025-03-08 13:44:05 +00:00
elseif isStarted ( QBInv ) then invName = QBInv
2025-03-01 12:58:43 +00:00
while remamount > 0 do
2025-03-06 23:49:07 +00:00
if Core.Functions . GetPlayer ( src ) . Functions.RemoveItem ( item , 1 , slot ) then
2025-03-01 12:58:43 +00:00
remamount -= 1
else
2025-03-08 13:44:05 +00:00
print ( " ^1Error removing " .. item .. " Amount left: " .. remamount )
2025-03-01 12:58:43 +00:00
break
end
end
if Config.Crafting . showItemBox then
2025-03-08 13:44:05 +00:00
TriggerClientEvent ( ( isStarted ( QBInv ) and QBInvNew and " qb- " or " " ) .. " inventory:client:ItemBox " , src , Items [ item ] , " remove " , amount or 1 )
2025-03-01 12:58:43 +00:00
end
2025-03-08 13:44:05 +00:00
elseif isStarted ( PSInv ) then invName = PSInv
2025-03-01 12:58:43 +00:00
while remamount > 0 do
2025-03-08 13:44:05 +00:00
if Core.Functions . GetPlayer ( src ) . Functions.RemoveItem ( item , 1 , slot ) then
2025-03-01 12:58:43 +00:00
remamount -= 1
else
2025-03-08 13:44:05 +00:00
print ( " ^1Error removing " .. item .. " Amount left: " .. remamount )
2025-03-01 12:58:43 +00:00
break
end
end
if Config.Crafting . showItemBox then
2025-03-08 13:44:05 +00:00
TriggerClientEvent ( " inventory:client:ItemBox " , src , Items [ item ] , " remove " , amount or 1 )
end
2025-04-07 20:52:59 +01:00
elseif isStarted ( RSGInv ) then invName = RSGInv
while remamount > 0 do
if Core.Functions . GetPlayer ( src ) . Functions.RemoveItem ( item , 1 , slot ) then
remamount -= 1
else
print ( " ^1Error removing " .. item .. " Amount left: " .. remamount )
break
end
end
if Config.Crafting . showItemBox then
TriggerClientEvent ( " rsg-inventory:client:ItemBox " , src , Items [ item ] , " remove " , amount or 1 )
end
2025-03-08 13:44:05 +00:00
end
-----
-- Fallback for if no inventory found:
-----
if invName == " " then
if isStarted ( QBExport ) or isStarted ( QBXExport ) then -- if qbcore or qbxcore, just use core functions
invName = isStarted ( QBXExport ) and QBXExport or isStarted ( QBExport ) and QBExport
Core.Functions . GetPlayer ( src ) . Functions.RemoveItem ( item , remamount , slot )
elseif ESX and isStarted ( ESXExport ) then -- if esx then use core functions
invName = ESX
ESX.GetPlayerFromId ( src ) . removeInventoryItem ( item , remamount )
2025-03-01 12:58:43 +00:00
end
2025-03-08 13:44:05 +00:00
end
-- Final check for if inventory was found
if invName == " " then
print ( " ^4ERROR^7: No Inventory detected - Check starter.lua " )
2025-03-01 12:58:43 +00:00
else
2025-03-08 13:44:05 +00:00
debugPrint ( " ^6Bridge^7: ^3 " .. action .. " ^7[ " .. invName .. " ] Player( " .. src .. " ) " .. Items [ item ] . label .. " ( " .. item .. " ) x " .. ( amount or 1 ) )
2025-03-01 12:58:43 +00:00
end
end
else
2025-03-08 13:44:05 +00:00
local amountToAdd = amount or 1
if isStarted ( OXInv ) then invName = OXInv
exports [ OXInv ] : AddItem ( src , item , amountToAdd , info , slot )
2025-03-01 12:58:43 +00:00
2025-03-08 13:44:05 +00:00
elseif isStarted ( QSInv ) then invName = QSInv
exports [ QSInv ] : AddItem ( src , item , amountToAdd , slot , info )
2025-03-01 12:58:43 +00:00
2025-03-08 13:44:05 +00:00
elseif isStarted ( CoreInv ) then invName = CoreInv
exports [ CoreInv ] : addItem ( src , item , amountToAdd , info )
2025-03-01 12:58:43 +00:00
2025-03-08 13:44:05 +00:00
elseif isStarted ( CodeMInv ) then invName = CodeMInv
exports [ CodeMInv ] : AddItem ( src , item , amountToAdd , slot , info )
2025-03-01 12:58:43 +00:00
2025-03-08 13:44:05 +00:00
elseif isStarted ( OrigenInv ) then invName = OrigenInv
exports [ OrigenInv ] : addItem ( src , item , amountToAdd , info , slot )
2025-04-30 17:53:26 +01:00
elseif isStarted ( TgiannInv ) then invName = TgiannInv
exports [ TgiannInv ] : AddItem ( src , item , amountToAdd , slot , info )
2025-03-08 13:44:05 +00:00
elseif isStarted ( QBInv ) then invName = QBInv
if Core.Functions . GetPlayer ( src ) . Functions.AddItem ( item , amountToAdd , nil , info ) then
TriggerClientEvent ( ( isStarted ( QBInv ) and QBInvNew and " qb- " or " " ) .. " inventory:client:ItemBox " , src , Items [ item ] , " add " , amountToAdd )
2025-03-01 12:58:43 +00:00
end
2025-04-07 20:52:59 +01:00
elseif isStarted ( RSGInv ) then invName = RSGInv
if Core.Functions . GetPlayer ( src ) . Functions.AddItem ( item , amountToAdd , nil , info ) then
TriggerClientEvent ( " rsg-inventory:client:ItemBox " , src , Items [ item ] , " add " , amountToAdd )
end
2025-03-08 13:44:05 +00:00
elseif isStarted ( PSInv ) then invName = PSInv
if Core.Functions . GetPlayer ( src ) . Functions.AddItem ( item , amountToAdd , nil , info ) then
2025-03-01 12:58:43 +00:00
if Config.Crafting . showItemBox then
2025-03-08 13:44:05 +00:00
TriggerClientEvent ( " inventory:client:ItemBox " , src , Items [ item ] , " add " , amountToAdd )
2025-03-01 12:58:43 +00:00
end
end
2025-03-08 13:44:05 +00:00
end
if invName == " " then
if isStarted ( QBExport ) or isStarted ( QBXExport ) then -- if qbcore or qbxcore, just use core functions
invName = isStarted ( QBXExport ) and QBXExport or isStarted ( QBExport ) and QBExport
Core.Functions . GetPlayer ( src ) . Functions.AddItem ( item , amountToAdd , nil , info )
elseif ESX and isStarted ( ESXExport ) then -- if esx then use core functions
invName = ESX
ESX.GetPlayerFromId ( src ) . addInventoryItem ( item , amountToAdd )
end
end
-- Final check for if inventory was found
if invName == " " then
print ( " ^4ERROR^7: No Inventory detected - Check starter.lua " )
2025-03-01 12:58:43 +00:00
else
2025-03-08 13:44:05 +00:00
debugPrint ( " ^6Bridge^7: ^3 " .. action .. " ^7[ " .. invName .. " ] Player( " .. src .. " ) " .. Items [ item ] . label .. " ( " .. item .. " ) x " .. ( amount or 1 ) )
2025-03-01 12:58:43 +00:00
end
end
end )
2025-03-08 13:44:05 +00:00
-------------------------------------------------------------
-- Exploit Protection
-------------------------------------------------------------
--- Warns and kicks a player if they try to remove an item they don't have.
2025-03-01 12:58:43 +00:00
---
2025-03-08 13:44:05 +00:00
--- @param src number The player's source ID.
--- @param item string The item name.
2025-03-01 12:58:43 +00:00
---
--- @usage
--- ```lua
--- dupeWarn(playerId, "health_potion")
--- ```
2025-03-08 13:44:05 +00:00
function dupeWarn ( src , item , amount )
2025-03-01 12:58:43 +00:00
local name = getPlayer ( src ) . name
2025-04-29 19:55:30 +01:00
print ( " ^5DupeWarn^7: " .. name .. " (^1 " .. tostring ( src ) .. " ^7) ^2Tried to remove item '^3 " .. item .. " ^7'^2 but it wasn't there^7 " )
2025-03-01 12:58:43 +00:00
if not debugMode then
DropPlayer ( src , name .. " ( " .. tostring ( src ) .. " ) Kicked for suspected duplicating items: " .. item )
end
print ( " ^5DupeWarn^7: " .. name .. " (^1 " .. tostring ( src ) .. " ^7) ^2Dropped from server - exploit protection detected an item not being found in players inventory^7 " )
end
2025-03-08 13:44:05 +00:00
-------------------------------------------------------------
-- Tool Durability & Metadata
-------------------------------------------------------------
--- Reduces the durability of a tool by a specified damage amount.
2025-03-01 12:58:43 +00:00
---
2025-03-08 13:44:05 +00:00
--- If durability reaches zero or below, the tool is removed and a break sound is played.
2025-03-01 12:58:43 +00:00
---
2025-03-08 13:44:05 +00:00
--- @param data table Contains:
--- - item (string): The tool's name.
--- - damage (number): The damage % to apply.
2025-03-01 12:58:43 +00:00
---
--- @usage
--- ```lua
--- breakTool({ item = "drill", damage = 10 })
--- ```
function breakTool ( data ) -- WIP
local durability , slot = getDurability ( data.item )
if not durability then durability = 100 end
durability -= data.damage
if durability <= 0 then
removeItem ( data.item , 1 )
local breakId = GetSoundId ( )
PlaySoundFromEntity ( breakId , " Drill_Pin_Break " , PlayerPedId ( ) , " DLC_HEIST_FLEECA_SOUNDSET " , 1 , 0 )
else
TriggerServerEvent ( getScript ( ) .. " :server:setMetaData " , { item = data.item , slot = slot , metadata = { durability = durability } } )
end
end
2025-03-08 13:44:05 +00:00
--- Retrieves the durability and slot number of an item in a player's inventory.
2025-03-01 12:58:43 +00:00
---
2025-03-08 13:44:05 +00:00
--- Searches through the player's inventory for the specified item.
2025-03-01 12:58:43 +00:00
---
2025-03-08 13:44:05 +00:00
--- @param item string The item name.
--- @return number|nil number The durability, or nil if not found.
--- @return number|nil number The slot number, or nil if not found.
2025-03-01 12:58:43 +00:00
---
--- @usage
--- ```lua
--- local durability, slot = getDurability("drill")
--- if durability then
--- print("Durability:", durability)
2025-03-08 13:44:05 +00:00
--- print("Slot:", slot)
2025-03-01 12:58:43 +00:00
--- end
--- ```
function getDurability ( item )
local lowestSlot = 100
local durability = nil
2025-04-08 17:48:38 +01:00
if isStarted ( QBInv ) or isStarted ( PSInv ) or isStarted ( RSGInv ) then
2025-03-01 12:58:43 +00:00
local itemcheck = Core.Functions . GetPlayerData ( ) . items
2025-03-08 20:55:05 +00:00
for k , v in pairs ( itemcheck ) do
2025-03-01 12:58:43 +00:00
if v.name == item then
if v.slot <= lowestSlot then
lowestSlot = v.slot
2025-05-02 22:16:51 +01:00
durability = itemcheck [ k ] . info and itemcheck [ k ] . info.durability or nil
2025-03-01 12:58:43 +00:00
end
end
end
end
if isStarted ( OXInv ) then
local itemcheck = exports [ OXInv ] : Search ( ' slots ' , item )
2025-03-08 20:55:05 +00:00
for k , v in pairs ( itemcheck ) do
2025-03-01 12:58:43 +00:00
if v.slot <= lowestSlot then
debugPrint ( v.slot , itemcheck [ k ] . metadata.durability )
lowestSlot = v.slot
2025-05-02 22:16:51 +01:00
durability = v.metadata and v.metadata . durability or nil
2025-03-01 12:58:43 +00:00
end
end
end
if isStarted ( QSInv ) then
local itemcheck = exports [ QSInv ] : getUserInventory ( )
2025-03-08 13:44:05 +00:00
for _ , v in pairs ( itemcheck ) do
if v.name == item and v.slot <= lowestSlot then
lowestSlot = v.slot
2025-05-02 22:16:51 +01:00
durability = v.info and v.info . durability or nil
2025-03-08 13:44:05 +00:00
end
end
end
if isStarted ( CoreInv ) then
local itemcheck = exports [ CoreInv ] : getInventory ( )
for _ , v in pairs ( itemcheck ) do
if v.name == item and v.slot <= lowestSlot then
lowestSlot = v.slot
2025-05-02 22:16:51 +01:00
durability = v.metadata and v.metadata . durability or nil
2025-03-08 13:44:05 +00:00
end
end
end
if isStarted ( CodeMInv ) then
local itemcheck = exports [ CodeMInv ] : GetClientPlayerInventory ( )
for _ , v in pairs ( itemcheck ) do
2025-03-01 12:58:43 +00:00
if v.name == item and v.slot <= lowestSlot then
lowestSlot = v.slot
2025-05-02 22:16:51 +01:00
durability = v.info and v.info . durability or nil
2025-03-01 12:58:43 +00:00
end
end
end
if isStarted ( OrigenInv ) then
local itemcheck = exports [ OrigenInv ] : getPlayerInventory ( )
2025-03-08 13:44:05 +00:00
for _ , v in pairs ( itemcheck ) do
2025-03-01 12:58:43 +00:00
if v.name == item and v.slot <= lowestSlot then
lowestSlot = v.slot
2025-05-02 22:16:51 +01:00
durability = v.metadata and v.metadata . durability or nil
2025-03-08 13:44:05 +00:00
end
end
end
2025-04-30 17:53:26 +01:00
if isStarted ( TgiannInv ) then
local itemcheck = exports [ TgiannInv ] : GetPlayerItems ( )
for _ , v in pairs ( itemcheck ) do
if v.name == item and v.slot <= lowestSlot then
lowestSlot = v.slot
2025-05-02 22:16:51 +01:00
durability = v.metadata and v.metadata . durability or nil
2025-04-30 17:53:26 +01:00
end
end
end
2025-03-08 13:44:05 +00:00
-- For ESX default inventory (es_extended)
if ESX and isStarted ( ESXExport ) then
local xPlayer = ESX.GetPlayerData ( ) or { }
if xPlayer.inventory then
for _ , v in ipairs ( xPlayer.inventory ) do
if v.name == item then
-- Optionally use a slot field if available; otherwise, use the index
if v.slot and v.slot <= lowestSlot then
lowestSlot = v.slot
end
if v.metadata and v.metadata . durability then
durability = v.metadata . durability
end
end
2025-03-01 12:58:43 +00:00
end
end
end
2025-03-08 13:44:05 +00:00
2025-03-01 12:58:43 +00:00
return durability , lowestSlot
end
2025-03-08 13:44:05 +00:00
--- Server event handler to set metadata for an item.
2025-03-01 12:58:43 +00:00
---
2025-03-08 13:44:05 +00:00
--- Updates item metadata (e.g. durability) for the player's inventory based on slot.
2025-03-01 12:58:43 +00:00
---
2025-03-08 13:44:05 +00:00
--- @param data table Contains:
--- - item (string): The item name.
--- - slot (number): The inventory slot.
--- - metadata (table): The metadata to set.
2025-03-01 12:58:43 +00:00
---
2025-03-08 13:44:05 +00:00
--- @usage
2025-03-01 12:58:43 +00:00
--- ```lua
--- TriggerServerEvent("script:server:setMetaData", { item = "drill", slot = 5, metadata = { durability = 80 } })
--- ```
RegisterNetEvent ( getScript ( ) .. " :server:setMetaData " , function ( data )
local src = source
2025-04-08 17:48:38 +01:00
if isStarted ( QBInv ) or isStarted ( PSInv ) or isStarted ( RSGInv ) then
2025-03-01 12:58:43 +00:00
debugPrint ( src , data.item , 1 , data.slot )
local Player = Core.Functions . GetPlayer ( src )
Player.PlayerData . items [ data.slot ] . info = data.metadata
Player.PlayerData . items [ data.slot ] . description = " HP : " .. data.metadata . durability
Player.Functions . SetInventory ( Player.PlayerData . items )
2025-03-08 13:44:05 +00:00
elseif isStarted ( OXInv ) then
exports [ OXInv ] : SetDurability ( src , data.slot , data.metadata . durability )
2025-03-01 12:58:43 +00:00
elseif isStarted ( QSInv ) then
2025-03-08 13:44:05 +00:00
exports [ QSInv ] : SetItemMetadata ( src , data.slot , data.metadata )
2025-03-01 12:58:43 +00:00
elseif isStarted ( CoreInv ) then
2025-03-08 13:44:05 +00:00
exports [ CoreInv ] : setMetadata ( src , data.slot , data.metadata )
2025-03-01 12:58:43 +00:00
elseif isStarted ( CodeMInv ) then
2025-03-08 13:44:05 +00:00
exports [ CodeMInv ] : SetItemMetadata ( src , data.slot , data.metadata )
2025-03-01 12:58:43 +00:00
2025-03-08 13:44:05 +00:00
elseif isStarted ( OrigenInv ) then
exports [ OrigenInv ] : setMetadata ( src , data.slot , data.metadata )
2025-04-30 17:53:26 +01:00
elseif isStarted ( TgiannInv ) then
exports [ TgiannInv ] : UpdateItemMetadata ( src , data.item , data.slot , data.metadata )
2025-03-01 12:58:43 +00:00
end
2025-03-08 13:44:05 +00:00
end )
2025-03-01 12:58:43 +00:00
2025-03-08 13:44:05 +00:00
-------------------------------------------------------------
-- Random Reward
-------------------------------------------------------------
--- Grants a random reward from a predefined reward pool if the player is eligible.
2025-03-01 12:58:43 +00:00
---
2025-03-08 13:44:05 +00:00
--- Checks if the item qualifies for a reward, removes the item, then calculates a random reward based on rarity.
2025-03-01 12:58:43 +00:00
---
2025-03-08 13:44:05 +00:00
--- @param itemName string The item name to check.
2025-03-01 12:58:43 +00:00
---
---@usage
--- ```lua
--- getRandomReward("gold_ring")
--- ```
2025-03-08 13:44:05 +00:00
function getRandomReward ( itemName )
2025-03-01 12:58:43 +00:00
if Config.Rewards . RewardPool then
local reward = false
2025-03-08 13:44:05 +00:00
if type ( Config.Rewards . RewardItem ) == " string " then
Config.Rewards . RewardItem = { Config.Rewards . RewardItem }
end
2025-03-01 12:58:43 +00:00
for k , v in pairs ( Config.Rewards . RewardItem ) do
2025-03-08 13:44:05 +00:00
if v == itemName then
reward = true
break
end
2025-03-01 12:58:43 +00:00
end
if reward then
removeItem ( itemName , 1 )
local totalRarity = 0
2025-03-08 13:44:05 +00:00
for i = 1 , # Config.Rewards . RewardPool do
2025-03-01 12:58:43 +00:00
totalRarity += Config.Rewards . RewardPool [ i ] . rarity
end
2025-03-08 13:44:05 +00:00
debugPrint ( " ^6Bridge^7: ^3getRandomReward^7: Total Rarity ' " .. totalRarity .. " ' " )
2025-03-01 12:58:43 +00:00
local randomNum = math.random ( 1 , totalRarity )
2025-03-08 13:44:05 +00:00
debugPrint ( " ^6Bridge^7: ^3getRandomReward^7: Random Number ' " .. randomNum .. " ' " )
2025-03-01 12:58:43 +00:00
local currentRarity = 0
2025-03-08 13:44:05 +00:00
for i = 1 , # Config.Rewards . RewardPool do
2025-03-01 12:58:43 +00:00
currentRarity += Config.Rewards . RewardPool [ i ] . rarity
if randomNum <= currentRarity then
debugPrint ( " ^6Bridge^7: ^3getRandomReward^7: ^2Selected toy ^7'^6 " .. Config.Rewards . RewardPool [ i ] . item .. " ^7' " )
addItem ( Config.Rewards . RewardPool [ i ] . item , 1 )
return
end
end
end
end
end
2025-03-08 13:44:05 +00:00
-------------------------------------------------------------
-- Carry Capacity Check
-------------------------------------------------------------
--- Checks if a player can carry the specified items based on weight.
2025-03-01 12:58:43 +00:00
---
2025-03-08 13:44:05 +00:00
--- Calculates the current total weight in the player's inventory and determines whether adding the new items would exceed capacity.
2025-03-01 12:58:43 +00:00
---
2025-03-08 13:44:05 +00:00
--- @param itemTable table A table where keys are item names and values are required quantities.
--- @param src number The player's source ID.
--- @return table A table mapping each item to a boolean indicating if it can be carried.
2025-03-01 12:58:43 +00:00
---
2025-03-08 13:44:05 +00:00
--- @usage
--- local carryCheck = canCarry({ ["health_potion"] = 2, ["mana_potion"] = 3 }, playerId)
--- if carryCheck["health_potion"] and carryCheck["mana_potion"] then
--- -- Player can carry items.
2025-03-01 12:58:43 +00:00
--- else
2025-03-08 13:44:05 +00:00
--- -- Notify player.
2025-03-01 12:58:43 +00:00
--- end
function canCarry ( itemTable , src )
local resultTable = { }
if src then
if isStarted ( OXInv ) then
for k , v in pairs ( itemTable ) do
resultTable [ k ] = exports [ OXInv ] : CanCarryItem ( src , k , v )
end
elseif isStarted ( QSInv ) then
for k , v in pairs ( itemTable ) do
2025-03-08 13:44:05 +00:00
resultTable [ k ] = exports [ QSInv ] : CanCarryItem ( src , k , v )
2025-03-01 12:58:43 +00:00
end
elseif isStarted ( CoreInv ) then
2025-03-08 13:44:05 +00:00
for k , v in pairs ( itemTable ) do
resultTable [ k ] = exports [ CoreInv ] : canCarry ( src , k , v )
end
2025-03-01 12:58:43 +00:00
2025-03-08 13:44:05 +00:00
elseif isStarted ( CodeMInv ) then --- This really needs updating, their docs are confusing..
local items = getPlayerInv ( src )
local totalWeight = 0
if not items then return false end
for _ , item in pairs ( items ) do
totalWeight += ( item.weight * item.amount )
end
2025-03-01 12:58:43 +00:00
for k , v in pairs ( itemTable ) do
2025-03-08 13:44:05 +00:00
local itemInfo = Items [ k ]
if not itemInfo then
resultTable [ k ] = true
else
resultTable [ k ] = ( totalWeight + ( itemInfo.weight * v ) ) <= InventoryWeight
end
2025-03-01 12:58:43 +00:00
end
elseif isStarted ( OrigenInv ) then
for k , v in pairs ( itemTable ) do
resultTable [ k ] = exports [ OrigenInv ] : canCarryItem ( src , k , v )
end
2025-04-30 17:53:26 +01:00
elseif isStarted ( TgiannInv ) then
for k , v in pairs ( itemTable ) do
resultTable [ k ] = exports [ TgiannInv ] : CanCarryItem ( source , k , v )
end
2025-04-07 20:52:59 +01:00
elseif isStarted ( QBInv ) then
for k , v in pairs ( itemTable ) do
resultTable [ k ] = exports [ QBInv ] : CanAddItem ( src , k , v )
end
elseif isStarted ( PSInv ) then
2025-03-08 13:44:05 +00:00
local items = getPlayerInv ( src )
local totalWeight = 0
2025-03-01 12:58:43 +00:00
if not items then return false end
2025-03-08 13:44:05 +00:00
for _ , item in pairs ( items ) do
totalWeight += ( item.weight * item.amount )
end
2025-03-01 12:58:43 +00:00
for k , v in pairs ( itemTable ) do
local itemInfo = Items [ k ]
if not itemInfo and not Player.Offline then
resultTable [ k ] = true
else
2025-03-08 13:44:05 +00:00
resultTable [ k ] = ( totalWeight + ( itemInfo.weight * v ) ) <= InventoryWeight
2025-03-01 12:58:43 +00:00
end
2025-04-07 20:52:59 +01:00
end
2025-03-01 12:58:43 +00:00
end
end
return resultTable
2025-03-26 21:43:48 +00:00
end
-------------------------------------------------------------
-- Server Callback Registration
-------------------------------------------------------------
2025-04-29 12:26:49 +01:00
AuthEvent = nil
2025-03-26 21:43:48 +00:00
currentToken = nil
if isServer ( ) then
createCallback ( getScript ( ) .. " :server:canCarry " , function ( source , itemTable )
local result = canCarry ( itemTable , source )
return result
end )
local AuthEvent = getScript ( ) .. " : " .. keyGen ( ) .. keyGen ( ) .. keyGen ( ) .. keyGen ( ) .. " : " .. keyGen ( ) .. keyGen ( ) .. keyGen ( ) .. keyGen ( )
validTokens = validTokens or { }
createCallback ( AuthEvent , function ( source )
local src = source
local token = keyGen ( ) .. keyGen ( ) .. keyGen ( ) .. keyGen ( ) -- Use a secure random generator here
2025-04-07 20:52:59 +01:00
debugPrint ( GetInvokingResource ( ) )
if GetInvokingResource ( ) and GetInvokingResource ( ) ~= getScript ( ) and GetInvokingResource ( ) ~= " qb-core " then
debugPrint ( " ^1Error^7: ^1Possible exploit^7, ^1vital function was called from an external resource^7 " )
return " "
end
2025-03-26 21:43:48 +00:00
debugPrint ( " ^1Auth^7:^2 Player Source^7: " .. src .. " ^2requested new token^7: " , token )
validTokens [ src ] = token
timeOutAuth ( validTokens [ src ] , src ) -- Give script 10 seconds, then clear token
return token
end )
function timeOutAuth ( token , src )
local token = token
SetTimeout ( 10000 , function ( )
if token == validTokens [ src ] then
print ( " ^1--------------------------------------------^7 " )
print ( " ^7Clearing token for player ^1 " .. src .. " ^7 " , token )
print ( " ^7This shouldn't happen unless a token has been called by a player or script and it hasn't been used " )
print ( " ^1--------------------------------------------^7 " )
end
end )
end
RegisterNetEvent ( getScript ( ) .. " :clearAuthToken " , function ( )
local src = source
debugPrint ( " ^1Auth^7: ^2Manually removing token for Player Source^7: " , src , validTokens [ src ] )
validTokens [ src ] = nil
end )
receivedEvent = { }
createCallback ( getScript ( ) .. " :callback:GetAuthEvent " , function ( source )
local src = source
2025-04-07 20:52:59 +01:00
debugPrint ( GetInvokingResource ( ) )
if GetInvokingResource ( ) and GetInvokingResource ( ) ~= getScript ( ) and GetInvokingResource ( ) ~= " qb-core " then
debugPrint ( " ^1Error^7: ^1Possible exploit^7, ^1vital callback was called from an external resource^7 " )
return " "
end
2025-03-26 21:43:48 +00:00
debugPrint ( " ^1Auth^7: ^2Player Source^7: " .. src .. " ^2requested ^3AuthEvent^7 " , AuthEvent )
if not receivedEvent [ src ] then receivedEvent [ src ] = true
return AuthEvent
else
print ( " ^1Auth^7: ^1Player ^7 " .. src .. " ^1tried to request auth token more than once^7 " )
return " "
end
end )
else
2025-04-29 12:26:49 +01:00
onPlayerLoaded ( function ( )
debugPrint ( " ^1Auth^7: ^2Requesting ^3Auth Event^7 " )
AuthEvent = triggerCallback ( getScript ( ) .. " :callback:GetAuthEvent " )
end , true )
2025-03-26 21:43:48 +00:00
end