Installation
Configure the inventory system, framework functions, vehicle storage, items, shops and death events.
Required dependencies
Required for Lua 5.4 and escrow support.
Database storage used by the inventory resource.
Default death-event integration; replaceable with another server-side event.
Configuration guide
danger
This resource requires additional configuration. Follow each section below to connect it to your server systems.
Adding faction safes
Config.FactionSafes = {
{
name = 'police',
position = vector3(3324.2, 5166.1, 18.4), -- Safe position
size = 100, -- Maximum safe weight
slots = 40, -- Maximum safe slots
header = 'Police-Safe', -- Inventory header name (when opened)
distance = 3 -- Distance to be able to open.
}
}
Vehicles and database rows
Q: Why do I have to define the SQL rows here?
A: The previous version loaded vehicle inventories when they were opened. It relied on the client to identify the vehicle type, and the weight was assigned afterward on the server.
info
Inventories are now loaded together with the database data. This makes it easier to identify each vehicle model and validate its plate safely.
Config.VehicleMysql = {
tablename = 'vehicles', -- Table name of the vehicles
platerow = 'plate', -- Whats the row name of the plate inside the 'vehicles' table?
modelrow = 'model', -- Whats the row name of the model inside the 'vehicles' table?
trunkSlots = 40, -- Default value if vehicle model is not present in Config.Vehicles, slots amount for vehicle inventories (TRUNK)
gloveboxSlots = 40, -- Default value if vehicle model is not present in Config.Vehicles, Slots amount for vehicle inventories (GLOVEBOX)
trunkSize = 100, -- Default value if vehicle model is not present in Config.Vehicles
gloveboxSize = 10 -- Default value if vehicle model is not present in Config.Vehicles
}
Death event
If you do not use the default CFX baseevents resource, identify the event provided by your player-death system and configure its name here.
danger
If this is not configured correctly, inventory items will not be deleted when the player dies.
Config.DeathEvent = 'baseevents:onPlayerDied'
Modify the GetPlayerFaction function
Connect this function to your faction getter. Otherwise, players will not be able to open faction safes.
--- Get the Player's Faction
---@param source string | number PlayerSrc
---@return string
Utils.GetPlayerFaction = function(source)
return 'police'
end
Registering items
- You do not need to add every argument to the functions.
- Omitted arguments use their default values.
-- Example(s)
ItemController.registerItem('bread', "Bread", false, true, false, 5, "Bread is tasty..")
ItemController.registerItem('weapon_pistol', 'Pistol', true, false, true, 2.0)
ItemController.registerItem('cabbage', 'Cabbage')
--- Registers items so they can be added later.
---@param item string
---@param formatname string
---@param tradable boolean Whether the item can be traded and dropped.
---@param stackable boolean Whether the item can be stacked.
---@param candelete boolean Whether the system can delete the item on death.
---@param weight number Item weight; decimal values such as 0.25 are supported.
---@param description string Optional item description.
---@param defaultVariables table Default variables assigned when the item is added.
ItemController.registerItem = function
(
item,
formatname,
tradable,
stackable,
candelete,
weight,
description,
defaultVariables
)
Registering usable items
- Before registering a usable-item event, define the item.
- These events receive two arguments: the player source and the slot being used.
- To remove an item after use, pass the used slot to the
x_y:removeItemfunction.
ItemController.registerUsableItem('bread', function(source, slot)
local playerInventory = StorageController.getPlayerInventory(source)
if playerInventory then
playerInventory:removeItem('bread', 1, slot)
end
end)
-- For weapons
ItemController.registerUsableItem('weapon_pistol', function(source)
TriggerClientEvent(Config.Events.use_weapon, source, 'weapon_pistol')
end)
Declaring new vehicle weight(s) in config
- Vehicles not present in
Config.Vehiclesuse the default weights and slot counts. - You do not need to provide all four table keys. For example, you can configure only the trunk.
Config.Vehicles = {
blade = {
trunk = 200, -- Maximum weight
glovebox = 150, -- Maximum weight
trunkslots = 20, -- Maximum slots
gloveboxslots = 20 -- Maximum slots
},
infernus = {
trunk = 15
}
}
Using the inventory with multicharacter resources
- Modify the
Utils.GetIdentifierfunction to match your multicharacter system.
--- Get the Player's identifier.
---- If you use a custom multicharacter resource, adapt this function to your needs.
---@param source string | number PlayerSrc
---@return string
Utils.GetIdentifier = function(source)
if not Utils.PlayerExist(source) then
return
end
for k, v in pairs(GetPlayerIdentifiers(source)) do
if string.match(v, 'license:') then
return string.gsub(v, 'license:', '')
end
end
return "UNKNOWN_IDENTIFIER"
end
Creating shops
caution
Assign a unique UID to every shop. Registering two shops with the same UID causes an error and does not overwrite the first shop.
Why does each shop need a UID?
If you use a shop business system, you can connect its MySQL identifier to the shop UID to track purchases. This requires additional integration.
Adding shop images
cef/img/shopimages/example-drinks.png
Shops:__init__({
uid = 'grocery-1',
position = vector3(3324.2, 5166.1, 18.4),
shopname = 'Grocery Store',
shopimage = 'grocery.png',
tables = {
{
name = 'Foods',
categoryimage = 'example-category.png',
categories = {
{
name = 'Sandwiches',
items = {
{
item = 'sandwich',
price = 20
}
}
},
{
name = 'Vegetables',
items = {
{
item = 'cabbage',
price = 35
}
}
}
}
}
}
})
Dropped items
You have two options for dropping an item:
- Drag the item to the Drop button.
- Press shift and drag it out to the world.
info
Dropped items use a single model because individual models could fall through the world. You can change the shared model if needed.
Config.Dropped = {
remainOnGround = 20, -- Minutes to remain the item on the ground.
model = 'ba_prop_battle_ps_box_01', -- Dropped item model.
textRange = 6, -- Text rendering max range.
HudPickupRange = 4, -- Pickup range (to be showed in the CEF/NUI)
keyPickupRange = 2, -- Pickup range with key.
pickupKey = 38, -- Pickup control key (**IsControlJustPressed**)
streamRange = 15, -- Stream range of the objects.
streamUpdater = 1000, -- How often update the streamed objects. (for loop)
EnableDropFromVehicle = false -- Enable or disable dropping out items from any vehicle.
}
Aiming / Raycasting / Trade
info
When AimConfig.enabled is set to true, holding Shift activates the raycasting system.
Raycasting currently supports two features:
- Trading items with a target player.
- Dropping items to the ground.
Vehicle targeting was planned but is not included.
Config.AimConfig = {
enabled = true, -- Enable or disable the entire raycast system.
enableKey = 21, -- Shift (Sprint / Run)
distance = 5, -- Raycast maximum distance
renderMS = 10, -- Raycast rendering speed MS
EnableDrawLine = true,
EnableSprite = true,
EnableMeters = true,
PlayerSpriteDict = 'mpinventory', -- Texture dictory. What to show when targetPlayer is hovered?
PlayerSpriteName = 'mp_specitem_ped', -- Texture name. What to show when targetPlayer is hovered?
DropSpriteDict = 'mpinventory', -- Texture dictory. What to show when the ground is hovered?
DropSpriteName = 'mp_arrow' -- Texture name. What to show when the ground is hovered?
}
Weapons
Weapons use the same ammunition system, so magazines do not need to be applied separately to the character.
danger
Why is the weapon deleted after the player fires?
This occurs when the item name does not match the weapon name. Register weapons using their actual names, such as weapon_pistol, so GetHashKey can resolve them correctly.
ItemController.registerItem('weapon_pistol', 'Pistol', true, false, true, 2.0)
ItemController.registerUsableItem('weapon_pistol', function(source)
TriggerClientEvent(Config.Events.use_weapon, source, 'weapon_pistol')
end)
Config.Weapons = {
['WEAPON_PISTOL'] = '9mm_rounds',
['WEAPON_PISTOL50'] = '556_rounds',
['WEAPON_STUNGUN'] = {},
['WEAPON_KNIFE'] = {}
}
Server event listeners
Config.ServerEvents = {
item_defined = 'aquiver-invapi:item-defined',
player_item_added = 'aquiver-invapi:item-added-toplayer',
player_item_removed = 'aquiver-invapi:item-removed-player'
}
AddEventHandler(Config.ServerEvents.item_defined, function(itemTable)
print(string.format('invapi-item-defined: %s', json.encode(itemTable)))
end)
AddEventHandler(Config.ServerEvents.player_item_added, function(source, itemTable, quantity)
print(string.format('invapi-item-added-toplayer: %s quantity: %s', json.encode(itemTable), quantity))
end)
AddEventHandler(Config.ServerEvents.player_item_removed, function(source, item, quantity)
print(string.format('invapi-item-removed-player: %s, %s', item, quantity))
end)
Server export functions
To add more exports, review the functions available on the inventory class and expose the ones your integration requires.
exports('av_givePlayerItem', av_givePlayerItem)
exports('av_removePlayerItem', av_removePlayerItem)
exports('av_getPlayerItemCount', av_getPlayerItemCount)
exports('av_playerHasItems', av_playerHasItems)
exports('av_playerGetInventoryWeight', av_playerGetInventoryWeight)
function av_givePlayerItem(source, item, quantity, vars, slot)
local playerInventory = StorageController.getPlayerInventory(source)
if playerInventory then
return playerInventory:addItem(item, quantity, vars, slot)
end
end
function av_removePlayerItem(source, item, quantity, slot)
local playerInventory = StorageController.getPlayerInventory(source)
if playerInventory then
return playerInventory:removeItem(item, quantity, slot)
end
end
function av_getPlayerItemCount(source, item)
local playerInventory = StorageController.getPlayerInventory(source)
if playerInventory then
return playerInventory:getItemCount(item)
else
return 0
end
end
function av_playerHasItems(source, itemsTable)
local playerInventory = StorageController.getPlayerInventory(source)
if playerInventory then
return playerInventory:hasItems(itemsTable)
end
end
function av_playerGetInventoryWeight(source)
local playerInventory = StorageController.getPlayerInventory(source)
if playerInventory then
return playerInventory:getInventoryWeight()
end
end