Use Item Binding when an Item Object’s data should drive a public property on its GameObject. One reusable weapon prefab can therefore take its Attack from an Iron Sword or Fire Wand without a separate prefab script for each Definition.

The binding is two-way rather than a one-time copy: the Item initializes the property, reads of the bound attribute use the property, and supported attribute changes update the property. Use a custom change-event handler instead when the value needs conversion, combines several attributes, or should trigger a larger workflow.

Before you begin

Prepare one small, type-safe example:

  • The scene has an initialized Inventory System Manager and the intended database.
  • A Weapon Item Category contains an integer Item Attribute named Attack.
  • Iron Sword and Fire Wand inherit Weapon, and their Default Items provide different Attack values.
  • The weapon prefab has an Item Object and a gameplay component with a public int Attack property that has both a getter and setter.
  • Use a mutable, unique Weapon Item when each copy can change independently at runtime.

The category selected on Item Binding defines the available rows and also validates the Item assigned at runtime. Selecting Weapon accepts Definitions directly in Weapon and in its child categories.

A new component has no Item Category and therefore no binding rows. Selecting a Category generates its Item, Definition, and Category attribute entries; each object/property mapping starts unassigned at (none).

Configure the binding

  1. Select the reusable Iron Sword or Fire Wand GameObject or prefab.
  2. Add Item Object and the gameplay component that owns the target property.
  3. Add Item Binding on the same GameObject.
  4. In Database, confirm the database used by the scene’s Inventory System Manager.
  5. Set Item Category to Weapon.
  6. Open Item Attributes. On the Attack row, assign the gameplay component in the object selector, then choose its Attack property.
  7. For a Fire Wand that casts several projectiles, add an integer ProjectileCount Item Attribute to Weapon and map it to a public ProjectilesPerCast property. Iron Sword can retain the category’s default value when that property is unused.
  8. Leave unrelated rows at (none). Use Item Definition Attributes, Category Attributes, and Order only when those scopes or display order are relevant.

The legacy example below maps the integer NumOfProjectiles attribute to the BulletsPerFire property. The object and property selectors follow the same pattern as the Iron Sword and Fire Wand Attack binding.

Item Binding Inspector row mapping the NumOfProjectiles attribute to the RangeAttack component's BulletsPerFire property

Editor checkpoint: Database and Item Category are assigned, the Attack row shows the intended component and property rather than (none), and the property type exactly matches the attribute value type.

How the binding runs

The released Version 1 component follows this lifecycle:

  1. Awake deserializes each typed binding entry and creates property getter and setter delegates.
  2. Start looks for an Item Object on the same GameObject. If one exists, Item Binding registers for EventNames.c_ItemObject_OnItemChanged and binds its current Item.
  3. When ItemObject.SetItem changes the Item, Item Binding unbinds the previous attributes, checks the configured Category, and binds matching Item, Definition, and Category attributes by name.
  4. Each new binding immediately calls the property’s setter with the attribute’s unbound value. This initializes the weapon component from Iron Sword or Fire Wand.
  5. While bound, GetValue() on that attribute uses the property’s getter. A successful SetOverrideValue() on a mutable attribute also calls the property’s setter.
  6. When the Item changes or the component is destroyed, the binding reads the current property and attempts to apply it back to the old attribute before detaching.

Changing the component property does not independently raise an Item-changed event or guarantee that the property’s latest value has already been written into the Item’s serialized override. The bound attribute returns the property value when read, but persistence should synchronize deliberate gameplay changes before saving.

If no Item Object exists, Item Binding falls back to an Inventory on the same GameObject and binds the first stack in its Main collection at Start. Version 1 does not listen for later Inventory changes in this mode, so it is unsuitable for a changing selection or rotating UI slot.

Choose the right attribute scope

Scope Good use Important consequence
Item Attribute Per-copy Attack, Durability, charge, or another runtime value Make the Item mutable; use unique Items when two copies need independent values and bindings.
Item Definition Attribute A value shared by every Item created from Iron Sword or Fire Wand The same Definition attribute object can be encountered by several Item Objects, but an attribute holds only one active binding. Avoid simultaneous two-way bindings to shared data.
Category Attribute A Weapon-wide value shared across many Definitions It has the same single-active-binding limitation and is better treated as shared configuration.

Immutable, non-unique Items can be reused as one equivalent registered Item, often the Definition’s shared Default Item. They work only when the bound property is treated as stable shared data. A write is not independent per GameObject and, when accepted by the shared attribute, can affect every representation; multiple representations can also compete for its one active binding. Prefer a mutable, unique Item Attribute for an independently changing Iron Sword or Fire Wand.

The property selector shows compatible public properties returned by reflection. Use an instance property with a public getter and setter. Fields, private accessors, and methods are not binding targets. Keep the setter focused on storing or applying the value because it runs during initial binding and later refreshes.

Use bindings with world objects

  • Equipped Items: Put Item Binding on the functional prefab referenced by UsableItemPrefab, beside its Item Object and weapon behavior. When the Equipper assigns Iron Sword or Fire Wand, the prefab’s Attack property refreshes from that Item.
  • Pickups and pooled objects: A pickup with an Item Object can rebind when SetItem assigns new Item data. A valid new Item refreshes the target properties; clearing the Item does not reset them to a default value.
  • Inventory UI: Item Binding is tied to an Item Object or the one-time Inventory fallback. Use Item View modules and their Item Info redraw flow for recycled inventory-grid cells rather than relying on the first Main-collection Item.
  • Complex presentation: Use ItemObjectVisualizer for prefab or sprite replacement. Use the Item Object change event when several attributes must jointly select a model, effect, or animation.

