OrigenNetwork
Docs

Server Hooks · origen_inventory

Hooks let external resources subscribe to inventory events on the server side and either inspect the payload, mutate it, or cancel the action by returning false.

The hook system is exposed through two exports — registerHook and removeHooks — and is symmetrical with the client-side hook API.

All hooks documented on this page run server-side. For client-side hooks (world points, UI events) see Custom · Client-side hooks.


API

registerHook(event, callback, options?)string (id)

Registers a server-side hook. Returns the internal hookId so you can remove it later.

lua
local hookId = exports.origen_inventory:registerHook('createItem', function(payload)
    return payload.metadata
end)
ParameterTypeDescription
eventstringHook event name (see list below).
callbackfunctionInvoked with the hook payload.
optionstable?Optional filters (itemFilter, inventoryFilter, typeFilter, debugger).

Filters (options)

lua
exports.origen_inventory:registerHook('swapItems', function(payload)
    -- only fires for these inventories / items / types
end, {
    itemFilter      = { tosti = true, water_bottle = true },
    inventoryFilter = { '^stash%-', '^trunk%-' },
    typeFilter      = { player = true, stash = true },
    debugger        = true, -- prints execution time and resource origin
})
FilterTypeDescription
itemFiltertable<string, true>Only fire when the involved item name is in this set.
inventoryFilterstring[]Lua patterns matched against the source/target inventory id.
typeFiltertable<string, true>Restrict to specific inventory/shop types (player, stash, shop, drop, ...).
debuggerbooleanLogs every hook call (resource, event, slot, execution time).

removeHooks(id?)void

Removes hooks belonging to the calling resource. Pass an id to remove a single hook, or omit it to remove every hook registered by the resource.

lua
exports.origen_inventory:removeHooks(hookId) -- single hook
exports.origen_inventory:removeHooks()        -- every hook from this resource

Hooks are also cleaned up automatically on onResourceStop, so you only need to call removeHooks for hot-swapped registrations.


Cancellation contract

Most server hooks honour a cancellation contract:

  • Return false → the inventory aborts the action (item is not added/swapped/bought/etc.).
  • Return anything else (or nothing) → the action proceeds normally.

The only exception is createItem, which is mutating: you must return the (possibly modified) metadata table.


Hooks reference

createItem

Fires when an item is being added to an inventory and metadata is being initialized. Mutating — must return metadata.

Payload

FieldTypeDescription
inventoryIdnumber|stringInventory receiving the item (player src, stash id, plate, ...).
inventoryTypestringplayer, stash, trunk, glovebox, ...
itemtableItem definition being created.
countnumberAmount being added.
metadatatableMutable metadata table.
lua
exports.origen_inventory:registerHook('createItem', function(payload)
    if payload.item.name == 'paperbag' and not payload.metadata.bagId then
        payload.metadata.bagId = math.random(1000, 9999)
    end
    return payload.metadata -- MUST return metadata
end)

If you forget to return metadata, the item will be created with an empty metadata table.


itemCreated

Fires after an item has been added to an inventory. Read-only / observational — return value is ignored.

Payload

FieldTypeDescription
inventoryIdnumber|stringInventory id.
inventoryTypestringInventory type.
itemtableThe item slot just created (with slot, count, metadata).
countnumberAmount added.
lua
exports.origen_inventory:registerHook('itemCreated', function(payload)
    print(('Item %s x%s added to %s'):format(payload.item.name, payload.count, payload.inventoryId))
end)

itemUsed

Fires after a slot is successfully used. Observational.

Payload

FieldTypeDescription
sourcenumberPlayer server id.
inventoryIdnumber|stringInventory the slot belongs to.
inventoryTypestringInventory type.
itemtableThe item slot used.
slotnumberSlot id.
lua
exports.origen_inventory:registerHook('itemUsed', function(payload)
    if payload.item.name == 'lockpick' then
        -- log lockpick usage
    end
end)

useSlot

Fires before a slot is used. Return false to cancel the use.

Payload

