> For the complete documentation index, see [llms.txt](https://docs.vames-store.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.vames-store.com/assets/vms_needs/guides/creating-a-custom-item-behavior.md).

# Creating a Custom Item Behavior

Item behaviors allow you to create completely custom interaction logic for items registered in `Config.Items`.

A behavior can define available controls, spawned objects, placement support, placed-object actions, primary interactions, custom actions, and cancellation logic.

Behavior files are located in: **shared/behaviors/**

After creating a behavior, register it using `RegisterBehavior` and assign its name to the item’s `behavior` option.

***

### 1. Create the Behavior

```lua
local CustomBehavior = {}
```

A behavior is a Lua table containing the methods used by VMS Needs during the item interaction lifecycle.

<table><thead><tr><th width="195.39990234375">Method</th><th width="106.60009765625">Required</th><th>Purpose</th></tr></thead><tbody><tr><td><code>GetControls</code></td><td>No</td><td>Defines the available interaction controls and item description.</td></tr><tr><td><code>PrimaryAction</code></td><td>No</td><td>Handles the primary <code>use</code> action.</td></tr><tr><td><code>HandleAction</code></td><td>No</td><td>Handles additional named controls.</td></tr><tr><td><code>GetObjects</code></td><td>No</td><td>Defines which objects should be spawned and attached.</td></tr><tr><td><code>CanPlace</code></td><td>No</td><td>Determines whether the item can currently be placed.</td></tr><tr><td><code>PlacedActions</code></td><td>No</td><td>Adds actions to an item after it has been placed.</td></tr><tr><td><code>CancelAction</code></td><td>No</td><td>Defines what happens when the player cancels item usage.</td></tr></tbody></table>

Only implement the methods required by your custom interaction.

### 2. GetControls

```lua
function CustomBehavior:GetControls()
    local controls = {
        {
            key = 'E',
            label = 'Primary Action',
            name = 'use',
        },
        {
            key = 'G',
            label = 'Custom Action',
            name = 'example_control',
        },
    }

    local description = 'Example description'

    return controls, description
end
```

<details>

<summary>Returned values</summary>

<table><thead><tr><th width="135">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>controls</code></td><td>List of controls available for the current item.</td></tr><tr><td><code>description</code></td><td>Optional text displayed alongside the controls.</td></tr></tbody></table>

</details>

<details>

<summary>Control fields</summary>

<table><thead><tr><th width="134.9998779296875">Field</th><th>Description</th></tr></thead><tbody><tr><td><code>key</code></td><td>Keyboard key displayed and listened for by the controls system.</td></tr><tr><td><code>label</code></td><td>Text displayed to the player. Use <code>TRANSLATE(...)</code> for localized labels.</td></tr><tr><td><code>name</code></td><td>Internal action identifier passed to the behavior.</td></tr></tbody></table>

</details>

The action named `use` calls `PrimaryAction`. Other action names are passed to `HandleAction`.

### 3. PrimaryAction

`PrimaryAction` is called when the player activates the control with the action name `use`.

```lua
function CustomBehavior:PrimaryAction()
    print('Player used the primary action')
end
```

For consumable items, you can call the internal `ConsumeItem` function to use the configured animations and status changes.

{% code expandable="true" %}

```lua
function CustomBehavior:PrimaryAction()
    ConsumeItem(function(action)
        if action == 'started' then
            print('Consumption started')
        elseif action == 'finished' then
            print('Consumption finished')
        end
    end)
end
```

{% endcode %}

### 4. HandleAction

`HandleAction` receives all named controls other than the primary `use` action.

```lua
function CustomBehavior:HandleAction(action)
    if action == 'example_control' then
        print('Player used the custom action')
    end
end
```

The `action` value matches the `name` configured in `GetControls`.

### 5. GetObjects

`GetObjects` defines the objects spawned while the item is being used.

{% code expandable="true" %}

```lua
function CustomBehavior:GetObjects(data)
    local item = Config.Items[data.name]

    return {
        {
            model = item.models.default,
            attach = item.attaches.hand,
        },
    }
end
```

{% endcode %}

<details>

<summary>Parameters</summary>

<table><thead><tr><th width="184.5999755859375">Field</th><th>Description</th></tr></thead><tbody><tr><td><code>data.name</code></td><td>Current item name.</td></tr><tr><td><code>data.metadata</code></td><td>Current item metadata.</td></tr><tr><td><code>data.visualState</code></td><td>Optional visual state requested by the behavior.</td></tr></tbody></table>

</details>

<details>

<summary>Returned object fields</summary>

<table><thead><tr><th width="184.5999755859375">Field</th><th>Description</th></tr></thead><tbody><tr><td><code>model</code></td><td>Model name or hash to spawn.</td></tr><tr><td><code>attach</code></td><td>Attachment configuration used for the object.</td></tr></tbody></table>

</details>

<details>

<summary>Advanced Example - Dynamic Model</summary>

{% code expandable="true" %}

```lua
function CustomBehavior:GetObjects(data)
    local item = Config.Items[data.name]
    local visualState = data.visualState or 'hand'

    local model

    if data.metadata.isLit then
        model = Object.GetVisualModel(
            item.models.joint.lit,
            data.metadata.value,
            item.size
        )
    else
        model = item.models.joint.unlit
    end

    return {
        {
            model = model,
            attach = item.attaches[visualState],
        },
    }
end
```

{% endcode %}

This example changes the model according to item metadata and remaining item size.

</details>

### 6. CanPlace

`CanPlace` determines whether the currently used item can be placed in the world.

```lua
function CustomBehavior:CanPlace()
    return true
end
```

Return `true` to allow placement or `false` to prevent it.

### 7. PlacedActions

`PlacedActions` defines the interactions available after the item has been placed in the world.

```lua
function CustomBehavior:PlacedActions(item)
    return {
        allowDefault = {
            take = false,
            pour = false,
        },

        options = {
            {
                name = 'custom_action',
                icon = 'fa-solid fa-xmark',
                label = 'sweep_away',
                actionControl = 'H',
                distance = 2.0,

                action = function()
                    print('Player used the placed-item action')
                end,

                canInteract = function()
                    return not currentItem.name
                end,
            },
        },
    }
end
```

<details>

<summary>allowDefault</summary>

<table><thead><tr><th width="144.60009765625">Field</th><th>Description</th></tr></thead><tbody><tr><td><code>take</code></td><td>Enables the built-in action for picking up the placed item.</td></tr><tr><td><code>pour</code></td><td>Enables the built-in pouring action when supported.</td></tr></tbody></table>

</details>

<details>

<summary>Custom option fields</summary>

<table><thead><tr><th width="144.5999755859375">Field</th><th>Description</th></tr></thead><tbody><tr><td><code>name</code></td><td>Unique action identifier.</td></tr><tr><td><code>icon</code></td><td>Target-system icon.</td></tr><tr><td><code>label</code></td><td>Translation suffix used by the target and 3D Text modules.</td></tr><tr><td><code>actionControl</code></td><td>Key used for the 3D Text interaction.</td></tr><tr><td><code>distance</code></td><td>Maximum interaction distance.</td></tr><tr><td><code>action</code></td><td>Function executed after selecting the action.</td></tr><tr><td><code>canInteract</code></td><td>Optional function determining whether the action is currently available.</td></tr></tbody></table>

</details>

{% hint style="info" %}
For `label = 'sweep_away'`, the system uses `target.sweep_away` or `3dtext.sweep_away`, depending on the active interaction system.
{% endhint %}

### 8. PackClientMetadata

`PackClientMetadata` allows a behavior to send only the metadata required on the client after a placed item is synchronized.

By default, VMS Needs does **not** send the complete metadata of placed items to clients in order to minimize the amount of data transferred during the initial synchronization. If your behavior requires specific metadata on the client (for example, to determine available interactions in `PlacedActions`), return only the required values from this function.

```lua
function CustomBehavior:PackClientMetadata(metadata)
    if metadata and metadata.isLine then
        return {
            isLine = true
        }
    end

    return nil
end
```

Return a table containing only the metadata required by the client, or `nil` if no metadata needs to be synchronized.

### 9. CancelAction

`CancelAction` defines what happens when the player closes or cancels the current item interaction.

{% code expandable="true" %}

```lua
function CustomBehavior:CancelAction()
    print('Player canceled item usage')

    CancelUsage()
end
```

{% endcode %}

`CancelUsage()` hides or returns the item according to its current state and configured item behavior.

{% code expandable="true" %}

```lua
function CustomBehavior:CancelAction()
    ThrowItem()
end
```

{% endcode %}

Use `ThrowItem()` when the item should be discarded instead of returned to the inventory.

### 10. Register the Behavior

{% code expandable="true" %}

```lua
RegisterBehavior('custom_behavior', CustomBehavior)
```

{% endcode %}

The registration name must match the `behavior` option configured for the item.

{% code expandable="true" %}

```lua
['my_item'] = {
    behavior = 'custom_behavior',

    -- Other item configuration...
}
```

{% endcode %}

### 11. Complete Example

{% code expandable="true" %}

```lua
local CustomBehavior = {}

function CustomBehavior:GetControls()
    return {
        {
            key = 'E',
            label = 'Use',
            name = 'use',
        },
        {
            key = 'G',
            label = 'Custom Action',
            name = 'custom_action',
        },
        {
            key = Config.Controls.MAIN.CANCEL,
            label = 'Put Away',
            name = 'cancel',
        },
    }, 'Custom item'
end

function CustomBehavior:GetObjects(data)
    local item = Config.Items[data.name]

    return {
        {
            model = item.models.default,
            attach = item.attaches.hand,
        },
    }
end

function CustomBehavior:PrimaryAction()
    print('Primary action used')
end

function CustomBehavior:HandleAction(action)
    if action == 'custom_action' then
        print('Custom action used')
    end
end

function CustomBehavior:CanPlace()
    return true
end

function CustomBehavior:CancelAction()
    CancelUsage()
end

RegisterBehavior('custom_behavior', CustomBehavior)
```

{% endcode %}

**Behavior-specific configuration**

A custom behavior decides which entries are required inside `models`, `attaches`, `animation`, and `particles`. When creating a new behavior, you are responsible for reading and using those configuration entries inside the behavior file.

We recommend copying the built-in behavior closest to your intended interaction and using it as a starting point.
