OrigenNetwork
Docs

Installation · origen_inventory

Follow the steps below to install origen_inventory on your server.


1. Add the resource to your server

Copy the origen_inventory folder into your resources directory and add it to your server.cfg.

The ensure order is important — every dependency must be running before origen_inventory.

cfg
# server.cfg
 
ensure oxmysql
ensure ox_lib
ensure qb-core            # or es_extended / qbx_core
 
# Optional integrations
ensure qs-smartphone-pro  # or lb-phone
ensure origen_clothing    # only if you use Clothes-As-Item
 
ensure origen_inventory

Never start origen_inventory before oxmysql and your framework core. Without them the database driver and bridge layer will fail to initialize and inventories will not load.


2. Replace your previous inventory

If you are migrating from another inventory resource you must remove (or disable) it before starting origen_inventory. There can only be one active inventory provider at a time.

If your other scripts depend on qb-inventory or ox_inventory exports, open fxmanifest.lua and uncomment the matching provide line so those export calls resolve to origen_inventory:

lua
-- Uncomment if you have old scripts that use qb-inventory
-- provide 'qb-inventory'
 
-- Uncomment if you have qbx_core installed
-- provide 'ox_inventory'

3. Import the SQL schema

Import the file origen_inventory.sql into your database. It creates the four tables required by the resource: gloveboxitems, stashitems, trunkitems, origen_customitems and origen_inventory_equipped_clothes.