FieldTypeDescription
sourcenumberPlayer server id.
inventoryIdnumber|stringInventory id.
inventoryTypestringInventory type.
itemtableThe slot being used.
slotnumberSlot id.
lua
exports.origen_inventory:registerHook('useSlot', function(payload)
    if payload.item.name == 'weapon_pistol' and IsRestrictedZone(payload.source) then
        return false -- cancel use
    end
end)

swapItems

Fires before any move / swap / split / give between two inventories (player-to-player, stash transfers, trunk, drops, etc.). Return false to cancel the transfer.

Payload

FieldTypeDescription
sourcenumber?Player server id (when applicable).
actionstringmove, swap, split, give.
fromInventorystring|numberSource inventory id.
fromTypestringSource inventory type (player, stash, ...).
fromSlottableSlot data being moved.
toInventorystring|numberDestination inventory id.
toTypestringDestination inventory type.
toSlottable?Slot data being swapped (only present on swap/merge).
countnumberAmount being moved.
lua
exports.origen_inventory:registerHook('swapItems', function(payload)
    -- block moving illegal items into a public trunk
    if payload.toType == 'trunk' and payload.fromSlot.name == 'weapon_rpg' then
        return false
    end
end)

createDrop

Fires before a ground drop is created. Return false to block the drop.

Payload

FieldTypeDescription
sourcenumberPlayer creating the drop.
coordsvector3Drop coordinates.
itemtableSlot data being dropped.
countnumberAmount being dropped.
lua
exports.origen_inventory:registerHook('createDrop', function(payload)
    if Config.NoDropZones[GetZoneAtCoords(payload.coords)] then
        return false
    end
end)

buyItem

Fires before a shop purchase is committed. Return false to cancel the purchase.

Payload

FieldTypeDescription
sourcenumberBuyer server id.
shopTypestringShop id (e.g. barber_supplies).
itemtableItem being bought.
countnumberQuantity.
pricenumberUnit price.
currencystring?Optional currency override (cash, bank, custom).
lua
exports.origen_inventory:registerHook('buyItem', function(payload)
    -- block restricted weapons from being bought outside police stations
    if payload.item.type == 'weapon' and not IsAtPoliceStation(payload.source) then
        return false
    end
end)

openInventory

Fires before a stash or shop is opened. Return false to deny access.

Payload

FieldTypeDescription
sourcenumberPlayer server id.
inventoryIdstring|numberStash / shop id.
inventoryTypestringstash, shop, trunk, glovebox.
lua
exports.origen_inventory:registerHook('openInventory', function(payload)
    if payload.inventoryType == 'stash' and payload.inventoryId:match('^faction%-') then
        return PlayerHasFactionAccess(payload.source, payload.inventoryId)
    end
end)

clearInventory

Fires before an inventory is cleared. Return false to cancel the clear.

Payload

FieldTypeDescription
inventoryIdstring|numberInventory being cleared.
inventoryTypestringInventory type.
lua
exports.origen_inventory:registerHook('clearInventory', function(payload)
    if payload.inventoryType == 'stash' and IsAuditedStash(payload.inventoryId) then
        return false -- audited stashes cannot be wiped
    end
end)

itemExpired

Fires when an item with decay reaches its expiration. Return false to keep the item in the slot anyway (rare — usually you let it be removed).

Payload

FieldTypeDescription
inventoryIdstring|numberInventory holding the item.
inventoryTypestringInventory type.
itemtableThe expired item slot.
slotnumberSlot id.
lua
exports.origen_inventory:registerHook('itemExpired', function(payload)
    if payload.item.name == 'sealed_evidence' then
        return false -- evidence does not decay even if config says so
    end
end)

Performance notes

  • Each hook is wrapped in a pcall. Errors inside your hook are isolated and won't crash the inventory.
  • Execution time is measured. If a hook takes longer than 100ms the inventory will print a debug log so you can spot slow callbacks.
  • Use the itemFilter / inventoryFilter / typeFilter options whenever possible — they short-circuit the dispatch loop and are dramatically cheaper than filtering inside your callback.

See also