⚠️ Note: This description is not always up to date.
Many new improvements and features have been added, so the information below may not be fully accurate.
For the latest and most accurate updates, please join our Official Discord — all recent changes and announcements are posted there.
[QB INVENTORY REWORK] a modern, feature-rich, and optimized inventory system for the QBCore Framework.
QB Inventory Rework is a complete replacement for the default QBCore inventory, designed to provide a more immersive and functional experience for players.
- Cash as an item
- New give system
- Rob Player
- Decay system for food & drinks
- Weapon attachment panel
- New 2-panel UI layout
- Toggle blur effect
- Code modifications for optimization & security
Join the Official AP Code Discord
Ensure you have the following resources installed and running before installing qb-Inventory rework :
Follow these steps very carefully to ensure a smooth installation.
- Download this resource's files
- Rename qb-inventory-rework to qb-inventory
- delete your old inventory and replace with
qb-inventoryrework
🚨 IMPORTANT: Always create a backup of any file you are about to edit!
You need to edit the qb-core/server/player.lua file to integrate the money-as-an-item system.
Open qb-core/server/player.lua and find the following functions:
self.Functions.AddMoneyself.Functions.RemoveMoneyself.Functions.SetMoneyself.Functions.GetMoney
Delete all four of these functions entirely and replace them with the code block below:
--------------------------EDITED BY APCODE START--------------------------
function self.Functions.AddMoney(moneytype, amount, reason)
reason = reason or 'unknown'
moneytype = moneytype:lower()
amount = tonumber(amount)
if amount < 0 then return end
if not self.PlayerData.money[moneytype] then return false end
if moneytype == 'cash' and GetResourceState('qb-inventory') ~= 'missing' and exports['qb-inventory']:IsCashAsItem() then
if exports['qb-inventory']:AddCash(self.PlayerData.source, amount) then
local newCashAmount = exports['qb-inventory']:GetItemCount(self.PlayerData.source, 'cash') or 0
self.PlayerData.money.cash = newCashAmount
if not self.Offline then
self.Functions.UpdatePlayerData()
if amount > 100000 then
TriggerEvent('qb-log:server:CreateLog', 'playermoney', 'AddMoney (as item)', 'lightgreen', '**' .. GetPlayerName(self.PlayerData.source) .. ' (citizenid: ' .. self.PlayerData.citizenid .. ' | id: ' .. self.PlayerData.source .. ')** $' .. amount .. ' (cash) added, reason: ' .. reason, true)
else
TriggerEvent('qb-log:server:CreateLog', 'playermoney', 'AddMoney (as item)', 'lightgreen', '**' .. GetPlayerName(self.PlayerData.source) .. ' (citizenid: ' .. self.PlayerData.citizenid .. ' | id: ' .. self.PlayerData.source .. ')** $' .. amount .. ' (cash) added, reason: ' .. reason)
end
TriggerClientEvent('hud:client:OnMoneyChange', self.PlayerData.source, moneytype, amount, false)
TriggerClientEvent('QBCore:Client:OnMoneyChange', self.PlayerData.source, moneytype, amount, 'add', reason)
TriggerEvent('QBCore:Server:OnMoneyChange', self.PlayerData.source, moneytype, amount, 'add', reason)
end
return true
else
return false
end
end
self.PlayerData.money[moneytype] = self.PlayerData.money[moneytype] + amount
if not self.Offline then
self.Functions.UpdatePlayerData()
if amount > 100000 then
TriggerEvent('qb-log:server:CreateLog', 'playermoney', 'AddMoney', 'lightgreen', '**' .. GetPlayerName(self.PlayerData.source) .. ' (citizenid: ' .. self.PlayerData.citizenid .. ' | id: ' .. self.PlayerData.source .. ')** $' .. amount .. ' (' .. moneytype .. ') added, new ' .. moneytype .. ' balance: ' .. self.PlayerData.money[moneytype] .. ' reason: ' .. reason, true)
else
TriggerEvent('qb-log:server:CreateLog', 'playermoney', 'AddMoney', 'lightgreen', '**' .. GetPlayerName(self.PlayerData.source) .. ' (citizenid: ' .. self.PlayerData.citizenid .. ' | id: ' .. self.PlayerData.source .. ')** $' .. amount .. ' (' .. moneytype .. ') added, new ' .. moneytype .. ' balance: ' .. self.PlayerData.money[moneytype] .. ' reason: ' .. reason)
end
TriggerClientEvent('hud:client:OnMoneyChange', self.PlayerData.source, moneytype, amount, false)
TriggerClientEvent('QBCore:Client:OnMoneyChange', self.PlayerData.source, moneytype, amount, 'add', reason)
TriggerEvent('QBCore:Server:OnMoneyChange', self.PlayerData.source, moneytype, amount, 'add', reason)
end
return true
end
function self.Functions.RemoveMoney(moneytype, amount, reason)
reason = reason or 'unknown'
moneytype = moneytype:lower()
amount = tonumber(amount)
if amount < 0 then return end
if not self.PlayerData.money[moneytype] then return false end
if moneytype == 'cash' and GetResourceState('qb-inventory') ~= 'missing' and exports['qb-inventory']:IsCashAsItem() then
if exports['qb-inventory']:RemoveCash(self.PlayerData.source, amount, reason) then
local newCashAmount = exports['qb-inventory']:GetItemCount(self.PlayerData.source, 'cash') or 0
self.PlayerData.money.cash = newCashAmount
if not self.Offline then
self.Functions.UpdatePlayerData()
if amount > 100000 then
TriggerEvent('qb-log:server:CreateLog', 'playermoney', 'RemoveMoney (as item)', 'red', '**' .. GetPlayerName(self.PlayerData.source) .. ' (citizenid: ' .. self.PlayerData.citizenid .. ' | id: ' .. self.PlayerData.source .. ')** $' .. amount .. ' (cash) removed, reason: ' .. reason, true)
else
TriggerEvent('qb-log:server:CreateLog', 'playermoney', 'RemoveMoney (as item)', 'red', '**' .. GetPlayerName(self.PlayerData.source) .. ' (citizenid: ' .. self.PlayerData.citizenid .. ' | id: ' .. self.PlayerData.source .. ')** $' .. amount .. ' (cash) removed, reason: ' .. reason)
end
TriggerClientEvent('hud:client:OnMoneyChange', self.PlayerData.source, moneytype, amount, true)
TriggerClientEvent('QBCore:Client:OnMoneyChange', self.PlayerData.source, moneytype, amount, 'remove', reason)
TriggerEvent('QBCore:Server:OnMoneyChange', self.PlayerData.source, moneytype, amount, 'remove', reason)
end
return true
else
return false
end
end
for _, mtype in pairs(QBCore.Config.Money.DontAllowMinus) do
if mtype == moneytype then
if (self.PlayerData.money[moneytype] - amount) < 0 then
return false
end
end
end
if self.PlayerData.money[moneytype] - amount < QBCore.Config.Money.MinusLimit then
return false
end
self.PlayerData.money[moneytype] = self.PlayerData.money[moneytype] - amount
if not self.Offline then
self.Functions.UpdatePlayerData()
if amount > 100000 then
TriggerEvent('qb-log:server:CreateLog', 'playermoney', 'RemoveMoney', 'red', '**' .. GetPlayerName(self.PlayerData.source) .. ' (citizenid: ' .. self.PlayerData.citizenid .. ' | id: ' .. self.PlayerData.source .. ')** $' .. amount .. ' (' .. moneytype .. ') removed, new ' .. moneytype .. ' balance: ' .. self.PlayerData.money[moneytype] .. ' reason: ' .. reason, true)
else
TriggerEvent('qb-log:server:CreateLog', 'playermoney', 'RemoveMoney', 'red', '**' .. GetPlayerName(self.PlayerData.source) .. ' (citizenid: ' .. self.PlayerData.citizenid .. ' | id: ' .. self.PlayerData.source .. ')** $' .. amount .. ' (' .. moneytype .. ') removed, new ' .. moneytype .. ' balance: ' .. self.PlayerData.money[moneytype] .. ' reason: ' .. reason)
end
TriggerClientEvent('hud:client:OnMoneyChange', self.PlayerData.source, moneytype, amount, true)
if moneytype == 'bank' then
TriggerClientEvent('qb-phone:client:RemoveBankMoney', self.PlayerData.source, amount)
end
TriggerClientEvent('QBCore:Client:OnMoneyChange', self.PlayerData.source, moneytype, amount, 'remove', reason)
TriggerEvent('QBCore:Server:OnMoneyChange', self.PlayerData.source, moneytype, amount, 'remove', reason)
end
return true
end
function self.Functions.SetMoney(moneytype, amount, reason)
reason = reason or 'unknown'
moneytype = moneytype:lower()
amount = tonumber(amount)
if amount < 0 then return false end
if not self.PlayerData.money[moneytype] then return false end
if moneytype == 'cash' and GetResourceState('qb-inventory') ~= 'missing' and exports['qb-inventory']:IsCashAsItem() then
local currentCash = exports['qb-inventory']:GetItemCount(self.PlayerData.source, 'cash') or 0
local difference = amount - currentCash
local success = false
if difference > 0 then
success = exports['qb-inventory']:AddItem(self.PlayerData.source, 'cash', difference, nil, {}, 'setmoney_command')
elseif difference < 0 then
success = exports['qb-inventory']:RemoveItem(self.PlayerData.source, 'cash', math.abs(difference), nil, 'setmoney_command')
else
success = true
end
if success then
local newTotalCash = exports['qb-inventory']:GetItemCount(self.PlayerData.source, 'cash') or 0
self.PlayerData.money.cash = newTotalCash
if not self.Offline then
self.Functions.UpdatePlayerData()
local difference = newTotalCash - (currentCash or 0)
TriggerEvent('qb-log:server:CreateLog', 'playermoney', 'SetMoney (as item)', 'green', '**' .. GetPlayerName(self.PlayerData.source) .. ' (citizenid: ' .. self.PlayerData.citizenid .. ' | id: ' .. self.PlayerData.source .. ')** cash set to $' .. newTotalCash .. ', reason: ' .. reason)
TriggerClientEvent('hud:client:OnMoneyChange', self.PlayerData.source, moneytype, math.abs(difference), difference < 0)
TriggerClientEvent('QBCore:Client:OnMoneyChange', self.PlayerData.source, moneytype, newTotalCash, 'set', reason)
TriggerEvent('QBCore:Server:OnMoneyChange', self.PlayerData.source, moneytype, newTotalCash, 'set', reason)
TriggerClientEvent('qb-inventory:client:updateCash', self.PlayerData.source, newTotalCash)
end
end
return success
end
local difference = amount - self.PlayerData.money[moneytype]
self.PlayerData.money[moneytype] = amount
if not self.Offline then
self.Functions.UpdatePlayerData()
TriggerEvent('qb-log:server:CreateLog', 'playermoney', 'SetMoney', 'green', '**' .. GetPlayerName(self.PlayerData.source) .. ' (citizenid: ' .. self.PlayerData.citizenid .. ' | id: ' .. self.PlayerData.source .. ')** $' .. amount .. ' (' .. moneytype .. ') set, new ' .. moneytype .. ' balance: ' .. self.PlayerData.money[moneytype] .. ' reason: ' .. reason)
TriggerClientEvent('hud:client:OnMoneyChange', self.PlayerData.source, moneytype, math.abs(difference), difference < 0)
TriggerClientEvent('QBCore:Client:OnMoneyChange', self.PlayerData.source, moneytype, amount, 'set', reason)
TriggerEvent('QBCore:Server:OnMoneyChange', self.PlayerData.source, moneytype, amount, 'set', reason)
end
return true
end
function self.Functions.GetMoney(moneytype)
if not moneytype then return false end
moneytype = moneytype:lower()
if moneytype == 'cash' and GetResourceState('qb-inventory') ~= 'missing' and exports['qb-inventory']:IsCashAsItem() then
local cashCount = exports['qb-inventory']:GetItemCount(self.PlayerData.source, 'cash') or 0
if self.PlayerData.money.cash ~= cashCount then
self.PlayerData.money.cash = cashCount
end
return cashCount
end
return self.PlayerData.money[moneytype]
end
-----------------------------EDITED BY APCODE END--------------------------Still in qb-core/server/player.lua, find the function QBCore.Player.CheckPlayerData. Delete this function and replace it with the code block below. This change ensures the player's inventory is loaded correctly when they join the server.
--------------------------EDITED BY APCODE START--------------------------
function QBCore.Player.CheckPlayerData(source, PlayerData)
PlayerData = PlayerData or {}
local Offline = not source
if source then
PlayerData.source = source
PlayerData.license = PlayerData.license or QBCore.Functions.GetIdentifier(source, 'license')
PlayerData.name = GetPlayerName(source)
end
local validatedJob = false
if PlayerData.job and PlayerData.job.name ~= nil and PlayerData.job.grade and PlayerData.job.grade.level ~= nil then
local jobInfo = QBCore.Shared.Jobs[PlayerData.job.name]
if jobInfo then
local jobGradeInfo = jobInfo.grades[tostring(PlayerData.job.grade.level)]
if jobGradeInfo then
PlayerData.job.label = jobInfo.label
PlayerData.job.grade.name = jobGradeInfo.name
PlayerData.job.payment = jobGradeInfo.payment
PlayerData.job.grade.isboss = jobGradeInfo.isboss or false
PlayerData.job.isboss = jobGradeInfo.isboss or false
validatedJob = true
end
end
end
if validatedJob == false then
PlayerData.job = nil
end
local validatedGang = false
if PlayerData.gang and PlayerData.gang.name ~= nil and PlayerData.gang.grade and PlayerData.gang.grade.level ~= nil then
local gangInfo = QBCore.Shared.Gangs[PlayerData.gang.name]
if gangInfo then
local gangGradeInfo = gangInfo.grades[tostring(PlayerData.gang.grade.level)]
if gangGradeInfo then
PlayerData.gang.label = gangInfo.label
PlayerData.gang.grade.name = gangGradeInfo.name
PlayerData.gang.payment = gangGradeInfo.payment
PlayerData.gang.grade.isboss = gangGradeInfo.isboss or false
PlayerData.gang.isboss = gangGradeInfo.isboss or false
validatedGang = true
end
end
end
if validatedGang == false then
PlayerData.gang = nil
end
applyDefaults(PlayerData, QBCore.Config.Player.PlayerDefaults)
if GetResourceState('qb-inventory') ~= 'missing' then
PlayerData.items = exports['qb-inventory']:LoadInventory(PlayerData.source, PlayerData.citizenid)
if exports['qb-inventory']:IsCashAsItem() then
if PlayerData.items then
local cashInInventory = 0
for _, item in pairs(PlayerData.items) do
if item and item.name == 'cash' then
cashInInventory = cashInInventory + item.amount
end
end
PlayerData.money.cash = cashInInventory
end
end
end
return QBCore.Player.CreatePlayer(PlayerData, Offline)
end
--------------------------EDITED BY APCODE END--------------------------['cash'] = {
name = 'cash',
label = 'Cash',
weight = 0,
type = 'item',
image = 'cash.png',
unique = false,
useable = false,
shouldClose = false,
description = 'Don\'t spend it all in one place.'
},To make food and drinks perishable, you need to add a decay rate to them. Open qb-core/shared/items.lua and for every food and drink item, add the following line inside its definition:
decayrate = 86400.0
EXAMPLE :
['sandwich'] = {
name = 'sandwich',
label = 'Sandwich',
weight = 200,
type = 'item',
image = 'sandwich.png',
unique = false,
useable = true,
shouldClose = true,
description = 'Nice bread for your stomach',
decayrate = 86400.0
},If you encounter any issues, require assistance, or wish to suggest new features, please join our official Discord server. We're here to help!
Join the Official AP Code Discord
All major configuration options can be found in the config.lua file. You can adjust:
- The default keybind to open the inventory.
- Maximum weight and slot counts.
- Storage sizes for trunks, gloveboxes, and drops.
- Items sold in Vending Machines.
- And much more.