sql
CREATE TABLE IF NOT EXISTS `gloveboxitems` (
	`id` INT(11) NOT NULL AUTO_INCREMENT,
	`plate` VARCHAR(255) NOT NULL COLLATE 'latin1_swedish_ci',
	`items` LONGTEXT NULL DEFAULT NULL COLLATE 'utf8mb4_bin',
	`label` VARCHAR(100) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
	`slots` INT(11) NULL DEFAULT NULL,
	`personal` VARCHAR(255) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
	`weight` INT(11) NULL DEFAULT NULL,
	`job` VARCHAR(100) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
	PRIMARY KEY (`plate`) USING BTREE,
	INDEX `id` (`id`) USING BTREE
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=152;
 
CREATE TABLE IF NOT EXISTS `stashitems` (
	`id` INT(11) NOT NULL AUTO_INCREMENT,
	`stash` VARCHAR(255) NOT NULL COLLATE 'latin1_swedish_ci',
	`items` LONGTEXT NULL DEFAULT NULL COLLATE 'utf8mb4_bin',
	`label` VARCHAR(100) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
	`slots` INT(11) NULL DEFAULT NULL,
	`job` VARCHAR(100) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
	`personal` VARCHAR(255) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
	`weight` INT(11) NULL DEFAULT NULL,
	PRIMARY KEY (`stash`) USING BTREE,
	INDEX `id` (`id`) USING BTREE
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1;
 
CREATE TABLE IF NOT EXISTS `trunkitems` (
	`id` INT(11) NOT NULL AUTO_INCREMENT,
	`plate` VARCHAR(255) NOT NULL COLLATE 'latin1_swedish_ci',
	`items` LONGTEXT NULL DEFAULT NULL COLLATE 'utf8mb4_bin',
	`label` VARCHAR(100) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
	`personal` VARCHAR(255) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
	`weight` INT(11) NULL DEFAULT NULL,
	`slots` INT(11) NULL DEFAULT NULL,
	`job` VARCHAR(100) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
	PRIMARY KEY (`plate`) USING BTREE,
	INDEX `id` (`id`) USING BTREE
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1;
 
DROP TABLE IF EXISTS `origen_customitems`;
CREATE TABLE `origen_customitems` (
	`name` VARCHAR(100) NOT NULL COLLATE 'utf8mb4_unicode_ci',
	`label` VARCHAR(255) NOT NULL COLLATE 'utf8mb4_unicode_ci',
	`weight` INT(11) NOT NULL DEFAULT '0',
	`type` VARCHAR(50) NOT NULL DEFAULT 'item' COLLATE 'utf8mb4_unicode_ci',
	`image` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8mb4_unicode_ci',
	`description` TEXT NULL DEFAULT NULL COLLATE 'utf8mb4_unicode_ci',
	`unique` TINYINT(1) NOT NULL DEFAULT '0',
	`rarity` VARCHAR(50) NULL DEFAULT NULL COLLATE 'utf8mb4_unicode_ci',
	`stack` TINYINT(1) NOT NULL DEFAULT '0',
	`close` TINYINT(1) NOT NULL DEFAULT '1',
	`server` LONGTEXT NULL DEFAULT NULL COLLATE 'utf8mb4_bin',
	`client` LONGTEXT NULL DEFAULT NULL COLLATE 'utf8mb4_bin',
	`decay` INT(11) NULL DEFAULT NULL,
	`buttons` LONGTEXT NULL DEFAULT NULL COLLATE 'utf8mb4_bin',
	PRIMARY KEY (`name`) USING BTREE,
	CONSTRAINT `server` CHECK (json_valid(`server`)),
	CONSTRAINT `client` CHECK (json_valid(`client`)),
	CONSTRAINT `buttons` CHECK (json_valid(`buttons`))
)
COLLATE='utf8mb4_unicode_ci'
ENGINE=InnoDB
;
 
CREATE TABLE IF NOT EXISTS `origen_inventory_equipped_clothes` (
	`identifier` VARCHAR(50) NOT NULL COLLATE 'utf8mb4_unicode_ci',
	`data` LONGTEXT NULL DEFAULT NULL COLLATE 'utf8mb4_bin',
	`last_updated` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
	PRIMARY KEY (`identifier`) USING BTREE,
	CONSTRAINT `data_json` CHECK (json_valid(`data`))
)
COLLATE='utf8mb4_unicode_ci'
ENGINE=InnoDB
;

origen_customitems is dropped and recreated by the import file. If you already have custom items registered, back them up before running the SQL again.


4. Items

origen_inventory ships its own item dictionary (config/items.lua and config/weapons.lua). When you replace your previous inventory:

  • QBCore / QBX: You can keep using your existing shared/items.lua if your scripts depend on it. The bridge in bridge/qbcore/server/items.lua and bridge/qbx/server/players.lua reads through both sources.
  • ESX: Items declared in the framework items table will be loaded as well via bridge/esx/server/items.lua.
  • Custom items: Items added at runtime through exports.origen_inventory:AddCustomItem(...) are persisted in origen_customitems and reloaded automatically on resource start.

5. ESX bridge setup

This step is only required if you are running ESX (es_extended). QBCore and QBX users can skip to step 6.

origen_inventory ships two override files that must be placed inside es_extended so the framework delegates all inventory calls to origen_inventory instead of its built-in inventory.

Where to place the files

Copy both files from the bridge/esx/overrides/ folder inside origen_inventory into your es_extended resource:

Source file (inside origen_inventory)Destination (inside es_extended)
bridge/esx/overrides/origeninventory.luaes_extended/overrides/origeninventory.lua
bridge/esx/overrides/origeninventory_player.luaes_extended/overrides/origeninventory_player.lua

Then make sure both files are declared in es_extended/fxmanifest.lua under server_scripts:

lua
-- es_extended/fxmanifest.lua
server_scripts {
  -- ... existing entries ...
  'overrides/origeninventory.lua',
  'overrides/origeninventory_player.lua',
}

What each file does

origeninventory.lua — overrides the ESX item and usable-item functions so that calls to ESX.GetItemLabel, ESX.RegisterUsableItem and ESX.UseItem route to origen_inventory instead of the default ESX dictionary. It also handles starting account money and starting inventory items for new characters.

lua
if Config.CustomInventory ~= "origen_inventory" then return end
 
MySQL.ready(function()
    TriggerEvent("__cfx_export_origen_inventory_Items", function(ref)
        if ref then
            ESX.Items = exports.origen_inventory:Items()
        end
    end)
end)
 
---@diagnostic disable-next-line: duplicate-set-field
ESX.GetItemLabel = function(itemName)
    local item = exports.origen_inventory:Items(itemName)
    if item then
        return item.label
    end
 
    print(('[^3WARNING^7] Attemting to get invalid Item -> ^5%s^7'):format(itemName))
end
 
---@diagnostic disable-next-line: duplicate-set-field
function ESX.RegisterUsableItem(item, cb)
    Core.UsableItemsCallbacks[item] = cb
    exports.origen_inventory:CreateUseableItem(item, cb)
end
 
---@diagnostic disable-next-line: duplicate-set-field
function ESX.UseItem(source, item, ...)
    local src, itm = source, item
    if type(src) == 'string' then item = src source = itm end
 
    if ESX.Items[item] then
        return exports['origen_inventory']:UseItem(item, source, ...)
    else
        print(('[^3WARNING^7] Item ^5"%s"^7 was used but does not exist!'):format(item))
    end
end
 
exports("GetUseablesItems", function()
    return Core.UsableItemsCallbacks
end)
 
function setPlayerInventory(playerId, xPlayer, inventory, isNew)
    if isNew then
        local shared = json.decode(GetConvar("inventory:accounts", '"money"'))
 
        for i = 1, #shared do
            local name = shared[i]
            local account = Config.StartingAccountMoney[name]
            if account then
                exports.origen_inventory:AddItem(playerId, name, account)
            end
        end
 
        if Config.StartingInventoryItems and type(Config.StartingInventoryItems) == "table" then
            for item, count in pairs(Config.StartingInventoryItems) do
                exports.origen_inventory:AddItem(playerId, item, count)
            end
        end
    end
end

origeninventory_player.lua — injects Core.PlayerFunctionOverrides.OrigenInventory, replacing the default player inventory methods (getInventory, addInventoryItem, removeInventoryItem, hasItem, addWeapon, canCarryItem, etc.) with their origen_inventory equivalents. This ensures any internal ESX call that touches player inventory goes through origen_inventory.

lua
------ Dont touch this file unless you know what you are doing
------ This file is used to override the inventory functions
---
---
---- Origen_File_Version - 4
---
---
if Config.CustomInventory ~= "origen_inventory" then return end
 
Core.PlayerFunctionOverrides.OrigenInventory = {
  getInventory = function(self)
    return function(minimal)
      local inventory = exports.origen_inventory:GetPlayerInventory(self.source)
      return inventory
    end
  end,
 
  getLoadout = function(self)
    return function()
      return {}
    end
  end,
 
  getInventoryItem = function(self)
    return function(name, metadata)
      local item = exports.origen_inventory:getItem(self.source, name)
      if not item then
        return {
          count = 0,
        }
      end
      return item
    end
  end,
 
  addInventoryItem = function(self)
    return function(name, count, metadata, slot)
      return exports.origen_inventory:AddItem(self.source, name, count or 1, metadata, slot, true)
    end
  end,
 
  removeInventoryItem = function(self)
    return function(name, count, metadata, slot)
      return exports.origen_inventory:RemoveItem(self.source, name, count or 1, metadata, slot, false)
    end
  end,
 
  setInventoryItem = function(self)
    return function(name, count, metadata)
      return exports.origen_inventory:SetInventoryItems(self.source, name, count, metadata)
    end
  end,
 
  save = function(self)
    return function(inventory)
      Core.SavePlayer(self)
    end
  end,
 
  canCarryItem = function(self)
    return function(name, count, metadata)
      return exports['origen_inventory']:CanCarryItem(self.source, name, count)
    end
  end,
 
  canSwapItem = function(self)
    return function(firstItem, firstItemCount, testItem, testItemCount)
      return true
    end
  end,
 
  setMaxWeight = function(self)
    return function() end
  end,
 
  addWeapon = function(self)
    ---@param weaponName item weapon
    ---@param ammo amount
    return function(weaponName, ammo)
      return exports['origen_inventory']:GiveWeaponToPlayer(self.source, weaponName, ammo)
    end
  end,
 
  addWeaponComponent = function(self)
    return function() end
  end,
 
  addWeaponAmmo = function(self)
    return function() end
  end,
 
  updateWeaponAmmo = function(self)
    return function() end
  end,
 
  setWeaponTint = function(self)
    return function() end
  end,
 
  getWeaponTint = function(self)
    return function() end
  end,
 
  removeWeapon = function(self)
    return function() end
  end,
 
  removeWeaponComponent = function(self)
    return function() end
  end,
 
  removeWeaponAmmo = function(self)
    return function() end
  end,
 
  hasWeaponComponent = function(self)
    return function()
      return false
    end
  end,
 
  hasWeapon = function(self)
    return function()
      return false
    end
  end,
 
  hasItem = function(self)
    return function(name, metadata)
      return exports.origen_inventory:getItem(self.source, name, metadata)
    end
  end,
 
  getWeapon = function(self)
    return function() end
  end,
}

Both files guard themselves with if Config.CustomInventory ~= "origen_inventory" then return end, so they are safe to leave in place if you ever switch inventories — they will simply no-op.


6. Configure the resource

Open config.lua, config_sv.lua and the files inside config/ and adjust them for your server. See the Configuration page for the full list of options.

The minimum you should review before going live:

  • Config.Framework (auto-detected; only override if you run a custom fork)
  • Config.Language
  • Config.Phone.Resource
  • Config.Progressbar
  • Config.Player.MaxWeight and Config.Player.MaxInventorySlots
  • Webhook URLs in config_sv.lua

7. Verify installation

After starting the server, join with a player and confirm:

  • Pressing F2 opens the player inventory.
  • Pressing TAB toggles the hotbar (if Config.UI.Hotbar = true).
  • Vehicle trunks open at the back of the vehicle (within Config.TrunkOpenDistance).
  • Vehicle gloveboxes open while inside the vehicle.
  • Stashes declared in config/stashes.lua show their marker on the configured locations.
  • Shops declared in config/shops.lua show their blip and marker.
  • Items are saved between sessions (player disconnect / reconnect).