Verify in Play Mode

  1. Assign an Iron Sword Item with Attack 20 to the Item Object. Confirm that the gameplay component’s Attack property becomes 20.
  2. Rebind the same Item Object to a Fire Wand with Attack 12. Confirm that the property changes once to 12 and the Item Object Inspector reports the Fire Wand Item.
  3. Change the bound property to 15, then read the Fire Wand’s Attack with GetValue(). Confirm that the returned value is 15.
  4. On a mutable Fire Wand, call SetOverrideValue(18) on its Attack attribute. Confirm that the property also becomes 18.
  5. Create two mutable, unique Iron Swords with different Attack overrides and bind each to a separate prefab instance. Confirm that changing one property does not affect the other.
  6. Clear an Item Object with ItemInfo.None. Confirm that no Item remains bound, and account for the target property retaining its last value until another valid Item binds or project code resets it.

Saving and multiplayer boundaries

The selected Item Category and typed binding entries are serialized with the scene object or prefab. Database is Inspector context resolved from the scene manager or editor window rather than a serialized Item Binding field. The active runtime relationship between an Item, attribute, binding delegate, and component property is not a save record.

Inventory Saver and Inventory System Manager Item Saver can preserve Inventory contents and mutable or unique Item data. They do not save an arbitrary bound component property. If gameplay changes the property directly, copy or reevaluate that value into the mutable Item attribute before the save occurs. After load, assign the restored Item to the Item Object so the binding initializes the property again.

The released Version 1 core package does not replicate Item Binding changes. In multiplayer, change the Item attribute on the authority, replicate the resolved Item identity and value, then bind or refresh the local representation. Do not let several clients independently use a shared Definition or Category attribute as live state.

Troubleshooting

Symptom Check Fix
No binding rows appear Database and Item Category Assign the active database and a Category that declares the intended attribute.
The target property is not listed Property visibility, getter/setter, and value type Expose a public instance property with the same type as the attribute; a serialized field alone is not enough.
The Item is rejected at runtime Configured Category and the Item’s direct or inherited Category Select the Item’s Category or a parent Category that inherently contains it.
Iron Sword binds but Attack does not update Attack row’s object and property selectors Assign the correct component and choose Attack instead of (none).
Fire Wand changes another weapon instance Attribute scope and Item mutability/uniqueness Move per-instance state to a Weapon Item Attribute and use separate mutable, unique Items.
A property changes but the saved Item restores an older value Whether the bound value was written to the Item before saving Explicitly update or reevaluate the mutable Item attribute, then save the Inventory and Item data.
A pooled object shows an old value after being cleared Item Object contains no valid Item, so no new value was applied Reset the component when clearing, or assign the next valid Item before showing the object.
Inventory fallback never follows a changed first Item Item Binding only inspects the Main collection once at Start Use an Item Object and call SetItem, or write a listener that rebinds when the collection changes.
Replacing the Item Object source through SetItemObject does not work Released V1 only handles initial source assignment reliably Keep Item Binding beside its automatic Item Object; use a custom binding component for a dynamically replaced source.

Developer details

Item Binding binds properties, not fields. A small target component can expose serialized backing fields through public properties:

using UnityEngine;

public class WeaponRuntimeSettings : MonoBehaviour
{
    [SerializeField] private int m_Attack;
    [SerializeField] private int m_ProjectilesPerCast = 1;

    public int Attack
    {
        get => m_Attack;
        set => m_Attack = value;
    }

    public int ProjectilesPerCast
    {
        get => m_ProjectilesPerCast;
        set => m_ProjectilesPerCast = value;
    }
}

The Inspector serializes one typed AttributeBinding<T> entry per Category attribute. Each entry stores the attribute name, bound Unity object, and property path. GenericAttributeBinding<T> provides the equivalent API for a non-Unity object, while ItemCategoryAttributeNameBinding and AttributeNameBinding bind an attribute’s name to a string property rather than binding its value.

ItemBinding.Initialize(bool force) rebuilds the runtime delegates, while Item, ItemObject, ItemCategory, and AttributeBindings expose the current state. SetItemObject is public, but released Version 1 unregisters and returns when a source is already assigned, so it should not be treated as a general hot-swap API.

With Opsive.UltimateInventorySystem.Core.AttributeSystem imported, a mutable Item Attribute can reevaluate its bound getter and store a direct property change before saving:

var attackAttribute = item.GetAttribute<Attribute<int>>(
    "Attack", false, false);

attackAttribute?.ReevaluateValue(true);

For transformations or multi-attribute logic, listen to the Item Object change event and update the component explicitly:

using Opsive.UltimateInventorySystem.Core;
using EventHandler = Opsive.Shared.Events.EventHandler;

private void OnEnable()
{
    EventHandler.RegisterEvent(
        m_ItemObject,
        EventNames.c_ItemObject_OnItemChanged,
        RefreshWeapon);

    RefreshWeapon();
}

private void OnDisable()
{
    EventHandler.UnregisterEvent(
        m_ItemObject,
        EventNames.c_ItemObject_OnItemChanged,
        RefreshWeapon);
}

private void RefreshWeapon()
{
    var item = m_ItemObject.Item;
    if (item != null && item.TryGetAttributeValue("Attack", out int attack)) {
        m_WeaponRuntimeSettings.Attack = attack;
    }
}

This event-driven route is clearer when Attack needs scaling, several attributes determine one result, or the component should reset when the Item is cleared.