Skip to main content

Third-party inventories

danger

This script is not guaranteed to be comptabile with inventory systems that are not either qb-inventory or ox_inventory. It contains customizable functions that enable POTENTIAL compatability with third-party inventories that operate SIMILARLY to ox_inventory or qb_inventory.

caution

Never make changes to ANY script without making a backup first, you never know what might happen!

Adding Inventory Images

Upload your image files to your inventory resource

Our first step for integrating an unsupported third-party inventory will be by adding images for our items. This may be contained within the HTML files for the script similar to qb-inventory or ox_inventory, or could potentially be located in a images directory in the client-side folder. You may need to keep track of the images names to update the items in your specific inventory script.

Understanding Metadata in r14-evidence

The metadata supplied to evidence bag creation contains a wide-array of various fields to record the different information types supplied with different evidence bag types. The first main metadata field created will be the type such as 'blood', 'casing', or carcasing that is used by qb-inventory to sort what metadata to display. When using ox_inventory, this is changed to evtype in order to not display it in the inventory screen.

After this, there are a currently sixteen fields which display specific information about the piece of evidence the bag respresents. This includes things like the label describing what is in the bag. The list is defined in the evmeta table contained in r14-evidence/server/main.lua which defines the label and order for the ox_inventory metadata conversion process. Fields without a label are displayed without a preceeding entry, and are built with them included such as iteminfo which is built based on the item contained in the bag.

Metadata Fields and Labels
    local evmeta = {
[1] = {field = 'label', label = 'Type',},
[2] = {field = 'tracking', label = 'Tracking ID',},
[3] = {field = 'date', label = 'Date',},
[4] = {field = 'ammolabel', label = 'Caliber',},
[5] = {field = 'serie', label = 'Serial',},
[6] = {field = 'serial', label = 'Serial',},
[7] = {field = 'bloodtype', label = 'Bloodtype',},
[8] = {field = 'fingerprint', label = 'Fingeprint',},
[9] = {field = 'dnalabel', label = 'DNA Code',},
[10] = {field = 'vehname', label = 'Vehicle Model',},
[11] = {field = 'vehcolor', label = 'Vehicle Color',},
[12] = {field = 'plate', label = 'VIN Match',},
[13] = {field = 'result', label = 'Result',},
[14] = {field = 'iteminfo'},
[15] = {field = 'street', label = 'Collected',},
[16] = {field = 'description'},
}

If you can't display metadata in your inventory script, it will simply make it much more difficult for players to interact with evidence bags as they will need to use the item to see what is contained in it, rather than being able to at a glance tell what it is.

Writing Custom Inventory Functions

As of 3/25/2023, there are five server-side inventory functions and two client-side inventory functions defined in the r14-evidence config which governs how the script interacts with the inventory system. If you do not have a moderate to advanced understanding of scripting, it is recommended that you contact a developer to write this integration. If you are going to attempt to do it yourself, please consult any documentation or the original developer of the inventory for support. Below we can see the config functions we use as a bridge, and can help guide you writing your own code.

DO NOT ALTER the function arguments unless you edit the actual script to change what is sent to these functions, you \ can use print() and json.encode() to help you figure out what is coming through these functions such as print(json.encode(item)) to print contents of the item table sent to Config.Functions.AddItem.

server-side inventory functions
    AddItem = function(source, item, amount, slot, data, nobox) -- this function adds an item to inventory
if Config.Inventory.Ox then
local success, response = ox_inventory:AddItem(source, item, amount, data, slot)

if success then return true end
elseif Config.Inventory.QB then
local Player = QBCore.Functions.GetPlayer(source)

if not nobox then TriggerClientEvent("inventory:client:ItemBox", source, QBCore.Shared.Items[item], "add") end

return Player.Functions.AddItem(item, amount, slot, data)
elseif Config.Inventory.Standalone then
-- there is nothing here, you must write it
end
end,
RemoveItem = function(source, item, amount, slot, nobox) -- removes an item from the player inventory
if Config.Inventory.Ox then
local success = ox_inventory:RemoveItem(source, item, amount, false, slot)

if success then return true end
elseif Config.Inventory.QB then
local Player = QBCore.Functions.GetPlayer(source)

if not nobox then TriggerClientEvent("inventory:client:ItemBox", source, QBCore.Shared.Items[item], "remove") end

return Player.Functions.RemoveItem(item, amount, slot)
elseif Config.Inventory.Standalone then
-- there is nothing here, you must write it
end
end,
UpdateMetadata = function(source, slot, data) -- this function is used to update an items metadata
if Config.Inventory.Ox then
ox_inventory:SetMetadata(source, slot, data)
elseif Config.Inventory.QB then
local Player = QBCore.Functions.GetPlayer(source)

Player.PlayerData.items[slot].info = data

Player.Functions.SetInventory(Player.PlayerData.items, true)
elseif Config.Inventory.Standalone then
-- there is nothing here, you must write it
end
end,
GetInventoryServer = function(source) -- this function should return the player inventory table
if Config.Inventory.Ox then
return ox_inventory:GetInventory(source)?.items
elseif Config.Inventory.QB then
local Player = QBCore.Functions.GetPlayer(source)

return Player.PlayerData.items
elseif Config.Inventory.Standalone then
-- there is nothing here, you must write it
end
end,
CreateUseableItem = function(name, cbfunc)
if Config.Inventory.Ox then
exports(name, cbfunc)
elseif Config.Inventory.QB then
QBCore.Functions.CreateUseableItem(name, cbfunc)
elseif Config.Inventory.Standalone then
-- there is nothing here, you must write it
end
end,

In addition to these server-side functions, we have two on the client-side of the script that are used to determine if a player has an item, as well as to fetch the caliber of the weapon being used by a player. You will need to create working versions of these functions for your inventory framework to enable r14-evidence functionality such as targeting and casing creation.

client-side inventory functions
    SearchInventoryClient = function(item, results) -- this function can be used to find an item in your inventory
if Config.Inventory.Ox then
local found = false

if ox_inventory:Search('count', item) > 0 then found = true end

if results then found = ox_inventory:Search('slots', item) end

return found
elseif Config.Inventory.QB then
local found = false
local PlayerData = QBCore.Functions.GetPlayerData()

for k, v in pairs(PlayerData.items) do
if v.name == item then found = true end
end

if results then found = PlayerData.items end

return found
elseif Config.Inventory.Standalone then
-- there is nothing here, you must write it
end
end,
GetCaliber = function(weapon)
if Config.Inventory.Ox then
if not OxWeapons then
OxWeapons = {}
for k, v in pairs(exports.ox_inventory:Items()) do if v.weapon then OxWeapons[v.hash or joaat(k)] = v.caliber end end
end

local caliber = OxWeapons and OxWeapons[weapon] or 'Unknown'

return caliber
elseif Config.Framework.QB or Config.Inventory.QB then
local caliber = QBCore.Shared.Weapons[weapon] and QBCore.Shared.Weapons[weapon].caliber or 'Unknown'

return caliber
elseif Config.Inventory.Standalone then
-- there is nothing here, you must write it
end
end,