From 4ffe8df78c736392beb7c51f2483f49f642a8daa Mon Sep 17 00:00:00 2001 From: Skulrag <58217414+Skulrag@users.noreply.github.com> Date: Wed, 21 Jan 2026 20:34:28 +0100 Subject: [PATCH 1/4] Add RegisterVehicleInventory server side function. Introduces Inventory.RegisterVehicleInventory to allow registering a vehicle's trunk or glovebox inventory on the server. --- modules/inventory/server.lua | 115 +++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) diff --git a/modules/inventory/server.lua b/modules/inventory/server.lua index 4b046ceed..66abc268d 100644 --- a/modules/inventory/server.lua +++ b/modules/inventory/server.lua @@ -1,6 +1,7 @@ if not lib then return end local Inventory = {} +local Vehicles = lib.load('data.vehicles') ---@type table local Inventories = {} @@ -2761,4 +2762,118 @@ end exports('InspectInventory', Inventory.InspectInventory) +---Register a vehicle trunk or glovebox inventory without requiring client interaction +---@param vehicleNetId number Network ID of the vehicle +---@param invType? 'trunk'|'glovebox' Type of vehicle inventory (default: 'trunk') +---@param source? number Player source for fallback vehicle class lookup +---@return string|nil inventoryId The created inventory ID, or nil on failure +function Inventory.RegisterVehicleInventory(vehicleNetId, invType, source) + if not vehicleNetId then + return lib.print.error('RegisterVehicleInventory: vehicleNetId is required') + end + + invType = invType or 'trunk' + + if invType ~= 'trunk' and invType ~= 'glovebox' then + return lib.print.error('RegisterVehicleInventory: invType must be "trunk" or "glovebox"') + end + + -- Get the vehicle entity from network ID + local entity = NetworkGetEntityFromNetworkId(vehicleNetId) + + if not entity or entity == 0 then + return lib.print.error('RegisterVehicleInventory: invalid vehicle network ID') + end + + if not DoesEntityExist(entity) then + return lib.print.error('RegisterVehicleInventory: vehicle entity does not exist') + end + + -- Get vehicle plate + local plate = GetVehicleNumberPlateText(entity) + + if not plate then + return lib.print.error('RegisterVehicleInventory: could not get vehicle plate') + end + + -- Trim plate if configured + if server.trimplate then + plate = string.strtrim(plate) + end + + -- Build inventory ID + local inventoryId = (invType == 'glovebox' and 'glove' or 'trunk') .. plate + + -- Check if inventory already exists + local existingInventory = Inventories[inventoryId] + + if existingInventory then + -- Update netid if it changed + if existingInventory.netid ~= vehicleNetId then + existingInventory.netid = vehicleNetId + existingInventory.entityId = entity + end + return inventoryId + end + + -- Get vehicle model + local model = GetEntityModel(entity) + + -- Try to get storage from model first + local storage = Vehicles[invType].models[model] + + -- If not found by model, we need the class (requires client callback) + if not storage then + if not source then + source = NetworkGetEntityOwner(entity) + end + + if not source or source == 0 then + return lib.print.error('RegisterVehicleInventory: cannot determine vehicle class without player source') + end + + -- Get vehicle class from client + local _, class = lib.callback.await('ox_inventory:getVehicleData', source, vehicleNetId) + storage = Vehicles[invType][class] + end + + if not storage then + return lib.print.error(('RegisterVehicleInventory: no storage config found for model %s'):format(model)) + end + + -- Get database ID + local dbId + if server.getOwnedVehicleId then + dbId = server.getOwnedVehicleId(entity) + else + dbId = plate + end + + -- Create the inventory + local inventory = Inventory.Create( + inventoryId, -- ID: 'trunkABC123' or 'gloveABC123' + plate, -- Label: vehicle plate + invType, -- Type: 'trunk' or 'glovebox' + storage[1], -- Slots + 0, -- Current weight + storage[2], -- Max weight + false, -- Owner + nil, -- Items (will be loaded from DB) + nil, -- Groups + dbId -- Database ID + ) + + if not inventory then + return lib.print.error('RegisterVehicleInventory: failed to create inventory') + end + + -- Store network ID and entity reference + inventory.netid = vehicleNetId + inventory.entityId = entity + + return inventoryId +end + +exports('RegisterVehicleInventory', Inventory.RegisterVehicleInventory) + return Inventory From c6f4d08756b25fcad8e67b7651d2ee99a6ca0806 Mon Sep 17 00:00:00 2001 From: Skulrag <58217414+Skulrag@users.noreply.github.com> Date: Wed, 21 Jan 2026 21:45:17 +0100 Subject: [PATCH 2/4] Declare source with proper way --- modules/inventory/server.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/inventory/server.lua b/modules/inventory/server.lua index 66abc268d..91e514ee1 100644 --- a/modules/inventory/server.lua +++ b/modules/inventory/server.lua @@ -2767,7 +2767,8 @@ exports('InspectInventory', Inventory.InspectInventory) ---@param invType? 'trunk'|'glovebox' Type of vehicle inventory (default: 'trunk') ---@param source? number Player source for fallback vehicle class lookup ---@return string|nil inventoryId The created inventory ID, or nil on failure -function Inventory.RegisterVehicleInventory(vehicleNetId, invType, source) +function Inventory.RegisterVehicleInventory(vehicleNetId, invType) + local source = source if not vehicleNetId then return lib.print.error('RegisterVehicleInventory: vehicleNetId is required') end From 63b618fe701293ee4f4b779840c8cb25ca7a38a6 Mon Sep 17 00:00:00 2001 From: Skulrag <58217414+Skulrag@users.noreply.github.com> Date: Fri, 23 Jan 2026 00:35:29 +0100 Subject: [PATCH 3/4] Refactored function to let it be more flexible with frameworks --- modules/inventory/server.lua | 78 +++++++----------------------------- 1 file changed, 15 insertions(+), 63 deletions(-) diff --git a/modules/inventory/server.lua b/modules/inventory/server.lua index 91e514ee1..5390bb8a2 100644 --- a/modules/inventory/server.lua +++ b/modules/inventory/server.lua @@ -76,7 +76,6 @@ function OxInventory:syncSlotsWithClients(slots, syncOwner) end end -local Vehicles = lib.load('data.vehicles') local RegisteredStashes = {} for _, stash in pairs(lib.load('data.stashes') or {}) do @@ -92,8 +91,6 @@ for _, stash in pairs(lib.load('data.stashes') or {}) do } end -local GetVehicleNumberPlateText = GetVehicleNumberPlateText - ---Atempts to lazily load inventory data from the database or create a new player-owned instance for "personal" stashes ---@param data table ---@param player table @@ -2762,26 +2759,31 @@ end exports('InspectInventory', Inventory.InspectInventory) ----Register a vehicle trunk or glovebox inventory without requiring client interaction ----@param vehicleNetId number Network ID of the vehicle + +---@param source number Player source +---@param inventoryId string The inventory ID to register ---@param invType? 'trunk'|'glovebox' Type of vehicle inventory (default: 'trunk') ----@param source? number Player source for fallback vehicle class lookup ---@return string|nil inventoryId The created inventory ID, or nil on failure -function Inventory.RegisterVehicleInventory(vehicleNetId, invType) - local source = source - if not vehicleNetId then +local function Inventory.RegisterVehicleInventory(source, inventoryId, vehicleNetId, invType) + + if not inventoryId then + return lib.print.error('RegisterVehicleInventory: inventoryId is required') + end + if not vehicleNetId then return lib.print.error('RegisterVehicleInventory: vehicleNetId is required') end + local existingInventory = Inventories[inventoryId] + if existingInventory then + return inventoryId + end + invType = invType or 'trunk' - if invType ~= 'trunk' and invType ~= 'glovebox' then return lib.print.error('RegisterVehicleInventory: invType must be "trunk" or "glovebox"') end - -- Get the vehicle entity from network ID local entity = NetworkGetEntityFromNetworkId(vehicleNetId) - if not entity or entity == 0 then return lib.print.error('RegisterVehicleInventory: invalid vehicle network ID') end @@ -2790,50 +2792,16 @@ function Inventory.RegisterVehicleInventory(vehicleNetId, invType) return lib.print.error('RegisterVehicleInventory: vehicle entity does not exist') end - -- Get vehicle plate - local plate = GetVehicleNumberPlateText(entity) - - if not plate then - return lib.print.error('RegisterVehicleInventory: could not get vehicle plate') - end - - -- Trim plate if configured - if server.trimplate then - plate = string.strtrim(plate) - end - - -- Build inventory ID - local inventoryId = (invType == 'glovebox' and 'glove' or 'trunk') .. plate - - -- Check if inventory already exists - local existingInventory = Inventories[inventoryId] - - if existingInventory then - -- Update netid if it changed - if existingInventory.netid ~= vehicleNetId then - existingInventory.netid = vehicleNetId - existingInventory.entityId = entity - end - return inventoryId - end - - -- Get vehicle model local model = GetEntityModel(entity) - - -- Try to get storage from model first local storage = Vehicles[invType].models[model] - - -- If not found by model, we need the class (requires client callback) if not storage then if not source then source = NetworkGetEntityOwner(entity) end - if not source or source == 0 then return lib.print.error('RegisterVehicleInventory: cannot determine vehicle class without player source') end - -- Get vehicle class from client local _, class = lib.callback.await('ox_inventory:getVehicleData', source, vehicleNetId) storage = Vehicles[invType][class] end @@ -2842,7 +2810,6 @@ function Inventory.RegisterVehicleInventory(vehicleNetId, invType) return lib.print.error(('RegisterVehicleInventory: no storage config found for model %s'):format(model)) end - -- Get database ID local dbId if server.getOwnedVehicleId then dbId = server.getOwnedVehicleId(entity) @@ -2850,25 +2817,10 @@ function Inventory.RegisterVehicleInventory(vehicleNetId, invType) dbId = plate end - -- Create the inventory - local inventory = Inventory.Create( - inventoryId, -- ID: 'trunkABC123' or 'gloveABC123' - plate, -- Label: vehicle plate - invType, -- Type: 'trunk' or 'glovebox' - storage[1], -- Slots - 0, -- Current weight - storage[2], -- Max weight - false, -- Owner - nil, -- Items (will be loaded from DB) - nil, -- Groups - dbId -- Database ID - ) - + local inventory = Inventory.Create(inventoryId, plate, invType, storage[1], 0, storage[2], false, nil, nil, dbId) if not inventory then return lib.print.error('RegisterVehicleInventory: failed to create inventory') end - - -- Store network ID and entity reference inventory.netid = vehicleNetId inventory.entityId = entity From 760fa1e3890f670d12d1b8926ad496bbb5231b35 Mon Sep 17 00:00:00 2001 From: Skulrag <58217414+Skulrag@users.noreply.github.com> Date: Sun, 25 Jan 2026 10:16:00 +0100 Subject: [PATCH 4/4] Update server.lua --- modules/inventory/server.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/inventory/server.lua b/modules/inventory/server.lua index 5390bb8a2..50d0bafde 100644 --- a/modules/inventory/server.lua +++ b/modules/inventory/server.lua @@ -2764,7 +2764,7 @@ exports('InspectInventory', Inventory.InspectInventory) ---@param inventoryId string The inventory ID to register ---@param invType? 'trunk'|'glovebox' Type of vehicle inventory (default: 'trunk') ---@return string|nil inventoryId The created inventory ID, or nil on failure -local function Inventory.RegisterVehicleInventory(source, inventoryId, vehicleNetId, invType) +function Inventory.RegisterVehicleInventory(source, inventoryId, vehicleNetId, invType) if not inventoryId then return lib.print.error('RegisterVehicleInventory: inventoryId is required')