-- ====================================== -- INVENTORY BRIDGE (GLOBAL) -- suporta: -- ox_inventory -- qs-inventory -- qb-inventory -- esx (limitado) -- ====================================== Inventory = {} local InvType = nil CreateThread(function() local forced = tostring((Config and Config.Inventory) or 'auto'):lower() local hasOx = GetResourceState('ox_inventory') == 'started' local hasQs = GetResourceState('qs-inventory') == 'started' or GetResourceState('qs_inventory') == 'started' local hasQb = GetResourceState('qb-inventory') == 'started' local hasEsx = GetResourceState('es_extended') == 'started' if forced == 'ox' then InvType = hasOx and 'ox' or nil elseif forced == 'qs' or forced == 'qs-inventory' or forced == 'qs_inventory' then InvType = hasQs and 'qs' or nil elseif forced == 'qb' then InvType = hasQb and 'qb' or nil elseif forced == 'esx' then InvType = hasEsx and 'esx' or nil else -- auto if hasOx then InvType = 'ox' elseif hasQs then InvType = 'qs' elseif hasQb then InvType = 'qb' elseif hasEsx then InvType = 'esx' end end if not InvType then print('^1[INVENTORY]^7 Nenhum inventario detectado!') end print('^2[INVENTORY]^7 Bridge ativa:', InvType) end) local function qsCall(fn, ...) local ok, result = pcall(function(...) return exports['qs-inventory'][fn](exports['qs-inventory'], ...) end, ...) if ok then return result end ok, result = pcall(function(...) return exports['qs_inventory'][fn](exports['qs_inventory'], ...) end, ...) if ok then return result end return nil end local function ensureTable(v) if type(v) == 'table' then return v end if type(v) == 'string' and v ~= '' then local ok, decoded = pcall(json.decode, v) if ok and type(decoded) == 'table' then return decoded end end return {} end local function normalizeQsItem(item, fallbackSlot) if type(item) ~= 'table' then return nil end local name = item.name or item.item if type(name) ~= 'string' or name == '' then return nil end return { name = name, slot = tonumber(item.slot or fallbackSlot) or nil, amount = tonumber(item.amount or item.count or item.quantity) or 0, count = tonumber(item.amount or item.count or item.quantity) or 0, metadata = ensureTable(item.metadata or item.info or item.data), info = ensureTable(item.info or item.metadata or item.data) } end local function normalizeQsItems(raw) local out = {} if type(raw) ~= 'table' then return out end for k, v in pairs(raw) do local item = normalizeQsItem(v, k) if item then out[#out + 1] = item end end return out end -- ====================================== -- GET ITEM COUNT -- ====================================== function Inventory.GetItemCount(src, item) if InvType == 'ox' then return exports.ox_inventory:GetItemCount(src, item) or 0 end if InvType == 'qs' then local amount = qsCall('GetItemTotalAmount', src, item) if amount == nil then local it = qsCall('GetItemByName', src, item) amount = it and (it.amount or it.count) or 0 end return tonumber(amount) or 0 end if InvType == 'qb' then local Player = Framework.Functions.GetPlayer(src) if not Player then return 0 end local it = Player.Functions.GetItemByName(item) return it and it.amount or 0 end if InvType == 'esx' then local xPlayer = Framework.GetPlayerFromId(src) if not xPlayer then return 0 end local it = xPlayer.getInventoryItem(item) return it and it.count or 0 end return 0 end -- ====================================== -- ADD ITEM -- ====================================== function Inventory.AddItem(src, item, amount, metadata) if InvType == 'ox' then return exports.ox_inventory:AddItem(src, item, amount, metadata) end if InvType == 'qs' then local canCarry = qsCall('CanCarryItem', src, item, amount) if canCarry == false then return false, 'inventory_full' end -- qs variants differ by version; try common signatures in order. local ok = qsCall('AddItem', src, item, amount, false, metadata) if not ok then ok = qsCall('AddItem', src, item, amount, nil, metadata) end if not ok then ok = qsCall('AddItem', src, item, amount, metadata) end if not ok then ok = qsCall('GiveItemToPlayer', src, item, amount, metadata) end if not ok then ok = qsCall('GiveItemToPlayer', src, item, amount, false, metadata) end return ok and true or false end if InvType == 'qb' then local Player = Framework.Functions.GetPlayer(src) if not Player then return false end return Player.Functions.AddItem(item, amount, false, metadata) end if InvType == 'esx' then local xPlayer = Framework.GetPlayerFromId(src) if not xPlayer then return false end xPlayer.addInventoryItem(item, amount) return true end return false end -- ====================================== -- REMOVE ITEM -- ====================================== function Inventory.RemoveItem(src, item, amount, metadata, slot) if InvType == 'ox' then return exports.ox_inventory:RemoveItem(src, item, amount, metadata, slot) end if InvType == 'qs' then local ok = qsCall('RemoveItem', src, item, amount, slot) if ok == nil then ok = qsCall('RemoveItem', src, item, amount) end return ok and true or false end if InvType == 'qb' then local Player = Framework.Functions.GetPlayer(src) if not Player then return false end return Player.Functions.RemoveItem(item, amount) end if InvType == 'esx' then local xPlayer = Framework.GetPlayerFromId(src) if not xPlayer then return false end xPlayer.removeInventoryItem(item, amount) return true end return false end -- ====================================== -- SEARCH ITEM (SLOTS) -- ====================================== function Inventory.Search(src, searchType, item) if InvType == 'ox' then return exports.ox_inventory:Search(src, searchType, item) end if InvType == 'qs' then local items = qsCall('Search', src, searchType or 'slots', item) if items == nil then items = qsCall('Search', src, item) end if type(items) == 'number' then if searchType == 'count' then return items end items = nil end if type(items) == 'table' then local normalized = normalizeQsItems(items) if searchType == 'count' then local total = 0 for _, v in ipairs(normalized) do total = total + (tonumber(v.count) or 0) end return total end return normalized end local inv = Inventory.GetInventory(src) local out = {} local list = inv and (inv.items or inv) or nil if type(list) ~= 'table' then return out end for _, v in pairs(list) do local name = v.name or v.item if name == item then out[#out + 1] = { name = name, slot = v.slot, count = v.amount or v.count or 0, metadata = v.info or v.metadata or {} } end end return out end if InvType == 'qb' then local Player = Framework.Functions.GetPlayer(src) if not Player then return nil end local items = {} for _, v in pairs(Player.PlayerData.items or {}) do if v.name == item then items[#items + 1] = { slot = v.slot, count = v.amount, metadata = v.info } end end return items end return nil end -- ====================================== -- GET INVENTORY -- ====================================== function Inventory.GetInventory(src) if InvType == 'ox' then return exports.ox_inventory:GetInventory(src) end if InvType == 'qs' then local raw = qsCall('GetInventory', src) if type(raw) ~= 'table' then return { items = {} } end local candidates = raw.items or raw.inventory or raw.slots or raw return { items = normalizeQsItems(candidates), raw = raw } end if InvType == 'qb' then local Player = Framework.Functions.GetPlayer(src) if not Player then return nil end return { items = Player.PlayerData.items } end return nil end -- ====================================== -- SET METADATA -- ====================================== function Inventory.SetMetadata(src, slot, metadata) if InvType == 'ox' then return exports.ox_inventory:SetMetadata(src, slot, metadata) end if InvType == 'qs' then local ok = qsCall('SetItemMetadata', src, slot, metadata) if ok == nil then ok = qsCall('SetMetaData', src, slot, metadata) end if ok == nil then ok = qsCall('SetItemMetadata', src, slot, 'info', metadata) end if ok == nil then ok = qsCall('SetMetaData', src, slot, 'info', metadata) end return ok end end function Inventory.GetItemList() if InvType == 'ox' then return exports.ox_inventory:Items() or {} end if InvType == 'qs' then return qsCall('GetItemList') or {} end if InvType == 'qb' then local core = exports['qb-core']:GetCoreObject() return (core and core.Shared and core.Shared.Items) or {} end return {} end -- ====================================== -- REGISTER STASH -- ====================================== function Inventory.RegisterStash(id, label, slots, weight, ownerSrc) if InvType == 'ox' then exports.ox_inventory:RegisterStash(id, label, slots, weight, false) return true end if InvType == 'qs' then qsCall('RegisterStash', tonumber(ownerSrc) or 0, id, slots, weight) return true end return false end -- ====================================== -- OPEN STASH -- ====================================== function Inventory.OpenStash(src, stash) local stashId = stash if type(stash) == 'table' then stashId = stash.id end if not stashId or stashId == '' then return false end if InvType == 'ox' then TriggerClientEvent('ox_inventory:openInventory', src, 'stash', stashId) return true end if InvType == 'qs' or InvType == 'qb' or InvType == 'esx' then local payload = type(stash) == 'table' and stash or { id = stashId } payload.invType = InvType TriggerClientEvent('nord_crafting:client:openStash', src, payload) return true end return false end exports('GetInventoryType', function() return InvType end) exports('GetItemCount', function(src, item) if type(src) ~= 'number' or type(item) ~= 'string' or item == '' then return 0 end return Inventory.GetItemCount(src, item) end) exports('AddItem', function(src, item, amount, metadata) if type(src) ~= 'number' or type(item) ~= 'string' or item == '' then return false end amount = math.max(1, math.floor(tonumber(amount) or 1)) return Inventory.AddItem(src, item, amount, metadata) end) exports('RemoveItem', function(src, item, amount, metadata, slot) if type(src) ~= 'number' or type(item) ~= 'string' or item == '' then return false end amount = math.max(1, math.floor(tonumber(amount) or 1)) return Inventory.RemoveItem(src, item, amount, metadata, slot) end) exports('SearchInventory', function(src, searchType, item) if type(src) ~= 'number' or type(item) ~= 'string' or item == '' then return nil end return Inventory.Search(src, searchType or 'slots', item) end) exports('GetInventory', function(src) if type(src) ~= 'number' then return nil end return Inventory.GetInventory(src) end) exports('GetItemList', function() return Inventory.GetItemList() end)