Zum Inhalt

Register Usable Item

Short reference for using cv.inventory.registerUsableItem to make items usable in the inventory system.


Concepts

  • cv.inventory.registerUsableItem registers an item as "usable" with a callback function that executes when a player uses the item from their inventory.
  • The function is server-side only - callbacks execute on the server when items are used.
  • Once registered, items automatically show as usable in the client inventory UI.
  • The callback receives player context, item details, and metadata for processing the item use.

Notes:

  • Always validate that the player and character context exist before processing item use.
  • By default, the inventory UI closes after using an item. This can be controlled with options.
  • Items must exist in the item_definitions database table before being registered as usable.
  • The isUsable flag is automatically set to true in the item definitions cache when registered.

Server-Side Registration

Basic Syntax

cv.inventory.registerUsableItem(itemName, callback, options)

Parameters: - itemName (string): The name of the item (must match item_definitions.name in database) - callback (function): Function called when the item is used - options (table|nil): Optional configuration table

Callback Parameters: The callback function receives the following parameters:

function(source, itemName, slot, quantity, metadata)
    -- source: Player server ID (number)
    -- itemName: Name of the item being used (string)
    -- slot: Inventory slot number (number)
    -- quantity: Amount of items in that slot (number)
    -- metadata: Item metadata table (table)
end

Options Table:

{
    closeInventory = true  -- (boolean) Close inventory after use (default: true)
}


Examples

Simple Food Item

cv.inventory.registerUsableItem("burger", function(source, itemName, slot, quantity, metadata)
    local player = cv.player.getPlayer(source)
    if not player or not player.charId then return end

    -- Remove the item from inventory
    cv.inventory.removeItem(player.charId, itemName, 1)

    -- Add hunger
    exports.cv_framework:AddHunger(source, 50)

    -- Notify player
    cv.notify(source, 'Hunger', 'You ate a burger', 'success')

    -- Play eating animation
    TriggerClientEvent('cv_framework:hunger:playAnimation', source, 'mp_player_inteat@burger', 'mp_player_int_eat_burger', 3000)
end)

Item with Validation

cv.inventory.registerUsableItem("water", function(source, itemName, slot, quantity, metadata)
    local player = cv.player.getPlayer(source)
    if not player or not player.charId then return end

    -- Check if player actually has the item
    local hasItem, count = cv.inventory.hasItem(player.charId, itemName, 1)
    if not hasItem then
        cv.notify(source, 'Error', 'You don\'t have this item', 'error')
        return
    end

    -- Remove the item
    cv.inventory.removeItem(player.charId, itemName, 1)

    -- Add thirst
    exports.cv_framework:AddThirst(source, 30)

    -- Notify and animate
    cv.notify(source, 'Thirst', 'You drank water', 'success')
    TriggerClientEvent('cv_framework:thirst:playAnimation', source, 'mp_player_intdrink', 'loop_bottle', 3000)
end)

Item That Keeps Inventory Open

cv.inventory.registerUsableItem("phone", function(source, itemName, slot, quantity, metadata)
    local player = cv.player.getPlayer(source)
    if not player or not player.charId then return end

    -- Open phone UI
    TriggerClientEvent('phone:open', source)

    -- Note: Inventory stays open because of options.closeInventory = false
end, {
    closeInventory = false
})

Batch Registration

local consumables = {
    { name = "water", thirst = 30 },
    { name = "coffee", thirst = 15 },
    { name = "burger", hunger = 45 },
    { name = "pizza", hunger = 60 }
}

for _, item in ipairs(consumables) do
    cv.inventory.registerUsableItem(item.name, function(source, itemName, slot, quantity, metadata)
        local player = cv.player.getPlayer(source)
        if not player or not player.charId then return end

        -- Remove item
        cv.inventory.removeItem(player.charId, itemName, 1)

        -- Apply effects
        if item.thirst then
            exports.cv_framework:AddThirst(source, item.thirst)
            cv.notify(source, 'System', 'You drank ' .. cv.inventory.getItemLabel(itemName), 'success')
        elseif item.hunger then
            exports.cv_framework:AddHunger(source, item.hunger)
            cv.notify(source, 'System', 'You ate ' .. cv.inventory.getItemLabel(itemName), 'success')
        end
    end)
end

Item with Metadata Processing

cv.inventory.registerUsableItem("lockpick", function(source, itemName, slot, quantity, metadata)
    local player = cv.player.getPlayer(source)
    if not player or not player.charId then return end

    -- Check durability from metadata
    local durability = metadata.durability or 100

    if durability <= 0 then
        cv.notify(source, 'Error', 'This lockpick is broken', 'error')
        cv.inventory.removeItem(player.charId, itemName, 1, slot)
        return
    end

    -- Start lockpicking minigame
    TriggerClientEvent('lockpick:startMinigame', source, {
        itemSlot = slot,
        durability = durability
    })
end, {
    closeInventory = true
})

Check if Item is Usable

Server:

local isUsable = exports.cv_framework:IsItemUsable(itemName)

Client:

local isUsable = cv.inventory.isItemUsable(itemName)

Trigger Item Use from Client

cv.inventory.triggerUsableItem(itemName, slot, quantity, metadata)

Get Item Definition

local itemDef = cv.inventory.getItemDefinition(itemName)
-- Returns: { name, label, weight, type, description, isUsable, ... }

Common Patterns

Character Validation Pattern

Always validate player and character context:

cv.inventory.registerUsableItem("myitem", function(source, itemName, slot, quantity, metadata)
    local player = cv.player.getPlayer(source)
    if not player or not player.charId then 
        return  -- Silently fail if no character loaded
    end

    -- Safe to proceed with character operations
end)

Item Removal Pattern

Remove items after use:

-- Remove 1 item
cv.inventory.removeItem(player.charId, itemName, 1)

-- Remove from specific slot
cv.inventory.removeItem(player.charId, itemName, 1, slot)

-- Remove all of the item
local hasItem, count = cv.inventory.hasItem(player.charId, itemName)
cv.inventory.removeItem(player.charId, itemName, count)

Animation Pattern

Play animations when using consumables:

-- Eating animation
TriggerClientEvent('cv_framework:hunger:playAnimation', source, 
    'mp_player_inteat@burger', 'mp_player_int_eat_burger', 3000)

-- Drinking animation
TriggerClientEvent('cv_framework:thirst:playAnimation', source, 
    'mp_player_intdrink', 'loop_bottle', 3000)

Important Notes

  1. Database Dependency: Items must exist in the item_definitions table before registration
  2. Load Order: Register usable items after the inventory module loads (in server.lua or after resource start)
  3. Global State: Usable items are stored globally and persist across resource restarts
  4. Client Sync: When items are registered after server start, item definitions are automatically broadcasted to all connected clients
  5. Default Behavior: By default, using an item closes the inventory UI
  6. Validation: Always validate player context - callbacks can be triggered even if player disconnects

Debugging

Enable debug mode to see registration logs:

Config.Debug = true

Logs will show: - [Inventory] Registered usable item: itemName - [Inventory] Registered usable item (cache updated): itemName (if cache already loaded)