Third-party inventories
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.
Never make changes to ANY script without making a backup first, you never know what might happen!
Adding Inventory Images
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.
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.
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.
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,