# Ultimate Inventory System - Opsive Documentation

> Complete Ultimate Inventory System documentation, generated from the Opsive documentation source on 2026-08-14.

Documentation home: https://opsive.com/support/documentation/ultimate-inventory-system/

## Contents

- [Ultimate Inventory System](#page-ultimate-inventory-system)
  - [Getting Started](#page-ultimate-inventory-system-getting-started)
    - [Installing and Requirements](#page-ultimate-inventory-system-getting-started-installing-and-requirements)
    - [Your First Inventory](#page-ultimate-inventory-system-getting-started-first-inventory)
    - [First Inventory UI](#page-ultimate-inventory-system-getting-started-first-inventory-ui)
    - [The Data Model at a Glance](#page-ultimate-inventory-system-getting-started-data-model-at-a-glance)
    - [Choose a Workflow](#page-ultimate-inventory-system-getting-started-choose-a-workflow)
    - [Getting Started Troubleshooting](#page-ultimate-inventory-system-getting-started-troubleshooting)
    - [Terminology](#page-ultimate-inventory-system-getting-started-terminology)
    - [Demo Scene](#page-ultimate-inventory-system-getting-started-demo-scene)
    - [New Database](#page-ultimate-inventory-system-getting-started-new-database)
    - [Defining Attributes](#page-ultimate-inventory-system-getting-started-defining-attributes)
    - [UI Customization](#page-ultimate-inventory-system-getting-started-ui-customization)
    - [Version 1.1 Update Guide](#page-ultimate-inventory-system-getting-started-version-1-1-update-guide)
    - [Version 1.2 Update Guide](#page-ultimate-inventory-system-getting-started-version-1-2-update-guide)
  - [Editor Window](#page-ultimate-inventory-system-editor-window)
    - [Attributes](#page-ultimate-inventory-system-editor-window-attributes)
    - [Item Category](#page-ultimate-inventory-system-editor-window-item-category)
    - [Item Definition](#page-ultimate-inventory-system-editor-window-item-definition)
    - [Crafting Category](#page-ultimate-inventory-system-editor-window-crafting-category)
    - [Crafting Recipe](#page-ultimate-inventory-system-editor-window-crafting-recipe)
    - [Currency](#page-ultimate-inventory-system-editor-window-currency)
    - [UI Designer](#page-ultimate-inventory-system-editor-window-ui-designer)
      - [Schemas](#page-ultimate-inventory-system-editor-window-ui-designer-schemas)
        - [Classic](#page-ultimate-inventory-system-editor-window-ui-designer-schemas-classic)
        - [RPG](#page-ultimate-inventory-system-editor-window-ui-designer-schemas-rpg)
      - [Main Menu](#page-ultimate-inventory-system-editor-window-ui-designer-main-menu)
      - [Inventory Grid](#page-ultimate-inventory-system-editor-window-ui-designer-inventory-grid)
      - [Item Shape Grid](#page-ultimate-inventory-system-editor-window-ui-designer-item-shape-grid)
      - [Equipment](#page-ultimate-inventory-system-editor-window-ui-designer-equipment)
      - [Item Hotbar](#page-ultimate-inventory-system-editor-window-ui-designer-item-hotbar)
      - [Shop](#page-ultimate-inventory-system-editor-window-ui-designer-shop)
      - [Crafting](#page-ultimate-inventory-system-editor-window-ui-designer-crafting)
      - [Save](#page-ultimate-inventory-system-editor-window-ui-designer-save)
      - [Storage](#page-ultimate-inventory-system-editor-window-ui-designer-storage)
      - [Chest](#page-ultimate-inventory-system-editor-window-ui-designer-chest)
      - [Item Description](#page-ultimate-inventory-system-editor-window-ui-designer-item-description)
      - [Currency](#page-ultimate-inventory-system-editor-window-ui-designer-currency)
      - [Inventory Monitor](#page-ultimate-inventory-system-editor-window-ui-designer-inventory-monitor)
      - [Item View](#page-ultimate-inventory-system-editor-window-ui-designer-item-view)
      - [Attribute View](#page-ultimate-inventory-system-editor-window-ui-designer-attribute-view)
      - [Item View Slots Container](#page-ultimate-inventory-system-editor-window-ui-designer-item-view-slots-container)
    - [Import & Export](#page-ultimate-inventory-system-editor-window-import-export)
    - [Editor Options by Feature](#page-ultimate-inventory-system-editor-window-editor-options-reference)
  - [Inventory System Manager](#page-ultimate-inventory-system-inventory-system-manager)
  - [Inventory](#page-ultimate-inventory-system-inventory)
    - [Item Collections](#page-ultimate-inventory-system-inventory-item-collections)
      - [Item Slot Collection](#page-ultimate-inventory-system-inventory-item-collections-item-slot-collection)
      - [Item Transaction Collection](#page-ultimate-inventory-system-inventory-item-collections-item-transaction-collection)
      - [Multi Stack Item Collection](#page-ultimate-inventory-system-inventory-item-collections-multi-stack-item-collection)
    - [Item Restrictions](#page-ultimate-inventory-system-inventory-item-restrictions)
      - [Dynamic Inventory Size](#page-ultimate-inventory-system-inventory-item-restrictions-dynamic-inventory-size)
  - [Item](#page-ultimate-inventory-system-item)
    - [Item Info](#page-ultimate-inventory-system-item-item-info)
    - [Item Upgrades](#page-ultimate-inventory-system-item-item-upgrades)
    - [Item Skills](#page-ultimate-inventory-system-item-item-skills)
    - [Item Stats](#page-ultimate-inventory-system-item-item-stats)
  - [Item Actions](#page-ultimate-inventory-system-item-actions)
    - [Built-in Item Actions](#page-ultimate-inventory-system-item-actions-built-in-item-actions)
  - [Item Objects](#page-ultimate-inventory-system-item-objects)
    - [Item Object Behaviour Handler](#page-ultimate-inventory-system-item-objects-usable-item-objects)
    - [Equipping Items](#page-ultimate-inventory-system-item-objects-equipping-items)
    - [Item Binding](#page-ultimate-inventory-system-item-objects-item-binding)
    - [Item Pickups](#page-ultimate-inventory-system-item-objects-item-pickups)
    - [Item and Currency Droppers](#page-ultimate-inventory-system-item-objects-item-and-currency-droppers)
      - [Custom Random Item Dropper](#page-ultimate-inventory-system-item-objects-item-and-currency-droppers-custom-random-item-dropper)
    - [Item Object Visualizer](#page-ultimate-inventory-system-item-objects-item-object-view)
  - [Attributes](#page-ultimate-inventory-system-attributes)
    - [Common Attributes](#page-ultimate-inventory-system-attributes-common-attribute-types)
  - [Currency](#page-ultimate-inventory-system-currency)
    - [Shop](#page-ultimate-inventory-system-currency-shop)
  - [Crafting](#page-ultimate-inventory-system-crafting)
    - [Custom Crafting Processors](#page-ultimate-inventory-system-crafting-custom-crafting-processors)
  - [Input](#page-ultimate-inventory-system-input)
    - [Handlers](#page-ultimate-inventory-system-input-handlers)
    - [Split Screen Co-op UI](#page-ultimate-inventory-system-input-split-screen-co-op-ui)
  - [Audio](#page-ultimate-inventory-system-audio)
  - [Save System](#page-ultimate-inventory-system-save-system)
  - [Interaction System](#page-ultimate-inventory-system-interaction-system)
  - [User Interface (UI)](#page-ultimate-inventory-system-ui)
    - [Display Panel & Manager](#page-ultimate-inventory-system-ui-display-panel-manager)
    - [Item View Slots Container](#page-ultimate-inventory-system-ui-item-view-slots-container)
      - [Item View Slot](#page-ultimate-inventory-system-ui-item-view-slots-container-item-view-slot)
      - [Inventory Grid](#page-ultimate-inventory-system-ui-item-view-slots-container-inventorygrid)
        - [Item Shape Inventory Grid](#page-ultimate-inventory-system-ui-item-view-slots-container-inventorygrid-item-shape-inventory-grid)
      - [Item Hotbar](#page-ultimate-inventory-system-ui-item-view-slots-container-item-hotbar)
        - [Hotbars](#page-ultimate-inventory-system-ui-item-view-slots-container-item-hotbar-hotbars)
      - [Item Slot Collection View (Equipment)](#page-ultimate-inventory-system-ui-item-view-slots-container-item-slot-collection-view-equipment)
      - [Move Items (Drag & Drop)](#page-ultimate-inventory-system-ui-item-view-slots-container-move-items-drag-drop)
      - [ItemInfo Filters and Sorters](#page-ultimate-inventory-system-ui-item-view-slots-container-item-info-filter-sorters)
      - [Item Shape Grid](#page-ultimate-inventory-system-ui-item-view-slots-container-item-shape-grid)
    - [Views](#page-ultimate-inventory-system-ui-views)
      - [Item View](#page-ultimate-inventory-system-ui-views-item-view)
      - [Attribute View](#page-ultimate-inventory-system-ui-views-attribute-views)
      - [Recipe View](#page-ultimate-inventory-system-ui-views-recipe-box)
      - [Multi Currency View](#page-ultimate-inventory-system-ui-views-multi-currency-view)
      - [Save View](#page-ultimate-inventory-system-ui-views-save-view)
    - [Item Description](#page-ultimate-inventory-system-ui-item-description)
    - [Inventory and Currency Monitors](#page-ultimate-inventory-system-ui-monitors)
    - [Main Menu](#page-ultimate-inventory-system-ui-main-menu)
    - [Shop Menu](#page-ultimate-inventory-system-ui-shop-menu)
    - [Save Menu](#page-ultimate-inventory-system-ui-save-menu)
    - [Storage Menu](#page-ultimate-inventory-system-ui-storage-menu)
    - [Chest Menu](#page-ultimate-inventory-system-ui-chest-menu)
    - [Crafting Menu](#page-ultimate-inventory-system-ui-crafting-menu)
    - [Menu Character](#page-ultimate-inventory-system-ui-menu-character)
  - [ResizableArray and ListSlice](#page-ultimate-inventory-system-resizeablearrays-and-listslices)
  - [Events](#page-ultimate-inventory-system-events)
  - [Spawn Player](#page-ultimate-inventory-system-spawn-player)
  - [Scene Transitions](#page-ultimate-inventory-system-scene-transitions)
  - [Integrations](#page-ultimate-inventory-system-integrations)
    - [Behavior Designer Pro](#page-ultimate-inventory-system-integrations-behavior-designer)
    - [Bolt](#page-ultimate-inventory-system-integrations-bolt)
    - [Dialogue System](#page-ultimate-inventory-system-integrations-dialogue-system)
    - [Input System](#page-ultimate-inventory-system-integrations-input-system)
    - [Master Audio](#page-ultimate-inventory-system-integrations-master-audio)
    - [PlayMaker](#page-ultimate-inventory-system-integrations-playmaker)
    - [Quest Machine](#page-ultimate-inventory-system-integrations-quest-machine)
    - [Save System Integration](#page-ultimate-inventory-system-integrations-save-system-integration)
    - [State Designer](#page-ultimate-inventory-system-integrations-state-designer)
    - [Ultimate Character Controller](#page-ultimate-inventory-system-integrations-opsive-character-controllers)
    - [Unity Localization](#page-ultimate-inventory-system-integrations-unity-localization)

---

<a id="page-ultimate-inventory-system"></a>

# Ultimate Inventory System

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/)

Ultimate Inventory System helps you define items once and use them across inventories, equipment, user interfaces, crafting, shops, pickups, and saved games. Use it when a project needs a modular inventory workflow that can be organized in the Unity editor without requiring code for the core setup. The minimum required Unity version is 2022.3.

The documentation examples use one recognizable database: **Consumable** and **Equippable/Weapon** categories; **Health Potion**, **Iron Sword**, and **Fire Wand** definitions; **Icon**, **Description**, **Attack**, **Durability**, and **Buy Price** attributes; **Bag** and **Equipment** collections; **Gold**; one shop; and one simple recipe.

## Start here

1. Follow [Installing and Requirements](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/installing-and-requirements/) and confirm that UIS, Opsive Shared, and the editor tools compile cleanly.
2. Build [Your First Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/first-inventory/) with one Health Potion in one Bag collection.
3. Add the [First Inventory UI](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/first-inventory-ui/) and verify that the same runtime Item appears in a generated grid.
4. Use [The Data Model at a Glance](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/data-model-at-a-glance/) before expanding the database.
5. Choose the next route from [Choose a Workflow](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/choose-a-workflow/).

Use [Getting Started Troubleshooting](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/troubleshooting/) to trace a missing Item from database registration through Inventory, collection, and UI ownership.

Once that foundation is in place, choose the workflow below that matches what you are building next.

## Understand the data model

- [Item](https://opsive.com/support/documentation/ultimate-inventory-system/item/) explains Categories, Definitions, item instances, inheritance, and the terminology used throughout the system.
- [Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/) explains the named values that describe items and how those values are inherited or overridden.
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/) explains how Item Collections such as Bag and Equipment form an Inventory.
- [Currency](https://opsive.com/support/documentation/ultimate-inventory-system/currency/) covers currencies such as Gold and the exchange of items through shops.

## Work in the editor

- [Editor Window](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/) covers creating, finding, organizing, filtering, and removing database objects.
- [Inventory System Manager](https://opsive.com/support/documentation/ultimate-inventory-system/inventory-system-manager/) explains the scene-level manager that connects the database and inventory systems.
- [Item Objects](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/) connects an item to a GameObject for pickups, equipped objects, and other visible world representations.

## Build UI and runtime interaction

- [User Interface](https://opsive.com/support/documentation/ultimate-inventory-system/ui/) introduces the modular inventory UI and UI Designer workflows.
- [Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/) covers commands a player can perform on an item from an Inventory.
- [Input](https://opsive.com/support/documentation/ultimate-inventory-system/input/) explains how player input opens and controls inventory interfaces.
- [Interaction System](https://opsive.com/support/documentation/ultimate-inventory-system/interaction-system/) covers pickups, chests, menus, and other interactions between the player and inventory objects.
- [Spawn Player](https://opsive.com/support/documentation/ultimate-inventory-system/spawn-player/) explains setups where the player or inventory UI is created after the scene loads.

## Add inventory systems

- [Crafting](https://opsive.com/support/documentation/ultimate-inventory-system/crafting/) covers recipes, ingredients, and crafting results.
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/) explains saving and restoring inventory state.
- [Scene Transitions](https://opsive.com/support/documentation/ultimate-inventory-system/scene-transitions/) covers keeping inventory data when moving between scenes.
- [Audio](https://opsive.com/support/documentation/ultimate-inventory-system/audio/) explains inventory-specific audio configuration and the shared Opsive audio system.
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/) lists the event systems available for reacting to inventory changes.

## Connect other assets and developer systems

- [Integrations](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/) routes to supported Opsive and third-party connections.
- [ResizeableArrays and ListSlices](https://opsive.com/support/documentation/ultimate-inventory-system/resizeablearrays-and-listslices/) documents the specialized collection types used by developer-facing inventory APIs.

---

<a id="page-ultimate-inventory-system-getting-started"></a>

# Getting Started

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/)

Use this section to move from an installed Ultimate Inventory System package to a small inventory that you can inspect in the editor and verify in Play Mode. The recommended route starts with the data model, creates a project database, then connects that data to an Inventory and UI.

Ultimate Inventory System is installed as a package. Its package content is available under `Packages/Opsive Ultimate Inventory System`; keep project-specific databases, prefabs, and other edited assets in your own project folders.

## Recommended route

1. Confirm the package and project baseline on [Installing and Requirements](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/installing-and-requirements/).
2. Follow [Your First Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/first-inventory/) to create one Health Potion in one Bag and verify it in Play Mode.
3. Add the [First Inventory UI](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/first-inventory-ui/) and verify the same Item in a generated grid.
4. Read [The Data Model at a Glance](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/data-model-at-a-glance/), then use the full [Terminology](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/terminology/) reference when a type or relationship is unfamiliar.
5. Explore the [Demo Scene](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/demo-scene/) after the small route works. Treat it as a reference rather than as the project database.
6. Follow [New Database](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/new-database/) and [Defining Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/) to expand the starter catalog deliberately.
7. Choose the next feature from [Choose a Workflow](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/choose-a-workflow/).

Use the page for the feature you are editing when a less-visible control is unfamiliar. [New Database](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/new-database/) explains database-field actions, [Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/attributes/) explains its row, cog, and removal menus, and [UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/) explains target selection and generated UI controls.

Add [Currency](https://opsive.com/support/documentation/ultimate-inventory-system/currency/), [Item Objects](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/), [Crafting](https://opsive.com/support/documentation/ultimate-inventory-system/crafting/), and the [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/) after the basic database, Inventory, and UI path works.

Use [Getting Started Troubleshooting](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/troubleshooting/) when an Item exists in one layer but is missing from the next.

## Start with the demo or a clean database

Choose the demo when you need a working reference for a feature. Import it from **Tools > Opsive > Ultimate Inventory System > Main Manager > Setup**. The sample scenes require TextMesh Pro and use the Universal Render Pipeline; projects on another render pipeline may need material and camera adjustments.

The demo depends on `DemoInventoryDatabase` and includes demo-specific scripts and objects. Avoid modifying those package or sample assets for production work. Create or duplicate a database into a project-owned folder before adapting the content.

Choose a clean database when you already understand the sample flow and want the smallest project-specific starting point. The New Database guide builds the shared examples used throughout this documentation.

## Editor checkpoints

Before entering Play Mode, confirm that:

- The Setup manager references the intended project database.
- The category hierarchy contains **All**, **Consumable**, **Equippable**, and **Weapon**.
- **Health Potion** uses **Consumable**; **Iron Sword** and **Fire Wand** use **Weapon**.
- The scene's Inventory System Manager references the same database.
- The player Inventory has the intended **Bag** and **Equipment** collections.
- The UI Designer setup has created the required canvas managers and the spawned UI reads from the player Inventory.

These checkpoints separate data problems from scene or UI problems. If a definition is missing an expected field, check its category and inherited attributes first. If the definition exists but does not appear at runtime, check the database and Inventory references. If the Item exists in the Inventory but is not visible, check the UI data source and generated view setup.

## Verify in Play Mode

Run one small end-to-end scenario before expanding the database:

1. Start with Health Potion and Iron Sword Items in **Bag**.
2. Open the inventory UI and confirm that both Items show the expected Icon and Description.
3. Equip Iron Sword and confirm that it moves to **Equipment** while Health Potion remains in **Bag**.
4. If Gold and Buy Price are configured, confirm that the currency and price appear in the relevant shop UI.

Once this works, add Fire Wand or another definition using the same **Weapon** inheritance instead of creating a new structure for every Item.

## Current getting-started guides

- [Installing and Requirements](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/installing-and-requirements/) verifies the released package and project baseline.
- [Your First Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/first-inventory/) creates the smallest database-to-Bag runtime result.
- [First Inventory UI](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/first-inventory-ui/) displays that Bag through UI Designer.
- [The Data Model at a Glance](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/data-model-at-a-glance/) provides the beginner mental model.
- [Choose a Workflow](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/choose-a-workflow/) routes by project goal.
- [Getting Started Troubleshooting](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/troubleshooting/) traces database, manager, Inventory, collection, and UI problems.
- [Terminology](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/terminology/) explains the UIS data model and the role of each object.
- [Demo Scene](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/demo-scene/) provides a working reference for the major systems.
- [UI Customization](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/ui-customization/) identifies the prefabs, views, and action sets that control the runtime UI.
- [New Database](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/new-database/) creates a project-owned catalog and starter categories.
- [Defining Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/) helps place shared and per-Item data correctly.

## Historical update guides

These guides are for projects upgrading from older UIS versions. They are not part of a new installation workflow.

- [Version 1.1 Update Guide](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/version-1-1-update-guide/)
- [Version 1.2 Update Guide](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/version-1-2-update-guide/)
- [Version 1.3 Update Guide](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/version-1-3-update-guide/) is a draft source and remains unpublished.

## Video overview

<iframe width="100%" height="600" src="https://www.youtube.com/embed/B27jtFOVljQ?rel=0&amp;list=PLCPL5IYZm1NKeRsX842Y3I7lAslYM-p9Q&amp;index=2" title="Ultimate Inventory System overview video" loading="lazy" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>

If the embedded player is unavailable, [watch the Ultimate Inventory System overview on YouTube](https://www.youtube.com/watch?v=B27jtFOVljQ&list=PLCPL5IYZm1NKeRsX842Y3I7lAslYM-p9Q&index=2).

---

<a id="page-ultimate-inventory-system-getting-started-installing-and-requirements"></a>

# Installing and Requirements

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/installing-and-requirements/)

Install the released Ultimate Inventory System Version 1 package and confirm that its editor, runtime, and Opsive Shared dependency compile before creating database or scene content.

## Requirements

- **Unity:** Use Unity 2022.3 or newer for the current released documentation baseline.
- **Packages:** Install one copy of Ultimate Inventory System Version 1 and its matching Opsive Shared package.
- **Compilation:** Resolve every Console compiler error before opening Main Manager or importing optional integrations.
- **Sample:** The demo requires TextMesh Pro and uses Universal Render Pipeline content.
- **Project ownership:** Keep project databases, prefabs, UI schemas, and edited assets under project-owned `Assets` folders rather than modifying package content.

These pages document released UIS Version 1. Version 2 development APIs and editor labels are not interchangeable with the current package.

## Install the package

1. Import or install the UIS package supplied through the Opsive download workflow.
2. Allow Unity to import UIS and Opsive Shared completely.
3. Wait for compilation to finish before importing integrations, samples, or copied project scripts.
4. Confirm that **Tools > Opsive > Ultimate Inventory System > Main Manager** and **UI Designer** are available.
5. Open Main Manager and confirm that Setup, Item Categories, Item Definitions, Currencies, Crafting data, Integrations, and the other installed Version 1 editors load without exceptions.

Do not combine package files from different UIS or Shared releases. An older integration should also be removed before importing its current replacement so duplicate types cannot hide the core package result.

## Verify the project structure

The runtime package appears under `Packages/Opsive Ultimate Inventory System` or the corresponding package entry. Treat it as package-owned content. Create a project folder such as `Assets/MyGame/Inventory` for the Inventory System Database, duplicated UI schema, Item prefabs, and project scripts.

## Import the optional demo

1. Open **Tools > Opsive > Ultimate Inventory System > Main Manager**.
2. Select **Setup** and import the Demo sample.
3. Install TextMesh Pro and its essential resources when prompted.
4. Confirm that the active render pipeline can display the sample's URP materials, or use the demo only as a structural reference in another pipeline.
5. Open the sample from its versioned `Assets/Samples` folder.

The sample uses `DemoInventoryDatabase` and demo-specific scripts. Reimport it when it is changed accidentally; do not turn the versioned sample folder into production content.

## Installation checkpoint

Before creating a database, confirm that:

- the Console has no compiler errors;
- Main Manager and UI Designer open;
- UIS and Opsive Shared exist once;
- the project-owned inventory folder exists; and
- any imported sample opens without missing-package errors.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| Main Manager is missing. | UIS package import and compiler errors. | Reimport the matching package and resolve the first Console error. |
| Duplicate type or assembly errors appear. | Multiple UIS, Shared, or integration copies. | Keep one matching release and remove the incomplete/older duplicate before reimporting. |
| Demo text is missing. | TextMesh Pro package and essential resources. | Install/import TMP, then reopen the sample. |
| Demo materials are pink. | Active render pipeline and sample URP materials. | Use a compatible URP setup or treat the demo as a structural reference. |
| Project edits disappear after an update. | Assets were edited under Packages or a versioned sample folder. | Duplicate/create them in a project-owned `Assets` folder. |

## Next step

Continue with [Your First Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/first-inventory/).

---

<a id="page-ultimate-inventory-system-getting-started-first-inventory"></a>

# Your First Inventory

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/first-inventory/)

Create one Health Potion definition, add one Bag collection to a player, and verify the runtime Item without building equipment, shops, crafting, saving, or a custom UI.

## Before you begin

- Complete [Installing and Requirements](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/installing-and-requirements/).
- Create a project-owned folder for the database.
- Use a saved test scene.

## Create the database

1. Open **Tools > Opsive > Ultimate Inventory System > Main Manager**.
2. Select **Setup**.
3. Under **Inventory System Database**, select **New** and save `GameInventoryDatabase` in the project folder created before opening the dialog.
4. Confirm that the new database remains selected.

![The UIS Setup manager exposes the Inventory System Database field and New button.](https://opsive.com/wp-content/uploads/2020/04/NewDatabase.png?v=dedd9f6255bf)

The new database contains the broad **All** category with common Icon and Description definition attributes.

## Create one category and definition

1. Open **Item Categories** and add `Consumable` below **All**.
2. Open **Item Definitions** and add `Health Potion`.
3. Assign **Consumable** as its category.
4. Set a clear Description and assign an Icon when an appropriate Sprite is available.

Do not add Attack, Durability, equipment, currency, or crafting data to this definition. The purpose of the first Item is to prove the catalog and Inventory connection.

![The UIS Item Definition editor shows a definition's category, attributes, and relationships.](https://opsive.com/wp-content/uploads/2020/04/ItemDefinitionEditor.png?v=2482860ad560)

## Add the scene manager

1. Return to Main Manager > **Setup**.
2. Under **Scene Setup**, select **Add Components**.
3. Select the generated `Game` GameObject.
4. Confirm that **Inventory System Manager > Database** references `GameInventoryDatabase`.
5. Keep **Pre Evaluate Attributes** enabled.

Use one active Inventory System Manager for this scene. The manager registers definitions; it does not own the player's Bag.

## Add the player Inventory

1. Create an empty GameObject named `Player`.
2. In Main Manager > Setup > **Character Setup**, assign Player and select **Add Components**.
3. Confirm that Player has Inventory Identifier and Inventory. Keep the first stable Inventory Identifier ID at `1`.
4. In Inventory > **Item Collections**, add one collection.
5. Name it `Bag`, use **Item Collection**, and set **Purpose** to **Main**.
6. Under Bag's starting **Item Amounts**, add one Health Potion with amount `1`.

![The Inventory Inspector shows the database context, Item Collections, starting Item Amounts, and selected Item attributes.](https://opsive.com/wp-content/uploads/2020/04/InventoryInspector.png)

## Editor checkpoint

Before Play Mode, confirm:

- Main Manager and Inventory System Manager reference `GameInventoryDatabase`;
- the database contains All, Consumable, and Health Potion;
- Health Potion uses Consumable;
- Player has Inventory Identifier ID `1` and Inventory;
- Bag is the Main collection; and
- Bag starts with one Health Potion.

## Verify in Play Mode

1. Enter Play Mode.
2. Select Player and inspect Inventory > Bag.
3. Confirm that Bag's runtime Item Stacks contain one Health Potion.
4. Confirm that the runtime Item resolves the Health Potion definition, Consumable category, Description, and Icon value.
5. Stop Play Mode and confirm that the authored starting amount remains `1` rather than being replaced by the runtime list.

This is the first-success checkpoint: database registration created an Item from the definition and the player's Main collection owns it.

## Make one controlled change

Change the starting amount to `3` and test again. Bag should contain three Health Potion Items or one stack with amount three according to the collection's stacking behavior. No UI is required to verify this data path.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| Health Potion is unavailable in the picker. | Selected database and definition category. | Select the same database in Main Manager and create/assign the definition there. |
| Bag is empty in Play Mode. | Starting Item Amounts and Bag initialization. | Add Health Potion to Bag's authored Item Amounts and retest. |
| A database-null warning appears. | Inventory System Manager Database. | Assign `GameInventoryDatabase` through Setup or the component. |
| The Item enters another collection. | Main purpose and collection order. | Set Bag Purpose to Main and use unique collection names. |
| An Item exists in edit mode but not runtime. | Console registration errors and duplicate names/IDs. | Fix the first manager error before editing Inventory UI. |

Use [Getting Started Troubleshooting](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/troubleshooting/) when the first failed data layer is unclear.

## Next step

Continue with [First Inventory UI](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/first-inventory-ui/), then read [The Data Model at a Glance](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/data-model-at-a-glance/) before expanding the catalog.

---

<a id="page-ultimate-inventory-system-getting-started-first-inventory-ui"></a>

# First Inventory UI

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/first-inventory-ui/)

Generate a project-owned UIS interface and display the Health Potion from the first Bag. Keep this tutorial limited to one grid; add equipment, descriptions, actions, shops, and crafting afterward.

## Before you begin

- Complete [Your First Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/first-inventory/).
- Confirm that Health Potion has an Icon and Description suitable for the selected Item View.
- Keep Player and its Bag active in the scene.

## Create the UI foundation

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer**.
2. In **Setup**, select **Setup** under **Create Canvas Managers**.
3. Select the **Classic** UI Designer schema and choose **Duplicate**.
4. Save the duplicate in the project-owned inventory/UI folder.
5. Select **Spawn In Scene**.
6. Confirm that the generated canvas contains Display Panel Manager and the schema's starting menu objects.

Never customize the package schema directly. The duplicated schema and generated project hierarchy are the editable starting point.

## Create the Bag grid

1. Open UI Designer > **Inventory Grid**.
2. Choose the generated Main Menu content as **Parent Transform**.
3. Set **Panel Option** to **Main Menu**.
4. Name both the panel and Inventory Grid `Bag`.
5. Assign Player's Inventory.
6. Choose a small **Grid** layout and create the panel.
7. In Edit, select the generated Bag grid and add an Item Collection filter for `Bag` when the schema does not already provide one.

![The Inventory Grid Inspector exposes its Inventory, navigation, and Item View Drawer configuration.](https://opsive.com/wp-content/uploads/2020/05/InventoryGridInspector.png)

## Verify the binding

Confirm that the Inventory Grid resolves Player's Inventory, its Item View Drawer uses the generated slot-content transform, and its Category Item View Set can resolve Consumable Items.

Do not add Item Actions or Item Description until the Health Potion icon appears. This isolates Inventory ownership from selection and action bindings.

## Verify in Play Mode

1. Enter Play Mode and open the generated Main Menu.
2. Open Bag.
3. Confirm that one Health Potion appears with its expected Icon.
4. Change the starting amount to `3`, restart Play Mode, and confirm that the displayed quantity or stack reflects the Inventory.
5. Close and reopen the menu and confirm that the UI reads the same Bag rather than creating Item data of its own.

![The runtime inventory grid displays Item icons in a fixed set of reusable slots.](https://opsive.com/wp-content/uploads/2020/05/GameplayGridUI.png?v=08069e9e1c22)

## Add one description after display works

Use UI Designer > **Item Description** to create a description panel and add an Item View Slots Container Description Binding from Bag. Select Health Potion and confirm that its Description updates. Stop here before adding Item Actions.

![The runtime Item Description presents the selected Item's icon, text, and attributes.](https://opsive.com/wp-content/uploads/2020/05/GameplayItemDescription.png?v=5716d1b61145)

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| UI Designer feature tabs are disabled. | Database, Canvas Managers, duplicated schema, and Spawn In Scene. | Complete the foundation in order. |
| Bag opens but is empty. | Player Inventory binding, Bag runtime contents, and collection filter. | Verify the Item in Inventory first, then bind/filter the same collection. |
| Slots appear without Item visuals. | Item View Drawer Content and Category Item View Set. | Use the generated slot content and add a Consumable mapping. |
| Health Potion uses the wrong appearance. | Category Item View Set specificity. | Map Consumable to the intended Item View prefab. |
| Description never updates. | Description binding source and target. | Bind the Bag Item View Slots Container to the intended Item Description. |

Use [Getting Started Troubleshooting](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/troubleshooting/) before adding more panels.

## Next step

Read [UI Customization](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/ui-customization/) for equipment, actions, descriptions, drag and drop, and other generated UI. Choose the next system from [Choose a Workflow](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/choose-a-workflow/).

---

<a id="page-ultimate-inventory-system-getting-started-data-model-at-a-glance"></a>

# The Data Model at a Glance

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/data-model-at-a-glance/)

Follow one Health Potion from editor catalog to runtime UI. Each UIS object owns a different part of the result; changing the wrong layer is the most common beginner mistake.

## The ownership chain

| Layer | Health Potion example | What it owns |
| --- | --- | --- |
| **Database** | `GameInventoryDatabase` | The catalog container and registered objects. |
| **Category** | Consumable | Inherited structure and attributes shared by related definitions. |
| **Definition** | Health Potion | The reusable template and definition-level values such as Icon and Description. |
| **Item** | One runtime Health Potion | The runtime object; mutable Item attributes can differ per instance. |
| **Item Stack** | Health Potion ×3 | One Item plus its amount inside a collection. |
| **Item Collection** | Bag | Where stacks live and which restrictions or purpose apply. |
| **Inventory** | Player Inventory | The owner of Bag and any other collections. |
| **Item View** | Potion slot icon | A UI presentation of Item data; it does not own the Item. |

![The Item Definition editor shows a definition's category, attributes, and relationships.](https://opsive.com/wp-content/uploads/2020/04/ItemDefinitionEditor.png?v=2482860ad560)

![The Inventory Inspector shows collections and starting Item amounts for the runtime owner.](https://opsive.com/wp-content/uploads/2020/04/InventoryInspector.png)

![The runtime Inventory Grid presents Items read from the bound collection.](https://opsive.com/wp-content/uploads/2020/05/GameplayGridUI.png?v=08069e9e1c22)

## Decide where an Attribute belongs

Ask these questions in order:

1. **Does every descendant of a Category share the same structural field?** Declare it on the Item Category.
2. **Does every Item created from one Definition share the same value?** Store it in Item Definition Attributes.
3. **Can two Items from the same Definition have different values?** Store it in Item Attributes and use a mutable category when required.
4. **Is the behavior more complex than data?** Use an Item Action, Item Object Behaviour, or project system instead of an Attribute expression.

Examples:

- Icon and Description normally belong to the Definition.
- Attack normally belongs to the weapon Definition.
- Durability belongs to the Item when two Iron Swords can be damaged differently.
- A Consume operation belongs to an Item Action, while its healing amount can be data.

## Distinguish data from scene objects

An Item is not a GameObject. An **Item Object** binds Item data to a scene object for a pickup, equipped object, or another visible representation. The Inventory and UI can use Items without spawning an Item Object.

## Verify the chain

Select an Item Definition, enter Play Mode, locate its Item Stack in Bag, then select its Item View. Confirm that each layer points to the same definition but owns different data and lifetime. Change only the definition Description and verify that the UI updates without replacing the Inventory.

## Continue learning

- [Terminology](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/terminology/) provides the complete glossary.
- [New Database](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/new-database/) builds the shared multi-category example.
- [Defining Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/) covers inheritance, Override, Inherit, and Modify.
- [Item](https://opsive.com/support/documentation/ultimate-inventory-system/item/) covers runtime identity and definition relationships.
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/) covers collection types and restrictions.

---

<a id="page-ultimate-inventory-system-getting-started-choose-a-workflow"></a>

# Choose a Workflow

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/choose-a-workflow/)

Choose the next UIS documentation path by the result your project needs. Complete the first Inventory and UI route before combining several systems.

## Inventory and equipment

Use this route for a player bag and equipped weapon:

1. [New Database](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/new-database/)
2. [Defining Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/)
3. [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/)
4. [Item Slot Collection](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/item-slot-collection/)
5. [Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/)
6. [Equipment UI](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/equipment/)

Verify one Iron Sword moving from Bag to Equipment before adding armor or loadouts.

## UIS with Ultimate Character Controller

Install and verify both products separately, then import the matching bridge and follow [Opsive Character Controllers](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/opsive-character-controllers/). Decide early whether UIS replaces the UCC inventory/item data route for the character. Do not configure two independent inventory owners for the same equipped item.

## Pickups and world objects

Use [Item Objects](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/), [Item Pickups](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-pickups/), and the [Interaction System](https://opsive.com/support/documentation/ultimate-inventory-system/interaction-system/). Prove one Health Potion pickup entering Bag before adding random drops, equipment prefabs, or pooling customization.

## Shop and currency

Create [Currency](https://opsive.com/support/documentation/ultimate-inventory-system/currency/), a [Shop](https://opsive.com/support/documentation/ultimate-inventory-system/currency/shop/), and then the [Shop UI](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/shop/). Verify one Gold purchase and one sale before adding price modifiers or multiple currencies.

## Crafting

Create a [Crafting Category and Recipe](https://opsive.com/support/documentation/ultimate-inventory-system/crafting/), assign a Crafter, then build the [Crafting UI](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/crafting/). Verify one recipe consuming fixed ingredients and adding one Health Potion.

## Saving and scene changes

Add the [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/) after stable IDs, Inventory ownership, and runtime item behavior work. Use [Scene Transitions](https://opsive.com/support/documentation/ultimate-inventory-system/scene-transitions/) when the player or managers persist between scenes. Save and restore one mutable Item before expanding the schema.

## Programmer-first integration

Read [The Data Model at a Glance](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/data-model-at-a-glance/), [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/), and the developer sections on Item, Inventory, and Item Collections. Create Items through the Inventory System Manager factory and route changes through Inventory/collection APIs rather than constructing unsafely detached data.

## Rule for every route

Build one end-to-end scenario, verify the owning database and collection in Play Mode, then add the next layer. Use [Getting Started Troubleshooting](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/troubleshooting/) whenever an Item disappears between layers.

---

<a id="page-ultimate-inventory-system-getting-started-troubleshooting"></a>

# Getting Started Troubleshooting

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/troubleshooting/)

Trace a missing or incorrect Item through UIS in data order: Database, Inventory System Manager, Definition, Inventory, Item Collection, then UI. Stop at the first layer where the expected value disappears.

## 1. Database

Open Main Manager and confirm the intended Inventory System Database is selected. Locate the category and definition by exact name and verify their relationship, attributes, and unique IDs.

If the editor shows the wrong catalog, do not repair scene or UI references yet. Select the intended database first.

## 2. Inventory System Manager

Select the scene's Inventory System Manager and confirm that **Database** matches Main Manager. Keep exactly one active manager for the world. Enter Play Mode and resolve database-null, duplicate-name, or duplicate-ID errors before continuing.

## 3. Runtime Item and Inventory

Select the player Inventory. Confirm that Inventory Identifier uses the intended stable ID, the expected Item exists at runtime, and the collection name and Purpose are correct.

![The Inventory Inspector shows Item Collections and the selected Item data used for runtime diagnosis.](https://opsive.com/wp-content/uploads/2020/04/InventoryInspector.png)

## 4. Collection and restrictions

Inspect the destination collection, its type, Item Slot Set when applicable, restrictions, overflow behavior, and exact collection name. Ask `CanAddItem` conceptually before assuming the UI or Item Action removed the Item.

## 5. UI binding

If the Item exists in Inventory but not UI, inspect:

- player Inventory or Dynamic Panel Owner binding;
- collection filter;
- Item View Drawer Content;
- Category Item View Set mapping;
- generated slot count and navigation; and
- the selected database of every referenced category or asset.

![The Inventory Grid Inspector exposes the Inventory and Item View Drawer that connect the runtime data to slots.](https://opsive.com/wp-content/uploads/2020/05/InventoryGridInspector.png)

## Symptom guide

| Symptom | Check | Fix |
| --- | --- | --- |
| Main Manager or UI Designer is missing. | Package import and compiler errors. | Restore one matching UIS/Shared package and resolve the first error. |
| Definition is absent from a picker. | Main Manager database and category assignment. | Create/select the definition in the active database. |
| Database works in editor but not Play Mode. | Inventory System Manager Database and startup errors. | Assign the same database and keep one manager. |
| Starting Item is missing. | Collection's authored Item Amounts and initialization. | Add the Item to the intended collection and retest. |
| Item enters the wrong collection. | Main Purpose, collection order, transaction routing, and restrictions. | Give the intended collection the correct Purpose and rule. |
| Item cannot equip. | Item Slot Set category, Equipment collection, Item Action, and destination restriction. | Fix the first category/slot mismatch. |
| Grid is empty. | Runtime Inventory contents, Inventory binding, and collection filter. | Prove the Item in Inventory, then bind/filter that collection. |
| Slots appear without icons. | Item View Drawer, Content, Category Item View Set, and Icon. | Repair the view mapping and definition data. |
| Item Action list is empty. | Item Categories, Category Item Action Set, and binding. | Add the matching category mapping and connect it to the selected grid. |
| Item disappears after scene change. | Player/manager lifetime and save ownership. | Persist the owner together or restore it through the Save System. |
| Saved mutable values reset. | Stable IDs, Inventory saver, manager item saver, and load order. | Save the complete owner chain and load after manager initialization. |

## Isolate safely

Use one Health Potion, one Bag, one player, and one grid. Remove filters, sorters, Item Actions, equipment, saving, and integrations from the reproduction. Restore one layer at a time after the smallest data path works.

## Related pages

- [Your First Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/first-inventory/)
- [First Inventory UI](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/first-inventory-ui/)
- [The Data Model at a Glance](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/data-model-at-a-glance/)
- [Inventory System Manager](https://opsive.com/support/documentation/ultimate-inventory-system/inventory-system-manager/)
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/)
- [UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/)
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)

---

<a id="page-ultimate-inventory-system-getting-started-terminology"></a>

# Terminology

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/terminology/)

Use these terms to decide where data belongs and which editor workflow to follow. Most item data moves through this relationship:

**Database → Category → Definition → Item → Collection → Inventory**

For a shorter visual introduction before this complete glossary, read [The Data Model at a Glance](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/data-model-at-a-glance/).

The database, categories, and definitions form the catalog in the editor. Items, collections, and inventories represent what exists during play.

## Core data model

| Object | What it represents | Standard example |
| --- | --- | --- |
| **Inventory System Database** | The project catalog that stores Item Categories, Item Definitions, Currencies, Crafting Categories, and Crafting Recipes. | `GameInventoryDatabase` |
| **Item Category** | A reusable structure that organizes related definitions and declares inherited attributes. Category-based systems can target it, and a category can inherit from more than one parent. | **All**, **Consumable**, **Equippable**, **Weapon** |
| **Item Definition** | A template for one type of item and its default values. | **Health Potion**, **Iron Sword**, **Fire Wand** |
| **Item** | A runtime item created from a definition. Mutable Items can hold values that differ from other Items created from the same definition. | One Iron Sword with its own remaining Durability |
| **Item Collection** | One named group of Item Stacks inside an Inventory, with optional restrictions or a specialized purpose. | **Bag**, **Equipment** |
| **Inventory** | The component that owns one or more Item Collections. | A player, shop, chest, or enemy Inventory |

The **Inventory System Manager** loads the Inventory System Database when the game starts. It registers the catalog objects and provides the central lookup and Item-creation service used at runtime.

An Item Definition can inherit from a parent definition in the same category. Its Default Item supplies the baseline values used when a runtime Item is created. Items remain data objects; Item Actions and Item Object Behaviours provide the logic that uses them.

## Worked example: from catalog to player Inventory

Start with **All** as the broad parent category. Place **Consumable** and **Equippable** beneath it, then place **Weapon** beneath **Equippable**.

- **Health Potion** uses **Consumable**.
- **Iron Sword** and **Fire Wand** use **Weapon**, so they also inherit from **Equippable** and **All**.
- **All** can declare common Item Definition attributes such as **Icon** and **Description**.
- **Weapon** can declare attributes used by weapon definitions, such as **Attack** and **Buy Price**.
- A per-Item attribute such as **Durability** can differ between two Iron Sword Items when the category is mutable.

At runtime, the Inventory System Manager creates Items from these definitions. Health Potion Items can be stored in the player's **Bag**. An Iron Sword Item can move from **Bag** to **Equipment** when it is equipped.

Category placement has consequences: definitions inherit the attributes declared by their category and its ancestors, and category-based Item Actions can use the same relationship. Put an attribute on the broadest category where every descendant genuinely needs it; otherwise, keep it on a narrower category.

## Attributes and inheritance

An **Attribute** is named data defined through an Item Category. Choose its collection according to where its value belongs:

| Attribute collection | Choose it when | Example |
| --- | --- | --- |
| **Item Category** | Every use of the category should share one category-level value. | A visual identity for the Weapon category |
| **Item Definition** | Each definition needs its own value, shared by Items created from that definition. | Icon, Description, Attack, Buy Price |
| **Item** | Each runtime Item may need a different value. | Durability on an individual Iron Sword |

Attribute values support three variants:

- **Override** replaces the inherited value.
- **Inherit** uses the parent value unchanged.
- **Modify** calculates a value from the inherited value or another attribute in the same collection.

Use Item Actions or other gameplay logic for behavior that is more complex than an attribute expression.

## Inventory actions and world objects

### Item Action

An **Item Action** is something the player or game can do with an Item from an Inventory. A Consume action can apply to **Consumable** Items such as Health Potion, while an Equip action can apply to **Equippable** Items such as Iron Sword or Fire Wand.

An **Item Action Set** groups actions for an Item Category. A **Category Item Action Set** combines multiple Item Action Sets so an inventory UI can find the actions that match the selected Item's categories.

### Item Object and Item Object Behaviour

An **Item Object** binds an Item to a GameObject when that Item needs a presence in the scene, such as a pickup or equipped weapon. An **Item Object Behaviour** adds scene-based behavior to that object, such as swinging an Iron Sword or firing a Fire Wand.

## Storage, quantities, and context

An Inventory can separate Items into collections with different purposes. A common player setup uses **Bag** for carried Items and **Equipment** for equipped Items.

| Term | Use it for | Example |
| --- | --- | --- |
| **Item Stack** | An Item and its amount inside an Item Collection. | A stack of 5 Health Potions in Bag |
| **Item Amount** | An Item and an amount when no collection context is required. | 2 Health Potions as a recipe input |
| **Item Info** | An Item Amount plus its source Item Stack and/or Item Collection. | Remove 2 Health Potions from a specific Bag stack |
| **Item Slot Set** | The names and allowed Item Categories for an Item Slot Collection. | Weapon and armor slots in Equipment |

Use Item Info when moving or removing Items and the exact source matters. Use Item Amount for a simple Item-and-quantity value outside a collection.

## Inventory UI terms

An **Item View** displays an Item through one or more Item View Modules. An **Item View Slot** hosts an Item View and handles UI interactions such as selection, clicking, dragging, and dropping. For example, a Bag grid can use Item View Slots to display Health Potion and Iron Sword Items and respond when the player selects one.

## Currency and crafting

A **Currency** defines a value that can be exchanged. A project can use **Gold** as the currency that pays an Item Definition's **Buy Price** in a shop.

A **Crafting Recipe** defines inputs and outputs. A simple recipe can consume ingredient Item Amounts and produce one Health Potion. A Crafting Processor performs the recipe's runtime logic.

## Next steps

1. [Create a new database](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/new-database/) with the standard categories and definitions.
2. [Define attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/) at the Category, Definition, or Item level.
3. Use the [Item Category editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-category/) and [Item Definition editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-definition/) to build the catalog.
4. Configure the player's [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/) and its [Item Collections](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/).
5. Add the relevant [Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/), [Item Objects](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/), [Currency](https://opsive.com/support/documentation/ultimate-inventory-system/currency/), or [Crafting](https://opsive.com/support/documentation/ultimate-inventory-system/crafting/) workflow.

## Related pages

- [Items](https://opsive.com/support/documentation/ultimate-inventory-system/item/)
- [Shop](https://opsive.com/support/documentation/ultimate-inventory-system/currency/shop/)
- [Common Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/common-attribute-types/)

---

<a id="page-ultimate-inventory-system-getting-started-demo-scene"></a>

# Demo Scene

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/demo-scene/)

Use the demo to see how catalog data becomes runtime Items, how those Items move through an Inventory, and how the UI, shop, crafting, and world interactions use the same data. Follow the route below once as an observer before adapting anything for the project.

## Before you begin

The demo requires TextMesh Pro. If it is not installed, add it through the [Unity Package Manager](https://docs.unity3d.com/Manual/upm-ui.html) and import the required TMP resources when Unity prompts you.

The sample uses the Universal Render Pipeline. On another render pipeline, materials may appear incorrect and the camera may need adjustment before the scene is useful as a visual reference.

The demo depends on `DemoInventoryDatabase`. Its Character Stats, Item Upgrade Menu, Gate, character scripts, and some other objects exist to support the sample; they are not core UIS components intended for production reuse. Inspect the demo in place, then create or duplicate a database and prefabs into project-owned folders for real work.

## Open the demo

1. Open **Tools > Opsive > Ultimate Inventory System > Main Manager**.
2. Select **Setup** and import the sample content if it is not already present.
3. In Unity's Project window, open `Assets/Samples`, expand the imported **Opsive Ultimate Inventory System** version, then open `Demo/Demo.unity`. If the version folder name differs, search under `Assets/Samples` for the `Demo` scene.
4. Allow Unity to finish importing and compiling before entering Play Mode.

## Follow the data through the editor

The demo's exact Item names may differ from the standardized examples used elsewhere in this documentation. Use a demo consumable as the **Health Potion** role, and use demo weapons as the **Iron Sword** or **Fire Wand** roles.

### 1. Inspect the database and definitions

Open the Main Manager and confirm that the demo uses `DemoInventoryDatabase`. In the Item Definitions editor, select one consumable and one weapon. Check their Item Categories and inherited attributes rather than changing their values.

![The UIS Item Definition editor with a definition selected and its category, attributes, and relationships visible.](https://opsive.com/wp-content/uploads/2020/04/ItemDefinitionEditor.png?v=2482860ad560)

This is the catalog side of the flow: the Database contains Categories and Definitions, and each Definition supplies the template for runtime Items.

### 2. Inspect the player Inventory

Select **Player Character** in the demo scene and find its Inventory component. Select the **(Main) Main** Item Collection to inspect carried Items. This collection serves the same role as **Bag** in the standardized examples.

Inspect the **Equipped** collection next. It serves the same role as **Equipment** and shows where an Iron Sword- or Fire Wand-style Item is stored after it is equipped.

### 3. Locate the runtime UI

Select the **Inventory System Canvas** GameObject. Its Display Panel Manager coordinates the gameplay and main-menu panels, while the child menus display the Inventory and related systems.

The UI does not create separate Item data. It reads Items from the player Inventory and selects the appropriate views and Item Actions for their Categories.

### 4. Locate the village systems

Expand **World > Static Interactables** to find the shop, crafting stable, storage, and other interactable examples. The village is the best place to observe buying and selling, moving Items between Inventories, upgrading, and crafting without combat pressure.

Use the shop as the **Gold** and **Buy Price** example: a Currency Owner supplies the player's currency, while Item data supplies the price used by the shop. Use the crafting stable to observe a Crafting Recipe consume inputs and add its output to an Inventory.

### 5. Use Items in the forest

The forest demonstrates the runtime side of the same model. The player can retrieve loot, add it to the main collection, equip weapons, use Items, and fight bandits. Watch the Inventory rather than only the character animation so it is clear which collection owns each Item before and after an action.

## Editor checkpoints

Before entering Play Mode, confirm that:

- `DemoInventoryDatabase` is the active database.
- **Player Character** has an Inventory with **(Main) Main** and **Equipped** collections.
- **Inventory System Canvas** contains the Display Panel Manager and menu objects.
- **World > Static Interactables** contains the shop and crafting stable.

## Observe the runtime flow

Use existing demo Items for these checks; the standardized names describe their roles even when the demo uses different labels.

1. Open the inventory UI and identify a Consumable Item that plays the Health Potion role.
2. Use or move that Item and confirm that the amount or owning collection changes in the player Inventory.
3. Equip a Weapon Item that plays the Iron Sword or Fire Wand role and confirm that it moves from **(Main) Main** to **Equipped**.
4. Visit the shop and observe the player's currency and the Item price before and after a transaction.
5. Complete a simple crafting interaction and confirm that the ingredients decrease and the output appears in the Inventory.
6. Collect loot in the forest and confirm that the new Item appears in the main collection and its UI.

## Troubleshooting

- **The demo scene or menus are missing:** Check whether the sample content was imported from Main Manager > Setup. Reimport the sample, then reopen the scene under `Assets/Samples`.
- **Text is missing or the UI reports TMP errors:** Install TextMesh Pro and import its required resources, then reopen the scene.
- **Materials are pink or the view is framed incorrectly:** Check the active render pipeline. The sample targets URP, so another pipeline needs compatible materials and may need camera adjustment.
- **An Item exists in the database but not in the UI:** Select **Player Character** and check the Item Collection first. If the Item is present there, inspect the Inventory System Canvas and its data source.
- **The demo stopped working after edits:** Restore or reimport the sample. Make changes in a duplicated project database and project-owned prefabs instead of `DemoInventoryDatabase` or the sample assets.

## Next pages

- [Terminology](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/terminology/) explains the data model used throughout this route.
- [New Database](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/new-database/) creates the project-owned starter catalog.
- [Defining Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/) places values at the Category, Definition, or Item level.
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/) explains the component and its Item Collections.
- [UI Customization](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/ui-customization/) identifies the views, action sets, and prefabs behind the demo UI.
- [Currency](https://opsive.com/support/documentation/ultimate-inventory-system/currency/) and [Crafting](https://opsive.com/support/documentation/ultimate-inventory-system/crafting/) continue the village workflows.

---

<a id="page-ultimate-inventory-system-getting-started-new-database"></a>

# New Database

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/new-database/)

Create a new Inventory System Database when the project needs its own item catalog instead of the demo data. By the end of this workflow, the database will contain a small category structure and two definitions: **Health Potion** and **Iron Sword**.

## Starting point

This page assumes Ultimate Inventory System is installed and you want a database created from scratch. Create the destination folder in Unity's Project window before opening the database save dialog.

> **Important:** Creating the parent folder from the file browser while the database dialog is already open can cause a **Missing Parent Folder** error. Create the folder first, then select **New**.

## Create the database

1. Open **Tools > Opsive > Ultimate Inventory System > Main Manager**.
2. Select the **Setup** manager.
3. Find the **Inventory System Database** section and select **New**.
4. Save the asset in the folder prepared above. A clear project-specific name, such as `GameInventoryDatabase`, makes the reference easy to recognize later.
5. Confirm that the new database is selected in the Setup manager.

![The Ultimate Inventory System Setup manager showing the Inventory System Database field and New button.](https://opsive.com/wp-content/uploads/2020/04/NewDatabase.png?v=dedd9f6255bf)

A database created from scratch includes an **All** Item Category with the common **Icon** and **Description** Item Definition attributes. Keep **All** as the shared parent while building the first categories.

## Use the database field actions

The cog beside **Inventory System Database** owns actions that affect the selected database rather than one Category or Definition.

### Duplicate the database

**Duplicate** copies the database and its owned Categories, Definitions, Currencies, Crafting Categories, and Recipes. The confirmation offers:

- **Keep references to prefabs**, which leaves prefab-valued Attributes pointing to the existing assets; or
- **Duplicate all referenced Prefabs**, which copies those prefabs for the new database.

Choose a project-owned destination under `Assets`. The copy is a new database, but selecting it in Main Manager does not update saved scene managers, savers, UI schemas, prefabs, or other consumers. Verify each owner before deleting the original.

### Generate database-name constants

**Generate C# script** writes `<DatabaseName>Names.cs` in the selected folder under the `Opsive.UltimateInventorySystem.DatabaseNames` namespace. It contains constants for Item Category names, source Attribute names, and Item Definition names. Generating to the same path overwrites the prior file without a backup. Treat it as generated code and regenerate it after renaming database objects.

### Replace references after a deliberate database switch

**Assets > Ultimate Inventory System > Replace Database Objects** uses the database currently selected in Main Manager. The command is available when the Project selection is an `IDatabaseSwitcher`, GameObject or prefab, Scene asset, or folder. A folder scan includes supported ScriptableObjects, prefabs, and scenes below that folder; affected scenes are saved.

This operation cannot be reversed from the tool. Commit or back up the project, select the intended database, choose the narrowest possible target, and review the asset and scene diff. It replaces supported references; it does not merge two databases. The Inventory System Manager's **Update Scene** command is the narrower route for the currently open scene.

## Build the sample structure

The database is the container, Item Categories define the structure and inherited attributes, and Item Definitions describe the item types that the game can create. Build categories before definitions so each definition immediately receives the correct inherited attributes.

### Create the categories

1. Open the **Item Categories** editor.
2. Add **Consumable** and set **All** as its parent.
3. Add **Equippable** and set **All** as its parent.
4. Add **Weapon** and set **Equippable** as its parent.

The resulting structure is:

- **All**
  - **Consumable**
  - **Equippable**
    - **Weapon**

This keeps shared display data on **All**, groups one-use items under **Consumable**, and lets **Weapon** inherit the behavior and attributes intended for **Equippable** items. More detailed categories can be added later when they serve a real workflow.

### Create the definitions

1. Open the **Item Definitions** editor.
2. Add **Health Potion**. New definitions initially use **Uncategorized**, so assign **Consumable** as its Item Category.
3. Set the inherited **Icon** and **Description** values when those assets and text are ready.
4. Add **Iron Sword** and assign **Weapon** as its Item Category.
5. Set its inherited **Icon** and **Description** values.

An Item Definition is the reusable template for runtime Items. **Health Potion** inherits from **Consumable** and **All**; **Iron Sword** inherits from **Weapon**, **Equippable**, and **All**.

## Visible checkpoint

Before adding more data, confirm that:

- The Setup manager references the new database.
- The category list contains **All**, **Consumable**, **Equippable**, and **Weapon**.
- **Consumable** and **Equippable** show **All** as their parent.
- **Weapon** shows **Equippable** as its parent.
- **Health Potion** uses **Consumable**, and **Iron Sword** uses **Weapon**.
- Both definitions expose the inherited **Icon** and **Description** fields.

At this point the relationship is **Database > Category > Definition**. Runtime Items are created from those definitions; they are not additional catalog entries that need to be created during this setup.

## Next workflow

Continue with [Defining Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/) before expanding the database. That page explains whether a value belongs to the Item Category, Item Definition, or runtime Item. For this sample, it is the place to decide how **Health Potion** stores its healing value and how **Iron Sword** stores values such as attack or per-item durability.

## Related pages

- [Terminology](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/terminology/)
- [Defining Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/)
- [Item Category editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-category/)
- [Item Definition editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-definition/)
- [Items](https://opsive.com/support/documentation/ultimate-inventory-system/item/)
- [Common Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/common-attribute-types/)

---

<a id="page-ultimate-inventory-system-getting-started-defining-attributes"></a>

# Defining Attributes

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/)

Place each value at the narrowest level that matches how it changes. Category-level values describe the category itself, Item Definition values differ by item type, and Item values can differ between runtime instances of the same definition.

The examples below use the starter database from [New Database](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/new-database/): **All > Consumable** and **All > Equippable > Weapon**, with **Health Potion**, **Iron Sword**, and **Fire Wand** definitions.

## Choose where the value belongs

| Attribute collection | Use it when | Standard example |
| --- | --- | --- |
| **Item Category** | The category itself has one shared value. | `CategoryIcon` for Weapon |
| **Item Definition** | Every Item created from one definition should share the value. | `Icon`, `Description`, `Attack`, `BuyPrice` |
| **Item** | Each runtime Item may need its own value. | `Durability` on an individual Iron Sword or Fire Wand |

Attributes are declared in the Item Category editor, even when their values belong to Item Definitions or runtime Items. A category passes those declarations to its descendants. The Item Definition editor then sets definition values and the Default Item values used as the starting point for runtime Items.

The [Common Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/common-attribute-types/) page lists names and types that built-in views or components may expect. In particular, `Description` is normally a string, `Icon` is a Sprite, and `BuyPrice` is normally a `CurrencyAmounts` Item Definition attribute.

## Configure the starter categories

1. Open **Tools > Opsive > Ultimate Inventory System > Main Manager** and select **Item Categories**.
2. Select **All**, then open the **Attributes** section and its **Item Definition** tab.
3. Confirm that `Icon` and `Description` are present. For the standard shop example, add `BuyPrice` here if every starter definition can be bought. Use the **+** button to add an attribute.
4. Select **Weapon**. In the **Item Definition** tab, add `Attack`.
5. In Weapon's **Item** tab, add `Durability` so each runtime weapon can have a different remaining value.
6. In Weapon's **Properties**, enable **Mutable** and **Unique** when each Iron Sword and Fire Wand must keep its own changing Durability and must not stack with another weapon.
7. Select **Consumable**. Leave **Mutable** and **Unique** disabled when Health Potion values do not change per instance and matching potions should stack in a normal Item Collection.

Do not redeclare `Icon`, `Description`, or `BuyPrice` on Weapon or Consumable when they already inherit those attributes from All. Add an attribute to a narrower category only when definitions outside that category should not receive it.

## Set the definition and Default Item values

1. Open the **Item Definitions** editor and select **Health Potion**.
2. In the Item Definition attributes, set its `Icon`, `Description`, and `BuyPrice` values. Health Potion does not inherit `Attack` or `Durability` because it is a Consumable rather than a Weapon.
3. Select **Iron Sword** and set its `Icon`, `Description`, `Attack`, and `BuyPrice` definition values.
4. In Iron Sword's **Default Item** attributes, set the starting `Durability`.
5. Repeat the weapon steps for **Fire Wand**, using values appropriate to that definition.

At this checkpoint, both weapon definitions should expose `Attack` at the Item Definition level and `Durability` on the Default Item. Health Potion should expose the common display and price values without the weapon-only fields.

## Choose an attribute variant

Each attribute value has a **Variant** choice:

- **Inherit** uses the value from its parent.
- **Override** supplies a specific value at the selected Category, Definition, or Item.
- **Modify** calculates a value from the inherited value or another attribute in the same collection.

Use **Override** for the direct `Attack` value of Iron Sword or Fire Wand. Use **Inherit** when a child Item Definition should keep its parent's value. Use **Modify** for a predictable variation, such as a child definition whose Attack is based on its parent's Attack.

For a fixed upgrade path, consider separate Item Definitions such as **Iron Sword > Iron Sword +1 > Iron Sword +2**. Parent and child definitions must use the same Item Category. The upgraded definition can inherit most values and override or modify only the values that change. Use a runtime Item attribute instead when the value belongs to one instance, such as Durability lost through use.

## Decide mutability and stacking

The **Mutable** and **Unique** Category properties affect Items directly assigned to that category:

| Choice | Result | Typical use |
| --- | --- | --- |
| **Immutable, common** | Values do not change per instance, and matching Items can stack. | Health Potion or materials |
| **Mutable, unique** | Every Item has its own identity and changing values. | Iron Sword or Fire Wand with Durability |
| **Immutable, unique** | Values stay fixed, but Items do not stack. | A key or other one-off Item |
| **Mutable, common** | Matching Items may stack even though values can change; the existing stack's values are retained when merging. | A deliberately shared mutable stack |

Use mutable, common Items only when that merge behavior is acceptable. If two weapons must retain different Durability values, they should be unique.

## Compare the existing demo patterns

The legacy demo uses Sword and Material categories to show the same decisions with a larger data model.

### Mutable, unique Sword

The demo Sword category is Mutable and Unique because each sword can change through upgrades without stacking into another sword.

![The demo Sword Item Category attributes showing inherited CategoryIcon and AnimatedID values.](https://opsive.com/wp-content/uploads/2020/07/SwordItemCategory.png?v=c530decab3a4)

`CategoryIcon` is inherited from Viewable and supplies the editor icon. `AnimatedID` is inherited from Animated and identifies the animation shared by Items in the category.

![The demo Sword Item Definition Attributes tab showing BaseAttack and other per-definition fields.](https://opsive.com/wp-content/uploads/2020/07/SwordItemDefinitionAttributes.png?v=3068af6b0bc4)

`BaseAttack` belongs to the Item Definition because it is fixed for that sword definition.

![The demo Sword Item Attributes tab showing the mutable Attack and Slots fields.](https://opsive.com/wp-content/uploads/2020/07/SwordItemAttributes.png?v=472d5bb4a737)

`Attack` and `Slots` belong to the runtime Item because they can change. The demo's Attack value uses **Modify** to begin from `BaseAttack`.

### Immutable, common Material

The demo Material category is Immutable and common because its values do not change per instance and matching materials should stack.

![The demo Material Item Category attributes showing its CategoryIcon value.](https://opsive.com/wp-content/uploads/2020/07/MaterialItemCategory.png?v=42fe933f9ca8)

The category-level `CategoryIcon` describes the Material category itself.

![The demo Material Item Definition Attributes tab showing values defined for each material type.](https://opsive.com/wp-content/uploads/2020/07/MaterialItemDefinitionAttributes.png?v=7619c5075416)

The remaining values belong to Item Definitions so each material type can supply its own fixed data.

![The demo Material Item Attributes tab showing that no per-Item attributes are required.](https://opsive.com/wp-content/uploads/2020/07/MaterialItemAttributes.png?v=897dcf262cb1)

No Item attributes are needed because individual material instances have no changing values.

## Verify at runtime

1. Add two Iron Sword Items and a stack of Health Potion Items to the player's **Bag** collection.
2. Enter Play Mode and inspect the Inventory component.
3. Change the Durability of one Iron Sword and confirm that the other sword keeps its own value.
4. Confirm that matching Health Potion Items stack when the collection permits stacking.
5. Open an Item View and confirm that Icon and Description come from the selected definition.
6. If the shop is configured, confirm that it reads the expected `BuyPrice` for each definition.

## Troubleshooting

- **An expected field is missing from a definition:** Check its Item Category and ancestors, then confirm that the attribute was added to the correct **Item Definition** or **Item** tab.
- **Changing one weapon changes every copy:** Check that the changing value is an Item attribute and that the direct category is **Mutable** and **Unique**.
- **Items do not stack:** Check the direct category's **Unique** property and any Item Collection restrictions.
- **An inherited value cannot be edited:** Change its Variant from **Inherit** to **Override**, or edit the parent value.
- **A child category reports an overlapping attribute:** Keep one declaration on the appropriate ancestor. Multiple parents cannot supply same-named attributes with conflicting types.

## Related pages

- [Terminology](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/terminology/)
- [New Database](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/new-database/)
- [Item Category editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-category/)
- [Item Definition editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-definition/)
- [Attribute editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/attributes/)
- [Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/)
- [Items](https://opsive.com/support/documentation/ultimate-inventory-system/item/)
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/)

---

<a id="page-ultimate-inventory-system-getting-started-ui-customization"></a>

# UI Customization

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/ui-customization/)

Customize the inventory UI by changing the generated prefabs, category mappings, and small View Module components rather than rebuilding item display and interaction logic for every panel. This workflow creates a **Bag** view for Health Potion and Iron Sword Items, then connects an **Equipment** view for equipped weapons.

## Before you begin

Confirm that:

- The project Inventory System Database is selected in **Main Manager > Setup**.
- **Health Potion** uses **Consumable**, and **Iron Sword** uses **Weapon** and **Equippable** through inheritance.
- Both definitions have the `Icon` and `Description` attributes used by the sample views.
- The player has an Inventory with **Bag** and **Equipment** Item Collections. For verification, Bag should contain at least one Health Potion and one Iron Sword.

UI Designer schemas are Scriptable Objects containing the prefabs and assets used to create the UI. Duplicate a schema before customization so the project owns the generated assets and package updates do not replace the edits.

## Create the UI foundation

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer**.
2. In **Setup**, find **Create Canvas Managers** and select **Setup**. This creates the canvas and manager components required by the UIS panels.
3. In **UI Designer Schema**, select a starting schema and choose **Duplicate**.
4. Select **Spawn In Scene** to create the schema's basic menu and enable the remaining UI Designer tabs.
5. In the scene hierarchy, confirm that the generated canvas contains a Display Panel Manager and the main menu or gameplay panel created by the schema.

Most UI Designer tabs have **Create** and **Edit** sections. Use **Parent Transform** in Create to choose where a new panel should be placed. In Edit, use **Find Available Targets in Scene** or drag the intended component into the target field before changing it.

## Create the Bag and Equipment views

### Bag Inventory Grid

1. Open the **Inventory Grid** tab in UI Designer.
2. Set **Parent Transform** to the intended main-menu content transform.
3. Choose the appropriate **Panel Option**. Use **Main Menu** when the grid belongs inside the generated main menu.
4. Set **Panel Name** and **Inventory Grid Name** to clear project names such as **Bag**.
5. Assign the player's **Inventory**.
6. Choose **Grid** or **List** under **Grid Options**, then set the grid size and layout for the number of visible slots.
7. Add an **Item Info Item Collection Filter** to the grid's default filters and configure it to show **Bag**.

The Bag view should now be present in the hierarchy, target the player Inventory, and limit its contents to the Bag collection. A tab can apply the same collection filter if the panel needs to switch between several collections.

### Equipment Item Slot Collection View

1. Open the **Equipment** tab in UI Designer.
2. Assign the **Item Slot Set** that defines the equipment slots and their allowed Item Categories.
3. Choose the parent panel and create the view.
4. On the generated Item Slot Collection View, set **Item Collection ID** to **Equipment**. Confirm that it uses the same Item Slot Set as the Equipment collection and that its weapon slot accepts the **Weapon** category.

At this checkpoint, Health Potion and Iron Sword can both appear in Bag, while the Equipment view has a valid destination for Iron Sword.

## Choose the display and interaction pattern

### Inventory Grid or List

Use an Inventory Grid when the player should scan icons spatially. Use the List option when names or longer rows are more important. Both use the Inventory Grid component and the same Item View Slot interaction system.

![The gameplay inventory grid displaying item icons in a fixed set of slots.](https://opsive.com/wp-content/uploads/2020/05/GameplayGridUI.png?v=08069e9e1c22)

The generated object includes the Inventory Grid and related grid components. Important choices include the assigned Inventory, grid size, layout group, navigation, filters, sorters, and whether tabs change the active filter.

![The Inventory Grid Inspector showing the inventory, grid, navigation, and Item View Drawer configuration.](https://opsive.com/wp-content/uploads/2020/05/InventoryGridInspector.png)

### Item Shape Grid

Use an Item Shape Grid only when an Item must occupy more than one grid cell. A conventional Health Potion and Iron Sword Bag normally needs a regular Inventory Grid; a shape grid is useful for a spatial backpack design where the sword covers several cells.

![The gameplay Item Shape Grid displaying items that occupy differently sized groups of cells.](https://opsive.com/wp-content/uploads/2021/01/Item-Shape-Grid.png?v=a104f8e7b404)

The Item Shape Grid component controls the shape-based placement and must match the intended grid dimensions and item-shape data.

![The Item Shape Grid Inspector showing its shape-based grid and layout settings.](https://opsive.com/wp-content/uploads/2021/01/ItemShapeGridInspector.png?v=bc10d783f6dd)

### Item Actions by Category

Use Item Actions for choices performed from the inventory UI. Map a Consume action to **Consumable** for Health Potion and an Equip action to **Equippable** for Iron Sword.

![The gameplay Item Action panel listing the actions available for the selected Item.](https://opsive.com/wp-content/uploads/2020/05/GameplayItemAction.png?v=c673c268052c)

An Item Action Set groups actions for one Item Category. A Category Item Action Set combines those sets, and an **Item View Slots Container Category Item Action Set Binding** connects the result to the selected Item in the Bag grid.

![The Category Item Action Set Inspector mapping Item Categories to their Item Action Sets.](https://opsive.com/wp-content/uploads/2020/04/CategoryItemActions.png?v=ea7e7348a24a)

### Item Views and Category Item View Sets

An Item View prefab controls the visual content inside a slot. Add focused Item View Modules for values such as Icon, name, quantity, selection, or rarity instead of creating one large display component.

![A gameplay Item View displaying the selected Item's visual content inside its slot.](https://opsive.com/wp-content/uploads/2020/05/GameplayItemBox.png?v=069889afa97d)

Use a **Category Item View Set** to map Item Categories to Item View prefabs. Create one from **Create > Ultimate Inventory System > UI > Category Item View Set**, then map **Consumable** and **Weapon** to the appropriate prefabs.

![The Item View prefab Inspector showing its reusable Item View Module components.](https://opsive.com/wp-content/uploads/2020/04/ItemViewInspector.png?v=f5fac6f48ce9)

### Item View Drawer

The Item View Drawer uses the Category Item View Set to choose a prefab for each Item. Assign the set on the drawer used by the Bag Inventory Grid, and confirm that its **Content** field uses the same transform as the Inventory Grid's **Content** field.

![The Item View Drawer Inspector showing its Category Item View Set and Content references.](https://opsive.com/wp-content/uploads/2020/11/Item-View-Drawer.png?v=502d84f67e88)

### Item Description and Attribute Views

Use an Item Description when the selected Item needs a larger panel containing its Icon, Description, and attributes. An Iron Sword description can show Attack and Durability, while a Health Potion can show its description and quantity.

![The gameplay Item Description panel showing the selected Item's icon, text, and attributes.](https://opsive.com/wp-content/uploads/2020/05/GameplayItemDescription.png?v=5716d1b61145)

Add an **Item View Slots Container Description Binding** beside the Bag grid so selection updates the description. The Item Description can use Item View Modules, including a **Category Attribute View Set Item View Module**, to choose which attributes appear for each Item Category.

![The Item Description Inspector showing the Item View Modules used to display selected Item details.](https://opsive.com/wp-content/uploads/2020/05/ItemDescriptionInspector.png)

## Editor checkpoints

Before entering Play Mode, confirm that:

- The generated canvas has its Display Panel Manager and main menu panels.
- The Bag Inventory Grid references the player Inventory and has an Item View Drawer.
- The Equipment view references the Equipment collection and a compatible Item Slot Set.
- The Item View Drawer references the intended Category Item View Set.
- The Category Item Action Set includes Consumable and Equippable mappings and is connected through the category action-set binding.
- The Item Description is connected to the Bag grid through its description binding.

## Verify in Play Mode

1. Open the inventory menu and confirm that Health Potion and Iron Sword appear in Bag with the correct Item View prefabs.
2. Navigate with the project's supported pointer, keyboard, or controller input and confirm that selection remains visible.
3. Select Health Potion and confirm that its Item Description updates and its Consume action is available.
4. Select Iron Sword and confirm that its weapon attributes and Equip action are available.
5. Equip Iron Sword and confirm that the Bag and Equipment views refresh to show the new owning collection.
6. If drag and drop is enabled, move Iron Sword between compatible slots, then try to place Health Potion in the weapon slot and confirm that the restriction rejects it.

## Troubleshooting

- **UI Designer tabs are unavailable:** Check that a database is selected, Canvas Managers were created, and a schema was duplicated and spawned.
- **The Bag grid is empty:** Check the Inventory assigned directly or through its panel binding, then confirm that the player Inventory contains Items in the expected collection.
- **An Item uses the wrong prefab:** Check the Category Item View Set mapping and the Item View Drawer reference. Use the most specific intended category mapping.
- **The action list is empty:** Check the Item's Categories, the Item Action Sets inside the Category Item Action Set, and the Item View Slots Container Category Item Action Set Binding.
- **The description does not update:** Check that the Item View Slots Container Description Binding references the Bag grid and the intended Item Description.
- **Drag and drop fails or accepts the wrong Item:** Check the source and destination Item View Slot restrictions, the Equipment Item Slot Set, and any move-action conditions.
- **A grid is clipped or navigates in the wrong direction:** Check **Grid Size**, the Unity layout group, and the Layout Group Navigation configuration in UI Designer.

## Related pages

- [UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/)
- [Inventory Grid in UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/inventory-grid/)
- [Equipment in UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/equipment/)
- [Item Shape Grid](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-shape-grid/)
- [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/inventorygrid/)
- [Item Info Filters and Sorters](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-info-filter-sorters/)
- [Item Slot Collection View](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-slot-collection-view-equipment/)
- [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/)
- [Views](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/)
- [Item Description](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-description/)
- [Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/)
- [New Database](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/new-database/)
- [Defining Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/)

---

<a id="page-ultimate-inventory-system-getting-started-version-1-1-update-guide"></a>

# Version 1.1 Update Guide

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/version-1-1-update-guide/)

Use this historical guide when moving an Ultimate Inventory System project from version 1.0.x to version 1.1.0. Version 1.1 replaced the user interface rather than updating it in place, so a successful migration keeps the project data but rebuilds the affected UI and reconnects renamed components and references.

## Confirm the update boundary

| Starting version | Target version | Use this guide? |
| --- | --- | --- |
| 1.0.x, including 1.0.7 | 1.1.0 | Yes. Follow the complete migration. |
| An earlier 1.1 patch | A later 1.1 patch | No. This guide addresses the 1.0-to-1.1 breaking changes. |
| 1.1.x | 1.2 or later | No. Use the update guide for the target release. |

The 1.0.x UI components and prefabs are not compatible with the 1.1 UI. Do not import 1.1 over an existing 1.0.x installation and expect Unity to resolve renamed or removed scripts.

## Before you begin

1. Commit the working project to version control or make a complete project backup that you can restore independently.
2. Back up any runtime save files separately. This historical update did not guarantee that every project-specific 1.0 save would load unchanged in 1.1.
3. Record the Unity version, installed UIS integrations, active Inventory System Database, Inventory Identifier IDs, and the scenes and prefabs that contain UIS components.
4. Run the 1.0.x project and record a baseline for the features you use, such as the Bag, Equipment, Gold balance, item actions, pickups, shops, crafting, and saving.
5. Make sure project-owned databases, prefabs, scripts, and UI assets are included in the backup before removing the old UIS package files.

Do the migration in a copy or branch of the project. Keep the original project and save data unchanged until the regression checks pass.

## Decide what must be migrated

| Area | Migration action |
| --- | --- |
| Inventory System Database and project data | Keep the project-owned assets, then reconnect serialized database references after importing 1.1. |
| Demo-derived or custom 1.0 menus and panels | Rebuild them with the 1.1 UI Designer. Do not carry the old UI prefabs forward. |
| Scenes and prefabs | Find every **Missing Script** component and replace it with the 1.1 component that now owns that responsibility. |
| Character inventory setup | Check Inventory, Currency Owner, Item User, Inventory Standard Input, Inventory Interactor, and Inventory Identifier together. |
| Item actions | Replace Category Item Actions references with Item Action Set references. |
| Equipped and world Item Objects | Update the Equipper, usable-item handler, behavior, and visual components described below. |
| Custom code | Replace renamed types, then update and compile one integration or custom assembly at a time. |
| Runtime saves | Treat compatibility as project-specific. Test only against a disposable copy and plan an explicit migration or fresh save if the data does not round-trip. |

## Replace version 1.0.x cleanly

1. Close Unity after making the backups and recording the baseline.
2. Remove the version 1.0.x UIS package files. Do not delete project-owned databases, prefabs, scenes, or scripts that merely reference UIS.
3. Import the version 1.1.0 core package without optional integrations.
4. Open the project and let Unity finish importing and compiling.
5. Resolve duplicate-type and compiler errors before importing integrations or repairing UI prefabs.

**Checkpoint:** the core package compiles without errors. Missing components in project scenes and prefabs may remain at this stage, but the Console should not show old and new UIS scripts compiling together.

## Reconnect database references

Version 1.1 introduced dynamic database references such as Dynamic Item Category, Dynamic Currency, and Dynamic Crafting Recipe. Reassign Inspector references that were serialized by the 1.0 components, including categories in Item Slot Sets, Item Action Set mappings, Category Item View Sets, currencies, and crafting recipes.

1. Confirm that the correct Inventory System Database is active.
2. Open each project-owned Item Slot Set and reassign its category references.
3. Reconnect the Item Action Set and Category Item View Set used by each relevant category or definition.
4. Check currency and crafting references in the systems your project uses.
5. Save the assets, close Unity, reopen the project, and confirm the assignments remain set.

**Checkpoint:** database-backed fields show the intended asset names after an editor restart rather than **None**, a missing value, or an object from another database.

## Rebuild the user interface

Recreate menus and panels taken from the 1.0 demo or built with 1.0 UI components using the 1.1 [UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/). Rebuilding is required because the underlying UI system changed substantially.

Use the following names while translating the old layout:

| Version 1.0 name | Version 1.1 name | What changed |
| --- | --- | --- |
| Item Box | Item View | Displays the selected item data. |
| Attribute Box | Attribute View | Displays an attribute value. |
| Box Slot | View Slot, such as Item View Slot | Owns selection, clicks, dragging, and navigation around a view. |

Rebuild only the interfaces the project uses, such as the inventory grid, Equipment, hotbar, shop, storage, crafting, save, or main menu. Reconnect each panel to the intended Inventory Identifier or owner and test its selection and navigation before moving to the next panel.

**Checkpoint:** each rebuilt panel opens without a missing component, displays the expected database content, and responds to the intended mouse, keyboard, or controller input.

## Repair the character setup

A typical 1.1 player inventory uses these components together:

- **Inventory** holds the character's item collections.
- **Currency Owner** holds balances such as Gold.
- **Item User** provides the character context used by item actions and equipped item behaviors.
- **Inventory Standard Input** handles inventory item use and UI input.
- **Inventory Interactor** supplies the character Inventory to compatible interactables.
- **Inventory Identifier** registers the character with the Inventory System Manager so other systems can resolve it by ID.

Compare every player prefab with this list. Preserve the project's Inventory Identifier values, then reconnect UI and interaction components to the correct player.

## Update actions, equipment, and Item Objects

### Item actions

**Category Item Actions** was renamed **Item Action Set**. Reassign the set used by each category. An Item Action Set can also be stored as an item attribute when individual definitions need different actions from the rest of their category.

### Equipped items

In 1.1, the **Equipper** is responsible for the visually equipped Item Object. Add **Usable Equipped Items Handler** beside it when the character must use equipped Item Object Behaviours, and assign the character's **Item User** to the handler.

Verify visual equipment and item use separately: seeing an Iron Sword model does not by itself prove that its behavior can run.

### Item Object components

| Version 1.0 name | Version 1.1 name | Migration note |
| --- | --- | --- |
| Item Object Action | Item Object Behaviour | The new name distinguishes a MonoBehaviour on the world object from an inventory Item Action. |
| Usable Item Object | Item Object Behaviour Handler | The handler composes one or more behaviors instead of requiring them through Item Object inheritance. |
| Item Pickup Visual Listener | Item Object View | The view responds to Item Object changes and can also drive a world-space Item View. |

**Historical naming note:** Item Object View was the replacement name in 1.1. Later Version 1 releases call this visual responsibility **Item Object Visualizer**, so current documentation and source use that newer name.

## Update custom code and integrations

Replace renamed types in custom scripts before changing behavior. Compile the core project first, then add each integration at a version that explicitly supports UIS 1.1 and compile again. The guide does not establish compatibility for an arbitrary current version of a third-party integration.

The version 1.1 Inventory System Manager APIs can resolve a registered Inventory or Display Panel Manager by ID:

```csharp
var inventoryIdentifier = InventorySystemManager.GetInventoryIdentifier(1);
var inventory = inventoryIdentifier?.Inventory;
inventory?.AddItem("potion", 3);

var displayPanelManager = InventorySystemManager.GetDisplayPanelManager(1);
displayPanelManager?.OpenPanel("Main Menu");
```

Keep the Inventory Identifier and panel-manager IDs aligned with the values recorded before the update. A lookup that returns no object is usually an identifier or initialization problem, not an item database problem.

## Check the editor before Play Mode

Before testing gameplay, confirm all of the following:

- The Console has no compiler errors.
- Project scenes and prefabs have no unresolved **Missing Script** components from UIS 1.0.
- The active database, dynamic category, currency, recipe, Item Slot Set, Item Action Set, and Category Item View Set references are assigned.
- Each player has the expected Inventory Identifier ID and the rebuilt UI resolves the same owner.
- The character has the input, Item User, interaction, and equipment components required by the features it uses.
- Each optional integration compiles after being added back individually.

Save the project and restart Unity once more. Recheck the Console and serialized assignments before entering Play Mode.

## Verify in Play Mode

Run a focused regression pass against the 1.0.x baseline:

1. Start with a known Bag, Equipment collection, Gold balance, three Health Potions, and an Iron Sword.
2. Open every rebuilt panel and verify content, selection, navigation, descriptions, and close behavior.
3. Use one Health Potion and confirm its amount and effect update once.
4. Equip and unequip the Iron Sword. Confirm both the visual Item Object and its usable behavior when the project supports one.
5. Pick up a world item and confirm its visual changes and its amount reaches the intended collection.
6. Complete one shop or crafting transaction if the project uses those systems.
7. Change scene or respawn the player if the project depends on identifier-based lookup across those workflows.
8. Save, exit Play Mode, restart the test, and load only from a disposable copy of the save. Compare items, collections, Gold, and equipped state with the expected result.

Do not overwrite the only copy of a 1.0 save while testing. If a save does not load correctly, stop and restore the backup before investigating IDs, database ordering, saver keys, or a project-specific data migration.

## Troubleshooting and recovery

| Symptom | Check | Fix |
| --- | --- | --- |
| Duplicate types or widespread compiler errors immediately after import | Old and new UIS package files coexist | Restore the migration backup, remove the 1.0 package files cleanly, and import 1.1 again. |
| A scene or prefab shows **Missing Script** | The object still references a renamed or removed 1.0 component | Replace it with the 1.1 component that owns the same responsibility, then reconnect its references. |
| A rebuilt panel is empty or does not respond | It still uses a 1.0 prefab, has no owner, or points at the wrong Inventory Identifier | Regenerate or rebuild it with UI Designer and reconnect its owner and input. |
| A database-backed field is empty after import | A 1.0 serialized reference was not reassigned to its 1.1 dynamic database field | Select the correct active database object again, save, and verify it survives an editor restart. |
| Item actions are missing | The category still expects Category Item Actions | Assign the equivalent Item Action Set to the category or definition. |
| An item equips visually but cannot be used | Equipper is working, but Usable Equipped Items Handler, Item User, or Item Object Behaviours are incomplete | Add or reconnect the handler and Item User, then verify the behavior list. |
| A pickup has no expected model | The old Item Pickup Visual Listener was removed | In 1.1 use Item Object View; in a later Version 1 project use the current Item Object Visualizer workflow. |
| Inventory input does nothing | Inventory Standard Input, Item User, UI owner, or the input integration is missing | Restore the required character components and add back only a UIS-1.1-compatible integration. |
| Loaded items, Gold, or equipment are wrong | The database IDs or order, Inventory Identifier, saver keys, or save format changed | Stop using that save, restore its backup, compare the recorded identifiers, and implement a project-specific migration or begin with a fresh save. |

## Related pages

- [Getting Started](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/)
- [UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/)
- [User Interface](https://opsive.com/support/documentation/ultimate-inventory-system/ui/)
- [Input](https://opsive.com/support/documentation/ultimate-inventory-system/input/)
- [Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/)
- [Equipping Items](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/equipping-items/)
- [Item Object View and Visualizer](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-object-view/)
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)
- [Version 1.2 Update Guide](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/version-1-2-update-guide/)
- [Version 1.3 Update Guide](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/version-1-3-update-guide/)

---

<a id="page-ultimate-inventory-system-getting-started-version-1-2-update-guide"></a>

# Version 1.2 Update Guide

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/version-1-2-update-guide/)

Use this historical guide when moving an Ultimate Inventory System project from version 1.1.x to version 1.2.0. Version 1.2 improves stability and feature coverage, but it also replaces shared audio code, changes save data infrastructure, removes one collection type, and renames inventory restriction APIs.

## Confirm the update boundary

| Starting version | Target version | Use this guide? |
| --- | --- | --- |
| 1.1.x, including 1.1.8 | 1.2.0 | Yes. Follow the complete migration. |
| 1.0.x | 1.2.0 | First complete the [Version 1.1 update](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/version-1-1-update-guide/), then use this guide. |
| An earlier 1.2 patch | A later 1.2 patch | No. This guide covers the breaking changes introduced by 1.2.0. |
| 1.2.x | 1.3 or later | No. Use the update guide for the target release. |

The release history does not define a universal compatibility matrix for every character controller or third-party integration. Install only integration versions that explicitly support the UIS and Opsive Shared versions used by the migrated project.

## Before you begin

1. Commit the working project to version control or make a complete restorable project backup.
2. Back up the Inventory System Database, project-owned item assets, prefabs, scenes, custom scripts, and runtime save files separately.
3. Record the Unity version, UIS version, Opsive Shared version, installed character controllers and integrations, active database, Inventory Identifier IDs, and save keys.
4. Run the 1.1.x project and record a baseline for the Bag, Equipment, Gold, item actions, audio, save slots, shops, crafting, and every integration the project uses.
5. Search scenes and prefabs for UIS and Opsive Shared components so renamed or removed scripts can be checked after import.

Do the migration in a project copy or branch. Runtime save compatibility is project-specific, especially when a project extends the save system, so test only with disposable copies of existing saves.

## Decide what must be migrated

| Area | Migration action |
| --- | --- |
| UIS and Opsive Shared package files | Remove the 1.1.x files before importing 1.2.0; do not overlay the packages. |
| Opsive character controllers and integrations | Reinstall or update them to versions compatible with the same Shared release, one at a time after the core project compiles. |
| Inventory System Database and project assets | Preserve them, open them under 1.2, and verify their references and representative definitions. |
| Version 1.1 UI | Keep it unless a component is missing or a custom script no longer compiles; 1.2 is not another complete UI replacement. |
| Audio | Replace references to the former UIS Audio Manager with the shared Audio Manager, Audio Config, and Audio Manager Module workflow. |
| Save UI and custom save code | Check Save System Manager, Save Views, metadata creation, save-slot display, and existing save files. |
| FixedSizeItemCollection | Replace it with a supported collection plus Item Restriction Object assets. |
| Custom inventory and restriction code | Apply the 1.2 method renames precisely; do not bulk-replace similarly named methods. |

## Replace version 1.1.x cleanly

1. Close Unity after completing the backup and baseline.
2. Remove the version 1.1.x Ultimate Inventory System files and its version of the `Assets/Opsive/Shared` folder. Do not delete project-owned databases, scenes, prefabs, or custom scripts.
3. Import the UIS 1.2.0 core package and its matching Opsive Shared files.
4. Open Unity and let the core assemblies import and compile before adding optional integrations.
5. If the project also uses an Opsive character controller, reinstall or update the controller to a release compatible with this Shared version.
6. Add UIS integrations back one at a time, compiling after each one.

**Checkpoint:** the UIS and Shared core assemblies compile without duplicate-type errors. The project contains one coherent Shared installation rather than files from both releases.

## Check TextMesh Pro assembly references

Some historical 1.2 projects reported that the `TMPro` namespace could not be found after replacing Shared.

![Unity Console error stating that the TMPro namespace could not be found](https://opsive.com/wp-content/uploads/2021/10/TextMeshPro-Error-1024x146.png)

If this exact compiler error appears, select these historical 1.2 Assembly Definition assets:

- `Assets/Opsive/Shared/Opsive.Shared.asmdef`
- `Assets/Opsive/UltimateInventorySystem/Scripts/Opsive.UltimateInventorySystem.asmdef`

In each Assembly Definition Inspector, ensure **Assembly Definition References** includes `Unity.TextMeshPro`, apply the change, and let Unity recompile. Do not change assembly references when the project does not report this error.

**Checkpoint:** the Console no longer reports a missing `TMPro` namespace, and both UIS runtime assemblies compile.

## Verify the database and project assets

Version 1.2 adds CSV import and export, but the CSV format has limitations and is not a replacement for a complete project backup.

1. Open the Inventory System Database in the Main Manager and confirm it is the intended project database.
2. Inspect representative categories, definitions, currencies, and recipes. For example, confirm Health Potion, Iron Sword, Gold, and one crafting recipe still show their expected values and relationships.
3. Open every scene and important prefab, then replace or reconnect any **Missing Script** component before entering Play Mode.
4. Check serialized database fields on custom components and integrations for missing categories, definitions, currencies, or recipes.
5. After the migrated database is verified, make a test CSV export if the project will use the new feature. Inspect the exported data before relying on it in a workflow.

**Checkpoint:** the database opens without errors, representative objects retain their values, all project scenes and prefabs are saved, and the Console is clear after an editor restart.

## Migrate audio

The old UIS-specific Audio Manager was removed. Version 1.2 uses the audio system in Opsive Shared so UIS and supported character controllers can use the same infrastructure.

1. Find prefabs, scenes, and custom scripts that referenced the former UIS Audio Manager.
2. Reconnect their clips through shared **Audio Config** assets.
3. For each Audio Config, verify the Audio Clips, Clip Selection, Audio Source Prefab, sharing and replacement choices, and Audio Modifier values the project needs.
4. For float overrides such as volume, pitch, and delay, choose no override, a constant, or a random range as appropriate. Set loop and output mixer choices independently.
5. If the project replaces Unity audio playback, derive a custom implementation from **Audio Manager Module** and test it independently before connecting UIS UI or item sounds.

**Checkpoint:** one UI click, one pickup, and one item action play the intended clip once, with the expected volume, pitch, and mixer output.

## Replace FixedSizeItemCollection

`FixedSizeItemCollection` was deprecated during 1.2 development and removed before the 1.2.0 release. Replace it with a supported collection and enforce capacity through restrictions.

1. Record the old collection name, purpose, default loadout, capacity, overflow behavior, and every UI that reads it.
2. Choose the replacement based on why the old collection was used. Use a standard Item Collection when only capacity mattered. Use an **Item Slot Collection** with an **Item Slot Set** when code or UI depends on named or indexed slots.
3. Create an **Item Restriction Set** asset from **Create > Ultimate Inventory System > Inventory > Item Restriction Set** when the replacement needs a capacity rule.
4. Add the restriction needed by the design. For example, **Item Collection Stack Amount Restriction** limits the number of stacks across named collections, while **Item Collection Stack Size Restriction** limits the amount allowed in each stack.
5. Add the Item Restriction Set to the Inventory's Item Collection Restriction Objects and target the replacement collection by its exact name.
6. Reconnect grids, hotbars, equipment views, actions, and custom code that referred to the removed collection type or its indexed access.

**Checkpoint:** fill a test Bag to its limit. The last valid Health Potion or Iron Sword is accepted, the next one follows the intended rejection or overflow behavior, and removing an item creates capacity again.

## Update save metadata and Save Views

Version 1.2 introduces save metadata so a save-slot view can show context without loading all saved gameplay data. The built-in manager uses basic metadata when no custom creator is assigned; projects can supply a custom Save Meta Data Creator for information such as play time or progress.

1. Open the **Save System Manager** and verify its save filename, extension, maximum save count, automatic load/save choices, and **Save Meta Data Creator**.
2. Leave the creator unassigned when the built-in basic metadata is sufficient. Reconnect a custom creator only after its code compiles against 1.2.
3. Open each Save Grid and Save View. Verify that empty and occupied slots draw correctly and that custom metadata modules still receive the expected type.
4. Keep the backed-up 1.1 save files unchanged. Test loading a copy, then save to a separate test slot and restart the player.

**Checkpoint:** empty slots, occupied slots, saving, loading, overwriting, and deleting work in the test environment, and the displayed metadata matches the selected slot.

## Update custom code

Version 1.2 renamed condition methods to state their purpose more clearly. Use these exact mappings:

| Version 1.1 API | Version 1.2 API | Scope |
| --- | --- | --- |
| `ItemCollection.AddItemCondition` | `ItemCollection.CanAddItem` | Item Collection subclasses and callers |
| `Inventory.AddCondition` / `IInventory.AddCondition` | `Inventory.CanAddItem` / `IInventory.CanAddItem` | Inventory implementations and callers |
| `Inventory.RemoveCondition` / `IInventory.RemoveCondition` | `Inventory.CanRemoveItem` / `IInventory.CanRemoveItem` | Inventory implementations and callers |
| `IItemRestriction.AddCondition` | `IItemRestriction.CanAddItem` | Restriction implementations |
| `IItemRestriction.RemoveCondition` | `IItemRestriction.CanRemoveItem` | Restriction implementations |

`ItemCollection.RemoveItemCondition` still exists in the 1.2.0 source. Do not replace that method merely because other removal-condition methods became `CanRemoveItem`.

Compile each custom assembly after updating its base types, overrides, interfaces, and call sites. Then rebuild or reinstall only the integration version intended for UIS 1.2; this guide does not promise that a newer integration package remains compatible with the historical release.

## Check the editor before Play Mode

Before testing gameplay, confirm all of the following:

- The Console has no compiler errors or duplicate UIS/Shared types.
- The TextMesh Pro references are present when the project uses the corresponding assemblies.
- Important scenes and prefabs contain no unresolved **Missing Script** components.
- The active database and representative category, definition, currency, and recipe references remain assigned.
- Every removed FixedSizeItemCollection has a supported replacement and the intended restrictions.
- Audio Config and Audio Manager Module references point to the shared audio system.
- Save System Manager, Save Views, and custom metadata creators are assigned as intended.
- Character controller and third-party integrations compile after being restored individually.

Save the project, restart Unity, and repeat this checkpoint before entering Play Mode.

## Verify in Play Mode

Compare the migrated project with the 1.1.x baseline:

1. Start with a known Bag, Equipment collection, Gold balance, three Health Potions, and an Iron Sword.
2. Add and remove items at, below, and above the Bag restriction limit. Confirm the accepted amount and overflow behavior.
3. Open the inventory and Equipment UI, navigate the views, use one Health Potion, and equip and unequip the Iron Sword.
4. Trigger a UI sound, pickup sound, and item-action sound. Confirm the shared audio configuration plays each as intended.
5. Complete one shop or crafting transaction if the project uses those systems.
6. Exercise every updated character-controller or third-party integration in the scene where it is used.
7. Create a new test save, verify its metadata, restart the player, load it, and compare items, Gold, equipment, and scene state.
8. Load only a disposable copy of a 1.1 save. If it does not round-trip correctly, stop and restore the backup rather than overwriting it.

## Troubleshooting and recovery

| Symptom | Check | Fix |
| --- | --- | --- |
| Duplicate types or widespread compiler errors after import | UIS 1.1, Shared 1.1, or an older integration still coexists with 1.2 | Restore the migration backup, remove the old package files cleanly, and import the 1.2 core again. |
| `TMPro` namespace cannot be found | The UIS or Shared Assembly Definition lost its TextMesh Pro reference | Add `Unity.TextMeshPro` to the two historical 1.2 Assembly Definitions and recompile. |
| A scene or prefab shows **Missing Script** | It references a removed 1.1 component | Replace the component with its 1.2 equivalent and reconnect its serialized data. |
| A collection or its UI is missing | It used FixedSizeItemCollection | Create a supported collection, add an Item Restriction Set, and reconnect all collection-name and UI references. |
| Too many or too few items fit | The restriction targets the wrong collection name or uses stack amount where stack size was intended | Match the exact collection name and choose the restriction that represents the design. |
| Audio is silent or uses unexpected pitch or volume | The old UIS Audio Manager remains referenced, or the Audio Config modifier/output is wrong | Reconnect the shared Audio Config and verify its source prefab, overrides, and mixer output. |
| Save slots are empty or metadata is wrong | The Save Meta Data Creator, Save View binding, extension, or test slot differs | Restore the intended creator and slot settings, then create a new disposable test save. |
| Custom restrictions do not compile | The 1.1 interface methods remain in an override or implementation | Apply the exact `CanAddItem` and `CanRemoveItem` mappings; retain `ItemCollection.RemoveItemCondition`. |
| A character-controller integration fails after the core compiles | Its package expects a different Opsive Shared or UIS version | Remove that integration and install a release explicitly compatible with the historical 1.2 setup. |
| A 1.1 save loads incorrect items, Gold, or equipment | Database identifiers, saver keys, metadata, or custom serialization changed | Stop using that save, restore its backup, and implement a project-specific migration or begin with a fresh save. |

## What version 1.2 adds

- Focused feature demo scenes for learning individual workflows.
- CSV database import and export, subject to the format's documented limitations.
- Shared Audio Config and Audio Manager Module infrastructure with clip selection and playback overrides.
- Save metadata that Save Views can display without loading all gameplay data.

Treat these as new capabilities to adopt after the migrated project passes its regression checks.

## Related pages

- [Getting Started](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/)
- [Version 1.1 Update Guide](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/version-1-1-update-guide/)
- [Version 1.3 Update Guide](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/version-1-3-update-guide/)
- [Database Import and Export](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/import-export/)
- [Audio](https://opsive.com/support/documentation/ultimate-inventory-system/audio/)
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)
- [Item Restrictions](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-restrictions/)
- [Opsive Character Controllers Integration](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/opsive-character-controllers/)

---

<a id="page-ultimate-inventory-system-editor-window"></a>

# Editor Window

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/)

Use the Main Manager to select an Inventory System Database and edit the Scriptable Objects referenced by it. Start with the data model, then add runtime UI: categories declare the structure, definitions describe each Item type, attributes supply values, and the remaining editors add Currency, crafting, UI, or bulk data workflows.

Each manager page documents the less-visible controls owned by that feature, including row context menus, Attribute cog and removal choices, UI Designer target selection, and database actions.

[Editor Options by Feature](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/editor-options-reference/) is a compact route to those owning guides; it does not duplicate their option descriptions.

## Open the database editors

1. Open **Tools > Opsive > Ultimate Inventory System > Main Manager**.
2. In **Setup**, select the project Inventory System Database.
3. Open the editor for the object type you want to create or review.
4. Confirm that the database shown by the Main Manager is the intended project database before making changes.

Objects created in these editors are saved as Scriptable Objects and referenced by the selected database. Related objects also retain their relationships, such as an Item Definition's Item Category or a Crafting Recipe's Crafting Category.

The editor keeps **Uncategorized** Item and Crafting Categories as safe defaults. A new Item Definition or Crafting Recipe uses the corresponding Uncategorized category until a project category is assigned.

## Follow the recommended route

1. In [Item Category](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-category/), create **All > Consumable** and **All > Equippable > Weapon**. Decide mutability and uniqueness before creating many definitions.
2. In [Item Definition](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-definition/), create **Health Potion** under Consumable and **Iron Sword** plus **Fire Wand** under Weapon.
3. In [Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/attributes/), confirm the inherited sources and values for `Icon`, `Description`, `Attack`, `Durability`, and `BuyPrice`. Attribute declarations themselves are added from the Item Category editor.
4. In [Currency](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/currency/), create **Gold** and set the icon and any amount or conversion rules the project needs.
5. In [Crafting Category](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/crafting-category/), organize recipes and choose the recipe type. Then use [Crafting Recipe](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/crafting-recipe/) to create one simple recipe with existing definitions as inputs and Health Potion as the output.
6. After the database is usable, open [UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/), create the Canvas Managers, duplicate a schema, and spawn the starting UI. Connect a **Bag** Inventory Grid and **Equipment** Item Slot Collection View to the player Inventory.
7. Use [Import and Export](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/import-export/) only for supported bulk edits or readable tables. It modifies an existing database, does not include every Unity object or custom value, and is not a backup system.

This order keeps the UI and runtime objects connected to stable database content instead of temporary Uncategorized entries.

## Choose an editor by task

Choose the editor that owns the task:

| User task | Editor | Expected result |
| --- | --- | --- |
| Organize definitions, declare attributes, and choose mutable, unique, or abstract behavior | [Item Category](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-category/) | A clear category hierarchy such as All > Equippable > Weapon |
| Create an Item template and set its Category, parent Definition, definition values, and Default Item values | [Item Definition](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-definition/) | Health Potion, Iron Sword, and Fire Wand definitions with the expected inherited fields |
| Inspect attribute source, inherited value, type, and Variant | [Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/attributes/) | Each field resolves from the intended Category, Definition, Default Item, or Item |
| Define money and optional conversion relationships | [Currency](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/currency/) | Gold is available to Currency Owners, shops, and price values |
| Organize recipes and select their processing type | [Crafting Category](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/crafting-category/) | Recipes share the intended type and category relationships |
| Set recipe inputs, outputs, and custom fields | [Crafting Recipe](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/crafting-recipe/) | The visual recipe summary matches the intended Health Potion recipe |
| Generate, find, and edit Inventory UI | [UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/) | The selected schema produces working Bag and Equipment panels |
| Move supported database fields through CSV or another module | [Import and Export](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/import-export/) | Existing objects are added or updated without treating the export as a full backup |

Open the linked feature page before using controls that appear only after right-clicking a row, opening a cog, or selecting a list entry; their consequences are documented with the affected data.

## Add and find database objects

Each object editor has a list and a selected-object panel. Enter a unique name beside **Add** to create an object, select it in the list, then edit its properties, attributes, or relationships.

![The Main Manager Item Category editor showing the category list and the selected category's editable sections.](https://opsive.com/wp-content/uploads/2020/04/ItemCategoryEditor-1.png?v=22af94b09ac7)

Use search before creating a similarly named object. The available tokens depend on the current editor:

- `c:<CategoryName>` finds Item Categories with that direct parent, or filters Definitions and Recipes by Category where supported.
- `i:<CategoryName>` finds Item Categories that inherit from that ancestor.
- `a:<AttributeName>` finds Categories or Definitions containing that attribute where supported.

The search bar also includes sorting and a filter-preset field. To save a frequent search, choose or enter the search, select the preset object field beside the search bar, and use **+** to create a Searchable List Filter Preset. The editor restores the saved preset when the window opens.

![The database object search bar showing its sorting control, filter-preset field, and add button.](https://opsive.com/wp-content/uploads/2020/04/SearchableFilterPreset.png?v=664c0fed42e4)

## Remove objects carefully

Database objects are related, so inspect the **Relationships** view before deleting one.

- Removing an **Item Category** breaks its direct child links. Available parents can be reconnected to the children, and directly assigned Item Definitions are moved to a suitable related Category or Uncategorized. At runtime, Definitions and Items belonging to the removed Category are unregistered.
- Removing an **Item Definition** reparents child Definitions to the removed Definition's parent when one exists. At runtime, Items belonging to that Definition are unregistered.
- Removing a runtime **Item** does not require Category or Definition cleanup. An Item Object can notify dependent MonoBehaviours before the Item is removed so they can release related state.

Use version control for recoverability. The Import and Export editor is intentionally incomplete and should not be used as a database backup.

## Editor checkpoints

Before building runtime scenes or UI, confirm that:

- The Main Manager references the intended Inventory System Database.
- All, Consumable, Equippable, and Weapon have the intended parent relationships.
- Health Potion uses Consumable; Iron Sword and Fire Wand use Weapon rather than Uncategorized.
- `Icon`, `Description`, and `BuyPrice` resolve for all three definitions, while weapon-only fields appear only on the Weapon branch.
- Gold exists and every configured price references the intended Currency.
- The sample Crafting Recipe uses the intended Crafting Category, inputs, output, and recipe type.
- The UI Designer schema is duplicated into project-owned assets before its prefabs are customized.

## Verify the next runtime workflow

1. Enter Play Mode and open the player Inventory.
2. Confirm that Health Potion, Iron Sword, and Fire Wand appear in **Bag** with their expected icons and descriptions.
3. Equip Iron Sword and confirm that it moves to **Equipment** and uses its intended runtime values.
4. Open the shop and confirm that the displayed Gold price matches the definition's `BuyPrice` used by the transaction.
5. Process the sample recipe and confirm that it consumes the configured inputs and adds Health Potion to the Inventory.

If one of these checks fails, return to the editor that owns that relationship or value rather than changing the generated UI first.

## Create an advanced search preset

For a filter that cannot be expressed with the built-in tokens, create a Scriptable Object that inherits `SearchableListFilterPreset` and override `IsValid`:

```csharp
/// <summary>
/// An object used to create filter and sort presets for searchable lists.
/// </summary>
public class SearchableListFilterPreset : ScriptableObject
{
    [Tooltip("The default search string.")]
    [SerializeField] protected string m_SearchString;
    [Tooltip("The default sort option, indicated by index.")]
    [SerializeField] protected int m_SortOptionIndex;

    public string SearchString {
        get => m_SearchString;
        set => m_SearchString = value;
    }

    public int SortOptionIndex {
        get => m_SortOptionIndex;
        set => m_SortOptionIndex = value;
    }

    /// <summary>
    /// Returns whether the object passes this custom filter.
    /// String matching is performed separately.
    /// </summary>
    public virtual bool IsValid(object obj)
    {
        return true;
    }
}
```

The preset can combine its custom object test with the saved search string and sort option.

## Next workflows

- [Create a new database](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/new-database/)
- [Define attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/)
- [Customize the generated UI](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/ui-customization/)
- [Learn from the demo scene](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/demo-scene/)

---

<a id="page-ultimate-inventory-system-editor-window-attributes"></a>

# Attributes

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/attributes/)

Use the Attribute editor to declare named values on an Item Category, then set or inherit those values on Categories, Item Definitions, Default Items, and runtime Items. Choose the collection before entering data: it determines which objects receive the field and where the value can vary.

## Choose the attribute collection

The Item Category editor has three tabs in its **Attributes** section:

| Collection | Use it when | Standard example |
| --- | --- | --- |
| **Item Category** | The value describes the category itself and can be inherited by child categories. | `CategoryIcon` for Weapon |
| **Item Definition** | Every Item created from one definition should share the value. | `Icon`, `Description`, `BuyPrice`, and `Attack` |
| **Item** | Each runtime Item instance may need its own value. | `Durability` on one Iron Sword or Fire Wand |

Attributes can be added or removed only from the Item Category editor. Item Definitions and Default Items display the declarations supplied by their direct category and ancestors, then let you inherit, override, or modify the values.

## Declare the starter attributes

1. Open **Tools > Opsive > Ultimate Inventory System > Main Manager**.
2. In **Setup**, confirm that the intended Inventory System Database is selected.
3. Open **Item Categories** and select **All**.
4. Open **Attributes > Item Definition**. Use **+** to add `Icon` as a `Sprite` and `Description` as a `string` if the new database does not already contain them.
5. Add `BuyPrice` as `CurrencyAmounts` when every starter definition can be sold by the sample shop.
6. Select **Weapon** and open **Attributes > Item Definition**. Add `Attack` as the numeric type used by the project, such as `int`.
7. Open Weapon's **Attributes > Item** tab and add `Durability` as `int`.

An attribute name must be unique for its Item Category, begin with a letter, and contain only letters, numbers, and underscores. Names are case-sensitive contracts with UI and system components, so use the exact configured spelling.

![The Item Category Attribute editor showing an attribute's name, type, value, source marker, and inherited-source marker.](https://opsive.com/wp-content/uploads/2020/04/ItemCategoryAttribute.png?v=9819adbdabf1)

## Read the source and inherited value

Each row shows the attribute name, type, value, and two colored markers:

- The left marker identifies the source Item Category that declared the attribute. Select it to open that category.
- The right marker identifies the object that currently supplies the inherited value.

The inherited-source letters are:

| Letter | Source object |
| --- | --- |
| **C** | Item Category |
| **S** | Attribute source |
| **I** | Default Item |
| **D** | Item Definition |

Use these markers before changing a value. They show whether Health Potion is reading a common value from All, whether Iron Sword is inheriting a Weapon declaration, or whether a child definition is inheriting from its parent definition.

## Set definition and Default Item values

After declaring the fields, open **Item Definitions**:

1. Select **Health Potion** and set its Item Definition `Icon`, `Description`, and `BuyPrice` values.
2. Select **Iron Sword** and set its Item Definition `Icon`, `Description`, `BuyPrice`, and `Attack` values.
3. In Iron Sword's **Default Item** attributes, set the starting `Durability`.
4. Repeat the weapon steps for **Fire Wand**, using its own definition values and starting Durability.

The Item Definition value is shared by Items created from that definition. The Default Item supplies the initial value for Item attributes. When Weapon is mutable, each runtime weapon receives a copy of its Default Item and can change Durability independently.

At this checkpoint, Health Potion should not expose `Attack` or `Durability`, while both weapon definitions should expose definition-level `Attack` and Default Item `Durability`.

## Choose Inherit, Override, or Modify

The **Variant** control determines how a value is resolved:

- **Inherit** reads the value from the parent shown by the inherited-source marker.
- **Override** stores a value directly on the selected Category, Definition, Default Item, or Item.
- **Modify** evaluates a formula using an inherited, override, or other attribute value. The built-in evaluator supports `int`, `float`, and `string`.

Use **Override** for the direct `Attack` values of Iron Sword and Fire Wand. Use **Inherit** when a child definition should keep its parent definition's value. Use **Modify** only for a clear relationship, such as Iron Sword +1 deriving its Attack from Iron Sword.

Open the cog menu and choose **Enable PreEvaluate** when an inherited or Modify result can be cached rather than recomputed every time it is requested. With **Inventory System Manager > Pre Evaluate Attributes** enabled, Categories and Definitions are reevaluated during database registration. Override values are read directly. Use **Disable PreEvaluate** for values that must resolve dynamically, or update them through the supported Attribute APIs so their cached values and notifications stay current.

## Rename, change type, move, or delete safely

### Rename an attribute

Change **Name** in the Item Category Attribute editor. The new name must still follow the naming rules and be unique. Then update every Item View Module, shop field, binding, script, or other consumer configured with the previous name. A renamed attribute and an unchanged consumer no longer match.

### Change the value type

Choose **Type** from the dropdown in the Item Category Attribute editor. A standard selection creates the matching `Attribute<T>` value; a custom Attribute type can provide its own behavior. Add missing selectable types through **Tools > Opsive > Unit Options**.

After a type change, review inherited and overridden values on every affected Category, Definition, and Default Item, then update consumers that expect the old type.

### Move between collections

Use **Move To > Item**, **Move To > Item Definition**, or **Move To > Item Category** from the cog menu when a declaration belongs in another collection. Moving between **Item Definition** and **Item** keeps values set for child objects. Moving a declaration into **Item Category** removes values that belonged to non-Category objects, so review the affected definitions before confirming.

Right-click an Attribute row and choose **Duplicate** to create a uniquely named declaration in the same collection. The editor propagates the declaration through the relevant Category family and deep-copies the corresponding values; rename and review the new family before using it.

### Delete a declaration

Select the attribute and use **-** from the Item Category editor. **Remove from Parents** removes the declaration through its parent chain. In the released Version 1 source, **Remove from Relevant Family** and **Remove from All Family** both execute the same full-family removal path, so do not rely on those two labels to produce different scopes. Inspect the category **Relationships** and make sure no UI, action, or script still expects the field before confirming a broad removal.

The Item Category editor owns these Attribute menus; use the neighboring [Item Category](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-category/) page for Category-level row and relationship actions.

## Editor checkpoints

Before entering Play Mode, confirm that:

- Every declaration appears once in the narrowest common category that needs it.
- `Icon`, `Description`, and `BuyPrice` are Item Definition declarations inherited from All.
- `Attack` is a Weapon Item Definition declaration and `Durability` is a Weapon Item declaration.
- Health Potion, Iron Sword, and Fire Wand show the expected source and inherited-source markers.
- Each direct value that should differ uses **Override**; inherited values remain **Inherit**.
- Iron Sword and Fire Wand Default Items have intentional starting Durability values.
- Weapon is mutable and unique when runtime Durability must vary by Item.
- Every configured consumer uses the exact attribute name and compatible value type.

## Verify in Play Mode

1. Add Health Potion, two Iron Sword Items, and one Fire Wand Item to the player's **Bag** collection.
2. Open the Item UI and confirm that each definition displays its own Icon and Description.
3. Open the shop and confirm that each definition's `BuyPrice` is read as the expected Gold amount.
4. Compare Iron Sword and Fire Wand and confirm that each reads its own `Attack` value.
5. Change the `Durability` of one Iron Sword and confirm that the other weapon Items keep their own values.
6. Confirm that matching Health Potion Items can stack when the collection permits stacking.

## Troubleshooting

- **A Definition or Default Item field is missing:** Check the direct Item Category, its ancestors, and the collection tab where the declaration was added.
- **A value is visible but cannot be edited:** Check **Variant**. Change **Inherit** to **Override** only when this object should own a different value.
- **A UI field becomes blank after a rename:** Update the consumer's attribute-name field to the new exact name and confirm that the type still matches.
- **A type is missing from the dropdown:** Add it through **Tools > Opsive > Unit Options** after the type compiles.
- **A runtime Item value does not change:** Confirm that the declaration is in the **Item** collection and that the direct Item Category is **Mutable**.
- **Changing one weapon changes every copy:** Confirm that Weapon is mutable and unique and that the changing field is an Item attribute initialized through the Default Item.
- **The inherited value comes from the wrong object:** Inspect the source markers, parent definition, and category parent order. Same-named attributes from multiple category parents use the first compatible source.
- **Values disappeared after moving or deleting a declaration:** Restore from version control if needed, then place the declaration in the correct collection before re-entering affected values.

## Related pages

- [Attributes and inheritance](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/)
- [Common Attributes and Types](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/common-attribute-types/)
- [Item Category editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-category/)
- [Item Definition editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-definition/)
- [Define attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/)
- [Create a new database](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/new-database/)
- [Customize Item UI](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/ui-customization/)

---

<a id="page-ultimate-inventory-system-editor-window-item-category"></a>

# Item Category

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-category/)

Create an Item Category when several Item Definitions need the same structure, inherited attributes, UI treatment, Item Actions, or inventory restrictions. Build categories before definitions so every new definition immediately receives the correct fields and behavior mappings.

## Create the starter category structure

1. Open **Tools > Opsive > Ultimate Inventory System > Main Manager**.
2. In **Setup**, confirm that the intended Inventory System Database is selected.
3. Open **Item Categories**.
4. Select the existing **All** category and review its common Item Definition attributes, including `Icon` and `Description`.
5. Enter **Consumable** beside **Add**, create it, and add **All** to **Parents**.
6. Create **Equippable** and add **All** to **Parents**.
7. Create **Weapon** and add **Equippable** to **Parents**.

The resulting hierarchy is:

- **All**
  - **Consumable**
  - **Equippable**
    - **Weapon**

Use Consumable for Health Potion. Use Weapon for Iron Sword and Fire Wand so both definitions also inherit from Equippable and All.

![The Item Category editor showing the category list and the selected category's Properties, Attributes, and Relationships sections.](https://opsive.com/wp-content/uploads/2020/04/ItemCategoryEditor.png?v=669d413293d0)

## Choose category properties

The **Properties** section controls decisions that apply to Items whose definitions directly use the category.

| Property | Choose it when | Standard example |
| --- | --- | --- |
| **Name** | The category needs a unique project name. The Scriptable Object filename follows it. | Weapon |
| **Mutable** | Runtime Items must change their own Item attribute values. | Weapon Items with changing `Durability` |
| **Unique** | Items must retain individual identity and should not stack in the default Item Collection. | Individual Iron Sword and Fire Wand Items |
| **Abstract** | The category exists only to organize or share data and should not be selectable by Item Definitions. | All or Equippable, when definitions always use narrower categories |
| **Editor Color** | A large database needs a visual grouping aid. | One color for equipment-related categories |
| **Editor Icon** | The category needs an explicit editor icon instead of the `CategoryIcon` attribute fallback. | A weapon-category icon |
| **Parents** | The category should inherit declarations or mappings from another category. | Weapon inherits from Equippable |

For the standard sample, leave Consumable **Mutable** and **Unique** disabled when matching Health Potion Items should stack and do not have per-instance changing values. Enable both on Weapon when each Iron Sword or Fire Wand must keep its own changing `Durability`.

Be cautious with mutable, common Items: when matching Items merge in an Item Collection, one instance's Item attribute values can be lost. Use **Unique** when individual runtime values must be preserved.

## Decide between one parent and multiple parents

Use a single parent when the category hierarchy already expresses the relationship. Weapon needs Equippable as its parent; it does not also need All because Equippable already inherits from All. Do not make Weapon inherit Consumable simply to reuse one value—move that shared declaration to All instead.

Multiple parents are useful only when a category genuinely combines independent capabilities. Before adding another parent, confirm that:

- The new parent is not a descendant of the selected category, which would create a loop.
- Same-named inherited attributes use the same type. Parents with same-named attributes of different types overlap and cannot be combined safely.
- The parent order is intentional. When multiple parents supply the same name and type, inheritance uses the first parent containing that attribute.

Use the **Relationships** section to review **Ancestors** and **Descendants** after changing parents.

## Declare attributes in the correct collection

The Item Category editor is the only place where attributes can be added or removed. The **Attributes** section has three tabs:

| Tab | What it declares | Standard example |
| --- | --- | --- |
| **Item Category** | Values that describe a category and can be inherited by child categories | `CategoryIcon` |
| **Item Definition** | Fields whose values are set per definition | `Icon`, `Description`, `BuyPrice`, and Weapon-only `Attack` |
| **Item** | Fields whose values can differ between runtime instances | Weapon-only `Durability` |

Keep `Icon`, `Description`, and `BuyPrice` on All when every definition needs them. Add `Attack` to Weapon's **Item Definition** tab and `Durability` to Weapon's **Item** tab. Iron Sword and Fire Wand then receive the weapon fields, while Health Potion does not.

Use **+** to add a declaration and **-** to remove one. Removing an inherited declaration can affect parent and child categories, definitions, and Default Item values, so review the removal prompt and the **Relationships** section before confirming it.

## Use categories in actions, equipment, and UI

Creating a category does not automatically create its downstream mappings. Configure the systems that consume it:

- In a **Category Item Action Set**, map a Consume action to Consumable and an Equip action to Equippable or Weapon. The Item View Slots Container binding then finds the actions that match the selected Item's categories.
- In an **Item Slot Set**, restrict a weapon slot to Weapon. A Right Hand slot with a size limit of 1 then accepts one Iron Sword or Fire Wand but rejects Health Potion.
- In a **Category Item View Set**, map Consumable or Weapon to a different Item View prefab only when those categories need different presentation.

Prefer the broadest category that accurately describes the behavior. Map Equip to Equippable when every equippable Item should receive it; map a weapon-only action to Weapon.

## Find and review categories

Use the search field when the category list becomes large:

- `c:<CategoryName>` finds categories with that direct parent.
- `i:<CategoryName>` finds categories that inherit from that ancestor.
- `a:<AttributeName>` finds categories containing that attribute.

The **Relationships** section provides navigation to **Ancestors**, **Descendants**, **Direct Item Definitions**, **Inherited Item Definitions**, **Direct Recipes**, and **Inherited Recipes**. Select the colored box beside a related object to open it.

Right-click a Category row and choose **Duplicate** when a new Category should begin with the same mutable/unique/abstract settings, parents, Attribute declarations, and values. The duplicate is a new Category identity with a generated name; existing Definitions stay assigned to the original. Rename it, review every copied Attribute family, and assign Definitions deliberately.

## Editor checkpoints

Before creating more definitions, confirm that:

- Consumable and Equippable show All as their direct parent.
- Weapon shows Equippable as its direct parent and All as an ancestor.
- Health Potion uses Consumable; Iron Sword and Fire Wand use Weapon rather than Uncategorized.
- All supplies the common Item Definition fields, while Weapon alone declares `Attack` and `Durability` in the intended tabs.
- Consumable is common and immutable for the stacking sample; Weapon is mutable and unique for per-Item Durability.
- Abstract is enabled only on categories that definitions should not select directly.
- Item Action Sets, Item Slot Sets, and Category Item View Sets reference the intended broad or narrow category.

## Verify in Play Mode

1. Add a stack of Health Potion Items and two Iron Sword Items to the player's **Bag** collection.
2. Confirm that matching Health Potion Items stack when the collection permits stacking.
3. Change the `Durability` of one Iron Sword and confirm that the other keeps its own value.
4. Open the inventory action list and confirm that Health Potion receives its Consumable actions while Iron Sword receives its equipment or weapon actions.
5. Equip Iron Sword and confirm that the Weapon slot accepts it.
6. Try to move Health Potion into the Weapon slot and confirm that the Item Slot Set restriction rejects it.

## Troubleshooting

- **A category is missing from the Item Definition category field:** Check whether **Abstract** is enabled. Disable it only if definitions should directly use that category.
- **A parent cannot be assigned:** Check for a descendant loop and same-named inherited attributes with conflicting types, then fix the hierarchy or move the shared declaration.
- **A definition is missing an attribute:** Check its direct Item Category, ancestors, and the tab where the declaration was added.
- **Weapon Items stack or share changing values:** Enable **Mutable** and **Unique** on the direct Weapon category and keep changing values in the **Item** attribute collection.
- **Health Potion does not stack:** Check that Consumable is not Unique and that the destination Item Collection allows stacking.
- **The wrong Item Actions appear:** Check the categories and exclusions on each Item Action Set, then confirm the Category Item Action Set binding used by the UI.
- **An Item cannot enter an equipment slot:** Check the Item Slot Set's allowed Item Category and confirm that the definition inherits from it.

## Related pages

- [Create a new database](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/new-database/)
- [Item Definition editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-definition/)
- [Attribute editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/attributes/)
- [Define attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/)
- [Attributes and inheritance](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/)
- [Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/)
- [Equipping Items and Item Slot Sets](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/equipping-items/)
- [Item Views and Category Item View Sets](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/)

---

<a id="page-ultimate-inventory-system-editor-window-item-definition"></a>

# Item Definition

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-definition/)

Create an Item Definition for each reusable Item type the game can produce, such as Health Potion, Iron Sword, or Fire Wand. Build the Item Category structure first: a definition must use a category, and that category determines which definition and runtime Item attributes are available.

## Before you begin

Confirm that the selected Inventory System Database contains:

- **All > Consumable** and **All > Equippable > Weapon**.
- `Icon`, `Description`, and `BuyPrice` in All's **Item Definition** attribute collection.
- `Attack` in Weapon's **Item Definition** collection.
- `Durability` in Weapon's **Item** collection.
- Weapon configured as mutable and unique when every runtime weapon must retain its own Durability.

If those declarations are not ready, configure them in the Item Category editor before adding definitions.

## Create Health Potion

1. Open **Tools > Opsive > Ultimate Inventory System > Main Manager**.
2. In **Setup**, confirm that the intended Inventory System Database is selected.
3. Open **Item Definitions**.
4. Enter **Health Potion** beside **Add** and create it. A new definition initially uses **Uncategorized**.
5. In **Properties**, set **Item Category** to **Consumable**.
6. In the definition's **Attributes** section, set `Icon`, `Description`, and `BuyPrice` to Health Potion values.
7. Leave Weapon-only fields absent. Health Potion should not receive `Attack` or `Durability` because Consumable does not inherit from Weapon.

At this checkpoint, Health Potion should show Consumable as its direct category and All as an inherited category.

![The Item Definition editor showing the definition list and the selected definition's Properties, Attributes, and Relationships sections.](https://opsive.com/wp-content/uploads/2020/04/ItemDefinitionEditor.png?v=2482860ad560)

## Create Iron Sword

1. Add **Iron Sword** and set **Item Category** to **Weapon**.
2. In the Item Definition attributes, set `Icon`, `Description`, `BuyPrice`, and `Attack`.
3. Open the **Default Item** attributes and set the starting `Durability`.
4. Confirm that the source of the common declarations is All and the source of the weapon declarations is Weapon.

The Default Item supplies the initial Item-level values for runtime Items created from this definition. When the Item is mutable, the system duplicates the Default Item so each runtime Iron Sword can keep its own Durability.

## Create Fire Wand efficiently

1. Right-click **Iron Sword** in the definition list and choose **Duplicate**.
2. Rename the copy **Fire Wand**. The definition name must remain unique and also identifies its Scriptable Object file.
3. Keep **Item Category** set to **Weapon**.
4. Replace the copied `Icon`, `Description`, `BuyPrice`, and `Attack` values with the Fire Wand values.
5. Set the Fire Wand Default Item's starting `Durability`.

Duplicating is useful when definitions share a category and most fields, but the duplicate is still an independent definition. Review every overridden value so the copied definition does not retain an Iron Sword asset or description by mistake.

## Choose definition properties

| Property | Decision | Standard example |
| --- | --- | --- |
| **Name** | Use a unique, player-recognizable definition name. | Iron Sword |
| **Item Category** | Choose the narrowest direct category that supplies the required fields and mappings. | Weapon, not Equippable or All |
| **Parent** | Use another definition only for a true variation with the same Item Category. | Iron Sword +1 can inherit from Iron Sword |
| **Editor Icon** | Set an editor-only icon when it should differ from the inherited `Icon` attribute. | Leave empty to use `Icon` |

Changing **Item Category** rebuilds the fields available to the definition and its Default Item. Values from the previous category can be removed when no matching declaration exists in the new category, so confirm the category before entering substantial data.

## Decide whether to use a parent definition

A parent definition must use the same Item Category as its child. Use a parent for a variation that should inherit most values, such as **Iron Sword +1** inheriting from Iron Sword and changing only `Attack` or `BuyPrice`.

Do not make Fire Wand a child of Iron Sword merely because both use Weapon. They are separate Item types and already share their structure through the Weapon category.

For a child definition, choose the Variant for each value deliberately:

- **Inherit** keeps the value from the parent definition.
- **Override** stores a value specific to the child.
- **Modify** derives a supported value from the inherited or another attribute value.

Parenting changes attribute inheritance from the Item Category value to the parent definition value. Use the **Relationships** section to inspect **Ancestors** and **Descendants** before relying on inherited data.

## Use the Attributes and Default Item sections

The definition has two value contexts:

| Context | Use it for | Standard example |
| --- | --- | --- |
| **Item Definition** | Values shared by every Item created from this definition | `Icon`, `Description`, `BuyPrice`, and `Attack` |
| **Default Item** | Starting values for Item attributes that can vary per runtime instance | `Durability` on Iron Sword or Fire Wand |

The Item Category editor owns the declarations. The Item Definition editor sets or inherits their values. If a field is missing here, add it to the correct attribute collection on the direct category or an ancestor rather than trying to create it on the definition.

Definition-specific behavior can also use an `ItemActionSet` Item Definition attribute when Items in the same broad category need different actions. For ordinary category-wide actions, use a Category Item Action Set instead.

## Find definitions and use list actions

Use the list search tokens when the database grows:

- `a:<AttributeName>` finds definitions containing the named attribute.
- `c:<ItemCategoryName>` finds definitions that inherit from the named category.

Right-click a definition to access these supported workflows:

- **Duplicate** creates an independent copy for a similar Item type.
- **Create Recipe** creates an **Uncategorized** Crafting Recipe with quantity `1` of the selected Item Definition as its output, copies the Definition's editor icon, and opens the new Recipe. Its ingredient list starts empty, so complete that workflow on the [Crafting Recipe](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/crafting-recipe/) page.

The **Relationships** section lists **Item Categories**, **Ancestors**, **Descendants**, **Direct Recipes**, and **Inherited Recipes**. Use it to confirm the data path and navigate to related objects.

## Editor checkpoints

Before entering Play Mode, confirm that:

- Health Potion uses Consumable; Iron Sword and Fire Wand use Weapon rather than Uncategorized.
- All three definitions expose `Icon`, `Description`, and `BuyPrice`.
- Only Iron Sword and Fire Wand expose Weapon's `Attack` and Default Item `Durability` fields.
- Every copied value on Fire Wand has been reviewed and replaced where necessary.
- Iron Sword and Fire Wand have no **Parent** unless they are intentionally part of a same-category variation chain.
- Any child definition shows the expected inherited source and uses **Override** or **Modify** only for intentional differences.
- **Editor Icon** is empty when the definition should use its `Icon` attribute in the editor.

## Verify in Play Mode

1. Add a stack of Health Potion Items, two Iron Sword Items, and one Fire Wand Item to the player's **Bag** collection.
2. Open the inventory UI and confirm that each definition displays its own Icon and Description.
3. Confirm that the shop reads each definition's expected `BuyPrice` in Gold when the shop is configured.
4. Compare Iron Sword and Fire Wand and confirm that each reports its own `Attack` value.
5. Change one Iron Sword's `Durability` and confirm that the other weapon Items keep their own values.
6. Confirm that matching Health Potion Items stack when the collection permits stacking.
7. If a definition-specific `ItemActionSet` is configured, invoke the Item and confirm that the selected definition uses the intended action set.

## Troubleshooting

- **A new definition remains Uncategorized:** Set **Item Category** in Properties, then verify the expected inherited fields before entering values.
- **An expected attribute is missing:** Check the direct Item Category and its ancestors, then add the declaration to the correct Item Definition or Item collection in the Item Category editor.
- **Values disappeared after changing category:** The new category does not declare matching fields. Restore the correct category and re-enter any values that were removed.
- **A field cannot be edited:** Check whether its Variant is **Inherit**. Use **Override** only when this definition should differ from its parent.
- **A Parent cannot be selected:** Confirm that both definitions use the same Item Category and that the relationship would not create an invalid ancestry.
- **Two weapons share changing Durability:** Keep `Durability` in the Item collection and confirm that Weapon is mutable and unique.
- **The editor shows the wrong icon:** Check **Editor Icon** first, then inspect the definition's `Icon` value and inherited source.
- **The wrong actions appear:** Check the definition's categories and the Category Item Action Set mappings, or the `ItemActionSet` value when using definition-specific behavior.

## Related pages

- [Create a new database](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/new-database/)
- [Item Category editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-category/)
- [Attribute editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/attributes/)
- [Define attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/)
- [Attributes and inheritance](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/)
- [Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/)
- [Item Skills and definition-specific action sets](https://opsive.com/support/documentation/ultimate-inventory-system/item/item-skills/)
- [Crafting Recipe editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/crafting-recipe/)

---

<a id="page-ultimate-inventory-system-editor-window-crafting-category"></a>

# Crafting Category

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/crafting-category/)

Create a Crafting Category to group recipes that should appear together and use the same Crafting Recipe type. Start with one concrete category for the first recipe; split categories only when the player-facing grouping or processing data is meaningfully different.

## Create the starter category

1. Open **Tools > Opsive > Ultimate Inventory System > Main Manager**.
2. In **Setup**, confirm that the intended Inventory System Database is selected.
3. Open **Crafting Categories**.
4. Enter **Consumable Recipes** beside **Add** and create it.
5. In **Properties**, keep **Abstract** disabled so Crafting Recipes can select this category directly.
6. Set **Recipe Type** to the built-in base Crafting Recipe type for the standard Health Potion recipe.
7. Choose a **Color** that makes this group recognizable in the editor.
8. Leave **Parents** empty for this first standalone category.

The database also retains an **Uncategorized** Crafting Category as a safe default. New Crafting Recipes use it until a project category is assigned; move finished recipes out of Uncategorized before runtime verification.

![The Crafting Category editor showing the category list and the selected category's Properties and Relationships sections.](https://opsive.com/wp-content/uploads/2020/04/CraftingCategoryEditor.png?v=ec139e192176)

## Choose category settings

| Setting | Use it for | Standard decision |
| --- | --- | --- |
| **Name** | The unique category and Scriptable Object name. | Consumable Recipes |
| **Abstract** | A grouping category that should not be selectable directly by a Crafting Recipe. | Disabled for the concrete starter category |
| **Color** | An editor-only visual aid for a larger recipe list. | One consistent color for consumable recipes |
| **Recipe Type** | The Crafting Recipe class used by direct recipes in this category. | The built-in base type for the simple Health Potion recipe |
| **Parents** | A higher-level recipe grouping when the hierarchy adds useful navigation. | None for the first standalone category |

The selected **Recipe Type** must inherit from the base Crafting Recipe type. Use a custom type only when recipes need additional serialized fields or different data, and pair it with a compatible Crafting Processor.

## Decide when to split categories

Keep recipes together when they:

- use the same Recipe Type and processor expectations;
- should appear in the same player-facing list or tab; and
- have the same broad purpose.

For the standard sample, place the recipe that produces Health Potion in **Consumable Recipes**. Add more categories later only for a clear reason. For example, a **Weapon Upgrades** category can be separate if Iron Sword or Fire Wand upgrade recipes need different fields, a different Recipe Type, or a distinct menu group.

Do not create one category per recipe. The Crafting Recipe already represents the individual input and output data.

Right-click a Crafting Category row and choose **Duplicate** when a new group should start with the same abstract flag, Recipe Type, and parents. Existing Recipes remain assigned to the original Category; the duplicate is a new identity. Set its editor color and icon separately and populate it deliberately.

## Use abstract parents deliberately

Add a parent category when several concrete groups need a shared place in the hierarchy. Mark a parent **Abstract** when recipes should select only its concrete descendants.

After changing **Parents**, use **Relationships** to inspect:

- **Ancestors** for the selected category's parent chain;
- **Descendants** for its child categories;
- **Direct Crafting Recipes** assigned to this category; and
- **Inherited Crafting Recipes** supplied through the hierarchy.

Avoid a parent relationship that would make a category one of its own descendants. Keep the hierarchy shallow unless the extra level improves editor or runtime organization.

## Connect the category to the Health Potion recipe

1. Open **Crafting Recipes** and create the Health Potion recipe.
2. Set its **Category** to **Consumable Recipes** rather than Uncategorized.
3. For the base Recipe Type, use existing Item Definitions for the ingredient entries and set Health Potion as the output.
4. Review the recipe's visual summary and confirm that its inputs and output are correct.

Assigning a Crafting Category converts the recipe to that category's **Recipe Type**. Changing a recipe to a category with a different type can remove fields that do not exist on the new type, so settle the category and type before entering substantial custom data.

## Connect the category to the Crafter and menu

The Crafter owns a Crafting Processor and the list of recipes available to the Crafting Menu. Add **Consumable Recipes** to the Crafter's **Crafting Categories** list so its recipes are available. Use **Miscellaneous Recipes** only for individual recipes that should be included outside the category lists.

Create or edit the Crafting Menu from the UI Designer **Crafting** tab. Confirm that the menu uses the intended player **Inventory** and the Crafter configured with Consumable Recipes. The recipe grid should then be able to list the Health Potion recipe, while the Recipe Panel shows its ingredients and output.

## Editor checkpoint

Before entering Play Mode, confirm that:

- Consumable Recipes exists in the intended database and is not Abstract.
- Its Recipe Type is the built-in base type used by the Health Potion recipe.
- The Health Potion recipe uses Consumable Recipes rather than Uncategorized.
- **Direct Crafting Recipes** lists the Health Potion recipe.
- The recipe visual summary shows the intended Item Definition inputs and Health Potion output.
- The Crafter includes Consumable Recipes in **Crafting Categories**.
- The Crafting Menu references the intended Inventory and Crafter.

## Verify in the Crafting Menu

1. Enter Play Mode and open the Crafting Menu.
2. Confirm that the Health Potion recipe appears in the recipe grid under the intended grouping.
3. Select it and confirm that the Recipe Panel shows the correct ingredients, output, and quantity controls.
4. With insufficient ingredients, attempt to craft and confirm that no ingredients are removed and no Health Potion is added.
5. Add the required ingredients to the player Inventory and craft once.
6. Confirm that the processor removes the configured inputs and adds the expected Health Potion output.

## Troubleshooting

- **Consumable Recipes cannot be selected on a recipe:** Check whether **Abstract** is enabled. Disable it for a concrete category.
- **A custom Recipe Type does not appear:** Confirm that the type compiles and inherits from the base Crafting Recipe type.
- **Recipe fields disappear after changing Category:** The new category uses a different Recipe Type. Restore the intended category or re-enter only the fields supported by the new type.
- **The Health Potion recipe is missing from Relationships:** Check that its direct **Category** is Consumable Recipes rather than Uncategorized or another group.
- **The recipe is absent from the Crafting Menu:** Check the Crafter's **Crafting Categories** and **Miscellaneous Recipes**, then confirm that the menu references that Crafter.
- **Crafting does not consume or produce Items:** Check the recipe inputs and output, the player's Inventory, and the Crafting Processor selected by the Crafter.
- **Unexpected recipes appear through a parent:** Inspect **Direct Crafting Recipes**, **Inherited Crafting Recipes**, and the category ancestry, then simplify the parent structure or adjust the Crafter grouping.

## Related pages

- [Crafting Recipe editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/crafting-recipe/)
- [Crafting concepts, processors, and Crafter](https://opsive.com/support/documentation/ultimate-inventory-system/crafting/)
- [Crafting Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/crafting-menu/)
- [Crafting UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/crafting/)
- [Custom Crafting Processors](https://opsive.com/support/documentation/ultimate-inventory-system/crafting/custom-crafting-processors/)

---

<a id="page-ultimate-inventory-system-editor-window-crafting-recipe"></a>

# Crafting Recipe

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/crafting-recipe/)

Create a Crafting Recipe to describe the ingredients and expected output that a Crafting Processor can use. For a simple workflow, use exact Item Definitions as ingredients and produce one Health Potion; use broader Category or Item-specific inputs only when the design requires them.

## Before you begin

Confirm that:

- The intended Inventory System Database is selected in the Main Manager.
- A concrete **Consumable Recipes** Crafting Category exists, is not Abstract, and uses the built-in base Crafting Recipe type.
- **Health Potion** exists as an Item Definition.
- The database contains the ingredient Item Definitions used by the project. The example below calls them **Herb** and **Water**; substitute existing definitions if the project uses different names.
- The player Inventory, Crafter, and Crafting Menu will be available for runtime verification.

## Create the Health Potion recipe

1. Open **Tools > Opsive > Ultimate Inventory System > Main Manager**.
2. In **Setup**, confirm that the intended Inventory System Database is selected.
3. Open **Crafting Recipes**.
4. Enter **Brew Health Potion** beside **Add** and create it. A new recipe initially uses the **Uncategorized** Crafting Category.
5. In **Properties**, set **Category** to **Consumable Recipes**.
6. Open **Ingredients**, add the Herb Item Definition with an amount of 2, and add the Water Item Definition with an amount of 1.
7. Open **Outputs** and add 1 Health Potion.
8. Review the visual recipe summary beneath the definition controls and confirm that it shows **2 Herb + 1 Water -> 1 Health Potion**.

![The Crafting Recipe editor showing the recipe list, selected recipe properties, ingredient and output controls, visual summary, and relationships.](https://opsive.com/wp-content/uploads/2020/04/CraftingRecipeEditor.png?v=60f866112032)

## Choose recipe properties

| Property | Decision | Standard example |
| --- | --- | --- |
| **Name** | Use a unique name that describes the result or player action. The Scriptable Object filename follows it. | Brew Health Potion |
| **Category** | Choose the concrete Crafting Category that supplies the recipe type and grouping. | Consumable Recipes |
| **Editor Icon** | Assign an editor-only visual when the recipe list needs one. | A Health Potion or crafting icon |

Changing **Category** converts the recipe to the new category's **Recipe Type**. Fields from the previous type can be removed when they do not exist on the new type, so choose the category before entering custom recipe data.

## Choose the ingredient scope

The base Recipe Type accepts Item Categories, Item Definitions, and Items as ingredients:

| Ingredient kind | Use it when | Effect |
| --- | --- | --- |
| **Item Category** | Any Item from a category should satisfy the requirement. | A broad material category can allow several definitions. |
| **Item Definition** | The recipe needs a specific Item type but any runtime copy is acceptable. | Any runtime Herb Item can satisfy the 2-Herb requirement. |
| **Item** | The recipe needs specific runtime Item data. | A processor can require a particular Item or attribute state. |

Use Item Definitions for the standard Health Potion recipe. They make the requirement predictable without depending on one runtime instance. Use a Category only when substitutions are intentional.

A recipe is a guideline for its Crafting Processor. If crafting depends on a runtime attribute, such as quality or Durability, confirm that the selected Recipe Type and processor evaluate that attribute rather than assuming the data alone enforces the rule.

## Configure the recipe tabs

### Ingredients

Add each required Item Category, Item Definition, or Item with its amount. For the example, enter 2 Herb and 1 Water as Item Definition amounts.

### Outputs

Add the Item amounts produced by a successful craft. The base workflow usually produces one Item type, but the output supports a list. Set Health Potion to an amount of 1.

### Other and custom tabs

The **Other** tab displays serialized fields supplied by a custom Recipe Type. A custom type can also add tabs, such as Currency requirements. Keep custom fields empty only when the selected processor does not require them.

The visual summary combines the tabs into one result view. Use it as the final editor check instead of reviewing each amount in isolation.

## Find and duplicate recipes

Use `c:<CraftingCategoryName>` in the search field to find recipes that inherit from a named Crafting Category.

Right-click a recipe and choose **Duplicate** when a new recipe uses the same Category and similar inputs. Rename the copy and review every ingredient, output, custom field, and Editor Icon before using it.

The **Relationships** section shows the Crafting Categories related to the recipe. Confirm that Consumable Recipes appears and that the category's **Direct Crafting Recipes** list contains Brew Health Potion.

## Connect the recipe to the Crafter and Crafting Menu

Add **Consumable Recipes** to the Crafter's **Crafting Categories** list. The Crafter combines its recipe list with a Crafting Processor, which decides whether the selected Inventory Items satisfy the recipe and performs the craft.

The Crafting Menu should reference the player's **Inventory** and that Crafter. Its **Crafting Recipe Grid** lists the available recipes, while the **Recipe Panel** displays the selected recipe's ingredients and output.

## Editor checkpoints

Before entering Play Mode, confirm that:

- Brew Health Potion uses Consumable Recipes rather than Uncategorized.
- Its Recipe Type is the base type expected by the Crafter's processor.
- Ingredients contains exactly 2 Herb and 1 Water as Item Definition amounts, or the project's documented substitutes.
- Outputs contains exactly 1 Health Potion.
- The visual summary matches the intended input-to-output relationship.
- Consumable Recipes lists Brew Health Potion under **Direct Crafting Recipes**.
- The Crafter includes Consumable Recipes and the Crafting Menu references that Crafter and the player Inventory.

## Verify with the Crafter and Crafting Menu

1. Enter Play Mode and open the Crafting Menu.
2. Confirm that Brew Health Potion appears in the Crafting Recipe Grid.
3. Select it and confirm that the Recipe Panel shows 2 Herb, 1 Water, and 1 Health Potion output.
4. With one ingredient missing, try to craft and confirm that no inputs are removed and no output is added.
5. Add the required Items to the player Inventory and craft a quantity of 1.
6. Confirm that exactly 2 Herb and 1 Water are removed and 1 Health Potion is added.
7. If the Quantity Picker is enabled, craft a larger valid quantity and confirm that every input and output amount scales consistently.

## Troubleshooting

- **Consumable Recipes cannot be selected:** Check whether the Crafting Category is Abstract and whether the Main Manager uses the same database.
- **Recipe fields disappear after changing Category:** The new category uses a different Recipe Type. Restore the intended Category or re-enter only fields supported by the new type.
- **The recipe accepts the wrong Items:** Check whether the ingredient uses an Item Category, Item Definition, or Item. Narrow the scope when substitutions are not intended.
- **An attribute-specific requirement is ignored:** Confirm that the Recipe Type stores the required data and that the Crafting Processor explicitly evaluates it.
- **The visual summary shows the wrong amount:** Correct the value in Ingredients or Outputs, then verify the summary before retesting.
- **The recipe is absent from the Crafting Menu:** Check the Crafter's **Crafting Categories** and **Miscellaneous Recipes**, then confirm that the menu references that Crafter.
- **Crafting succeeds but the Inventory does not change as expected:** Check the processor, recipe output, destination Inventory restrictions, and any external ingredient-removal option on the Crafter.
- **A duplicate retains old data:** Review the copied Category, ingredients, outputs, custom tabs, and Editor Icon before publishing it.

## Related pages

- [Crafting Category editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/crafting-category/)
- [Crafting concepts, processors, and Crafter](https://opsive.com/support/documentation/ultimate-inventory-system/crafting/)
- [Crafting Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/crafting-menu/)
- [Crafting UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/crafting/)
- [Custom Crafting Processors](https://opsive.com/support/documentation/ultimate-inventory-system/crafting/custom-crafting-processors/)
- [Item Definition editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-definition/)

---

<a id="page-ultimate-inventory-system-editor-window-currency"></a>

# Currency

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/currency/)

Create a Currency when an Inventory owner, shop, pickup, or UI needs to store and exchange a named value. Most projects should begin with one root Currency, such as Gold, and add conversion relationships only when players genuinely interact with multiple denominations.

## Create Gold

1. Open **Tools > Opsive > Ultimate Inventory System > Main Manager**.
2. In **Setup**, confirm that the intended Inventory System Database is selected.
3. Open **Currencies**.
4. Enter **Gold** beside **Add** and create it.
5. Set **Name** to the unique value `Gold` and assign the **Icon** used in the editor and runtime UI.
6. For a one-Currency project, leave **Base Currency**, **Overflow Currency**, and **Fraction Currency** unassigned. Gold is then the root of its own Currency family.
7. Set **Max Amount** only when the Currency Collection should enforce a project-specific upper limit, then verify that limit in Play Mode.

A Currency defines conversion and amount constraints, but it does not hold a player's balance by itself. A Currency Owner holds a Currency Collection at runtime.

![The Currency editor showing Gold's name, icon, conversion fields, amount limit, and Currency relationships.](https://opsive.com/wp-content/uploads/2020/04/CurrencyEditor.png?v=bc846bdec67e)

## Choose Currency properties

| Property | Use it for | Decision |
| --- | --- | --- |
| **Name** | The unique database name used to find the Currency. | Use `Gold` for the standard sample. |
| **Icon** | The editor and runtime representation. | Assign the same clear Gold icon used by the Currency UI. |
| **Base Currency** | The less valuable Currency from which the selected Currency is composed. | Leave empty for a root Currency. |
| **Base Exchange Rate** | The amount of Base Currency equal to one unit of the selected Currency. | Set only when **Base Currency** is assigned. |
| **Max Amount** | The maximum amount that a Currency Collection can retain for this Currency. | Use a deliberate project limit and test boundary behavior. |
| **Overflow Currency** | The more valuable Currency that receives value above **Max Amount**. | Assign only within the same conversion family. |
| **Fraction Currency** | The less valuable Currency that receives fractional value. | Assign only within the same conversion family. |

The base direction matters: **Base Currency** and **Fraction Currency** must be less valuable than the selected Currency, while **Overflow Currency** must be more valuable.

## Decide between one Currency and a family

### Use one root Currency

Use only Gold when prices, rewards, and balances are all expressed in Gold. This keeps Item prices, Currency Owner balances, and UI output easy to compare. No exchange-rate, overflow, or fraction relationship is required.

### Use convertible denominations

Create a family only when several denominations represent the same underlying value. The smallest denomination is the root. Each more valuable Currency references its less valuable **Base Currency** and defines a **Base Exchange Rate**.

For example, a Bronze > Silver > Gold family can define Silver in Bronze and Gold in Silver. Currencies in the family share the same root, so the Currency Collection can compute conversion through that root. Currencies with different roots cannot be converted to one another automatically.

Use **Overflow Currency** and **Fraction Currency** to keep amounts in valid denominations when a Currency Collection crosses a maximum or produces a fractional result. Avoid adding these relationships when the project wants separate, non-convertible economies.

## Review Currency relationships

The relationship view shows every Currency in the selected Currency's family and labels the **Root**, **Base**, **Overflow**, and **Fraction** roles. It also displays exchange rates. Select a Currency icon in the relationship view to open that Currency.

Before relying on conversion, trace the family back to one root and confirm that every rate points from a more valuable Currency to a less valuable Base Currency.

Right-click a Currency row and choose **Duplicate** when a new Currency should start with the same parent, exchange rate, icon, fraction/overflow references, and maximum amount. The duplicate is a new Currency identity; rename it and replace every relationship that should not continue pointing to the original family.

## Connect Gold to Items, owners, shops, and UI

### Set Item prices

Price is Item data, not a Currency property. Declare `BuyPrice` and, when needed, `SellPrice` as `CurrencyAmounts` **Item Definition** attributes. Set Health Potion, Iron Sword, and Fire Wand to amounts that reference Gold.

The Shop Currency Collection reads the attribute names configured on the shop. When no separate sell value is needed, it can be configured to read `BuyPrice` for both buying and selling.

### Give the player a balance

Add or configure a **Currency Owner** for the player Inventory. Its Currency Collection stores the Gold balance and performs addition, subtraction, division, and supported conversion.

### Display the balance

Use the UI Designer **Currency** tab to create a Multi Currency View or Currency Owner Monitor. Map Gold to the intended Currency View and bind the monitor to the player's Currency Owner.

The Currency definition, price attribute, runtime owner, shop, and UI must all reference the same Gold object from the selected database.

## Editor checkpoints

Before entering Play Mode, confirm that:

- Gold exists once in the intended Inventory System Database and has the expected Icon.
- Gold has no Base, Overflow, or Fraction relationship in the one-Currency setup.
- The relationship view identifies Gold as the root of its family.
- `BuyPrice` and optional `SellPrice` use the `CurrencyAmounts` type and reference Gold on Health Potion, Iron Sword, and Fire Wand.
- The player Currency Owner starts with the intended Gold amount.
- The Shop Currency Collection uses the same price attribute names defined by the Item Categories.
- The Currency Owner Monitor or Multi Currency View maps and displays Gold.

## Verify shop transactions in Play Mode

1. Enter Play Mode and record the player's starting Gold balance.
2. Open the Currency UI and confirm that it shows the same balance as the player's Currency Owner.
3. Buy Health Potion and confirm that the correct Gold amount is removed and the Item is added to the player's Inventory.
4. Attempt the same purchase without enough Gold and confirm that the transaction does not remove Currency or add the Item.
5. If selling is enabled, sell an Item and confirm that the balance increases by the configured `SellPrice`, or by `BuyPrice` when the shop intentionally shares that field.
6. For a multi-Currency family, test a value at each conversion boundary and confirm that overflow, fractions, and the displayed total use the intended denominations.

## Troubleshooting

- **Gold is missing from an editor field:** Check that the Main Manager and runtime scene reference the same Inventory System Database.
- **The shop shows no price or zero:** Check that the Item Definition exposes a `CurrencyAmounts` value, includes Gold, and uses the same attribute name configured by the Shop Currency Collection.
- **A transaction changes the wrong amount:** Check `BuyPrice`, `SellPrice`, and the shop's buy or sell modifier, then compare the before-and-after Currency Owner balance.
- **The balance UI is empty:** Check the Multi Currency View's Gold mapping and confirm that the Currency Owner Monitor resolves the intended owner or Inventory Identifier.
- **Two Currencies do not convert:** Check that both trace to the same root and that every Base Currency and exchange rate points in the correct value direction.
- **Overflow converts to the wrong denomination:** Check **Max Amount**, **Overflow Currency**, and the exchange rate on the more valuable Currency.
- **Fractional value disappears or loses precision:** Check **Fraction Currency** and the smallest denomination. Currency Collections maintain valid Currency amounts and can lose precision when a result is smaller than the root denomination.

## Related pages

- [Currency concepts and Currency Owners](https://opsive.com/support/documentation/ultimate-inventory-system/currency/)
- [Shops and transactions](https://opsive.com/support/documentation/ultimate-inventory-system/currency/shop/)
- [Attribute editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/attributes/)
- [Common price attributes](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/common-attribute-types/)
- [Define attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/)
- [Currency UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/currency/)
- [Multi Currency View and Currency Owner Monitor](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/multi-currency-view/)

---

<a id="page-ultimate-inventory-system-editor-window-ui-designer"></a>

# UI Designer

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/)

UI Designer assembles Inventory UI panels and supporting components from a project-owned schema. It creates a working starting point for menus, grids, views, bindings, and managers; the generated hierarchy and prefabs can then be styled or extended like other Unity UI.

UI Designer is optional. Ultimate Inventory System does not depend on its generated UI, so a project can use selected components, build the UI manually, or connect a different UI solution.

## Before you begin

Confirm that:

- The intended Inventory System Database is selected in **Main Manager > Setup**.
- Health Potion, Iron Sword, and Fire Wand have the Icon and Description values needed by Item Views.
- The player Inventory has **Bag** and **Equipment** Item Collections.
- Equipment uses an Item Slot Set whose weapon slot accepts the Weapon Item Category.
- Gold and `BuyPrice` are configured before building the Shop.
- Consumable Recipes, the Health Potion recipe, and a Crafter are configured before building the Crafting Menu.

Only the data required by the panels being built needs to exist. A basic Bag grid can be created before shop or crafting data is ready.

## Create the UI foundation

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer**.
2. In **Setup**, find **Create Canvas Managers** and select **Setup**. This creates the canvas and manager components required by the built-in UI.
3. In **UI Designer Schema**, select a starting schema and choose **Duplicate**. UI Designer requires a duplicate so project changes are made to project-owned assets rather than package assets.
4. Select **Spawn In Scene** to create the schema's basic menu and enable the remaining UI Designer tabs.
5. In the scene hierarchy, confirm that the generated canvas contains a Display Panel Manager and the schema's starting panels.

Use the Classic schema for a general grid-and-list starting point. Consider the RPG schema when the design centers on floating panels and Item Shape Grids. A schema is a collection of prefabs and assets, not a restriction on the final layout.

## Create and edit generated UI

Most UI Designer tabs have **Create** and **Edit** sections:

- In **Create**, set **Parent Transform** to the Rect Transform that should own the new object. Choose **Main Menu** in **Panel Option** when the panel belongs inside the generated Main Menu content.
- In **Edit**, use **Find Available Targets in Scene** or drag a component into the target field. Select a target before changing its generated options.

**Find Available Targets in Scene** searches compatible components below every active-scene root, including inactive children. Duplicate GameObject names receive numbered menu labels only to distinguish them; their Hierarchy names are not changed. Choosing a target changes the existing component controlled by **Edit** and does not create or bind another component.

The question-mark shortcut opens the relevant documentation. The magnifying-glass shortcut selects the resolved component in the scene hierarchy, which is the safest way to verify a similarly named target.

![The UI Designer documentation and scene-selection shortcut icons used to inspect the current submenu.](https://opsive.com/wp-content/uploads/2020/11/QuestionMarkANDSelectIcons.png?v=9cf257dd4ea9)

## Follow the recommended route

1. Review [Schemas](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/schemas/), duplicate one, and [create the Main Menu](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/main-menu/).
2. Create an [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/inventory-grid/) for **Bag** and bind it to the player Inventory. Add a collection filter when only Bag Items should appear.
3. Create [Equipment](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/equipment/) from the same Item Slot Set used by the Equipment Item Collection.
4. Configure the shared [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view-slots-container/) options, including Item View Drawer, Item Actions, moving, and Item Description binding.
5. Create or edit [Item Views](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view/), [Item Description](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-description/), and [Attribute Views](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/attribute-view/) only after the basic Item flow works.
6. Add the [Shop](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/shop/) after Gold and Item prices are ready.
7. Add [Storage](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/storage/) for direct player-to-storage exchange, then add a [Chest](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/chest/) when an interactable world object should open and bind that exchange UI.
8. Add [Crafting](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/crafting/) after the Crafter can process the Health Potion recipe.
9. Add optional feedback and utility UI, such as [Currency](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/currency/), [Inventory Monitor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/inventory-monitor/), [Item Hotbar](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-hotbar/), [Save](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/save/), or an [Item Shape Grid](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-shape-grid/).

This order isolates data or binding problems before several panels depend on the same Inventory and Item View setup.

## Choose a UI Designer tab by scenario

### Foundation and navigation

| Scenario | UI Designer page | Generated or edited result |
| --- | --- | --- |
| Choose the prefab and asset library | [Schemas](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/schemas/) | A project-owned Classic or RPG schema |
| Host several Inventory panels in one menu | [Main Menu](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/main-menu/) | A Display Panel Manager-controlled menu with subpanels and opening buttons |

### Inventory and equipment

| Scenario | UI Designer page | Generated or edited result |
| --- | --- | --- |
| Display Bag Items in a grid or list | [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/inventory-grid/) | An Inventory Grid with panel, Inventory, layout, navigation, filters, and tabs |
| Let Items occupy several cells | [Item Shape Grid](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-shape-grid/) | A shape grid plus matching controller and data configuration |
| Display and restrict equipped slots | [Equipment](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/equipment/) | An Item Slot Collection View based on an Item Slot Set |
| Provide direct input or drag-and-drop access | [Item Hotbar](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-hotbar/) | An Item Hotbar and editable Item View Slots |
| Apply shared grid, hotbar, and equipment behavior | [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view-slots-container/) | Drawer, action, movement, description, and slot configuration |

### Transactions and world interactions

| Scenario | UI Designer page | Generated or edited result |
| --- | --- | --- |
| Buy and sell Items | [Shop](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/shop/) | A Shop Menu with Shop, Inventory Grid, price view, and Quantity Picker options |
| Exchange Items between two Inventories | [Storage](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/storage/) | Player and storage grids with transfer behavior |
| Open storage from an interactable world object | [Chest](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/chest/) | A Chest Menu that binds to the Chest the player interacts with |
| Select and process recipes | [Crafting](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/crafting/) | A Crafting Menu with Crafter, Recipe Grid, and Recipe Panel options |
| Save and load through the provided simple menu | [Save](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/save/) | A Save Menu plus scene Saver discovery and grid editing |

### Views and feedback

| Scenario | UI Designer page | Generated or edited result |
| --- | --- | --- |
| Define the visual content inside an Item slot | [Item View](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view/) | An Item View prefab with selected Item View Modules |
| Show details for the selected Item | [Item Description](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-description/) | An Item Description with modules and an optional slot-container binding |
| Show one Attribute value | [Attribute View](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/attribute-view/) | An Attribute View with compatible Attribute View Modules |
| Show Gold or another Currency balance | [Currency](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/currency/) | Multi Currency Views, Currency Views, or Currency Owner Monitors |
| Notify the player when Inventory contents change | [Inventory Monitor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/inventory-monitor/) | An Inventory Monitor that presents Item Views when Items are added |

Use these pages as the task index for the generated UI.

The complete released Version 1 tab set is **Setup**, **Main Menu**, **Inventory Grid**, **Item Shape Grid**, **Equipment**, **Hotbar**, **Shop**, **Crafting**, **Save**, **Storage**, **Chest**, **Item Description**, **Currency**, **Inventory Monitor**, **Item View**, and **Attribute View**. A tab remains part of the customer-facing workflow even when the current schema or scene does not yet contain a compatible target.

## Editor checkpoints

Before entering Play Mode, confirm that:

- Canvas Managers exist, the schema was duplicated, and **Spawn In Scene** completed without Unity errors.
- The Display Panel Manager references the intended Main Menu and generated panels.
- The Bag Inventory Grid resolves the player Inventory, filters to Bag when required, and uses an Item View Drawer whose **Content** matches the grid content.
- Equipment uses the same Item Slot Set and Item Collection ID as the player's Equipment collection.
- Category Item View Sets and Category Item Action Sets reference objects from the selected database.
- The Shop uses the intended Shop component, Inventory Grid, Gold price view, and Quantity Picker configuration.
- Storage filters do not contain references from another database, and the Chest interaction can find and bind the intended Chest Menu.
- The Crafting Menu references the intended player Inventory and Crafter.
- Every Item Description or Attribute View binding points to the component that supplies its selected Item or Attribute.

## Verify in Play Mode

1. Open the Main Menu and confirm that each generated subpanel opens and closes through the Display Panel Manager.
2. Open Bag and confirm that Health Potion, Iron Sword, and Fire Wand display the expected Item Views, selection state, descriptions, and actions.
3. Equip Iron Sword and confirm that Bag and Equipment refresh and that the Weapon slot accepts it.
4. Buy Health Potion and confirm that the Shop updates Gold and Inventory contents.
5. Move an Item between the player and Storage Inventories, then interact with a Chest and confirm that the same menu binds to the selected Chest.
6. Craft Health Potion and confirm that the Recipe Panel, ingredients, output, and Inventory refresh are correct.
7. If an Attribute View displays Durability, change the selected weapon's value and confirm that the view updates.
8. Verify optional hotbar, monitor, save, Currency, or Item Shape Grid panels separately before combining them into the main navigation.

## Troubleshooting

- **The feature tabs are unavailable:** Check that the database is selected, Canvas Managers were created, a schema was duplicated, and **Spawn In Scene** completed.
- **A panel appears under the wrong object:** Check **Parent Transform** and **Panel Option**, then recreate or move the panel into the intended Main Menu content.
- **Edit cannot find a target:** Confirm that the generated object is present and active in the current scene, then use **Find Available Targets in Scene** or drag the component into the field.
- **The Bag grid is empty:** Check its Inventory or panel binding, collection filter, Item View Drawer, and matching **Content** transforms.
- **An Item uses the wrong appearance or actions:** Check the Item's Categories, Category Item View Set, Category Item Action Set, and their slot-container bindings.
- **Equipment has the wrong slots or rejects a Weapon:** Check the Item Slot Set, Item Collection ID, and generated Item View Slot restrictions.
- **Storage reports categories from the wrong database:** Select each warning and replace the referenced filter category with the matching category from the active database.
- **The Shop or Crafting Menu has no data:** Check the Shop or Crafter component, player Inventory binding, price or recipe data, and the panel's generated grids.
- **A custom View Module is missing from a dropdown:** Fix compilation errors and confirm that it inherits the appropriate Item View Module, Attribute View Module, or base View Module class.

## Related runtime UI pages

- [Inventory UI overview](https://opsive.com/support/documentation/ultimate-inventory-system/ui/)
- [Main Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/main-menu/)
- [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/)
- [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/inventorygrid/)
- [Item Views](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/)
- [Shop Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/shop-menu/)
- [Storage Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/storage-menu/)
- [Chest Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/chest-menu/)
- [Crafting Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/crafting-menu/)
- [Customize the generated UI](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/ui-customization/)

---

<a id="page-ultimate-inventory-system-editor-window-ui-designer-schemas"></a>

# Schemas

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/schemas/)

A UI Designer schema is a Scriptable Object that groups the prefabs and assets used to assemble Inventory UI. Choose a schema as a visual and structural starting point, duplicate it into project-owned assets, then generate and customize the panels required by the game.

Schemas and UI Designer are optional. They accelerate setup but do not constrain the final hierarchy, prefabs, or styling, and Ultimate Inventory System can run with manually built or third-party UI.

## Choose a starting schema

| Schema | Best starting point | Included direction |
| --- | --- | --- |
| [Classic](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/schemas/classic/) | A general Inventory UI with large, clear buttons and icons | Grid and list Inventories, hotbar, Shop, Crafting, Save, Item Description, and Currency views |
| [RPG](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/schemas/rpg/) | An adventure-style UI designed around floating panels or spatial inventory | Grid and list Inventories, Item Shape Grid, Equipment, hotbar, Shop, Crafting, Save, Item Description, and Currency views |

Choose Classic for the standardized **Bag** and **Equipment** workflow when a conventional grid is sufficient. Choose RPG when Items such as Iron Sword should occupy several cells in an Item Shape Grid. Either schema can be restyled after generation.

## Prepare the data and scene

Before generating UI, confirm that:

- The intended Inventory System Database is selected in **Main Manager > Setup**.
- The player Inventory has **Bag** and **Equipment** Item Collections.
- Equipment has an Item Slot Set whose weapon slot accepts Weapon.
- Health Potion, Iron Sword, and Fire Wand have the Icon and Description values needed by Item Views.
- The destination scene is open and contains the player Inventory that will be bound during setup.

Shop, Crafting, Storage, Chest, Save, or Item Shape Grid data is required only when those panels are being generated.

## Duplicate and spawn a schema

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer**.
2. In **Setup**, find **Create Canvas Managers** and select **Setup**.
3. In **UI Designer Schema**, select Classic or RPG.
4. Choose **Duplicate** and save the duplicated schema and its assets in a project-owned folder.
5. Confirm that the duplicated schema, rather than the package schema, is selected.
6. Select **Spawn In Scene** to create the basic menu and unlock the remaining UI Designer tabs.
7. In the hierarchy, confirm that the generated canvas contains a Display Panel Manager and the schema's starting panels.

UI Designer requires a duplicated schema before its generation tools are available. The duplicate also keeps project customization separate from package assets that can change during an update.

## Create the Bag panel

1. Open the UI Designer **Inventory Grid** tab.
2. In **Create**, set **Parent Transform** to the Main Menu content transform.
3. Set **Panel Option** to **Main Menu** when Bag should be a Main Menu subpanel.
4. Set **Panel Name** and **Inventory Grid Name** to clear project names such as `Bag`.
5. Assign the player **Inventory** and choose **Grid** under **Grid Options**.
6. Set the grid size and layout for the intended visible slots.
7. Add an Item Info Item Collection Filter that shows the **Bag** collection when the Inventory contains other collections.

In **Edit**, use **Find Available Targets in Scene** or drag the generated Inventory Grid into the target field. Confirm that its Item View Drawer uses the intended Category Item View Set and that the drawer and grid use the same **Content** transform.

## Create the Equipment panel

1. Open the UI Designer **Equipment** tab.
2. Assign the Item Slot Set used by the player's Equipment Item Collection.
3. Choose the intended parent panel and create the Item Slot Collection View.
4. Set its **Item Collection ID** to Equipment.
5. Confirm that the generated weapon Item View Slot accepts Weapon and rejects Consumable.

The Item Slot Set controls the number, names, and Item Category restrictions of the generated slots. The Item Slot Collection View and runtime Equipment collection must use the same set.

## Connect the shared views and bindings

The schema supplies prefab templates, but the generated UI still needs the correct runtime data sources:

- The Display Panel Manager opens and closes the Main Menu and its subpanels.
- The Inventory Grid is assigned directly to the player Inventory or receives it through an Item View Slots Container Panel Binding.
- The Equipment Item Slot Collection View resolves the Equipment collection through **Item Collection ID**.
- The Item View Drawer uses a Category Item View Set to choose the slot prefab for Consumable and Weapon Items.
- The Item View Slots Container Category Item Action Set Binding supplies actions such as Consume and Equip.
- The Item View Slots Container Description Binding sends the selected Item to the Item Description.

At the editor checkpoint, Health Potion, Iron Sword, and Fire Wand should all have a valid Item View mapping, while the Equipment panel should have a valid destination only for compatible Items.

## Customize safely

Choose the smallest scope that matches the intended change:

| Change | Edit | Result |
| --- | --- | --- |
| One panel in one scene | The generated scene hierarchy or its local prefab instance | Other generated panels keep the schema default. |
| Every future panel created from one template | The corresponding prefab in the duplicated project schema | Later UI Designer creation uses the project customization. |
| The complete visual system | The duplicated schema's coordinated prefab and asset set | Panels continue to share a consistent project style. |

Do not customize the package-owned source schema. Keep the duplicate and generated assets in version control before large changes.

Generating a new panel creates a fresh object from the currently selected schema. It does not automatically reproduce unrelated scene-only edits made to an earlier panel. When replacing or regenerating UI, compare the old hierarchy, bindings, and prefab overrides before removing it.

If a project switches from Classic to RPG, treat the new schema as a new baseline. Recheck layout, Item View prefabs, Category Item View Sets, Content transforms, navigation, and bindings instead of assuming the existing scene configuration transfers unchanged.

## Editor checkpoints

Before entering Play Mode, confirm that:

- Canvas Managers exist and the selected schema is the project-owned duplicate.
- **Spawn In Scene** completed without Unity errors or duplicate manager objects.
- The Display Panel Manager references the intended Main Menu and generated panels.
- Bag uses the player Inventory, the Bag collection filter, and matching grid/drawer **Content** transforms.
- Equipment uses the runtime collection's Item Slot Set and **Item Collection ID**.
- Consumable and Weapon have the intended Item View and Item Action mappings.
- The selected Item can reach the generated Item Description through its slot-container binding.
- Project changes were made to the duplicated schema or intended scene instances, not package assets.

## Verify in Play Mode

1. Open the generated Main Menu and confirm that Bag and Equipment panels open and close correctly.
2. Confirm that Health Potion, Iron Sword, and Fire Wand appear in Bag with their intended icons, selection visuals, and descriptions.
3. Select Health Potion and confirm that its Consume action is available.
4. Select and equip Iron Sword, then confirm that Bag and Equipment refresh to show the new owning collection.
5. Try to move Health Potion into the weapon slot and confirm that the Item Slot restriction rejects it.
6. Navigate every visible slot with the supported pointer, keyboard, or controller input and confirm that focus remains visible.
7. If the schema or a shared prefab was customized, open every affected panel and confirm that the visual change is consistent without breaking bindings.

## Troubleshooting

- **Schema tools remain unavailable:** Check that Canvas Managers were created and that a duplicated schema, not the package source, is selected.
- **Spawn In Scene creates the wrong visual style:** Check the selected schema and the prefab references stored by the duplicated schema.
- **A generated panel appears under the wrong object:** Check **Parent Transform** and **Panel Option** before creating it.
- **Bag is empty:** Check the Inventory or panel binding, the Bag collection filter, and the Item View Drawer and grid **Content** transforms.
- **Equipment has the wrong slots:** Check that the UI and Equipment Item Collection use the same Item Slot Set and Item Collection ID.
- **An Item uses the wrong prefab or actions:** Check its Categories, Category Item View Set, Category Item Action Set, and the slot-container bindings.
- **A customization appears only on one panel:** Determine whether the change belongs on the scene instance or the duplicated schema prefab, then apply it at the intended scope.
- **Regenerated UI loses a local change:** Reapply the change to the duplicated schema prefab when future generated instances should inherit it.
- **A package update changes the UI:** Confirm that the project references the duplicated schema assets rather than package-owned originals.

## Related pages

- [Classic schema](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/schemas/classic/)
- [RPG schema](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/schemas/rpg/)
- [UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/)
- [Main Menu](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/main-menu/)
- [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/inventory-grid/)
- [Equipment](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/equipment/)
- [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view-slots-container/)
- [Item Views](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view/)
- [Customize the generated UI](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/ui-customization/)
- [Runtime Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/)
- [Runtime Item Views](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/)

---

<a id="page-ultimate-inventory-system-editor-window-ui-designer-schemas-classic"></a>

# Classic

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/schemas/classic/)

The Classic schema is a minimalist UI with large buttons, clear Item icons, and conventional grid or list layouts. Use it when the project needs a readable general-purpose Inventory UI that can be generated quickly and restyled after the core interactions work. The UIS demo uses Classic as its baseline.

## Choose Classic when

Classic is a good starting point when:

- **Bag** should use a conventional Inventory Grid or List;
- controller, keyboard, or pointer navigation should remain visually clear;
- Shop, Crafting, Save, hotbar, description, and Currency panels should share one restrained style; and
- spatial Item placement is optional rather than the main visual identity.

Choose the [RPG schema](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/schemas/rpg/) instead when floating panels and Item Shape Grids are the primary direction. Both schemas are starting points and can be customized after generation.

## Create UI from the Classic schema

1. In **Main Manager > Setup**, confirm that the intended Inventory System Database is selected.
2. Open **Tools > Opsive > Ultimate Inventory System > UI Designer**.
3. In **Setup**, find **Create Canvas Managers** and select **Setup**.
4. In **UI Designer Schema**, select **Classic** and choose **Duplicate**.
5. Save the duplicate and its assets in a project-owned folder, then confirm that the duplicate is selected.
6. Select **Spawn In Scene**.
7. Confirm that the scene contains the generated canvas, Display Panel Manager, Main Menu, and Classic starting panels.

Duplicate the schema before changing its prefabs. This keeps project styling separate from package assets and makes future panels use the project-owned templates.

## Build the Bag and Equipment example

1. In **Inventory Grid**, set **Parent Transform** to the Main Menu content transform and choose **Main Menu** under **Panel Option**.
2. Set **Panel Name** and **Inventory Grid Name** to `Bag`, assign the player **Inventory**, and choose **Grid** or **List** under **Grid Options**.
3. Add an Item Info Item Collection Filter for the **Bag** collection when the Inventory also contains Equipment.
4. In **Equipment**, assign the Item Slot Set used by the player's Equipment Item Collection and create the Item Slot Collection View.
5. Set **Item Collection ID** to Equipment and confirm that the weapon slot accepts Weapon.
6. In the shared Item View Slots Container options, confirm that the Item View Drawer and grid use the same **Content** transform.
7. Map Consumable and Weapon in the Category Item View Set, then connect the Category Item Action Set and Item Description bindings.

At this checkpoint, Health Potion, Iron Sword, and Fire Wand should appear in Bag. Iron Sword and Fire Wand should have a valid Equipment destination, while Health Potion should be rejected by the weapon slot.

## Inventory layouts

### Inventory Grid

Use the grid when Item icons and spatial scanning are more important than long text rows.

![The Classic Inventory Grid displaying Item icons in evenly spaced square slots.](https://opsive.com/wp-content/uploads/2020/11/InventoryGrid-1-289x300.png)

### Inventory List

Use the list when Item names or row-based details need more horizontal space.

![The Classic Inventory List displaying Items as vertically arranged rows.](https://opsive.com/wp-content/uploads/2020/11/InventoryList-1-283x300.png)

### Item Shape Grid

Classic includes an Item Shape Grid template for Items that occupy several cells. The RPG schema remains the more focused starting point for a UI designed around this interaction.

![The Classic Item Shape Grid displaying differently sized Items across multiple cells.](https://opsive.com/wp-content/uploads/2020/11/ItemShapeGrid_v1_1_4.png?v=b50fa6a1c889)

### Item Hotbar

Use the hotbar for direct Item Actions through input or drag-and-drop assignment.

![The Classic Item Hotbar displaying a row of quick-access Item slots.](https://opsive.com/wp-content/uploads/2020/11/ItemHotbar.png)

## Menu workflows

### Shop Menu

The Shop template combines Item selection, prices, Currency display, and buying or selling controls. For the standard sample, its price views should read Health Potion, Iron Sword, and Fire Wand `BuyPrice` values in Gold.

![The Classic Shop Menu displaying the shop Inventory, selected Item, price, and transaction controls.](https://opsive.com/wp-content/uploads/2020/11/ShopScreenshot-1024x576.png)

### Crafting Menu

The Crafting template presents the Crafter's recipe list and selected recipe. Use it to show the ingredients and Health Potion output for the standard recipe.

![The Classic Crafting Menu displaying a recipe list and the selected recipe's ingredients and output.](https://opsive.com/wp-content/uploads/2020/07/CraftSystemScreenshot-1024x576.png)

### Save Menu

The provided Save Menu is a simple baseline for projects using the UIS save workflow. Projects with another save system can omit it or replace it.

![The Classic Save Menu displaying selectable save and load entries.](https://opsive.com/wp-content/uploads/2020/11/SaveSystemScreenshot-1024x576.png)

## Item and Currency views

### Item Description

Bind Item Description to the Bag Item View Slots Container so selecting Health Potion or Iron Sword updates the larger detail panel.

![The Classic Item Description panel displaying the selected Item's icon and descriptive details.](https://opsive.com/wp-content/uploads/2020/11/ItemDescription.png?v=4d17ea0e88b3)

### Multi Currency View

Map Gold to a Currency View and bind a Currency Owner Monitor when the panel should show the player's current balance.

![The Classic Multi Currency View displaying Currency icons and their current amounts.](https://opsive.com/wp-content/uploads/2020/11/MultiCurrencyView.png?v=a4b8f47077c7)

## Customize the duplicated schema

Edit a scene instance when only one generated panel should change. Edit the corresponding prefab in the duplicated Classic schema when every future generated instance should share the change.

Keep related prefabs consistent when changing slot size, typography, selection visuals, or navigation. After changing a shared Item View prefab, recheck Inventory Grid, Equipment, hotbar, Shop, and Crafting panels that use it.

Generating a new panel uses the currently selected duplicated schema. Scene-only overrides from an earlier panel are not automatically copied into a new generated instance.

## Editor checkpoints

Before entering Play Mode, confirm that:

- The selected Classic schema is the project-owned duplicate.
- **Spawn In Scene** completed without Unity errors.
- The Display Panel Manager references the generated Main Menu and panels.
- Bag resolves the player Inventory, collection filter, Item View Drawer, and matching **Content** transforms.
- Equipment uses the runtime collection's Item Slot Set and **Item Collection ID**.
- Category Item View and Item Action mappings use objects from the active database.
- Shop, Crafting, Save, Item Description, and Currency panels are included only when their runtime data or systems are configured.

## Verify in Play Mode

1. Open the Classic Main Menu and confirm that every included subpanel opens and closes correctly.
2. Confirm that Health Potion, Iron Sword, and Fire Wand appear in Bag with readable icons, selection state, and descriptions.
3. Equip Iron Sword and confirm that Bag and Equipment refresh and the selected Item remains understandable.
4. Buy Health Potion and confirm that Gold and Inventory contents update.
5. Craft Health Potion and confirm that the recipe panel and Inventory refresh after processing.
6. Navigate the grid, list, hotbar, and included menus with every supported input method.
7. Check customized prefabs at the smallest supported resolution and confirm that labels, slots, and focus visuals are not clipped.

## Troubleshooting

- **Classic cannot be selected or generated:** Check that Canvas Managers were created and a duplicated Classic schema is selected.
- **A panel uses package styling after customization:** Check that the active schema and prefab references point to the project-owned duplicate.
- **Bag is empty:** Check the Inventory or panel binding, Bag collection filter, Item View Drawer, and matching **Content** transforms.
- **An Item uses the wrong appearance:** Check its Categories and the Category Item View Set used by the drawer.
- **Equipment has the wrong slots:** Check the Item Slot Set, Item Collection ID, and generated Item View Slot restrictions.
- **A shared visual change is inconsistent:** Apply it to the duplicated schema prefab rather than only one scene instance, then retest every panel that consumes it.
- **Navigation skips or leaves the panel:** Check the grid size, Unity layout group, and Layout Group Navigation settings after changing the layout.

## Related pages

- [Schemas](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/schemas/)
- [RPG schema](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/schemas/rpg/)
- [UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/)
- [Main Menu](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/main-menu/)
- [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/inventory-grid/)
- [Item Shape Grid](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-shape-grid/)
- [Equipment](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/equipment/)
- [Item Hotbar](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-hotbar/)
- [Shop](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/shop/)
- [Crafting](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/crafting/)
- [Save](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/save/)
- [Item Description](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-description/)
- [Currency](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/currency/)
- [Customize the generated UI](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/ui-customization/)

---

<a id="page-ultimate-inventory-system-editor-window-ui-designer-schemas-rpg"></a>

# RPG

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/schemas/rpg/)

The RPG schema is an adventure-style UI built around floating panels, strong Item imagery, and spatial Item Shape Grids. Use it when arranging differently sized Items is part of the player experience and the interface is primarily controlled with a pointer, keyboard, or touch input.

## Choose the RPG schema when

RPG is a useful starting point when:

- the **Bag** should let Items occupy more than one cell;
- players should be able to move floating Inventory panels;
- Equipment, Shop, Crafting, hotbar, description, and Currency views should share a colorful adventure-game style; and
- spatial placement is more important than fitting the largest possible list into a compact panel.

Choose the [Classic schema](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/schemas/classic/) when a conventional grid or list is the primary layout. Both schemas are starting points and can be restyled after their data bindings and interactions work.

## Create UI from the RPG schema

1. In **Main Manager > Setup**, confirm that the intended Inventory System Database is selected.
2. Open **Tools > Opsive > Ultimate Inventory System > UI Designer**.
3. In **Setup**, find **Create Canvas Managers** and select **Setup**.
4. In **UI Designer Schema**, select **RPG** and choose **Duplicate**.
5. Save the duplicate and its assets in a project-owned folder, then confirm that the duplicate is selected.
6. Select **Spawn In Scene**.
7. Confirm that the scene contains the generated canvas, Display Panel Manager, Main Menu, and RPG starting panels.

Duplicate the schema before changing its prefabs. This keeps project styling separate from package assets and makes later panels use the project-owned templates.

## Build a spatial Bag and Equipment example

1. Define an Item Shape Attribute for the Items that will appear in the spatial Bag. For example, Health Potion can occupy one cell while Iron Sword uses a taller multi-cell shape.
2. In the UI Designer **Item Shape Grid** tab, set **Parent Transform** to the intended panel parent and choose **Floating** under **Panel Option** when the player should be able to move the panel.
3. Set **Panel Name** and **Grid Name** to `Bag`, then assign the player **Inventory**.
4. Set **Grid Size** and **Item Shape Size** for the visible Bag layout. Under **Item Collection**, choose Bag so this grid does not also display Equipment.
5. Create the Item Shape Grid and confirm that the Inventory now has the matching Item Shape Grid Controller and Item Shape Grid Data.
6. In **Equipment**, assign the Item Slot Set used by the player's Equipment Item Collection, create the Item Slot Collection View, and set its **Item Collection ID** to Equipment.
7. Confirm that the generated weapon slot accepts Weapon and that the Item Shape Grid uses Item Views intended for Item Shape Grids.

At this checkpoint, Health Potion and Iron Sword should appear in Bag with different visible shapes. Iron Sword should have a valid Equipment destination, while Health Potion should be rejected by the weapon slot.

## Inventory layouts

### Inventory Grid

Use the conventional grid when every Item should occupy one equal-sized slot.

![The RPG Inventory Grid displaying Item icons in evenly sized slots inside a floating panel.](https://opsive.com/wp-content/uploads/2021/01/Inventory-Grid.png?v=d83e38faa2d0)

### Inventory List

Use the list when names, amounts, or row-based details need more horizontal space.

![The RPG Inventory List displaying Items as vertically arranged rows in an adventure-style panel.](https://opsive.com/wp-content/uploads/2021/01/Inventory-List.png?v=6156b07820ac)

### Item Shape Grid

Use the Item Shape Grid when Items such as Iron Sword should occupy several cells. Its background layer shows available cells and placement feedback, while its foreground layer displays each Item across its complete shape.

![The RPG Item Shape Grid displaying differently sized Items arranged across a finite set of cells.](https://opsive.com/wp-content/uploads/2021/01/Item-Shape-Grid.png?v=a104f8e7b404)

The UI grid and the Item Shape Grid Data on the Inventory must use matching grid dimensions. Keep the generated Item Shape Item View modules because standard Item Views do not supply the same shape, selection, and drop-preview behavior.

### Equipment

The Equipment template creates an Item Slot Collection View from an Item Slot Set. Each visible slot should use the same Category restriction as the corresponding slot in the runtime Equipment collection.

![The RPG Equipment panel displaying dedicated Item slots for equippable categories.](https://opsive.com/wp-content/uploads/2021/01/Equipment-Panel.png?v=639ea7c12835)

### Item Hotbar

Use the hotbar for direct Item Actions through input or drag-and-drop assignment.

![The RPG Item Hotbar displaying a row of quick-access Item slots.](https://opsive.com/wp-content/uploads/2021/01/Item-Hotbar.png?v=7ebc98e146fe)

## Menu workflows

### Shop Menu

The Shop template combines Item selection, prices, Currency display, and buying or selling controls. In the standard example, price views can read the Health Potion, Iron Sword, and Fire Wand Buy Price values in Gold.

![The RPG Shop Menu displaying shop Items, the selected Item, prices, and transaction controls.](https://opsive.com/wp-content/uploads/2021/01/Shop-Menu.png?v=ec6b4bf69d5f)

### Crafting Menu

The Crafting template presents the Crafter's recipe list and selected recipe. Use it to show the ingredients and Health Potion output for the standard sample recipe.

![The RPG Crafting Menu displaying available recipes and the selected recipe's details.](https://opsive.com/wp-content/uploads/2021/01/Crafting-Menu.png?v=cb4790e6c3ea)

### Save Menu

The included Save Menu is a visual starting point for projects using the UIS save workflow. Projects with another save system can omit or replace it.

![The RPG Save Menu displaying selectable save and load entries.](https://opsive.com/wp-content/uploads/2021/01/Save-Menu.png?v=83d94a603e27)

## Item and Currency views

### Item Description

Bind Item Description to the Bag's Item View Slots Container so selecting Health Potion, Iron Sword, or Fire Wand updates the larger detail panel.

![The RPG Item Description panel displaying the selected Item's icon and descriptive details.](https://opsive.com/wp-content/uploads/2021/01/Item-Description.png?v=5e30c613c3df)

### Multi Currency View

Map Gold to a Currency View and bind a Currency Owner Monitor when the panel should show the player's current balance.

![The RPG Multi Currency View displaying Currency icons and their current amounts.](https://opsive.com/wp-content/uploads/2021/01/Mutli-Currency-View.png?v=321e9d5e3c5d)

## Customize the duplicated schema

Edit a scene instance when only one generated panel should change. Edit the corresponding prefab in the duplicated RPG schema when every future generated instance should share the change.

Keep related prefabs consistent when changing cell size, typography, selection visuals, or navigation. Item Shape Grid foreground and background views must continue to align, and the UI grid dimensions must continue to match the Item Shape Grid Data.

Generating a new panel uses the currently selected duplicated schema. Scene-only overrides from an earlier panel are not automatically copied into a new generated instance.

## Editor checkpoints

Before entering Play Mode, confirm that:

- The selected RPG schema is the project-owned duplicate.
- **Spawn In Scene** completed without Unity errors.
- The Display Panel Manager references the generated Main Menu and panels.
- Bag resolves the player Inventory, Bag collection, matching Item Shape Grid Data, and intended Item Shape Attribute.
- The UI and Inventory data use the same **Grid Size** and **Item Shape Size**.
- Equipment uses the runtime collection's Item Slot Set and **Item Collection ID**.
- Consumable and Weapon use compatible Item Views and Item Actions.
- Shop, Crafting, Save, Item Description, and Currency panels are included only when their runtime data or systems are configured.

## Verify in Play Mode

1. Open the RPG panels and confirm that every included panel opens, closes, and moves as intended.
2. Confirm that Health Potion and Iron Sword appear in Bag with their intended shapes, icons, selection state, and descriptions.
3. Drag Iron Sword to another valid position and confirm that the placement preview matches the occupied cells.
4. Try an invalid placement and confirm that the Item does not overlap an occupied or unavailable cell.
5. Equip Iron Sword and confirm that Bag and Equipment refresh to show the new owning collection.
6. Buy Health Potion and confirm that Gold and Inventory contents update.
7. Navigate every included grid, slot, and menu with each supported input method. If controller input is required, verify explicit navigation after changing any floating-panel layout.
8. Check the UI at the smallest supported resolution and confirm that labels, slots, shapes, and focus visuals are not clipped.

## Troubleshooting

- **RPG cannot be selected or generated:** Check that Canvas Managers were created and a duplicated RPG schema is selected.
- **A generated panel uses package styling after customization:** Check that the active schema and prefab references point to the project-owned duplicate.
- **The Item Shape Grid is empty:** Check the Inventory assignment, Item Collection selection, Item Shape Grid Data, and Item Shape Attributes.
- **Items appear in the wrong cells or at the wrong size:** Check that **Grid Size** and **Item Shape Size** match between the UI and the Inventory's grid data.
- **Dragging provides no shape preview:** Check that the generated Item View still includes the Item Shape Grid view modules and that the background and foreground layers are aligned.
- **Equipment has the wrong slots:** Check the Item Slot Set, Item Collection ID, and generated Item View Slot restrictions.
- **A floating panel cannot be moved:** Check that **Floating** was selected under **Panel Option** and that the generated header still has its drag handler.
- **Navigation skips or leaves a panel:** Check the layout, selectable navigation, and supported input configuration after repositioning or resizing the panel.

## Related pages

- [Schemas](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/schemas/)
- [Classic schema](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/schemas/classic/)
- [UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/)
- [Main Menu](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/main-menu/)
- [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/inventory-grid/)
- [Item Shape Grid](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-shape-grid/)
- [Runtime Item Shape Grid](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-shape-grid/)
- [Equipment](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/equipment/)
- [Item Hotbar](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-hotbar/)
- [Shop](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/shop/)
- [Crafting](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/crafting/)
- [Save](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/save/)
- [Item Description](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-description/)
- [Currency](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/currency/)
- [Customize the generated UI](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/ui-customization/)

---

<a id="page-ultimate-inventory-system-editor-window-ui-designer-main-menu"></a>

# Main Menu

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/main-menu/)

Use Main Menu as the navigation shell for Inventory panels that should share one screen. A typical menu opens **Bag** first, switches to **Equipment**, and can later add Shop, Crafting, or Save/Load without opening several overlapping menus.

Main Menu is optional. Keep a world interaction such as Chest in its own menu when it should open independently rather than appear as a permanent Inventory tab.

## Before you begin

Confirm that:

- the intended Inventory System Database is selected in **Main Manager > Setup**;
- Canvas Managers exist and a duplicated UI Designer schema has been spawned in the scene;
- the scene has an EventSystem and a Display Panel Manager;
- the player has an Inventory with **Bag** and **Equipment** Item Collections;
- Equipment is an Item Slot Collection with a Weapon slot that accepts Iron Sword; and
- Health Potion and Iron Sword have the Icon and Description values required by their Item Views.

Most spawned schemas already include a Main Menu. Check the Display Panel Manager's **Main Menu Panel** reference and the scene hierarchy first. When one exists, select it under **Edit** instead of creating a second menu.

## Set the panel owner

On the Display Panel Manager:

1. Assign the player GameObject to **Panel Owner**. This is the clearest choice for a single-player scene.
2. Alternatively, leave Panel Owner unassigned and set **Panel Owner Inventory Identifier ID** to the player's Inventory Identifier ID.
3. Assign the normal in-game panel to **Gameplay Panel** before creating Main Menu when UI Designer should add a **Main Menu** opening button there.

Inventory panels with **Bind To Panel Owner Inventory** enabled use the Inventory on this GameObject. If Panel Owner is missing and its Inventory Identifier cannot be found, the Display Panel Manager disables its UI at initialization.

## Create the Main Menu

Create a menu only when the spawned schema does not already provide the intended one:

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer**.
2. Select the **Main Menu** tab and open **Create**.
3. Set **Parent Transform** to a Rect Transform below the intended Display Panel Manager.
4. Set **Panel name** to a unique, descriptive value such as `Inventory Main Menu`.
5. Enable **Vertical** for the schema's vertical tab prefab, or disable it for the horizontal tab prefab.
6. Select **Create**.
7. Confirm that the Display Panel Manager's **Main Menu Panel** now references the generated Display Panel.
8. If **Gameplay Panel** was assigned, confirm that its main content contains the generated **Main Menu** Action Button.

![The Classic Main Menu showing Bag Items beside the character's Equipment slots.](https://opsive.com/wp-content/uploads/2020/11/EquipItemsScreenshot-1024x576.png)

Creating another Main Menu replaces the manager's Main Menu Panel reference but does not automatically remove an older menu or opener. Prefer editing the schema's existing menu unless a replacement is deliberate.

## Add Bag and Equipment

Add each subpanel from its own UI Designer tab. This creates both the panel and its mapped Main Menu button.

### Add Bag

1. Select **Inventory Grid**.
2. Set **Parent Transform** to the Main Menu Display Panel's **Main Content** transform.
3. Set **Panel Option** to **Main Menu**.
4. Set **Panel Name** and **Inventory Grid Name** to `Bag`, then assign the player **Inventory**.
5. Create the grid and configure its collection filter to show Bag while excluding Equipment.

### Add Equipment

1. Select **Equipment**.
2. Use the same Main Menu **Main Content** as **Parent Transform**.
3. Set **Panel Option** to **Main Menu** and **Panel Name** to `Equipment`.
4. Assign the player **Inventory** and the Item Slot Set used by the Equipment Item Collection.
5. Create the Item Slot Collection View, set its **Item Collection ID** to Equipment, and confirm that its Weapon slot accepts Iron Sword but rejects Health Potion.

At this checkpoint, the Main Menu should contain two inner Display Panels and two tab buttons. Bag and Equipment should also appear as paired **Panel** and **Button** entries on the Main Menu component.

## Add related panels

Use the same Main Menu Parent Transform and **Panel Option** for other persistent navigation destinations:

| Panel | Add it when | Expected data |
| --- | --- | --- |
| **Shop** | Buying or selling belongs inside the shared menu | Shop Inventory, Gold, and Item price attributes |
| **Crafting** | Players should choose recipes from the shared menu | Crafter, Crafting Categories, and the Health Potion recipe |
| **Save/Load** | The built-in slot menu belongs inside the shared menu | Save System Manager and required Saver components |
| **BlankSubPanel** | A project-specific page has no dedicated UI Designer tab | Custom content added manually after generation |

Item Description, Currency views, and other supporting UI normally belong inside the panel that supplies their data rather than becoming empty tabs of their own.

## Manage subpanels and buttons

1. In the Main Menu **Edit** section, select the intended Main Menu.
2. Review **Main Menu Sub Panels**. Each entry represents one runtime Panel/Button pair.
3. Select an entry and compare its displayed **Panel name** and **Button text**.
4. Use **Select Panel** and **Select Button** to locate the exact generated objects before changing their layout or text.
5. Use the add control only when a custom blank panel is needed. It creates a `BlankSubPanel` Display Panel and matching button.
6. Remove an entry only when both its panel and button should be deleted; removal destroys both generated objects and their Main Menu reference.

Keep every Panel and Button reference non-null. Give every Display Panel a unique **Unique Name**, and make its button text describe the same destination.

New subpanel buttons are inserted at the start of the **Menu Tabs** hierarchy, while their Panel/Button mappings are appended to **Main Menu Sub Panels**. After adding several panels, deliberately align the visual button order and the list order. The list determines which panel is first and which panel is remembered as previous; the hierarchy determines how the buttons appear on screen.

## Choose what opens first

Set **Menu Open Options** on Main Menu:

| Option | Result | Use it when |
| --- | --- | --- |
| **Open Previous Sub Menu** | Reopens the last selected panel | Players should return to their recent context |
| **Open First Sub Menu** | Opens index 0 in the Panels list | Bag should always be the starting page |
| **Open No Sub Menu** | Opens the shell with every subpanel closed | The player should explicitly choose a destination |

For the standard Bag and Equipment workflow, place Bag at index 0 and choose **Open First Sub Menu**. Confirm that the visually first button is also Bag after matching the list and hierarchy order.

On Main Menu, also confirm that **Close Button**, optional **Quit Button**, and **Menu Tabs** reference the intended generated controls. Quit calls `Application.Quit`, so it has no visible effect while testing inside the Unity Editor.

## Choose manager behavior

The Display Panel Manager controls the transition between gameplay and menu panels:

- Enable **Set Time Scale To Zero When Menu Is Opened** when opening Main Menu should pause scaled gameplay.
- Enable **Close Menu When Opening Another** when a new menu should close the current menu. When disabled, the manager refuses to open the second menu while another menu is active.
- Enable **Enable Input On Gameplay Selected** when selecting and leaving Gameplay Panel should toggle gameplay input events on the Panel Owner.

Choose these settings for the entire panel manager rather than per subpanel. Bag and Equipment are inner panels of the same Main Menu, so switching between them does not open a second menu.

## How it runs

1. Display Panel Manager opens its Main Menu Panel and closes the selected Gameplay Panel when Main Menu is a menu panel.
2. Main Menu applies **Menu Open Options** and opens the selected inner panel.
3. Pressing the Equipment button closes and deactivates every other mapped subpanel, then opens Equipment.
4. Pressing Bag repeats the same process in the other direction.
5. Closing Main Menu closes its selected subpanel and returns focus to the previous panel or selectable.

Each generated button is paired with its panel at initialization. This is why a non-null mapping and consistent order matter more than the button's visible position alone.

## Editor checkpoints

Before entering Play Mode, confirm that:

- the scene has an EventSystem, and the Display Panel Manager resolves the intended player through **Panel Owner** or **Panel Owner Inventory Identifier ID**;
- **Gameplay Panel** and **Main Menu Panel** reference the intended Display Panels;
- only one active Main Menu and one intended gameplay opener exist;
- the Main Menu Display Panel has a unique name and is configured as a menu panel;
- **Close Button**, **Menu Tabs**, and every Panel/Button pair have valid references;
- Bag and Equipment are children of the Main Menu's Main Content;
- Bag is index 0 when **Open First Sub Menu** is selected;
- the Menu Tabs hierarchy and Main Menu Sub Panels list use the same intended order;
- Bag binds to the player Inventory and filters out Equipment;
- Equipment binds to the same Inventory, Item Collection ID, and Item Slot Set used at runtime; and
- every related panel has the data it needs before its tab is exposed to players.

## Verify in Play Mode

1. Enter Play Mode and use the generated gameplay button or the project's menu input to open Main Menu.
2. Confirm that Bag opens first and shows Health Potion and Iron Sword while hiding Items already in Equipment.
3. Move to Equipment using pointer, keyboard, and controller input. Confirm that Bag closes, Equipment opens, and selection remains visible.
4. Equip Iron Sword and confirm that it leaves Bag and appears in the Weapon slot without changing the active Main Menu shell.
5. Return to Bag and confirm that both panels display the updated Inventory state.
6. Close Main Menu. Confirm that the selected subpanel closes, Gameplay Panel returns, and the configured time-scale and gameplay-input behavior are restored.
7. Reopen the menu and confirm that **Menu Open Options** chooses Bag, the previous panel, or no panel exactly as configured.
8. If Shop, Crafting, or Save/Load is included, open each tab and verify its data workflow independently.
9. Try to open another standalone menu while Main Menu is active and confirm that **Close Menu When Opening Another** applies the intended close-or-refuse policy.

## Troubleshooting

- **The entire UI disables itself on start:** Assign **Panel Owner**, or correct **Panel Owner Inventory Identifier ID** so it resolves an Inventory Identifier at initialization.
- **No Main Menu opening button was created:** Assign **Gameplay Panel** before creating Main Menu. Otherwise, add a project button that calls the generated Main Menu Display Panel's open flow.
- **Main Menu does not open:** Check **Main Menu Panel**, confirm that the panel is registered under the intended Display Panel Manager, and check whether another menu is blocking it.
- **A second Main Menu opens instead of the intended one:** Check for an older generated menu and opener, then keep one deliberate **Main Menu Panel** reference.
- **A tab opens the wrong panel:** In **Main Menu Sub Panels**, compare each **Panel name** and **Button text**, then use **Select Panel** and **Select Button** to repair the mismatched pair.
- **The wrong panel opens first:** Check **Menu Open Options** and the Panels list order. `Open First Sub Menu` uses list index 0, not the visually first hierarchy child.
- **A new panel does not appear as a tab:** Its **Panel Option** must be **Main Menu**, and its **Parent Transform** must be this Main Menu's Main Content.
- **The tab order looks reversed after adding panels:** UI Designer inserts new buttons at the start of Menu Tabs but appends their mappings to the list. Reorder the button hierarchy and Main Menu Sub Panels list to match.
- **Bag is empty or shows the wrong player:** Check the Display Panel Manager's Panel Owner, the panel's Inventory binding, and the Bag Item Collection filter.
- **Equipment shows the wrong slots or rejects Iron Sword:** Check the Equipment Item Collection, Item Collection ID, shared Item Slot Set, and the Weapon restriction.
- **Several subpanels remain visible:** Confirm that every destination is included in Main Menu's Panels list and that each entry references the intended inner Display Panel.
- **Keyboard or controller focus is lost:** Check the EventSystem, each Display Panel's Selectable On Open, Action Button navigation, and the selected schema's Menu Tabs layout.
- **Gameplay remains paused or input remains disabled:** Confirm that Main Menu actually closes, then check **Set Time Scale To Zero When Menu Is Opened** and **Enable Input On Gameplay Selected** on the same Display Panel Manager.
- **A duplicate panel-name warning appears:** Give each Display Panel a unique **Unique Name** before the manager registers it.
- **Quit appears to do nothing:** `Application.Quit` does not stop Play Mode in the Unity Editor; test it in a built player.

## Related pages

- [UI Designer workflow](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/)
- [Schemas](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/schemas/)
- [Inventory Grid for Bag](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/inventory-grid/)
- [Equipment](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/equipment/)
- [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view-slots-container/)
- [Shop](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/shop/)
- [Crafting](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/crafting/)
- [Save/Load](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/save/)
- [Main Menu runtime behavior](https://opsive.com/support/documentation/ultimate-inventory-system/ui/main-menu/)
- [Item Collections](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/)
- [Customize the generated UI](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/ui-customization/)

---

<a id="page-ultimate-inventory-system-editor-window-ui-designer-inventory-grid"></a>

# Inventory Grid

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/inventory-grid/)

Use the UI Designer Inventory Grid to present an Inventory as a fixed set of reusable Item slots. It can create a conventional icon grid or a one-column list, then connect that view to navigation, filtering, sorting, Item Actions, and Item Description.

This workflow creates a **Bag** panel that displays Health Potion, Iron Sword, and Fire Wand without also showing Items in the **Equipment** collection.

## Before you begin

Confirm that:

- the intended Inventory System Database is selected in **Main Manager > Setup**;
- UI Designer Canvas Managers and a duplicated schema have been created;
- **Spawn In Scene** has created the schema's canvas and managers;
- the player has an Inventory with **Bag** and **Equipment** Item Collections; and
- Health Potion, Iron Sword, and Fire Wand have the Icon and Description values required by the chosen Item Views.

Create the [UI Designer foundation](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/) first if the Inventory Grid tab is unavailable.

## Create the Bag Inventory Grid

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer** and select **Inventory Grid**.
2. In **Create**, set **Parent Transform** to the Rect Transform that should contain the new panel. For a main-menu Bag, use the generated Main Menu content transform.
3. Set **Panel Option** to **Main Menu**, then set **Panel Name** and **Inventory Grid Name** to `Bag`.
4. Assign the player's **Inventory**.
5. Under **Grid Options**, choose **Grid** for equal-sized icon slots or **List** for one scrollable column.
6. Set the grid size and Unity layout group for the intended number and direction of visible slots.
7. Create the Inventory Grid, then confirm that the Bag panel and its Item View Slots appear under the selected parent in the scene hierarchy.

The **Inventory Grid Name** identifies this Item View Slots Container to bindings and move conditions. Use a stable, descriptive name rather than leaving several grids with indistinguishable defaults.

## Show only the Bag collection

1. In **Edit**, use **Find Available Targets in Scene** or drag the generated Bag Inventory Grid into the target field.
2. In the filter and sorter options, add an **Item Info Item Collection Filter** to the grid's default filter configuration.
3. Configure the filter to show **Bag** and exclude Equipment.
4. Confirm that the Item View Drawer has **Use View Slots** enabled.
5. Set the Item View Drawer's **Content** to the transform that contains the generated Item View Slots. The drawer and grid must use the same content hierarchy.
6. Assign a Category Item View Set that can resolve both Consumable and Weapon Items.
7. Add the shared Item Action and Item Description bindings only after the basic Item display works.

At this editor checkpoint, the hierarchy should contain a named Bag panel, the generated slots, and an Inventory Grid bound to the player Inventory. Its default collection filter should target Bag, and its Item View Drawer should have a valid view for Health Potion, Iron Sword, and Fire Wand.

## Choose a grid or list layout

### Grid

Choose **Grid** when players should scan recognizable Item icons or move between rows and columns. The fixed slot count remains efficient even when the Inventory contains more Items than are currently visible.

![The Classic Inventory Grid displaying Item icons in evenly spaced square slots.](https://opsive.com/wp-content/uploads/2020/11/InventoryGrid-1-289x300.png)

### List

Choose **List** when Item names, amounts, or other row details need more horizontal space. The generated layout uses one column and a scrollbar while retaining the same Inventory Grid and Item View Slots Container behavior.

![The Classic Inventory List displaying Item icons and details in one scrollable column.](https://opsive.com/wp-content/uploads/2020/11/InventoryList-1-283x300.png)

Use an [Item Shape Grid](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-shape-grid/), not an Inventory Grid, when Items such as Iron Sword must occupy several cells.

## Configure size and navigation

Set the visible **Grid Size** in UI Designer so the correct number of Item View Slots is generated and previewed. The runtime Item Info Grid uses a fixed number of visible elements and redraws them for the current range of Items.

The Unity layout group controls slot spacing and order. **Layout Group Navigation** uses that order to connect neighboring selectable slots, so confirm its directional axis after changing rows, columns, or spacing.

Add a **Grid Navigator** when the Inventory can contain more Items than the visible slots. Choose the navigation that matches the interface: scrolling for a list, paging for a compact grid, or tab navigation when each tab represents a different filtered view.

Enable **Use Grid Index** on the runtime Inventory Grid only when Items should remember explicit positions and empty spaces within the grid. Leave it disabled when the view should simply draw the current filtered and sorted sequence.

## Add filtering, sorting, and tabs

- Use the default filter configuration for rules that should always apply, such as showing only the Bag collection.
- Add a search bar when players need to filter Items by typed text.
- Add a sort dropdown when players should choose the runtime order, such as Item name or amount.
- Use an Item Info Multi Filter Sorter when several rules must apply together. Order matters when filters and sorters are combined.
- Use a Tab Controller and Tab Toggles when one grid should switch between views. Each Inventory Tab Data entry can supply the filter or sorter applied by its tab.

For the standard example, one tab can show all Bag Items and another can filter to Consumable. Equipment should remain in its own Item Slot Collection View rather than being presented as another unfiltered Bag row.

## Connect selection and Item interactions

The generated Inventory Grid is an Item View Slots Container, so the same bindings can supply display and interaction behavior:

- The **Item View Drawer** chooses an Item View prefab through a Category Item View Set.
- An **Item View Slots Container Category Item Action Set Binding** can offer Consume for Health Potion and Equip for Iron Sword.
- An **Item View Slots Container Description Binding** can send the selected Item to an Item Description panel.
- Drag and drop requires the Cursor Manager, drag handler, drop handler, and compatible move or drop actions.

Configure these shared behaviors on the [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view-slots-container/) after confirming that the grid shows the correct Items. This keeps display problems separate from action or movement problems.

## Editor checkpoints

Before entering Play Mode, confirm that:

- **Parent Transform** and **Panel Option** place Bag under the intended menu.
- **Panel Name** and **Inventory Grid Name** both identify the panel clearly.
- The Inventory Grid resolves the player Inventory directly or through its panel binding.
- The Item Info Item Collection Filter shows Bag and excludes Equipment.
- The generated slot count, Unity layout group, and Layout Group Navigation agree on the intended row or column direction.
- The Item View Drawer uses the slot content transform and a Category Item View Set that resolves Consumable and Weapon.
- A Grid Navigator exists when the filtered Item count can exceed the visible slots.
- Optional search, sort, tabs, Item Actions, Item Description, and drag-and-drop components reference the Bag grid.

## Verify in Play Mode

1. Open Bag and confirm that Health Potion, Iron Sword, and Fire Wand appear with the intended Item Views.
2. Confirm that Items already in Equipment do not appear in Bag.
3. Navigate every visible slot with each supported pointer, keyboard, or controller input and confirm that selection remains visible.
4. Add enough Items to exceed the visible slot count, then confirm that scrolling or paging reaches every Item without creating extra visible slots.
5. Search, sort, or change tabs and confirm that the displayed Items update without changing the underlying Inventory contents.
6. If Item Description and Item Actions are configured, select Health Potion and Iron Sword and confirm that both views update.
7. Equip Iron Sword and confirm that it leaves the Bag view and appears in Equipment.
8. If drag and drop is enabled, move an Item between valid destinations and confirm that an incompatible Equipment slot rejects Health Potion.

## Troubleshooting

- **The Inventory Grid tab is unavailable:** Check that a database is selected, Canvas Managers were created, a schema was duplicated, and **Spawn In Scene** completed.
- **The grid appears under the wrong object:** Check **Parent Transform** and **Panel Option**. A Main Menu panel must use the Main Menu content transform.
- **Edit cannot find the grid:** Confirm that the generated object is active in the current scene, then use **Find Available Targets in Scene** or drag the Inventory Grid into the target field.
- **Bag is empty:** Check the direct Inventory or panel binding, confirm that the runtime Inventory contains Bag Items, and inspect the Item Collection filter.
- **Equipment Items appear in Bag:** Check that the Item Info Item Collection Filter shows Bag and excludes Equipment.
- **Slots appear but Item visuals do not:** Check **Use View Slots**, the Item View Drawer **Content**, and the Category Item View Set mappings.
- **The grid clips or navigates in the wrong direction:** Check **Grid Size**, the Unity layout group, and Layout Group Navigation after changing the layout.
- **Items beyond the visible slots cannot be reached:** Add or correct the Grid Navigator and confirm that its scrolling or paging controls target this grid.
- **Search, sorting, or tabs do not update:** Check the bound filter or sorter and confirm that the Tab Controller references the intended Inventory Tab Data.
- **Drag and drop uses the wrong destination:** Check the Inventory Grid Name, source and destination slot restrictions, and the configured drop action set.

## Related pages

- [UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/)
- [Schemas](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/schemas/)
- [Main Menu](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/main-menu/)
- [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view-slots-container/)
- [Item Views](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view/)
- [Item Description](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-description/)
- [Equipment](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/equipment/)
- [Item Shape Grid](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-shape-grid/)
- [Runtime Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/inventorygrid/)
- [Item Info filters and sorters](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-info-filter-sorters/)
- [Move Items with drag and drop](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/move-items-drag-drop/)
- [Customize the generated UI](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/ui-customization/)

---

<a id="page-ultimate-inventory-system-editor-window-ui-designer-item-shape-grid"></a>

# Item Shape Grid

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-shape-grid/)

Use an Item Shape Grid when Items occupy differently sized groups of cells in a finite Bag. Unlike a conventional Inventory Grid, it combines an Item's `Shape` data, Inventory-side Item Shape Grid Data, a layered UI, and shape-aware movement rules.

The standard example uses a one-cell Health Potion, a taller Iron Sword, and a differently shaped Fire Wand. Equipment remains a separate Item Slot Collection View.

## Before you begin

Confirm that:

- the intended Inventory System Database is selected in **Main Manager > Setup**;
- UI Designer Canvas Managers and a duplicated schema have been created;
- **Spawn In Scene** has created the starting UI;
- the player Inventory has **Bag** and **Equipment** Item Collections; and
- the destination scene contains the player Inventory that the Item Shape Grid will monitor.

The RPG schema is the most focused starting point for a spatial Bag, but either duplicated schema can supply the required components and Item View prefabs.

## Define the Item shapes

1. In the Item Category editor, declare `Shape` as an `ItemShape` in the **Item Definition** attribute collection on the narrowest common category used by the spatial Bag.
2. Open Health Potion and set a one-cell shape.
3. Open Iron Sword and set a longer multi-cell shape.
4. Open Fire Wand and set a distinct shape that is easy to distinguish during placement tests.
5. For every shape, place the anchor on a cell whose value is enabled.
6. Confirm that the Item Shape Grid components and Item View Modules are configured to read the same exact attribute name.

An ItemShape stores a grid of enabled cells and an anchor. The anchor is the point aligned to the destination cell during placement; an anchor on a disabled cell is invalid.

## Create the spatial Bag

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer** and select **Item Shape Grid**.
2. In **Create**, set **Parent Transform** to the Rect Transform that should contain the grid.
3. Choose **Main Menu** under **Panel Option** for a Bag inside the generated menu, or **Floating** when the player should be able to move the panel.
4. Set **Panel Name** and **Grid Name** to stable names such as `Spatial Bag`.
5. Assign the player's **Inventory**.
6. Set **Grid Size** to the intended number of cells and **Item Shape Size** to the pixel size of each cell.
7. Under **Item Collection**, choose Bag so Equipment Items are not placed in this grid. Choose None only when the grid intentionally monitors the entire Inventory.
8. Create the Item Shape Grid.
9. Confirm that UI Designer added or configured the matching Item Shape Grid Controller and Item Shape Grid Data beside the Inventory.

At this editor checkpoint, the scene contains a named Item Shape Grid, the player Inventory has matching grid data, and both use the same dimensions and Bag collection scope.

## Understand the two UI layers

The generated grid uses two aligned layers:

1. The **background layer** contains one interactive Item View Slot per cell. It shows selection and valid or invalid drop feedback across every cell occupied by the Item.
2. The **foreground layer** draws the Item Icon across its complete shape. It should not intercept interaction intended for the background slots.

Both layers use the shape-aware Item View configuration, but modules enable or disable their visual and interaction roles for each layer.

![A runtime Item Shape Grid displaying differently sized Item icons across a finite set of cells.](https://opsive.com/wp-content/uploads/2021/01/Item-Shape-Grid.png?v=a104f8e7b404)

## Match the UI to the Inventory data

The Item Shape Grid reads placement from Item Shape Grid Data on the bound Inventory. Keep these values aligned:

| UI Designer choice | Matching runtime data | Why it matters |
| --- | --- | --- |
| **Inventory** | The Inventory containing the controller and data | The view cannot resolve placement from another Inventory. |
| **Item Collection** | Item Collection ID or filter on the grid data | Bag stays separate from Equipment. |
| **Grid Size** | Grid Size on Item Shape Grid Data | Every UI cell has one corresponding data cell. |
| **Item Shape Size** | The UI cell size used by both layers | Foreground Icons align with background slots. |
| **Grid Name** | The intended grid-data entry or movement context | Multiple spatial grids remain distinguishable. |

When one Inventory has several Item Shape Grid Data entries, give each grid a distinct identity and collection or filter. Confirm that the UI resolves the data created for this grid rather than another spatial panel.

Use UI Designer to change Grid Size or Item Shape Size whenever possible. It can update the connected components together; changing one layer or data object by hand can leave the view and placement data out of sync.

## Keep the shape-aware Item View modules

The schema's Item Shape Grid prefab includes modules that a normal Item View does not:

- **Item Shape Item View** scales and positions the foreground visual for the complete Item shape.
- **Item Shape Drop Preview Item View** marks the cells that would accept or reject a drop.
- **Item Shape Selected Item View** highlights every cell occupied by the selected Item.
- **Item Shape Rect Place Item View** positions a child Rect Transform, such as an amount label, inside an irregular shape.
- **Canvas Group** hides or disables interaction on the foreground layer when the background must receive the input.

Keep **Item Shape View Content** assigned to the foreground content transform. Keep the Item View Drawer's **Content** assigned to the background Item View Slot content. The two transforms must use the same grid geometry.

## Configure shape-aware movement

1. Confirm that the canvas has an Item View Slots Cursor Manager.
2. Add or select the Item View Drop Handler used by the spatial Bag.
3. Assign an Item View Slot Drop Action Set.
4. Include an **Item View Shape Drop** condition so the destination is checked against the Item's complete shape.
5. Include the matching **Item View Shape Drop** action so a valid move updates the Item Shape Grid rather than treating the Item as a normal one-cell slot.
6. Add an Item View Slot Drag Handler for pointer input or an Item View Slot Move Cursor for keyboard and controller movement.
7. Test the preview over free cells, occupied cells, and the grid edges.

The placement preview and final drop must use the same shape rules. A green preview followed by a rejected or misaligned drop usually means the condition and action are not using the same Item Shape Grid setup.

## Choose an Item Shape Grid only when needed

| Requirement | Use |
| --- | --- |
| Every Item occupies one equal slot | [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/inventory-grid/) |
| Items occupy several or irregular cells | Item Shape Grid |
| Fixed named slots accept specific categories | [Equipment](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/equipment/) |

A regular Bag with Health Potion, Iron Sword, and Fire Wand does not require spatial data unless placement itself is part of the intended player experience.

## Editor checkpoints

Before entering Play Mode, confirm that:

- Health Potion, Iron Sword, and Fire Wand resolve an `ItemShape` through the exact configured attribute name.
- Every ItemShape anchor is on an enabled cell.
- **Inventory** points to the player Inventory that owns the controller and grid data.
- **Item Collection** targets Bag and does not unintentionally include Equipment.
- **Grid Size** matches between the UI and Item Shape Grid Data.
- **Item Shape Size** aligns foreground visuals with background slots.
- Item Shape View Content and the Item View Drawer Content reference the intended aligned layers.
- The Item View prefab retains its Item Shape, selection, drop-preview, placement, and Canvas Group modules.
- The drop action set has both shape-aware validation and shape-aware placement.
- The panel remains readable and fully inside the canvas at the smallest supported resolution.

## Verify in Play Mode

1. Open the spatial Bag and confirm that Health Potion occupies one cell while Iron Sword and Fire Wand use their intended shapes.
2. Select each Item and confirm that every occupied background cell highlights while the foreground Icon remains one coherent visual.
3. Drag Iron Sword to an open area and confirm that the preview and final placement cover the same cells.
4. Hover Iron Sword over an occupied area and the edge of the grid and confirm that the invalid preview prevents the drop.
5. Move Health Potion into a one-cell gap and confirm that its anchor aligns to the selected destination cell.
6. Move Items with each supported pointer, keyboard, or controller path and confirm that all inputs use the same placement rules.
7. Equip Iron Sword and confirm that it leaves the Bag grid and appears in Equipment without leaving occupied Bag cells behind.
8. Close and reopen the menu and confirm that every Item remains in its current grid position.

## Troubleshooting

- **The Item Shape Grid tab is unavailable:** Check that a database is selected, Canvas Managers were created, a schema was duplicated, and **Spawn In Scene** completed.
- **The grid is empty:** Check **Inventory**, **Item Collection**, Item Shape Grid Controller, Item Shape Grid Data, and the configured `Shape` attribute name.
- **Every Item occupies one cell:** Check that each definition has an ItemShape value and that the Item View retains Item Shape Item View.
- **An Item is offset or covers the wrong cells:** Check its anchor, UI and data **Grid Size**, **Item Shape Size**, and the foreground/background content transforms.
- **Selection highlights only one cell:** Check Item Shape Selected Item View and confirm that the background layer receives the selected Item's full shape.
- **No valid or invalid placement preview appears:** Check Item Shape Drop Preview Item View, the Item View Drop Handler, and the shape-aware drop condition.
- **The preview is valid but the drop fails or lands incorrectly:** Check that the drop action set also uses the shape-aware drop action and targets this grid's data.
- **Clicks do not reach the background cells:** Check the foreground Canvas Group and confirm that the foreground visual does not intercept raycasts.
- **Equipment Items appear in the spatial Bag:** Check **Item Collection** and the Item Collection ID or filter on Item Shape Grid Data.
- **Resizing corrupts placement or alignment:** Reapply the size through UI Designer, then confirm every connected data and content object uses the updated dimensions.

## Related pages

- [UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/)
- [RPG schema](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/schemas/rpg/)
- [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/inventory-grid/)
- [Equipment](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/equipment/)
- [Item View](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view/)
- [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view-slots-container/)
- [Runtime Item Shape Grid](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-shape-grid/)
- [Move Items with drag and drop](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/move-items-drag-drop/)
- [Common attribute types](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/common-attribute-types/)
- [Attribute editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/attributes/)
- [Customize the generated UI](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/ui-customization/)

---

<a id="page-ultimate-inventory-system-editor-window-ui-designer-equipment"></a>

# Equipment

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/equipment/)

Use the UI Designer Equipment tab to create an Item Slot Collection View with one visible Item View Slot for each entry in an Item Slot Set. The view binds to the player's Equipment Item Collection and applies the same category restrictions, so a Weapon slot can accept Iron Sword while rejecting Health Potion.

The Equipment panel displays and moves Items. An Equipper is a separate runtime component that spawns the corresponding equipment visuals on the character.

## Before you begin

Confirm that:

- the intended Inventory System Database is selected in **Main Manager > Setup**;
- UI Designer Canvas Managers and a duplicated schema have been created;
- **Spawn In Scene** has created the schema's canvas and managers;
- the player Inventory has **Bag** and **Equipment** Item Collections;
- Equipment is an Item Slot Collection; and
- Iron Sword uses Weapon while Health Potion uses Consumable.

The Equipment Item Collection, Item Slot Collection View, and Equipper must use the same Item Slot Set when all three participate in the workflow.

## Prepare the Item Slot Set

1. In the Project window, choose **Create > Ultimate Inventory System > Inventory > Item Slot Set**.
2. Give the asset a descriptive project name, such as `Humanoid Equipment`.
3. Add a slot named `Right Hand`.
4. Set its Item Category to **Weapon** and its size limit to `1`.
5. Add any other slots the game needs, using the narrowest category that accurately describes each destination.
6. Assign this Item Slot Set to the player's Equipment Item Slot Collection.

The Item Slot Set is the source of truth for slot names, accepted Item Categories, and size limits. For the standard example, Right Hand accepts one Iron Sword or Fire Wand because both use Weapon, but rejects Health Potion because Consumable does not inherit from Weapon.

## Create the Equipment panel

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer** and select **Equipment**.
2. In **Create**, choose the intended parent or panel for the generated view.
3. Assign the same **Item Slot Set** used by the player's Equipment Item Collection.
4. Create the Item Slot Collection View.
5. On the generated view, set **Item Collection ID** to Equipment.
6. Confirm that every entry under **Item Slots > Item View Slots** points to the corresponding generated visible slot.
7. Enable **Set Item View Slot Restriction** so each visible slot receives the Item Category restriction defined by the Item Slot Set.

The generated result should contain one visible slot per Item Slot Set entry. Use **Equipment Options** in UI Designer to select a generated Item View Slot in the hierarchy or add another restriction when the UI needs a narrower rule than the collection itself.

![The generated Equipment panel displaying dedicated Item View Slots for different equipment categories.](https://opsive.com/wp-content/uploads/2020/11/Equipment.png?v=fe8c42170ef5)

## Connect the Inventory and Item Views

The Item Slot Collection View resolves its runtime collection through **Item Collection ID**. That destination must be an Item Slot Collection using the same Item Slot Set as the view.

Configure the shared [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view-slots-container/) options after the basic binding works:

1. Confirm that the Item View Drawer uses **Use View Slots**.
2. Assign a Category Item View Set that can resolve Weapon Items.
3. Set the drawer's **Content** to the transform containing the generated Item View Slots.
4. Add a Description binding if selecting Iron Sword should update an Item Description panel.
5. Add the intended Item Action binding if players equip or unequip through an action menu.
6. Configure drag and drop when Items should move directly between Bag and Equipment.

At this editor checkpoint, the generated Right Hand view should map to the Right Hand entry in the shared Item Slot Set, resolve the Equipment collection, and visibly reject Items outside Weapon.

## Understand the runtime flow

When an Item is moved into Equipment:

1. The Item Slot Collection checks the Item against the Item Slot Set.
2. The Item is placed only in a compatible slot with sufficient size.
3. The Item Slot Collection View redraws the corresponding visible Item View Slot.
4. If an Equipper watches that collection, it updates the character's equipment visual.

When a compatible Item replaces an occupied slot, the Item Slot Collection handles the displaced Item according to the Inventory's main-collection setup. In the standard Bag and Equipment workflow, confirm that the displaced weapon returns to Bag.

The Equipment UI does not automatically change character statistics. Stats, attacks, and other game-specific effects belong to the project's equipment or Item logic.

## Choose slot restrictions deliberately

| Goal | Item Slot Set choice | Runtime result |
| --- | --- | --- |
| Accept any equippable Item in one slot | Use Equippable | Iron Sword and other descendants of Equippable are valid. |
| Accept only weapons | Use Weapon | Iron Sword and Fire Wand are valid; Health Potion is rejected. |
| Allow only one Item | Set the size limit to `1` | A second compatible Item replaces or is handled against the occupied slot. |
| Add a UI-only constraint | Add an Item View Slot Restriction in Equipment Options | The visible destination can reject an Item before a move is submitted. |

Keep the Item Slot Set and visible restrictions aligned. A UI slot that appears to accept an Item while the runtime collection rejects it creates confusing drag-and-drop feedback.

## Editor checkpoints

Before entering Play Mode, confirm that:

- Equipment is an Item Slot Collection in the player Inventory.
- The Equipment Item Collection, Item Slot Collection View, and Equipper use the same Item Slot Set.
- **Item Collection ID** resolves the Equipment collection rather than Bag or another collection.
- Every Item Slot Set entry maps to the intended generated Item View Slot.
- **Set Item View Slot Restriction** is enabled when the UI should mirror the set's category rules.
- Right Hand accepts Weapon with a size limit of `1`.
- Iron Sword and Fire Wand use Weapon, while Health Potion uses Consumable.
- The Item View Drawer can resolve Weapon and uses the generated slots' content transform.
- Optional Item Actions, Item Description, and drag-and-drop components reference the Equipment view.

## Verify in Play Mode

1. Open Bag and Equipment with Iron Sword and Health Potion initially in Bag.
2. Equip or drag Iron Sword into Right Hand and confirm that it leaves Bag and appears in the Equipment slot.
3. If an Equipper is configured, confirm that the Iron Sword equipment visual appears on the character.
4. Try to move Health Potion into Right Hand and confirm that the Weapon restriction rejects it without removing it from Bag.
5. Move Fire Wand into the occupied Right Hand slot and confirm that the configured replacement behavior returns Iron Sword to Bag.
6. Unequip the current weapon and confirm that both Bag and Equipment redraw correctly.
7. If Item Description or Item Actions are configured, select an equipped Item and confirm that the connected panel updates.
8. Test every supported pointer, keyboard, or controller path and confirm that focus and restrictions behave consistently.

## Troubleshooting

- **The Equipment tab is unavailable:** Check that a database is selected, Canvas Managers were created, a schema was duplicated, and **Spawn In Scene** completed.
- **The wrong number of slots is generated:** Check the Item Slot Set selected in UI Designer, update the set first, then recreate or edit the view.
- **Equipment stays empty:** Check **Item Collection ID** and confirm that it resolves an Item Slot Collection on the bound Inventory.
- **Iron Sword is rejected:** Check that Iron Sword uses Weapon, Right Hand accepts Weapon, and the view and collection use the same Item Slot Set.
- **Health Potion can enter the Weapon slot:** Check the Item Slot Set category and enable **Set Item View Slot Restriction** on the view.
- **An Item moves into Equipment but its icon does not appear:** Check the Item View Slot mapping, Item View Drawer, Category Item View Set, and **Content** transform.
- **The icon appears but no character visual is equipped:** Check the Equipper, its Equipment collection reference, its Item Slot Set, and the Item's equipment-prefab data.
- **Replacing a weapon loses or misroutes the old Item:** Check which Item Collection is configured as the Inventory's main destination and confirm that it is the intended Bag collection.
- **Drag and drop does nothing:** Check the Cursor Manager, drag handler, drop handler, destination restriction, and configured drop action set.
- **UI and runtime acceptance disagree:** Compare the Item Slot Set assigned to the collection and view, then inspect any additional Item View Slot Restrictions.

## Related pages

- [UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/)
- [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/inventory-grid/)
- [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view-slots-container/)
- [Item Views](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view/)
- [Runtime Item Slot Collection View](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-slot-collection-view-equipment/)
- [Item Slot Collection](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/item-slot-collection/)
- [Equipping Items and Item Slot Sets](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/equipping-items/)
- [Move Items with drag and drop](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/move-items-drag-drop/)
- [Item Category](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-category/)
- [Customize the generated UI](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/ui-customization/)

---

<a id="page-ultimate-inventory-system-editor-window-ui-designer-item-hotbar"></a>

# Item Hotbar

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-hotbar/)

Use an Item Hotbar to assign quick-access slots to Items already held by the player. Pressing a slot invokes the configured Item behavior, while assigning or unassigning a slot does not move the Item out of **Bag**.

The standard example assigns Health Potion to a quick-use slot and Iron Sword to another slot while both remain in the player Inventory.

## Choose the hotbar data model

Ultimate Inventory System includes three useful patterns:

| Pattern | What the slots represent | Choose it when |
| --- | --- | --- |
| **Item Hotbar** | Assignments that monitor Items in the Inventory | Health Potion should remain in Bag while a key uses it. |
| **Inventory Mirror Hotbar** | The first slots of an Inventory Grid | The quick bar should always mirror Bag ordering. |
| **Item Slot Collection View** | Items moved into a dedicated Item Collection | Quick slots must own their Items separately, like an Equipment-style collection. |

This page uses Item Hotbar. Choose [Equipment](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/equipment/) and an Item Slot Collection View when the project needs collection-backed slots instead of monitored assignments.

## Before you begin

Confirm that:

- the intended Inventory System Database is selected in **Main Manager > Setup**;
- UI Designer Canvas Managers and a duplicated schema have been created;
- **Spawn In Scene** has created the starting UI;
- the player Inventory contains a Bag collection with Health Potion and Iron Sword;
- the intended Item Actions can run from the player's Item User; and
- Inventory Input is available for the hotbar controls.

Configure the [shared Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view-slots-container/) behavior after the hotbar can resolve its Inventory and slots.

## Create the Item Hotbar

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer** and select **Item Hotbar**.
2. In **Create**, choose the schema hotbar template and the parent transform that should contain it.
3. Create the Item Hotbar from the duplicated project schema.
4. In **Edit**, use **Find Available Targets in Scene** or drag the generated Item Hotbar into the target field.
5. In **Hotbar Options**, find the generated Item View Slots, then add or remove slots until the hotbar has the intended size.
6. Keep the slot order intentional: runtime input and assignment use the slot index.
7. Add or confirm the Item View Slots Container Panel Binding that supplies the player Inventory and initializes the hotbar.
8. Bind the Item Hotbar to the intended Inventory Input so each quick-access input reaches the matching slot.

At this editor checkpoint, the hotbar has a stable row of indexed slots, resolves the player Inventory, and refreshes when that Inventory changes.

![A runtime Item Hotbar displaying assigned Item icons in a row of quick-access slots.](https://opsive.com/wp-content/uploads/2020/11/ItemHotbar.png)

## Configure Item Views and actions

1. Set **Container Name** to a stable value such as `Hotbar`.
2. Confirm that the container and Item View Drawer use the same **Content** transform.
3. Enable **Use View Slots** on the Item View Drawer.
4. Assign a Category Item View Set that can display Health Potion and Iron Sword.
5. Add an Item View Slots Container Category Item Action Set Binding when the hotbar should use actions matched from the assigned Item's categories.
6. Confirm the binding's **Item User** and empty-slot behavior.
7. Map the intended quick-use action for Health Potion and the intended weapon action for Iron Sword.

The hotbar uses Item View Slots Container events to invoke an Item by slot index. When the bound Inventory updates, refresh keeps the monitored Item amount and state current without transferring ownership to the hotbar.

## Let players assign slots

Use **Assign Hotbar Item Action** when the player should choose a hotbar destination from Bag:

1. Add the action to the Item Action Set available from the Bag Inventory Grid.
2. Assign an Async Func Action Panel prefab containing an **Async Func Action Panel Int** or a compatible derived component.
3. Confirm that the Item User implements Item Hotbar Owner or has a neighboring component that does.
4. Invoke the action for Health Potion and choose a hotbar slot.
5. Repeat the action to test the configured assign or toggle assign/unassign behavior.

Use **UnAssign Hotbar Item Action** from the hotbar when a dedicated unassign choice is required. Unassigning clears the monitored reference from the slot; it does not remove the Item from Bag.

## Support drag-and-drop assignment

1. Confirm that the canvas has an Item View Slots Cursor Manager.
2. Configure the Item View Drop Handler and Item View Slot Drop Action Set used by Bag and the hotbar.
3. Add an Item View Slot Drag Handler for pointer input or an Item View Slot Move Cursor for keyboard and controller movement.
4. Add conditions that allow an Inventory Item to be assigned to a compatible hotbar slot.
5. Add the intended hotbar assignment action rather than a normal Inventory give or exchange action.
6. Use **ItemViewDropContainerRemoveAction** when dragging away from the hotbar should remove the assignment.

The movement result should match the Item Action workflow: the assignment changes, but Health Potion or Iron Sword remains in its original Inventory collection.

## Choose quick-use behavior carefully

- Use one direct action when the hotbar input has an obvious meaning, such as consuming Health Potion.
- Use an action panel only when the player must choose between several valid actions after selecting the hotbar slot.
- Keep slot assignment separate from Item use. Assigning Health Potion must not consume it.
- Keep weapon behavior explicit. Assigning Iron Sword can invoke an equip, unequip, or use action only when that action is intentionally mapped.
- Use a Cooldown Item View when a compatible Item Action exposes a cooldown that players need to see.

Test the same action from Bag before assigning it to the hotbar. This distinguishes an Item Action or Item User problem from a hotbar input problem.

## Preserve assignments when required

An Item Hotbar assignment is container state. Add an **ItemViewSlotContainerSaver** when assignments must survive the project's save and load cycle. Saving the Inventory alone does not necessarily reproduce which monitored Item was assigned to each UI slot.

After loading, verify both the assigned definition and any state required to identify the intended runtime Item.

## Editor checkpoints

Before entering Play Mode, confirm that:

- the generated hotbar belongs to the project or duplicated schema rather than package assets;
- **Hotbar Options** shows the intended number and order of Item View Slots;
- the panel binding resolves the player Inventory and initializes the hotbar;
- Inventory Input maps each quick-use control to the intended slot index;
- the Item View Drawer has **Use View Slots**, a valid Category Item View Set, and matching **Content**;
- the category action-set binding has the intended Item User and actions for Health Potion and Iron Sword;
- Assign Hotbar Item Action has a compatible Async Func Action Panel prefab;
- the Item User implements or can find Item Hotbar Owner;
- optional drag-and-drop components use assignment and unassignment actions rather than Inventory transfer actions; and
- ItemViewSlotContainerSaver is present only when hotbar assignments must persist.

## Verify in Play Mode

1. Open Bag, invoke Assign Hotbar Item Action for Health Potion, and choose the first hotbar slot.
2. Confirm that Health Potion remains in Bag and its Icon and amount appear in the assigned slot.
3. Press the first quick-use input and confirm that the intended Health Potion action runs and the displayed amount refreshes.
4. Assign Iron Sword to another slot and confirm that its configured action runs without silently changing Item ownership unless that action intentionally does so.
5. Unassign Health Potion and confirm that only the hotbar slot clears while the remaining Item stays in Bag.
6. Remove the assigned Item from the Inventory and confirm that the hotbar clears or updates its monitored state.
7. Repeat assignment, use, and unassignment with every supported pointer, keyboard, and controller path.
8. If persistence is configured, save, change the assignments, load, and confirm that the saved slot assignments return.

## Troubleshooting

- **The Item Hotbar tab is unavailable:** Check that a database is selected, Canvas Managers were created, a schema was duplicated, and **Spawn In Scene** completed.
- **The hotbar is empty after assignment:** Check the panel binding, bound Inventory, Item View Slots, and Item View Drawer Category mapping.
- **Assign Hotbar Item Action does not open a slot list:** Check its Async Func Action Panel prefab and confirm that it contains Async Func Action Panel Int.
- **The assignment action cannot find the hotbar:** Check that the Item User implements or has a neighboring Item Hotbar Owner.
- **Pressing a quick-use input does nothing:** Check Inventory Input, the slot index mapping, category action-set binding, Item User, and the assigned Item's valid actions.
- **The wrong slot fires:** Check the Item View Slot order in Hotbar Options and the corresponding input index.
- **The displayed amount is stale:** Check that the hotbar is bound to the correct Inventory and refreshes when that Inventory changes.
- **Assigning removes the Item from Bag:** Check that the project uses Item Hotbar assignment rather than a collection give or exchange action or an Item Slot Collection View.
- **Unassigning deletes or moves the Item:** Replace the transfer action with UnAssign Hotbar Item Action or the hotbar-specific drop remove action.
- **Assignments disappear after loading:** Add or configure ItemViewSlotContainerSaver and confirm that the hotbar is included in the save workflow.
- **An assigned Item shows no Icon:** Check the Category Item View Set, Item View Drawer, `Icon` value, and matching **Content** transforms.

## Related pages

- [UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/)
- [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view-slots-container/)
- [Item View](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view/)
- [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/inventory-grid/)
- [Equipment and collection-backed slots](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/equipment/)
- [Runtime Item Hotbar](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-hotbar/)
- [Built-in hotbar patterns](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-hotbar/hotbars/)
- [Built-in Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/built-in-item-actions/)
- [Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/)
- [Move Items with drag and drop](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/move-items-drag-drop/)
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)
- [Customize the generated UI](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/ui-customization/)

---

<a id="page-ultimate-inventory-system-editor-window-ui-designer-shop"></a>

# Shop

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/shop/)

Use the UI Designer **Shop** tab to create a menu where the player can browse Items, see their Buy Price in Gold, choose a quantity, and buy or sell. This workflow uses Health Potion and Iron Sword to verify that the displayed price, player balance, and Inventory transaction all agree.

## Before you begin

Confirm that:

- the intended Inventory System Database is selected in **Main Manager > Setup**;
- Gold exists and the player Inventory has a Currency Owner with a starting balance;
- Health Potion and Iron Sword have a `CurrencyAmounts` Item Definition attribute named `BuyPrice`, with a Gold amount assigned to each;
- `SellPrice` also exists when the menu should support selling;
- the Shop Inventory contains the Items that should appear for sale; and
- Canvas Managers exist and a duplicated UI Designer schema has been spawned in the scene.

The Shop finds prices by attribute name. `BuyPrice` on each Item and **Buy Attribute Name** on the Shop must use the same spelling and capitalization.

## Create the Shop Menu

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer**.
2. Select the **Shop** tab and open **Create**.
3. Set **Parent Transform** to the Rect Transform that should contain the menu.
4. Set **Panel Option**:
   - Choose **Basic** for a standalone menu panel.
   - Choose **Main Menu** to add Shop as an inner panel of the generated Main Menu. In this case, **Parent Transform** must be that Main Menu's main content transform.
5. Select **Create**.
6. In **Edit**, select the new Shop Menu. Use **Find Available Targets in Scene** when it is not already selected.
7. In **Shop**, add the Shop component. UI Designer also creates and assigns the Shop Inventory when adding the component here.
8. In **Inventory Grid**, create the grid if the schema does not already provide one. Use **Edit Inventory Grid** to configure its Item Views, layout, and navigation.
9. In **Currency Displays**, create the **Total Price UI**. This Multi Currency View shows the price for the selected quantity.
10. In **Quantity Picker Panel**, create the quantity control used to confirm buying or selling.

![The Classic Shop Menu showing the shop Inventory grid, selected Item details, Gold prices, and buy and sell controls.](https://opsive.com/wp-content/uploads/2020/11/ShopScreenshot-1024x576.png)

Use the UI Designer **Currency** tab to add a separate Currency Owner Monitor when the menu should also show how much Gold the player owns. The Total Price UI and the player's balance are different views and should not share the same data source.

## Configure Items, prices, and stock

### Set the price source

On the Shop component:

- Set **Buy Attribute Name** to `BuyPrice`.
- Set **Sell Attribute Name** to `SellPrice` when selling is enabled. If one price should be used in both directions, point both fields to the same deliberate attribute.
- Use **Buy Modifier** or **Sell Modifier** only when this Shop should adjust the Item's stored price. A value of `0` leaves the price unchanged.

Health Potion and Iron Sword can both use Gold while keeping different `BuyPrice` values. The Shop reads the selected Item's value, applies the relevant modifier, and multiplies it by the chosen quantity before drawing the Total Price UI.

### Choose the stock behavior

By default, buying adds a new Item to the player without removing the entry from the Shop Inventory. Use **Shop Add Remove Binding** when stock should change:

- Enable **Remove On Buy** to subtract purchased Items from the Shop Inventory and prevent purchases beyond the remaining amount.
- Enable **Add On Sell** to place Items sold by the player into the Shop Inventory.
- On Shop Menu, enable **Limit Buy Quantity To Available Item Amount** when the quantity picker should also stop at the amount currently in stock.

For an unlimited Health Potion supply, leave **Remove On Buy** disabled. For a single Iron Sword in stock, enable it and verify that the Item disappears after purchase.

### Bind the player Inventory

The Shop Menu needs the player's Inventory to find the player's Currency Owner and to decide where purchased Items go. Keep **Bind To Panel Owner Inventory** enabled when the Display Panel Manager's Panel Owner is the player. Otherwise, use **Bind To Inventory By Identifier** or assign **Inventory** directly.

In Buy mode, the Inventory Grid displays the Shop Inventory. In Sell mode, it displays the bound player Inventory.

## Choose the opening and interaction behavior

| Choice | Use it when | Result |
| --- | --- | --- |
| **Open Buy Sub Menu** | Buying is the primary action | The menu opens with the Shop Inventory visible |
| **Open Sell Sub Menu** | Selling is the primary action | The menu opens with the player Inventory visible |
| **Open No Sub Menu** | The player should choose Buy or Sell first | The menu opens without immediately showing either list |
| **Open Quantity Picker On Item Click** | A click should begin the transaction flow | Clicking an Item opens the quantity picker |
| **Select Only With Click** | Navigation or hover selection should not replace the active transaction Item | Only a click changes the chosen Item |

The quantity picker uses the player's available Gold to limit or reject a purchase. For selling, its maximum is the amount of the selected Item in the player Inventory.

## How the transaction runs

1. The player opens Buy or Sell, and the grid binds to the corresponding Inventory.
2. Selecting an Item lets the Shop read its configured Buy Price or Sell Price.
3. The quantity picker redraws **Total Price** whenever the quantity changes.
4. On Buy, the Shop removes the Gold total from the player's Currency Owner and adds the selected Item amount to the player's configured destination collection.
5. On Sell, the Shop removes the Item amount from the player and adds the sell value to the player's Currency Owner.
6. The Inventory Grid redraws after the transaction. A Currency Owner Monitor refreshes the visible Gold balance when the Currency changes.

## Editor checkpoints

Before entering Play Mode, confirm that:

- the Shop Menu is under the intended Display Panel Manager or Main Menu content;
- **Shop**, **Inventory Grid**, **Total Price UI**, and **Quantity Picker Panel** all have valid references;
- the Shop Inventory contains Health Potion and Iron Sword;
- both Items expose `BuyPrice` as `CurrencyAmounts` and each value contains Gold;
- **Buy Attribute Name** matches `BuyPrice` exactly, and selling fields match the chosen sell attribute;
- the Multi Currency View used by **Total Price** maps Gold to a valid Currency View;
- the Shop Menu resolves the intended player Inventory and its Currency Owner;
- purchased Consumables and Weapons have valid destination Item Collections; and
- finite-stock settings agree across **Shop Add Remove Binding** and **Limit Buy Quantity To Available Item Amount**.

## Verify in Play Mode

1. Give the player enough Gold to buy Health Potion but less than the Iron Sword price.
2. Open Buy and confirm that the Shop Inventory shows both Items with their expected Gold prices.
3. Select Health Potion, change the quantity, and confirm that **Total Price** changes by the same multiple.
4. Buy Health Potion and confirm that the selected quantity appears in the player Inventory and the Gold balance decreases by the displayed total.
5. Select Iron Sword and confirm that purchase cannot be completed while the player lacks enough Gold.
6. Add enough Gold, buy Iron Sword, and confirm that it reaches the intended player collection.
7. If finite stock is enabled, confirm that the Shop Inventory decreases and that a sold-out Item cannot be bought again.
8. Open Sell, sell an eligible Item, and confirm that the Item amount decreases while Gold increases by the displayed sell total.

## Troubleshooting

- **The Shop Menu does not open:** Check that its Display Panel is registered with the intended Display Panel Manager or Main Menu and that the opening button targets that panel.
- **Buy shows the player's Items instead of the Shop's:** Check the Shop reference and its assigned Inventory. Buy mode binds the grid to the Shop Inventory; Sell mode binds it to the player Inventory.
- **Health Potion or Iron Sword is missing:** Check that the Shop Inventory contains the Item, the Item has the configured Buy Price attribute, and the Inventory Grid's filters allow its Category.
- **The price is blank or zero:** Check that `BuyPrice` is a `CurrencyAmounts` value containing Gold, **Buy Attribute Name** matches it exactly, and **Total Price** maps Gold to a Currency View.
- **The total does not change with quantity:** Check the **Quantity Picker Panel** and **Total Price** references on Shop Menu.
- **Buy remains unavailable:** Check that the Shop Menu resolves the correct player Inventory, that the Inventory has a Currency Owner, and that the player owns enough Gold for the selected quantity.
- **Gold changes but the balance display does not:** Check the separate Currency Owner Monitor and its Multi Currency View. Do not use the Total Price UI as the player's balance view.
- **A purchased Item does not appear:** Check the default Item Collection used when buying and any Category-specific destination collection. Confirm that the destination exists on the player Inventory.
- **Stock never decreases:** Add **Shop Add Remove Binding** and enable **Remove On Buy**. Also enable **Limit Buy Quantity To Available Item Amount** when the picker should respect stock before confirmation.
- **A sold Item does not enter Shop stock:** Enable **Add On Sell** on **Shop Add Remove Binding**.

## Related pages

- [UI Designer workflow](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/)
- [Shop runtime behavior](https://opsive.com/support/documentation/ultimate-inventory-system/ui/shop-menu/)
- [Shops and transactions](https://opsive.com/support/documentation/ultimate-inventory-system/currency/shop/)
- [Create and configure Gold](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/currency/)
- [Currency UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/currency/)
- [Inventory Grid UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/inventory-grid/)
- [Item View UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view/)
- [Common price attributes](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/common-attribute-types/)
- [Define Item attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/)

---

<a id="page-ultimate-inventory-system-editor-window-ui-designer-crafting"></a>

# Crafting

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/crafting/)

Use the UI Designer **Crafting** tab to create a menu that lists a Crafter's recipes, shows the selected ingredients and output, and lets the player choose a quantity to craft. This workflow uses **Brew Health Potion**, which consumes 2 Herb and 1 Water from the player's main **Bag** collection and adds 1 Health Potion back to Bag.

The included Crafting Menu is a practical starting point for recipe selection and quantity-based crafting. Create a custom menu or processor when the game needs a different ingredient-selection flow, timed crafting, stations with specialized rules, or another result presentation.

## Before you begin

Confirm that:

- the intended Inventory System Database is selected in **Main Manager > Setup**;
- **Consumable Recipes** exists as a concrete Crafting Category;
- **Brew Health Potion** belongs to Consumable Recipes and uses 2 Herb plus 1 Water to produce 1 Health Potion;
- the player has an Inventory whose main Item Collection is **Bag**;
- Herb, Water, and Health Potion can be added to Bag; and
- Canvas Managers exist and a duplicated UI Designer schema has been spawned in the scene.

Create the category and recipe first when they are not ready. The Crafting Menu presents data supplied by its Crafter; it does not define the recipe itself.

## Create the Crafting Menu

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer**.
2. Select the **Crafting** tab and open **Create**.
3. Set **Parent Transform** to the Rect Transform that should contain the menu.
4. Choose a **Panel Option**:
   - **Basic** creates a standalone menu panel that disables itself when closed.
   - **Main Menu** creates a Main Menu inner panel. Its Parent Transform must be the Main Menu's main content transform.
5. Select **Create**.
6. In **Edit**, select the generated Crafting Menu. Use **Find Available Targets in Scene** when it is not already selected.

![The Classic Crafting Menu displaying a recipe list and the selected recipe's ingredients and output.](https://opsive.com/wp-content/uploads/2020/07/CraftSystemScreenshot-1024x576.png)

## Add and configure the Crafter

1. In the UI Designer **Crafter** section, add a Crafter directly to the Crafting Menu when one is not already present.
2. Select that Crafter and add **Consumable Recipes** to **Crafting Categories**.
3. Leave **Miscellaneous Recipes** empty for Brew Health Potion. The category already supplies that recipe, so adding it again can create a duplicate entry.
4. Keep **Processor** set to the Version 1 **Simple Crafting Processor With Currency** for the standard workflow. It also handles recipes that have no Currency cost.
5. In the processor settings, keep **Externally Remove Ingredients** disabled.
6. Add `Bag` to **Ingredient Item Collections** so ingredient selection is limited to the player's Bag.
7. On the Crafting Menu component, confirm that **Crafter** references this configured component.

The standard processor removes selected ingredients from the Inventory's main Item Collection and adds the result through that Inventory, which also targets its main collection. For this workflow, Bag must therefore be the player's main collection as well as the named ingredient collection. Equipment remains outside the craft.

Use **Miscellaneous Recipes** only for a recipe that should be available without including its whole category. Do not include the same recipe through both lists.

## Configure the Recipe Panel

1. In the UI Designer **Recipe Panel** section, create the panel if the schema does not already provide it.
2. Under **Ingredient Item Views and Descriptions**, provide at least two entries: one for Herb and one for Water.
3. Use **Select Item View** and **Select Item Description** to confirm that each entry has the intended visual and description modules.
4. On the Recipe Panel component, confirm that its result Item View and description can display Health Potion.
5. On the Crafting Menu component, confirm that **Recipe Panel** references this panel.

The Recipe Panel updates the displayed ingredient and output amounts when the player changes the crafting quantity. Using Item Definition ingredients for Herb and Water makes both requirements visible in the provided panel.

## Configure the recipe grid

Use **Grid Size & Layout Group** to provide enough visible slots for the Crafter's recipes. A small grid is sufficient for the single Health Potion example; increase it only when more recipes are added.

Under **Grid Navigation**, choose a navigation option when the recipe count can exceed the visible slots. Confirm that its vertical direction and any linked tab behavior match the layout.

Leave **Grid Tabs** absent for the single Consumable Recipes group. When the menu later needs several groups, create **Crafting Tabs**, name each Tab Toggle, and configure its Crafting Tab Data with an **Item Category** or **Crafting Category** filter. A Consumable tab can filter by Consumable or Consumable Recipes.

On the Crafting Menu component, confirm that:

- **Crafting Recipe Grid**, **Recipe Panel**, and **Quantity Picker Panel** reference the generated controls;
- **Open Quantity Picker Panel On Recipe Click** is enabled when clicking Brew Health Potion should immediately ask for a quantity;
- **Close Quantity Picker Panel On Close** is enabled; and
- **Exit Button** references the intended close button.

## Bind the player Inventory

The Crafting Menu inherits the standard Inventory panel binding:

- Keep **Bind To Panel Owner Inventory** enabled when the Display Panel Manager's Panel Owner is the player.
- Otherwise, set **Bind To Inventory By Identifier** to the player's Inventory Identifier ID, or assign **Inventory** directly.

For a station-specific Crafter, a Crafting Menu Opener can bind both the interacting player's Inventory and that station's Crafter immediately before opening the menu. This allows one Crafting Menu to be reused by several stations with different recipe lists.

## How it runs

1. Opening the menu reads the recipes from the assigned Crafter and draws them in the Crafting Recipe Grid.
2. Selecting Brew Health Potion displays its Herb and Water requirements and its Health Potion output in the Recipe Panel.
3. Clicking the recipe opens the Quantity Picker Panel when that option is enabled.
4. As the player increases the quantity, the Recipe Panel scales every displayed amount. The confirm action is disabled when Bag cannot supply that quantity.
5. Confirming **Craft** asks the processor to validate and remove the Bag ingredients, then adds the Health Potion output to the player's main Bag collection.
6. The menu redraws its recipes, resets the displayed quantity to 1, and invokes **On Craft Complete** with the success result.

## Editor checkpoints

Before entering Play Mode, confirm that:

- the Crafting Menu is under the intended Display Panel Manager or Main Menu content transform;
- its Inventory binding resolves the player whose main collection is Bag;
- **Crafter**, **Crafting Recipe Grid**, **Recipe Panel**, and **Quantity Picker Panel** all have valid references;
- the Crafter includes Consumable Recipes and does not also list Brew Health Potion under Miscellaneous Recipes;
- the Crafter uses the intended Version 1 processor with **Externally Remove Ingredients** disabled and `Bag` in **Ingredient Item Collections**;
- the Recipe Panel has two ingredient Item View and description entries plus a valid Health Potion result view;
- the recipe grid has enough slots and usable navigation for the available recipes;
- every optional tab has Crafting Tab Data that allows Brew Health Potion through its filter; and
- the Quantity Picker and Exit button references are valid.

## Verify in Play Mode

1. Put 1 Herb and 1 Water in Bag, enter Play Mode, and open the Crafting Menu.
2. Confirm that Brew Health Potion appears once in the recipe grid and that selecting it shows 2 Herb, 1 Water, and 1 Health Potion.
3. Click the recipe. Confirm that the Quantity Picker opens with **Craft** as its action and that confirmation is disabled because one Herb is missing.
4. Add a second Herb to Bag, close the Quantity Picker, and click the recipe again. Confirm that quantity 1 can now be crafted.
5. Craft once. Confirm that exactly 2 Herb and 1 Water are removed and 1 Health Potion is added to Bag. Equipment should not change.
6. Add 4 Herb and 2 Water, choose quantity 2, and confirm that the Recipe Panel shows 4 Herb, 2 Water, and 2 Health Potions before crafting.
7. Craft that quantity and confirm that the displayed and actual Inventory changes match.
8. Navigate every recipe slot with each supported input method, then close and reopen the menu and confirm that selection and quantities return to their intended starting state.

## Troubleshooting

- **The Crafting Menu cannot be created as a Main Menu panel:** Check **Parent Transform**. It must be the Main Menu Display Panel's main content transform.
- **The menu opens with no recipes:** Check the Crafting Menu's **Crafter** reference, the Crafter's **Crafting Categories**, and **Draw Recipes On Open**. Confirm that all recipe and category references belong to the active database.
- **Brew Health Potion appears twice:** Remove it from **Miscellaneous Recipes** when Consumable Recipes already includes it.
- **Selecting the recipe shows missing ingredients:** Check that the Recipe Panel has one Item View and description entry per displayed Item Definition ingredient. Brew Health Potion needs entries for Herb and Water.
- **Clicking the recipe does not open a quantity choice:** Check **Open Quantity Picker Panel On Recipe Click** and the **Quantity Picker Panel** reference.
- **Craft remains disabled with enough ingredients elsewhere:** Check **Ingredient Item Collections**. This workflow deliberately searches `Bag`, and Bag must be the player's main Item Collection.
- **Ingredients are selected but crafting fails:** Check that Herb and Water are actually in the main Bag collection and that **Externally Remove Ingredients** remains disabled unless another system handles the removal callback.
- **Health Potion is not added after a successful craft:** Check the player Inventory binding, confirm that Bag is its main Item Collection, and check Bag restrictions or capacity for Health Potion.
- **A tab hides Brew Health Potion:** Check the Tab Toggle's Crafting Tab Data. Its **Item Category** and **Crafting Category** filters must both allow the recipe.
- **The wrong player's Items are used:** Check **Bind To Panel Owner Inventory**, **Bind To Inventory By Identifier**, or the direct **Inventory** reference. For a shared station menu, confirm that its opener supplies the interacting player's Inventory.
- **The first recipe cannot be reached or navigation leaves the grid:** Check **Grid Size & Layout Group**, **Grid Navigation**, Layout Group Navigation, and any tab linkage after changing the grid dimensions.
- **The quantity panel stays open after leaving the menu:** Enable **Close Quantity Picker Panel On Close** and confirm that the Crafting Menu references the correct panel.

## Related pages

- [UI Designer workflow](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/)
- [Crafting Category editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/crafting-category/)
- [Crafting Recipe editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/crafting-recipe/)
- [Crafting concepts, processors, and Crafter](https://opsive.com/support/documentation/ultimate-inventory-system/crafting/)
- [Crafting Menu runtime behavior](https://opsive.com/support/documentation/ultimate-inventory-system/ui/crafting-menu/)
- [Custom Crafting Processors](https://opsive.com/support/documentation/ultimate-inventory-system/crafting/custom-crafting-processors/)
- [Main Menu UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/main-menu/)
- [Inventory Grid UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/inventory-grid/)
- [Item Collections](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/)
- [Customize the generated UI](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/ui-customization/)

---

<a id="page-ultimate-inventory-system-editor-window-ui-designer-save"></a>

# Save

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/save/)

Use the UI Designer **Save** tab to create a simple slot-based menu for saving, loading, overwriting, and deleting game data. The menu presents the slots; the Save System Manager writes the files, and Saver components decide which runtime state is included.

The example below saves a player Inventory with Health Potion in **Bag** and Iron Sword in **Equipment**. Use the provided menu as a working baseline or connect its optional events to a project-specific save backend.

## Set up the save system

1. Open **Tools > Opsive > Ultimate Inventory System > Main Manager** and select **Setup**.
2. Open **Save Setup**.
3. Set **Object to save** to the player GameObject that owns the Inventory.
4. Select **Add Components**.
5. On the Inventory System Manager GameObject, confirm that Save Setup added **Save System Manager** and **Inventory System Manager Item Saver**.
6. On the player, confirm that it added **Inventory Saver**. When the player also owns Currency, confirm that **Currency Owner Saver** was added.

Inventory Saver records the Item IDs and amounts in every Item Collection, including Bag and Equipment. Inventory System Manager Item Saver records the actual Item data referenced by those IDs, which is required for mutable or unique Items such as an Iron Sword with changing Durability.

For a character using the Ultimate Character Controller integration, use Inventory Bridge Saver instead of the standard Inventory Saver.

On Inventory Saver, assign the player **Inventory** and leave **Additive** disabled for a normal restore. A load then clears the current Item Collections before restoring the saved contents. Enable Additive only when loading should deliberately add the saved Items to the current state.

Each Saver's full key must be unique. When a scene has repeated GameObject names and Saver types, set a distinct **Key** so every component can register.

## Configure the Save System Manager

For the first manual test:

- Set **Max Saves** to the number of slots the menu should offer.
- Keep a stable **Save File Name**, **Save File Extension**, and **Save Meta Data File Extension**.
- Leave **Debug Json Copy** disabled unless a readable diagnostic copy is needed.
- Leave the automatic load and save options disabled so the test changes only when the menu actions are used.
- Leave **Save Meta Data Creator** unassigned to use the built-in basic metadata, which lets the standard Save View show the save time.
- Confirm that **Inventory System Manager Item Saver** references the component created during Save Setup.

The manager writes files below `Application.persistentDataPath`. Its component context menu can print or open that folder when the files need to be inspected.

## Create the Save Menu

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer**.
2. Select the **Save** tab and open **Create**.
3. Set **Parent Transform** to the Rect Transform that should contain the menu.
4. Choose a **Panel Option**:
   - **Basic** creates a standalone Save Menu.
   - **Main Menu** adds a **Save/Load** inner panel to the Main Menu. Its Parent Transform must be the Main Menu's main content transform.
5. Select **Create**.
6. In **Edit**, select the generated Save Menu. Use **Find Available Targets in Scene** when it is not already selected.

![The Classic Save Menu displaying selectable save and load entries.](https://opsive.com/wp-content/uploads/2020/11/SaveSystemScreenshot-1024x576.png)

## Audit the Saver components

Open **Save System Manager and Savers** in the Save tab. The list shows Saver components found in the scene; select an entry to locate and inspect it.

For the standard Inventory round trip, the list should include:

- Inventory System Manager Item Saver on the manager GameObject; and
- Inventory Saver on the player.

It can also include Currency Owner Saver when Gold should persist, Inventory Grid Saver when explicit grid positions matter, or another specialized Saver for project data. This UI Designer list is an audit view: add a missing Saver through **Save Setup** or the Inspector, then return and confirm that it appears.

Saver components register with the Save System Manager when they start at runtime. Keep the required Saver GameObjects active and their keys unique.

## Configure the save-slot grid

1. Under **Grid Size & Layout Group**, set enough visible slots for **Max Saves** or for the number intended on one page.
2. Confirm that the Save View prefab displays both the file number and the save metadata content.
3. Add **Layout Group Navigation** when the slots should support controller or keyboard navigation.
4. Under **Grid Navigation**, choose buttons, scrolling, or another supported option when Max Saves exceeds the visible grid size.
5. On the Save Menu component, confirm that **Save Grid** references the generated grid.
6. On the Save Grid, confirm that **Action Panel** and **Confirmation Pop Up** reference the generated controls.

When the menu opens, the grid refreshes from the Save System Manager, creates an entry for every allowed slot, and selects the first slot. Save writes to the selected index. Load and Delete are meaningful only after that index contains a save; overwrite, load, and delete use the confirmation popup.

## Choose the action behavior

Keep **Optional Save Event**, **Optional Load Event**, and **Optional Delete Event** disabled to use the built-in Save System Manager.

Enabling one of these optional events cancels that default action. Use it only when the event invokes the intended replacement workflow, such as a third-party backend or a wrapper that eventually calls the relevant Save Grid Save, Load, or Delete operation.

## How it runs

1. Opening the Save Menu refreshes the grid from the manager's current metadata and selects the first slot.
2. Saving asks every registered Saver for its state, creates metadata, and writes the save and metadata files.
3. Saving an occupied slot asks the player to confirm the overwrite. With the built-in basic metadata, released Version 1 can also show this confirmation on an entry labeled Empty.
4. Loading an occupied slot asks for confirmation, reads its data, and restores every registered Saver in load-priority order.
5. Deleting an occupied slot removes its save and metadata files, then refreshes the slot as empty.

For the standard player, Inventory System Manager Item Saver restores Item data before Inventory Saver rebuilds Bag and Equipment. With **Additive** disabled, the loaded contents replace the temporary changes made after saving.

## Editor checkpoints

Before entering Play Mode, confirm that:

- one Save System Manager exists and **Inventory System Manager Item Saver** is assigned;
- the player has an Inventory Saver whose **Inventory** reference is correct and **Additive** is disabled;
- all Saver full keys are unique;
- **Max Saves** matches the intended slot count;
- the Save Menu is below the intended Display Panel Manager or Main Menu content transform;
- **Save Grid**, **Action Panel**, and **Confirmation Pop Up** all have valid references;
- the visible grid size and Grid Navigation can reach every allowed save slot;
- the Save View has valid file-number and content text references;
- the UI Designer audit list includes the required Saver components; and
- optional action events are disabled unless their replacement callbacks are fully connected.

## Verify in Play Mode

1. Start with three Health Potions in Bag and Iron Sword in an Equipment slot. If Iron Sword has runtime Durability, record its value.
2. Enter Play Mode, open the Save Menu, and select an empty slot. Confirm that it is labeled **Empty**, then choose Save. Do not use Load or Delete if the built-in Version 1 action panel also exposes them for that empty entry.
3. Confirm the save if prompted, then confirm that the slot changes from **Empty** to a dated entry.
4. Remove two Health Potions, move Iron Sword out of Equipment, and change its Durability when applicable.
5. Select the saved slot, choose Load, and confirm the prompt. Verify that Bag again has three Health Potions, Iron Sword returns to the saved Equipment slot, and its saved Durability is restored.
6. Change the Inventory again, choose Save on the occupied slot, and confirm that the overwrite prompt appears.
7. Load that slot and confirm that the newly overwritten state, rather than the first state, is restored.
8. Delete the slot and confirm that it returns to **Empty**. Do not use Load or Delete if the built-in action panel still displays them for that empty entry.
9. Save once more, stop and restart Play Mode, open the menu, and confirm that the slot metadata is read from disk. Load it manually and verify the Inventory again.
10. Navigate every slot with each supported input method and confirm that selection remains visible.

## Troubleshooting

- **The Save Menu cannot be created as a Main Menu panel:** Check **Parent Transform**. It must be the Main Menu Display Panel's main content transform.
- **The Save tab has no useful runtime setup:** Run **Main Manager > Setup > Save Setup** first. The UI Designer creates and audits the menu; Save Setup creates the manager and standard Saver components.
- **The Saver audit list omits the player:** Check **Object to save** in Save Setup, add Inventory Saver to the Inventory GameObject, then refresh the Save tab.
- **A duplicate-Saver-key warning appears:** Give repeated GameObjects distinct names or assign a unique **Key** on each conflicting Saver.
- **The slot count is wrong:** Check **Max Saves** on Save System Manager, then reopen the menu so Save Grid refreshes. Adjust the grid size and navigation separately.
- **Selecting a slot does nothing:** Check the Save Grid's **Action Panel**, **Confirmation Pop Up**, and parent Display Panel references.
- **An Empty slot still shows Load or Delete, or Save asks to overwrite it:** Released Version 1 checks whether a metadata object exists rather than its Empty state when enabling these actions. Use Save for the empty slot and do not invoke Load or Delete; customize Save Grid when those actions must be hidden.
- **Save, Load, or Delete appears to do nothing:** Check whether its optional event is enabled. Enabling an optional event cancels the default function, so its callback must perform the replacement action.
- **The entry is saved but Bag and Equipment do not restore:** Check that Inventory Saver is active, registered, and references the player Inventory. Leave **Additive** disabled for replacement behavior.
- **Iron Sword returns but its runtime attributes do not:** Check that Inventory System Manager Item Saver exists and is assigned on Save System Manager.
- **Gold does not restore:** Add Currency Owner Saver to the GameObject that owns the player's Currency Owner.
- **Items load into the wrong collections or slots:** Keep the Inventory's Item Collection order and Item Slot Collection setup compatible with the saved version. Inventory Saver restores collections by their index.
- **Automatic loading reads data but the Inventory stays at its scene defaults:** Enable **Load On Start** on the required Saver components when the manager loads before those Savers register.
- **Unexpected data replaces the manual test:** Disable **Auto Load On Initialize**, **Auto Load On Scene Loaded**, **Auto Save On Scene Unloaded**, and **Auto Save On Application Quit** while isolating the menu workflow.
- **The save exists in one build but not another:** Check the platform-specific `Application.persistentDataPath`, file name, and extensions. Use the manager's context menu to inspect the current folder.
- **A UCC-integrated character does not restore correctly:** Use Inventory Bridge Saver for the integration rather than the standard Inventory Saver.

## Related pages

- [UI Designer workflow](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/)
- [Save System and Saver components](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)
- [Save Menu runtime behavior](https://opsive.com/support/documentation/ultimate-inventory-system/ui/save-menu/)
- [Save View](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/save-view/)
- [Main Menu UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/main-menu/)
- [Inventory Grid UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/inventory-grid/)
- [Item Collections](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/)
- [Customize the generated UI](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/ui-customization/)

---

<a id="page-ultimate-inventory-system-editor-window-ui-designer-storage"></a>

# Storage

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/storage/)

Use the UI Designer **Storage** tab to create a menu that moves Items directly between the player's Inventory and another Inventory. This workflow uses Health Potion and Iron Sword in **Bag**, while keeping **Equipment** out of the exchange grids.

The provided Storage Menu is a focused Store/Retrieve workflow. It opens a quantity picker when the player clicks an Item, so use a custom pair of Inventory Grids instead when the design depends on Item Actions or drag and drop.

## Before you begin

Confirm that:

- the intended Inventory System Database is selected in **Main Manager > Setup**;
- Canvas Managers exist and a duplicated UI Designer schema has been spawned in the scene;
- the player has an Inventory with **Bag** as its main Item Collection and **Equipment** as a separate equipped collection;
- Bag contains a Health Potion and an unequipped Iron Sword for the first test;
- the storage object has its own Inventory and main Item Collection; and
- the selected schema has Item Views for Consumable and Weapon Items.

The built-in Storage Menu sends stored Items to the storage Inventory's main Item Collection and sends retrieved Items to the player's main Item Collection. Make Bag the player's main destination when retrieved Items should return to Bag rather than Equipment.

## Create the Storage Menu

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer**.
2. Select the **Storage** tab and open **Create**.
3. Set **Parent Transform** to a Rect Transform below the intended Display Panel Manager.
4. Select **Create**. UI Designer creates a standalone Storage Menu panel that disables itself when closed.
5. In **Edit**, select the new Storage Menu. Use **Find Available Targets in Scene** when it is not already selected.
6. Under **Inventory Grid**, create **Storage Inventory Grid** and **Client Inventory Grid** if the schema does not already provide them. Client refers to the player.
7. Use **Edit Storage Inventory Grid** and **Edit Client Inventory Grid** to configure each grid's layout, Item Views, navigation, and filters.
8. Under **Quantity Picker Panel**, create the quantity control used by Store and Retrieve.
9. On the Storage Menu component, assign the other Inventory to **Storage Inventory**.

![The Storage Menu showing separate player and storage Inventory grids with Store and Retrieve controls.](https://opsive.com/wp-content/uploads/2020/12/StorageMenu.png?v=3a4668097fc7)

## Bind the player and storage Inventories

The Storage Menu inherits the standard player Inventory binding:

- Keep **Bind To Panel Owner Inventory** enabled when the Display Panel Manager's Panel Owner is the player.
- Otherwise, set **Bind To Inventory By Identifier** to the player's Inventory Identifier ID, or assign **Inventory** directly.
- Assign the separate container or shared stash Inventory to **Storage Inventory**.

The **Client Inventory Grid** displays the bound player Inventory. The **Storage Inventory Grid** displays **Storage Inventory**. These must be two different Inventory components for a meaningful exchange.

For a reusable menu that opens several containers, set the active storage Inventory before opening the menu. Use the [Chest workflow](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/chest/) when an interactable world object should perform that binding automatically.

## Configure the grids for Bag and Equipment

1. In **Edit Client Inventory Grid**, add or update the default Item Collection filter so it shows **Bag** and excludes **Equipment**.
2. In **Edit Storage Inventory Grid**, show the storage Inventory's main collection.
3. Confirm that both Item View Drawers use a Category Item View Set that resolves Health Potion as Consumable and Iron Sword as Weapon.
4. Confirm that each grid and its Item View Drawer use the same **Content** transform.
5. Add a Grid Navigator when either Inventory can contain more Items than its visible slots.

Filtering Equipment prevents an equipped Iron Sword from appearing as a storable Bag Item. When Iron Sword is retrieved later, the built-in menu adds it to the player's main collection, which is Bag in this setup; it does not equip the weapon automatically.

## Replace categories from another database

Schema Storage prefabs can contain Item Info Category Filters that still reference the schema's original database. At runtime, an invalid reference logs: `Some of the categories referenced on the item info category filter do not reference the right database`.

Select each warning's context object, inspect the affected tab or default filter, and replace its category with the matching Consumable, Weapon, or other category from the active database. Do not leave an invalid category merely because the grid appears to work with the current sample Items.

## Choose the opening behavior

| **Menu Open Options** | Use it when | Initial focus |
| --- | --- | --- |
| **Open Store Sub Menu** | Storing player Items is the primary action | The Client Inventory Grid |
| **Open Retrieve Sub Menu** | Retrieving stored Items is the primary action | The Storage Inventory Grid |
| **Open No Sub Menu** | The player should choose Store or Retrieve first | The menu buttons before either Item list is active |

Store and Retrieve both use the same Quantity Picker Panel. Its maximum is the amount in the clicked Item stack, and a quantity below one cancels the transfer.

## How the exchange runs

1. Opening Store draws both Inventories and focuses the Client Inventory Grid.
2. Clicking Health Potion or Iron Sword opens the Quantity Picker Panel with **Store** as the confirmation text.
3. Confirming transfers that amount from its player Item Collection to the storage Inventory's main Item Collection.
4. Opening Retrieve focuses the Storage Inventory Grid and changes the confirmation text to **Retrieve**.
5. Confirming transfers that amount from storage to the player's main Item Collection, Bag.
6. Both grids redraw after the transfer.

Destination Item restrictions still apply. When the destination rejects some or all of a transfer, the rejected amount is returned to its source collection instead of being silently lost.

## Editor checkpoints

Before entering Play Mode, confirm that:

- the Storage Menu is below the intended Display Panel Manager;
- **Client Inventory Grid**, **Storage Inventory Grid**, and **Quantity Picker Panel** all have valid references;
- the player binding resolves the Inventory whose main collection is Bag;
- **Storage Inventory** references a different Inventory with a valid main collection;
- the Client grid shows Bag and excludes Equipment;
- both grids and their Item View Drawers use matching **Content** transforms;
- Consumable and Weapon resolve to valid Item Views in both grids;
- every Item Info Category Filter references the active Inventory System Database; and
- the selected **Menu Open Options** matches the intended first action.

## Verify in Play Mode

1. Open Store and confirm that Health Potion and the unequipped Iron Sword appear in the Client Inventory Grid.
2. Confirm that an Item already in Equipment does not appear in that grid.
3. Store part of a Health Potion stack and confirm that the player amount decreases while the storage amount increases by the same value.
4. Store Iron Sword and confirm that it moves from Bag into the storage Inventory.
5. Open Retrieve, retrieve Iron Sword, and confirm that it returns to Bag rather than Equipment.
6. Cancel a quantity choice and confirm that neither Inventory changes.
7. Test a destination restriction and confirm that rejected Items remain in or return to the source Inventory.
8. Close and reopen the menu, then confirm that both grids redraw the current Inventory contents.

## Troubleshooting

- **The Storage Menu does not open:** Check that its Display Panel is registered with the intended Display Panel Manager and that the opener targets that panel.
- **The Client grid is empty:** Check **Bind To Panel Owner Inventory**, **Bind To Inventory By Identifier**, or the direct **Inventory** reference, then confirm that Bag contains Items allowed by the grid filter.
- **The Storage grid is empty:** Check **Storage Inventory**, its main Item Collection, and the Storage Inventory Grid's filter.
- **Equipment Items appear in the Client grid:** Check the Item Collection filter and limit it to Bag. The built-in menu can transfer from whichever player collection supplied the selected Item.
- **An Item has no visual:** Check both Item View Drawers, their **Content** transforms, and the Category Item View Set mappings for Consumable and Weapon.
- **The database-category warning appears:** Select the warning's context object and replace every invalid filter category with the equivalent category from the active database.
- **Clicking an Item does nothing:** Check the correct Client or Storage Inventory Grid reference and the **Quantity Picker Panel** reference. The built-in menu handles clicks directly rather than through Item Actions.
- **Only part of an Item moves:** Check the selected quantity and the destination Inventory's Item restrictions or collection capacity. Rejected amounts return to the source.
- **Retrieved Items enter the wrong collection:** The built-in menu retrieves into the player's main Item Collection. Make Bag the main collection or use a custom exchange workflow when the destination must vary.
- **Store and Retrieve begin on the wrong side:** Check **Menu Open Options** and choose the intended Store, Retrieve, or no-submenu state.

## Related pages

- [UI Designer workflow](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/)
- [Storage Menu runtime behavior](https://opsive.com/support/documentation/ultimate-inventory-system/ui/storage-menu/)
- [Inventory Grid UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/inventory-grid/)
- [Equipment UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/equipment/)
- [Chest UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/chest/)
- [Item Collections](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/)
- [Item Info filters and sorters](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-info-filter-sorters/)
- [Move Items with drag and drop](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/move-items-drag-drop/)
- [Customize the generated UI](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/ui-customization/)

---

<a id="page-ultimate-inventory-system-editor-window-ui-designer-chest"></a>

# Chest

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/chest/)

Use the UI Designer **Chest** tab to create a menu for taking Items and Currency from an interactable chest. One Chest Menu can serve several chests because the chest that the player opens supplies both its Inventory and the player's Inventory at runtime.

This built-in workflow is retrieval-only. In the example below, Health Potion and Iron Sword move from the chest into the player's **Bag** while **Equipment** remains unchanged. Use the [Storage workflow](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/storage/) when the player must also deposit Items.

## Before you begin

Confirm that:

- the intended Inventory System Database is selected in **Main Manager > Setup**;
- Canvas Managers exist and a duplicated UI Designer schema has been spawned in the scene;
- the player has an Inventory with **Bag** as its main Item Collection and **Equipment** as a separate equipped collection;
- the player has an Inventory Interactor linked to that Inventory and a working interaction input;
- the chest has its own Inventory and main Item Collection; and
- the selected schema has Item Views for the Consumable and Weapon categories.

The Demo folder's **Chest** prefab is the quickest starting point because it already demonstrates the participating chest and interaction components. When building a chest from scratch, use the steps below to make each relationship explicit.

## Create the Chest Menu

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer**.
2. Select the **Chest** tab and open **Create**.
3. Set **Parent Transform** to a Rect Transform below the intended Display Panel Manager.
4. Select **Create**. UI Designer creates a standalone Chest Menu panel that disables itself when closed.
5. In **Edit**, select the new Chest Menu. Use **Find Available Targets in Scene** when it is not already selected.
6. Under **Inventory Grid**, create **Chest Inventory Grid** if the schema does not already provide it.
7. Select **Edit Chest Inventory Grid** to configure its layout, Item Views, navigation, and filters.
8. Under **Quantity Picker Panel**, create the quantity control used when the player takes part of an Item stack.

The generated menu handles grid clicks directly: clicking an Item opens the Quantity Picker Panel with **Take** as the confirmation text. It does not run Item Actions. Use a custom Inventory Grid workflow when taking an Item must open an action menu or support drag and drop.

## Set the player destination

On the Chest Menu component, set **Add To Item Collection Name** to `Bag`. When the menu cannot find that named collection, it falls back to the player's main Item Collection.

This choice controls where both an individually selected Item and **Take All Items** place their results. It does not equip Iron Sword automatically, so **Equipment** should remain unchanged unless it is deliberately named as the destination or made the player's main collection.

If the chest can hold Gold, both the chest and player Inventories need Currency Owners. Assign an optional **Multi Currency View** to show the chest's current balance, and assign the intended **Take Currency Button** when the player should be able to collect it separately.

## Connect an interactable chest

1. Add an Inventory to the chest GameObject and make its intended container the main Item Collection.
2. Add a Chest component. Assign **Panel Manager**, **Chest Menu**, **Inventory**, and an Animator that responds to the `Open` and `Close` triggers.
3. Add an Interactable component and a trigger Collider. Ensure **Interactor Layer Mask** includes the player's layer.
4. Add a Chest Interactable beside the Interactable and assign its **Chest** reference.
5. On the player, assign the player Inventory to the Inventory Interactor and configure **Input**, or enable **Auto Interact** when entering the trigger should open the chest immediately.

At initialization, a Chest Menu assigns itself to scene Chest components that do not already have a Chest Menu. Explicitly assigning **Chest Menu** on each Chest makes the intended relationship clear and avoids ambiguity when a scene contains more than one menu.

## Choose the available actions

| Chest Menu control | What it does |
| --- | --- |
| Click an Item | Opens the Quantity Picker Panel, initially selecting the full stack, then moves the confirmed amount to Bag |
| **Take Currency Button** | Moves all Currency from the chest Currency Owner to the player's Currency Owner |
| **Take All Items Button** | Moves every Item from the chest's main Item Collection to Bag, then closes the menu |
| **Take All Button** | Takes all Currency and all Items, then closes the menu |
| **Cancel Button** | Closes the menu without taking another Item |

Leave **Do Not Close Chest If Empty** disabled for the normal close-animation and re-enable-interaction lifecycle. Enable it only when an emptied chest should deliberately remain open: when the chest's main Item Collection is empty, this setting prevents the Chest component's close operation.

## How it runs

1. The Inventory Interactor passes the player's Inventory to the Chest Interactable.
2. The Chest binds that Inventory to the Chest Menu, marks itself as the active chest, starts its open animation, and opens the menu.
3. The Chest Inventory Grid binds to the active chest's Inventory and displays the Items allowed by its filters. Configure those filters for the chest's main Item Collection because that is where the built-in Take operations retrieve Items.
4. Taking Health Potion or Iron Sword moves the chosen amount into Bag and redraws the chest grid.
5. Closing the menu closes the quantity picker and calls the Chest's close operation. The Chest Interactable then becomes available again.

Because the active Chest is set each time the player interacts, the same menu can display a different Inventory when the player opens a second chest.

## Editor checkpoints

Before entering Play Mode, confirm that:

- the Chest Menu is below the intended Display Panel Manager;
- **Chest Inventory Grid** and **Quantity Picker Panel** have valid references;
- the grid shows the chest's main Item Collection and its Item View Drawer resolves both Consumable and Weapon Items;
- **Add To Item Collection Name** is exactly `Bag` and the player's Inventory contains that collection;
- the Chest references the intended Panel Manager, Chest Menu, chest Inventory, and Animator;
- the Chest Interactable references the same Chest and sits beside an enabled Interactable;
- the chest has a trigger Collider and its **Interactor Layer Mask** includes the player;
- the Inventory Interactor references the player's Inventory and has a usable **Input**; and
- the optional Currency view and buttons have valid references when the chest contains Gold.

## Verify in Play Mode

1. Put three Health Potions and one Iron Sword in the chest's main Item Collection. Record the player's Bag and Equipment contents.
2. Enter Play Mode, approach the chest, and use the Inventory Interactor. Confirm that the chest opens and the Chest Menu shows those Items.
3. Select Health Potion, take one, and confirm that the chest now shows two while Bag gains one. Equipment should not change.
4. Take Iron Sword and confirm that it enters Bag rather than becoming equipped.
5. If the chest contains Gold, use **Take Currency** and confirm that its full amount moves to the player's Currency Owner and the optional view redraws at zero.
6. Close the menu and confirm that the close animation runs and the chest can be interacted with again.
7. Open a second Chest that uses the same menu and confirm that its own contents replace the first chest's contents in the grid.
8. Use **Take All Items** or **Take All** and confirm that the menu closes after the transfer.

## Troubleshooting

- **The chest is never selected:** Check the trigger Collider, **Interactor Layer Mask**, and the player's Collider. Then confirm that the player has an Inventory Interactor with the intended Inventory and interaction input.
- **The interaction does nothing:** Check that Chest Interactable references the Chest and sits beside the enabled Interactable. Its interactor must supply an Inventory.
- **The warning `Chest Menu is null` appears:** Assign the intended Chest Menu on the Chest component. Automatic discovery only fills an unassigned Chest when the menu initializes in the scene.
- **The chest opens but the menu does not:** Check **Panel Manager**, the Chest Menu's Display Panel registration, and that the Chest references that menu.
- **The menu opens with the wrong chest contents:** Check the Chest's **Inventory** reference and its main Item Collection. In a scene with multiple menus, explicitly assign the intended Chest Menu on every Chest.
- **The grid is empty although the chest contains Items:** Check **Chest Inventory Grid**, confirm that its filters include the active chest Inventory's main Item Collection, and check the Item Views for Consumable and Weapon.
- **Clicking an Item does nothing:** Check the Chest Inventory Grid and **Quantity Picker Panel** references. The built-in Chest Menu handles the click directly rather than using Item Actions.
- **Items enter the wrong player collection:** Check **Add To Item Collection Name**. If `Bag` is misspelled or absent, the menu uses the player's main Item Collection instead.
- **Iron Sword is equipped immediately:** Check whether Equipment was named as the destination or made the main collection. The intended setup sends retrieved Items to Bag.
- **Take Currency does nothing:** Check that both Inventories have Currency Owners and that **Take Currency Button** references the intended button. The Multi Currency View is optional and does not provide the Currency data itself.
- **The chest cannot be interacted with after it is emptied:** Check **Do Not Close Chest If Empty**. Disable it when closing the menu should run the Chest close operation and re-enable the Interactable.
- **The open or close animation does not run:** Check the Chest's Animator and confirm that its controller responds to the `Open` and `Close` triggers.

## Related pages

- [UI Designer workflow](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/)
- [Chest Menu runtime behavior](https://opsive.com/support/documentation/ultimate-inventory-system/ui/chest-menu/)
- [Storage UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/storage/)
- [Inventory Grid UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/inventory-grid/)
- [Currency UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/currency/)
- [Interaction System](https://opsive.com/support/documentation/ultimate-inventory-system/interaction-system/)
- [Item Collections](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/)
- [Customize the generated UI](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/ui-customization/)

---

<a id="page-ultimate-inventory-system-editor-window-ui-designer-item-description"></a>

# Item Description

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-description/)

An Item Description is a larger Item View for the Item currently selected in Bag, Equipment, a hotbar, or another Item View Slots Container. Use it when the player needs more than a slot icon, such as the Item name, Description, Attack, or Durability.

This workflow creates one shared detail panel: Health Potion shows its common information, while Iron Sword and Fire Wand also show Weapon attributes.

## Before you begin

Confirm that:

- the intended Inventory System Database is selected in **Main Manager > Setup**;
- UI Designer Canvas Managers and a duplicated schema have been created;
- **Spawn In Scene** has created the starting UI;
- the Bag Inventory Grid displays Health Potion, Iron Sword, and Fire Wand; and
- the definitions resolve the attributes that the panel will read.

For the standard example, keep `Icon` and `Description` available to all three definitions. Weapon can additionally supply `Attack`, while each runtime weapon can hold its own `Durability` value.

## Create the Item Description

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer** and select **Item Description**.
2. In **Create**, choose the description template closest to the intended layout.
3. Choose the parent panel or transform that should contain the detail view.
4. Create the Item Description from the duplicated project schema.
5. In **Edit**, select the created Item Description.
6. Add or remove Item View Modules for the values the panel should display.
7. Configure the template's Item name, Icon, and Description fields or modules with their intended UI elements and attribute names.
8. Keep the panel visible in the editor long enough to confirm that its labels, images, and attribute area fit the intended layout.

![The generated Item Description panel displaying the selected Item's large icon and descriptive details.](https://opsive.com/wp-content/uploads/2020/11/ItemDescription.png?v=4d17ea0e88b3)

The Item Description is a special Item View, so it can use the same focused Item View Modules as other views. Avoid adding a field merely because the data exists; show only information that helps the player decide what to do with the selected Item.

## Bind Bag selection to the description

1. Select the Bag Inventory Grid or its parent object.
2. Add an **Item View Slots Container Description Binding** beside the Bag container.
3. Assign the generated Item Description to the binding.
4. Configure whether selection or click should update the description, based on the project's input pattern.
5. Select Health Potion, Iron Sword, and Fire Wand in the editor or Play Mode and confirm that the same detail panel receives each Item.

The description binding must sit beside the Item View Slots Container that supplies the selected Item. Add a separate binding beside Equipment only when selecting an equipped Item should drive the same or another description panel.

## Show different attributes by category

Use a **Category Attribute View Set Item View Module** when the attribute area should change with the selected Item Category. It can create the Attribute Views appropriate for the current Item instead of leaving irrelevant Weapon rows visible for Health Potion.

| Selected Item | Common content | Category-specific content |
| --- | --- | --- |
| Health Potion | Icon, name, Description | No Weapon-only fields |
| Iron Sword | Icon, name, Description | Attack and current Durability |
| Fire Wand | Icon, name, Description | Its own Attack and Durability values |

Configure the category mappings so Consumable receives the simple layout and Weapon receives the weapon Attribute Views. Use an Int Value Attribute Box or another compatible Attribute View Module when the source attribute is an integer. Attribute spelling and type must match the database declaration.

## Choose how the description appears

### Fixed detail panel

Use a fixed panel beside Bag when details should remain visible as selection changes. This is the clearest starting point for keyboard and controller navigation.

### Menu-owned panel

Add an **Item Description Panel Binding** beside the Display Panel when the description needs to initialize with that menu. Confirm that opening and reopening the menu refreshes the selected or cleared state correctly.

### Slot-following tooltip

Use **Item View Slot Panel To Tooltip** when the description should be positioned near the selected or clicked Item View Slot. Test the tooltip at every screen edge so it remains readable and does not cover the selected slot or leave the visible canvas.

Choose one primary presentation per context. Running a fixed detail panel and tooltip from the same selection can duplicate information and make focus changes harder to follow.

## Decide where to customize

Edit the generated scene instance when only one menu needs a different description layout. Edit the project-owned Item Description prefab when every use of that view should change. Edit the corresponding prefab in the duplicated schema when future UI Designer output should start with the customization.

After changing a shared prefab, recheck Bag, Equipment, Shop, and any tooltip that uses it. A layout that fits a wide menu panel may be too large for a slot-following tooltip.

## Editor checkpoints

Before entering Play Mode, confirm that:

- the Item Description belongs to the project or duplicated schema rather than package-owned assets;
- every Item View Module references its intended Image, text, or child object;
- `Icon` and `Description` resolve for Health Potion, Iron Sword, and Fire Wand;
- the Weapon attribute layout uses the exact `Attack` and `Durability` names and compatible Attribute View types;
- the Category Attribute View Set maps Consumable and Weapon to the intended layouts;
- the Item View Slots Container Description Binding sits beside Bag and points to this Item Description;
- any Equipment binding points to the intended detail panel;
- an Item Description Panel Binding sits beside the Display Panel when panel initialization is required; and
- any Item View Slot Panel To Tooltip has enough canvas space for its complete layout.

## Verify in Play Mode

1. Open Bag and select Health Potion. Confirm that its Icon, name, and Description appear without Weapon-only rows.
2. Select Iron Sword and confirm that the same panel replaces the Health Potion content and shows the intended Attack and Durability.
3. Select Fire Wand and confirm that its values replace Iron Sword without leaving stale text or images.
4. Select an empty slot and confirm that the prior Item details are cleared or intentionally retained according to the binding configuration.
5. Equip Iron Sword, select it in Equipment, and confirm that any Equipment description binding updates the intended panel.
6. Change a runtime Durability value, refresh or reselect the Item, and confirm that the displayed value matches the Item instance.
7. Close and reopen the menu and confirm that the Item Description Panel Binding initializes a valid state.
8. If a tooltip is used, test the first and last visible slots at the smallest supported resolution and confirm that the panel remains inside the canvas.

## Troubleshooting

- **The Item Description tab is unavailable:** Check that a database is selected, Canvas Managers were created, a schema was duplicated, and **Spawn In Scene** completed.
- **Selection changes but the description does not:** Check that the Item View Slots Container Description Binding is beside the correct container and references this Item Description.
- **The panel updates only on click or only on selection:** Check the update behavior configured on the description binding and match it to the intended input flow.
- **Icon or Description is blank:** Check the exact attribute name, declaration scope, definition value, and the module's UI reference.
- **Health Potion shows Weapon rows:** Check the Category Attribute View Set mapping and confirm that Consumable does not inherit from Weapon.
- **Iron Sword is missing Attack or Durability:** Check that Weapon declares the attribute in the correct collection and that the selected Item resolves a value with the expected type.
- **A previous Item's values remain visible:** Check that every custom Item View or Attribute View Module clears its output and that empty-slot selection redraws the description.
- **The panel is blank when the menu first opens:** Add or check the Item Description Panel Binding beside the Display Panel, then confirm the menu establishes an initial selection.
- **Equipment selection updates the wrong panel:** Check the Equipment container's Description binding and remove duplicate bindings that target another Item Description.
- **The tooltip leaves the screen or covers the selected slot:** Check Item View Slot Panel To Tooltip placement and retest the panel dimensions at the canvas edges.

## Related pages

- [UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/)
- [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/inventory-grid/)
- [Equipment](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/equipment/)
- [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view-slots-container/)
- [Item View](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view/)
- [Attribute View](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/attribute-view/)
- [Runtime Item Description](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-description/)
- [Runtime Item View](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/item-view/)
- [Runtime Attribute Views](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/attribute-views/)
- [Common attribute types](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/common-attribute-types/)
- [Display Panel Manager](https://opsive.com/support/documentation/ultimate-inventory-system/ui/display-panel-manager/)
- [Customize the generated UI](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/ui-customization/)

---

<a id="page-ultimate-inventory-system-editor-window-ui-designer-currency"></a>

# Currency

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/currency/)

Use the UI Designer **Currency** tab to create a live Gold balance or a reusable view for a price, reward, or crafting cost. A Multi Currency View controls how each Currency is displayed; its data source determines whether the number represents the player's balance or a value such as an Item's Buy Price.

## Before you begin

Confirm that:

- the intended Inventory System Database is selected in **Main Manager > Setup**;
- Gold exists in **Main Manager > Currencies** and has the Icon used by the UI;
- Canvas Managers exist and a duplicated UI Designer schema has been spawned in the scene;
- the player Inventory has a Currency Owner with a starting Gold amount; and
- for a shop test, Health Potion has a `CurrencyAmounts` Item Definition attribute named `BuyPrice` that contains Gold, and the Shop's **Buy Attribute Name** is also `BuyPrice`.

The exact `BuyPrice` name matters: the Shop looks up the Item attribute by the configured string.

## Create a live Gold balance

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer**.
2. Select the **Currency** tab and open **Create**.
3. Set **Parent Transform** to the Rect Transform that should contain the balance. It must be below a Display Panel Manager in the hierarchy.
4. Choose **Currency Owner Monitor** and select **Create**. This schema option creates the monitor together with a Multi Currency View.
5. On the Multi Currency View, confirm that Gold is paired with the intended Currency View. The Currency View supplies the amount text and can also display Gold's Icon.
6. On the Currency Owner Monitor, set **Inventory ID** to the player's Inventory Identifier ID. Alternatively, assign **Currency Owner** directly and leave **Inventory ID** at `0` when the view should always use that reference.
7. Position the generated object within its parent panel, then save the scene or prefab.

![The Currency UI Designer showing the Multi Currency View creation and editing controls.](https://opsive.com/wp-content/uploads/2020/11/MultiCurrencyView.png?v=a4b8f47077c7)

The monitor finds the Currency Owner through **Inventory ID** or the direct **Currency Owner** reference, draws its Currency Collection in the Multi Currency View, and listens for later Currency changes. A purchase or reward therefore updates the Gold number without a separate manual refresh.

## Show an Item's Buy Price

A Buy Price and a player balance are different data sources. Do not add a Currency Owner Monitor to a price-only view, because the monitor will replace the displayed value with the player's balance.

For a shop:

1. Set Health Potion's `BuyPrice` to a Gold amount.
2. Confirm that the Shop reads `BuyPrice` through **Buy Attribute Name**.
3. In the UI Designer **Shop** tab, open **Currency Displays** and create the **Total Price UI**.
4. Confirm that the generated Shop Menu references that Multi Currency View as its **Total Price**.
5. Keep the separate Currency Owner Monitor visible when the player should see both the price and their remaining Gold.

The Shop Menu draws the selected Item and quantity's total into its price view. The Currency Owner Monitor continues to draw the player's current balance in its own view.

## Choose the view type

| UI Designer option | Use it for | Data source |
| --- | --- | --- |
| **Multi Currency View** | A standard balance, price, cost, or reward that can contain one or more Currencies | The owning menu, view module, or another component draws a Currency Collection or Currency Amounts |
| **Multi Currency View Small** | The same information in a more compact schema layout | The owning menu, view module, or another component |
| **Currency Owner Monitor** | A live player balance | The Currency Owner resolved through **Inventory ID** or assigned directly |
| **Currency View** | The visual for one Currency Amount, normally used within a Multi Currency View | Its parent Multi Currency View |

On a Currency View, enable **Hide If Zero** only when a zero amount should disappear. Assign **Image** when the Currency Icon should be shown; the **Text** reference displays the numeric amount.

## Editor checkpoints

Before entering Play Mode, confirm that:

- **Parent Transform** is under a Display Panel Manager and the created object is under the intended canvas or panel;
- the Multi Currency View maps Gold to a Currency View with a valid Text reference;
- the Currency Owner Monitor's **Inventory ID** matches the intended player's Inventory Identifier ID, or **Currency Owner** is assigned directly;
- the balance view and the Shop total-price view are separate when both are visible;
- Health Potion's `BuyPrice` is a `CurrencyAmounts` value containing Gold;
- the Shop's **Buy Attribute Name** matches `BuyPrice` exactly; and
- the Currency definition, Item price, player Currency Owner, Shop, and UI all reference Gold from the selected database.

## Verify in Play Mode

1. Enter Play Mode and record the Gold amount on the player's Currency Owner.
2. Open the panel containing the Currency Owner Monitor and confirm that it shows the same amount.
3. Open the Shop and select Health Potion. Confirm that the price view shows its `BuyPrice` in Gold, while the balance view still shows the amount the player owns.
4. Change the purchase quantity and confirm that the Shop's total price changes for that quantity.
5. Buy Health Potion and confirm that the balance decreases by the displayed total and refreshes immediately.
6. Try the purchase without enough Gold and confirm that the transaction does not change the displayed balance.

## Troubleshooting

- **Create is disabled:** Check **Parent Transform**. It must be a Rect Transform with a Display Panel Manager on an ancestor.
- **The view is empty:** Check that the Multi Currency View maps Gold to a Currency View and that the Currency View has a valid Text reference. Then check that a monitor or owning menu supplies the amount.
- **The balance is zero or belongs to the wrong player:** Check that **Inventory ID** matches the player's Inventory Identifier ID, or assign the intended **Currency Owner** directly. An **Inventory ID** of `0` does not perform an ID lookup.
- **The balance changes in data but not on screen:** Check that the Currency Owner Monitor references the intended Multi Currency View and that both components remain active. The monitor listens for Currency Owner updates and redraws the view.
- **The Shop price is missing or zero:** Check that `BuyPrice` exists as a `CurrencyAmounts` Item Definition attribute, contains Gold, and matches the Shop's **Buy Attribute Name** exactly.
- **The price view shows the player's balance:** Check whether a Currency Owner Monitor was added to the price view. Remove that monitor and let the Shop Menu draw the total price instead.
- **The amount is visible but the Gold icon is missing:** Check Gold's Icon and the Currency View's Image reference.
- **Gold disappears when its amount reaches zero:** Check **Hide If Zero** on the Currency View and disable it when zero should remain visible.

## Related pages

- [UI Designer workflow](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/)
- [Create and configure Gold](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/currency/)
- [Shop UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/shop/)
- [Multi Currency View runtime components](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/multi-currency-view/)
- [Shop Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/shop-menu/)
- [Currency and Currency Owners](https://opsive.com/support/documentation/ultimate-inventory-system/currency/)
- [Shops and transactions](https://opsive.com/support/documentation/ultimate-inventory-system/currency/shop/)
- [Common price attributes](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/common-attribute-types/)
- [Define Item attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/)

---

<a id="page-ultimate-inventory-system-editor-window-ui-designer-inventory-monitor"></a>

# Inventory Monitor

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/inventory-monitor/)

Use an Inventory Monitor to show temporary Item View notifications when Items are added to an Inventory. It is player feedback only: it does not add, remove, or move the Items that it displays.

The standard example monitors **Bag** so collecting Health Potion or Iron Sword produces a notification, while moving Iron Sword from Bag to **Equipment** does not look like a new pickup.

## Before you begin

Confirm that:

- the intended Inventory System Database is selected in **Main Manager > Setup**;
- UI Designer Canvas Managers and a duplicated schema have been created;
- **Spawn In Scene** has created the starting UI;
- the player has an Inventory Identifier beside the Inventory;
- Bag and Equipment have stable Item Collection names or IDs; and
- Health Potion, Iron Sword, and Fire Wand have the Icon and other values required by the notification Item View.

Test Inventory additions independently of the monitor first. A notification cannot appear for an Item that was rejected before reaching the Inventory.

## Create the Inventory Monitor

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer** and select **Inventory Monitor**.
2. Create the Inventory Monitor from the duplicated project schema.
3. Select the generated Inventory Monitor in the scene hierarchy.
4. Set **Inventory Identifier ID** to the ID used by the player Inventory.
5. Choose **Bag** in the monitored Item Collections and exclude Equipment.
6. Keep the schema-provided Item View presentation until the monitor resolves the correct Inventory and collection changes.
7. Position the generated notification area inside the canvas safe area, away from menus and controls that must remain interactive.
8. Add Health Potion to Bag in Play Mode and confirm that one notification appears.

UI Designer creates the Inventory Monitor component and its schema presentation. Most project-specific work happens on the generated component and Item View prefab: choosing the Inventory, collections, grouping behavior, placement, and visual content.

![A runtime Inventory Monitor showing temporary Item-added notifications for collected Items.](https://opsive.com/wp-content/uploads/2020/11/InventoryMonitor.png?v=54bc755866a7)

## Choose what should create a notification

Monitor only the collections that represent the player-facing acquisition event.

| Inventory change | Recommended result | Configuration check |
| --- | --- | --- |
| Add Health Potion from a world pickup to Bag | Show the Item and added amount | Bag is monitored and the addition retains its origin information. |
| Add Iron Sword from a Shop or pickup to Bag | Show a Weapon notification | Weapon resolves a valid monitor Item View. |
| Move Iron Sword from Bag to Equipment | Do not present it as newly acquired | Equipment is excluded and the same-Inventory move keeps its origin ItemInfo. |
| Load existing Bag contents | Usually suppress acquisition popups | Temporarily mute the monitor during bulk restoration when the load workflow would otherwise emit additions. |

ItemInfo can preserve the source collection or stack for an addition. That origin lets the Inventory and monitor distinguish an external acquisition from a move between collections in the same Inventory.

## Combine matching additions when useful

Enable the monitor's option to combine similar Items within one active notification when several matching additions should read as one result. For example, adding three matching Health Potion Items in quick succession can display one Health Potion view with the combined amount.

Keep additions separate when order or source matters. Iron Sword and Fire Wand should remain distinct even though both use Weapon, because they are different Item Definitions.

Test grouping with additions separated by both short and long intervals. The result should match the notification lifetime and animation used by the selected schema prefab.

## Customize the notification Item View

Start with a compact Item View containing:

- **Icon Item View** for the Item's `Icon`;
- **Name Item View** when the Icon alone is ambiguous; and
- **Amount Item View** when matching additions can be combined or stacked.

Edit the project-owned monitor Item View prefab when every notification should change. Keep text readable for Health Potion, Iron Sword, and Fire Wand, and verify that a large amount does not overlap the Icon.

The monitor is not an Inventory Grid. Do not add selection, Item Actions, or drag-and-drop unless the project intentionally turns the notification into an interactive feature with its own tested input behavior.

## Temporarily mute the monitor

Disable the Inventory Monitor GameObject when no notifications should be processed. Runtime logic can also use the Inventory Monitor listen Boolean event to stop and resume listening without replacing the component.

Mute only for a deliberate interval, such as loading an existing Inventory. Re-enable the monitor before new pickups resume, then verify that it does not replay additions that occurred while listening was disabled.

## Support more than one player

Each local player should have a unique Inventory Identifier ID, and each monitor or canvas should use the matching ID. Duplicate IDs can cause one monitor to resolve the wrong player Inventory or show the same pickup in more than one UI.

Keep each player's notification area inside that player's canvas or viewport and test simultaneous additions.

## Editor checkpoints

Before entering Play Mode, confirm that:

- the generated Inventory Monitor belongs to the project or duplicated schema rather than package assets;
- **Inventory Identifier ID** matches the intended player Inventory;
- Bag is monitored and Equipment is excluded for the acquisition-only workflow;
- the notification Item View can resolve Consumable and Weapon Items;
- Health Potion, Iron Sword, and Fire Wand have valid Icons;
- the grouping choice matches the intended notification behavior;
- the notification area and its largest expected message fit inside the canvas;
- only one active monitor targets this Inventory and collection combination; and
- any load or bulk-add workflow deliberately mutes and restores the monitor when needed.

## Verify in Play Mode

1. Add one Health Potion from a pickup to Bag and confirm that one notification shows its Icon, name, and amount.
2. Add several matching Health Potion Items within the grouping window and confirm that they combine or remain separate according to the configured option.
3. Add Iron Sword and Fire Wand and confirm that each uses its own Item View content.
4. Move Iron Sword from Bag to Equipment and confirm that the monitor does not present it as a new acquisition.
5. Remove an Item and confirm that an add-only monitor does not show a pickup notification.
6. Mute the monitor, add an Item, restore listening, and confirm that later additions appear without replaying the muted change.
7. At the smallest supported resolution, add enough Items to overlap notification lifetimes and confirm that the views remain readable and inside the canvas.
8. In a multi-player setup, add an Item to each player and confirm that only the matching monitor responds.

## Troubleshooting

- **The Inventory Monitor tab is unavailable:** Check that a database is selected, Canvas Managers were created, a schema was duplicated, and **Spawn In Scene** completed.
- **No notification appears:** Check that the monitor GameObject is active, listening is enabled, **Inventory Identifier ID** resolves the player, and Bag is monitored.
- **The wrong player's Items appear:** Check for duplicate or mismatched Inventory Identifier IDs on the players, canvases, and monitors.
- **Equipping Iron Sword shows a pickup notification:** Exclude Equipment and confirm that the move preserves origin ItemInfo instead of creating an unrelated external addition.
- **Matching Health Potion additions create too many views:** Enable or adjust the similar-Item combining behavior and retest within the active notification lifetime.
- **Different Items combine incorrectly:** Confirm that grouping compares the intended Item identity rather than only the shared Weapon or Consumable category.
- **The notification has no Icon or name:** Check the Item View modules, their UI references, and the selected definition's `Icon` and name.
- **Notifications overlap or leave the canvas:** Reposition the parent, adjust the project-owned view layout or lifetime, and retest the largest expected burst.
- **Notifications never resume after loading:** Re-enable the GameObject or restore the Inventory Monitor listening state at the end of the load workflow.
- **Every addition appears twice:** Check for duplicate active Inventory Monitor components targeting the same Inventory and collections.

## Related pages

- [UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/)
- [Item View](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view/)
- [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/inventory-grid/)
- [Equipment](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/equipment/)
- [Runtime Inventory Monitor](https://opsive.com/support/documentation/ultimate-inventory-system/ui/monitors/)
- [Item Collections](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/)
- [Item Pickups](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-pickups/)
- [Split-screen UI and Inventory IDs](https://opsive.com/support/documentation/ultimate-inventory-system/input/split-screen-co-op-ui/)
- [Inventory events](https://opsive.com/support/documentation/ultimate-inventory-system/events/)
- [Customize the generated UI](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/ui-customization/)

---

<a id="page-ultimate-inventory-system-editor-window-ui-designer-item-view"></a>

# Item View

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view/)

An Item View is the reusable visual placed inside an Inventory slot, Equipment slot, Shop row, or Item Description. Build it from small Item View Modules so Icon, name, amount, selection, and other values update whenever the displayed Item changes.

Use one simple shared view when Items need the same presentation. Add category-specific views only when Consumable and Weapon genuinely need different layouts or information.

## Before you begin

Confirm that:

- the intended Inventory System Database is selected in **Main Manager > Setup**;
- UI Designer Canvas Managers and a duplicated schema have been created;
- **Spawn In Scene** has created the starting UI;
- a Bag Inventory Grid or another Item View Slots Container exists for testing; and
- Health Potion, Iron Sword, and Fire Wand have the `Icon` and other attributes the view will read.

An Item View draws data and visual state. Its parent [Item View Slot](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-view-slot/) detects selection, clicks, restrictions, and drag-and-drop.

## Create an Item View

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer** and select **Item View**.
2. In **Create**, choose the schema template closest to the target context, such as a compact grid view or a wider list or Shop view.
3. Create the Item View from the duplicated project schema rather than editing a package-owned template.
4. In **Edit**, select the created Item View that should be changed.
5. Add or remove entries in the Item View Modules section. Available Item View Module types appear in the module dropdown.
6. Configure each module's target UI element, such as the Image used by Icon Item View or the text component used by Name Item View.
7. Save the result as the project prefab used by the intended Category Item View Set.

Start with the smallest useful module set. For a Bag grid, Icon Item View, Amount Item View, and Select Image View are usually enough to prove the display and selection flow before adding more decoration.

## Choose modules by outcome

| Needed result | Item View Module | Standard example |
| --- | --- | --- |
| Show the Item image | **Icon Item View** | Read Health Potion or Iron Sword `Icon` into an Image. |
| Show the Item name | **Name Item View** | Label a List or Shop row as Health Potion. |
| Show a stack count | **Amount Item View** | Display the number of Health Potion Items in one stack. |
| Make selection visible | **Select Image View** | Change the slot image when keyboard, controller, or pointer selection moves to Iron Sword. |
| Show whether the Item is equipped | **Equipped Select Item View** | Change a visual when Iron Sword belongs to Equipment instead of Bag. |
| Show an integer attribute | **Int Attribute Item View** | Display an integer `Attack` value for Iron Sword or Fire Wand. |
| Change child objects by owning collection | **Item Slots Item View** | Enable an equipped marker only while the Item belongs to Equipment. |
| Draw a multi-cell Item correctly | **Item Shape Item View** | Scale Iron Sword across its Item Shape Grid cells. |
| Present a use cooldown | **Cooldown Item View** | Show the cooldown used by a compatible Item Action setup. |

Name Item View writes the Item name. Icon Item View reads the Item's `Icon` attribute. If an attribute name or value is missing, the module cannot display it even when the prefab wiring is correct.

## Use Item Views in different contexts

### Inventory slot

A compact Item View should keep the Icon and selection state readable at the smallest supported slot size. Add the amount only when the Item can stack.

![A gameplay Item View presenting one Item inside a compact Inventory slot.](https://opsive.com/wp-content/uploads/2020/05/GameplayItemBox.png?v=069889afa97d)

### Category-specific grid view

A Category Item View Set can use a distinct prefab for a category that needs a different silhouette or overlay. Keep the interaction area on the parent Item View Slot rather than recreating click behavior inside the visual prefab.

![A Head Gear Item View displayed with its category-specific presentation in an Inventory Grid.](https://opsive.com/wp-content/uploads/2020/11/HeadGearItemViewGrid.png?v=4a42226fe4e8)

### Shop view

A wider Shop view can combine Icon, name, and contextual price presentation. Shop-specific code may update a processed price after the base Item View is drawn, so do not assume the Item alone contains every value displayed by the row.

![A Sword Item View displayed as a wider row in the Shop interface.](https://opsive.com/wp-content/uploads/2020/11/SwordItemViewShop.png?v=ba0a56830c87)

## Map views by Item Category

The Item View Drawer uses a Category Item View Set to choose the prefab for each Item.

1. Create the mapping asset with **Create > Ultimate Inventory System > UI > Category Item View Set** if the project does not already have one.
2. Map **All** to the common Item View when every Item can share the same fallback presentation.
3. Add a **Weapon** mapping only when Iron Sword and Fire Wand need a more specific view.
4. Add a **Consumable** mapping only when Health Potion needs a distinct view.
5. Assign the Category Item View Set to the Item View Drawer used by Bag, Equipment, or the intended menu.
6. Enable **Use View Slots** when the drawer draws into generated Item View Slots.
7. Confirm that the drawer's **Content** and the Item View Slots Container's **Content** reference the same transform.

Category inheritance and mapping order affect which prefab resolves. Prefer the broadest mapping that gives the correct result, then add a narrower mapping only for a real visual difference.

## Decide where to make a change

| Intended scope | Edit | Result |
| --- | --- | --- |
| One visible instance in one scene | The generated scene or prefab instance | Other panels keep their current view. |
| Every use of one project view | The project-owned Item View prefab | Every drawer that resolves this prefab receives the change. |
| Future UI generated from the schema | The corresponding prefab in the duplicated schema | Later UI Designer output starts with the customized view. |

After editing a shared prefab, recheck every Inventory Grid, Equipment view, hotbar, Shop, and Crafting panel that uses it. A module that fits a Shop row may be clipped in a smaller grid slot.

## Editor checkpoints

Before entering Play Mode, confirm that:

- the edited prefab belongs to the project or duplicated schema rather than the package source;
- every Item View Module has its required Image, text, or child-object reference;
- the Bag view can resolve `Icon` for Health Potion, Iron Sword, and Fire Wand;
- the Category Item View Set has a valid common mapping and only the needed specific mappings;
- the intended Item View Drawer references that Category Item View Set;
- **Use View Slots** is enabled when the view is drawn inside generated slots;
- the drawer and Item View Slots Container use the same **Content** transform; and
- Item Shape Grid views retain their required Item Shape-specific modules.

## Verify in Play Mode

1. Open Bag and confirm that Health Potion, Iron Sword, and Fire Wand use the intended prefabs and Icons.
2. Change selection with each supported input method and confirm that Select Image View shows one clear selected state.
3. Add more than one Health Potion and confirm that Amount Item View updates without showing a stale amount on an empty slot.
4. If Weapon has a specific mapping, confirm that Iron Sword and Fire Wand use it while Health Potion uses the common or Consumable view.
5. Equip Iron Sword and confirm that any Equipped Select Item View or Item Slots Item View state updates when the owning collection changes.
6. Select Items in Bag, Equipment, and Shop and confirm that the same shared prefab remains readable in every context that consumes it.
7. Remove or replace an Item and confirm that old Icon, name, amount, and selection values are cleared before the slot is reused.
8. If an Item Shape Grid is used, drag Iron Sword and confirm that its foreground view covers the intended cells without intercepting the background slot interaction.

## Troubleshooting

- **An Item View Module is missing from the dropdown:** Fix compilation errors, then check that the component inherits from Item View Module or the base View Module type.
- **Slots exist but no Item View appears:** Check the Item View Drawer, Category Item View Set, **Use View Slots**, and matching **Content** transforms.
- **An Item uses the wrong prefab:** Check its direct Item Category, inherited categories, mapping order, and the Category Item View Set assigned to this drawer.
- **The Icon is blank:** Check that the Item resolves an `Icon` attribute and that Icon Item View references the intended Image.
- **The name, amount, or attribute does not update:** Check the corresponding module's UI reference and confirm that the source value exists with the expected type.
- **Old values remain after an Item is removed:** Check every custom module's clear behavior and confirm that the slot is redrawn when its Item changes.
- **Selection changes but has no visible feedback:** Check Select Image View and confirm that the Item View is inside the Item View Slot receiving selection events.
- **The equipped marker never changes:** Check Equipped Select Item View or Item Slots Item View, the bound Inventory, and the Item's owning Item Collection.
- **A view is clipped in one menu:** Check that prefab's Rect Transform and module layout at the consuming slot size; use a separate context-specific prefab when necessary.
- **An Item Shape is drawn as one normal cell:** Use an Item Shape-compatible prefab with the required Item Shape Item View modules.

## Custom Item View Modules

Create a custom module only when the existing focused modules cannot express the visual. A custom component must inherit from the Item View Module base class, or from the more general View Module base class when that behavior is appropriate. After scripts compile, the UI Designer discovers eligible module types for its dropdown.

Keep one responsibility per module and implement both the value update and clear behavior. This prevents a reused slot from retaining data from the previous Item.

## Related pages

- [UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/)
- [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/inventory-grid/)
- [Equipment](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/equipment/)
- [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view-slots-container/)
- [Item Description](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-description/)
- [Attribute View](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/attribute-view/)
- [Runtime Item View](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/item-view/)
- [Views and Category Item View Sets](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/)
- [Item View Slot](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-view-slot/)
- [Item Shape Grid](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-shape-grid/)
- [Customize the generated UI](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/ui-customization/)

---

<a id="page-ultimate-inventory-system-editor-window-ui-designer-attribute-view"></a>

# Attribute View

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/attribute-view/)

An Attribute View presents one attribute value in the UI. Use it inside an Item Description or comparison panel when the player needs a clear label and value, such as Iron Sword Attack or its current Durability.

Attribute Views are reusable visual prefabs. The attribute name, value type, and source Item must be supplied by the surrounding view or binding.

## Before you begin

Confirm that:

- the intended Inventory System Database is selected in **Main Manager > Setup**;
- UI Designer Canvas Managers and a duplicated schema have been created;
- **Spawn In Scene** has created the starting UI;
- an Item Description or other parent view exists for testing; and
- the source attributes have been declared and assigned values.

For the standard example, declare `Attack` as an integer Item Definition attribute on Weapon and `Durability` as an integer Item attribute on Weapon. Set definition values for Iron Sword and Fire Wand, then set each definition's starting Durability through its Default Item.

## Create an Attribute View

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer** and select **Attribute View**.
2. In **Create**, choose the template closest to the intended label-and-value layout.
3. Create the Attribute View from the duplicated project schema.
4. In **Edit**, select the created Attribute View.
5. Add or remove entries in the Attribute View Modules section. Eligible module types appear in the module dropdown.
6. Configure each module's text, image, or other UI reference.
7. Set the formatting required by the source type, such as the decimal format for a float value.
8. Save the project-owned prefab and assign it to the Attribute View Set or parent view that will supply the attribute.

Keep one row focused on one value. A compact `Attack 12` view is easier to reuse than a single component that also tries to draw the Item name, Icon, price, and selection state.

## Choose a module for the value type

| Value to display | Attribute View Module pattern | Standard use |
| --- | --- | --- |
| Whole number | **Int Value Attribute Box** | Iron Sword `Attack` or current `Durability` |
| Decimal number | **Float Value Attribute Box** | A project-defined multiplier or duration, with a controlled decimal format |
| Text | **String Attribute Box** | A short string attribute when it belongs in an attribute row |
| Name and arbitrary value | **Name Value Attribute Box** | A general labeled row for a supported value type |

The UI Designer templates may also expose the generic **Value Attribute View** and **Float Value Attribute View** patterns. Use the exact option shown by the installed schema, then confirm that its expected source type matches the database attribute.

Do not choose a module only because its output looks similar. A float module cannot correctly read an integer declaration without an intentional conversion, and a simple text module is not a substitute for dedicated Shop Currency views.

## Use Attribute Views in an Item Description

1. Create the reusable Attribute View prefabs needed by the project, such as `Attack Value` and `Durability Value`.
2. In the Item Description, add or configure a **Category Attribute View Set Item View Module**.
3. Map Weapon to the Attribute Views for `Attack` and `Durability`.
4. Map Consumable only to values that apply to Health Potion, or leave the extra attribute area empty.
5. Confirm that the attribute names use the same spelling and capitalization as their declarations.
6. Select Health Potion, Iron Sword, and Fire Wand and verify that the parent view supplies the correct attribute to each row.

Health Potion should not show empty Weapon rows. Iron Sword and Fire Wand should use the same Attribute View prefabs while displaying the values from their own definitions and runtime Items.

## Choose the presentation style

### Comparison-style value

Use a comparison treatment only when the surrounding UI supplies a meaningful reference value. For example, a weapon-selection panel can compare Fire Wand Attack with the currently equipped Iron Sword. Keep the base value readable even when no comparison is available.

![A comparison-style Attribute View displaying a value with a distinct comparison treatment.](https://opsive.com/wp-content/uploads/2020/11/ComparAttributeView.png?v=ae6d130687c6)

### Themed value

The legacy healing example shows how a label, icon, and value can share one reusable row. Use this pattern only when the project defines a compatible source attribute; the standard Health Potion sample does not require a separate healing field.

![A themed Attribute View presenting a healing value with its label and visual treatment.](https://opsive.com/wp-content/uploads/2020/11/HealAttributeView.png?v=69a36d1a9b9f)

## Match scope to runtime behavior

`Attack` belongs on the Item Definition when every Iron Sword Item shares the same base value. `Durability` belongs on the Item when each runtime weapon can change independently. The Attribute View reads the resolved value; it does not decide where that value should live.

When a runtime value changes, refresh or redraw the supplying Item Description and confirm that the Attribute View receives the updated Item value. If two weapons must retain different Durability values, Weapon must be mutable and unique and the declaration must remain in the Item collection.

## Decide where to customize

Edit the generated instance when one panel needs a unique row. Edit the project-owned Attribute View prefab when every Item Description using that prefab should change. Edit the corresponding prefab in the duplicated schema when future UI Designer output should start with the customization.

After changing a shared prefab, recheck every Item Description, comparison panel, and tooltip that consumes it. Long labels and large numeric values must still fit at the smallest supported size.

## Editor checkpoints

Before entering Play Mode, confirm that:

- the Attribute View prefab belongs to the project or duplicated schema rather than package assets;
- every Attribute View Module has its required UI references;
- the selected module accepts the declared attribute type;
- numeric format settings show the intended precision without hiding meaningful values;
- `Attack` is an integer Item Definition attribute on Weapon;
- `Durability` is an integer Item attribute on Weapon;
- Iron Sword and Fire Wand have intentional source values;
- the Category Attribute View Set maps Weapon to the Attack and Durability views without giving those rows to Consumable; and
- the parent Item Description supplies the selected Item and redraws the attribute area.

## Verify in Play Mode

1. Open Bag and select Health Potion. Confirm that no empty Attack or Durability row is shown.
2. Select Iron Sword and confirm that its Attack and current Durability appear with the intended labels and formatting.
3. Select Fire Wand and confirm that its own values replace Iron Sword without stale text.
4. Change one Iron Sword Item's Durability, refresh or reselect it, and confirm that the Attribute View shows the changed runtime value.
5. Confirm that another Iron Sword or Fire Wand keeps its own Durability value.
6. If a comparison view is used, change the comparison target and confirm that both the base value and comparison treatment update.
7. Select an empty slot and confirm that the parent view clears or hides all attribute rows according to its intended behavior.
8. Test the longest label and largest expected value at the smallest supported resolution and confirm that neither is clipped.

## Troubleshooting

- **The Attribute View tab is unavailable:** Check that a database is selected, Canvas Managers were created, a schema was duplicated, and **Spawn In Scene** completed.
- **An Attribute View Module is missing from the dropdown:** Fix compilation errors, then confirm that the component inherits from Attribute View Module or the base View Module type.
- **The row is blank:** Check the exact attribute name, declaration scope, source Item value, and module UI references.
- **The wrong Item's value appears:** Check the parent Item Description or comparison binding and confirm that it redraws when selection changes.
- **Health Potion shows Weapon fields:** Check the Category Attribute View Set mapping and confirm that Consumable does not inherit from Weapon.
- **Iron Sword has no Durability row:** Check that `Durability` is declared on Weapon's Item collection, initialized on the Default Item, and requested with an integer-compatible view.
- **Changing one weapon changes every copy:** Check that Weapon is mutable and unique and that `Durability` remains an Item attribute.
- **A float has too many or too few decimal places:** Check the Float Value module's format setting and test zero, negative, and large values.
- **A previous value remains after selection changes:** Check the clear behavior of custom modules and confirm that the parent view redraws or removes unused rows.
- **A Currency value is unreadable:** Use the dedicated Shop or Currency view rather than a generic Attribute View string representation.

## Custom Attribute View Modules

Create a custom module only when the built-in value modules cannot express the visual. The component must inherit from the Attribute View Module base class, or the more general View Module base class when appropriate. After the scripts compile, eligible module types appear in the UI Designer dropdown.

Keep value updates, formatting, and clear behavior deterministic so a reused Attribute View never retains the previous Item's data.

## Related pages

- [UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/)
- [Item Description](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-description/)
- [Item View](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view/)
- [Attribute editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/attributes/)
- [Item Category](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-category/)
- [Item Definition](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-definition/)
- [Runtime Attribute Views](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/attribute-views/)
- [Runtime Item Description](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-description/)
- [Views](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/)
- [Common attribute types](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/common-attribute-types/)
- [Define attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/)
- [Customize the generated UI](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/ui-customization/)

---

<a id="page-ultimate-inventory-system-editor-window-ui-designer-item-view-slots-container"></a>

# Item View Slots Container

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view-slots-container/)

Item View Slots Container options provide the shared display and interaction layer used by Inventory Grid, Item Hotbar, and the Equipment Item Slot Collection View. Configure them after the panel shows the correct Items to add category-based Item Views, Item Actions, Item Description, and movement between slots.

This workflow connects a **Bag** Inventory Grid and **Equipment** view so Health Potion can show Consume, Iron Sword can show Equip, and only compatible Items can move into the Weapon slot.

## Before you begin

Confirm that:

- UI Designer Canvas Managers and a duplicated schema have been created;
- **Spawn In Scene** has created the canvas and manager objects;
- the player Inventory has **Bag** and **Equipment** Item Collections;
- a Bag Inventory Grid and Equipment Item Slot Collection View display the correct source data;
- Equipment uses an Item Slot Set whose Weapon slot accepts Iron Sword and rejects Health Potion; and
- the project has the Item View, Item Action, and Item Description assets required by the interactions being added.

Prove the Bag and Equipment data bindings first. Adding several interaction bindings at once makes an empty or misbound container harder to diagnose.

## Configure the container and Item View Drawer

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer** and select the tab for the generated container, such as **Inventory Grid** or **Equipment**.
2. In **Edit**, use **Find Available Targets in Scene** or drag the intended container into the target field.
3. Set **Container Name** to a stable name such as `Bag` or `Equipment`. Drop conditions can use this name to distinguish source and destination containers.
4. Confirm that **Content** references the transform whose children are the Item View Slots.
5. Add or select the **Item View Drawer** and enable **Use View Slots**.
6. Set the drawer's **Content** to the same transform used by the Item View Slots Container.
7. Assign a Category Item View Set that resolves Consumable and Weapon to the intended Item View prefabs.
8. Add an Item View Slots Container Panel Binding when the panel should initialize and refresh as it opens. Use its panel-owner Inventory option when the Inventory belongs to the active panel owner.

At this checkpoint, Health Potion, Iron Sword, and Fire Wand should draw through the intended Category Item View mappings, and selection should remain on the parent Item View Slots rather than on duplicate controls inside the Item Views.

![The Item View Drawer configuration showing its Category Item View Set, view-slot mode, and Content reference.](https://opsive.com/wp-content/uploads/2020/11/Item-View-Drawer.png?v=502d84f67e88)

## Choose the important container settings

| Setting | Use it when | Check |
| --- | --- | --- |
| **Container Name** | Drop rules or other systems must identify this container | Bag and Equipment have distinct stable names. |
| **Slot Cursor** | The selected slot needs a shared cursor visual | The cursor follows selection for every supported input method. |
| **Item View Drawer** | Items need category-based visual prefabs | The drawer has a Category Item View Set and matching Content. |
| **Swap Item View On Assign** | A newly assigned Item may resolve to a different category view | Switching from Health Potion to Iron Sword replaces the prefab when required. |
| **Content** | The container must find its Item View Slots | It points to their immediate parent transform. |

The container can be bound directly to an Inventory or collection, or receive its Inventory through a panel binding. Use one clear source and verify it before configuring actions or movement.

## Add category-based Item Actions

Use an **Item View Slots Container Category Item Action Set Binding** when available actions should be combined from the selected Item's categories. For the standard example, map Consume to Consumable and Equip to Equippable or Weapon.

1. Add the category action-set binding beside the Bag container.
2. Assign the Category Item Action Set containing the project's Consumable and Equippable or Weapon Item Action Sets.
3. Confirm the **Item User**. When the container is bound to an Inventory, the binding can normally find an Item User beside that Inventory.
4. Assign an **Action Panel** when clicking should open a list of valid actions.
5. Enable **Use Item On Click** only when clicking should invoke the configured action directly.
6. Use **Use Item Action Index** only when the interface intentionally invokes a specific action rather than presenting the available list.
7. Enable **Disable Action On Empty Slots** so an empty slot cannot invoke an Item Action.
8. Set **Max Number Of Actions** high enough for the largest valid action list shown by this container.

![The Category Item Action Set binding showing its Item User, Action Panel, click behavior, and category action-set fields.](https://opsive.com/wp-content/uploads/2020/11/Item-View-Slot-Item-Action-Set-Binding.png?v=5081d9866b5f)

Use an **Item View Slots Container Item Action Binding** when the container needs one fixed Item Action configuration instead of matching several category-based sets.

![The single Item Action binding showing its selected container action configuration.](https://opsive.com/wp-content/uploads/2020/11/Item-View-Slots-Container-Item-Action-Binding.png?v=2dfaf81a8d3d)

Direct click behavior can invoke an action immediately. Prefer an Action Panel when the selected Item can have several valid choices or when an irreversible action needs an explicit user choice.

## Connect Item Description

1. Create or select the Item Description that should show the current Item.
2. Add an **Item View Slots Container Description Binding** beside Bag or Equipment.
3. Assign the intended Item Description and configure whether selection or click should update it.
4. Repeat the binding on another container only when both should drive the same description panel.
5. Select each container in the editor and confirm that the binding points to the intended local container and description.

In Play Mode, moving selection from Health Potion to Iron Sword should update Icon, Description, and any configured Attribute Views without changing the Items themselves.

## Add pointer drag-and-drop

1. Confirm that the canvas has an **Item View Slots Cursor Manager**. It tracks the source Item and displays the moving Item View.
2. Add an **Item View Drop Handler** and assign an Item View Slot Drop Action Set.
3. If a project action set does not exist, create one with **Create > Ultimate Inventory System > UI > Item View Slot Drop Action Set**.
4. Add conditions that confirm the destination can accept the source Item, then add the intended give, exchange, or smart-exchange action.
5. Add an **Item View Slot Drag Handler** for pointer drag-and-drop.
6. Confirm that Bag and Equipment are both registered with the movement components used by the panel.

For Bag-to-Equipment movement, the destination condition should respect the Equipment Item Slot Set and Item View Slot Restriction. Iron Sword may move into the Weapon slot; Health Potion must stay in Bag when the destination rejects it.

## Add keyboard or controller movement

1. Add an **Item View Slot Move Cursor** to the container.
2. Add or map a **Move Item Action** that starts the move from the selected slot.
3. Assign an optional Move Display Panel when the player should be able to cancel with the panel's back input.
4. Add the Item Action binding components to **Unbind While Moving** so choosing the destination does not also invoke the selected Item's normal action.
5. Confirm that the same Item View Drop Handler and Item View Slot Drop Action Set validate the destination.

Both movement paths should produce the same Inventory result. Pointer and controller input differ only in how the source and destination slots are selected.

## Editor checkpoints

Before entering Play Mode, confirm that:

- Bag and Equipment have distinct **Container Name** values.
- Each container's **Content** is the parent of its Item View Slots.
- Each Item View Drawer uses the same **Content** transform as its container and has **Use View Slots** enabled.
- The Category Item View Set resolves Consumable and Weapon.
- The panel binding resolves the intended player Inventory and refreshes the container when the panel opens.
- The category action-set binding has the correct Item User, Category Item Action Set, click behavior, and empty-slot protection.
- The Description binding references the intended Item Description.
- The Item View Slots Cursor Manager, Item View Drop Handler, and drop action set are assigned for movement.
- Pointer movement has an Item View Slot Drag Handler.
- Keyboard or controller movement has an Item View Slot Move Cursor and the action bindings appear under **Unbind While Moving**.
- The Equipment Weapon slot uses the same restrictions as its runtime Item Slot Collection.

## Verify in Play Mode

1. Open Bag and confirm that Health Potion, Iron Sword, and Fire Wand use the intended Item Views.
2. Select Health Potion and confirm that Item Description updates and only the intended Consumable actions are available.
3. Select Iron Sword and confirm that the description and Equip action replace the Health Potion state.
4. Select an empty slot and confirm that no stale description or Item Action can be invoked.
5. Drag Iron Sword from Bag to the Equipment Weapon slot and confirm that both containers redraw.
6. Try to drag Health Potion to the same destination and confirm that the move is rejected without removing it from Bag.
7. Repeat the valid and invalid moves with the Move Item Action using keyboard or controller input.
8. Close and reopen the panel and confirm that the panel binding refreshes Bag and Equipment from the current Inventory state.

## Troubleshooting

- **Slots exist but Item Views do not appear:** Check the Category Item View Set, **Use View Slots**, and matching container and drawer **Content** transforms.
- **The wrong Item View prefab appears:** Check the Item's categories, Category Item View Set mappings, and category inheritance order.
- **The action list is empty:** Check the selected Item's categories, Item Action Sets inside the Category Item Action Set, binding reference, and Item User.
- **Clicking invokes the wrong action immediately:** Check **Use Item On Click**, **Use Item Action Index**, and whether an Action Panel should be used instead.
- **An empty slot still triggers an action:** Enable **Disable Action On Empty Slots** and confirm that the binding targets this container.
- **Item Description does not update:** Check the Description binding, its target Item Description, and whether it responds to selection or click.
- **Drag-and-drop does nothing:** Check the Item View Slots Cursor Manager, Item View Drop Handler, Item View Slot Drag Handler, and assigned drop action set.
- **Iron Sword cannot move into Equipment:** Check the destination Item Slot Set, Item View Slot Restriction, drop condition, and Equipment collection binding.
- **Health Potion enters the Weapon slot:** Check that both the runtime Equipment slot and visible Item View Slot restrict the destination to Weapon.
- **Controller movement also invokes Equip or Consume:** Add the action bindings to **Unbind While Moving** on the Item View Slot Move Cursor.
- **A panel shows stale Items after reopening:** Check the Item View Slots Container Panel Binding and the Inventory supplied by the panel owner.
- **A drop goes to the wrong container:** Check **Container Name** and any source or destination name conditions in the drop action set.

## Related pages

- [UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/)
- [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/inventory-grid/)
- [Equipment](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/equipment/)
- [Item Hotbar](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-hotbar/)
- [Item View](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view/)
- [Item Description](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-description/)
- [Runtime Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/)
- [Item View Slot](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-view-slot/)
- [Move Items with drag and drop](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/move-items-drag-drop/)
- [Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/)
- [Built-in Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/built-in-item-actions/)
- [Display Panel Manager](https://opsive.com/support/documentation/ultimate-inventory-system/ui/display-panel-manager/)
- [Customize the generated UI](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/ui-customization/)

---

<a id="page-ultimate-inventory-system-editor-window-import-export"></a>

# Import & Export

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/import-export/)

Use Import/Export to make supported database content readable in a spreadsheet, add a large set of records, or apply the same text-value change to many records. The default **CSV Import Export Module** transfers only part of an existing Inventory System Database; it does not create a database and is not a backup system.

> **Important:** Import changes and saves the selected database, cannot be undone, and can replace supported values. Commit the database folder to version control or make a complete project backup before importing.

## Before you begin

1. Open **Tools > Opsive > Ultimate Inventory System > Main Manager**.
2. Select the intended Inventory System Database in the **Database** field.
3. Open **Import/Export**.
4. Leave **Default CSV Import Export Module** assigned for the standard CSV layout.

To create a reusable project configuration, use **Assets > Create > Ultimate Inventory System > Editor > Import Export > CSV Export Module** and assign the new asset here. The asset stores the module's table keys and transfer configuration; creating it does not export or import anything by itself.
5. If you need to change column keys or module settings, duplicate the module into a project-owned folder and assign the duplicate. The module is a Scriptable Object, so edits are saved to the asset; a package update can replace changes made to the supplied module.

![The UIS Main Manager Import/Export panel with DemoInventoryDatabase selected, the Default CSV Import Export Module, table settings, and Import and Export buttons.](https://opsive.com/wp-content/uploads/2021/10/Import-Export-Manager.png?v=0f86d4151767)

For the safest first transfer, [create a test database](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/new-database/) or work on a version-control branch. Import there, inspect the result, and only then repeat the same process with the project database.

## What the CSV can transfer

The default module writes five tables into one `.csv` file:

| Table | Supported data |
| --- | --- |
| Item Category | ID, name, abstract/mutable/unique choices, parents, attribute declarations, and supported attribute values |
| Item Definition | ID, name, category, parent definition, and supported Definition and Default Item attribute values |
| Crafting Category | ID, name, abstract choice, parents, and recipe type |
| Crafting Recipe | ID, name, category, standard item/category/definition ingredient lists, and default outputs |
| Currency | ID, name, exchange rate, parent, maximum amount, overflow currency, and fraction currency |

Unity Object values, custom recipe data, and attribute values that cannot be converted to and from text are not reliable CSV transfers. Simple values such as `int`, `float`, and `string` are the best fit. Keep the real database and its related assets in the project backup even when the CSV appears complete.

### Item Category table

![An exported Item Category CSV table showing IDs, names, abstract, mutable and unique choices, parents, an attribute list, and attribute value columns.](https://opsive.com/wp-content/uploads/2021/10/Item-Category-Import-1024x99.png)

### Item Definition table

![An exported Item Definition CSV table showing Potion and Wood records with their categories, parent definitions, attribute lists, and attribute value columns.](https://opsive.com/wp-content/uploads/2021/10/Item-Definition-Import-1024x227.png)

### Crafting Category table

![An exported Crafting Category CSV table showing IDs, names, abstract choices, parents, and recipe type names.](https://opsive.com/wp-content/uploads/2021/10/Crafting-Category-Import.png?v=c0e97991349d)

### Crafting Recipe table

![An exported Crafting Recipe CSV table showing Big Potion and Potion recipes with categories, definition ingredients, and outputs.](https://opsive.com/wp-content/uploads/2021/10/Crafting-Recipe-import.png?v=f555fdef6dfc)

### Currency table

![An exported Currency CSV table showing Bronze, Silver, and Gold with exchange rates, parents, maximum amounts, overflow currencies, and fraction currencies.](https://opsive.com/wp-content/uploads/2021/10/Currency-import.png?v=806caa3da890)

## Export the database

1. Confirm the intended database and module in **Import/Export**.
2. Select **Export**.
3. Choose a location and save the `.csv` file.
4. Open the file in a spreadsheet editor and confirm that the required table sections and records are present before editing it.

Use the exported file as the template for an import. Keep each table's first ID column and its `NAME` column. The importer recognizes tables from keys such as `ITEM CATEGORY`, `ITEM DEFINITION`, `CRAFTING CATEGORY`, `CRAFTING RECIPE`, and `CURRENCY`; those keys must match the assigned module. A new Item Definition or Crafting Recipe also needs its `CATEGORY` column so it can be created in the correct category.

When editing a CSV, preserve names unless you intend to create another object. Other supported columns can be omitted when updating existing objects, but leaving the exported structure intact makes missing dependencies and accidental column changes easier to spot.

## Import into a test database

1. Select the test database in the Main Manager.
2. Open **Import/Export** and assign the same module configuration that produced the CSV.
3. Select **Import**.
4. Read the **Importing Database info?** warning. Confirm **Yes** only after checking the database and backup.
5. Select the `.csv` file and wait for the import to finish.
6. Check the Console for **Import Complete** and for warnings about values, types, parents, categories, or other unresolved references.

Import first creates missing objects, then applies supported values and saves the database assets. It does not present a conflict picker.

## Understand matching and conflicts

The importer matches each object by its type and `NAME`, not by ID alone:

| CSV situation | Import result |
| --- | --- |
| The same type and name already exist | The existing object receives the supported CSV values. If its ID differs, the importer uses the requested ID when that ID is available. |
| The name does not exist | A new object is created. Changing a name in the CSV therefore creates another object rather than renaming the original. |
| The requested ID is already in use | The importer assigns an available unique ID instead. |
| A database object is absent from the CSV | The existing object remains; import never deletes records. |
| A parent, category, ingredient, or other referenced name cannot be resolved | The relationship or entry may be ignored. Inspect the Console and the imported object rather than assuming the row was applied completely. |

Because an existing name is updated without a per-record prompt, review duplicate names, IDs, and relationship columns before confirming the import. Do not use CSV import as a merge tool for two independently edited production databases without testing the exact file first.

## Verify the imported data

In the Main Manager, confirm that:

- expected records were created or updated, and no unintended near-duplicate names appeared;
- Item Categories retain their parent relationships and attribute declarations;
- Health Potion uses **Consumable**, while Iron Sword and Fire Wand use **Weapon**;
- imported attribute values show the intended type, variant, and source;
- Gold retains its intended parent and amount rules; and
- the sample recipe retains its Crafting Category, ingredients, amounts, and Health Potion output.

For data used at runtime, enter Play Mode and perform one focused check. For example, inspect Health Potion in the **Bag**, complete the sample recipe, or make a Gold shop transaction. Confirm that the runtime result uses the imported values; a clean CSV import message does not prove that every Unity reference or custom value survived.

## Troubleshooting

- **Import updates the wrong object:** Check the object's type and `NAME`. Matching is name-based within each data type; restore the backup, correct the CSV, and import again.
- **A renamed row creates a duplicate:** The importer treats the new name as a new object and does not delete the old one. Restore the backup or remove the unintended object in the appropriate editor after checking its relationships.
- **A relationship is missing after import:** Check that the referenced name is spelled exactly as it appears in the same database and that its table is included. Review the Console, correct the dependency, and repeat the import from a clean backup or test database.
- **An attribute value is unchanged or logs a conversion warning:** Check that the attribute exists in the expected collection and that its type can be converted from text. Apply Unity Object or unsupported custom values in the editor instead.
- **The importer cannot find a table:** Restore the exported header key, or assign the module whose configured keys match the CSV.
- **The result is difficult to compare:** Export the test database after import and compare its CSV with the intended file, then inspect the project asset changes in version control.

## Related pages

- [Main Manager and database editors](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/)
- [Item Categories](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-category/)
- [Item Definitions](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-definition/)
- [Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/attributes/)
- [Currencies](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/currency/)
- [Crafting Categories](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/crafting-category/)
- [Crafting Recipes](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/crafting-recipe/)

## Extend the transfer format

For a transfer that the supplied CSV module cannot represent, create a project-owned Scriptable Object that inherits `ImportExportModule`. Implement both operations for the exact data you support, and keep the same backup-first and test-database workflow.

```csharp
/// <summary>
/// The Import Export Module is a scriptable object used to import and export data from a database.
/// </summary>
public abstract class ImportExportModule : ScriptableObject
{
    /// <summary>
    /// Export the inventory system database.
    /// </summary>
    /// <param name="database">The database to export.</param>
    public abstract void Export(InventorySystemDatabase database);

    /// <summary>
    /// Import the inventory system database.
    /// </summary>
    /// <param name="database">The database to import.</param>
    public abstract void Import(InventorySystemDatabase database);
}
```

Use the released `CsvImportExportModule` as a reference for creating tables, resolving database objects, marking imported assets dirty, and saving the database.

---

<a id="page-ultimate-inventory-system-editor-window-editor-options-reference"></a>

# Editor Options by Feature

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/editor-options-reference/)

Ultimate Inventory System documents each customer-visible editor option with the data or workflow it changes. Use this page only to find the correct guide.

## Find the owning page

- [Editor Window](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/) covers manager selection, list search tokens, relationships, and safe deletion.
- [New Database](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/new-database/) covers New, Duplicate, Generate C# script, and Replace Database Objects.
- [Item Category](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-category/), [Item Definition](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-definition/), [Crafting Category](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/crafting-category/), [Crafting Recipe](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/crafting-recipe/), and [Currency](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/currency/) cover their respective row actions and relationships.
- [Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/attributes/) covers Attribute right-click, cog, Move To, pre-evaluation, and removal commands.
- [Import and Export](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/import-export/) covers module selection, CSV actions, and the CSV Export Module asset.
- [UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/) covers every feature tab, Create/Edit controls, documentation and hierarchy shortcuts, and target selection.
- [Item Shape Grid](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-shape-grid/) covers the cell **Set Anchor** command.
- [Item Collections](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/) covers Overflow Options and concrete Item Overflow Action assets.
- [Inventory System Manager](https://opsive.com/support/documentation/ultimate-inventory-system/inventory-system-manager/) covers Scene, Character, Save, Input, UI, and pickup-template Setup actions.

Runtime component fields remain on the page for that component or workflow.

---

<a id="page-ultimate-inventory-system-inventory-system-manager"></a>

# Inventory System Manager

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/inventory-system-manager/)

The **Inventory System Manager** turns one Inventory System Database into the runtime catalog used by Items, Inventories, currencies, crafting, and UI lookups. Create one manager for the active game world, assign the same project database used by the editor, and let player Inventories reference the registered data.

For the shared example, the manager registers the **Consumable** and **Weapon** categories, the **Health Potion** and **Iron Sword** definitions, and each definition's default Item. A player's **Bag** stores runtime Items created from those definitions; the manager does not store the Bag itself.

## Create the manager from Setup

1. Open **Tools > Opsive > Ultimate Inventory System > Main Manager**.
2. Select the **Setup** manager.
3. Under **Inventory System Database**, select the project database. Create one first if needed by following [New Database](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/new-database/).
4. Find **Scene Setup** and select **Add Components**.
5. In the Hierarchy, select the resulting `Game` GameObject and find **Inventory System Manager**.
6. Confirm that **Database** references the database selected in the Main Manager.
7. Keep **Pre Evaluate Attributes** enabled for the normal workflow.
8. Decide whether **Dont Destroy On Load** should remain disabled or whether this `Game` root will be the one persistent manager for the application.

Scene Setup creates a `Game` GameObject when no Scheduler exists; otherwise it reuses the Scheduler's GameObject. It adds Inventory System Manager, Item Object Spawner, Scheduler, Object Pool, and Audio Manager, and assigns the Main Manager's selected database to Inventory System Manager.

The other Setup boxes own different features:

| Setup box | Customer-visible action | Result |
| --- | --- | --- |
| **Input Setup** | **Add Inputs** | Adds the supplied legacy Input Manager mappings after an irreversible-change confirmation. It does not create Input System actions; see [Input](https://opsive.com/support/documentation/ultimate-inventory-system/input/). |
| **Character Setup** | Assign **Character Gameobject**, then **Add Components** | Adds missing Inventory Identifier, Inventory, Item User, Unity Input, Currency Owner, and Inventory Interactor components. It does not build the character's collections, loadout, UI, or networking; see [Spawn Player](https://opsive.com/support/documentation/ultimate-inventory-system/spawn-player/). |
| **Save Setup** | Assign **Object to save**, then **Add Components** | Adds the applicable Inventory or Currency saver and creates the shared save managers where needed; see [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/). |
| **UI Setup** | **Open UI Designer** | Selects UI Designer in the Main Manager. It does not generate UI until that workflow's Setup actions are run; see [UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/). |

The Setup manager's **Create Templates > Option** offers **Item Pickup**, **Inventory Pickup**, **Random Inventory Pickup**, and **Currency Pickup**. Those controls and their **Default Pickup Model Prefab**, **3D Pickup**, and optional Item View behavior are documented with [Item Pickups](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-pickups/).

![The legacy Inventory System Manager Inspector with DemoInventoryDatabase assigned to the Database field.](https://opsive.com/wp-content/uploads/2020/05/InventorySystemManager.png?v=e8a9bd93072d)

The legacy crop shows the still-current **Database** field. The released Version 1 Inspector also exposes **Pre Evaluate Attributes** and **Dont Destroy On Load**.

## Keep the editor and scene on one database

The database selected in the Main Manager controls what the data editors display. The **Database** field on Inventory System Manager controls what the scene registers in Play Mode. Use the same asset for both.

When intentionally switching an existing scene to another database:

1. make a version-control checkpoint or backup;
2. assign the new asset under **Database**;
3. confirm the **Update Scene Database** prompt, or select **Update Scene** in the Inspector; and
4. inspect the Console, scene objects, prefabs, and other scenes for references that still belong to the old database.

The update replaces compatible database references in the current scene and saves the scene. The Inspector warns that this process cannot be reversed, and it does not automatically update every other scene or prefab in the project.

## Understand startup and registration order

Inventory System Manager initializes in `Awake`. Released Version 1 uses this order:

1. create a new runtime register;
2. create a new runtime factory;
3. initialize and register every Item Category;
4. initialize and register every Item Definition, followed by that definition's default Item;
5. initialize and register every Currency;
6. initialize and register every Crafting Category;
7. initialize and register every Crafting Recipe;
8. when **Pre Evaluate Attributes** is enabled, reevaluate Category attributes and then Definition attributes; and
9. mark the manager initialized.

This order lets an Iron Sword Item resolve its Weapon category and definition before the Item itself enters the register. Name lookups are exact and case-sensitive. Duplicate names are rejected with an error. Duplicate IDs can be replaced with generated IDs during registration, so fix collisions in the database instead of relying on runtime reassignment; stable IDs matter for saving and networked projects.

Leave **Pre Evaluate Attributes** enabled unless an advanced project has measured and tested another strategy. Disabling it skips the final full attribute reevaluation; it does not skip database registration.

An empty **Database** produces a warning, but the manager still creates its register and factory and sets `IsInitialized` to true. Treat a valid database and successful lookups—not `IsInitialized` alone—as the readiness check.

## Connect Inventories through identifiers

Inventory System Manager is global catalog and lookup infrastructure. Each character still owns its own **Inventory**, Item Collections, Currency Owner, and UI.

1. Add or create the player through **Main Manager > Setup > Character Setup**.
2. Confirm that the character has **Inventory** and **Inventory Identifier** on the same GameObject.
3. Keep the first player's **Inventory Identifier > ID** at its default of `1`.
4. Configure the Inventory with a `Bag` collection, then add Health Potion and Iron Sword Items through a loadout, pickup, shop, or project code.
5. Give every additional player a unique, nonzero Inventory Identifier ID.

Inventory Identifier finds the Inventory, Currency Owner, and Item User beside it during `Awake`, then registers itself with Inventory System Manager. Systems can retrieve the player with `GetInventoryIdentifier(id)` instead of holding a scene reference.

For split-screen, use one shared Inventory System Manager and database. Give player one and player two different Inventory Identifier, Display Panel Manager, and UI IDs; do not create a manager per player. See [Split Screen Co-op UI](https://opsive.com/support/documentation/ultimate-inventory-system/input/split-screen-co-op-ui/).

## Choose the scene lifetime

| Scene model | **Dont Destroy On Load** | Manager placement |
| --- | --- | --- |
| Each gameplay scene is independent | Disabled, the Version 1 default | Run Scene Setup in every scene that can start directly. Each scene builds a fresh runtime register. |
| One bootstrap owns global services | Enabled | Put the manager on the bootstrap `Game` root and do not add another manager to destination scenes. |
| Additive scenes | Usually enabled on the owning bootstrap | Keep the manager in exactly one loaded scene; content scenes should not contain another one. |
| Split-screen players | Either choice based on scene flow | Share one manager. Separate players with Inventory Identifier and UI IDs. |

**Dont Destroy On Load** persists the manager's entire GameObject, not only the component. When Scene Setup placed Scheduler, Object Pool, Audio Manager, and Item Object Spawner on the same `Game` root, those components persist with it.

When persistence is disabled, unloading the scene removes the runtime register. Runtime-created Items and registered identifiers are not transferred into a new manager automatically. Persist the owning objects together or use the [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/) to recreate their state deliberately.

Do not depend on two managers resolving themselves. The public API is static and points to one singleton register. A persistent manager plus another manager in a destination or additive scene creates ambiguous initialization and database ownership.

## Editor checkpoint

Before entering Play Mode, confirm that:

- exactly one active Inventory System Manager owns the current world;
- **Database** matches the asset selected in the Main Manager;
- the database contains Consumable, Weapon, Health Potion, and Iron Sword with unique names and IDs;
- **Pre Evaluate Attributes** is enabled;
- **Dont Destroy On Load** matches the scene-loading design;
- no destination or additive scene creates a second manager when the `Game` root persists;
- each player has an active Inventory Identifier with a unique, nonzero ID;
- the first player has an Inventory with a `Bag` collection; and
- Save Setup includes Inventory System Manager Item Saver when runtime Item state must survive saving and loading.

## Verify in Play Mode

1. Enter Play Mode and confirm that the Console has no “database is null,” duplicate-name, or wrong-database messages.
2. Resolve Health Potion and Iron Sword by their exact names. Confirm that both definitions are available.
3. Create one Item from each definition and add them to the player's Bag. Confirm that the Inventory and UI show the expected definitions and attributes.
4. Resolve Inventory Identifier ID `1` and confirm that it returns the player with the expected Bag.
5. When the manager is scene-local, load another independently playable scene and repeat the lookups against that scene's manager.
6. When the manager is persistent, load every destination and additive scene. Confirm that the original `Game` root remains and no second manager appears.
7. Save and load a mutable or unique Iron Sword. Confirm that its runtime ID and overridden values return when the manager Item saver is configured.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| The Console says the database is null | **Inventory System Manager > Database** | Assign the same project database selected in the Main Manager. |
| An unexpected `InventorySystemManager` GameObject appears at runtime | Whether project code accessed the static manager before a configured manager existed | Add an active configured manager through Scene Setup and avoid early static access. Released V1 creates an empty manager on demand when none is found. |
| `GetItemDefinition("Health Potion")` returns null | Exact spelling, capitalization, selected database, and registration errors | Use the exact database name and resolve duplicate or null database entries in the Main Manager. |
| Custom code fails when calling UIS from `Awake` | Whether Inventory System Manager has completed its own `Awake` | Move the lookup to `Start`, set an explicit script execution order, or wait until the configured manager is initialized and its database lookup succeeds. |
| Player ID lookup returns null or the wrong player | Inventory Identifier activation and unique nonzero IDs | Keep the identifier beside Inventory and assign stable IDs before Play Mode. Do not let duplicate-ID reassignment define player ownership. |
| Attributes use stale or unexpected inherited values | **Pre Evaluate Attributes** and Category/Definition setup | Enable pre-evaluation and correct the inheritance in the database editor. |
| A second scene uses the wrong database or global objects | A persistent `Game` root and another scene manager are both active | Keep one owning manager and remove the destination scene's duplicate setup. |
| Runtime Items disappear after a scene change | The manager and owning Inventory were scene-local | Persist the intended objects together or save and rebuild them in the next scene. |
| A switched scene still references old database objects | Whether only the manager field changed | Run **Update Scene**, then update affected prefabs and other scenes separately. |
| A runtime Item returns with default values after load | Inventory System Manager Item Saver and the Item's mutable/unique configuration | Run Save Setup, keep stable IDs, and verify that the Inventory Saver contributes the Item ID to the manager Item saver. |

## Version 1 Inspector defaults

| Field | Default | Purpose |
| --- | --- | --- |
| **Database** | None | Primary Inventory System Database registered during `Awake`. |
| **Pre Evaluate Attributes** | Enabled | Performs the final Category and Definition attribute reevaluation after registration. |
| **Dont Destroy On Load** | Disabled | Keeps the manager scene-local unless explicitly enabled. |

Selecting a manager whose **Database** is empty can fill the field from the database currently selected in the Main Manager. Verify the result rather than depending on that Inspector convenience.

## Developer API and events

Use the static lookups after the configured manager has initialized:

```csharp
var consumable = InventorySystemManager.GetItemCategory("Consumable");
var potionDefinition = InventorySystemManager.GetItemDefinition("Health Potion");
var swordDefinition = InventorySystemManager.GetItemDefinition("Iron Sword");

var player = InventorySystemManager.GetInventoryIdentifier(1);
var bag = player?.Inventory.GetItemCollection("Bag");

var potion = InventorySystemManager.CreateItem(potionDefinition);
var sword = InventorySystemManager.CreateItem(swordDefinition);

if (bag != null && potion != null && sword != null) {
    bag.AddItem((ItemInfo)(1, potion));
    bag.AddItem((ItemInfo)(1, sword));
}
```

Definition, Category, Currency, Crafting Category, and Crafting Recipe lookups accept either name or `uint` ID. `GetItem(uint)` retrieves a registered runtime Item. `CreateItem` accepts a definition name, Item Definition, or source Item, with optional attribute overrides and an optional requested ID. A requested ID that already belongs to another Item can be replaced during registration, and an immutable value-equivalent Item may resolve to an equivalent registered Item instead of a distinct instance.

The `Register` property exposes the individual registers, and `Factory` exposes object creation. `PrintGetReadableRegisteredObjectsNamesAndIDs()` writes the registered names and IDs to the Console for diagnostics. `GetGlobal<T>(id)` and `SetGlobal<T>(object, id)` provide the generic runtime register used by some supporting systems.

Inventory System Manager does not send a dedicated “manager initialized” Opsive event in released Version 1. `IInventorySystemManager.IsInitialized` is the available state flag. The factory exposes a C# event for runtime Item creation:

```csharp
private void Start()
{
    InventorySystemManager.Factory.OnItemCreation += HandleItemCreated;
}

private void OnDestroy()
{
    if (InventorySystemManager.IsNull) { return; }
    InventorySystemManager.Factory.OnItemCreation -= HandleItemCreated;
}

private void HandleItemCreated(Item item)
{
    // React to the registered runtime Item.
}
```

Do not call `Initialize()` as a routine runtime refresh. It creates a new register and factory, which discards runtime registrations and factory event subscriptions before the primary database is registered again.

`AddDatabase(IInventorySystemDatabase)` can register another database into the current manager, but released V1 still treats **Database** as the primary asset for scene validation. Additional databases can collide by exact name or ID and are not a substitute for separate manager worlds. Prefer one project database unless a custom workflow explicitly handles those boundaries.

## Related pages

- [Getting Started](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/)
- [New Database](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/new-database/)
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/)
- [Items](https://opsive.com/support/documentation/ultimate-inventory-system/item/)
- [Split Screen Co-op UI](https://opsive.com/support/documentation/ultimate-inventory-system/input/split-screen-co-op-ui/)
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/)

---

<a id="page-ultimate-inventory-system-inventory"></a>

# Inventory

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/)

An **Inventory** owns the Item Collections that hold a character's, Shop's, chest's, or pickup's runtime Items. Use separate collections when Items have different jobs: a **Bag** can hold Health Potion and unequipped Iron Sword Items, while **Equipment** exposes fixed slots for the Iron Sword after it is equipped.

The Inventory is the outer container. Item Collections decide where Item Stacks live, and Item Restrictions decide whether an Item can enter or leave a collection.

## Choose the collection structure

Start with the smallest structure that supports the game:

| Collection | Recommended type | Purpose | Example outcome |
| --- | --- | --- | --- |
| **Bag** | **Item Collection**, or **Multi Stack Item Collection** when one Item needs several limited stacks | **Main** | Health Potion and an unequipped Iron Sword enter the player's general storage. |
| **Equipment** | **Item Slot Collection** | **Equipped** | An Item Slot Set accepts an Iron Sword in a Weapon slot and rejects unrelated categories. |

`Inventory.AddItem` sends an Item to `MainItemCollection`. Set Bag's **Purpose** to **Main** for the simple workflow. If no collection has that purpose, the Inventory falls back to its first collection; an explicit Main purpose and unique collection names make the result clear to both people and code.

Add more collections only for a concrete rule. For example, a **Multi Stack Item Collection** can split Health Potion into bounded stacks, while an **Item Transaction Collection** can act as an intake collection that routes each new Item to the first named destination that accepts it.

## Create the Inventory

1. Select the player or other GameObject that should own the Items.
2. Add **Inventory**.
3. Confirm that **Database** at the top of the Inspector shows the released Version 1 Inventory System Database used by the scene. This is the Inspector's database context; the Inventory System Manager supplies the active database at runtime.
4. Add **Inventory Identifier** when UI, interaction, saving, or another system must find this Inventory by ID.
5. Set the Inventory Identifier's **ID** to a stable, unique, non-zero value. Its released Version 1 default is `1`.
6. In **Item Collections**, use the plus button to add Bag and Equipment. Select a row to edit that collection.

Inventory Identifier registers itself with the Inventory System Manager during `Awake` and finds the Inventory, Currency Owner, and Item User on the same GameObject. A zero or duplicate ID is reassigned when it registers, so give each player, chest, or persistent Inventory its own stable value rather than relying on a conflicting serialized ID.

## Configure Bag

1. Select Bag in **Item Collections**.
2. Set **Name** to `Bag`. Collection names are not enforced as unique, but name-based lookups return the first match, so treat them as unique within an Inventory.
3. Set **Collection** to **Item Collection** for unrestricted stacks, or **Multi Stack Item Collection** when the design requires multiple stacks and a stack-size limit.
4. Set **Purpose** to **Main**.
5. Under **Item Amounts**, add the starting Items. A useful checkpoint is 3 Health Potion Items and 1 Iron Sword.

The Item picker supports the same focused search syntax used by the Version 1 database editor:

- `c:Consumable` finds definitions in the Consumable category;
- `a:Attack` finds definitions with the Attack attribute; and
- `iron c:Weapon a:Attack` combines a name fragment, inherited category, and attribute.

Default Item Amounts are loaded after every collection initializes. In Play Mode, the selected collection instead shows its current Item Stacks, so the Inspector is useful for confirming where a pickup, Shop purchase, or Item Action moved an Item.

![The legacy Version 1 Inventory Inspector showing the database context, Item Collection Restriction Objects, Main and Equipped collections, Item Amounts, and the selected Item attributes; current releases label the top field Database.](https://opsive.com/wp-content/uploads/2020/04/InventoryInspector.png)

## Configure Equipment

1. Select Equipment in **Item Collections**.
2. Set **Name** to `Equipment`, **Collection** to **Item Slot Collection**, and **Purpose** to **Equipped**.
3. Assign **Item Slot Set**. Its Weapon slot should accept the Weapon category inherited by Iron Sword.
4. Leave **New Item Priority** disabled when an occupied slot should keep its current unique Item. Enable it only when a newly added unique Item may replace that slot's current Item.
5. Leave **Try Give Previous Item To New Item Collection** disabled unless a replacement should first be returned to the collection recorded on the incoming `ItemInfo`.

An Item Slot Collection requires a valid Item Slot Set, and every slot requires an Item Category. This collection-level rule works alongside Inventory restrictions: Iron Sword may fit the Weapon slot while Health Potion does not.

## Add restrictions only where needed

The base Item Collection has no capacity limit. Add a restriction when the design requires category, stack-count, stack-size, or another acceptance rule.

1. Create an **Item Restriction Set** from **Create > Ultimate Inventory System > Inventory > Item Restriction Set**.
2. Add the required restriction types to that asset. For example, an **Item Collection Category Restriction** can allow Consumable Items in Bag, and **Item Collection Stack Amount Restriction** can cap the number of stacks across named collections.
3. Add the asset to the Inventory's **Item Collection Restriction Objects** list.
4. Keep every collection name in the restriction synchronized with the Inventory Inspector. The built-in restrictions resolve their target collections by name.

At runtime, the Inventory duplicates the assigned restriction objects and also finds components on the same GameObject that implement `IItemRestriction`. It evaluates each restriction in order. A null result rejects the Item; a smaller returned Amount allows only a partial move.

Each Item Collection also has **Overflow Options**:

| Option | Released Version 1 default | Result |
| --- | --- | --- |
| **Return Overflow** | Off | When enabled and the source collection is known, rejected Items are offered back to that source. |
| **Invoke Rejected Event** | On | Sends the rejection and overflow events with the requested, added, and rejected `ItemInfo` values. |
| **Overflow Action** | None | Runs an assigned Item Overflow Action, such as a project-specific drop response. |

Review the complete [Item Restrictions](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-restrictions/) workflow before combining several rules or changing Inventory size at runtime.

## Route additions through a transaction collection

Most characters can keep Bag as Main and move Iron Sword to Equipment through an equip Item Action. Use an **Item Transaction Collection** as Main only when incoming Items should be routed automatically.

For an intake collection that sends Health Potion to Bag and Iron Sword to Equipment:

1. Add a collection named `Intake`, change **Collection** to **Item Transaction Collection**, and set **Purpose** to **Main**.
2. Change Bag's Purpose from Main to None.
3. In **Item Collection Names**, add `Bag` before `Equipment`.
4. Restrict Bag to Consumable and Equipment to Weapon. The transaction collection tries destinations in list order and uses the first collection whose `CanAddItem` result is non-null and non-zero.
5. Keep **Prevent Adding When No Match** enabled. This is the Version 1 default.
6. Enable **Return Real Added Item Amount** when the caller must receive the actual amount accepted by the destination after a partial move. It is disabled by default.

The transaction collection does not replace destination restrictions. Its routing decision depends on them. See [Item Transaction Collection](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/item-transaction-collection/) for its return and overflow behavior.

## Editor checkpoint

Before entering Play Mode, confirm that:

- **Database** is the intended Inventory System Database and every starting Item belongs to it;
- Inventory Identifier has a unique, non-zero **ID** when another system looks up this Inventory;
- every Item Collection has a unique **Name** and the intended **Purpose**;
- Bag is the explicit Main collection unless a deliberate transaction collection is Main;
- Equipment uses Item Slot Collection with a valid Item Slot Set and category on every slot;
- Item Collection Restriction Objects reference the intended asset and its collection names match exactly; and
- the default Item Amounts show 3 Health Potion and 1 Iron Sword in the intended starting collections.

## Verify in Play Mode

1. Select the Inventory and then Bag. Confirm that the Play Mode **Item Amounts** list contains the default Health Potion and Iron Sword Items.
2. Pick up another Health Potion or add one through the Shop. Confirm that Bag updates in real time and the UI shows the same amount.
3. Equip Iron Sword through the project's Item Action. Confirm that it leaves Bag and appears in Equipment's Weapon slot.
4. Try to add Health Potion directly to Equipment. Confirm that the slot or category restriction rejects it.
5. If Intake is Main, add both definitions through `Inventory.AddItem`. Confirm that each reaches the first compatible destination and that an unmatched Item is rejected.
6. Check any listener or monitor that uses Inventory Identifier and confirm that it follows the intended Inventory, not another object with a conflicting ID.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| The Inspector says the database is missing or its objects do not match | **Database**, the scene's Inventory System Manager, and the referenced defaults or slot set | Select the correct database. Use **Convert Inventory Objects** only when the Inspector should replace references with equivalents from that database. |
| An added Item enters the wrong collection | Which collection has **Purpose: Main**, or the Intake **Item Collection Names** order | Make Bag the explicit Main collection for the simple workflow, or correct the transaction order and destination restrictions. |
| Iron Sword is rejected by Equipment | **Item Slot Set**, Weapon slot category, and Inventory restrictions | Assign the intended slot set and ensure Iron Sword inherits the accepted Weapon category. |
| Health Potion enters Equipment | The Equipment slot category and any category restriction | Restrict the slot or collection to Equippable/Weapon and verify Health Potion remains under Consumable. |
| Only part of an amount is added | Stack-size, stack-count, and slot restrictions plus **Overflow Options** | Inspect the `CanAddItem` result, increase the relevant limit, or handle the rejected remainder explicitly. |
| A pickup or purchase reports success but the expected amount is missing | Transaction **Return Real Added Item Amount** and rejection events | Enable the real-added return when callers need the destination result and handle the rejected `ItemInfo`. |
| UI, save, or interaction binds the wrong Inventory | Duplicate or zero Inventory Identifier **ID** values | Assign a stable, unique, non-zero ID to every registered owner and retest the lookup. |
| Default Items are absent in Play Mode | The selected collection's Item Amounts and database membership | Add the Items to that collection's edit-time default list and replace any references from another database. |

## Continue with the Inventory routes

- [Item Collections](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/) explains Item Stacks, purposes, overflow, and the collection API.
- [Item Restrictions](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-restrictions/) covers restriction assets, runtime restriction components, rejection, and dynamic limits.
- [Item Slot Collection](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/item-slot-collection/) configures fixed Equipment, hotbar, or pouch slots.
- [Multi Stack Item Collection](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/multi-stack-item-collection/) configures multiple bounded stacks of one Item.
- [Item Transaction Collection](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/item-transaction-collection/) configures ordered destination routing.
- [Dynamic Inventory Size](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-restrictions/dynamic-inventory-size/) changes stack capacity from Item attributes.
- [Item Pickups](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-pickups/) moves world Items into an Inventory through the interaction system.
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/) explains safe registration and unregistration for the named Inventory events.

## Use the Inventory API

Use `ItemInfo` when the source collection, destination collection, or exact Item Stack matters. The returned `ItemInfo.Amount` reports how much was actually added or removed by the receiving API.

```csharp
var bag = inventory.GetItemCollection("Bag");
var equipment = inventory.GetItemCollection(ItemCollectionPurpose.Equipped)
    as ItemSlotCollection;

var added = inventory.AddItem("Health Potion", 5);
var potionDefinition = InventorySystemManager.GetItemDefinition("Health Potion");
var hasPotion = inventory.HasItem((1, potionDefinition));

var swordDefinition = InventorySystemManager.GetItemDefinition("Iron Sword");
var swordInfo = inventory.GetItemInfo(swordDefinition);
if (swordInfo.HasValue) {
    var removed = inventory.RemoveItem((1, swordInfo.Value));
}
```

`inventory.AllItemInfos` exposes the Inventory's cached runtime Items but intentionally ignores collections whose Purpose is **Loadout** or **Hide**.

Check a destination before presenting a move as available:

```csharp
var ironSword = InventorySystemManager.CreateItem("Iron Sword");
var requested = (ItemInfo)(1, ironSword);
var allowed = equipment.CanAddItem(requested);

if (allowed.HasValue && allowed.Value.Amount == requested.Amount) {
    var actuallyAdded = equipment.AddItem(requested);
}
```

A custom `IItemRestriction` implements `Initialize`, `CanAddItem(ItemInfo, ItemCollection)`, and `CanRemoveItem(ItemInfo)`. Return null to reject the operation or return an `ItemInfo` with a reduced Amount to permit only part of it.

The released Version 1 Inventory flow sends these core named events:

| Event | Target and payload |
| --- | --- |
| `EventNames.c_ItemCollection_OnUpdate` | The Item Collection; no payload. |
| `EventNames.c_Inventory_OnUpdate` | The Inventory; no payload after its visible cache updates. |
| `EventNames.c_Inventory_OnAdd_ItemInfo_ItemStack` | The Inventory; the original `ItemInfo` and resulting `ItemStack`. |
| `EventNames.c_Inventory_OnRemove_ItemInfo` | The Inventory; the removed `ItemInfo`. |
| `EventNames.c_Inventory_OnAddItemRejected_ItemInfoToAdd_ItemInfoAdded_ItemInfoRejected` | The Inventory; requested, accepted, and rejected `ItemInfo` values. |
| `EventNames.c_Inventory_OnAddItemOverflow_ItemInfoToAdd_ItemInfoAdded_ItemInfoRejected` | The Inventory; the same three values for overflow handling. |

Register and unregister matching signatures over the same Unity lifecycle. Use the [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/) page for the Version 1 `EventHandler` pattern.

---

<a id="page-ultimate-inventory-system-inventory-item-collections"></a>

# Item Collections

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/)

An **Item Collection** is one named group of Item Stacks inside an Inventory. Use collections to separate Items by job: **Bag** can hold Health Potion and unequipped Iron Sword Items, while **Equipment** can expose fixed slots for equipped Items.

The collection type controls how Items are stored. Its **Purpose** gives the collection a recognized role, and Inventory-level Item Restrictions can limit what the collection accepts or removes.

## Choose a collection type

Start with the base type, then choose a specialized collection only when its behavior matches the design.

| Collection type | Use it when | Important released Version 1 fields and defaults |
| --- | --- | --- |
| **Item Collection** | Bag needs one stack for matching common Items and no built-in capacity limit. | **Overflow Options** defaults to Return Overflow off, Invoke Rejected Event on, and no Overflow Action. |
| **Item Slot Collection** | Equipment, a hotbar, or a pouch needs fixed slots defined by an Item Slot Set. | **New Item Priority** and **Try Give Previous Item To New Item Collection** both default to off. |
| **Item Transaction Collection** | A Main intake collection should route an incoming Item to the first named collection that accepts it. | **Return Real Added Item Amount** defaults to off; **Prevent Adding When No Match** defaults to on. |
| **Multi Stack Item Collection** | Health Potion or another common Item needs several bounded stacks. | **Default Stack Size Limit** is `99`; **Stack Size Limit Attribute Name** is `StackSizeLimit`. |

The specialized collection pages explain the choices that appear after changing **Collection**:

- [Item Slot Collection](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/item-slot-collection/)
- [Item Transaction Collection](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/item-transaction-collection/)
- [Multi Stack Item Collection](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/multi-stack-item-collection/)

## Understand Items, stacks, and collection ownership

An **Item Stack** is a runtime object that contains an Item, an Amount, and its Item Collection. An **ItemInfo** is the value passed through most collection operations; it can carry an Item Amount together with the source collection and exact Item Stack. Keep that source information when an overflow should return to its origin or a removal must target a particular stack.

The base Item Collection applies these rules:

- Add and remove requests must use a positive Amount.
- Matching common Items share one stack. Immutable, common Health Potion Items are the straightforward example.
- A unique Item occupies its own stack with an Amount of one. Adding an amount greater than one creates distinct Items with different IDs, so two mutable, unique Iron Sword Items can retain different Durability values.
- Mutable, common Items can stack, but when they merge the existing stack's Item and values are retained. Use this combination only when shared mutable state is intentional.
- A mutable Item that still belongs to another collection is duplicated before it is added. Remove a unique Item from Bag before adding it to Equipment when the move must preserve that Item's identity and current values.
- The base collection has no stack-size or stack-count limit. Use Multi Stack Item Collection or an Item Restriction when the design needs one.

See [Item Info](https://opsive.com/support/documentation/ultimate-inventory-system/item/item-info/) for the distinction between Item Amount, Item Stack, and ItemInfo.

## Configure a collection in the Inventory Inspector

1. Select the GameObject with **Inventory**, then select a row under **Item Collections**.
2. Set **Name** to a unique value such as `Bag`. A newly constructed collection starts as `NewItemCollection`, and name-based lookups return the first match.
3. Choose the type in **Collection**. Changing type asks for confirmation because type-specific values can be lost.
4. Set **Purpose** only when the collection has one of the recognized roles described below.
5. Expand **Overflow Options** and keep the defaults until the design has a defined rejection flow.
6. Under **Item Amounts**, add the edit-time starting Items. For the shared example, add 3 Health Potion and 1 Iron Sword to Bag.

Outside Play Mode, **Item Amounts** edits the collection's Default Loadout. In Play Mode, the same area shows the current Item Stacks and refreshes when the collection updates. Add, remove, and amount changes made there are routed through the collection API.

![The legacy Version 1 Item Collections Inspector with Main selected, showing Name, Collection, Purpose, the default Overflow Options, and starting Item Amounts.](https://opsive.com/wp-content/uploads/2020/04/ItemCollectionInspector-e1642585366351.png?v=204278e9ed38)

## Set the collection Purpose

Use unique names for project-specific roles and reserve **Purpose** for behavior that depends on it.

| Purpose | Released Version 1 behavior |
| --- | --- |
| **None** | No predefined role. Use the collection's Name to find it. |
| **Main** | The default destination used by `Inventory.AddItem`. If no collection is explicitly Main, the Inventory falls back to its first collection. |
| **Secondary** | A custom secondary role. It is also used by the Ultimate Character Controller integration, so do not repurpose it when that integration is active. |
| **Equipped** | Marks equipped Items and is used by the Ultimate Character Controller integration. Equipment is the usual collection name. |
| **Loadout** | Holds loadout Items. It is used by the Ultimate Character Controller integration and is excluded from the Inventory's visible `AllItemInfos` cache. |
| **Hide** | Excludes the collection from the Inventory's visible `AllItemInfos` cache. |
| **Drop** | Identifies a collection used for dropping Items. |

Several APIs accept an `ItemCollectionID`, which can match by Name or Purpose. A Name match has more weight when both are supplied. Avoid duplicate names and use only one collection for each system-significant Purpose.

## Configure Bag and Equipment

For the shared player Inventory:

1. Configure `Bag` as **Item Collection** with **Purpose: Main**.
2. Add 3 Health Potion and 1 Iron Sword under Bag's edit-time Item Amounts.
3. Configure `Equipment` as **Item Slot Collection** with **Purpose: Equipped**.
4. Assign an Item Slot Set whose Weapon slot accepts the Weapon category inherited by Iron Sword.
5. Move Iron Sword through the project's equip Item Action. Remove it from Bag before it is added to Equipment so its unique runtime values are preserved.

At runtime, matching immutable Health Potion Items merge into Bag's existing stack. The unique Iron Sword remains a separate stack until the equip flow moves it into Equipment's Weapon slot.

## Handle restrictions and overflow

`CanAddItem` first checks the Item and its database membership, then asks the owning Inventory to apply its Item Restrictions. A null result rejects the request. A returned ItemInfo with a smaller Amount permits a partial addition.

When less than the requested amount is accepted, the receiving collection applies **Overflow Options**:

| Option | Default | Result |
| --- | --- | --- |
| **Return Overflow** | Off | If enabled and the source collection is known, offers the rejected ItemInfo back to that source. |
| **Invoke Rejected Event** | On | Sends the Inventory rejection and overflow events and invokes the collection's `OnItemAddOverflow` event. |
| **Overflow Action** | None | Invokes the assigned Item Overflow Action with the requested, added, and rejected ItemInfo values. |

Use **Assets > Create > Ultimate Inventory System > Item Overflow Actions > Item Overflow Action With Item Action** when the rejected remainder should invoke a configured Item Action. Assign the concrete asset under **Overflow Action** and test the requested, accepted, and rejected amounts. The Assets menu also exposes an abstract **Item Overflow Actions > ...** placeholder in the released package; it is not a usable asset. Choose **Item Overflow Action With Item Action** or a project-defined concrete `ItemOverflowAction` instead.

Use [Item Restrictions](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-restrictions/) for category, stack-count, stack-size, or custom acceptance rules. Returning overflow is not a substitute for checking a destination first: call `CanAddItem` before presenting a move as available.

## Editor checkpoint

Before entering Play Mode, confirm that:

- every collection has a unique **Name** and the intended **Collection** type;
- Bag is the explicit **Main** collection;
- Equipment is **Equipped** and has a valid Item Slot Set;
- the starting **Item Amounts** are in the intended collection;
- unique Items such as Iron Sword are configured to keep their own runtime values;
- Multi Stack fields use the intended limit and attribute name when that type is selected;
- transaction destination names match collection names exactly and are in the intended order; and
- Overflow Options and Inventory restrictions describe what should happen to a rejected remainder.

## Verify in Play Mode

1. Select Bag and confirm that **Item Amounts** now represents live Item Stacks.
2. Add another Health Potion. Confirm that the base collection increases the existing common stack.
3. Add two mutable, unique Iron Sword Items. Confirm that each appears separately and can retain a different Durability value.
4. Equip one Iron Sword. Confirm that the same runtime Item leaves Bag and appears in Equipment.
5. Attempt a disallowed move, such as Health Potion into a Weapon slot. Confirm that `CanAddItem` rejects it and the configured overflow response runs.
6. If a transaction collection is Main, add Health Potion and Iron Sword through `Inventory.AddItem` and confirm that each reaches the first compatible named destination.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| An Item enters the wrong collection | Main Purpose, duplicate collection names, and transaction destination order | Give Bag the explicit Main Purpose, make names unique, and reorder the transaction list. |
| Matching Health Potion Items do not stack | The Item Category's Unique setting, collection type, and runtime Item values | Keep the simple potion immutable and common, or use the intended Multi Stack behavior. |
| Two Iron Sword Items lose their separate Durability | Mutable and Unique category settings, or a mutable-common merge | Make runtime weapons mutable and unique so each Item has its own stack and ID. |
| Moving Iron Sword creates a copy | Whether the mutable Item still belongs to Bag when it is added to Equipment | Remove the complete unique Item from Bag first, then add the returned ItemInfo to Equipment. |
| Only part of an amount is added | Inventory restrictions, slot compatibility, and stack limits | Inspect the `CanAddItem` result and handle the rejected remainder through Overflow Options. |
| A collection appears empty only in aggregate UI or code | Its Purpose | Use Loadout or Hide only when the collection should be omitted from the Inventory's visible cache. |
| Default Items disappear or duplicate after entering Play Mode | The edit-time Item Amounts on each collection | Keep each intended default in one collection and verify the Default Loadout after changing collection type. |
| A type-specific field is missing | The selected **Collection** type | Select the intended specialized type and re-enter any values that were not retained during the type change. |

## Continue with collection workflows

- [Item Slot Collection](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/item-slot-collection/) configures fixed Equipment, hotbar, and pouch slots.
- [Item Transaction Collection](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/item-transaction-collection/) configures ordered routing into named destination collections.
- [Multi Stack Item Collection](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/multi-stack-item-collection/) configures multiple bounded stacks for matching Items.
- [Item Restrictions](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-restrictions/) limits additions and removals across one or more collections.
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/) configures the owning component, Inventory Identifier, and complete Bag/Equipment workflow.
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/) shows safe registration and unregistration for named Inventory events.

## Use the Item Collection API

Keep the returned ItemInfo: its Amount is the amount actually accepted or removed, and its collection and stack references identify the result.

```csharp
var bag = inventory.GetItemCollection("Bag");
var potion = InventorySystemManager.CreateItem("Health Potion");
var requested = (ItemInfo)(3, potion);

var allowed = bag.CanAddItem(requested);
if (allowed.HasValue && allowed.Value.Amount > 0) {
    var added = bag.AddItem(requested);
}

var potionDefinition = InventorySystemManager.GetItemDefinition("Health Potion");
var potionAmount = bag.GetItemAmount(potionDefinition, false);
var removed = bag.RemoveItem(potionDefinition, 1);
```

Filter and sort without allocating a permanent array, then return the pooled array after using the `ListSlice`:

```csharp
var itemInfos = GenericObjectPool.Get<ItemInfo[]>();
var mutableItems = bag.GetItemInfos(
    ref itemInfos,
    info => info.Item.IsMutable,
    Comparer<ItemInfo>.Create((left, right) =>
        string.Compare(
            left.Item.ItemDefinition.Name,
            right.Item.ItemDefinition.Name,
            StringComparison.Ordinal)));

// Read mutableItems before returning its backing array.
GenericObjectPool.Return(itemInfos);
```

The collection exposes these instance events:

| Event | Payload |
| --- | --- |
| `OnItemCollectionUpdate` | No payload; sent after a visible collection change. |
| `OnItemAdded` | The original `ItemInfo` and resulting `ItemStack`. |
| `OnItemRemoved` | The removed `ItemInfo`. |
| `OnItemAddOverflow` | The requested, added, and rejected `ItemInfo` values. |

The matching named update event is `EventNames.c_ItemCollection_OnUpdate`, targeted at the Item Collection. Additions and removals also send `EventNames.c_Inventory_OnAdd_ItemInfo_ItemStack` and `EventNames.c_Inventory_OnRemove_ItemInfo` to the owning Inventory in Play Mode. Rejected additions can send `EventNames.c_Inventory_OnRejected_ItemInfo`, `EventNames.c_Inventory_OnAddItemRejected_ItemInfoToAdd_ItemInfoAdded_ItemInfoRejected`, and `EventNames.c_Inventory_OnAddItemOverflow_ItemInfoToAdd_ItemInfoAdded_ItemInfoRejected` when **Invoke Rejected Event** is enabled.

Register and unregister matching signatures over the same Unity lifecycle. See [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/) for the released Version 1 pattern.

---

<a id="page-ultimate-inventory-system-inventory-item-collections-item-slot-collection"></a>

# Item Slot Collection

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/item-slot-collection/)

Use an **Item Slot Collection** when an Inventory needs a fixed, ordered set of named slots. In the shared example, **Bag** holds an unequipped Iron Sword and **Equipment** uses a Weapon slot that accepts Iron Sword but rejects Health Potion.

An **Item Slot Set** asset defines the slot names, order, and accepted Item Category. The Item Slot Collection owns the runtime Item Stacks for those slots. An Equipment UI or Equipper can then use the same set to display or visually equip the Items.

## Create the Item Slot Set

1. In the Project window, choose **Create > Ultimate Inventory System > Inventory > Item Slot Set**.
2. Name the asset `PlayerEquipmentItemSlotSet`.
3. In its Inspector, set **Database** to the Inventory System Database used by the scene.
4. Under **Item Slot Set**, add a slot and select it.
5. Set **Name** to `Weapon` and **Item Category** to **Weapon**.
6. Add only the other slots the game uses, such as Head or Chest, and assign an Item Category to every slot.
7. Put the slots in their intended display and save order before the game is released.

The category check uses inheritance. A Weapon slot accepts an Iron Sword whose definition belongs to Weapon or one of its descendant categories. Health Potion remains under Consumable, so it does not match.

Slot names should be unique because name-based lookups use the first match. The released Version 1 Item Slot Set has no per-slot stack-size field: the number of entries fixes the number of slots, while a separate Inventory restriction is needed to limit the Amount inside a stack.

![The legacy Version 1 Item Slot Set Inspector showing the database, ordered Right Hand, Head, Chest, and Legs slots, and the selected Right Hand slot restricted to the Weapons category.](https://opsive.com/wp-content/uploads/2021/01/ItemSlotSet.png)

## Configure the Equipment collection

1. Select the player Inventory and add or select the Equipment row under **Item Collections**.
2. Set **Name** to `Equipment`.
3. Set **Collection** to **Item Slot Collection**.
4. Set **Purpose** to **Equipped**.
5. Assign `PlayerEquipmentItemSlotSet` to **Item Slot Set**.
6. Leave **New Item Priority** disabled for the normal workflow. Its released Version 1 default is off.
7. Leave **Try Give Previous Item To New Item Collection** disabled unless direct additions should try to return a replaced Item to the source collection carried by the incoming ItemInfo. Its default is also off.
8. Leave **Item Amounts** empty when the character starts unequipped, or add an Iron Sword when it should start equipped.

**New Item Priority** applies to unique Items. When it is off, adding a unique Iron Sword directly to an occupied slot is rejected. When it is on, the new unique Item can replace the current Item. The standard **Move To Collection Item Action** handles an equipment exchange more deliberately: it verifies the move, removes the old Item, adds the new one, and returns the old Item to the original collection.

![The legacy Version 1 Equipment Item Slot Collection with Purpose set to Equipped, an Item Slot Set assigned, New Item Priority enabled, Try Give Previous Item To New Item Collection disabled, and no default Item Amounts.](https://opsive.com/wp-content/uploads/2021/01/ItemSlotCollectionInspector.png?v=bc47220072dd)

## Understand runtime slot selection

Calling `AddItem(itemInfo)` lets the collection choose a slot:

1. It ignores slots whose **Item Category** does not inherently contain the Item.
2. For a matching common Item, it reuses an existing stackable slot.
3. Otherwise it chooses the first empty matching slot.
4. If every matching slot is occupied, it returns the last matching slot as the replacement candidate.

`CanAddItem` returns null when the Item matches no slot, when the Item is invalid for the active database, or when an Inventory restriction rejects it. A non-null result can still be reduced by an Inventory restriction.

Each slot retains one Item Stack reference, but a common Item Stack can have an Amount greater than one. A mutable, unique Iron Sword normally occupies one slot with an Amount of one.

The index and name overloads target a particular slot. Released Version 1 confirms that the Item matches at least one slot in the set, but the explicit overload does not separately compare the Item against the category of the requested index. UI views add their own per-slot category restriction. In custom code, validate the requested slot's category or prefer the automatic `AddItem(itemInfo)` overload.

## Decide category, slot, and amount limits

Use the smallest rule that expresses the design:

| Requirement | Configure | Result |
| --- | --- | --- |
| Iron Sword fits the Weapon slot but Health Potion does not | The slot's **Item Category: Weapon** | The Item Slot Set performs the normal category match. |
| Equipment has exactly Weapon, Head, and Chest positions | Three ordered Item Slot Set entries | The collection creates one runtime slot for each entry. |
| A common Item in a slot has a maximum Amount | **Item Collection Stack Size Restriction** targeting `Equipment` | The restriction limits the accepted Amount, using its configured default or `StackSizeLimit` Item attribute. |
| Fewer stacks are allowed across one or more collections | **Item Collection Stack Amount Restriction** | The configured **Max Stack Amount** limits occupied stacks across the named collections. |
| The whole Equipment collection needs an additional allow or deny list | **Item Collection Category Restriction** | The collection-level rule runs in addition to each slot category. |

Configure positive limits explicitly on stack restrictions; their fields do not derive values from the number of slots. Keep restriction collection names synchronized with `Equipment`. See [Item Restrictions](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-restrictions/) for the complete restriction workflow.

## Move Iron Sword between Bag and Equipment

For the normal nontechnical workflow, add **Move To Collection Item Action** to the Iron Sword's available Item Actions:

1. Set its first collection to Bag or **Purpose: Main**.
2. Set its second collection to Equipment or **Purpose: Equipped**.
3. Keep the action names `Equip` and `Unequip`, which are the released Version 1 defaults.
4. Invoke Equip from the Bag UI.

The action checks that the full Item can leave Bag and selects a compatible Equipment slot. For an empty slot, it also confirms that the full Item can enter. If the target already contains a different Item, it first confirms that Item can return to Bag. It then removes the selected Iron Sword before adding it to Equipment, preserving the mutable Item's identity and Durability; any rejected remainder is returned to the Main collection.

Use the integration-specific equip action instead when the character is driven by the Opsive character-controller bridge. The [Built-in Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/built-in-item-actions/) page explains the released Version 1 distinction.

## Connect the Equipment UI and Equipper

The runtime data, UI, and character visual must agree on the same slot definition:

1. Use the UI Designer **Equipment** workflow to create an **Item Slot Collection View**.
2. Set its **Item Collection ID** to Equipment or **Purpose: Equipped**.
3. Assign the same `PlayerEquipmentItemSlotSet` used by the Equipment collection.
4. Keep **Set Item View Slot Restrictions** and **Add View Slot Category Restrictions** enabled. Both default to on and copy each Item Slot category to the corresponding visible Item View Slot.
5. When character equipment visuals are required, add **Equipper**, target the Equipment collection, and assign the same Item Slot Set.

The Item Slot Collection View validates that its Item Slot Set is the same asset used by the runtime collection. The Equipper listens for Inventory add and remove events: adding Iron Sword to Equipment creates or updates its equipment visual, and removing it unequips that visual. The collection and UI do not apply game-specific stat changes by themselves.

See [Equipment in UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/equipment/), [Item Slot Collection View](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-slot-collection-view-equipment/), and [Equipping Items](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/equipping-items/) for the focused workflows.

## Preserve slots when saving

For the standard UIS save workflow, add **Inventory Saver** to the Inventory owner and **Inventory System Manager Item Saver** to the Save System Manager. The Inventory Saver serializes an Item Slot Collection by `ItemsBySlot`, including empty positions, then restores each Item to its saved index. The manager Item saver preserves the data behind mutable or unique Item IDs such as Iron Sword Durability.

Keep the Inventory's collection order and the Item Slot Set's slot order compatible with existing save files. The released Version 1 save data addresses collections and slots by index. A character using the Ultimate Character Controller integration uses its Inventory Bridge Saver instead of the standard Inventory Saver.

See [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/) for setup and integration caveats.

## Editor checkpoint

Before entering Play Mode, confirm that:

- Equipment is an **Item Slot Collection** with **Purpose: Equipped**;
- Equipment, Item Slot Collection View, and Equipper reference the same Item Slot Set asset;
- every slot has a unique **Name** and a nonempty **Item Category** from the active Database;
- the Weapon slot accepts the category inherited by Iron Sword;
- **New Item Priority** and **Try Give Previous Item To New Item Collection** match the intended replacement policy;
- any stack-size or stack-count restriction targets the exact `Equipment` collection name;
- the Equipment UI has one Item View Slot per Item Slot Set entry in the same order; and
- the save components required by the chosen standard or integration workflow are present.

## Verify in Play Mode

1. Select Equipment and confirm that its live **Item Amounts** list starts empty, unless a default equipped Item was configured.
2. Invoke Equip on Iron Sword in Bag. Confirm that the same Item leaves Bag and enters the Weapon slot.
3. Confirm that the Equipment Item View Slot shows Iron Sword and, when an Equipper is configured, the matching visual appears on the character.
4. Attempt to equip Health Potion. Confirm that no slot matches and the action remains unavailable or the addition is rejected.
5. Equip a second Iron Sword through the Move To Collection action. Confirm that the previous sword returns to Bag rather than being lost.
6. Save with Iron Sword equipped, change the Inventory, then load. Confirm that Iron Sword returns to the same slot with its saved mutable values.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| Iron Sword has no valid target slot | Weapon slot **Item Category**, Item definition category, and Database | Assign Weapon to the slot, ensure Iron Sword inherits it, and use objects from the active database. |
| Health Potion enters a slot through custom code | Whether an explicit index overload bypassed the requested slot's category check | Validate `ItemSlotSet.GetSlot(index).Category.InherentlyContains(item)` or use automatic `AddItem(itemInfo)`. |
| A second Iron Sword is rejected | Occupied target and **New Item Priority** | Use Move To Collection Item Action for an exchange, or enable New Item Priority only when direct replacement is intended. |
| The replaced Item disappears or overflows | **Try Give Previous Item To New Item Collection**, incoming ItemInfo source, and Overflow Options | Use the standard move action, or retain the source ItemInfo and configure the replacement/overflow policy explicitly. |
| Equipment UI is empty or logs a slot-set mismatch | **Item Collection ID** and Item Slot Set on the view and collection | Target Equipment and assign the same Item Slot Set asset to both. |
| The UI accepts the wrong category | **Set Item View Slot Restrictions**, **Add View Slot Category Restrictions**, and visible slot order | Enable both settings and regenerate or realign the Item View Slots from the Item Slot Set. |
| The icon changes but no character visual appears | Equipper collection ID, Item Slot Set, and Iron Sword equipment-prefab data | Target the Equipped collection, reuse the same set, and configure the expected equipment prefab attributes. |
| A common Item exceeds the intended amount | Item Slot Set was expected to provide a size limit | Add and configure an Item Collection Stack Size Restriction for Equipment. |
| Loaded Items return to the wrong slots | Inventory collection order or Item Slot Set order changed | Restore the compatible order or migrate the save data before changing released slot layouts. |

## Use the Item Slot Collection API

Prefer automatic placement for category-safe moves. Check that the target is empty when replacement is not part of the operation, remove the Item from Bag, and return it if the addition fails:

```csharp
var bag = inventory.GetItemCollection("Bag");
var equipment = inventory.GetItemCollection(ItemCollectionPurpose.Equipped)
    as ItemSlotCollection;

var swordDefinition = InventorySystemManager.GetItemDefinition("Iron Sword");
var swordInfo = bag.GetItemInfo(swordDefinition);
if (swordInfo.HasValue) {
    var targetIndex = equipment.GetTargetSlotIndex(swordInfo.Value.Item);
    var targetItem = targetIndex >= 0
        ? equipment.GetItemInfoAtSlot(targetIndex)
        : ItemInfo.None;

    if (targetIndex >= 0 && targetItem.Item == null) {
        var removed = bag.RemoveItem(swordInfo.Value);
        if (removed.Amount > 0) {
            var added = equipment.AddItem(removed);
            if (added.Amount != removed.Amount) {
                bag.AddItem((ItemInfo)(removed.Amount - added.Amount, removed));
            }
        }
    }
}
```

Use the slot query and mutation APIs when the slot itself is meaningful:

```csharp
var weaponIndex = equipment.ItemSlotSet.GetIndexOf("Weapon");
var weaponInfo = equipment.GetItemInfoAtSlot(weaponIndex);
var actualIndex = equipment.GetItemSlotIndex(weaponInfo.Item);
var potentialIndex = equipment.GetTargetSlotIndex(weaponInfo.Item);

var removedWeapon = equipment.RemoveItemInSlot("Weapon");
```

`SwapItemSlot(firstIndex, secondIndex)` swaps two compatible slots. `ItemsBySlot` preserves every positional entry, including empty slots. `GetAllItemStacks()` contains only occupied stacks, so do not use its list index as a slot index.

Item Slot Collection inherits `OnItemCollectionUpdate`, `OnItemAdded`, `OnItemRemoved`, and `OnItemAddOverflow`. It also sends `EventNames.c_ItemCollection_OnUpdate` to the collection and the normal `EventNames.c_Inventory_OnAdd_ItemInfo_ItemStack` and `EventNames.c_Inventory_OnRemove_ItemInfo` events to its Inventory. Equipper listens to the Inventory add/remove events and sends `EventNames.c_Equipper_OnChange` after its visible equipment changes.

Register and unregister matching signatures over the same Unity lifecycle. See [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/) for the released Version 1 event pattern.

## Related pages

- [Item Collections](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/)
- [Item Restrictions](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-restrictions/)
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/)
- [Built-in Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/built-in-item-actions/)
- [Equipment in UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/equipment/)
- [Equipping Items](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/equipping-items/)
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)

---

<a id="page-ultimate-inventory-system-inventory-item-collections-item-transaction-collection"></a>

# Item Transaction Collection

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/item-transaction-collection/)

Use an **Item Transaction Collection** as a routing entry point when different Items should enter different collections through one add operation. In the shared example, an `Intake` collection sends Health Potion to **Bag** and Iron Sword to **Equipment**.

The transaction collection does not store routed Items. It checks its named destination collections in order, chooses the first one that can accept a nonzero Amount, and delegates the addition to that collection. Destination restrictions therefore define the route.

## Configure the destinations first

Create and test the collections that will receive Items before adding the router:

1. Configure `Bag` as a base Item Collection.
2. Add an **Item Collection Category Restriction** that allows Consumable Items in Bag.
3. Configure `Equipment` as an Item Slot Collection whose Weapon slot accepts the Weapon category.
4. Confirm that Health Potion can enter Bag but Iron Sword cannot.
5. Confirm that Iron Sword can enter Equipment but Health Potion cannot.

Without the Bag restriction, the base collection accepts both Items. If Bag appears first in the route, it would also receive Iron Sword and Equipment would never be checked.

See [Item Restrictions](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-restrictions/) and [Item Slot Collection](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/item-slot-collection/) for those destination rules.

## Configure the Intake collection

1. Add an Item Collection named `Intake` to the Inventory.
2. Set **Collection** to **Item Transaction Collection**.
3. Set **Purpose** to **Main**, then change Bag's Purpose to None.
4. Under **Item Collection Names**, add `Bag` first and `Equipment` second.
5. Keep **Prevent Adding When No Match** enabled. This is the released Version 1 default.
6. Leave **Return Real Added Item Amount** disabled for the initial full-accept-or-reject workflow. It is disabled by default.
7. Under the inherited **Overflow Options**, keep **Return Overflow** disabled, **Invoke Rejected Event** enabled, and **Overflow Action** empty until the rejection policy is deliberate.

Use exact, unique collection names. Released Version 1 does not skip a name that fails to resolve before calling the destination, so a missing or misspelled name can cause a runtime exception. Never include Intake itself in its destination list because that would recurse back into the same router.

![The legacy Version 1 Inventory Inspector showing a Main transaction collection named Default, seven ordered destination collection names, the older Overflow Back To Origin and Rejected Item Actions fields, Return Real Added Item Amount disabled, and a populated default Item Amounts list.](https://opsive.com/wp-content/uploads/2021/07/Item-Transaction-Collection.png?v=649680361908)

The legacy image predates the current released Version 1 field layout. Current source uses the inherited **Overflow Options** instead of **Overflow Back To Origin** and **Rejected Item Actions**, and adds **Prevent Adding When No Match**. Use the current labels described on this page.

## Follow the runtime routing order

For every addition, the transaction collection:

1. resolves each name in **Item Collection Names** in list order;
2. calls that destination's `CanAddItem`;
3. selects the first result that is non-null and has a nonzero Amount;
4. sends the full original requested Amount to that destination's `AddItem`; and
5. applies the transaction collection's overflow behavior if the destination accepts less than requested.

The route does not continue to later destinations with a rejected remainder. If Bag says it can accept 3 of 5 Health Potion Items, Bag is selected, receives the request, and the remaining 2 go through overflow handling instead of being offered to Equipment.

The inherited base collection splits a unique Item request with an Amount greater than one into distinct unique Items. Each of those Items is routed separately.

| Request | Destination checks | Result |
| --- | --- | --- |
| 3 Health Potion | Bag accepts; Equipment is not checked | Bag stores all 3. |
| 1 Iron Sword | Bag rejects; Equipment accepts | Equipment stores the sword in its Weapon slot. |
| An Item accepted by neither collection | Both reject | With **Prevent Adding When No Match** enabled, the request is rejected and overflow handling runs. |
| 5 Health Potion when Bag accepts only 3 | Bag returns a partial result | Bag stores 3; the other 2 are overflow, and Equipment is not checked. |

The transaction collection's own Item Stacks remain empty. Inventory and destination collection views show the actual Items.

## Choose the return and no-match behavior

The two transaction-specific booleans affect what the caller sees:

| Setting | Default | Released Version 1 behavior |
| --- | --- | --- |
| **Prevent Adding When No Match** | On | `CanAddItem` returns null when no named destination accepts anything. The transaction reports zero added and runs its inherited overflow path. |
| **Return Real Added Item Amount** | Off | After a destination is selected, the transaction reports the requested Amount even when the destination accepted less. Overflow still runs for the rejected remainder. |

Enable **Return Real Added Item Amount** only when the caller must receive the destination's returned ItemInfo and the destination normally accepts the complete request or rejects it outright. With the default off, use Inventory events or inspect the destination when the accepted Amount matters.

Do not disable **Prevent Adding When No Match** for a normal router. When it is off and no destination matches, the transaction runs overflow handling but, with Return Real also off, reports the requested Amount even though no destination stored it.

## Preserve or return the origin

The inherited **Return Overflow** option can offer a rejected remainder back to its origin when all of these are true:

- the incoming ItemInfo retains an Item Collection source;
- the source is not the transaction collection itself; and
- the source can accept the rejected ItemInfo.

Adding a newly created Item by name does not provide an origin. Removing an Item from a source collection and then passing the returned ItemInfo to Intake does preserve that source reference.

The transaction creates a destination ItemInfo from only the Item and Amount, so it does not pass the source and stack references to the destination. This prevents the destination's own Return Overflow option from returning it directly; the transaction collection handles the original source context after the destination returns.

## Account for released Version 1 overflow limitations

Partial acceptance can produce more than one overflow notification for one routing request:

1. the destination collection handles its rejected remainder;
2. the transaction collection handles the same partial result; and
3. with **Return Real Added Item Amount** enabled, inherited Item Collection code sees the partial return and can invoke the transaction overflow path again.

As a result, rejection events or Overflow Actions with side effects can run multiple times. In addition, when **Return Overflow** succeeds, released Version 1 replaces the returned ItemInfo Amount with the Amount accepted back by the origin; that value is not necessarily the Amount stored in the destination.

A no-match request can also run the transaction overflow path twice when **Prevent Adding When No Match** is disabled and **Return Real Added Item Amount** is enabled.

For predictable routing, prefer destination rules that fully accept or fully reject each request. If partial routing, precise returned Amounts, and side-effecting overflow actions must be combined, use a tested custom router rather than relying on the built-in transaction collection's return value.

## Editor checkpoint

Before entering Play Mode, confirm that:

- Intake is the only collection with **Purpose: Main**;
- every **Item Collection Names** entry resolves to a unique destination and Intake is not listed;
- Bag appears before Equipment only because Bag rejects Weapon Items;
- Bag and Equipment each accept the intended category and reject the other example Item;
- **Prevent Adding When No Match** remains enabled;
- **Return Real Added Item Amount** matches the caller's expectations;
- Overflow Options are configured on both the destinations and Intake with duplicate notifications in mind; and
- no default Item Amounts were added to Intake, because it is a router rather than storage.

## Verify in Play Mode

1. Add 3 Health Potion through `Inventory.AddItem`. Confirm that Bag receives all 3 and Intake remains empty.
2. Add 1 Iron Sword through the same API. Confirm that Bag rejects it and Equipment receives it.
3. Add an Item that neither destination accepts. With **Prevent Adding When No Match** enabled and **Return Overflow** disabled, confirm that the returned Amount is zero and that the rejection listener runs.
4. Temporarily limit Bag so only part of a Health Potion request fits. Confirm that the remainder does not fall through to Equipment.
5. Observe rejection and overflow listeners during the partial test. Record how many notifications the selected Return Real and Overflow Options combination produces before attaching side effects.
6. For an origin test, remove Health Potion from a source collection, pass the returned ItemInfo to Intake, and confirm the configured Return Overflow behavior.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| Iron Sword always enters Bag | Bag is unrestricted or appears before Equipment | Restrict Bag to Consumable, or put a suitably restricted Equipment destination first. |
| Routing throws a null-reference exception | **Item Collection Names** spelling and collection existence | Correct or remove every stale name; V1 does not safely skip a missing destination. |
| Routing never completes | Intake or another transaction collection points back to Intake | Remove the recursive route and point only to storage collections. |
| An unmatched Item appears to have been added | **Prevent Adding When No Match** is off and Return Real is off | Re-enable Prevent Adding When No Match and retest the return value. |
| The caller reports more Items than the destination contains | **Return Real Added Item Amount** is off | Enable it only after testing the overflow behavior, or inspect the destination/event payload instead. |
| A rejected remainder is not tried in the next collection | The first destination returned a nonzero partial Amount | Design routes as full accept/reject, or implement a router that explicitly distributes the remainder. |
| Overflow Actions run twice or more | A partial destination result, or no match with Prevent Adding When No Match off; then Return Real and the destination/transaction overflow settings | Avoid side effects on overlapping overflow paths or use a custom router for partial transactions. |
| A rejected Item does not return to its source | Incoming ItemInfo source and Intake **Return Overflow** | Pass the ItemInfo returned by the source removal and enable Return Overflow on Intake. |
| Intake looks empty in the Inspector | Whether Items reached the named destinations | Inspect Bag and Equipment; Intake intentionally does not retain routed Item Stacks. |

## Use the Item Transaction Collection API

Use the Inventory API when Intake is Main. A newly created Item has no source collection:

```csharp
var potionResult = inventory.AddItem("Health Potion", 3);
var swordResult = inventory.AddItem("Iron Sword", 1);
```

Preview the selected destination or preserve an origin explicitly:

```csharp
var intake = inventory.GetItemCollection("Intake")
    as ItemTransactionCollection;
var bag = inventory.GetItemCollection("Bag");

var swordDefinition = InventorySystemManager.GetItemDefinition("Iron Sword");
var swordInfo = bag.GetItemInfo(swordDefinition);
if (swordInfo.HasValue) {
    var destination = intake.GetItemCollectionToTransactionTo(swordInfo.Value);

    if (destination != null) {
        var removed = bag.RemoveItem(swordInfo.Value);
        var reportedResult = intake.AddItem(removed);
    }
}
```

`GetItemCollectionToTransactionTo` runs the same ordered `CanAddItem` checks and exposes the selected destination. `AddingToCollection` contains that last selection.

Do not treat Intake as an aggregate collection. `GetAllItemStacks`, `GetItemAmount`, and the definition/category query overloads inspect its empty local stack list. `GetItemInfo(Item)` is the one query overridden to search the linked destinations in order, and removal with a concrete ItemInfo walks those destinations in order. Query Inventory, Bag, or Equipment when counts and complete lists matter.

Observe routing on the owning Inventory:

| Event | Meaning |
| --- | --- |
| `EventNames.c_Inventory_OnAdd_ItemInfo_ItemStack` | A destination accepted an Item and supplies the resulting stack. |
| `EventNames.c_Inventory_OnRejected_ItemInfo` | A rejected ItemInfo was reported. |
| `EventNames.c_Inventory_OnAddItemRejected_ItemInfoToAdd_ItemInfoAdded_ItemInfoRejected` | Requested, accepted, and rejected values from an overflow path. |
| `EventNames.c_Inventory_OnAddItemOverflow_ItemInfoToAdd_ItemInfoAdded_ItemInfoRejected` | The same three values for overflow handling. |

The transaction collection does not invoke its normal add/update event when a destination stores the Item; the destination collection updates instead. Its `OnItemAddOverflow` callback can run when Intake handles overflow and **Invoke Rejected Event** is enabled.

Register and unregister matching event signatures over the same Unity lifecycle. See [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/) for the released Version 1 pattern.

## Related pages

- [Item Collections](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/)
- [Item Restrictions](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-restrictions/)
- [Item Slot Collection](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/item-slot-collection/)
- [Multi Stack Item Collection](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/multi-stack-item-collection/)
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/)
- [Item Pickups](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-pickups/)
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/)

---

<a id="page-ultimate-inventory-system-inventory-item-collections-multi-stack-item-collection"></a>

# Multi Stack Item Collection

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/multi-stack-item-collection/)

Use a **Multi Stack Item Collection** when one common Item should occupy several bounded stacks. For example, a Bag with a stack limit of 10 stores 25 Health Potion Items as three stacks: 10, 10, and 5.

The stack-size limit applies to each stack, not to the collection as a whole. This collection can create any number of stacks unless an Inventory restriction limits them.

## Configure a bounded Bag

1. Select the GameObject with the **Inventory** component.
2. Under **Item Collections**, select the collection used for general storage.
3. Set **Name** to `Bag`.
4. Set **Collection** to **Multi Stack Item Collection**.
5. Set **Purpose** to **Main** when Bag should receive calls to `Inventory.AddItem` by default.
6. Set **Default Stack Size Limit**. Use `10` while following the example on this page; the released Version 1 default is `99`.
7. Keep **Stack Size Limit Attribute Name** set to `StackSizeLimit`. This is the released Version 1 default.

The two stack settings apply only to the Multi Stack Item Collection. The inherited **Overflow Options** control what happens when an Inventory restriction accepts less than the requested Amount.

## Set a different limit for one Item

Use **Default Stack Size Limit** when most common Items should use the same limit. Use an integer attribute when one definition needs a different value:

1. In the Item Category editor, declare an Item Definition `int` attribute named `StackSizeLimit` on a suitable parent such as Consumable.
2. Select **Health Potion** in the Item Definition editor.
3. Set its `StackSizeLimit` value to a positive whole number, such as `5`.
4. Confirm that **Stack Size Limit Attribute Name** on Bag exactly matches `StackSizeLimit`.

At runtime, the collection asks the Item for an integer with that name. When it cannot find one, it uses **Default Stack Size Limit**. The value must be greater than zero: released Version 1 does not clamp or reject zero before using it in stack calculations, and zero can cause a divide-by-zero exception.

Keep a stack limit on the Item Definition when every Health Potion should use the same value. See [Defining Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/) and [Common Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/common-attribute-types/) for the data workflow.

## Follow the stack order

When an Amount is added, the collection uses this order:

1. fill a supplied target ItemStack first, when the caller provides one that belongs to Bag;
2. scan compatible existing stacks in collection order and fill their remaining space;
3. append as many full new stacks as required; and
4. append one remainder stack when an Amount remains.

With a limit of 10, adding 25 Health Potion to an empty Bag produces `10, 10, 5`. Adding 7 more fills the last stack to 10, then appends a stack of 2, producing `10, 10, 10, 2`.

Removal by Item without a target walks matching stacks from the end, so it normally reduces the newest remainder before earlier full stacks. Supplying a specific ItemInfo targets its ItemStack first and can leave that stack partially filled in its current collection position. The Item Definition removal overload first resolves a matching ItemInfo, so code should not depend on every removal overload choosing the same stack.

This is collection order, not a permanent UI slot assignment. An Inventory Grid can filter, sort, or maintain its own grid indexes independently.

## Choose which Items may stack

| Item configuration | Multi Stack behavior | Shared example |
| --- | --- | --- |
| Immutable, common | Matching Items from the same definition fill compatible stacks, then create more stacks. | Health Potion |
| Mutable, common | Matching additions can merge into the stored common Item; the existing Item values are retained. | Use only when shared mutable values are intentional. |
| Unique, mutable or immutable | Each Item remains separate with an Amount of 1, even when the requested Amount is greater than one. | Iron Sword with per-Item Durability |
| Different Item Definitions | Items never share a stack. | Health Potion and another consumable remain separate. |

The collection is most useful for common Items. Do not make Iron Sword common merely to use a larger stack limit; keep it mutable and unique when each sword must retain its own Durability.

## Limit the number of stacks

**Default Stack Size Limit** and `StackSizeLimit` do not limit Bag's total capacity. To cap the number of ItemStacks:

1. create an **Item Restriction Set**;
2. add an **Item Collection Stack Amount Restriction**;
3. include `Bag` under **Item Collection Names**; and
4. set **Max Stack Amount** to the total number of stacks Bag may hold.

The restriction counts existing stacks and asks the Multi Stack Item Collection how much of the incoming request fits in their free space plus the available new stacks. It can therefore accept a partial Amount. The rejected remainder then follows Bag's **Overflow Options**.

Use an **Item Collection Category Restriction** as well when Bag should accept Consumable Items but reject Equipment. Use the Multi Stack fields, rather than a second stack-size restriction, for this collection's per-stack limit. See [Item Restrictions](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-restrictions/).

## Connect UI and saving

Each ItemStack is a separate ItemInfo in the Inventory cache. An Inventory Grid can therefore show `10`, `10`, and `5` Health Potion as three separate entries. Its filter, sorter, and **Use Grid Index** behavior determine the visible order; the collection itself does not reserve fixed UI slots.

An **Inventory Saver** records every stack as an Item ID and Amount in collection order. Loading a non-slot collection adds those saved entries back through the collection API. If the stack limit or Inventory restrictions changed after saving, the loaded Items can be merged, split, or rejected according to the new configuration instead of recreating the old stack objects exactly.

Use **Inventory System Manager Item Saver** to preserve mutable or unique Item state. Use **Inventory Grid Saver** when player-arranged grid positions must also persist. See [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/) and [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/inventory-grid/).

## Editor checkpoint

Before entering Play Mode, confirm that:

- Bag uses **Multi Stack Item Collection** and has the intended **Purpose**;
- **Default Stack Size Limit** is greater than zero;
- **Stack Size Limit Attribute Name** exactly matches an `int` attribute or deliberately falls back to the default;
- Health Potion is common and immutable for the simple stacking example;
- Iron Sword remains unique when its runtime values must stay separate;
- an Item Collection Stack Amount Restriction exists if Bag needs a total stack limit;
- the Inventory Grid is allowed to show more than one entry for the same definition; and
- the save setup includes both Item state and grid-position savers when the game needs them.

## Verify in Play Mode

1. Start with an empty Bag and a stack limit of 10.
2. Add 25 Health Potion. Confirm that Bag contains three stacks with Amounts `10`, `10`, and `5`.
3. Add 7 more. Confirm that the stacks become `10`, `10`, `10`, and `2`.
4. Remove 7 through the same Health Potion Item reference without specifying a stack. Confirm that the raw collection order returns to `10`, `10`, and `5`.
5. Add two unique Iron Sword Items. Confirm that they appear as two separate Amount-1 stacks and keep independent Durability values.
6. If a stack-count restriction is configured, fill Bag to its limit and add another Health Potion. Confirm the partial or rejected Amount and the configured overflow response.
7. Save, change the scene, then load. Confirm the stack totals and, when configured, the visible Inventory Grid positions.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| All Health Potion Items stay in one large stack | Bag's **Collection** type | Select **Multi Stack Item Collection**, then re-enter its type-specific settings if the type changed. |
| Every stack uses 99 instead of the definition value | Attribute name, type, and location | Define an Item Definition `int` named `StackSizeLimit` and match the Inspector string exactly. |
| Adding an Item throws a divide-by-zero exception | **Default Stack Size Limit** and the resolved `StackSizeLimit` value | Set both possible values to positive integers. |
| Bag keeps creating more stacks | Whether an Item Collection Stack Amount Restriction includes `Bag` | Add or correct that restriction; Multi Stack has no total capacity by itself. |
| A partial stack is not the first visible slot | Inventory Grid filter, sorter, and **Use Grid Index** | Treat collection order and visible grid order separately; configure the grid for the intended presentation. |
| Two swords merge or share changing values | Weapon's **Mutable** and **Unique** category settings | Make per-instance weapons mutable and unique. |
| One add request triggers several callbacks | How many existing or new stacks were affected | Handle `OnItemAdded` per stack, or query and aggregate the final state after `AddItem` returns. |
| Loaded stacks have different boundaries | Stack limit or restrictions changed since the save | Keep those rules stable across saves, or migrate and retest the saved Inventory. |
| Grid positions reset after loading | Whether **Inventory Grid Saver** is configured | Save the Inventory content and grid index state together. |

## Use the Multi Stack API

Query total Amount and stack count separately:

```csharp
var bag = inventory.GetItemCollection("Bag")
    as MultiStackItemCollection;
var potionDefinition = InventorySystemManager.GetItemDefinition("Health Potion");

var added = bag.AddItem(potionDefinition, 25);
var totalAmount = bag.GetItemAmount(potionDefinition, false);
var stackCount = bag.GetItemAmount(potionDefinition, false, true);
var stacks = bag.GetAllItemStacks();
var removed = bag.RemoveItem(added.Item, 7);
```

The collection exposes `DefaultStackSizeLimit` and `StackSizeLimitAttributeName` as writable properties. Set them before adding Items. Changing a limit does not immediately rebalance existing stacks; a later add, remove, or load can reshape them.

When `AddItem` touches several stacks, released Version 1 invokes `OnItemAdded` and `EventNames.c_Inventory_OnAdd_ItemInfo_ItemStack` once for each affected stack. The returned ItemInfo reports the total accepted Amount but references only the last stack touched. A removal spanning several stacks produces one combined `OnItemRemoved` result.

Only pass a target ItemStack when it belongs to Bag and contains a stackable-equivalent Item. Released Version 1 checks that the target belongs to the collection but does not validate target compatibility before increasing its Amount.

Register and unregister matching event signatures over the same Unity lifecycle. See [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/) for the released Version 1 event pattern.

## Related pages

- [Item Collections](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/)
- [Item Restrictions](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-restrictions/)
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/)
- [Defining Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/)
- [Common Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/common-attribute-types/)
- [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/inventory-grid/)
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/)

---

<a id="page-ultimate-inventory-system-inventory-item-restrictions"></a>

# Item Restrictions

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-restrictions/)

Use Item Restrictions to decide which Items a collection accepts and how much capacity an Inventory has. For the shared setup, restrictions can keep Health Potion in **Bag**, keep Iron Sword and Fire Wand in **Equipment**, and limit Bag to a fixed number of ItemStacks.

Restrictions do not store Items. They evaluate an ItemInfo before its receiving Item Collection changes. A restriction may accept the request, reduce its Amount, or reject it.

## Choose the restriction route

| Route | Use it for | Where it is configured |
| --- | --- | --- |
| **Item Restriction Set Object** | Reusable category, stack-count, and single-stack rules | A project asset assigned under Inventory's **Item Collection Restriction Objects** |
| **Dynamic Inventory Size** | Capacity that changes when bag Items are added or removed | A component beside the Inventory |
| **Item Shape Grid Controller** | Capacity based on shape-grid fit | A component created as part of the Item Shape Grid workflow |
| Custom `IItemRestriction` | A project-specific acceptance or removal rule | A serializable class in a Restriction Set, or a component beside Inventory |
| **Group Item Restriction Object** | Maintaining an existing legacy setup only | A legacy project asset; do not use its overflow actions for new work |

Start with an Item Restriction Set for ordinary Bag and Equipment rules. Use specialized component restrictions only when capacity depends on runtime equipment or a spatial grid.

## Create an Item Restriction Set

1. In the Project window, choose **Create > Ultimate Inventory System > Inventory > Item Restriction Set**.
2. Name the asset `PlayerInventoryRestrictions`.
3. In **Restrictions**, use **+** to add entries.
4. Drag entries into evaluation order. Put inexpensive category checks first, capacity checks after them, and custom rules last.
5. Select each entry in the list to edit its fields below the list.

![The legacy Version 1 Item Restriction Set Inspector listing category and maximum-stack restrictions, with a Weapons ItemCollectionCategoryRestriction selected and configured for the Equippable category.](https://opsive.com/wp-content/uploads/2020/04/Item-Restriction-Set-Object-Inspector.png?v=d3a354d2603e)

The legacy image uses a larger sample database, but the **Restrictions** list, reorder controls, and selected restriction fields still represent the released Version 1 workflow.

## Configure the built-in set restrictions

Released Version 1 provides these general-purpose restriction classes in the Restriction Set picker:

| Restriction | Exact fields | New-entry defaults | What it limits |
| --- | --- | --- | --- |
| **Item Collection Category Restriction** | **Item Collection Names**, **Allowed Item Categories**, **Not Allowed Item Categories** | Names unset; category lists empty | Which category trees may enter named collections |
| **Item Collection Stack Amount Restriction** | **Item Collection Names**, **Max Stack Amount** | Names unset; `0` maximum | Total ItemStack count shared by the named collections |
| **Item Collection Stack Size Restriction** | **Item Collection Names**, **Default Stack Size Limit**, **Stack Size Limit Attribute Name** | Names unset; `0`; `StackSizeLimit` | Amount accepted into one matching stack in a normal Item Collection |

Do not leave **Item Collection Names** unset. Released V1 iterates that array without a null guard during initialization. Add at least one name, match the Inventory collection's capitalization, and remove blank rows. An explicitly empty array affects no collection, while names that do not resolve are silently skipped.

### Restrict categories

Add two **Item Collection Category Restriction** entries:

1. For Bag, set **Item Collection Names** to `Bag` and **Allowed Item Categories** to Consumable.
2. For Equipment, set **Item Collection Names** to `Equipment` and **Allowed Item Categories** to Weapon.
3. Leave **Not Allowed Item Categories** empty unless an allowed parent has a child that must still be denied.

Allowed and denied entries include their category descendants. When the same Item matches both lists, **Not Allowed Item Categories** wins. With both category lists empty, a configured collection accepts every category and the restriction has no effect.

This rule affects additions only. It does not remove an Item that is already in a collection, and it does not block removal.

### Limit the number of stacks

Add **Item Collection Stack Amount Restriction**, set **Item Collection Names** to `Bag`, and choose a positive **Max Stack Amount**, such as `12`.

The maximum is shared across every named collection in that one restriction. If both Bag and Equipment are listed with a maximum of 12, their combined ItemStack count is limited to 12; each collection does not receive 12 slots of its own.

The restriction asks the receiving collection how much of the request fits in existing stacks plus the remaining new-stack capacity. A Multi Stack Item Collection can therefore accept a partial Health Potion Amount when only part of one final stack fits. A normal Item Collection can keep adding a common Item to its existing stack even when no new stack is available.

Keep **Max Stack Amount** at or above the current number of stacks. In released V1, a normal Item Collection that is already over the maximum can still accept a new common Item in some cases because the base capacity calculation handles zero free stacks but not a negative free-stack count consistently.

### Limit one normal stack

Use **Item Collection Stack Size Restriction** only when a normal Item Collection needs a maximum Amount in its one matching stack:

1. Set **Item Collection Names** to `Bag`.
2. Set **Default Stack Size Limit** to a positive value such as `20`.
3. Keep **Stack Size Limit Attribute Name** as `StackSizeLimit` when Item Definitions may override the default with an `int` attribute.

The restriction finds one matching ItemInfo and returns only the Amount that fits below the selected limit. Its default limit is `0`, so a newly configured entry blocks Items without a positive `StackSizeLimit` attribute until **Default Stack Size Limit** is set.

Do not combine this restriction with **Multi Stack Item Collection** to define that collection's per-stack size. The restriction sees one existing stack and can prevent the Multi Stack collection from creating its intended additional stacks. Configure **Default Stack Size Limit** and **Stack Size Limit Attribute Name** on the Multi Stack collection itself instead.

See [Defining Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/) when Health Potion needs a definition-specific `StackSizeLimit`.

## Attach the set to Inventory

1. Select the player GameObject with **Inventory**.
2. Expand **Item Collection Restriction Objects**.
3. Add `PlayerInventoryRestrictions` to the array.
4. Keep the asset order deliberate when more than one restriction object is assigned.
5. Confirm that the Inventory still contains collections named exactly `Bag` and `Equipment`.

![The legacy Version 1 Inventory Inspector showing AdventureKitInventoryDatabase, one Item Collection Restriction Object assigned, and Default, Weapons, and Armors collections below it.](https://opsive.com/wp-content/uploads/2020/04/Inventory-Inspector-Item-Restrictions.png?v=803ee7709042)

Inventory duplicates each assigned restriction object during initialization. Editing the project asset after the Inventory has initialized does not update that runtime copy automatically; configure the asset before Play Mode or deliberately reinitialize the Inventory.

## Understand evaluation order

On initialization, Inventory builds one ordered restriction list:

1. duplicated assets from **Item Collection Restriction Objects**, in array order;
2. each Item Restriction Set's entries, in its internal list order; and
3. `IItemRestriction` components found on the Inventory GameObject, in component order.

For both addition and removal checks, each restriction receives the result of the previous restriction. A null result stops evaluation. A reduced Amount continues through the remaining restrictions, so later rules see the reduced request. All restrictions must accept; they are combined as **AND**, not **OR**.

The three modern set restrictions pass removal requests through unchanged. Dynamic Inventory Size is the built-in exception: it can reject removal of a bag Item when losing that Item's capacity would leave the Inventory over its maximum.

Adding a restriction component after Inventory initialization does not register it automatically. Call `Inventory.AddRestriction` for a runtime-created restriction, and retain the same instance if it may later be passed to `Inventory.RemoveRestriction`.

## Handle partial and rejected additions

The modern set restrictions do not invoke rejection events during `CanAddItem`. When an actual `AddItem` call accepts less than requested, the receiving Item Collection handles the remainder through its **Overflow Options**:

| Option | Released Version 1 default | Result |
| --- | --- | --- |
| **Return Overflow** | Off | Offers the rejected remainder back to its source collection when a valid source is present. |
| **Invoke Rejected Event** | On | Sends the Inventory rejection and overflow events and invokes the collection callback. |
| **Overflow Action** | Empty | Runs the assigned Item Overflow Action with requested, added, and rejected ItemInfo values. |

The principal event is `EventNames.c_Inventory_OnAddItemRejected_ItemInfoToAdd_ItemInfoAdded_ItemInfoRejected`:

- `ItemInfoToAdd` is the original request and may retain its source collection;
- `ItemInfoAdded` is the collection's result; with **Return Overflow** off, its Amount is zero for a full rejection and the accepted Amount for a partial result; and
- `ItemInfoRejected` is the remainder that did not fit.

The same overflow path also sends `c_Inventory_OnRejected_ItemInfo` and `c_Inventory_OnAddItemOverflow_ItemInfoToAdd_ItemInfoAdded_ItemInfoRejected` when **Invoke Rejected Event** is enabled. A `CanAddItem` preview alone does not send these modern events.

The collection processes overflow in this order: **Return Overflow**, **Overflow Action**, the three Inventory events, then its `OnItemAddOverflow` callback. A successful return to the origin can change the Amount reported in `ItemInfoAdded`, so treat the requested, stored, returned, and rejected values as distinct.

An Item Transaction Collection can route Items to restricted destinations, but its first destination that accepts a nonzero Amount wins. A partial remainder is not tried in later destinations, and released V1 can invoke overlapping overflow paths. See [Item Transaction Collection](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/item-transaction-collection/) before combining routing with side-effecting overflow actions.

## Use component-based restrictions

### Dynamic Inventory Size

**Dynamic Inventory Size** counts ItemStacks across **Restricted Item Collection Names**. Its released V1 defaults are:

- **ID** `0`;
- **Base Max Stack Amount** `99`;
- **Use Bag Items** enabled;
- **Bag Item Category** named `Bag Item`;
- **Bag Size Item Attribute Name** `BagSize`;
- **Prevent Remove Bag Item If Would Overflow** disabled; and
- size-change overflow set to **Remove Last Items**, with its rejected event disabled and no Overflow Action.

Its size-change options apply when capacity shrinks, not to an ordinary rejected add. Configure them deliberately: the default can remove last stacks silently when capacity decreases.

Released V1 has two important limitations. **Remove First Items** does not iterate because its loop condition is incorrect, so use **Remove Last Items** or **Do Not Remove**. Initial bag-size recomputation also stops at the first ItemStack that is outside **Bag Item Category** or lacks `BagSize`; keep **Bags Item Collection Names** dedicated to valid bag Items.

See [Dynamic Inventory Size](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-restrictions/dynamic-inventory-size/) for its Inventory Grid binding and complete setup. This is the only direct child page in the Item Restrictions section.

### Item Shape Grid Controller

**Item Shape Grid Controller** is a component restriction installed by the Item Shape Grid workflow. It checks whether a matching grid has room for the Item's `Shape`. Its relevant released V1 defaults are **No Grid Add Item** off, **Shape Attribute Name** `Shape`, and **Warn If Multiple Match** off.

It is intentionally hidden from the Item Restriction Set picker. Configure it through [Item Shape Grid](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-shape-grid/), where the controller and its Item Shape Grid Data remain synchronized.

## Keep Group Item Restriction legacy-only

Do not create a **Group Item Restriction Object** for a new Inventory. Its current Inspector exposes **Item Collection IDs**, **Item Collection Overflow**, and the **Item Collection Restrictions** flags in this order: Category Restriction, Full Size, Category Size, Definition Size, then Item Size during runtime evaluation.

The unset defaults are no enabled flags, `int.MaxValue` for every size limit, `CategorySizeLimit`, `DefinitionSizeLimit`, and `ItemSizeLimit` as the attribute names, **Reject ItemCategories** enabled, and **Reject Incoming Item** as the overflow action. **Remove Replaced Item** and **Overflow Back To Origin** are off, while the overflow collection and both Item Action sets are empty.

![The legacy Group Item Restriction Inspector showing DemoInventoryDatabase, collapsed Item Collection IDs, the former Do Not Add overflow label, unchecked replacement and return options, Mixed restriction flags, Category Default Size Limit 100 with CategorySizeLimit, and Item Default Size Limit 99 with ItemSizeLimit.](https://opsive.com/wp-content/uploads/2020/04/GroupItemCollectionRestriction.png?v=6f03a7e829a8)

The image contains the former **Do Not Add** label; current source names that enum value **Reject Incoming Item**.

Legacy overflow processing runs inside `CanAddItem`. A preview can therefore reject, move, or forcibly remove Items before any add occurs, and a later `AddItem` call can run the side effects again. **Overflow Back To Origin** also assumes an origin collection and can fail for a newly created Item. In addition, legacy Full Size undercounts some Multi Stack requests, and Category Size counts existing stacks but compares them with the incoming Item Amount.

The runtime `GroupItemRestriction` type may also appear in the Restriction Set picker; do not select it for new work. Existing Group assets also need a non-null **Item Collection IDs** array before initialization. Avoid treating `CanAddItem` as a harmless preview against those assets, leave forced removal, return routing, and Item Actions unused, and test every enabled flag. Replace category, stack-count, and stack-size flags with the three modern set restrictions when the asset can be migrated.

## Editor checkpoint

Before entering Play Mode, confirm that:

- every Restriction Set entry names an existing collection with exact capitalization;
- Bag allows Consumable and Equipment allows Weapon, with no unintended category in both allowed and denied lists;
- every maximum is positive and not already below the current stack count;
- Multi Stack Bag uses its own stack-size fields rather than Item Collection Stack Size Restriction;
- Restriction Set entries and assigned assets are in the intended evaluation order;
- **Invoke Rejected Event** is enabled on collections whose rejection UI or logging depends on it;
- no legacy Group overflow action can mutate Items during a preview;
- Dynamic Inventory Size avoids **Remove First Items** and uses dedicated valid bag collections; and
- the Dynamic Inventory Size or Item Shape Grid component is on the same GameObject as Inventory when used.

## Verify in Play Mode

1. Add Health Potion to Bag. Confirm that the accepted Amount and ItemStack count stay within the configured limits.
2. Try to add Iron Sword and Fire Wand directly to Bag. Confirm that the Consumable category rule rejects them.
3. Add Iron Sword and Fire Wand to Equipment. Confirm that its Weapon rule accepts them while rejecting Health Potion.
4. Fill Bag to **Max Stack Amount**, then try to add an Item that requires a new stack. Confirm a zero or partial result and the configured rejection event.
5. For a normal Item Collection with a stack-size restriction, add more Health Potion than its limit. Confirm the accepted and rejected Amounts separately.
6. Remove an ordinary Item. Confirm the three modern set restrictions allow removal.
7. If Dynamic Inventory Size is enabled, remove a capacity-granting bag Item and confirm either the prevention rule or the selected size-change overflow behavior.
8. Call `CanAddItem` without adding. Confirm that modern restrictions do not change the Inventory or emit rejection events.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| A restriction never runs | **Item Collection Names**, spelling, asset assignment, and initialization timing | Use exact collection names, assign the set before Play Mode, and reinitialize after deliberate runtime changes. |
| Bag rejects every new Item | **Max Stack Amount** or **Default Stack Size Limit** left at `0` | Enter a positive maximum before testing. |
| A denied child category enters Bag | Whether only **Allowed Item Categories** was configured | Add the child to **Not Allowed Item Categories**; denied categories are checked after allowed categories. |
| An Item matches the first rule but still fails | Later Restriction Set entries, other assigned assets, and component restrictions | Inspect the full evaluation order; every rule must accept the result. |
| Multi Stack Bag never creates another stack | Item Collection Stack Size Restriction targets Bag | Remove that restriction and use the Multi Stack collection's own limit fields. |
| Capacity is shared unexpectedly | Multiple names in one Item Collection Stack Amount Restriction | Use separate restriction entries when Bag and Equipment need separate maxima. |
| Rejection code runs after `CanAddItem` only | A legacy Group overflow action is still active | Remove the legacy side effect and use collection Overflow Options with the modern restrictions. |
| Removing a bag Item does not reduce Dynamic capacity correctly | Bag Item category, `BagSize`, and contents of the bag-item collections | Keep only eligible bag Items in those collections and ensure every stack has the integer attribute. |
| **Remove First Items** leaves overflow in place | Released V1 Dynamic Inventory Size limitation | Use **Remove Last Items** or **Do Not Remove**. |
| `CanAddItem` reports space but the later add fails | Inventory changed between preview and add, or another rule reduced the request | Treat the `AddItem` return as authoritative and handle its rejected remainder. |

## Implement a custom restriction

The released Version 1 interface uses `CanAddItem` and `CanRemoveItem`:

```csharp
[System.Serializable]
public sealed class ExampleRestriction : IItemRestriction
{
    [System.NonSerialized] private IInventory m_Inventory;

    public void Initialize(IInventory inventory, bool force)
    {
        m_Inventory = inventory;
    }

    public ItemInfo? CanAddItem(
        ItemInfo itemInfo,
        ItemCollection receivingCollection)
    {
        // Return itemInfo, a reduced ItemInfo, or null.
        return itemInfo;
    }

    public ItemInfo? CanRemoveItem(ItemInfo itemInfo)
    {
        // Return itemInfo, a reduced ItemInfo, or null.
        return itemInfo;
    }
}
```

A constructible serializable class appears in the Restriction Set picker unless it is hidden from that picker. A `MonoBehaviour` implementation is discovered beside Inventory during initialization instead. Keep preview methods free of side effects; they may be called by UI before the real add or remove.

Preview with the receiving collection so collection-specific validation also runs:

```csharp
var bag = inventory.GetItemCollection("Bag");
var potion = InventorySystemManager.CreateItem("Health Potion");
var request = (ItemInfo)(potion, 25);

var allowed = bag.CanAddItem(request);
if (allowed.HasValue && allowed.Value.Amount > 0) {
    var actualResult = bag.AddItem(request);
}
```

Register and unregister matching rejection event signatures over the same Unity lifecycle. See [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/) for the complete pattern and payloads.

## Related pages

- [Dynamic Inventory Size](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-restrictions/dynamic-inventory-size/)
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/)
- [Item Collections](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/)
- [Multi Stack Item Collection](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/multi-stack-item-collection/)
- [Item Slot Collection](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/item-slot-collection/)
- [Item Transaction Collection](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/item-transaction-collection/)
- [Item Shape Grid](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-shape-grid/)
- [Defining Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/)
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/)

---

<a id="page-ultimate-inventory-system-inventory-item-restrictions-dynamic-inventory-size"></a>

# Dynamic Inventory Size

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-restrictions/dynamic-inventory-size/)

Use **Dynamic Inventory Size** when an Inventory's capacity should change at runtime. For example, Bag can begin with room for four ItemStacks, and equipping a Small Backpack can add four more.

The limit applies to ItemStacks, not total Item Amount. Ten Health Potion Items in one stack use one space; the same Items split across two stacks use two spaces. The component enforces the data limit, while an optional Inventory Grid binding presents that limit in the UI.

## Prepare the Bag capacity data

Keep the Items that grant capacity separate from the Items whose capacity is restricted. This avoids ambiguity and works around released Version 1 recomputation limits.

1. On the player Inventory, create or identify the `Bag` Item Collection that will hold Health Potion and other carried Items.
2. Add a second Item Collection named `Capacity`. Store only capacity-granting Items in this collection.
3. In the database, create an Item Category named `Bag Item`.
4. Add an Item Definition `int` attribute named `BagSize` to that category or to its definitions.
5. Create a Small Backpack definition in the category and set `BagSize` to `4`.
6. Configure capacity Items as amount-one Items. Prefer unique Items, or otherwise guarantee that each one occupies its own ItemStack and is added or removed as a complete stack.

The dedicated `Capacity` collection must contain only Items in **Bag Item**, and every Item in it must resolve a positive integer `BagSize`. See [Defining Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/) for the attribute workflow.

## Configure Dynamic Inventory Size

Add **Dynamic Inventory Size** to the same GameObject as **Inventory**, then configure the example:

1. Keep **ID** at `0`. Use another unique ID only when this Inventory has more than one Dynamic Inventory Size component.
2. Assign **Inventory**, or leave it empty when the component is beside the Inventory that it should restrict.
3. Set **Base Max Stack Amount** to `4`.
4. Add `Bag` to **Restricted Item Collection Names**.
5. Enable **Use Bag Items**.
6. Under **Bag Item Category**, select **Bag Item** or keep its **Name** set to `Bag Item` so the category resolves at runtime.
7. Keep **Bag Size Item Attribute Name** set to `BagSize`.
8. Add `Capacity` to **Bags Item Collection Names**.
9. For the first test, enable **Prevent Remove Bag Item If Would Overflow** and select **Do Not Remove** under **Size Change Overflow Options**. This avoids silently discarding carried Items while the setup is being verified.

![Dynamic Inventory Size Inspector configured with ID 0, Player Inventory, a base limit of 12, Main as the restricted collection, BagCollection as the capacity collection, the BagSize attribute, and Remove Last Items overflow handling.](https://opsive.com/wp-content/uploads/2022/04/DynamicInventorySizeInspector.png?v=c20a601b9a68)

The legacy feature-scene image uses `Main`, `BagCollection`, and a base limit of 12. The same fields should use `Bag`, `Capacity`, and 4 for the example on this page.

The maximum is clamped to zero and calculated as:

```text
Base Max Stack Amount + capacity contributed by qualifying ItemStacks
```

With no Small Backpack, Bag accepts four ItemStacks. Adding the backpack to Capacity contributes its `BagSize` value of 4, raising Bag's maximum to eight stacks.

## Understand when capacity updates

When Inventory initializes, the component resolves the named collections, computes capacity from the ItemStacks already in the capacity collections, and subscribes to their add and remove notifications. A qualifying addition or removal updates the maximum immediately.

The component does not poll Item attributes. Configure **Use Bag Items** before Play Mode: disabling it stops future add and remove adjustments, but does not clear the contribution already counted, and `RecomputeBagSize()` does not honor the disabled flag. After a deliberate category, attribute-name, or collection-name change, call `RecomputeBagSize()` only when the capacity collections follow the Version 1 safeguards below.

One Dynamic Inventory Size can share a single maximum across several names in **Restricted Item Collection Names**. Its current count is the sum of ItemStacks in all of those collections. Use separate components with unique IDs when Bag and Equipment need independent limits. Every Inventory restriction still participates, so an Item must also pass any category or other restrictions configured on the Inventory.

## Choose what happens when capacity shrinks

**Prevent Remove Bag Item If Would Overflow** rejects removal of a qualifying capacity Item when losing its `BagSize` would place the restricted collections over their new maximum. It does not prevent removal when the remaining capacity is sufficient.

When capacity does shrink below the current stack count, **Remove Option** determines the result:

| Option | Released Version 1 behavior | When to use it |
| --- | --- | --- |
| **Remove Last Items** | Removes complete ItemStacks from the end of the restricted collections' internal order until the count fits. | Use only with a deliberate **Overflow Action** or overflow event that preserves, drops, or reports removed Items. |
| **Remove First Items** | Does not remove anything because the released Version 1 loop condition is incorrect. | Do not use in Version 1. |
| **Do Not Remove** | Leaves the existing Items in place even though the Inventory is over capacity. New additions that require more stacks remain restricted. | Use when another system will resolve the excess, or while validating a setup without destructive overflow. |

The default is **Remove Last Items**, with **Invoke Rejected Event** disabled and no **Overflow Action**. That combination can remove complete stacks without notifying gameplay code, so do not leave it unchanged by accident. “First” and “last” refer to raw collection order, not a sorted Inventory Grid.

Each removed overflow stack is offered to **Overflow Action** first. When **Invoke Rejected Event** is enabled, the component then sends its overflow event and invokes `OnSizeChangeOverflow`.

## Use the limit with a Multi Stack Bag

A [Multi Stack Item Collection](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/multi-stack-item-collection/) can fill compatible existing stacks before it needs another capacity slot. If only one new stack remains, an addition may therefore be partially accepted rather than fully rejected.

For example, with a Health Potion stack size of 10, one existing stack containing 8 Potions can accept 2 more without creating a new stack. Dynamic Inventory Size counts that as the same one occupied space. A request that needs another stack is limited by the remaining **Max Stack Amount**.

Do not use a Multi Stack collection for the capacity Items themselves unless the project has custom handling. Released Version 1 recomputation contributes `BagSize` once per qualifying ItemStack, while runtime add and remove notifications can occur when an existing stack's Amount changes. Stacked or partially removed backpacks can therefore make the running total drift. Dedicated, amount-one capacity Items avoid this mismatch.

## Bind the capacity to an Inventory Grid

The data restriction works without UI. To resize or disable visible slots as the maximum changes:

1. Select the GameObject with the **Inventory Grid**.
2. Add **Dynamic Inventory Size Inventory Grid Binding** beside it.
3. Set **Dynamic Inventory Size ID** to the matching Dynamic Inventory Size **ID**. Enable **Use Tab ID As Size ID** instead when each tab's ID selects a different limit.
4. Assign a text component to **Display Amount**. The released Version 1 binding expects this reference when it finds a matching limit.
5. Keep **Display Amount Format** as `{0}/{1}` to show current ItemStack count over maximum.
6. Enable **Set Max Element Count** to make the grid use the dynamic maximum.
7. Enable **Set Disable Element Option** only when out-of-capacity slots should also be disabled, then choose the matching grid option such as **Disable After Element Count**.

![Dynamic Inventory Size Inventory Grid Binding configured for ID 0 with Current Over Max Text, the {0}/{1} display format, maximum element count enabled, and slots disabled after the element count.](https://opsive.com/wp-content/uploads/2022/04/DynamicInventorySizeInventoryGridBinding.png?v=630f72c5cc0f)

The binding changes grid presentation; it does not replace the Dynamic Inventory Size restriction. Give every Dynamic Inventory Size on one Inventory a unique ID. Duplicate IDs produce a warning and one component replaces the other in the binding's lookup.

## Plan for saving and loading

**Inventory Saver** saves the ItemStacks in each collection. It does not save a separate Dynamic Inventory Size total, so capacity is rebuilt from **Base Max Stack Amount** and the restored capacity Items. **Inventory Grid Saver** is still required when player-arranged grid positions must also persist.

Released Version 1 keeps restrictions and capacity callbacks active during a non-additive load. It clears collections in Inventory order and then restores them in that same order. This creates two decisions to test:

- removing a capacity Item during the clear can be rejected by **Prevent Remove Bag Item If Would Overflow**, or can invoke the selected shrink behavior; and
- restoring Bag before Capacity gives Bag only its base maximum, so later saved stacks may be partially accepted or rejected.

Do not rely on collection order alone to solve both sides of this sequence. Keep **Base Max Stack Amount** large enough for the project's load bootstrap, or provide a project-specific load sequence that restores capacity before restricted contents and deliberately controls shrink side effects. After loading, `RecomputeBagSize()` can synchronize the total only when the capacity collections contain exclusively qualifying amount-one Items.

See [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/) for Inventory and grid savers.

## Editor checkpoint

Before entering Play Mode, confirm that:

- `Bag` and `Capacity` match the Inventory collection names exactly;
- only amount-one **Bag Item** definitions with a positive integer `BagSize` can enter Capacity;
- Bag is present under **Restricted Item Collection Names** and Capacity is present under **Bags Item Collection Names**;
- **Base Max Stack Amount** is positive and is not already below Bag's starting ItemStack count;
- **Remove First Items** is not selected;
- overflow removal is either prevented or paired with an intentional action/event;
- every Dynamic Inventory Size component has a unique **ID**; and
- the Inventory Grid binding has a matching ID and a valid **Display Amount** reference.

## Verify in Play Mode

1. Start without the Small Backpack. Confirm that the UI reads `0/4` and that Bag's maximum is four ItemStacks.
2. Add Items until Bag contains four distinct stacks. Confirm that an addition requiring a fifth stack is rejected, while an Amount that still fits an existing compatible stack may be accepted.
3. Add Small Backpack to Capacity. Confirm that the display changes to `4/8` and four more stacks can be added.
4. Fill Bag above four stacks, then try to remove Small Backpack. With **Prevent Remove Bag Item If Would Overflow** enabled, confirm that removal is rejected.
5. Reduce Bag to four stacks or fewer and remove Small Backpack again. Confirm that removal succeeds and the maximum returns to four.
6. Save and load the Inventory. Confirm that Small Backpack, Bag contents, the displayed maximum, and any saved grid positions all return without rejected or duplicated Items.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| Adding Small Backpack does not increase capacity | **Use Bag Items**, category, `BagSize` type/name, and **Bags Item Collection Names** | Enable bag Items, use the exact category and integer attribute name, and put the Item in the named Capacity collection. |
| Capacity rebuild stops before all backpacks are counted | Whether Capacity contains an ordinary Item or an Item without `BagSize` | Move every unrelated Item out of Capacity and give every remaining Item the expected category and integer attribute. Released V1 stops recomputation at the first invalid stack. |
| Capacity drifts after adding to or partially removing a backpack stack | Whether capacity Items stack or have Amount greater than one | Make each capacity Item an amount-one ItemStack and add or remove complete stacks only. |
| A fifth Health Potion Amount is accepted at a four-stack limit | Whether it fitted an existing compatible stack | This is expected. The restriction limits ItemStacks, not Amount; use a stack-size rule when each stack also needs an Amount limit. |
| Removing a backpack silently removes carried Items | **Remove Option**, **Invoke Rejected Event**, and **Overflow Action** | Enable prevention, select **Do Not Remove**, or configure a tested action/event before allowing the capacity to shrink. |
| **Remove First Items** leaves the Inventory over capacity | Released Version 1 loop limitation | Use **Remove Last Items** or **Do Not Remove**. |
| The grid does not resize | Binding ID, tab ID, and **Set Max Element Count** | Match the component ID or tab ID and enable maximum element count. |
| The grid throws an error while drawing | **Display Amount** reference | Assign a valid text component; released V1 writes to it without a null check. |
| Saved Bag stacks are missing after load | Collection restore order and the base capacity available before Capacity is restored | Increase the load bootstrap capacity or implement and test an explicit capacity-first load workflow. |
| A capacity Item remains or duplicates after non-additive load | Prevention blocked its removal during the clear | Test the clear/shrink policy and use a load workflow that deliberately handles capacity Items. |

## Version 1 Inspector defaults

The released Version 1 component starts with these serialized values:

| Dynamic Inventory Size field | Default |
| --- | --- |
| **ID** | `0` |
| **Inventory** | None; the same-GameObject Inventory initializes it in Play Mode |
| **Base Max Stack Amount** | `99` |
| **Restricted Item Collection Names** | Unset |
| **Use Bag Items** | Enabled |
| **Bag Item Category** | Name `Bag Item`; direct Item Category reference unset |
| **Bag Size Item Attribute Name** | `BagSize` |
| **Bags Item Collection Names** | Unset |
| **Prevent Remove Bag Item If Would Overflow** | Disabled |
| **Size Change Overflow Options > Remove Option** | **Remove Last Items** |
| **Size Change Overflow Options > Invoke Rejected Event** | Disabled |
| **Size Change Overflow Options > Overflow Action** | None |

The released Version 1 grid binding defaults are **Dynamic Inventory Size ID** `0`, **Use Tab ID As Size ID** disabled, **Display Amount** unset, **Display Amount Format** `{0}/{1}`, **Set Max Element Count** enabled, **Set Disable Element Option** disabled, **Disable Element Option** **Do Not Disable Elements**, and **Custom Disable Element Index** `-1`.

## Developer API and events

`MaxStackAmount` returns the clamped sum of `BaseMaxStackAmount` and `BagsStackSize`. `GetCurrentStackAmount()` returns the combined ItemStack count of the restricted collections. `RecomputeBagSize()` rebuilds the bag contribution, while `CanAddItem` and `CanRemoveItem` expose the restriction checks used by Inventory.

Changing `BaseMaxStackAmount` or `BagsStackSize` through their public setters invokes size-change processing. In released V1, those setters pass the changed term rather than the full combined maximum to `OnRestrictedSizeAmountChange`. Verify project-specific runtime changes when both base and bag contributions are nonzero. Changing `UseBagItems` does not reset an already accumulated bag contribution.

The component sends these Opsive events on its Inventory:

- `EventNames.c_Inventory_OnDynamicInventorySizeChange_ID_PreviousSizeInt_NewSizeInt` with `int ID`, `int previousSize`, and `int newSize` whenever size-change processing runs; and
- `EventNames.c_Inventory_OnDynamicInventorySizeChangeOverflow_ItemInfoRemoved` with the removed `ItemInfo` only when shrink overflow removes a stack and **Invoke Rejected Event** is enabled.

Its C# `OnSizeChangeOverflow` callback also receives that removed `ItemInfo` under the same **Invoke Rejected Event** condition. Register and unregister matching event signatures over the same Unity lifecycle. See [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/) for the Version 1 event pattern.

## Related pages

- [Item Restrictions](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-restrictions/)
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/)
- [Multi Stack Item Collection](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/multi-stack-item-collection/)
- [Defining Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/)
- [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/inventory-grid/)
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/)

---

<a id="page-ultimate-inventory-system-item"></a>

# Item

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/item/)

An **Item** is the runtime data record created from an Item Definition. It is not a MonoBehaviour, a Unity Object, an amount, or a place in an Inventory. Use an Item to answer questions such as “which definition is this?” and, for mutable Items, “what is this copy's current Durability?”

The usual path is **Item Category → Item Definition → Item → Item Stack in an Item Collection**. For example, Consumable defines the rules for Health Potion, the Health Potion definition supplies its shared values, and a runtime Item is placed in the player's Bag with an amount.

## Understand the Item data model

| Layer | What it owns | Standard example |
| --- | --- | --- |
| **Item Category** | Structure and rules shared by definitions, including required attributes and the **Mutable** and **Unique** choices | Consumable or Weapon |
| **Item Definition** | The reusable database entry and shared values for one Item type | Health Potion, Iron Sword, or Fire Wand |
| **Default Item** | Starting values for the Item attributes declared by the category | Starting `Durability` for Iron Sword |
| **Item** | A runtime reference, ID, optional custom name, definition, and Item attribute values | One runtime Iron Sword |
| **Item Amount** | An Item plus an integer amount, without location | 5 Health Potion Items |
| **Item Stack** | An Item and amount owned by a specific Item Collection | A stack of 5 Health Potion Items in Bag |
| **Item Info** | An Item Amount plus optional Item Collection and Item Stack context | The exact stack from which 2 potions were removed |

An Item does not contain its own quantity. The collection owns that through an Item Stack. Use [Item Info](https://opsive.com/support/documentation/ultimate-inventory-system/item/item-info/) whenever the source collection, destination collection, stack, or actual amount moved matters.

## Choose mutable, immutable, common, or unique

The Item Definition uses the **Mutable** and **Unique** settings of its direct Item Category.

| Category choices | Runtime behavior | Good fit |
| --- | --- | --- |
| Immutable, common | Equivalent Items can reuse one registered reference and stack together. Their Item attributes cannot be changed after creation. | Health Potion when every copy has the same data |
| Mutable, common | Item attributes can change. Common Items can stack only when their values are equivalent, and collections may treat Items from the same definition as similar. | A stackable resource whose changing values do not need individual identity |
| Immutable, unique | Items do not stack, but their values remain fixed. Do not use this combination when each copy needs changing state or reliable per-copy reference identity. | A non-stackable token with fixed data |
| Mutable, unique | Every Item can retain its own ID and changing Item attributes, and it does not stack. | Iron Sword or Fire Wand with per-copy `Durability` |

**Unique** controls stacking, not the amount requested by an API call. If a collection receives an amount greater than one for a unique Item, Version 1 adds separate amount-one entries and duplicates the Item as required. Use mutable and unique together when individual runtime state must survive.

Be cautious with mutable, common Items. When same-definition Items are merged or treated as similar by a collection, one instance's values may become the values represented by the resulting stack. Prefer mutable, unique Items for equipment, charges, durability, or any other per-copy state.

## Build the standard sample Items

1. Open **Tools > Opsive > Ultimate Inventory System > Main Manager** and select the intended Inventory System Database in **Setup**.
2. Under **Item Categories**, configure Consumable as immutable and common for the stacking sample.
3. Configure Weapon as mutable and unique. Declare shared fields such as `Attack` in the **Item Definition** attribute collection and per-copy fields such as `Durability` in the **Item** attribute collection.
4. Under **Item Definitions**, create Health Potion with Consumable as its **Item Category**.
5. Create Iron Sword and Fire Wand with Weapon as their **Item Category**. Set their definition values, then set their starting `Durability` under **Default Item**.
6. Add the definitions to an Inventory, pickup, Shop, or another system that creates runtime Items. Do not treat the Default Item as a scene object; it supplies the starting Item-level values.

Category attributes describe the category itself. Item Definition attributes are shared by every Item made from that definition. Item attributes are copied from the Default Item and are the only values intended to vary between runtime copies. See [Defining Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/) before moving a field between these layers.

## Follow runtime ownership

The Inventory System Manager's factory creates and registers Items from the active database. An immutable common creation request can return an existing equivalent registered Item rather than allocate a distinguishable copy. A mutable unique Iron Sword receives its own runtime identity.

Items are plain data objects. A scene representation such as a pickup or equipped model is an Item Object that can bind to an Item; it is not the Item itself. Likewise, an Item can exist before it enters an Inventory. Once it enters a collection:

- immutable Items may be represented in several collections because equivalent copies can share a reference;
- a mutable Item tracks one Item Collection at a time;
- adding a mutable Item that already belongs to a different collection causes the receiving collection to duplicate it before adding; and
- collection restrictions can reject all or part of the requested amount, so use the returned Item Info as the result.

For a transfer, remove the Item Info from the source and add the returned result to the destination. Passing only an Item loses the stack and origin information needed for precise moves.

## Editor checkpoint

Before entering Play Mode, confirm that:

- Health Potion uses Consumable, with **Mutable** and **Unique** disabled;
- Iron Sword and Fire Wand use Weapon, with **Mutable** and **Unique** enabled;
- shared values such as `Icon`, `Description`, and `Attack` are set on the definition rather than repeated on runtime Items;
- changing values such as `Durability` are declared as Item attributes and have intentional Default Item values;
- the definitions belong to the same database selected by the scene's Inventory System Manager; and
- Bag contains the intended starting Item Amounts, such as 5 Health Potion Items, 2 Iron Sword Items, and 1 Fire Wand Item.

## Verify in Play Mode

1. Select the player's Inventory and open Bag in the Inspector.
2. Confirm that the 5 Health Potion Items occupy one stack when no stack restriction requires otherwise.
3. Confirm that the two Iron Sword Items appear as separate amount-one entries.
4. Change one Iron Sword's `Durability` through the game's normal action or test workflow. Confirm that the second sword and Fire Wand keep their own values.
5. Move an Iron Sword from Bag to Equipment. Confirm that the returned Item Info identifies the amount and that the Item is no longer represented by the Bag stack.
6. Save, change the mutable Item values, then load. Confirm that each saved Item returns with the correct definition and Item attribute values.

## Save runtime Items deliberately

The database already stores Item Categories and Item Definitions. A save records runtime Item identity and Item attribute state only when another saver, such as an Inventory Saver, reports the relevant Item IDs to the Inventory System Manager Item Saver. The Inventory Saver separately preserves collection contents and amounts so the stacks can be rebuilt.

On load, Version 1 resolves each saved Item from its saved Item Definition ID, restores its serialized Item attributes, and reuses a registered Item when the same Item ID is already present. The manager saver can also preserve custom Item names and direct nested `ItemAmounts` attributes when its corresponding options are enabled.

Custom attribute state on immutable common Items is not a supported save workflow. If an Item's values must change and persist, make its category mutable. Registering an Item at runtime alone also does not make it persistent; a saver must include its ID.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| Health Potion does not stack | Consumable's **Unique** and **Mutable** settings, attribute overrides, and destination restrictions | Use an immutable common category for identical potions and remove unintended per-copy overrides. |
| Two weapons share changing Durability | Weapon's category settings and the attribute collection containing `Durability` | Enable **Mutable** and **Unique**, and declare `Durability` as an Item attribute. |
| A unique add produces several entries | The requested Amount | This is expected: Version 1 expands a unique amount into separate amount-one entries. Request one when only one copy is intended. |
| A moved Item remains associated with the wrong place | Whether code passed a bare Item or an Item Info, and whether it removed from the source first | Transfer the source Item Info and use the returned result from remove and add operations. |
| An Item is rejected as not part of the active database | The scene manager's database and the definition/category references | Select the correct database or replace stale references with objects from the active database. |
| A runtime attribute refuses to change | The category's **Mutable** setting and the attribute's layer | Make the category mutable and place changing data in the Item attribute collection. |
| An Item returns with default values after loading | Inventory Saver coverage and the manager item saver | Ensure the owning Inventory is saved and that its Item IDs are reported before the manager item saver runs. |
| A custom immutable Item does not restore | Whether code created immutable common Items with different Item attribute values | Use a mutable category for persistent custom Item state. |

## Choose the next Item topic

- [Item Info](https://opsive.com/support/documentation/ultimate-inventory-system/item/item-info/) explains Item Amount, Item Stack, Item Collection context, and precise add or remove results.
- [Item Upgrades](https://opsive.com/support/documentation/ultimate-inventory-system/item/item-upgrades/) compares definition inheritance, mutable attributes, nested upgrade Items, and crafting-based progression.
- [Item Skills](https://opsive.com/support/documentation/ultimate-inventory-system/item/item-skills/) presents options for data-driven Item behavior and definition-specific action sets.
- [Item Stats](https://opsive.com/support/documentation/ultimate-inventory-system/item/item-stats/) shows ways to aggregate Item attributes and apply them to characters or equipment.

## Related workflows

- [Terminology](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/terminology/) places Item in the full database-to-Inventory model.
- [Item Category editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-category/) configures attributes, mutability, uniqueness, and inheritance.
- [Item Definition editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-definition/) creates Health Potion, Iron Sword, and Fire Wand definitions and their Default Items.
- [Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/) explains category, definition, and Item attribute inheritance.
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/) configures Bag and Equipment ownership.
- [Item Collections](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/) explains stacks, amounts, restrictions, and collection results.
- [Item Objects](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/) connects Item data to pickups and scene objects.
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/) configures Inventory and Item persistence.
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/) explains safe Version 1 event registration and unregistration.

## Use the Item API

Create Items through the Inventory System Manager so they are initialized against the active database and registered correctly:

```csharp
var potion = InventorySystemManager.CreateItem("Health Potion");

var swordDefinition = InventorySystemManager.GetItemDefinition("Iron Sword");
var sword = InventorySystemManager.CreateItem(swordDefinition);

// Copies the current Item attribute values. The register still applies
// the category's mutable, unique, and equivalence rules.
var swordCopy = InventorySystemManager.CreateItem(sword);
```

An overload accepts a requested ID, but the Item Register assigns a new one when that ID is empty or already belongs to another registered Item. Treat the returned Item's `ID` as authoritative.

Item attribute lookup checks the Item first, then its Item Definition, then its Item Category by default. Use `TryGetAttributeValue` when a field may be absent:

```csharp
if (sword.TryGetAttributeValue<int>("Attack", out var attack)) {
    Debug.Log($"Attack: {attack}");
}

var durability = sword.GetAttribute<Attribute<int>>("Durability");
if (sword.IsMutable && durability != null) {
    durability.SetOverrideValue(durability.GetValue() - 1);
}
```

`OnItemAttributeChange` is a C# event raised for Item attribute changes while the application is playing. Bound Item Objects are refreshed by the same notification. The factory also exposes `OnItemCreation`; remember that an immutable common creation request may return an existing equivalent Item.

```csharp
void WatchItem(Item item)
{
    item.OnItemAttributeChange += OnItemAttributeChanged;
}

void StopWatchingItem(Item item)
{
    item.OnItemAttributeChange -= OnItemAttributeChanged;
}

void OnItemAttributeChanged(AttributeBase attribute)
{
    Debug.Log($"Changed {attribute.Name}");
}
```

Use Item Info for collection operations and inspect the returned Amount rather than assuming the request succeeded in full:

```csharp
var bag = inventory.GetItemCollection("Bag");
var requested = (ItemInfo)(potion, 5);
var allowed = bag.CanAddItem(requested);

if (allowed.HasValue && allowed.Value.Amount > 0) {
    var added = bag.AddItem(requested);
    Debug.Log($"Added {added.Amount} of {added.Item.name}");
}
```

Use `Item.AreValueEquivalent` to compare category, definition, and Item attribute values; `Item.AreStackableEquivalent` to ask whether two Items may share a stack; and `Item.AreSimilar` for the looser collection lookup semantics. Inventory add, remove, rejection, and overflow notifications are named Inventory events rather than Item events; see [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/) for their exact Version 1 payloads.

---

<a id="page-ultimate-inventory-system-item-item-info"></a>

# Item Info

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/item/item-info/)

**Item Info** describes an Item transaction: which Item, how many, and—when known—which Item Collection and Item Stack it came from or is going to. Use it when “2 Health Potion Items” is not enough information and the exact stack in Bag matters.

Item Info is a runtime value, not a database object or an editor asset. Collections, inventory UI, Item Actions, drag-and-drop, Shops, and crafting pass it around so they can keep the Item and its current location context together.

## Read one Item Info

| Property | Meaning | Health Potion example |
| --- | --- | --- |
| `Item` | The runtime Item reference | The Health Potion Item |
| `Amount` | The amount requested, allowed, added, or removed by this particular value | 2 |
| `ItemAmount` | The same Item and Amount packaged together | 2 Health Potion Items |
| `ItemCollection` | The source or destination collection, when known | Bag |
| `ItemStack` | One specific stack in that collection, when known | The stack that currently contains the potion Items |
| `Inventory` | The Inventory obtained from `ItemCollection.Inventory` | The player's Inventory |

The meaning of `Amount` depends on where the Item Info came from. Before a transaction it is a request. A restriction result is the amount permitted. An `AddItem` or `RemoveItem` result is the amount actually processed. Name variables accordingly—`requested`, `allowed`, `added`, and `removed` are clearer than reusing one `itemInfo` variable.

## Choose Item, Item Amount, Item Stack, or Item Info

| Type | Use it when | What it does not tell you |
| --- | --- | --- |
| **Item** | Identity, definition, category, or attributes matter | Amount or location |
| **Item Amount** | Only the Item and a quantity matter | Collection or stack |
| **Item Stack** | You need the live amount in one exact collection stack | A smaller requested or processed amount |
| **Item Info** | You need an amount plus optional origin or destination context | A permanent location or multiple exact stacks |

For an immutable common Health Potion, the same Item reference can appear in several places. The Item Stack distinguishes the stack in Bag from a stack in a chest. For a mutable unique Iron Sword, the Item identifies the individual sword, while Item Info also identifies the stack and collection currently presenting it.

## Follow a Health Potion removal

Suppose Bag contains one stack of 5 Health Potion Items:

1. Converting the stack to Item Info produces `Amount = 5`, `ItemCollection = Bag`, and `ItemStack.Amount = 5`.
2. Create a request for 2 by copying that Item Info and changing only its Amount. The request still points to the exact stack.
3. `Bag.RemoveItem(request)` returns an Item Info whose `Amount` is 2—the amount actually removed.
4. The returned `ItemStack` is the same live stack, which now has `Amount = 3`.

The two amounts are intentionally different: `removed.Amount` describes the transaction, while `removed.ItemStack.Amount` describes what remains.

If the removal empties the stack, Version 1 removes it from the collection, resets it, and returns it to an object pool. The returned Item Info still reports the Item and amount removed, but its stack reference is no longer a durable record of the old location. Do not cache Item Stack references after a transaction; query the collection again when current state matters.

## Use Item Info in UI, actions, and drops

An Item View receives Item Info so separate modules can show the Item's attributes and stack Amount. Selecting a view passes the same context to an Item Action panel. `ItemAction` can obtain its Item User from `ItemInfo.Inventory` when no Item User was supplied explicitly, so a bare Item Info without a collection may not provide enough context for the action.

Drag-and-drop keeps both `SourceItemInfo` and `DestinationItemInfo`. The source stack tells the move which entry to remove, while the destination view and collection decide where the Item can be added. Requery the view or collection after the move because both original values can be stale.

The built-in Drop Item Action can reduce the passed Amount to one, optionally remove that Item Info from its collection, and then create the pickup. When **Remove On Drop** is enabled, pass Item Info that includes the real source collection and ensure removal is allowed. A bare Item Info has no collection to remove from.

## Prepare a runtime checkpoint

There is no Item Info asset to configure. Prepare a scene that makes the value observable:

1. Give the player an Inventory with a collection named Bag.
2. Add 5 Health Potion Items and 1 Iron Sword to Bag's starting Item Amounts.
3. Bind an Inventory Grid or Item View Slots Container to that Inventory and collection.
4. Include an action that removes or consumes one Health Potion and a move from Bag to Equipment for Iron Sword.
5. Add Inventory Saver and the Save System only when the test should include persistence.

Before entering Play Mode, confirm that the grid reads from Bag, the actions receive the selected Item View Slot's Item Info, and the active database contains both definitions.

## Verify in Play Mode

1. Select Health Potion in the inventory UI. Confirm that its view reports the stack amount of 5 and belongs to Bag.
2. Remove or consume 2. Confirm that the transaction result reports 2 while the refreshed stack and UI report 3.
3. Remove the remaining 3. Confirm that the slot clears and that later code obtains a new Item Info instead of using the emptied stack reference.
4. Drag Iron Sword from Bag to Equipment. Confirm that the source entry clears, the destination receives the exact sword, and both views redraw.
5. Attempt a move that a destination restriction rejects. Confirm that the processed Amount is zero or smaller than requested and that rejected overflow is handled.
6. Save and load. Confirm that the Inventory rebuilds the Item Stacks, then requery Item Info rather than comparing the new stack references with values captured before loading.

## Interpret collection results safely

| API shape | Failure or partial result |
| --- | --- |
| `GetItemInfo(...)` | Returns nullable `ItemInfo?`; no matching entry is `null`. |
| `CanAddItem(...)` and `RemoveItemCondition(...)` | Return nullable `ItemInfo?`; `null` rejects the operation, while a smaller Amount permits only part. |
| `AddItem(...)` and `RemoveItem(...)` | Return non-nullable Item Info; inspect `Amount`, which is normally 0 when nothing was processed. |
| `GiveItem(...)` | Returns nullable Item Info and removes before adding. If the destination accepts only part, the rejection callback receives the remainder; the callback must decide how to handle or return it. |

`ItemInfo.None` is the default value: null Item, zero Amount, null collection, and null stack. A failed add or remove can instead return zero Amount with a non-null Item or collection, so `result == ItemInfo.None` is not a general success test. Check `Amount` and, when needed, `Item`.

## Know the serialization and lifetime limits

Item Info is marked serializable, but only its Item Amount field is serialized. Item Collection and Item Stack are explicitly nonserialized runtime references. Saving an Item Info directly therefore does not preserve its origin.

The Version 1 Inventory Saver stores Item ID and Amount per collection. On load it resolves the Items and rebuilds the stacks. Grid and Item View Slots Container savers separately restore presentation indexes where configured. Requery Item Info after loading.

One Item Info can point to only one Item Stack. Some aggregate operations cannot represent every resulting stack:

- adding an amount greater than one for a unique Item creates separate amount-one entries, while the returned Item Info can report the total Amount and reference only the first resulting stack; and
- removing by Item Definition across several stacks can report the total removed Amount while retaining only the final stack context.

Operate one stack at a time when every exact source or destination must be retained.

Item Info is a value-type snapshot, but its Item, Item Collection, and Item Stack members are references. Copying Item Info copies those references; it does not clone the stack. Delayed actions, confirmation panels, and asynchronous code should verify that the Item still exists in the expected collection before changing it.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| `ItemInfo.Inventory` is null | Whether `ItemCollection` is present | Construct the value from a live stack or include the source collection, or pass the Item User explicitly. |
| A remove affects the wrong stack | Whether the request includes the selected `ItemStack` | Copy the selected stack's Item Info and change only the requested Amount. |
| The returned Amount and stack Amount differ | Whether the operation was a partial removal | Read `ItemInfo.Amount` as processed and `ItemStack.Amount` as remaining. This difference is expected. |
| A cached stack suddenly contains no Item or different data | Whether its stack was emptied, pooled, and later reused | Do not retain stack references after collection changes; requery the collection or UI. |
| Code treats a rejected operation as success | Whether it compares only with `ItemInfo.None` | Check `Amount > 0`, and compare it with the requested Amount when full completion is required. |
| Drag-and-drop duplicates or loses an Item | Source collection/stack context and rejected remainder handling | Use the source Item Info, remove first, add the actual removed Amount, and explicitly handle any remainder. |
| Drop creates a pickup without reducing Bag | **Remove On Drop**, source collection context, and removal restrictions | Enable removal, pass the live source Item Info, and confirm the collection can remove the requested Amount. |
| An old Item Info is wrong after loading | Nonserialized collection/stack references | Requery the rebuilt Inventory or Item View Slots Container after load. |

## Related workflows

- [Item](https://opsive.com/support/documentation/ultimate-inventory-system/item/) explains runtime identity, mutability, uniqueness, and attribute ownership.
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/) configures Bag and Equipment.
- [Item Collections](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/) explains stack ownership, add/remove results, and overflow.
- [Multi Stack Item Collection](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/multi-stack-item-collection/) creates several stacks for one common Item.
- [Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/) uses Item Info to invoke actions on selected Items.
- [Move Items with drag and drop](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/move-items-drag-drop/) configures source and destination UI context.
- [Item View](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/item-view/) displays Item Info through UI modules.
- [Item and Currency Droppers](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-and-currency-droppers/) creates runtime drops and pickups.
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/) rebuilds Inventory contents and UI positions.
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/) explains safe Version 1 event registration and unregistration.

## Use the Item Info API

### Construct values without losing context

Create a bare request when only Item and Amount matter:

```csharp
var potion = InventorySystemManager.CreateItem("Health Potion");
var request = new ItemInfo(potion, 5);
```

Constructors that receive an Item Definition or name call `InventorySystemManager.CreateItem` immediately. They are convenient, but constructing the Item Info also creates or resolves a registered runtime Item.

Create a full value from a stack, or preserve an existing value's collection and stack while changing the Amount:

```csharp
var current = bag.GetItemInfo(potion);
if (current.HasValue) {
    var removeTwo = new ItemInfo(2, current.Value);
    var removed = bag.RemoveItem(removeTwo);

    Debug.Log($"Removed: {removed.Amount}");
    Debug.Log($"Remaining in referenced stack: {removed.ItemStack?.Amount ?? 0}");
}
```

The public constructors cover Item Amount with optional collection and stack, Item with Amount, Item Definition or name with Amount, copying another Item Info with a new Item Amount or Amount, and creating from an Item Stack. Tuple conversions with collection or stack context are implicit; bare Item/Amount, Item Amount, and Item Stack conversions are explicit.

```csharp
ItemInfo destinationRequest = (potion, 5, bag);
ItemInfo exactStackRequest = (potion, 2, bag, destinationStack);
ItemInfo fromStack = (ItemInfo)destinationStack;
ItemInfo bareRequest = (ItemInfo)(potion, 5);
```

A null Item Stack converts to `ItemInfo.None`.

### Check, add, remove, and transfer

Check the permitted result, then inspect the actual result independently because collection state can change between calls:

```csharp
var requested = (ItemInfo)(potion, 5);
var allowed = bag.CanAddItem(requested);

if (allowed.HasValue && allowed.Value.Amount > 0) {
    var added = bag.AddItem(requested);
    var complete = added.Amount == requested.Amount;
    Debug.Log($"Added {added.Amount}; complete: {complete}");
}
```

For an exact transfer, start with the source stack's Item Info and use the amount actually removed:

```csharp
var source = bag.GetItemInfo(potion);
if (source.HasValue) {
    var requestedMove = new ItemInfo(2, source.Value);
    var removed = bag.RemoveItem(requestedMove);
    var added = storage.AddItem(new ItemInfo(removed.Item, removed.Amount));

    if (added.Amount < removed.Amount) {
        var remainder = new ItemInfo(removed.Item, removed.Amount - added.Amount);
        bag.AddItem(remainder);
    }
}
```

Use `GiveItem` when its remove-first behavior and rejection callback match the workflow. The callback receives rejected Item Info; it does not automatically choose where the remainder should go.

### Compare Item Info values

`ItemInfo.Equals`, `==`, and `!=` compare the complete Item Amount, Item Collection, and Item Stack. In released Version 1 this effectively requires the same Amount and Item reference plus the same collection and stack references. Two values describing equal amounts in different stacks are not equal.

Do not use equality to ask whether Items can stack or are value-equivalent. Use the Item comparison methods described on the [Item](https://opsive.com/support/documentation/ultimate-inventory-system/item/) page.

### Listen for transaction results

The Item Collection exposes C# events, and an Inventory with that collection sends matching named events:

| Notification | Payload |
| --- | --- |
| `ItemCollection.OnItemAdded` | The admitted Item Info, including origin context, and the destination Item Stack |
| `EventNames.c_Inventory_OnAdd_ItemInfo_ItemStack` | The same add payload on the Inventory; the named event is sent in Play Mode |
| `ItemCollection.OnItemRemoved` | Item Info containing the amount actually removed and the source context |
| `EventNames.c_Inventory_OnRemove_ItemInfo` | The same removed Item Info on the Inventory |
| `ItemCollection.OnItemAddOverflow` | Original, added, and rejected Item Info values when rejected events are enabled |
| `EventNames.c_Inventory_OnAddItemRejected_ItemInfoToAdd_ItemInfoAdded_ItemInfoRejected` and `EventNames.c_Inventory_OnAddItemOverflow_ItemInfoToAdd_ItemInfoAdded_ItemInfoRejected` | Requested, added, and rejected Item Info values |

Specific add or remove callbacks run before the collection update notification. The Inventory listens to the collection update, refreshes its cached Item Info list, and then sends `EventNames.c_Inventory_OnUpdate`.

```csharp
private void OnEnable()
{
    EventHandler.RegisterEvent<ItemInfo, ItemStack>(
        inventory,
        EventNames.c_Inventory_OnAdd_ItemInfo_ItemStack,
        OnItemAdded);

    EventHandler.RegisterEvent<ItemInfo>(
        inventory,
        EventNames.c_Inventory_OnRemove_ItemInfo,
        OnItemRemoved);
}

private void OnDisable()
{
    EventHandler.UnregisterEvent<ItemInfo, ItemStack>(
        inventory,
        EventNames.c_Inventory_OnAdd_ItemInfo_ItemStack,
        OnItemAdded);

    EventHandler.UnregisterEvent<ItemInfo>(
        inventory,
        EventNames.c_Inventory_OnRemove_ItemInfo,
        OnItemRemoved);
}

private void OnItemAdded(ItemInfo addedInfo, ItemStack destinationStack)
{
    Debug.Log($"Added {addedInfo.Amount} to a stack of {destinationStack.Amount}");
}

private void OnItemRemoved(ItemInfo removedInfo)
{
    Debug.Log($"Removed {removedInfo.Amount}");
}
```

Always unregister the same delegate and signature that were registered. Requery the collection inside delayed work rather than retaining the event's Item Stack reference.

---

<a id="page-ultimate-inventory-system-item-item-upgrades"></a>

# Item Upgrades

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/item/item-upgrades/)

Ultimate Inventory System Version 1 does not include a standalone item-upgrade subsystem. It provides the Item Definition relationships, attributes, inventory transactions, crafting framework, and demo examples from which you can build the upgrade rules that fit your game.

For a short, authored path such as **Iron Sword → Iron Sword +1**, use parent and child Item Definitions. Use mutable Item attributes when every weapon can grow independently, or adapt the demo's slot system when Items can hold reusable upgrade Items.

## Choose an upgrade model

| Desired result | Recommended model | Important trade-off |
| --- | --- | --- |
| A finite path with known results, such as Iron Sword → Iron Sword +1 → Iron Sword +2 | Parent and child Item Definitions | Easy to inspect, but every upgrade tier is another definition. |
| Per-instance levels, rolls, or procedural growth | Mutable Item attributes | Scales without more definitions, but project code must calculate and present every result. |
| Runes, gems, or parts that can be inserted and removed | Upgrade Items stored in an `ItemAmounts` attribute | Flexible, but the included implementation is a demo to copy and adapt, not a production subsystem. |
| An upgrade that consumes ingredients through the Crafting Menu | Crafting Recipe with a custom Crafting Processor | Reuses crafting selection and events, but changing the input Item requires custom transaction logic. |

Choose one model as the source of truth. Mixing a definition tier, a runtime `Level`, and slotted upgrades is possible, but define the order in which those values are combined so the same Item always resolves to the same result.

## Build Iron Sword → Iron Sword +1

This definition-based workflow is the clearest starting point for a small, linear upgrade path.

1. Open **Tools > Opsive > Ultimate Inventory System > Main Manager** and select **Item Categories**.
2. Select **Weapon**. In **Attributes > Item Definition**, confirm that `Attack` exists as an `int`.
3. Add an Item Definition attribute named `Upgrade` with the type `ItemDefinition`. This is a project-defined link; UIS does not interpret the name automatically.
4. Open **Item Definitions** and create **Iron Sword** and **Iron Sword +1**. Give both definitions the same direct **Item Category**, Weapon.
5. Select Iron Sword +1 and set **Parent** to Iron Sword. Parent and child definitions must use the same direct Item Category.
6. On Iron Sword +1, set `Attack` to **Modify** with the expression `<Inherited> + 2`, or use **Override** when the upgraded value should not depend on its parent.
7. On Iron Sword, set `Upgrade` to Iron Sword +1. Leave `Upgrade` empty on the final tier, or point it at the next child when another tier exists.
8. Add project-owned upgrade logic, such as an Item Action or menu command, that reads `Upgrade`, checks the cost and requirements, then replaces one selected Iron Sword with one Item created from Iron Sword +1.

At the editor checkpoint, Iron Sword +1 should show Iron Sword as its **Parent**, the relationship view should show it below Iron Sword, and its resolved `Attack` should be two points higher. The base Iron Sword's `Upgrade` value should point at Iron Sword +1.

An Item Definition relationship supplies inheritance; it does not define upgrade direction, cost, eligibility, or replacement. The custom `Upgrade` attribute and your project logic provide those rules. A custom requirements type is optional. For a small game, separate attributes such as `UpgradeGoldCost` and `RequiredLevel` are often easier to inspect.

## Replace the Item safely

Treat a definition upgrade as an inventory transaction, not as a rename. Iron Sword +1 creates a new Item from a different Item Definition.

1. Start with the selected [Item Info](https://opsive.com/support/documentation/ultimate-inventory-system/item/item-info/) so the source Item Collection and actual amount are known.
2. Resolve and validate the next Item Definition, payment, level, and any other requirements before changing the Inventory.
3. Create the replacement Item and check the destination collection's restrictions. Equipment slots may accept Iron Sword but reject Iron Sword +1 if its category or slot rules differ.
4. Remove one original Item and add one replacement Item as one project-controlled operation. Check the `Amount` returned by both operations and restore the original when the replacement is rejected.
5. Explicitly copy any state that should survive, such as current Durability. The new definition's Default Item supplies new starting values; UIS does not automatically map runtime attributes from the old Item.
6. Charge the cost only after the Item exchange can complete, or restore both the Item and payment on failure.

Inventory add and remove notifications update collection-driven views. If a custom panel holds its own selected Item Info, assign the returned replacement Item Info and redraw that panel rather than continuing to display the removed Item.

## Use mutable Item attributes for open-ended progression

Use this model when one Iron Sword can be level 7 while another Iron Sword remains level 1.

1. In Weapon's **Attributes > Item**, add the per-instance values, such as `Level` and `Attack`.
2. In Weapon's **Properties**, enable **Mutable** and **Unique**. Mutable allows runtime Item attributes to change; Unique keeps two weapons with different state from stacking as one Item.
3. Set the starting values in Iron Sword's **Default Item** attributes.
4. In project code, verify the cost, calculate the next values, and set the Item attribute overrides.
5. Let the Item attribute change notification refresh bound Item Objects, and explicitly redraw any custom UI that caches values.

This changes the existing runtime Item rather than replacing its definition. It works well for procedural growth, but the database no longer shows every possible tier. Save the Inventory and the mutable Item state before relying on the values across sessions.

Do not use a mutable, common Item for equipment whose upgrade state must remain independent. Similar common Items may be merged or represented by one stack, which makes per-copy progression ambiguous.

## Adapt the demo slot-upgrade example

The demo's **Upgrade Menu** and **Item Upgrade Panel** are sample scripts. `UpgradeMenu` identifies itself as demo code and instructs developers to copy and adjust it; these classes are not a general core upgrade component.

The sample uses these data contracts:

- The upgradable Item has `SlotCount` as an `int` and `Slots` as `ItemAmounts`.
- The panel exposes **Upgradable Item View**, **Upgrade Item View Slots**, **Upgrade Item Removers**, **Slot Count Attribute Name**, and **Slots Attribute Name**.
- When the two name fields are blank, the setup uses `SlotCount` and `Slots`.
- Upgrade Items contribute `BoostConstant` and `BoostMultiplier` values.
- The demo recalculates weapon `Attack` from `BaseAttack` and armor `Defense` from `BaseDefense` whenever a slot changes.

Copy the sample scripts into a project-owned namespace before changing their rules. Decide which Item Categories accept which upgrade Items, validate every inventory removal and return, and make the slot change transactional. The demo panel performs its own preview, redraw, and Item-change callbacks; a different UI must provide equivalent refresh behavior.

Because `Slots` contains runtime Items, enable **Using Nested Items** on `InventorySystemManagerItemSaver`. Version 1 saves nested Items in Item attributes only one level deep, so an upgrade Item should not contain another nested Item that also needs saving.

## Use crafting for ingredient-driven upgrades

A Crafting Recipe can express a requirement such as one Weapon plus upgrade materials. The built-in Simple Crafting Processor can select and consume ordinary ingredients and create declared results, but it does not infer how an arbitrary input weapon becomes its next tier.

Use a [custom Crafting Processor](https://opsive.com/support/documentation/ultimate-inventory-system/crafting/custom-crafting-processors/) when the result depends on the selected Iron Sword, its current attributes, or the material mix. The processor should validate the exact selected Item Info, calculate or resolve the replacement, and complete the remove/add operation without losing the original on failure.

Use crafting when the Crafting Menu is the player-facing upgrade flow. Use an Item Action or dedicated menu when the upgrade begins from an inventory selection and does not need the recipe interface.

## Verify in Play Mode

Test upgrades with two different Iron Sword Items so shared-state mistakes are visible.

1. Put two Iron Sword Items and the required Gold or materials in **Bag**.
2. Upgrade one sword. Confirm that only the selected Item changes and the other sword keeps its original definition or attributes.
3. Move or equip the upgraded sword. Confirm that Equipment restrictions accept it and the Item View shows the new name, icon, and resolved `Attack`.
4. Attempt the upgrade without enough resources and with a full or rejecting destination. The original sword and its payment should remain unchanged.
5. Save, change scenes or restart Play Mode as required by the test setup, then load. Confirm the upgraded definition or mutable attributes return correctly.
6. For the slot model, remove and reinsert an upgrade Item and confirm that both the calculated stat and the nested Item survive save and load.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| Iron Sword +1 cannot use Iron Sword as its Parent | Compare the two definitions' direct **Item Category** values. | Assign both to Weapon; parent and child definitions must share the same direct category. |
| `Attack` does not increase | Inspect the child's `Attack` Variant and modify expression. | Use **Modify** with `<Inherited> + 2`, or set the intended value with **Override**. |
| The upgraded Item disappears | Compare the returned `Amount` from removal and addition, and inspect destination restrictions. | Validate first, handle partial results, and restore the original Item when the replacement cannot be added. |
| Upgrading one weapon changes or merges another | Check Weapon's **Mutable** and **Unique** settings. | Use mutable, unique Items for independent per-instance state. |
| The UI still shows the old sword | Check whether the panel retained its old selected Item Info. | Assign the returned replacement Item Info and redraw or refresh the custom panel. |
| Slotted upgrade Items are missing after load | Inspect `InventorySystemManagerItemSaver` and the nesting depth. | Enable **Using Nested Items** and keep saved nested Items to one level. |
| A Crafting Recipe accepts materials but produces the wrong weapon | Check whether it uses a built-in processor with a fixed result. | Use a custom Crafting Processor that reads the selected input Item and resolves its next definition or attributes. |

## Current Version 1 boundaries

- There is no built-in Upgrade Manager, universal level formula, cost model, or upgrade button.
- A Parent relationship provides inheritance only. It does not mean “upgrade to this child,” and a parent can have more than one child.
- Changing a runtime Item's Item Definition in place is not the supported definition-tier workflow. Create the replacement from the next definition and exchange it through its collection.
- Mutable Item values require a mutable Item Category. Use Unique when each copy needs independent progression.
- The demo slot-upgrade scripts are samples and do not guarantee rollback when a collection rejects an Item.
- Nested Item saving supports one level through **Using Nested Items**.

## Related pages

- [Item Definition](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-definition/) explains categories, parents, Default Item values, and relationship views.
- [Defining Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/) explains where Item Definition and Item values belong.
- [Item Stats](https://opsive.com/support/documentation/ultimate-inventory-system/item/item-stats/) covers attribute variants, runtime mutation, and stat consumers.
- [Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/) is the starting point for an upgrade command launched from an Item selection.
- [Custom Crafting Processors](https://opsive.com/support/documentation/ultimate-inventory-system/crafting/custom-crafting-processors/) shows how to extend validation and result creation.
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/) covers the manager and Inventory savers required for runtime Item state.
- [Demo Scene](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/demo-scene/) explains how to study sample-only systems without treating them as core production components.

## Developer reference

- `ItemDefinition.Parent`, `ChildrenReadOnly`, and `SetParent` expose the definition relationship. Author database relationships in the Main Manager so asset changes are explicit.
- `InventorySystemManager.CreateItem(ItemDefinition, ...)` creates the replacement Item from the next definition.
- `Item.TryGetAttributeValue<T>` reads resolved values. `Item.GetAttribute<Attribute<T>>` retrieves a typed Attribute, and `Attribute<T>.SetOverrideValue` changes a mutable runtime Item attribute and sends its change notification.
- `ItemCollection.CanAddItem`, `AddItem`, and `RemoveItem` return or accept Item Info. Inspect the returned `Amount`; an attempted transaction is not proof that the full amount moved.
- `CraftingProcessor` provides ingredient selection, `CanCraft`, and the protected `CanCraftInternal` and `CraftInternal` extension points. Derive from `SimpleCraftingProcessor` when its standard ingredient handling remains useful.

Keep the upgrade formula, eligibility check, payment, Item exchange, and UI refresh in one project-owned service or action. That prevents different menus from applying subtly different upgrade rules.

---

<a id="page-ultimate-inventory-system-item-item-skills"></a>

# Item Skills

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/item/item-skills/)

Use an Item as a skill when two definitions in the same category need different behavior. For example, Iron Sword and Fire Wand can both be Weapon Items and share Equip and Drop actions, while **Use** performs a sword strike for one definition and casts a projectile for the other.

In released Version 1, the practical data-driven pattern is to store an **Item Action Set** reference in an Item Definition attribute. A shared **Use Item Action Set Attribute** action reads that reference from the selected Item and invokes one action by index. This keeps the common UI workflow on Weapon while letting each definition choose its own result.

## Choose the behavior layer

| Need | Recommended Version 1 route | Example |
| --- | --- | --- |
| Every Item in a category uses the same inventory action | Map an Item Action Set through a Category Item Action Set | Every Weapon can Equip or Drop |
| Definitions in one category need different actions | Store an Item Action Set as an Item Definition attribute and invoke it with Use Item Action Set Attribute | Iron Sword strikes; Fire Wand casts |
| The behavior needs an equipped prefab, animation point, or scene component | Put Item Object Behaviours on the usable Item Object and trigger them through Usable Equipped Items Handler | Swing the equipped sword model or spawn from the wand tip |
| The action needs both definition data and a character system | Use a custom Item Action selected by the definition, then obtain the character component from Item User | Fire Wand checks and spends mana |

Keep ordinary inventory actions category-driven. Use the definition attribute only for behavior that truly changes by definition; otherwise every new definition requires another asset assignment.

## Build the Iron Sword and Fire Wand example

### Declare definition attributes

1. Open **Tools > Opsive > Ultimate Inventory System > Main Manager**.
2. Under **Item Categories**, select Weapon.
3. In the **Item Definition** attribute collection, add an attribute named `ItemActionSet` whose value type is `ItemActionSet`.
4. Add a float Item Definition attribute named `Cooldown` when the two skills need different reuse times.

These values belong on the definition because all runtime copies of Iron Sword should select the same skill asset, while Fire Wand selects another. Put the reference on an Item attribute only when individual runtime copies genuinely need different behavior and the category is mutable.

The legacy example below calls the assigned asset `Throwable Item Action`; in this workflow, the same override field points to `Iron Sword Skill Actions` or `Fire Wand Skill Actions`.

![An ItemActionSet attribute overriding its inherited value with the Throwable Item Action asset.](https://opsive.com/wp-content/uploads/2020/06/ItemActionSetAttribute.webp?v=f15c48fb821c)

### Create the definition-specific action sets

1. Use **Create > Ultimate Inventory System > Item Actions > Item Action Set** to create `Iron Sword Skill Actions`.
2. Set **Item Category** to Weapon and add the action that performs the sword skill under **Item Actions**.
3. Create `Fire Wand Skill Actions`, set **Item Category** to Weapon, and add the action that performs the wand skill.
4. In **Item Definitions**, assign the first asset to Iron Sword's `ItemActionSet` value and the second to Fire Wand's value.
5. Set `Cooldown` to an intentional value for each definition, such as a shorter sword delay and a longer wand delay.

The built-in Item Actions mostly operate on inventory and UI state. The actual strike, spell, mana system, animation, or projectile is game-specific, so implement that part as a custom Item Action or an Item Object Behaviour.

### Add the shared Use action

1. Create an Item Action Set named `Weapon Skill Entry`.
2. Set **Item Category** to Weapon.
3. Add **Use Item Action Set Attribute** to **Item Actions**.
4. Set **Attribute Name** to `ItemActionSet` and **Action Index** to the action that should run from each assigned asset.
5. Keep **Use One** enabled when the nested action should receive Amount 1.
6. Keep **Remove On Use** disabled for Iron Sword and Fire Wand. Enable it only for a consumable skill Item that should be removed after use.
7. Set **Cooldown Attribute Name** to `Cooldown` and **Cooldown Item User Data Name** to `ItemCooldown` when using the built-in cooldown path.

![An Item Action Set for Usable Item with Use Item Action Set Attribute targeting ItemActionSet at index 0, Use One enabled, and Remove On Use disabled.](https://opsive.com/wp-content/uploads/2020/11/UseItemActionSetExample.png?v=760d9244d8c0)

The legacy crop ends after **Remove On Use**. Scroll the selected action to configure **Cooldown Attribute Name** and **Cooldown Item User Data Name** when those controls are below the visible Inspector area.

**Use One** does not consume an Item; it only changes the Item Info Amount passed to the nested action. **Remove On Use** removes that amount after the nested action is invoked.

### Expose the action in inventory UI

1. Create or select the **Category Item Action Set** used by the inventory grid or hotbar.
2. Add `Weapon Skill Entry` alongside the Item Action Sets that provide Equip, Drop, or Assign actions.
3. On the Item View Slots Container, use **Item View Slots Container Category Item Action Set Binding** and assign that Category Item Action Set.
4. Keep **Auto Set Item User** enabled when the bound Inventory's Item User should execute the skill.
5. Set **Use Item Action Index** only when click or hotbar input should invoke one fixed action. `-1` invokes all available actions, which is rarely appropriate when Equip, Drop, and Use are all present.

The category binding assembles the actions that match the selected Item. When Use runs, the wrapper resolves `ItemActionSet` from Iron Sword or Fire Wand and invokes the configured nested index.

## Decide how input reaches the skill

For inventory or hotbar use, let the Item View Slots Container binding pass the selected Item Info and Item User to the action. **Item Hotbar Handler** maps each configured input to a hotbar slot, and that slot invokes its configured Item Action.

For behavior tied to an equipped GameObject:

1. Give the Weapon definition a **Usable Item Prefab** that contains an Item Object.
2. Add **Item Object Behaviour Handler** beside the Item Object and place the sword or wand behaviors in **Item Object Behaviours**.
3. Add **Usable Equipped Items Handler** to the character with the Equipper and Item User.
4. In **Inputs**, map each input to an **Item Object Index** and **Action Index**.

The handler asks the Equipper for the Item Object in that slot and invokes the matching Item Object Behaviour. Its base cooldown is `CanUse => Time.time >= m_NextUseTime`; a custom behavior sets `m_NextUseTime` after use.

Use this equipped-object route when the skill must work with a model, muzzle, animation, or another scene component. Use the Item Action Set attribute route when the skill can run from Item data and Item User alone. A project can combine both, but keep one system responsible for the actual effect so input does not trigger it twice.

## Configure cooldowns and costs deliberately

Use Item Action Set Attribute looks for a float attribute named by **Cooldown Attribute Name**. When present, it stores the next allowed time on Item User under **Cooldown Item User Data Name**, keyed by the Item ID. It sends `EventNames.c_CharacterGameObject_UsedItemActionWithCooldown_ItemAction_ItemInfo_Float` on the Item User GameObject after use.

A **Cooldown Item View** module can display that timer. Its **Item User Inventory ID**, **Cooldown Attribute Name**, and **Cooldown Item User Data Name** must identify the same user and names used by the action.

Version 1 does not provide a general mana, stamina, currency, or ingredient cost field on Use Item Action Set Attribute. **Remove On Use** only consumes the selected Item. For another cost, use one custom Item Action that checks the resource in `CanInvokeInternal`, applies the effect, and deducts the cost in a controlled order.

The wrapper invokes the nested action and then applies Remove On Use and cooldown. Because Item Action invocation returns no success result, the wrapper cannot know whether the nested action's own `CanInvoke` rejected it. Do not enable consumption or cooldown around a nested action that may refuse unless a custom wrapper coordinates the whole transaction.

## Editor checkpoint

Before entering Play Mode, confirm that:

- Weapon declares `ItemActionSet` and optional `Cooldown` in the Item Definition attribute collection;
- Iron Sword references `Iron Sword Skill Actions` and Fire Wand references `Fire Wand Skill Actions`;
- both definition-specific assets contain the intended action at the wrapper's **Action Index**;
- `Weapon Skill Entry` contains Use Item Action Set Attribute with matching attribute and cooldown names;
- **Remove On Use** is disabled for the reusable Weapon Items;
- the Category Item Action Set includes `Weapon Skill Entry` and the UI uses Item View Slots Container Category Item Action Set Binding;
- the binding supplies an Item User, especially when a `Cooldown` attribute is present;
- Cooldown Item View uses the same Inventory ID and data names when an overlay is required; and
- any equipped-object implementation has the intended Usable Item Prefab, behavior order, Item Object Index, and Action Index.

## Verify in Play Mode

1. Put Iron Sword and Fire Wand in Bag and open the inventory UI.
2. Select each Item and confirm that the common Equip and Drop actions appear with Use.
3. Invoke Use on Iron Sword. Confirm that only the sword action runs and the sword remains in Bag.
4. Invoke Use on Fire Wand. Confirm that only the wand action runs and the correct character or projectile source is used.
5. Invoke each skill again during its cooldown. Confirm that CanInvoke blocks it and the cooldown overlay shows the remaining time.
6. Use the hotbar or configured input. Confirm that it supplies the correct slot's Item Info and the player's Item User.
7. Equip the Items when using Item Object Behaviours. Confirm that the input invokes the behavior index on the equipped Item Object rather than the inventory action a second time.
8. Save and load. Confirm that the Item definitions still reference their action assets. Expect the built-in Item User cooldown timer to reset unless the project adds custom persistence for it.

## Save and lifetime behavior

Item Action Sets and definition attribute references are project assets, so they remain part of the Inventory System Database setup. Inventory saving restores Items and their saved Item attributes; it does not serialize the runtime Item Action objects as new save data.

Item User stores cooldowns and other action data in a runtime dictionary initialized during `Awake`. The built-in save system does not persist this dictionary. Arbitrary Item Object Behaviour fields and active scene effects are also outside the Inventory Saver's scope. Add a project-specific saver when cooldown progress or behavior state must survive loading.

Item Action Sets deserialize and initialize their Item Action collection for runtime use. Treat the actions in an asset as shared configuration. Do not store per-character or per-use state inside an Item Action unless the implementation deliberately separates that state by Item User or Item.

## Current Version 1 boundaries

- Use Item Action Set Attribute selects exactly one nested action by **Action Index**; it does not select by action name or automatically invoke the entire assigned set.
- The wrapper reads `ItemActionSet` through the Item attribute lookup, but it does not validate the assigned asset's Item Category or Exception Categories before invoking it.
- `ItemActionSet.MatchItem` checks Item Category. Exception Categories are applied while `CategoryItemActionSet.GetItemActionsForItem` builds the UI list, but the direct `UseItemAction` and `UseAllItemActions` methods do not apply those exceptions.
- A Cooldown attribute requires a valid Item User. Direct code that supplies null can fail when the wrapper tries to read or write Item User data.
- Cooldown is keyed by Item ID for each Item User. Immutable common Items that share an ID also share that user's cooldown entry; mutable unique Iron Sword and Fire Wand Items keep separate entries.
- Remove On Use does not verify the amount actually removed, and it runs after nested invocation. Use a custom transactional action when inventory restrictions or other costs can reject the operation.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| Iron Sword and Fire Wand run the same skill | Each definition's `ItemActionSet` value and the layer where it was declared | Keep the declaration on Weapon but assign different values on the two definitions. |
| Use does not appear | Category Item Action Set, Weapon Skill Entry category, UI binding, and **Max Number Of Actions** | Add the entry asset, assign the category binding, and allow enough displayed actions. |
| Use appears but nothing happens | **Attribute Name**, missing asset, **Action Index**, and the nested action's CanInvoke result | Match the attribute name exactly, assign a nonempty asset, and choose a valid index. |
| Cooldown use throws or stops unexpectedly | Item User and **Auto Set Item User** | Add Item User to the bound Inventory owner or pass it explicitly. |
| Cooldown works but the overlay does not | Item User Inventory ID and both cooldown names on Cooldown Item View | Match the action fields and point the module at the correct Inventory Identifier. |
| The Weapon disappears after Use | **Remove On Use** and **Use One** | Disable Remove On Use for reusable equipment; Use One alone does not consume it. |
| Mana or currency is never charged | The selected wrapper has no generic cost field | Implement the check and deduction in the nested custom Item Action. |
| An excluded category still runs through code | Whether the project calls CategoryItemActionSet directly | Apply the exception check in project code or use the category UI lookup path. |
| Cooldown vanishes after load | Item User runtime data is not saved | Accept a fresh cooldown or add a custom saver for next-use times. |
| Equipped input does nothing | Usable Item Prefab, Equipper slot, behavior array, Item Object Index, and Action Index | Confirm the prefab spawned in the expected slot and both indexes match the configured arrays. |

## Related workflows

- [Item](https://opsive.com/support/documentation/ultimate-inventory-system/item/) explains category, definition, and runtime Item ownership.
- [Item Info](https://opsive.com/support/documentation/ultimate-inventory-system/item/item-info/) explains the amount and Inventory context passed into actions.
- [Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/) explains where to declare and set the action-set reference.
- [Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/) covers Item Action Set, Category Item Action Set, and custom actions.
- [Item Hotbar](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-hotbar/) connects indexed input to Item Actions.
- [Item View](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/item-view/) displays attributes and cooldown modules.
- [Equipping Items](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/equipping-items/) creates equipped Item Objects.
- [Item Object Behaviour Handler](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/usable-item-objects/) runs behavior attached to a usable prefab.
- [Input](https://opsive.com/support/documentation/ultimate-inventory-system/input/) selects and configures the Version 1 input route.
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/) persists Inventory contents and Item data.
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/) explains safe registration and unregistration.

## Use the Item Skills API

### Invoke the definition-selected action safely

Resolve the definition's Item Action Set, initialize its collection, validate the index, and check the selected action before invoking it:

```csharp
public bool TryInvokeAssignedSkill(
    ItemInfo itemInfo,
    ItemUser itemUser,
    int actionIndex = 0)
{
    if (itemInfo.Item == null || itemInfo.Amount <= 0) { return false; }

    if (!itemInfo.Item.TryGetAttributeValue<ItemActionSet>(
            "ItemActionSet", out var actionSet) || actionSet == null) {
        return false;
    }

    var actions = actionSet.ItemActionCollection;
    if (actions == null) { return false; }

    actions.Initialize(false);

    if (actionIndex < 0 || actionIndex >= actions.Count) { return false; }

    var action = actions[actionIndex];
    if (action == null) { return false; }

    if (!action.CanInvoke(itemInfo, itemUser)) { return false; }

    action.InvokeAction(itemInfo, itemUser);
    return true;
}
```

`InvokeAction` checks `CanInvoke` again. The helper's explicit check makes the result useful to the caller; the base Version 1 API itself returns void.

### Build the category action list

Use Category Item Action Set when the caller needs the same category and exception filtering used by the UI:

```csharp
var buffer = new ItemAction[5];
var actions = categoryItemActionSet.GetItemActionsForItem(
    itemInfo.Item, ref buffer);

for (int i = 0; i < actions.Count; i++) {
    Debug.Log(actions[i].Name);
}
```

`UseItemAction(itemInfo, itemUser, index)` and `UseAllItemActions(itemInfo, itemUser)` are convenient direct methods, but Version 1's implementations select by matching Item Category and do not apply Exception Categories.

### Listen for the built-in cooldown

Use Item Action Set Attribute sends the wrapper action, Item Info, and cooldown duration to the Item User GameObject:

```csharp
private void OnEnable()
{
    EventHandler.RegisterEvent<ItemAction, ItemInfo, float>(
        itemUser.gameObject,
        EventNames.c_CharacterGameObject_UsedItemActionWithCooldown_ItemAction_ItemInfo_Float,
        OnSkillCooldownStarted);
}

private void OnDisable()
{
    EventHandler.UnregisterEvent<ItemAction, ItemInfo, float>(
        itemUser.gameObject,
        EventNames.c_CharacterGameObject_UsedItemActionWithCooldown_ItemAction_ItemInfo_Float,
        OnSkillCooldownStarted);
}

private void OnSkillCooldownStarted(
    ItemAction action,
    ItemInfo itemInfo,
    float cooldown)
{
    Debug.Log($"{itemInfo.Item.name} cooldown: {cooldown}");
}
```

The Item View Slots Container binding also exposes UnityEvents for action invocation, cancellation, and panel-open failure. Inventory removal events run separately when Remove On Use changes a collection. Always unregister the exact event signature and target used during registration.

---

<a id="page-ultimate-inventory-system-item-item-stats"></a>

# Item Stats

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/item/item-stats/)

Use Item attributes as the data behind equipment bonuses, weapon damage, durability, healing, or another game-specific stat. Ultimate Inventory System Version 1 stores and resolves those values, can total numeric attributes, and can bind an Item value to a component property. Your character, combat, or ability system still owns the final calculation and effect.

For a small example, give Iron Sword an `Attack` value of 12 and Fire Wand an `Attack` value of 18. Equipping either Item changes the equipment contribution to the character's attack, while each weapon's `Durability` remains an independent runtime value.

## Choose what owns each value

| Value | Recommended owner | Why |
| --- | --- | --- |
| Iron Sword or Fire Wand `Attack` | Weapon **Item Definition** attribute | Every Item created from that definition starts with the same attack value. |
| One weapon's `Durability` | Weapon **Item** attribute | Each mutable, unique runtime Item can change independently. |
| Character base attack | The character or combat system | It belongs to the character, not an inventory Item. |
| Final attack | A project-owned calculation | It can combine the base value, equipped Item attributes, buffs, status effects, and game rules in an explicit order. |

There is no built-in `ItemStats` component or universal modifier stack. Attribute names and types are project contracts. A consumer only finds `Attack` when it requests that exact, case-sensitive name with a compatible type.

## Configure Iron Sword and Fire Wand

1. Open **Tools > Opsive > Ultimate Inventory System > Main Manager** and select **Item Categories**.
2. Select Weapon, then open **Attributes > Item Definition**.
3. Add `Attack` as `int`. Use the same type for every definition and consumer in this workflow.
4. Open **Attributes > Item** and add `Durability` as `int`.
5. In Weapon's **Properties**, enable **Mutable** and **Unique** when each weapon must retain its own Durability.
6. Select **Item Definitions**, open Iron Sword, and set its Item Definition `Attack` to 12 with **Variant** set to **Override**.
7. Set Iron Sword's Default Item `Durability` to its starting value.
8. Repeat the definition and Default Item values for Fire Wand, setting `Attack` to 18.
9. Confirm that the character Inventory has an `ItemSlotCollection` for equipment. The standard sample calls it **Equipment** and gives it the **Equipped** purpose.
10. On the **Equipper** component, assign **Inventory** and point **Equipment Item Collection ID** at that collection. The Version 1 default ID uses the name `Equipped` and the purpose `Equipped`; change the name when the database uses `Equipment`.

Creating the attributes does not change a character stat by itself. Choose one of the consumers below, then verify that it reads the resolved Item value.

The included feature scene **14 Get Set Attribute Stat (With Code)** demonstrates reading, changing, and totaling attributes. Its `GetSetAttributeExample` script is also a useful source reference for a custom implementation.

## Choose how the value is consumed

| Outcome | Version 1 route | Important behavior |
| --- | --- | --- |
| Add equipped bonuses to a character total | `ItemCollection.GetIntSum`, `GetFloatSum`, or an Equipper stat helper | Recalculate from the base value when equipment changes. |
| Apply a value to the spawned sword or wand | **Item Binding** beside an **Item Object** | The target must be a public property of the same value type. |
| Display one selected Item's value | **Attribute Item View** or **Int Attribute Item View** | Set **Attribute Name** to `Attack`; these modules do not calculate the equipment total. |
| Preview an equipment change | `GetEquipmentStatPreviewAdd` or `GetEquipmentStatPreviewRemove` | The built-in preview methods return `int`. |
| Heal, damage, or apply a timed effect when an Item is used | A custom Item Action or Item Object Behaviour | Read the attribute, then call the project-owned health, combat, or ability system. |

### Recalculate a character total

Keep the character's base attack separate from the equipment contribution:

`final attack = base attack + sum of Attack on Equipment`

Recompute the entire result after an equip or unequip. Do not repeatedly add and subtract float bonuses from a stored total, because accumulated rounding error can move the value away from the intended result.

Use `EventNames.c_Equipper_OnChange` when the calculation follows the Equipper. Use the Equipment collection's `OnItemCollectionUpdate` C# event when the calculation follows that collection. Both routes cover equipment content changes.

If an equipped Item's `Attack` can change without moving between collections, also react to that Item's `OnItemAttributeChange` event or recalculate from the action that changes it. An equipment collection update is not an automatic notification for every in-place attribute change.

### Apply Attack to a weapon component

Use **Item Binding** when the spawned Iron Sword or Fire Wand should copy `Attack` into a component on its Item Object:

1. Add **Item Object** and **Item Binding** to the usable or equipment prefab.
2. On Item Binding, assign **Database**, then set **Item Category** to Weapon.
3. Open **Item Definition Attributes** and find `Attack`.
4. Assign the component that receives the value.
5. Select a public `int` property, such as `Damage`. Fields and properties of another type are not offered.

Item Binding listens for `EventNames.c_ItemObject_OnItemChanged`, validates that the bound Item belongs to the configured category, and binds all matching attributes. Reading the bound attribute uses the property value; setting the attribute updates the property.

Use this route for a property on the weapon GameObject. Use a character-level recalculation when several equipped Items contribute to one total.

### Display or compare stats in UI

**Attribute Item View** converts the selected attribute's value to text. Its relevant fields are **Attribute Name**, **Attribute Value Text**, **Default Text Value**, and **Disable On Clear**. **Int Attribute Item View** requires an integer attribute and clears its value text to `0` when the Item or attribute is unavailable.

These modules show one Item. Version 1's demo includes `DemoCompareAttributeView`, which uses the Equipper's current and preview totals, but that class is sample-specific rather than a general runtime stat-comparison system. Create a project UI module when the comparison needs float values, custom modifier rules, or multiple equipment sets.

## Build formulas at the right level

An Attribute's **Variant** can be **Inherit**, **Override**, or **Modify**. The built-in Modify evaluator supports `int`, `float`, and `string` attributes. The resolved value is what the sum helpers and Item Binding consume.

Use **Modify** for a relationship inside the Item data model. For example, an Iron Sword +1 child definition can derive `Attack` from its parent with `<Inherited> + 2`. Keep a direct Iron Sword or Fire Wand value as **Override** when there is no meaningful parent formula.

Use gameplay code for relationships outside the Item hierarchy, such as:

- character base attack plus equipped Item attack;
- a Fire Wand bonus that depends on the character's current mana;
- additive bonuses followed by multiplicative buffs;
- minimums, maximums, damage types, status effects, or difficulty scaling.

Modify expressions do not inspect arbitrary character state or define a global modifier order. Document one calculation order in the owning gameplay system so UI previews and runtime effects use the same rules.

## Editor checkpoint

Before entering Play Mode, confirm that:

- Weapon declares `Attack` as an `int` Item Definition attribute and `Durability` as an `int` Item attribute;
- Iron Sword and Fire Wand override their own `Attack` values;
- both Default Items have intentional starting Durability;
- Weapon is **Mutable** and **Unique** when Durability must differ per instance;
- Equipment is an `ItemSlotCollection` with the **Equipped** purpose;
- the Equipper's **Inventory** and **Equipment Item Collection ID** resolve to that collection;
- every consumer uses the exact name `Attack` and the `int` type;
- any Item Binding targets Weapon and a writable public `int` property; and
- the character calculation has a defined base value and recalculation trigger.

## Verify in Play Mode

1. Give the character Iron Sword and Fire Wand in **Bag**.
2. Record the character's base attack, then equip Iron Sword into **Equipment**.
3. Confirm that the final attack equals the base value plus 12.
4. Swap Iron Sword for Fire Wand and confirm that the final attack uses 18 instead.
5. When using Item Binding, inspect the spawned Item Object and confirm that its public damage property matches the equipped Item's `Attack`.
6. When using an Item View module, select each weapon and confirm that its own Attack appears; do not treat that value as the full character total.
7. Change one weapon's Durability and confirm that another Iron Sword or Fire Wand keeps its own value.
8. Save and load, then confirm that mutable Item values are restored and the character total is recalculated from the restored equipment.

## Save and update behavior

Item Category and Item Definition stat values are database configuration. A runtime Item's overridden attributes, such as one weapon's Durability, are included when that Item is saved through the Version 1 save flow and `InventorySystemManagerItemSaver`. Editing custom immutable Item values is not supported by that saver; changing per-instance stats requires mutable Items, and unique Items avoid merging different values into one stack.

The final character attack, temporary buffs, and values held only on a bound gameplay component are not Item attributes automatically. Recalculate them after load, or give the owning gameplay system its own saver when their state must persist.

Useful Version 1 notifications include:

- `ItemCollection.OnItemCollectionUpdate` after collection contents update;
- `EventNames.c_Equipper_OnChange` on the Equipper after equip or unequip;
- `Item.OnItemAttributeChange` when a runtime Item attribute notifies a change in Play Mode; and
- `AttributeBase.OnAttributeChanged` for a specific attribute.

Register only for the scope that owns the calculation, and unregister the same callback when that owner is disabled or destroyed.

## Current Version 1 boundaries

- Item Stats is a documentation pattern, not a separate component, asset, formula graph, or save object.
- Numeric sum helpers recognize `int` and `float` values with the requested name. Missing attributes and other value types contribute nothing.
- `ItemCollection.GetIntSum` and `GetFloatSum` count an attribute once per Item stack. They do not multiply it by the stack amount.
- `AttributeUtility` and `Inventory` have overloads with `perAmount: true` when a stackable Item should contribute once per unit.
- Integer sum and Equipper preview APIs cast float totals to `int`. Use float APIs or a custom preview when fractions matter.
- `IEquipper` exposes `GetEquipmentStatInt` and integer preview methods. `EquipperBase` also exposes `GetEquipmentStatFloat` on the concrete type.
- Sum helpers do not apply slot weights, caps, modifier priority, damage types, or project-specific eligibility rules.
- Item Binding supports public properties whose type matches the attribute. It does not bind ordinary fields or calculate totals across several Items.
- Equipment-change notifications do not replace an attribute-change notification when a stat changes in place.
- UIS saves the Item data selected by its savers; it does not automatically save or restore a derived character total.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| Equipping a weapon does not change attack | Recalculation callback, Equipment collection ID, and attribute spelling | Point the Equipper and calculation at the same collection and request exact `Attack`. |
| The total is always zero | Equipment collection type, Item contents, and `Attack` type | Use an initialized `ItemSlotCollection` and confirm each equipped Item resolves an `int` or `float` Attack. |
| A stack contributes less than expected | Whether the calculation should count stacks or units | Use an `AttributeUtility` or `Inventory` overload with `perAmount: true` for a per-unit stat. |
| A decimal bonus loses its fraction | `GetIntSum` or an integer preview API | Use `GetFloatSum` and a custom float preview. |
| Changing Attack while equipped does not refresh the character | Only an equipment-change event is registered | React to `Item.OnItemAttributeChange` or recalculate immediately after the action changes Attack. |
| Item Binding does not list the target | Target member kind and value type | Expose a writable public property whose type exactly matches the attribute. |
| Item Binding reports a category mismatch | **Item Category** on the binding | Select Weapon or another category that inherently contains the bound Item. |
| Two swords share changed Durability | Weapon mutability, uniqueness, and attribute collection | Declare Durability as an Item attribute and make Weapon mutable and unique. |
| Durability resets after load | Item saver setup and whether that Item is included | Configure the Inventory and manager Item savers, then save the mutable Item that owns the override. |
| UI shows the weapon value but not final attack | Item View module data source | Use a character-stat UI component for the aggregated result; keep Item View for the selected Item. |

## Related tasks

- [Define and place attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/)
- [Understand inheritance and Modify expressions](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/)
- [Configure the Attribute editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/attributes/)
- [Equip Items](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/equipping-items/)
- [Bind Item attributes to a component](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-binding/)
- [Create Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/)
- [Use Items as skills](https://opsive.com/support/documentation/ultimate-inventory-system/item/item-skills/)
- [Configure Item Views](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/item-view/)
- [Save runtime Item data](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)

## Use the stat APIs

### Recalculate after equipment changes

The Equipper event is a concise trigger when Attack is fixed while an Item remains equipped:

```csharp
public class CharacterAttack : MonoBehaviour
{
    [SerializeField] private Equipper m_Equipper;
    [SerializeField] private int m_BaseAttack = 5;

    public int Attack { get; private set; }

    private void OnEnable()
    {
        if (m_Equipper == null) { return; }

        EventHandler.RegisterEvent(
            m_Equipper,
            EventNames.c_Equipper_OnChange,
            Recalculate);

        Recalculate();
    }

    private void OnDisable()
    {
        if (m_Equipper == null) { return; }

        EventHandler.UnregisterEvent(
            m_Equipper,
            EventNames.c_Equipper_OnChange,
            Recalculate);
    }

    private void Recalculate()
    {
        Attack = m_BaseAttack + m_Equipper.GetEquipmentStatInt("Attack");
    }
}
```

`EventNames.c_Equipper_OnChange` is executed on the Equipper instance. Register and unregister against that same target and callback.

### Choose stack or per-unit sums

Collection helpers count each Item stack once. Pass `perAmount: true` to an `AttributeUtility` overload when every unit in a stack should contribute:

```csharp
var equipment = inventory.GetItemCollection("Equipment");

var oncePerStack = equipment.GetFloatSum("Attack");

var oncePerUnit = AttributeUtility.GetFloatSum(
    "Attack",
    equipment.GetAllItemStacks(),
    perAmount: true);
```

Both sums accept resolved `int` and `float` attributes. `GetIntSum` returns the float sum cast to `int`, so use `GetFloatSum` when any contributor can contain a fractional value.

### React to one Item's attribute

Use the Item event when a mutable equipped stat can change in place:

```csharp
private void TrackItem(Item item)
{
    item.OnItemAttributeChange += HandleItemAttributeChanged;
}

private void StopTrackingItem(Item item)
{
    item.OnItemAttributeChange -= HandleItemAttributeChanged;
}

private void HandleItemAttributeChanged(AttributeBase attribute)
{
    if (attribute.Name == "Attack") {
        Recalculate();
    }
}
```

Subscribe when the Item enters the relevant equipment slot and unsubscribe when it leaves. For a one-off action, recalculating immediately after `SetOverrideValue` may be simpler than maintaining subscriptions.

---

<a id="page-ultimate-inventory-system-item-actions"></a>

# Item Actions

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/)

Item Actions are commands that act on an Item selected from an Inventory interface. Use them for choices such as drinking a Health Potion, equipping an Iron Sword, assigning a Fire Wand to a hotbar, moving an Item, or dropping it into the world.

An Item Action is not the visible behavior of a sword swing or spell. Those GameObject and character behaviors belong to Item Objects, abilities, or project gameplay code. The Item Action is the inventory-side command that validates the selected Item and starts that behavior or transaction.

## Understand the action flow

| Part | Responsibility | Standard example |
| --- | --- | --- |
| **Item Action** | Validates and performs one command for an Item Info and Item User | Drink, Equip, or Drop |
| **Item Action Set** | Groups actions for one Item Category, with optional exception categories | Consumable actions or Weapon actions |
| **Category Item Action Set** | Orders several Item Action Sets so one Item can receive actions from every matching category | Use, Equip, then Drop |
| **Item View Slots Container Category Item Action Set Binding** | Gets the selected slot's Item Info, finds matching actions, and opens an Item Action Panel or invokes an action directly | The action binding on the Bag grid |
| **Item Action Panel** | Presents the matching actions and invokes the player's choice | A menu listing Drink and Drop for Health Potion |
| **Item User** | Supplies the player or character context and its inventory input | The player that owns Bag |

The category mapping is additive. If Iron Sword belongs to Weapon and also matches a general droppable category, it receives the actions from both matching sets. The order of Item Action Sets in the Category Item Action Set, followed by the order of actions inside each set, determines the displayed action order.

## Create the action sets

The following setup gives Health Potion a **Drink** command, gives Iron Sword and Fire Wand an **Equip** command, and gives all three Items a **Drop** command.

1. In the Project window, choose **Create > Ultimate Inventory System > Item Actions > Item Action Set**.
2. Name the first asset **Consumable Item Actions**, select the Inventory System **Database**, and set **Item Category** to Consumable.
3. Under **Item Actions**, add the project's custom Drink action and set its **Name** to `Drink`. Its `CanInvoke` rule should reject Items that do not have the data required by the health system.
4. Create **Weapon Item Actions**, set **Item Category** to Weapon, and add the appropriate built-in or integration-specific equip action. Set its visible name to `Equip` or let a toggle action switch between `Equip` and `Unequip` when supported.
5. Create **Droppable Item Actions**, set **Item Category** to the broad category shared by Items that may be dropped, and add **Drop Item Action** or **Quantity Drop Item Action**.
6. Add any protected child categories to **Exception Categories**. For example, a quest-only category can inherit common Item data without receiving Drop.

An Item Action Set matches its selected category and descendant categories. Exception Categories remove their matching descendants from the action list produced for the UI.

![The Item Action Set Inspector targets the Pickupable category, has an empty Exception Categories list, and contains a DropItemAction named Drop with its pickup prefab and drop settings.](https://opsive.com/wp-content/uploads/2020/04/ItemActionSetInspector.png?v=65318e7d19b4)

## Combine the category mappings

1. Choose **Create > Ultimate Inventory System > Item Actions > Category Item Action Set**.
2. Name the asset **Main Inventory Category Item Actions**.
3. Add **Consumable Item Actions**, **Weapon Item Actions**, and **Droppable Item Actions** to **Category Item Actions** in the order the commands should appear.
4. Avoid adding the same Item Action Set twice. Version 1 concatenates matching actions; it does not deduplicate them or apply a separate priority value.

At the editor checkpoint, selecting Health Potion should resolve Drink and Drop, while Iron Sword and Fire Wand should resolve Equip and Drop. If an Item belongs to several matching categories, verify the final combined order rather than checking only one Item Action Set.

![The Category Item Action Set Inspector lists Consumable, Equippable, Open Item, Assign To Hotbar, and Droppable Item Action Sets in their evaluation order.](https://opsive.com/wp-content/uploads/2020/04/CategoryItemActions.png?v=ea7e7348a24a)

## Connect actions to an inventory grid

The UI Designer schemas normally provide the required panel and binding. When configuring a custom Inventory Grid or another Item View Slots Container:

1. Add **Item View Slots Container Category Item Action Set Binding** to the same UI workflow as the container.
2. Assign **Action Panel** when the player should choose from a list. Assign the **Category Item Action Set** created above.
3. Leave **Auto Set Item User** enabled when the bound Inventory's Item User should perform the action. Assign **Item User** manually only when another actor owns the command.
4. Enable **Use Item On Click** when selecting or clicking a slot should open the action panel or run the configured direct action.
5. Enable **Disable Action On Empty Slots** and **Prevent Open When No Action** for a normal inventory menu.
6. **Max Number Of Actions** defaults to `5` and creates the initial action array. Version 1 can resize that array when more category matches are found, so this field is not a category filter or availability limit.
7. On the Item Action Panel, enable **Hide Cannot Invoke Actions** when unavailable commands should be omitted instead of remaining in the list and failing their final `CanInvoke` check.

With an **Action Panel** assigned, triggering the binding opens the panel and lets the player choose. Without a panel, **Use Item Action Index** chooses a direct action; the Version 1 default of `-1` invokes every matching action. Do not leave `-1` on a panel-free binding that contains several destructive or mutually exclusive commands.

![The Item View Slots Container Category Item Action Set Binding uses an Item Action Panel, click-to-use, action index minus one, automatic Item User assignment, five initial actions, and a category action set containing six mappings.](https://opsive.com/wp-content/uploads/2020/04/Item-View-Slots-Container-Category-Item-Actions-Set-Binding.png?v=62383a9b8ab2)

## Add keyboard or gamepad input

Clicking a slot is only one trigger. Add **Item View Slot Container Item Action Handler** when input should run the selected slot's default or indexed action.

- **Item Action Binding** identifies the binding to trigger.
- **Default Input** calls the binding's default flow.
- **Action Inputs** maps inputs to explicit action indexes.
- **Handle Input Only If Panel Selected** prevents a background menu from responding.
- **Use Item Action Binding Item User Player Input** is enabled by default and reads input from the bound Item User.

Action indexes depend on the current combined category matches. Use a stable named or dedicated action flow when different Item types produce different list orders; an index that means Drink for Health Potion may mean Equip for Iron Sword.

## Keep Item Info and Item User context

The binding passes the selected slot's Item Info to the action. This preserves the exact runtime Item, amount, Item Collection, and Item Stack context. It matters when Bag contains two unique Iron Swords, when only one Health Potion should be consumed, or when Equip must move an Item from Bag rather than finding another Item with the same definition.

`ItemUser` supplies the acting character and its `InventoryInput`. When no Item User is passed and the Item Info belongs to an Inventory, `ItemAction` falls back to that Inventory's Item User. Actions that require character components should return `false` from `CanInvoke` when the required Item User or component is missing.

Every invocation calls `CanInvoke` before performing the action. Use that check for current state such as amount, collection, cooldown, destination capacity, or required gameplay component. Still inspect the returned results of collection transactions inside the action; availability can change between displaying a button and choosing it.

## Choose built-in or custom actions

Use [Built-in Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/built-in-item-actions/) for the complete Version 1 list and each action's prerequisites. The main groups are:

- Immediate actions such as Drop, Remove, Duplicate, Move To Collection, Play Audio Clip, Multi Item Action, and Use Item Action Set Attribute.
- Panel-driven actions such as Quantity Drop, Assign Hotbar, confirmation, Move Item, and Open Other Item View Slot Container.
- Abstract base actions that provide a quantity picker, asynchronous choice panel, Item Object reference, or Item View Slots Container context for a custom action.

Create a custom action when the command belongs to the project's gameplay rules. A Drink action, for example, can read Health Potion data, ask the character health component whether healing is possible, apply the effect, then remove exactly the amount that was consumed. Keep the health calculation in the health system rather than turning the Item Action into a second character-stat system.

## Verify in Play Mode

1. Put Health Potion, Iron Sword, and Fire Wand in Bag and open the inventory menu.
2. Select Health Potion. Confirm that the panel shows Drink and Drop in the configured order and does not show Equip.
3. Select Iron Sword and Fire Wand. Confirm that each shows Equip and Drop and that the action receives the exact selected weapon.
4. Invoke Equip. Confirm that the Item moves to Equipment, the Bag and Equipment views redraw, and the command changes to Unequip when the configured action supports both directions.
5. Invoke Drink with more than one Health Potion in the stack. Confirm that only the intended amount is removed and the health effect occurs once.
6. Test with an empty slot, an Item in an exception category, a full destination collection, and a missing Item User dependency. The panel should stay closed, hide the unavailable command, or refuse invocation without losing an Item.
7. Use keyboard or gamepad input while another panel is selected. When **Handle Input Only If Panel Selected** is enabled, the background inventory must not invoke an action.

## Saving and multiplayer

Item Action Set and Category Item Action Set assets are configuration; they do not need runtime save records. Save the results of an action through the systems the action changes. For example, use the Inventory and Item savers for a consumed Health Potion or moved Iron Sword, and the Item View Slot Container saver when a hotbar assignment must persist.

`ItemUser`'s runtime action-data dictionary, an open action panel, a pending quantity choice, and an in-progress action are not automatically saved. Reconstruct transient UI state after loading, or add a project saver when a custom cooldown or action state must persist outside Item attributes.

Version 1 does not provide a general networking or authority layer for Item Actions. In a multiplayer project, validate and execute inventory-changing actions on the authoritative side, then replicate the resulting Inventory, Item, equipment, or gameplay state. Do not let each client independently remove, duplicate, equip, or drop the same Item.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| No actions appear for Health Potion | Check the Item's inherited categories, the Item Action Set's **Item Category**, exceptions, and the binding's **Category Item Action Set**. | Map Consumable to the intended set, remove an accidental exception, and assign the aggregate asset to the binding. |
| The same action appears twice | Inspect every matching Item Action Set and the aggregate list order. | Remove the duplicate action or duplicate set reference; Version 1 does not deduplicate matches. |
| Clicking an Item runs several actions immediately | Check whether **Action Panel** is empty and **Use Item Action Index** is `-1`. | Assign an Item Action Panel or choose one explicit index. |
| An action button appears but does nothing | Check `CanInvoke`, Item User dependencies, collection restrictions, and **Hide Cannot Invoke Actions**. | Supply the missing context or make `CanInvoke` explain the real availability rule; hide unavailable actions when appropriate. |
| Equip acts on the wrong Item or collection | Inspect the Item Info passed from the selected slot. | Use the provided Item Info and its source collection instead of searching again by Item Definition. |
| Keyboard input triggers a hidden inventory | Inspect **Handle Input Only If Panel Selected** and the handler's player input source. | Enable panel-selection gating and bind the correct Item User input. |
| A panel-based action fails when called from code | Check whether it implements `IActionWithPanel` or `IActionWithSlotContainer`. | Invoke it through the binding/panel flow, or provide its required panel and slot-container context before calling it. |
| An action works locally but duplicates results online | Check which peer is allowed to invoke the inventory transaction. | Make one authoritative side execute the action and replicate only the result. |

## Current Version 1 boundaries

- Category matching is additive and ordered; there is no built-in priority or deduplication pass.
- Exception Categories are applied by `GetItemActionsForItem`, which is the UI binding's filtered retrieval path. The direct `CategoryItemActionSet.UseItemAction` and `UseAllItemActions` methods do not apply exception filtering in Version 1.
- An action index is positional and can change when category mappings or action order changes.
- Panel-based and slot-container actions require UI context that a direct API call does not provide automatically.
- Item Actions run locally unless a project or integration adds authority and replication.
- The framework saves action results through Inventory, Item, hotbar, and project-specific savers; it does not serialize an action invocation in progress.

## Related pages

- [Built-in Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/built-in-item-actions/) describes every included action and its setup.
- [Item Info](https://opsive.com/support/documentation/ultimate-inventory-system/item/item-info/) explains the Item, amount, collection, and stack context passed to an action.
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/) covers the collections and restrictions that actions modify.
- [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/) explains the UI container that selects the target Item.
- [Input Handlers](https://opsive.com/support/documentation/ultimate-inventory-system/input/handlers/) covers the wider Version 1 inventory input flow.
- [Item Objects](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/) explains the GameObject-side behavior that an Item Action may start or control.
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/) covers the savers for Inventory, Item, and hotbar results.

## Developer reference

A custom Item Action is a serializable class that inherits `ItemAction`. The editor discovers it for the Item Action type dropdown after Unity recompiles.

```csharp
[System.Serializable]
public class MyItemAction : ItemAction
{
    protected override bool CanInvokeInternal(ItemInfo itemInfo, ItemUser itemUser)
    {
        return itemInfo.Item != null && itemInfo.Amount > 0;
    }

    protected override void InvokeActionInternal(ItemInfo itemInfo, ItemUser itemUser)
    {
        // Call project gameplay code and inspect every inventory transaction result here.
    }
}
```

- `ItemAction.Initialize(false)` must run before a directly created action can pass `CanInvoke`. Item Action Sets and panels initialize their serialized actions for you.
- `ItemAction.Setup` stores `BoundItemInfo` and `BoundItemUser`; `InvokeAction(ItemInfo, ItemUser)` performs its own `CanInvoke` check before calling `InvokeActionInternal`.
- `CategoryItemActionSet.GetItemActionsForItem` returns the ordered, exception-filtered actions for an Item. `ItemViewSlotsContainerCategoryItemActionSetBinding` uses that result for the selected slot.
- `ItemViewSlotsContainerItemActionBindingBase` exposes direct use by selected slot, slot index, action index, or action name. Prefer names over indexes only when action names are kept unique and stable.
- The binding exposes **On Cannot Open Panel**, **On Action Canceled**, and **On Action Invoked** UnityEvents. `ActionPanel` also exposes `OnActionsAssigned`, `OnBeforeAnyItemActionInvoke`, and `OnAfterAnyItemActionInvoke` C# events.
- `IActionWithPanel`, `IActionWithSlotContainer`, `ItemActionWithQuantityPickerPanel`, `ItemActionWithAsyncFuncActionPanel<T>`, and `ItemObjectAction` provide the extra context needed by more involved custom actions.

---

<a id="page-ultimate-inventory-system-item-actions-built-in-item-actions"></a>

# Built-in Item Actions

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/built-in-item-actions/)

Ultimate Inventory System Version 1 includes 16 concrete Item Action types. Use them to inspect an item, move or remove it, open a choice panel, assign it to a hotbar, or compose a larger interaction. The action receives the selected `ItemInfo`, so its amount, collection, Inventory, and Item User determine what happens.

The `Name` field is the label shown to the player. Set it deliberately, especially for `ItemActionWithConfirmationPopUp`, `MoveToInventoryItemAction`, and `UnAssignHotbarItemAction`, which do not set a default name. `OpenOtherItemViewSlotContainerItemAction` defaults to the developer-oriented label `Select ExternalItemAction`, so it should normally be renamed too.

## Choose an action by outcome

| Player outcome | Start with | Example |
| --- | --- | --- |
| Inspect the selected item | `DebugItemAction` or `DebugItemObjectAction` | Check the resolved attributes on an Iron Sword. |
| Put an item into the world | `DropItemAction` or `QuantityDropItemAction` | Drop one Health Potion or choose an amount from a stack. |
| Delete or copy an inventory entry | `RemoveItemAction` or `DuplicateItemAction` | Remove a consumed potion during a prototype. |
| Equip, unequip, transfer, or reposition | `MoveToCollectionItemAction`, `MoveToInventoryItemAction`, or `MoveItemAction` | Move an Iron Sword between Bag and Equipment. |
| Run a definition-specific effect | `UseItemActionSetAttribute` | Invoke the action referenced by a Health Potion or Fire Wand attribute. |
| Run several actions together | `MultiItemAction` | Invoke a Fire Wand effect and play its sound from one button. |
| Ask before continuing | `ItemActionWithConfirmationPopUp` | Confirm before removing an Iron Sword. |
| Play feedback | `PlayAudioClipItemAction` | Play the configured Fire Wand sound. |
| Assign or clear a hotbar slot | `AssignHotbarItemAction` or `UnAssignHotbarItemAction` | Assign a Health Potion to slot 1. |
| Select a slot in another panel | `OpenOtherItemViewSlotContainerItemAction` | Choose an ingredient from Bag for another UI. |

## Inspect item data

These actions are diagnostic. Both remain eligible even when the selected `ItemInfo` has no Item, so the Console output can expose missing data.

| Item Action type | Default name and settings | Result and requirements |
| --- | --- | --- |
| `DebugItemAction` | Name: `Debug`; no additional fields | Logs the selected `ItemInfo`, Item Definition, Category, and resolved Item, Definition, and Category attributes. A missing Item is reported instead of rejected. |
| `DebugItemObjectAction` | Name: `Debug`; no additional serialized fields | Adds the Item Object and Item User to the same diagnostic output. The caller must supply the target through `SetItemObject`; otherwise the logged Item Object is null. |

Use `DebugItemAction` for an inventory or menu problem. Use `DebugItemObjectAction` only when the interaction already knows which scene `ItemObject` belongs to the action.

## Drop, remove, or duplicate items

| Item Action type | Important fields and Version 1 defaults | Result and requirements |
| --- | --- | --- |
| `DropItemAction` | Name: `Drop`; **Pick Up Item Prefab:** none; **Drop One:** off; **Remove On Drop:** off; **Drop Radius:** `2`; **Center Offset:** `(0, 0, 0)` | Spawns the selected amount near the Item User, or near the Inventory when there is no Item User. The prefab root must contain an `ItemObject` or an `Inventory`. Turn on **Remove On Drop** for a true transfer; the default creates the world object without removing the inventory entry. |
| `QuantityDropItemAction` | Name: `Drop`; **Quantity Panel Prefab:** none; **Pick Up Item Prefab:** none; **Remove On Drop:** off; **Drop Radius:** `2`; **Center Offset:** `(0, 0, 0)` | Opens a quantity picker from `1` to the selected amount, then follows the same drop rules. A single item bypasses the panel. It requires a valid `QuantityPickerPanel` prefab and panel context when the amount is greater than one. |
| `RemoveItemAction` | Name: `Remove`; **Remove Amount:** `-1` | Removes the selected amount from its current Item Collection. A value of `0` or less removes the full selected amount; a positive value removes no more than that value. It does not create a pickup. |
| `DuplicateItemAction` | Name: `Duplicate`; no additional fields | Adds an amount of `1` for the selected Item to the same Item Collection. Collection restrictions and overflow still apply. This reuses the same Item; it is not a deep copy of a mutable Item. |

The drop actions report configuration problems only when invoked: their eligibility check does not validate the prefab, actor, or removal result. Test both the spawned object and the inventory count. For an Opsive Character Controller character, use the integration's specialized drop actions so the world drop follows the character-controller workflow.

## Equip, transfer, or reposition items

| Item Action type | Important fields and Version 1 defaults | Result and requirements |
| --- | --- | --- |
| `MoveToCollectionItemAction` | Name: `Equip`; **First Collection ID:** Main; **Second Collection ID:** Equipped; **Move From First To Second Action Name:** `Equip`; **Move From Second To First Action Name:** `Unequip` | Moves the complete selected amount between two collections in the same Inventory and changes its label for the current direction. It checks removal, destination capacity, restrictions, and equipment-slot exchange before becoming available. A displaced slot item returns to the source collection. |
| `MoveToInventoryItemAction` | Name: empty; **Target Inventory ID:** `1`; **Target Collection ID:** Equipped | Removes the selected item from its source collection and adds it to the registered target Inventory and collection. An unaccepted amount returns to the source, and a displaced slot item moves back to the source collection. Its eligibility check confirms the two target references, but does not preflight all add or remove restrictions. |
| `MoveItemAction` | Name: `Move`; no additional fields | Starts the `ItemViewSlotMoveCursor` at the selected slot. It is available only when the action receives an Item View Slots Container and that container has an `ItemViewSlotMoveCursor`; the destination selection completes the move. |

For an Iron Sword, the usual Version 1 setup is a Bag collection with the Main purpose and an Equipment `ItemSlotCollection` with the Equipped purpose. The default `MoveToCollectionItemAction` then produces one **Equip**/**Unequip** button and preserves the item displaced from the equipment slot.

Use `MoveToInventoryItemAction` only for a different Inventory Identifier, such as moving an item into a companion or storage Inventory. It is not the normal Bag-to-Equipment action within one Inventory.

## Use, combine, or confirm effects

| Item Action type | Important fields and Version 1 defaults | Result and requirements |
| --- | --- | --- |
| `UseItemActionSetAttribute` | Name: `Use`; **Attribute Name:** `ItemActionSet`; **Action Index:** `0`; **Use One:** on; **Remove On Use:** off; **Cooldown Attribute Name:** `Cooldown`; **Cooldown Item User Data Name:** `ItemCooldown` | Reads an `ItemActionSet` attribute from the selected Item and invokes the indexed nested action. **Use One** sends an amount of one. **Remove On Use** removes that amount after the invocation attempt. A float cooldown attribute stores the next-use time on the Item User and raises the Version 1 used-with-cooldown event. |
| `MultiItemAction` | Name: `Use`; **All Conditions Must Pass:** off; **Item Action Set:** none | Invokes every action in the referenced set in list order. When **All Conditions Must Pass** is on, every nested `CanInvoke` check must pass before the sequence starts. When it is off, the wrapper stays available and each nested action performs its own check. The action set reference is required. |
| `ItemActionWithConfirmationPopUp` | Name: empty; **Confirmation Pop Up Prefab:** none; **Item Action Set On Confirm:** none; **Item Action Set On Cancel:** none | Opens the configured `ConfirmationPopUp`. Confirm and cancel each invoke every action in their corresponding set, then close the popup. It requires a parent display panel, previous selection, parent transform, and popup prefab supplied by a panel-aware UI binding. |
| `PlayAudioClipItemAction` | Name: `Play Audio`; **Audio Clip Set:** empty | Plays one of the configured clips. It is always eligible and the core implementation does not supply a scene GameObject to the audio set; subclass it when the sound must originate from a specific object. |

`UseItemActionSetAttribute` is a wrapper, not a healing or casting system. For a Health Potion, place the actual restore-health action at index `0` of an Item Action Set, reference that set from an `ItemActionSet` attribute, and turn on **Remove On Use**. For a Fire Wand, the referenced set can contain a custom cast action. A `MultiItemAction` can then combine that use action with `PlayAudioClipItemAction`.

The wrapper confirms that the attribute, action set, and index exist, but it does not require the nested action's eligibility check to pass before applying **Remove On Use** and cooldown. Verify the nested effect as well as the item count. A cooldown attribute also requires a valid Item User; the cooldown data stored on that Item User is runtime state and is not automatically saved.

## Work with hotbars and other panels

| Item Action type | Important fields and Version 1 defaults | Result and requirements |
| --- | --- | --- |
| `AssignHotbarItemAction` | Name: `Assign`; **Async Func Action Panel Prefab:** none; **Add Cancel Option:** on; **Display Panel Manager ID:** `0`; **Hotbar Panel Name:** `Item Hotbar`; **Toggle Assign:** off; **Show Item Names:** off; **Use Item View Slot If Available:** on | Finds the named display panel and its bound `ItemHotbar`, opens one choice per hotbar slot, and adds the selected Item to that slot. ID `0` can fall back to the parent panel manager. **Toggle Assign** lets the same choice clear a matching assignment. The selected item must still exist in its Item Collection. |
| `UnAssignHotbarItemAction` | Name: empty; no additional fields | Clears the selected `ItemHotbar` slot without removing the item from its Inventory. Add it only to a hotbar's action set: its base eligibility check knows that a slot container exists, but does not confirm that the container is an `ItemHotbar`. |
| `OpenOtherItemViewSlotContainerItemAction` | Name: `Select ExternalItemAction`; **Display Unique Name:** empty | Opens another panel by its exact unique name and waits for a slot selection. Both panels need Item View Slots Container bindings. When the origin has an `ItemViewDropHandler`, the selection follows that drop workflow; otherwise the selected target `ItemInfo` is added through the origin container. |

`AssignHotbarItemAction` does not require the legacy `ItemHotbarOwner` setup described by older copies of this page. In Version 1 it resolves a `DisplayPanelManager`, finds **Hotbar Panel Name**, then looks for an `ItemHotbar` on the panel's bound Item View Slots Container.

Its prefab must contain an `AsyncFuncActionsPanel<int>` or a subclass. With **Show Item Names** off, the choices are numbered from `1`; with it on, each choice uses the item currently assigned to that slot or `Empty`. When **Use Item View Slot If Available** is on and the choice buttons are Item View Slots, the action also draws each slot's current `ItemInfo`.

## Configure the sample items

1. Open the Item Action Set used by the item's Category. Under **Item Actions**, add an entry and select its **Item Action** type.
2. For **Health Potion**, add `UseItemActionSetAttribute`, rename it **Drink**, keep **Use One** on, and turn on **Remove On Use**. Add an `ItemActionSet` attribute named `ItemActionSet` to the item data and place the actual potion effect at action index `0` in that referenced set.
3. For **Iron Sword**, add `MoveToCollectionItemAction`. Keep Main and Equipped when Bag and Equipment use those purposes, and keep the **Equip**/**Unequip** labels.
4. For **Fire Wand**, add `UseItemActionSetAttribute` for the wand's custom cast effect. Add `AssignHotbarItemAction` when the player should choose a hotbar slot; set a valid async action-panel prefab and match **Hotbar Panel Name** to the panel's unique name.
5. Give every visible action a short player-facing **Name**. Avoid exposing class-style defaults such as `Select ExternalItemAction`.

Editor checkpoint: each Item Action Set should list the intended concrete type, all required object references should be assigned, and the action names should read naturally together. The Health Potion should show **Drink**, the Iron Sword should show **Equip**, and the Fire Wand should show **Use** and **Assign** when its prerequisites are present.

## Verify in Play Mode

| Test | Expected result | What it verifies |
| --- | --- | --- |
| Select Health Potion and choose **Drink** | The custom effect occurs, exactly one potion is removed, and the action is unavailable during a configured cooldown. | Attribute spelling, action index, nested effect, Item User, removal, and cooldown. |
| Select Iron Sword and choose **Equip**, then select it in Equipment | The sword moves from Bag to Equipment; the action label changes to **Unequip** and moves it back. | Collection purposes, slot compatibility, restrictions, and dynamic action name. |
| Select Fire Wand and choose **Assign** | The slot-choice panel opens, the chosen hotbar slot displays the wand, and the wand remains in its collection. | Panel manager resolution, panel name, binding, and hotbar assignment. |
| Drop a Health Potion | A configured pickup appears near the player and the Bag amount changes only when **Remove On Drop** is on. | Prefab contents, spawn reference, selected amount, and removal choice. |

Also test an ineligible case: fill or restrict the Equipment collection, then select the Iron Sword. `MoveToCollectionItemAction` should not offer a move that cannot complete in full.

## Troubleshooting

### An action is missing from the menu

**Symptom:** the selected item has no expected action.

**Check:** confirm the Category Item Action Set includes the item's Category, does not exclude it, and the concrete action's prerequisites pass. Panel actions also need the Item View Slots Container binding to supply panel and slot context.

**Fix:** correct the Category mapping or the failing collection, attribute, panel, or slot reference. Use `DebugItemAction` to confirm which Category and attributes the Item resolves.

### Drop creates a copy or creates nothing

**Symptom:** a pickup appears but the Bag count does not change, or no useful pickup appears.

**Check:** inspect **Remove On Drop**, **Pick Up Item Prefab**, and the Console. The prefab root must contain an `ItemObject` or `Inventory`, and the action needs an Item User or Inventory GameObject as its spawn reference.

**Fix:** turn on **Remove On Drop** for a transfer and assign a compatible prefab. Test both the spawned object and the source count.

### A quantity, confirmation, or slot-choice panel fails to open

**Symptom:** the action logs a missing reference, throws when invoked, or opens no usable panel.

**Check:** confirm the correct panel prefab and component are assigned and that the action was opened from a panel-aware item-action binding.

**Fix:** use a `QuantityPickerPanel`, `ConfirmationPopUp`, or matching async-function panel prefab as required, and supply it from an Item View Slots Container action workflow.

### Equip, move, or hotbar assignment does nothing

**Symptom:** the action is unavailable, warns, or leaves the item unchanged.

**Check:** compare collection purposes and restrictions; confirm the destination slot accepts the Item; verify `ItemViewSlotMoveCursor` for `MoveItemAction`; and match **Hotbar Panel Name** exactly to a panel bound to an `ItemHotbar`.

**Fix:** correct the collection or slot configuration, add the required cursor, or repair the panel binding. Use `UnAssignHotbarItemAction` only from the hotbar container.

### Use removes an item but the effect does not occur

**Symptom:** the Health Potion count decreases without restoring health.

**Check:** confirm the `ItemActionSet` attribute name, referenced set, **Action Index**, and nested action's own prerequisites. The wrapper can remove the item after a nested invocation attempt that did not run.

**Fix:** make the nested action eligible before enabling **Remove On Use**, and test the effect and amount together.

## Version 1 behavior and limitations

- The core actions do not implement healing, spell casting, weapon use, or character animation. Put that behavior in a custom or integration action and call it through the appropriate wrapper.
- Drop, duplicate, remove, audio, quantity-drop, and confirmation actions have permissive eligibility checks. A visible button is not proof that every required reference is valid.
- Inventory mutations use the normal Item Collection add/remove paths and therefore their restrictions, overflow handling, and collection events. Panel-only choices and Item User cooldown data are transient unless another system saves them.
- The core package does not replicate Item Action invocation over a network. Synchronize the resulting inventory and gameplay state in the networking solution used by the project.
- The Opsive Character Controller integration provides specialized drop and equip actions. Prefer those for integrated characters rather than combining the generic core actions with character equipment manually.

## Developer reference

### Invocation and events

`ItemAction.InvokeAction(ItemInfo itemInfo, ItemUser itemUser)` calls `CanInvoke` before the concrete implementation. The action must be initialized. When `itemUser` is null and the `ItemInfo` has an Inventory, Version 1 uses `Inventory.ItemUser` as the fallback.

The concrete core types do not expose one common success event. Instead:

- Item Collection changes raise the standard add, remove, update, rejection, and overflow events.
- `ActionPanel<T>` exposes `OnActionsAssigned`, `OnBeforeAnyItemActionInvoke`, and `OnAfterAnyItemActionInvoke`; the Item View Slots Container binding also exposes **On Cannot Open Panel**, **On Action Canceled**, and **On Action Invoked** UnityEvents.
- `UseItemActionSetAttribute` raises `EventNames.c_CharacterGameObject_UsedItemActionWithCooldown_ItemAction_ItemInfo_Float` only when it applies a configured cooldown.

### Abstract extension types

| Base type | Context it supplies | Key Version 1 field or method |
| --- | --- | --- |
| `ItemActionWithQuantityPickerPanel` | Opens a pooled quantity panel under the parent display panel and awaits an integer. | **Quantity Panel Prefab**; override `SetupQuantityPickerSettings` and `InvokeWithAwaitedValue`. |
| `ItemActionWithAsyncFuncActionPanel<T>` | Opens a list of asynchronous choices and awaits a value of type `T`. | **Async Func Action Panel Prefab**; **Add Cancel Option** defaults on; override `InvokeWithAwaitedValue`. |
| `ItemObjectAction` | Holds a scene `ItemObject` supplied by the caller. | Call `SetItemObject` before invocation. |
| `ItemViewSlotsContainerItemAction` | Receives the origin Item View Slots Container, selected slot index, display panel, and previous selection. | Implements the panel and slot-container context used by move, unassign, and external-panel actions. |

The catalogs above cover all 16 concrete Item Action classes shipped in the Version 1 core package. Integration packages can add more types with product-specific prerequisites.

## Related pages

- [Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/) explains Item Action Sets, Category matching, and UI invocation.
- [Item Info](https://opsive.com/support/documentation/ultimate-inventory-system/item/item-info/) explains the amount, Item, Item Collection, and Inventory passed to an action.
- [Item Collections](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/) explains Bag, Equipment, restrictions, and collection purposes.
- [Item Hotbar](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-hotbar/) explains the Version 1 hotbar UI workflow.
- [Opsive Character Controllers integration](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/opsive-character-controllers/) covers the character-specific bridge and actions.
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/) explains which resulting inventory state can be persisted.

---

<a id="page-ultimate-inventory-system-item-objects"></a>

# Item Objects

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/)

An Item Object connects Ultimate Inventory System item data to a Unity GameObject. Add one when an item needs a physical presence, such as a Health Potion pickup, an equipped Iron Sword, or a usable Fire Wand. An item that only exists inside an Inventory does not need an Item Object.

The component is intentionally reusable: calling `SetItem` unbinds the previous Item and binds the new one, so one pooled pickup or equipment prefab can represent different Items over its lifetime.

## Understand what the Item Object owns

| Object | Responsibility |
| --- | --- |
| Item Definition | Database-authored identity, Category, and default Definition attributes, such as the definition for Iron Sword. |
| Item | The concrete common, mutable, or unique data created from a Definition. Runtime Item attributes such as Durability belong here. |
| Item Info | The Item plus an amount and optional Item Collection and stack context. |
| Item Object | A scene `MonoBehaviour` that holds an `ItemInfo` and binds its Item to a GameObject. |

An Item Object does not automatically add or remove anything from an Inventory. `ItemPickup` performs the world-to-Inventory transfer, while an `Equipper` observes an Equipment collection and creates or removes the corresponding scene object.

## Create a basic Item Object

1. Make sure the scene has an initialized Inventory System Manager and the intended database.
2. Select the GameObject or reusable prefab that should represent the item and add **Item Object**.
3. In the Item Object Inspector, confirm **Database**, set **Amount**, and select an Item Definition. When the amount is `0` or less, choosing a Definition changes it to `1`.
4. Expand **Item Details** to confirm the generated Item name, ID, Category, Definition, and its Mutable and Unique state.
5. Inspect the **Item Attributes**, **Item Definition Attributes**, and **Item Category Attributes** tabs. Only Item attributes are editable from this Inspector; inherited Definition and Category values are shown for context.
6. Add the component that gives the object its role: a visualizer, pickup, binding, behavior handler, or equipment workflow.

![Item Object Inspector with Database and Amount fields, selected Item Definition details, and Item, Definition, and Category attribute tabs](https://opsive.com/wp-content/uploads/2020/07/ItemObject.png?v=f7f23121adfa)

Editor checkpoint: the Item Object shows the correct database, a positive amount, and the intended Definition. The Item Details Category should match the companion component's requirements before entering Play Mode.

## How the binding runs

On `Awake`, the Item Object validates that its Item has an Item Definition. In Play Mode it registers the Item with the Inventory System Manager, initializes the Item, and refreshes its attributes. Invalid data is replaced with `ItemInfo.None`.

At startup and whenever `SetItem` changes the value, the component removes its binding from the previous Item and adds itself to the new Item's runtime Item Object list. `SetAmount` changes only the amount while keeping the same Item. Destroying the component removes the binding.

The Item Object sends `EventNames.c_ItemObject_OnItemChanged` when it is enabled and whenever its Item Info changes in Play Mode. Components such as `ItemObjectVisualizer` and `ItemBinding` listen for that event so a pooled object redraws and rebinds itself without being recreated.

One Item can be bound to more than one Item Object. `GetLastItemObject` therefore means the most recently bound object, not a persistent or network-safe identity.

## Choose the world-object workflow

Every direct child of this section covers a different use of the same Item Object binding.

| Goal | Components and important Version 1 defaults | Continue with |
| --- | --- | --- |
| Equip an Iron Sword or armor visual | An `Equipper` watches an `ItemSlotCollection`. **Equipment Item Collection ID** defaults to name `Equipped` and purpose `Equipped`; **Equipable Prefab Attribute Name** defaults to `EquipmentPrefab`; **Usable Item Prefab Attribute Name** defaults to `UsableItemPrefab`. | [Equipping Items](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/equipping-items/) |
| Copy an Item attribute into a component property | Put `ItemBinding` beside the Item Object, choose **Database** and **Item Category**, then add compatible attribute-to-property bindings. The Category and binding list are empty until configured. | [Item Binding](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-binding/) |
| Pick up a Health Potion from the world | Use `ItemObject`, `ItemPickup`, and `Interactable` on the prefab. **Add To Item Collection** defaults to Main and **Fail If Full Amount Does Not Fit** defaults off. The inherited **Deactivate On Interact** defaults on and **Schedule Reactivation Time** defaults to `-1`. | [Item Pickups](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-pickups/) |
| Spawn loot, currency, or an Inventory pickup | `ItemObjectSpawner` defaults to **ID** `1` and needs an **Item Object Prefab**. `ItemDropper`, `CurrencyDropper`, and their random variants provide designer-driven drop tables and pickup prefabs. | [Item and Currency Droppers](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-and-currency-droppers/) |
| Swap the model or sprite when the Item changes | Add `ItemObjectVisualizer` beside the Item Object. An empty **Prefab Attribute Name** falls back to `PickupPrefab` at runtime; an empty **Item Prefab Visualizer Parent** uses the current transform. **Default Visual Prefab** is used when the Item lacks that attribute, and **Item View** is optional. | [Item Object Visualizer](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-object-view/) |
| Run an equipped Fire Wand or weapon behavior | Add `ItemObjectBehaviourHandler`. **Item Object** falls back to the component on the same GameObject, while **Item Object Behaviours** is the ordered array used by `UseItem`. Each behavior decides whether it can run. | [Item Object Behaviour Handler](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/usable-item-objects/) |

### Health Potion pickup

Use a generic pickup prefab with `ItemObject`, `ItemPickup`, `Interactable`, and `ItemObjectVisualizer`. Bind the Health Potion with amount `1`; use a `PickupPrefab` GameObject attribute when the visualizer should swap in a potion-specific model. On interaction, `ItemPickup` tries the configured destination and reports success, failure, or a partial pickup through its UnityEvents and audio fields.

Turn on **Fail If Full Amount Does Not Fit** when the transfer should fail instead of adding only part of the stack. Leave it off when partial pickup is intentional. This flag does not keep a failed pickup active by itself: configure **Deactivate On Interact** and reactivation behavior for the desired failure flow.

### Equipped Iron Sword

Keep the owned Iron Sword in the Inventory rather than placing a permanent Item Object on the character. Moving the Item into the Equipped `ItemSlotCollection` causes `Equipper` to create an Item Object from its `EquipmentPrefab` attribute and place it in the matching slot. Removing the Item destroys or returns that object to its pool.

The generic Equipper does not change character stats or play equip animations. Those are project-specific behavior or integration responsibilities.

### Usable Fire Wand

For a Fire Wand, the Equipper can create the functional `UsableItemPrefab` and place the visual `EquipmentPrefab` beneath it. Put `ItemObjectBehaviourHandler` and the wand behaviors on the usable prefab. Add `ItemBinding` when Definition or Item attributes such as Attack or projectile count should drive public component properties.

`ItemObjectBehaviourHandler` only dispatches the selected array entry when its `CanUse` value is true. It does not define the spell, animation, targeting, or input by itself.

## Verify in Play Mode

| Test | Expected result | What it verifies |
| --- | --- | --- |
| Rebind one pooled pickup from Health Potion to Fire Wand | Item Details refer to the new Item, the visual changes once, and no old potion data remains on bound properties. | Item Object rebinding, change event, visualizer, and Item Binding. |
| Interact with a Health Potion pickup | The accepted amount appears in the destination Main collection and the pickup reports success, partial success, or failure consistently with capacity. | Item Info amount, Interactable, destination collection, and pickup settings. |
| Move Iron Sword into and out of Equipment | The sword object appears in the matching character slot and is removed or pooled when unequipped. | Equipment collection ID, Item Slot Set, prefab attributes, and Equipper listeners. |
| Use the equipped Fire Wand | The intended behavior index runs only when `CanUse` is true, with the wand Item Object and character Item User. | Behavior array order, Item User route, cooldown logic, and bound attributes. |

Also disable and re-enable a reusable pickup. Its visual and bound properties should still match its current Item after the Item Object change event runs.

## Persistence and multiplayer boundaries

`ItemObject` has no dedicated Version 1 saver. Inventory Saver and Inventory System Manager Item Saver preserve Inventory contents and registered mutable or unique Item data; they do not preserve the runtime list that links an Item to scene Item Objects. `GameObjectSaver` can preserve selected transform, active, destroyed, or component-enabled state, but it does not serialize the Item Object's `ItemInfo` association.

For persistent world loot, save enough item identity, amount, and transform data to respawn or rebind the object. For equipped visuals, restore the Equipment collection and let the Equipper rebuild its Item Objects.

The Version 1 core package does not replicate Item Object bindings, spawns, pickup outcomes, or behavior calls over a network. Replicate the authoritative Item identity and amount, then call `SetItem` on each required representation so local listeners update.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| The Item Object clears itself at startup | Check whether the selected Item has a valid Item Definition from the active database. | Select the correct **Database** and Definition; use the database conversion prompt only when equivalent objects exist. |
| A pooled object keeps the previous model or property values | Check that the new Item is assigned with `SetItem`, that the visualizer or binding is enabled, and that `ItemBinding` uses a Category containing both Items. | Rebind through `SetItem`, keep event listeners paired, and broaden or split the configured binding Category. |
| A Health Potion cannot be picked up | Check the `Interactable`, an Inventory-capable Interactor, **Add To Item Collection**, destination restrictions, and **Fail If Full Amount Does Not Fit**. | Repair the interaction setup or destination and choose whether partial pickup is allowed. |
| Iron Sword is in Equipment but no object appears | Check the Equipper's Inventory, **Equipment Item Collection ID**, Item Slot Set, matching slot Category, and non-null `EquipmentPrefab` attribute. | Make the collection, slot set, and Equipper use the same IDs and assign a prefab that can become an Item Object. |
| Fire Wand input runs the wrong behavior or nothing | Check **Item Object Behaviours** order, null entries, selected action index, and each behavior's `CanUse`. | Reorder or assign the array and make the chosen behavior eligible before dispatch. |

## Related pages

- [Items](https://opsive.com/support/documentation/ultimate-inventory-system/item/) explains Definition, Item, identity, mutability, and attributes.
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/) explains collection ownership and transactions.
- [Item Slot Collection](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/item-slot-collection/) configures Equipment slots used by the Equipper.
- [Interaction System](https://opsive.com/support/documentation/ultimate-inventory-system/interaction-system/) configures Interactable and Interactor behavior.
- [Built-in Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/built-in-item-actions/) covers UI-driven drop, move, use, and hotbar actions.
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/) covers Inventory, Item, and GameObject persistence.
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/) explains safe Version 1 event registration and unregistration.

## Use the Item Object API

Register for the parameterless change event while the listener is enabled. Run the handler once after registration so the component is correct even when Unity enables the Item Object first.

```csharp
using EventHandler = Opsive.Shared.Events.EventHandler;

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

    HandleItemChanged();
}

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

private void HandleItemChanged()
{
    var itemInfo = m_ItemObject.ItemInfo;
    // Refresh this component from itemInfo.
}
```

Create and bind an Item through the manager. `SetItem(Item)` uses an amount of one; `SetAmount` keeps the current Item; `SetItem(ItemInfo.None)` clears the binding.

```csharp
var healthPotion = InventorySystemManager.CreateItem("Health Potion");

m_ItemObject.SetItem(healthPotion);
m_ItemObject.SetAmount(5);

var stack = (ItemInfo)(3, healthPotion);
m_ItemObject.SetItem(stack);

// Clear the world representation before reusing it.
m_ItemObject.SetItem(ItemInfo.None);
```

The Item-side lookup methods expose current runtime bindings only. Iterate them when several representations are valid; do not save an array index or assume `GetLastItemObject` is authoritative.

```csharp
for (var i = 0; i < healthPotion.GetItemObjectCount(); i++)
{
    var itemObject = healthPotion.GetItemObjectAt(i);
    // Use the current scene representation.
}
```

---

<a id="page-ultimate-inventory-system-item-objects-usable-item-objects"></a>

# Item Object Behaviour Handler

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/usable-item-objects/)

Use an **Item Object Behaviour Handler** when an equipped Item needs GameObject behavior that player input or project code can trigger. An Iron Sword can call a melee component, while a Fire Wand can call a projectile component and obtain its values from the equipped Item.

The handler does not provide a general attack, spell, or consume system. It maps an action index to a project-specific **Item Object Behaviour**, checks whether that behavior can run, and passes it the equipped **Item Object** and **Item User**.

| Goal | Use |
| --- | --- |
| Swing an equipped Iron Sword or cast with an equipped Fire Wand | Item Object Behaviour Handler on the usable Item Object prefab |
| Drink a Health Potion directly from Bag | An [Item Action](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/), unless the potion is deliberately equipped or spawned as an Item Object |
| Move an Item between Bag and Equipment | An Item Action or Inventory UI transaction; the behavior handler does not move Items |

## Before you begin

Prepare the equipment workflow before adding usable behavior:

- an initialized Inventory System Manager and database;
- a player Inventory with Bag and a slot-based Equipment collection;
- an Item Slot Set shared by the Equipment collection and Equipper;
- an **Item User** and player input implementation on the character;
- an **Equipper** configured for the Equipment collection; and
- valid `EquipmentPrefab` and, when needed, `UsableItemPrefab` GameObject attributes.

See [Equipping Items](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/equipping-items/) for the complete collection, slot, prefab, and Equipper setup.

## Build an Iron Sword usable prefab

This workflow uses action index `0` for a sword attack.

1. Create a prefab that will be the sword's functional Item Object. Add **Item Object** to its root.
2. Add the project's melee component to the same root. The component must inherit `ItemObjectBehaviour` and implement `Use`.
3. Add **Item Object Behaviour Handler** to that root.
4. Leave **Item Object** empty when the Item Object component is on the same GameObject. The handler finds it in `Awake`. Assign the field explicitly only when the handler intentionally targets another Item Object.
5. Set **Item Object Behaviours** to size `1` and assign the melee component to element `0`.
6. On the Iron Sword Definition, assign the visible sword model to `EquipmentPrefab`. Assign the functional prefab to `UsableItemPrefab` when the visual and behavior roots are separate.
7. If Attack or another Item attribute should configure the melee component, add **Item Binding** to the usable root and bind that attribute to a public property on the component. See [Item Binding](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-binding/).

The array order is the action contract. Element `0` is action index `0`, element `1` is action index `1`, and so on. The handler does not search the prefab for behaviors or identify them by name.

### Editor checkpoint

Before entering Play Mode, confirm that:

- Iron Sword has a non-null `EquipmentPrefab`;
- `UsableItemPrefab` is either absent or references a valid functional prefab;
- the functional root contains Item Object, Item Object Behaviour Handler, and the melee behavior;
- every **Item Object Behaviours** element contains the intended component; and
- each configured action index matches the array element that should run.

## Connect character input

Add **Usable Equipped Items Handler** to the character that owns the Equipper and Item User.

1. Assign **Item User**, or leave it empty only when Item User is on the same GameObject.
2. Add an element under **Inputs**.
3. Leave **Input Type** as **Button Down** for a one-use-per-press action, or deliberately choose another supported input type.
4. Set **Input Name** to the project input mapped to the sword attack.
5. Set **Item Object Index** to the sword's index in the Equipper's **Item Object Slots** list.
6. Set **Action Index** to `0` for the first behavior in the sword handler.

The released Version 1 defaults for each input are **Button Down**, an empty **Input Name**, **Long Press Duration** `0.5`, **Wait For Long Press Release** off, **Item Object Index** `0`, and **Action Index** `0`. Supply a real Input Name unless **Automatic** or a project-controlled route is intentional.

Item Object Index and Action Index identify different things. Item Object Index selects an equipped slot; Action Index selects a behavior on the Item Object in that slot.

## How it runs

When the configured input is detected:

1. Usable Equipped Items Handler asks the Equipper for the Item Object at **Item Object Index**.
2. It looks for an `IItemObjectBehaviourHandler` on that Item Object's root GameObject.
3. Item Object Behaviour Handler validates **Action Index** and gets that array element.
4. If the component exists and its `CanUse` property is true, the handler calls `Use`.
5. `Use` receives the exact equipped Item Object and the character's Item User, so project code can read Item attributes or reach character gameplay systems.

An input is ignored when the slot is empty, the Item Object root has no handler, the action index is outside the array, or `CanUse` is false. A null behavior element logs a warning. The handler does not queue a blocked use or return a success result.

The Usable Equipped Items Handler disables itself when its player's gameplay-input event disables input. This prevents configured uses while another system has turned off gameplay input, provided the project sends that event through the same player input GameObject.

## Understand prefab ownership

The default Equipper always requires `EquipmentPrefab`.

- When `UsableItemPrefab` is absent, `EquipmentPrefab` becomes the Item Object root. Put the handler and behavior on that prefab.
- When `UsableItemPrefab` exists, it becomes the functional Item Object root and the equipment model is created beneath it. Put the handler and behavior on the usable prefab, not only on the visual model.

This placement matters because Usable Equipped Items Handler checks the Item Object's root GameObject; it does not search child objects for the handler.

The Equipment collection remains the source of truth. Adding Iron Sword to an Equipment slot makes the Equipper create or reuse the functional root and visual model. Removing it clears the slot and destroys or returns those objects to their pools. The behavior handler does not equip, unequip, pick up, or drop the Item by itself.

## Control cooldowns

Every Item Object Behaviour begins usable. Its default `CanUse` returns true when `Time.time` is greater than or equal to its protected `m_NextUseTime` value.

A custom behavior owns its cooldown. During `Use`, set `m_NextUseTime` to `Time.time + cooldown`. The handler does not do this automatically. Each behavior component has its own value, so an attack and a reload stored at different action indexes can use independent cooldowns.

Keep these timing choices in mind:

- **Button Down** requests one use for each completed press and release.
- **Button Down Continuous** can request a use every frame while the button is held; `CanUse` must prevent unwanted repeats.
- **Automatic** requests a use every Update and runs again as soon as the behavior becomes available.
- `Time.time` uses scaled game time, so a paused or slowed time scale also pauses or slows the default cooldown.
- Input during a cooldown is discarded rather than buffered.

An Item Object returned to the Version 1 pool is disabled, not reconstructed. Its nonserialized `m_NextUseTime` field can therefore remain set if the same instance is reused during the same session. Reset the value in project code only when immediate reuse after re-equipping is the intended design.

## Apply the pattern to common Items

### Iron Sword

Use a custom melee behavior at action index `0`. The behavior can read Attack from the Item Object's Item, obtain the character combat component through Item User, start animation and collision timing, and then advance `m_NextUseTime`.

### Fire Wand

Use a custom ranged behavior at action index `0`. An Item Binding can copy Attack and project-specific values such as projectile count or projectile prefab into public properties on that behavior. The behavior then launches the projectile and applies its own cooldown. Keep the wand model in `EquipmentPrefab` and reusable casting logic in `UsableItemPrefab` when several Definitions share the same implementation.

### Health Potion

For a Health Potion selected in Bag, use an Item Action so the command keeps the selected Item Info and collection context, applies healing, and removes the correct amount. Use an Item Object Behaviour only when the potion is represented as an equipped or world Item Object and should follow this component-and-input route.

## Verify in Play Mode

1. Put Iron Sword in Bag, equip it into the expected Equipment slot, and confirm that the Equipper creates an Item Object in the matching **Item Object Slots** entry.
2. Press the configured input once. Confirm that only the behavior at the configured action index runs and receives Iron Sword and the expected Item User.
3. Press again before the cooldown ends. The second use should be ignored without starting another attack.
4. Press after the cooldown. The behavior should run again exactly once.
5. Equip Fire Wand into the same or another configured slot. Confirm that Item Binding applies its values before the first cast and that the input selects the correct slot and action.
6. Unequip the Item and press the input. No behavior should run while the selected slot is empty.
7. Disable gameplay input through the character's normal input-gating flow. The handler should stop responding until gameplay input is enabled again.

## Saving and multiplayer

Inventory saving restores the Equipment collection; the Equipper then recreates the appropriate Item Objects from their prefab attributes. The behavior array and its serialized settings belong to the prefab and do not need a separate save record.

The default system does not save an in-progress use, the remaining `m_NextUseTime`, a running behavior coroutine, or other custom gameplay state. Store persistent cooldowns or charges in a saved Item attribute or a project saver when they must survive loading.

Released Version 1 does not replicate Item Object Behaviour calls or enforce multiplayer authority. In a networked project, let the authoritative side validate the equipped Item, action index, cooldown, resource costs, and resulting damage or projectile. Replicate the accepted result rather than allowing each client to apply it independently.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| Input does nothing | Check Item User, the player input implementation, **Input Name**, and gameplay-input gating. | Put the required components on the same character or assign Item User explicitly, then test the input mapping while gameplay input is enabled. |
| The wrong equipped Item responds | Compare **Item Object Index** with the ordered **Item Object Slots** generated by the Equipper's Item Slot Set. | Use the zero-based slot index for the intended Equipment slot. |
| The wrong behavior runs | Compare **Action Index** with the **Item Object Behaviours** array order. | Reorder the array or update the input's action index; indexes are positional. |
| The equipped model appears but cannot be used | Inspect which prefab is the functional Item Object root and whether the handler is on that root. | Put the handler and behavior on `UsableItemPrefab`, or on `EquipmentPrefab` when no usable prefab is defined. |
| The Console warns that an action component is null | Inspect the selected **Item Object Behaviours** element. | Assign a behavior component to every reachable element or remove the unused entry. |
| Holding input triggers too often | Check **Input Type** and whether the custom behavior advances `m_NextUseTime`. | Use **Button Down** for one use per press and set the next-use time when the behavior runs. |
| The Item remains unavailable after a quick unequip and re-equip | Check whether the pooled behavior instance still has a future next-use time. | Keep that continuity when it is intended, or reset the custom cooldown when the usable object is enabled. |
| Fire Wand uses default values instead of Item attributes | Check the Item Binding's source, attribute names, target component, and public property paths. | Keep Item Binding on the usable root and bind each correctly typed attribute to a public property. |

## Current Version 1 boundaries

- The framework supplies the handler and base behavior. Actual attacks, spells, consumable effects, and character rules are project-specific; the demo's melee and ranged behaviors are examples, not general runtime actions.
- Item Object and action selection are positional integer indexes. There is no name lookup, action priority, or automatic remapping when array order changes.
- The input route finds the behavior handler only on the equipped Item Object's root.
- The built-in input check handles Automatic, Button Down, Button Down Continuous, Double Press, Long Press, Tap, and Axis. Manual and Custom enum values do not invoke an action through `SimpleInput.CheckInput`; call `UseItem` or add project input code for those routes.
- A blocked cooldown, invalid index, empty slot, or missing handler is ignored without a result event. Only a null behavior element produces the handler's warning.
- Cooldown state is per component, uses scaled time, is not saved, and may remain on a pooled instance during the current session.
- The behavior handler has no built-in save, networking, cost, animation, projectile, damage, or use-completed event layer.

## Related pages

- [Item Objects](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/) explains the relationship between Items and their scene GameObjects.
- [Equipping Items](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/equipping-items/) configures Equipment collections, slots, prefab attributes, and the Equipper.
- [Item Binding](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-binding/) copies Item attributes into public component properties.
- [Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/) covers inventory-side commands such as drinking, equipping, and dropping.
- [Input Handlers](https://opsive.com/support/documentation/ultimate-inventory-system/input/handlers/) covers the wider Version 1 input routes.
- [Item Slot Collection](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/item-slot-collection/) explains slot-based Equipment ownership.
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/) covers Inventory and Item persistence.
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/) lists the framework event pattern used by equipment and inventory systems.

## Developer reference

A custom behavior inherits `ItemObjectBehaviour`. Set its next-use time when the action is accepted, then call the project's gameplay system with the Item Object and Item User context.

```csharp
using Opsive.UltimateInventorySystem.Core;
using Opsive.UltimateInventorySystem.ItemActions;
using Opsive.UltimateInventorySystem.ItemObjectBehaviours;
using UnityEngine;

public sealed class FireWandCast : ItemObjectBehaviour
{
    [SerializeField] private float m_Cooldown = 0.5f;

    public override void Use(ItemObject itemObject, ItemUser itemUser)
    {
        m_NextUseTime = Time.time + m_Cooldown;

        // Read the equipped Item and call the project's projectile system.
        var item = itemObject.Item;
    }
}
```

The main runtime entry points are:

- `ItemObjectBehaviour.CanUse` and `Use(ItemObject, ItemUser)` for behavior eligibility and execution;
- `ItemObjectBehaviourHandler.UseItem(ItemUser, int)` for direct use of one action index; and
- `UsableEquippedItemsHandler.UseItem(int, int)` for direct selection by equipped-slot index and action index.

The Equipper publishes its standard equipped, unequipped, and changed events when the Equipment collection changes. The behavior handler does not publish a use event, so a project that needs started, completed, canceled, cooldown, or resource-consumed notifications must define those around its gameplay behavior.

---

<a id="page-ultimate-inventory-system-item-objects-equipping-items"></a>

# Equipping Items

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/equipping-items/)

Use an **Equipper** when moving an Item into a slot-based Equipment collection should create a visible or usable GameObject on the character. In the shared example, an Iron Sword appears in the character's hand and a Fire Wand can combine a reusable behavior prefab with a different visual model.

The Equipment collection remains the source of truth. The Equipper watches that collection and builds Item Objects from prefab attributes; it does not decide which Item may be equipped, move Items between collections, read player input, or apply character stats.

## Before you begin

Prepare these parts before configuring the Equipper:

- an initialized Inventory System Manager using the intended database;
- a player Inventory with a Bag collection and an Item Slot Collection for Equipment;
- an Item Slot Set whose slots use categories from that database;
- an Equippable or Weapon category that contains Iron Sword and Fire Wand; and
- GameObject attributes and prefabs for the equipment visuals.

Use the same Item Slot Set asset on the Equipment collection, Equipment UI, and Equipper. The slot names, order, and categories must agree across all three.

## Understand the equipment flow

| Part | Responsibility |
| --- | --- |
| Item Slot Set | Defines the ordered slot names and the Item Category accepted by each slot. |
| Equipment Item Slot Collection | Owns the equipped Items at runtime. Moving an Item into or out of this collection is the equip or unequip decision. |
| Equipper | Watches Inventory add and remove events, then creates or removes the Item Object for the affected slot. |
| Item Object slot | Maps one Item Slot Set entry to a rigid attachment transform or a skinned-mesh binding. |
| Equipment UI or Item Action | Lets the player request the collection move. It does not create the character model itself. |

The released Version 1 Item Slot Set contains **Name** and **Item Category** for each entry. It does not contain a per-slot size field. Use an Inventory restriction when an equipped stack needs an amount limit.

## Create the Item Slot Set and Equipment collection

1. In the Project window, choose **Create > Ultimate Inventory System > Inventory > Item Slot Set**.
2. Name the asset `PlayerEquipmentItemSlotSet` and set **Database** to the active Inventory System Database.
3. Under **Item Slot Set**, add `Right Hand` with **Item Category** set to Weapon.
4. Add only the other slots the game needs, such as Head, Chest, or Legs. Give every slot a unique name and a nonempty category.

![Legacy Item Slot Set Inspector with named equipment slots and an Item Category assigned to the selected slot](https://opsive.com/wp-content/uploads/2020/04/ItemSlotSet.png)

5. On the player Inventory, add or select the Equipment Item Collection.
6. Set **Name** to `Equipment`, **Collection** to **Item Slot Collection**, and **Purpose** to **Equipped**.
7. Assign `PlayerEquipmentItemSlotSet` to **Item Slot Set**.
8. Keep **New Item Priority** off for a normal equipment workflow. Use **Move To Collection Item Action** when equipping a new Item should return the previous Item to Bag safely.

![Legacy Inventory Inspector with an Equipped Item Slot Collection and its Item Slot Set assigned](https://opsive.com/wp-content/uploads/2020/04/EquippedItemCollection.png?v=9e7d9176e545)

The collection chooses the first empty slot whose category inherently contains the Item. If no matching slot is empty, replacement behavior depends on the collection settings and the operation that moved the Item. Do not assume that a directly replaced Item always returns to Bag; the standard Move To Collection action performs the safer exchange.

## Configure the equipment prefab attributes

The default Equipper looks up these GameObject attributes on the Item, its Definition, and then its Category:

| Attribute | Required | Purpose |
| --- | --- | --- |
| `EquipmentPrefab` | Yes | The visible sword, wand, armor, or other equipment prefab. |
| `UsableItemPrefab` | No | A functional prefab containing reusable Item Object behaviors, attacks, or other logic. |

For an Iron Sword, set `EquipmentPrefab` on the Definition to the sword model. If the sword needs reusable melee behavior, also provide a non-null `UsableItemPrefab`; the Equipper creates that functional prefab as the Item Object and places the sword model beneath it.

For a Fire Wand, the Definition can provide its distinct wand model while a shared Weapon category provides a reusable `UsableItemPrefab`. An [Item Binding](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-binding/) can copy attributes such as Attack or projectile count into public properties on that functional prefab.

These scopes are a convention, not a lookup requirement. The important rules are that `EquipmentPrefab` exists and is non-null, and that `UsableItemPrefab` is either absent or points to a valid prefab. In released Version 1, defining `UsableItemPrefab` with a null value does not behave like omitting it; the Equipper tries to spawn the null functional prefab and the equip visual fails.

## Configure the Equipper

1. Add **Equipper** to the character. Assign **Inventory**, or leave it empty only when the Inventory is on the same GameObject.
2. Set **Equipment Item Collection ID** to name `Equipment` and purpose **Equipped**. Its released Version 1 defaults are name `Equipped` and purpose **Equipped**, so change the name when the collection uses `Equipment`.
3. Leave **Equipable Prefab Attribute Name** as `EquipmentPrefab` and **Usable Item Prefab Attribute Name** as `UsableItemPrefab`, unless the database deliberately uses different names.
4. Assign `PlayerEquipmentItemSlotSet` to **Item Slot Set**. The **Item Object Slots** list is regenerated in the same order as the asset.
5. Select `Right Hand`, leave **Skinned Equipment** off, and assign the hand socket to **Transform**.
6. In **More Options**, add any default hand or body GameObjects to **Hide When Wearing Equipment**. They are disabled while that slot has an Item Object and restored when it is cleared.
7. Leave the slot's **Item Object** empty before Play Mode; it shows the current spawned representation at runtime.

![Legacy Equipper Inspector with collection ID, prefab attribute names, Item Slot Set, and per-slot Item Object settings](https://opsive.com/wp-content/uploads/2020/04/CharacterEquipper.png?v=2735350ec3e8)

**Skinned Mesh Character** defaults to enabled. For a rigged character, assign **Main Root Node** or let the Equipper find the root bone from a child Skinned Mesh Renderer. Turn the option off for a character that has no bone hierarchy.

Editor checkpoint: the Equipment collection, Equipment UI, and Equipper use the same Item Slot Set; the Equipper resolves the Equipment Item Slot Collection; every Item Object slot has the intended rigid or skinned setting; and Iron Sword and Fire Wand both provide a valid `EquipmentPrefab`.

## Choose rigid or skinned equipment

### Rigid equipment

Use rigid equipment for an Iron Sword, Fire Wand, shield, or another object that follows one transform without deforming.

- Leave **Skinned Equipment** off.
- Assign the attachment point, such as the right-hand socket, to **Transform**.
- Author the prefab so its local origin and rotation align correctly at that socket.

When equipped, the Item Object becomes a child of the slot Transform with zero local position and rotation and a local scale of one.

### Skinned equipment

Use skinned equipment for clothes or armor that must deform with the character.

- Keep **Skinned Mesh Character** enabled and set a valid **Main Root Node**.
- Enable **Skinned Equipment** on the corresponding Item Object slot.
- Include a Skinned Mesh Renderer and the matching character bone hierarchy in the equipment prefab.
- Keep every relevant bone name unique and consistent with the character rig.

![Legacy Unity editor view of a skinned armor prefab prepared with a Skinned Mesh Renderer and matching character rig](https://opsive.com/wp-content/uploads/2020/04/SkinnedMeshArmor-1024x477.png)

At runtime, the Equipper matches the equipment bones to character bones by name, assigns the new root and bone array to each Skinned Mesh Renderer, and removes the temporary equipment rig. These objects use a character-specific pool because their renderers remain bound to that character's bones.

## How equipping runs

When the Equipper starts, it resolves its Inventory, finds the collection identified by **Equipment Item Collection ID**, and requires that collection to be an Item Slot Collection. It registers for the Inventory add and remove events, then creates Item Objects for Items that already occupy Equipment slots.

When Iron Sword moves from Bag to Equipment:

1. The Item Slot Collection selects a compatible Weapon slot.
2. The Inventory add event tells the Equipper which Item Stack and slot changed.
3. The Equipper reads `EquipmentPrefab` and, when present, `UsableItemPrefab`.
4. It creates the Item Object, stores it in the matching Item Object slot, and positions or skins it.
5. It hides any GameObjects configured for that occupied slot and sends the Equipper change events.

When the Item leaves Equipment, the Equipper clears the slot, restores hidden GameObjects, and destroys or returns the Item Object to its pool. It does not move the Item back to Bag; the UI action or project code performs that collection transaction.

For Fire Wand input, add **Usable Equipped Items Handler** beside the Equipper and Item User. The handler maps an input to an Item Object slot index and behavior index. See [Usable Item Objects](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/usable-item-objects/) for the functional prefab workflow.

## Save, stats, and multiplayer boundaries

The Equipper does not need its own saver. **Inventory Saver** records the Equipment Item Slot Collection by slot index, and **Inventory System Manager Item Saver** preserves registered mutable or unique Item data. Loading removes and re-adds the collection contents, so the Equipper removes and rebuilds the corresponding visuals through the normal Inventory events.

Keep the Inventory collection order and Item Slot Set order compatible with existing save files. The standard Version 1 save data addresses collections and Equipment slots by index.

Equipping does not automatically change character stats. `EquipperBase` can total a numeric attribute across the Equipment collection, but the project decides when and how to apply that result. The demo's character-stat implementation is an example rather than a required UIS subsystem.

The released Version 1 core package does not replicate Equipment collection changes, spawned Item Objects, or use calls over a network. In a multiplayer project, make the Inventory transaction authoritative, replicate the resulting Item and slot state, and let each client update its local representation.

## Verify in Play Mode

1. Start with Iron Sword and Fire Wand in Bag and no Item in Equipment. Confirm that no equipment Item Object is present.
2. Invoke **Equip** on Iron Sword. Confirm that the same Item moves into the Weapon slot and the sword appears at the right-hand Transform.
3. Invoke **Unequip**. Confirm that the sword object is removed or pooled, any hidden default hand object returns, and Iron Sword moves back to Bag.
4. Equip Fire Wand. Confirm that its functional prefab is the Item Object and its `EquipmentPrefab` visual appears beneath it.
5. Trigger one configured equipped-item input. Confirm that the intended behavior index runs once through the Item User.
6. Try to equip Health Potion. Confirm that the Consumable Item has no compatible Equipment slot and no visual appears.
7. Save with Iron Sword equipped, unequip it, then load. Confirm that it returns to the same slot with one correctly rebuilt visual.
8. For skinned armor, animate the character and confirm that the mesh deforms with the character without missing-bone warnings.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| Equipment contains Iron Sword but no object appears | **Inventory**, **Equipment Item Collection ID**, collection type, and `EquipmentPrefab` | Resolve the intended Item Slot Collection and assign a non-null Equipment prefab. |
| Equipping fails after adding an optional usable-prefab attribute | Whether `UsableItemPrefab` exists with a null value | Remove the attribute when no functional prefab is needed, or assign a valid prefab. |
| The sword appears at the character origin | Right Hand **Transform** and **Skinned Equipment** | Assign the hand socket and keep rigid equipment unskinned. |
| The wrong slot receives the Item | Item Slot Set order, slot categories, and the Item Definition category | Use the same set everywhere and narrow each slot to the intended inherited category. |
| The UI changes but the character visual does not | Item Slot Set on the collection, UI, and Equipper; collection ID; prefab attributes | Make all three use the same asset and identifiers, then repair the Item's prefab data. |
| A default body or hand mesh remains visible through equipment | **Hide When Wearing Equipment** on the selected Item Object slot | Add the default GameObjects that should be disabled while the slot is occupied. |
| Skinned armor logs missing-root or missing-bone messages | **Main Root Node**, duplicate bone names, equipment root bone, and prefab hierarchy | Use matching uniquely named rigs and assign the character's correct root node. |
| Equipped-item input does nothing | Item User, Usable Equipped Items Handler indexes, and Item Object Behaviour Handler | Assign matching components and valid slot and behavior indexes. |
| Loaded equipment returns to another slot | Inventory collection order or Item Slot Set order changed after the save | Restore the compatible order or migrate the saved data. |

## Related pages

- [Item Objects](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/)
- [Item Slot Collection](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/item-slot-collection/)
- [Equipment in UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/equipment/)
- [Item Binding](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-binding/)
- [Usable Item Objects](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/usable-item-objects/)
- [Built-in Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/built-in-item-actions/)
- [Input Handlers](https://opsive.com/support/documentation/ultimate-inventory-system/input/handlers/)
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/)

## Developer reference

Query the Equipment collection and the representation for a named slot after the Equipper has initialized:

```csharp
var equipment = inventory.GetItemCollection(
    new ItemCollectionID("Equipment", ItemCollectionPurpose.Equipped))
    as ItemSlotCollection;

var weaponIndex = equipment.ItemSlotSet.GetIndexOf("Right Hand");
var equippedItem = equipper.GetEquippedItem(weaponIndex);
var equippedObject = equipper.GetEquippedItemObject(weaponIndex);
```

`Equip`, `UnEquip`, and the representation queries do not perform a safe Bag-to-Equipment transaction. In normal gameplay, move the Item through the Item Slot Collection or **Move To Collection Item Action** and let the Equipper respond to Inventory events.

Register for the parameterless change event when a system only needs to recompute its state:

```csharp
using EventHandler = Opsive.Shared.Events.EventHandler;

private void OnEnable()
{
    EventHandler.RegisterEvent(
        equipper,
        EventNames.c_Equipper_OnChange,
        HandleEquipmentChanged);
}

private void OnDisable()
{
    EventHandler.UnregisterEvent(
        equipper,
        EventNames.c_Equipper_OnChange,
        HandleEquipmentChanged);
}
```

The released Version 1 source declares `c_Equipper_OnUnequipped_Item_Index` with the same underlying event string as `c_Equipper_OnEquipped_Item_Index`. Do not register both constants expecting distinct channels. Use `c_Equipper_OnChange` and inspect the current slot state, or observe the Inventory add and remove events when custom code must distinguish the transition.

---

<a id="page-ultimate-inventory-system-item-objects-item-binding"></a>

# Item Binding

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-binding/)

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](https://opsive.com/wp-content/uploads/2020/05/ItemBinding.png?v=d35e5eb701a3)

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. |

## Related pages

- [Item Objects](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/)
- [Equipping Items](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/equipping-items/)
- [Item Pickups](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-pickups/)
- [Usable Item Objects](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/usable-item-objects/)
- [Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/)
- [Defining Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/)
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/)

## Developer details

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

```csharp
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:

```csharp
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:

```csharp
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.

---

<a id="page-ultimate-inventory-system-item-objects-item-pickups"></a>

# Item Pickups

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-pickups/)

Use a pickup when a player should transfer an Item, a group of Items, or Currency from the world into their Inventory. The released Version 1 components share the same Interactable flow but differ in what they transfer: Item Pickup reads one Item Info, Inventory Pickup reads a source Inventory, Random Inventory Pickup samples that Inventory as a probability table, and Currency Pickup reads a Currency Owner.

## Before you begin

The character and pickup must participate in the same interaction and inventory setup:

- The scene has an initialized Inventory System Manager with the intended Inventory System Database.
- The character has an **Inventory** and an **Inventory Interactor**, or another component implementing `IInteractorWithInventory`.
- The character has the configured player input and a Collider or Collider2D on a layer included by the pickup's **Interactor Layer Mask**.
- The pickup has an **Interactable**, one pickup behavior, the appropriate Item Object, Inventory, or Currency Owner, and a working trigger collision setup.
- At least one object in the collision pair has a Rigidbody or Rigidbody2D, and the pickup's interaction volume is a trigger.

By default, the GameObject deactivates and is destroyed or returned to its pool after every interaction attempt, including a failed attempt. The workflow below configures a safer full-success pickup.

## Create a Health Potion pickup

1. Open **Tools > Opsive > Ultimate Inventory System > Main Manager** and select **Setup**.
2. Under **Create Templates**, set **Option** to **Item Pickup**.
3. Assign **Default Pickup Model Prefab**, leave **3D Pickup** enabled for a 3D project, and optionally assign an **Item View Prefab** whose root has an Item View component. Select **Create**.
4. On the generated Item Object, confirm the same **Database** used by the scene manager, select Health Potion, and set **Amount** to the quantity represented by this pickup.
5. On Item Pickup, leave **Add To Item Collection** at its Main-purpose default unless the Item must go to another collection. Turn on **Fail If Full Amount Does Not Fit** for an all-or-nothing Health Potion stack.
6. Turn off **Deactivate On Interact**. In **On Pickup Success**, call this pickup's public `Deactivate()` method. The pickup now remains available after a capacity failure but disappears after a complete transfer.
7. On Interactable, set **Interactor Layer Mask** to the character layer. Keep only the project's collision mode enabled: **3D** for Collider triggers or **2D** for Collider2D triggers.
8. If an Item View Prefab was used, confirm that its generated Canvas appears in **Select Indicators**. Set the Canvas **Render Mode** to **World Space** when it should follow the pickup in the scene.
9. Keep **Item Object Visualizer** when Health Potion, Iron Sword, and Fire Wand share the same pickup shell but need different models.

The Setup Manager's 3D template creates an Interactable and Rigidbody on the root, a regular Box Collider, and a trigger Sphere Collider beneath **Model Parent**. The 2D template uses Rigidbody2D, BoxCollider2D, and a trigger CircleCollider2D. Verify the generated sizes and layers against the character rather than assuming the defaults fit the game.

Editor checkpoint: the Item Object reports Health Potion and the intended amount, **Add To Item Collection** resolves to the character's Main collection, the trigger overlaps the character layer, and only **On Pickup Success** deactivates the all-or-nothing pickup.

## Understand the released defaults

| Component | Inspector field | Default | Effect |
| --- | --- | --- | --- |
| Interactable | Interactor Layer Mask | Everything | Any layer can enter until narrowed. |
| Interactable | Is Interactable | On | Selection and interaction are allowed. |
| Interactable | Auto Interact | Off | Entering the trigger selects; input performs the interaction. |
| Interactable | 2D / 3D | Both on | Both trigger callback families are checked. Disable the unused mode. |
| Interactable | On Interact / On Select / On Deselect | Empty | No project UnityEvent response runs until listeners are assigned. |
| Pickup behavior | Deactivate On Interact | On | Every interaction attempt deactivates after its transfer method returns. |
| Pickup behavior | Schedule Reactivation Time | `-1` | No scheduled reactivation; Pickup Base destroys or pools the GameObject after deactivation. |
| Pickup behavior | Select Indicators | Empty | Nothing is automatically shown on selection. |
| Pickup behavior | On Pickup Success / Fail / Partial Pickup | Empty | No project response is invoked until listeners are assigned. |
| Pickup behavior | Audio Clip / Audio Config / Fail Audio Clip / Fail Audio Config / Partial Pickup Audio Clip / Partial Pickup Audio Config | Unassigned | No pickup-result audio plays. |
| Item Pickup | Add To Item Collection | Purpose `Main`, no name | The destination resolves to the Main collection. |
| Item Pickup | Fail If Full Amount Does Not Fit | Off | A destination may accept only part of the Item Info amount. |
| Inventory Pickup | Remove Picked Up Items / Pickup Duplicate Items | Both off | Accepted originals move to the destination and new copies are put back into the source Inventory. |
| Random Inventory Pickup | Min Amount / Max Amount | `1` / `2` | One or two weighted draws are made. |
| Random Inventory Pickup | Amount Probability Distribution | Unassigned | The draw count is chosen uniformly between Min and Max, inclusive. |

The success, fail, and partial sections each have a UnityEvent, Audio Clip, and Audio Config. These callbacks report the transfer outcome; **Deactivate On Interact** still controls what happens to the world object afterward.

## How an Item Pickup transfers Item Info

Item Pickup requires an Item Object and uses its complete `ItemInfo`: the Item, amount, and optional stack or collection context. The Item's Definition and ID come from the Inventory System Database and runtime manager; **Add To Item Collection** identifies only the destination collection.

`ItemCollectionID` contains a Name and Purpose. A matching name is preferred over a purpose-only match, and a collection matching both is the strongest match. If Item Pickup cannot resolve the configured ID, it falls back to the destination Inventory's Main collection.

When an Inventory-capable Interactor uses the pickup:

1. Item Pickup resolves the destination Item Collection.
2. `CanAddItem` determines whether restrictions and available space accept none, part, or all of the Item Info amount.
3. No accepted amount, or a partial amount while **Fail If Full Amount Does Not Fit** is on, invokes **On Pickup Fail** and its fail audio.
4. Otherwise `AddItem` performs the transfer. An actual amount below the requested amount invokes **On Partial Pickup**; an equal amount invokes **On Pickup Success**.
5. The inherited interaction method then applies **Deactivate On Interact**, regardless of the outcome.

An Interactor that does not implement `IInteractorWithInventory` returns without a success, fail, or partial notification. With **Deactivate On Interact** enabled, that attempt still deactivates the pickup.

Released Version 1 does not subtract an accepted partial amount from `ItemObject.ItemInfo`. With the default lifecycle, a partial transfer destroys the whole pickup and the remainder is lost. If deactivation is disabled, the original full amount remains and can be added again. Use **Fail If Full Amount Does Not Fit** for all-or-nothing stacks, or write a custom Item Pickup that reduces the Item Object amount and deactivates only when the remainder reaches zero.

## Choose a pickup type

| Goal | Required source component | Transfer behavior | Important limitation |
| --- | --- | --- | --- |
| Pick up one Health Potion stack or Iron Sword | Item Object + Item Pickup | Adds the Item Object's Item Info to one destination collection. | Partial acceptance does not update the source amount. |
| Empty or copy a loot container | Inventory + Inventory Pickup | Processes every stack in the source Inventory's Main collection. | Source-copy behavior depends on two flags; other source collections are ignored. |
| Award weighted random loot | Inventory + Random Inventory Pickup | Uses source stack amounts as weights and makes Min-to-Max draws with replacement. | The probability table is built once at `Start`; later source changes do not rebuild it. |
| Pick up Gold | Currency Owner + Currency Pickup | Adds the Currency Owner's Currency Collection to the Interactor Inventory's Currency Collection. | It has no failure branch and assumes both Currency components exist. |

All four types require Interactable through the shared pickup behavior. Inventory Pickup and Random Inventory Pickup also require Inventory. Currency Pickup requires Interactable in code, while the Setup Manager template additionally creates the required Currency Owner.

## Configure an Inventory Pickup

Inventory Pickup reads only its own Inventory's Main Item Collection and checks every stack against the destination. Use the flags according to what the source represents:

| Remove Picked Up Items | Pickup Duplicate Items | Result for an accepted Iron Sword |
| --- | --- | --- |
| Off | Off | Remove the full source stack, put a full replacement copy back in the source, then attempt to add the original to the player. This is the default reusable-template behavior. |
| On | Off | Remove the full source stack, then attempt to add that original stack to the player. Use this only when the full stack is expected to fit. |
| Off | On | Leave the source unchanged and create a copy of the amount that `CanAddItem` accepted for the player. |
| On | On | Remove the full source stack, then create a copy of that removed stack for the player. |

Inventory Pickup reports failure when no stack can be accepted, partial pickup when at least one stack or amount cannot be fully accepted, and success when everything fits. It also sends `OnItemPickupStartPickup` and `OnItemPickupStopPickup` string events on the source Inventory GameObject around the transfer.

With **Remove Picked Up Items** on, Version 1 removes the full source stack as soon as the destination can accept any nonzero amount. If the destination then accepts only part, the unaccepted remainder is not restored to the source. Use this mode only when each source stack is expected to fit completely, or implement a remainder-aware transfer. The default off/off combination puts a full replacement copy back in the source, so it behaves as a reusable template rather than a container that is gradually emptied.

## Configure a Random Inventory Pickup

Use the source Inventory's Main collection as a weight table. Health Potion amount `8` and Iron Sword amount `2` give each draw an 80% Health Potion and 20% Iron Sword weighting. The source amounts are weights, not the quantities awarded in one result.

**Min Amount** and **Max Amount** choose the total number of draws, inclusive. Repeated draws of the same Item are combined. With no **Amount Probability Distribution**, every count in that range is equally likely. With a curve, a random sample is evaluated and mapped from Min to Max.

The table is constructed once at `Start`. Changing the source Inventory later does not rebuild its stored weights. Min, Max, and the curve are read when a result is requested, but dynamic loot weights require a recreated or custom component.

Random Inventory Pickup checks whether at least one result can be added and then adds the generated Item amounts through the destination collection. It reports partial only when at least one generated entry accepts zero; accepting a nonzero amount below the requested amount can still report success because the returned `AddItems` total is not inspected. It does not remove the weighted source entries.

## Configure a Gold pickup

Create a **Currency Pickup** template and set **Currency Owner > Currency Amount** to Gold and the intended amount. The player's Inventory must expose a `CurrencyCollection` through its Currency Owner setup.

On interaction, Currency Pickup adds the complete source Currency Collection to the destination and invokes success. Released Version 1 does not check a returned result before reporting success and does not provide fail or partial logic for Currency. A missing source Currency Owner or destination Currency Collection causes a null-reference error rather than a pickup failure event, so verify both before Play Mode.

## Use selection, visuals, and input

Interactable checks the enabled 2D or 3D trigger callback, **Interactor Layer Mask**, and **Is Interactable** before adding itself to an Interactor. Selection invokes **On Select** and enables every **Select Indicators** GameObject. Deselect invokes **On Deselect** and hides them.

The standard Inventory Interactor selects the first available Interactable. Its **Auto Interact** default is off and its **Input** default is the `Action` button on Button Down. Interactable has a separate **Auto Interact** toggle that interacts immediately after selection. Prefer one intentional automatic-interaction route rather than enabling both without testing overlapping triggers.

Item Object Visualizer can swap a shared pickup shell to the Health Potion or Iron Sword model and update a world-space Item View. Inventory Item Visualizer can show one representative Item for an Inventory Pickup. These visualizers do not change transfer eligibility or ownership.

## Reactivate or pool a pickup

With **Deactivate On Interact** on and **Schedule Reactivation Time** at `-1` or `0`, Pickup Base first deactivates the GameObject, then returns it to the Opsive Object Pool when pooled or destroys it otherwise. Item Pickup clears its Item Object before cleanup, so pooled reuse must assign a new valid Item Info before the pickup becomes interactable again.

Set **Schedule Reactivation Time** above zero for a repeatable pickup. The GameObject is disabled, remains out of the pool, then is enabled and marked interactable after the delay. Item Pickup rechecks whether its Item Object still contains a valid Item Definition. Its Item Info is not consumed on success, so a scheduled Health Potion pickup awards the same amount again after every respawn by design.

Inventory Pickup and Currency Pickup do not clear their source Inventory or Currency Owner during pooled cleanup. Their next use reflects whichever source data and copy/remove settings remained. Reset those components explicitly when a pooled object should represent different loot.

## Spawn or drop pickups

Use Item Object Spawner when code already has an Item Info and a world position. Player-facing **Drop Item Action** and **Quantity Drop Item Action** can route a Bag selection through that spawner. Item and Currency Droppers provide fixed or random authoring workflows for world rewards.

Whichever route creates the GameObject, assign the Item Object before exposing a pooled Item Pickup to interaction. Item Pickup listens for Item Object changes and disables interaction when the Item or its Definition is invalid.

## Verify in Play Mode

1. Approach a Health Potion pickup. Confirm that its selection indicator appears only in range and the configured Action input interacts once.
2. Pick it up with space in Bag. Confirm that the exact Item Info amount enters Main, success feedback runs, and the success-only deactivation pattern removes the pickup.
3. Fill Bag and try again. Confirm that **Fail If Full Amount Does Not Fit** prevents any transfer, fail feedback runs, and the pickup remains available.
4. Test an Iron Sword whose Category is rejected by Bag. Confirm that the restriction produces failure rather than silently changing the destination.
5. Set a short positive **Schedule Reactivation Time** on a repeatable pickup. Confirm that it disappears, returns after the delay, and awards the same Item again.
6. For Inventory Pickup with **Remove Picked Up Items** on, first confirm that every source stack fits completely. Then restrict one entire Item Category and confirm that accepted stacks leave while zero-acceptance stacks remain.
7. Run a weighted Random Inventory Pickup several times. Confirm that every result count is between Min and Max and that Health Potion appears more often over many trials.
8. Pick up Gold and confirm that the player's Currency Collection increases by the source amount.

## Saving and multiplayer boundaries

There is no pickup-specific Saver. Inventory Saver can preserve an Inventory Pickup's source contents, and Currency Owner Saver can preserve a Currency Pickup's Currency amounts. GameObject Saver can preserve configured active or destroyed state, but none automatically records that a particular interaction attempt succeeded, failed, or is waiting on scheduled reactivation.

For persistent world loot, save the Item identity, amount, transform, and consumed or remaining state, then respawn or rebind the pickup after load. A pooled Item Pickup clears its Item Object before returning to the pool, so the pool instance is not authoritative save data.

Released Version 1 does not replicate trigger selection, transfer requests, Item Collection transactions, pickup destruction, scheduled respawn, or pooled state. In multiplayer, validate the interaction and destination capacity on the authority, apply the authoritative Item or Currency transaction once, and replicate the resulting Inventory and world-pickup state.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| The pickup is never selected | Trigger overlap, Rigidbody/Rigidbody2D, **2D/3D**, character layer, and an `IInteractor` in the collider's parent hierarchy | Repair the physics pair, enable the correct mode, and include the character layer. |
| Interaction runs but no Item is added | Character `IInteractorWithInventory`, Item Object validity, database, and destination collection | Use Inventory Interactor, bind an Item with a valid Definition, and align the scene and Item databases. |
| A failed pickup disappears | **Deactivate On Interact** | Turn it off and call `Deactivate()` from **On Pickup Success** instead. |
| A partial Health Potion pickup duplicates on retry | Item Object amount remains unchanged after partial acceptance | Turn on **Fail If Full Amount Does Not Fit** or implement a remainder-aware Item Pickup. |
| An Item goes to Main instead of another collection | **Add To Item Collection** Name/Purpose and whether that collection exists | Correct the identifier; an unresolved destination falls back to Main. |
| A pooled Item Pickup returns but cannot be used | Item Pickup cleared its Item Object during pool cleanup | Assign a valid Item Info before enabling or exposing the pooled object. |
| A respawned Inventory Pickup contains unexpected Items | **Remove Picked Up Items**, **Pickup Duplicate Items**, and retained source state | Choose the intended source mode and reset the Inventory before reuse. |
| Random loot ignores changed weights | The table was built at `Start` | Recreate the component or add project code that rebuilds the probability table. |
| Random loot reports success after adding less than requested | Whether each selected entry accepted a nonzero but partial amount | Treat destination collection results as authoritative, or override the pickup to compare the returned added total. |
| Currency Pickup throws a null-reference error | Source Currency Owner and destination Currency Collection | Add and initialize both Currency components before interaction. |

## Related pages

- [Item Objects](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/)
- [Item Object Visualizer](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-object-view/)
- [Item and Currency Droppers](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-and-currency-droppers/)
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/)
- [Interaction System](https://opsive.com/support/documentation/ultimate-inventory-system/interaction-system/)
- [Input Handlers](https://opsive.com/support/documentation/ultimate-inventory-system/input/handlers/)
- [Built-in Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/built-in-item-actions/)
- [Currency](https://opsive.com/support/documentation/ultimate-inventory-system/currency/)
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/)

## Developer details

`PickupBase` exposes the success, fail, and partial UnityEvents plus their audio fields. `Deactivate()` and `Reactivate()` are public. Cleanup uses `ObjectPool.Destroy` for a pooled GameObject and `Destroy` otherwise.

`ItemPickup.ItemObject` and `ItemPickup.ItemInfo` expose the current source. `AddToItemCollection` and `FailIfFullAmountDoesNotFit` are settable properties, and `OnStateChange` is a parameterless C# event raised when Item validity is reevaluated. The component listens for `EventNames.c_ItemObject_OnItemChanged`.

`InventoryPickup.Inventory` exposes its source Inventory and `AddToItemCollection` is settable. The source-transfer flags are protected serialized fields rather than public properties. The component emits `OnItemPickupStartPickup` and `OnItemPickupStopPickup` by string name on the source Inventory GameObject; destination Item Collection updates provide transaction-level Inventory events.

`RandomInventoryPickup` exposes `MinAmount`, `MaxAmount`, and `AmountProbabilityDistribution`. `CurrencyPickup.CurrencyOwner` exposes its source owner. Currency changes notify the Currency Owner and Currency Collection event routes after the amount is added.

Interactable publishes the standard select, deselect, and interact UnityEvents and executes `EventNames.c_Interactable_OnSelect_IInteractor`, `EventNames.c_Interactable_OnDeselect_IInteractor`, and `EventNames.c_Interactable_OnInteract_IInteractor` on its GameObject. Use authoritative collection events when project code needs the accepted amount rather than only the pickup's coarse success, fail, or partial result.

---

<a id="page-ultimate-inventory-system-item-objects-item-and-currency-droppers"></a>

# Item and Currency Droppers

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-and-currency-droppers/)

Use a dropper when an enemy death, opened chest, solved puzzle, or another game event should create Item or Currency pickups in the world. Choose the component by where the contents come from and whether the result is fixed or random.

Droppers do not listen for an enemy-death event by themselves. Configure the contents and pickup prefab, then call `Drop()` from the project event that owns the reward.

## Choose a drop workflow

| Goal | Use | Result |
| --- | --- | --- |
| Spawn one known Item Info from code | **Item Object Spawner** | Creates one configured Item Object at an exact world position. |
| Let a player drop an Item from an Item Action menu | **Drop Item Action** or **Quantity Drop Item Action** | Creates an Item or Inventory pickup near the Item User or Inventory. |
| Drop every configured Item from a reward Inventory | **Item Dropper** | Creates one Item Pickup per Item Info, or one Inventory Pickup containing the full list. |
| Select Items from a weighted reward Inventory | **Random Item Dropper** | Draws a configured number of results, using source stack Amounts as weights. |
| Copy a fixed set of currencies into a pickup | **Currency Dropper** | Creates one Currency Pickup with the Currency Owner's current amounts. |
| Vary a fixed set of currency amounts | **Random Currency Dropper** | Multiplies every source amount by one random multiplier before creating the pickup. |

The **Item Dropper**, **Random Item Dropper**, **Currency Dropper**, and **Random Currency Dropper** all inherit the same placement settings:

- **Pick Up Prefab** has no default and must contain the expected pickup component on its root GameObject.
- **Drop Transform** has no fallback and must be assigned.
- **Drop Radius** defaults to `0`.

The component spawns at the Drop Transform plus a random horizontal offset inside the radius and a fixed `1` unit upward offset. A radius of `0` still places the pickup one unit above the transform.

## Build the pickup prefabs

Match the prefab to the dropper before configuring reward data:

| Pickup purpose | Required root components | What happens on interaction |
| --- | --- | --- |
| One Item or stack, such as Health Potion or Iron Sword | **Item Pickup**, **Item Object**, and **Interactable** | Adds the Item Info to the configured destination collection. |
| Several Items in one container | **Inventory Pickup**, **Inventory**, and **Interactable** | Attempts to add the pickup Inventory's Main contents to the interacting Inventory. |
| Gold or another Currency | **Currency Pickup**, **Currency Owner**, and **Interactable** | Adds the pickup Currency Owner's amounts to the interacting Inventory's Currency Collection. |

Add an Item Object Visualizer or Inventory Item Visualizer when the pickup should select a model from Item attributes. Configure **On Pickup Success**, **On Pickup Fail**, **On Partial Pickup**, and their audio fields on Item and Inventory pickups where the player needs feedback.

Currency Pickup reports success after it attempts to add its Currency amounts; released Version 1 does not translate a Currency capacity or add failure into the pickup's fail or partial callbacks.

See [Item Pickups](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-pickups/) for destination, capacity, deactivation, and reactivation behavior.

## Configure fixed Item drops

Use **Item Dropper** when the reward list is already known.

1. Add an Inventory to the reward owner, such as an enemy.
2. Add an Item Collection named `ItemDrops` with purpose **Drop**, matching the Item Dropper's released Version 1 **Item Collection ID** defaults.
3. Put the intended reward Item amounts in that collection. For example, add two Health Potions and one Iron Sword.
4. Add **Item Dropper** and assign **Inventory**, **Pick Up Prefab**, and **Drop Transform**.
5. Choose an Item Pickup prefab to create one world object per Item Info, or an Inventory Pickup prefab to put the whole reward list in one world object.
6. Keep **Drop Copies** enabled when the source Inventory is a reusable reward table. It defaults to on.
7. Keep **Split Unique Items** enabled when an amount containing unique Items should become separate Item Infos. It also defaults to on.
8. Disable **Allow Empty Drops** when an Inventory Pickup must not be created for an empty list. Its default is on.

For common Items, the Item identity is shared by design. For unique Items, **Drop Copies** creates new runtime Items before binding them to the pickup. With an Item Pickup prefab, the dropper creates one pickup for each resulting Item Info; with an Inventory Pickup prefab, it creates one pickup and replaces its Main collection contents with the result list.

`ItemDropper.Drop()` does not remove the reward data from its source collection. Turning **Drop Copies** off changes whether unique Item data is cloned, but it still does not perform an Inventory transfer. Clear or destroy the source explicitly when the original should no longer exist.

## Configure weighted Item drops

Use **Random Item Dropper** when the source Inventory should act as a weighted table.

1. Configure the base Item Dropper fields and an `ItemDrops` collection before the component enters Play Mode.
2. Use each source stack's Amount as its weight. For example, Health Potion amount `6` and Iron Sword amount `1` make a potion six times as likely as the sword on each draw.
3. Set **Min Amount** and **Max Amount** to the number of draws. Their defaults are `1` and `2`.
4. Leave **Amount Probability Distribution** empty for a uniform integer count between Min and Max, inclusive.
5. Add a curve only when the number of draws should favor part of that range. Curve time is sampled from `0` to `1`; the clamped curve value maps from Min to Max and is rounded to an integer.

Each draw selects with replacement. Repeated selections of the same Item are combined into one result amount before the inherited copy and split rules run.

The probability table is built once in `Awake`. Changes to the source collection after that point do not rebuild the table, and the released Version 1 Random Item Dropper has no empty-table guard. Populate at least one positive-weight Item before Play Mode or rebuild the table in a custom component.

For random rarity, Attack, or other Item attributes, continue to [Custom Random Item Dropper](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-and-currency-droppers/custom-random-item-dropper/). That child workflow subclasses Random Item Dropper and modifies mutable, unique Items before their pickups are created.

## Configure fixed and random Gold drops

Use a Currency Owner as the reward template:

1. Add a Currency Owner to the enemy or reward GameObject and give it the base amount, such as `10 Gold`.
2. Add **Currency Dropper** for an exact copy or **Random Currency Dropper** for a scaled result.
3. Assign the source **Currency Owner**, a **Currency Pickup** prefab whose root also has its own Currency Owner, and a **Drop Transform**.
4. For Random Currency Dropper, set **Min Offset** and **Max Offset**. The released Version 1 defaults are `0.3` and `3`.

The offsets are multipliers, not percentages added to the base. With `10 Gold` and a range of `0.5` to `1.5`, the pickup receives the source Currency collection scaled by one uniformly selected multiplier in that range. The same multiplier is applied to every Currency entry in the source owner.

Currency droppers copy amounts into the pickup and do not subtract them from the source Currency Owner. Remove or change the source amount separately when it represents spendable ownership rather than a reward template.

## Let the player drop an Item

Use an Item Action when the player initiates the drop from Bag or another UI:

- **Drop Item Action** is named `Drop`. **Drop One** defaults off, **Remove On Drop** defaults off, **Drop Radius** defaults to `2`, and **Center Offset** defaults to zero.
- **Quantity Drop Item Action** is also named `Drop`. It opens the configured Quantity Picker for stacks larger than one, with a range from `1` to the selected amount. Its **Remove On Drop** default is off and its Drop Radius default is `2`.

Both actions use the Item User's GameObject as the center, falling back to the Item's Inventory GameObject. Their random offset is a box-like range: horizontal axes run from half a radius below to half a radius above the center, while the vertical axis runs from `0` to the full radius.

Enable **Remove On Drop** when the pickup should own the Item that leaves Bag. Released Version 1 does not check the returned removal amount before it spawns the requested pickup, so expose the action only for Items and collections that allow the full removal.

The pickup prefab must have an Item Object or Inventory on its root for the action to populate it. Add the corresponding Item Pickup or Inventory Pickup behavior as well when the world object must be collectible.

## Use an Item Object Spawner from code

Add **Item Object Spawner** near the Inventory System Manager when project code already has an Item Info and exact position.

1. Keep **ID** at its default `1`, or assign a unique value and use the same value for lookup.
2. Assign **Item Object Prefab**. The prefab must contain an Item Object and should include Item Pickup and Interactable when it is collectible.
3. Use `Spawn` for an immediate object, `SpawnWithDelay` for a delayed object, or `SpawnWithAutoDestroy` for scheduled cleanup.

The spawner registers itself in the Inventory System Manager global register during `Awake`. It uses the supplied world position exactly and does not apply the Dropper radius or upward offset.

## Build a Health Potion, Iron Sword, and Gold reward

For an enemy that normally drops consumables, rarely drops equipment, and always drops some Gold:

1. Create an `ItemDrops` collection containing Health Potion amount `6` and Iron Sword amount `1`.
2. Configure Random Item Dropper with **Min Amount** `1`, **Max Amount** `2`, **Drop Copies** on, and **Split Unique Items** on.
3. Use an Item Pickup prefab when each selected result should be a separate world object.
4. Give the enemy's Currency Owner `10 Gold` and configure Random Currency Dropper with multipliers `0.5` and `1.5`.
5. Use separate Drop Transforms or small radii so the Item and Currency pickups do not overlap.
6. Call both components' `Drop()` methods once from the enemy's confirmed death event.

This setup treats the source Inventory and Currency Owner as reward tables. Repeated enemy instances may reuse the same configuration because the default Item workflow copies unique reward Items and the Currency workflow copies amounts.

## Editor checkpoint

Before entering Play Mode, confirm that:

- every Dropper has a non-null **Drop Transform** and root-compatible **Pick Up Prefab**;
- Item droppers resolve the intended Inventory and `ItemDrops` collection;
- the Random Item Dropper has at least one positive-weight Item before `Awake`;
- Min Amount is not greater than Max Amount;
- **Drop Copies**, **Split Unique Items**, and **Allow Empty Drops** match the ownership and empty-result policy;
- each Currency Dropper resolves a source Currency Owner, and its pickup prefab has both Currency Pickup and Currency Owner;
- Item Actions use **Remove On Drop** only where the full source amount can be removed;
- the project event calls each intended `Drop()` exactly once; and
- pickup Interactable settings, layers, destination collection, and feedback callbacks are configured.

## Verify in Play Mode

1. Trigger one fixed Item Dropper. Confirm that the expected Health Potion and Iron Sword contents appear in the correct number of Item or Inventory pickups.
2. Trigger the Random Item Dropper repeatedly in a test scene. Confirm that every run produces between Min and Max draws and that Health Potion is selected more often than Iron Sword over many runs.
3. Inspect a dropped unique Iron Sword and confirm it is a copy when **Drop Copies** is enabled.
4. Trigger the Currency Dropper and confirm that an exact copy of the source Gold appears. Then test the Random Currency Dropper and confirm that the result stays within the configured multiplier range.
5. Pick up every result. Confirm that Item pickups report success, partial success, or failure according to destination capacity, and that the Gold reaches the player's Currency Collection.
6. Invoke Drop Item Action from Bag with **Remove On Drop** enabled. Confirm that the chosen amount leaves Bag and the pickup contains that same amount.
7. Trigger the reward twice only when two reward rolls are intended. Confirm that one death event does not accidentally create duplicate sets.

## Save and multiplayer boundaries

Droppers and Item Object Spawner have no dedicated save data for spawned world rewards. Inventory Saver and Currency Owner Saver can preserve their configured source owners, but a runtime pickup's contents and transform are not automatically recreated after loading merely because a dropper created it.

For persistent ground loot, save the Item or Currency identity, amount, transform, and any claimed state, then restore the pickup explicitly. Random Item tables and Unity random state are not saved by the dropper, so save the selected result rather than rolling it again on load.

The released Version 1 core package does not replicate `Drop()`, random selection, spawned pickup ownership, or pickup interaction over a network. Run the reward roll on the authority, replicate the resolved results and positions, and prevent clients from rolling independently.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| Nothing drops when the enemy dies | Death-event binding and whether `Drop()` is called | Connect the confirmed death event to each intended Dropper once. |
| `Drop()` throws before spawning | **Drop Transform**, source Inventory or Currency Owner, and Pick Up Prefab | Assign every required reference; released Version 1 has no Drop Transform fallback. |
| Random Item Dropper fails with an empty table | `ItemDrops` contents at `Awake` and positive stack Amounts | Populate the collection before Play Mode or rebuild the table in a subclass. |
| Runtime edits do not change Item probabilities | The one-time probability-table build in `Awake` | Configure weights before initialization or implement an explicit rebuild. |
| An empty Inventory Pickup appears | **Allow Empty Drops** and the resolved source collection | Disable Allow Empty Drops or add the intended rewards to `ItemDrops`. |
| Dropped Items still remain in the source Inventory | **Drop Copies** was expected to transfer ownership | Remove or clear source contents explicitly; Drop Copies controls unique Item cloning, not source removal. |
| Player Item Action duplicates the stack | **Remove On Drop** | Enable it and ensure the collection permits the full removal. |
| Gold varies much more than expected | **Min Offset** and **Max Offset** were treated as percentages | Enter multipliers such as `0.8` and `1.2` for an 80%-to-120% range. |
| Pickup is visible but cannot be collected | Root pickup components, Interactable, Inventory Interactor, and layers | Use the matching root component set and repair the interaction route. |
| Pickups appear one unit too high | The Dropper's fixed vertical offset | Move the Drop Transform down or override `DropOffset()` for a different placement rule. |
| Auto-destroy removes only part of a non-pooled spawned object | Whether Item Object Spawner created a pooled instance | Use a pooled prefab or override cleanup; released Version 1 destroys only the Item Object component on its non-pooled cleanup path. |

## Related pages

- [Custom Random Item Dropper](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-and-currency-droppers/custom-random-item-dropper/)
- [Item Objects](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/)
- [Item Pickups](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-pickups/)
- [Built-in Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/built-in-item-actions/)
- [Interaction System](https://opsive.com/support/documentation/ultimate-inventory-system/interaction-system/)
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/)
- [Currency](https://opsive.com/support/documentation/ultimate-inventory-system/currency/)
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/)

## Developer reference

Call designer-configured droppers from the gameplay event that owns the reward:

```csharp
public void HandleEnemyDefeated()
{
    m_RandomItemDropper.Drop();
    m_RandomCurrencyDropper.Drop();
}
```

Use the global Item Object Spawner when code provides the Item and exact world position:

```csharp
var spawner = InventorySystemManager.GetGlobal<ItemObjectSpawner>(1);
var healthPotion = InventorySystemManager.CreateItem("Health Potion");
var pickupInfo = (ItemInfo)(1, healthPotion);

var pickup = spawner.Spawn(pickupInfo, transform.position);
```

`ItemDropper.GetItemsToDrop()` exposes the resolved fixed or random result before spawning. A custom dropper can modify mutable, unique Items and then call the protected `DropItemsInternal` method, as shown on the direct child page.

The built-in Dropper classes do not send a dedicated completion event. Observe the pickup's success, fail, and partial UnityEvents for collection outcomes, or wrap `Drop()` in the project event that already knows why the reward was created.

---

<a id="page-ultimate-inventory-system-item-objects-item-and-currency-droppers-custom-random-item-dropper"></a>

# Custom Random Item Dropper

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-and-currency-droppers/custom-random-item-dropper/)

Create a custom Random Item Dropper when the selected reward needs per-instance values before its pickup appears. The released Version 1 sample chooses Items through the built-in weighted table, copies unique Items, changes their `Attack` attribute with an Animation Curve, and then uses the normal pickup-spawn path.

Use this pattern for an Iron Sword whose Attack varies on each drop. A Health Potion without Attack passes through unchanged, while Gold remains a separate Currency Dropper workflow.

## Understand what the supplied example changes

The Version 1 package includes `CustomRandomAttackStatDropper`, a subclass of `RandomItemDropper`. Its `Drop()` sequence is:

1. Call inherited `GetItemsToDrop()` to select and copy the Item Infos.
2. Find the selected Items that have an `Attack` attribute.
3. Read the base integer Attack from each Item Definition's Default Item.
4. Evaluate **Random Attack Multiplier Distribution** at `Random.value`.
5. Multiply the base Attack, round it to an integer, and set the runtime Item override.
6. Call inherited `DropItemsInternal()` to create Item or Inventory pickups.

The shipped sample randomizes Attack only. It does not include the rarity-weight table previously shown on this page. A rarity system can use the same customization point, but its weights, dependencies, and validation are project-specific.

## Before you begin

Prepare the data and pickup workflow first:

- Add a Weapon category whose **Item Attributes** include an integer `Attack` attribute.
- Create an Iron Sword Definition that inherits Weapon and produces a mutable, unique Item so each dropped copy can hold its own override.
- Create a Health Potion under Consumable without `Attack`; the example will skip it.
- Configure an Item Pickup or Inventory Pickup prefab as described on the parent [Item and Currency Droppers](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-and-currency-droppers/) page.
- Add an Inventory with an `ItemDrops` collection before the custom dropper enters Play Mode.

The runtime override must belong to the Item data. A Definition-only value can provide the base, but the selected runtime Item needs a compatible `Attribute<int>` that accepts `SetOverrideValue`.

## Configure the inherited reward table

The custom component retains every Random Item Dropper field and default:

1. Assign **Inventory** and target the `ItemDrops` collection. **Item Collection ID** defaults to name `ItemDrops` and purpose **Drop**.
2. Put Health Potion amount `6` and Iron Sword amount `1` in the collection.
3. Keep **Drop Copies** enabled so a selected unique Iron Sword is copied before its Attack changes. This defaults to on.
4. Keep **Split Unique Items** enabled so separate unique rewards remain separate Item Infos. This also defaults to on.
5. **Allow Empty Drops** defaults to enabled, but the shipped custom `Drop()` bypasses this inherited check. The safer implementation below restores it.
6. Set **Min Amount** and **Max Amount** to the number of weighted draws. Their defaults are `1` and `2`.
7. Leave **Amount Probability Distribution** empty for a uniform draw count, or use a curve whose clamped output maps from Min to Max.
8. Assign **Pick Up Prefab**, **Drop Transform**, and **Drop Radius**.

The source stack Amount is a weight, not the amount of that Item in one selected result. Health Potion weight `6` and Iron Sword weight `1` make the potion six times as likely on each draw. Repeated selections of the same Item are combined into one result amount.

Random Item Dropper does not filter by Item Category. It uses every valid stack in the configured collection. Keep unrelated Items out of `ItemDrops`, or add collection restrictions or a custom filtering step before building the table.

The table is constructed once in `Awake`. Populate the collection before then. Later collection edits do not change its entries or weights unless the custom component explicitly rebuilds the table.

## Configure the Attack multiplier

Add `CustomRandomAttackStatDropper` to the reward owner and configure **Random Attack Multiplier Distribution**.

The curve is sampled with a uniform input from `0` through `1`. Its output is used directly as the multiplier and is not clamped. For an Iron Sword with base Attack `20`:

| Curve output | Dropped Attack |
| --- | --- |
| `0.8` | `16` |
| `1.0` | `20` |
| `1.25` | `25` |

A straight curve from `0.8` at time `0` to `1.2` at time `1` produces a uniform linear range around the base. A shaped curve changes the output distribution. Avoid negative or unexpectedly large values unless the game design intends them.

Health Potion has no Attack, so the custom code leaves it unchanged. Iron Sword must expose `Attack` as `Attribute<int>` on both the Definition's Default Item and the selected runtime Item. A missing attribute or a different type must be handled explicitly in project code.

## Add the Gold reward

Keep Currency selection separate from Item customization:

1. Give the enemy's source Currency Owner `10 Gold`.
2. Add **Random Currency Dropper** with a Currency Pickup prefab and its own Drop Transform.
3. Set **Min Offset** to `0.5` and **Max Offset** to `1.5` for a reward scaled from 50% to 150% of the source Gold.
4. Call both the custom Item dropper and Random Currency Dropper once from the confirmed enemy-death event.

The custom class does not use Item Object Spawner. It inherits Item Dropper's pickup creation and placement. Use Item Object Spawner instead when code already knows one resolved Item Info and an exact world position.

## How selection, ownership, and spawning run

With the standard configuration, one enemy death follows this order:

1. The inherited table chooses one or two results using the Health Potion and Iron Sword weights.
2. `GetItemsToDrop()` copies a selected unique Iron Sword because **Drop Copies** is enabled.
3. The custom method changes Attack on that copied Item only.
4. An Item Pickup prefab creates one pickup per resolved Item Info; an Inventory Pickup prefab creates one pickup containing the full list.
5. Placement uses the Drop Transform, a random horizontal point inside Drop Radius, and the inherited fixed one-unit upward offset.
6. Random Currency Dropper performs its separate Gold roll and creates its Currency Pickup.

The source `ItemDrops` collection is a probability table. Neither the base nor custom dropper removes its contents. If **Drop Copies** is disabled, the custom code can mutate the source unique Iron Sword itself, causing later rolls to start from changed runtime data. Keep copying enabled for reusable reward tables.

The shipped custom override calls `DropItemsInternal()` directly instead of `base.Drop()`. That bypasses the `Allow Empty Drops` check implemented by `ItemDropper.Drop()`. With an empty result, an Item Pickup prefab creates nothing, while an Inventory Pickup prefab can create an empty pickup. Restore that guard in production code when empty Inventory pickups are not intended.

## Editor checkpoint

Before entering Play Mode, confirm that:

- Iron Sword is mutable and unique and has an integer Item-level `Attack` override target;
- its Definition's Default Item also exposes `Attack` as `Attribute<int>`;
- Health Potion intentionally lacks Attack and remains unchanged;
- `ItemDrops` exists and contains at least one positive-weight Item before `Awake`;
- Min Amount is not greater than Max Amount;
- **Drop Copies** and **Split Unique Items** are enabled for per-instance Iron Swords;
- the Attack multiplier curve has deliberate time and value ranges;
- Pick Up Prefab has the matching root pickup components;
- Drop Transform is assigned; and
- the enemy-death event calls the custom Item dropper and Gold dropper exactly once.

## Verify deterministically in Play Mode

Use an isolated test scene so other systems do not consume Unity's global random sequence.

1. Set **Drop Radius** to `0`, populate the same `ItemDrops` collection, and call `Random.InitState(12345)` immediately before `Drop()`.
2. Record the selected Definitions, amounts, Iron Sword Attack, and pickup positions.
3. Reset the scene, restore the same source data, seed, and call order, then repeat. Confirm that the recorded results match.
4. Change only the seed. Confirm that every run still returns between Min and Max draws and every Iron Sword Attack remains within the curve's intended output range.
5. Run many distinct seeds and count selections. Confirm that Health Potion trends toward six selections for each Iron Sword selection; do not judge a weighted distribution from only a few rolls.
6. Confirm that Health Potion has no new Attack override and that the source Iron Sword retains its original value when **Drop Copies** is enabled.
7. Pick up the Items and Gold. Confirm that the player's Inventory and Currency Collection receive the resolved amounts once.

Do not reseed Unity's global random generator before every production enemy death, or identical encounter state may repeat identical loot. For replayable production logic, use a project-owned random source or save the resolved reward results.

## Events, saving, and multiplayer boundaries

The custom dropper adds no event of its own. The inherited Item or Inventory pickup exposes success, fail, and partial UnityEvents for collection outcomes. A project can send a separate event after `DropItemsInternal()` when it needs to know that pickup objects were created rather than collected.

The dropper does not save its probability-table snapshot, random state, resolved results, spawned pickup transforms, or runtime Attack overrides on ground loot. Inventory Saver and Inventory System Manager Item Saver preserve Items after they enter a saved Inventory, but persistent unclaimed rewards need their resolved Item data, amount, and transform saved explicitly.

The released Version 1 core package does not replicate the roll, override, spawn, or pickup result. In a multiplayer game, roll and customize on the authority, then replicate the resolved Item identity, Attack, amount, and spawn transform. Clients must not rerun the probability table independently.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| The custom dropper throws during its first roll | `ItemDrops` contents at `Awake` and total positive weight | Populate the table before initialization; the inherited Version 1 table has no empty guard. |
| Iron Sword drops but Attack never changes | Mutable and Unique settings, Item-level Attack, and curve values | Make the dropped Item a copied mutable unique instance with `Attribute<int>` and a non-flat multiplier curve. |
| An invalid cast or null error occurs in Attack customization | Attack type on the Definition Default Item and runtime Item | Use `Attribute<int>` in both places or update the custom code and calculation for the chosen type. |
| Health Potion produces an Attack warning | Health Potion unexpectedly inherits an Attack field or custom code assumes every Item has one | Keep it outside the Weapon Attack attribute path or retain the `HasAttribute` guard. |
| Probabilities ignore an Inspector edit made during Play Mode | The table was already built in `Awake` | Re-enter Play Mode with the new source data or implement a safe rebuild method. |
| A selected Iron Sword changes the next roll's source data | **Drop Copies** is disabled | Enable Drop Copies for a reusable reward table. |
| An empty Inventory Pickup appears | Custom `Drop()` bypasses the inherited empty-result guard | Add the `Allow Empty Drops` check before calling `DropItemsInternal()`. |
| Gold and Item rewards duplicate | Enemy death invokes either dropper more than once | Bind one confirmed death transition and guard it against repeated calls. |
| A repeated deterministic test changes unexpectedly | Another component consumed `UnityEngine.Random` or initialization order changed | Seed immediately before the roll in an isolated scene and keep call order fixed. |

## Related pages

- [Item and Currency Droppers](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-and-currency-droppers/)
- [Item Pickups](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-pickups/)
- [Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/)
- [Defining Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/)
- [Item Objects](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/)
- [Currency](https://opsive.com/support/documentation/ultimate-inventory-system/currency/)
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/)

## Developer implementation

The shipped sample uses `CustomRandomAttackStatDropper`. The following version preserves its selection, customization, and spawn order while adding the missing empty-result and attribute-type guards:

```csharp
using Opsive.Shared.Utility;
using Opsive.UltimateInventorySystem.Core.AttributeSystem;
using Opsive.UltimateInventorySystem.Core.DataStructures;
using Opsive.UltimateInventorySystem.DropsAndPickups;
using UnityEngine;

public class RandomAttackItemDropper : RandomItemDropper
{
    [SerializeField]
    private AnimationCurve m_RandomAttackMultiplierDistribution;

    private const string AttackAttributeName = "Attack";

    public override void Drop()
    {
        var itemsToDrop = GetItemsToDrop();

        if (!m_AllowEmptyDrops) {
            var totalAmount = 0;
            for (var i = 0; i < itemsToDrop.Count; i++) {
                totalAmount += itemsToDrop[i].Amount;
            }

            if (totalAmount == 0) { return; }
        }

        AssignRandomAttack(itemsToDrop);
        DropItemsInternal(itemsToDrop);
    }

    protected virtual void AssignRandomAttack(ListSlice<ItemInfo> itemInfos)
    {
        if (m_RandomAttackMultiplierDistribution == null) { return; }

        for (var i = 0; i < itemInfos.Count; i++) {
            var item = itemInfos[i].Item;
            if (item == null ||
                !item.HasAttribute(AttackAttributeName, false, false)) {
                continue;
            }

            var defaultItem = item.ItemDefinition?.DefaultItem;
            var baseAttack = defaultItem?.GetAttribute<Attribute<int>>(
                AttackAttributeName);
            var runtimeAttack = item
                .GetAttribute<Attribute<int>>(
                    AttackAttributeName, false, false);

            if (baseAttack == null || runtimeAttack == null) {
                Debug.LogWarning(
                    $"{item.name} must expose {AttackAttributeName} as Attribute<int>.");
                continue;
            }

            var multiplier = m_RandomAttackMultiplierDistribution
                .Evaluate(Random.value);
            var value = Mathf.RoundToInt(baseAttack.GetValue() * multiplier);
            runtimeAttack.SetOverrideValue(value);
        }
    }
}
```

`GetItemsToDrop()` is public and virtual; `DropItemsInternal()` is protected and virtual. Override the customization method separately so a project can test value assignment without spawning. If rarity affects Attack, select and apply rarity first, then choose the matching Attack curve, while validating every weight and curve entry before the first roll.

---

<a id="page-ultimate-inventory-system-item-objects-item-object-view"></a>

# Item Object Visualizer

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-object-view/)

Use Item Object Visualizer when one reusable GameObject should show the model or sprite for whichever Item is currently assigned to its Item Object. It is particularly useful for pooled pickups: the interaction components remain the same while a Health Potion, Iron Sword, or Fire Wand supplies a different visual prefab.

The visualizer is a presentation component. It does not add the Item to an Inventory, equip it, save it, or synchronize it over a network.

## Before you begin

Prepare the Item data and one safe place for the generated visual:

- The scene has an initialized Inventory System Manager and the intended database.
- The reusable GameObject has an **Item Object** component.
- The relevant Item Category declares a `GameObject` Item Definition Attribute named `PickupPrefab`, and each Definition assigns its own prefab. A custom attribute name is also supported.
- The prefab has an empty child Transform reserved for the generated model or sprite. Keeping this parent empty prevents the visualizer from removing an unrelated child when it refreshes.

Use an Item Definition Attribute for a visual shared by every copy of Iron Sword or Fire Wand. Use an Item Attribute only when an individual runtime Item can have a different visual; that Item should be mutable, and usually unique, when different copies must keep independent values.

## Configure the Item Object Visualizer

1. Select the reusable world object or pickup prefab.
2. Add **Item Object Visualizer** on the same GameObject as **Item Object**.
3. Leave **Prefab Attribute Name** empty to use `PickupPrefab`, or enter the exact name of another `GameObject` attribute.
4. Assign the reserved empty child Transform to **Item Prefab Visualizer Parent**. If this field is empty, the component uses its own Transform, but a dedicated parent is safer.
5. Assign **Default Visual Prefab** when Items without the named attribute should still have a visible model.
6. Optionally assign an **Item View** to update a world-space label or icon from the same Item Info.
7. From the component's context menu, choose **Update Item Visuals** to preview the currently assigned Item in Edit Mode.

| Inspector field | Released Version 1 default |
| --- | --- |
| Prefab Attribute Name | Empty in serialized data; initialization changes it to `PickupPrefab`. |
| Item Prefab Visualizer Parent | None; initialization uses the visualizer's own Transform. |
| Default Visual Prefab | None. A missing attribute then produces no visual and reports an error. |
| Item View | None; the visualizer works without world-space UI. |

The legacy Inspector below leaves **Prefab Attribute Name** empty, so the runtime convention is `PickupPrefab`. It uses a dedicated Item Object Parent, an ItemPickupBag fallback, and a Panel Item View.

![Item Object Visualizer Inspector with an empty Prefab Attribute Name, Item Object Parent, ItemPickupBag default visual, and Panel Item View](https://opsive.com/wp-content/uploads/2020/11/Item-Object-Visualizer.png?v=3231bb41c933)

Editor checkpoint: the Item Object contains the intended Item, the visualizer is beside it, the visual parent is empty before previewing, and every Definition-specific prefab reference is non-null.

## Choose the prefab source

When the visualizer resolves its `GameObject` attribute, released Version 1 searches in this order:

| Source | Good use | Result |
| --- | --- | --- |
| Item Attribute | A visual override for one mutable, usually unique Item | Overrides Definition and Category values. |
| Item Definition Attribute | The normal Iron Sword, Fire Wand, or Health Potion model | Shared by every Item created from that Definition. |
| Item Category Attribute | One visual shared by an entire Category | Used only when neither the Item nor Definition provides the value. |
| Default Visual Prefab | A generic bag, crate, or placeholder | Used only when no matching typed attribute exists. |

An existing attribute with a null prefab value does not use **Default Visual Prefab**. The component reports an error and displays no generated visual. This distinction makes a missing value easy to find, but every declared visual attribute must have a valid prefab.

Keep the selected prefab focused on presentation. Do not point the visualizer at a prefab that contains the same visualizer and resolves the same attribute, because each generated child could create another copy of itself.

## How visual replacement runs

On `Awake`, Item Object Visualizer finds the Item Object on the same GameObject and validates its Item. On enable it listens for `EventNames.c_ItemObject_OnItemChanged` and immediately redraws the current Item.

Each redraw follows the same sequence:

1. Clear the optional Item View and remove the last child beneath **Item Prefab Visualizer Parent**.
2. Pass the current Item Info to the optional Item View.
3. Resolve the configured `GameObject` attribute, using **Default Visual Prefab** only when the attribute is absent.
4. In Play Mode, instantiate the prefab through the Opsive Object Pool beneath the visual parent. In Edit Mode, instantiate a normal preview object.

When the Item Object is rebound from Iron Sword to Fire Wand, the old visual is therefore returned to its pool when it is a pooled object, or destroyed when it is not, before the wand visual is created. Assigning `ItemInfo.None` removes the generated visual and clears the Item View.

Disabling the visualizer unregisters its listener but does not remove the current child. Re-enabling it refreshes the visual. Changing only an attribute value on the same Item does not send the Item Object change event; call `UpdateVisual()` after that change when the model must update immediately.

## Use one world object for several Items

For a shared pickup shell, give Health Potion, Iron Sword, and Fire Wand their own `PickupPrefab` Definition values. Assign any one of those Items to the shell's Item Object. The same Interactable and Item Pickup configuration can then remain pooled while Item Object Visualizer swaps only the child model.

The Equipper already creates objects from its `EquipmentPrefab` and `UsableItemPrefab` attributes. Item Object Visualizer is not a replacement for that workflow. Add it to an equipped reusable shell only when that shell needs to swap an additional child visual, and point it at a separate attribute intended for that child rather than back at the shell prefab itself.

Common, immutable Items work for shared Definition or Category visuals because the visualizer only reads the prefab reference. Use a mutable, unique Item Attribute when two otherwise identical Iron Swords must show different runtime appearances. After changing such an override, refresh the visualizer explicitly.

## Add a world-space Item View

The **Item View** field is optional. When assigned, it receives the current Item Info on every redraw and receives `ItemInfo.None` when the visual is removed. This is suitable for a pickup name, icon, or amount displayed above the world object; it is not a replacement for the Item Views used by an inventory grid.

The Version 1 Setup Manager's **Item Pickup** template can create most of this arrangement. **Default Pickup Model Prefab** supplies the fallback visual, and the optional **Item View Prefab** must have an Item View component at its root. The template creates a Model Parent, adds Item Object Visualizer, places the Item View in a Canvas above the pickup, and adds that Canvas to the pickup's selection indicators. Confirm that the Canvas uses **World Space** when the panel should follow the pickup in the scene. Select and Unselect can then show and hide it as the player enters or leaves interaction range.

For a manual setup, create the world-space Canvas yourself, assign its Item View to the visualizer, and connect the Canvas visibility to the pickup's Select and Unselect behavior.

## Show a representative Inventory Item

Inventory Item Visualizer uses the same four Inspector fields, but it reads an **Inventory** on the same GameObject rather than an Item Object.

![Inventory Item Visualizer Inspector with an empty Prefab Attribute Name, Item Object Parent, InventoryPickupBag default visual, and Panel Item View](https://opsive.com/wp-content/uploads/2020/11/Inventory-Item-Visualizer.png?v=c5058104a2a6)

On enable and whenever the Inventory sends `EventNames.c_Inventory_OnUpdate`, the component scans `Inventory.AllItemInfos`. It selects the first non-null Item that declares the configured `GameObject` attribute; if none does, it falls back to the first non-null Item and then applies the normal lookup and default rules.

Use this component when a chest, loot bag, or Inventory Pickup needs one representative model. It does not combine several models or provide a designer-selectable priority. If several Items qualify, their current Inventory order decides which one is shown. Keep only one eligible Item when the result must be deterministic, or use an Item Object Visualizer and explicitly assign the representative Item.

## Verify in Play Mode

1. Assign an Iron Sword to the Item Object. Confirm that exactly one sword visual appears beneath the reserved parent and that the Item View shows the sword's Item Info.
2. Rebind the same Item Object to a Fire Wand. Confirm that the sword child is removed or returned to its pool before one wand child appears.
3. Bind an Item with no `PickupPrefab`. Confirm that **Default Visual Prefab** appears.
4. Set a declared `PickupPrefab` value to null. Confirm that no generated model appears and that the Console identifies the null visual attribute.
5. Change a mutable, unique Item's visual override, call `UpdateVisual()`, and confirm that only that Item Object changes.
6. For Inventory Item Visualizer, add one Item with the configured visual attribute and confirm that it becomes the representative model after the Inventory update.
7. Disable and re-enable the visualizer. Confirm that it refreshes to one child rather than accumulating duplicate visuals.

## Saving and multiplayer boundaries

The visualizer has no dedicated saver. Save the authoritative Item identity, amount, and mutable or unique Item data through the appropriate Inventory and Item save workflow, then restore or rebind that Item. The visualizer rebuilds the child from the restored data when it enables or receives an Item Object or Inventory update. The spawned child, current pool instance, and active listener are not separate save records.

Released Version 1 does not replicate Item Object Visualizer or Inventory Item Visualizer state. In multiplayer, synchronize the Item identity and any visual-driving attribute value through the project's networking layer, then bind or refresh the local visualizer. Do not synchronize a generated child object's transient pool identity as the source of truth.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| No model appears | Attribute spelling and type, the Item's initialization, the Definition value, and **Default Visual Prefab** | Use the exact `GameObject` attribute name, assign a non-null value, and bind a valid Item. |
| The default is ignored | Whether the named attribute exists but contains a null prefab | Assign the attribute value or remove that declaration so the fallback can be used. |
| An unrelated child disappears | **Item Prefab Visualizer Parent** and its child list | Assign an empty Transform used only by the visualizer; it removes the last child on refresh. |
| Old and new models overlap | Whether other code adds children to the visual parent or bypasses `UpdateVisual` | Reserve the parent for the visualizer and rebind through `ItemObject.SetItem` or call `UpdateVisual()`. |
| A runtime attribute changes but the model does not | Whether the Item itself was rebound | Call `UpdateVisual()` after changing the visual-driving attribute on the same Item. |
| Disabling the component leaves the model visible | Released V1 unregisters on disable but does not clear the current child | Hide or clear the parent explicitly, or assign `ItemInfo.None` before disabling when the visual must disappear. |
| Inventory Item Visualizer chooses the wrong Item | Several Inventory entries declare the configured attribute | Keep one eligible representative, control Inventory order, or use an Item Object Visualizer with an explicit Item. |
| A world-space label is empty | **Item View**, its modules, and the current Item Info | Assign a configured Item View and confirm that the bound Item and amount are valid. |

## Related pages

- [Item Objects](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/)
- [Item Pickups](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-pickups/)
- [Equipping Items](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/equipping-items/)
- [Common Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/common-attribute-types/)
- [Defining Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/)
- [Item Views](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/item-view/)
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/)
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/)

## Developer details

`ItemVisualizerBase` provides the shared serialized fields and lifecycle. Its public `ItemView` property assigns the optional view, `UpdateVisual(ItemInfo)` displays a supplied Item Info, and each concrete component implements parameterless `UpdateVisual()` to reread its own source.

`ItemObjectVisualizer` resolves its sibling Item Object, registers the parameterless Item Object change event while enabled, and redraws from `ItemObject.ItemInfo`. `InventoryItemVisualizer` resolves and initializes its sibling Inventory, registers the Inventory update event, and redraws from its selected entry in `AllItemInfos`.

`SetVisualInternal` and `RemoveVisualInternal` are protected extension points for a custom visualizer. The base implementation uses `Item.TryGetAttributeValue<GameObject>`, which checks Item, Definition, and Category attributes in that order. A custom component can override these methods when it needs several child visuals, a different selection policy, or lifecycle behavior beyond replacing the last child.

---

<a id="page-ultimate-inventory-system-attributes"></a>

# Attributes

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/)

Attributes give Item Categories, Item Definitions, and runtime Items named values such as `Icon`, `Description`, `Attack`, `Durability`, or `BuyPrice`. Declare each attribute on an Item Category, then place its value at the level that matches what the value describes and how often it can change.

## Choose where the value belongs

| Attribute collection | Use it when | Standard example |
| --- | --- | --- |
| **Item Category** | The value describes the category itself and can be inherited by child categories. | `CategoryIcon` for Weapon |
| **Item Definition** | Every Item created from one definition should share the value. | `Icon`, `Description`, `Attack`, or `BuyPrice` on Iron Sword |
| **Item** | Each runtime instance may need its own value. | `Durability` on one Iron Sword or Fire Wand |

Attributes can only be declared from the Item Category editor. Think of the category declaration as defining which named values are available. Item Definitions and Items then inherit, override, or modify the values declared for their category.

The Default Item on an Item Definition supplies the starting Item-level values for Items created from that definition. For example, Iron Sword and Fire Wand can share the `Durability` declaration from Weapon but start with different default values.

## Follow the starter workflow

The standard documentation sample uses **All > Consumable** and **All > Equippable > Weapon**, with **Health Potion**, **Iron Sword**, and **Fire Wand** definitions.

1. In the **Item Categories** editor, select **All** and declare `Icon`, `Description`, and `BuyPrice` in the **Item Definition** attribute collection.
2. Select **Weapon** and declare `Attack` in the **Item Definition** collection.
3. On Weapon, declare `Durability` in the **Item** collection. Make Weapon mutable and unique when every weapon instance must retain its own changing Durability.
4. In the **Item Definitions** editor, set the shared display and price values for Health Potion, Iron Sword, and Fire Wand.
5. Set `Attack` for Iron Sword and Fire Wand. Health Potion does not receive that field because Consumable does not inherit from Weapon.
6. Set the starting `Durability` on the Default Item for Iron Sword and Fire Wand.
7. Keep a value set to **Inherit** when its parent is correct; use **Override** for a value specific to the selected Category, Definition, or Item.

Do not redeclare the same attribute on every child category. Put a declaration on the closest common ancestor whose descendants all need it, then add narrower declarations only for values specific to one branch.

For the full editor sequence, including mutability and stacking decisions, follow [Defining Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/).

## Understand inheritance and variants

An inherited value is resolved through the data model:

| Selected attribute | Where its parent value comes from |
| --- | --- |
| **Item** | The Item Definition's Default Item |
| **Default Item** | A parent Item Definition's Default Item, or the Item Category's Item attribute |
| **Item Definition** | A parent Item Definition, or the Item Category's Item Definition attribute |
| **Item Category** | The first parent category containing the attribute, or the type's default value |

Each value has one of three **Variant** choices:

- **Inherit** gets the value from the parent shown by the editor.
- **Override** stores a value directly on the selected object.
- **Modify** evaluates an expression based on the inherited value, override value, or other attributes.

Use **Override** for the direct `Attack` value of Iron Sword. Use **Inherit** when a child definition should keep its parent's value. Use **Modify** for a predictable relationship, such as an upgraded sword whose Attack is based on its parent definition.

## Choose a supported name and type

Attribute values can use common types such as `int`, `float`, `bool`, `string`, `Vector3`, Unity objects, Item Amounts, Currency Amounts, Item Shapes, and Item Action Sets.

Use [Common Attributes and Types](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/common-attribute-types/) when a built-in view or system expects a conventional name or value type. This is the only direct child page in this section and includes `Description`, `Icon`, `BuyPrice`, `PickupPrefab`, `EquipmentPrefab`, `Shape`, and other established attributes.

When the required value type is not listed, open **Tools > Opsive > Unit Options** and add it to the available types.

![The Unit Options window listing an attribute value type that can be made available in the attribute type dropdown.](https://opsive.com/wp-content/uploads/2020/04/AddUnitOptionType.webp?v=e36ba0583c8e)

A custom class that inherits `Attribute<T>` can change expression parsing for that type. After creating the class, add it through Unit Options so it can be selected from the attribute type dropdown.

## Editor checkpoints

Before entering Play Mode, confirm that:

- The attribute is declared once in the intended collection on the appropriate Item Category.
- Child categories and definitions show the expected inherited source.
- Health Potion exposes the common display and price fields without Weapon-only fields.
- Iron Sword and Fire Wand expose definition-level `Attack` and Default Item `Durability`.
- The selected **Variant** is intentional: inherited values show their parent source, while overrides contain the expected local value.
- Weapon is mutable and unique if two weapon Items must keep different Durability values.

## Verify at runtime

1. Add two Iron Sword Items, one Fire Wand Item, and a stack of Health Potion Items to the player's **Bag** collection.
2. Enter Play Mode and confirm that Item Views read each definition's `Icon` and `Description`.
3. Confirm that Iron Sword and Fire Wand report their own definition-level `Attack` values.
4. Change the `Durability` of one Iron Sword and confirm that the other weapon Items keep their own values.
5. Confirm that matching Health Potion Items can stack when the collection permits stacking.
6. If a shop is configured, confirm that it reads each definition's expected `BuyPrice`.

Runtime Item attribute values can be changed only when the Item is mutable. The Item's direct category controls that choice.

## Use Modify expressions

The built-in **Modify** expression evaluator supports `int`, `float`, and `string` attributes. It recognizes:

- `[OtherAttribute]` to get another attribute by name.
- `<Override>` to use this attribute's override value.
- `<Inherited>` to use this attribute's inherited value.
- `$` before a value expression, such as `$[OtherAttribute]` or `$<Inherited>`, to resolve it from the perspective of the attribute that holds the expression.

Without `$`, referenced values are resolved from the perspective of the attribute that originally requested the result. This matters when one attribute inherits a Modify expression from another object.

Use **Pre-evaluate** when the result can be cached rather than recalculated every time it is requested. For a type that needs different parsing rules, create a custom Attribute type and its own parser.

When a value depends heavily on external state, a Modify expression may not be the clearest choice. A utility or extension method, a dedicated calculation class, or a Scriptable Object with a calculation function can keep that logic explicit while still accepting the Item as input.

## Bind attributes to Item Objects

Add an [Item Binding](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-binding/) beside the [Item Object](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/) when an attribute should drive a component property on an Item's GameObject. A binding can connect a value such as damage to a component field. For more control, listen for the Item binding event and use attributes to choose a model, sprite, audio clip, or another Item-specific result.

## Developer API

Attributes are accessed in a similar way on Item Categories, Item Definitions, and Items. These examples read values from an Item:

```csharp
// Get the Attack attribute and its resolved, override, and inherited values.
var attackAttribute = item.GetAttribute<Attribute<int>>("Attack");
if (attackAttribute != null) {
    var attack = attackAttribute.GetValue();
    var attackOverride = attackAttribute.OverrideValue;
    var attackInherited = attackAttribute.GetInheritedValue();
}

// Read an Icon value directly.
if (item.TryGetAttributeValue("Icon", out Sprite icon)) {
    // Use the icon.
}

// Iterate through the Item's available attributes.
var includeItemDefinitionAttributes = true;
var includeItemCategoryAttributes = true;
var attributeCount = item.GetAttributeCount(
    includeItemDefinitionAttributes,
    includeItemCategoryAttributes);

for (int i = 0; i < attributeCount; i++) {
    var attribute = item.GetAttributeAt(
        i,
        includeItemDefinitionAttributes,
        includeItemCategoryAttributes);
    Debug.Log(attribute.GetValueAsObject());
}
```

Attribute declarations cannot be added directly to a runtime Item. A mutable Item can change values that its Item Category already declares:

```csharp
if (!item.IsMutable) {
    // Immutable Items cannot change their attribute values at runtime.
}

var attackAttribute = item.GetAttribute<Attribute<int>>("Attack");
if (attackAttribute != null) {
    attackAttribute.SetVariantType(VariantType.Inherit);
    attackAttribute.SetOverrideValue(10);
    attackAttribute.SetModifyExpression("<Inherited> + 5", true);
}
```

Be careful when an attribute contains a mutable reference type. Copy an inherited value before changing it, then store the copy as the override:

```csharp
var itemSlotsAttribute = item.GetAttribute<Attribute<ItemAmounts>>("Slots");
if (itemSlotsAttribute != null) {
    var itemSlots = itemSlotsAttribute.GetValue();
    if (itemSlots == itemSlotsAttribute.OverrideValue) {
        itemSlots.Add(newItem);
    } else {
        itemSlots = new ItemAmounts(itemSlots);
        itemSlots.Add(newItem);
        itemSlotsAttribute.SetOverrideValue(itemSlots);
    }
}
```

## Troubleshooting

- **A Definition or Item field is missing:** Check that the attribute was declared in the correct collection on its Item Category or an inherited parent category.
- **A child shows the wrong value:** Check the inherited source in the Attribute editor, then decide whether the child should inherit or override it.
- **Changing one weapon changes every copy:** Check that `Durability` is an Item attribute and that Weapon is mutable and unique.
- **A runtime value cannot be changed:** Check the direct Item Category's **Mutable** setting.
- **A Modify expression resolves an unexpected value:** Check whether the reference should use the requesting Item's perspective or the `$` perspective of the attribute holding the expression.
- **A custom type is missing from the dropdown:** Add the type through **Tools > Opsive > Unit Options** after the class compiles.

## Related tasks

- [Define attributes in the editor](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/)
- [Review common attribute names and types](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/common-attribute-types/)
- [Edit Item Category declarations](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-category/)
- [Set Item Definition and Default Item values](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-definition/)
- [Use the Attribute editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/attributes/)
- [Bind an Item to a GameObject](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-binding/)

---

<a id="page-ultimate-inventory-system-attributes-common-attribute-types"></a>

# Common Attributes

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/common-attribute-types/)

Use established attribute names when a built-in UI or system component is already configured to read them. The name, value type, and attribute collection must agree with that consumer. Many components let you change the attribute name in the Inspector, so treat the names below as supported conventions rather than reserved words.

## Display Items in the editor and UI

| Name | Type | Recommended collection | Consumer | Standard example |
| --- | --- | --- | --- | --- |
| `Description` | `string` | **Item Definition** | Item Description and its View Modules | Health Potion instructions or Iron Sword flavor text |
| `Icon` | `Sprite` | **Item Definition** | Icon Item View; also the Item Definition editor when **Editor Icon** is empty | A different icon for Health Potion, Iron Sword, and Fire Wand |
| `CategoryIcon` | `Sprite` | **Item Category** | Item Category editor when **Editor Icon** is empty | One icon representing Weapon |

Declare `Description` and `Icon` in the **Item Definition** collection on **All** when every definition should have them. Health Potion, Iron Sword, and Fire Wand then inherit those declarations and override the values on their own definitions. Put `CategoryIcon` in the **Item Category** collection because it describes the category itself.

The UI reads these values only when the relevant Item View or Item Description module is present and configured with the matching attribute name.

## Price Items in Gold

| Name | Type | Recommended collection | Consumer | Use |
| --- | --- | --- | --- | --- |
| `BuyPrice` | `CurrencyAmounts` | **Item Definition** | Shop Currency Collection and price views | What the player pays |
| `SellPrice` | `CurrencyAmounts` | **Item Definition** | Shop Currency Collection and price views | What the player receives |
| `Price` | `CurrencyAmounts` | **Item Definition** | A shop or view explicitly configured to use this alternative name | One shared price when separate buy and sell values are unnecessary |

A `CurrencyAmounts` value can contain one or more Currency-and-amount entries. In the standard sample, set each definition's `BuyPrice` to an amount of **Gold**. Gold remains a Currency in the database; it is referenced by the price attribute rather than becoming an Item attribute itself.

The shop documentation recommends `BuyPrice` and `SellPrice`. If the project does not need a separate sell price, the Shop Currency Collection can be configured to read `BuyPrice` for both transactions. Price displays must use the same configured names as the shop.

## Spawn pickups and equipped prefabs

| Name | Type | Recommended collection | Consumer | Standard example |
| --- | --- | --- | --- | --- |
| `PickupPrefab` | `GameObject` | **Item Definition** | Item Object Visualizer configured for dropped Items | A Health Potion bottle pickup or Iron Sword world model |
| `UsableItemPrefab` | `GameObject` | **Item Category** when logic is shared; **Item Definition** when it differs | Equipper | Shared melee-use logic, or definition-specific Fire Wand casting logic |
| `EquipmentPrefab` | `GameObject` | **Item Definition** | Equipper | The visible Iron Sword or Fire Wand model |

The Equipper separates use logic from the visible model. `UsableItemPrefab` normally contains the scripts that use the Item and no model. `EquipmentPrefab` normally contains the model and is spawned beneath the usable prefab for non-skinned equipment. The usable prefab should include an Item Object component; an Item Object Behaviour Handler can provide use behavior.

For a shared weapon interaction, define `UsableItemPrefab` in the **Item Category** collection on Weapon. If Fire Wand and Iron Sword require different use logic, declare it in Weapon's **Item Definition** collection instead and set a value on each definition. Set `EquipmentPrefab` on each definition so each weapon displays its own model.

## Give each definition its own action

| Name | Type | Recommended collection | Consumer | Standard example |
| --- | --- | --- | --- | --- |
| `ItemActionSet` | `ItemActionSet` | **Item Definition** | Use Item Action Set Attribute Item Action | Health Potion restores health while Fire Wand invokes a cast action |

Use this pattern when Items in the same broad category need different behavior. The **Use Item Action Set Attribute** Item Action reads the Scriptable Object stored by the attribute and invokes an action from it. A conventional Category Item Action Set is simpler when every Item in the category performs the same action.

## Support spatial and nested inventory

| Name | Type | Recommended collection | Consumer | Standard example |
| --- | --- | --- | --- | --- |
| `Shape` | `ItemShape` | **Item Definition** | Item Shape Grid data and Item Shape Item View modules | Iron Sword occupies a longer group of cells than Health Potion |
| `Slots` | `ItemAmounts` | **Item** when contents differ per instance | Item Slots Item View and project upgrade/socket logic | One Iron Sword contains its own rune or upgrade Items |

An `ItemShape` stores a boolean grid and an anchor. The Item Shape Grid and its View Modules must use the same configured attribute name. Use this attribute only when Items occupy multiple cells; a regular Bag grid does not need it.

`ItemAmounts` stores one or more Item-and-amount entries and supports nested Item serialization. Put `Slots` in the **Item** collection when two Iron Sword instances can contain different upgrades. The Item must be mutable, and usually unique, for those contents to vary safely by instance.

## Track equipped state and inventory limits

| Name | Type | Recommended collection | Consumer | Use |
| --- | --- | --- | --- | --- |
| `IsEquipped` | `bool` | **Item** | An Equipped Item View configured to read the attribute | Optional explicit equipped state |
| `StackSizeLimit` | `int` | **Item Definition** | Multi Stack Item Collection through **Stack Size Limit Attribute Name** | A smaller maximum stack for Health Potion |
| `CategorySizeLimit` | `int` | **Item Category** | Legacy Group Item Restriction configured with the matching name | Limit all Items in one category |
| `DefinitionSizeLimit` | `int` | **Item Definition** | Legacy Group Item Restriction configured with the matching name | Limit one definition, such as Iron Sword |
| `ItemSizeLimit` | `int` | **Item** | Legacy Group Item Restriction configured with the matching name | Limit one particular mutable Item |

`IsEquipped` is optional. Most equipment UI can determine state from membership in the Equipment Item Collection, which avoids maintaining a second value. If a configured view explicitly reads `IsEquipped`, define it as an Item attribute and make the Item mutable so the value can change at runtime.

The Multi Stack Item Collection has a default stack limit and an attribute-name field for definition-specific limits. The Group Item Restriction remains available for attribute-driven limits, but its overflow actions are legacy. Prefer the newer Item Restriction Set and rejection event workflow for new inventory restrictions unless the older attribute-based behavior is specifically required.

## Choose the value type

Use the type required by the consuming component. The images below show how the common value editors appear.

### Numeric, Boolean, and text values

`int` stores whole numbers such as `Attack` or `StackSizeLimit`. It supports Modify expressions.

![An integer Attribute value field in the Attribute editor.](https://opsive.com/wp-content/uploads/2020/05/IntAttributeType.webp?v=1503e13dfd61)

`float` stores decimal values such as a multiplier or precise duration. It supports Modify expressions.

![A floating-point Attribute value field in the Attribute editor.](https://opsive.com/wp-content/uploads/2020/05/FloatAttributeType.webp?v=7059cb4bc7da)

`bool` stores an on/off value such as optional `IsEquipped` state.

![A Boolean Attribute toggle in the Attribute editor.](https://opsive.com/wp-content/uploads/2020/05/BoolAttributeType.webp?v=8eef2c4b8e3d)

`string` stores text such as `Description`. It supports Modify expressions.

![A string Attribute text field in the Attribute editor.](https://opsive.com/wp-content/uploads/2020/05/StringAttributeType.webp?v=59ad94c30212)

### Unity object references

Unity object types such as `GameObject`, `Sprite`, and `Material` reference project assets. Use `Sprite` for `Icon` and `GameObject` for pickup or equipment prefabs.

![A GameObject Attribute object-reference field in the Attribute editor.](https://opsive.com/wp-content/uploads/2020/05/GameObjectAttribute.webp?v=b0dd85458eaf)

### Inventory-specific values

`ItemAmounts` stores nested Items and amounts, such as the contents of `Slots`.

![An ItemAmounts Attribute editor listing nested Item-and-amount entries.](https://opsive.com/wp-content/uploads/2020/05/ItemAmountAttributeType-1.webp?v=d62a33e1389e)

`CurrencyAmounts` stores Currency-and-amount entries, such as a `BuyPrice` paid in Gold.

![A CurrencyAmounts Attribute editor listing a Currency and its amount.](https://opsive.com/wp-content/uploads/2020/06/CurrencyAmountAttributeType.webp?v=715c5523900a)

`ItemShape` stores the occupied cells and anchor used by an Item Shape Grid.

![An ItemShape Attribute editor showing the occupied-cell grid and anchor.](https://opsive.com/wp-content/uploads/2020/11/ItemShapeAttribute.webp?v=846ec6adac5d)

`ItemActionSet` references an Item Action Set Scriptable Object for definition-specific behavior.

![An ItemActionSet Attribute object-reference field in the Attribute editor.](https://opsive.com/wp-content/uploads/2020/06/ItemActionSetAttribute.webp?v=f15c48fb821c)

## Editor checkpoints

Before entering Play Mode, confirm that:

- Every attribute name uses the exact spelling and capitalization expected by its consumer.
- The declared value type matches the component field: for example, `Icon` is a `Sprite` and `BuyPrice` is `CurrencyAmounts`.
- The attribute is declared in the intended collection on the closest shared Item Category.
- Health Potion, Iron Sword, and Fire Wand definitions override their own `Icon`, `Description`, and `BuyPrice` values.
- Weapon data exposes the expected use and equipment prefabs plus any project-defined `Attack` or `Durability` values.
- Every consuming component points to the same attribute name used by the database.

## Verify in Play Mode

1. Open the Bag UI and confirm that Health Potion, Iron Sword, and Fire Wand display the expected icons and descriptions.
2. Open the shop and confirm that each definition's price is shown in Gold and matches the value used by the transaction.
3. Drop each Item and confirm that the intended pickup visual appears.
4. Equip Iron Sword and Fire Wand and confirm that each uses the correct visual and use behavior.
5. If `Shape` is configured, move the Items in the shape grid and confirm that their occupied cells match their definitions.
6. If `Slots` is configured, change one weapon's nested Items and confirm that another instance is unchanged.
7. Test the configured stack and inventory limits and confirm that rejected Items follow the project's rejection workflow.

## Troubleshooting

- **A UI field is blank:** Check the attribute spelling, type, collection, and the Item View or Item Description module's configured attribute name.
- **The editor preview uses the wrong icon:** Check **Editor Icon** first, then verify `Icon` on the Item Definition or `CategoryIcon` on the Item Category.
- **The shop shows zero or the wrong Currency:** Check that the price is `CurrencyAmounts`, includes Gold, and uses the same name configured by the Shop Currency Collection and price view.
- **The wrong equipment prefab appears:** Check whether the Equipper is reading `UsableItemPrefab` or `EquipmentPrefab`, then inspect the inherited source and local override.
- **A nested Item changes on every copy:** Move `Slots` to the Item collection and confirm that the direct category is mutable and unique.
- **A stack or inventory limit is ignored:** Check the collection or restriction component's attribute-name field and confirm that the value is an `int` on the expected Category, Definition, or Item.

## Related pages

- [Attributes and inheritance](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/)
- [Defining Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/)
- [Item Views](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/item-view/)
- [Item Description](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-description/)
- [Shops and prices](https://opsive.com/support/documentation/ultimate-inventory-system/currency/shop/)
- [Equipping Items](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/equipping-items/)
- [Item Object Visualizer](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-object-view/)
- [Item Skills](https://opsive.com/support/documentation/ultimate-inventory-system/item/item-skills/)
- [Item Shape Grid](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-shape-grid/)
- [Multi Stack Item Collection](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/multi-stack-item-collection/)
- [Item Restrictions](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-restrictions/)

---

<a id="page-ultimate-inventory-system-currency"></a>

# Currency

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/currency/)

Use Currency to give an Inventory owner a balance, price Items, and complete transactions such as buying an Iron Sword for Gold. Begin with one root Currency and add denominations only when the player needs to exchange or display them.

The standard example uses **Gold**, an Iron Sword with a `BuyPrice` of **50 Gold**, and a player who begins with **100 Gold**.

## Understand the Currency model

| Part | What it represents | Gold example |
| --- | --- | --- |
| Currency | A database object that defines a name, Icon, limits, and conversion relationships. It does not store a balance. | Gold |
| Currency Amount | One Currency paired with an amount. | 50 Gold |
| Currency Amounts | A list of Currency Amount values, commonly used by Item attributes and prices. | Iron Sword `BuyPrice` = 50 Gold |
| Currency Collection | A balance that can add, remove, compare, and normalize related Currencies. | The player's 100 Gold |
| Currency Owner | The component that holds a Currency Collection at runtime. | The player wallet |
| Shop | Reads an Item price, checks the buyer or seller, and changes both Currency and Inventory contents. | Buy one Iron Sword for 50 Gold |

Keep these responsibilities separate. Gold defines the value, `BuyPrice` defines what the Iron Sword costs, and the player's Currency Owner records what the player owns.

## Set up the Gold workflow

### Create Gold

1. Open **Tools > Opsive > Ultimate Inventory System > Main Manager**.
2. In **Setup**, confirm that the intended Inventory System Database is selected.
3. Open **Currencies**, create **Gold**, and assign its Icon.
4. For a one-Currency project, leave **Base Currency**, **Overflow Currency**, and **Fraction Currency** empty.
5. Keep **Max Amount** large enough for the intended economy. Set a smaller value only when the Currency Collection should enforce that boundary.
6. Review **Exchange Rates** and confirm that Gold is the root of its own family.

The [Currency editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/currency/) explains every field and the relationship view.

### Define the Iron Sword price

1. In the Main Manager, open **Item Categories** and select the category that supplies Iron Sword's Item Definition attributes.
2. Add `BuyPrice` as a `CurrencyAmounts` **Item Definition** attribute if the category does not already provide it.
3. Open **Item Definitions**, select **Iron Sword**, and set `BuyPrice` to 50 Gold.
4. Add a separate `SellPrice` only when selling should use different stored data. A Shop can deliberately use the same attribute name in both directions.

![A CurrencyAmounts Item Definition attribute editor listing Gold and its configured price amount.](https://opsive.com/wp-content/uploads/2020/06/CurrencyAmountAttributeType.webp?v=715c5523900a)

The attribute name is a contract. The Item and the Shop's **Buy Attribute Name** must use the same spelling and capitalization, and the value must be `CurrencyAmounts` for the standard Shop.

### Give the player a balance

1. Add a **Currency Owner** to the same player GameObject as the Inventory and Inventory Identifier.
2. Confirm that the component uses the same Inventory System Database as Gold and Iron Sword.
3. In the Currency Owner Inspector, add Gold and set the starting amount to 100.
4. Keep the player's destination Item Collection, such as **Bag**, ready to accept Iron Sword.

The Currency Owner's Currency Collection normalizes additions and removals according to Gold's Currency settings and notifies the connected UI when its value changes.

### Connect the Shop and UI

1. On the **Shop** component, set **Buy Attribute Name** to `BuyPrice` and leave **Buy Modifier** at `0` for the stored 50-Gold price.
2. Confirm that the Shop Inventory contains Iron Sword and that the player's destination collection resolves to Bag.
3. Create the Shop Menu and its Total Price view from the UI Designer **Shop** tab.
4. Create a separate **Currency Owner Monitor** from the UI Designer **Currency** tab to show the player's Gold balance.
5. Map Gold to a valid Currency View in both the price and balance displays.

The Total Price view and Currency Owner Monitor show different data: the first shows the selected transaction total, while the second shows the player's current balance.

## Choose one Currency or a family

Use one root Currency when every price, reward, and balance is expressed in Gold. This avoids conversion rules and makes a displayed price directly comparable with the player's balance.

Use a Currency family only when several denominations represent the same underlying value. The visible Version 1 fields work together as follows:

| Field | Rule |
| --- | --- |
| **Base Currency** | The less valuable parent Currency. The root has no Base Currency. |
| **Base Exchange Rate** | The amount of Base Currency equal to one unit of the selected Currency. The value must be at least 1. |
| **Max Amount** | The greatest amount of that denomination retained by a Currency Collection before overflow handling. |
| **Overflow Currency** | A more valuable Currency in the same family that receives excess value. |
| **Fraction Currency** | A less valuable Currency in the same family that receives a fractional remainder. |

For example, Silver can use Bronze as its Base Currency with a Base Exchange Rate of 100, meaning 1 Silver equals 100 Bronze. Gold can then use Silver as its Base Currency. Currencies can convert only when they share the same root.

Base relationships establish exchange rates, but **Overflow Currency** and **Fraction Currency** decide how a Currency Collection stores out-of-range or fractional results. Without a valid next denomination, excess value cannot be retained above Max Amount and fractional value below the smallest configured denomination can lose precision.

## How a Shop transaction runs

For a standard purchase:

1. The Shop finds the Item's value using **Buy Attribute Name**.
2. It multiplies the stored `CurrencyAmounts` value by the selected Item quantity and by `1 + Buy Modifier`. A Buy Modifier of `0` leaves the value unchanged.
3. It checks that the Item is buyable, the destination Item Collection can accept it, all buy conditions pass, and the Currency Owner has the calculated amount.
4. It removes that Currency and adds the Item to the player's selected destination collection.
5. Successful purchase events let the UI refresh and let **Shop Add Remove Binding** remove finite stock when **Remove On Buy** is enabled.

Selling reverses the data flow: the Shop checks the Item and sell conditions, removes the Item from the seller, reads **Sell Attribute Name**, applies `1 + Sell Modifier`, and adds the resulting Currency to the seller's Currency Owner. Validate the sell attribute before enabling the transaction.

Currency Collections keep each result in a valid discrete state. Fractional price modifiers can therefore be converted through Fraction Currency or lose precision when no smaller denomination exists.

## Editor checkpoint

Before entering Play Mode, confirm that:

- Gold exists once in the intended Inventory System Database and is the root of its Currency family;
- Iron Sword exposes `BuyPrice` as a `CurrencyAmounts` Item Definition attribute containing 50 Gold;
- the player Currency Owner contains 100 Gold and shares the player Inventory's GameObject and database;
- the Shop's **Buy Attribute Name** is exactly `BuyPrice` and **Buy Modifier** is `0`;
- the Shop Inventory contains Iron Sword and the player's Bag can accept it;
- the Shop total-price view maps Gold; and
- the separate Currency Owner Monitor resolves the player's Currency Owner and maps Gold.

## Verify in Play Mode

1. Enter Play Mode and confirm that the balance view shows 100 Gold.
2. Open the Shop, select one Iron Sword, and confirm that Total Price shows 50 Gold.
3. Buy it and confirm that Iron Sword appears in Bag while the balance becomes 50 Gold.
4. Try to buy another quantity whose total exceeds the remaining balance. Confirm that the transaction is rejected and neither the Bag nor the Gold balance changes.
5. If selling is configured, sell an eligible Item and confirm that the Item amount decreases and Gold increases by the displayed sell total.
6. If a multi-Currency family is configured, test values immediately below and above each Max Amount and confirm that overflow, fractions, and the UI use the intended denominations.

## Troubleshooting

- **Gold is absent from an editor field:** Check that the Main Manager, scene components, and Item data use the same Inventory System Database.
- **Iron Sword has no price:** Check that its category supplies `BuyPrice` as a `CurrencyAmounts` Item Definition attribute and that Iron Sword has a Gold value.
- **The Shop reports a missing price or shows zero:** Check `BuyPrice` spelling and type against **Buy Attribute Name**, then confirm that the selected Item exposes the attribute.
- **Buy remains unavailable with enough Gold:** Check the player's Currency Owner, the calculated quantity total, buy conditions, and whether Bag can accept Iron Sword.
- **The wrong amount is removed:** Check the stored `BuyPrice`, selected quantity, and **Buy Modifier**. Remember that the multiplier is `1 + Buy Modifier`.
- **The balance changes but the UI does not:** Check that the Currency Owner Monitor resolves the intended Currency Owner and that its Multi Currency View maps Gold.
- **Related Currencies do not convert:** Check that both trace to the same root and that each **Base Currency** and **Base Exchange Rate** points from the more valuable denomination to the less valuable one.
- **Overflow stops at Max Amount:** Check that **Overflow Currency** is a more valuable member of the same family and that an exchange rate exists between them.
- **A fractional result is rounded away:** Add a valid lower-value **Fraction Currency** or keep prices and modifiers in the smallest supported whole unit.
- **Shop stock never decreases:** Add **Shop Add Remove Binding** and enable **Remove On Buy**; the default Shop treats its Inventory entry as an unlimited source.

## Continue with shops

- [Shop](https://opsive.com/support/documentation/ultimate-inventory-system/currency/shop/) is the direct child guide for buying, selling, price attributes, stock behavior, callbacks, and the public transaction methods.

## Related pages

- [Currency editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/currency/)
- [Common price attributes](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/common-attribute-types/)
- [Define attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/)
- [Shop UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/shop/)
- [Currency UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/currency/)
- [Shop Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/shop-menu/)
- [Multi Currency View and Currency Owner Monitor](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/multi-currency-view/)

## Developer reference

### Work with a Currency Owner

`InventorySystemManager.GetCurrency` resolves a Currency by database name. `CurrencyAmount` accepts either constructor order and supports `(int, Currency)` and `(Currency, int)` tuple conversion. The Currency Owner exposes its Currency Collection through `CurrencyAmount`.

```csharp
var gold = InventorySystemManager.GetCurrency("Gold");
CurrencyAmount ironSwordPrice = (50, gold);

var balance = currencyOwner.CurrencyAmount;
var canAfford = balance.HasCurrency(gold, ironSwordPrice.Amount);

var added = currencyOwner.AddCurrency(gold, 25);
var removed = currencyOwner.RemoveCurrency(gold, 10);

var exactGoldAmount = balance.GetAmountOf(gold);
var familyValueInRootUnits = balance.GetFullAmountAsRootCurrency(gold);
```

`GetAmountOf` returns only the selected denomination. `GetFullAmountAsRootCurrency` combines every stored Currency from the same family and expresses the total in root units. `HasCurrency` uses the family value, so a compatible set of denominations can satisfy one related-Currency amount.

Use `Currency.TryGetExchangeRateTo(otherCurrency, out rate)` to test conversion. It returns `false` when the Currencies do not share a root.

### Use the Version 1 Shop methods

The released Version 1 Shop methods accept an `Inventory`, an `ICurrencyOwner`, and an `ItemInfo`. The ItemInfo carries the Item, amount, and source collection:

```csharp
var bought = shop.BuyItem(buyerInventory, currencyOwner, itemInfo);
var sold = shop.SellItem(sellerInventory, currencyOwner, itemInfo);
```

Both methods return `false` when validation fails. In the built-in synchronous purchase path, the Shop checks the destination and funds before removing Currency and adding the Item. When **Add Item With Callback** is enabled, Currency is removed before the external add callback reports success; provide project-level rollback if that callback can fail. Selling removes the Item before it calculates and adds the sell value, so a custom sell path must also handle rollback when later work can fail.

---

<a id="page-ultimate-inventory-system-currency-shop"></a>

# Shop

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/currency/shop/)

Use a Shop to let a player buy and sell Items with a Currency Owner. This workflow creates a Gold shop where Health Potion costs 10 Gold, Iron Sword costs 50 Gold, and successful purchases enter the player's Bag.

The standard Version 1 Shop reads prices from Item attributes. It does not hold a shopkeeper balance: buying removes Gold from the buyer, and selling adds Gold to the seller. Add custom logic when the shop itself must own or run out of Currency.

## Before you begin

Confirm that:

- the intended Inventory System Database contains Gold, Health Potion, and Iron Sword;
- the player GameObject has an Inventory, Inventory Identifier, and Currency Owner with 100 Gold;
- the player's Inventory has a **Bag** Item Collection that can accept both Items;
- a shopkeeper GameObject has an Inventory containing the Items offered for sale; and
- the scene has the Canvas Managers required by the Shop Menu.

Start with the [Currency workflow](https://opsive.com/support/documentation/ultimate-inventory-system/currency/) when Gold, the player balance, or the price attributes do not exist yet.

## Define the Item prices

1. Open **Tools > Opsive > Ultimate Inventory System > Main Manager**.
2. In **Item Categories**, select the category that supplies Health Potion and Iron Sword's Item Definition attributes.
3. Add `BuyPrice` with the `CurrencyAmounts` type if it is not already present.
4. Add `SellPrice` with the same type when selling should use a separately stored value.
5. In **Item Definitions**, set Health Potion's `BuyPrice` to 10 Gold and Iron Sword's `BuyPrice` to 50 Gold.
6. For the sell test, set Health Potion's `SellPrice` to 5 Gold and Iron Sword's `SellPrice` to 25 Gold.

Use Item Definition attributes for stable prices shared by every runtime copy of an Item Definition. The Shop reads the attribute name as text, so spelling, capitalization, and value type must match its Inspector fields exactly.

## Configure the Shop

1. Select the shopkeeper GameObject and confirm that its Inventory contains Health Potion and Iron Sword.
2. Add the **Shop** component.
3. Set **Inventory** to the shopkeeper Inventory.
4. Set **Buy Attribute Name** to `BuyPrice` and **Sell Attribute Name** to `SellPrice`.
5. Leave **Buy Modifier** and **Sell Modifier** at `0` so the Shop uses the stored prices unchanged.
6. Leave **Add Item With Callback** and **Remove Item With Callback** disabled for the standard synchronous workflow.
7. Set **Default Item Collection To Add On Buy** so purchased Items enter the player's Bag.
8. Leave **Item Collection To Add On Buy By Category** empty unless some Item Categories must use a different destination.

![The Version 1 Shop Inspector showing price attribute names, modifiers, callback options, the Shop Inventory, and purchase destination collections.](https://opsive.com/wp-content/uploads/2020/04/Shop.png?v=0cc4a191bf8a)

The Shop calculates each total as the stored price multiplied by the Item quantity and by `1 + modifier`. A modifier of `0` keeps the price unchanged; a Sell Modifier of `-0.2` pays 80 percent of the stored `SellPrice`.

To use one stored value in both directions, set **Sell Attribute Name** to `BuyPrice` and apply a Sell Modifier when the Shop should pay less than its purchase price.

## Connect the Shop Menu

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer**.
2. Select **Shop**, create a Shop Menu, and bind its **Shop** reference to the configured component.
3. Confirm that the menu resolves the player's Inventory. The menu gets the player's Currency Owner through that Inventory.
4. Create the **Inventory Grid**, **Total Price UI**, and **Quantity Picker Panel** required by the menu.
5. Confirm that the Total Price Multi Currency View maps Gold to a valid Currency View.
6. Use the UI Designer **Currency** tab to create a separate Currency Owner Monitor when the player should see the remaining Gold balance.

The Shop Menu shows the Shop Inventory in Buy mode and the player's Inventory in Sell mode. It passes the selected Item and quantity to the Shop as one `ItemInfo`.

The [Shop UI Designer workflow](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/shop/) covers the complete generated-menu setup and binding choices.

## Choose unlimited or finite stock

The default Shop does not remove an Item from the Shop Inventory after purchase. Its Inventory acts as a catalog, so Health Potion and Iron Sword remain available as an unlimited supply.

For finite stock:

1. Add **Shop Add Remove Binding** beside the Shop component.
2. Assign its **Shop** reference.
3. Enable **Remove On Buy** to require and remove the purchased amount from Shop Inventory after a successful purchase.
4. Enable **Add On Sell** when Items sold by the player should enter Shop Inventory and become available for later purchase.
5. On Shop Menu, enable **Limit Buy Quantity To Available Item Amount** when the quantity picker should also stop at current stock.

![The Shop Add Remove Binding Inspector showing the Shop reference with Remove On Buy and Add On Sell enabled.](https://opsive.com/wp-content/uploads/2020/04/ShopAddRemoveBinding.png?v=a07b817f7c88)

Shop Add Remove Binding participates in the buy conditions when Remove On Buy is enabled, then changes stock only after the Shop reports a successful transaction.

## How buying works

For the built-in synchronous path, the Shop:

1. Rejects a missing buyer Inventory, Currency Owner, Item, or non-positive amount.
2. Confirms that the Shop Inventory contains the Item and that the Item has the attribute named by **Buy Attribute Name**.
3. Checks custom buy conditions and verifies that the destination Item Collection can accept the selected amount.
4. Reads the `CurrencyAmounts` price, applies quantity and `1 + Buy Modifier`, and confirms that the buyer has the resulting amount.
5. Removes that Currency from the buyer.
6. Adds the Item to **Default Item Collection To Add On Buy**, or to the first matching category-specific destination.
7. Returns success to the menu and raises the successful-buy events used by Shop Add Remove Binding.

For mutable, unique Items, the Shop creates a separate Item instance for every purchased unit. Other Items are added using the selected ItemInfo amount.

## How selling works

For the built-in synchronous path, the Shop:

1. Confirms that the selected Item belongs to the seller and has the attribute named by **Sell Attribute Name**.
2. Checks custom sell conditions.
3. Removes the selected amount from its source Item Collection, falling back to the seller's Main Item Collection when the ItemInfo does not identify a valid seller collection.
4. Reads the `CurrencyAmounts` sell value, applies quantity and `1 + Sell Modifier`, and adds that amount to the seller's Currency Owner.
5. Returns success to the menu and raises the successful-sell events used by Shop Add Remove Binding.

The default Shop neither receives the buyer's Gold nor pays from a shopkeeper wallet. Extend the Shop or add conditions when the seller payment must depend on a separate shop balance.

## Editor checkpoint

Before entering Play Mode, confirm that:

- Health Potion has `BuyPrice` = 10 Gold and `SellPrice` = 5 Gold;
- Iron Sword has `BuyPrice` = 50 Gold and `SellPrice` = 25 Gold;
- the Shop uses `BuyPrice` and `SellPrice` with both modifiers set to `0`;
- **Inventory** references the shopkeeper Inventory and both Items appear there;
- the player's Currency Owner contains 100 Gold;
- **Default Item Collection To Add On Buy** resolves to Bag;
- the Shop Menu resolves the Shop, player Inventory, Total Price UI, and Quantity Picker Panel;
- the price view and optional balance view both map Gold; and
- finite-stock settings agree between Shop Add Remove Binding and Shop Menu.

## Verify in Play Mode

1. Enter Play Mode and confirm that the player's balance shows 100 Gold.
2. Open Buy, select two Health Potions, and confirm that Total Price shows 20 Gold.
3. Complete the purchase. Confirm that two Health Potions enter Bag and the balance becomes 80 Gold.
4. Buy one Iron Sword. Confirm that it enters Bag and the balance becomes 30 Gold.
5. Attempt another 50-Gold Iron Sword purchase. Confirm that the Shop rejects it and neither the balance nor Bag changes.
6. Open Sell and sell one Health Potion. Confirm that one leaves the player Inventory and 5 Gold is added.
7. For a separate finite-stock test, reset the scene, enable **Remove On Buy**, give the Shop one Iron Sword, and buy it. Confirm that the Shop stock becomes zero and another purchase is unavailable.
8. Enable **Add On Sell**, sell an eligible Item, and confirm that it appears in the Shop Inventory after the successful sale.

## Troubleshooting

- **An Item does not appear in Buy mode:** Check that the Shop's Inventory contains it, that it has the configured `BuyPrice` attribute, and that the Inventory Grid permits its Item Category.
- **The price is blank or zero:** Check that `BuyPrice` or `SellPrice` is a `CurrencyAmounts` value containing Gold and that the Shop's attribute-name field matches it exactly.
- **The wrong total is displayed:** Check the selected quantity and modifier. The multiplier is `1 + modifier`, so `-0.2` means 80 percent rather than negative 20 percent.
- **Buy is disabled with enough Gold:** Check that the Shop Menu resolves the intended player Inventory and Currency Owner, then confirm that Bag exists and can accept the Item.
- **A purchase succeeds but the Item goes to the wrong collection:** Check **Default Item Collection To Add On Buy** and every entry in **Item Collection To Add On Buy By Category**.
- **Shop stock never decreases:** Add Shop Add Remove Binding and enable **Remove On Buy**. Also enable the Shop Menu stock limit when the quantity picker should respect the available amount.
- **Sold Items do not become stock:** Enable **Add On Sell** and confirm that the binding references the same Shop.
- **The Gold balance changes but its UI does not:** Check the separate Currency Owner Monitor; the Total Price view displays the transaction total, not the player's balance.
- **Custom add or remove callbacks return false after another value changed:** The standard callback paths do not perform automatic rollback. Restore the previous Currency or Item state in the custom integration.
- **Selling removes an Item but adds no Gold:** Check `SellPrice` name and `CurrencyAmounts` type before the sale. The built-in path removes the Item before it calculates and adds the Currency value.

## Related pages

- [Currency and Currency Owners](https://opsive.com/support/documentation/ultimate-inventory-system/currency/)
- [Create and configure Gold](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/currency/)
- [Common price attributes](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/common-attribute-types/)
- [Define Item attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/)
- [Shop UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/shop/)
- [Currency UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/currency/)
- [Shop Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/shop-menu/)
- [Multi Currency View and Currency Owner Monitor](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/multi-currency-view/)

## Developer reference

### Call the Version 1 transaction methods

The released Version 1 API accepts an `ItemInfo`, not separate `Item` and amount arguments. ItemInfo carries the Item, amount, and source Item Collection.

```csharp
var bought = shop.BuyItem(buyerInventory, currencyOwner, itemInfo);
var sold = shop.SellItem(sellerInventory, currencyOwner, itemInfo);
```

Both calls return `false` when validation fails. Useful override points include `IsItemBuyable`, `CanBuyerBuyItem`, `TryGetBuyValueForBuyer`, `GetBuyModifierForBuyer`, and their sell equivalents. Components can add project rules through `IShopBuyCondition` and `IShopSellCondition`.

### Handle the callback modes

**Add Item With Callback** causes the Shop to remove the purchase Currency and then execute `EventNames.c_InventoryGameObject_OnBuyAddItem_Shop_ItemInfo_ActionBoolSucces` on the buyer Inventory GameObject. For the standard Shop, the listener receives `ShopGeneric<CurrencyCollection>`, `ItemInfo`, and an `Action<bool>` callback. A `false` result ends the transaction without a built-in Currency refund.

**Remove Item With Callback** executes `EventNames.c_InventoryGameObject_OnSellRemoveItem_ShopBase_ItemInfo_ActionBoolSucces` on the seller Inventory GameObject. The listener receives the Shop, ItemInfo, and `Action<bool>` callback. Only a `true` result continues to calculate and add the sell Currency.

Shop Add Remove Binding is separate from these callback modes. It listens for successful Shop transactions and updates the Shop Inventory; it does not replace adding to or removing from the player's Inventory.

---

<a id="page-ultimate-inventory-system-crafting"></a>

# Crafting

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/crafting/)

Use crafting to turn Items already held by an Inventory into one or more output Items. A Crafting Recipe describes the expected inputs and output; a Crafter chooses which recipes are available and which Crafting Processor applies them. The included workflow is suitable for a straightforward recipe such as **2 Herb + 1 Water -> 1 Health Potion**, while the same structure can support category-based substitutions, Gold costs, or custom rules.

## How the crafting parts fit together

| Part | Responsibility | Health Potion example |
| --- | --- | --- |
| Crafting Category | Groups recipes and determines their Crafting Recipe type. | **Consumable Recipes** uses the built-in base recipe type. |
| Crafting Recipe | Stores ingredient requirements and default output. | **Brew Health Potion** requires 2 Herb and 1 Water and outputs 1 Health Potion. |
| Crafter | Collects the available recipes and holds the processor. | Includes Consumable Recipes and uses the standard processor. |
| Crafting Processor | Selects and validates ingredients, removes them, and adds the output. | Finds Herb and Water in Bag, then creates Health Potion. |
| Crafting Menu | Binds a player Inventory to a Crafter and presents recipe, quantity, and result controls. | Shows Brew Health Potion and enables Craft only when enough ingredients exist. |
| Crafting Result | Reports whether processing succeeded and contains the produced Crafting Output. | Success with a Crafting Output containing Health Potion. |

The recipe is data, not the final rule. The processor decides whether the current Inventory satisfies that data and what happens when the craft is performed. Keep the first recipe and processor simple before adding character levels, ingredient quality, timers, or randomized output.

## Before you begin

Prepare these objects in the same Inventory System Database:

- **Herb**, **Water**, and **Health Potion** Item Definitions;
- a player Inventory whose main Item Collection is **Bag**;
- a concrete **Consumable Recipes** Crafting Category; and
- a Canvas with the UIS managers needed by the UI Designer.

The names Herb and Water are sample ingredient definitions. Substitute the project's existing names consistently if its crafting materials already use different terms.

## Build the Health Potion workflow

### Create the Crafting Category

1. Open **Tools > Opsive > Ultimate Inventory System > Main Manager**.
2. In **Setup**, select the intended Inventory System Database.
3. Open **Crafting Categories** and create **Consumable Recipes**.
4. Keep **Abstract** disabled so a recipe can select it directly.
5. Set **Recipe Type** to the built-in base Crafting Recipe type.

Use [the Crafting Category editor workflow](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/crafting-category/) to review its Properties and Relationships before creating recipes.

### Create the Crafting Recipe

1. Open **Crafting Recipes** and create **Brew Health Potion**.
2. Set **Category** to **Consumable Recipes**, not Uncategorized.
3. Under **Ingredients**, add 2 Herb and 1 Water as Item Definition amounts.
4. Under **Outputs**, add 1 Health Potion.
5. Confirm that the visual recipe summary shows **2 Herb + 1 Water -> 1 Health Potion**.

Item Definition ingredients are the clearest default: any runtime Item with the matching definition can satisfy the requirement. [The Crafting Recipe editor workflow](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/crafting-recipe/) explains when to use a broader Item Category or a specific Item instead.

### Create the Crafting Menu

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer**.
2. In **Crafting**, create a Basic panel or a Main Menu inner panel.
3. In the **Crafter** section, add a Crafter to the generated Crafting Menu.
4. Confirm that the Crafting Menu references the generated Recipe Grid, Recipe Panel, Quantity Picker Panel, and Crafter.
5. Bind the menu to the player Inventory whose main collection is Bag.

Follow [the Crafting UI Designer workflow](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/crafting/) for the exact panel, grid, binding, and navigation choices. Use [Crafting Menu runtime behavior](https://opsive.com/support/documentation/ultimate-inventory-system/ui/crafting-menu/) when adjusting an existing generated menu.

### Configure the Crafter

1. Select the Crafter added to the menu.
2. Confirm that **Database** references the same database as the scene's Inventory System Manager.
3. Add **Consumable Recipes** to **Crafting Categories**.
4. Leave **Miscellaneous Recipes** empty for this example. The category already supplies Brew Health Potion.
5. Keep **Processor** set to **Simple Crafting Processor With Currency**. It supports the standard recipe even when the recipe has no Currency cost.
6. Keep **Externally Remove Ingredients** disabled.
7. Add `Bag` to **Ingredient Item Collections**.

![The Version 1 Crafter Inspector showing DemoInventoryDatabase, All Recipes in Crafting Categories, an empty Miscellaneous Recipes list, SimpleCraftingProcessorWithCurrency, and the ingredient-removal option.](https://opsive.com/wp-content/uploads/2020/04/CrafterInspector_v1_1_4.png?v=15573e38fbdb)

The processor can search the entire Inventory when **Ingredient Item Collections** is empty. For the standard workflow, limit the search to Bag and make Bag the main Item Collection: the simple processor removes selected ingredients from the Inventory's main collection and adds crafted output through that Inventory.

Use **Miscellaneous Recipes** for one exceptional recipe that should be available without including its whole category. Do not add the same recipe through both **Crafting Categories** and **Miscellaneous Recipes**, or it can appear twice.

## Choose the right ingredient and processor

### Ingredient scope

| Ingredient kind | Use it when | Example |
| --- | --- | --- |
| Item Definition | Any runtime copy of one exact definition is valid. | Any Herb Item can satisfy the Herb amount. |
| Item Category | Several related definitions are interchangeable. | Any Item in a Materials category can satisfy one material requirement. |
| Item | The processor must match the stored runtime Item values. | A particular mutable Item whose quality matters. |

Use Item Definitions until substitutions or Item-specific data are an intentional design requirement.

### Processor choice

- **Simple Crafting Processor** handles Item, Item Definition, and Item Category ingredients.
- **Simple Crafting Processor With Currency** adds Currency requirements when the selected recipe type provides them. It is also the Crafter Inspector's default and can process the no-cost Health Potion recipe.
- A custom processor is appropriate when crafting depends on skill level, station state, minigame score, ingredient quality, delayed completion, or nonstandard output.

Changing **Processor** type displays a warning because the change cannot be undone and fields unsupported by the new type can be lost. Make the change in version control and review every processor setting afterward.

Enable **Externally Remove Ingredients** only when another system listens for the processor's removal callback and reports success. With no handler, the standard craft cannot complete.

## Editor checkpoints

Before entering Play Mode, confirm that:

- Herb, Water, Health Potion, Consumable Recipes, and Brew Health Potion all belong to the active database;
- Consumable Recipes is concrete and uses the recipe type expected by Brew Health Potion;
- the recipe summary shows exactly 2 Herb, 1 Water, and 1 Health Potion;
- the Crafter includes Consumable Recipes once and does not also list Brew Health Potion under Miscellaneous Recipes;
- the Crafter uses the intended processor with **Externally Remove Ingredients** disabled;
- `Bag` appears in **Ingredient Item Collections** and is the player's main Item Collection;
- the Crafting Menu references that Crafter and the correct player Inventory; and
- the Recipe Grid, Recipe Panel, and Quantity Picker Panel references are assigned.

## Verify in Play Mode

1. Put 1 Herb and 1 Water in Bag, enter Play Mode, and open the Crafting Menu.
2. Confirm that Brew Health Potion appears once and displays the correct inputs and output.
3. Try to craft one. Confirm that the action is unavailable or fails without removing either ingredient.
4. Add a second Herb to Bag and craft a quantity of 1.
5. Confirm that exactly 2 Herb and 1 Water are removed and 1 Health Potion is added to Bag.
6. Add 4 Herb and 2 Water, choose a quantity of 2, and confirm that the displayed and actual amounts scale to 4 Herb, 2 Water, and 2 Health Potions.
7. Close and reopen the menu. Confirm that the recipe list and quantity return to their expected starting state.

## Troubleshooting

- **Brew Health Potion does not appear:** Check the Crafter's **Crafting Categories**, the recipe's direct Category, and the Crafting Menu's Crafter reference. Confirm that every reference belongs to the active database.
- **The recipe appears twice:** Check whether it is supplied by Consumable Recipes and also listed under **Miscellaneous Recipes**. Remove the duplicate source.
- **Craft remains unavailable with enough Items:** Check the ingredient kind and amounts, the `Bag` spelling in **Ingredient Item Collections**, and the Inventory bound to the menu.
- **Ingredients are in Equipment but are not used:** This workflow deliberately searches Bag. Move them into Bag or intentionally change the processor's collection scope and removal behavior.
- **Crafting fails after enabling external removal:** Check that a listener handles the removal callback and reports success. Otherwise disable **Externally Remove Ingredients**.
- **Ingredients disappear but the output is missing:** Check that Health Potion can be added to the Inventory's main Bag collection and that capacity or restrictions do not reject it.
- **The wrong player's Items are used:** Check the Crafting Menu Inventory binding or the Crafting Menu Opener that supplies the Inventory and Crafter.
- **Recipe fields change or disappear:** Check whether its Crafting Category now uses a different Recipe Type. Restore the intended type before re-entering custom data.
- **Processor fields disappear after a type change:** Restore from version control if needed, then select the intended Processor and recheck all serialized settings.

## Related workflows

- [Crafting Category editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/crafting-category/)
- [Crafting Recipe editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/crafting-recipe/)
- [Crafting UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/crafting/)
- [Crafting Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/crafting-menu/)
- [Item Collections](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/)
- [Currencies](https://opsive.com/support/documentation/ultimate-inventory-system/currency/)
- [Custom Crafting Processors](https://opsive.com/support/documentation/ultimate-inventory-system/crafting/custom-crafting-processors/): the direct child guide for level gates, calculated results, custom Recipe types, and other processor logic.

## Developer API

`CraftingProcessor.CanCraft` and `CraftingProcessor.Craft` can auto-select ingredients from an Inventory. The overload that accepts a `ListSlice<ItemInfo>` is available when another system chooses the exact runtime Items. `CraftingResult.Success` reports the outcome, and `CraftingResult.CraftingOutput` contains the produced Item amounts.

```csharp
var processor = crafter.Processor;
var quantity = 1;

if (processor.CanCraft(recipe, inventory, quantity)) {
    var result = processor.Craft(recipe, inventory, quantity);
    if (result.Success) {
        var output = result.CraftingOutput;
        // React to the successful craft.
    }
}
```

The Crafter builds its runtime recipe list from **Miscellaneous Recipes** plus every recipe inherited through its selected **Crafting Categories**. Call `Initialize(true)` after replacing those serialized arrays at runtime, or use `AddRecipe` to add one available recipe to an initialized Crafter.

---

<a id="page-ultimate-inventory-system-crafting-custom-crafting-processors"></a>

# Custom Crafting Processors

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/crafting/custom-crafting-processors/)

Create a custom Crafting Processor when a recipe needs a rule or result that the built-in processors cannot express. Start with one visible change, such as requiring a crafting level for **Brew Health Potion** or assigning a runtime **Quality** value to the crafted Health Potion.

The built-in **Simple Crafting Processor** handles standard Item, Item Definition, and Item Category ingredients. **Simple Crafting Processor With Currency** adds Currency requirements. Keep one of those processors when changing the recipe data is enough.

## Choose the smallest extension

| Desired result | Recommended approach |
| --- | --- |
| Change the required ingredients or output amounts | Edit the Crafting Recipe; no custom processor is needed. |
| Apply one level requirement to every recipe in a Crafting Category | Map `recipe.Category` to a level in a custom processor. |
| Give each recipe its own level requirement | Add a field to a custom Crafting Recipe type and read it from a custom processor. |
| Set an Item attribute from a character stat or minigame result | Override the output-creation step and set the mutable Item attribute before adding the result to the Inventory. |
| Replace ingredient selection, removal, and output creation together | Override the full crafting transaction only when the narrower extension points are insufficient. |

Prefer the narrowest option. It keeps the built-in validation, ingredient removal, quantity handling, and crafting events intact.

## Prepare the Health Potion test

Use one known recipe so a processor change has an unambiguous result:

- **Brew Health Potion** belongs to **Consumable Recipes**.
- It requires 2 Herb and 1 Water from the player's **Bag**.
- It normally produces 1 Health Potion.
- The Crafter includes Consumable Recipes and the Crafting Menu references that Crafter and Inventory.

Confirm that this recipe works with a built-in processor before adding a custom rule. That separates a processor problem from a recipe, Inventory, or UI setup problem.

## Require a crafting level

Use a custom Recipe Type when the required level varies by recipe. The complete Version 1 example is in [Developer reference](#developer-reference).

1. Add the `LevelCraftingRecipe` and `LevelCraftingProcessor` classes to the project and allow Unity to compile.
2. Open **Tools > Opsive > Ultimate Inventory System > Main Manager** and select **Crafting Categories**.
3. Select **Consumable Recipes** and set **Recipe Type** to **Level Crafting Recipe**. If only some consumable recipes need this data, create a separate concrete category for them instead.
4. Select **Crafting Recipes**, open **Brew Health Potion**, and set **Required Level** in the **Other** tab.
5. Select the GameObject with the Crafter component and change **Processor** to **Level Crafting Processor**.
6. Set **Test Crafting Level** while proving the workflow. Replace the example getter with the project's character-level source before shipping.

The expected outcome is simple: below the Required Level, the craft is rejected and the Bag does not change. At or above the Required Level, the same recipe consumes its ingredients and adds the Health Potion.

All direct recipes in one Crafting Category share its Recipe Type. Changing that type converts the existing recipes and can discard fields that are not present on the new type, so make the change in version control and review every recipe afterward.

## Set runtime output quality

Use a mutable Item attribute when the output remains a Health Potion but one runtime value depends on a character stat, tool, or minigame result. The example processor overrides only output creation; the Simple Crafting Processor still validates and removes the ingredients.

1. Add an integer **Quality** Item attribute to the Item Category used by Health Potion and make it mutable.
2. Add the `QualityCraftingProcessor` class from [Developer reference](#developer-reference) and allow Unity to compile.
3. Select the Crafter and change **Processor** to **Quality Crafting Processor**.
4. Set **Test Crafting Quality** to a recognizable value, such as 3.
5. Keep Brew Health Potion's normal ingredient and output lists unchanged.
6. After the test works, replace the example quality getter with the project's character-stat or minigame provider.

On a successful craft, the processor creates the Health Potion, sets its Item-level Quality, and then adds it to the Inventory. The recipe still controls the Item Definition and amount; the external source controls only the runtime value.

## Connect a processor safely

The Crafter Inspector labels the type selector **Processor**. Selecting another type opens **Change Crafting Processor Type?** because the action cannot be undone and some values may be lost.

After confirming the change, review every processor field. In particular, retain the intended **Externally Remove Ingredients** and **Ingredient Item Collections** behavior inherited from Simple Crafting Processor. Leave external removal disabled unless another system handles the removal callback and reports success.

## Editor checkpoint

Before entering Play Mode, confirm that:

- the custom processor class compiles and appears in the Crafter's **Processor** selector;
- the Crafter still includes Consumable Recipes;
- **Ingredient Item Collections** still points to Bag when the project limits ingredient searches to that collection;
- **Externally Remove Ingredients** has the intended value;
- a level-gated recipe uses the custom Recipe Type and shows **Required Level** in **Other**; and
- a quality-based output has a mutable integer Quality Item attribute.

## Verify in Play Mode

Test one variable at a time:

1. Give the Bag exactly 2 Herb and 1 Water.
2. For the level processor, set Test Crafting Level below Required Level and attempt Brew Health Potion. Confirm that neither ingredient is removed and no Health Potion is added.
3. Raise Test Crafting Level to the requirement and craft again. Confirm that 2 Herb and 1 Water are removed and 1 Health Potion is added.
4. For the quality processor, set Test Crafting Quality to 3 and craft once. Inspect the resulting Health Potion or show its Quality through an Attribute View, and confirm that the value is 3.
5. Craft a quantity greater than 1 when the menu permits it. Confirm that ingredient and output amounts scale with quantity while every produced Item receives the same tested Quality.

## Troubleshooting

- **The custom processor is absent from Processor:** Check that the class compiles, inherits from Crafting Processor or one of its subclasses, and is not abstract; then reselect the Crafter.
- **Processor settings disappeared:** Changing the Processor type can lose unsupported fields. Restore the previous version if needed, select the intended type again, and re-enter every custom and inherited setting.
- **Required Level is absent from the recipe:** Check that the recipe's Crafting Category uses the custom Recipe Type, then open the recipe's **Other** tab.
- **Every level-gated craft fails:** Check that the processor and recipe types are paired, the test or character level source returns the expected value, and the base processor can find the ingredients.
- **Ingredients disappear even though the level is too low:** Apply the level test in `CanCraftInternal` and return `false` before the craft begins; do not remove Items in the level getter.
- **Quality stays at its default:** Check that Health Potion has an integer Quality Item attribute, that the attribute is mutable, and that the name and type match the code exactly.
- **Crafting succeeds but the wrong collection changes:** Check **Ingredient Item Collections**, the Inventory's Main Item Collection, and any external-removal handler.

## Related pages

- [Crafting concepts, processors, and Crafter](https://opsive.com/support/documentation/ultimate-inventory-system/crafting/)
- [Crafting Category editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/crafting-category/)
- [Crafting Recipe editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/crafting-recipe/)
- [Attribute editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/attributes/)
- [Attribute View](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/attribute-view/)
- [Crafting Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/crafting-menu/)

## Developer reference

These examples match the released Ultimate Inventory System Version 1 signatures. In the protected methods, `selectedIngredients` comes before `quantity`.

| Extension point | Use it for |
| --- | --- |
| `CanCraftInternal(recipe, inventory, selectedIngredients, quantity)` | Add a rule while retaining the built-in ingredient and Inventory checks. |
| `CreateCraftingOutput(recipe, inventory, quantity)` | Create or modify runtime output while retaining built-in validation and ingredient removal. |
| `RemoveIngredients(inventory, selectedIngredients)` | Replace removal only when the built-in or external-removal paths cannot support the design. |
| `CraftInternal(recipe, inventory, selectedIngredients, quantity)` | Replace the complete transaction. Reproduce validation, removal, output creation, Inventory updates, and failure handling deliberately. |

### Gate a recipe by level

The test field keeps the sample self-contained. Replace `GetCraftingLevel` with the project's real level provider.

```csharp
using Opsive.Shared.Utility;
using Opsive.UltimateInventorySystem.Core.DataStructures;
using Opsive.UltimateInventorySystem.Core.InventoryCollections;
using Opsive.UltimateInventorySystem.Crafting;
using Opsive.UltimateInventorySystem.Crafting.Processors;
using System;
using UnityEngine;

public class LevelCraftingRecipe : CraftingRecipe
{
    [SerializeField] protected int m_RequiredLevel = 1;

    public int RequiredLevel => m_RequiredLevel;
}

[Serializable]
public class LevelCraftingProcessor : SimpleCraftingProcessor
{
    [SerializeField] protected int m_TestCraftingLevel = 1;

    protected override bool CanCraftInternal(
        CraftingRecipe recipe,
        IInventory inventory,
        ListSlice<ItemInfo> selectedIngredients,
        int quantity)
    {
        var levelRecipe = recipe as LevelCraftingRecipe;
        if (levelRecipe == null) { return false; }

        if (GetCraftingLevel(inventory) < levelRecipe.RequiredLevel) {
            return false;
        }

        return base.CanCraftInternal(
            recipe, inventory, selectedIngredients, quantity);
    }

    protected virtual int GetCraftingLevel(IInventory inventory)
    {
        // Replace this test value with the project's character-level source.
        return m_TestCraftingLevel;
    }
}
```

### Set a mutable output attribute

This example preserves the Simple Crafting Processor's validation and removal path while creating the output with a runtime Quality value.

```csharp
using Opsive.UltimateInventorySystem.Core;
using Opsive.UltimateInventorySystem.Core.DataStructures;
using Opsive.UltimateInventorySystem.Core.InventoryCollections;
using Opsive.UltimateInventorySystem.Crafting;
using Opsive.UltimateInventorySystem.Crafting.Processors;
using System;
using UnityEngine;

[Serializable]
public class QualityCraftingProcessor : SimpleCraftingProcessor
{
    [SerializeField] protected int m_TestCraftingQuality = 1;

    protected override CraftingOutput CreateCraftingOutput(
        CraftingRecipe recipe, IInventory inventory, int quantity)
    {
        var sourceAmounts = recipe.DefaultOutput.ItemAmounts;
        var resultAmounts = new ItemAmount[sourceAmounts.Count];
        var craftingQuality = GetCraftingQuality(inventory);

        for (int i = 0; i < resultAmounts.Length; i++) {
            var sourceAmount = sourceAmounts[i];
            var craftedItem = InventorySystemManager.CreateItem(sourceAmount.Item);
            var quality = craftedItem.GetAttribute<
                Opsive.UltimateInventorySystem.Core.AttributeSystem.Attribute<int>>(
                "Quality");

            if (quality != null) {
                quality.SetOverrideValue(craftingQuality);
            }

            var resultAmount = new ItemAmount(
                craftedItem, sourceAmount.Amount * quantity);
            resultAmounts[i] = resultAmount;
            inventory.AddItem((ItemInfo)resultAmount);
        }

        return new CraftingOutput(resultAmounts);
    }

    protected virtual int GetCraftingQuality(IInventory inventory)
    {
        // Replace this test value with the project's stat or minigame source.
        return m_TestCraftingQuality;
    }
}
```

---

<a id="page-ultimate-inventory-system-input"></a>

# Input

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/input/)

Ultimate Inventory System uses input in two places. Unity's EventSystem moves focus, clicks buttons, and submits UI selections. UIS handler components use an Opsive player-input implementation for actions such as interacting, opening a panel, changing a grid tab, or using a hotbar slot. Configure both layers before testing a menu.

## Choose an input backend

| Project input | Opsive component on the player | Additional requirement | Best fit |
| --- | --- | --- | --- |
| Unity Input Manager | **Unity Input** | Input Manager entries and a **Standalone Input Module** for UI | An existing Version 1 project that already uses Unity's legacy input settings |
| Unity Input System | **Unity Input System** | Unity's **Player Input** component, an Input Action Asset, and an **Input System UI Input Module** | New controller support, rebinding, or local multiplayer |
| Rewired, InControl, Control Freak, or Easy Touch | The component supplied by the optional Opsive integration | The third-party asset, its matching released bridge, and its UI input route | A project that already standardizes input on that asset |
| Custom input | A component that implements `IPlayerInput` | Project-specific button and axis lookup | A custom input service that must drive UIS without changing its handlers |

The abstract Opsive `PlayerInput` class supplies shared behavior; it is not the component to add directly. Choose one concrete Opsive implementation on the same player GameObject as the Inventory. When using Unity's Input System, the similarly named Unity **Player Input** component is also required on that GameObject.

Do not leave two Opsive input implementations active on one player. UIS components request `IPlayerInput`, so an ambiguous setup can make different handlers resolve different components.

## Set up the Unity Input Manager

Use this path when the project uses Unity's legacy Input Manager.

1. Open **Tools > Opsive > Ultimate Inventory System > Main Manager**.
2. Select **Setup**.
3. Under **Input Setup**, select **Add Inputs** and approve the Project Settings change.
4. Under **Character Setup**, select the player GameObject and add the standard character components, or add **Unity Input** manually beside the existing Inventory.
5. In the Unity Input Inspector, review **Force Input**, **Disable Cursor**, **Enable Cursor With Escape**, and the look/controller fields that apply to the project.
6. On the scene's EventSystem, use **Standalone Input Module** for UI selection and submission.

**Add Inputs** edits `ProjectSettings/InputManager.asset`. It creates the Version 1 names used by the default handlers, including `Open Panel`, `Close Panel`, `Next`, `Previous`, `Action`, and `Equip First Item` through `Equip Tenth Item`. It does not create Unity Input System actions.

![The Version 1 Unity Input Inspector showing the shared player-input settings and legacy Input Manager options.](https://opsive.com/wp-content/uploads/2021/02/Unity-Input.png)

![A Unity EventSystem configured with Standalone Input Module for legacy menu navigation.](https://opsive.com/wp-content/uploads/2021/02/StandardInputModule.webp?v=d24ff889eb3a)

## Set up the Unity Input System

Use this path when the project uses Unity's Input System package.

1. Install and enable Unity's Input System package for the project.
2. Add **Unity Input System** to the player GameObject. Remove the legacy **Unity Input** component when it is no longer used.
3. Add Unity's **Player Input** component to the same GameObject.
4. Assign an Input Action Asset to **Actions**. The Opsive Shared package includes `CharacterInput.inputactions` as a starting point.
5. Confirm that the active action map contains actions matching every UIS handler's **Input Name**. The component looks up actions by name in the current action map.
6. On the EventSystem, replace **Standalone Input Module** with **Input System UI Input Module** and assign its UI actions.
7. In the Opsive Unity Input System Inspector, review **Force Input**, **Disable Cursor**, **Enable Cursor With Escape**, **Prevent Look Vector Changes**, and **Disable Player Input**.

The Opsive **Unity Input System** component reads buttons and axes from Unity's **Player Input**. If Unity's component or its current action map is missing, UIS handler names cannot resolve to actions even when the UI can still be clicked with a pointer.

## Set up an optional input integration

The UIS online catalog lists Rewired, InControl, Control Freak, and Easy Touch because each can supply the Opsive `IPlayerInput` used by Inventory handlers. They do not replace the EventSystem side of menu input.

1. Verify the third-party input product with one of its own controls.
2. Open **Tools > Opsive > Ultimate Inventory System > Main Manager > Integrations** and select the matching input product.
3. Install the third-party product first and its Opsive bridge second. Resolve compilation before changing the player.
4. Replace the current concrete Opsive input component on the player; do not leave Unity Input or Unity Input System enabled beside it.
5. Configure the third-party EventSystem input module or UI bridge required by that product.
6. Map UIS handler names such as `Action`, `Open Panel`, `Close Panel`, `Next`, `Previous`, and the hotbar inputs to the same player.

Choose the backend deliberately:

- **Rewired** is appropriate when Rewired Players, Actions, Maps, and controller assignment already own project input. Assign a unique Rewired Player ID per local player.
- **InControl** is appropriate when InControl devices and bindings already own project input. Implement or assign the integration binding map expected by its Opsive component.
- **Control Freak** uses the Control Freak rig and its Opsive input replacement. A touch-controls option does not create the rig; configure the Control Freak UI separately.
- **Easy Touch** is an older catalog route. Confirm that the current downloaded bridge compiles with the installed Easy Touch and UIS versions before planning production support.

Rewired and InControl support are shared Opsive input integrations and may be distributed with another supported Opsive package. Control Freak and Easy Touch availability can depend on the current catalog. Record the exact package pair that passes the project test; the UIS Version 1 package does not embed all four installers.

See [Input System integrations](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/input-system/) for Unity Input System-specific details.

## Configure UIS handler inputs

UIS components store their trigger as a **Simple Input** or as a named input string. A Simple Input exposes **Input Type** and **Input Name**. **Long Press Duration** and **Wait For Long Press Release** apply when **Input Type** is **Long Press**.

![A UIS Simple Input showing the Input Type and Input Name fields used by a handler.](https://opsive.com/wp-content/uploads/2021/02/Capture_SimpleInput.png?v=a49d205a32f1)

| Workflow | Component and field | Version 1 default |
| --- | --- | --- |
| Interact with a pickup or interactable | **Inventory Interactor > Input** | **Button Down**, `Action` |
| Open the Main Menu | **Display Panel Manager Handler > Open Toggle Panel Input** | Toggle **Main Menu** with `Open Panel` |
| Close the selected panel | **Display Panel Manager Handler > Close Panel Input** | **Button Down**, `Close Panel` |
| Move to the next or previous grid tab | A Grid Base-derived component's **Next Tab Input** and **Previous Tab Input** | `Next` and `Previous` |
| Use a numbered hotbar slot | **Item Hotbar Handler > Hotbar Input** | `Equip First Item` through `Equip Tenth Item`, mapped to indexes 0 through 9 |

Choose the Input Type for the intended interaction:

- **Button Down** triggers once when the button is pressed.
- **Button Down Continuous** remains active while the button is held.
- **Double Press**, **Long Press**, and **Tap** use the timing supplied by the Opsive player input.
- **Axis** triggers when the named raw axis has a nonzero value and records that value.
- **Automatic** triggers every check.
- **Manual** and **Custom** do not trigger through `SimpleInput.CheckInput`; use them when project code calls the relevant UIS API instead.

The same Input Name must exist in the chosen backend. For the legacy Input Manager this is an axis entry. For Unity's Input System it is an action in the current action map. For an integration it is the name understood by that integration's `IPlayerInput` implementation.

## Keep menu and gameplay input separate

Opening an inventory menu often needs to stop interactions, hotbar shortcuts, or equipped-item actions while leaving menu navigation and the close-panel input available. **Enable Disable Inventory Input** sends the Version 1 gameplay-input event to the Inventory identified by **Inventory ID**.

For a full-screen menu:

1. Add **Enable Disable Inventory Input** to an object that is enabled with the menu.
2. Set **Inventory ID** to the player's Inventory Identifier ID.
3. Set **On Component Enable** to **Disable**.
4. Set **On Component Disable** to **Enable**.
5. Confirm that the menu's EventSystem and Display Panel Manager Handler remain active so the player can navigate and close the menu.

Each listening component decides how to respond to `OnEnableGameplayInput`. The built-in Inventory Interactor, hotbar handlers, and equipped-item handlers disable their gameplay checks, while the menu can continue to use Unity UI navigation.

## Editor checkpoint

Before entering Play Mode, confirm that:

- the Inventory GameObject has exactly one active Opsive component that implements `IPlayerInput`;
- a Unity Input System setup also has Unity's **Player Input** on the same GameObject with **Actions** assigned;
- every handler Input Name exists in the legacy Input Manager, the current Input Action map, or the selected integration;
- the Display Panel Manager has the intended player as its **Panel Owner**, because panel and grid handlers resolve input from that owner;
- the EventSystem uses the input module that matches the chosen backend;
- **Open Toggle Panel Input** names an existing panel and has the intended **Toggle** value;
- the Simple Input types match one-shot, held, timed, or axis behavior; and
- an Enable Disable Inventory Input component uses the same ID as the player's Inventory Identifier.

## Verify in Play Mode

1. Approach an interactable and press `Action`. Confirm that the Inventory Interactor performs one interaction.
2. Press `Open Panel`. Confirm that the configured Main Menu opens and receives UI selection.
3. Navigate with keyboard or controller, submit a button, and move between grid tabs with `Next` and `Previous`.
4. Press `Close Panel`. Confirm that the selected panel closes even when gameplay input is disabled for the menu.
5. Use the first and second hotbar inputs. Confirm that each activates only its assigned slot.
6. Open a menu that enables **Enable Disable Inventory Input**. Confirm that interaction and hotbar input stop, then resume when the menu closes.
7. Repeat the workflow with every supported device. For Unity's Input System, also switch action maps as the game normally would and confirm the UIS action names exist in the active map.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| No UIS shortcut responds | Check the player for an active component that implements `IPlayerInput`. | Add the correct concrete Opsive input component beside the Inventory and remove competing implementations. |
| Unity Input System throws an error at startup | Check for Unity's **Player Input** on the same GameObject as **Unity Input System**. | Add it and assign an Input Action Asset before entering Play Mode. |
| An Input System action exists but never fires | Check which action map Unity's **Player Input** has activated and compare the action name with the UIS **Input Name**. | Add the action to the active map or update the handler name. |
| Pointer clicks work but keyboard or controller UI navigation does not | Check the EventSystem input module and its UI action assignments. | Use Standalone Input Module for the legacy Input Manager or Input System UI Input Module for Unity's Input System. |
| UI navigation works but `Open Panel` does not | Check the Display Panel Manager's **Panel Owner** and confirm that owner resolves the player's `IPlayerInput`. | Assign the correct owner and create the named backend action. |
| The wrong panel opens | Check **Panel Name** and **Toggle** in **Open Toggle Panel Input**. | Match the panel's exact configured name and choose Open or Toggle intentionally. |
| Input fires every frame or never repeats | Check **Input Type**. | Use **Button Down** for one press, **Button Down Continuous** for a held action, or the intended timed type. |
| Gameplay shortcuts still work over a full-screen menu | Check **Inventory ID**, **On Component Enable**, and whether the handler listens for the gameplay-input event. | Target the correct Inventory and disable custom handlers when that event is false. |
| Closing the menu does not restore gameplay input | Check **On Component Disable** on Enable Disable Inventory Input. | Set it to **Enable** and confirm that the component is actually disabled when the menu closes. |
| One local player controls another player's UI | Check that each player has its own Canvas, EventSystem, UI input module, player input, Inventory Identifier, and panel owner. | Follow the split-screen workflow and bind every UI root to its matching player. |

## Input workflows

- [Input Handlers](https://opsive.com/support/documentation/ultimate-inventory-system/input/handlers/) explains which UIS component turns each input into an interaction, panel, hotbar, item-action, or grid operation.
- [Split Screen Co-op UI](https://opsive.com/support/documentation/ultimate-inventory-system/input/split-screen-co-op-ui/) covers separate Canvases, EventSystems, player inputs, and panel owners for local multiplayer.

## Related pages

- [Input System integrations](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/input-system/)
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/)
- [User interface](https://opsive.com/support/documentation/ultimate-inventory-system/ui/)
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/)

## Developer reference

UIS handlers depend on `Opsive.Shared.Input.IPlayerInput`. Its Version 1 API includes `GetButton`, `GetButtonDown`, `GetButtonUp`, `GetDoublePress`, `GetTap`, `GetLongPress`, `GetAxis`, and `GetAxisRaw`, plus controller, cursor, mouse-position, look-vector, and pointer-over-UI queries. This allows a handler to keep the same code when the concrete input backend changes.

The gameplay-input event targets the player's Inventory GameObject. Use the UIS EventNames constant rather than duplicating its string:

```csharp
using Opsive.Shared.Events;
using Opsive.UltimateInventorySystem.Core;
using UnityEngine;

public static class InventoryInputUtility
{
    public static void SetGameplayInput(GameObject inventoryGameObject, bool enabled)
    {
        EventHandler.ExecuteEvent<bool>(
            inventoryGameObject,
            EventNames.c_CharacterGameObject_OnEnableGameplayInput_Bool,
            enabled);
    }
}
```

A custom backend should implement `IPlayerInput` on a Component attached to the player. UIS obtains that interface from the Inventory GameObject, a child in the hotbar case, or the Display Panel Manager's panel owner. Preserve those ownership relationships when adapting an existing project input service.

`Inventory Input`, `Inventory Standard Input`, and `Input Event` are legacy classes. The first two have been deprecated since Version 1.1.5, and Input Event is obsolete in the released source. Use an `IPlayerInput` implementation and current UIS handlers instead.

---

<a id="page-ultimate-inventory-system-input-handlers"></a>

# Handlers

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/input/handlers/)

Input handlers connect a named button, timed press, or axis to an Ultimate Inventory System action. Choose a handler by the outcome you want: interact with the world, open or close a menu, change a grid tab, use a hotbar slot, run an Item Action, or use an equipped Item Object.

The handler does not define the keyboard key or controller button. Its **Input Name** is resolved by the player's `IPlayerInput` implementation. Set up the backend first with the [Input workflow](https://opsive.com/support/documentation/ultimate-inventory-system/input/).

## Choose the handler by outcome

| Outcome | Component | Where it gets player input | Gameplay-input gated |
| --- | --- | --- | --- |
| Open, toggle, or close a named panel | **Display Panel Manager Handler** | Display Panel Manager's **Panel Owner** | No |
| Close one popup from its background or close input | **Display Panel Closer** | That panel's manager and **Panel Owner** | No |
| Pick up an Item or interact with a chest, Shop, or crafting station | **Inventory Interactor** | The GameObject containing its Inventory | Yes |
| Use an Item Hotbar slot | **Item Hotbar Handler** | The bound Inventory or its children | Yes |
| Trigger an Item Action for a numbered slot in a generic container | **Item View Slot Container Indexed Actions Handler** | The bound Inventory | Yes |
| Trigger the default, indexed, or named Item Action on the selected slot | **Item View Slot Container Item Action Handler** or **Named Item Action Handler** | The bound Item User | No; it can require the panel to be selected |
| Use an equipped Item Object action | **Usable Equipped Items Handler** | Its Item User | Yes |
| Move to the next or previous grid tab | A Grid Base-derived component | The panel manager's **Panel Owner** | No |
| Gate gameplay handlers from another component's lifecycle | **Enable Disable Inventory Input** | The Inventory found by **Inventory ID** | Sends the gate event |

“Gameplay-input gated” means the built-in handler listens for `EventNames.c_CharacterGameObject_OnEnableGameplayInput_Bool` and enables or disables itself. Menu handlers remain available so the player can navigate and close the UI.

## Open and close panels

Use **Display Panel Manager Handler** for a menu-wide shortcut such as toggling the Main Menu.

1. Add the handler beside the **Display Panel Manager** or assign **Display Panel Manager** explicitly.
2. Confirm that the manager's **Panel Owner** is the player GameObject with the Inventory and `IPlayerInput` implementation.
3. In **Close Panel Input**, keep **Input Type** at **Button Down** and set **Input Name** to `Close Panel` for the Version 1 default.
4. In **Open Toggle Panel Input**, add one entry for each shortcut.
5. Enable **Toggle** when a second press should close the panel, set **Panel Name** to the panel's **Unique Name**, and assign the Input Name. The default entry toggles `Main Menu` with `Open Panel`.
6. Use **Disable Cursor While Gameplay** and **Enable Cursor With Close** only when this handler should also own those cursor transitions.

The handler calls `OpenPanel`, `TogglePanel`, or `CloseSelectedPanel` on the assigned manager. It does not contain Shop- or crafting-specific logic; once a Shop Menu or Crafting Menu is selected, Unity UI navigation and button callbacks operate that menu.

For a modal popup, **Display Panel Closer** can close only its assigned **Display Panel**:

1. Assign **Display Panel** or place the closer beside the panel so it resolves automatically.
2. Keep **Close On Click** enabled when clicking the raycast background should close the popup.
3. Enable **Close On Input** to use **Close Input**. Its default is **Button Down** with `Close Panel`.

**Close On Input** is disabled by default. A visible Simple Input does not run until that option is enabled.

## Interact with Items, chests, Shops, and crafting stations

Use one **Inventory Interactor** on the player to drive several kinds of world interaction.

1. Add it beside the player's Inventory and concrete `IPlayerInput` component.
2. Assign **Inventory**, or leave it empty to use the Inventory on the same GameObject.
3. Set **Input** to **Button Down** with `Action`, the Version 1 default.
4. Assign **Interactable Indicator** when the player needs a visible prompt.
5. Leave **Auto Interact** disabled when the player must press the input. Enable it only when entering range should immediately interact.
6. On the world object, add **Interactable** with a trigger Collider. Set **Interactor Layer Mask** to include the player and enable the appropriate **2D** or **3D** trigger path.
7. Add the behavior that should receive the player's Inventory.

Choose the world behavior by scenario:

- An Item, Currency, or Inventory pickup adds its configured contents to the interactor's Inventory.
- A chest uses **Chest Interactable** to open its chest for that Inventory.
- A Shop or crafting station uses **Menu Interactable Behavior** with **Shop Menu Opener** or **Crafting Menu Opener**. Assign **Shop** or **Crafter** on the opener. **Use Player ID As Panel Manager ID** lets the same station choose the correct player's menu in a multiplayer setup.

The Inventory Interactor tracks available Interactables and calls the selected one's interaction behavior. The Shop Menu Opener then binds the player's Inventory and Shop; the Crafting Menu Opener binds the player's Inventory and Crafter. Their purchase, sale, and craft controls are normal menu interactions rather than separate input handlers.

## Trigger hotbar and Item Actions

### Use an Item Hotbar slot

Add **Item Hotbar Handler** beside an **Item Hotbar**.

- Assign **Item Hotbar**, or leave it empty to resolve the component on the same GameObject.
- In **Hotbar Input**, keep only the slots the project uses.
- Each entry contains **Index**, **Input Type**, and **Input Name**. The Version 1 defaults map indexes 0 through 9 to `Equip First Item` through `Equip Tenth Item` with **Button Down**.

When an input triggers, the handler calls `ItemHotbar.UseItem(index)`, which forwards to the hotbar's Item Action binding.

Use **Item View Slot Container Indexed Actions Handler** when the visual container is not an Item Hotbar but each numbered key should still trigger the Item Action bound to that slot. Assign **Item View Slots Container**, **Item Actions Binding**, and the **Input** entries. This handler resolves input from the bound Inventory and follows gameplay-input gating.

### Use an action on the selected slot

Use **Item View Slot Container Item Action Handler** when the player first selects an Item View Slot and then presses a shortcut.

1. Assign **Item Action Binding**, or place the handler beside the binding so it resolves automatically.
2. Set **Default Input** to trigger the binding's default action.
3. Add **Action Inputs** entries when a button must run a specific Item Action index.
4. Enable **Handle Input Only If Panel Selected** so an inactive inventory, Shop, or crafting panel cannot consume the same shortcut.
5. Keep **Use Item Action Binding Item User Player Input** enabled to use the Item User already assigned to the binding.

Use **Item View Slot Container Named Item Action Handler** when action names are more stable than their array positions. Its **Action Inputs** entries pair a **Name** with a Simple Input and call the matching named Item Action on the selected slot.

Shop and Crafting Menu buttons do not need these handlers. Add one only when a selected Item should expose project-specific Item Actions inside that menu. Confirm the menu supports Item Actions before adding shortcuts; for example, a specialized chest workflow can use other click behavior instead.

### Use an equipped Item Object

Use **Usable Equipped Items Handler** with the default UIS equipping system when an input should operate an already equipped Item Object.

1. Place it beside the Equipper and **Item User**.
2. Assign **Item User** or leave it empty to resolve the local component.
3. Add **Inputs** entries.
4. For each entry, choose **Input Type** and **Input Name**, then set **Item Object Index** and **Action Index**.

The handler gets the equipped Item Object at that index, finds its `IItemObjectBehaviourHandler`, and asks it to use the selected action through the Item User. It follows gameplay-input gating.

## Change grid tabs

Grid Base-derived components already check input; no separate handler is required. Set **Next Tab Input** and **Previous Tab Input** on the grid. Their Version 1 defaults are `Next` and `Previous`.

The grid resolves `IPlayerInput` from its parent panel manager's **Panel Owner**. If pointer selection works but tab shortcuts do not, inspect the panel owner before changing the grid.

## Gate gameplay handlers while a menu is open

The **Display Panel Manager** can send the gameplay-input event automatically:

1. Assign **Gameplay Panel** and the player's GameObject as **Panel Owner**.
2. Enable **Enable Input On Gameplay Selected**.
3. Open a menu and confirm that the selected panel changes away from Gameplay Panel.

With this option enabled, the manager sends `false` to the panel owner when selection leaves Gameplay Panel and `true` when selection returns. Inventory Interactor, Item Hotbar Handler, Item View Slot Container Indexed Actions Handler, and Usable Equipped Items Handler respond by disabling or enabling themselves.

Display Panel Manager Handler, Display Panel Closer, Grid Base, and selected-slot Item Action handlers do not automatically disable through this event. This is intentional for menu input. Enable **Handle Input Only If Panel Selected** on selected-slot action handlers when their shortcuts should work only in their own panel.

Custom gameplay handlers should register for the same event or be enabled and disabled by the project menu state. Avoid disabling the EventSystem or every player-input query, because the open menu still needs navigation and a close action.

For an overlay or state that is not controlled by Display Panel Manager, add **Enable Disable Inventory Input** to the GameObject whose enabled state should control gameplay shortcuts:

1. Set **Inventory ID** to the player's Inventory Identifier ID. Its Version 1 default is `1`.
2. Set **On Component Enable** to **Disable** when enabling this component should pause gameplay handlers.
3. Set **On Component Disable** to **Enable** so those handlers resume when the component turns off.

Both lifecycle choices default to **None**. The component finds the Inventory by ID and sends the same gameplay-input event on that Inventory GameObject; it does not disable panel navigation.

## Editor checkpoint

Before entering Play Mode, confirm that:

- the player has an Inventory and exactly one concrete `IPlayerInput` implementation;
- Display Panel Manager **Panel Owner** points to that player;
- every handler Input Name exists in the selected input backend;
- every **Panel Name** matches a Display Panel **Unique Name**;
- **Close On Input** is enabled on any Display Panel Closer expected to read its Close Input;
- Inventory Interactor references the intended Inventory and the Interactable layer mask includes the player;
- Shop Menu Opener has **Shop**, Crafting Menu Opener has **Crafter**, and each Menu Interactable Behavior has the intended **Menu Opener**;
- hotbar indexes are within the container's slot count and their Item Action binding is assigned;
- selected-slot Action Inputs point to valid Item Action indexes or names;
- **Handle Input Only If Panel Selected** is enabled where panels reuse shortcuts;
- **Enable Input On Gameplay Selected** is enabled only when the manager should gate gameplay handlers; and
- every **Enable Disable Inventory Input** uses the intended **Inventory ID** and complementary enable/disable choices.

## Verify in Play Mode

1. Approach an Item pickup and press `Action`. Confirm that it is selected, interacts once, and adds its contents to the player's Inventory.
2. Approach a Shop and a crafting station. Confirm that the same Action input opens each intended menu with the correct player Inventory bound.
3. Press `Open Panel`, navigate the menu, change a grid tab with `Next` or `Previous`, and close it with `Close Panel`.
4. Open and close a popup by its background, then repeat with Close Input when that option is enabled.
5. Use two hotbar shortcuts. Confirm that each triggers only its assigned slot and Item Action.
6. Select an Item View Slot and test its default, indexed, or named action shortcut. Confirm that the same shortcut does nothing while another panel is selected when panel-only handling is enabled.
7. Test one equipped Item Object input and confirm that its configured action index runs.
8. Leave Gameplay Panel for a menu. Confirm that the Inventory Interactor, hotbar, indexed-slot handler, and equipped-item handler stop, while panel close and grid navigation continue.
9. Return to Gameplay Panel and confirm that every gated handler resumes once without a duplicate response.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| Every handler is silent | Check the player or panel owner for a concrete `IPlayerInput` implementation. | Complete the parent Input setup and ensure handlers resolve the same player. |
| A panel shortcut does nothing | Check **Display Panel Manager**, **Panel Owner**, Input Name, and **Panel Name**. | Assign the correct manager and match an existing Display Panel **Unique Name**. |
| A popup closes by click but not by input | Check **Close On Input**. | Enable it and configure **Close Input**. |
| The Inventory Interactor never selects the object | Check the trigger Collider, **Interactor Layer Mask**, **2D** or **3D**, and the player's Collider. | Correct the physics setup before debugging the Action input. |
| `Action` selects an object but nothing happens | Check for the required pickup, Chest Interactable, or Menu Interactable Behavior and opener. | Add and configure the behavior that performs the interaction. |
| A Shop or crafting menu opens for the wrong player | Check **Use Player ID As Panel Manager ID**, Inventory Identifier IDs, and panel manager IDs. | Give each player and panel manager a matching unique ID. |
| A hotbar shortcut throws or remains disabled | Check that the bound Inventory has an `IPlayerInput` component and that the Item Hotbar and binding are assigned. | Bind the player Inventory before enabling the handler and remove out-of-range entries. |
| A selected-slot shortcut fires in another menu | Check **Handle Input Only If Panel Selected**. | Enable it and ensure the Item View Slots Container belongs to the intended Display Panel. |
| An indexed Item Action runs the wrong behavior | Check whether the Item Action Set order changed. | Update the action index or use the Named Item Action Handler when names are the stable contract. |
| Equipped-item input does nothing | Check **Item User**, the Equipper, Item Object Index, Action Index, and the equipped object's behavior handler. | Assign the matching components and a valid equipped object/action pair. |
| Gameplay shortcuts still run over menus | Check **Enable Input On Gameplay Selected**, **Gameplay Panel**, and **Panel Owner**. | Enable gating and make the player GameObject the target. Gate custom handlers separately. |
| Menu shortcuts stop with gameplay input | Check whether a custom system disables the whole EventSystem or input backend. | Gate gameplay handlers rather than the menu's navigation and close path. |

## Related pages

- [Input setup and backend choices](https://opsive.com/support/documentation/ultimate-inventory-system/input/)
- [Split Screen Co-op UI](https://opsive.com/support/documentation/ultimate-inventory-system/input/split-screen-co-op-ui/)
- [Interaction system](https://opsive.com/support/documentation/ultimate-inventory-system/interaction-system/)
- [Item pickups](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-pickups/)
- [Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/)
- [Display Panel Manager](https://opsive.com/support/documentation/ultimate-inventory-system/ui/display-panel-manager/)
- [Item Hotbar](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-hotbar/)
- [Shop Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/shop-menu/)
- [Crafting Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/crafting-menu/)
- [Chest Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/chest-menu/)
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/)

## Developer reference

The handlers call public UIS APIs, so project code can perform the same action without simulating a key press:

```csharp
inventoryInteractor.Interact();
displayPanelManager.TogglePanel("Main Menu");
displayPanelManager.CloseSelectedPanel();
itemHotbar.UseItem(0);
itemActionBinding.TriggerItemAction();
itemActionBinding.UseItemActionOnSelectedSlot("Equip");
usableEquippedItemsHandler.UseItem(itemObjectIndex: 0, itemActionIndex: 0);
```

`InventoryInteractor.Interact()` acts on its current selected Interactable. `DisplayPanelManager` also provides `OpenPanel`, `TogglePanel`, `OpenMainMenu`, `CloseMainMenu`, and `ToggleMainMenu` overloads. Item Action bindings can trigger the default action or a specific action by index or name.

To gate a custom gameplay handler with the same route as the built-in components, keep the event listener active and let it toggle a separate gameplay behavior. Register on the GameObject that owns the Inventory and match the Version 1 event signature:

```csharp
using Opsive.Shared.Events;
using Opsive.UltimateInventorySystem.Core;
using UnityEngine;

public class CustomGameplayInputGate : MonoBehaviour
{
    [SerializeField] private GameObject m_InventoryGameObject;
    [SerializeField] private Behaviour m_GameplayHandler;

    private void OnEnable()
    {
        EventHandler.RegisterEvent<bool>(
            m_InventoryGameObject,
            EventNames.c_CharacterGameObject_OnEnableGameplayInput_Bool,
            OnEnableGameplayInput);
    }

    private void OnDisable()
    {
        EventHandler.UnregisterEvent<bool>(
            m_InventoryGameObject,
            EventNames.c_CharacterGameObject_OnEnableGameplayInput_Bool,
            OnEnableGameplayInput);
    }

    private void OnEnableGameplayInput(bool enable)
    {
        if (m_GameplayHandler != null) {
            m_GameplayHandler.enabled = enable;
        }
    }
}
```

Interactables also publish `c_Interactable_OnSelect_IInteractor`, `c_Interactable_OnDeselect_IInteractor`, and `c_Interactable_OnInteract_IInteractor`. Display Panel Manager publishes panel open/close, new-selection, and gameplay-panel-selection events. Use those notifications for UI feedback or coordination; use the public handler APIs when code should initiate the action.

---

<a id="page-ultimate-inventory-system-input-split-screen-co-op-ui"></a>

# Split Screen Co-op UI

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/input/split-screen-co-op-ui/)

Split-screen UI works when every local player owns a complete route from input to Inventory to Canvas. Give each player a unique Inventory Identifier, Display Panel Manager, UI root, and EventSystem. The players can still use the same Shop or Crafter because UIS can route an interaction to the correct player's menu.

![Two local players with independent Inventory panels open side by side, each showing its own equipment, Items, and character preview.](https://opsive.com/wp-content/uploads/2021/02/SplitScreenUI_1.png?v=bb2f79d9f927)

![Player one remains in gameplay while player two uses the Crafting menu in the right half of the split-screen view.](https://opsive.com/wp-content/uploads/2021/02/SplitScreenUI_2.png?v=83a7f3400bea)

## Choose the ownership model

Use one UIS ID per player and carry it through the Inventory and UI setup.

| Player-owned part | Player one | Player two | Version 1 behavior |
| --- | --- | --- | --- |
| **Inventory Identifier > ID** | `1` | `2` | The default is `1`. The value cannot be `0` and must be unique. |
| **Display Panel Manager > ID** | `1` | `2` | The default is `1`. Menu openers can find the correct manager with this ID. |
| **Panel Owner Inventory Identifier ID** | `1` | `2` | The default is `1`. It is used only when **Panel Owner** is not assigned directly. |
| **Dynamic Panel Owner > Display Panel Manager ID** | `1` | `2` | Optional for a player spawned after its UI. The default is `1`. |
| **Event System Identifier > ID** | `1` | `2` | The serialized default is `0`. In Version 1, runtime selection uses the assigned **Event System** reference; matching the ID remains a useful scene convention. |
| Input player or device ID | Backend-specific | Backend-specific | Unity Player Input and Rewired use their own indexes or device pairing. These do not have to equal the UIS IDs. |

The simplest convention is `1` for every UIS field belonging to player one and `2` for every UIS field belonging to player two. Do not reuse an Inventory Identifier ID. The Version 1 register can assign a different ID to a duplicate, which breaks the intended UI mapping.

## Before you begin

- Configure each gameplay camera's viewport independently. UIS controls the inventory UI, not the split-screen camera layout.
- Finish one player's Inventory, panel, input, and EventSystem workflow before duplicating it.
- Use Unity's Input System or the matching Rewired integration when players need independent devices. The legacy Unity Input Manager exposes global named axes and is not a reliable ownership boundary for local multiplayer.
- Keep one shared Inventory System Manager and database. Players can share Item Definitions such as Health Potion and Iron Sword while owning different runtime Items, collections, and Gold balances.
- Decide whether one save slot should contain both players or whether the project needs separate player profiles. UIS saves all registered savers through one Save System Manager by default.

## Create the second player and UI

1. Duplicate the working player and its Inventory Canvas. Give the player roots clear names such as `Player 1` and `Player 2`.
2. Constrain the top-level UI panel in each Canvas to its half of the screen with Rect Transform anchors and zero offsets. Avoid scaling the whole Canvas to `0.5`, which also shrinks text and controls.
3. Set **Inventory Identifier > ID** to `1` and `2` on the two players.
4. Set each Canvas's **Display Panel Manager > ID** to the matching value.
5. Assign the matching player GameObject to **Panel Owner**. If the UI must discover a player instead, leave **Panel Owner** empty and set **Panel Owner Inventory Identifier ID** to the matching ID.
6. Assign a separate **Gameplay Panel** and **Main Menu Panel** under each Canvas. Keep each Display Panel Manager Handler bound to the manager in its own Canvas.
7. Leave **Set Time Scale To Zero When Menu Is Opened** disabled on both managers when one player must continue moving while the other uses a menu. The Version 1 default is disabled.
8. Enable **Enable Input On Gameplay Selected** when opening a menu should pause only that player's interaction, hotbar, and equipped-item handlers. Assign **Gameplay Panel** and **Panel Owner** first so the event targets the correct player. This option is disabled by default.

For players spawned after the UI, add **Dynamic Panel Owner** to each player and set **Display Panel Manager ID** to its matching manager. The component assigns its GameObject as the panel owner during `Awake`, so the Display Panel Manager must already be registered. If the players load before the UI, let each manager find its player through **Panel Owner Inventory Identifier ID** instead.

![Inventory Identifier and Dynamic Panel Owner components both configured with ID 1 for player one.](https://opsive.com/wp-content/uploads/2021/02/InventoryIdentifierAndDynamicPanelOwner.png?v=d9f2f8be0459)

![Player-one Canvas components showing Display Panel Manager ID 1, Panel Owner Player Character 1, gameplay-input gating, and Event System Identifier linked to EventSystem 1.](https://opsive.com/wp-content/uploads/2021/02/MultiplayerInventoryCanvasInspector.png?v=4167e7ffde2c)

## Configure input and EventSystems

Create one EventSystem and matching UI input module for each player. Add **Event System Identifier** to the root GameObject that contains that player's UI selectables, then assign that player's EventSystem in **Event System**.

UIS selection calls inspect the selectable's transform root for this identifier. If the component or reference is missing, Version 1 falls back to `EventSystem.current`, which can make both Canvases use whichever EventSystem is current. UIS creates its Event System Manager automatically when it is first needed; a separate manager component is not required in the scene.

### Unity Input System

1. Add the Opsive **Unity Input System** component and Unity's **Player Input** component to each player beside its Inventory.
2. Assign **Actions** on both Player Input components. The Opsive Shared package includes `CharacterInput.inputactions`; both players can reference the same asset while Unity pairs each Player Input instance with its devices.
3. Create `EventSystem 1` and `EventSystem 2`. Add **Multiplayer Event System** and **Input System UI Input Module** to each.
4. Set each Multiplayer Event System's **Player Root** to its player's UI root.
5. Assign the UI actions on each Input System UI Input Module, then assign that module to the matching Player Input's **UI Input Module** field.
6. Pair a different gamepad or device set with each Player Input. When the scene always uses gamepads, set **Default Control Scheme** to the project's Gamepad scheme.
7. On each UI root, assign its own EventSystem to **Event System Identifier > Event System**.

A keyboard and mouse are shared devices. The released Opsive Unity Input System component deliberately makes them available to each Player Input when present, so use separate gamepads for independent ownership instead of expecting one keyboard to identify two players.

![Multiplayer Event System with Player Root set to Inventory System Canvas 1 and Input System UI Input Module using the CharacterInput action asset.](https://opsive.com/wp-content/uploads/2021/02/InputSystemEventSystem.png?v=0a7972529ea1)

### Rewired

1. Install the Rewired asset and the matching Opsive integration for this UIS release.
2. Replace the player's concrete Opsive input component with **Rewired Input** and assign a unique Rewired player ID. Rewired commonly uses `0` for player one and `1` for player two; these values are separate from the UIS IDs.
3. Use the co-op input manager or equivalent setup supplied by the integration so both Rewired players exist before the UI reads input.
4. Add **Rewired Event System** and **Rewired Standalone Input Module** to each player's EventSystem GameObject.
5. Enable **Always Update** on both Rewired Event Systems.
6. Under **Rewired Player Ids**, keep only the matching **Player Id** for that EventSystem.
7. Assign each Rewired EventSystem through the **Event System Identifier** on its player's UI root.

![Rewired Event System with Always Update enabled and Rewired Standalone Input Module assigned to player ID 0.](https://opsive.com/wp-content/uploads/2021/02/RewiredEventSystem.png?v=ffa03580ecef)

## Route shared Shops and crafting stations

A Shop or Crafter can be shared, but each player still needs a separate Shop Menu or Crafting Menu under their own Display Panel Manager.

1. On the shared world object, use **Menu Interactable Behavior** with the appropriate **Shop Menu Opener** or **Crafting Menu Opener**.
2. Keep **Use Player ID As Panel Manager ID** enabled. It is enabled by default in Version 1.
3. Confirm that each player's Inventory Identifier ID matches that player's Display Panel Manager ID.
4. Give both managers a panel with the same expected menu name, but keep the actual panel and menu instances under their own Canvases.
5. Assign the shared **Shop** or **Crafter** on the opener.

When a player interacts, Menu Interactable Behavior reads that player's Inventory Identifier ID, changes the opener to the matching Display Panel Manager, and passes that player's Inventory to the menu. The Shop Menu or Crafting Menu then binds the shared Shop or Crafter to that player's separate UI instance. If **Use Player ID As Panel Manager ID** is disabled, the opener uses its fixed manager and can send both players to one Canvas.

## Keep runtime behavior independent

`Time.timeScale` is global. If either Display Panel Manager enables **Set Time Scale To Zero When Menu Is Opened**, opening one menu pauses scaled gameplay for both players. Leave it disabled on every player-owned manager for simultaneous play.

Gameplay-input gating is local because Display Panel Manager sends its events to **Panel Owner**. With **Enable Input On Gameplay Selected** enabled, leaving player one's Gameplay Panel disables the built-in gameplay handlers on player one while player two continues. Panel navigation and close input remain available so the first player can leave the menu.

**Close Menu When Opening Another** also applies within one Display Panel Manager. It does not close a menu selected by another player's manager.

## Save both players safely

Add an **Inventory Saver** to each player Inventory and a **Currency Owner Saver** when Gold must also persist. Other player-specific state needs its own appropriate Saver. **Additive** is disabled by default on both components; keep it disabled when loading should replace the saved Inventory or balance rather than merge it into the current state.

Inventory Identifier IDs do not isolate save records. `SaverBase` builds its **Full Key** from the Saver GameObject name, Saver type, and **Key**. **Key** is empty by default. Give duplicated players distinct GameObject names, distinct Key values, or both. If two Savers produce the same Full Key, the second Saver is not registered and its state is not stored independently.

Save System Manager is global. Calling save slot `0` from either player's Save Menu saves every registered player Saver into the same slot. That is suitable for one shared co-op campaign. Separate player profiles require project-specific control over which Savers and save indexes belong to each profile.

## Editor checkpoint

Before entering Play Mode, confirm that:

- Inventory Identifier IDs are nonzero, unique, and match the intended Display Panel Manager IDs;
- every Canvas has its own Display Panel Manager, panels, and Display Panel Manager Handler;
- **Panel Owner** points to the correct player, or **Panel Owner Inventory Identifier ID** can resolve that player at initialization;
- each player has exactly one concrete Opsive `IPlayerInput` implementation;
- Unity Input System players each have Player Input, Actions, a paired device, and their own UI Input Module;
- each Multiplayer Event System **Player Root** contains only that player's UI;
- each UI root has Event System Identifier referencing its own EventSystem;
- Rewired EventSystems have **Always Update** enabled and only the intended Rewired **Player Id**;
- **Set Time Scale To Zero When Menu Is Opened** is disabled on all player-owned managers for simultaneous play;
- **Enable Input On Gameplay Selected** and **Gameplay Panel** are configured per player when gameplay shortcuts should pause behind menus;
- shared Menu Interactable Behaviors keep **Use Player ID As Panel Manager ID** enabled; and
- duplicated Inventory and Currency Owner Savers produce different Full Keys.

## Verify in Play Mode

1. Move player one and player two separately. Confirm that each device affects only its assigned player.
2. Open both Main Menus at the same time. Confirm that each Canvas shows its own Inventory, Gold, selection, and Item details.
3. Move the selection in both menus. Confirm that each EventSystem highlights controls only inside its own Player Root.
4. Close player one's menu. Confirm that player two's menu remains open.
5. Leave player one in gameplay while player two opens a Shop or Crafting Menu. Confirm that player one keeps moving and player two's gameplay handlers pause.
6. Let both players interact with the same Shop or Crafter. Confirm that each interaction opens the menu on the correct side and binds the correct player Inventory.
7. Give player one a Health Potion and player two an Iron Sword, save, change both Inventories, and load. Confirm that each Item returns to its original owner.
8. Repeat after reloading the scene or spawning players in the project's real order. Confirm that the panel owners and EventSystems resolve without manual reassignment.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| Player two opens player one's menu | Compare Inventory Identifier **ID**, Display Panel Manager **ID**, and **Panel Owner**. | Use a unique matching UIS ID per player and assign the correct owner. |
| A Canvas disables itself at startup | Check whether **Panel Owner** is empty and **Panel Owner Inventory Identifier ID** can already resolve a registered player. | Assign the owner directly, correct the ID, or change the spawn order. |
| Both Canvases highlight the same control | Check Event System Identifier on each UI root and its **Event System** reference. | Point each root to its own EventSystem instead of falling back to `EventSystem.current`. |
| Unity Input System moves the wrong UI | Check **Player Root**, Player Input **UI Input Module**, action assignments, and paired devices. | Bind each Player Input to its own module and device, and keep its Player Root inside the matching Canvas. |
| Rewired navigation is silent | Check **Always Update** and **Rewired Player Ids > Player Id**. | Enable Always Update and assign only the intended Rewired player. |
| One player opening a menu pauses both players | Check **Set Time Scale To Zero When Menu Is Opened** on every Display Panel Manager. | Disable it for split-screen menus; use player-targeted input gating instead. |
| A player moves or uses the hotbar behind a menu | Check **Gameplay Panel**, **Panel Owner**, and **Enable Input On Gameplay Selected**. | Configure them on that player's Display Panel Manager and gate custom gameplay handlers separately. |
| A shared Shop or Crafter opens on the wrong side | Check **Use Player ID As Panel Manager ID** and matching Inventory/manager IDs. | Enable the option and give each manager its own menu instance with the expected name. |
| Both UIs show the same Inventory | Check menu, monitor, and Item View Slot Container bindings for copied direct references. | Bind each Canvas to its own panel owner or matching Inventory Identifier ID. |
| One player's saved Inventory replaces the other's | Compare the duplicated Saver **Full Key** inputs: GameObject name, type, and **Key**. | Give the player GameObjects or Saver Keys unique values, then create a fresh test save. |
| Saving from either UI unexpectedly affects both players | Check whether both menus call the global Save System Manager and the same save index. | Keep this for a shared campaign or implement explicit per-profile Saver/index ownership. |

## Related pages

- [Input setup and backend choices](https://opsive.com/support/documentation/ultimate-inventory-system/input/)
- [Input Handlers](https://opsive.com/support/documentation/ultimate-inventory-system/input/handlers/)
- [Spawned players and UI ownership](https://opsive.com/support/documentation/ultimate-inventory-system/spawn-player/)
- [Interaction system](https://opsive.com/support/documentation/ultimate-inventory-system/interaction-system/)
- [Display Panel Manager](https://opsive.com/support/documentation/ultimate-inventory-system/ui/display-panel-manager/)
- [Shop Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/shop-menu/)
- [Crafting Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/crafting-menu/)
- [Save system](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/)

## Developer reference

Version 1 exposes the ownership lookups used by the editor workflow:

```csharp
using Opsive.UltimateInventorySystem.Core;
using Opsive.UltimateInventorySystem.Input;
using UnityEngine;

public static class LocalPlayerUI
{
    public static void AssignPanelOwner(uint playerID, GameObject firstSelectable)
    {
        var inventoryIdentifier = InventorySystemManager.GetInventoryIdentifier(playerID);
        var panelManager = InventorySystemManager.GetDisplayPanelManager(playerID);

        if (inventoryIdentifier == null || panelManager == null) {
            return;
        }

        panelManager.SetPanelOwner(inventoryIdentifier.gameObject);
        EventSystemManager.Select(firstSelectable);
    }
}
```

`EventSystemManager.Select` finds the Event System Identifier on the selectable's transform root and selects through its assigned EventSystem. `InventorySystemManager.GetInventoryIdentifier(uint)` and `GetDisplayPanelManager(uint)` use the UIS IDs; they do not use the Unity Player Input or Rewired player index.

Display Panel Manager targets panel open/close, selected-panel, gameplay-panel, and gameplay-input events to its **Panel Owner**. The Version 1 constants include `c_GameObject_OnPanelOpenClose_PanelEventData`, `c_GameObject_OnNewPanelSelected_PanelEventData`, `c_GameObject_OnGameplayPanelSelected_Bool`, and `c_CharacterGameObject_OnEnableGameplayInput_Bool`. Keeping a different owner per manager also separates these event routes.

Menu Interactable Behavior calls `ChangePanelManagerIndex` with the interacting Inventory Identifier ID before opening a shared Shop or Crafter menu. Save System Manager's `Save(int)` and `Load(int)` operate on the global registered Saver set; use unique Saver Full Keys even when project code initiates saving directly.

---

<a id="page-ultimate-inventory-system-audio"></a>

# Audio

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/audio/)

Use UIS audio feedback to confirm a button press, make keyboard or gamepad selection easier to follow, or distinguish inventory outcomes such as a successful pickup from a failed one. UIS uses the shared Opsive Audio Manager; the UIS-specific **Button Audio Handler** connects that system to a Unity Button, an Action Button, or an Item View Slot without custom code.

## Before you begin

Confirm that the scene contains an **Audio Manager**. The standard UIS setup creates it for you:

1. Open **Tools > Opsive > Ultimate Inventory System > Main Manager**.
2. Open **Setup**.
3. Under **Scene Setup**, select **Add Components** if the scene has not already been configured.
4. In the Hierarchy, confirm that the **Game** GameObject has an **Audio Manager** component with its default 2D Audio Manager Module.

Choose short clips that are easy to distinguish. A subtle select sound works well while moving between Bag slots; use a firmer click sound when the player submits an action such as using Health Potion.

## Create a Button Audio asset

1. In the Project window, right-click the project-owned folder where you keep UI configuration assets.
2. Select **Create > Ultimate Inventory System > UI > Button Audio**.
3. Name the asset for its role, such as `InventoryButtonAudio`.
4. Assign **Click Clip** and, for Action Buttons, **Select Clip**.
5. Leave **Click Config** and **Select Config** empty to use the Audio Manager's default configuration, or assign purpose-built 2D Audio Config assets when these sounds need different mixer, volume, pitch, delay, or source behavior.

![The Button Audio asset Inspector with Click Clip, Click Config, Select Clip, and Select Config fields.](https://opsive.com/wp-content/uploads/2021/10/Unity_I3zbvN8Qg8.webp?v=d40077cd0c9d)

Choose the fields by interaction:

| Interaction | Button Audio field | When it plays |
| --- | --- | --- |
| Press a Unity Button | **Click Clip** and **Click Config** | The Button invokes its click event. |
| Submit an Action Button or Item View Slot | **Click Clip** and **Click Config** | The selected control is submitted by pointer, keyboard, or gamepad. |
| Select an Action Button or Item View Slot | **Select Clip** and **Select Config** | The control becomes selected. A standard Unity Button does not use this sound through Button Audio Handler. |

The clip field is the simplest place for one sound. An Audio Config is optional: when a direct clip is assigned, the config controls how that clip plays; when the direct clip is empty, the config can supply its own clip selection. See [Audio Config and Audio Manager behavior](https://opsive.com/support/documentation/ultimate-character-controller/audio/) for the shared playback settings.

## Add audio to a control

1. Select the GameObject that contains the **Button**, **Action Button**, or **Item View Slot** component.
2. Add **Button Audio Handler** to that same GameObject.
3. Assign the Button Audio asset to **Button Audio**.
4. Leave **Button** and **Action Button** empty if the relevant component is on the same GameObject; the handler finds those references when the scene starts. Assign them explicitly when you want the Inspector to show the intended control.
5. Apply the change to the project-owned prefab if the control is spawned at runtime.

![An Item View Slot Inspector with Button Audio Handler assigned to a Button Audio asset and the Item View Slot referenced as the Action Button.](https://opsive.com/wp-content/uploads/2021/10/Unity_vrM5cvbXNR.webp?v=1678c14bbd37)

Use one Button Audio asset across controls that should sound consistent. Create a separate asset for an interaction that needs a distinct cue, such as confirming a purchase or deleting an item. Leave **Select Clip** empty when selection changes frequently and the extra feedback would be distracting.

## Use audio in other inventory interactions

Button Audio Handler is for UI controls. Version 1 also exposes audio at other useful points:

- Pickup components can use separate clips and Audio Configs for successful, failed, and partial pickups. This makes a full Bag sound different from a successful Health Potion pickup.
- The built-in **Play Audio** Item Action uses an Audio Clip Set. Add it to an Item Action Set when invoking an item should produce a sound as part of that action.
- An Item View Drop Action can play an Audio Clip Set after a drag-and-drop operation. Use it when moving Iron Sword between Bag and Equipment needs confirmation separate from the slot click.

These systems still use the shared Audio Manager, so the same mixer and Audio Config choices can keep UI, item, and pickup feedback consistent.

## Verify in Play Mode

1. Enter Play Mode and open the inventory UI.
2. Move selection between two Item View Slots with the pointer or navigation input. Confirm that **Select Clip** plays once when each Action Button becomes selected.
3. Submit the selected slot or another configured Action Button. Confirm that **Click Clip** plays.
4. Press a configured standard Unity Button. Confirm that the click sound plays and that no select sound is expected from Button Audio Handler.
5. Repeat the interaction quickly and confirm that the volume, mixer output, and overlap behavior match the assigned Audio Config or the default 2D configuration.

## Troubleshooting

- **No sound plays and the Console reports that the audio asset is missing:** Check **Button Audio** on Button Audio Handler and assign the asset before entering Play Mode.
- **No sound plays and there is no warning:** Check that Button Audio Handler is on the same GameObject as the Button or Action Button, or assign the correct reference explicitly. Also confirm that the clip or its Audio Config contains audio and that the scene has an active Audio Listener.
- **Click works but select does not:** Check the control type. Button Audio Handler only connects selection audio to an **Action Button**; a standard Unity **Button** connects only its click event.
- **The select sound fires too often while moving across slots:** Check whether the Item View Slots select on pointer enter. Leave **Select Clip** empty or use a quieter clip when hover selection makes the feedback too frequent.
- **UI audio is positional, quiet, or changes with the camera:** Check the assigned Audio Config and Audio Source prefab. Screen UI normally uses the default 2D configuration rather than a spatial 3D source.
- **A prefab instance works in one scene but not another:** Check that the handler and Button Audio reference were applied to the source prefab and that the other scene completed **Scene Setup**.

## Related pages

- [Shared Audio Manager and Audio Config](https://opsive.com/support/documentation/ultimate-character-controller/audio/)
- [Item View Slots](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-view-slot/)
- [Built-in Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/built-in-item-actions/)
- [Item Pickups](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-pickups/)
- [Move items with drag and drop](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/move-items-drag-drop/)
- [Master Audio integration](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/master-audio/)

## Developer behavior

`ButtonAudioHandler` resolves a neighboring `Button` and `ActionButton` during `Awake` when their serialized references are empty. During `Start`, it registers `Button.onClick` for the click sound, `ActionButton.OnSubmitE` for the click sound, and `ActionButton.OnSelectE` for the select sound. `ItemViewSlot` inherits `ActionButton`, so it follows the same submit and select path.

Both sounds are sent through `Opsive.Shared.Audio.AudioManager.PlayAtPosition` with their respective clip and Audio Config. If no Button Audio asset is assigned at startup, the handler logs a warning and does not register the control events.

---

<a id="page-ultimate-inventory-system-save-system"></a>

# Save System

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)

The Save System stores Ultimate Inventory System runtime state in local, numbered save slots. Use it to restore a player's **Bag**, **Equipment**, **Gold**, and mutable Item values, or let another save solution store the same UIS `SaveData` inside its own file.

The released Version 1 system is a local persistence layer. It does not provide cloud synchronization, network authority, encryption, or automatic migration between changed data models.

## Before you begin

Create and assign the [Inventory System Manager](https://opsive.com/support/documentation/ultimate-inventory-system/inventory-system-manager/) before adding savers. The manager's database supplies the Item, Item Definition, and Currency IDs needed to rebuild a save.

For a useful first test, prepare a player with:

- an Inventory containing **Bag** and **Equipment** Item Collections;
- a **Health Potion** in Bag and an **Iron Sword** in Equipment;
- a Currency Owner with a **Gold** balance.

Treat database IDs, Item Collection order, GameObject names, saver keys, and relevant UI IDs as part of the save format. Changing them after release can make an older save resolve to the wrong data or fail to load.

## Add the manager and core savers

1. Open **Tools > Opsive > Ultimate Inventory System > Main Manager**.
2. Select **Setup**.
3. In **Save Setup**, assign the player to **Object to save**.
4. Select **Add Components**.

The setup adds a **Save System Manager** and **Inventory System Manager Item Saver** to the Inventory System Manager GameObject when they are missing. It also adds an **Inventory Saver** and/or **Currency Owner Saver** to the selected object when that object has the corresponding Inventory or Currency Owner.

Repeat the object step for each independently saved owner. If the Inventory belongs to an Ultimate Character Controller character, use the integration's **Inventory Bridge Saver** instead of the standard Inventory Saver.

![Save System Manager and Inventory System Manager Item Saver components with their default Version 1 settings](https://opsive.com/wp-content/uploads/2020/04/Save-System-Manager.png?v=f5bc9a905819)

### Configure the Save System Manager

The released Version 1 defaults are deliberately manual:

| Inspector field | Default | What it controls |
| --- | --- | --- |
| **Auto Load On Initialize** | Off | Reads slot `0` into the manager's cache during initialization. Enable **Load On Start** on savers that must apply data after they register. |
| **Auto Load On Scene Loaded** | Off | Loads slot `0` after a scene-load callback. Saver registration timing still matters. |
| **Auto Save On Scene Unloaded** | Off | Writes slot `0` when a scene unloads. Scene objects may already be leaving, so configure **Save On Destroy** or save manually before the transition. |
| **Auto Save On Application Quit** | Off | Writes slot `0` on quit, using only savers whose own **Save On Application Quit** field is enabled. |
| **Save File Name** | `SaveFile` | Prefix used for data files. |
| **Save File Extension** | `save` | Extension used for the main save data. |
| **Max Saves** | `5` | Number of slots listed and scanned, with valid indexes from `0` through `Max Saves - 1`. |
| **Save Meta Data Creator** | None | Uses the built-in basic date/time metadata when no custom creator is assigned. |
| **Save Meta Data File Extension** | `metadata` | Extension used for the separate slot metadata file. |
| **Inventory System Manager Item Saver** | None | Resolves the saver from the same GameObject or Inventory System Manager when left empty. An explicit reference is also valid. |
| **Debug Json Copy** | Off | Writes readable JSON copies for debugging. These copies are not the authoritative save files. |

The files are written under [`Application.persistentDataPath`](https://docs.unity3d.com/ScriptReference/Application-persistentDataPath.html). Open the Save System Manager component menu and choose **PrintSaveFolderPath** to print the active location to the Console.

![Save System Manager component menu with PrintSaveFolderPath selected](https://opsive.com/wp-content/uploads/2020/04/SaveSysteManagerSavePath.png?v=e85eae077d83)

### Configure each Saver

Every `SaverBase` component exposes these shared fields:

- **Key** distinguishes multiple savers of the same type on GameObjects with the same name.
- **Save On Application Quit** lets that saver contribute to the manager's automatic quit save.
- **Save On Destroy** caches that saver's current data as its GameObject is destroyed.
- **Load On Start** applies already cached data after the saver registers in `Start`.

A saver's full lookup key is formed from its GameObject name, component type, and **Key**. Keep all three stable. Give same-type savers a unique **Key** when their GameObjects share a name; a duplicate full key prevents the later saver from registering.

For the Inventory Saver:

1. Assign the player's Inventory, or leave **Inventory** empty when the component is on the same GameObject.
2. Leave **Additive** off for a normal restore. Loading then clears the current Item Collections before restoring the save.
3. Enable **Additive** only when loading should merge saved Items into the current Inventory and possible duplicate or combine existing stacks.

![Inventory Saver assigned to the Player Character Inventory with Additive disabled](https://opsive.com/wp-content/uploads/2020/04/InventorySaver.png?v=6afdc0c40662)

The Inventory System Manager Item Saver is required by the Inventory Saver and preserves the state of referenced Items, including mutable and unique Items. **Using Nested Items** supports one level of nested Items stored through non-inherited `ItemAmounts` attributes, and **Save Item Names** includes Item names in the saved Item records.

## Choose what to persist

Add only the savers needed by the experience:

| Saver | Persists | Does not replace |
| --- | --- | --- |
| **Inventory System Manager Item Saver** | Item records referenced by other savers, including mutable and unique Item state | Inventory membership or UI placement |
| **Inventory Saver** | Item IDs and amounts in each Item Collection, including fixed Equipment slot positions | Equipped world models, open menus, or grid presentation |
| **Currency Owner Saver** | Currency IDs and integer balances, such as Gold | Shop UI state or an unfinished transaction |
| **Item View Slots Container Saver** | Assignments in slot containers such as a hotbar or equipment view | Inventory contents |
| **Inventory Grid Saver** | Inventory grid ordering and tab-specific index data | Item ownership |
| **Inventory Grid Index Data Saver** | Shared grid index maps whose grid IDs are not `-1` | Item ownership |
| **Item Shape Grid Data Saver** | Shape-grid cell occupancy and anchors | A different grid size; the saved and current cell counts must match |
| **GameObject Saver** | Selected position, rotation, active, destroyed, and component-enabled state | Scene selection or arbitrary component data |

Crafting recipes are database data rather than save-slot progress. A completed recipe's consumed Currency and resulting Items persist through the Currency Owner Saver and Inventory Saver. A selected recipe, open crafting menu, or custom in-progress crafting process needs its own saver.

Version 1's GameObject Saver has a known **Save Scale** load defect: the stored scale is applied to rotation. Do not enable **Save Scale** unless that source issue has been patched in the project.

## How saving and loading runs

Savers register with the manager in `Start`. The manager sorts them by numeric priority, with lower values running first.

During a save:

1. The manager announces the save index.
2. The Inventory Saver runs at priority `-100`, stores collection contents, and reports the Item IDs it uses.
3. Default-priority savers record Currency, UI layout, and other state.
4. The Inventory System Manager Item Saver runs last at priority `10000` and serializes each referenced Item once.
5. The manager creates metadata and writes the slot when disk output is enabled.

During a load, the dependency order reverses where needed:

1. The Inventory System Manager Item Saver runs first at priority `-10000` and recreates or resolves saved Items.
2. The Inventory Saver runs at priority `-100` and places those Items back into Bag, Equipment, and other collections by collection index.
3. Default-priority Currency and UI savers restore their state.
4. The manager announces that loading is complete.

This is why the Inventory System Manager Item Saver must be present even though it does not own an Inventory itself.

## Choose an automatic or manual flow

All four automatic manager options use slot `0`. Use explicit `Save(index)` and `Load(index)` calls when the player can choose between slots.

For a scene transition, the most predictable flow is:

1. Call `SaveSystemManager.Save(index)` before unloading the old scene.
2. Let all savers in the new scene register in `Start`.
3. Call `SaveSystemManager.Load(index)` after registration.

If the manager loads before scene savers register, enable **Load On Start** on those savers. If **Auto Save On Scene Unloaded** is used, enable **Save On Destroy** for scene-bound savers so their latest state reaches the manager's cache before the object disappears. See [Scene Transitions](https://opsive.com/support/documentation/ultimate-inventory-system/scene-transitions/) for manager and player-lifetime choices.

For application-quit saving, enable both the manager's **Auto Save On Application Quit** and **Save On Application Quit** on every saver that should refresh its data. The manager writes slot `0` after those opted-in savers run.

## Work with slots and metadata

A slot consists of two files. With the defaults, slot `0` uses `SaveFile_000.save` for data and `SaveFile_000.metadata` for its lightweight summary. Metadata is separate so a [Save Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/save-menu/) can list slot dates or custom progress without loading every Inventory.

When **Save Meta Data Creator** is empty, Version 1 creates basic metadata containing the save time. Extend `SaveMetaData` and `SaveMetaDataCreator` only when the slot list needs information such as a level name, play time, or player progress. Keep the previous metadata type readable if shipped saves must continue to appear.

The manager scans metadata for each index up to **Max Saves**. Increasing that value exposes more slot indexes; reducing it does not delete higher-numbered files. An interrupted write can leave only one half of a slot, so preserve both files when copying or backing up saves.

## Verify a round trip in Play Mode

1. Enter Play Mode with one Health Potion in **Bag**, an Iron Sword in **Equipment**, and a known Gold balance.
2. Call `SaveSystemManager.Save(0)` from the Save Menu or a temporary test script or button.
3. Remove the potion, unequip the sword, and change the Gold balance.
4. Call `SaveSystemManager.Load(0)`.
5. Confirm that Bag contents, the Equipment slot, mutable Item values, and Gold match the saved state.
6. Stop and re-enter Play Mode, then load slot `0` again to confirm that the result came from disk rather than only the manager's memory.
7. Use **PrintSaveFolderPath** and confirm that both the `.save` and `.metadata` files exist.

If hotbar assignments, Inventory grid order, or shape-grid placement must also survive, add the corresponding UI saver and repeat the test with that layout changed after saving.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| The save loads but the Inventory is empty | The Inventory System Manager Item Saver is missing, or loading ran before the Inventory Saver registered | Add the manager Item saver and load after `Start`, or enable **Load On Start** when the manager preloads the slot |
| Loading adds duplicate Items | **Additive** is enabled on the Inventory Saver | Disable **Additive** for a replace-style restore |
| A saver logs that its key is already registered | Another saver has the same GameObject name, component type, and **Key** | Assign a stable, unique **Key** or rename the object before saves ship |
| Items restore into the wrong collection or an old save stops loading | Item Collection count or order changed | Restore the original schema or migrate the old save into the new collection layout |
| An Item or Currency ID cannot be found | Its database asset or ID changed | Restore the original database entry/ID or provide an explicit migration |
| Bag and Gold return, but a hotbar or grid layout does not | Only data savers are present | Add the matching Item View Slots Container, Inventory Grid, or Item Shape Grid data saver |
| Automatic scene loading misses scene objects | Savers were not registered when the manager loaded | Enable **Load On Start** or issue the load after all scene savers start |
| A slot does not appear, or deletion leaves a file behind | The `.save` and `.metadata` pair is incomplete | Back up the folder, remove the orphaned pair, and create a fresh save |
| A UCC character restores incorrectly | The standard Inventory Saver is attached | Replace it with the integration's **Inventory Bridge Saver** |
| A GameObject's rotation changes when scale is loaded | **Save Scale** is enabled on Version 1's GameObject Saver | Disable it or patch the Version 1 source before using scale persistence |

## Plan for releases, security, and networking

Version 1 does not include automatic schema migration. Keep saver full keys, database IDs, Item Collection order, grid IDs, and serialized field layouts stable. Test every update against copies of real older saves. A project that must change those contracts should version its metadata and convert old `SaveData` before handing it to current savers.

The disk format wraps serialized UIS data and metadata; **Debug Json Copy** is only a diagnostic mirror. Writes are not transactional, and the built-in files are not encrypted, authenticated, or safe to load from an untrusted source. Add project-specific backups, integrity checks, encryption, cloud synchronization, and conflict handling when the game requires them.

The manager is also not a network save authority. In a multiplayer game, let the server or host own persistence and replicate the restored authoritative state. Do not let multiple clients write the same local slot as a synchronization strategy.

## Related pages

- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/) explains Bag, Equipment, and other Item Collections restored by the Inventory Saver.
- [Currency](https://opsive.com/support/documentation/ultimate-inventory-system/currency/) covers Currency Owners and Gold balances.
- [Items](https://opsive.com/support/documentation/ultimate-inventory-system/item/) explains the Item state serialized by the Inventory System Manager Item Saver.
- [Save Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/save-menu/) provides runtime slot selection and save/load/delete controls.
- [UI Designer Save](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/save/) adds the Save Menu through the editor workflow.
- [Scene Transitions](https://opsive.com/support/documentation/ultimate-inventory-system/scene-transitions/) covers saver lifetime across scene changes.
- [Opsive Character Controllers](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/opsive-character-controllers/) covers the Inventory Bridge Saver integration route.
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/) explains the shared event registration pattern used by save notifications.

## Developer reference

### Save System Manager API

Use a slot index from `0` through `MaxSaves - 1`:

```csharp
// Save, load, inspect, and delete slot 0.
SaveSystemManager.Save(0);

if (SaveSystemManager.HasSaveFile(0)) {
    SaveSystemManager.Load(0);
}

var currentSave = SaveSystemManager.GetCurrentSaveDataInfo();
var allSlots = SaveSystemManager.GetSaves();

SaveSystemManager.DeleteSave(0);
```

The global save lifecycle events carry the slot index as an `int`:

| Event constant | Timing |
| --- | --- |
| `EventNames.c_WillStartSaving_Index` | Before registered savers serialize |
| `EventNames.c_SavingComplete_Index` | After the save operation completes |
| `EventNames.c_WillStartLoadingSave_Index` | Before registered savers restore |
| `EventNames.c_LoadingSaveComplete_Index` | After registered savers restore |
| `EventNames.c_WillDeleteSave_Index` | Before the slot pair is deleted |
| `EventNames.c_DeleteSaveComplete_Index` | After both slot files are deleted successfully |

Inventory-specific save and load events also include the Inventory and its serialized Inventory data. Register and unregister event callbacks with the shared `EventHandler` during matching Unity lifecycle methods; see [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/).

### Store UIS data inside another save system

Pass `false` as the second `Save` argument to refresh the in-memory UIS `SaveData` without writing a UIS file. Serialize that data with the host system, then provide the reconstructed `SaveData` when loading:

```csharp
public static SaveData CaptureUISData(int slot)
{
    SaveSystemManager.Save(slot, false);
    return SaveSystemManager.GetCurrentSaveDataInfo().Data;
}

public static void ApplyUISData(int slot, SaveData restoredData)
{
    if (restoredData == null) { return; }
    SaveSystemManager.Load(slot, restoredData);
}
```

The host serializer must preserve the complete `SaveData` object. Apply it only after the UIS manager and required savers are initialized.

### Create a custom Saver

Inherit `SaverBase`, return a `Serialization` from `SerializeSaveData`, and apply the matching data type in `DeserializeAndLoadSaveData`:

```csharp
using System;
using Opsive.Shared.Utility;
using Opsive.UltimateInventorySystem.SaveSystem;
using UnityEngine;

public class PlayerProgressSaver : SaverBase
{
    [Serializable]
    private struct PlayerProgressSaveData
    {
        public int QuestStage;
    }

    [SerializeField] private int m_QuestStage;

    public override Serialization SerializeSaveData()
    {
        return Serialization.Serialize(new PlayerProgressSaveData {
            QuestStage = m_QuestStage
        });
    }

    public override void DeserializeAndLoadSaveData(Serialization serializedSaveData)
    {
        var data = serializedSaveData
            .DeserializeFields(MemberVisibility.All) as PlayerProgressSaveData?;

        if (data.HasValue) {
            m_QuestStage = data.Value.QuestStage;
        }
    }
}
```

Set a unique **Key** when more than one `PlayerProgressSaver` can share a GameObject name. Override `SavePriority` or `LoadPriority` only when the custom data has a real dependency on another saver.

---

<a id="page-ultimate-inventory-system-interaction-system"></a>

# Interaction System

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/interaction-system/)

Use the interaction system when a player should pick up an Item, open a chest, enter a Shop, or use a crafting station. The same three-part flow supports each outcome: an **Inventory Interactor** represents the player, an **Interactable** marks a world object, and an **Interactable Behavior** performs that object's action.

## How an interaction runs

1. A player Collider or Collider2D enters the trigger on an Interactable.
2. **Interactor Layer Mask** checks the layer of the GameObject carrying that player collider.
3. The Interactable finds an `IInteractor` on that GameObject or one of its parents and adds itself to the interactor.
4. The standard Inventory Interactor selects the first registered Interactable and can show its **Interactable Indicator**.
5. The Inventory Interactor's **Input**, or an enabled **Auto Interact** option, requests the interaction.
6. The Interactable invokes its UnityEvent and named event. Its Interactable Behavior then picks up an Item, opens a menu, or performs another outcome.
7. Leaving the trigger removes the Interactable. If it was selected, the next registered Interactable becomes selected.

The standard Version 1 Inventory Interactor does not rank targets by distance. When triggers overlap, it interacts with the first target in its list. Keep interaction triggers distinct when the player must have an unambiguous choice, or derive a custom Inventory Interactor when the project needs another selection rule.

## Set up the player

1. Select the player GameObject that owns the **Inventory**.
2. Confirm that the same GameObject has a concrete Opsive player-input component and add **Inventory Interactor**. The Main Manager's Character Setup can add the standard UIS character components.
3. Assign **Inventory**, or leave it empty when the Inventory is on the same GameObject so the component can find it at startup.
4. Assign an optional **Interactable Indicator** such as a prompt. The Inventory Interactor keeps it hidden until at least one Interactable is in range.
5. Leave **Auto Interact** disabled for a button-driven player.
6. Expand **Input**. The released Version 1 default is **Input Type: Button Down** and **Input Name: Action**. The old **Standard Inventory Input** component is not required by the current Inventory Interactor.
7. Ensure that the player has the Collider or Collider2D needed to enter the target's trigger. Configure Unity's Rigidbody and collision-layer requirements for the project's 2D or 3D physics setup.

![The legacy Version 1 Inventory Interactor Inspector showing Inventory, Interactable Indicator, and Auto Interact; current releases also show the Input settings below these fields.](https://opsive.com/wp-content/uploads/2020/04/InventoryInteractor.png?v=ee6a172ebab0)

The Input name is resolved by the player's `IPlayerInput` implementation. Complete the [input setup](https://opsive.com/support/documentation/ultimate-inventory-system/input/) if `Action` is not reaching the Inventory Interactor.

## Set up a world object

1. Add a Collider or Collider2D to the world object and enable **Is Trigger**.
2. Add **Interactable** to the same GameObject.
3. Set **Interactor Layer Mask** to include the layer used by the player's entering collider. It defaults to **Everything**; narrow it when only particular actors should interact. A collider on a child GameObject must use an included layer too.
4. Leave **Is Interactable** enabled.
5. Enable the physics mode the target uses. **2D** accepts 2D trigger events and **3D** accepts 3D trigger events; both are enabled by default.
6. Leave **Auto Interact** disabled when the player should press the Inventory Interactor's configured Input.
7. Optionally connect **On Select**, **On Deselect**, and **On Interact** UnityEvents for presentation that does not belong in the outcome behavior.

![The Interactable Inspector showing Interactor Layer Mask, Is Interactable, Auto Interact, the 2D and 3D trigger switches, and the On Interact, On Select, and On Deselect events.](https://opsive.com/wp-content/uploads/2020/04/Interactable.png?v=06c5379b0dd9)

Choose one automatic-interaction location:

| Desired result | Inventory Interactor **Auto Interact** | Interactable **Auto Interact** |
| --- | --- | --- |
| The player presses the configured Input | Off | Off |
| This player automatically uses every target it enters | On | Off |
| This particular target runs as soon as it is selected | Off | On |

Keeping only one automatic path active makes the trigger behavior easier to reason about.

## Add the outcome behavior

Attach one concrete Interactable Behavior beside the Interactable. The base behavior supplies these shared choices:

| Inspector field | Released Version 1 default | Use |
| --- | --- | --- |
| **Deactivate On Interact** | On | Removes the target from the interactor and deactivates its GameObject after the outcome runs. Disable it for a reusable Shop or crafting station. |
| **Schedule Reactivation Time** | `-1` | A positive value reactivates a deactivated target after that many seconds. A value of zero or less does not schedule reactivation. |
| **Select Indicators** | Empty | Activates the assigned GameObjects while this target is selected and hides them when it is deselected. |

Use the behavior that matches the outcome:

| Outcome | Components beside Interactable | Important configuration |
| --- | --- | --- |
| Pick up a Health Potion | **Item Object** and **Item Pickup** | Set the Item Object to Health Potion. **Add To Item Collection** defaults to the `Main` purpose, which can be the player's Bag. Enable **Fail If Full Amount Does Not Fit**—off by default—only when a partial pickup should be rejected. |
| Open a Shop | **Menu Interactable Behavior** and **Shop Menu Opener** | Disable **Deactivate On Interact**. Assign **Menu Opener**, set **Panel Name** to the Shop Menu's unique name, and assign **Shop**. |
| Open a crafting station | **Menu Interactable Behavior** and **Crafting Menu Opener** | Disable **Deactivate On Interact**. Assign **Menu Opener**, set **Panel Name** to the Crafting Menu's unique name, and assign **Crafter**. |
| Open a chest | **Chest Interactable** with the chest setup | Assign the Chest or a GameObject implementing `IChest`. The behavior passes the player's Inventory to the chest and makes the target unavailable while the chest is open. |

**Menu Interactable Behavior** enables **Use Player ID As Panel Manager ID** by default. With that option enabled, the opener uses the `InventoryIdentifier.ID` from the interacting player's Inventory GameObject to find the matching Display Panel Manager. This supports the correct player-owned UI in setups with more than one panel manager. Disable it only when the opener's fixed **Panel Manager Index**, which defaults to `1`, is intentional.

For example, a Shop selling Health Potion should have an Interactable and trigger on the shopkeeper object, a reusable Menu Interactable Behavior, and a Shop Menu Opener connected to that Shop. The interaction supplies the player's Inventory to the Shop Menu; the Shop remains responsible for its Items, Gold prices, and transactions.

## Editor checkpoint

Before entering Play Mode, confirm that:

- the player has Inventory, Inventory Interactor, a concrete Opsive input component, and a collider, plus Inventory Identifier when a menu interaction uses the player ID;
- the target has an Interactable, a trigger collider, and one outcome behavior;
- **Interactor Layer Mask** includes the layer on the entering player collider;
- **Auto Interact** is enabled only where the chosen interaction style requires it;
- a pickup has a valid Item Object and destination Item Collection;
- a menu target keeps **Deactivate On Interact** disabled and references the correct opener; and
- each menu opener resolves the intended **Panel Name**, Display Panel Manager, and Shop, Crafter, or other data source.

## Verify in Play Mode

1. Approach a Health Potion pickup. Confirm that its Select Indicators and the player's Interactable Indicator appear only while the pickup is in range.
2. Press `Action`, or enter the trigger when using Auto Interact. Confirm that Health Potion enters Bag and the pickup deactivates or is destroyed according to its behavior settings.
3. Leave and re-enter a reusable target. Confirm that Select and Deselect presentation resets correctly.
4. Approach the Shop and interact. Confirm that the Shop Menu opens for the approaching player's Inventory, shows the expected Shop Items, and can complete the Gold transaction.
5. If two target triggers can overlap, enter them in both orders and confirm that the default first-registered selection is acceptable.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| The target is never selected | The trigger collider, 2D/3D switch, and **Interactor Layer Mask** | Enable the matching physics mode, verify Unity's trigger setup, and include the exact layer of the entering player collider. |
| The prompt appears, but pressing the button does nothing | Inventory Interactor **Input** and the player's `IPlayerInput` component | Keep **Input Type** at **Button Down**, match **Input Name** to the configured action, and complete the project input setup. |
| The target runs immediately | **Auto Interact** on both the player and target | Disable both for input-driven interaction, or keep it enabled only on the intended side. |
| The wrong nearby target runs | Overlapping interaction triggers | Resize or reposition the triggers so the intended target registers first, or implement a custom Inventory Interactor selection rule. |
| A pickup does not enter the Inventory | Item Object, **Add To Item Collection**, capacity, and **Fail If Full Amount Does Not Fit** | Assign a valid Item, target an existing collection such as Bag, and choose the partial-pickup rule that matches its capacity. |
| A Shop or crafting interaction does not open a menu | **Menu Opener**, **Panel Name**, player Inventory Identifier, and panel-manager index | Assign the matching opener and data source, use the panel's exact unique name, and make its Display Panel Manager index match the selected player ID or fixed index. |
| A menu target disappears after one use | **Deactivate On Interact** on Menu Interactable Behavior | Disable it for a reusable menu interaction. |

## Related pages

- [Input](https://opsive.com/support/documentation/ultimate-inventory-system/input/) explains the player-input implementation and Unity EventSystem setup.
- [Input handlers](https://opsive.com/support/documentation/ultimate-inventory-system/input/handlers/) compares Inventory Interactor with the other UIS input handlers.
- [Item pickups](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-pickups/) covers Item, Inventory, Currency, and random pickups.
- [Shop](https://opsive.com/support/documentation/ultimate-inventory-system/currency/shop/) configures the Shop, Gold prices, Shop Menu, and transactions.
- [Crafting](https://opsive.com/support/documentation/ultimate-inventory-system/crafting/) connects Crafting Recipes, a Crafter, and the Crafting Menu.
- [Chest Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/chest-menu/) explains the standard chest-to-player Inventory flow.

## Extend the interaction API

`InventoryInteractor` implements `IInteractorWithInventory`, which extends `IInteractor` with an `Inventory` property. `Interactable` implements `IInteractable`, including `CanInteract`, `Select`, `Deselect`, and `Interact`. Implement those interfaces directly when a custom object cannot use the standard components.

For a custom outcome on a standard Interactable, derive from `InteractableBehavior` and implement `OnInteractInternal`. Keep the developer-specific work after the standard selection and trigger setup:

```csharp
using Opsive.UltimateInventorySystem.Interactions;

public class ExampleInteractableBehavior : InteractableBehavior
{
    protected override void OnInteractInternal(IInteractor interactor)
    {
        if (!(interactor is IInteractorWithInventory interactorWithInventory)) { return; }

        var inventory = interactorWithInventory.Inventory;
        // Apply the project-specific outcome to the Inventory.
    }
}
```

Override `CanInteract` to reject an interaction, or override `OnSelect` and `OnDeselect` for additional presentation. Call the base selection methods when the inherited **Select Indicators** should still work.

The Interactable also invokes these named events on its GameObject, each with the current `IInteractor` argument:

- `EventNames.c_Interactable_OnSelect_IInteractor`
- `EventNames.c_Interactable_OnDeselect_IInteractor`
- `EventNames.c_Interactable_OnInteract_IInteractor`

Register and unregister matching handlers over the same Unity lifecycle, as `InteractableBehavior` does in `Start` and `OnDestroy`.

---

<a id="page-ultimate-inventory-system-ui"></a>

# User Interface (UI)

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/ui/)

Ultimate Inventory System provides modular runtime UI for showing and managing inventories without making the inventory data depend on a particular screen layout. Start with UI Designer when you want a working interface quickly. Use the same runtime components directly when you already have a UI framework or need a custom presentation.

The examples on these pages use a player with a **Bag** collection, an **Equipment** collection, Gold, and familiar items such as a Health Potion and Iron Sword.

## Create the first interface

1. Open **Tools > Opsive > Ultimate Inventory System > Main Manager**.
2. Select **Setup**, find **UI Setup**, and click **Open UI Designer**. You can also open **Tools > Opsive > Ultimate Inventory System > UI Designer** directly.
3. In the UI Designer **Setup** tab, click **Setup** under **Create Canvas Managers** if the scene does not already have an inventory canvas. This creates an **Inventory Canvas**, a **Display Panel Manager**, and an Event System when one is missing.
4. Under **UI Designer Schema**, duplicate an included schema before customizing it. Select the scene's **DisplayManager**, choose the duplicated **Schema**, and click **Validate**.
5. Click **Spawn In Scene** to create the schema's full layout. Read the generated Instruction Panel before removing or rearranging objects.
6. Use the UI Designer tabs to create or edit the Bag grid, Equipment view, shop, crafting, and save interfaces needed by the project.

For the complete editor workflow and schema choices, see [UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/).

### Editor checkpoint

The scene should contain an active Inventory Canvas with a Display Panel Manager and generated Display Panels beneath it. The manager should reference the intended **Panel Owner**, or its **Panel Owner Inventory Identifier ID** should match the player's Inventory Identifier. The selected schema should pass **Validate** before you build more panels.

## Understand the runtime UI

The Inventory and Currency Owner hold the player's data. UI components read and change that data through bindings; closing or replacing a panel does not remove the Bag, Equipment, items, or Gold.

| Layer | What it does |
| --- | --- |
| **View** and **View Module** | Present one value through reusable modules, such as an icon, name, amount, or attribute. |
| **Item View** | Presents an `ItemInfo`, such as an Iron Sword and its amount. |
| **Item View Slot** | Adds selection and pointer or button interaction around an Item View. |
| **Item View Slots Container** | Coordinates a set of slots, including inventory grids, hotbars, and equipment slot views. |
| **Binding** | Supplies the relevant Inventory, collection, selected item, description, or action context. |
| **Display Panel** | Represents one openable screen or menu. |
| **Display Panel Manager** | Finds its child panels, assigns their owner, and coordinates which panel or menu is selected. |

This separation lets the same Health Potion data appear in a Bag grid, item description, shop row, and crafting result without duplicating the item.

## Bind the interface to its player

The Display Panel Manager owns the screen hierarchy, but **Panel Owner** identifies the player or Inventory that receives panel events and supplies runtime context.

- For a single local player, assign the player GameObject directly to **Panel Owner**.
- When **Panel Owner** is empty, the manager looks up **Panel Owner Inventory Identifier ID**. Its default is `1`, matching the default Inventory Identifier ID.
- The manager disables its GameObject when that owner cannot be found. Assign the owner later with `SetPanelOwner`, or make the identifiers available before the manager initializes.
- Keep the player's Inventory, Currency Owner, Item User, and Inventory Identifier on the intended owner object. The Main Manager's **Character Setup** can add the standard components.

The manager also exposes **Gameplay Panel**, **Main Menu Panel**, **Set Time Scale To Zero When Menu Is Opened**, **Close Menu When Opening Another**, and **Enable Input On Gameplay Selected**. Change these only when they match the game's menu and pause rules.

### Local multiplayer and controllers

Give each local player a unique Inventory Identifier ID and each UI root a corresponding Display Panel Manager ID and owner. Each player/UI pair also needs the correct Event System and input routing. An ID selects local runtime objects; it is not a network player identity. See [Split-screen co-op UI](https://opsive.com/support/documentation/ultimate-inventory-system/input/split-screen-co-op-ui/) for the complete setup.

## Choose the interface by task

### Build the shared UI foundation

- [Display Panel and Manager](https://opsive.com/support/documentation/ultimate-inventory-system/ui/display-panel-manager/) explains panel ownership, menu selection, opening, and closing.
- [Views](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/) explains the View and View Module presentation system.
- [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/) covers grids and other selectable groups of item slots.
- [Item Description](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-description/) shows the selected item in a detail panel or tooltip.
- [Main Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/main-menu/) groups the Bag, Equipment, and other panels behind one menu.

### Connect inventory and system screens

- [Storage Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/storage-menu/) transfers items between the player's Bag and a separate Inventory.
- [Chest Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/chest-menu/) presents a chest Inventory through an interaction workflow.
- [Shop Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/shop-menu/) buys and sells items such as Health Potions and Iron Swords using Gold.
- [Crafting Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/crafting-menu/) selects recipes, shows ingredients and results, and runs a Crafter.
- [Save Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/save-menu/) exposes save slots and Save System Manager operations to the player.

### Add feedback and presentation

- [Inventory Monitor](https://opsive.com/support/documentation/ultimate-inventory-system/ui/monitors/) displays short feedback when an item is added to an Inventory.
- [Menu Character](https://opsive.com/support/documentation/ultimate-inventory-system/ui/menu-character/) renders a character and its equipped items inside a menu.

## Input and Event System setup

The Display Panel Manager warns when the scene has no current Event System. Confirm that the Canvas has a Graphic Raycaster, the scene has an Event System with the intended input module, and the player input is routed to the same UI owner. UI Designer's **Create Canvas Managers > Setup** creates the basic canvas and creates an Event System when none exists.

Opening a panel does not automatically define every gameplay-input rule. Use the Display Panel Manager's menu and input options, plus the project's input integration, to decide whether character input remains enabled while a menu is open. See [Input](https://opsive.com/support/documentation/ultimate-inventory-system/input/) for the Version 1 input components and supported integrations.

## Verify in Play Mode

1. Start with a Health Potion in **Bag**, an Iron Sword in **Equipment** or Bag, and a known Gold amount.
2. Open the Main Menu and confirm the Bag grid shows the correct items and amounts.
3. Select each item and confirm its Item Description and available actions update.
4. Move or equip the Iron Sword and confirm both the Bag and Equipment views refresh from the Inventory data.
5. Open one system panel, such as the Shop or Crafting Menu, and confirm it uses the same player, item, and currency data.
6. Close the menu and reopen it. The Inventory data should remain unchanged even though panels and selections can reset.

For local multiplayer, repeat the test with both players and verify that each controller changes only its own UI and Inventory.

## Save and network boundaries

Inventory, item, and currency persistence comes from their Save System savers, not from the UI itself. Add UI-specific savers only when the project must restore values such as grid state or a saved Item View Slots Container selection. Open panels and transient menu selections normally return to their configured starting state. See [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/) and [Save Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/save-menu/).

Version 1 does not make the UI network-replicated. Display Panel Manager and Inventory Identifier IDs are local lookup keys. A multiplayer integration or project network layer must decide ownership, authority, and which inventory changes are replicated.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| The inventory canvas disables itself on startup | **Panel Owner** is empty and **Panel Owner Inventory Identifier ID** cannot be found. | Assign the player directly or give the player the matching Inventory Identifier before the manager initializes. |
| Buttons do not select or click | The scene has no Event System, the wrong input module is active, or the Canvas has no Graphic Raycaster. | Add or correct those components and verify that the intended player's input controls that Event System. |
| The panel opens but shows no items | Its binding resolved a null Inventory or the wrong collection. | Confirm the Display Panel Manager owner and select the Bag or Equipment collection expected by the binding. |
| One player's controller changes another player's menu | The players share an owner ID, Display Panel Manager, or Event System route. | Give each player/UI pair unique IDs and bind each canvas to its own owner and input path. |
| A second menu refuses to open | **Close Menu When Opening Another** is disabled while another menu is selected. | Close the current menu first, or enable the option when menus should replace one another. |
| Items save but the current UI selection does not | Only Inventory and Currency savers are present. | Add the relevant UI saver when that state must persist, or treat the selection as temporary UI state. |

## Developer details

The Display Panel Manager registers itself with the Inventory System Manager and discovers child Display Panels during initialization. Its public workflow includes `SetPanelOwner`, `GetPanel`, `OpenPanel`, `ClosePanel`, `TogglePanel`, and the Main Menu open, close, and toggle methods. Panel open and close events are sent through the assigned Panel Owner, so custom UI should keep that owner consistent with the Inventory it presents.

The following community diagrams show several Version 1 binding relationships. They are most useful when maintaining an existing prefab; UI Designer is the clearer starting point for a new interface.

![Storage Menu hierarchy connecting player and storage inventory grids to description, tab-control, drag-and-drop, Inventory, and database objects](https://opsive.com/wp-content/uploads/2020/04/Diagram_5-988x1024.png)

![Bag grid and Equipment slot view bindings connected to item descriptions, item action sets, an Item Slot Set, and the inventory database](https://opsive.com/wp-content/uploads/2020/04/Diagram_4-1024x650.png)

![Inventory Grid Tab Control Binding and Item Info Grid connected to a Tab Control prefab and its toggle children](https://opsive.com/wp-content/uploads/2020/04/Diagram_3.png?v=8ea4f126d028)

![Item View Slot Container Description Binding connecting an Inventory Grid to an Item Description prefab](https://opsive.com/wp-content/uploads/2020/04/Diagram_2.png?v=39ebd96b213f)

![Category Item Action Set Binding connecting an Inventory Grid to an Item Action Panel and optional item tooltip](https://opsive.com/wp-content/uploads/2020/04/Diagram_1-1024x401.png)

For custom UI code, begin with [Views](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/), [Display Panel and Manager](https://opsive.com/support/documentation/ultimate-inventory-system/ui/display-panel-manager/), and the [events reference](https://opsive.com/support/documentation/ultimate-inventory-system/events/).

---

<a id="page-ultimate-inventory-system-ui-display-panel-manager"></a>

# Display Panel & Manager

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/ui/display-panel-manager/)

The Display Panel Manager coordinates a Canvas of openable UI, assigns the player whose Inventory the panels use, and restores the previous panel and control focus when a panel closes. Use it for a Main Menu containing Bag and Equipment panels, shops, crafting, storage, and other UIS screens. It is optional when the project already has a complete UI framework and binds UIS views itself.

## Create the Canvas manager

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer**.
2. Select **Setup**.
3. Under **Create Canvas Managers**, click **Setup** when the scene does not already have an inventory Canvas.
4. Select the generated **Inventory Canvas** and review its Display Panel Manager.

The setup creates a Screen Space Overlay Canvas, Canvas Scaler, Graphic Raycaster, Prevent Selectable Deselection, Item View Slot Cursor Manager, Display Panel Manager Handler, and Display Panel Manager. It also creates an Event System with a Standalone Input Module when no Event System exists.

For a generated single-player setup, the manager initially uses the GameObject tagged `Player` as **Panel Owner**. Assign the intended owner explicitly when the player is spawned later or another object uses that tag.

## Configure the Display Panel Manager

![Display Panel Manager Inspector with ID 1, Player Character as Panel Owner, Gameplay and Main Menu panel references, time-scale pausing enabled, and menu replacement disabled](https://opsive.com/wp-content/uploads/2020/11/Display-Panel-Manager.png?v=3c827aa6c17e)

The legacy image shows the manager's core references. Released Version 1 also includes **Panel Owner Inventory Identifier ID** and **Enable Input On Gameplay Selected**.

| Setting | Default | Purpose |
| --- | --- | --- |
| **ID** | `1` | Registers this manager for lookup. Each simultaneous manager needs a unique nonzero ID. |
| **Panel Owner** | None | Receives panel events and supplies Inventory, input, and other player context to bindings. |
| **Panel Owner Inventory Identifier ID** | `1` | Finds an Inventory Identifier when Panel Owner is empty. |
| **Gameplay Panel** | None | Identifies the normal gameplay state and the panel that returns after closing a menu. |
| **Main Menu Panel** | None | Supplies the target for the Main Menu open, close, and toggle methods. |
| **Set Time Scale To Zero When Menu Is Opened** | Disabled | Sets `Time.timeScale` to `0` while the selected menu is open and to `1` when it closes. |
| **Close Menu When Opening Another** | Disabled | Replaces the selected menu when enabled; otherwise a second menu is refused. |
| **Enable Input On Gameplay Selected** | Disabled | Sends the gameplay-input enable event when selection moves into or out of the Gameplay Panel. |

The time-scale option does not remember a previous nonstandard time scale. Projects that use slow motion, nested pause systems, or scene changes while paused should manage time centrally instead.

## Bind the panel owner

The Panel Owner is normally the player GameObject containing the Inventory, Inventory Identifier, Item User, Currency Owner, and player input. Bag and Equipment panel bindings can then use **Bind To Panel Owner Inventory** instead of holding separate Inventory references.

At initialization the manager:

1. registers itself with the Inventory System Manager by ID;
2. discovers all child Display Panels, including inactive children;
3. looks up **Panel Owner Inventory Identifier ID** when Panel Owner is empty; and
4. sets up every discovered panel and binding after an owner is available.

If no owner can be found, the manager logs a warning and disables its GameObject. Call `SetPanelOwner` after spawning the player to set up and reactivate it. **Dynamic Panel Owner** can do this from a player at `Awake`, using **Display Panel Manager ID** with a default of `1`, but it does not retry when the manager is unavailable at that moment. An explicit call after both objects exist is safer for asynchronous spawning.

Changing the owner unregisters panel events from the old owner, invokes `OnPanelOwnerAssigned`, reinitializes panel bindings for the new owner, and sends the panel-owner-change event.

## Configure each Display Panel

| Setting | Default | Purpose |
| --- | --- | --- |
| **Unique Name** | Empty | Registers the panel for name-based lookup. Names must be unique within one manager. |
| **Is Menu Panel** | Disabled | Marks a root menu. The manager allows only one selected menu at a time. |
| **Is Non Selectable Panel** | Disabled | Opens an overlay such as a tooltip without replacing the selected panel. |
| **Start Enabled** | Disabled | Starts active without sending an open event. |
| **Open On Start** | Disabled | Opens at `Start` and sends normal open events. |
| **Set Active On Open** | Enabled | Activates the panel GameObject before selection and open callbacks. |
| **Set Disable On Close** | Enabled | Deactivates the panel GameObject when it closes. |
| **Selectable On Open** | None | Gives keyboard or controller focus to a chosen Selectable. |
| **Main Content** | None; uses the panel Rect Transform during setup | Tells UI Designer where generated content belongs. |
| **Bindings** | Empty | Receives initialize, open, close, and open-back callbacks. Bindings on the same GameObject are added during setup. |

A blank Unique Name prevents name lookup but not direct-reference opening. Duplicate names produce a warning and leave the first registered panel under that name.

## Build a Bag and Equipment Main Menu

Use the Gameplay Panel as the normal selected panel and assign a root Main Menu Display Panel with **Is Menu Panel** enabled. Add Bag and Equipment as submenu Display Panels paired with their tab buttons in the Main Menu binding.

![Main Menu and Display Panel Inspectors with two submenu panel-button pairs, Main Menu as the unique menu name, activation options, and a Main Content transform](https://opsive.com/wp-content/uploads/2020/11/Main-Menu.png?v=1beb0142dc0d)

Bag and Equipment are normally non-menu panels inside the Main Menu. Their Item View Slots Container Panel Bindings can both resolve the player's Inventory through Panel Owner while selecting different collections or slot views.

![Main Inventory Grid Display Panel with an Item View Slots Container Panel Binding using Panel Owner Inventory, the Main Inventory Grid, Draw On Open, and Select Slot On Open](https://opsive.com/wp-content/uploads/2020/11/Item-View-Slots-Container-Panel-Binding.png?v=cded25da383a)

For the complete menu and collection-view workflows, see [Main Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/main-menu/) and [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/).

## How opening and closing works

Opening a non-menu panel records the currently selected panel and currently selected UI control as its direct previous targets. Opening a menu first applies the one-menu rule, closes the Gameplay Panel without navigating back, and records the current selected panel as the menu's previous panel.

When a selected panel closes with `selectPrevious` enabled:

1. its direct Previous Panel receives `OpenBack`;
2. its Previous Selectable receives focus again; and
3. the manager updates Selected Display Panel from the open-back event.

This is a per-panel chain, not an independent history stack. Reopening the same panel from another place replaces that panel's previous references. Use explicit navigation when a screen can be reached through several nested routes and the direct previous relationship is insufficient.

An **Is Non Selectable Panel** overlay can open and close without taking selected-panel status, which makes it suitable for tooltips and short prompts. A root **Is Menu Panel** is different: it participates in the one-menu rule and in time-scale behavior.

## Focus, input, and the Event System

Set **Selectable On Open** for every panel that must work immediately with keyboard or controller input. The panel remembers the control selected before it opened and restores that control when it closes.

Prevent Selectable Deselection restores the last selected GameObject whenever the Event System selection becomes null. Enable **Allow Deselection While Gameplay Panel Selected** on that component when gameplay should have no UI selection.

Display Panel Manager Handler reads input from the Panel Owner. Its Version 1 defaults include **Close Panel Input** named `Close Panel` and one toggle entry that maps `Open Panel` to the panel named `Main Menu`. It can also lock or reveal the cursor as selection moves between gameplay and menus.

The manager warns when no current Event System exists. For local multiplayer, Event System Manager uses the **Event System** reference on an Event System Identifier found on the local UI root; without one, it falls back to `EventSystem.current`.

## Multiple managers and local multiplayer

Give each player/UI pair:

- a unique Display Panel Manager **ID**;
- a unique Inventory Identifier ID;
- the correct Panel Owner;
- its own Canvas and panel hierarchy; and
- the intended Event System and input route.

Duplicate Display Panel Manager IDs cannot be reassigned automatically because the manager exposes a read-only ID to the runtime register. The first registered object remains the object found by that ID. Test every lookup and input route rather than relying on hierarchy order. Follow [Split-screen co-op UI](https://opsive.com/support/documentation/ultimate-inventory-system/input/split-screen-co-op-ui/) for the full ownership workflow.

## Editor checkpoint

Before entering Play Mode, confirm that:

- the manager ID is unique and the owner is the intended player;
- **Gameplay Panel** and **Main Menu Panel** are assigned;
- every name-opened panel has a nonempty, unique **Unique Name**;
- Main Menu is a menu panel while Bag and Equipment are configured as intended subpanels;
- every controller-driven panel has a valid **Selectable On Open** and navigation links;
- Bag and Equipment bindings resolve the Panel Owner's Inventory;
- the Canvas has a Graphic Raycaster and the correct Event System/input module; and
- the time-scale and gameplay-input options match the project's pause policy.

## Verify in Play Mode

1. Start with the Gameplay Panel open and confirm normal gameplay input works.
2. Toggle Main Menu. Confirm that gameplay closes, Main Menu becomes the selected menu, and its first intended control receives focus.
3. Open Bag, switch to Equipment, then return. Confirm that only the intended submenu is visible and focus follows the tab or panel configuration.
4. Close Main Menu. Confirm that Gameplay Panel opens back and the previous gameplay or menu control state is restored as configured.
5. Attempt to open another root menu while Main Menu is open. With **Close Menu When Opening Another** disabled, confirm that it is refused; enable the setting and confirm replacement instead.
6. Enable the time-scale option, open Main Menu, and confirm `Time.timeScale` becomes `0`; close it and confirm the value becomes `1`.
7. Open a nonselectable tooltip and confirm that Selected Display Panel does not change.
8. For local multiplayer, open both menus independently and confirm that each controller changes only its own Bag, Equipment, focus, and Canvas.

## Save, scenes, and network boundaries

Display Panel Manager does not save the open panel, previous-panel chain, selected control, or time scale. UIS savers can persist Inventory and selected grid data separately, but a newly loaded UI starts from its configured **Start Enabled** and **Open On Start** state. Close a paused menu or explicitly restore the project time scale before unloading its scene; destroying the manager does not restore it.

Version 1 does not replicate panel state, focus, manager IDs, or owner changes over a network. The project or networking integration must assign the local owner and open local UI on the owning client. Display Panel Manager IDs and Inventory Identifier IDs are local lookup keys, not network identities.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| The entire inventory Canvas disables itself | Panel Owner is empty and **Panel Owner Inventory Identifier ID** cannot be resolved. | Assign the player or call `SetPanelOwner` after it spawns. |
| Opening by name does nothing | **Unique Name** is blank, misspelled, or duplicated. | Give every name-opened child panel one unique name and reinitialize the manager. |
| A second root menu will not open | Another menu is selected and **Close Menu When Opening Another** is disabled. | Close the current menu or enable replacement. |
| Closing a panel returns to the wrong screen | The panel's direct Previous Panel was overwritten by another open route. | Open it through the intended parent or implement explicit navigation for that route. |
| Controller focus disappears | **Selectable On Open**, navigation, Event System, or Prevent Selectable Deselection is missing or misconfigured. | Assign the first control and verify the player-specific Event System path. |
| Gameplay input remains active behind the menu | **Enable Input On Gameplay Selected** is disabled or no listener handles its event. | Enable it when the player input supports that event, or disable gameplay input in the project's menu controller. |
| Time resumes at the wrong speed | The built-in option restores `Time.timeScale` to `1`, not the prior value. | Manage pause and slow motion through a central system. |
| One controller operates both menus | Manager IDs, owners, Event Systems, or player inputs are shared. | Give each player/UI pair unique local IDs and explicit routes. |
| A panel added at runtime is missing from lookup | It was added after the manager's child discovery and was not set up or registered. | Set it up with the intended manager or call `RegisterPanel` after creation. |

## Related pages

- [User Interface overview](https://opsive.com/support/documentation/ultimate-inventory-system/ui/)
- [UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/)
- [Main Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/main-menu/)
- [Main Menu UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/main-menu/)
- [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/)
- [Views](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/)
- [Input](https://opsive.com/support/documentation/ultimate-inventory-system/input/)
- [Split-screen co-op UI](https://opsive.com/support/documentation/ultimate-inventory-system/input/split-screen-co-op-ui/)
- [Inventory System Manager](https://opsive.com/support/documentation/ultimate-inventory-system/inventory-system-manager/)
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)

## Developer details

Use `InventorySystemManager.GetDisplayPanelManager(id)` for ID lookup. Display Panel Manager exposes `GetPanel`, `OpenPanel`, `ClosePanel`, `TogglePanel`, `SetSelectedPanel`, `CloseSelectedPanel`, `OpenMainMenu`, `CloseMainMenu`, `ToggleMainMenu`, and `SetPanelOwner`. Display Panel exposes `SmartOpen`, `SmartClose`, `SmartToggle`, `Open`, `OpenBack`, `Close`, `PreviousPanel`, `PreviousSelectable`, `IsOpen`, and `GetBinding<T>`.

```csharp
var manager = InventorySystemManager.GetDisplayPanelManager(1);
var mainMenu = manager.GetPanel("Main Menu");

manager.OpenPanel(mainMenu);

if (manager.SelectedDisplayPanel == mainMenu) {
    manager.CloseSelectedPanel();
}
```

Panel Owner receives `PanelEventData` through the panel-open/close and new-panel-selected events. It also receives the gameplay-panel-selected Boolean and, when enabled, the gameplay-input Boolean. Display Panel provides C# and Unity events for open, close, and open-back, while each Display Panel Binding receives corresponding lifecycle callbacks. The manager also exposes the C# `OnPanelOwnerAssigned` event and sends the global panel-owner-change event after a successful owner assignment.

---

<a id="page-ultimate-inventory-system-ui-item-view-slots-container"></a>

# Item View Slots Container

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/)

An Item View Slots Container presents a group of selectable Item slots through one consistent interaction model. Inventory Grid, Item Hotbar, Item Slot Collection View, and Item Shape Grid specialize that model for different jobs while reusing selection, click, Item Actions, descriptions, and Item movement.

For a typical character, use an Inventory Grid for the Bag and an Item Slot Collection View for Equipment. The player can select an Iron Sword in Bag, inspect it, run an Equip action, or move it to an Equipment slot without each panel inventing a different input flow.

## Choose the right container

Start with the specialized page that matches the player-facing result:

| Goal | Continue with |
| --- | --- |
| Understand one selectable slot, its Item View, and restrictions | [Item View Slot](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-view-slot/) |
| Show a scrollable or paged Bag, shop, or storage list | [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/inventorygrid/) |
| Assign Items to quick-use positions without moving the source Items | [Item Hotbar](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-hotbar/) |
| Show named Equipment positions backed by an Item Slot Collection | [Item Slot Collection View (Equipment)](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-slot-collection-view-equipment/) |
| Let Items occupy multiple cells in a finite layout | [Item Shape Grid](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-shape-grid/) |
| Filter or reorder the ItemInfo values shown by a grid | [Item Info Filter and Sorters](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-info-filter-sorters/) |
| Move Items with drag and drop or keyboard/controller actions | [Move Items (Drag and Drop)](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/move-items-drag-drop/) |

Filtering and sorting change the visible order; they do not reorder the underlying Inventory by themselves. Likewise, a Hotbar can monitor assigned Items without transferring them out of Bag. Choose the data behavior first, then customize the shared container options.

## Create and inspect the slots

Create the specialized view from its UI Designer page, then select the generated container. The plain `Item View Slots Container` retrieves the **Item View Slot** children beneath **Content** when it initializes. Each slot normally contains an Item View that draws the assigned `ItemInfo`.

![A configured hotbar Item View Slots Container with its Item View Drawer and category Item Action Set binding visible in the Inspector.](https://opsive.com/wp-content/uploads/2020/11/ItemViewSlotContainerInspector.png?v=b22bdf8fbcda)

The important container fields are:

| Inspector field | Default | Purpose |
| --- | --- | --- |
| **Container Name** | Empty | Identifies this container to drop-action conditions and other rules. Use a distinct name such as `Bag` or `Equipment`. |
| **Slot Cursor** | None | Direct Item View Slot Cursor Manager reference. |
| **Slot Cursor ID** | `1` | Runtime lookup ID used when **Slot Cursor** is unassigned. |
| **Inventory** | None | Inventory used when a panel binding does not provide one. |
| **Draw On Enable** | Off | Schedules a redraw when the object becomes enabled. Leave it off for a panel that controls its own redraw. |
| **Draw On Inventory Update** | On | Schedules a redraw when the bound Inventory sends its update event. |
| **Item View Drawer** | None | Chooses and creates Item View prefabs through a Category Item View Set. |
| **Swap Item View On Assign** | Off | Replaces the slot's Item View when a new `ItemInfo` is assigned. Enable only with a configured drawer. |
| **Content** | None | Parent containing the Item View Slot children; the container's RectTransform is used when this is unassigned. |

The container passes **Content** to its Item View Drawer during initialization. The drawer can choose a different prefab for Health Potion and Iron Sword based on the configured Category Item View Set. If every Item uses the same slot layout, keep **Swap Item View On Assign** off and let the existing Item View redraw.

An Item View Slot reads any Item View Slot Restriction components on its own GameObject. Container `CanAddItem` and `CanMoveItem` checks use those restrictions before assigning or swapping values. Specialized containers add their own Inventory or Item Collection rules.

## Bind the Inventory and panel owner

Use an **Item View Slots Container Panel Binding** when the container belongs to a Display Panel. It initializes the container, assigns the panel, binds an Inventory, redraws on open, and controls the initial selection.

![The Main Inventory Grid Display Panel with an Item View Slots Container Panel Binding that uses the panel owner's Inventory and selects a slot when opened.](https://opsive.com/wp-content/uploads/2020/11/ItemViewSlotsContainerPanelBinding.png?v=666818709707)

The Inventory source is chosen in this order:

1. An explicit **Inventory** reference, when assigned.
2. The Display Panel Manager's Panel Owner Inventory when **Bind To Panel Owner Inventory** is enabled. This is enabled by default.
3. The Inventory registered to **Bind To Inventory By Identifier**, when the value is not `0` and panel-owner binding is disabled.

For a single-player Bag, panel-owner binding is usually the simplest choice. For a second local player or a panel that is not owned by the character, disable panel-owner binding and use the correct Inventory Identifier ID or explicit Inventory. Do not give two players the same identifier.

The panel binding's runtime defaults are:

| Inspector field | Default | Effect |
| --- | --- | --- |
| **Draw On Initialize** | Off | Does not draw during binding initialization. |
| **Reset Draw On Open** | On | Resets view-specific state, then schedules a draw when the panel opens. |
| **Draw On Open** | On | Schedules a normal draw only when **Reset Draw On Open** is off. |
| **Select Slot On Open** | On | Selects index `0`, or the remembered valid index. |
| **Deselect Slot On Close** | On | Deselects the current slot and clears the container selection. |
| **Remember Selected Slot** | Off | Returns to index `0` instead of the most recently selected index. |

An Equipment Item Slot Collection View still needs the correct Equipment collection and Item Slot Set. The panel binding chooses the owning Inventory; the specialized view chooses the collection and maps its slots.

## Configure selection, focus, and input

Item View Slots are Unity UI Action Buttons. The EventSystem drives selection and submit, while pointer clicks and drag events are forwarded through the container. Selecting a slot updates the container's selected slot; submitting or clicking raises the click event and notifies the slot's Item View modules.

For predictable keyboard and controller navigation:

1. Keep one valid slot selected while the panel is active.
2. Leave **Select Slot On Open** enabled unless another control deliberately receives focus.
3. Use **Remember Selected Slot** only when returning to the previous slot is helpful.
4. Leave **Deselect Slot On Close** enabled so a hidden panel does not keep focus.
5. In local multiplayer, give each player the intended EventSystem/input ownership and Inventory binding; the container does not infer player ownership from its position in the hierarchy.

Selection and click are separate events. A description commonly redraws on selection, while an Item Action panel commonly opens on click or submit.

## Add shared container behavior

The UI Designer's **Item View Slots Container Common Options** page adds and edits the shared components on a generated container.

### Item Actions

Choose one of these bindings:

- **Item View Slots Container Item Action Binding** uses one Item Action Set and first checks whether that set matches the Item.
- **Item View Slots Container Category Item Action Set Binding** selects actions by category. **Max Number Of Actions** defaults to `5` and limits the temporary action list size.

Both bindings use the container's selected slot. **Use Item On Click** is enabled by default. With an Item Action Panel assigned, click opens that panel; without one, **Use Item Action Index** defaults to `-1`, which invokes every available action. For a Bag, a category set can offer Use for Health Potion and Equip for Iron Sword. Enable **Disable Action On Empty Slots** and **Prevent Open When No Action** when empty or unsupported slots should do nothing.

**Auto Set Item User** is enabled by default and takes the Item User from the bound Inventory. Indexed and named Item Action Handler components can trigger actions through input; **Handle Input Only If Panel Selected** prevents a hidden or background panel from responding.

### Item descriptions and tooltips

An **Item View Slot Container Description Binding** passes the selected or optionally clicked slot's `ItemInfo` to an Item Description. An **Item View Slot Panel To Tooltip** only places and shows a panel beside a slot; it does not supply description or action content. See [Item Description](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-description/) for the exact binding defaults and tooltip setup.

Current Version 1 uses **Anchor Relative Offset** for tooltip placement. Configure **Panel Bounds** and test edge slots so the tooltip remains within the visible Canvas.

### Item View Drawer

The Item View Drawer uses a Category Item View Set to choose the best matching Item View prefab. Category order and inheritance matter. Use it when Health Potion, Iron Sword, and other categories require structurally different slot views; use Item View Modules when the structure is shared and only the values differ.

### Moving Items

Pointer drag and non-pointer movement share an **Item View Slot Cursor Manager** and **Item View Drop Handler**. The Drop Handler needs an **Item View Slot Drop Action Set** to decide whether a move, swap, transfer, or rejection occurs.

- Add an **Item View Slot Drag Handler** for pointer drag and drop.
- Add an **Item View Slot Move Cursor** for the Move Item Action used by keyboard or controller.
- Put conflicting bindings, such as Item Actions, in **Unbind While Moving** so the placement click does not also invoke an Item Action.

Use the drop action set for movement between Bag and Equipment. Directly swapping the visible Item Views is not a substitute for a valid Inventory transaction.

## How it runs

1. The specialized container finds or creates its Item View Slots and initializes each slot index.
2. It binds every Item View Slots Container Binding on the same GameObject.
3. The panel binding assigns its Display Panel and resolves the Inventory from an explicit reference, panel owner, or Inventory Identifier.
4. When the Inventory updates, **Draw On Inventory Update** schedules `Draw()`.
5. `Draw()` defers work until `LateUpdate`; `ForceDraw()` redraws immediately. The container assigns `ItemInfo` values to Item Views and raises `OnDraw` after the redraw.
6. Selection, click, pointer, and drag events include the container, slot, current `ItemInfo`, local slot index, and any specialized index offset.
7. Description, Item Action, movement, and other bindings respond to the same container events.

The base container coordinates UI. Inventory Grid, Item Slot Collection View, Item Shape Grid, and hotbar variants override add, remove, or move behavior to match their data source. Use the specialized container API when a change must affect the Inventory or Item Collection.

## Editor checkpoint

Before entering Play Mode, confirm that:

- **Content** contains the expected number of active Item View Slots and each slot has an Item View;
- **Container Name** is meaningful and unique wherever drop conditions use it;
- the **Slot Cursor** reference or **Slot Cursor ID** resolves to the Canvas manager used by this player;
- the Category Item View Set has a valid fallback and mappings for Health Potion and Iron Sword;
- the panel binding references this container and resolves the intended Inventory;
- Bag and Equipment do not accidentally bind to another player's Inventory Identifier;
- Item Action bindings have a valid Item Action Set or Category Item Action Set and intended Item User;
- description and action bindings sit on the same GameObject as the container;
- movement has a Cursor Manager, Drop Handler, Drop Action Set, and the correct pointer or Move Cursor handler; and
- Equipment uses the intended Item Slot Collection and compatible Item Slot Set.

## Verify in Play Mode

1. Open Bag. Slot `0` or the remembered valid slot should receive focus, and the grid should show the bound Inventory.
2. Navigate with keyboard/controller and pointer. Selection, submit, and click should affect only the active player's panel.
3. Select Health Potion and Iron Sword. The Item Description should replace its content without stale values.
4. Submit Health Potion and confirm the intended Use action or action panel appears. Empty slots should remain inactive when configured.
5. Move Iron Sword from Bag to a valid Equipment slot. Both data collections and both views should update.
6. Attempt an invalid Equipment drop. The drop action set and slot restrictions should reject it without losing the Item.
7. Close and reopen the panel. Confirm the reset or remembered-selection behavior and ensure the hidden panel no longer receives input.
8. Change the Inventory from code or another system and confirm **Draw On Inventory Update** refreshes the visible slots.

## Save and network boundaries

`ItemViewSlotsContainerBase` does not save UI selection, focus, tooltip position, or a pending cursor move. Save the underlying Inventory, Item Collections, hotbar assignment data where supported, and mutable Items through the relevant UIS save components. Reopen or redraw the container after loading.

These Version 1 UI classes do not replicate Inventory transactions or assign network ownership. A networking integration must authorize and synchronize the underlying data change, then refresh each client's local container. Do not treat `AssignItemToSlot` on a generic UI container as a networked Inventory transfer.

## Troubleshooting

- **The container has no slots:** Check **Content** and confirm its active children have Item View Slot components with Item View children.
- **The first open is blank:** Check the panel binding's Inventory source, **Reset Draw On Open**, and **Draw On Open**. Remember that `Draw()` completes in `LateUpdate`.
- **The wrong character's Items appear:** Check the Display Panel Manager's Panel Owner, **Bind To Panel Owner Inventory**, and **Bind To Inventory By Identifier**. An explicit **Inventory** reference takes priority.
- **Opening the panel selects the wrong slot:** Check **Remember Selected Slot** and the last recorded index; invalid remembered indices fall back to `0`.
- **A background panel responds to input:** Enable **Handle Input Only If Panel Selected** on its Item Action Handler and verify EventSystem ownership.
- **Every Item uses the same appearance:** Check **Item View Drawer**, **Swap Item View On Assign**, and Category Item View Set matching order.
- **Clicking an Item runs several actions:** With no Action Panel, `-1` for **Use Item Action Index** invokes all actions. Assign a panel or choose one index.
- **A description or action binding never updates:** Place the binding on the same GameObject as the container and verify its target references.
- **Dragging moves the picture but not the Item:** Check the Drop Handler and Item View Slot Drop Action Set. The cursor visual is not the Inventory transaction.
- **Keyboard movement also invokes an Item Action:** Add the action binding to **Unbind While Moving** on Item View Slot Move Cursor.
- **A tooltip uses an unexpected offset:** Recheck the current **Anchor Relative Offset** and **Panel Bounds** rather than copying the retired **Anchor Offset** label from older screenshots.

## Related pages

- [UI Designer common container options](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view-slots-container/)
- [Item Description](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-description/)
- [Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/)
- [Display Panel Manager](https://opsive.com/support/documentation/ultimate-inventory-system/ui/display-panel-manager/)
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/)
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)

## Developer details

- `ItemViewSlotsContainerBase` exposes `ItemViewSlots`, `SlotCount`, `Inventory`, `Panel`, `ContainerName`, `SelectSlot(int)`, and `GetSelectedSlot()`.
- Use `GetItemViewSlot(int)`, `GetItemViewAt(int)`, and `GetItemAt(int)` to inspect a slot. `GetItemViewAt` is the current Version 1 method name.
- `Draw()` schedules a redraw; `ForceDraw()` performs it immediately; `ResetDraw()` lets a specialized container restore its initial navigation or paging state.
- `AddItem`, `RemoveItem`, `CanMoveItem`, and `MoveItem` are virtual. Their data effects depend on the specialized container.
- Selection events are `OnItemViewSlotSelected`, `OnItemViewSlotDeselected`, and `OnItemViewSlotClicked`. Pointer events include `OnItemViewSlotPointerDownE`, `OnItemViewSlotBeginDragE`, `OnItemViewSlotDragE`, `OnItemViewSlotEndDragE`, and `OnItemViewSlotDropE`.
- `ItemViewSlotEventData` exposes `ItemViewSlotsContainer`, `ItemViewSlot`, `ItemView`, `ItemInfo`, `SlotIndex`, `SlotIndexOffset`, and `ItemIndex`.
- `OnBindInventory`, `OnUnBindInventory`, `OnDraw`, and `OnResetDraw` support custom bindings. Unsubscribe custom handlers when their owner is destroyed or unbound.
- `SetOneTimeClickAction(ItemViewSlotActionEvent)` intercepts the next submit/click event and can stop normal propagation when constructed with `stopPropagation: true`.

---

<a id="page-ultimate-inventory-system-ui-item-view-slots-container-item-view-slot"></a>

# Item View Slot

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-view-slot/)

An **Item View Slot** is the selectable and draggable control around one [Item View](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/item-view/). It turns a visual Health Potion or Iron Sword into a focusable UI destination, then forwards selection, activation, pointer, and drag information to its Item View Slots Container.

The slot does not own the Inventory Item. It presents the `ItemInfo` assigned by Bag, Equipment, a hotbar, or another specialized container. Moving the Item requires the container or another Inventory transaction; changing the slot's display alone does not change the Inventory.

## Inspect a generated slot

Create the intended container through UI Designer, then select one of its generated Item View Slot children. The slot should contain an Item View with the modules required for that context.

![The Item View Slot Inspector with its Item View reference, container-assigned index, Action Button input settings, selection transitions, and click event.](https://opsive.com/wp-content/uploads/2020/11/ItemViewSlotInspector.png?v=5a2570e65b5d)

The page-specific fields are:

| Inspector field | Version 1 default | Purpose |
| --- | --- | --- |
| **Item View** | None on a manually added slot | Visual child that receives `ItemInfo`, selection, and click notifications. At `Awake`, the slot finds an Item View in its children when this is unassigned. |
| **Index** | `0` | Local index assigned again by the owning Item View Slots Container during initialization. |

The inherited Action Button fields that change common slot behavior are:

| Inspector field | Version 1 default | Effect |
| --- | --- | --- |
| **Disabled And Selected Sprite** | None | Optional sprite used when a selected slot is not interactable. |
| **Disabled And Selected Color** | Gray | Color used for that selected and disabled state with a color transition. |
| **On Click Event** | Empty | Optional UnityEvent invoked when `Press()` completes. Standard container bindings do not require it. |
| **On Pointer Click Input Button** | Left | Chooses which mouse buttons may press the Action Button. |
| **Select On Pointer Enter** | On | Selects the slot when a moving pointer enters it. |
| **Deselect On Pointer Exit** | On | Deselects the slot when the pointer exits it. |
| **Unselected Press Selects And Press** | Off | An activation that reaches `Press()` while unselected selects the slot without submitting it. Normal left pointer-down selection usually occurs before the click. |

The slot also inherits Unity Selectable transition, color, sprite, animation, interactable, and Navigation settings. Configure those through the normal Unity UI controls.

## Keep the Item View connection valid

`SetItemView` connects the two parts of the control:

- the Item View's **Target Graphic** becomes the Action Button target, so Unity's highlighted, selected, pressed, and disabled transitions affect the intended Image;
- the Item View receives this slot as its `ViewSlot`; and
- Item View Modules that depend on a slot can resolve the current selection and index context.

Keep exactly one intended Item View assigned or discoverable beneath the slot. Version 1 does not guard every click and value path against a missing Item View, so a slot without one can throw an exception instead of acting as a harmless empty control.

The Item View handles presentation through modules. A compact Bag slot commonly uses **Icon Item View**, **Amount Item View**, and **Select Image View**. An Equipment slot may add an equipped marker. The parent Item View Slot remains the interaction area rather than duplicating buttons inside those visual modules.

## Understand ItemInfo and index ownership

The `ItemInfo` exposed by a slot is the current value held by its Item View. It can identify the Item, amount, ItemStack, and source Item Collection, but the slot is not the data authority.

When a container assigns Health Potion:

1. the container chooses a local slot index;
2. `AssignIndex` records that local index;
3. `SetItemInfo` passes the value to every compatible Item View Module; and
4. an empty or invalid Item clears the Item View and its modules.

If the slot is already selected, assigning a new value replays its selection notification so the replacement Item receives the correct highlight state.

Do not edit **Index** to reorder Bag or Equipment. The owning container overwrites it from its Item View Slot array. For paged or filtered containers, the local **Slot Index** can differ from the underlying **Item Index**. Container event data reports both `SlotIndex` and `ItemIndex`, where `ItemIndex` includes the container's current offset.

Calling `SetItemInfo` directly updates presentation only. Use the Inventory Grid, Item Slot Collection View, hotbar, drop action, or Inventory API when the Item itself must move or change.

## How selection and activation run

### Selection and highlight

When the EventSystem selects a slot, the Action Button enters its selected state and the slot calls `ItemView.Select(true)`. Every Item View Module implementing the selectable interface receives that state. **Select Image View** can swap a sprite, while **Select View** can enable a highlight GameObject or invoke a Boolean event.

Deselecting the slot calls `ItemView.Select(false)`. Pointer enter and exit use those same selection paths when their default options remain enabled. Keyboard and controller navigation use Unity Selectable Navigation and the EventSystem assigned to this UI owner.

Use both levels deliberately:

- the Action Button transition gives the whole slot a standard Unity UI state; and
- selectable Item View Modules give the Item-specific visual a focused highlight.

If neither is configured with a visible target, selection can work without any visible feedback.

### Click and submit

Pointer click and submit call the Action Button's `Press()` method. When the press completes, it invokes **On Click Event** and `OnSubmitE`. The owning container converts `OnSubmitE` into `OnItemViewSlotClicked`, which is the event used by standard Item Action and optional click-driven description bindings.

The slot also calls `ItemView.Click()` after pointer click or submit so custom clickable Item View Modules can react. Standard Item Actions are normally configured on the Item View Slots Container, not on the slot's UnityEvent.

For a Bag example, selection can update the Health Potion description, while activation can open its Use action. For Equipment, selecting Iron Sword can update the description and activation can offer Unequip.

## Configure restrictions

Add restrictions to the same GameObject as the Item View Slot. `CanContain` returns true only when every attached restriction accepts the candidate `ItemInfo`.

Version 1 supplies:

- **Item View Slot Category Restriction**, which accepts a configured Item Category; and
- **Item View Slot Definition Restriction**, which accepts a configured Item Definition.

Both have **Inherently** enabled by default. A Weapon category restriction therefore accepts Iron Sword and compatible descendant categories but rejects Health Potion. Empty `ItemInfo` values and a restriction with no configured category or definition are accepted so a slot can be cleared.

Restrictions are cached during the slot's `Awake`. Add and configure them before entering Play Mode. A component added later is not included automatically by the released Version 1 slot.

`SetItemInfo` itself does not call `CanContain`. The containing view's `CanAddItem`, `CanMoveItem`, or drop condition must perform that check before assigning the visual. Custom code that calls `SetItemInfo` directly bypasses restrictions as well as the Inventory transaction.

## Connect actions and descriptions

Item Action and Item Description behavior belongs beside the [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/), where one binding can serve every slot.

- An Item Action binding listens to `OnItemViewSlotClicked`. **Use Item On Click** defaults on, and it can either open an Item Action Panel or invoke the configured action index.
- An Item Description binding listens to selection by default. **Draw On Select** and **Draw On Container Draw** default on, while **Draw On Click** defaults off.

This separation keeps Item View Slot prefabs reusable. The same slot can display Health Potion in Bag, Iron Sword in Equipment, or an assigned Fire Wand in a hotbar while the surrounding container chooses the valid actions and destination description.

## Connect pointer movement and drag-and-drop

The Action Button emits pointer-down, begin-drag, drag, end-drag, and drop events. The owning container subscribes to those events, adds the slot, Item View, current `ItemInfo`, local index, offset, and pointer ID, then raises its matching container event.

The slot does not move an Item by itself. Configure the shared [move Items workflow](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/move-items-drag-drop/):

1. add or resolve an Item View Slot Cursor Manager;
2. configure an Item View Drop Handler and Item View Slot Drop Action Set;
3. add an Item View Slot Drag Handler for pointer input; and
4. add an Item View Slot Move Cursor when keyboard or controller users can move Items.

The Cursor is a preview. A drop condition and action must validate and perform the underlying Bag-to-Equipment or within-container transaction. A rejected Iron Sword destination should leave both the slot display and Inventory unchanged.

## Configure navigation and ownership

Use Unity Selectable **Navigation** to define the next slot for left, right, up, and down movement. Grid and specialized container setup may generate or update those links. Test the actual runtime hierarchy after adding, removing, or reordering slots.

Each container subscribes to its slots during initialization and assigns their local indexes. A slot has no serialized Inventory or container field. The bound container and its panel binding supply that context in events.

For local multiplayer, keep each player's container under the correct Display Panel Manager and EventSystem ownership. A slot uses the EventSystem resolved for its GameObject; it does not infer a player from the `ItemInfo` or sibling controls.

## Editor checkpoint

Before entering Play Mode, confirm that:

- **Item View** references the intended child and has a valid **Target Graphic**;
- the Item View includes the required Icon, amount, selection, or equipped-state modules;
- every restriction is on the same GameObject and has a valid category or definition from the active database;
- **Index** order matches the owning container's Item View Slot array;
- the Unity Selectable transition produces a readable normal, highlighted, selected, pressed, and disabled state;
- Navigation connects every slot used by keyboard or controller;
- pointer-enter selection matches the intended mouse behavior;
- Item Action and Item Description bindings are on the owning container;
- drag-and-drop has a Cursor Manager, Drop Handler, Drop Action Set, and intended input handler; and
- the panel and EventSystem belong to the correct local player.

## Verify in Play Mode

1. Open Bag and move selection between Health Potion and Iron Sword with pointer, keyboard, and controller.
2. Confirm that exactly one slot has visible selection feedback and that the Item View modules agree with the Action Button state.
3. Select Health Potion and confirm that the connected description updates without activating Use.
4. Submit or click Health Potion and confirm that the configured Item Action panel or Use action runs once.
5. Select an empty slot and confirm that old Icon, amount, selection, and description data clear as configured.
6. Try to move Health Potion into a Weapon-restricted Equipment slot and confirm that it is rejected without changing Bag.
7. Move Iron Sword into that slot and confirm that both containers redraw from the completed Inventory transaction.
8. Begin and cancel a drag, then navigate again. Confirm that no cursor preview or stale highlight remains.

## Save and network boundaries

An Item View Slot is a local UI control. Its current `ItemInfo`, index, selected state, navigation state, pointer state, and in-progress drag are not authoritative save data. Save the Inventory, Item Collections, hotbar assignments, and mutable Items through their relevant Version 1 savers, then let the container rebuild and redraw its slots after loading.

The slot has no built-in network replication or authority. A networking implementation must synchronize the underlying Inventory or assignment transaction, then redraw local slots. Replicating a slot's Icon or calling `SetItemInfo` remotely does not synchronize the Item.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| The slot throws an error when drawn or clicked | **Item View** reference and child hierarchy | Assign one valid Item View before Play Mode. |
| The Item appears but selection is invisible | Item View **Target Graphic**, Action Button transition, and selectable modules | Assign the intended Image and configure a visible selected state. |
| Pointer hover never selects | **Select On Pointer Enter**, pointer movement, raycasts, and EventSystem | Enable the option and ensure the slot receives pointer events. |
| The first non-pointer activation only selects | **Unselected Press Selects And Press** | Leave it off for select-then-activate behavior, or enable it when one press should do both. |
| Clicking never opens Item Actions | Owning container's Item Action binding and **Use Item On Click** | Configure the binding on the container and confirm the slot is selected and interactable. |
| Selection changes but the description does not | Item Description binding and **Draw On Select** | Bind the description to the correct container and enable selection drawing. |
| A restriction added at runtime has no effect | When the restriction was attached | Add it before `Awake`, or implement a custom refresh path for runtime changes. |
| A forbidden Item still appears | Code calling `SetItemInfo` or `AssignItemToSlot` directly | Validate through `CanContain` and perform the specialized container or Inventory transaction. |
| Dragging moves only an image | Drop Handler and Drop Action Set | Configure a valid data-moving action; the slot only reports the drag. |
| Keyboard navigation skips or leaves the panel | Unity Navigation links and active runtime hierarchy | Rebuild or explicitly configure neighbors after changing slots. |
| The wrong player's slot receives focus | Display Panel Manager and EventSystem ownership | Place the container under the intended player's UI and use its event system. |
| Loaded UI shows stale data | Underlying saver and post-load redraw | Load authoritative Item data, then reset or redraw the container. |

## Related pages

- [Create and customize Item Views](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view/)
- [Item View runtime reference](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/item-view/)
- [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/)
- [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/inventorygrid/)
- [Equipment Item Slot Collection View](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-slot-collection-view-equipment/)
- [Item Hotbar](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-hotbar/)
- [Move Items with drag and drop](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/move-items-drag-drop/)
- [Item Description](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-description/)
- [Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/)
- [Input handlers](https://opsive.com/support/documentation/ultimate-inventory-system/input/handlers/)
- [Save system](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)

## Developer details

Use the slot API for view state and restrictions, not as a substitute for an Inventory transaction:

```csharp
itemViewSlot.SetItemView(itemView);
itemViewSlot.AssignIndex(localIndex);

if (itemViewSlot.CanContain(itemInfo)) {
    itemViewSlot.SetItemInfo(itemInfo);
}
```

`SetItemInfo` clears the Item View when the Item is null or has an empty ID. `SetItemView` assigns the Action Button target graphic and gives the Item View this slot. `DisableImage` disables the slot's Image component, and `UpdateUI` reapplies the slot reference to the Item View.

Action Button events include `OnSubmitE`, `OnSelectE`, `OnDeselectE`, `OnCancelE`, `OnMoveE`, pointer down/up/enter/exit, and begin-drag/drag/end-drag/drop. The owning container exposes higher-level `OnItemViewSlotSelected`, `OnItemViewSlotDeselected`, `OnItemViewSlotClicked`, pointer-down, drag, and drop events.

`ItemViewSlotEventData` contains `ItemViewSlotsContainer`, `ItemViewSlot`, `ItemView`, `ItemInfo`, `SlotIndex`, `SlotIndexOffset`, and `ItemIndex`. Pointer event data adds the original `PointerEventData` and pointer ID. Treat these event objects as transient container state rather than storing them as long-lived Item references.

To create a custom restriction, inherit `ItemViewSlotRestriction` and implement `CanContain(ItemInfo)`. Attach it before the slot's `Awake`, and keep the authoritative add or move check in the specialized container or Inventory layer.

---

<a id="page-ultimate-inventory-system-ui-item-view-slots-container-inventorygrid"></a>

# Inventory Grid

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/inventorygrid/)

An Inventory Grid shows `ItemInfo` values from an Inventory in a fixed set of reusable slots. Use it for a Bag, shop stock, storage, or any view that may contain more Items than can be displayed at once.

For example, a 4-by-4 Bag can show Health Potion and Iron Sword, filter to Consumables or Weapons, and page through a larger Inventory without creating one Unity UI object for every Item. Selection, Item Actions, descriptions, and movement come from the shared Item View Slots Container workflow.

## Before you begin

Confirm that:

- the Inventory and its Bag collection already exist;
- Health Potion and Iron Sword appear in that Inventory in Play Mode;
- UI Designer Canvas Managers and a project-owned schema have been created; and
- the Display Panel Manager has the correct Panel Owner or the Inventory has a unique Inventory Identifier ID.

An Inventory Grid starts from `Inventory.AllItemInfos`. Add an Item Collection filter when the panel should show Bag but not Equipment, Loadout, or another collection.

## Create the grid or list

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer** and select **Inventory Grid**.
2. Choose a **Panel Option**. **Simple** is the default; **Basic**, **Floating**, and **MainMenu** are also supplied.
3. Set **Panel Name**. The creator starts with `My Inventory Grid Panel`.
4. Optionally assign **Inventory**. Leaving it empty lets the generated panel binding resolve its Inventory at runtime.
5. Choose **Grid Option**:
   - **Grid** creates rows and columns. **Grid Size** defaults to `4 x 4` in UI Designer.
   - **List** creates a single column from the list schema. **List Length** defaults to `5`.
6. Set **Inventory Grid Name**, which defaults to `Inventory Grid`, then create the panel.

UI Designer creates the Display Panel, Inventory Grid, Item Info Grid, Grid Event System, Item View Drawer, Item View Slots, and Item View Slots Container Panel Binding. When an explicit Inventory is assigned, the creator also adds Inventory Grid Index Data to that Inventory if it is missing.

## Understand the generated components

The grid uses a fixed number of Action Buttons equal to **Grid Size**. The Grid Event System reuses those buttons while the Item Info Grid changes which range of `ItemInfo` values they draw. Configure the size before Play Mode; the initialized grid does not rebuild its runtime slot count when **Grid Size** changes.

![A configured Inventory Grid Inspector showing the Inventory Grid, Item Info Grid, Grid Event System, and Item View Drawer for a five-by-five grid.](https://opsive.com/wp-content/uploads/2020/04/InventoryGridInspector-2.png?v=a6d98c19fd7a)

### Inventory Grid

In addition to the shared container fields, Inventory Grid adds:

| Inspector field | Default | Purpose |
| --- | --- | --- |
| **Grid** | None | Required Item Info Grid. The component looks on the same GameObject when this is unassigned. |
| **Use Grid Index** | On | Keeps Item Stacks at indexed visual positions and allows gaps. |
| **Reset Index On Reset Draw** | Off | Returns the visible range to index `0` when the panel performs a reset draw. |
| **Remove Empty Indexes On Reset Draw** | Off | Compacts stored visual positions during a reset draw. |

Moving an Item between two positions in the same Inventory Grid changes the grid indexer's visual order; it does not move the Item between Inventory collections. Transfers between Bag and Equipment require the movement/drop-action workflow.

### Item Info Grid

The Item Info Grid controls the visible range and slot behavior:

| Inspector field | Default | Purpose |
| --- | --- | --- |
| **Grid ID** | `-1` | Treats this grid as unique. A shared non-negative ID lets grids for the same Inventory and tab synchronize indexed positions. |
| **Canvas** | None | Canvas used by the grid; the parent Canvas is found during initialization. |
| **Grid Size** | `5 x 4` on the component | Number of reusable columns and rows. UI Designer overrides this with the creator choice. |
| **Set Real Element Count As Max** | On | Limits navigation to the filtered Item count. |
| **Max Element Count** | `100` | Navigation count used only when the real count is not the maximum. |
| **Disable Element Option** | **Do Not Disable Elements** | Controls whether unused slots remain active. |
| **Custom Disable Element Index** | `-1` | Custom cutoff used by the matching disable options. |
| **View Drawer Base** | None | Required Item View Drawer that draws each slot. |
| **Grid Event System** | None | Required component that creates/listens to the fixed Action Buttons. |
| **Grid Navigator** | None | Optional paging, scroll-step, or scroll-view navigator. |
| **Tab Control** | None | Optional control used with Inventory tabs. |
| **Select Button On Initialize** | On | Selects local slot `0` when the grid initializes. |
| **Refresh On Enable** | Off | Does not refresh merely because the Item Info Grid component becomes enabled. |
| **Next Tab Input** | `Next` | Panel-owner input name for the next tab. |
| **Previous Tab Input** | `Previous` | Panel-owner input name for the previous tab. |
| **Filter Sorter Base** | None | Default ItemInfo filter/sorter bound at initialization. |

The Grid Event System's **Draggable** option is on by default, which forwards pointer drag events. It does not perform Inventory transactions by itself. **Button Prefab** must contain an Action Button, and **Content** must contain only compatible slot buttons for the configured size.

## Bind the Inventory and Bag collection

The generated Item View Slots Container Panel Binding resolves its Inventory in this order: explicit **Inventory**, the Display Panel Manager's Panel Owner when **Bind To Panel Owner Inventory** is enabled, then **Bind To Inventory By Identifier** when panel-owner binding is off.

After the owner is correct, decide which collections appear:

- Use **Item Info Item Collection Filter** to show only Bag or to hide selected collections. Its **Show Item Collections** list shows every collection when empty; **Hide Item Collections** defaults to Loadout and Hide purposes.
- Use **Item Info Item Collection And Category Filter** when category filtering should apply only to selected collections.
- Leave the collection filter out only when the grid should intentionally show every `ItemInfo` returned by the Inventory.

Test the source with an Item that differs across collections. If Iron Sword is equipped, a Bag-only grid should not also show its Equipment entry.

## Choose indexed or compact ordering

With **Use Grid Index** enabled, the Inventory Grid Indexer associates each Item Stack with a visual index. Empty positions remain available, and moving within the grid swaps those positions. New Item Stacks are assigned an available index.

With **Use Grid Index** disabled, filtered results are drawn as a compact sequence. This is usually better for shop lists and search results. The supplied Inventory Search Filter temporarily disables indexed ordering while the search field contains text, then restores the previous setting when the field is cleared.

**Grid ID** and the current tab ID identify shared index data. Two grids bound to the same Inventory, with the same non-negative Grid ID and tab ID, copy each other's visual ordering. Keep `-1` when the view should remain unique.

## Add filters, search, and sorting

In UI Designer's Inventory Grid **Edit** section, use **Filters and Sorters** to create:

- **Default Filters**, applied every time the grid draws;
- a **Name Search Bar**, which filters Item names without case-sensitive matching; and
- a **Sort Drop Down**, which can sort once or bind a sorter for later redraws.

An Item Info Multi Filter Sorter runs its entries in list order. A Bag setup might first restrict **Show Item Collections** to Bag, then use an Item Info Category Filter for Consumable or Weapon. Sorters can compare name, amount, category name, or one named attribute.

Filtering and sorting change the view, not the Inventory contents. A one-time dropdown sort changes indexed positions; a bound sorter transforms the list on each draw. If manual gaps and continuous sorting conflict, decide whether the grid should preserve positions (**Use Grid Index** on) or present a continuously ordered list (off).

See [Item Info Filter and Sorters](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-info-filter-sorters/) for the built-in options and custom extension points.

## Add tabs

Choose **Create Inventory Tabs** under UI Designer's **Grid Tabs** section. Each Tab Toggle receives Inventory Tab Data and can provide its own Inventory, Item Info filter, maximum count, disable behavior, and grid indexer.

![A Weapons Tab Toggle configured with Inventory Tab Data and a multi-filter containing an Item Info Category Filter for Weapons.](https://opsive.com/wp-content/uploads/2020/04/InventoryTabDataInspector.png?v=9cb75c0e0fac)

For example:

- **All** uses only the Bag collection filter.
- **Consumables** adds the Consumable category filter and shows Health Potion.
- **Weapons** adds the Weapon category filter and shows Iron Sword.

The Inventory Grid Tab Control Binding switches the filter and tab indexer, then schedules a redraw. **Reset Tab Index On Reset Draw** and **Select Slot 0 On Change Tab** are both off by default. Enable the second option when changing tabs must always establish a valid selection for descriptions or Item Actions.

An Inventory Tab Data **Inventory** reference can switch the entire source Inventory for that tab. Leave it empty when every tab is only another view of the same Bag.

## Configure navigation and input

UI Designer's **Grid Navigation** supports **None**, **Buttons**, **Scroll Step**, and **Scroll View**. Choose vertical or horizontal navigation and optionally link reaching a tab boundary to the Tab Control.

The navigator changes the Item Info Grid's start index; the fixed slots stay in place and redraw a different slice. `ItemViewSlotEventData.SlotIndex` is the local visible slot, while `ItemIndex` includes the grid's current start-index offset.

Next/previous tab input comes from the Display Panel's owner and is accepted only while that panel is selected. For local multiplayer, verify the correct Panel Owner, Inventory Identifier, EventSystem, and player input rather than sharing one grid between players.

## Add actions, descriptions, and movement

Inventory Grid is an Item View Slots Container, so the shared UI Designer options apply:

- Add an Item Description binding to show Health Potion or Iron Sword details when selection changes.
- Add an Item Action Set or Category Item Action Set binding to offer Use, Equip, Drop, or another supported action.
- Add the Cursor Manager, Drop Handler, Drop Action Set, and Drag Handler for pointer movement.
- Add Item View Slot Move Cursor for keyboard/controller movement.

Selection and click operate on the visible slot's current `ItemInfo`. When an Item Action or move changes the Inventory, the Inventory update schedules a new grid draw. See [Move Items (Drag and Drop)](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/move-items-drag-drop/) for the complete transaction setup.

## Use an Item Shape Inventory Grid

Use [Item Shape Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/inventorygrid/item-shape-inventory-grid/) when one Item must occupy multiple cells in an Inventory-backed grid. It adds Item Shape data, controller, binding, and specialized Item View modules; setting a standard Inventory Grid to a larger slot size does not provide shape occupancy rules.

## How it runs

1. The Item Info Grid initializes its Grid Event System, creates or reuses `Grid Size.x * Grid Size.y` Action Buttons, and initializes the Item View Drawer.
2. The panel binding assigns the Inventory and Display Panel to the Inventory Grid.
3. Inventory Grid starts from `Inventory.AllItemInfos`, applies the active filter/sorter, then applies indexed ordering when **Use Grid Index** is enabled.
4. Item Info Grid stores the resulting sequence and draws only the range from its start index to its end index.
5. The Item View Drawer clears/reuses or replaces Item Views for the fixed slots.
6. Selection, click, pointer, and drag events flow from Grid Event System to Item Info Grid and then through the Inventory Grid's Item View Slots Container events.
7. Inventory updates schedule another draw; multiple matching grids can copy index data before redrawing.

The Inventory Grid's `Draw()` is deferred by the container until `LateUpdate`. `ForceDraw()` performs the container draw immediately, while `Grid.Draw()` draws the currently supplied ItemInfo sequence immediately.

## Editor checkpoint

Before entering Play Mode, confirm that:

- the generated panel belongs to the project schema, not package assets;
- the Inventory Grid references its Item Info Grid;
- **Grid Size** matches the intended number of slots and the Grid Layout Group constraint;
- Grid Event System has a compatible **Button Prefab**, **Content**, and Grid Layout Group;
- Item View Drawer has the intended Category Item View Set;
- the panel binding resolves the character's Inventory;
- a Bag-only grid has an Item Collection filter for Bag;
- every tab has Inventory Tab Data and the intended filter chain;
- the Grid Navigator references this Item Info Grid and its controls;
- Item Action and description bindings target the same container; and
- drag or non-pointer movement has every required cursor/drop component.

## Verify in Play Mode

1. Open Bag and confirm slot `0` is selected and the correct character's Items appear.
2. Add Health Potion and Iron Sword to Bag. Both should appear once, while equipped or hidden collections remain excluded.
3. Page or scroll beyond the first visible range, then return. Selection and the Item Description should match the newly visible `ItemInfo`.
4. Switch between All, Consumables, and Weapons tabs. Health Potion and Iron Sword should appear only in the expected results, with no stale slot content.
5. Search for `sword`, clear the search, and confirm compact search results return to the previous indexed layout.
6. Sort by name or amount and verify whether the configured one-time or bound behavior is retained on redraw.
7. Move Iron Sword to an empty visual index, close and reopen the panel, and verify the configured reset/compaction behavior.
8. Drag Iron Sword to a valid Equipment slot and confirm the Inventory transaction updates both panels. Reject an invalid drop without losing the Item.

## Save and network boundaries

Save the Inventory contents with the Inventory save workflow. Add **Inventory Grid Saver** when indexed positions—and each tab's indexer—must survive a save/load cycle. That saver stores grid index data, not the Inventory itself, current selection, current tab, search text, or panel focus.

Inventory Grid Index Data shares positions between matching grids during the current runtime. It is not a replacement for Inventory Grid Saver across sessions.

Version 1 Inventory Grid does not replicate Inventory changes or grid ordering. A networking layer must authorize and synchronize the underlying Inventory transaction. Refresh the local grid after synchronized data arrives, and synchronize visual index data separately only if every client must see the same manual layout.

## Troubleshooting

- **The grid is empty:** Check the panel binding's Inventory source, then remove filters temporarily. Inventory Grid reads `Inventory.AllItemInfos` before filtering.
- **Equipment Items appear in Bag:** Add or correct **Item Info Item Collection Filter** and include only Bag in **Show Item Collections**.
- **The wrong player's Inventory appears:** Check Panel Owner, **Bind To Panel Owner Inventory**, explicit **Inventory**, and **Bind To Inventory By Identifier**.
- **There are too few or too many slots:** Set **Grid Size** before Play Mode and confirm Grid Event System **Content** and the Grid Layout Group constraint match it.
- **Empty slots disappear unexpectedly:** Check **Set Real Element Count As Max** and **Disable Element Option**.
- **Sorting appears to be ignored:** Check **Use Grid Index**. Indexed ordering can intentionally preserve manual positions; disable it for a continuously sorted list or use a one-time index sort.
- **Changing tabs leaves no valid description:** Enable **Select Slot 0 On Change Tab** and confirm the selected tab has Inventory Tab Data.
- **Next/previous tab input does nothing:** Confirm the grid has a parent Display Panel, that panel is selected, its owner supplies player input, and the input names match `Next` and `Previous` or the configured replacements.
- **Dragging raises events but no Item moves:** **Draggable** only forwards pointer events. Add and configure the Cursor Manager, Drop Handler, Drop Action Set, and Drag Handler.
- **Items move visually but return after loading:** Add Inventory Grid Saver and ensure the Inventory itself loads before grid index data is restored.
- **Two grids unexpectedly share positions:** Give them different Grid IDs or leave **Grid ID** at `-1`; matching Inventory, Grid ID, and tab ID share ordering.

## Related pages

- [Create an Inventory Grid with UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/inventory-grid/)
- [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/)
- [Item Info Filter and Sorters](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-info-filter-sorters/)
- [Move Items (Drag and Drop)](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/move-items-drag-drop/)
- [Item Description](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-description/)
- [Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/)
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)

## Developer details

- `InventoryGrid.Grid`, `GridID`, `TabID`, `FilterSorter`, `UseGridIndex`, and `InventoryGridIndexer` expose the current grid state.
- `SetInventory(Inventory)` changes the source and registers for Inventory updates.
- `FilterAndSortItemInfos(bool notify = true)` returns the sequence that will be drawn and optionally notifies matching grids.
- `BindGridFilterSorter(IFilterSorter<ItemInfo>)` returns the previously bound filter/sorter. `SortItemIndexes(Comparer<ItemInfo>)` changes the indexer's order.
- `RemoveEmptyIndexedItems()` compacts the indexer. `MoveItem(sourceIndex, destinationIndex)` swaps visual Item Stack indices and schedules a draw.
- `AddItem(ItemInfo, index)` adds through the Inventory, records the returned Item Stack at the index, and schedules a draw. `RemoveItem(ItemInfo, index)` removes through the Inventory; the index parameter does not select a different collection.
- `Grid.StartIndex`, `Grid.EndIndex`, `Grid.SetIndex(...)`, and `SlotIndexOffset` describe the current visible slice.
- Item Info Grid events include `OnElementSelected`, `OnElementClicked`, `OnEmptySelected`, `OnEmptyClicked`, and pointer/drag events. Container-level events remain available for shared bindings.
- Grid Event System exposes unavailable-navigation events for all four directions, allowing navigators or tabs to respond when Unity navigation cannot move to another visible slot.

---

<a id="page-ultimate-inventory-system-ui-item-view-slots-container-inventorygrid-item-shape-inventory-grid"></a>

# Item Shape Inventory Grid

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/inventorygrid/item-shape-inventory-grid/)

In released Ultimate Inventory System Version 1, the component for a spatial inventory is named **Item Shape Grid**. Use it when an Item should occupy several cells in a finite Bag, such as a one-cell Health Potion beside a tall Iron Sword. Use a regular [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/inventorygrid/) when every Item occupies one equal slot.

An Item Shape Grid is not an Inventory Grid with an extra binding. It combines an `ItemShape` attribute, placement data beside the Inventory, a shape-aware runtime view, and shape-aware movement rules. The [UI Designer Item Shape Grid workflow](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-shape-grid/) is the safest way to create those parts together.

![A runtime Item Shape Grid with differently sized items arranged across a finite grid of cells.](https://opsive.com/wp-content/uploads/2021/01/Item-Shape-Grid.png?v=a104f8e7b404)

## Before you begin

Prepare:

- an Inventory System Database with a `Shape` Item Definition Attribute of type `ItemShape`;
- Item Definitions such as Health Potion and Iron Sword;
- a player Inventory with a **Bag** Item Collection;
- a UI Designer canvas and duplicated schema; and
- enough screen space for the intended number and pixel size of cells.

The generated grid binds to one Inventory. Its placement data belongs beside that Inventory, not on the UI panel.

## Define each Item shape

1. In the Item Category editor, add `Shape` as an `ItemShape` in the **Item Definition** attribute collection.
2. Open Health Potion and leave its shape at one cell.
3. Open Iron Sword, use **Columns** and **Rows** to create its footprint, and enable **Use a custom shape?** only if it should not occupy a complete rectangle.
4. Enable every occupied cell. Right-click an enabled cell and choose **Set Anchor** to define the cell that follows the pointer or selected destination.
5. Repeat with a clearly different footprint for Fire Wand when testing irregular shapes.

The anchor must remain on an enabled cell. The editor prevents the anchor cell from being disabled. If an Item has no `Shape` value, or its shape contains only one cell, the grid treats it as a one-cell Item.

![An ItemShape Attribute editor with row and column controls, enabled footprint cells, and an anchor cell.](https://opsive.com/wp-content/uploads/2020/11/ItemShapeAttribute.webp?v=846ec6adac5d)

Version 1 stores a fixed footprint and anchor; it does not provide a rotate command or rotation field. If the design needs rotated placement, author a separate rotated shape and implement the choice and placement rules as a customization.

## Create the spatial Bag in UI Designer

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer**.
2. Select **Item Shape Grid**, then open **Create**.
3. Assign the intended **Parent Transform** and choose a **Panel Option**. The creator starts with **Simple**.
4. Set **Panel Name** and **Grid Name** to stable names such as `Spatial Bag`.
5. Assign the player's **Inventory**.
6. Set **Grid Size**. The creator starts at 8 by 8 cells.
7. Set **Item Shape Size**, the pixel size of one cell. The creator starts at 100 by 100 pixels.
8. Choose **Bag** under **Item Collection**. Use the all-collections choice only when every applicable collection should share this placement grid.
9. Create the grid.

UI Designer creates the panel and Item Shape Grid, adds an **Item Shape Grid Controller** and matching **Item Shape Grid Data** beside the Inventory when needed, and adds an **Item View Slots Container Panel Binding** that supplies that Inventory to the panel. The older **Inventory Grid Item Shape Binding** shown in early documentation is not part of the released Version 1 setup.

## Match the Inventory data to the view

The Item Shape Grid resolves its data from the bound Inventory by **Item Shape Grid Data ID**. The first generated grid uses ID `0`. Give every additional data entry a unique ID, and use different Item Collections or filters when an Inventory has more than one spatial grid.

![An Inventory Inspector with Item Shape Grid Controller and Item Shape Grid Data configured together.](https://opsive.com/wp-content/uploads/2021/01/ItemShapeGridController-And-Data_v1_1_4.png?v=f62aa1647e32)

Check these values before editing the generated hierarchy by hand:

| Setting | Released Version 1 behavior |
| --- | --- |
| **Shape Attribute Name** | Defaults to `Shape`. It must match the attribute name used by the Item Definitions and Item View modules. |
| **Item Shape Grid Data ID** / **ID** | Connects the UI grid to one data entry on the bound Inventory. |
| **Grid Size** | Must match on Item Shape Grid and Item Shape Grid Data. |
| **Item Collections** | Limits the data entry to named collections such as Bag. With no collections specified, it uses the Inventory's collections. |
| **Item Info Filter** | Optionally narrows which Items this data entry accepts. |
| **Only Try Add To First Collection** | Off by default. When off, the data tries its connected collections in order until one accepts the Item. |
| **Smart Two Way Move** | Off by default. Turn it on only when Items should exchange positions within the same grid when both footprints fit. |
| **No Grid Add Item** | Off by default. With it off, the controller rejects an add when no matching grid has room. |
| **Warn If Multiple Match** | Off by default. Turn it on while configuring multiple grids so overlapping collection or filter rules are visible. |

![The Item Shape Grid Inspector showing its data ID, grid and cell sizes, view-slot prefab, drawer, foreground content, layout, and navigation fields.](https://opsive.com/wp-content/uploads/2021/01/ItemShapeGridInspector.png?v=bc10d783f6dd)

The UI **Grid Size** controls the number of Item View Slots, while **Item Shape Size** controls the size of each cell. UI Designer updates the linked objects together. If their sizes differ at runtime, the Item Shape Grid reports an error and cannot map the data cells reliably.

## Keep the two view layers aligned

The generated view uses two aligned layers:

1. The background has one interactive Item View Slot per cell. Selection and drop feedback color all cells occupied by the Item.
2. The foreground draws one coherent Icon across the complete footprint. It should not intercept input intended for the background slots.

Keep **Item Shape View Content** assigned to the foreground content transform and keep the Item View Drawer's **Content** assigned to the background slots. Both layers must use the same cell size and origin.

![An Item View Inspector with the Item Shape Item View and shape selection and drop-preview modules used by a spatial grid.](https://opsive.com/wp-content/uploads/2021/01/ItemShapeItemViewInspector_v_1_1_4.png?v=846763cda888)

The schema's shape-aware Item View includes:

- **Item Shape Item View**, which sizes and positions the foreground Icon from the `Shape` value;
- **Item Shape Drop Preview Item View**, which colors the prospective occupied cells for a valid or invalid drop;
- **Item Shape Selected Item View**, which highlights the complete selected footprint;
- **Item Shape Rect Placer Item View**, which places a child such as an amount label inside an irregular footprint; and
- **Canvas Group**, which lets the foreground visual stop intercepting input.

Do not replace this prefab with a normal one-cell Item View unless the replacement retains the shape-aware modules and uses the same `Shape` attribute name.

## Configure movement and drag-and-drop

For pointer drag-and-drop between containers, keep the shape schema's **Item View Shape Drop** condition and action in the Item View Slot Drop Action Set. The condition tests the complete footprint at the destination; the action removes and adds the involved ItemInfo values only after the exchange fits. Same-grid movement uses the Item Shape Grid's own move rules.

The source Item's anchor offset is preserved while it moves, so grabbing a non-anchor cell does not make the Icon jump. With **Smart Two Way Move** off, an occupied destination is not exchanged within the same grid. With it on, both Items move only when both complete footprints fit in the other's position.

There is no built-in runtime rotation step. Movement tests the authored orientation exactly as it appears in the `Shape` attribute.

## How placement and stacking run

The Item Shape Grid Controller is also an Inventory restriction. Before an Item is added, it selects data whose Item Collection and optional filter match, then checks for a free footprint. New placements scan the grid from the top-left, row by row. If an Item moves between collections during one frame, the data can reuse its recent position.

An ItemStack occupies its footprint once, regardless of its amount. A non-unique, stackable-equivalent Item can join a compatible existing stack without consuming another footprint when the receiving collection accepts the full amount. A unique Item, a non-equivalent Item, or an Item that cannot join the stack needs its own available footprint.

The controller listens to Inventory add and remove events to place and clear ItemStacks. Hide and Loadout collections are ignored by the shape controller. If application code bypasses the controller's restriction and adds an Item when no position exists, Version 1 logs a warning and the Item has no grid placement.

## Save and network the layout deliberately

Inventory saving and spatial layout saving are separate concerns. Add **Item Shape Grid Data Saver** for each data entry whose cell positions must persist, and save the Inventory that owns the referenced ItemStacks. On load, the Inventory Items must exist and the saved cell count must match the current grid size before the saver can rebuild the layout.

Released Version 1 does not include shape-grid-specific network replication. A multiplayer implementation must synchronize both the Inventory transaction and the authoritative Item Shape Grid Data; synchronizing only the UI does not synchronize placement.

## Editor checkpoint

Before entering Play Mode, confirm that:

- Health Potion and Iron Sword resolve `Shape` values through the exact configured name;
- every custom footprint has an anchor on an enabled cell;
- the panel binding references the Inventory that owns the controller and data;
- **Item Shape Grid Data ID** matches one **ID** on that Inventory;
- **Grid Size** matches between the Item Shape Grid and Item Shape Grid Data;
- **Item Collections** includes Bag and does not unintentionally include Equipment;
- the foreground and background content transforms are aligned; and
- the Item View prefab retains its shape, selection, drop-preview, placement, and Canvas Group modules.

## Verify in Play Mode

1. Open the Bag. Confirm that Health Potion occupies one cell and Iron Sword covers its authored footprint.
2. Add another Health Potion. If it joins the same stack, confirm that no second footprint appears.
3. Drag Iron Sword to an open area. Confirm that the preview and final placement cover the same cells and preserve the grabbed-cell offset.
4. Hover Iron Sword over an occupied area and the grid edge. Confirm that the invalid preview prevents the drop.
5. Move Iron Sword onto another Item with **Smart Two Way Move** off, then on. Confirm that an exchange occurs only in the enabled case and only when both footprints fit.
6. Move Iron Sword from Bag to Equipment and back. Confirm that the Bag cells clear and are reclaimed without a ghost footprint.
7. Save, move the Items, then load. Confirm that both the ItemStacks and their cell positions return.

## Troubleshooting

- **Every Item occupies one cell:** Check that `Shape` is an `ItemShape` Item Definition Attribute, that each definition has a value, and that **Shape Attribute Name** matches on the controller and Item View.
- **The grid is empty:** Check the panel binding's Inventory, **Item Shape Grid Data ID**, the data **ID**, **Item Collections**, and **Item Info Filter**.
- **The console reports different grid sizes:** Check **Grid Size** on both Item Shape Grid and Item Shape Grid Data, then resize through UI Designer so the slot count also updates.
- **An Item is offset or clipped:** Check its anchor, **Item Shape Size**, **Item Shape View Content**, the Item View Drawer content, and the two layers' Rect Transforms.
- **The preview covers the right cells but the drop fails:** Check that the drop action set contains both the shape-aware condition and action and that the destination resolves the expected grid data.
- **Items exchange when they should not, or never exchange:** Check **Smart Two Way Move** and test whether both complete footprints fit at the two anchor positions.
- **An added Item is in the Inventory but not in the grid:** Check for the no-place warning, overlapping grid filters, and code that added the Item without respecting the controller restriction.
- **Positions reset after loading:** Check that both the Inventory and every required Item Shape Grid Data have savers, that they load in a compatible order, and that the grid dimensions have not changed.
- **Remote players see different positions:** Check the multiplayer authority and synchronize Item Shape Grid Data in addition to Inventory transactions; Version 1 has no built-in shape-grid replication.

## Developer details

`ItemShapeGridController.GetGridDataWithID` resolves the data used by the UI. `ItemShapeGridData.TryFindAvailablePosition`, `IsPositionAvailable`, `AddItemToPosition`, and `TryMoveIndex` expose the placement operations. `ItemShapeGridDataSaver` serializes each cell's ItemStack identity and anchor state.

The controller subscribes to the Inventory add and remove events; it does not publish a separate shape-grid placement event. Custom systems that move Items directly should use the grid or data APIs so the footprint remains consistent with the Inventory.

## Related pages

- [UI Designer Item Shape Grid](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-shape-grid/)
- [Runtime Item Shape Grid component](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-shape-grid/)
- [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/inventorygrid/)
- [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/)
- [Move Items with drag-and-drop](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/move-items-drag-drop/)
- [Common attribute types](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/common-attribute-types/)
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/)
- [Save system](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)

---

<a id="page-ultimate-inventory-system-ui-item-view-slots-container-item-hotbar"></a>

# Item Hotbar

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-hotbar/)

Use an Item Hotbar when the player should assign quick-access slots to Items that remain in the Inventory. A Health Potion can stay in **Bag** while slot 1 uses it, and a Fire Wand can stay in the same collection while another slot invokes its configured Item Action.

The hotbar stores monitored `ItemInfo` assignments; it is not another Item Collection. Assigning, moving, or clearing a hotbar slot does not by itself add, remove, or transfer an Item in the Inventory.

![A runtime Item Hotbar displaying assigned Item icons in a horizontal row of quick-access slots.](https://opsive.com/wp-content/uploads/2020/11/ItemHotbar.png)

## Choose the hotbar behavior

Version 1 includes three useful patterns. The [built-in hotbar patterns](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-hotbar/hotbars/) page provides the short comparison; choose the data model before styling the UI.

| Pattern | What its slots represent | Use it when |
| --- | --- | --- |
| **Item Hotbar** | Assignments that monitor Items in the bound Inventory | Health Potion should remain in Bag while a key uses it. |
| **Inventory Mirror Hotbar** | A window onto consecutive entries from an Inventory Grid | The quick bar should always reflect the grid's current filtered and sorted order. |
| [**Item Slot Collection View**](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-slot-collection-view-equipment/) | Items held by a dedicated Item Collection | A slot must own an equipped or loadout Item rather than monitor Bag. |

This page describes **Item Hotbar**. `InventoryMirrorHotbar` forwards movement and add/remove operations to its assigned Inventory Grid. An Item Slot Collection View uses collection rules and ownership instead.

## Before you begin

Prepare:

- a player Inventory with a **Bag** collection and test Items such as Health Potion and Fire Wand;
- an Item User and Item Actions that already work from the Inventory UI;
- a UI Designer canvas and duplicated schema;
- one player-input component that implements `IPlayerInput` beneath the bound Inventory; and
- a decision about whether assignments must survive save and load.

Test the Health Potion and Fire Wand actions from Bag first. This separates an Item Action or Item User problem from a hotbar assignment or input problem.

## Create the Item Hotbar in UI Designer

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer** and select **Hotbar**.
2. In **Create**, assign the intended **Parent Transform**.
3. Set **Number of Slots**. The creator starts with `3`.
4. Keep **Hotbar Type** set to **Item Hotbar**. This is the creator default.
5. Create the hotbar from the duplicated schema.
6. In **Edit > Hotbar Options**, add or remove Item View Slots until the row has the intended size.
7. Keep the slots in the intended hierarchy order. The container assigns zero-based indexes in that order at runtime.
8. Confirm that the generated **Item View Slots Container Panel Binding** binds to the panel owner's Inventory.

The generated panel starts open and uses its panel binding to initialize, draw, and select the hotbar. The Item Hotbar itself can leave **Inventory** unassigned in the prefab when the panel binding supplies it at runtime.

At this editor checkpoint, the hotbar has a stable slot count and order, the panel resolves the correct player Inventory, and the first quick-use input targets slot index `0`.

## Check the runtime components

The schema creates an Item Hotbar, Item View Drawer, category action-set binding, and Item Hotbar Handler. Keep them on the generated objects unless a replacement provides the same responsibilities.

![The Item Hotbar Inspector with the Item Actions Binding and assignment-refresh settings used by the quick-access slots.](https://opsive.com/wp-content/uploads/2020/05/ItemHotbarInspector.png?v=797a5932171d)

Important released Version 1 settings are:

| Component and setting | Default or generated behavior |
| --- | --- |
| Item Hotbar > **Item Actions Binding** | Required. If empty, the component looks for an Item View Slots Container Item Action Binding on the same GameObject. |
| Item Hotbar > **Remove Item If Amount Is 0** | Off by default. When enabled, a monitored assignment clears after no matching Item remains in the Inventory. |
| Item View Slots Container > **Container Name** | The schema uses `Hotbar`. Keep names distinct when code looks up several containers. |
| Item View Slots Container > **Slot Cursor ID** | Defaults to `1` when no Slot Cursor reference is assigned. |
| Item View Slots Container > **Draw On Enable** | Off by default; the panel binding handles the initial draw. |
| Item View Slots Container > **Draw On Inventory Update** | On by default so amounts and runtime Item state refresh after Inventory changes. |
| Item View Slots Container > **Swap Item View On Assign** | Enabled by the supplied schema so the Item View Drawer can choose the matching prefab for the assigned Item. |
| Category Item Action Set Binding > **Use Item On Click** | On by default. Clicking or submitting a slot invokes the configured action path. |
| Category Item Action Set Binding > **Use Item Action Index** | The base component defaults to `-1`, which invokes all matching actions. The supplied hotbar schema sets it to `0`, the first action. |
| Category Item Action Set Binding > **Auto Set Item User** | On by default. The binding uses the bound Inventory's Item User. |
| Category Item Action Set Binding > **Max Number Of Actions** | Defaults to `5`. Increase it only when a category can expose more actions through this binding. |

Keep the Item View Drawer **Content** and the Item Hotbar **Content** on the same slot parent. Keep **Use View Slots** enabled and assign a Category Item View Set that can display both Health Potion and Fire Wand.

## Configure what each slot uses

`ItemHotbar.UseItem(index)` delegates to the Item Actions Binding. With the supplied Category Item Action Set Binding, the assigned Item's category chooses the available actions.

- Set **Use Item Action Index** to the one action that quick input should invoke. The schema value `0` invokes the first matching action.
- Use `-1` only when every matching action should run from one input. This is rarely appropriate for a hotbar with several unrelated actions.
- Leave **Use Item On Click** enabled when pointer click or UI submit should behave like the indexed shortcut.
- Use an **Action Panel** only when choosing among actions after selecting the slot is intentional.
- Give Health Potion a quick-use action and give Fire Wand the project's intended use or equip action. Assigning either Item must not invoke the action immediately.

The Item Hotbar refreshes every assigned slot before drawing. It first checks the original Item Collection for the current amount, then looks elsewhere in the same Inventory for the same Item if that collection no longer contains it. With **Remove Item If Amount Is 0** off, a missing Item can remain assigned with amount `0`; with it on, the slot clears.

## Configure indexed input

**Item Hotbar Handler** polls an array of **Hotbar Input** entries. The supplied defaults map indexes `0` through `9` to **Equip First Item** through **Equip Tenth Item**, using **Button Down**.

1. Keep **Item Hotbar** assigned, or leave it empty when the handler is on the same GameObject and should find that component at startup.
2. Keep only the **Hotbar Input** entries used by the visible slots.
3. Match each entry's **Index** to the intended zero-based slot.
4. Define the named inputs in the chosen Opsive player-input implementation.
5. Test keyboard, controller, or the installed input integration separately.

The handler finds `IPlayerInput` under the bound Inventory. If it cannot find one, it disables itself. It also listens for the character's **Enable Gameplay Input** event, so the built-in shortcuts stop while that player's gameplay input is disabled.

## Let the player assign and clear slots

The supplied `AssignHotbarItemAction` is a demo Item Action that opens an asynchronous integer-choice panel and assigns the selected slot.

1. Add **Assign Hotbar Item Action** to an Item Action Set available from the Bag UI.
2. Assign a compatible **Async Func Action Panel Prefab**. The supplied integer panel returns a slot index and uses `-1` for cancel.
3. Keep **Hotbar Panel Name** equal to the generated panel's exact name. Its default is `Item Hotbar`.
4. Set **Display Panel Manager ID** to the correct manager when the scene has more than one. Its default is `0`, which can fall back to the action's parent panel manager or a scene lookup.
5. Enable **Toggle Assign** when choosing the same Item and slot again should clear the assignment. It is off by default.
6. Enable **Show Item Names** when the choice list should show the current assigned names instead of slot numbers. It is off by default.
7. Leave **Use Item View Slot If Available** enabled when the panel buttons are Item View Slots and should show their current assignments. It is on by default.

Use `UnAssignHotbarItemAction` from the hotbar for an explicit clear action. It calls `UnAssignSlot` and leaves the Item in its Inventory collection.

For drag-and-drop, use the standard smart-exchange condition and action supplied by the schema. Version 1 treats a destination Item Hotbar as an assignment target and does not remove the source Item from the same Inventory. Use `ItemViewDropContainerRemoveAction` when dragging away from the hotbar should clear the source assignment; its **Remove From Source Container** setting is on by default.

## Save assignments when required

Hotbar assignments are UI container state. Saving the Inventory alone preserves the Items but not necessarily the slot mapping.

Add **Item View Slots Container Saver** to the hotbar when assignments must persist, and assign its **Item View Slots Container** reference. When the reference is empty, the saver looks for a container on the same GameObject. It stores an ItemStack identity for every slot and restores each match from the bound Inventory by index.

The Inventory must also have its normal saver, and its ItemStacks must exist before the hotbar mapping is restored. Give each local player's saver a distinct Full Key through a distinct GameObject name, Saver **Key**, or both.

## Keep player ownership explicit

For local multiplayer, create one hotbar panel per player. Bind each panel to that player's Inventory, keep its Item Hotbar Handler with that player's `IPlayerInput`, and route `AssignHotbarItemAction` to that player's Display Panel Manager. The same panel name can be reused inside different managers, but a global manager lookup must not choose another player's hotbar.

Item Hotbar assignments are local runtime UI state. Released Version 1 does not include hotbar-assignment network replication. A networked game must synchronize the authoritative assignment separately and validate the invoked Item Action on the owning player or server. Synchronizing the Inventory alone does not reproduce the slot mapping.

## Editor checkpoint

Before entering Play Mode, confirm that:

- **Hotbar Type** is Item Hotbar rather than Inventory Mirror Hotbar;
- the number and hierarchy order of Item View Slots match the indexed inputs;
- the panel binding resolves the intended player Inventory;
- **Item Actions Binding**, Category Item Action Set, Item User, and Item View Drawer are assigned;
- **Use Item Action Index** invokes only the intended quick action;
- the Item Hotbar Handler can find the correct player's `IPlayerInput`;
- **Hotbar Panel Name** and **Display Panel Manager ID** resolve the intended panel;
- assignment and drop actions monitor Items instead of transferring them from Bag; and
- Item View Slots Container Saver is present only when assignments must persist.

## Verify in Play Mode

1. Assign Health Potion from Bag to slot 1. Confirm that the Item remains in Bag and its Icon and amount appear in the hotbar.
2. Press the first indexed input. Confirm that the intended Health Potion action runs once and the displayed amount refreshes.
3. Assign Fire Wand to slot 2. Confirm that the second input invokes only its intended Item Action.
4. Reassign Health Potion to another slot with **Toggle Assign** enabled, then choose the same slot again. Confirm that the expected slot moves or clears without moving the Item from Bag.
5. Drag an Item from Bag onto the hotbar, then drag it away using the remove action. Confirm that only the assignment changes.
6. Remove all Health Potions from the Inventory. Test **Remove Item If Amount Is 0** both off and on and confirm the zero-amount or cleared result.
7. Disable gameplay input by opening the configured menu. Confirm that hotbar shortcuts stop for that player and resume afterward.
8. If saving is configured, save, change the assignments, then load. Confirm that the assigned ItemStacks return to the same slot indexes.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| The hotbar is empty after assignment | Panel binding Inventory, Item View Slots, Content, and Category Item View Set | Bind the correct Inventory and restore the generated slot and drawer references. |
| Pressing a shortcut does nothing | Item Hotbar Handler, `IPlayerInput`, input name/type, slot index, and gameplay-input state | Use the intended player's input component, correct the index, and confirm gameplay input is enabled. |
| The wrong slot fires | Hotbar Input **Index** values and Item View Slot hierarchy order | Make both zero-based orders match. |
| One press invokes several actions | Category Item Action Set and **Use Item Action Index** | Select one action index instead of `-1`, or simplify the category's hotbar actions. |
| Assign Hotbar Item Action cannot find the hotbar | **Display Panel Manager ID**, **Hotbar Panel Name**, and panel binding | Route the action to the correct manager and use the panel's exact name. |
| The assignment panel does not open | **Async Func Action Panel Prefab** and parent Display Panel | Assign a compatible integer action panel prefab and invoke from a bound panel context. |
| Assigning removes the Item from Bag | Hotbar type and drag/drop action set | Use Item Hotbar and its smart-assignment path, not a give/exchange action or collection-backed view. |
| Clearing a slot removes the Item | Unassign action and drop remove target | Use `UnAssignHotbarItemAction` or remove from the hotbar source container only. |
| The amount does not refresh | **Draw On Inventory Update**, bound Inventory, and original Item Collection | Enable redraw on Inventory update and bind the hotbar to the Inventory that owns the Item. |
| A missing Item remains with amount 0 | **Remove Item If Amount Is 0** | Enable it when assignments should clear as soon as no matching Item remains. |
| Assignments disappear after loading | Item View Slots Container Saver, Inventory saver, load order, and Saver Full Keys | Save both states, load Inventory ItemStacks first, and give each saver a unique key. |
| Player two uses player one's hotbar | Panel-owner Inventory, Display Panel Manager ID, and player input ownership | Give each player a separate bound panel, manager route, handler, and saver key. |

## Related pages

- [Built-in hotbar patterns](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-hotbar/hotbars/)
- [UI Designer Hotbar](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-hotbar/)
- [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/)
- [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/inventorygrid/)
- [Item Slot Collection View](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-slot-collection-view-equipment/)
- [Move Items with drag-and-drop](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/move-items-drag-drop/)
- [Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/)
- [Built-in Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/built-in-item-actions/)
- [Input](https://opsive.com/support/documentation/ultimate-inventory-system/input/)
- [Split-screen co-op UI](https://opsive.com/support/documentation/ultimate-inventory-system/input/split-screen-co-op-ui/)
- [Save system](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)

## Developer reference

The main runtime methods are `AssignItemToSlot`, `ToggleAssignItemToSlot`, `UnassignItemFromSlots`, `UnAssignSlot`, and `UseItem`. `ItemHotbar.CanGiveItem` always returns `false`, which is the ownership boundary that distinguishes monitored assignments from a collection-backed container.

```csharp
hotbar.AssignItemToSlot(itemInfo, 0);
hotbar.UseItem(0);
hotbar.UnAssignSlot(0);
```

`ItemViewSlotsContainerBase` exposes Inventory bind/unbind, slot selection, click, pointer, draw, and reset events. Assignment itself does not publish a dedicated hotbar-changed event in Version 1. `ItemHotbarHandler` listens for `c_CharacterGameObject_OnEnableGameplayInput_Bool` to gate indexed input, while `ItemViewSlotsContainerSaver` serializes and restores the slot-to-ItemStack mapping.

---

<a id="page-ultimate-inventory-system-ui-item-view-slots-container-item-hotbar-hotbars"></a>

# Hotbars

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-hotbar/hotbars/)

Choose a hotbar by deciding what each visible slot represents. A quick-use slot can monitor a Health Potion that remains in **Bag**, mirror an Inventory Grid entry, hold a Fire Wand in a dedicated Item Collection, or expose a project-specific Item workflow.

Released Ultimate Inventory System Version 1 supplies two choices in **UI Designer > Hotbar**, an Equipment-style alternative in **UI Designer > Equipment**, and base components for a custom implementation.

## Compare the hotbar patterns

| Pattern | What the slot owns | Best fit | What changes when the player assigns an Item |
| --- | --- | --- | --- |
| **Item Hotbar** | A monitored `ItemInfo` assignment | Health Potion stays in Bag while a numbered key uses it. | Only the hotbar assignment changes. The Item does not move between collections. |
| **Inventory Mirror Hotbar** | A view of consecutive filtered and sorted Inventory Grid entries | The first few Inventory Grid entries should always be the quick bar. | The underlying Inventory Grid changes; the hotbar redraws from that grid. |
| **Item Slot Collection View** | An Item in a dedicated Item Slot Collection | Fire Wand must occupy a Weapon, Equipment, loadout, or other fixed slot. | The Item moves into the configured Item Collection. |
| **Custom container** | Whatever ownership rule the project implements | An ability-style bar or another rule that the three supplied patterns do not express. | The custom `ItemViewSlotsContainerBase` subclass decides. |

The supplied **Hotbar** creator builds only **Item Hotbar** and **Inventory Mirror Hotbar**. Use the **Equipment** creator for an Item Slot Collection View. A custom container must be added and configured manually.

## Before you begin

Prepare one small comparison fixture:

- a player Inventory with a **Bag** collection;
- Health Potion and Fire Wand Items with working Item Actions;
- an Inventory Grid bound to Bag;
- a UI Designer canvas created from a duplicated schema;
- an `IPlayerInput` implementation for the owning player; and
- an Inventory saver if Items must survive save and load.

Test both Item Actions from the Inventory UI first. This separates an Item Action or Item User problem from a hotbar ownership, binding, or input problem.

The supplied Feature Demo scenes also show the patterns independently: **6 Hotbar**, **6_1 Inventory Mirror Hotbar**, **6_2 Shared Inventory With Mirror Hotbar**, and **6_3 Hotbar Unassign slot**.

## Create a monitored Item Hotbar

Use this pattern when the player chooses quick-access assignments but the Items should remain in Bag.

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer** and select **Hotbar**.
2. Set **Number of Slots**. The creator defaults to `3`.
3. Keep **Hotbar Type** set to **Item Hotbar**, the creator default.
4. Create the panel and confirm that its panel binding resolves the intended player's Inventory.
5. In **Hotbar Options**, add or remove Item View Slots and keep their hierarchy order aligned with the intended input indexes.
6. Assign Health Potion or Fire Wand with `AssignHotbarItemAction` or the supplied smart drag-and-drop path.

The Item Hotbar monitors the assigned ItemStack. Its amount refreshes from the bound Inventory, but assigning or clearing the slot does not transfer the Item. **Remove Item If Amount Is 0** is off by default; enable it when a monitored slot should clear after no matching Item remains.

The generated **Item Hotbar Handler** uses **Hotbar Input** entries for indexes `0` through `9`. The supplied entries are **Equip First Item** through **Equip Tenth Item**, all using **Button Down**. Each input invokes the configured Item Actions Binding for its zero-based slot.

## Create an Inventory Mirror Hotbar

Use this pattern when the quick bar should always show a slice of an Inventory Grid rather than store independent assignments.

1. In **UI Designer > Hotbar**, set **Hotbar Type** to **Inventory Mirror Hotbar**.
2. Set **Number of Slots** and create the panel.
3. On Inventory Mirror Hotbar, assign **Inventory Grid To Mirror**. The component requires this reference even when an ID is also used.
4. Keep **Inventory Grid ID To Mirror** at its default `0`, or set it to the shared grid ID that should trigger updates.
5. Set **Start Index**. Its default `0` displays the first filtered and sorted entry in the first hotbar slot.
6. Enable **Prevent Move To Grid** or **Prevent Move From Grid** only when drag-and-drop should be one-way.

The mirror calls the Inventory Grid's filter and sorter, then displays one consecutive entry per visible slot. Moving, adding, removing, or unassigning through the mirror is forwarded to the Inventory Grid. The display continues to respond to matching Inventory Grid updates even while the grid panel is closed.

This pattern is order-dependent. A sorter, filter, grid ID, or **Start Index** change can make a different Item appear under the same numbered input without creating a new hotbar assignment.

## Create a collection-backed hotbar

Use an Item Slot Collection View when a quick slot must own an Item. This is the same runtime view used for Equipment, but its Item Collection can be a project-specific collection such as `Hotbar Collection`.

1. Create an Item Slot Set with one entry for each quick slot. Use narrow categories where the slot is meaningful, such as Consumable for Health Potion or Weapon for Fire Wand.
2. Add an Item Slot Collection to the player Inventory and assign that Item Slot Set.
3. Open **UI Designer > Equipment** and choose the same **Item Slot Set**. The creator requires a set from the current database.
4. Create the Item Slot Collection View, then set **Item Collection ID** to the new collection rather than the default Equipped purpose.
5. Confirm that **Set Item View Slot Restrictions** and **Add View Slot Category Restrictions** produce the intended category rule for every visible slot.
6. Add an Item Actions Binding for the action that each slot should invoke.
7. Add **Item View Slot Container Indexed Actions Handler** and assign **Item View Slots Container**, **Item Actions Binding**, and the **Input** entries.

The indexed handler defaults to the same ten **Equip First Item** through **Equip Tenth Item** inputs using **Button Down**. Unlike Item Hotbar Handler, it looks for `IPlayerInput` on the bound Inventory GameObject itself, so assign references explicitly when the input component lives elsewhere.

Dragging Health Potion or Fire Wand into this view moves the Item into its Item Slot Collection. Clearing a slot must move or remove the Item according to the configured Item Action or drag-and-drop action; `UnAssignHotbarItemAction` is only for Item Hotbar assignments.

An Item Slot Collection View does not automatically equip a character model or apply game-specific effects. An Equipper or the project's own Item logic handles those results.

## Build an ability-style or custom hotbar

Use a custom container only when the ownership rule cannot be represented by monitored Items, a grid slice, or an Item Slot Collection. For example, a project that represents abilities as Items might display a Fire Wand action beside non-Inventory commands while keeping one shared indexed-input row.

Derive the runtime container from `ItemViewSlotsContainerBase`, then define how it gets, adds, removes, and moves its entries. Reuse the Item View Drawer, Item View Slots, Item Actions Binding, drag-and-drop actions, and container events where their Item semantics still apply. Add **Item View Slot Container Indexed Actions Handler** when each visual index should trigger an Item Action, or implement project-specific input when a slot is not an Item.

Do not use a custom container merely to change colors, spacing, icons, or slot count. Those are view and UI Designer concerns, not new ownership behavior.

## Compare actions and amount refresh

| Pattern | Indexed action path | Amount and icon refresh |
| --- | --- | --- |
| Item Hotbar | Item Hotbar Handler calls `UseItem(index)`, which delegates to the Item Actions Binding. | Redraw checks the monitored Item in its original collection, then elsewhere in the same Inventory. |
| Inventory Mirror Hotbar | Uses the inherited Item Hotbar Handler and action binding. | Redraw reads the current filtered and sorted Inventory Grid slice. |
| Item Slot Collection View | Item View Slot Container Indexed Actions Handler triggers its assigned Item Actions Binding. | Redraw reads each index from the Item Slot Collection. |
| Custom container | Use the indexed handler only for Item-backed slots; otherwise supply custom input. | The custom container must define a deterministic source and redraw rule. |

Pointer click or UI submit behavior comes from the Item Actions Binding, not from the visual slot alone. Keep the same action index, Item User, and category action set when comparing keyboard, controller, and pointer results.

## Choose persistence and player ownership

| Pattern | State to save | Released Version 1 approach |
| --- | --- | --- |
| Item Hotbar | Slot-to-ItemStack assignments, plus Inventory contents | Add **Item View Slots Container Saver** to the hotbar and keep the normal Inventory saver. Restore Inventory ItemStacks before the slot mapping. |
| Inventory Mirror Hotbar | Inventory contents and, when required, the Inventory Grid's index data | The mirror has no independent assignment mapping. Save the Inventory and the grid/index data used to derive its order. |
| Item Slot Collection View | Items and indexes inside the Item Slot Collection | Inventory Saver preserves Item Slot Collection entries by slot. The view redraws from that collection. |
| Custom container | The state defined by the custom ownership rule | Reuse Item View Slots Container Saver only when an ItemStack-to-index mapping completely describes that state; otherwise provide a matching saver. |

For local multiplayer, give each player a separate panel owner, Inventory, input route, Display Panel Manager, and saver key. A shared Inventory Mirror Hotbar can intentionally point at common Inventory Grid index data, but player-specific hotbars should not resolve another player's grid or input.

Released Version 1 does not replicate hotbar assignments or custom slot state over a network. Synchronize authoritative state and action requests in the project's networking layer. A mirror or collection-backed view can redraw from synchronized Inventory data, but that does not make its UI input authoritative.

## Editor checkpoint

Before entering Play Mode, confirm that:

- the selected pattern matches the intended ownership rule;
- every panel binding resolves the correct player's Inventory;
- slot hierarchy order, visible count, and zero-based input indexes match;
- Item Actions Binding, Item User, Category Item Action Set, and Item View Drawer references are valid;
- an Inventory Mirror Hotbar has **Inventory Grid To Mirror**, the intended grid ID, and the intended **Start Index**;
- an Item Slot Collection View and its destination collection use the same Item Slot Set;
- the indexed handler can resolve `IPlayerInput` from the bound Inventory GameObject;
- drag-and-drop changes only the assignment, grid, or collection intended by the selected pattern; and
- the saver setup covers the pattern's actual state rather than only its visible slots.

## Verify in Play Mode

1. Assign Health Potion from Bag to an Item Hotbar slot. Confirm that the Item stays in Bag, the amount refreshes, and the numbered input invokes its action once.
2. Put Health Potion and Fire Wand in the mirrored Inventory Grid. Change the grid's sort or order and confirm that the mirror follows it, including while the Inventory Grid panel is closed.
3. Drag Fire Wand into a Weapon slot in the collection-backed hotbar. Confirm that it leaves Bag, enters the configured Item Slot Collection, and the indexed input invokes the intended action.
4. Try Health Potion in the Weapon slot and confirm that the category restriction rejects it without losing the Item.
5. For an Item-backed custom or ability-style slot, confirm that the indexed input uses the intended Item Action and that a non-Item command follows its separate input path.
6. Disable gameplay input for the owning player and confirm that both supplied indexed handlers stop, then resume when gameplay input is enabled.
7. Save, change every hotbar, and load. Confirm that monitored assignments, mirrored order, and collection-backed Items each restore from their own source of truth.
8. Repeat with a second local player and confirm that neither player's inputs, panel bindings, nor saver keys affect the other hotbar.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| Assigning an Item unexpectedly removes it from Bag | Selected hotbar pattern and drag-and-drop action | Use Item Hotbar for monitoring; use Item Slot Collection View only when ownership should move. |
| The mirror is empty or logs that a grid is required | **Inventory Grid To Mirror** | Assign the actual Inventory Grid; the ID alone is not a replacement for the reference. |
| The mirror shows the wrong Items | Grid filter, sorter, ID, **Start Index**, and slot count | Make the mirror point at the intended ordered slice and retest after the grid redraws. |
| Dragging between the mirror and grid is blocked | **Prevent Move To Grid** and **Prevent Move From Grid** | Disable the direction guard that should remain interactive. |
| The collection-backed hotbar stays empty | **Item Collection ID**, collection type, and Item Slot Set | Resolve an Item Slot Collection and use the same set on the collection and view. |
| Fire Wand is rejected from its slot | Item Category and Item Slot Set restriction | Make Fire Wand a member of the accepted category or choose the correct slot category. |
| A numbered key does nothing | Handler reference, input name/type, zero-based index, `IPlayerInput`, and gameplay-input state | Bind the intended handler and action binding, correct the input index, and place or explicitly resolve the player's input component. |
| Clicking works but a key invokes a different action | Item Actions Binding and action index | Use the same category action set and intended action index for both paths. |
| Item Hotbar assignments disappear after load | Item View Slots Container Saver, Inventory saver, load order, and saver keys | Save both Inventory and assignments, restore Items first, and make every player's Full Key unique. |
| A mirror restores different slots | Inventory Grid sorting/index data and its saver | Persist the source order when it is not derived deterministically from current Inventory data. |
| Player two controls player one's hotbar | Panel owner, Inventory, manager, handler, and input ownership | Give each player an isolated binding and input route. |

## Related pages

- [Item Hotbar](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-hotbar/)
- [UI Designer Hotbar](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-hotbar/)
- [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/inventorygrid/)
- [Item Slot Collection View](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-slot-collection-view-equipment/)
- [UI Designer Equipment](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/equipment/)
- [Item Slot Collection](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/item-slot-collection/)
- [Move Items with drag-and-drop](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/move-items-drag-drop/)
- [Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/)
- [Input](https://opsive.com/support/documentation/ultimate-inventory-system/input/)
- [Split-screen co-op UI](https://opsive.com/support/documentation/ultimate-inventory-system/input/split-screen-co-op-ui/)
- [Save system](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)

## Developer reference

`ItemHotbar` provides monitored assignments and `UseItem`. `InventoryMirrorHotbar` overrides refresh and transfer operations so they act on its required `InventoryGrid`. `ItemSlotCollectionView` maps each visual index to an `ItemSlotCollection` entry and validates the shared `ItemSlotSet`. `ItemViewSlotContainerIndexedActionsHandler` can trigger an Item Actions Binding by visual index for collection-backed or custom Item containers.

All four patterns can reuse the bind/unbind, selection, click, pointer, draw, and reset events exposed by the Item View Slots Container base classes. Version 1 does not publish a dedicated Item Hotbar assignment-changed event. Inventory Mirror Hotbar listens for the Inventory Grid update event, while both supplied indexed handlers listen for the character gameplay-input enable event.

---

<a id="page-ultimate-inventory-system-ui-item-view-slots-container-item-slot-collection-view-equipment"></a>

# Item Slot Collection View (Equipment)

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-slot-collection-view-equipment/)

Use an **Item Slot Collection View** to present fixed, named Equipment positions backed by an Inventory's Item Slot Collection. A Right Hand slot can accept Iron Sword or Fire Wand through the Weapon category while rejecting Health Potion through the Consumable category.

The view displays and moves the Item Stacks in Equipment. An **Equipper** is a separate runtime component that reacts to those collection changes and creates or removes the character's equipped Item Objects.

## Before you begin

Prepare:

- a player Inventory with **Bag** and **Equipment** Item Collections;
- Equipment configured as an **Item Slot Collection** with **Purpose: Equipped**;
- one Item Slot Set asset with a `Right Hand` slot that accepts Weapon;
- Iron Sword and Fire Wand in Weapon and Health Potion in Consumable;
- a UI Designer canvas and duplicated schema; and
- an Equipper using the same Item Slot Set when the character needs visible equipment models.

The Equipment collection, Item Slot Collection View, and Equipper should all reference the same Item Slot Set asset. The view enforces this match against the collection at runtime.

## Create the Equipment view

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer**.
2. Select **Equipment**, then open **Create**.
3. Choose the intended **Parent Transform** and **Panel Option**. The creator starts with **Simple** and the panel name `Equipment Panel`.
4. Assign the player **Inventory** for an explicit binding, or leave it unassigned when the panel owner's Inventory should be used.
5. Assign the Item Slot Set used by the Equipment Item Slot Collection.
6. Create the view.
7. Select the generated Item Slot Collection View and confirm that **Item Collection ID** resolves Equipment through **Purpose: Equipped**.

UI Designer creates one Item View Slot for every Item Slot Set entry, names each generated object from the slot name, maps the slots by index, and adds the category restrictions. It also adds an **Item View Slots Container Panel Binding** and configures the schema's Equipment Item View set.

At this checkpoint, the generated Right Hand view should map to index `0` when Right Hand is the first Item Slot Set entry. Changing the order of the set changes the meaning of every mapped index.

## Match the view to the Equipment collection

![The Item Slot Collection View Inspector with Equipment collection binding, automatic category restrictions, an Item Slot Set, and mapped Item View Slots.](https://opsive.com/wp-content/uploads/2020/11/ItemSlotCollectionViewInspector.png?v=135533bbcc09)

The page-specific fields are:

| Inspector field | Version 1 default | Purpose |
| --- | --- | --- |
| **Item Collection ID** | Name unset, **Purpose: Equipped** | Finds the Item Slot Collection on the bound Inventory. |
| **Set Item View Slot Restrictions** | On | Copies the Item Slot Set restrictions before the Inventory is bound. |
| **Item Slot Set** | None on a manually added component | Defines slot names, order, and accepted Item Categories. |
| **Add View Slot Category Restrictions** | On | Adds an Item View Slot Category Restriction when a mapped view does not already have one. |
| **Item Slots Item View Slots** | Resized to the Item Slot Set count | Maps each Item Slot Set entry to one visible Item View Slot by index. |

The generated panel also uses the shared [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/) settings. Important inherited defaults include **Slot Cursor ID: 1**, **Draw On Enable: Off**, **Draw On Inventory Update: On**, and **Swap Item View On Assign: Off**. UI Designer supplies the Item View Drawer and Content references from the selected schema.

When Inventory binding completes, the view requires:

1. **Item Collection ID** to resolve an Item Slot Collection; and
2. that collection's **Item Slot Set** to be the same asset assigned to the view.

If either check fails, Version 1 logs an error and clears the view's Inventory binding. A set with matching names but a different asset reference is still a mismatch.

## Keep slot order, categories, and visual size aligned

Each Item Slot Set entry stores a **Name** and **Item Category**. Version 1 does not provide a per-slot size or stack-limit field on that asset. The number of entries controls the number of Equipment positions, while Inventory restrictions control stack limits when those are needed.

The visible slot's RectTransform size comes from the Equipment Item View prefab selected by the UI Designer schema. When the generated UI needs larger weapon slots, customize the Item View prefab or generated RectTransforms; do not look for a size setting on the Item Slot Set.

Keep the mapping exact:

- Item Slot Set index `0` maps to **Item Slots Item View Slots** index `0`;
- Item Slot Set index `1` maps to view index `1`; and
- every mapped entry must reference a non-null Item View Slot.

Changing the Item Slot Set after generation resizes the serialized mapping array, but it does not create a complete replacement UI hierarchy. Recreate or deliberately edit the Equipment view, then inspect every mapping and restriction.

With **Add View Slot Category Restrictions** enabled, the view adds an **Item View Slot Category Restriction** to each mapped slot and assigns the set's Item Category. Its **Inherently** option defaults to on, so a Weapon slot accepts Items in Weapon or a descendant category. Empty Items are always allowed so a slot can be cleared.

## Configure Item Views and interaction

Use the UI Designer's [common container options](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view-slots-container/) after the collection binding works.

### Item appearance

The Item View Drawer chooses a prefab through the schema's Equipment Category Item View Set. Confirm that it can resolve Weapon for Iron Sword and Fire Wand and has an empty view for unoccupied slots. Keep **Swap Item View On Assign** off when every slot uses the generated structure; enable it only when the drawer is configured to replace Item View prefabs safely.

### Item Actions and descriptions

Add an Item Action binding when selecting Iron Sword should offer **Unequip**, or when selecting it in Bag should offer **Equip**. The normal action should move the Item between Bag and Equipment; the Item Slot Collection View then redraws from the resulting collections.

Add an Item Description binding when selecting an equipped Item should show its Icon, Description, Attack, or Durability. These bindings use the selected Item View Slot and do not change the Equipment collection by themselves.

### Input and focus

The shared container forwards selection, click, submit, pointer, and drag events. Keep **Select Slot On Open** enabled on the panel binding when Right Hand should receive initial focus, and keep **Deselect Slot On Close** enabled so a hidden Equipment panel does not continue receiving input.

For local multiplayer, bind each Equipment panel to the intended panel owner, explicit Inventory, or unique Inventory Identifier. The default panel binding uses **Bind To Panel Owner Inventory: On** and **Bind To Inventory By Identifier: 0**.

## Move Items safely

For pointer drag and drop, configure the shared [move Items workflow](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/move-items-drag-drop/) with an Item View Slot Cursor Manager, Item View Drop Handler, Item View Slot Drop Action Set, and Item View Slot Drag Handler. Use an Item View Slot Move Cursor for keyboard or controller movement.

The Equipment view applies two layers of acceptance:

1. the visible Item View Slot restriction checks the destination category; and
2. the Equipment Item Slot Collection and Inventory restrictions decide whether the transaction can complete.

Moving Iron Sword from Bag to Right Hand should remove it from Bag and add it to the Equipment Item Slot Collection. Dragging Health Potion to Right Hand should fail before either collection changes.

Movement inside the Equipment view calls `SwapItemSlot` only when both visible slots can accept the other's Item. A Right Hand Weapon and a Consumable slot therefore cannot exchange Iron Sword and Health Potion. Movement between Bag and Equipment must use a drop action that transfers the underlying ItemInfo values; swapping only the visible Item Views does not equip anything.

When a destination is occupied, choose a drop action or Item Action that deliberately returns the replaced Item to Bag. The Item Slot Collection's low-level replacement settings are separate from the view and can overflow an Item when the intended return path is unavailable.

## How equip and unequip run

1. The panel binding supplies an Inventory to the Item Slot Collection View.
2. The view resolves Equipment and validates the shared Item Slot Set.
3. On draw, each visible index reads the ItemStack at the same index in the Item Slot Collection.
4. A valid action or drop moves Iron Sword from Bag into the matching Equipment slot.
5. The Inventory add event schedules the UI redraw.
6. An Equipper watching Equipment receives the Inventory add event and creates the configured equipment Item Object for that slot.
7. Removing Iron Sword from Equipment redraws the empty UI slot and tells the Equipper to remove or return the Item Object to its pool.

The Item Slot Collection View does not spawn character models, apply attacks, or change statistics. Those results belong to the Equipper, Item Objects, Item Actions, attributes, or other gameplay systems.

## Save and network boundaries

Use **Inventory Saver** to persist Equipment. Released Version 1 serializes an Item Slot Collection from `ItemsBySlot`, including empty positions, and restores Items by collection and slot index. The view should redraw from that data after loading; it does not need to become the authoritative save source.

Keep Inventory collection order and Item Slot Set order compatible with existing save files. Reordering Right Hand and another slot after release changes the meaning of saved indices. Use the Inventory System Manager Item Saver as required for mutable or unique Item data such as Iron Sword Durability.

The standard save flow does not preserve the currently focused UI slot or a pending drag operation. Reopen or redraw the panel after loading.

Released Version 1 does not include Equipment-view or Equipper network replication. A multiplayer implementation must authorize and synchronize the Bag-to-Equipment Inventory transaction, then let each client redraw the view and create its local equipment representation. Do not replicate only the icon or Item Object.

## Editor checkpoint

Before entering Play Mode, confirm that:

- Equipment is an Item Slot Collection with **Purpose: Equipped**;
- Equipment, the Item Slot Collection View, and Equipper use the same Item Slot Set asset;
- every set entry has a unique name and non-null Item Category from the active database;
- **Item Collection ID** resolves the intended player's Equipment collection;
- every **Item Slots Item View Slots** entry is assigned and follows the same order as the set;
- **Set Item View Slot Restrictions** and **Add View Slot Category Restrictions** are enabled;
- Right Hand accepts Weapon, while Health Potion remains Consumable;
- the Item View Drawer resolves the Weapon and empty Item Views;
- Item Action and Item Description bindings reference this Equipment view;
- the Cursor Manager, Drop Handler, Drop Action Set, and intended input handler are connected; and
- the panel binding resolves the correct player Inventory.

## Verify in Play Mode

1. Open Equipment and confirm that every Item Slot Set entry has one visible slot in the same order.
2. Move Iron Sword from Bag to Right Hand. Confirm that Bag loses it and the Equipment view displays it.
3. If an Equipper is present, confirm that the Iron Sword Item Object appears on the character.
4. Try to move Health Potion into Right Hand. Confirm that the Weapon restriction rejects it without removing it from Bag.
5. Replace Iron Sword with Fire Wand through the configured action or drop flow. Confirm that Fire Wand equips and Iron Sword returns to Bag.
6. Unequip Fire Wand. Confirm that the Equipment slot clears, Bag receives it, and the character representation is removed.
7. Select an equipped Item with pointer and keyboard or controller. Confirm that focus, description, and Item Actions update consistently.
8. Save with Iron Sword equipped, change the Equipment, then load. Confirm that Iron Sword returns to the same slot and the view redraws.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| Equipment stays blank and the Console reports no matching collection | **Item Collection ID** and the bound Inventory | Set the collection to **Purpose: Equipped** or the exact Equipment name, and bind the intended Inventory. |
| The Console reports different Item Slot Sets | The assets assigned to the view and Equipment collection | Assign the same Item Slot Set asset, not a separate copy with matching names. |
| The wrong number of UI slots appears | Item Slot Set count and **Item Slots Item View Slots** | Recreate or edit the generated view and map one non-null Item View Slot per set entry. |
| Later slots accept the wrong categories | An earlier mapped Item View Slot is null | Assign every mapping; Version 1 stops applying automatic restrictions when it reaches a null entry. |
| Health Potion enters Right Hand | The set's category and Item View Slot Category Restriction | Set Right Hand to Weapon and enable both automatic restriction options. |
| Iron Sword is rejected | Iron Sword category, active database, and the shared set | Use Weapon or a valid descendant and confirm all objects belong to the selected database. |
| The Item moves but the icon does not update | **Draw On Inventory Update**, Item View Drawer, and mapped Item View | Restore the generated drawer/view references and redraw the panel. |
| The icon updates but no model appears | Equipper collection ID, Item Slot Set, Item Object slots, and prefab attributes | Point the Equipper at Equipment and configure the Iron Sword equipment representation. |
| Replacing a weapon loses the old Item | Drop or Item Action return path and Inventory overflow behavior | Use a transaction that confirms Bag can receive the old weapon before replacing it. |
| Dragging changes only the cursor image | Drop Handler and Drop Action Set | Add a valid underlying Inventory transfer action; the cursor is only a preview. |
| The wrong player's Equipment appears | Panel owner, explicit Inventory, and Inventory Identifier | Bind each panel to its owning player's unique Inventory. |
| Loaded Items return to the wrong slots | Item Slot Set or collection order changed | Restore a compatible order or migrate the existing save data. |

## Related pages

- [Create Equipment in UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/equipment/)
- [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/)
- [Item View Slot](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-view-slot/)
- [Item Slot Collection](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/item-slot-collection/)
- [Equipping Items](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/equipping-items/)
- [Move Items with drag and drop](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/move-items-drag-drop/)
- [Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/)
- [Item Description](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-description/)
- [Input handlers](https://opsive.com/support/documentation/ultimate-inventory-system/input/handlers/)
- [Save system](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)

## Developer details

Use the view's name and mapping helpers instead of assuming a hierarchy path:

```csharp
var rightHandView = equipmentView.GetItemViewSlot("Right Hand");
var rightHandSlot = equipmentView.GetItemSlot(rightHandView);

equipmentView.SetInventory(playerInventory);
equipmentView.ChangeItemCollectionId("Equipment");
equipmentView.Draw();
```

`GetItemViewSlot(ItemSlot)`, `GetItemViewSlot(string)`, and `GetItemSlot(ItemViewSlot)` expose the mapping. `ResizeItemViewSlotsToItemSlotsSetCount` resizes the reference array, while `SetItemViewSlotRestrictions` copies category restrictions to mapped views.

The specialized `CanAddItem` checks the view restriction and `Inventory.CanAddItem` before targeting the Equipment collection. `CanMoveItem` requires each destination view to accept the other Item, and `MoveItem` swaps the underlying Item Slot Collection indices before redrawing those two slots.

Version 1's explicit `ItemSlotCollection.AddItem(itemInfo, index)` path confirms that the Item matches some slot in the set but does not independently recheck the category of the requested index. Keep the view restrictions enabled and validate a requested slot category in custom code before calling the indexed collection API directly.

The view inherits `OnItemViewSlotSelected`, `OnItemViewSlotDeselected`, `OnItemViewSlotClicked`, pointer/drag events, `OnBindInventory`, `OnUnBindInventory`, and `OnDraw` from Item View Slots Container. Unsubscribe custom event handlers when their owner is destroyed or unbound.

---

<a id="page-ultimate-inventory-system-ui-item-view-slots-container-move-items-drag-drop"></a>

# Move Items (Drag & Drop)

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/move-items-drag-drop/)

Use the same movement rules to let a player drag Items with a pointer or move them with keyboard or controller input. A shared cursor shows the Item being moved, while each destination container uses an Item View Drop Handler and an ordered Drop Action Set to accept, reject, move, transfer, or exchange the underlying `ItemInfo`.

The cursor is only a visual preview. A successful Bag-to-Equipment move must change the Inventory or Item Collection through the destination container; moving an Icon between slots is not an Inventory transaction.

## Before you begin

Create and bind the participating [Item View Slots Containers](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/) first. For the examples below:

- **Bag** is an Inventory Grid containing Health Potion and Iron Sword;
- **Equipment** is an Item Slot Collection View with a Weapon slot;
- the Equipment collection and its visible Item View Slot both reject Health Potion; and
- both containers belong to the same player Inventory and active Display Panel Manager.

Create a project-owned Drop Action Set rather than editing an asset inside the package. Use one set for containers that should follow the same movement policy, or separate sets when Bag, Equipment, hotbars, and world-drop destinations require different outcomes.

## Add movement in UI Designer

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer** and select the tab for the generated container, such as **Inventory Grid** or **Equipment**.
2. Select the intended generated container and open **Moving Items** in its Item View Slots Container options.
3. Under **Cursor Manager**, choose **Create** if the player's Canvas does not already contain an Item View Slot Cursor Manager. One manager can serve several containers for the same player.
4. Under **Drop Handler**, choose **Create**, then assign **Item View Slot Drop Action Set**. Add a Drop Handler to every container that can be a destination.
5. Under **Drag Handler**, choose **Create** on every container from which pointer dragging may begin.
6. Under **Move Cursor**, choose **Create** on every container that supports the keyboard/controller **Move** Item Action.
7. Add the **Move** Item Action to the Item Action Set used by that container. The action is available only when an Item View Slot Move Cursor exists beside the container.
8. Add Item Action bindings and other conflicting container bindings to **Unbind While Moving** so selecting the destination does not also consume, equip, or otherwise use the Item.

UI Designer adds the Cursor Manager to the parent Canvas, and adds the Drop Handler, Drag Handler, and Move Cursor to the selected container. Creating the Move Cursor also creates a **Move Cursor Panel** beneath the container's Display Panel content.

## Configure the Item View Slot Cursor Manager

The Item View Slot Cursor Manager records the source slot and creates a floating Item View while a move is active. It registers by **ID**, so containers and Drop Handlers can find the correct manager without a direct reference.

| Inspector field | Version 1 default | Use |
| --- | --- | --- |
| **ID** | `1` | Identifies this manager. Use a distinct ID for each local player's movement UI. |
| **Canvas** | None | Parent Canvas used for the floating Item View. The component finds its parent Canvas when this is unassigned. |
| **Position Offset** | `(0, 0)` | Adds an offset to the floating view position. |
| **Use Container To Spawn Item View** | On | Uses the source container's matching Item View prefab for the floating view. |
| **Category Item View Set** | None | Supplies the floating prefab when **Use Container To Spawn Item View** is off. |
| **On Start Move Event** / **On End Move Event** | Empty | Optional visual, audio, or input feedback around the pending move. |

Only one floating Item View can be active on a manager. The source Item View and floating Item View notify modules that implement the movable interface, allowing the source to dim and the floating view to use a moving state. The floating prefab needs a Canvas Group; movement disables its interaction and raycasts so the destination slot can receive the drop.

When the source container closes, the manager cancels pointer movement and redraws the source container. A missing floating prefab produces a warning and leaves no useful movement preview, so verify the container's Item View prefab or the fallback Category Item View Set.

## Configure the Item View Drop Handler

Add an Item View Drop Handler to each potential destination container. It listens to that container's selection, deselection, click, and pointer-drop events, combines them with the cursor manager's source data, and evaluates the assigned action set.

![The Item View Drop Handler Inspector with its cursor manager reference, drop-target option, feedback events, and Item View Slot Drop Action Set.](https://opsive.com/wp-content/uploads/2020/11/Item-View-Drop-Handler-Inspector.png?v=8948e3e43589)

| Inspector field | Version 1 default | Use |
| --- | --- | --- |
| **Cursor Manager ID** | `1` | Finds a registered Cursor Manager when no direct reference is assigned. |
| **Item View Slot Cursor Manager** | None | Optional direct manager reference; the handler otherwise checks the ID and then its parents. |
| **Drop On Last Selected View** | Off | Off uses the slot that received the pointer drop. On redirects the drop to the last selected slot, which is useful only when selection is the intended destination. |
| **On Select Can Drop Event** / **On Select Cannot Drop Event** | Empty | Optional feedback while a pending Item hovers or navigates over a destination. |
| **On Drop Success Event** / **On Drop Fail Event** | Empty | Optional feedback after a rule matches or no rule matches. |
| **Item View Slot Drop Action Set** | None | Required ordered conditions and actions for the destination. |

The handler also notifies Item View Modules that implement the drop-hover interface. Use those modules to show valid and invalid destination states. That preview is based on the first passing rule; it does not move the Item.

For pointer movement, the source and destination event data must have the same pointer ID. For keyboard/controller movement, the Drop Handler treats a click or submit on the selected slot as the drop.

## Define the Drop Action Set

Create an asset with **Create > Ultimate Inventory System > UI > Item View Slot Drop Action Set**, then assign it to every participating Drop Handler that should share the policy.

![The Item View Slot Drop Action Set Inspector with ordered condition and action groups for moving within one container and exchanging between containers.](https://opsive.com/wp-content/uploads/2020/11/ItemViewSlotDropActionSetInspector.png?v=b24b371fd6ee)

A new Version 1 set starts with two ordered groups:

| Order | Conditions | Actions | Outcome |
| --- | --- | --- | --- |
| 1 | **Container Can Move** | **Move Index** | Moves or swaps Item Stack indexes within the same compatible container. |
| 2 | **Container Can Smart Exchange** | **Container Smart Exchange** | Transfers the source to another compatible container and returns the destination Item when the reverse leg is valid. |

The groups are evaluated from top to bottom. Every condition in a group must pass, the actions in the first passing group run in list order, and later groups are ignored. Keep specific rules before broad rules.

For the Bag and Equipment example:

1. moving Iron Sword between two Bag positions uses **Move Index**;
2. moving Iron Sword from Bag to an empty Weapon slot uses **Container Smart Exchange**;
3. dropping Iron Sword onto an occupied compatible Equipment slot can exchange the Items when both directions are valid; and
4. moving Health Potion to the Weapon slot fails because the destination container or visible slot rejects it.

**Container Can Smart Exchange** checks source give permission, destination add permission, and both visible slot restrictions. **Enforce Two Way Check** is off by default, so a valid source-to-destination leg may pass even when the reverse leg cannot. Enable it when an occupied destination must be able to return its Item to the source.

### Amounts, stacks, swaps, and overflow

The standard movement path carries the current source `ItemInfo`, including its current amount and Item Stack reference. It does not show a quantity prompt or split a stack. Add a separate quantity workflow before starting movement when the player must move only part of a Health Potion stack.

The specialized container decides what an index means and how Items are stored:

- Inventory Grid moves indexed Item Stacks and adds through its Inventory;
- Item Slot Collection View swaps Item Slot Collection entries and applies its slot restrictions;
- Item Shape Grid requires its shape-aware condition and action; and
- hotbars can represent assignments or mirrored Inventory positions rather than owning another Item Stack.

Conditions must account for collection capacity, slot restrictions, and the destination's add behavior before an action removes the source. Drop actions execute sequentially and the Drop Action Set does not provide a general transaction rollback or overflow destination. A custom **Give** or **Exchange** action paired with incomplete conditions can remove an Item before a later add fails.

Use **Container Smart Exchange** for the common case, test full and occupied destinations, and add an explicit fallback only when the design has a safe place for rejected overflow. A failed rule should leave Health Potion or Iron Sword in its source collection.

## Add pointer drag-and-drop

The Item View Slot Drag Handler belongs beside the source container. Its important fields are:

| Inspector field | Version 1 default | Effect |
| --- | --- | --- |
| **Item View Slot Cursor Manager** | None | Finds a manager in the parents when unassigned. |
| **Disable Drag On Empty Slot** | On | Prevents a drag from starting when the slot has no Item. |
| **Keep Offset** | On | Starts the floating view from the source slot position and then applies pointer movement. |
| **Mouse Input** | Left, Right, and Middle | Allows all three pointer buttons unless narrowed. |
| **On Drag Started Event** / **On Drag Ended Event** | Empty | Optional feedback around the pointer gesture. |

The runtime sequence is:

1. the source container raises its begin-drag event;
2. the Drag Handler validates the pointer button and nonempty source;
3. the Cursor Manager records the source `ItemInfo`, container, slot, local index, index offset, and pointer ID, then creates the floating view;
4. the Drag Handler moves the floating view by the pointer delta;
5. destination selection asks its Drop Handler which rule would pass and can update hover feedback;
6. the pointer drop runs the first passing action group on the matching destination; and
7. the cursor is removed and affected containers redraw.

Limit **Mouse Input** to the controls used by the project. Leaving all three buttons enabled can start movement from a button reserved for context menus or another action.

## Add keyboard or controller movement

The **Move** Item Action starts an Item View Slot Move Cursor from the currently selected slot. Navigation then moves the selection and floating view. Clicking or submitting the destination sends it through the same Drop Handler and Drop Action Set used by pointer input.

![The Item View Slot Move Cursor Inspector with its Move Display Panel, unbind-while-moving lists, move events, and redraw options.](https://opsive.com/wp-content/uploads/2020/11/Item-VIew-Slot-Move-Cursor-Inspector.png?v=38c62a9bb372)

| Inspector field | Version 1 default | Use |
| --- | --- | --- |
| **Move Display Panel** | None when added manually | UI Designer creates and assigns a Move Cursor Panel. |
| **Unbind While Moving** | Empty | Temporarily unbinds listed Item View Slots Container bindings during the pending move. |
| **Unbind Interface While Moving** | Empty | Finds and unbinds container-binding interfaces on the listed GameObjects. |
| **On Move Start** / **On Move End** / **On Move Canceled** | Empty | Optional movement feedback. |
| **Draw On Move End** | On | Redraws the bound container after a completed move. |
| **Draw On Move Cancel** | On | Redraws after the component's cancel path. |

Add the Item Action binding that normally opens Use, Equip, or another action to **Unbind While Moving**. Otherwise the submit used to place Iron Sword can also invoke its normal Item Action.

### Version 1 cancel boundary

The released Version 1 source describes the Move Display Panel as a way to cancel with the panel's back input, but its `ItemViewSlotMoveCursor.CancelMove()` guard returns while a move is active. Do not rely on that tooltip without testing the exact package revision. If closing the panel leaves the floating view active, update to a release containing the correction or route the cancel input through the Cursor Manager's public `CancelMove()` method and verify the move-end and panel-close events together.

Pending movement is transient. Always test cancel, panel close, source-container close, and interrupted input as separate cases.

## Editor checkpoint

Before entering Play Mode, confirm that:

- the player's Canvas has one Item View Slot Cursor Manager with the intended **ID** and **Canvas**;
- every container resolves that manager through **Slot Cursor** or **Slot Cursor ID**;
- every destination has an Item View Drop Handler with the same manager ID and an assigned Drop Action Set;
- the default **Container Can Move** rule appears before **Container Can Smart Exchange**;
- Bag and Equipment have the correct Inventory and Item Collection bindings;
- the Equipment Weapon slot has both its collection restriction and matching Item View Slot restriction;
- every pointer source has an Item View Slot Drag Handler with the intended **Mouse Input**;
- every keyboard/controller source has an Item View Slot Move Cursor and a **Move** Item Action;
- conflicting Item Action bindings appear under **Unbind While Moving**;
- the floating Item View prefab has a Canvas Group and readable moving state;
- valid and invalid drop-hover feedback can be distinguished; and
- the Move Display Panel cancel path has been verified in this exact Version 1 package.

## Verify in Play Mode

1. Drag Iron Sword between two Bag slots. Confirm that the Item Stack index changes once and no duplicate appears.
2. Drag Iron Sword from Bag to an empty Equipment Weapon slot. Confirm that Bag, Equipment, and the underlying collections all update.
3. Drag Health Potion to the same Weapon slot. Confirm that invalid feedback appears and the Potion remains in Bag.
4. Fill or restrict the destination, then repeat the Iron Sword drop. Confirm that rejection does not remove the source or route it to an unexpected collection.
5. Put a compatible Item in both source and destination and verify the intended exchange in both directions.
6. Drag a stack of Health Potions and confirm that the configured movement rule handles the entire displayed amount; no split prompt should appear in the standard flow.
7. Repeat valid and invalid moves with the keyboard/controller **Move** action. Confirm that destination submit does not also invoke Use or Equip.
8. Cancel an active pointer move, close the source panel, and test the Move Cursor panel's back input separately. Confirm that the floating view, source dimming, hover preview, and pending state all clear.
9. With local multiplayer, repeat the move for each player and confirm that each cursor, EventSystem, Inventory, and panel affects only its owner.

## Save and network boundaries

The Cursor Manager, floating Item View, selected destination, hover result, pointer ID, and pending Move Cursor state are UI state and are not saved. Save the authoritative Inventory, Item Collections, mutable Items, and any supported hotbar or grid-position data, then redraw the containers after loading. Do not restore a move that was in progress when saving.

These Version 1 movement components do not provide network authority, prediction, rollback, or replication. A multiplayer implementation must validate the requested Inventory transaction on the authority, synchronize the resulting Inventory or collections, and redraw each client's local UI. Do not replicate the floating Icon as proof that the Item moved.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| Dragging never starts | Drag Handler, **Disable Drag On Empty Slot**, **Mouse Input**, and slot raycasts | Add the handler to the source, use an allowed pointer button, and confirm the source contains an Item. |
| The source dims but no floating Item appears | Cursor Manager **Canvas**, container Item View prefab, fallback Category Item View Set, and Canvas Group | Assign a usable floating prefab and Canvas Group, then verify the manager's Canvas. |
| The floating Item appears but every drop fails | Destination Drop Handler and **Item View Slot Drop Action Set** | Add the handler to the destination and assign an initialized action set. |
| A drop uses the wrong slot | **Drop On Last Selected View**, pointer selection, and destination event data | Leave the option off for pointer-position drops, or make selection the deliberate destination. |
| Health Potion enters a Weapon slot | Equipment collection restriction, visible slot restriction, and smart-exchange condition | Apply the Weapon restriction at both data and UI layers and keep the validation condition before the action. |
| An Item disappears when the destination is full | Custom action order and capacity conditions | Check the full add path before removing the source; use Smart Exchange or implement an explicit rollback/fallback. |
| Only the Icon moves | Action group and specialized container action | Use **Move Index**, **Container Smart Exchange**, or another action that changes the underlying data. |
| A partial stack cannot be moved | Standard movement carries the full source `ItemInfo` | Ask for an amount and create the partial `ItemInfo` in a separate quantity workflow before moving. |
| Pointer drop ends on a different pointer | Source and destination pointer IDs | Keep the drag and drop on the same pointer and EventSystem. |
| Controller placement also consumes or equips the Item | **Unbind While Moving** | Add the Item Action binding and any conflicting binding to the Move Cursor's unbind list. |
| Back closes the panel but leaves movement active | Version 1 Move Cursor cancel guard | Verify the installed patch and route cancel through the Cursor Manager's `CancelMove()` when required. |
| Valid/invalid hover colors never change | Drop-hover Item View Module and feedback events | Add a compatible preview module or connect the select-can-drop and select-cannot-drop events. |
| The wrong player's Item moves | manager **ID**, container **Slot Cursor ID**, panel owner, and EventSystem | Give each local player a distinct manager and bind every container to the matching owner. |
| A saved game restores stale movement UI | saved data and post-load redraw | Save authoritative Inventory state only, clear pending movement, and redraw after load. |

## Related pages

- [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/)
- [UI Designer common container options](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view-slots-container/)
- [Item View Slot](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-view-slot/)
- [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/inventorygrid/)
- [Equipment Item Slot Collection View](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-slot-collection-view-equipment/)
- [Item Shape Grid](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-shape-grid/)
- [Item Hotbar](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-hotbar/)
- [Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/)
- [Input handlers](https://opsive.com/support/documentation/ultimate-inventory-system/input/handlers/)
- [Save system](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)

## Developer details

`ItemViewSlotDropHandlerStreamData` records the source and destination containers, slots, `ItemInfo` values, local slot indexes, and index offsets. Its `SourceIndex` and `DestinationIndex` are the local slot index plus the relevant container offset. Conditions should treat this data as read-only; actions may update it with the actual Item removed before a later action adds that Item.

The Drop Action Set exposes `GetFirstPassingConditionIndex`, `GetFirstPassingCondition`, and `HandleItemViewSlotDrop`. A return value of `-1` means no group passed. The Drop Handler's success event means a group matched and its actions ran; it is not a separate verification that every custom data mutation succeeded.

Important runtime APIs include:

- `ItemViewSlotCursorManager.StartMove`, `CancelMove`, `BeforeDrop`, `RemoveItemView`, `SetPosition`, and `AddDeltaPosition`;
- `ItemViewDropHandler.HandleItemViewSlotDrop`, `ItemViewSlotSelected`, and `ItemViewSlotDeselected`;
- `ItemViewSlotDropActionSet.HandleItemViewSlotDrop` and `GetFirstPassingConditionIndex`;
- `ItemViewSlotsContainerBase.CanAddItem`, `CanGiveItem`, `CanMoveItem`, `AddItem`, `RemoveItem`, and `MoveItem`; and
- `ItemViewSlotMoveCursor.StartMove(int)`.

Version 1 also includes conditions for container add/give/move, container name, source Item Collection, source amount, null source or destination, same-container matching, smart exchange, and Item Shape placement. Actions include container give/remove/exchange/smart exchange, Inventory give/exchange, move index, Item Action invocation, Item Object spawning, audio playback, and Item Shape placement.

Create a custom rule by deriving from `ItemViewDropCondition` or `ItemViewDropAction`:

```csharp
[Serializable]
public class SameContainerCondition : ItemViewDropCondition
{
    public override bool CanDrop(ItemViewDropHandler handler)
    {
        return handler.SourceContainer == handler.DestinationContainer;
    }
}

[Serializable]
public class MoveIndexAction : ItemViewDropAction
{
    public override void Drop(ItemViewDropHandler handler)
    {
        handler.SourceContainer.MoveItem(
            handler.StreamData.SourceIndex,
            handler.StreamData.DestinationIndex);
    }
}
```

Keep conditions free of mutations, place capacity and restriction checks before removal actions, and test every custom rule with an empty, occupied, restricted, full, and invalid destination.

---

<a id="page-ultimate-inventory-system-ui-item-view-slots-container-item-info-filter-sorters"></a>

# ItemInfo Filters and Sorters

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-info-filter-sorters/)

ItemInfo filters decide which Inventory entries a grid displays, while sorters decide their visible order. Use them to keep Equipment out of a **Bag** grid, create Consumable and Weapon tabs, search for Health Potion by name, or order stacks by amount without changing which Items the Inventory owns.

Filtering and continuous sorting are view operations. A one-time Inventory Grid sort changes the grid's stored index order, but none of these components transfers or deletes an Item.

## Choose a built-in filter

| Component | Important Inspector fields and defaults | Released Version 1 behavior |
| --- | --- | --- |
| **Inventory Search Filter** | **Inventory Grid**, **Input Field**, and optional **Bind Sorter While Searching** have no manual default references. UI Designer wires the grid and schema input field. | Matches the runtime Item name using the current culture and ignores letter case. It temporarily replaces the grid's bound filter/sorter while the input is nonempty. |
| **Item Info Category Filter** | **Show Item Category** and **Hide Item Category** default to none. **Show Attribute Name** is empty. **Show Category Icon** is unassigned. **Category Icon Attribute Name** defaults to `CategoryIcon`. | Shows Items inherently contained by the show category and excludes Items inherently contained by the hide category. A true boolean named by **Show Attribute Name** overrides both category checks. |
| **Item Info Item Collection Filter** | **Show Item Collections** is empty. **Hide Item Collections** defaults to Loadout and Hide. | An empty show list accepts every collection except the hidden ones. Add Bag to show only Bag, then keep any additional collections that must remain hidden. |
| **Item Info Item Collection And Category Filter** | **Item Collections** is empty and it inherits the Category Filter fields. | With an empty collection list, the category rule applies to every Item. With entries, the category rule applies only inside those collections; Items from other collections pass unchanged. It is not a strict collection-and-category intersection. |
| **Item Info Multi Filter Sorter** | **Grid Filters** starts empty when created by UI Designer. | Runs each referenced filter or sorter in list order and skips a reference to itself. Every filter must accept an Item for `CanContain` to return true. |

Category membership uses the Item's inherent category relationship, including the category hierarchy. There is no separate built-in Item Definition filter. Name search and name sorting use `Item.name`, which normally starts with the Item Definition name but can differ for a runtime Item.

## Choose a built-in sorter

| Component | Important Inspector fields and defaults | Released Version 1 order |
| --- | --- | --- |
| **Item Info Amount Sorter** | No settings. | Largest `ItemInfo.Amount` first. |
| **Item Info Attribute Value Sorter** | **Attribute Name** is empty. **Ascending** defaults on. | Sorts present attribute values in ascending order by default. Values must implement `IComparable`; Items without the attribute follow Items that have it. |
| **Item Info Category Name Sorter** | **Ascending** defaults off. | The released comparator produces category names A-Z while the field is off and Z-A while it is on. Null Items follow valid Items. |
| **Item Info Name Sorter** | **Ascending** defaults off. | The released comparator produces runtime Item names A-Z while the field is off and Z-A while it is on. Null Items follow valid Items. |

The **Ascending** behavior of the two name sorters is counterintuitive in released Version 1; verify the visible order rather than assuming the toggle's label. Attribute sorting uses the expected on-for-ascending behavior.

Built-in sorters compare one key and return equality when that key matches. The underlying `Array.Sort` operation is not stable, so equal keys have no guaranteed secondary order. For a permanent amount-then-name or category-then-name order, use one custom comparer that includes every key and a final deterministic tie-breaker.

## Add default filters in UI Designer

Create one shared chain for rules that should apply whenever the grid is not temporarily controlled by a tab, search, or bound dropdown sorter.

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer**, select **Inventory Grid**, and edit the intended grid.
2. Open **Filters and Sorters**.
3. Under **Default Filters**, create the filter collection. UI Designer adds an Item Info Multi Filter Sorter and binds it to the Item Info Grid.
4. Add **Item Info Item Collection Filter** first. Set **Show Item Collections** to Bag so equipped or hidden Items do not appear in the Bag view.
5. Add **Item Info Category Filter** only when this entire view should show one category, such as Consumable.
6. Add at most one sorter after the filters, such as Item Info Name Sorter.
7. Select each generated component to edit its Inspector values, then return to UI Designer to confirm the **Default Filters** list.

Order the chain as narrowing filters followed by one final sorter. A later filter sees only the entries accepted by the earlier filters. A later sorter reorders the complete result, so stacking several built-in sorters does not create a dependable multi-key order.

At this editor checkpoint, Bag accepts Health Potion and Iron Sword, excludes Items held only by Equipment or Hide, and presents the remaining entries in the chosen visible order.

## Add name search without losing the Bag rule

1. In **Filters and Sorters**, create **Name Search bar Filter**.
2. UI Designer creates the search field, assigns its **Inventory Grid**, and creates a Multi Filter Sorter for **Bind Sorter While Searching**.
3. Add an Item Info Item Collection Filter to the search list and set **Show Item Collections** to Bag.
4. Add any category filter that must still apply while searching.
5. Add one optional sorter last, such as Item Info Name Sorter.

The search component first checks the current input against `Item.name`, then runs **Bind Sorter While Searching**. It redraws on every text change. When the first nonempty query starts, it stores the previously bound filter/sorter, binds itself, and temporarily turns **Use Grid Index** off. Clearing the input restores the previous binding and the **Use Grid Index** value captured when the search component awoke.

Because search replaces the active binding, repeat essential Bag or category rules inside its search chain. Otherwise a search for `iron` can display an Iron Sword from a collection that the normal Bag view hides.

Search does not inspect Description, Item Category, Item Definition attributes, or arbitrary display text. Create a custom search filter if the player must query those values.

## Build category tabs

Use tabs when one grid should switch between complete filter chains, such as **All**, **Consumable**, and **Weapon**.

1. In UI Designer's **Grid Tabs**, choose **Create Inventory Tabs**. The released creator starts with three Tab Toggles.
2. Rename the tabs All, Consumable, and Weapon.
3. Select All and create **Tab Filters** containing the Bag collection filter and the intended sorter.
4. Select Consumable and create **Tab Filters** containing the same Bag filter, an Item Info Category Filter that shows Consumable, and the sorter.
5. Select Weapon and repeat with Weapon as **Show Item Category**.

Selecting a tab binds that tab's Item Info Filter, sets the Inventory Grid's tab ID, restores the tab's grid index data, and redraws. A tab filter replaces the previously bound default chain; include every rule that must remain active in every tab.

Use **Item Info Item Collection And Category Filter** only when category filtering should affect selected collections while all other collections remain visible. For a strict Bag-and-Consumable tab, use separate collection and category filters in a Multi Filter Sorter.

## Add a player-controlled sort dropdown

Under **Filters and Sorters**, create **Drop Down Sorter**, then add only the choices the player needs:

- Item Info Name Sorter for Health Potion and Iron Sword by Item name;
- Item Info Amount Sorter for the largest stacks first; and
- Item Info Attribute Value Sorter for a comparable value such as the numeric Attack attribute.

The **Inventory Grid Sorter Drop Down** contains **Inventory Grid**, **Dropdown**, **Grid Sorters**, **Sort Selected Tab Only**, and **Bind The Sorter**. Both boolean choices default off. Dropdown option `0` means no sort; sorter list index `0` maps to dropdown option `1`.

With **Bind The Sorter** off, selecting a choice performs a one-time index sort, redraws, and resets the dropdown to option `0`. Option `0` performs no new sort; it does not restore the index order that existed before a one-time sort. If tabs exist and **Sort Selected Tab Only** is off, the binding sorts every tab's stored indexer; turn it on to affect only the selected tab.

With **Bind The Sorter** on, the selected sorter becomes the grid's continuous bound filter/sorter. This replaces the current default or tab filter instead of composing with it, and choosing option `0` unbinds to `null` rather than restoring the previous chain. Keep the default one-time mode when collection/category filters must remain intact, or implement an explicit composite control for continuous filter-plus-sort behavior.

## Understand grid indexes and refresh cost

On each draw, Inventory Grid starts with `Inventory.AllItemInfos`, applies the active filter/sorter, and then applies the Inventory Grid indexer when **Use Grid Index** is enabled. This has several practical effects:

- a bound sorter is easiest to reason about with **Use Grid Index** off;
- a one-time dropdown sort changes the indexer and is intended to work with stored positions;
- search temporarily disables index ordering so its filtered result can be presented directly;
- Inventory Mirror Hotbar reads the same filtered and sorted Inventory Grid result; and
- changing a filter does not itself move, remove, or save an Item.

Filters scan the current ItemInfo list. Each sorter copies the current list into a pooled array and calls `Array.Sort`. A Multi Filter Sorter repeats that work for every entry in its chain, and Inventory Search Filter redraws for every input change. Prefer a few meaningful filters and one sorter, avoid duplicate stages, and use a single custom comparer when several sort keys are required.

The pooled output array reduces repeated allocations, but custom filters can reintroduce allocations if they build temporary lists or strings on every draw.

## Editor checkpoint

Before entering Play Mode, confirm that:

- the grid's default chain begins with the intended Item Collection rule;
- each tab repeats shared Bag restrictions instead of relying on the replaced default chain;
- search repeats every restriction that must remain active while text is nonempty;
- every Multi Filter Sorter contains filters first and no more than one final sorter;
- **Attribute Name** is exact and resolves to one compatible `IComparable` value type on the Items being compared;
- Item Info Name Sorter and Category Name Sorter have the visually verified A-Z or Z-A setting;
- **Use Grid Index**, one-time sorting, and continuous binding match the intended position model; and
- the sort dropdown's first option is the unsorted option, followed by one option per **Grid Sorters** entry.

## Verify in Play Mode

1. Open Bag with Health Potion and Iron Sword present, and put another Item in Equipment. Confirm that the Bag collection filter hides the equipped Item without changing Inventory contents.
2. Select Consumable and Weapon tabs. Confirm that Health Potion and Iron Sword appear only under their inherent category rules and that each tab retains the Bag restriction.
3. Search for `potion` using different letter casing. Confirm that Health Potion matches by runtime Item name and that hidden collections remain hidden.
4. Clear the search. Confirm that the previous tab or default filter returns and **Use Grid Index** returns to the value captured when the search initialized.
5. Choose amount sorting and confirm that larger stacks appear before smaller stacks.
6. Choose Attack attribute sorting and confirm that Items with valid comparable Attack values are ordered before Items without that attribute.
7. Compare the name sorter's **Ascending** toggle in both positions and retain the one that produces the intended visible order in Version 1.
8. With tabs enabled, compare **Sort Selected Tab Only** off and on and confirm which stored tab indexes change.
9. Add or remove an Item and confirm that bound filters refresh while a one-time sorted index remains consistent with the configured Inventory Grid index data.
10. If an Inventory Mirror Hotbar uses this grid, confirm that it shows the same leading filtered and sorted entries.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| Equipment Items appear in Bag | **Show Item Collections** and **Hide Item Collections** | Show Bag explicitly and keep every collection that must be excluded in the hide list. |
| A strict Bag category tab shows Items from another collection | Filter type | Use separate Item Info Item Collection Filter and Item Info Category Filter entries; the combined filter intentionally passes unlisted collections. |
| Search reveals otherwise hidden Items | **Bind Sorter While Searching** chain | Repeat the Bag and category filters inside the search chain. |
| Clearing search does not return the expected view | Previous binding, tab changes, and **Use Grid Index** | Confirm search began from the intended tab/default binding and clear the field before changing filter ownership. |
| A tab ignores the default filter | That tab's **Tab Filters** | Add the shared collection and category rules to every tab; tab selection replaces the default binding. |
| Name order appears reversed | Item Info Name Sorter or Category Name Sorter **Ascending** | In Version 1, off produces A-Z and on produces Z-A for these two sorters. |
| Attribute sorting appears unchanged | **Attribute Name**, attribute presence, value type, and equal values | Use the exact attribute name and one compatible `IComparable` type; add a custom tie-breaker when values can match. |
| Several sorters produce inconsistent ties | Multi Filter Sorter order and comparer equality | Replace them with one custom multi-key comparer. Built-in sorting is not stable. |
| Choosing a bound dropdown sort removes category filtering | **Bind The Sorter** | Use the default one-time mode or a custom control that binds a composite filter/sorter. |
| Bound sorting conflicts with manual positions | **Use Grid Index** | Turn index ordering off for a continuously ordered view, or use one-time index sorting for positional grids. |
| Search feels expensive in a large Inventory | Number of filter stages and per-filter allocations | Remove redundant stages, keep one sorter, and avoid allocating temporary collections or strings on each input change. |

## Related pages

- [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/inventorygrid/)
- [Create an Inventory Grid with UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/inventory-grid/)
- [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/)
- [Item Hotbar patterns](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-hotbar/hotbars/)
- [Item Shape Grid](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-shape-grid/)
- [ItemInfo](https://opsive.com/support/documentation/ultimate-inventory-system/item/item-info/)
- [Item Collections](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/)
- [Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/)
- [Resizable arrays and ListSlice](https://opsive.com/support/documentation/ultimate-inventory-system/resizeablearrays-and-listslices/)
- [Customize generated UI](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/ui-customization/)

## Developer details

Implement `IFilterSorter<ItemInfo>` directly, or derive a component from `ItemInfoFilterSorterBase`, `ItemInfoFilterBase`, or `ItemInfoSorterBase`. `ItemInfoFilterBase` turns a per-Item `Filter` decision into a pooled list operation and uses the same decision for `CanContain`. `ItemInfoSorterBase` requires a `Comparer<ItemInfo>`, copies into the pooled output array, and always returns true from `CanContain`.

Bind a filter or sorter when it should run on every draw:

```csharp
var previousFilterSorter = inventoryGrid.BindGridFilterSorter(filterSorter);
inventoryGrid.Draw();

// Restore the previous view later.
inventoryGrid.BindGridFilterSorter(previousFilterSorter);
inventoryGrid.Draw();
```

Perform a one-time positional sort with a sorter comparer:

```csharp
inventoryGrid.SortItemIndexes(itemInfoSorter.Comparer);
inventoryGrid.Draw();
```

For a custom filter component, implement the smallest per-Item rule and let the base class reuse the pooled output array:

```csharp
public sealed class PositiveAmountItemInfoFilter : ItemInfoFilterBase
{
    public override bool Filter(ItemInfo itemInfo)
    {
        return itemInfo.Item != null && itemInfo.Amount > 0;
    }
}
```

For stable multi-key ordering, implement one `ItemInfoSorterBase` comparer that compares the primary key, then name, then a stable Item identifier. Do not rely on several sequential built-in sorters to preserve earlier ties.

---

<a id="page-ultimate-inventory-system-ui-item-view-slots-container-item-shape-grid"></a>

# Item Shape Grid

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-shape-grid/)

Use an **Item Shape Grid** when placement is part of the inventory experience and Items can occupy several cells in a finite Bag. A Health Potion can use one cell while an Iron Sword spans a taller footprint. Use a regular [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/inventorygrid/) when every Item should occupy one equal slot.

The runtime grid is more than a visual layout. An `ItemShape` value defines each footprint, Item Shape Grid Data records occupied cells beside the Inventory, and the Item Shape Grid renders and moves those Items through a shape-aware two-layer view.

![A runtime Item Shape Grid displaying differently sized Item icons across a finite grid of cells.](https://opsive.com/wp-content/uploads/2021/01/Item-Shape-Grid.png?v=a104f8e7b404)

## Before you begin

Prepare:

- an Inventory System Database with Health Potion and Iron Sword Item Definitions;
- a `Shape` Item Definition Attribute of type `ItemShape` on the category used by those Items;
- a player Inventory with a **Bag** Item Collection;
- UI Designer Canvas Managers and a duplicated schema; and
- enough panel space for the intended number and pixel size of cells.

The [UI Designer Item Shape Grid workflow](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-shape-grid/) is the safest way to generate the connected UI, controller, data, and Inventory binding. This page explains how those generated runtime parts work and what to check when customizing them.

## Define each Item shape

1. In the Item Category editor, add `Shape` as an `ItemShape` in the **Item Definition** attribute collection.
2. Open Health Potion and leave its footprint at one cell.
3. Open Iron Sword and use **Columns** and **Rows** to create its footprint.
4. Enable **Use a custom shape?** only when an Item should not occupy every cell in its rectangle.
5. For a custom footprint, enable each occupied cell. Right-click an enabled cell and choose **Set Anchor** to choose the cell that follows the selected destination.

The anchor must remain on an enabled cell. The editor keeps the anchor cell enabled, and the runtime aligns that anchor to the destination cell. An Item without the configured `Shape` value, or with a one-cell shape, is treated as one cell.

![An ItemShape Attribute editor with row and column controls, enabled footprint cells, and an anchor cell.](https://opsive.com/wp-content/uploads/2020/11/ItemShapeAttribute.webp?v=846ec6adac5d)

Released Version 1 stores one fixed footprint and anchor. It has no built-in rotation field or rotate command. If Iron Sword needs horizontal and vertical orientations, provide separate authored data and custom logic for choosing and placing the orientation.

## Create the spatial Bag

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer**.
2. Select **Item Shape Grid**, then open **Create**.
3. Assign the intended **Parent Transform** and **Inventory**.
4. Keep the default **Panel Option** of **Simple**, or choose the panel type needed by the surrounding UI.
5. Give **Panel Name** and **Grid Name** stable names such as `Spatial Bag`.
6. Set **Grid Size**. The creator starts at 8 by 8 cells.
7. Set **Item Shape Size**, the pixel size of one cell. The creator starts at 100 by 100 pixels.
8. Under **Item Collection**, select **Bag**.
9. Create the grid.

UI Designer creates the panel and Item Shape Grid, adds an **Item Shape Grid Controller** and **Item Shape Grid Data** beside the assigned Inventory when needed, assigns the next available data ID, and adds an **Item View Slots Container Panel Binding** for that Inventory.

The Version 1 creator also displays an `ALL (NONE)` collection choice. The creator writes that text into the data's **Item Collections** array, but runtime all-collection behavior requires the array to be empty. Select a real collection such as Bag for the normal workflow. To intentionally use every Inventory collection, clear **Item Collections** on the generated Item Shape Grid Data and confirm that the Console does not report an `ALL (NONE)` collection warning.

![An Inventory Inspector with Item Shape Grid Controller and Item Shape Grid Data configured for a spatial Bag.](https://opsive.com/wp-content/uploads/2021/01/ItemShapeGridController-And-Data_v1_1_4.png?v=f62aa1647e32)

## Understand the runtime parts

| Part | Runtime responsibility |
| --- | --- |
| `ItemShape` attribute | Stores the footprint size, enabled cells, and anchor for an Item Definition. |
| **Item Shape Grid Controller** | Acts as an Inventory restriction, chooses the first matching data entry, and checks that an added Item can be placed. |
| **Item Shape Grid Data** | Owns the cell map for one spatial grid and its collection or filter rules. It belongs with the Inventory. |
| **Item Shape Grid** | Resolves data by ID from the bound Inventory and presents the background cells and foreground Item views. |
| Shape-aware Item View modules | Size the Icon, highlight the occupied cells, preview drops, and position labels within irregular footprints. |
| Shape drop condition and action | Validate and perform shape-aware movement between Item View Slots Containers. |
| **Item Shape Grid Data Saver** | Persists the cell map and anchor markers for one data entry. |

The Inventory owns the Items and placement data. The panel displays that data; moving or copying the UI does not create another independent grid.

## Match the data and view settings

The Item Shape Grid uses **Item Shape Grid Data ID** to find one data entry on the bound Inventory. The first generated entry uses ID `0`. Every additional spatial grid on the same Inventory needs a unique ID and a clear collection or filter scope.

### Item Shape Grid Controller

| Setting | Default | Effect |
| --- | --- | --- |
| **No Grid Add Item** | Off | An Inventory add is rejected when no matching grid has room. Turning it on allows the Inventory add even when no grid placement exists. |
| **Shape Attribute Name** | `Shape` | Must exactly match the Item Definition Attribute and the shape-aware Item View. |
| **Warn If Multiple Match** | Off | Reports when more than one data entry accepts an Item. The controller still uses the first match. |

Hide and Loadout-purpose collections are ignored by the controller. When several normal collections or filters overlap, order the controller's data entries deliberately and enable the warning while testing.

### Item Shape Grid Data

| Setting | Default | Effect |
| --- | --- | --- |
| **ID** | `0` on the first generated entry | Connects this data to the UI's **Item Shape Grid Data ID**. |
| **Only Try Add To First Collection** | Off | Tries connected collections in order until one can accept the complete amount. When on, only the first is attempted. |
| **Item Collections** | Generated from the UI Designer choice | Empty means all Inventory collections. Named entries such as Bag limit the data to those collections. |
| **Item Info Filter** | None | Optionally limits which Items can enter this spatial grid. |
| **Grid Size** | Copied from UI Designer | Must match the UI grid. A manually added data component has no useful nonzero size until configured. |
| **Smart Two Way Move** | Off | Allows a same-grid exchange only when both complete footprints fit at their new anchors. |

### Item Shape Grid view

| Setting | Default | Effect |
| --- | --- | --- |
| **Item Shape Grid Data ID** | `0` | Selects the Inventory-side data entry. |
| **Grid Size** | 8 by 8 | Creates one background Item View Slot for every cell and must match the data. |
| **Item Shape Size** | 100 by 100 | Sets the pixel size of one cell. |
| **Item View Slot Prefab** | Supplied by the generated schema | Creates the interactive background cells. |
| **Item View Drawer** | The component on the same GameObject when unassigned | Supplies and reuses Item views. |
| **Item Shape View Content** | Generated foreground content | Receives one coherent foreground view for each placed ItemStack. |
| **Grid Layout Group** | The drawer content's layout when unassigned | Arranges the background cells. |
| **Navigation Type** | **Per Item** | Chooses whether selection moves per Item, per cell, or uses custom Unity navigation. |

![The Item Shape Grid Inspector with data ID, grid and cell sizes, view references, layout group, and navigation mode.](https://opsive.com/wp-content/uploads/2021/01/ItemShapeGridInspector.png?v=bc10d783f6dd)

Use UI Designer when changing **Grid Size** or **Item Shape Size** so it can update the connected slots, layout, and data together. At runtime, a size mismatch between the view and Item Shape Grid Data produces an error and prevents reliable cell mapping.

## Keep the two view layers aligned

The generated grid uses two matching layers:

1. The **background layer** contains one interactive Item View Slot per cell. Selection and drop feedback color every enabled cell in the Item's footprint.
2. The **foreground layer** draws one coherent Item Icon across the complete footprint. Its Canvas Group does not block pointer input intended for the background slots.

Keep **Item Shape View Content** assigned to the foreground transform and the Item View Drawer's **Content** assigned to the background transform. Both layers need the same cell size and origin.

![An Item View Inspector with Item Shape modules for footprint sizing, selection, drop preview, and label placement.](https://opsive.com/wp-content/uploads/2021/01/ItemShapeItemViewInspector_v_1_1_4.png?v=846763cda888)

The shape-aware Item View normally includes:

- **Item Shape Item View**, which reads **Shape Attribute Name** (`Shape` by default), sizes the view from a 100 by 100 **Default Slot Size**, and reads **Shape Icon Attribute Name** (`Icon` by default). **Use Backup Icon** is on by default.
- **Item Shape Drop Preview Item View**, which colors all prospective cells according to whether the drop conditions pass.
- **Item Shape Selected Item View**, which highlights the selected Item's complete footprint.
- **Item Shape Rect Placer Item View**, which places a Rect Transform such as an amount label on the anchor or another occupied cell.
- **Canvas Group**, which allows the foreground layer to remain visible without intercepting input.

Do not replace this prefab with a normal one-cell Item View unless the replacement retains the required Item Shape modules and exact attribute names.

## How placement and stacking work

Before the Inventory accepts an Item, the controller checks matching Item Shape Grid Data entries in order. Each data entry applies its **Item Collections** and **Item Info Filter**, then tests the complete footprint. With **No Grid Add Item** off, an Item that fits no matching grid is rejected.

New placements scan from the top-left, row by row, and align the Item's anchor to the candidate cell. Only enabled cells in a custom shape must be free and inside the grid. When an Item transfers between collections in the same frame, the data can reuse its recently cleared position.

One ItemStack uses one footprint regardless of its amount. Another non-unique, stack-compatible Item can reuse that footprint only when the receiving collection accepts the complete amount into the existing stack. Otherwise it needs another open footprint.

## Configure movement, input, and navigation

Use the shared [drag-and-drop workflow](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/move-items-drag-drop/) for the cursor manager, drop handler, pointer drag handler, and keyboard or controller move cursor. A shape grid adds these rules:

- same-grid movement uses Item Shape Grid Data and preserves the offset between the grabbed cell and the Item's anchor;
- **Smart Two Way Move** controls whether two Items can exchange positions inside the same grid;
- movement between containers needs the shape-aware **Item View Shape Drop** condition and action so the complete destination footprint and any reverse exchange are checked; and
- placement always uses the authored orientation because Version 1 has no runtime rotation command.

Choose **Navigation Type** according to the intended input:

- **Per Item** moves selection between visible Item anchors and is the default;
- **Per Slot** navigates through individual cells; or
- **Custom** leaves the configured Unity `Navigation` links unchanged.

Test pointer, keyboard, and controller paths separately. The same valid or invalid cells should appear in the preview and final placement.

## Save and synchronize the layout

Saving the Inventory and saving its spatial layout are separate operations. Add an **Item Shape Grid Data Saver** for every data entry whose positions must persist, in addition to the saver for the Inventory Items. The data saver stores each cell's ItemStack identity and anchor marker. During load, those Items must already exist in the Inventory and the saved cell count must match the current grid size.

UI Designer does not add the data saver automatically. Resizing a saved grid also changes its cell count, so old placement data is not loaded into a differently sized layout.

Released Version 1 has no shape-grid-specific network replication. For multiplayer, keep one Inventory, controller, data set, and bound grid per local owner. A network implementation must synchronize both the authoritative Inventory transaction and Item Shape Grid Data; synchronizing only the UI or Inventory amount is not enough to reproduce positions.

## Editor checkpoint

Before entering Play Mode, confirm that:

- Health Potion and Iron Sword resolve `Shape` through the exact configured attribute name;
- every custom footprint has its anchor on an enabled cell;
- the panel binding references the Inventory that owns the controller and data;
- **Item Shape Grid Data ID** matches one data **ID** on that Inventory;
- **Item Collections** contains Bag, not the literal `ALL (NONE)` placeholder;
- **Grid Size** matches between the view and data;
- foreground and background content use the same geometry;
- the Item View retains the shape, selection, drop-preview, label-placement, and Canvas Group modules; and
- the shape-aware condition and action are present when Items move between containers.

## Verify in Play Mode

1. Open Bag. Confirm that Health Potion occupies one cell and Iron Sword covers its authored footprint.
2. Select each Item. Confirm that every occupied background cell highlights while the foreground remains one coherent Icon.
3. Add another Health Potion to a compatible stack. Confirm that its amount changes without creating a second footprint.
4. Drag Iron Sword from a non-anchor cell to an open area. Confirm that the preview and final placement cover the same cells without the Icon jumping.
5. Hover Iron Sword over the grid edge and an occupied area. Confirm that the invalid preview prevents the move.
6. Test an occupied destination with **Smart Two Way Move** off and then on. Confirm that an exchange occurs only when enabled and both complete footprints fit.
7. Move Iron Sword between Bag and Equipment. Confirm that its old Bag cells clear and no ghost footprint remains.
8. Save, move the Items, then load. Confirm that both Item amounts and cell positions return.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| The grid is empty and the Console names `ALL (NONE)` as missing | **Item Collections** on Item Shape Grid Data | Select Bag in UI Designer, or clear the data array when all collections are intentional. |
| Every Item occupies one cell | The `Shape` Item Definition Attribute and **Shape Attribute Name** | Add an `ItemShape` value to each definition and use the same exact name on the controller and Item View. |
| The grid cannot find its data | Panel binding Inventory, **Item Shape Grid Data ID**, and data **ID** | Bind the owning Inventory and make the two IDs match. |
| The Console reports different grid sizes | **Grid Size** on the Item Shape Grid and Item Shape Grid Data | Resize through UI Designer so data, slots, and layout update together. |
| An Item is offset or clipped | Its anchor, **Item Shape Size**, foreground content, and drawer content | Put the anchor on the intended enabled cell and realign both view layers. |
| Selection or preview colors only one cell | Item Shape Selected Item View and Item Shape Drop Preview Item View | Restore the shape-aware modules and confirm they read the same `Shape` value. |
| A preview is valid but the final drop fails | The destination data and shape-aware drop action set | Use both the **Item View Shape Drop** condition and action for movement between containers. |
| Items never exchange inside the grid | **Smart Two Way Move** and both footprints | Enable the setting and confirm each full shape fits at the other's anchor. |
| An Item exists in the Inventory but has no position | **No Grid Add Item**, filters, and controller warnings | Keep the setting off for a strict spatial Bag and remove overlapping or nonmatching scopes. |
| Positions reset after loading | Inventory saver, Item Shape Grid Data Saver, load order, and grid dimensions | Save every data entry, load Items first, and keep the saved and current cell counts equal. |
| Remote players disagree about positions | Network authority and synchronized shape data | Replicate the Inventory transaction and authoritative Item Shape Grid Data in custom networking code. |

## Related pages

- [Create an Item Shape Grid in UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-shape-grid/)
- [Detailed Item Shape Inventory Grid reference](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/inventorygrid/item-shape-inventory-grid/)
- [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/inventorygrid/)
- [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/)
- [Move Items with drag-and-drop](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/move-items-drag-drop/)
- [ItemInfo filters and sorters](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-info-filter-sorters/)
- [Common attribute types](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/common-attribute-types/)
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/)
- [Save system](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)

## Developer details

`ItemShapeGridController` registers for Inventory add and remove events, selects the first matching `ItemShapeGridData`, and exposes `GetGridDataWithID` for view lookup. It does not publish a separate public placement-changed event. The normal Item View Slots Container selection, click, and drop events still drive UI interaction, while `ItemShapeItemView.OnGridInfoSet` is available when a custom module needs the resolved shape-grid view state.

`ItemShapeGridData` provides `TryFindAvailablePosition`, `IsPositionAvailable`, `AddItemToPosition`, `CanMoveIndex`, `TryMoveIndex`, `TryGetAnchorOffset`, `GetAnchorIndex`, `GetElementAt`, and `GetItemPos`. Use these APIs instead of editing cells independently so Inventory ownership, anchors, and complete footprints remain consistent.

---

<a id="page-ultimate-inventory-system-ui-views"></a>

# Views

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/)

Views turn runtime data into reusable UI. Use them when the same Item, Attribute, Currency amount, Crafting Recipe, or save slot must appear consistently in an Inventory grid, Item Description, shop, Crafting Menu, or Save Menu.

A View is responsible for the value currently being displayed and its shared visual state. Its View Modules each draw one part of that value, such as an icon, name, amount, or selection highlight. The Inventory Grid, menu, drawer, or other owner still decides which value the View receives and what a click means.

## Choose the view for the value

| What the UI must show | Use | Typical owner or binding | UI Designer starting point |
| --- | --- | --- | --- |
| A Health Potion, Iron Sword, or Fire Wand with its icon, name, and amount | [Item View](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/item-view/) | Item View Slot, Inventory Grid, Item Description, shop, or another Item View Drawer | [Item View](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view/) |
| One Attribute and its value, such as Attack, Durability, or Description | [Attribute View](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/attribute-views/) | Item Description or another component that supplies an Attribute | [Attribute View](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/attribute-view/) |
| Gold or another Currency balance, price, or cost | [Multi Currency View](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/multi-currency-view/) | Currency Owner Monitor, Shop Menu, Crafting Menu, or another component that supplies Currency amounts | [Currency](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/currency/) |
| A Crafting Recipe and its output | [Recipe View](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/recipe-box/) | Crafting Recipe View Drawer or Crafting Menu | [Crafting](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/crafting/) |
| A save slot and its metadata | [Save View](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/save-view/) | Save View Drawer and Save Grid | [Save](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/save/) |

Multi Currency View is the main exception to the typed View and View Module pattern. It maps each configured Currency to a Currency View, then draws a supplied Currency Collection or list of Currency amounts.

## Understand the responsibilities

| Part | Responsibility |
| --- | --- |
| Owner, container, or menu | Chooses the runtime value, supplies supporting context such as the player's Inventory, and decides what selection, submit, or click does. |
| View Drawer | Creates or reuses the required View prefab, clears its previous value, and gives it the new value. A drawer can also forward selected and clicked states. |
| View | Holds the current typed value and forwards clear, select, click, hide, set-value, and refresh operations to compatible modules. |
| View Module | Draws one concern, such as an icon or amount, and clears that concern when the View is reused. |
| Category View Set | Chooses a prefab for an Item Category or Crafting Category so different data can use different layouts. |
| View Slot | Provides the selectable UI slot around a View when a container needs pointer, controller, navigation, or drag-and-drop interaction. |

This separation keeps presentation reusable. An Item View can display an Iron Sword, but it does not find the player's Bag, move the sword to Equipment, or run an Item Action by itself.

## Create a reusable Item View

Use Item View as the clearest example of the shared pattern:

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer**.
2. Select **Item View**, then create or duplicate a project-owned prefab instead of editing a demo or package asset in place.
3. On the Item View component, assign **Target Graphic** when selection should affect a particular Graphic. Assign a **Canvas Group** when the View must be hidden and made non-interactable as one unit.
4. Add only the Item View Modules the layout needs. A compact Bag slot might use icon, name, amount, and selected-state modules; a detailed panel can use a separate prefab with more modules.
5. Confirm that every module references its own Text, Image, or other visible control.
6. Save the prefab and assign it to the drawer or category mapping used by the target menu.

![Item View component with Target Graphic and Canvas Group references alongside focused Item View Module components.](https://opsive.com/wp-content/uploads/2020/04/ItemViewInspector.png?v=f5fac6f48ce9)

The Item View retrieves the View Modules attached to the same GameObject. Each module receives the same `ItemInfo`, but it updates only its own part of the presentation.

## Map categories to View prefabs

Create a mapping asset with **Create > Ultimate Inventory System > UI > Category Item View Set**. Assign an **Empty Item View**, then map categories to the prefabs that should draw them.

For the shared sample database, one common prefab can handle the **All** category. Add a **Consumable** mapping only when Health Potion needs a different layout, and a **Weapon** mapping only when Iron Sword and Fire Wand need weapon-specific information. The runtime lookup uses the most specific applicable category mapping, so a child category can override the broader fallback without duplicating every entry.

![Category Item View Set mapping Item Categories to reusable Item View prefabs and an Empty Item View.](https://opsive.com/wp-content/uploads/2020/04/CategoryItemViewSetInspector.png?v=a2e6dd512fe9)

Assign the asset to **Category Item View Set** on the Item View Drawer. The equivalent recipe workflow uses a Category Recipe View Set to select Recipe View prefabs by Crafting Category.

### Important View Drawer choices

| Setting | Use it when |
| --- | --- |
| **Use View Slot** | Each View needs selection, clicks, navigation, or another slot-level interaction. This is enabled by default. |
| **Disable View Slot Image Component** | The slot's Image exists for interaction but should not draw over the View. This is enabled by default. |
| **Content** | Views should be created under a specific layout transform. When unassigned, the drawer uses its own transform. |
| **Remove Views On Initialize** | Authored child Views are placeholders and the drawer should rebuild them. This is enabled by default. |
| **Draw Empty Views On Initialize** | Empty slots should be visible before data is supplied. This is enabled by default. |

## Connect the data owner

The same prefab behaves differently according to the component that supplies its value:

- An Inventory Grid gives each Item View Slot an `ItemInfo` from Bag and owns selection, movement, and Item Actions.
- An Item Description supplies the selected Item and its Attributes to Item and Attribute Views.
- A Shop Menu supplies the Item while its pricing workflow can update a price module after the View is drawn.
- A Crafting Menu supplies a Crafting Recipe and the player's Inventory context to its recipe and ingredient presentation.
- A Save Grid supplies `SaveDataInfo` plus the save-slot index to each Save View.
- A Currency Owner Monitor supplies the player's Gold balance, while a Shop Menu can supply a purchase total to another Multi Currency View.

Use an [Item View Slot](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-view-slot/) when the Item View must react to focus, selection, submit, pointer, or drag-and-drop input. Use an [Item Description](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-description/) when the selected Item should drive a separate details panel.

## Editor checkpoint

Before entering Play Mode, confirm that:

- the View prefab contains the correct typed View and every required module;
- **Target Graphic**, **Canvas Group**, and each module's visible references are assigned where used;
- the owner, container, or drawer references the intended prefab or category set;
- every category that needs a distinct layout resolves to a valid prefab;
- **Empty Item View** is assigned when empty slots should be drawn; and
- the menu or container has the correct player Inventory, Currency Owner, Crafter, or Save System binding.

## Verify in Play Mode

Compare several values rather than checking a single populated slot:

1. Open Bag with a Health Potion, Iron Sword, and Fire Wand. Confirm that each View shows the correct icon, name, and amount, and that the expected Consumable or Weapon prefab is selected.
2. Move selection between occupied and empty slots. Confirm that the highlight follows selection and that an emptied or reused slot does not retain the previous icon, amount, or text.
3. Open the Item Description for Iron Sword, then Fire Wand. Confirm that Attribute Views refresh to the newly selected Item rather than keeping stale Attack or Durability values.
4. Open a shop and compare the player's Gold balance with an Item's total price. Confirm that each Multi Currency View shows the value supplied by its own owner.
5. Select the Health Potion recipe. Confirm that its Recipe View changes with the selected recipe and shows the expected output.
6. Open the Save Menu and compare an empty slot with an occupied slot. Confirm that each Save View receives the correct index and metadata.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| A slot is present but its icon, name, or amount is blank | The corresponding View Module and its Text or Image reference | Add the correct typed module and assign its visible control. |
| An old icon or value remains after the slot changes | The custom module's clear behavior | Ensure every custom module clears all state it sets; drawers clear pooled Views before assigning the next value. |
| Selection or clicking has no visible effect | **Target Graphic**, the selectable or clickable module, and the surrounding View Slot | Assign the target, include the required module, and let an Item View Slot or container own the interaction. |
| Hiding a View causes an error or leaves it interactive | **Canvas Group** on the View | Add and assign a Canvas Group before using the View's hide operation. |
| Every Item uses the same prefab | **Category Item View Set** and its category mappings | Assign the set to the drawer and add only the category-specific overrides that are required. |
| A View uses the wrong player's data | The menu or container's Inventory Identifier or owner binding | Bind the parent runtime UI to the intended player; do not try to solve ownership inside the visual prefab. |
| A price, cost, or other calculated value is stale | The component that supplies or post-processes the value | Refresh the owning menu or use the drawer's after-drawing event to apply context-specific data after the base View is populated. |

## Related pages

- [UI Designer overview](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/)
- [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/)
- [Item Description](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-description/)
- [Crafting Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/crafting-menu/)
- [Save Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/save-menu/)

## Customize a View

Create a custom module only when the shipped modules cannot display the required value. Inherit from the module base for the correct value type, update the visual in `SetValue`, and reset every changed visual in `Clear`. Keeping modules small lets the same icon, amount, selection, or attribute presentation be reused across several prefabs.

The base View exposes clear, select, click, hide, set-value, and refresh operations. A View Drawer exposes before-drawing and after-drawing events; the latter is useful for contextual values, such as a shop price that is not stored directly on the Item. These are presentation hooks: the Inventory, shop, crafting, save, and networking systems remain the authorities for their own runtime data.

---

<a id="page-ultimate-inventory-system-ui-views-item-view"></a>

# Item View

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/item-view/)

An Item View presents one `ItemInfo` through reusable visual modules. Use it for a Bag slot, Equipment slot, hotbar entry, shop row, crafting ingredient, or Item Description when the Item's icon, name, amount, Attributes, or state must update without rebuilding the UI.

The Item View displays data; it does not own the Inventory or decide what a click does. Its Item View Slot, container, drawer, and category mapping provide those surrounding responsibilities.

## Before you begin

Confirm that:

- Health Potion, Iron Sword, and Fire Wand exist in the selected Inventory System Database;
- each definition has a valid `Icon` Sprite when the View will show an icon;
- a project-owned UI Designer schema has been duplicated and spawned;
- a Bag Inventory Grid or another Item View Slots Container exists for testing; and
- the target Inventory and player ownership are already correct on that container or menu.

Start with a simple shared prefab. Create category-specific or context-specific prefabs only when the information or layout genuinely differs.

## Understand the surrounding components

| Component | Responsibility |
| --- | --- |
| **Item View** | Holds the current `ItemInfo` and sends set-value, clear, select, click, hide, and refresh operations to compatible View Modules. |
| **Item View Module** | Draws one concern, such as Icon, name, amount, selection, or equipped state. |
| **Item View Slot** | Wraps the View in an action button, supplies the slot index, applies restrictions, detects selection and submit or pointer clicks, and forwards select or click state to the View. |
| **Item View Slots Container** | Owns a group of slots, binds an Inventory, redraws on Inventory changes, and publishes selection, click, and drag-and-drop events. |
| **Item View Drawer** | Creates or reuses Views, clears old state, assigns the new `ItemInfo`, and obtains the correct prefab from a Category Item View Set. |
| **Category Item View Set** | Maps Item Categories to Item View prefabs and supplies an Empty Item View when the Item is null. |

Keep input and Inventory logic on the slot, container, or binding. A standalone Item View can render Iron Sword, but it cannot equip that sword or move it from Bag to Equipment by itself.

## Create an Item View

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer**.
2. Select **Item View** and open **Create**.
3. Choose **Item View Preset**. **For Grid** is the default; released Version 1 also supplies **For List**, **For Shop**, **For Item Shape**, **For Ingredient**, and **For Inventory Monitor**.
4. Set **Parent Transform** when the new View should be created under a specific layout, then create it from the duplicated project schema.
5. Open **Edit**, select the generated View, and add or remove entries in **ItemView Modules**.
6. Assign every module's Image, Text, Sprite, child object, Attribute name, or other required reference.
7. Save the project-owned prefab and assign it to the intended Category Item View Set.

![Item View component with Target Graphic and Canvas Group references alongside its attached Item View Modules.](https://opsive.com/wp-content/uploads/2020/04/ItemViewInspector.png?v=f5fac6f48ce9)

On the Item View component, **Target Graphic** becomes the target graphic of its Item View Slot. Assign **Canvas Group** when the whole View must be hidden and made non-interactable with the View API.

## Choose modules by scenario

### Show a normal Bag Item

Use a small set first:

- **Icon Item View** reads the exact `Icon` Sprite Attribute. Assign **Icon**, choose a **Missing Icon**, and enable **Disable On Clear** only when an empty slot should hide the Image component.
- **Name Item View** writes the Item's name to **Name Text**.
- **Amount Item View** writes the current `ItemInfo.Amount` as `x amount`. **Hide Threshold** defaults to `1`; the optional **Disable Below Threshold** and **Disable Above Threshold** objects let the layout change on either side of that threshold.
- **Enable Disable Item View Module** switches separate GameObject groups for occupied and empty states.

Health Potion normally uses Icon and Amount. Iron Sword and Fire Wand may use the same prefab, but a unique weapon amount is usually less useful than its equipped or durability state.

### Make selection visible

Use **Select Image View** to swap an Image between **Default** and **Selected** Sprites, or **Select View** to enable different GameObjects and invoke its selection event. These modules receive selection from the Item View Slot. Without a slot, their cleared state is deselected.

The View itself should not add another Button to compete with the Item View Slot. Keep one interaction owner so pointer, keyboard, and controller selection agree.

### Show equipment state

Use **Equipped Item View** to enable objects while an Item is equipped, or **Equipped Select Item View** when one Image must represent default, selected, equipped, and equipped-selected states.

Both modules first look for the boolean Attribute named by **Equipped Attribute Name**, which defaults to `IsEquipped`. When that Attribute is absent, they compare the Item's current collection with the equipped collection identifier, whose default purpose is **Equipped**. This requires an `ItemInfo` that retains its source Item Collection.

Do not use **Item Slots Item View** as an equipment marker. It draws icons for Items stored in an `ItemAmounts` Attribute named `Slots`, with each contained Item's `Icon`; it is intended for sockets or Items that contain other Items.

### Show Item Attributes or prices

- **Attribute Item View** converts a named Attribute value to text, uses **Default Text Value** when cleared, and can disable a chosen GameObject when the Attribute is missing.
- **Int Attribute Item View** reads only an integer Attribute and clears its text to `0`. Use it for an integer `Attack` or `Durability` value.
- **Attribute View For Item View Module** sends one named Attribute into a nested Attribute View when the value needs its own reusable presentation.
- **Category Attribute View Set Item View Module** builds several Attribute rows for an Item Description.
- **Currency Item View** reads a `CurrencyAmounts` Attribute named by **Currency Attribute Name** and draws it through an assigned **Multi Currency View**. A raw `BuyPrice` is suitable for a basic display, while a Shop may replace it with a context-specific processed price after drawing.

### Compare against an Inventory

Use **Inventory Amount Item View** when the row should show the total amount of the Item Definition in an Inventory. **Use Inventory ID** is disabled by default; when enabled, **Inventory ID** defaults to `1`. Use **Amount Comparison Item View** for an `available/required` display with positive and negative colors, optionally restricted to named Item Collections.

These modules need the intended Inventory through their runtime context. A missing Inventory produces a warning and clears the display, so verify ownership in split-screen or dynamically spawned UI.

### Use specialized presentation

Use the dedicated modules and preset for special systems:

- **Item Shape Item View** and its companion selection, drop-preview, and placement modules are required for multi-cell Item Shape UI.
- **Cooldown Item View** is for the compatible Item Action cooldown flow. Its defaults look for Inventory Identifier `1`, the `Cooldown` Attribute, and Item User data named `ItemCooldown`; it is not a general timer.
- **Drop Hover Icon Preview Item View** is driven by an Item View Drop Handler during drag-and-drop.

## Map prefabs by category

Create the mapping asset with **Create > Ultimate Inventory System > UI > Category Item View Set**.

1. Assign **Empty Item View** when empty slots should use a prefab.
2. Map **All** to the common grid View.
3. Add **Weapon** only when Iron Sword and Fire Wand need a more specific presentation.
4. Add **Consumable** only when Health Potion needs a distinct presentation.
5. Assign the set to **Category Item View Set** on the Item View Drawer.
6. Keep **Use View Slot** enabled, its Version 1 default, when the drawer must create or reuse Item View Slots for interaction.
7. Confirm that the drawer and container use the intended **Content** transform.

The set selects the most specific matching category mapping it can resolve through category inheritance. A null-category entry can act as a broad fallback, but an explicit All mapping is clearer for the shared database. With multiple incomparable parent categories, avoid ambiguous competing mappings or verify the resolved prefab deliberately.

## Choose a safe customization scope

| Intended change | Edit | Result |
| --- | --- | --- |
| One panel in one scene | The generated scene or prefab instance | Other consumers keep their existing presentation. |
| Every use of one layout | A project-owned Item View prefab | Each drawer that resolves that prefab receives the change. |
| Future UI Designer output | The corresponding prefab in the duplicated schema | Newly generated Views start with the change. |
| A genuinely different context | A separate grid, list, shop, ingredient, monitor, or Item Shape prefab | One context can change without clipping or overloading another. |
| A genuinely different category | A separate prefab mapped in Category Item View Set | Only the matching category branch uses the variation. |

Do not edit the package or demo prefab directly. After changing a shared prefab, recheck every grid, Equipment view, hotbar, shop, and crafting panel that consumes it.

## Editor checkpoint

Before entering Play Mode, confirm that:

- the prefab belongs to the project or duplicated schema;
- it has one Item View component and the intended Item View Modules;
- **Target Graphic**, optional **Canvas Group**, and every module UI reference are assigned;
- Health Potion, Iron Sword, and Fire Wand resolve an `Icon` Sprite;
- every named Attribute uses the exact spelling and expected value type;
- Category Item View Set has a valid Empty Item View and unambiguous category mappings;
- Item View Drawer references that set and uses the intended **Content**;
- Item View Slot wraps the View when selection or clicking is required; and
- the Item View Slots Container is bound to the correct player's Inventory.

## Verify in Play Mode

1. Open Bag and confirm that Health Potion, Iron Sword, and Fire Wand use the intended prefab and Icon.
2. Add several Health Potions. Confirm that Amount Item View updates, then remove the stack and confirm that the empty slot does not retain its icon or amount.
3. Move selection with every supported input method. Confirm that exactly one Item View shows its selected state and that submit or click reaches the parent container's action flow.
4. Equip Iron Sword. Confirm that its equipped presentation changes when its `ItemInfo` moves to Equipment, while Fire Wand in Bag remains unequipped.
5. If Weapon has a distinct mapping, confirm that both weapons use it and Health Potion does not.
6. Change one weapon's runtime `Durability`, refresh or redraw its View, and confirm that an Attribute module shows the new value without changing another weapon.
7. Open the shop or crafting panel when that prefab is shared there. Confirm that prices or required amounts use the correct owner context and fit the different layout.
8. Replace an occupied slot with a different Item and confirm that name, Icon, amount, selection, equipment, Attribute, and conditional child states are all cleared before reuse.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| Slots exist but no Item View appears | Item View Drawer, **Category Item View Set**, mapping prefab, and **Content** | Assign the missing references and ensure the mapped prefab contains Item View. |
| An Item uses the wrong prefab | Its inherited categories and competing mappings | Keep one clear broad mapping and add only the necessary, more specific override. |
| Icon is blank or always uses the fallback | `Icon` Attribute type/value and **Icon** Image reference | Supply a Sprite value and assign the module's Image and **Missing Icon** intentionally. |
| A single Health Potion still shows an amount decoration | **Hide Threshold** and the two threshold-controlled GameObjects | Keep the threshold at `1` and assign the decoration to the correct side of the threshold. |
| Selection changes but the View does not | Item View Slot, **Target Graphic**, and selectable module references | Wrap the View in the active slot and assign the module's selected and default visuals. |
| Equipped state never changes | `IsEquipped`, source Item Collection, and equipped collection identifier | Use a valid boolean Attribute or preserve the source collection in `ItemInfo`. |
| Socket icons are mistaken for equipped state | The selected module | Use Equipped Item View for equipment; reserve Item Slots Item View for the `Slots` ItemAmounts Attribute. |
| Inventory amount or comparison is blank | Bound Inventory, **Use Inventory ID**, and collection names | Supply the correct Inventory context or use a valid identifier and collection names. |
| Old data remains after reuse | Every custom module's `Clear()` behavior | Reset all text, images, colors, child states, and cached values in `Clear()`. |
| A shop price is wrong | Raw Currency Attribute versus processed shop price | Let the Shop apply its context-specific price after the base View is drawn. |
| The View is clipped in one context | Preset, Rect Transform, and consuming slot size | Use a context-specific project prefab instead of forcing one oversized layout everywhere. |

## Related pages

- [Views, drawers, and category sets](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/)
- [UI Designer Item View](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view/)
- [Item View Slot](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-view-slot/)
- [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/)
- [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/inventorygrid/)
- [Equipment collection View](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-slot-collection-view-equipment/)
- [Item Shape Grid](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-shape-grid/)
- [Attribute View](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/attribute-views/)
- [Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/)
- [Customize generated UI](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/ui-customization/)

## Customize modules and use the API

Create a custom module only when the focused shipped modules cannot express the required presentation. Inherit from `ItemViewModule`, update one concern in `SetValue(ItemInfo)`, and reset every changed or cached state in `Clear()`.

```csharp
public sealed class DurabilityWarningItemView : ItemViewModule
{
    [SerializeField] private GameObject m_Warning;

    public override void SetValue(ItemInfo info)
    {
        var showWarning = info.Item != null &&
            info.Item.TryGetAttributeValue<int>("Durability", out var durability) &&
            durability <= 10;

        m_Warning.SetActive(showWarning);
    }

    public override void Clear()
    {
        m_Warning.SetActive(false);
    }
}
```

Implement `IViewModuleSelectable` when the module needs the View's select state. Implement `IItemViewSlotDropHoverSelectable` only when the Item View Drop Handler should drive a drag-hover preview. Implement `IInventoryDependent` when an owning system must supply an Inventory; not every View host injects that dependency, so the module must be tested in each consuming context.

The Item View API exposes `SetValue(ItemInfo)`, `Clear()`, `Select(bool)`, `Click()`, `Hide(bool)`, and `Refresh()`. An Item View Drawer also exposes before-drawing and after-drawing events for contextual presentation. These APIs update UI only; Item movement, Item Actions, saving, and networking remain the responsibility of their owning systems.

---

<a id="page-ultimate-inventory-system-ui-views-attribute-views"></a>

# Attribute View

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/attribute-views/)

An Attribute View displays one resolved Attribute value, such as an Iron Sword's `Attack` or current `Durability`. Use it when an Item Description, comparison panel, or other UI needs a reusable value row instead of Item-specific presentation logic.

The surrounding Item Description or binding chooses the Attribute. The Attribute View holds the resulting `AttributeInfo`, and its Attribute View Modules draw the name, value, color, or conditional state.

## Before you begin

Confirm that:

- the Attribute is declared in the correct collection on an Item Category;
- the selected Item Category, Item Definition, or Default Item supplies the intended value;
- a project-owned UI Designer schema has been duplicated and spawned; and
- an Item Description or another parent component exists to supply an Attribute at runtime.

For the shared example, declare `Attack` as an integer **Item Definition** Attribute on Weapon and `Durability` as an integer **Item** Attribute. Iron Sword and Fire Wand can then share the same Attribute View prefabs while showing their own definition and runtime values. Health Potion should not receive either Weapon-only row.

## Create an Attribute View

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer**.
2. Select the **Attribute View** tab and open **Create**.
3. Set **Parent Transform** when the new View should be created under a particular UI layout, then create it from the duplicated project schema.
4. Open **Edit** and select the generated Attribute View.
5. Add only the Attribute View Modules required by this row, then assign each module's Text, Image, or GameObject references.
6. Save the project-owned prefab.
7. Assign the prefab directly to its parent UI, or map an Attribute name to it through a Category Attribute View Set.

The Attribute View's base **Target Graphic** is useful when a surrounding View Slot needs a target. Assign **Canvas Group** only when the whole View must be hidden and made non-interactable through the View API.

## Choose a module for the value

The released Version 1 runtime supplies these Attribute View Module types:

| Module | Use | Important fields and behavior |
| --- | --- | --- |
| **Value Attribute View** | Display an integer, string, or another value through its text representation. | Assign **Attribute Text**. **Clear If Null Value** is disabled by default; enable it when the resolved value may be null or empty. |
| **Float Value Attribute View** | Display a `float` with controlled precision. | Assign **Value Text**. **Format** defaults to `{0:0.00}`. Values lower than **Clear Below Threshold**, which defaults to `0`, clear the text; a value equal to the threshold is still displayed. A non-float Attribute displays `?`. |
| **Name Value Attribute View** | Display the Attribute name and value in separate controls. | Assign **Attribute Name Text** and **Attribute Value Text**. Enable **Clear If Null Value** when a missing value should clear both controls. |
| **Show Hide Attribute View** | Show one set of GameObjects and hide another according to a numeric comparison. | Configure **Show**, **Hide**, **Compare Operator**, **Compare Value**, and **Pass If Null**. Use it only with values that can be converted to a number. |
| **Value To Color Attribute View** | Map an integer or enum value to a color. | Assign **Icon** and the indexed **Colors** array. Out-of-range or unsupported values use **Missing Color**. **Disable On Clear** is disabled by default. |

Use **Value Attribute View** for integer `Attack` or `Durability`; there is no separate integer runtime module class in released Version 1. Use **Float Value Attribute View** only for an Attribute declared as `float`, not merely because the desired text contains a decimal point.

Each module must clear every visual it changes. Attribute Views and their parents may be pooled or reused, so stale text and colors otherwise remain when selection changes.

## Bind Attribute names by category

For an Item Description that should build its rows from the selected Item:

1. Create a set with **Create > Ultimate Inventory System > UI > Category Attribute View Set**.
2. Add a Weapon entry. Map the exact name `Attack` to the Attack Attribute View prefab and `Durability` to the Durability prefab.
3. Add a Consumable entry only for values that Health Potion should show, such as `Description` when the project presents that value as an Attribute row.
4. On the Item Description, add or select **Category Attribute View Set Item View Module**.
5. Assign the set to **Category Attribute View Set** and assign the layout transform to **Attribute UI Parent**.
6. Bind the Item Description to the Inventory Grid or other selection source.

At runtime, the module checks every set entry whose Item Category contains the selected Item. For each exact Attribute name it can find, it creates the mapped prefab below **Attribute UI Parent** and gives the Attribute View both the resolved Attribute and the selected `ItemInfo`.

Broad and narrow category entries can both contribute rows. For example, an All entry can supply `Description` while the Weapon entry adds `Attack` and `Durability`. Avoid mapping the same Attribute name in both entries unless two rows are intentional.

## Match the View to Attribute scope

The Attribute View presents the value it receives; it does not choose where that value is stored.

| Scope | What the View should demonstrate | Example |
| --- | --- | --- |
| **Item Category** | One resolved value that describes a category and may be inherited by child categories. | A Weapon `CategoryIcon` row in a category-oriented panel. |
| **Item Definition** | A value shared by Items created from that definition. | Iron Sword and Fire Wand display their own `Attack` values. |
| **Item** | A value that may differ for each mutable runtime Item. | Two Iron Sword Items display different remaining `Durability`. |

The Default Item on an Item Definition provides the starting Item-level value. If `Durability` must change independently, Weapon must be configured so those runtime Items are mutable and unique. Changing the visual prefab does not make an immutable Item editable.

When a runtime Attribute changes, refresh or redraw the owning Item Description. A View that still holds the same Attribute can also be refreshed, but the parent remains responsible for selecting the correct Item and removing rows that no longer apply.

## Editor checkpoint

Before entering Play Mode, confirm that:

- the prefab has an Attribute View component and only compatible Attribute View Modules;
- every Text, Image, GameObject array, and optional Canvas Group reference is assigned where used;
- the module accepts the declared value type;
- `Attack` is declared in Weapon's **Item Definition** collection;
- `Durability` is declared in Weapon's **Item** collection and initialized on each definition's Default Item;
- the Category Attribute View Set uses the exact Attribute spelling and a prefab containing Attribute View;
- Weapon maps to the Attack and Durability rows while Consumable does not; and
- the Item Description has valid **Category Attribute View Set** and **Attribute UI Parent** references.

## Verify in Play Mode

1. Open Bag and select Health Potion. Confirm that no empty `Attack` or `Durability` row is created.
2. Select Iron Sword. Confirm that its definition-level `Attack` and current Item-level `Durability` use the expected labels and formatting.
3. Select Fire Wand. Confirm that both values are replaced and no Iron Sword text remains.
4. Change one Iron Sword Item's `Durability`, then refresh or reselect it. Confirm that the row shows the new runtime value.
5. Select another Iron Sword or Fire Wand and confirm that its own `Durability` has not changed.
6. Select an empty slot and confirm that all Attribute View rows are removed or cleared.
7. If a float row is used, test a value below, equal to, and above **Clear Below Threshold**, plus the largest expected formatted value.
8. If a Show Hide or Value To Color module is used, test every comparison or indexed state and confirm that an unsupported value uses the intended cleared or missing presentation.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| No Attribute row is created | Category mapping, exact Attribute name, and selected Item's categories | Correct the name and map the prefab under a category that contains the selected Item. |
| The row exists but its text is blank | Module UI reference, source value, and null-clearing option | Assign the Text control and confirm the selected Item resolves a non-null value of the expected type. |
| A float displays `?` | The Attribute's declared type | Use Float Value Attribute View only with `float`; use Value Attribute View for an integer. |
| A small or negative float disappears | **Clear Below Threshold** | Lower the threshold when those values should remain visible. |
| Health Potion shows Weapon rows | Category Attribute View Set entries and category inheritance | Keep `Attack` and `Durability` under Weapon rather than All or Consumable. |
| The same Attribute appears twice | Broad and narrow category mappings | Remove the duplicate mapping; all matching category entries contribute rows. |
| Changing one weapon changes another | Attribute scope and Weapon mutability/uniqueness | Keep `Durability` in the Item collection and use mutable, unique weapon Items. |
| A previous value remains after selection changes | Custom module `Clear` behavior and parent redraw | Clear every visual in the module and ensure the Item Description redraws on selection changes. |
| Conditional objects never change as expected | **Compare Operator**, **Compare Value**, and source type | Use a numeric or convertible Attribute and test both passing and failing values. |
| A color always uses **Missing Color** | Attribute type, integer or enum index, and **Colors** length | Supply an in-range integer or enum value and add a color for every supported index. |

## Related pages

- [Views and View Modules](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/)
- [UI Designer Attribute View](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/attribute-view/)
- [UI Designer Item Description](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-description/)
- [Runtime Item Description](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-description/)
- [Attributes and scope](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/)
- [Define Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/defining-attributes/)
- [Common Attribute names and types](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/common-attribute-types/)

## Customize and use the API

Create a custom module only when the shipped modules cannot present the required value. Inherit from `AttributeViewModule`, implement `SetValue(AttributeInfo)` for the visible state, and implement `Clear()` for every state that the module changes. `AttributeInfo` contains both the resolved Attribute and its originating `ItemInfo`, so a custom module can use Item context without making the Attribute View responsible for selection.

To supply a View directly, resolve the Attribute from the intended Item and pass both values together:

```csharp
if (itemInfo.Item != null &&
    itemInfo.Item.TryGetAttribute("Durability", out var attribute)) {
    attributeView.SetValue((attribute, itemInfo));
} else {
    attributeView.Clear();
}
```

Call `Refresh()` when the current Attribute object changed and the same View should redraw. Call `Clear()` before reusing the View for an empty or unrelated value. These calls only update presentation; Attribute persistence, saving, and network synchronization remain the responsibility of their owning systems.

Released Version 1's Show Hide Attribute View writes the evaluated Attribute name and numeric value to the Console each time it updates. Account for that built-in behavior before using it in a frequently refreshed list, or replace it with a project-owned module when the logging is unsuitable.

---

<a id="page-ultimate-inventory-system-ui-views-recipe-box"></a>

# Recipe View

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/recipe-box/)

A Recipe View presents one Crafting Recipe in a recipe grid. Use it to give each recipe a consistent tile, such as a Health Potion icon, while the Crafting Menu handles selection, quantity, ingredient checks, and the craft action.

The released Version 1 type is **Recipe View**. Some asset-menu labels and older source names still say **Recipe Box**, including **Category Recipe Box Set**; those names refer to the same recipe-tile workflow.

## Before you begin

Prepare the following in the active Inventory System Database:

- a **Consumable Recipes** Crafting Category;
- a **Brew Health Potion** recipe that consumes 2 Herb and 1 Water and outputs 1 Health Potion;
- a Crafter that exposes that recipe through **Crafting Categories** or **Miscellaneous Recipes**; and
- a player Inventory whose main Item Collection is **Bag**.

Create a Crafting Menu from **Tools > Opsive > Ultimate Inventory System > UI Designer > Crafting**. Its Crafting Recipe Grid supplies each recipe to a Recipe View; the view does not find recipes or an Inventory by itself.

## Understand the recipe presentation

| Part | Responsibility |
| --- | --- |
| **Recipe View** | Holds the current Crafting Recipe and updates its View Modules. |
| **First Output Recipe View** | Sends the first Item Amount from the recipe's **Default Output** to a nested Item View. |
| **Crafting Recipe View Drawer** | Chooses and creates the Recipe View prefab used by a grid slot. |
| **Category Recipe View Set** | Maps Crafting Categories to Recipe View prefabs and provides an empty view. |
| **Crafting Recipe Grid** | Draws the Crafter's recipes and reports selection or clicks. |
| **Recipe Panel** | Shows the selected recipe's full result, ingredients, descriptions, and optional Currency cost. |
| **Quantity Picker Panel** | Changes the requested amount and enables the craft action only when the processor accepts that quantity. |

A compact Recipe View and a detailed Recipe Panel solve different problems. The tile helps the player choose a recipe; the panel explains what the selected recipe consumes and produces.

## Configure the Recipe View

1. Select the Recipe View prefab used by the Crafting Recipe Grid. The Classic and RPG UI Designer schemas include one, or you can duplicate the schema-owned prefab before customizing it.
2. On **Recipe View**, assign **Target Graphic** when the tile needs a selectable visual target and **Canvas Group** when the whole tile should fade as the View changes state.
3. Keep the **Modules** list synchronized with the View Module components on the prefab. Version 1 retrieves attached modules during initialization, and the UI Designer also refreshes the list when editing a View.
4. Add or select **First Output Recipe View** and assign its **Item View** reference.
5. Configure that nested Item View with the modules needed for the output, such as icon, name, or amount.

![Recipe View Inspector with Target Graphic, Canvas Group, Modules, and a First Output Recipe View module linked to an Item View.](https://opsive.com/wp-content/uploads/2020/05/RecipeViewInspector.png?v=375dd5bb8d98)

**First Output Recipe View** displays only the first direct Item Amount in the recipe's **Default Output**. Make Health Potion that first output for the sample tile. A recipe without a direct Item Amount output logs a warning and cannot provide a value to this module.

## Map recipe categories to prefabs

Use one mapping when every recipe shares a tile, or map categories when recipes need different layouts.

1. Create or select a **Category Recipe View Set**. In Version 1, the create menu is **Create > Ultimate Inventory System > UI > Category Recipe Box Set**.
2. Assign **Empty Recipe View** for an empty grid slot.
3. Add an entry to **Categories Recipe Views**, select **Consumable Recipes** under **Category**, and assign the Recipe View prefab under **Item View Prefab**. The last label is retained from the older Inspector even though this field expects a recipe view.
4. Use a null-category entry as the fallback for recipes that do not match a more specific mapping.
5. On the grid's **Crafting Recipe View Drawer**, assign this asset to **Category Item View Set**. This released Inspector label is also inherited legacy wording; the field accepts a Category Recipe View Set.

Every mapped prefab must contain a View that accepts a Crafting Recipe. Otherwise, the drawer returns an invalid view and Version 1 logs a warning.

## Connect the selected-recipe details

Open the generated menu in the UI Designer **Crafting** tab and confirm these relationships:

1. **Crafter** includes Consumable Recipes and uses the intended Crafting Processor.
2. **Crafting Recipe Grid** uses the Recipe View drawer and category mapping configured above.
3. **Recipe Panel** has a result Item View for Health Potion and at least two **Ingredient Items** entries for Herb and Water.
4. **Total Craft Cost** is assigned only when the recipe processor uses Currency ingredients.
5. **Quantity Picker Panel** is assigned on the Crafting Menu.

The Recipe Panel's ingredient list is a fixed set of presentations. Provide at least one entry for every ingredient that the selected recipe must display. The panel multiplies ingredient, result, and Currency amounts by the selected quantity.

## Choose selection, quantity, and status behavior

The Recipe View displays the recipe, but the surrounding menu owns interaction and availability:

- **Draw Recipes On Open**, enabled by default, redraws the Crafter's current recipe list whenever the menu opens.
- Selecting a grid entry updates the Recipe Panel. Clicking it also opens the Quantity Picker Panel when **Open Quantity Picker Panel On Recipe Click** is enabled, which is the default.
- The quantity starts at 1. Each change asks the Crafter's processor whether that amount can be crafted, updates the Recipe Panel, and disables the confirm action when the check fails.
- A Currency ingredient can be shown by **Total Craft Cost**; the Recipe Panel changes the cost color when the bound Inventory cannot afford it.
- **On Craft Complete** receives a Boolean success result after a craft attempt. Use that event for feedback that belongs outside the recipe tile.

There is no built-in craftable-status field on `RecipeView` or `FirstOutputRecipeView`. Add a custom View Module only when the tile itself must show availability; otherwise, keep status in the Recipe Panel and quantity confirmation flow.

## Editor checkpoint

Before entering Play Mode, confirm that:

- the Recipe View prefab contains **Recipe View** and **First Output Recipe View**;
- **First Output Recipe View > Item View** references a configured nested Item View;
- Brew Health Potion's first **Default Output** Item Amount is 1 Health Potion;
- the Category Recipe View Set maps Consumable Recipes to that prefab and has an **Empty Recipe View**;
- the Crafting Recipe View Drawer references the intended set;
- the Crafting Menu references its Crafter, Crafting Recipe Grid, Recipe Panel, and Quantity Picker Panel;
- the Crafter exposes Brew Health Potion exactly once; and
- the Recipe Panel has two ingredient presentations plus a Health Potion result presentation.

The visible checkpoint is one Brew Health Potion tile in the recipe grid and, when selected in the editor hierarchy, a Recipe View whose module points to its nested Item View.

## Verify in Play Mode

1. Put 1 Herb and 1 Water in Bag, open the Crafting Menu, and confirm that the Brew Health Potion tile shows the Health Potion output.
2. Select the tile. Confirm that the Recipe Panel shows 2 Herb, 1 Water, and 1 Health Potion while the craft action remains unavailable.
3. Add a second Herb and click the tile. Confirm that the quantity picker opens at 1 and enables **Craft**.
4. Craft once. Verify that exactly 2 Herb and 1 Water leave Bag, 1 Health Potion enters Bag, and **On Craft Complete** reports success.
5. Add 4 Herb and 2 Water, choose quantity 2, and verify that the panel previews 4 Herb, 2 Water, and 2 Health Potions before crafting.
6. Increase the quantity beyond the available ingredients. Confirm that the preview updates but the craft action becomes unavailable.
7. Clear or filter out the selection and confirm that the empty Recipe View and cleared Recipe Panel do not retain another recipe's details.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| The recipe grid is empty | The Crafting Menu's **Crafter**, **Crafting Categories**, **Miscellaneous Recipes**, active database, and **Draw Recipes On Open**. | Assign the intended Crafter and expose Brew Health Potion once from the active database. |
| A recipe slot uses the wrong layout | The Category Recipe View Set entries and the drawer's **Category Item View Set** assignment. | Map Consumable Recipes to the intended prefab and keep a null-category fallback only for unmatched recipes. |
| Empty slots log a warning | **Empty Recipe View** is not assigned. | Assign a valid empty prefab to the Category Recipe View Set. |
| The tile is blank | **First Output Recipe View > Item View** or Brew Health Potion's **Default Output**. | Assign the nested Item View and make Health Potion the first direct Item Amount output. |
| The tile retains an earlier output after changing recipes | The new recipe has no direct Item Amount in **Default Output**. | Correct the recipe output; the Version 1 module warns and returns without replacing the nested Item View value in this case. |
| The selected recipe has missing ingredients or descriptions | **Recipe Panel > Ingredient Items** has fewer entries than the recipe needs. | Add one Item View and description entry for Herb and another for Water. |
| Clicking does not open a quantity choice | **Open Quantity Picker Panel On Recipe Click** or **Quantity Picker Panel**. | Enable the setting and assign the generated panel. |
| Craft stays unavailable with enough items | The bound Inventory, processor, ingredient collections, and exact recipe amounts. | Bind the player's Bag and configure the processor to search the collection that holds Herb and Water. |
| A custom tile never shows availability | The logic was added to the Recipe View, but no custom View Module updates it. | Keep availability in the standard quantity flow or implement a module that receives and refreshes that state. |

## Related pages

- [Views](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/)
- [Item View](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/item-view/)
- [Crafting Menu runtime workflow](https://opsive.com/support/documentation/ultimate-inventory-system/ui/crafting-menu/)
- [Crafting UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/crafting/)
- [Crafting Category editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/crafting-category/)
- [Crafting Recipe editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/crafting-recipe/)
- [Crafting concepts and processors](https://opsive.com/support/documentation/ultimate-inventory-system/crafting/)
- [Custom Crafting Processors](https://opsive.com/support/documentation/ultimate-inventory-system/crafting/custom-crafting-processors/)

## Developer and lifecycle details

`RecipeView` is a `View<CraftingRecipe>`. Calling `SetValue` forwards the recipe to its modules; `Clear` clears their presentation. `FirstOutputRecipeView.SetValue` reads `recipe.DefaultOutput.ItemAmounts[0]` and sends that Item Amount to its nested Item View with no Inventory origin.

`CraftingRecipeViewDrawer.GetViewPrefabFor` asks its `CategoryRecipeViewSet` for the prefab. The Crafting Menu calls `SetCrafter` and `DrawRecipes` when a station changes the available recipe set; selection and click callbacks update the Recipe Panel and quantity flow. `OnCraftComplete` exposes only the success Boolean, while the virtual `OnCraftComplete` method also receives the full Crafting Result, recipe, Inventory, and quantity.

Recipe Views, selected recipes, quantities, and open-panel state are presentation state and are not saved by the view. A successful craft changes the Inventory immediately, so an Inventory saver can persist the resulting Herb, Water, and Health Potion amounts. Version 1 does not replicate Recipe View selection or craft commands; multiplayer code must validate the craft on the authoritative side and synchronize the resulting Inventory changes.

---

<a id="page-ultimate-inventory-system-ui-views-multi-currency-view"></a>

# Multi Currency View

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/multi-currency-view/)

A Multi Currency View displays one or more Currency amounts, such as the player's Gold balance, an Iron Sword's total shop price, or a Crafting Recipe cost. Use a Currency Owner Monitor for a live wallet balance; let the Shop, Crafting Menu, Item View module, or other owning component supply contextual prices and costs.

The View does not hold or convert Currency. It maps each configured Currency to one Currency View and redraws those child Views from the value it receives.

## Before you begin

Confirm that:

- Gold exists in the selected Inventory System Database and has an Icon when the UI will show one;
- the player has a Currency Owner containing a known starting Gold amount;
- UI Designer Canvas Managers and a duplicated project schema have been created and spawned;
- the target panel has a valid parent Rect Transform; and
- for a shop test, Iron Sword has a `CurrencyAmounts` Item Definition Attribute named `BuyPrice` that contains Gold.

Create and verify the Currency data before styling the display. A correctly wired View cannot show a Currency that is missing from the active database or from its supplied value.

## Choose the data source

| Intended display | Data source | Owner |
| --- | --- | --- |
| Player's live Gold balance | Currency Owner's Currency Collection | **Currency Owner Monitor** |
| Selected Item and quantity's shop total | Calculated Currency Collection | **Shop Menu** |
| Recipe or quantity's crafting cost | Calculated Currency Collection | **Crafting Menu** or Recipe Panel |
| An Item's raw `BuyPrice` or another Currency Attribute | `CurrencyAmounts` Attribute | **Currency Item View** inside an Item View |
| A fixed reward, preview, or custom total | Currency Collection or Currency Amount array | Project code or another owning component |

Do not attach a Currency Owner Monitor to a price-only View. The monitor will redraw the player's balance over the contextual value supplied by the shop, recipe, or Item.

## Create a Multi Currency View

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer**.
2. Select **Currency** and open **Create**.
3. Choose one of the released Version 1 options:
   - **Multi Currency View** for the standard layout;
   - **Multi Currency View Small** for a compact layout;
   - **Currency Owner Monitor** for a ready-made balance View and monitor; or
   - **Currency View** for a single child View that another component will manage.
4. Set **Parent Transform**, then create the selected project-owned UI.
5. Select the Multi Currency View in **Edit** or the Inspector.
6. In **Currencies With Views**, add Gold and assign the Currency View that should display it.
7. On that Currency View, assign **Text**. Assign **Image** when Gold's Icon should be shown.
8. Leave **Hide If Zero** disabled, its default, when `0` must remain visible. Enable it only when the entire Currency View GameObject should become inactive at zero.

![Multi Currency View Inspector mapping configured Currencies to their corresponding Currency View components.](https://opsive.com/wp-content/uploads/2020/11/MultiCurrencyViewInspector.png?v=2023358c8ce0)

Every mapping needs a Currency and Currency View from the active database and scene or prefab. Keep the child hierarchy and layout order consistent with the mapping so a family of denominations reads naturally.

## Configure each Currency View

Currency View displays one `CurrencyAmount`:

- **Text** is required and shows the integer amount.
- **Image** is optional and uses the Currency's Icon.
- **Hide If Zero** is disabled by default. When enabled, setting the amount to zero deactivates the Currency View GameObject; setting a nonzero amount activates it again.

![Currency View Inspector with Hide If Zero, Image, and Text references for one displayed Currency.](https://opsive.com/wp-content/uploads/2020/11/CurrencyViewInspector.png?v=de842a3f6544)

Use zero-hiding deliberately. It works well in a layout group that should collapse unused denominations, but it can make a fixed-width price row shift as values cross zero. Keep zero visible when stable alignment matters.

## Bind a live Currency Owner

Choose **Currency Owner Monitor** in the UI Designer when the View should follow a player's wallet.

1. Assign **Multi Currency View**. When it is unassigned, the monitor tries to find one on the same GameObject at startup, but an explicit reference is easier to audit.
2. Set **Inventory ID** to the intended player's Inventory Identifier ID. The Version 1 default is `1`.
3. Alternatively, assign **Currency Owner** directly. A direct reference takes precedence; set **Inventory ID** to `0` when ID lookup should be disabled entirely.
4. In split-screen or runtime-spawned UI, give each player a distinct Inventory Identifier ID and verify that each monitor resolves the matching Currency Owner.

![Currency Owner Monitor Inspector with Inventory ID, Currency Owner, and Multi Currency View references.](https://opsive.com/wp-content/uploads/2020/11/CurrencyOwnerInspector.png?v=7e9aff742999)

At startup, the monitor resolves its Currency Owner, subscribes to the Currency Owner update event, and immediately draws the current Currency Collection. Later additions, removals, and replacements that notify the Currency Owner redraw the View automatically.

## Choose a Currency layout

### One Gold Currency

Map only Gold when every balance, reward, and price is expressed in Gold. This is the simplest layout and makes the player's balance directly comparable with the shop total.

### Several unrelated Currencies

Map each independent Currency to its own Currency View. A supplied Currency Collection draws the stored amount for each mapping; a missing amount appears as zero or is hidden according to that Currency View's **Hide If Zero** setting.

### A convertible Currency family

For a family such as Bronze, Silver, and Gold, map every denomination the UI should expose. Arrange the child Views from the most valuable to the least valuable, or follow the order established by the rest of the game UI.

Multi Currency View does not calculate exchange rates or combine a family into one total. With a Currency Collection input, it asks the collection for the stored amount of each mapped denomination after the collection's overflow and fraction rules have run. With a Currency Amount array, it matches exact Currency references and supplies zero for every mapped Currency missing from the array.

If the UI should show one converted total rather than the stored denominations, calculate or normalize that value before drawing it. Do not expect a raw array containing Bronze to populate the Silver or Gold Currency Views automatically.

## Show a balance beside a shop price

Keep two Views when the player needs both values:

1. Use a Currency Owner Monitor for the player's current Gold balance.
2. Let the Shop Menu draw Iron Sword's calculated `BuyPrice` and selected quantity into a separate Multi Currency View.
3. Map Gold in both Views, but do not add the monitor to the Shop total.
4. When an Item row shows a raw Currency Attribute, use **Currency Item View** and assign its **Multi Currency View** and **Currency Attribute Name**. The Shop can replace that raw value with its processed context-specific price after the Item View is drawn.

The balance View updates when the transaction changes the Currency Owner. The Shop total updates when selection or quantity changes. Their similar appearance does not make them the same data source.

## Editor checkpoint

Before entering Play Mode, confirm that:

- every Currency and Item price comes from the active Inventory System Database;
- each **Currencies With Views** entry has a valid Currency View;
- every Currency View has a required **Text** reference and an intentional optional **Image**;
- **Hide If Zero** matches the desired stable or collapsing layout;
- the balance monitor has the correct **Inventory ID** or direct **Currency Owner**;
- **Multi Currency View** is assigned on the monitor;
- the Shop total and player balance use separate Multi Currency Views; and
- every mapped denomination in a Currency family has the intended hierarchy order and overflow or fraction configuration.

## Verify in Play Mode

1. Give the player 100 Gold, enter Play Mode, and confirm that the Currency Owner Monitor shows `100` with the Gold Icon.
2. Add 25 Gold through the Currency Owner, then remove 10. Confirm that the balance changes immediately to `125` and then `115` without reopening the panel.
3. If **Hide If Zero** is enabled, remove the remaining Gold and confirm that the Gold GameObject becomes inactive. Add Gold again and confirm that it returns to the layout.
4. For a Bronze/Silver family configured at 100 Bronze per Silver with the intended overflow rules, add 250 Bronze. Confirm that the Currency Collection and mapped Views agree on the stored result, such as 2 Silver and 50 Bronze.
5. Pass a Currency Amount array containing only Bronze and confirm that absent Silver and Gold mappings show zero or hide; the View must not convert that raw array.
6. Open the Shop, select one Iron Sword with a `BuyPrice` of 50 Gold, and confirm that the Shop total shows `50` while the balance still shows the player's current amount.
7. Change quantity and confirm that only the Shop total changes. Complete a valid purchase and confirm that the balance decreases by the displayed total.
8. Attempt a purchase that costs more than the remaining Gold and confirm that neither the Inventory nor the Currency Owner balance changes.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| The Multi Currency View is empty | **Currencies With Views**, owning data source, and child **Text** references | Add valid mappings and let a monitor, menu, or project component draw a value. |
| Gold shows `0` despite a nonzero wallet | Currency Owner Monitor's **Inventory ID** or direct **Currency Owner** | Bind the monitor to the Currency Owner that actually holds the player's balance. |
| The balance belongs to another player | Duplicate Inventory Identifier IDs and the default monitor ID of `1` | Give each player a unique ID and configure each monitor explicitly. |
| The amount changes in data but not on screen | Monitor activation, **Multi Currency View**, and whether the Currency Owner change notified listeners | Keep the monitor active, assign the correct View, and mutate Currency through notifying Currency Owner or Currency Collection APIs. |
| Gold disappears at zero | **Hide If Zero** | Disable it when a visible zero and stable layout are required. |
| The Icon is missing but the number is correct | Currency Icon and Currency View **Image** | Assign Gold's Icon and the intended Image reference. |
| A family shows the wrong denominations | Stored Currency Collection, family overflow/fraction rules, and mapped Currencies | Correct the Currency data and map every denomination the UI should show. |
| A raw Bronze array does not update Silver | Input overload | Supply the exact Currency entries or normalize into a Currency Collection before drawing. |
| Shop total shows the player's balance | Currency Owner Monitor attached to the price View | Remove the monitor and let Shop Menu own the total-price View. |
| Shop total is missing | `BuyPrice`, **Buy Attribute Name**, Gold mapping, and selected quantity | Correct the Attribute and ensure Shop Menu references a mapped Multi Currency View. |
| Text-color API throws or has no effect | Empty mappings or missing Currency View **Text** | Configure at least one mapped Currency View with Text before calling the color methods. |

## Related pages

- [Views and owner responsibilities](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/)
- [Currency UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/currency/)
- [Currency editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/currency/)
- [Currency model and conversion](https://opsive.com/support/documentation/ultimate-inventory-system/currency/)
- [Shop and transactions](https://opsive.com/support/documentation/ultimate-inventory-system/currency/shop/)
- [Shop Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/shop-menu/)
- [Crafting Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/crafting-menu/)
- [Item View and Currency Item View](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/item-view/)
- [Split-screen UI ownership](https://opsive.com/support/documentation/ultimate-inventory-system/input/split-screen-co-op-ui/)
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)

## Developer API, events, saving, and networking

Draw a Currency Collection when the UI should reflect its stored denominations. Draw an array when the caller already has exact Currency amounts:

```csharp
multiCurrencyView.DrawCurrency(currencyOwner.CurrencyAmount);
multiCurrencyView.DrawCurrency(new[] {
    new CurrencyAmount(gold, 50),
});

multiCurrencyView.SetTextColor(Color.white);
multiCurrencyView.DrawEmptyCurrency();
```

`DrawCurrency(null)` sets every mapped child to `CurrencyAmount.None`; a child with **Hide If Zero** disabled displays `0`. `DrawEmptyCurrency()` calls `Clear()` on each child instead, leaving its text empty or its GameObject hidden. `GetTextColor()` reads the first mapping and therefore requires at least one valid mapped Currency View.

A Currency View can also receive one amount directly:

```csharp
currencyView.SetValue(new CurrencyAmount(gold, 50));
currencyOwnerMonitor.SetCurrencyOwner(currencyOwner);
```

Currency Owner Monitor listens for the Version 1 Currency Owner update event and unregisters when destroyed. Multi Currency View and Currency View do not own persistence or network state. Use Currency Owner Saver when the wallet must persist through the Save System, and let the project's networking layer synchronize the authoritative Currency Owner before redrawing or notifying its local UI.

---

<a id="page-ultimate-inventory-system-ui-views-save-view"></a>

# Save View

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/save-view/)

A Save View presents one numbered save slot and its lightweight metadata in the Save Menu. Use it to distinguish an empty slot from an occupied one without loading the full saved Inventory first.

The Save View is presentation only. The Save Grid owns selection and the Save, Load, and Delete actions; the Save System Manager owns the local files; and Saver components decide whether Bag, Equipment, Gold, mutable Item values, or other runtime state is included.

## Before you begin

Set up the Save System before customizing its slot presentation:

1. Open **Tools > Opsive > Ultimate Inventory System > Main Manager**.
2. Select **Setup**, then open **Save Setup**.
3. Assign the player under **Object to save** and select **Add Components**.
4. Confirm that the Inventory System Manager has **Save System Manager** and **Inventory System Manager Item Saver**.
5. Confirm that the player has **Inventory Saver**. Add **Currency Owner Saver** when Gold must persist.
6. Open **Tools > Opsive > Ultimate Inventory System > UI Designer**, select **Save**, and create a **Basic** or **Main Menu** Save Menu.

For the first test, keep the four automatic load and save options disabled. The released Version 1 manager defaults to **Max Saves** `5`, **Save File Name** `SaveFile`, **Save File Extension** `save`, and **Save Meta Data File Extension** `metadata`. Leaving **Save Meta Data Creator** unassigned uses the built-in date-and-time metadata.

## Understand the slot data flow

| Part | Responsibility |
| --- | --- |
| **Save System Manager** | Scans metadata, maintains numbered slots, asks Savers for data, and reads or writes local files. |
| **SaveDataInfo** | Carries the slot **Index**, lightweight **MetaData**, and full **Data** when that data has been loaded. |
| **Save Menu** | Refreshes its Save Grid when the panel opens and selects the first slot. |
| **Save Grid** | Draws slots, opens the Action Panel, confirms destructive actions, and calls Save, Load, or Delete. |
| **Save View Drawer** | Assigns the absolute slot index and sends each `SaveDataInfo` to a Save View. |
| **Save View** | Holds the current slot value and forwards it to Save View Modules. |
| **Save View Module** | Draws the formatted slot number plus **Empty**, a basic timestamp, or a fallback save-file label. |

The manager stores metadata separately from the full save data so the grid can list slots without deserializing every Inventory. Keep each slot's `.save` and `.metadata` files together.

## Configure the Save View prefab

The UI Designer schema includes a Save View prefab. Duplicate the project-owned schema or prefab before making visual changes rather than editing a package or demo asset in place.

1. Select the Save Grid and locate its **Save View Drawer**.
2. Assign the intended prefab to **Save Box Prefab**. The field keeps the older `box` label but expects a Save View prefab.
3. On **Save View**, assign **Target Graphic** when the slot's Button should use a Graphic from the view. Assign **Canvas Group** when the whole slot should fade or be hidden together.
4. Keep the **Modules** list synchronized with the Save View Module components attached to the prefab.
5. On **Save View Module**, keep **File Number Format** as `{0:00}` to display indexes `00`, `01`, and so on, or choose another valid composite format.
6. Assign **File Number Text** and **Save Content Text** to the visible text controls.

![Save View and Save View Module Inspector fields for the numbered slot and its metadata content text.](https://opsive.com/wp-content/uploads/2021/10/Save-View.png?v=4cb8bad90a44)

The drawer supplies a zero-based slot index before the module draws. With the default format, the first file is therefore shown as `00`, matching Save System Manager index `0`.

## Choose the metadata presentation

The shipped Save View Module has three display states:

- **Empty** when metadata is null or `MetaData.IsEmpty` is true;
- the saved date and time when metadata is `BasicSaveMetaData`; and
- **Save File N** for another metadata type, where `N` is `SaveDataInfo.Index`.

Use a custom Save Meta Data Creator and custom Save View Module when the slot must show a character name, location, play time, difficulty, thumbnail reference, or application save version. The creator must return an empty metadata object whose `IsEmpty` is true and saved metadata whose `IsEmpty` is false. The module must clear every custom text or image so a reused slot cannot retain the previous save's details.

Do not read the full `SaveData` merely to draw the list. Put only the small, stable summary needed by the menu in metadata.

## Configure the Save Grid actions

Confirm these generated references and Version 1 defaults:

| Save Grid field | Default | Purpose |
| --- | --- | --- |
| **Action Panel** | Generated reference | Presents **Save**, **Load**, and **Delete** for the selected slot. |
| **Confirmation Pop Up** | Generated reference | Confirms overwrite, load, and delete. |
| **Optional Save Event > Use Optional Event** | Disabled | Replaces the built-in Save call when enabled. |
| **Optional Load Event > Use Optional Event** | Disabled | Replaces the built-in Load call when enabled. |
| **Optional Delete Event > Use Optional Event** | Disabled | Replaces the built-in Delete call when enabled. |

Enabling an optional event cancels the corresponding built-in operation. Its callback must perform the complete replacement action; an event that only plays audio or shows feedback leaves the slot unchanged.

Keep the visible grid and navigation within indexes `0` through **Max Saves - 1**. Extra selectable layout cells are not usable save slots.

## How slot actions run

1. Opening the Save Menu refreshes the grid from `SaveSystemManager.GetSaves()` and selects its first button.
2. Clicking or submitting a slot opens the Action Panel.
3. **Save** collects every registered Saver, creates new metadata, and writes both slot files. A metadata-null entry saves without confirmation; an entry with metadata asks to overwrite.
4. **Load** asks for confirmation, reads the selected `.save` file, and applies every registered Saver in load-priority order.
5. **Delete** asks for confirmation and removes the selected data and metadata files.
6. The Save Grid refreshes after each action so the Save View reflects the manager's latest metadata.

Released Version 1 creates a non-null empty metadata object for every unused slot. The Save View correctly displays **Empty**, but the built-in Save Grid tests only whether metadata is null when it enables Load/Delete or decides whether Save needs overwrite confirmation. An Empty slot can therefore still offer Load and Delete and can ask for overwrite confirmation. Use Save on that entry and avoid Load/Delete, or customize Save Grid to check `MetaData.IsEmpty` as well.

## Handle incomplete or damaged slots

The default Save View reports metadata state; it does not validate the matching data file.

- A valid metadata file with a missing data file can look occupied, but Load logs that the slot cannot be loaded.
- A corrupt metadata or data file can fail during Version 1 deserialization; there is no built-in damaged-slot presentation or migration screen.
- The built-in delete path is not transactional. If one file in the pair is already missing, it can return before removing the remaining file or clearing the in-memory entry.

For a shipped game, validate file pairs in a project-owned persistence layer before exposing them to the grid. Back up the save folder before repairing an orphaned pair, then remove or migrate both files for that index together. Use **PrintSaveFolderPath** from the Save System Manager component menu to identify the current platform's folder.

## Editor checkpoint

Before entering Play Mode, confirm that:

- one Save System Manager exists and **Max Saves** matches the intended slot count;
- the required Inventory, Item, and Currency Saver components are active and use unique full keys;
- Save Menu references the generated **Save Grid**;
- Save Grid references its **Action Panel**, **Confirmation Pop Up**, and Save View Drawer;
- the drawer's **Save Box Prefab** contains Save View and Save View Module;
- **File Number Text** and **Save Content Text** reference visible controls;
- the number of reachable slot buttons does not exceed **Max Saves**;
- optional action events remain disabled unless their replacement callbacks are complete; and
- every supported input method can reach the grid, Action Panel, and confirmation popup.

The visible checkpoint is five slots labeled `00` through `04` with the default manager settings. Unused slots show **Empty**.

## Verify in Play Mode

1. Start with three Health Potions in **Bag**, an Iron Sword in **Equipment**, and a known Gold balance.
2. Open the Save Menu and confirm that unused slots display **Empty** with the expected zero-based numbers.
3. Select slot `00`, choose **Save**, and accept the overwrite prompt if Version 1 shows one. Confirm that the content changes from **Empty** to a date and time.
4. Remove two Health Potions, unequip the Iron Sword, and spend some Gold.
5. Choose **Load** on slot `00` and accept the prompt. Confirm that Bag, Equipment, and Gold return to their saved values.
6. Change the state again, save to `00`, and confirm the overwrite. Load it and verify that the newer state replaced the earlier state.
7. Save a different state to `01`. Switch between `00` and `01` and confirm that each Save View retains its own number and timestamp.
8. Delete slot `01` and confirm that its Save View returns to **Empty**. Do not use Load or Delete on it even if the Version 1 action panel still exposes those choices.
9. Save slot `00` again, stop and restart Play Mode, reopen the menu, and confirm that the dated entry is reconstructed from disk. Load it and verify the Inventory and Gold one more time.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| The slot number or content is blank | **File Number Text** and **Save Content Text** on Save View Module. | Assign both visible text controls. |
| Every slot shows the same number | Save Grid uses the wrong drawer or a custom drawer does not call `SaveView.SetIndex`. | Use Save View Drawer or forward the absolute element index before drawing. |
| A reused slot keeps another save's custom image or text | The custom Save View Module's `Clear` implementation. | Reset every visual value that the module sets. |
| An Empty slot offers Load/Delete or asks to overwrite | Version 1 action conditions check whether metadata exists, while the view checks `MetaData.IsEmpty`. | Use Save only, or customize Save Grid so its action conditions also reject empty metadata. |
| Save, Load, or Delete only invokes feedback | The corresponding **Optional ... Event** is enabled. | Disable it, or make its callback call the complete replacement operation. |
| A blank cell beyond the final slot can be selected | Grid size or navigation exposes an index at or above **Max Saves**. | Restrict visible and navigable cells to `0` through **Max Saves - 1**. |
| A dated slot will not load | Its `.metadata` exists but its `.save` file is missing, unreadable, or corrupt. | Back up the folder, repair or remove the pair, and create a fresh slot. |
| Delete does not clear an orphaned slot | One file in the pair was already missing. | Repair the pair outside the default menu after a backup; Version 1 deletion is not transactional. |
| Bag, Equipment, or Gold does not return | The matching Saver is missing, inactive, duplicated by key, or bound to the wrong owner. | Correct the Saver setup and repeat a save/restart/load round trip. |
| Custom metadata still shows **Save File N** | The default Save View Module does not know the custom metadata type. | Add a custom Save View Module that reads that type and clears its own presentation. |

## Related pages

- [Views](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/)
- [Save Menu runtime workflow](https://opsive.com/support/documentation/ultimate-inventory-system/ui/save-menu/)
- [Save UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/save/)
- [Save System and Saver components](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)
- [Main Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/main-menu/)
- [Scene Transitions](https://opsive.com/support/documentation/ultimate-inventory-system/scene-transitions/)
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/)

## Developer, event, cloud, and network boundaries

`SaveView` is a `View<SaveDataInfo>`. `SaveViewDrawer.BeforeDrawingBox` calls `SetIndex`, and `SaveViewModule.SetValue` formats that index and reads only `MetaData`. Subclass `SaveViewModule` to present a custom metadata type, and override both `SetValue` and `Clear` so pooled views remain deterministic.

`SaveGrid.Save`, `Load`, and `Delete` forward to `SaveSystemManager.Save`, `Load`, and `DeleteSave`. Its virtual methods are the safer integration points for a replacement backend. The manager publishes slot-index events before and after save, load, and delete: `c_WillStartSaving_Index`, `c_SavingComplete_Index`, `c_WillStartLoadingSave_Index`, `c_LoadingSaveComplete_Index`, `c_WillDeleteSave_Index`, and `c_DeleteSaveComplete_Index`.

The built-in manager writes local files under `Application.persistentDataPath`. It does not provide cloud synchronization, conflict resolution, encryption, automatic backups, schema migration, or network authority. It also uses one global manager rather than per-player Save View ownership. Add those policies in a project-owned persistence layer, keep authoritative multiplayer saves server-side, and use an overridden Save Grid or complete optional-event handlers to connect that layer to the UI.

---

<a id="page-ultimate-inventory-system-ui-item-description"></a>

# Item Description

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-description/)

An Item Description shows details for the `ItemInfo` supplied by an Inventory Grid, Item Hotbar, Equipment view, or another Item View Slots Container. Use one when selecting an Item should reveal more than its slot can show.

For example, one panel can show the Health Potion's name, `Icon`, and `Description`, then add `Attack` and `Durability` when the player selects an Iron Sword or Fire Wand. The panel does not choose or own the Item. A binding passes it the selected or clicked slot's current `ItemInfo`.

## Before you begin

Confirm that:

- the Inventory System Database contains the Items that the container will draw;
- `Description` is a string attribute and `Icon` is a Sprite attribute where those values are required;
- the Bag, Equipment view, hotbar, or other Item View Slots Container already displays Items; and
- the project uses its own duplicated UI Designer schema rather than editing package assets.

The standard `Item Description` component reads the Item name and a string description. Item View Modules add the icon, amount, or other attributes.

## Create an Item Description

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer** and select **Item Description**.
2. In the **Create** section, leave **Give Description a Panel** enabled for a fixed panel or tooltip. This option is enabled by default.
3. Choose an **Item Description Preset**. **Standard** is the default; **Small** and **Big** are the other supplied choices.
4. Choose the intended parent and create the description.
5. In the **Edit** section, select the generated Item Description and keep only the Item View Modules that support a player decision.

When **Give Description a Panel** is enabled, UI Designer creates a non-selectable Display Panel and an **Item Description Panel Binding**. That binding initializes the description with its panel; it does not supply the selected Item.

## Configure the core text

The concrete `Item Description` component has these fields:

| Inspector field | Default | Purpose |
| --- | --- | --- |
| **Description Attribute Name** | `Description` | Name of the string attribute shown as the description. |
| **Item Name Text** | None | Text element that receives the current Item's name. |
| **Description Text** | None | Text element that receives the attribute value. |
| **No Item Selected Message** | `No Item selected` | Name-area text shown after the view is cleared. |
| **No Description Message** | `The item does not have a description` | Text shown when the current Item has no matching string attribute. |
| **Block Raycast And Interactable** | Off | Whether the description's Canvas Group blocks raycasts and remains interactable after the view is cleared. Keep this off for a passive tooltip. |

Assign both text references. If **Item Name Text** or **Description Text** is missing, the standard component cannot draw or clear that field.

## Add icons and category-specific attributes

An Item Description is also an Item View, so modules on the same GameObject receive the same `ItemInfo`.

| Module | Use it for |
| --- | --- |
| **Icon Item View** | Reads the Sprite attribute named `Icon`. **Missing Icon** is used when the value is absent; **Disable On Clear** can hide the Image for an empty selection. |
| **Amount Item View** | Shows the amount represented by the selected slot's `ItemInfo`. |
| **Attribute Item View** | Converts one named attribute value to text. Set **Default Text Value** and optionally **Disable On Clear** for a missing value. |
| **Category Attribute View Set Item View Module** | Creates Attribute View prefabs under **Attribute UI Parent** for every configured category that contains the selected Item. |

Use a Category Attribute View Set when different Item groups need different rows:

| Category mapping | Example result |
| --- | --- |
| Consumable | Health Potion shows its `Description` without Weapon-only rows. |
| Weapon | Iron Sword and Fire Wand show `Attack` and `Durability` when those attributes exist. |

Category membership includes inheritance. If both a parent category and a child category match, the module processes both mappings. Avoid mapping the same attribute in both unless two rows are intentional. A missing attribute is skipped rather than rendered with an empty generated row.

## Bind a fixed description to a container

The quickest route is through the Item Description page's **Item View Slots Container Binding** section in UI Designer:

1. Assign the Bag Inventory Grid, Equipment view, Item Hotbar, or other **Item View Slots Container**.
2. Choose **Bind Item View Slot Container**.
3. Confirm that an **Item View Slot Container Description Binding** now sits on the same GameObject as the container.
4. Assign either **Item Description Panel** or a direct **Item Description** reference. When the panel reference is set, its description is used.

The container finds and binds compatible components on its own GameObject. The description binding listens to that container's selection, click, deselection, and redraw events.

The important binding defaults are:

| Inspector field | Default | Effect |
| --- | --- | --- |
| **Hide If Selected Item Is Null** | Off | Clears the content but leaves the description object or panel visible for an empty selection. |
| **Draw On Select** | On | Draws the selected slot's `ItemInfo`. |
| **Draw On Click** | Off | Ignores click as a separate draw trigger. |
| **Draw On Container Draw** | On | Redraws the currently selected slot when the container redraws. |
| **Clear On Deselected** | Off | Keeps the previous content when a slot is deselected. |
| **Hide On Deselected** | Off | Keeps the description visible when a slot is deselected. |

Choose selection for keyboard and controller navigation. Enable click when the design deliberately updates details only after activation. These bindings do not provide a separate pointer-hover trigger: a pointer updates the description only if the project's UI selection behavior selects the slot, or custom code supplies its `ItemInfo`.

## Use the description as a tooltip

A tooltip needs two jobs to remain separate:

- **Item View Slot Container Description Binding** supplies and clears the content.
- **Item View Slot Panel To Tooltip** positions and shows the Display Panel beside the selected or clicked slot.

With a panel-backed description selected in UI Designer, assign the container and choose **Convert To Tooltip**. The generated setup places and shows the tooltip on selection, hides it on deselection, and disables click placement and click display by default.

In the **Item View Slot Panel To Tooltip** Inspector, use **Panel Bounds** to keep the tooltip within a visible RectTransform. **Place On Select**, **Show On Select**, and **Hide Show On Deselect** are enabled by default; **Place On Click** and **Show On Click** are disabled. Test the first and last visible slots because the panel is placed relative to the selected slot and its Canvas.

## How it runs

1. The Item View Slots Container binds the description binding on the same GameObject.
2. The binding immediately tries to draw the currently selected slot.
3. Selection, an enabled click trigger, or a container redraw passes that slot's `ItemInfo` to `ItemDescriptionBase.SetValue`.
4. The standard Item Description draws the Item name and `Description`; each Item View Module receives the same value.
5. The Category Attribute View Set module removes the previous generated rows and creates the rows for every matching category.
6. A missing Item clears the core text and all modules. **Hide If Selected Item Is Null** additionally closes the bound Display Panel or deactivates a directly referenced description.

`ItemInfo` identifies the Item and amount and can retain its source Item Collection and Item Stack. The standard name, description, and icon renderers read the Item itself. The view does not remove, copy, equip, or otherwise modify that Item.

## Mutable and common Items

The description reads the exact runtime Item carried by the selected slot's `ItemInfo`. Common values such as a Health Potion's `Description` can resolve from its shared data, while a mutable Iron Sword can show the attribute values resolved for that particular runtime Item.

Changing an attribute does not make `ItemDescription` subscribe to that attribute. The view refreshes when its container redraws, when selection or an enabled click trigger supplies the Item again, or when code calls `Refresh()`. If Durability changes while the same Iron Sword remains selected, redraw the container, reselect the slot, or refresh the description.

## Editor checkpoint

Before entering Play Mode, confirm that:

- the Item Description has valid **Item Name Text** and **Description Text** references;
- the Health Potion, Iron Sword, and Fire Wand resolve the expected `Description` and `Icon` values;
- every module references its intended text, Image, or attribute parent;
- the Category Attribute View Set uses categories from the active database and its attribute names match exactly;
- the description binding is on the same GameObject as the Item View Slots Container;
- the binding references the intended Item Description or Item Description Panel; and
- a tooltip has a Display Panel, both required bindings, and suitable **Panel Bounds**.

## Verify in Play Mode

1. Open Bag and select Health Potion. Its name, icon, and description should appear without Weapon-only rows.
2. Select Iron Sword, then Fire Wand. The old rows should be removed and replaced with each Item's current `Attack` and `Durability` values.
3. Select an empty slot. Confirm that the empty message, clear, or hide behavior matches the binding settings.
4. Close and reopen the owning menu. The panel should initialize and the selected slot should redraw without stale content.
5. Change a mutable Iron Sword's Durability, redraw or refresh the description, and confirm that the displayed value changes.
6. For a tooltip, navigate to slots at every canvas edge and confirm that the panel remains visible and does not capture input intended for the slot.

## Save and network boundaries

An Item Description is a local view. Its current selection, generated attribute rows, and tooltip position are not save data. Save the Inventory and mutable Item attributes through the UIS save workflow, then let the container redraw after loading.

Version 1 does not make the description a network authority or replicate it. Networked projects should synchronize the Inventory or Item data through their networking solution and refresh the local description after that data changes.

## Troubleshooting

- **The name or description throws an error or stays blank:** Check **Item Name Text** and **Description Text**, then verify that **Description Attribute Name** matches a string attribute on the selected Item.
- **The icon is missing:** Check that the module has an Image reference and that the Item resolves a Sprite attribute named exactly `Icon`; otherwise **Missing Icon** is shown.
- **Health Potion shows Weapon rows:** Check category inheritance and the Category Attribute View Set. Remove the Consumable from any Weapon path and remove duplicated mappings.
- **Iron Sword or Fire Wand has no attribute rows:** Check **Attribute UI Parent**, the active database categories, exact attribute names, and that every mapped prefab has an Attribute View component.
- **Selection changes but the panel does not:** Check that the description binding is beside the correct container and references the intended description. The **Item Description Panel Binding** alone initializes a panel but does not draw a selected Item.
- **A previous Item remains after deselection:** Enable **Clear On Deselected**, or rely on selection of an empty slot and confirm **Draw On Select** is enabled.
- **A mutable value stays stale:** Redraw the container, reselect the slot, or call `Refresh()` after the attribute changes.
- **A tooltip moves but its content does not change:** The tooltip component only places and shows the panel. Add or repair the separate description binding.
- **Pointer movement does not update the tooltip:** The supplied binding responds to selection and optional click, not raw hover. Configure pointer-driven selection or provide a custom hover binding.

## Related pages

- [Create an Item Description with UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-description/)
- [Item View](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/item-view/)
- [Attribute Views](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/attribute-views/)
- [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/)
- [Display Panel Manager](https://opsive.com/support/documentation/ultimate-inventory-system/ui/display-panel-manager/)
- [Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/)
- [ItemInfo](https://opsive.com/support/documentation/ultimate-inventory-system/item/item-info/)
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)

## Developer details

- `ItemDescriptionBase.SetValue(ItemInfo)` initializes the view, passes the value to its modules, and clears when `ItemInfo.Item` is null.
- `Clear()` clears the current value and every module. `Refresh()` calls `SetValue` again with the current `ItemInfo`.
- `ItemViewSlotContainerDescriptionBinding.DrawDescriptionOfSelectedSlot()` redraws the container's selected slot; `ClearDescription()` clears and optionally hides it.
- `BindItemViewSlotContainer(...)` and `UnbindItemViewSlotContainer()` manage the container event subscriptions.
- `ItemViewSlotPanelToTooltip.PlacePanel(...)` positions the panel; it does not set description content.
- `GetViewModule<T>()` and `InvokeOnAllModules<T>(...)` provide access to attached view modules for custom presentation logic.

---

<a id="page-ultimate-inventory-system-ui-monitors"></a>

# Inventory and Currency Monitors

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/ui/monitors/)

Use a monitor when the UI should react to existing Inventory or Currency data without changing that data. Released Ultimate Inventory System Version 1 ships two monitor components: **Inventory Monitor** shows temporary notifications for newly added Items, while **Currency Owner Monitor** keeps a Multi Currency View synchronized with a player's balance.

## Choose the monitor for the outcome

| Player-facing outcome | Shipped component | What it observes | What it does not do |
| --- | --- | --- | --- |
| Show `Health Potion +1` after a pickup | **Inventory Monitor** | Item additions to selected Item Collections | It does not add, remove, move, select, or save Items. |
| Keep the player's Gold amount current | **Currency Owner Monitor** | Updates from one Currency Owner | It does not calculate a Shop price or perform a transaction. |

A Shop total and a player balance are different values. Let the Shop Menu draw the selected Item's total price, and use a separate Currency Owner Monitor for the Gold the player currently owns.

## Resolve the correct player

Both monitors can use a direct reference or an **Inventory ID**, but neither automatically binds from **Display Panel Manager > Panel Owner**.

| Monitor | Direct-reference choice | ID choice | Released V1 precedence |
| --- | --- | --- | --- |
| Inventory Monitor | **Starting Monitored Inventory** | **Inventory ID**, default `1` | The direct Inventory is used when assigned; otherwise the monitor resolves the matching Inventory Identifier. ID `0` disables lookup. |
| Currency Owner Monitor | **Currency Owner** | **Inventory ID**, default `1` | The direct Currency Owner is used when assigned; otherwise the monitor resolves the matching Inventory Identifier's Currency Owner. ID `0` disables lookup. |

For a fixed single-player scene, either approach is valid. IDs are easier when a prefab cannot store a scene reference. For split-screen, give every player a unique Inventory Identifier ID and use a separate monitor in each player's Canvas.

When a player spawns after its monitor, bind explicitly after the Inventory Identifier has registered. Use `SetMonitoredInventory` for Inventory Monitor or `SetCurrencyOwner` for Currency Owner Monitor. Re-enabling Inventory Monitor also retries its ID lookup. Do not rely on a later Panel Owner change to switch either monitor to a different player.

## Show Item-added notifications

Create the starting presentation through **Tools > Opsive > Ultimate Inventory System > UI Designer > Inventory Monitor**. UI Designer instantiates the selected schema's Inventory Monitor and assigns the schema Item View prefab.

1. Place the generated monitor in the intended Canvas safe area.
2. Set **Inventory ID**, or assign **Starting Monitored Inventory** directly.
3. Under **Monitored Item Collections**, add `Bag` for pickup feedback. When the list is empty, released V1 monitors only the Inventory's main Item Collection.
4. Assign **Monitor Content**, or leave it empty to use the monitor's own Rect Transform.
5. Confirm that **Item View Prefab** contains an Item View configured to show useful values such as Icon, name, and amount.
6. Set **Max Displays** to at least `1`. The raw component has no nonzero code default; the released demo uses `5`.
7. Enable **Combine Similar Items** when matching additions should update one active or queued notification. It is disabled by default.
8. Set positive values for **Rect Max Display Time**, **Rect Min Display Time**, and **Rect Transition Time**. The released demo uses `2`, `0.3`, and `0.3` seconds respectively.

![Legacy Inventory Monitor Inspector with inventory ownership, Item View, display-count, and notification-timing configuration.](https://opsive.com/wp-content/uploads/2020/04/Inventory-Monitor-1.png?v=8e19fd70dcd1)

The monitor responds only to additions whose destination passes the collection filter. It ignores transfers that originate from the same Inventory and additions originating from **Hide** or **Loadout** collections. Moving Iron Sword from Bag to Equipment therefore does not appear as a new pickup, while adding Health Potion from a world pickup to Bag does.

When **Combine Similar Items** is enabled, the monitor combines Items that are stackably equivalent. Health Potion additions can accumulate in one view; Iron Sword and Fire Wand remain separate when their Item data is not stackably equivalent.

## Show a live Gold balance

Create the starting presentation through **Tools > Opsive > Ultimate Inventory System > UI Designer > Currency**, choose **Currency Owner Monitor**, and select **Create**. This option creates the monitor with a Multi Currency View.

1. Map Gold to its Currency View in **Multi Currency View > Currencies With Views**.
2. Give the Gold Currency View a valid **Text** reference and, when needed, an **Image** for Gold's Icon.
3. On Currency Owner Monitor, set **Inventory ID**, or assign **Currency Owner** directly.
4. Assign **Multi Currency View**. When this field is empty, the monitor looks for that component on the same GameObject during `Start`.
5. Keep this balance view separate from Shop, crafting, reward, or cost views that another component draws directly.

After resolving its Currency Owner, the monitor immediately draws the current Currency Collection. It then listens for Currency Owner updates and redraws every mapped Currency. A purchase can therefore reduce the Gold balance while the Shop's separate total-price view continues to show the transaction cost.

## Editor checkpoint

Before entering Play Mode, confirm that:

- every monitor resolves the intended player's direct owner or unique Inventory Identifier ID;
- split-screen players do not share one monitor instance;
- Inventory Monitor watches Bag for acquisition feedback and does not treat Equipment as a pickup source;
- **Item View Prefab**, **Monitor Content**, **Max Displays**, and all three timing values are valid;
- Health Potion, Iron Sword, and Fire Wand provide the values used by the notification Item View;
- Currency Owner Monitor references a Multi Currency View that maps Gold to a valid Currency View;
- the balance view is not also used as a Shop total-price view; and
- no duplicate active monitors observe the same player and outcome.

## Verify in Play Mode

1. Add one Health Potion from a world pickup to Bag. Confirm that one Item View appears with the correct Item and amount, then fades.
2. Add several equivalent Health Potion Items quickly. Confirm that they combine or remain separate according to **Combine Similar Items**.
3. Add Iron Sword and Fire Wand. Confirm that different Items do not merge into one notification.
4. Move Iron Sword from Bag to Equipment. Confirm that the same-Inventory transfer does not appear as a new acquisition.
5. Disable and re-enable Inventory Monitor, then collect another Health Potion. Confirm that listening stops and resumes without replaying the earlier addition.
6. Record the player's Gold and confirm that Currency Owner Monitor displays the same amount.
7. Buy Health Potion with Gold. Confirm that the separate Shop price shows the transaction total and the monitored balance decreases after the purchase.
8. In a runtime-spawn or split-screen test, change each player's Items and Gold independently. Confirm that only the matching Canvas responds.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| No Item notification appears | **Starting Monitored Inventory**, **Inventory ID**, destination collection, active state, and listening state | Resolve the intended Inventory, monitor Bag, and enable or restart listening. |
| The monitor warns that its display prefab is null | **Item View Prefab** | Assign a prefab containing an Item View, preferably through the project-owned UI Designer schema. |
| The monitor is configured but cannot present a notification | **Max Displays** and the three time fields | Use at least one display and positive display and transition times. |
| Equipping Iron Sword creates a pickup notification | Origin ItemInfo and whether project code represented the operation as a same-Inventory transfer | Move the existing Item between collections instead of creating an unrelated external addition. |
| Matching Health Potions do not combine | **Combine Similar Items** and whether the Items are stackably equivalent | Enable combining and align the Item data that defines stack equivalence. |
| The wrong player's Items or Gold appear | Direct owner references and duplicate or mismatched Inventory Identifier IDs | Remove stale direct references and give each player-monitor pair a unique matching ID. |
| A monitor created before the player stays unbound | The owner did not exist when `Start` performed the ID lookup | Call the appropriate setter after spawn, or re-enable Inventory Monitor after registration. |
| Gold remains blank | **Currency Owner**, **Inventory ID**, **Multi Currency View**, Gold mapping, and Currency View **Text** | Resolve the correct owner and complete the Gold-to-view mapping. |
| A Shop price shows the player's whole balance | Currency Owner Monitor is attached to the Shop's total-price view | Remove it from that view and use a separate balance Multi Currency View. |
| Both split-screen Canvases respond | Monitors share an ID or direct owner | Use one explicitly bound monitor per player and Canvas. |
| Pickup notifications appear during a standard save load | The load was performed outside the UIS save lifecycle events | Use the UIS Save System flow, or stop and restart listening around the custom bulk restore. |

## Related pages

- [Create an Inventory Monitor in UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/inventory-monitor/)
- [Create Currency views in UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/currency/)
- [Item View](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/item-view/)
- [Multi Currency View](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/multi-currency-view/)
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/)
- [Currency and Currency Owners](https://opsive.com/support/documentation/ultimate-inventory-system/currency/)
- [Item Pickups](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-pickups/)
- [Split Screen Co-op UI](https://opsive.com/support/documentation/ultimate-inventory-system/input/split-screen-co-op-ui/)
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/)

## Developer, save, and network details

Inventory Monitor exposes `SetMonitoredInventory`, `StartListening`, and `StopListening`. Project code can also send `EventNames.c_InventoryGameObject_InventoryMonitorListen_Bool` to the monitored Inventory GameObject:

```csharp
EventHandler.ExecuteEvent<bool>(
    playerInventory.gameObject,
    EventNames.c_InventoryGameObject_InventoryMonitorListen_Bool,
    false);
```

Inventory Monitor listens to `EventNames.c_Inventory_OnAdd_ItemInfo_ItemStack`. During a normal UIS load it handles `EventNames.c_WillStartLoadingSave_Index`, remembers whether it was listening, and resumes after `EventNames.c_LoadingSaveComplete_Index`. It has no saver because it presents Inventory state rather than owning it.

Currency Owner Monitor exposes `SetCurrencyOwner`, registers for `EventNames.c_CurrencyOwner_OnUpdate`, and redraws the Currency Owner's amounts through `MultiCurrencyView.DrawCurrency`. Although it observes the global panel-owner-change event, released V1 does not use the new Panel Owner argument to select another Currency Owner; call `SetCurrencyOwner` when the displayed player changes. Save the authoritative balance with **Currency Owner Saver**, not the view.

Released UIS Version 1 does not replicate monitor ownership, Item additions, Currency balances, or UI presentation. A networking layer must replicate the authoritative Inventory and Currency changes; each client then binds its local monitors to the appropriate replicated player state.

---

<a id="page-ultimate-inventory-system-ui-main-menu"></a>

# Main Menu

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/ui/main-menu/)

Use Main Menu as a shared navigation shell for Inventory screens such as Bag, Equipment, Shop, Crafting, and Save/Load. Each tab maps one Action Button to one inner Display Panel, while the Display Panel Manager opens and closes the shell for the correct player.

Main Menu does not own Inventory data. Bag, Equipment, and every other subpanel keep their own Inventory, Item Collection, Shop, Crafter, or Save bindings. Main Menu only decides which mapped subpanel is active.

## Before you begin

Confirm that the scene has:

- an EventSystem;
- a Display Panel Manager under the intended player's Canvas;
- a valid **Panel Owner**, or a **Panel Owner Inventory Identifier ID** that resolves the player;
- a **Gameplay Panel** if opening Main Menu should replace the normal gameplay HUD; and
- the data and runtime components required by each intended subpanel.

For a small test, create a player Inventory with **Bag** and **Equipment** collections. Put Health Potion and Iron Sword in Bag, and configure Equipment with a Weapon slot that accepts Iron Sword.

## Create or select the Main Menu

Most UI Designer schemas already include a Main Menu. Select the existing menu under **Edit** when it is the intended shell; creating another one changes the manager reference but does not remove the old menu or its opener.

When a new shell is required:

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer**.
2. Select **Main Menu** and open **Create**.
3. Set **Parent Transform** below the intended Display Panel Manager.
4. Set **Panel name** to a unique value such as `Inventory Main Menu`. The creation default is `Main Menu`.
5. Leave **Vertical** on for the vertical schema prefab, or turn it off for the horizontal prefab. It is on by default.
6. Select **Create**.
7. Confirm that the Display Panel Manager's **Main Menu Panel** references the generated Display Panel.
8. If **Gameplay Panel** was assigned before creation, confirm that its Main Content contains a generated **Main Menu** Action Button.

UI Designer wires that gameplay button to the generated Display Panel's smart-open flow. If no Gameplay Panel existed during creation, add a project input or button that opens the manager's Main Menu Panel.

## Configure the Main Menu component

Select the generated Main Menu. The component maps controls to inner panels:

![The registered Main Menu Inspector image showing subpanel mappings and the Close, Quit, and Menu Tabs references.](https://opsive.com/wp-content/uploads/2020/11/MainMenuInspector.png?v=a0f21ef98e71)

| Inspector field | Manual Version 1 default | Use |
| --- | --- | --- |
| **Panels** | Empty | Ordered Panel/Button pairs. List order controls first, previous, and next subpanel behavior. |
| **Close Button** | None | Closes the Main Menu Display Panel and returns to its previous panel or selectable. The schema prefab assigns this. |
| **Quit Button** | None | Calls `Application.Quit` when submitted. The schema prefab may assign this. |
| **Menu Tabs** | None | Parent Rect Transform for generated tab buttons. The schema prefab assigns this. |
| **Menu Open Options** | **Open Previous Sub Menu** | Chooses which mapped panel opens with the shell. |

Every **Panels** entry needs both a non-null Display Panel and Action Button. The Main Menu subscribes to each button's submit event during initialization. A click, keyboard submit, or controller submit therefore opens the paired panel through the same path.

The generated Main Menu Display Panel uses these important settings:

- **Is Menu Panel** is on, so the manager treats it as the active menu;
- **Start Enabled** and **Open On Start** are off;
- **Set Active On Open** and **Set Disable On Close** are on; and
- **Unique Name** must be unique under its Display Panel Manager.

## Add Bag and Equipment subpanels

Create subpanels through their own UI Designer tabs so their data bindings and Main Menu mapping are created together.

### Add Bag

1. In UI Designer, select **Inventory Grid**.
2. Set **Parent Transform** to the Main Menu Display Panel's **Main Content**.
3. Set **Panel Option** to **Main Menu**.
4. Name the panel and grid `Bag`, assign the player Inventory, and configure its filter or Item Collection behavior.
5. Create the grid and confirm that Main Menu gains a Bag Panel/Button pair.

### Add Equipment

1. In UI Designer, select **Equipment**.
2. Use the same Main Menu **Main Content** as **Parent Transform**.
3. Set **Panel Option** to **Main Menu** and name the panel `Equipment`.
4. Assign the player Inventory and the Item Slot Set used by the Equipment Item Collection.
5. Create the view and confirm that Main Menu gains an Equipment Panel/Button pair.

Use the same pattern for Shop, Crafting, Save/Load, and other supported panels. In the Main Menu **Edit** section, adding an entry directly creates a `BlankSubPanel` and matching button for project-specific content.

![The registered subpanel example showing Inventory Grid and Save Menu configured as destinations inside one Main Menu.](https://opsive.com/wp-content/uploads/2020/11/SubPanelForMainMenu.png?v=82f26a7b4031)

UI Designer's generated inner-panel prefab uses **Is Menu Panel** off, **Set Active On Open** on, and **Set Disable On Close** off. That last setting is deliberate: Main Menu explicitly closes and deactivates every non-selected mapped panel when switching tabs. The Main Menu shell, rather than each inner Display Panel alone, owns tab visibility.

Keep the inner panels in the Main Menu's Main Content and leave them as non-menu panels. Marking each inner panel as a menu would make the Display Panel Manager treat tab changes as separate menu openings.

## Keep list order and tab order aligned

In UI Designer's Main Menu **Edit** section:

1. Review **Main Menu Sub Panels**.
2. Select each entry and compare its **Panel name** and **Button text**.
3. Use **Select Panel** and **Select Button** to locate the paired objects.
4. Reorder the list into the intended runtime order.
5. Reorder the children beneath **Menu Tabs** into the same visual order.

UI Designer inserts a newly generated tab button at sibling index `0`, but appends its Panel/Button pair to the list. After adding several panels, the visible button order can therefore be the reverse of the list order. **Open First Sub Menu**, `OpenPrevious()`, and `OpenNext()` use the list, not the hierarchy.

Removing an entry with UI Designer destroys its generated panel and button as well as the mapping. Use **Select Panel** and **Select Button** before confirming removal.

## Choose what opens with the menu

Set **Menu Open Options** according to the desired return behavior:

| Option | Runtime result | Good use |
| --- | --- | --- |
| **Open Previous Sub Menu** | Reopens the last selected list entry. On the first open, the runtime index starts at `0`. | Return the player to their recent tab. |
| **Open First Sub Menu** | Opens list index `0` every time. | Always start on Bag. |
| **Open No Sub Menu** | Closes and deactivates every mapped subpanel. | Show only the shell until the player chooses a tab. |

For the Bag and Equipment example, put Bag at list index `0` and use **Open First Sub Menu**. Confirm that the first visible tab is also Bag after matching the Menu Tabs hierarchy to the list.

`OpenPrevious()` and `OpenNext()` move one list entry without wrapping. They do nothing at the first and last entries respectively.

## Understand ownership and panel flow

The Display Panel Manager owns the panel session:

1. it resolves **Panel Owner** directly or through **Panel Owner Inventory Identifier ID**;
2. it registers every child Display Panel and its **Unique Name**;
3. it opens **Main Menu Panel** as a menu and closes the selected Gameplay Panel;
4. Main Menu applies **Menu Open Options** and opens one mapped inner panel;
5. each inner panel resolves and presents its own data; and
6. closing Main Menu closes the selected subpanel and reopens the previous panel or selectable.

Main Menu passes itself as the previous panel when it opens a subpanel. Switching tabs closes every other mapped panel without selecting its previous control, deactivates it, and then opens the requested panel with its mapped Action Button as the previous selectable.

The manager-wide settings also apply:

- **Set Time Scale To Zero When Menu Is Opened** pauses and restores scaled time around menu state;
- **Close Menu When Opening Another** closes the current menu before opening a new one; when off, the manager refuses the second menu; and
- **Enable Input On Gameplay Selected** sends gameplay-input enable or disable events when focus enters or leaves Gameplay Panel.

For local multiplayer, give each player's Display Panel Manager a distinct **ID**, Panel Owner, EventSystem ownership, Canvas, Main Menu Panel, and bound Inventory. Main Menu has no independent player ID; it inherits context from the manager and the bindings on its subpanels.

## Editor checkpoint

Before entering Play Mode, confirm that:

- one intended Display Panel Manager owns this Main Menu and resolves the correct Panel Owner;
- **Gameplay Panel** and **Main Menu Panel** reference the intended Display Panels;
- the Main Menu shell has **Is Menu Panel** on and a unique **Unique Name**;
- the shell's **Close Button**, optional **Quit Button**, and **Menu Tabs** references are valid;
- every **Panels** entry contains the matching inner panel and tab button;
- the Main Menu Sub Panels list and Menu Tabs hierarchy use the intended matching order;
- Bag is index `0` when **Open First Sub Menu** should start there;
- inner panels are beneath Main Content, have **Is Menu Panel** off, and use the intended generated close behavior;
- Bag and Equipment bind to the same player Inventory and their intended Item Collections;
- Equipment uses the correct Item Slot Set and accepts Iron Sword while rejecting Health Potion;
- each inner panel has a visible **Selectable On Open** or deliberate navigation path; and
- there is only one intended gameplay opener for this Main Menu.

## Verify in Play Mode

1. Open Main Menu through the generated gameplay button or project input.
2. Confirm that Gameplay Panel closes and Bag opens first with Health Potion and Iron Sword.
3. Submit the Equipment tab with pointer, keyboard, and controller. Confirm that Bag deactivates, Equipment opens, and focus remains visible.
4. Equip Iron Sword and confirm that Bag and Equipment update without closing the Main Menu shell.
5. Return to Bag and confirm that it reflects the same Inventory state.
6. Close and reopen Main Menu. Confirm that **Menu Open Options** chooses the previous tab, list index `0`, or no tab exactly as configured.
7. Open every additional Shop, Crafting, or Save/Load tab and verify its own data flow.
8. Try to open another standalone menu and confirm that **Close Menu When Opening Another** produces the intended close-or-refuse behavior.
9. Close Main Menu and confirm that the selected subpanel closes, Gameplay Panel and its previous selection return, time scale is restored, and gameplay input is enabled as configured.
10. In a built player, test Quit separately. `Application.Quit` does not stop Unity Editor Play Mode.

## Save and network boundaries

Main Menu keeps the selected panel index only in memory. It does not save the open tab, Action Button selection, previous panel, or previous selectable. Save the authoritative Inventory, Equipment, Gold, crafting, and other subpanel data through their supported savers, then redraw or reopen the panel after loading.

The Main Menu and Display Panel Manager do not replicate panel state or authorize Inventory transactions. In a networked game, keep menu selection local, synchronize the authoritative data used by each subpanel, and ensure the local player's manager owns the correct UI. Opening Equipment locally does not equip an Item on the network.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| The UI disables itself during initialization | **Panel Owner** and **Panel Owner Inventory Identifier ID** | Assign the player directly or use an ID that resolves an Inventory Identifier. |
| Main Menu does not open | Display Panel Manager **Main Menu Panel**, EventSystem, and another active menu | Assign the generated shell, verify its manager, and apply the intended close-or-refuse setting. |
| No gameplay opener was generated | Whether **Gameplay Panel** was assigned before Main Menu creation | Assign it before generation, or add a button/input that calls the Main Menu open flow. |
| The wrong or duplicate Main Menu opens | Multiple generated shells, opener buttons, and **Main Menu Panel** | Keep one deliberate manager reference and remove obsolete generated UI manually. |
| A tab opens the wrong panel | **Main Menu Sub Panels** Panel/Button pairs | Use **Select Panel** and **Select Button** to repair the mismatched entry. |
| The wrong tab opens first | **Menu Open Options** and list index `0` | Reorder the list; do not rely on the visible hierarchy order alone. |
| Visible tab order and next/previous order disagree | Menu Tabs sibling order versus Panels list order | Reorder both structures into the same sequence. |
| Several inner panels remain visible | Missing mappings or custom panel activation | Add every tab destination to **Panels** and let Main Menu switch those mapped panels. |
| A subpanel is treated as another menu | Inner Display Panel **Is Menu Panel** | Turn it off for Main Menu children. Keep it on only for the shell. |
| Bag or Equipment shows the wrong character | manager Panel Owner and each subpanel Inventory binding | Bind every panel to the same intended player's Inventory. |
| Keyboard or controller focus disappears | EventSystem, **Selectable On Open**, Action Button navigation, and null mappings | Assign a visible default selectable and repair the tab navigation. |
| Closing does not restore gameplay | shell **Set Disable On Close**, previous panel, time-scale, and input settings | Close through the Main Menu/manager flow and verify the same manager owns Gameplay Panel. |
| A duplicate-name warning appears | child Display Panel **Unique Name** values | Give every registered Display Panel a unique nonempty name. |
| Quit does nothing in Play Mode | Unity Editor versus built player | Test `Application.Quit` in a development build. |

## Related pages

- [Build and edit Main Menu in UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/main-menu/)
- [Display Panel and Manager](https://opsive.com/support/documentation/ultimate-inventory-system/ui/display-panel-manager/)
- [Item View Slots Container](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/)
- [Shop Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/shop-menu/)
- [Crafting Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/crafting-menu/)
- [Save Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/save-menu/)
- [Storage Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/storage-menu/)
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/)
- [Input handlers](https://opsive.com/support/documentation/ultimate-inventory-system/input/handlers/)
- [Save system](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)

## Developer details

Open the shell through its manager so menu exclusivity, gameplay-panel state, Panel Owner events, time scale, and previous selection are handled consistently:

```csharp
public void ToggleInventoryMenu()
{
    displayPanelManager.ToggleMainMenu();
}

public void ShowBag()
{
    mainMenu.OpenSubPanel(0);
}
```

`MainMenu.Initialize(DisplayPanel, bool)` subscribes each mapped Action Button's `OnSubmitE` to `OpenSubPanel(index)`. It also binds Close Button submit to `DisplayPanel.Close(true)` and Quit Button submit to `Application.Quit`.

`OpenSubPanel(int)` records the requested index, closes and deactivates every other mapped panel, and opens the selected panel with the Main Menu Display Panel and paired Action Button as its previous context. An index below `0` or beyond the list closes all mapped panels and opens none.

`OnOpen()` applies `MenuOpenOptions`. `OnClose()` closes the currently selected subpanel without selecting its previous control. `OpenPrevious()` and `OpenNext()` change the selected list index without wrapping.

Display Panel Manager exposes `OpenMainMenu()`, `CloseMainMenu()`, `ToggleMainMenu()`, `OpenPanel(DisplayPanel)`, `OpenPanel(string)`, `ClosePanel(string, bool)`, and `TogglePanel(DisplayPanel)`. Prefer those manager paths to setting GameObjects active directly.

---

<a id="page-ultimate-inventory-system-ui-shop-menu"></a>

# Shop Menu

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/ui/shop-menu/)

The Shop Menu gives a player one interface for browsing shop stock, choosing a quantity, paying with Currency, and selling Items back. In Buy mode it displays the Shop Inventory; in Sell mode it displays the player's bound Inventory.

This page explains the generated menu at runtime. Use [UI Designer: Shop](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/shop/) for the editor tool that creates and lays out the hierarchy, and [Shop](https://opsive.com/support/documentation/ultimate-inventory-system/currency/shop/) for the transaction component that validates prices and moves Currency and Items.

The example below sells a Health Potion for 10 Gold and an Iron Sword for 50 Gold. The player starts with 60 Gold, so the first purchase succeeds and a second Iron Sword purchase is rejected without changing either Inventory.

## Before you begin

Prepare the data and owners before creating the menu:

1. Create **Gold** in the Inventory System Database.
2. Give the player's Inventory a Currency Owner with 60 Gold.
3. Add a `CurrencyAmounts` Item Definition attribute named `BuyPrice` and set Health Potion to 10 Gold and Iron Sword to 50 Gold.
4. Add a `CurrencyAmounts` attribute named `SellPrice` when the menu should support selling. For this test, set Health Potion to 5 Gold and Iron Sword to 25 Gold.
5. Give the Shop its own Inventory containing Health Potion and Iron Sword.
6. Confirm that the player's **Bag** can accept both Item Categories.
7. Set up the Canvas, EventSystem, and Display Panel Manager used by the player.

Attribute names are case-sensitive text lookups. The Shop's **Buy Attribute Name** and **Sell Attribute Name** must match `BuyPrice` and `SellPrice` exactly, and both values must use the `CurrencyAmounts` type.

## Create the Shop Menu

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer**.
2. Select the **Shop** tab and open **Create**.
3. Assign the **Parent Transform**.
4. Choose **Panel Option**:
   - **Basic** creates a standalone menu panel.
   - **Main Menu** adds a **Shop** inner panel. Its Parent Transform must be the Main Menu's main content transform.
5. Select **Create**.
6. In **Edit**, select the generated Shop Menu. Use **Find Available Targets in Scene** if necessary.
7. Under **Shop**, add a Shop component. The UI Designer also adds and assigns an Inventory for that Shop.
8. Under **Inventory Grid**, create or select the grid that will display shop stock and player Items.
9. Under **Currency Displays**, create **Total Price UI**.
10. Under **Quantity Picker Panel**, create the quantity control.

The UI Designer configures the hierarchy; it does not define Item prices, fund the player, or stock the Shop Inventory. Complete those data steps in the Main Manager and runtime components.

## Connect the menu

The generated schema normally supplies the UI references. Verify them before changing the hierarchy:

| Shop Menu field | Released Version 1 default | Purpose |
| --- | --- | --- |
| **Bind To Panel Owner Inventory** | On | Uses the Inventory on the Display Panel Manager's Panel Owner when no Inventory is assigned directly |
| **Bind To Inventory By Identifier** | `0` | Resolves a specific Inventory Identifier when panel-owner binding is off; `0` means unused |
| **Inventory** | None | Direct player/client Inventory; takes precedence over the two automatic choices |
| **Shop** | None | Shop whose stock, prices, and transaction rules are displayed |
| **Inventory Grid** | None | Displays Shop Inventory in Buy mode and player Inventory in Sell mode |
| **Total Price** | None | Multi Currency View redrawn for the selected quantity |
| **Quantity Picker Panel** | None | Chooses and confirms the transaction amount |
| **Limit Buy Quantity To Available Item Amount** | Off | Also caps the Buy quantity by the amount currently shown in Shop Inventory |
| **Select Only With Click** | Off | When enabled, navigation selection alone does not change the chosen transaction Item |
| **Open Quantity Picker On Item Click** | On | Opens the quantity confirmation flow when an Item is clicked |
| **Buy Title** | `SHOP - BUY` | Menu title in Buy mode |
| **Sell Title** | `SHOP - SELL` | Menu title in Sell mode |
| **Menu Open Options** | **Open Buy Sub Menu** | Chooses the initial Buy, Sell, or no-submenu view |
| **On Buy Success / Failed** | No listeners | Optional feedback after the Shop returns its result |
| **On Sell Success / Failed** | No listeners | Optional feedback after the Shop returns its result |

The generated menu also assigns **Menu Title**, **Buy Button**, **Sell Button**, **Close Button**, **Buy Modifier Text**, and **Sell Modifier Text**. The script defaults for these references are None, so inspect them if a customized prefab no longer updates or responds.

![Shop Menu Inspector with player Inventory binding, Shop, Inventory Grid, Total Price, quantity picker, titles, buttons, and transaction events.](https://opsive.com/wp-content/uploads/2020/11/ShopMenuInspector.png?v=c99039594ed8)

## Configure prices and destinations

On the Shop component, use these released Version 1 settings:

| Shop field | Default | Recommended starting value |
| --- | --- | --- |
| **Buy Attribute Name** | `BuyPrice` | Keep `BuyPrice` |
| **Buy Modifier** | `0` | Keep `0` to use the stored price unchanged |
| **Sell Attribute Name** | `SellPrice` | Keep `SellPrice` when a separate sell value exists |
| **Sell Modifier** | `0` | Keep `0` to use the stored sell value unchanged |
| **Add Item With Callback** | Off | Keep off for the standard synchronous purchase |
| **Remove Item With Callback** | Off | Keep off for the standard synchronous sale |
| **Inventory** | None | Assign the Shop Inventory stocked with Health Potion and Iron Sword |
| **Default Item Collection To Add On Buy** | Main-purpose collection | Resolve it to the player's Bag for this example |
| **Item Collection To Add On Buy By Category** | Empty | Add entries only when categories need different destinations |

The modifier is added to `1` before multiplication. A modifier of `0` charges 100 percent of the stored price; `-0.2` charges or pays 80 percent. The quantity then multiplies the resulting Currency amounts.

The Total Price Multi Currency View must contain a Currency View for Gold. Use a separate Currency Owner Monitor when the menu should also show the player's current balance; Total Price shows the transaction cost, not the balance.

## Choose stock behavior

The standard Shop treats its Inventory as a catalog. A successful purchase does not remove stock unless **Shop Add Remove Binding** is present.

For unlimited Health Potions, leave **Remove On Buy** off and leave **Limit Buy Quantity To Available Item Amount** off. The Shop Inventory needs at least one Health Potion entry so it appears in the Buy grid, but repeated purchases do not consume that entry.

For one Iron Sword in finite stock:

1. Add **Shop Add Remove Binding** beside the Shop.
2. Assign its **Shop** reference, or keep both components on the same GameObject so it can resolve the reference.
3. Enable **Remove On Buy**. This adds a buy condition and removes stock after a successful purchase.
4. Enable **Limit Buy Quantity To Available Item Amount** on Shop Menu so the quantity picker does not offer more than the current stock.
5. Enable **Add On Sell** when Items sold by the player should enter Shop Inventory.

Use both finite-stock settings. The menu limit improves the quantity choice, while Shop Add Remove Binding enforces and changes the Shop Inventory.

## Choose the player and Shop when opening

The player Inventory supplies the Currency Owner and receives purchased Items. Shop Menu resolves it in this order:

1. a directly assigned **Inventory**;
2. the Display Panel Manager's Panel Owner when **Bind To Panel Owner Inventory** is enabled; or
3. **Bind To Inventory By Identifier** when panel-owner binding is disabled and the ID is not `0`.

Use **Shop Menu Opener** when several shopkeepers share one menu. Assign its client Inventory or **Client Inventory Identifier Index**, target **Menu**, and **Shop**. Opening it binds the client Inventory, calls `SetShop` with that shopkeeper, and then smart-opens the panel. An interaction can also pass the interacting character's Inventory directly.

![Shop Menu Opener Inspector with the client Inventory, target Shop Menu, and Shop references used when opening the panel.](https://opsive.com/wp-content/uploads/2020/11/ShopMenuOpenerInspector.png?v=e68eb36f6052)

Choose the initial mode with **Menu Open Options**:

- **Open Buy Sub Menu** opens the Shop Inventory immediately.
- **Open Sell Sub Menu** opens the player Inventory immediately.
- **Open No Sub Menu** leaves the player on the Buy and Sell choice while the Item grid stays closed.

## How a transaction runs

1. Opening Buy assigns the Shop Inventory to the grid; opening Sell assigns the bound player Inventory.
2. Selecting an Item reads its configured Buy Price or Sell Price.
3. Opening the quantity picker sets a minimum of `1`. Buy quantity is limited by affordable Gold and, when enabled, current shop stock; Sell quantity is limited by the selected player stack.
4. Changing the quantity redraws Total Price.
5. Confirming Buy asks the Shop to validate the Item, destination collection, conditions, and available Currency. On success it removes the player's Gold and adds the Item to the configured player collection.
6. Confirming Sell asks the Shop to validate ownership and conditions. On success it removes the Item from the player and adds the Sell Price to the player's Currency Owner.
7. Shop Menu invokes its success or failure UnityEvent and redraws the Inventory Grid.

When the player cannot afford one unit, Version 1 still gives the picker a maximum of `1`, but disables its confirmation action. Test the enabled state rather than interpreting the displayed quantity as permission to buy.

## Editor checkpoint

Before entering Play Mode, confirm that:

- Health Potion has `BuyPrice` = 10 Gold and `SellPrice` = 5 Gold;
- Iron Sword has `BuyPrice` = 50 Gold and `SellPrice` = 25 Gold;
- the Shop uses those exact attribute names with both modifiers set to `0`;
- the Shop Inventory contains both Items;
- the player's Inventory resolves through the intended direct, panel-owner, identifier, or opener path;
- the player Currency Owner contains 60 Gold;
- **Default Item Collection To Add On Buy** resolves to Bag;
- Shop, Inventory Grid, Total Price, Quantity Picker Panel, title, buttons, and modifier text references are assigned;
- the Total Price view maps Gold and any balance display uses its own Currency Owner Monitor;
- finite-stock settings agree between Shop Add Remove Binding and Shop Menu; and
- mouse, keyboard, and controller can reach Buy, Sell, Items, quantity controls, confirmation, and Close.

## Verify in Play Mode

1. Open Buy and confirm that Health Potion and Iron Sword come from the Shop Inventory.
2. Select two Health Potions. Confirm that Total Price shows 20 Gold, then buy them. Verify that two Potions enter Bag and the balance falls from 60 to 40 Gold.
3. Select one Iron Sword. Confirm that Total Price shows 50 Gold and that confirmation is unavailable because the player has only 40 Gold. Verify that neither Gold nor either Inventory changes.
4. Add 20 Gold, buy the Iron Sword, and verify that it reaches Bag while the displayed balance decreases by exactly 50 Gold.
5. For finite stock, begin with one Iron Sword, enable both **Remove On Buy** and **Limit Buy Quantity To Available Item Amount**, then purchase it. Confirm that it leaves the Shop Inventory and cannot be bought again.
6. Open Sell, choose one Health Potion, and confirm a total of 5 Gold. Sell it and verify that one Potion leaves the player and 5 Gold is added.
7. Enable **Add On Sell** and repeat the sale. Confirm that the sold Item appears in the Shop Inventory only after the successful transaction.
8. Open the shared menu from two different Shop Menu Openers and confirm that each uses its assigned Shop while the interacting player's Inventory and Gold remain the client.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| Buy shows the player's Items | The Shop reference and Shop Inventory | Assign the intended Shop; Buy mode should bind its Inventory, while Sell mode binds the player Inventory |
| Health Potion or Iron Sword is missing | Shop Inventory contents, Inventory Grid filters, and the configured price attribute | Add the Item to Shop Inventory and ensure its Category is visible and `BuyPrice` exists |
| Price or Total Price is blank | Attribute spelling/type and the Gold mapping on Multi Currency View | Use a `CurrencyAmounts` value, match the Shop field exactly, and add a Currency View for Gold |
| Quantity changes but Total Price does not | **Total Price** and **Quantity Picker Panel** references | Restore the generated references and confirm the quantity panel's amount event is connected through Shop Menu initialization |
| Buy is unavailable even with enough Gold | The bound player Inventory, Currency Owner, Item destination, and Shop conditions | Bind the correct player, confirm Gold is on its Currency Owner, and make sure Bag accepts the Item |
| The player has no Gold but the picker shows `1` | Released Version 1 clamps the displayed maximum to at least one | Rely on the disabled confirmation state, or customize the picker presentation for zero affordability |
| A purchase succeeds but stock does not decrease | **Shop Add Remove Binding > Remove On Buy** | Add the binding and enable the option; the menu quantity limit alone does not remove stock |
| The picker offers more than finite stock | **Limit Buy Quantity To Available Item Amount** | Enable it in addition to **Remove On Buy** |
| A sold Item does not enter Shop Inventory | **Shop Add Remove Binding > Add On Sell** | Enable it and confirm the binding references the same Shop |
| Gold changes but the balance display does not | Whether the UI is Total Price or a Currency Owner Monitor | Add or reconnect a separate monitor for the player's Currency Owner |
| The wrong player pays or receives the Item | Direct Inventory, Panel Owner, Identifier ID, and Shop Menu Opener client Inventory | Keep one deliberate owner route and pass the interacting player's Inventory when opening shared UI |
| A shared menu keeps the previous shopkeeper | The Shop reference on the current Shop Menu Opener | Assign a non-null Shop; `SetShop(null)` does not clear the previous Shop in released Version 1 |

## Related pages

- [Shop](https://opsive.com/support/documentation/ultimate-inventory-system/currency/shop/) covers Item pricing, transaction order, stock binding, and Shop conditions.
- [UI Designer: Shop](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/shop/) creates and edits the generated menu hierarchy.
- [Currency](https://opsive.com/support/documentation/ultimate-inventory-system/currency/) explains Gold, Currency Owners, and conversions.
- [Multi Currency View](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/multi-currency-view/) displays Total Price and Currency balances.
- [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/inventorygrid/) controls Item filtering, views, and navigation.
- [Main Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/main-menu/) covers the parent used by the UI Designer's **Main Menu** option.
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/) explains how player and Shop Inventories or Currency can persist.
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/) explains the shared event registration pattern.

## Developer, save, and network boundaries

`ShopMenu.SetShop(shop)` changes the Shop used by a shared menu. `ShopMenuOpener.Open(inventory)` binds that client Inventory, assigns its Shop, and calls `SmartOpen()`. The transaction calls are `Shop.BuyItem(buyerInventory, currencyOwner, itemInfo)` and `Shop.SellItem(sellerInventory, currencyOwner, itemInfo)`; `ItemInfo` carries the Item, amount, and source collection.

Shop Menu exposes **On Buy Success**, **On Buy Failed**, **On Sell Success**, and **On Sell Failed** UnityEvents. Successful Shop transactions also publish player-Inventory and Shop-GameObject events for buy and sell completion. Register and unregister shared event listeners during matching Unity lifecycle methods.

Although the Shop Menu field accepts `ShopBase`, its released Version 1 price-display path casts that reference to the built-in `Shop` that uses `CurrencyCollection`. A different currency-backed ShopBase requires a compatible custom menu or an overridden pricing path; assigning an arbitrary subclass is not enough.

The callback modes are narrow integration hooks, not transactional rollback. In Buy callback mode, Currency is removed before the external add callback, and a false callback does not refund it automatically. In the standard Sell path, the Item is removed before the sell value is added; a mis-typed Sell Price can therefore leave the Item removed without payment. Validate price attributes before enabling a shop, and make custom callbacks restore earlier state when a later step fails.

Inventory Saver and Currency Owner Saver can persist the player's purchases and Gold. Finite Shop stock needs its own Inventory Saver if it must survive a restart. The menu's selected mode, selection, and open quantity are UI state and are not saved by the Shop Menu.

Released Version 1 does not make Shop transactions network-authoritative, atomic across clients, or backed by a shopkeeper Currency balance. In multiplayer, run validation and ownership changes on the server or host, then replicate the accepted Inventory and Currency result. Do not let multiple clients call the local Shop as an authority.

---

<a id="page-ultimate-inventory-system-ui-save-menu"></a>

# Save Menu

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/ui/save-menu/)

The Save Menu lets a player choose a local slot, then save, load, overwrite, or delete it. The menu displays and selects slots; the Save System Manager writes the files, while Saver components decide which game state belongs in each slot.

Use the menu for a manual save flow such as preserving three Health Potions in **Bag**, an Iron Sword in **Equipment**, and the player's **Gold** balance. The released Version 1 menu uses one global Save System Manager, so opening it from a particular character does not limit the operation to that character.

## Before you begin

Set up and test the [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/) before creating its menu:

1. Open **Tools > Opsive > Ultimate Inventory System > Main Manager**.
2. Select **Setup**, then open **Save Setup**.
3. Assign the player GameObject to **Object to save** and select **Add Components**.
4. Confirm that **Save System Manager** and **Inventory System Manager Item Saver** are on the Inventory System Manager GameObject.
5. Confirm that **Inventory Saver** is on the player. Add **Currency Owner Saver** when Gold should persist.

For a normal restore, leave **Additive** disabled on Inventory Saver. The Inventory System Manager Item Saver is also required when Items have runtime state, such as an Iron Sword whose Durability changes.

For the first manual test, leave the manager's four automatic load and save options disabled. Its released Version 1 defaults are **Max Saves** `5`, **Save File Name** `SaveFile`, **Save File Extension** `save`, and **Save Meta Data File Extension** `metadata`. Leave **Save Meta Data Creator** unassigned to use the built-in date-and-time summary.

## Create the Save Menu

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer**.
2. Select the **Save** tab and open **Create**.
3. Assign the **Parent Transform** that should contain the menu.
4. Choose a **Panel Option**:
   - **Basic** creates a standalone Save Menu.
   - **Main Menu** adds a **Save/Load** inner panel. For this option, Parent Transform must be the Main Menu's main content transform.
5. Select **Create**.
6. In the **Edit** section, select the generated menu. Use **Find Available Targets in Scene** if it is not already selected.

The UI Designer also exposes **Save System Manager and Savers**, **Grid Size & Layout Group**, and **Grid Navigation**. Use the first section to audit the Saver components found in the scene. Use the grid sections to make every configured slot reachable by mouse, keyboard, or controller.

For a detailed walkthrough of the generator and its grid controls, see [UI Designer: Save](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/save/).

## Connect the runtime components

The generated hierarchy should already be connected. Verify these references before customizing its layout:

| Component | Field | Expected reference or value |
| --- | --- | --- |
| **Save Menu** | **Save Grid** | The generated slot grid |
| **Save Grid** | **Action Panel** | The panel that presents Save, Load, and Delete |
| **Save Grid** | **Confirmation Pop Up** | The confirmation dialog used for overwrite, load, and delete |
| **Save Grid** | **Optional Save Event** | Disabled for the built-in save action |
| **Save Grid** | **Optional Load Event** | Disabled for the built-in load action |
| **Save Grid** | **Optional Delete Event** | Disabled for the built-in delete action |
| **Save View Module** | **File Number Format** | `{0:00}` by default |
| **Save View Module** | **File Number Text** | The text element that displays the slot number |
| **Save View Module** | **Save Content Text** | The text element that displays **Empty**, a date, or custom metadata |

Enabling an optional event cancels the corresponding built-in operation. Its callback must perform the replacement save, load, or delete itself; an event that only plays feedback leaves the slot unchanged.

Keep the visible grid and its navigation within the manager's valid indexes, from `0` through **Max Saves - 1**. Do not leave selectable padding cells beyond that range.

## Understand slot data and ownership

Each occupied slot has a main `.save` file and a separate `.metadata` file under `Application.persistentDataPath`. The lightweight metadata lets the menu list slots without loading their full Inventory data. With the built-in metadata creator, an occupied Save View displays the save date and time; an empty view displays **Empty**.

Saving asks every registered Saver for its current state. Loading applies every registered Saver in dependency order. This means:

- Inventory Saver controls Bag and Equipment membership;
- Inventory System Manager Item Saver preserves the Item records and mutable values referenced by that Inventory;
- Currency Owner Saver controls Gold; and
- specialized UI savers are needed when hotbar assignments or grid positions must also persist.

The Save Menu has no Inventory Identifier or per-player owner field. In local multiplayer, selecting slot `0` from either player's menu saves or loads all Savers registered with the one Save System Manager. Separate player profiles require project-specific slot ownership or separate persistence orchestration; the built-in menu does not provide that boundary.

## How it runs

1. Opening the Display Panel initializes the Save Grid when necessary.
2. The menu refreshes the grid from the Save System Manager's current slot metadata and selects the first button.
3. Selecting a slot opens the Action Panel.
4. **Save** writes immediately when the selected entry has no metadata; otherwise it asks for overwrite confirmation.
5. **Load** and **Delete** ask for confirmation before calling the Save System Manager.
6. After an action, the grid refreshes so its slot labels match the manager's current metadata.

The released Version 1 implementation creates a non-null, empty metadata object for an unused slot. The Save View correctly labels it **Empty**, but the built-in action conditions test only whether metadata is null. As a result, an Empty entry can still expose Load and Delete, and Save can ask for overwrite confirmation. Treat **Empty** as unsaved: use Save, do not use Load or Delete, or customize Save Grid so its conditions also check `MetaData.IsEmpty`.

## Editor checkpoint

Before entering Play Mode, confirm that:

- one Save System Manager exists and **Max Saves** matches the intended slot count;
- Inventory System Manager Item Saver is present and assigned or resolvable from the manager;
- the player has an active Inventory Saver with the correct Inventory reference;
- Currency Owner Saver is present when Gold should persist;
- every Saver has a unique full key;
- Save Menu, Save Grid, Action Panel, Confirmation Pop Up, and Save View text references are assigned;
- the number of reachable slot buttons does not exceed **Max Saves**;
- optional events are disabled unless complete replacement operations are connected; and
- each supported input method can navigate the grid and confirmation popup.

## Verify in Play Mode

Use a complete round trip rather than confirming only that a file appears:

1. Start with three Health Potions in **Bag**, an Iron Sword in **Equipment**, and a known Gold balance.
2. Open the Save Menu. Confirm that unused entries display **Empty** and that the first entry is selected.
3. Choose **Save** on an Empty entry. Accept the overwrite prompt if Version 1 displays one, then confirm that the entry changes to a date and time.
4. Remove two Health Potions, unequip the Iron Sword, change its runtime Durability if applicable, and spend some Gold.
5. Choose **Load** on the occupied entry and accept the prompt. Confirm that Bag, Equipment, Durability, and Gold match the saved state.
6. Change the state again, choose **Save** on the occupied entry, and confirm the overwrite. Load it and verify that the newer state replaced the earlier one.
7. Choose **Delete** on the occupied entry. Confirm that it returns to **Empty**. Do not select Load or Delete on that empty entry even if Version 1 still enables those actions.
8. Save again, stop and restart Play Mode, then open and load the entry. This confirms that the data came from disk rather than only the manager's runtime cache.
9. Repeat the selection and confirmation flow with every supported input method and every valid slot.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| The menu opens but selecting a slot does nothing | **Save Grid**, **Action Panel**, **Confirmation Pop Up**, and the parent Display Panel references | Reassign the generated references, then reopen the panel |
| An Empty entry offers Load or Delete, or Save asks to overwrite it | The view uses `MetaData.IsEmpty`, but released Version 1 action conditions check only whether metadata exists | Use Save for Empty entries and avoid Load/Delete, or customize Save Grid to include the empty-state check |
| Save, Load, or Delete produces only feedback | The corresponding **Optional ... Event** is enabled | Disable it to restore the built-in operation, or make the callback invoke the replacement operation |
| A blank button beyond the final slot can be selected | The grid exposes more selectable cells than **Max Saves** | Match the visible/navigation range to indexes `0` through **Max Saves - 1** |
| The slot changes to a date, but Bag or Equipment does not return | Inventory Saver is missing, inactive, unregistered, or points at the wrong Inventory | Add or reconnect Inventory Saver and load after its `Start` registration; keep **Additive** disabled for replacement |
| Iron Sword returns without its runtime values | Inventory System Manager Item Saver is missing or not assigned | Add the saver to the Inventory System Manager and connect it to Save System Manager |
| Gold does not return | Currency Owner Saver is absent or references the wrong Currency Owner | Add and configure Currency Owner Saver on the owner of the tested Gold balance |
| Loading duplicates Items | **Additive** is enabled on Inventory Saver | Disable **Additive** unless merging is intentional |
| A menu opened by one local player restores both players | The menu calls the global Save System Manager and all registered Savers | Add project-specific profile and ownership rules; do not treat the built-in menu as player-scoped |
| A deleted or interrupted slot behaves inconsistently | Only one of its `.save` and `.metadata` files exists | Back up the save folder, remove the orphaned pair, and create a fresh slot |
| The menu works until a scene transition | The manager or required Savers do not survive, register, or load in the expected order | Choose a consistent lifetime and load after the destination Savers register; see [Scene Transitions](https://opsive.com/support/documentation/ultimate-inventory-system/scene-transitions/) |

## Related pages

- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/) explains manager settings, Saver responsibilities, slot files, and release boundaries.
- [UI Designer: Save](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/save/) covers the generated hierarchy and layout workflow.
- [Save View](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/save-view/) explains how slot metadata is presented.
- [Main Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/main-menu/) covers the parent panel used by the **Main Menu** option.
- [Split-Screen Co-op UI](https://opsive.com/support/documentation/ultimate-inventory-system/input/split-screen-co-op-ui/) explains player-owned UI and the global Save System boundary.
- [Scene Transitions](https://opsive.com/support/documentation/ultimate-inventory-system/scene-transitions/) covers manager, player, and Saver lifetime across scenes.
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/) explains the shared event registration pattern.

## Developer, event, and release boundaries

`SaveGrid.Save(index)`, `Load(index)`, and `Delete(index)` forward to `SaveSystemManager.Save`, `Load`, and `DeleteSave`. `Refresh()` reads `SaveSystemManager.GetSaves()`. Override these virtual methods when the panel should delegate to another backend, and keep the optional-event behavior in mind so one click does not run two persistence paths.

The manager publishes slot-index events before and after save, load, and delete operations: `c_WillStartSaving_Index`, `c_SavingComplete_Index`, `c_WillStartLoadingSave_Index`, `c_LoadingSaveComplete_Index`, `c_WillDeleteSave_Index`, and `c_DeleteSaveComplete_Index`. Register and unregister listeners during matching Unity lifecycle methods.

Deleting a damaged slot is not transactional in released Version 1. The built-in delete path returns early if the data file is missing, and it can also return before clearing the in-memory entry when the metadata file is missing. Repair an orphaned pair outside the normal menu flow after taking a backup.

The built-in Save Menu and Save System provide local files only. They do not add cloud conflict handling, encryption, save migration, backups, network authority, or separate player profiles. Add those policies in a project-owned persistence layer and use the optional events or an overridden Save Grid to connect it.

---

<a id="page-ultimate-inventory-system-ui-storage-menu"></a>

# Storage Menu

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/ui/storage-menu/)

The Storage Menu moves an Item amount between a player Inventory and a second Inventory such as a chest or shared stash. Its two grids let the player store Items from **Bag** and retrieve them later without exposing **Equipment**.

This page explains the supplied runtime menu. Use [UI Designer: Storage](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/storage/) to generate and edit its hierarchy. The released Version 1 implementation is a focused demo workflow: it handles grid clicks directly, sends Items to main Item Collections, and is not a general Item Action or drag-and-drop transaction system.

## Before you begin

Prepare two initialized Inventories:

- a player Inventory whose main Item Collection is **Bag** and whose separate **Equipment** collection contains equipped Items; and
- a storage Inventory with a valid main Item Collection.

For the first test, put three Health Potions and an unequipped Iron Sword in Bag. Put a second Health Potion in storage so both transfer directions can be verified. Confirm that both destination collections accept the Consumable and Weapon categories used in the test.

Also create the Canvas, EventSystem, and Display Panel Manager used by the player. The generated menu needs Item Views that can draw both Health Potion and Iron Sword.

## Create the Storage Menu

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer**.
2. Select the **Storage** tab and open **Create**.
3. Assign the **Parent Transform** below the intended Display Panel Manager.
4. Select **Create**. Unlike Shop and Save, the released Storage creator has no Panel Option; it creates a standalone menu panel that disables itself when closed.
5. In **Edit**, select the generated Storage Menu. Use **Find Available Targets in Scene** if necessary.
6. Under **Inventory Grid**, create **Storage Inventory Grid** and **Client Inventory Grid** when the schema has not already supplied them.
7. Use **Edit Storage Inventory Grid** and **Edit Client Inventory Grid** to configure each grid's views, filters, layout, and navigation.
8. Under **Quantity Picker Panel**, create the shared quantity control.
9. On Storage Menu, assign **Storage Inventory**, or set it through a Storage Menu Opener when several storage objects share one menu.

The UI Designer builds and reconnects UI objects. It does not create the player's Inventory, choose Bag as the main collection, populate storage, or add save behavior.

## Connect the runtime fields

The generated schema normally serializes the UI references. The script defaults below identify what must be assigned when a prefab is built or modified manually:

| Storage Menu field | Released Version 1 default | Purpose |
| --- | --- | --- |
| **Bind To Panel Owner Inventory** | On | Uses the Inventory on the Display Panel Manager's Panel Owner when no Inventory is assigned directly |
| **Bind To Inventory By Identifier** | `0` | Resolves a player Inventory Identifier when panel-owner binding is off; `0` means unused |
| **Inventory** | None | Direct client/player Inventory; takes precedence over the automatic choices |
| **Menu Title** | None | Displays the hard-coded `Storage - Store` or `Storage - Retrieve` title |
| **Storage Inventory** | None | The second Inventory used as storage |
| **Client Inventory Grid** | None | Draws the bound player Inventory |
| **Storage Inventory Grid** | None | Draws Storage Inventory |
| **Quantity Picker Panel** | None | Chooses and confirms the transfer amount |
| **Store Button** | None | Focuses the client grid and Store flow |
| **Retrieve Button** | None | Focuses the storage grid and Retrieve flow |
| **Close Button** | None | Closes and disables the generated standalone panel |
| **Menu Open Options** | **Open Store Sub Menu** | Chooses the initial Store, Retrieve, or no-submenu state |

The two Inventory references must point to different owners for a meaningful exchange. The client Inventory is resolved in this order: direct **Inventory**, the Panel Owner when **Bind To Panel Owner Inventory** is on, then **Bind To Inventory By Identifier** when its ID is not `0`.

## Filter Bag and Equipment

The client grid should show only Items the player is allowed to store:

1. Edit **Client Inventory Grid** and locate its Item Info Item Collection Filter or equivalent multi-filter entry.
2. Add **Bag** to **Show Item Collections**.
3. Add **Equipment** to **Hide Item Collections**, or otherwise exclude it explicitly. The filter's code defaults hide Loadout- and Hide-purpose collections, but a project-specific Equipment collection should not rely on that coincidence.
4. Edit **Storage Inventory Grid** and show only the storage Inventory's main collection.
5. Confirm that every Item Info Category Filter uses categories from the active Inventory System Database.
6. Confirm that both grids' Category Item View Sets map Consumable and Weapon to valid Item Views.

Filtering Equipment is important because Store uses the collection carried by the clicked ItemInfo. If Equipment appears in the client grid, an equipped Iron Sword can be removed from that collection by this menu; the Storage Menu does not run an unequip workflow first.

The storage grid should also stay on its main collection. Retrieve always removes from `Storage Inventory.MainItemCollection`, even if a customized grid displays an Item from another storage collection.

## Choose a fixed or reusable storage owner

Assign **Storage Inventory** directly when one menu belongs to one stash. For several world containers sharing one menu, add **Storage Menu Opener** to each interactable and assign:

- **Client Inventory** or **Client Inventory Identifier Index** when parameterless opening is used;
- the target **Menu**; and
- that object's **Storage Inventory**.

Calling the opener with an interacting Inventory binds that Inventory as the client, calls `SetStorageInventory` for the current container, and smart-opens the panel. This avoids leaving a scene-wide menu permanently tied to one chest.

The opener does not enforce permissions, distance, locks, or ownership. Put those checks in the interaction that decides whether to call Open.

## Choose destinations, rejection, and closing

The released menu has fixed transfer destinations:

| Direction | Source | Destination |
| --- | --- | --- |
| Store | The clicked player Item's collection, normally Bag | Storage Inventory's main Item Collection |
| Retrieve | Storage Inventory's main Item Collection | Player Inventory's main Item Collection, normally Bag |

It does not retrieve directly into Equipment, auto-equip an Iron Sword, or select a destination by Item Category. Use a custom transfer workflow when those outcomes are required.

Each transfer removes from the source first and attempts to add to the destination. If the destination accepts only part of the amount, the callback adds the rejected amount back to the original source stack. Both grids are then redrawn. Test restrictions and capacity deliberately so the visible result matches the intended rule.

The Close button closes the menu with the generated panel's disable-on-close behavior. Closing also closes the Quantity Picker Panel; a pending choice then returns without moving an Item. There is no released field that closes the Storage Menu automatically after a successful transfer.

**Menu Open Options** controls initial focus:

- **Open Store Sub Menu** enters Store and selects the first client slot.
- **Open Retrieve Sub Menu** enters Retrieve and selects the first storage slot.
- **Open No Sub Menu** enters Store internally and closes the client grid after drawing. Released Version 1 does not explicitly close the storage grid in this branch, so verify the generated schema and customize `OnOpen` when both lists must begin hidden.

Store and Retrieve choose the title and focused grid; they do not disable the opposite grid's click handler. If both grids remain visible, clicking a client Item stores it and clicking a storage Item retrieves it regardless of the current title.

## How a transfer runs

1. Opening the menu opens both grid panels, then applies **Menu Open Options**.
2. Store or Retrieve draws both Inventories and selects the first slot on the focused side.
3. Clicking an Item opens Quantity Picker Panel with a minimum of `0`, a maximum equal to the clicked stack amount, and an initial quantity of `1`.
4. The confirmation text reads **Store** for a client Item or **Retrieve** for a storage Item.
5. Confirming a quantity below `1`, cancelling, or closing returns without a transfer.
6. A confirmed positive quantity is given to the other Inventory's main collection. Any rejected amount is returned to its source.
7. Both Inventory Grids redraw.

The menu subscribes directly to each grid's Item-click event. It does not open an Item Action panel. Build a custom pair of Inventory Grids when storage must use Item Actions, drag and drop, floating panels, or category-specific destinations.

## Editor checkpoint

Before entering Play Mode, confirm that:

- the Storage Menu is below the intended Display Panel Manager;
- the direct, Panel Owner, identifier, or opener route resolves the intended player Inventory;
- **Storage Inventory** resolves a different Inventory;
- both Inventories have a valid main Item Collection and Bag is the player's main collection;
- Client Inventory Grid, Storage Inventory Grid, Quantity Picker Panel, Menu Title, and all three buttons are assigned;
- the client grid shows Bag and excludes Equipment;
- the storage grid shows only its main collection;
- Consumable and Weapon resolve to valid Item Views;
- every category filter references the active Inventory System Database;
- grid Content, Item View Drawer, navigation, and selection references remain valid; and
- **Menu Open Options** produces the intended initial focus and visibility.

## Verify in Play Mode

1. Open Store and confirm that three Health Potions and the unequipped Iron Sword appear in the client grid.
2. Confirm that an Iron Sword already in Equipment does not appear.
3. Click the Health Potion stack, choose `2`, and confirm Store. Verify that Bag decreases from three to one while storage increases by exactly two.
4. Store the unequipped Iron Sword and confirm that it leaves Bag and enters the storage main collection.
5. Open Retrieve, choose Iron Sword, and confirm that it returns to Bag rather than Equipment.
6. Retrieve one Health Potion and confirm that both Inventory amounts change by one.
7. Open the quantity picker and cancel, then repeat and close the whole menu. Confirm that neither action moves an Item.
8. Apply a destination capacity or category restriction, attempt a multi-Item transfer, and confirm that rejected Items return to the source without changing the total amount across both Inventories.
9. Close and reopen the menu. Confirm that both grids redraw current contents and focus the option selected by **Menu Open Options**.
10. When several containers share the menu, open each one and confirm that the storage grid changes to that opener's Inventory while the same player remains the client.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| The client grid is empty | Direct Inventory, Panel Owner, identifier ID, and Bag filter | Keep one valid player-binding route and confirm Bag contains visible Items |
| The storage grid is empty | **Storage Inventory**, its main collection, and the storage grid filter | Assign the correct Inventory and limit the grid to its populated main collection |
| Equipment Items appear | Client Item Collection filter | Show Bag and explicitly hide Equipment |
| An Item has no view | Category Item View Set, Item View Drawer, and Content references | Map Consumable and Weapon to valid Item Views and reconnect the drawer hierarchy |
| A category-database warning appears | Item Info Category Filters copied from the schema database | Replace each category with the equivalent from the active database |
| Clicking an Item does nothing | Correct grid reference, Quantity Picker Panel, and Item amount | Restore the generated references and ensure the slot carries a non-null Item |
| An equipped Iron Sword is moved without unequipping | Equipment is visible in the client grid | Exclude Equipment or replace the direct click flow with an equip-aware custom action |
| Retrieved Items enter the wrong collection | The player's main Item Collection | Make Bag the main collection or implement a custom destination selector |
| An Item displayed from a secondary storage collection will not retrieve | Retrieve always reads Storage Inventory's main collection | Filter the storage grid to its main collection or override the transfer logic |
| Only part of the selected amount moves | Destination restrictions or capacity | Adjust the destination rules; the rejected remainder should be returned to the source |
| Open No Sub Menu still leaves a list visible | Released `OnOpen` closes only the client grid explicitly | Customize `OnOpen` to close both grids for a true choice-only state |
| Custom button callbacks disappear at runtime | Storage Menu initialization calls `RemoveAllListeners` on Store, Retrieve, and Close | Put custom behavior on the menu's transfer/open hooks or subclass initialization instead of relying on extra button listeners |

## Related pages

- [UI Designer: Storage](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/storage/) creates and edits the supplied hierarchy.
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/) explains Inventory ownership and Item Collections.
- [Item Collections](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/) covers main collections, restrictions, and transfer behavior.
- [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/inventorygrid/) covers filtering, Item Views, and navigation.
- [ItemInfo filters and sorters](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-info-filter-sorters/) explains Bag, Equipment, and category filtering.
- [Move Items with drag and drop](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/move-items-drag-drop/) provides an alternative interaction pattern.
- [UI Designer: Chest](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/chest/) creates an interactable container workflow.
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/) explains how both Inventories can persist.

## Developer, save, and network boundaries

`StorageMenu.BindInventory(inventory)` changes the client, and `SetStorageInventory(inventory)` changes the other side and updates its grid. `StorageMenuOpener.Open(inventory)` performs both bindings before calling `SmartOpen()`.

Transfers call `ItemCollection.GiveItem`. The source removes first, the destination adds what it accepts, and the menu's rejection callback attempts to add the remainder back to the original stack. Inventory add/remove events still fire during this sequence; the Storage Menu does not publish a separate completed-transfer event or provide an atomic rollback boundary.

The supplied class lives in the Version 1 demo namespace. Subclass or replace it when a production design needs permissions, custom destinations, Item Actions, transactional logging, or a different open/close model. Its initialization also clears all listeners from the Store, Retrieve, and Close buttons before installing its own handlers.

To persist the result, add an Inventory Saver for the player and a separate Inventory Saver for the storage Inventory, along with the Inventory System Manager Item Saver required for Item data. The menu's open mode, selected slot, and pending quantity are not saved. Closing the menu does not automatically save either Inventory.

The built-in transfer is local and has no network authority, reservation, conflict resolution, or locking. In multiplayer, let the server or host validate container access and perform the transfer, then replicate the accepted Inventory state. Do not allow two clients to mutate the same local storage Inventory independently.

---

<a id="page-ultimate-inventory-system-ui-chest-menu"></a>

# Chest Menu

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/ui/chest-menu/)

The Chest Menu lets a player take Items and optional Currency from an interactable chest. One menu can serve many chests because the chest that opens it supplies the active chest Inventory, while the interacting character supplies the destination Inventory.

This page explains the released runtime components. Use [UI Designer: Chest](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/chest/) to generate and edit the menu hierarchy. Chest Menu is retrieval-only; use [Storage Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/storage-menu/) when the player must also deposit Items.

## Before you begin

Prepare:

- a player Inventory with **Bag** as the intended destination and **Equipment** as a separate collection;
- an Inventory Interactor that can supply that player Inventory;
- a chest Inventory whose main Item Collection contains three Health Potions and one Iron Sword;
- a working Interactable, trigger Collider, and input route; and
- a Canvas, EventSystem, and Display Panel Manager.

The Demo folder's **Chest** prefab is a useful working reference because it already demonstrates the Chest, Chest Interactable, Inventory, Animator, and interaction relationship. When building one manually, make every reference below explicit.

## Create the Chest Menu

1. Open **Tools > Opsive > Ultimate Inventory System > UI Designer**.
2. Select the **Chest** tab and open **Create**.
3. Assign **Parent Transform** below the intended Display Panel Manager.
4. Select **Create**. The released creator has no Panel Option; it creates a standalone menu panel that disables itself when closed.
5. In **Edit**, select the generated Chest Menu. Use **Find Available Targets in Scene** if necessary.
6. Under **Inventory Grid**, create **Chest Inventory Grid** if the schema did not supply it.
7. Select **Edit Chest Inventory Grid** to configure its Item Views, filter, layout, and navigation.
8. Under **Quantity Picker Panel**, create the quantity control.

UI Designer creates the menu, not the world chest. The active Chest and player Inventory are supplied at runtime before the Display Panel opens.

## Connect the Chest Menu fields

The generated schema normally assigns the UI references. The released Version 1 script defaults are:

| Chest Menu field | Default | Purpose |
| --- | --- | --- |
| **Bind To Panel Owner Inventory** | On | Initial inherited player binding when no Inventory is assigned; a normal Chest interaction later replaces it with the interacting Inventory |
| **Bind To Inventory By Identifier** | `0` | Optional player Inventory Identifier when panel-owner binding is off; `0` means unused |
| **Inventory** | None | Direct player destination; a normal `Chest.Open` binds its client Inventory explicitly |
| **Inventory Grid** | None | Required grid that displays the active chest Inventory |
| **Multi Currency View** | None | Optional display of Currency held by the chest |
| **Take Currency Button** | None | Moves all chest Currency to the player |
| **Take All Items Button** | None | Moves all Items, then closes the menu |
| **Take All Button** | None | Takes Currency, then Items, then closes the menu |
| **Cancel Button** | None | Closes without another transfer |
| **Quantity Picker Panel** | None | Required amount selector for an Item click |
| **Do Not Close Chest If Empty** | Off | When enabled, closing the panel skips `Chest.Close` if the chest main collection is empty |
| **Add To Item Collection Name** | Empty | Named player destination, with fallback to the player's main Item Collection |

Set **Add To Item Collection Name** to `Bag`. This keeps a retrieved Iron Sword in Bag instead of equipping it. When `Bag` is misspelled or absent, the menu silently falls back to the player's main Item Collection.

The menu's player-binding fields are useful for manual opening, but the normal chest flow is more specific: `Chest.Open(clientInventory)` calls `BindInventory`, assigns itself through `SetChest`, and only then smart-opens the panel.

## Configure the chest grid and quantity picker

Configure Chest Inventory Grid to show only the active chest Inventory's main Item Collection. Individual Take and Take All both remove from that main collection, even if a customized grid displays another collection.

In the grid's filters:

1. Add the chest's main collection to **Show Item Collections**.
2. Exclude any secondary collections that should not be retrievable.
3. Confirm that Item Info Category Filters reference the active Inventory System Database.
4. Map Consumable and Weapon to valid Item Views so Health Potion and Iron Sword draw correctly.
5. Add navigation when the chest can contain more stacks than visible slots.

Clicking an Item opens Quantity Picker Panel with a minimum of `0`, a maximum equal to the clicked stack, and the full stack selected initially. Confirmation text is **Take**. Selecting a value below `1`, cancelling, or closing the panel moves nothing.

The menu handles the grid's click event directly. It does not open Item Actions or support depositing by drag and drop. Use a custom grid workflow when Take must be an Item Action, Items can be dragged between floating panels, or the destination varies by category.

## Connect the world chest

1. Add an Inventory to the chest GameObject and configure its main Item Collection.
2. Add **Chest** and assign **Panel Manager**, **Chest Menu**, **Inventory**, and **Animator**.
3. Give the Animator controller `Open` and `Close` triggers.
4. Add **Interactable** and a trigger Collider. Ensure **Interactor Layer Mask** includes the player.
5. Add **Chest Interactable** beside Interactable and assign its **Chest**, or assign **Chest Game Object** when using another `IChest` implementation.
6. On the player, assign its Inventory to **Inventory Interactor** and configure interaction input or deliberate auto-interaction.

When Chest Menu initializes, it finds concrete Chest components in the scene and assigns itself only to those whose Chest Menu is currently None. Explicit assignments are safer when a scene contains more than one menu.

Chest Interactable accepts an interactor that implements `IInteractorWithInventory`. It passes that Inventory into the Chest, disables further interaction while the chest is open, and re-enables interaction when the Chest publishes its close event.

## Choose the available retrieval controls

| Control | Released behavior |
| --- | --- |
| Click an Item | Opens the quantity picker with the whole stack selected; confirmation moves that amount to Bag or the fallback main collection |
| **Take Currency** | Moves all Currency from the chest Currency Owner to the player's Currency Owner and redraws the optional Currency view |
| **Take All Items** | Attempts to move every Item from the chest main collection, then closes the Display Panel |
| **Take All** | Takes Currency first, then attempts all Items, then closes the Display Panel |
| **Cancel** | Closes without taking another Item |

There is no Store control. To verify a true store-and-retrieve round trip, use Storage Menu to place Health Potion and Iron Sword into the same chest Inventory, then use Chest Menu to take them back. Pre-populating the chest in the editor tests retrieval only.

Leave **Do Not Close Chest If Empty** off for the normal lifecycle. With it on, closing an empty chest's menu does not call `Chest.Close`; the close animation and `IChest.OnClose` event do not run, so Chest Interactable can remain disabled. Enable it only as part of a custom open-chest lifecycle that handles those consequences.

## Understand destination rejection

Individual Take and Take All remove from the chest first and call the destination collection's add operation. In released Version 1, Chest Menu passes no rejected-Item callback. If Bag accepts only part of an amount because of capacity, category, or stack restrictions, the rejected remainder is not automatically returned to the chest.

Before shipping the supplied menu:

- ensure Bag can accept every Item and quantity exposed by the chest; or
- customize Chest Menu to preflight `CanAddItem` and return rejected amounts to the source.

This differs from the supplied Storage Menu, which installs a callback that attempts to return rejected amounts. Neither menu is a network transaction or durable rollback system.

## How opening and retrieval runs

1. Chest Interactable passes the interacting player's Inventory to `Chest.Open`.
2. Chest triggers its `Open` animation, binds the player Inventory, calls `SetChest(this)`, opens the Display Panel, and invokes `IChest.OnOpen`.
3. Chest Menu closes any old quantity panel, binds Chest Inventory Grid to the active Chest Inventory, draws it, and selects the first button.
4. The optional Multi Currency View draws the chest Currency balance.
5. An Item click waits asynchronously for a quantity decision, then gives that amount from the chest main collection to Bag or the fallback player main collection.
6. Closing the menu closes the quantity panel and normally calls `Chest.Close`, which triggers the close animation and `IChest.OnClose`.

Do not open the Display Panel directly before calling `SetChest`; `OnOpen` immediately reads the active `IChest` and its Inventory.

## Editor checkpoint

Before entering Play Mode, confirm that:

- Chest Menu is registered below the intended Display Panel Manager;
- Inventory Grid and Quantity Picker Panel are assigned;
- **Add To Item Collection Name** is exactly `Bag`, and the player owns that collection;
- the chest grid shows only the chest main collection and resolves Consumable and Weapon Item Views;
- every filter uses categories from the active database;
- Chest references the intended Panel Manager, Chest Menu, chest Inventory, and Animator;
- Chest Interactable resolves the same Chest and sits beside an enabled Interactable;
- the trigger Collider and Interactor Layer Mask admit the player;
- Inventory Interactor supplies the intended player Inventory;
- both Inventories have Currency Owners when Take Currency is present; and
- **Do Not Close Chest If Empty** is off unless a custom lifecycle replaces the close event.

## Verify in Play Mode

1. Start with three Health Potions and one Iron Sword in the chest main collection. Record Bag and Equipment.
2. Interact with the chest. Confirm that the `Open` animation runs, the menu shows the current chest contents, and the chest becomes temporarily non-interactable.
3. Click Health Potion. Confirm that the picker initially selects all three, change the amount to `1`, and Take. Verify that the chest has two and Bag gains one.
4. Take Iron Sword and confirm that it enters Bag while Equipment remains unchanged.
5. Open the picker for Health Potion and cancel. Repeat and close the menu. Confirm that neither action moves an Item.
6. Close normally and confirm that the `Close` animation runs and the chest becomes interactable again.
7. Open a second Chest that shares the same menu and confirm that its Inventory replaces the first chest's contents.
8. If Currency is configured, give the chest 25 Gold, select **Take Currency**, and verify that all 25 moves to the player's Currency Owner while the chest view redraws at zero.
9. Use **Take All Items** with a destination known to accept every remaining Item. Confirm that the Items enter Bag and the panel closes.
10. For a bidirectional round trip, use Storage Menu to store Health Potion and Iron Sword in this Inventory, then reopen Chest Menu and retrieve them. Confirm that Chest Menu itself never exposes a deposit action.

Test rejection only in a disposable save or duplicated scene: released Chest Menu does not return a rejected remainder.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| Interaction does nothing | Trigger, layer mask, Inventory Interactor, Chest Interactable, and `IInteractorWithInventory` | Restore the interaction chain and ensure the interactor supplies an Inventory |
| `Chest Menu is null` is logged | **Chest Menu** on Chest | Assign the intended menu explicitly; automatic discovery only fills a currently unassigned concrete Chest |
| The open animation runs but no menu appears | Chest triggers Animator before checking its menu reference | Assign Chest Menu and Panel Manager, then retry |
| The panel opens with a null-reference error | Active `IChest`, its Inventory, Inventory Grid, or Quantity Picker Panel is missing | Open through `Chest.Open` or call `SetChest` and bind the player before opening |
| The wrong chest contents appear | Active Chest assignment and its **Inventory** | Assign each world Chest explicitly when multiple menus exist and verify its main collection |
| The grid is empty | Main-collection filter and Category Item View Set | Show the chest main collection and map Consumable and Weapon from the active database |
| Clicking an Item does nothing | Inventory Grid, Quantity Picker Panel, and clicked Item amount | Restore the generated references; the supplied menu uses direct clicks rather than Item Actions |
| Iron Sword enters Equipment | **Add To Item Collection Name** or player main collection | Set the name to `Bag` and ensure Bag exists |
| Only part of a stack reaches Bag and the remainder disappears | Destination capacity or restrictions | Do not use the supplied transfer with rejecting destinations; add a preflight and rejection callback |
| Take Currency does nothing | Currency Owners and button reference | Add Currency Owners to both Inventories and assign **Take Currency Button** |
| An empty chest stays open and cannot be interacted with | **Do Not Close Chest If Empty** skipped `Chest.Close` and its close event | Disable the option or implement a custom lifecycle that closes and re-enables interaction |
| Take All closes after an incomplete result | Destination rejected an Item, but Take All closes unconditionally | Preflight the complete transfer or replace Take All with a transactional custom operation |

## Related pages

- [UI Designer: Chest](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/chest/) creates and edits the menu hierarchy.
- [Storage Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/storage-menu/) provides bidirectional Store and Retrieve controls.
- [Interaction System](https://opsive.com/support/documentation/ultimate-inventory-system/interaction-system/) explains Interactors and Interactables.
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/) explains Inventory ownership and Item Collections.
- [Item Collections](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/) covers main collections, restrictions, and transfer behavior.
- [Inventory Grid](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/inventorygrid/) covers filters, Item Views, and navigation.
- [Move Items with drag and drop](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/move-items-drag-drop/) provides an alternative UI pattern.
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/) explains how player and chest contents can persist.
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/) explains the shared event registration pattern.

## Developer, save, and network boundaries

Any `IChest` can be assigned before opening:

```csharp
chestMenu.BindInventory(playerInventory);
chestMenu.SetChest(myChest);
chestMenu.DisplayPanel.SmartOpen();
```

`IChest` exposes its Inventory and open state, plus `Open(Inventory)`, `Close()`, `OnOpen`, and `OnClose`. The concrete Chest implementation uses `Open` and `Close` Animator triggers. Chest Menu itself publishes no completed-transfer event; observe Inventory and Currency changes or add a project-specific event around the operation.

To persist retrieval, add Inventory Saver components for both the player and chest Inventories and keep the Inventory System Manager Item Saver available. Add Currency Owner Saver to both owners when chest Currency should persist. Chest Menu does not save its selected Item, pending quantity, panel state, Animator state, or active Chest assignment.

The supplied operations are local, remove-before-add, and not atomic. They do not provide chest locks, access permissions, rollback, network authority, or simultaneous-client conflict handling. In multiplayer, let the server or host reserve the chest, validate capacity, perform the transfer, and replicate the accepted result.

---

<a id="page-ultimate-inventory-system-ui-crafting-menu"></a>

# Crafting Menu

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/ui/crafting-menu/)

The Crafting Menu lets a player browse a Crafter's recipes, inspect their ingredients and outputs, choose a quantity, and craft with the bound Inventory. This page follows one complete runtime flow: **2 Herb + 1 Water -> 1 Health Potion**, with Bag as the player's main Item Collection.

Use the included menu for immediate, quantity-based crafting. A custom menu or [custom Crafting Processor](https://opsive.com/support/documentation/ultimate-inventory-system/crafting/custom-crafting-processors/) is a better fit for timed queues, minigames, manually chosen ingredients, or another result flow.

## Before you begin

Prepare the following in the active Inventory System Database:

- Herb, Water, and Health Potion Item Definitions;
- a **Brew Health Potion** recipe that consumes 2 Herb and 1 Water and outputs 1 Health Potion;
- a player Inventory whose main Item Collection is **Bag**; and
- a Crafter that exposes the recipe through **Crafting Categories** or **Miscellaneous Recipes**.

Create or review those objects in [Crafting](https://opsive.com/support/documentation/ultimate-inventory-system/crafting/), [Crafting Category](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/crafting-category/), and [Crafting Recipe](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/crafting-recipe/) before configuring the runtime menu.

## Create or select the menu

Open **Tools > Opsive > Ultimate Inventory System > UI Designer**, select **Crafting**, and create either:

- **Basic** for a standalone menu panel; or
- **Main Menu** for an inner panel whose parent is the Main Menu's main content.

The generated object supplies a Crafting Menu, Crafting Recipe Grid, Recipe Panel, Quantity Picker Panel, Exit Button, and Display Panel. The [Crafting UI Designer workflow](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/crafting/) covers creation, grid layout, navigation, tabs, and visual customization. The remainder of this page explains how those parts work together at runtime.

## Connect the runtime parts

| Part | Runtime responsibility | Health Potion example |
| --- | --- | --- |
| **Inventory** | Supplies ingredients and receives crafted output. | Bag starts with Herb and Water and receives Health Potion. |
| **Crafter** | Supplies recipes and owns the Crafting Processor. | Exposes Brew Health Potion and uses the standard processor. |
| **Crafting Recipe Grid** | Draws the Crafter's recipes and reports selection or clicks. | Shows Brew Health Potion once. |
| **Recipe Panel** | Shows the selected output, ingredient amounts, descriptions, and optional Currency cost. | Shows 2 Herb, 1 Water, and 1 Health Potion for quantity 1. |
| **Quantity Picker Panel** | Changes the requested amount and confirms or cancels the craft. | Quantity 2 previews 4 Herb, 2 Water, and 2 Health Potions. |
| **Display Panel** | Opens, closes, and restores menu selection through the Display Panel Manager. | Opens as a standalone panel or inside the Main Menu. |

![Crafting Menu Inspector with panel-owner Inventory binding enabled and references for the Crafter, Crafting Recipe Grid, Recipe Panel, Quantity Picker Panel, Exit Button, and Draw Recipes On Open](https://opsive.com/wp-content/uploads/2020/11/CraftingMenuInspector.png?v=470c797d63d8)

The legacy Inspector image shows the menu's core object references. Current Version 1 also exposes the filtering, tab-data, quantity-panel behavior, Inventory Identifier binding, and completion-event settings described below.

## Bind the player Inventory

The Crafting Menu inherits the standard Inventory panel binding. Choose one source:

1. Keep **Bind To Panel Owner Inventory** enabled, which is the default, when the Display Panel Manager's Panel Owner is the player.
2. Set **Bind To Inventory By Identifier** to a nonzero Inventory Identifier ID when the player must be found by ID.
3. Assign **Inventory** directly for a fixed runtime Inventory.

The direct Inventory reference takes priority, followed by Panel Owner binding and then the identifier lookup. For the sample, the resolved Inventory must use Bag as its main Item Collection.

Configure the Crafter's **Processor** as **Simple Crafting Processor With Currency**, keep **Externally Remove Ingredients** disabled, and add `Bag` to **Ingredient Item Collections**. The standard processor then searches Bag for Herb and Water, removes them from the Inventory's main collection, and adds Health Potion through that Inventory, which also targets the main collection.

If **Ingredient Item Collections** is empty, the processor searches the entire Inventory. Its normal removal and output paths still use the main Item Collection, so keeping the sample ingredients and output in the main Bag avoids an apparent match followed by a failed craft.

## Configure the Recipe Panel

The Recipe Panel needs one result presentation and enough ingredient presentations for the selected recipe. For Brew Health Potion, provide at least two **Ingredient Items** entries: one can draw Herb and the other Water.

The important references are:

- **Total Craft Cost** for a recipe type that also consumes Currency;
- **Result Item > Item View** and **Item Description** for Health Potion;
- **Ingredient Items** for each visible ingredient Item View and description;
- **Ingredient View Parent** for generated ingredient views; and
- **Ingredient Description Parent** for generated descriptions.

![Recipe Panel Inspector with Total Craft Cost, a result Item View and description, four ingredient entries, and ingredient view and description parents](https://opsive.com/wp-content/uploads/2020/11/RecipePanelInspector.png?v=fe2b26f4df9b)

The panel multiplies every displayed input, output, and Currency amount by the selected quantity. It also listens for updates from the bound Inventory, so the availability presentation refreshes after items change.

## Choose the important settings

| Setting | Version 1 default | Use it when |
| --- | --- | --- |
| **Bind Filter Sorters To Grid** | Enabled | The menu's combined recipe filters should drive the Crafting Recipe Grid. |
| **Use Grid Filter Sorter** | Enabled | The grid's own filter or sorter should participate. |
| **Use Tab Control Tab Data** | Enabled | Recipe tabs use Crafting Tab Data to add category filters. |
| **Draw Recipes On Open** | Enabled | The list should reflect the current Crafter every time the panel opens. |
| **Close Quantity Picker Panel On Close** | Enabled | Leaving the menu should also dismiss the quantity choice. |
| **Open Quantity Picker Panel On Recipe Click** | Enabled | Clicking a recipe should immediately ask for a quantity. |
| **On Craft Complete** | No persistent listener required | Another component should react to the success Boolean. |

Keep the first Health Potion menu without tabs unless several recipe groups need filtering. When tabs are present, each tab's Crafting Tab Data must allow Brew Health Potion through its Item Category or Crafting Category filter.

## Reuse one menu for several crafting stations

A Crafter can live directly on the Crafting Menu for one fixed recipe set. To reuse the same menu with several stations, put a Crafter and **Crafting Menu Opener** on each station instead.

Configure the opener with:

- **Panel Manager Index**, default `1`, for the intended Display Panel Manager;
- **Panel Name** or a direct **Menu** reference for the Crafting Menu;
- **Client Inventory Identifier Index**, default `0`, or **Client Inventory** when the opener is not driven by an interactor; and
- **Crafter** for that station's recipe set.

Opening binds the supplied player Inventory, assigns the station's Crafter through `SetCrafter`, and smart-opens the menu. A Menu Interactable Behavior can supply the interacting player's Inventory and update the panel-manager index before opening. This keeps the UI shared while allowing an alchemy table and forge to show different recipes.

## How it runs

1. Opening the Display Panel binds the player Inventory to the menu and Recipe Panel.
2. With **Draw Recipes On Open** enabled, the menu reads the Crafter's current recipes, applies grid and tab filters, and selects the first recipe button.
3. Selecting Brew Health Potion updates the Recipe Panel.
4. Clicking the recipe makes it the craft target, opens the Quantity Picker Panel when that option is enabled, and sets the displayed quantity to 1.
5. Each quantity change calls the processor's `CanCraft` check. The Recipe Panel scales its amounts, and the confirm action is disabled when Bag cannot supply that quantity.
6. Confirming **Craft** asks the processor to validate and remove the ingredients, then create and add the output.
7. The menu invokes **On Craft Complete** with the success result, redraws the recipes, resets quantity to 1, and refreshes the Recipe Panel.
8. Closing the menu also closes the Quantity Picker Panel when **Close Quantity Picker Panel On Close** is enabled.

## Editor checkpoint

Before entering Play Mode, confirm that:

- the Crafting Menu belongs to the intended Display Panel Manager or Main Menu;
- its Inventory binding resolves the player whose main collection is Bag;
- **Crafter**, **Crafting Recipe Grid**, **Recipe Panel**, and **Quantity Picker Panel** are assigned;
- the Crafter exposes Brew Health Potion exactly once;
- its processor has **Externally Remove Ingredients** disabled and `Bag` in **Ingredient Item Collections**;
- the Recipe Panel has two ingredient presentations plus a valid Health Potion result presentation;
- optional tabs and filters allow the recipe through;
- **Exit Button** points to the intended close button; and
- the Canvas has an Event System and the correct input module for the player.

## Verify in Play Mode

1. Put 1 Herb and 1 Water in Bag, open the menu, and select Brew Health Potion.
2. Confirm that the Recipe Panel shows 2 Herb, 1 Water, and 1 Health Potion and that crafting is unavailable.
3. Add a second Herb. Confirm that the menu refreshes and quantity 1 can be crafted.
4. Craft once. Verify that exactly 2 Herb and 1 Water leave Bag and 1 Health Potion enters Bag.
5. Add 4 Herb and 2 Water, select quantity 2, and verify that the preview changes to 4 Herb, 2 Water, and 2 Health Potions.
6. Confirm the craft and compare the actual Inventory changes with that preview.
7. Navigate the recipe grid, quantity picker, confirm, cancel, and exit controls with each supported input device.
8. Close and reopen the menu. Confirm that recipes redraw and the quantity returns to 1.

For a shared station menu, repeat the test at two stations and confirm that each opener supplies the correct Crafter while both use the interacting player's Bag.

## Save and network boundaries

A successful craft changes the Inventory immediately. The Inventory saver can therefore persist the resulting Herb, Water, and Health Potion amounts. The Crafting Menu itself does not save the selected recipe, open panel, quantity, filter, or transient button selection, and the standard processor does not provide a timed queue or in-progress craft to save.

Version 1 does not replicate Crafting Menu state or craft commands over a network. A network integration must establish player ownership and authority, run the craft once on the authoritative side, and replicate the resulting Inventory changes. Display Panel Manager and Inventory Identifier IDs are local lookup keys rather than network identities.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| The menu opens with no recipes | **Crafter**, **Crafting Categories**, **Miscellaneous Recipes**, active database, and **Draw Recipes On Open**. | Assign the correct Crafter and include Brew Health Potion once from the active database. |
| Brew Health Potion appears twice | The recipe comes from both a Crafting Category and **Miscellaneous Recipes**. | Remove one source. |
| The ingredient or result panel is blank | **Recipe Panel**, its result references, or its **Ingredient Items** list is incomplete. | Assign the result presentation and at least two ingredient entries for Herb and Water. |
| Craft remains unavailable with enough ingredients | The menu is bound to the wrong Inventory, the processor searches another collection, or the recipe amounts/types do not match. | Bind the intended player, use `Bag` in **Ingredient Item Collections**, and recheck the recipe. |
| Ingredients are found but the craft fails | Bag is not the Inventory's main collection or **Externally Remove Ingredients** has no callback handler. | Make Bag the main collection for this workflow and disable external removal unless a handler reports success. |
| Health Potion does not enter Bag | Main-collection capacity or restrictions reject it. | Allow Health Potion in Bag and make room before crafting. |
| Clicking a recipe does not open the quantity choice | **Open Quantity Picker Panel On Recipe Click** is disabled or **Quantity Picker Panel** is unassigned. | Enable the option and assign the generated panel. |
| The quantity panel remains after closing | **Close Quantity Picker Panel On Close** is disabled or the menu references another panel. | Enable the option and correct the reference. |
| A tab hides the recipe | Its Crafting Tab Data filter excludes the recipe. | Correct the Item Category or Crafting Category filter, or remove tabs from the single-group example. |
| The wrong player's Bag changes | Panel Owner, identifier binding, direct Inventory, or station opener points to another player. | Use one intentional binding route and verify the opener receives the interacting Inventory. |
| Buttons do not respond | Event System, input module, selection, or grid navigation is incorrect. | Repair the player's Event System route and UI navigation. |

## Related pages

- [Crafting concepts, recipes, and processors](https://opsive.com/support/documentation/ultimate-inventory-system/crafting/)
- [Crafting UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/crafting/)
- [Crafting Category editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/crafting-category/)
- [Crafting Recipe editor](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/crafting-recipe/)
- [Custom Crafting Processors](https://opsive.com/support/documentation/ultimate-inventory-system/crafting/custom-crafting-processors/)
- [Recipe Box views](https://opsive.com/support/documentation/ultimate-inventory-system/ui/views/recipe-box/)
- [Display Panel and Manager](https://opsive.com/support/documentation/ultimate-inventory-system/ui/display-panel-manager/)
- [Main Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/main-menu/)
- [Item Collections](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/)
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)

## Developer details

`CraftingMenuBase` exposes the assigned `Crafter` and `SelectedRecipe`, plus `SetCrafter`, `DrawRecipes`, `CraftingAmountChanged`, and `DoCraft`. `CraftingMenuOpener.Open` binds an `Inventory`, assigns its Crafter, and calls `SmartOpen` on the Display Panel.

The processor raises the Inventory events for `CanCraft` and `Craft`, with the latter supplying the `CraftingRecipe` and `CraftingResult`. The menu separately invokes its **On Craft Complete** UnityEvent with `CraftingResult.Success`. When **Externally Remove Ingredients** is enabled, a listener must handle the processor's ingredient-removal callback and report success; without that listener, the standard craft fails.

---

<a id="page-ultimate-inventory-system-ui-menu-character"></a>

# Menu Character

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/ui/menu-character/)

Use a menu character preview to show the player's equipped Items beside the Bag or Equipment UI. In released Ultimate Inventory System Version 1, **Menu Character** is a scene and prefab pattern rather than a UIS component: a duplicate visual character uses an **Equipper**, a Unity Camera renders it to a Render Texture, and a Raw Image displays that texture in the menu.

## Choose the preview source

| Approach | Use it when | Important tradeoff |
| --- | --- | --- |
| Dedicated preview character | The menu needs a stable pose, isolated lighting, or a transparent background | Recommended. It needs its own visual rig and an explicit reference to the correct player's Inventory. |
| Camera on the live character | A simple third-person game can show the real character without a duplicate | The preview reacts to the world, may be obscured, is unsuitable for many first-person setups, and cannot use an independent menu pose. |

The dedicated preview is the more predictable choice. It observes the real Equipment collection; it must not own a second Inventory or save a second copy of the player's Items.

## Before you begin

Complete the normal equipment workflow first:

- the player has an Inventory with a Bag collection and an Equipment **Item Slot Collection**;
- Equipment, its UI, and the player's Equipper use the same **Item Slot Set**;
- equippable Items such as Iron Sword and Fire Wand provide a valid `EquipmentPrefab` GameObject attribute; and
- moving an Item into Equipment already updates the player character correctly.

See [Equipping Items](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/equipping-items/) if this workflow is not working yet.

## Build a dedicated preview character

1. Duplicate only the player's visible model and Animator hierarchy. Remove gameplay, input, interaction, Inventory, Currency Owner, and saver components from the duplicate.
2. On the preview Animator, disable **Apply Root Motion**. Assign a simple idle or menu pose. If the Main Menu sets `Time.timeScale` to zero, set **Update Mode** to **Unscaled Time** so the pose can continue animating.
3. Add the released V1 **Equipper** component to the duplicate root.
4. Set **Equipment Item Collection ID** to the player's Equipment collection. The V1 default is name `Equipped` with purpose **Equipped**; change the name to `Equipment` when that is the collection's actual name.
5. Keep **Equipable Prefab Attribute Name** as `EquipmentPrefab`. Keep **Usable Item Prefab Attribute Name** as `UsableItemPrefab` only when the preview also needs that functional prefab. If gameplay Items define `UsableItemPrefab` but the preview should create only their models, point the preview Equipper at a separate optional attribute name that those Items do not define, or use a display-only Equipper subclass.
6. Assign the same **Item Slot Set** used by the player's Equipment collection. The Inspector builds **Item Object Slots** from that asset.
7. Select each Item Object Slot. For a rigid Iron Sword or Fire Wand, leave **Skinned Equipment** off and assign the hand socket to **Transform**. For rigged clothing, enable **Skinned Equipment** and use matching, uniquely named bones.
8. Leave each slot's **Item Object** empty before Play Mode. It reports the spawned object at runtime. Use **More Options > Hide When Wearing Equipment** only for model parts that should disappear while that slot is occupied.
9. **Skinned Mesh Character** is enabled by default. Assign **Main Root Node**, or let the Equipper find it from a child Skinned Mesh Renderer. Disable this option when the preview has no skinned bone hierarchy.

The Equipper does not choose an animation or pose. Keep that responsibility in the preview Animator rather than adding gameplay animation logic to the menu model.

## Bind the correct Inventory owner

For a scene-owned single player, drag the active player's **Inventory** component into **Equipper > Inventory**. Do not leave the field empty on a separate preview object: the V1 fallback searches only the Equipper's own GameObject.

UIS panel ownership and preview ownership are related but separate:

| Setting | V1 default | What it controls |
| --- | --- | --- |
| **Inventory Identifier > ID** | `1` | Registers the player's Inventory owner for lookup. The ID must be nonzero and unique. |
| **Display Panel Manager > Panel Owner** | None | Receives panel and input events and supplies the owner to supported UI bindings. |
| **Panel Owner Inventory Identifier ID** | `1` | Resolves Panel Owner when it is not assigned directly. |
| **Equipper > Inventory** | None | Supplies the Equipment collection shown by this preview. It does not bind automatically from Panel Owner. |

When the player is spawned at runtime, assign the resolved player's Inventory before the preview Equipper reaches `Start`, then enable the preview. If the UI exists first, **Dynamic Panel Owner** can assign the Display Panel Manager when the player appears, but a small project-specific preview binder must still pass that owner's Inventory to the preview Equipper. `DisplayPanelManager.OnPanelOwnerAssigned` is the useful notification for that binder.

For split-screen, give each player a unique Inventory Identifier ID and a matching Display Panel Manager ID. Use one preview character, Camera, Render Texture, and Raw Image per player. Sharing the preview or Render Texture allows the last rendered or last bound player to replace the other player's view. See [Split Screen Co-op UI](https://opsive.com/support/documentation/ultimate-inventory-system/input/split-screen-co-op-ui/) for the complete ownership setup.

## Render the preview in the menu

1. Put the preview character on a dedicated layer that the gameplay Cameras do not render.
2. Choose **Create > Render Texture** in the Project window and set a size appropriate for the menu panel.
3. Create a Camera for the preview, frame the character, restrict **Culling Mask** to the preview layer, and assign the Render Texture to **Target Texture**.
4. For a transparent result, use a solid camera background with alpha `0`. The exact camera background label differs between the Built-in Render Pipeline and Scriptable Render Pipelines.
5. Add a **Raw Image** to the Main Menu and assign the same Render Texture to **Texture**. Turn off **Raycast Target** when the preview should not receive pointer input.
6. Keep the preview rig outside the gameplay area or otherwise isolate its lighting and shadows. Layer isolation is safer than relying on distance alone.

The Main Menu UI Designer creates menu panels and bindings, but it does not create this character-preview rig. Add the Raw Image and preview objects after the menu structure is in place.

## How it runs

At startup, the preview Equipper resolves its assigned Inventory and finds the configured Equipment Item Slot Collection. It creates representations for Items already equipped, then listens for Inventory add and remove events. Moving Iron Sword into Equipment creates the sword model in the matching Item Object Slot; moving it out removes that model.

The Camera writes the settled preview to the Render Texture and the Raw Image displays it. UIS does not automatically turn the preview Camera, rig, or Animator on and off with the panel, so projects that need the optimization should connect that lifetime to their menu open and close workflow.

## Editor checkpoint

Before entering Play Mode, confirm that:

- the preview contains visual and Animator components but no second Inventory or saver;
- **Equipper > Inventory** resolves the intended player before the Equipper starts;
- **Equipment Item Collection ID** matches an Item Slot Collection on that Inventory;
- the preview Equipper, Equipment collection, and Equipment UI use the same Item Slot Set;
- every rigid slot has the correct **Transform**, and skinned equipment has a valid **Main Root Node**;
- the preview Camera renders only the preview layer into **Target Texture**; and
- the Raw Image uses that same Render Texture.

## Verify in Play Mode

1. Start with Iron Sword in Bag and its Equipment slot empty. Open the Main Menu and confirm that the correct player's preview appears without a sword.
2. Equip Iron Sword. Confirm that one sword appears at the intended hand socket without changing the live player's Inventory twice.
3. Unequip it. Confirm that the preview removes the sword and restores any objects configured under **Hide When Wearing Equipment**.
4. Equip Fire Wand and confirm that its own `EquipmentPrefab` appears in the same compatible slot.
5. Close and reopen the Main Menu. Confirm that the preview still shows the current Equipment state.
6. When the menu pauses scaled time, confirm that an Animator using **Unscaled Time** continues the intended menu pose.
7. In a runtime-spawn or split-screen test, open each player's menu and confirm that its preview follows only that player's Equipment.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| The preview fails during startup | **Equipper > Inventory** is empty and the preview has no Inventory on the same GameObject | Assign the real player's Inventory before the Equipper starts. |
| The character appears but equipped Items do not | **Equipment Item Collection ID**, collection type, and Item Slot Set | Point the Equipper at the correct Equipment Item Slot Collection and use the same slot set throughout. |
| An equipped Item logs a prefab error | `EquipmentPrefab`, or an optional `UsableItemPrefab` defined with a null value | Assign a valid Equipment prefab. Remove the optional usable-prefab attribute when the preview does not need it, rather than leaving its value null. |
| The preview creates an unwanted functional weapon object | **Usable Item Prefab Attribute Name** resolves the gameplay Item's usable prefab | Use a separate undefined optional attribute name for the display-only Equipper, or a project-specific display-only subclass. |
| A sword appears at the character origin | The matching Item Object Slot's **Skinned Equipment** and **Transform** | Keep a rigid weapon unskinned and assign the intended hand socket. |
| Skinned clothing is missing or distorted | **Main Root Node**, bone names, and the slot's **Skinned Equipment** option | Use matching uniquely named rigs and the correct character root node. |
| The preview shows another player's equipment | Panel Owner, Inventory Identifier ID, and the Inventory assigned to the preview Equipper | Bind each preview explicitly to its matching player; Panel Owner alone does not rebind Equipper. |
| Both split-screen panels show the same image | Preview rig, Camera, or Render Texture is shared | Give each player a separately bound preview and output texture. |
| The preview freezes while the menu is open | Display Panel Manager pauses scaled time and the Animator uses the normal update mode | Set the preview Animator's **Update Mode** to **Unscaled Time**, or do not pause scaled time. |
| The background is opaque | Camera background alpha, render-pipeline camera settings, Render Texture format, and Raw Image color | Configure an alpha-capable output and keep the Raw Image color alpha at `1`. |
| The preview is visible in the game world | Gameplay Camera **Culling Mask** and the preview layer | Put the rig on a dedicated layer and exclude it from gameplay Cameras. |

## Related pages

- [Main Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/main-menu/)
- [Display Panel Manager](https://opsive.com/support/documentation/ultimate-inventory-system/ui/display-panel-manager/)
- [Main Menu UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/main-menu/)
- [Equipping Items](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/equipping-items/)
- [Item Slot Collection](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/item-slot-collection/)
- [Spawn Player](https://opsive.com/support/documentation/ultimate-inventory-system/spawn-player/)
- [Split Screen Co-op UI](https://opsive.com/support/documentation/ultimate-inventory-system/input/split-screen-co-op-ui/)
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)

## Developer, save, and network boundaries

Released V1 has no `MenuCharacter` component and no automatic Panel Owner-to-Equipper binding. `EquipperBase` stores its Inventory in a protected serialized field and resolves it in `Start`; it does not expose a public Inventory setter. A runtime owner binder therefore needs a small `Equipper` subclass or another project-specific initialization path, and it must set the Inventory before the Equipper starts. Rebinding an already started Equipper is a custom lifecycle because the component has already cached the Equipment collection and registered its Inventory events.

`DisplayPanelManager.OnPanelOwnerAssigned` and the global `EventNames.c_OnPanelOwnerChange_GameObjectPanelOwner_DisplayPanelManager` event announce a UI owner change. The preview Equipper emits `EventNames.c_Equipper_OnChange` after an equip or unequip operation. These notifications do not synchronize ownership by themselves.

The preview needs no saver. Save the authoritative player Inventory with **Inventory Saver**; after loading changes the Equipment collection, the initialized preview follows its normal Inventory events. Do not add an Inventory Saver to a display-only duplicate.

Released UIS Version 1 does not replicate Inventory, Equipment, spawned Item Objects, Cameras, or Render Textures. A networking layer must establish the authoritative Inventory and replicate its Equipment state. Each client can then bind a local preview to the Inventory representation it is allowed to display. Inventory Identifier ID is a local UIS lookup key, not a network object identity.

---

<a id="page-ultimate-inventory-system-resizeablearrays-and-listslices"></a>

# ResizableArray and ListSlice

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/resizeablearrays-and-listslices/)

`ResizableArray<T>` and `ListSlice<T>` are runtime collection utilities used by Ultimate Inventory System APIs that need to reuse buffers or pass a range of results without creating a new list every time. You are most likely to encounter them while extending inventory queries, item actions, crafting, currency calculations, or UI filtering.

Use them only when their ownership rules are useful and measured allocations matter. A normal array or `List<T>` is clearer for most project data, Inspector-authored settings, and code whose size changes unpredictably.

The published URL keeps the historical `resizeablearrays-and-listslices` spelling. The released Version 1 C# names are exactly `ResizableArray<T>` and `ListSlice<T>` in the `Opsive.Shared.Utility` namespace.

## Choose the appropriate collection

| Need | Prefer | Why |
| --- | --- | --- |
| A fixed set of Inspector or saved data | Array | Ownership, length, and Unity serialization are straightforward. |
| A general-purpose collection with unpredictable additions and removals | `List<T>` | Familiar behavior and geometric capacity growth suit frequent changes. |
| A reusable runtime buffer whose approximate maximum size is known | `ResizableArray<T>` | Logical Count can be reset while the backing array is retained. |
| A temporary, read-only view passed to or returned from a UIS API | `ListSlice<T>` | The struct refers to an existing source instead of copying its elements. |
| A result that must outlive or be independent of its source buffer | An owned array or list copy | Later source changes cannot alter the result. |

Neither utility is automatically faster. `ResizableArray<T>` still allocates when it exhausts its backing array, and `ListSlice<T>` saves a copy only while the caller can safely share the source and its lifetime.

## Understand ResizableArray ownership

`ResizableArray<T>` is a class that wraps a `T[]` and maintains two sizes:

- `Count` is the number of logical elements.
- `Array.Length` is the capacity of the exposed backing array.

`new ResizableArray<T>(8)` creates capacity for eight elements but starts with `Count == 0`. Index, enumerate, sort, and copy only the range from zero up to `Count - 1`, even though the `Array` property may expose more slots.

Calling `Add` writes at Count and increases Count. If the buffer is full, released Version 1 grows it to exactly the required count rather than using the geometric growth of `List<T>`. Preallocate a realistic capacity when additions happen in a hot path; otherwise repeated additions beyond capacity can repeatedly allocate and copy the array.

### Reset or release retained values

The reset methods have different effects:

| Operation | Logical Count | Backing array |
| --- | --- | --- |
| `Clear()` | Becomes zero | Capacity and old slot values are retained. |
| `RemoveAll()` | Becomes zero | Every previously counted slot is set to `default(T)`; capacity is retained. |
| `Trim(newCount)` | Can only become smaller | Capacity and trimmed slot values are retained. |
| `Resize(newCount)` | Becomes the requested nonnegative count | Capacity grows only when required; retained values can become logical again. |
| `Truncate()` | Unchanged | The backing array is resized to exactly Count. |

Use `Clear()` when retaining references is intentional and every new logical slot will be overwritten. Use parameterless `RemoveAll()` when the buffer should release references to old Item data. After `Clear()` or `Trim()`, expanding Count within existing capacity can expose retained values; assign every newly active element before reading it.

### Borrow or copy an input array

`Initialize(array, false)` and `new ResizableArray<T>(array, false, count)` keep the supplied array as the backing storage. Mutating that array mutates the `ResizableArray<T>`, and mutating the wrapper's `Array` mutates the caller's array.

Pass `true` for the `copy` argument when the wrapper must own an independent array. The overload that initializes from another `ResizableArray<T>` also copies its entire backing capacity and logical Count.

The static `ResizableArray.Copy` methods copy active elements into a caller-supplied `ref T[]` buffer, then return a `ResizableArray<T>` backed by that result buffer. The new wrapper no longer shares the source, but it does share the supplied result buffer. Do not reuse or overwrite that buffer while the returned wrapper is still needed.

## Understand ListSlice lifetime

`ListSlice<T>` is a struct containing a reference to an `IReadOnlyList<T>` plus start and end metadata. Constructing or passing the struct does not copy the elements.

For the safe and common Version 1 case, create a full-range view whose start is zero:

```csharp
using Opsive.Shared.Utility;

var itemNames = new ResizableArray<string>(8);
itemNames.Add("Health Potion");
itemNames.Add("Iron Sword");
itemNames.Add("Fire Wand");

ListSlice<string> visibleItems = itemNames;

for (var i = 0; i < visibleItems.Count; i++) {
    UnityEngine.Debug.Log(visibleItems[i]);
}
```

`ListSlice<T>` does not implement `IEnumerable<T>`, so use Count and the indexer rather than `foreach`.

The slice records its end when it is created. If `itemNames` later adds a fourth element, the existing slice still reports three. Changing an existing source element is visible through the slice. Removing elements, clearing the source, resizing a reused output array, or reusing a pooled result buffer can make an older slice stale or invalid. Treat a slice as borrowed data that is valid only until its source is changed.

### Null, empty, and one-element views

- `default(ListSlice<T>)` and `ListSlice<T>.Empty` both have Count zero and `IsNull == true` in released Version 1.
- A slice created from a non-null empty array or list has Count zero and `IsNull == false`.
- The implicit conversion from one `T` creates a one-element virtual slice without a backing list.
- `Last` is valid only when Count is greater than zero.

Use `IsNull` only when the difference between "no source" and "an empty source" matters. Use `Count == 0` for ordinary empty-result handling.

### Keep ref-buffer results local

Several UIS methods accept a reusable `ref T[]` and return a `ListSlice<T>` over the populated part. This avoids allocating a result collection on every call, but the caller owns the buffer lifetime.

```csharp
using Opsive.UltimateInventorySystem.Core.DataStructures;
using Opsive.UltimateInventorySystem.Core.InventoryCollections;

public sealed class BagQuery
{
    private ItemInfo[] m_ItemInfoBuffer;

    public void CheckBag(Inventory inventory)
    {
        var results = inventory.GetItemInfos(
            ref m_ItemInfoBuffer,
            itemInfo => itemInfo.Item != null);

        for (var i = 0; i < results.Count; i++) {
            var itemInfo = results[i];
            // Inspect Health Potion, Iron Sword, or Fire Wand here.
        }

        // Consume or copy results before another call reuses m_ItemInfoBuffer.
    }
}
```

The example uses the released `Inventory.GetItemInfos` pattern and a start index of zero. The returned slice and the field buffer are working storage, not durable inventory state.

If the result must outlive the next query, copy the active entries into storage that your code owns. `ListSlice<T>.CopyTo(ref buffer)` can reuse a destination array, but its returned slice then borrows that destination buffer. `ToArray()` creates a new array for a full, zero-based list-backed slice, with the Version 1 limitations described below.

## Use a reusable buffer safely

The following component rebuilds a small display list without retaining old references. It uses the shared Health Potion, Iron Sword, and Fire Wand examples, but the same pattern applies to `ItemInfo` results.

```csharp
using Opsive.Shared.Utility;
using UnityEngine;

public sealed class InventoryNameBuffer : MonoBehaviour
{
    private readonly ResizableArray<string> m_Names =
        new ResizableArray<string>(8);

    public void Rebuild()
    {
        m_Names.RemoveAll();
        m_Names.Add("Health Potion");
        m_Names.Add("Iron Sword");
        m_Names.Add("Fire Wand");

        ListSlice<string> names = m_Names;
        for (var i = 0; i < names.Count; i++) {
            Debug.Log(names[i]);
        }
    }
}
```

Use a `for` loop in frequently executed code. The `ResizableArray<T>` enumerator is implemented with `yield return`; `foreach` is supported for `ResizableArray<T>`, but it creates an enumerator rather than providing a special allocation-free struct enumerator.

## Verify the behavior with tests

Test Count, aliasing, and lifetime assumptions before using either type in a performance-sensitive extension.

```csharp
using NUnit.Framework;
using Opsive.Shared.Utility;

public class CollectionUtilityTests
{
    [Test]
    public void FullSliceSharesValuesButKeepsItsOriginalCount()
    {
        var source = new ResizableArray<string>(3);
        source.Add("Health Potion");
        source.Add("Iron Sword");

        ListSlice<string> view = source;
        source[0] = "Greater Health Potion";
        source.Add("Fire Wand");

        Assert.AreEqual("Greater Health Potion", view[0]);
        Assert.AreEqual(2, view.Count);
    }

    [Test]
    public void RemoveAllReusesCapacityAndClearsReferences()
    {
        var source = new ResizableArray<string>(3);
        source.Add("Health Potion");

        source.RemoveAll();

        Assert.AreEqual(0, source.Count);
        Assert.AreEqual(3, source.Array.Length);
        Assert.IsNull(source.Array[0]);
    }
}
```

For a UIS-specific test, query Bag into a reusable `ItemInfo[]`, assert the returned Count and Item Definitions, mutate Bag, query again, and verify the new result. Do not keep the first slice and expect it to remain a snapshot after the buffer is reused.

## Serialization and editor use

These utilities are runtime and developer-facing types, not normal UIS database objects.

- `ResizableArray<T>` is not marked `[Serializable]` in Opsive Shared 2.0. UIS commonly uses it for runtime buffers or serializes its data explicitly.
- `ListSlice<T>` is not a serializable data container; it stores a temporary reference and range.
- Do not expect a `[SerializeField] ResizableArray<T>` or `ListSlice<T>` field to behave like a normal Inspector-authored list.
- Do not save a slice as inventory state. Save Items, collections, attributes, or project data through the appropriate UIS saver, then rebuild temporary buffers after loading.

Use an array, `List<T>`, ScriptableObject, or UIS data object for authoring. Use these utilities inside runtime code where their buffer-sharing behavior is explicit.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| Allocations still occur while adding results | Compare Count with `Array.Length` and inspect whether `Add` repeatedly exhausts capacity. | Preallocate a realistic capacity, reuse the same instance, or use `List<T>` when growth is unpredictable. |
| Old Item references appear after rebuilding | Check whether code called `Clear()` or `Trim()` and then enlarged Count without assigning every slot. | Call `RemoveAll()` to clear references, or overwrite every newly active element before reading it. |
| A saved slice changes after another query | Check whether both results share the same `ref T[]` buffer. | Consume the slice before the next query or make an owned copy of its active elements. |
| Indexing a slice throws after its source changes | Compare the slice's recorded Count with the source's current length or Count. | Treat the slice as invalid after structural source changes and request a new slice. |
| `foreach` does not compile for `ListSlice<T>` | Check the type; it does not implement an enumerable interface. | Iterate from zero to Count with a `for` loop. |
| `Last` throws | Check whether Count is zero. | Test Count before reading Last. |
| Removing an equal reference object returns false | Check whether it is the same object instance. Version 1 `Remove(T)` uses reference identity for class types. | Pass the stored instance, or locate the intended index and call `RemoveAt` after validating it. |
| The collection does not appear or persist as expected in the Inspector | Check whether a runtime utility was used as authored or saved data. | Store authored data in a supported array, list, UIS object, or saver and rebuild the runtime utility. |

## Current Version 1 boundaries

- Ultimate Inventory System 1.3.0 depends on Opsive Shared 2.0.0; its namespace is `Opsive.Shared.Utility`, not the Version 3 `Opsive.Shared.Runtime.Utility` namespace.
- The historical page slug says `resizeable`, but the type and source filename are `ResizableArray` and `ResizableArray.cs`.
- The Version 1 `ListSlice<T>` implementation is reliable for the common start-zero view used by UIS. Nonzero-start constructors, `ToListSlice(start, end)`, and `NewSlice` have inconsistent offset behavior in the indexer, copy, array-conversion, and sort paths. Avoid nonzero starts unless the Shared package has been patched and tested for the project.
- `ListSlice<T>.ToArray()` does not handle its virtual one-element form and is unsafe with the nonzero-start limitation. Use `CopyTo(ref buffer)` for a one-element slice, or copy a tested start-zero list-backed slice.
- ListSlice constructors do not validate start and end. Count can be invalid, and an empty `Last` access throws.
- `ResizableArray<T>` exposes its backing array, and its indexer validates only the backing array bounds, not logical Count. Always enforce `0 <= index < Count` in project code.
- `Insert` on an empty, preallocated Version 1 `ResizableArray<T>` can access the element before index zero. Use `Add` for the first element.
- `RemoveAt`, copy overloads, and constructor Count values do not add full range or capacity validation. Validate indexes, Count, source ranges, and destination capacity before calling them.
- `Remove(T)` cannot remove null and uses reference identity for class instances, while `Contains` and `IndexOf` use `EqualityComparer<T>.Default`.
- The utilities are not synchronized, job-safe, native collections, save records, or immutable snapshots.

## Related pages

- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/) explains the collections queried by many `ListSlice<ItemInfo>` APIs.
- [Item Info](https://opsive.com/support/documentation/ultimate-inventory-system/item/item-info/) explains the Item, amount, collection, and stack context carried by common result buffers.
- [Item Info Filter Sorters](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-info-filter-sorters/) covers a runtime workflow that uses slices and reusable arrays.
- [Crafting](https://opsive.com/support/documentation/ultimate-inventory-system/crafting/) uses list slices for ingredients and selected results.
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/) explains UIS event signatures, some of which pass `ListSlice<T>` values.
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/) covers persistent data; temporary buffers and slices should be rebuilt after loading.

## API reference

### ResizableArray members

`ResizableArray<T>` implements `IList`, `IList<T>`, and `IReadOnlyList<T>`.

- Constructors create an empty buffer, preallocate capacity, wrap or copy an array, or copy an `IReadOnlyList<T>` into a new array.
- `Initialize` replaces the current backing data from a size, array, or another `ResizableArray<T>`.
- `Count`, `Array`, `Last`, and the indexer expose logical size, storage, the last logical entry, and direct indexed access.
- `Add`, `AddRange`, `Insert`, `Remove`, `RemoveAt`, `RemoveAll`, and `Clear` change the logical contents.
- `Trim`, `Resize`, and `Truncate` change Count or physical capacity with the distinctions described above.
- `Contains`, `IndexOf`, and `MoveElementIndex` search or reorder the active range.
- `Sort(Comparer<T>)` sorts the active range from zero through Count.
- `CopyTo` writes Count elements to a supplied array or `ResizableArray<T>`; destination storage must already be large enough for the instance overloads.
- Static `ResizableArray.Copy` copies active elements into a reusable `ref T[]` and returns a wrapper over that buffer.

### ListSlice members

- Constructors accept an `IReadOnlyList<T>`, a source with start and end indexes, or one virtual element.
- Implicit conversions exist from `List<T>`, `T[]`, `ResizableArray<T>`, one `T`, and `(IReadOnlyList<T>, start, end)` tuples.
- `ToListSlice` extension methods create views from an `IReadOnlyList<T>`.
- `Count`, `Last`, the read-only indexer, `IsNull`, and `Empty` expose the view state.
- `Contains` compares active values with `EqualityComparer<T>.Default`.
- `CopyTo(ref T[])` copies into a reusable array and returns a new start-zero slice over it.
- `ToArray()` allocates an array, subject to the Version 1 restrictions above.
- `Sort(T[], Comparer<T>)` sorts the supplied array using the slice's stored range; it does not replace or copy the slice's source.
- `NewSlice(start, end)` creates another view over the stored list, but nonzero ranges require the Version 1 caution above.

---

<a id="page-ultimate-inventory-system-events"></a>

# Events

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/events/)

Events let another component react when gameplay changes instead of checking the Inventory every frame. Use them to refresh custom UI, advance a quest, play feedback, or record that a player added a Health Potion, bought an Iron Sword, or completed a craft.

Released Ultimate Inventory System Version 1 exposes both normal C# events and the named Opsive Event Handler. Most cross-system notifications use the Event Handler, so this page focuses on registering for those events safely.

## Choose what to observe

The target is part of an Event Handler subscription. Registering the correct event name on the wrong object will not receive the event.

| Outcome | Register on | Event name | Handler parameters |
| --- | --- | --- | --- |
| An Item was added | The `Inventory` component | `EventNames.c_Inventory_OnAdd_ItemInfo_ItemStack` | `ItemInfo`, `ItemStack` |
| An Item was removed | The `Inventory` component | `EventNames.c_Inventory_OnRemove_ItemInfo` | `ItemInfo` |
| A Shop buy completed | The Shop GameObject | `EventNames.c_ShopGameObject_OnBuyComplete_BuyerInventory_ItemInfo` | `Inventory`, `ItemInfo` |
| A Shop sale completed | The Shop GameObject | `EventNames.c_ShopGameObject_OnSellComplete_SellerInventory_ItemInfo` | `Inventory`, `ItemInfo` |
| A craft attempt completed | The Inventory GameObject | `EventNames.c_InventoryGameObject_OnCraft_CraftingRecipe_CraftingResult` | `CraftingRecipe`, `CraftingResult` |
| A crafting availability check ran | The Inventory GameObject | `EventNames.c_InventoryGameObject_OnCanCraft_CraftingRecipe_Bool` | `CraftingRecipe`, `bool` |

Use completion events for feedback that should happen once. A Crafting Menu may call `CanCraft` repeatedly while it refreshes, so its event is better for diagnostics than for sound effects or quest progress. Shop completion events run only after a successful transaction. The craft completion event includes a `CraftingResult` whose `Success` value can be either `true` or `false`.

## Add a lifecycle-safe listener

Create `UISGameplayEventListener.cs`, add it to a scene GameObject, and assign the player's **Inventory** and the Shop GameObject. Keep only the subscriptions that the project needs.

```csharp
using Opsive.Shared.Events;
using Opsive.UltimateInventorySystem.Core;
using Opsive.UltimateInventorySystem.Core.DataStructures;
using Opsive.UltimateInventorySystem.Core.InventoryCollections;
using Opsive.UltimateInventorySystem.Crafting;
using UnityEngine;

public class UISGameplayEventListener : MonoBehaviour
{
    [SerializeField] private Inventory m_PlayerInventory;
    [SerializeField] private GameObject m_ShopGameObject;

    private Inventory m_ListenedInventory;
    private GameObject m_ListenedShopGameObject;

    private void OnEnable()
    {
        m_ListenedInventory = m_PlayerInventory;
        if (m_ListenedInventory != null) {
            EventHandler.RegisterEvent<ItemInfo, ItemStack>(
                m_ListenedInventory,
                EventNames.c_Inventory_OnAdd_ItemInfo_ItemStack,
                OnItemAdded);
            EventHandler.RegisterEvent<ItemInfo>(
                m_ListenedInventory,
                EventNames.c_Inventory_OnRemove_ItemInfo,
                OnItemRemoved);
            EventHandler.RegisterEvent<CraftingRecipe, CraftingResult>(
                m_ListenedInventory.gameObject,
                EventNames.c_InventoryGameObject_OnCraft_CraftingRecipe_CraftingResult,
                OnCraftCompleted);
        }

        m_ListenedShopGameObject = m_ShopGameObject;
        if (m_ListenedShopGameObject != null) {
            EventHandler.RegisterEvent<Inventory, ItemInfo>(
                m_ListenedShopGameObject,
                EventNames.c_ShopGameObject_OnBuyComplete_BuyerInventory_ItemInfo,
                OnBuyCompleted);
            EventHandler.RegisterEvent<Inventory, ItemInfo>(
                m_ListenedShopGameObject,
                EventNames.c_ShopGameObject_OnSellComplete_SellerInventory_ItemInfo,
                OnSellCompleted);
        }
    }

    private void OnDisable()
    {
        if (m_ListenedInventory != null) {
            EventHandler.UnregisterEvent<ItemInfo, ItemStack>(
                m_ListenedInventory,
                EventNames.c_Inventory_OnAdd_ItemInfo_ItemStack,
                OnItemAdded);
            EventHandler.UnregisterEvent<ItemInfo>(
                m_ListenedInventory,
                EventNames.c_Inventory_OnRemove_ItemInfo,
                OnItemRemoved);
            EventHandler.UnregisterEvent<CraftingRecipe, CraftingResult>(
                m_ListenedInventory.gameObject,
                EventNames.c_InventoryGameObject_OnCraft_CraftingRecipe_CraftingResult,
                OnCraftCompleted);
        }

        if (m_ListenedShopGameObject != null) {
            EventHandler.UnregisterEvent<Inventory, ItemInfo>(
                m_ListenedShopGameObject,
                EventNames.c_ShopGameObject_OnBuyComplete_BuyerInventory_ItemInfo,
                OnBuyCompleted);
            EventHandler.UnregisterEvent<Inventory, ItemInfo>(
                m_ListenedShopGameObject,
                EventNames.c_ShopGameObject_OnSellComplete_SellerInventory_ItemInfo,
                OnSellCompleted);
        }

        m_ListenedInventory = null;
        m_ListenedShopGameObject = null;
    }

    private void OnItemAdded(ItemInfo originalItemInfo, ItemStack addedItemStack)
    {
        if (addedItemStack == null) { return; }

        Debug.Log($"Added {originalItemInfo.Amount} item(s). " +
                  $"The destination stack now contains {addedItemStack.Amount}.");
    }

    private void OnItemRemoved(ItemInfo removedItemInfo)
    {
        Debug.Log($"Removed {removedItemInfo.Amount} item(s).");
    }

    private void OnBuyCompleted(Inventory buyerInventory, ItemInfo itemInfo)
    {
        Debug.Log($"{buyerInventory.name} bought {itemInfo.Amount} item(s).");
    }

    private void OnSellCompleted(Inventory sellerInventory, ItemInfo itemInfo)
    {
        Debug.Log($"{sellerInventory.name} sold {itemInfo.Amount} item(s).");
    }

    private void OnCraftCompleted(CraftingRecipe recipe, CraftingResult result)
    {
        var recipeName = recipe == null ? "Unknown recipe" : recipe.name;
        Debug.Log($"Crafting {recipeName} " +
                  (result.Success ? "succeeded." : "failed."));
    }
}
```

`OnEnable` and `OnDisable` keep the listener aligned with the component's active state. The script stores the objects it registered against so it unregisters from the same targets even if an Inspector reference changes while the component is enabled.

## Verify in Play Mode

1. Enter Play Mode and add a Health Potion to the assigned Inventory. Confirm that one add message appears and reports the resulting stack amount.
2. Remove one Health Potion. Confirm that one remove message appears.
3. Buy an Iron Sword from the assigned Shop. Confirm that the buy message appears only after the purchase succeeds.
4. Sell an Item to the same Shop. Confirm that the sale message identifies the seller Inventory.
5. Attempt the Health Potion recipe once without enough ingredients and once with enough ingredients. Confirm that the craft message reports failure and success respectively.
6. Disable the listener component and repeat an action. Confirm that no message appears.
7. Re-enable the component and repeat the action. Confirm that exactly one message appears rather than a duplicate.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| The listener never runs | Compare the registered target with the table above. An Inventory event targets the `Inventory` component, while Shop and craft events in these examples target GameObjects. | Register on the exact object used by the Version 1 execution call. |
| Unity reports an Event Handler type error | Compare the generic types, their order, and the handler method parameters. | Make all three signatures identical to the source event. Do not reuse an event name with different payload types. |
| The callback runs twice | Check whether the component registered in both `Awake` or `Start` and `OnEnable`, or enabled twice without matching cleanup. | Register once and pair every registration with the matching `OnDisable` unregistration. |
| A disabled or destroyed listener still runs | Compare the target, name, generic types, and method passed to `UnregisterEvent`. | Unregister with the same four pieces used for registration. Avoid an inline lambda unless its delegate is stored for cleanup. |
| The Inventory add test does nothing in Edit Mode | Version 1 sends the Inventory add Event Handler notification during Play Mode. | Test the runtime workflow in Play Mode. |
| A Shop completion event does not run | Check whether the transaction actually succeeded. | Correct the price, Currency, destination Item Collection, or other failed Shop condition before debugging the listener. |
| Craft feedback runs repeatedly | Check whether the listener uses the `OnCanCraft` event. | Use `c_InventoryGameObject_OnCraft_CraftingRecipe_CraftingResult` for one result per craft attempt. |
| A callback-based transaction never completes | Check whether a callback event handler invokes its supplied `Action<bool>`. | Invoke the callback exactly once during the event call, with `true` to continue or `false` to reject the operation. |

## Related pages

- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/)
- [Item Collections](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/)
- [Shop](https://opsive.com/support/documentation/ultimate-inventory-system/currency/shop/)
- [Crafting](https://opsive.com/support/documentation/ultimate-inventory-system/crafting/)
- [Custom Crafting Processors](https://opsive.com/support/documentation/ultimate-inventory-system/crafting/custom-crafting-processors/)

## Developer reference

### Match registration, execution, and unregistration

An Event Handler route consists of four matching parts:

1. the target object, unless the event is global;
2. the event-name constant;
3. the generic payload types in their exact order; and
4. a handler whose parameters match those payload types.

Version 1 executes a named event with `ExecuteEvent`, not `Execute`. This custom targeted event uses one `int` payload:

```csharp
private const string c_Player_OnPotionCountChanged_Int =
    "Player_OnPotionCountChanged_Int";

private void Register(GameObject player)
{
    EventHandler.RegisterEvent<int>(
        player, c_Player_OnPotionCountChanged_Int, OnPotionCountChanged);
}

private void Send(GameObject player, int newCount)
{
    EventHandler.ExecuteEvent<int>(
        player, c_Player_OnPotionCountChanged_Int, newCount);
}

private void Unregister(GameObject player)
{
    EventHandler.UnregisterEvent<int>(
        player, c_Player_OnPotionCountChanged_Int, OnPotionCountChanged);
}

private void OnPotionCountChanged(int newCount)
{
    // Update the dependent system.
}
```

Global events use the overloads without a target object. Targeted and global routes are separate, even when their event-name strings match. The Event Handler invokes matching listeners synchronously. A listener can unregister during execution, and the handler keeps the remaining list valid.

All UIS Event Handler constants are declared in `EventNames.cs`. Their names generally follow this pattern:

```csharp
c_TargetObjectType_EventDescription_Parameter1Type_Parameter2Type
```

Use the constant's source comment and the corresponding `ExecuteEvent` call as the authority for the target and payload signature.

### Choose between C# events and the Event Handler

Use a normal C# event when the publisher exposes one and the listener already owns a direct reference to it. For example, an `ItemCollection` exposes `OnItemAdded`, `OnItemRemoved`, `OnItemAddOverflow`, and `OnItemCollectionUpdate`. Subscribe with `+=` and unsubscribe with `-=` using the same lifecycle discipline.

Use the Opsive Event Handler when UIS publishes a named target or global event, when multiple Opsive systems need the same route, or when the listener should not depend on the publisher's concrete event member. Do not assume that every operation exposes both styles.

### Distinguish notifications from transaction callbacks

Completion events report something that already happened. The following Version 1 events are synchronous transaction hooks and include an `Action<bool>` that decides whether processing continues:

| Integration hook | Target | Payload signature |
| --- | --- | --- |
| `EventNames.c_InventoryGameObject_OnBuyAddItem_Shop_ItemInfo_ActionBoolSucces` | Buyer Inventory GameObject | `ShopGeneric<CurrencyCollection>`, `ItemInfo`, `Action<bool>` |
| `EventNames.c_InventoryGameObject_OnSellRemoveItem_ShopBase_ItemInfo_ActionBoolSucces` | Seller Inventory GameObject | `ShopBase`, `ItemInfo`, `Action<bool>` |
| `EventNames.c_InventoryGameObject_OnCraftRemoveItem_CraftingProecessor_ItemInfoListSlice_ActionBoolSucces` | Inventory GameObject | `CraftingProcessor`, `ListSlice<ItemInfo>`, `Action<bool>` |

The spelling of these constants, including `Succes` and `Proecessor`, is part of the Version 1 API. Copy the constants instead of correcting their names in code. Use the completion events for ordinary UI, audio, quest, or analytics listeners; use callback hooks only when the project intentionally owns that transaction step.

---

<a id="page-ultimate-inventory-system-spawn-player"></a>

# Spawn Player

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/spawn-player/)

Spawn a UIS player only after the configured Inventory System Manager and database are ready. The player prefab owns the Inventory, Item Collections, Currency Owner, Inventory Identifier, input, and interaction components; the project, character controller, or networking solution owns the spawn point, prefab instantiation, respawn rules, and authority.

Released Ultimate Inventory System Version 1 does not include a player spawner or spawn-point component. Its role begins when the configured player GameObject becomes active.

## Understand the spawn sequence

Use this order for a new player:

1. Initialize the configured Inventory System Manager and its database.
2. Initialize Save System Manager when the player will restore saved data.
3. Instantiate the configured player prefab at the project-owned spawn point.
4. Let Inventory, Currency Owner, Item User, and Inventory Identifier initialize in `Awake`.
5. Let Inventory Interactor and saver components initialize in `Start`.
6. Assign or resolve the UI's Panel Owner.
7. Load saved data only after the replacement player's savers have registered.
8. Announce player readiness through the project spawner or networking layer.

Do not use an early static UIS lookup to discover whether setup exists. If no configured Inventory System Manager is active, static access can create an empty `InventorySystemManager` GameObject with no database. Establish the manager root first and then spawn the player.

## Prepare the player prefab

1. Open the player prefab in Prefab Mode, or select a scene instance that will be applied back to the prefab.
2. Open **Tools > Opsive > Ultimate Inventory System > Main Manager**.
3. Select **Setup**.
4. Under **Character Setup**, assign **Character Gameobject**.
5. Select **Add Components**.

Character Setup adds these components when they are missing:

- **Inventory Identifier**;
- **Inventory**;
- **Item User**;
- the released Version 1 **Unity Input** implementation;
- **Inventory Interactor**; and
- **Currency Owner**.

Character Setup sets the added Unity Input component's cursor options **Enable Cursor With Escape** and **Disable Cursor** off. It does not choose a player prefab, spawn point, database, Item Collections, loadout, UI, or network owner.

### Configure the player identity

Keep Inventory Identifier on the same GameObject as Inventory, Currency Owner, and Item User for the standard workflow.

| Inspector field | Version 1 default | Spawn requirement |
| --- | --- | --- |
| **Inventory Identifier > ID** | `1` | Must be nonzero, unique among live players, and stable when UI or saves refer to the player |
| **Item User > Inventory Input** | None | Resolves a compatible player input component from the same GameObject |
| **Inventory Interactor > Inventory** | None | Resolves Inventory from the same GameObject in `Start` |
| **Inventory Interactor > Interactable Indicator** | None | Optional project visual shown when interaction is available |
| **Inventory Interactor > Auto Interact** | Off | Leaves interaction on input rather than triggering automatically |
| **Inventory Interactor > Input** | `Action`, `Button Down` | Default interaction input configured by the component |

Inventory Identifier registers itself with Inventory System Manager in `Awake`. When two live identifiers request the same ID, Version 1 may assign a generated ID to the later object. Treat that as an error for player ownership; configure unique IDs rather than depending on runtime reassignment.

### Configure Bag, Equipment, Items, and Gold

Character Setup creates the components but not the finished player data model.

1. In Inventory, name the main Item Collection **Bag** and keep its purpose as **Main**.
2. Add an Item Slot Collection named **Equipment** when the player equips Items into fixed slots.
3. Add one **Health Potion** to Bag's **Default Loadout** for a visible spawn test.
4. Add or equip an **Iron Sword** according to the project's Equipment workflow.
5. In Currency Owner, configure **Currency Amount** with a known starting **Gold** value.
6. Confirm that every referenced Category, Definition, Item, and Currency belongs to the database assigned to Inventory System Manager.

An Inventory with no serialized collection creates one fallback collection named `NewItemCollection` and marks the first collection as **Main**, but it has no project-specific structure or restrictions. Configure Bag and Equipment explicitly on the prefab.

Inventory applies each collection's Default Loadout after all of its Item Collections initialize. A non-additive Inventory Saver load later clears the current collections before restoring the saved state, preventing the default Health Potion from being added on top of a normal replacement load.

## Choose the spawn point and prefab lifetime

Use the project spawner, Unity scene loader, character controller, or networking solution to choose the spawn Transform. Instantiate with the final position and rotation so character and project `Awake` logic sees the intended pose.

Choose one player lifetime:

| Lifetime | Behavior | UIS consequence |
| --- | --- | --- |
| Scene-owned player | Destroy and respawn on each scene | Save before unload and load after the replacement savers register |
| Persistent player | Apply `DontDestroyOnLoad` to the player root in project code | Inventory, Equipment, Gold, identifiers, and UI owner references remain in memory |
| Respawn in the same scene | Destroy and instantiate a replacement | Decide whether death retains, clears, or reloads Inventory and Currency before the new player becomes ready |
| Pooled player | Disable and reuse an object | Requires a custom identifier lifecycle; Inventory Identifier does not automatically unregister on disable |

Do not spawn a scene-owned player when a persistent copy already exists. Duplicate Inventories, identifiers, inputs, savers, and UI owners can all appear valid individually while operating on different player objects.

For pooled players, Version 1 exposes `InventoryIdentifier.Unregister()` and `RegisterIdentifier()`, but unregistering resets the registered ID. A custom pooling layer must restore the intended ID and registration deliberately before making that player authoritative again.

## Connect the player and UI

Display Panel Manager supports either relative spawn order.

### UI exists before the player

When **Panel Owner** is empty and **Panel Owner Inventory Identifier ID** cannot be found, Display Panel Manager registers itself, logs a warning, and disables its GameObject. Add **Dynamic Panel Owner** to the player prefab and keep its **Display Panel Manager ID** matched to the intended UI.

Released Version 1 defaults are:

- **Display Panel Manager > ID**: `1`;
- **Display Panel Manager > Panel Owner**: None;
- **Display Panel Manager > Panel Owner Inventory Identifier ID**: `1`; and
- **Dynamic Panel Owner > Display Panel Manager ID**: `1`.

Dynamic Panel Owner calls `SetPanelOwner` in `Awake`. The manager then initializes its panels and re-enables the UI GameObject.

### Player exists before the UI

When the UI appears later, Display Panel Manager resolves the registered Inventory Identifier whose ID matches **Panel Owner Inventory Identifier ID**. No Dynamic Panel Owner is required for this order, although using it consistently is valid when the matching panel manager already exists.

### Player and UI spawn together

Load or instantiate them only after Inventory System Manager exists. Keep the UI and player IDs matched. If they are in an additive player/UI scene, do not put a second Inventory System Manager in that scene.

The Display Panel Manager owns UI selection, not the player spawn lifecycle. Use its `OnPanelOwnerAssigned` event or the Opsive owner-change event when project UI must react to a new owner.

## Restore saved state after spawning

When a newly spawned player should continue an earlier Inventory:

1. Under **Main Manager > Setup > Save Setup**, assign the player prefab or instance to **Object to save** and select **Add Components**.
2. Confirm that Inventory Saver and Currency Owner Saver are present.
3. Confirm that the manager `Game` root has Save System Manager and Inventory System Manager Item Saver.
4. Keep Inventory Saver **Additive** off for a replacement restore.
5. Keep the player's GameObject name and each saver's **Key** stable between saves.
6. Call `SaveSystemManager.Load(slot)` only after the new savers reach `Start`.

When Save System Manager preloads the slot before the player exists, enable **Load On Start** on the player's savers. For scene unloads, enable **Save On Destroy** or save explicitly before destroying the old player. See [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/) and [Scene Transitions](https://opsive.com/support/documentation/ultimate-inventory-system/scene-transitions/) for the full timing model.

For Ultimate Character Controller characters, use the integration's **Inventory Bridge Saver** instead of the standard Inventory Saver.

Multiple spawned players need stable, unique saver full keys as well as unique Inventory Identifier IDs. Rename the runtime GameObjects before saver `Start`, or use distinct configured prefab variants/keys, so two `Player(Clone)` objects do not compete for the same saver key.

## Keep the Inventory separate only for advanced setups

The standard prefab keeps Inventory, Currency Owner, Item User, Inventory Identifier, input, and Inventory Interactor together. This lets each component resolve its dependencies from the same GameObject.

An Inventory can live on another GameObject, such as a persistent UI root, if Inventory Identifier remains beside that Inventory and project code resolves it by ID. This is an advanced ownership model:

- the visible character must obtain that external Inventory explicitly;
- Inventory Interactor looks for player input on the Inventory GameObject and therefore does not support this separation without customization;
- same-GameObject fallbacks in other UIS components must be reviewed; and
- the external Inventory's lifetime, identifier, UI owner, savers, and network authority must remain aligned.

Prefer the standard co-located prefab unless persistent inventory ownership is a deliberate architectural requirement.

## Configure local multiplayer and networking

For local split-screen:

1. share one Inventory System Manager and database;
2. give every player prefab a unique, nonzero Inventory Identifier ID;
3. give every UI a unique Display Panel Manager ID and matching Panel Owner Inventory Identifier ID;
4. connect each UI root to its intended EventSystem through Event System Identifier;
5. give every saved player a stable GameObject name or saver **Key**; and
6. verify that each input implementation belongs to the correct local player.

Configure identity on prefab variants or before activation when other `Awake` logic requires the final ID. Changing the ID after instantiation unregisters and re-registers the Inventory Identifier, but any component that already cached the earlier identity must also be rebound.

Released UIS Version 1 has no network player-spawn, ownership, prediction, replication, or scene-migration component. Inventory Identifier ID is a local UIS lookup key, not a network object ID. Let the networking layer spawn the authoritative prefab, assign network ownership, choose the UIS ID, synchronize Inventory/Currency mutations, and announce readiness. Do not let every client independently apply a default loadout or local save to the same network player.

## Editor checkpoint

Before entering Play Mode, confirm that:

- the configured Inventory System Manager and database load before the player prefab;
- the prefab contains Inventory Identifier, Inventory, Item User, player input, Inventory Interactor, and Currency Owner;
- Inventory Identifier **ID** is nonzero, stable, and unique;
- Bag is the main Item Collection and Equipment uses the intended slot collection;
- the Health Potion, Iron Sword, and Gold references belong to the active database;
- the spawn system instantiates the intended prefab at the intended Transform;
- the UI's Display Panel Manager and Panel Owner IDs match the player;
- Dynamic Panel Owner is present when UI can exist first;
- savers and stable keys are configured when spawned state must be restored; and
- split-screen or network ownership is assigned before the player is announced as ready.

## Verify in Play Mode

1. Start with the player absent and confirm that exactly one configured Inventory System Manager is active.
2. Spawn the prefab at a visibly different test point and confirm its position and rotation.
3. Resolve the configured Inventory Identifier ID and confirm that it returns the spawned player.
4. Confirm that Bag contains the default Health Potion, Equipment follows its configured starting state, and Currency Owner has the expected Gold.
5. Open the Inventory UI and confirm that it shows and modifies this player's Inventory.
6. Pick up an Item or interact with a Shop to verify Inventory Interactor and input ownership.
7. Destroy and respawn the player. Verify the designed rule: reset to defaults, retain a persistent Inventory, or restore the save after saver `Start`.
8. Spawn a second local player and confirm that IDs, UI, input, EventSystems, and saver keys remain separate.
9. Change scenes and confirm that the chosen persistent or recreated-player model does not produce duplicates.
10. In a networked test, verify on a remote client that only authoritative replicated state determines Items and Gold.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| Spawning logs that the database is null | The configured manager did not initialize before player `Awake` | Establish the manager/bootstrap first and delay prefab activation |
| `GetInventoryIdentifier(id)` returns null | ID is `0`, the prefab is inactive, the manager register was recreated, or spawning has not reached `Awake` | Use a stable nonzero ID and query after the active prefab registers |
| The second player receives an unexpected ID | Another live Inventory Identifier already uses the serialized ID | Assign unique prefab IDs and remove duplicate players |
| The player has no Bag or useful Item Collection | Character Setup added Inventory but the prefab data model was never configured | Add and name Bag/Equipment collections in the Inventory Inspector |
| The Health Potion appears twice after loading | Inventory Saver **Additive** is on, or project code reapplies the loadout after load | Use a non-additive replacement load and initialize defaults only once |
| Gold resets on respawn | Currency Owner Saver is missing or no explicit persistence rule exists | Add the saver and load after `Start`, or keep Currency Owner persistent |
| Interaction input does nothing | Inventory Interactor cannot find Inventory/player input, or UI left gameplay input disabled | Keep dependencies together, assign them explicitly, and verify UI/input events |
| UI remains disabled | Display Panel Manager has no owner | Match Panel Owner Inventory Identifier ID or use Dynamic Panel Owner |
| UI controls the wrong player | Player, Display Panel Manager, or EventSystem ownership IDs are crossed | Give every local player/UI pair a unique and matching configuration |
| Saved players overwrite each other | Spawned GameObjects and saver **Key** values produce the same full key | Rename each player before saver `Start` or use unique configured saver keys |
| A pooled player's lookup points to an inactive object | Inventory Identifier does not unregister on disable | Add an explicit pool registration lifecycle or avoid pooling the identity owner |
| A remote client has different Items or Gold | Local spawn defaults or save loading ran without network authority | Let the server/host initialize and replicate the authoritative state |

## Version 1 boundaries

- No built-in player spawner, spawn point, respawn controller, or network player authority is supplied.
- Character Setup adds components; it does not configure Item Collections, default Items, Gold, UI, saves, or spawn rules.
- Inventory Identifier registers in `Awake`; Inventory Interactor and savers complete relevant setup in `Start`.
- Inventory Identifier does not automatically unregister when a pooled player is disabled.
- Display Panel Manager can wait for a player owner, but the project decides when the player is ready for gameplay.
- Database IDs, Inventory Identifier IDs, saver keys, collection layout, and UI IDs must remain stable when saves or persistent references depend on them.

## Related pages

- [Inventory System Manager](https://opsive.com/support/documentation/ultimate-inventory-system/inventory-system-manager/) covers manager creation and initialization.
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/) covers Bag, Equipment, and Item Collection setup.
- [Currency](https://opsive.com/support/documentation/ultimate-inventory-system/currency/) covers Currency Owner and starting Gold.
- [Interaction System](https://opsive.com/support/documentation/ultimate-inventory-system/interaction-system/) covers Inventory Interactor and world interactions.
- [Display Panel Manager](https://opsive.com/support/documentation/ultimate-inventory-system/ui/display-panel-manager/) covers Panel Owner and UI initialization.
- [Split Screen Co-op UI](https://opsive.com/support/documentation/ultimate-inventory-system/input/split-screen-co-op-ui/) covers per-player UI and EventSystems.
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/) covers saver keys and post-spawn restoration.
- [Scene Transitions](https://opsive.com/support/documentation/ultimate-inventory-system/scene-transitions/) covers persistent and recreated-player scene models.
- [Opsive Character Controllers](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/opsive-character-controllers/) covers character integration setup.

## Developer details

### Spawn and validate the prefab

The project spawner should instantiate the prefab at the final pose, give each runtime player a stable name before saver `Start`, and verify the identity serialized on the prefab:

```csharp
using Opsive.UltimateInventorySystem.Core;
using Opsive.UltimateInventorySystem.Core.InventoryCollections;
using UnityEngine;

public class UISPlayerSpawner : MonoBehaviour
{
    [SerializeField] private GameObject m_PlayerPrefab;
    [SerializeField] private Transform m_SpawnPoint;
    [SerializeField] private uint m_ExpectedInventoryID = 1;

    public GameObject Spawn()
    {
        if (InventorySystemManager.IsNull ||
            !InventorySystemManager.Instance.IsInitialized ||
            InventorySystemManager.Instance.Database == null) {
            Debug.LogError("Spawn the configured Inventory System Manager first.");
            return null;
        }

        var player = Instantiate(
            m_PlayerPrefab,
            m_SpawnPoint.position,
            m_SpawnPoint.rotation);

        player.name = $"Player_{m_ExpectedInventoryID}";

        var identifier = player.GetComponent<InventoryIdentifier>();
        if (identifier == null || identifier.ID != m_ExpectedInventoryID) {
            Debug.LogError("The player prefab has the wrong Inventory Identifier ID.", player);
        }

        return player;
    }
}
```

`Instantiate` invokes `Awake` before returning for an active prefab, so the expected Inventory Identifier ID must already be serialized on that prefab when other `Awake` logic depends on it. The runtime name change still occurs before the new object's first `Start`, when `SaverBase` registers its full key.

### Resolve the player and bind the UI

After the player has registered:

```csharp
const uint playerID = 1;
const uint panelManagerID = 1;

var identifier = InventorySystemManager.GetInventoryIdentifier(playerID);
var inventory = identifier?.Inventory;
var currencyOwner = identifier?.CurrencyOwner;
var panelManager = InventorySystemManager.GetDisplayPanelManager(panelManagerID);

if (identifier != null && panelManager != null) {
    panelManager.SetPanelOwner(identifier.gameObject);
}
```

Use `Inventory.IsInitialized` as an Inventory readiness check. When a saved spawn is required, also wait for its Saver components to register before calling `SaveSystemManager.Load`.

UIS has no player-spawned event. The project spawner should publish that lifecycle signal after identity, UI ownership, and optional save restoration are complete. Useful V1 notifications after that point include `DisplayPanelManager.OnPanelOwnerAssigned`, `EventNames.c_OnPanelOwnerChange_GameObjectPanelOwner_DisplayPanelManager`, and the Inventory update/add/remove events documented on [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/).

---

<a id="page-ultimate-inventory-system-scene-transitions"></a>

# Scene Transitions

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/scene-transitions/)

A scene transition is an ownership decision: keep the UIS managers, player, and UI alive, or rebuild some of them and restore their state. Decide that boundary before adding save calls. Most projects are simplest with one persistent `Game` manager root and either one persistent player or an explicit save-and-respawn flow.

Released Ultimate Inventory System Version 1 does not include a scene-loading controller, loading-screen flow, player spawner, or network transition authority. Use Unity's scene APIs or the project's loader for those jobs, then connect UIS through the manager, identifiers, savers, and UI owner fields described here.

## Choose a scene model

| Model | What persists | How state moves | Best fit | Main tradeoff |
| --- | --- | --- | --- | --- |
| Complete setup in every scene | Nothing | Save before unload and load after the new player starts | Small projects and isolated scene testing | Manager, player, and UI configuration is duplicated across scenes |
| Persistent bootstrap | `Game`, and optionally player and UI roots | Objects keep their runtime state in memory | Most games with one global database and player | Every destination scene must omit duplicate managers and persistent objects |
| Persistent managers, recreated player/UI | `Game` only | Inventory Saver, Currency Owner Saver, stable IDs, and UI rebinding | Different player prefabs or scene-specific UI | Spawn and load order must be controlled |
| Smart loader or additive manager scene | A manager prefab or additive manager scene | Custom loader ensures managers exist before UIS objects initialize | Opening gameplay scenes directly in the Editor | Requires project code and an explicit initialization barrier |

Do not combine the models accidentally. For example, persisting the bootstrap player and also spawning a destination-scene player creates duplicate Inventory Identifier IDs, duplicate input, and competing UI owners.

## Set up one manager root

1. Open **Tools > Opsive > Ultimate Inventory System > Main Manager**.
2. Select **Setup**.
3. Under **Scene Setup**, select **Add Components**.
4. Select the resulting `Game` GameObject in the Hierarchy.
5. On **Inventory System Manager**, confirm that **Database** references the project database.
6. Enable **Dont Destroy On Load** when this is the one persistent manager root. The released Version 1 default is off.

Scene Setup creates or reuses `Game` and adds Inventory System Manager, Item Object Spawner, Scheduler, Object Pool, and Audio Manager. **Dont Destroy On Load** persists the entire `Game` GameObject, so all of those components persist with the manager.

When Save Setup adds Save System Manager and Inventory System Manager Item Saver to the same `Game` root, they persist with it as well. Save System Manager has no separate **Dont Destroy On Load** field.

Remove the same manager setup from destination and additive content scenes. A second Inventory System Manager destroys its own GameObject after detecting the existing singleton, which can also remove other components placed on that duplicate root. Early static UIS access can instead create an unconfigured `InventorySystemManager` GameObject with no database, so the configured root must initialize before Inventories, identifiers, UI, or project code use the static API.

For a bootstrap model, add the bootstrap scene to Unity's build list and enter the game through that scene. A gameplay scene opened directly needs an Editor helper or smart loader that establishes the same manager root before any UIS component runs.

## Decide whether the player persists

### Keep the same player

Persist the player's root through project code with `DontDestroyOnLoad`. Its Inventory, Item Collections, Currency Owner, Inventory Identifier, and saver components then remain the same runtime objects, so Bag, Equipment, Gold, and mutable Item values do not need a save/load cycle merely to cross a scene boundary.

Keep only one player instance. Destination scenes must not spawn another copy. If the UI also persists, its existing **Panel Owner** can remain the player. If the UI is recreated, match its **Panel Owner Inventory Identifier ID** to the persistent player's Inventory Identifier.

The Save System is still useful for checkpoints, application restarts, or recovery, even when the player persists between scenes.

### Recreate the player

1. In **Main Manager > Setup > Character Setup**, assign **Character Gameobject** and select **Add Components**.
2. Confirm that **Inventory Identifier > ID** is a stable, nonzero value. Its Version 1 default is `1`.
3. Under **Save Setup**, assign the player to **Object to save** and select **Add Components**.
4. Confirm that the player has Inventory Saver and Currency Owner Saver, and that the persistent `Game` root has Inventory System Manager Item Saver.
5. Keep **Additive** off on Inventory Saver for a normal replacement load.
6. Keep each saver's GameObject name, component type, and **Key** stable between the old and new player.

Save manually before unloading, then load only after the replacement player's savers have registered in `Start`:

```csharp
SaveSystemManager.Save(0);

// Load or activate the destination scene, create the player, and wait for its
// Inventory Saver and Currency Owner Saver to reach Start.

SaveSystemManager.Load(0);
```

This explicit flow is more predictable than relying only on scene callbacks. Use a project readiness signal from the spawner or loader rather than assuming one frame is always enough for an asynchronously created player.

## Configure automatic scene saving carefully

Save System Manager exposes these transition fields, all disabled by default:

| Inspector field | Transition behavior |
| --- | --- |
| **Auto Load On Initialize** | Reads slot `0` into the manager's cache during initialization; it does not make an unregistered saver apply its data |
| **Auto Load On Scene Loaded** | Calls `Load(0)` from Unity's `sceneLoaded` callback |
| **Auto Save On Scene Unloaded** | Calls `Save(0)` from Unity's `sceneUnloaded` callback |
| **Auto Save On Application Quit** | Writes slot `0` after opted-in savers refresh their data on quit |

All automatic routes use slot `0`. Use manual `Save(index)` and `Load(index)` calls for selectable slots.

![Save System Manager with Auto Load On Scene Loaded and Auto Save On Scene Unloaded enabled](https://opsive.com/wp-content/uploads/2020/12/SaveSystemManager.png)

The legacy crop shows the still-current transition toggles. The released Version 1 Inspector also includes file extension, metadata, item saver, and debug settings outside this crop.

Saver components register in `Start`, while Save System Manager listens to Unity scene callbacks. When the manager loads before a replacement saver registers, enable **Load On Start** so that saver applies the data already in the manager's cache. When a scene object may be destroyed before the manager's unload callback, enable **Save On Destroy** so it refreshes its cached data first.

![Inventory Saver with Load On Start enabled and Additive disabled](https://opsive.com/wp-content/uploads/2020/12/InventorySaverInspector.png?v=0dd8132cbfc1)

For an automatic recreated-player flow, use this combination:

- **Save System Manager > Auto Save On Scene Unloaded**: on;
- **Save System Manager > Auto Load On Scene Loaded**: on;
- each scene-bound saver **Save On Destroy**: on; and
- each replacement saver **Load On Start**: on.

This combination handles the common Version 1 timing gap, but a manual save before unload and a deliberate load after player readiness is easier to reason about and test.

## Connect the player and UI in order

The supported startup order is:

1. configured Inventory System Manager and database;
2. Save System Manager when persistence is used;
3. player Inventory, Currency Owner, and Inventory Identifier;
4. Display Panel Manager and other UI bindings; and
5. a save load after all replacement savers have registered.

Inventory Identifier registers itself in `Awake`. Its exact **ID** field defaults to `1` and cannot intentionally remain `0`. Display Panel Manager also defaults to **ID** `1`, a null **Panel Owner**, and **Panel Owner Inventory Identifier ID** `1`.

The UI supports either player/UI order:

- **Player first:** Display Panel Manager resolves the registered Inventory Identifier whose ID matches **Panel Owner Inventory Identifier ID**.
- **UI first:** Display Panel Manager registers itself, warns that no Panel Owner exists, and disables its GameObject. Add **Dynamic Panel Owner** to the later player and match its **Display Panel Manager ID** (default `1`); `SetPanelOwner` initializes and re-enables the UI.
- **Persistent UI, recreated player:** call `SetPanelOwner` for the new player, or use Dynamic Panel Owner with the matching manager ID. Do not leave the UI bound to the destroyed player.

UI panels, current selection, hotbar assignments, and grid ordering are separate concerns. Recreated UI starts from its configured defaults unless the relevant UI saver is present. See [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/) for Item View Slots Container, Inventory Grid, and Item Shape Grid data savers.

UIS does not display or coordinate a loading screen. Keep transition input blocking, fade timing, async operation progress, and scene activation in the project loader. Bind or re-enable UIS UI only after its player owner exists.

## Handle local multiplayer and networking

For local split-screen, share one Inventory System Manager and database. Give each player a unique Inventory Identifier ID and each UI a matching, unique Display Panel Manager ID and Panel Owner Inventory Identifier ID. Keep each UI root connected to its intended EventSystem through Event System Identifier. Recheck those relationships after respawning either player.

Released Version 1 scene and save systems are local singletons, not networking features. They do not synchronize scene activation, Inventories, Currency, runtime Item IDs, save slots, or UI owners. In a networked game, let the server or host own the transition and restored game state, then replicate authoritative results through the selected networking solution. Clients should not independently load the same local slot and assume the results will match.

## Editor checkpoint

Before entering Play Mode, confirm that:

- exactly one active Inventory System Manager owns the selected database;
- **Dont Destroy On Load** matches the chosen scene model;
- destination scenes do not contain duplicate `Game`, player, or persistent UI roots;
- the replacement player has Inventory, Currency Owner, Inventory Identifier, Inventory Saver, and Currency Owner Saver where required;
- Inventory Identifier IDs are stable, nonzero, and unique;
- saver GameObject names and **Key** values are stable and unique;
- **Load On Start** and **Save On Destroy** match the chosen automatic flow;
- Display Panel Manager IDs and **Panel Owner Inventory Identifier ID** values target the correct player;
- Dynamic Panel Owner targets the correct Display Panel Manager when the player appears after the UI; and
- every directly opened gameplay scene has a tested route that creates the configured managers first.

## Verify the transition in Play Mode

1. Enter the first scene and confirm that exactly one `Game` root and one player exist.
2. Put one Health Potion in **Bag**, an Iron Sword in **Equipment**, and set a known **Gold** balance.
3. Open the Inventory UI and confirm that it belongs to the expected Inventory Identifier ID.
4. Transition to the destination scene.
5. For a persistent player, confirm that the same Inventory and Currency Owner still contain the test state.
6. For a recreated player, save before unloading, wait for the replacement player and savers, load the slot, and confirm that Bag, Equipment, mutable Item values, and Gold return.
7. Open the recreated or rebound UI and confirm that selection and input affect the new player rather than the destroyed one.
8. Return to the first scene and confirm that no duplicate manager, player, UI, or EventSystem was created.
9. Test every gameplay scene both through the normal bootstrap route and through any supported direct-Editor route.
10. For split-screen, repeat the transition with both players and verify that each UI still targets its own identifier and EventSystem.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| The Console reports a null database on a generated `InventorySystemManager` | Project code or an Inventory Identifier accessed the static API before the configured manager initialized | Load or instantiate the configured manager first and move early UIS work later in the lifecycle |
| The destination's `Game` root disappears | A persistent Inventory System Manager already existed on another root | Remove the duplicate manager setup from destination and additive scenes |
| Bag or Equipment is empty after recreating the player | No save occurred, Inventory Saver is missing, or load ran before its `Start` | Add Save Setup, save before unload, then load after saver registration or enable **Load On Start** |
| Gold resets while Items return | Currency Owner Saver is missing or has a changed full key | Add the saver and keep its GameObject name and **Key** stable |
| Automatic unload saves old data | Scene-bound savers were destroyed before the manager callback | Enable **Save On Destroy** or save manually before unload |
| Automatic load does nothing | Replacement savers had not registered | Enable **Load On Start** or load from the spawner's explicit ready callback |
| The UI is disabled after loading | Display Panel Manager could not find its Panel Owner | Match **Panel Owner Inventory Identifier ID**, or add Dynamic Panel Owner to the spawned player |
| A persistent UI controls the previous player | Its Panel Owner still references the destroyed object | Call `SetPanelOwner` with the replacement player after spawning |
| A second player receives a different ID at runtime | Two live Inventory Identifiers attempted to register the same ID | Remove the duplicate player and assign unique, stable IDs before Play Mode |
| Split-screen selection moves in the wrong UI | The UI root resolves the wrong EventSystem or player ID | Correct Event System Identifier and the matching Inventory/Display Panel IDs |
| Opening a gameplay scene directly creates an empty manager | Its helper did not create the configured root before other UIS `Awake` calls | Move the loader earlier, instantiate the manager prefab synchronously, or enter through the bootstrap scene |
| The loading screen never appears or never closes | UIS has no transition/loading-screen coordinator | Drive it from the project scene loader and treat UIS readiness as one step in that flow |
| Network clients restore different state | Each client is using local UIS scene/save state independently | Make one server or host authoritative and replicate the restored result |

## Version 1 boundaries

- **Dont Destroy On Load** belongs to Inventory System Manager and persists its entire GameObject.
- Inventory System Manager is one global runtime register; it is not a separate world per scene or player.
- A premature static access can create an empty manager automatically.
- Inventory Identifiers register in `Awake`; savers register later in `Start`.
- Automatic scene save/load uses slot `0` and Unity's scene callbacks.
- Stable database IDs, Item Collection order, saver full keys, Inventory Identifier IDs, and UI IDs are part of the persistence contract.
- No built-in component waits for an async player spawn, switches scenes, renders loading progress, migrates save data, or synchronizes a network session.

## Related pages

- [Inventory System Manager](https://opsive.com/support/documentation/ultimate-inventory-system/inventory-system-manager/) covers manager creation, startup, and **Dont Destroy On Load**.
- [Spawn Player](https://opsive.com/support/documentation/ultimate-inventory-system/spawn-player/) covers Inventory Identifier and UI ordering for a runtime-created player.
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/) covers saver setup, slot behavior, and migration boundaries.
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/) explains Bag, Equipment, and Item Collection ownership.
- [Currency](https://opsive.com/support/documentation/ultimate-inventory-system/currency/) explains the Currency Owner and Gold state.
- [Display Panel Manager](https://opsive.com/support/documentation/ultimate-inventory-system/ui/display-panel-manager/) covers Panel Owner and panel lifecycle.
- [Split Screen Co-op UI](https://opsive.com/support/documentation/ultimate-inventory-system/input/split-screen-co-op-ui/) covers per-player IDs and EventSystems.
- [Opsive Character Controllers](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/opsive-character-controllers/) covers the character integration and Inventory Bridge Saver.

## Developer details

### Rebind a recreated player

After the configured manager and replacement player exist, the public V1 lookups can reconnect the UI:

```csharp
const uint playerID = 1;
const uint panelManagerID = 1;

var player = InventorySystemManager.GetInventoryIdentifier(playerID);
var panelManager = InventorySystemManager.GetDisplayPanelManager(panelManagerID);

if (player != null && panelManager != null) {
    panelManager.SetPanelOwner(player.gameObject);
}
```

`DisplayPanelManager.OnPanelOwnerAssigned` is the component's C# notification. UIS also executes `EventNames.c_OnPanelOwnerChange_GameObjectPanelOwner_DisplayPanelManager` after assigning a non-null owner. The Save System lifecycle exposes the slot-index events documented on [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/). UIS does not send a dedicated scene-transition-complete event; use the project loader or Unity `SceneManager` callback as the outer lifecycle.

### Allow gameplay scenes to start directly

The following legacy example is project code, not a supplied UIS component. Configure its Script Execution Order to `-500`, place it in directly opened scenes, and assign either a manager prefab or a manager scene, not both. The prefab route initializes synchronously when instantiated. For an additive manager scene, keep other UIS content inactive until that scene has loaded and its manager has initialized.

```csharp
public class SceneLoaderManagerExample : MonoBehaviour
{
   [SerializeField] protected GameObject m_ManagerPrefab;
   [SerializeField] protected int m_ManagerSceneBuildIndex= - 1;

   private void Awake()
   {
       if (!InventorySystemManager.IsNull) {
           //This gameobject is only needed to load the managers remove it once it is done.
           Destroy(gameObject);
           return;
       }

       // Instantiate a prefab of managers (Make sure to DontDestroyOnLoad).
       if (m_ManagerPrefab != null) {
           var managers = Instantiate(m_ManagerPrefab);
           //Optional don't destroy on load here instead of within the manager components
           //DontDestroyOnLoad(managers);
       }

       //Instead of a prefab load an additive scene with the manager (Make sure to DontDestroyOnLoad).
       if (m_ManagerSceneBuildIndex >= 0) {
           SceneManager.LoadScene(m_ManagerSceneBuildIndex, LoadSceneMode.Additive);
       }

       //This gameobject is only needed to load the managers remove it once it is done.
       Destroy(gameObject);
   }
}
```

The example retains ordinary space indentation so it is safe to copy into a source file. Add the required `UnityEngine`, `UnityEngine.SceneManagement`, and UIS namespaces in the project script.

---

<a id="page-ultimate-inventory-system-integrations"></a>

# Integrations

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/)

Integrations connect Ultimate Inventory System to input, character, visual-scripting, quest, dialogue, audio, and localization tools without replacing the database or Inventory workflow.

## Available integrations

| Integration | What to verify first |
| --- | --- |
| [Behavior Designer Pro](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/behavior-designer/)<br>[Asset Store](https://assetstore.unity.com/packages/tools/visual-scripting/behavior-designer-pro-dots-powered-behavior-trees-298743?aid=1100lGdc) | A behavior-tree task detects or adds a Health Potion in the agent's Inventory. |
| [Bolt](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/bolt/)<br>[Package documentation](https://docs.unity3d.com/Manual/com.unity.visualscripting.html) | A legacy graph can expose the `Opsive.UltimateInventorySystem` assembly and invoke a simple Inventory API. |
| [Dialogue System](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/dialogue-system/)<br>[Asset Store](https://assetstore.unity.com/packages/tools/behavior-ai/dialogue-system-for-unity-11672?aid=1100lGdc) | A dialogue condition reads the player's Inventory and a response changes the expected value. |
| [Input System](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/input-system/)<br>[Package documentation](https://docs.unity3d.com/Packages/com.unity.inputsystem@latest) | The player opens, navigates, and closes a panel with the intended device. Use the current [Input](https://opsive.com/support/documentation/ultimate-inventory-system/input/) page as the primary setup route. |
| [Master Audio](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/master-audio/)<br>[Asset Store](https://assetstore.unity.com/packages/tools/audio/master-audio-2022-aaa-sound-212962?aid=1100lGdc) | One inventory or menu action plays through Master Audio instead of a Unity Audio Source. |
| [PlayMaker](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/playmaker/)<br>[Asset Store](https://assetstore.unity.com/packages/tools/visual-scripting/playmaker-368?aid=1100lGdc) | An action adds a Health Potion or Gold and the finite state machine reaches its success path. |
| [Quest Machine](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/quest-machine/)<br>[Asset Store](https://assetstore.unity.com/packages/tools/game-toolkits/quest-machine-39834?aid=1100lGdc) | A quest condition detects the required Item and its reward reaches the correct Inventory. |
| [Save System Integration](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/save-system-integration/) | Current provider named by the download. One save and load restores the Inventory exactly once without duplicate Items. |
| [State Designer](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/state-designer/)<br>[Asset Store](https://assetstore.unity.com/packages/tools/visual-scripting/state-designer-dots-powered-finite-state-machines-369152?aid=1100lGdc) | A transition detects one Health Potion and its State runs the configured Item Action. |
| [Ultimate Character Controller](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/opsive-character-controllers/)<br>[Asset Store](https://assetstore.unity.com/packages/tools/game-toolkits/ultimate-character-controller-233710?aid=1100lGdc) | The character equips an Iron Sword from its Inventory and the expected item action runs. |
| [Unity Localization](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/unity-localization/)<br>[Package documentation](https://docs.unity3d.com/Packages/com.unity.localization@latest) | Changing locale updates a Health Potion name and description without showing the source-language value afterward. |

## Understand the installation routes

- **Downloaded from Opsive:** get the bridge that matches the installed product versions from [Opsive Downloads](https://opsive.com/downloads/). Optional bridges appear in the project only after import.
- **Provided by Opsive Shared:** Unity Input System support and the `CharacterInput.inputactions` starting asset are part of the shared input workflow and do not use a separate Inventory bridge.
- **Provider-maintained:** Dialogue System and Quest Machine support files are maintained by Pixel Crushers. Use the provider route named by the current download when its supported versions or saver integration changes.
- **No dedicated current package:** the legacy Bolt route exposes the public runtime assembly through reflection. Bolt is now Unity Visual Scripting; do not apply an old DLL workaround unless the conflicting file actually exists.

The online catalog also lists Control Freak, Easy Touch, InControl, and Rewired. Their natural setup lives on [Input](https://opsive.com/support/documentation/ultimate-inventory-system/input/), because these bridges replace the shared `IPlayerInput` provider rather than adding Inventory data or Item Actions.

## Install an integration

Open **Tools > Opsive > Ultimate Inventory System > Main Manager** and select **Integrations**. Download optional bridges from [Opsive Downloads](https://opsive.com/downloads/); they are not stored in the base product's Integrations folder before import.

An integration may add an **Integration Inspector** or may be configured through its own action, task, component, or sample. Its page below identifies unusual version requirements, provider-owned downloads, and the first useful connection.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| The Integrations page is empty | Check editor network access and whether **Available Integrations** is still loading. | Download the bridge directly from [Opsive Downloads](https://opsive.com/downloads/); an empty online list does not mean the runtime is missing. |
| An installed integration does not appear under Integration Inspectors | Check whether that integration defines an Ultimate Inventory System `IntegrationInspector`. | Follow its child page or demo workflow. Not every supported integration adds a custom Inspector. |
| A Bolt or Visual Scripting graph cannot find Ultimate Inventory System | Check the graph tool's assembly or node-library settings for `Opsive.UltimateInventorySystem`. | Add the runtime assembly and regenerate its unit or node database. Do not apply the legacy Antlr workaround unless a real duplicate DLL exists. |
| Dialogue or Quest state changes but is lost after loading | Check the Pixel Crushers Ultimate Inventory System saver bridge and whether both systems use the intended save owner. | Configure one supported bridge path and verify a fresh save before migrating existing data. |
| Input can click a menu but Ultimate Inventory System shortcuts do not run | Check for one concrete Opsive `IPlayerInput`, matching action names, and the correct EventSystem input module. | Complete the Input workflow, then retest the integration with one device and one player. |

## Related pages

- [Input](https://opsive.com/support/documentation/ultimate-inventory-system/input/)
- [Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/)
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/)
- [Audio](https://opsive.com/support/documentation/ultimate-inventory-system/audio/)
- [Save system](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)
- [Inventory database import and export](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/import-export/)

## Developer and version reference

The released Version 1 runtime assembly is `Opsive.UltimateInventorySystem`. Reflection-based tools should expose that assembly rather than editor or test assemblies.

The Version 1 Main Manager discovers installed integration Inspectors by finding non-abstract `IntegrationInspector` implementations in loaded assemblies. Its **Available Integrations** tab obtains a current list from Opsive at editor time; that online catalog is separate from the bridge packages available through Opsive Downloads.

---

<a id="page-ultimate-inventory-system-integrations-behavior-designer"></a>

# Behavior Designer Pro

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/behavior-designer/)

The [Behavior Designer Pro](https://assetstore.unity.com/packages/tools/visual-scripting/behavior-designer-pro-dots-powered-behavior-trees-298743?aid=1100lGdc) integration lets an agent use Ultimate Inventory System data in its decisions. A behavior tree can check whether an Inventory contains a Health Potion, use that Item, compare Gold, exchange Items with another Inventory, open a panel, or request a save without a custom bridge component.

This page covers the integration for released Ultimate Inventory System Version 1 and the Graph Designer-based Behavior Designer Pro. It does not cover the original Behavior Designer package or Ultimate Inventory System Version 2; those products use different task and data APIs.

## Before you begin

- Install released Ultimate Inventory System Version 1 and confirm that its Inventory works without Behavior Designer Pro.
- Install Behavior Designer Pro and let Unity compile before importing the integration.
- Create the Item Definitions, Item Collections, Currency, and Item Actions that the tree will use. The integration refers to that existing Ultimate Inventory System data; it does not create a database for you.
- Keep a backup or source-control checkpoint before replacing an older copy of the integration.

## Install the integration

1. Sign in to [Opsive Downloads](https://opsive.com/downloads/) and download the Behavior Designer Pro integration for Ultimate Inventory System. The bridge is not included in either base product's Integrations folder before this download.
2. Import the downloaded package after both products have compiled successfully. Importing it creates the integration files in the project.
3. Confirm that Unity installs the task sources under `Assets/Opsive/BehaviorDesigner/Integrations/UltimateInventorySystem/Tasks` and finishes compiling without errors.
4. Open the Behavior Designer Pro Task List and search for **Add Item**, **Has Item With Definition**, and **Use Item From Inventory**. The package is ready when those Ultimate Inventory System tasks are available.

The integration adds tasks, not a scene component. Configure each task in the normal Behavior Designer Pro Task Inspector.

## Create a Health Potion decision

This small tree uses a Health Potion when the agent has one and lets a Selector choose another branch when it does not.

1. Put the behavior tree on the same GameObject as the Ultimate Inventory System **Inventory**. For this example, that GameObject also needs an **Item User**.
2. Add a Selector. Give its first branch a Sequence and reserve the second branch for the agent's normal fallback behavior.
3. Add **Has Item With Definition** to the Sequence. Set **Item Definition** to **Health Potion** and **Amount** to `1`. Leave **Item Collection Purpose** at **None** to search the whole Inventory, or select the purpose of the collection that should be checked.
4. Add **Use Item From Inventory** after the condition. Set **Item Definition** to **Health Potion**, assign the **Item Action Set** that contains the potion's consume action, and enter its **Action Index**. Set **Amount** to `1` and enter the exact **Item Collection Name** when the action should use a specific collection.
5. Leave **Target Game Object** empty when the tree and Inventory share a GameObject. Assign another GameObject or a GameObject Shared Variable only when that target owns all components required by the task.

When the condition succeeds, the Sequence runs the configured Item Action. If the Inventory does not contain the requested amount, the condition fails and the Selector tries its next branch. **Use Item From Inventory** reports the result returned by the assigned Item Action Set, so the task can still fail when the Item exists but its action cannot run.

## Choose a task for the outcome

### Check or change Items

| Task | Important fields and result |
| --- | --- |
| **Add Item** | **Amount**, **Item Definition**, and **Item Collection Purpose**. Creates a runtime Item from the definition and succeeds only when the full requested amount is added. |
| **Remove Item** | **Amount**, **Item Definition**, and **Item Collection Purpose**. The released task succeeds when it removes any amount, even if that is less than requested. Keep the tree on the Inventory GameObject for this task. |
| **Has Item With Definition** | Checks an **Item Definition** and **Amount**. **Check Inherently** includes child definitions; **Count Stacks** counts stacks instead of the total amount in those stacks. |
| **Has Item With Category** | Checks an **Item Category** and **Amount**. The inheritance, stack-counting, and collection-purpose choices work like the definition task. |
| **Compare Item Amount** | Compares an **Item Definition** amount with **Equals To**, **Greater Than**, or **Greater Or Equals To**. See the released-version comparison note below before using a smaller-than option. |
| **Exchange Item Between Inventories** | Assign **Other Inventory Game Object**, **Item Definition**, and **Amount**. Enable **Give Item** to move from the target Inventory to the other Inventory; disable it to move in the other direction. |
| **Drop Item From Inventory** | Assign **Item Object Spawner ID**, **Item Definition**, and **Amount**. **Remove Item On Drop** decides whether the source Inventory loses the Item. Keep the tree on the Inventory GameObject and use a valid spawner ID. |
| **Use Item From Inventory** | Assign **Item Action Set**, **Action Index**, **Item Definition**, and the intended **Item Collection Name**. The target needs both an Inventory and an Item User. |
| **Use Item Object** | Set **Item Object Slot Index** and **Action Index**. The target needs a **Usable Equipped Items Handler**. |

For tasks with **Item Collection Purpose**, **None** searches the whole Inventory. **Main**, **Equipped**, and the other values limit the operation to the collection with that purpose.

### Check or change Currency

| Task | Important fields and result |
| --- | --- |
| **Has Currency** | Set **Currency Amounts** to the required Gold or other currencies. The target needs a **Currency Owner**. |
| **Add Currency** | Adds the configured **Currency Amounts** to the target Currency Owner and returns its success result. |
| **Remove Currency** | Removes the configured **Currency Amounts** and fails when the Currency Owner cannot pay the complete amount. |
| **Compare Currency** | Compares **Currency Amounts** on the behavior tree's GameObject. Use the equality or greater-than choices in the released package. |

### Interact, control UI, and save

| Task | Important fields and result |
| --- | --- |
| **Interact** | The target needs both **Inventory** and **Inventory Interactor** components. The task requests an interaction and then succeeds; verify the world interaction separately. |
| **Open Close Panel** | Set **Display Panel Manager ID** and the exact **Panel Unique Name**. **Toggle** takes precedence; otherwise **Close** chooses between opening and closing, and **Close Selected** provides a close fallback. |
| **Save**, **Load**, and **Delete Save** | Set **Save Index**. These tasks request the Ultimate Inventory System Save System operation and return success immediately, so confirm the saved or loaded result rather than relying only on the node color. |

## Use constants and Shared Variables

Every integration field is a Behavior Designer Pro Shared Variable. Enter a constant directly in the Task Inspector for a fixed Health Potion, amount, or target. Bind the field to an existing Shared Variable when another task needs to provide or change the value at runtime.

- **Target Game Object** defaults to the GameObject running the behavior tree on target-aware tasks.
- **Item Definition** identifies Ultimate Inventory System database data. Item tasks then find or create the corresponding runtime Item.
- **Currency Amounts** can contain one or more Currency values that must be handled together.
- **Check Inherently** includes child Item Definitions or Item Categories in the match.
- **Count Stacks** compares the number of matching stacks instead of adding the Item amounts in those stacks.

See [Behavior Designer Pro Shared Variables](https://opsive.com/support/documentation/behavior-designer-pro/variables/) for the editor workflow used to bind a field.

## Editor checkpoint

Before entering Play Mode, confirm all of the following:

- The Task List contains all 18 Ultimate Inventory System task classes and the Console has no compilation errors.
- The behavior tree is on the intended Inventory GameObject, especially when it uses **Remove Item**, **Drop Item From Inventory**, or **Compare Currency**.
- Each Item Definition and Item Category comes from the same Inventory Database used by the target Inventory.
- Every specific collection purpose, collection name, panel name, manager ID, spawner ID, slot index, and action index matches the configured Ultimate Inventory System object.
- The target owns the extra component required by the task, such as Currency Owner, Item User, Inventory Interactor, or Usable Equipped Items Handler.

## Verify in Play Mode

1. Give the agent one Health Potion and run the example tree. Confirm that **Has Item With Definition** succeeds, **Use Item From Inventory** runs, and the configured Item Action produces its visible result.
2. Inspect the Inventory after the action. Confirm that the expected amount or runtime Item state changed; a green behavior-tree node alone is not sufficient verification.
3. Remove the Health Potion and run the tree again. The condition should fail and the Selector should enter its fallback branch.
4. Test a required component failure deliberately on a copy of the agent. The affected task should not be treated as a substitute for validating the Inventory, Item User, Currency Owner, manager, or handler setup.
5. If the tree saves or loads, change a known Item amount, use the same **Save Index**, and verify that a fresh load restores the actual Inventory state.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| Ultimate Inventory System tasks do not appear in the Task List | Check the Console, the imported task folder, and whether the project uses Behavior Designer Pro rather than the original Behavior Designer package. | Resolve the first compile error, remove duplicate integration scripts, and import the package built for Ultimate Inventory System Version 1 and Behavior Designer Pro. |
| An Item or Currency task fails immediately | Check **Target Game Object** and the required Inventory or Currency Owner component. | Put the tree on the owning GameObject for the first test, then assign a valid target only after the local workflow passes. |
| Remove or Drop works only on the tree owner | The released **Remove Item** and **Drop Item From Inventory** task sources operate on the behavior tree's GameObject even though they expose **Target Game Object**. | Keep the behavior tree on the Inventory GameObject for those tasks, or update the integration source before targeting another object. |
| An Item condition reports an unexpected amount | Check **Item Collection Purpose**, **Check Inherently**, and **Count Stacks**. | Search the whole Inventory with **None** first, then add the intended collection, inheritance, or stack restriction one at a time. |
| Use Item From Inventory finds the Item but fails | Check Item User, Item Action Set, Action Index, Item Collection Name, and the action's own requirements. | Assign the same working action set used by the Ultimate Inventory System UI, verify its index, and test that action directly before running the tree. |
| A panel task turns green but no panel changes | Check **Display Panel Manager ID**, **Panel Unique Name**, and whether **Toggle** or **Close** is enabled. | Copy the manager ID and unique name from the scene configuration and choose one intended operation. |
| A smaller-than comparison succeeds for the wrong amount | The inspected Version 1 integration does not evaluate the numeric value in the **Smaller Than** and **Smaller Or Equals To** paths of **Compare Item Amount** and **Compare Currency**. | Use **Has Item**, equality, or a greater-than comparison, or update the integration before relying on a smaller-than branch. |
| Save, Load, or Delete Save turns green without the expected data change | These tasks return success immediately after requesting the Save System operation. | Verify the Save Index, registered save objects, stored file, and restored Inventory state through the [Save system workflow](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/). |

## Related pages

- [Integrations](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/)
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/)
- [Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/)
- [Currency](https://opsive.com/support/documentation/ultimate-inventory-system/currency/)
- [Interaction system](https://opsive.com/support/documentation/ultimate-inventory-system/interaction-system/)
- [Save system](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)
- [Behavior Designer Pro Actions](https://opsive.com/support/documentation/behavior-designer-pro/concepts/tasks/action/)
- [Behavior Designer Pro Conditionals](https://opsive.com/support/documentation/behavior-designer-pro/concepts/tasks/conditional/)

## Developer and version reference

The integration source verified for this page targets Ultimate Inventory System `1.3.0` and Opsive Behavior Designer `3.1.0`. It is compiled for the Graph Designer task model and uses `Opsive.GraphDesigner.Runtime.Variables.SharedVariable<T>`. It is not source-compatible with the original Behavior Designer task API or with Ultimate Inventory System Version 2 currency and inventory types.

The package contains these 18 task classes: `AddCurrency`, `AddItem`, `CompareCurrency`, `CompareItemAmount`, `DeleteSave`, `DropItemFromInventory`, `ExchangeItemBetweenInventories`, `HasCurrency`, `HasItemWithCategory`, `HasItemWithDefinition`, `Interact`, `Load`, `OpenClosePanel`, `RemoveCurrency`, `RemoveItem`, `Save`, `UseItemFromInventory`, and `UseItemObject`.

Most target-aware classes inherit Behavior Designer Pro's `TargetGameObjectAction` or `TargetGameObjectConditional`, which resolves an empty target to the behavior tree's GameObject. In the inspected package, `RemoveItem` and `DropItemFromInventory` declare a target field but read the tree GameObject, while `CompareCurrency` has no target field. Keep those operations on the Inventory or Currency Owner GameObject unless you maintain a corrected integration build.

---

<a id="page-ultimate-inventory-system-integrations-bolt"></a>

# Bolt

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/bolt/)

Use this page only when maintaining an existing **legacy Bolt** project with Ultimate Inventory System Version 1. Ultimate Inventory System does not ship a Bolt installer or custom Bolt units. The legacy integration works by asking Bolt to reflect the public `Opsive.UltimateInventorySystem` runtime assembly.

For a new project, do not interpret this page as dedicated support for the current Unity Visual Scripting package. Unity replaced Bolt's Setup Wizard with Visual Scripting settings, while the released Ultimate Inventory System Version 1 project does not include or test a Visual Scripting integration package. Treat that combination as a project-owned compatibility evaluation.

## Choose the compatible route

| Project | Recommendation |
| --- | --- |
| Existing Bolt graph with the Bolt Setup Wizard | Continue with the legacy reflection workflow below and test the exact Bolt version already used by the project. |
| Current Unity Visual Scripting | Prefer a supported integration or a small project-owned adapter. If you evaluate reflection, use **Edit > Project Settings > Visual Scripting > Node Library** and **Type Options**, then regenerate the Node Library. This is not a shipped Ultimate Inventory System integration. |
| Ultimate Inventory System Version 2 | Use Version 2 documentation and APIs. Version 1 types and member signatures are not a compatibility promise. |

Do not remove `Antlr3.Runtime.dll` from a current Ultimate Inventory System Version 1 installation. The released package no longer contains that DLL or an `UltimateInventorySystem/Plugins` folder. Only investigate a duplicate assembly when Unity identifies real files at two specific paths.

## Configure legacy Bolt

1. Install and compile Ultimate Inventory System Version 1 and the project's existing Bolt version before changing the Bolt unit database.
2. Open the **Bolt Setup Wizard** used by that legacy version.
3. In **Assemblies**, add `Opsive.UltimateInventorySystem`.
4. In **Types**, add only the Ultimate Inventory System types the graph needs. A practical first set is `Inventory`, `ItemDefinition`, `ItemInfo`, and `ItemAmount`.
5. Finish the wizard and let Bolt rebuild its reflected unit database.
6. Search the graph's unit picker for `Inventory.GetItemAmount` and `Inventory.AddItem`. Do not proceed to a production graph until both members appear with the expected parameter types.

There is no additional Ultimate Inventory System `.unitypackage` to import for this route. The runtime assembly is auto-referenced and its public members are the integration surface.

## Build a safe first graph

Use a one-Item test before reflecting Shop, crafting, save, or UI APIs.

1. Add an Ultimate Inventory System **Inventory** to the GameObject that owns the graph and make sure it uses the intended Inventory Database.
2. Create or select the **Health Potion** Item Definition in that database.
3. In Bolt, get the `Inventory` component from the graph owner.
4. Call `Inventory.GetItemAmount(ItemDefinition, bool, bool)` with **Health Potion**, `false` for **Check Inherently**, and `false` for **Unique**. Store or display the returned integer.
5. Call `Inventory.AddItem(ItemDefinition, int)` with **Health Potion** and `1`.
6. Read the returned `ItemInfo.Amount`. Treat an amount of `1` as the successful result; a flow connection alone does not prove that the Inventory accepted the Item.
7. Call `GetItemAmount` again and confirm that the visible Inventory and returned count both increased by one.

This graph verifies component resolution, database references, overload selection, return-value handling, and reflected units without relying on a dedicated adapter.

## Use the reflected APIs deliberately

Ultimate Inventory System Version 1 does not define Bolt-specific unit names. Bolt generates ordinary member units from public C# members, and their presentation can vary with the Bolt version. Start with these source-verified signatures:

| Outcome | Version 1 public member | Result to inspect |
| --- | --- | --- |
| Find a definition by name | `InventorySystemManager.GetItemDefinition(string)` | An `ItemDefinition`, or null when the name is not registered. |
| Count an Item | `Inventory.GetItemAmount(ItemDefinition, bool checkInherently, bool unique)` | The matching integer amount. |
| Add an Item | `Inventory.AddItem(ItemDefinition, int amount)` | `ItemInfo`; its `Amount` is the amount actually added. |
| Remove an Item | `Inventory.RemoveItem(ItemDefinition, int amount)` | `ItemInfo`; its `Amount` is the amount actually removed. |
| Inspect an Item result | `ItemInfo.Amount`, `ItemInfo.Item`, and `ItemInfo.ItemCollection` | The result data returned by the Inventory operation. |

Reflection does not guarantee that every public generic, delegate, `ref`, nullable, or collection-heavy member becomes a convenient Bolt unit. Prefer simple overloads with explicit types. Add `ItemInfo` and `ItemAmount` to Bolt's Types list only when a graph needs their ports or members; exposing every Ultimate Inventory System type makes the unit picker harder to use and does not create a supported wrapper.

## Handle Inventory events

The package does not ship Bolt event units. Ultimate Inventory System Version 1 raises its Inventory notifications through `Opsive.Shared.Events.EventHandler`, not through Bolt Custom Events.

For a legacy graph, prefer an explicit call followed by checking its returned `ItemInfo` or integer. If the graph must react to changes made elsewhere, add a project-owned adapter that registers for the required Ultimate Inventory System event and forwards a simple signal to Bolt. The commonly used source events are:

- `Inventory_OnUpdate` with no payload.
- `Inventory_OnAdd_ItemInfo_ItemStack` with `ItemInfo` and `ItemStack` payloads.
- `Inventory_OnRemove_ItemInfo` with an `ItemInfo` payload.

The adapter must register and unregister with the same target Inventory during the Unity lifecycle. See [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/) before exposing these notifications to a graph.

## Editor checkpoint

Before entering Play Mode, confirm all of the following:

- The Console is clear before and after rebuilding Bolt's unit database.
- `Opsive.UltimateInventorySystem` appears once in Bolt's Assemblies list.
- The intended overloads show `ItemDefinition`, Boolean options, and integer amounts rather than similarly named `Item`, `ItemInfo`, or string overloads.
- The graph's Inventory and Health Potion references come from the active Ultimate Inventory System Version 1 database.
- No current Ultimate Inventory System file has been deleted or renamed to follow the obsolete Antlr instruction.

## Verify in Play Mode

1. Start with zero Health Potions and display the result of `GetItemAmount`; it should be `0`.
2. Trigger `AddItem` once and inspect the returned `ItemInfo.Amount`; it should be `1`.
3. Confirm that the Inventory UI or Inspector shows one Health Potion and that a second count returns `1`.
4. Try a null Item Definition or an Inventory restriction on a test object. The returned result should reveal that nothing was added.
5. Build a Development Build for the target platform. Reflection and generated unit databases can behave differently in an AOT or stripped build, so an editor-only test is not sufficient.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| No Ultimate Inventory System members appear in Bolt | Check the exact Assemblies entry and the first Console error. | Add `Opsive.UltimateInventorySystem`, resolve compilation, and rebuild Bolt's unit database. |
| An Ultimate Inventory System type cannot be selected for a port or variable | Check whether that exact type is present in Bolt's Types list. | Add only the required type, such as `ItemDefinition` or `ItemInfo`, then rebuild the unit database. |
| Several `AddItem` or `GetItemAmount` units look identical | Check the full parameter types and return type. | Use the `ItemDefinition` overload documented above and expose all input ports before connecting the graph. |
| Add Item runs but the Inventory does not change | Inspect the returned `ItemInfo.Amount`, the active database, and Inventory restrictions. | Use a registered Item Definition, verify the target Inventory, and handle a zero return amount as failure. |
| The graph cannot receive an Inventory event | Check whether the graph expects a Bolt Custom Event that Ultimate Inventory System never sends. | Read the operation's return value or create a lifecycle-safe adapter for the exact Ultimate Inventory System event. |
| Unity reports a duplicate Antlr assembly | Inspect the Console for both concrete DLL paths. | Back up the project and resolve the actual third-party duplicate according to its provider. Do not delete a nonexistent Ultimate Inventory System DLL or rename arbitrary assemblies. |
| Instructions mention Node Library instead of Setup Wizard | Check whether the project uses current Unity Visual Scripting rather than legacy Bolt. | Follow Unity's [Visual Scripting project settings](https://docs.unity3d.com/Packages/com.unity.visualscripting@1.8/manual/vs-configuration.html) and treat Ultimate Inventory System reflection as a custom compatibility test. |
| The graph works in the Editor but not in a build | Check generated units, AOT support, managed stripping, and Development Build logs. | Regenerate the graph tool's unit/AOT data and preserve only the Ultimate Inventory System members the graph actually reflects. |

## Related pages

- [Integrations](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/)
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/)
- [Inventory System Manager](https://opsive.com/support/documentation/ultimate-inventory-system/inventory-system-manager/)
- [Items](https://opsive.com/support/documentation/ultimate-inventory-system/item/)
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/)
- [Create an Inventory Database](https://opsive.com/support/documentation/ultimate-inventory-system/getting-started/new-database/)

## Developer and version reference

The archived Ultimate Inventory System Version 1 `master` source verified for this page is package version `1.3.0`. Its runtime assembly definition is named `Opsive.UltimateInventorySystem`, is auto-referenced, and depends on Opsive Shared. That development checkout contains historical installers for Dialogue System, Localization, PlayMaker, and Quest Machine, but no Bolt or Unity Visual Scripting installer. Customer projects should obtain current optional bridges from [Opsive Downloads](https://opsive.com/downloads/); they are not present in the installed product's Integrations folder before download. The released project also declares no `com.unity.visualscripting` package dependency.

Ultimate Inventory System removed its NCalc and `Antlr3.Runtime.dll` dependencies on April 6, 2021. Current Version 1 master contains no precompiled DLL in the Ultimate Inventory System package, so the legacy instruction to remove `Assets/Opsive/UltimateInventorySystem/Plugins/Antlr3.Runtime.dll` is not valid for this release.

The exact event constants above are declared in `Opsive.UltimateInventorySystem.Core.EventNames` and dispatched through `Opsive.Shared.Events.EventHandler`. They are not generated Bolt event units. A custom adapter should register and unregister the same delegate against the same Inventory target and expose only the simple payload required by the graph.

---

<a id="page-ultimate-inventory-system-integrations-dialogue-system"></a>

# Dialogue System

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/dialogue-system/)

The [Dialogue System](https://assetstore.unity.com/packages/tools/behavior-ai/dialogue-system-for-unity-11672?aid=1100lGdc) integration lets a conversation read or change Ultimate Inventory System Items and Currency. A merchant can offer a response only when the player owns a Health Potion, remove that potion, award Gold, or open an Ultimate Inventory System Shop without duplicating Inventory data inside the dialogue database.

Pixel Crushers maintains this integration for Dialogue System 2.x. Use a bridge package that explicitly matches released Ultimate Inventory System Version 1 and the installed Dialogue System release. The installer does not declare a minimum or maximum Dialogue System version, and Pixel Crushers updates it independently of Ultimate Inventory System, so a package that merely has the same filename is not enough evidence of compatibility.

## Before you begin

- Install and compile Ultimate Inventory System Version 1 and Dialogue System 2.x before importing the bridge.
- Confirm that the player's Ultimate Inventory System Inventory and Currency Owner work outside a conversation.
- Give every Item Definition, Currency, Item Collection, shop object, and scene owner a stable, exact name. The Lua bridge resolves these names at runtime.
- Decide which product owns saving before adding a saver. Do not let both systems write and restore the same state independently.

Sign in to [Opsive Downloads](https://opsive.com/downloads/) and download the Dialogue System integration after both products compile. The bridge is not included in the base product's Integrations folder before download; importing the matched package creates the integration files in the project. See the [Pixel Crushers Ultimate Inventory System integration manual](https://www.pixelcrushers.com/dialogue_system/manual2x/html/uis.html) for provider-specific changes.

## Install and enable the bridge

1. Back up the project and remove an older duplicate of the two **Opsive UIS Support** folders if you are replacing the integration.
2. Import the matched `DialogueSystem.unitypackage` after both products compile.
3. Confirm that Unity installs support scripts beneath these folders:
   - `Assets/Pixel Crushers/Common/Third Party Support/Opsive UIS Support`
   - `Assets/Pixel Crushers/Dialogue System/Third Party Support/Opsive UIS Support`
4. Select the persistent **Dialogue Manager** GameObject and add **UIS Lua** from **Pixel Crushers > Dialogue System > Third Party > Opsive > UIS Lua**.
5. Leave **Unregister On Disable** off for a persistent Dialogue Manager. Enable it only when this component should remove all six Ultimate Inventory System Lua functions when disabled.
6. Open the Dialogue Editor and confirm that the Lua wizard lists the Ultimate Inventory System condition and script functions supplied by `UIS Lua Function Info.asset`.

The bridge uses the existing Ultimate Inventory System Inventory Database. It does not copy Items, Currency, or Shops into the Dialogue System database.

## Create an Item-for-Gold conversation

This example shows a response only when the player owns a Health Potion, then trades one potion for five Gold.

1. Tag the player GameObject **Player**. Put its Ultimate Inventory System **Inventory** and **Currency Owner** on that object or one of its children.
2. In a response dialogue entry, enter this Lua in **Conditions**:

```lua
uisGetItemAmount("Health Potion", "") >= 1
```

3. In the same entry's **Script**, remove the potion and award the Gold:

```lua
uisRemoveItem("Health Potion", 1, "", "")
uisAddCurrency("Gold", 5, "")
```

4. Add another response for the case where the player has no potion, or let the unavailable response remain hidden according to the conversation's response settings.
5. Use the exact Ultimate Inventory System names **Health Potion** and **Gold**. The empty owner strings tell the verified bridge to find a GameObject tagged **Player**.
6. After the script runs, check the Inventory and Currency display. The change functions do not return a success value to Lua, so visible state or a follow-up get function is the reliable result.

This keeps the dialogue decision in Dialogue System while Ultimate Inventory System remains the source of truth for the Item and Gold balances.

## Use the Lua functions

| Goal | Function | Important behavior |
| --- | --- | --- |
| Read an Item amount | `uisGetItemAmount(itemName, inventoryName)` | Returns a number. A blank owner uses a GameObject tagged Player. |
| Add an Item | `uisAddItem(itemName, amount, inventoryName, itemCollectionName)` | Adds an integer amount. A blank collection uses the Inventory's normal add route. |
| Remove an Item | `uisRemoveItem(itemName, amount, inventoryName, itemCollectionName)` | Finds a matching Item and requests removal. Recheck the amount when the result matters. |
| Read Currency | `uisGetCurrencyAmount(currencyName, currencyOwnerName)` | Returns the Currency Owner's amount as a number. |
| Add Currency | `uisAddCurrency(currencyName, amount, currencyOwnerName)` | Adds the configured Currency amount and returns no Lua result. |
| Remove Currency | `uisRemoveCurrency(currencyName, amount, currencyOwnerName)` | Requests removal and returns no Lua result; check the balance first when insufficient funds must choose another branch. |

For a named owner, the bridge searches for that GameObject, then looks for an Inventory or Currency Owner on it or its children. For a blank owner, it searches by the Player tag. Item names and Currency names are resolved through `InventorySystemManager`.

Item amounts arrive from Lua as numbers but are converted to integers. Do not use fractional Item amounts. Currency amounts remain numeric and follow the Currency's configured precision and conversion rules.

If **Item Collection Name** is present, it must exactly match an Item Collection on the resolved Inventory. In the verified source, a missing collection name falls back to the broader Inventory route instead of reporting an error, so verify the affected collection after every dialogue action.

## Use quests and Shops

Dialogue System quest conversations can use the same functions in dialogue-entry **Conditions** and **Script** fields. For example, require a quest giver to see one Iron Sword with `uisGetItemAmount`, then award Gold with `uisAddCurrency` when Dialogue System advances the quest state. The quest state still belongs to Dialogue System; the integration only reads or changes Ultimate Inventory System data.

Pixel Crushers Quest Machine uses a separate integration. Use the [Quest Machine integration](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/quest-machine/) when the quest itself is a Quest Machine quest rather than a Dialogue System quest.

The package also adds the sequencer command `OpenShop()`. The most reliable setup for the verified package is:

1. Put an Ultimate Inventory System **Shop** component on the conversation speaker. The sequencer command accepts this concrete `ShopBase` implementation.
2. Make the player the conversation listener and give it an Inventory, or tag the player **Player**.
3. Keep an Ultimate Inventory System **Shop Menu** in the scene beneath a **Display Panel Manager**.
4. Enter `OpenShop()` in the dialogue entry's **Sequence** field.

When the sequence runs, the command finds the Shop, assigns the player's Inventory as the client, assigns the Shop to the menu, and asks the Display Panel Manager to open it. Verify the no-argument form before using optional subjects because their handling depends on the integration revision.

## Choose one save owner

Saving is the area most likely to differ between provider revisions. Follow the files and instructions included with the matched bridge. The installer verified for this page contains two mutually exclusive routes:

| Save owner | Components in the verified installer | Rule |
| --- | --- | --- |
| Pixel Crushers Save System | **UIS Saver** on the Pixel Crushers Save System object and **Save System Manager No Disk** in place of the normal Ultimate Inventory System disk-writing manager | Pixel Crushers stores the combined saved game. Keep **Save Slot** at `0` for this archived bridge because its load path restores slot 0. |
| Ultimate Inventory System Save System | **Pixel Crushers to UIS Saver** registered with the Ultimate Inventory System Save System | Ultimate Inventory System records and restores Pixel Crushers saved-game data. Do not also add **UIS Saver**. |

Do not configure both rows. Also do not ship the demo's **Redirect Save Load Button To Test Menu** component; its source explicitly marks it as test-only.

If a newer integration Inspector says that one of these legacy components is no longer used, follow that newer package's instructions rather than recreating the archived setup.

## Editor checkpoint

Before entering Play Mode, confirm all of the following:

- Unity has one copy of each **Opsive UIS Support** script and no compile errors.
- The persistent Dialogue Manager has one enabled **UIS Lua** component.
- The Lua wizard shows `uisGetItemAmount`, `uisAddItem`, `uisRemoveItem`, `uisGetCurrencyAmount`, `uisAddCurrency`, and `uisRemoveCurrency`.
- The Player tag or explicit owner name resolves to the intended Inventory and Currency Owner.
- Health Potion, Gold, Item Collection names, and Shop subjects exactly match the Ultimate Inventory System configuration.
- Exactly one save system owns the combined save, and the project does not contain both saver routes.

## Verify in Play Mode

1. Start with one Health Potion and zero Gold. Begin the conversation and confirm that the trade response is available.
2. Select the response. Confirm that the potion amount decreases by one and Gold increases by five in Ultimate Inventory System, not only in a dialogue variable.
3. Start the conversation again. The response should now follow the no-potion path.
4. Test a misspelled Item name on a copy of the conversation. With Dialogue System warning logging enabled, the Console should identify the missing definition and Ultimate Inventory System state should remain unchanged.
5. Run the Shop conversation and confirm that `OpenShop()` opens the Ultimate Inventory System Shop Menu with the expected Shop and player Inventory.
6. Save, change the Item and Gold balances, then load. Confirm that dialogue/quest state and Ultimate Inventory System state return together exactly once.
7. Reload the scene and repeat the conversation to catch duplicate Dialogue Managers, duplicate Lua registration, or a missing persistent save owner.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| Unity reports missing Pixel Crushers namespaces after import | Check whether Dialogue System compiled before the bridge and whether the bridge matches Dialogue System 2.x. | Remove the incomplete support folders, install the prerequisite, and import one matched integration package. |
| Lua reports an unknown `uis...` function | Check that one enabled Ultimate Inventory System Lua component exists on the active Dialogue Manager and whether **Unregister On Disable** removed the functions. | Enable the correct component, avoid duplicate Dialogue Managers, and restart the scene after registration. |
| An Item or Currency get function returns `0` | Check the exact Ultimate Inventory System name, Player tag or explicit owner name, and component location. | Correct the name and make sure Inventory or Currency Owner exists on the resolved object or a child. |
| A change function runs but state does not change | Check the target, collection name, available amount, and Inventory restrictions. | Recheck with the corresponding get function and treat an unchanged value as failure. |
| The wrong Item Collection changes | Check spelling and capitalization of **Item Collection Name**. | Use the exact collection name; a missing match can fall back to the broader Inventory route in the verified package. |
| Remove Currency continues even when funds are insufficient | The Lua change function does not return the Ultimate Inventory System removal result. | Put `uisGetCurrencyAmount(...) >= price` in Conditions before running the removal script, then verify the balance. |
| `OpenShop()` logs that a subject, menu, manager, or Inventory is missing | Check the speaker's Shop component, listener/player Inventory, Shop Menu, and parent Display Panel Manager. | Make the no-argument convention work first, then add explicit subjects only when the installed integration documents them. |
| Loading duplicates or loses Ultimate Inventory System data | Check for both saver routes, two disk writers, duplicate saver keys, and a nonzero slot in the archived **UIS Saver**. | Choose one save owner, keep unique saver keys, and verify a new slot-0 save before migrating existing saves. |
| Quest Machine does not react to these Lua functions | Check whether the quest belongs to Quest Machine rather than Dialogue System. | Install and configure the separate Quest Machine integration. |

## Related pages

- [Integrations](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/)
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/)
- [Currency](https://opsive.com/support/documentation/ultimate-inventory-system/currency/)
- [Shops](https://opsive.com/support/documentation/ultimate-inventory-system/currency/shop/)
- [Shop Menu](https://opsive.com/support/documentation/ultimate-inventory-system/ui/shop-menu/)
- [Save system](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/)
- [Quest Machine integration](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/quest-machine/)

## Developer and version reference

The Ultimate Inventory System Version 1 package verified for this page is version `1.3.0`. Its checked-in `DialogueSystem.unitypackage` contains `UISLua`, `UISUtility`, `SequencerCommandOpenShop`, `UISSaver`, `SaveSystemManagerNoDisk`, `PixelCrushersToUISSaver`, a demo scene and database, and `UIS Lua Function Info.asset`. It contains no manifest that pins a Dialogue System version. Pixel Crushers release notes show that the provider updates this bridge between Dialogue System 2.x releases, so source from the matched download takes precedence over an older copied folder.

`UISLua` registers all six functions in `OnEnable`. **Unregister On Disable** defaults to false; when enabled, `OnDisable` unregisters them. A blank owner name uses a Player-tagged GameObject, while a nonempty name uses Pixel Crushers' hard GameObject lookup. The component then searches the object and its children for Inventory or Currency Owner.

The Item change functions accept a Lua number and cast it to `int`. All four change functions return `void`, so a dialogue script cannot infer success from the call itself. The get functions return `double`, and the integration logs missing-name or missing-owner warnings only when Dialogue System warning logging is enabled.

In the archived source, `UISSaver.ApplyData` restores Ultimate Inventory System save index `0` even though the component exposes **Save Slot**, and `SequencerCommandOpenShop` does not reliably consume its documented optional player-inventory subject. Keep the saver on slot 0 and prefer `OpenShop()` with speaker/listener defaults unless a newer matched integration corrects those behaviors.

---

<a id="page-ultimate-inventory-system-integrations-input-system"></a>

# Input System

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/input-system/)

Use Unity's Input System when the player needs gamepad support, device pairing, rebinding, or input actions shared with the rest of the project. Ultimate Inventory System continues to request familiar names such as `Action`, `Open Panel`, and `Close Panel`; the Opsive input component translates those requests into Unity Input Actions.

Unity Input System support is included in Opsive Shared for released Ultimate Inventory System Version 1. Do not download a separate Ultimate Inventory System integration for this route. Rewired and InControl still use their own optional integrations.

## Before you begin

This page covers the released Version 1/master setup. The checked-in release project is verified with Unity 2022.3.62f3, Ultimate Inventory System 1.3.0, Opsive Shared 2.0.3, and Unity Input System 1.11.2. Use an Input System package version supported by the Unity editor version in your own project; do not substitute an Ultimate Inventory System Version 2 integration.

The setup has two input paths:

| Player action | Component that reads it | Example |
| --- | --- | --- |
| Ultimate Inventory System gameplay or menu shortcut | Opsive **Unity Input System**, through Unity **Player Input** | Interact, open or close a panel, change a tab, or use a hotbar slot |
| Unity UI navigation | **Input System UI Input Module** on the EventSystem | Move selection, submit, cancel, point, click, or scroll |

Both paths must be configured. Pointer clicks can work even when Ultimate Inventory System shortcuts do not, and an Ultimate Inventory System shortcut can open a panel even when controller navigation is not configured.

## Enable Unity's Input System

1. Open **Window > Package Manager** and install **Input System**.
2. Open **Edit > Project Settings > Player > Other Settings**.
3. Set **Active Input Handling** to **Input System Package (New)** or **Both**. Restart the editor if Unity requests it.
4. Let Unity finish compiling, then confirm that **Unity Input System** appears in the Add Component menu.
5. Locate `CharacterInput.inputactions` in the Opsive Shared package. It is a starting asset with **Gameplay** and **UI** action maps and Keyboard, Gamepad, and Mobile control schemes.

The Opsive component is compiled only while Unity defines `ENABLE_INPUT_SYSTEM`. If the component does not appear, correct the package and Active Input Handling setup before changing the player prefab.

## Connect the player

Keep the Opsive and Unity input components together on the same player input GameObject. A character created by an Opsive setup manager may place them on a child input object rather than directly on the character root.

1. Select the GameObject that currently provides input for the player's Inventory and UI.
2. Remove or disable the legacy Opsive **Unity Input** component when the project no longer uses the old Input Manager. Do not leave two concrete Opsive input components active for one player.
3. Add the Opsive **Unity Input System** component.
4. Confirm that Unity's **Player Input** component is on the same GameObject. Adding **Unity Input System** normally adds it during component reset, but the runtime still requires it to be present.
5. On Unity **Player Input**, assign `CharacterInput.inputactions` to **Actions**.
6. Set **Default Map** to **Gameplay**. Choose a **Default Scheme** only when the player must start with a particular control scheme; otherwise allow Unity Player Input to choose from the available devices.
7. In the Opsive **Unity Input System** Inspector, review **Force Input**, **Disable Cursor**, **Enable Cursor With Escape**, **Prevent Look Vector Changes**, and **Disable Player Input** for the project.
8. On the Ultimate Inventory System **Display Panel Manager**, assign the intended player as **Panel Owner**. Panel and grid handlers resolve their Opsive player input from this owner.

![Unity Player Input component with the CharacterInput action asset assigned to Actions.](https://opsive.com/wp-content/uploads/2020/08/UnityPlayerInputActions.png?v=b96ea0e649fc)

The abstract Opsive `PlayerInput` class is shared by Ultimate Inventory System and the Opsive character controllers, but it is not a component to add directly. For this route, the concrete Opsive component is **Unity Input System** and the similarly named Unity component is **Player Input**.

## Match Ultimate Inventory System names to the active action map

The released Opsive **Unity Input System** component looks up each requested action by name in Unity Player Input's current action map. The included **Gameplay** map already contains common Version 1 names, including:

- `Action` for interactions;
- `Open Panel` and `Close Panel` for the Main Menu;
- `Next` and `Previous` for grid tabs;
- `Equip First Item` through `Equip Tenth Item` for hotbar slots; and
- the movement, look, use, and equipment actions used by Opsive character controllers.

If the project uses a custom Input Action Asset, create actions whose names match the Ultimate Inventory System handler **Input Name** values. The Unity Player Input **Behavior** setting does not dispatch these Ultimate Inventory System shortcuts; the Opsive component reads the current actions directly.

Only the current action map is searched. If project code switches Unity Player Input away from **Gameplay**, any Ultimate Inventory System name missing from the new current map stops resolving. Either keep the required Ultimate Inventory System actions in every map that must handle them or keep **Gameplay** current while the EventSystem reads its own UI action references.

`Close Panel` and the UI action `Cancel` are separate names. Binding both to the same physical button is valid, but one does not automatically replace the other.

## Configure the EventSystem

For a single player, use one EventSystem for the active Ultimate Inventory System Canvas.

1. Select the scene's EventSystem GameObject.
2. Remove **Standalone Input Module**.
3. Add **Input System UI Input Module**.
4. Assign an Input Action Asset to **Actions Asset**. `CharacterInput.inputactions` includes a **UI** map, or the project can use its own UI action asset.
5. Confirm the module's **Point**, **Left Click**, **Middle Click**, **Right Click**, **Scroll Wheel**, **Move**, **Submit**, **Cancel**, **Tracked Position**, and **Tracked Orientation** assignments that the project uses. Unity can match these fields when **Actions Asset** changes, but inspect them rather than assuming every custom action name was found.
6. Select an Ultimate Inventory System button before entering Play Mode, or configure the panel's first selectable so controller navigation has a starting point.

The UI module reads UI actions independently of the Opsive component. Switching Unity Player Input to the **UI** map is not required for a single-player menu and can remove `Close Panel` from the current map unless the project duplicates that action.

## Choose the important input options

| Setting | Use it when |
| --- | --- |
| **Force Input** | Choose **None** for platform-driven behavior, **Standalone** to prevent mobile on-screen mode, or **On Screen** to force the on-screen-control path while testing. |
| **Disable Cursor** | Gameplay should lock and hide the cursor while the Opsive input component is active. Ultimate Inventory System panels can still manage cursor changes through their panel handler. |
| **Enable Cursor With Escape** | Pressing Escape should unlock and show the cursor. |
| **Prevent Look Vector Changes** | Character look input should stop while Escape has released the cursor. This field appears when **Enable Cursor With Escape** is enabled. |
| **Disable Player Input** | Disabling the Opsive component should also disable Unity's **Player Input** component. Leave it disabled when another system owns Unity Player Input's lifetime. |
| Unity Player Input **Default Map** | Select **Gameplay** for the supplied `CharacterInput.inputactions` workflow. A blank value leaves no current action map for the Opsive component to search. |
| Unity Player Input **Auto-Switch** | Allow one local player to change devices automatically. Use deliberate device pairing instead for local multiplayer. |

## Editor checkpoint

Before entering Play Mode, confirm that:

- the project has the Input System package enabled and **Unity Input System** compiles;
- the input GameObject has exactly one concrete Opsive input component;
- Opsive **Unity Input System** and Unity **Player Input** are on the same GameObject;
- Unity Player Input has **Actions** assigned and **Gameplay** selected as **Default Map**;
- every Ultimate Inventory System handler **Input Name** exists in the current action map;
- the EventSystem uses **Input System UI Input Module**, not **Standalone Input Module**;
- the UI module's point, click, move, submit, and cancel actions are assigned;
- the Display Panel Manager's **Panel Owner** is the player that owns this input; and
- the scene contains only the EventSystems intended for the current player setup.

## Verify in Play Mode

1. Trigger an interactable with `Action`. Confirm that the intended player performs one interaction.
2. Press the action bound to `Open Panel`. Confirm that the expected Ultimate Inventory System panel opens.
3. Move UI selection with a keyboard or gamepad, submit a button, point and click, and scroll a list.
4. Change a grid tab with `Next` and `Previous` and use at least one numbered hotbar action.
5. Press the action bound to `Close Panel`. Confirm that the panel closes and gameplay input resumes as designed.
6. Switch between keyboard and gamepad. Confirm that the same Ultimate Inventory System actions still resolve and the correct control scheme becomes active.
7. If the game switches action maps, repeat the open, close, and interaction checks after every switch.
8. If **Disable Player Input** is enabled, disable and re-enable the Opsive component once and confirm that Unity Player Input follows it.

## Local multiplayer and UI ownership

Give each local player its own Opsive **Unity Input System**, Unity **Player Input**, Inventory ownership, Canvas, and UI input route. Use a **Multiplayer Event System** and **Input System UI Input Module** per player, set each Multiplayer Event System's **Player Root**, and assign the matching module to Unity Player Input's **UI Input Module** field. Pair each Player Input with its intended device.

Keyboard and mouse are shared devices. The released Opsive component deliberately makes them available to every enabled Unity Player Input instance, so use separate gamepads when local players need independent ownership. Follow the complete [Split Screen Co-op UI workflow](https://opsive.com/support/documentation/ultimate-inventory-system/input/split-screen-co-op-ui/) instead of duplicating a single-player EventSystem without changing its owner and Player Root.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| **Unity Input System** is missing from Add Component | Check the Input System package, compile errors, and **Active Input Handling**. | Install a package version supported by the Unity editor, enable **Input System Package (New)** or **Both**, restart, and resolve the first compile error. |
| Play Mode reports an error as the input component starts | Check for Unity **Player Input** on the same GameObject as Opsive **Unity Input System**. | Add Player Input there and assign an Input Action Asset before entering Play Mode. |
| Pointer clicks work but Ultimate Inventory System shortcuts do nothing | Check Unity Player Input's **Default Map**, current action map, and the Ultimate Inventory System handler's **Input Name**. | Activate a map containing the matching action or rename the handler/action consistently. |
| `Cancel` works but `Close Panel` does not | Compare the UI module's **Cancel** action with the Ultimate Inventory System Display Panel Manager Handler's `Close Panel` input. | Bind the `Close Panel` action in the current gameplay map; do not rely on the UI action alone. |
| A panel opens but controller navigation does not move | Check the EventSystem module, UI action assignments, and initial selection. | Replace **Standalone Input Module**, assign **Move**, **Submit**, and **Cancel**, and give the panel a first selectable. |
| Input fires twice or different handlers disagree | Check for both Opsive **Unity Input** and **Unity Input System**, or another `IPlayerInput` implementation, on one player. | Keep only the concrete Opsive input component chosen for that player. |
| Actions stop after a menu or gameplay-state change | Inspect Unity Player Input's current action map at that moment. | Keep the required Ultimate Inventory System names in the new map or stop switching away from the map that contains them. |
| One player controls another player's UI | Check device pairing, **UI Input Module**, **Player Root**, Display Panel Manager **Panel Owner**, and Ultimate Inventory System player IDs. | Give every player a separate ownership route and complete the split-screen setup. |
| Both local players respond to the keyboard | Check whether the project expects a shared keyboard to identify separate players. | Pair separate gamepads for independent players; the released Opsive component shares keyboard and mouse access. |
| A current project still follows the old integration-download instructions | Check whether it imported a historical Input System integration over the current Opsive Shared package. | Remove duplicate historical scripts and use the Input System implementation already included with released Opsive Shared. |

## Related pages

- [Input setup and backend choices](https://opsive.com/support/documentation/ultimate-inventory-system/input/)
- [Input Handlers](https://opsive.com/support/documentation/ultimate-inventory-system/input/handlers/)
- [Split Screen Co-op UI](https://opsive.com/support/documentation/ultimate-inventory-system/input/split-screen-co-op-ui/)
- [Display Panel Manager](https://opsive.com/support/documentation/ultimate-inventory-system/ui/display-panel-manager/)
- [Integrations](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/)
- [Opsive Character Controllers](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/opsive-character-controllers/)

## Developer and version reference

The concrete implementation is `Opsive.Shared.Input.InputSystem.UnityInputSystem`, which derives from `Opsive.Shared.Input.PlayerInput` and implements the `IPlayerInput` contract consumed by Ultimate Inventory System. At startup it obtains `UnityEngine.InputSystem.PlayerInput` from the same GameObject. Its button and axis methods search `PlayerInput.currentActionMap` by name, poll button controls, and read float action values. It does not require Unity Player Input event callbacks to invoke Ultimate Inventory System handlers.

The released source wraps the component in `#if ENABLE_INPUT_SYSTEM`. The Version 1/master project checked for this page uses Unity Input System 1.11.2 and sets Active Input Handling to **Both**. That is the verified release combination, not a promise that every older or newer Input System package is compatible with every Unity editor.

The included `CharacterInput.inputactions` asset has **Gameplay** and **UI** maps plus Keyboard, Gamepad, and Mobile schemes. The released Ultimate Inventory System player prefab assigns that asset to Unity Player Input and uses **Gameplay** as **Default Map**. Its Input System UI Input Modules use action references for UI navigation separately from the Opsive gameplay-action lookup.

---

<a id="page-ultimate-inventory-system-integrations-master-audio"></a>

# Master Audio

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/master-audio/)

Use the [Master Audio](https://assetstore.unity.com/packages/tools/audio/master-audio-2022-aaa-sound-212962?aid=1100lGdc) integration when Ultimate Inventory System button feedback, pickups, Item Actions, and other Opsive sounds should play through Master Audio Sound Groups. The bridge replaces the default Opsive Audio Manager module, so existing Ultimate Inventory System components keep their normal audio fields while Master Audio controls the actual Variations, voices, buses, and spatial behavior.

The same shared bridge is used by Ultimate Inventory System and the Opsive character controllers. Import it once when both products are installed.

## Supported package boundary

This page targets released Ultimate Inventory System Version 1/master. The checked-in Version 1 project is Ultimate Inventory System 1.3.0 with Opsive Shared 2.0.3. The current local Opsive bridge was verified with Master Audio 2024 v1.0.3 and its runtime calls use the audio APIs present in Opsive Shared 2.0.3.

The bridge package does not declare a minimum or maximum Master Audio version. Treat Master Audio 2024 v1.0.3 as the verified combination, then test the matching package from the [Opsive Downloads page](https://opsive.com/downloads/?pid=22330) before migrating a production audio setup. Do not assume that a bridge built for Ultimate Inventory System Version 2 or a different Master Audio generation is interchangeable.

Master Audio also includes a small `MA_Opsive.unitypackage` in its third-party integrations folder. That package routes sounds only by Audio Clip name and does not contain the **Master Audio Config** workflow described here. Use the current Opsive `MasterAudio.unitypackage` download for released Ultimate Inventory System Version 1 instead of importing both bridges.

## Before you begin

1. Back up or commit the project before changing the global audio module.
2. Install Master Audio and confirm that its own examples or a test Sound Group play without Ultimate Inventory System.
3. Add and configure the Master Audio GameObject by following the [Master Audio documentation](https://www.dtdevtools.com/docs/masteraudio/TOC.htm).
4. In Master Audio's Group Mixer, create the Sound Groups that Ultimate Inventory System will request. Each Sound Group needs at least one playable Variation.
5. Let the project compile before importing the Opsive bridge. The bridge directly references `DarkTonic.MasterAudio`; importing it before Master Audio produces missing-namespace errors.
6. Download and import the Master Audio integration offered for the released Opsive product combination. If Ultimate Character Controller already imported the same bridge, do not import a second copy.

After import, the project should contain **Master Audio Manager Module** and **Master Audio Config** asset types in the **Create > Opsive > Audio** menu.

## Route Opsive audio through Master Audio

The Audio Manager has one active module, so this change affects every Opsive system that uses it.

1. Open **Tools > Opsive > Ultimate Inventory System > Main Manager**.
2. Open **Setup** and, under **Scene Setup**, select **Add Components** if the scene does not already contain the shared Opsive components.
3. In the Hierarchy, select the GameObject with the **Audio Manager** component. The standard Ultimate Inventory System setup places it on the `Game` GameObject.
4. Use the **MasterAudioManagerModule** asset included with the integration, or create one with **Create > Opsive > Audio > Master Audio Manager Module**.
5. Assign that asset to **Audio Manager > Audio Manager Module**.
6. Keep **Require Group Name** enabled for an explicit setup. Every Ultimate Inventory System audio hook must then reference a **Master Audio Config** with **Audio Group Name** assigned.

Disabling **Require Group Name** enables a compatibility fallback: the bridge resolves an Audio Clip and asks Master Audio for a Sound Group with exactly the same name. It still does not play that clip directly. Use this only when the Master Audio Sound Groups already follow the Audio Clip filenames.

## Connect an Ultimate Inventory System button sound

This example routes an inventory button through a Master Audio Sound Group named `UIS UI Click`.

1. In Master Audio, create the `UIS UI Click` Sound Group and add one or more click Variations. Configure the group as 2D because Ultimate Inventory System button audio is requested at a neutral world position.
2. In the Project window, select **Create > Opsive > Audio > Master Audio Config** and name the asset `UISButtonClickMasterAudio`.
3. Set **Audio Group Name** to `UIS UI Click`.
4. Leave **Variation** set to **(Random Variation)** to let Master Audio choose, or select one Variation when this interaction must always use the same sound. **[Type In]** exposes **Variation Name** for a Variation that cannot be listed.
5. Use the inherited Audio Modifier only for **Volume Override**, **Pitch Override**, or **Delay Override** when this Ultimate Inventory System use needs to differ from the Sound Group defaults.
6. Open the Ultimate Inventory System **Button Audio** asset used by the inventory control and assign the new config to **Click Config**. Assign a separate config to **Select Config** when selection should use another Sound Group.
7. Confirm that the control has **Button Audio Handler** and that its **Button Audio** field references this Button Audio asset.

With **Require Group Name** enabled, **Click Clip** and **Select Clip** are optional for the Master Audio route because the Sound Group supplies the Variations. Keeping direct clips can still make it easier to return to the default Opsive audio module later.

## Connect pickups and other Ultimate Inventory System sounds

The same config pattern works anywhere Ultimate Inventory System exposes an Audio Config.

- On a Health Potion pickup, assign Master Audio Config assets to **Audio Config**, **Fail Audio Config**, and **Partial Pickup Audio Config** for distinct success, full-Bag, and partial-pickup Sound Groups.
- On a Button Audio asset, use **Click Config** and **Select Config** for submit and selection feedback.
- In an Audio Clip Set used by an Item Action or drag-and-drop action, use a Master Audio Config for each entry that needs a different Sound Group or Variation.

Master Audio decides whether these groups are 2D or 3D. UI groups are normally 2D. Pickup and world-action groups can be 3D because the bridge sends their transform or world position to Master Audio.

Changing **Audio Manager Module** is not per sound. Audit every Opsive audio field in the project before removing the default module, especially when **Require Group Name** is enabled. An unmigrated direct Audio Clip will otherwise be silent.

## Editor checkpoint

Before entering Play Mode, confirm that:

- Master Audio compiles before the Opsive bridge and the scene has an active Master Audio GameObject;
- only one copy of `MasterAudioManagerModule` and `MasterAudioConfig` is present;
- the scene has one active Opsive **Audio Manager** with **MasterAudioManagerModule** assigned to **Audio Manager Module**;
- **Require Group Name** matches the chosen explicit-config or clip-name fallback workflow;
- every explicit **Master Audio Config** has a valid **Audio Group Name**;
- a selected **Variation** belongs to that Sound Group, or **Variation** is left random intentionally;
- each Sound Group has at least one playable Variation;
- Ultimate Inventory System button, pickup, and Item Action fields reference the intended configs; and
- UI groups are 2D while positional groups have the intended Master Audio distance and spatial settings.

## Verify in Play Mode

1. Open the Ultimate Inventory System Main Menu and select a configured Item View Slot. Confirm that its selection Sound Group plays once.
2. Submit the slot or a configured button. Confirm that Master Audio shows a voice in the expected click Sound Group.
3. Repeat the click several times. A random config should use the group's Variation rules; a specific **Variation** should remain fixed.
4. Pick up a Health Potion. Confirm that the success group plays at the pickup position.
5. Fill the Bag and repeat the pickup. Confirm that the fail group plays instead of the success group.
6. Trigger one Item Action or drag-and-drop sound that uses an Audio Clip Set. Confirm that it also routes through Master Audio.
7. Test a sound that has not yet been migrated. With **Require Group Name** enabled it should remain silent, which identifies another hook that needs a config.
8. Reload the scene and repeat one UI and one world sound to confirm that both the Master Audio GameObject and Opsive Audio Manager initialize in the real scene order.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| Importing the bridge creates `DarkTonic.MasterAudio` compile errors | Check whether Master Audio is installed and compiling before the bridge scripts. | Install the supported Master Audio package first, remove the incomplete bridge copy, and reimport the matching Opsive package. |
| **Master Audio Config** or **Require Group Name** is missing | Check whether the project imported Master Audio's bundled `MA_Opsive.unitypackage` instead of the current Opsive bridge. | Remove the older bridge files and import the released `MasterAudio.unitypackage` from Opsive Downloads. |
| No Opsive sound plays after assigning the module | Check **Audio Manager Module**, the Master Audio GameObject, and the Console. | Assign the included MasterAudioManagerModule asset, keep Master Audio active, and resolve its first runtime error. |
| A direct Audio Clip used to work but is now silent | Check **Require Group Name** and whether the Ultimate Inventory System field has a Master Audio Config. | Assign a config with **Audio Group Name**, or disable the requirement only when a same-named Sound Group exists for the clip. |
| **Audio Group Name** has no useful choices | Check whether the intended Master Audio GameObject and Sound Groups exist in the current scene. | Create or import the Sound Groups, then reselect the config so its Inspector can find them. |
| The selected Variation does not play | Compare **Variation** or **Variation Name** with the children of the chosen Sound Group. | Select an existing Variation or return to **(Random Variation)**. |
| UI audio is positional, quiet, or changes with the camera | Check the selected Master Audio Sound Group's spatial settings. | Configure the UI group as 2D; Opsive Audio Config spatial fields are not what drives the Master Audio Variation. |
| One Ultimate Inventory System sound works but other Ultimate Inventory System sounds are silent | Check every Button Audio, pickup, Audio Clip Set, and other Audio Config field. | Migrate each hook because the Audio Manager module is global. |
| Two copies of the bridge produce duplicate-type errors | Check for both the shared Opsive integration and Master Audio's bundled `MA_Opsive` folder. | Keep one bridge package that matches the documented release boundary and remove the duplicate. |
| Stopping one sound also stops another on the same object | Check whether both sounds were attached to the same transform. | Use separate playback transforms or a project-specific module when sounds need independent stopping. The supplied bridge stops all Master Audio sounds associated with the transform. |

## Related pages

- [Ultimate Inventory System audio workflow](https://opsive.com/support/documentation/ultimate-inventory-system/audio/)
- [Item Pickups](https://opsive.com/support/documentation/ultimate-inventory-system/item-objects/item-pickups/)
- [Built-in Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/built-in-item-actions/)
- [Item View Slots](https://opsive.com/support/documentation/ultimate-inventory-system/ui/item-view-slots-container/item-view-slot/)
- [Integrations](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/)
- [Shared Opsive Audio Manager](https://opsive.com/support/documentation/ultimate-character-controller/audio/)
- [Character Controller Master Audio integration](https://opsive.com/support/documentation/ultimate-character-controller/integrations/master-audio/)
- [Master Audio Sound Groups](https://www.dtdevtools.com/docs/masteraudio/SoundGroups.htm)

## Developer and runtime reference

The bridge supplies `Opsive.Shared.Integrations.MasterAudio.MasterAudioManagerModule`, which derives from `Opsive.Shared.Audio.AudioManagerModule`, and `MasterAudioConfig`, which derives from `AudioConfig`. Ultimate Inventory System continues to call `Opsive.Shared.Audio.AudioManager`; changing the manager module redirects those existing calls without changing Ultimate Inventory System components.

For transform playback the module calls `MasterAudio.PlaySound3DAtTransform`. For positioned playback it calls `MasterAudio.PlaySound3DAtVector3`. **Audio Group Name** supplies the Sound Group, and **Variation** optionally supplies one exact Variation. If a Master Audio call neither plays nor schedules a sound, the bridge returns `PlayResult.None`.

The bridge applies volume, pitch, and delay overrides from the individual play request first, then from the Master Audio Config. Master Audio owns looping, buses, voice limits, spatial blend, reverb, and the Variation Audio Sources. The inherited Opsive fields for Audio Source prefabs, sharing or replacing Audio Sources, output mixer, loop, stereo pan, spatial blend, and reverb are not consumed by this module.

This integration routes Opsive sound-effect playback. It does not turn Ultimate Inventory System audio fields into Master Audio playlists or control a Playlist Controller.

Both `Stop` overloads call `MasterAudio.StopAllSoundsOfTransform` and return no Audio Source, so stopping by config or PlayResult is not isolated to one Variation. Account for that behavior when multiple long-running sounds share a transform.

The current local bridge package was built against Master Audio 2024 v1.0.3 and Opsive Shared 2.1.0. Source comparison confirms that the Audio Manager, Audio Config, Audio Clip Info, modifier, and PlayResult APIs it uses are present in the released Ultimate Inventory System Version 1 Opsive Shared 2.0.3 checkout. Because the package has no formal third-party version constraint, compile and verify this minimal workflow before converting all project audio.

---

<a id="page-ultimate-inventory-system-integrations-playmaker"></a>

# PlayMaker

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/playmaker/)

The [PlayMaker](https://assetstore.unity.com/packages/tools/visual-scripting/playmaker-368?aid=1100lGdc) integration lets an FSM inspect or change an Ultimate Inventory System Inventory, use Item Actions, change Gold, open a panel, request a save, or send an Ultimate Inventory System Item Action back into PlayMaker as an event. A simple FSM can check for a Health Potion, use it when available, and take a different transition when the Inventory is empty.

This page covers the PlayMaker bridge available for released Ultimate Inventory System Version 1. The verified Ultimate Inventory System package version is `1.3.0`. The bridge uses PlayMaker's classic `HutongGames.PlayMaker` action API directly, but its source does not declare an integration version or a minimum PlayMaker version. Use the `Playmaker.unitypackage` downloaded for the installed Version 1 release rather than copying actions from a different major version.

## Before you begin

- Install and compile PlayMaker before importing the Ultimate Inventory System integration. The integration scripts reference PlayMaker types directly and cannot compile without them.
- Confirm that Ultimate Inventory System works on its own and that the target GameObject has the intended **Inventory**. Add **Item User** when the FSM will invoke an Item Action.
- Create the Item Definitions, Item Action Sets, Currency, panels, and save objects that the FSM will reference. The bridge controls existing Ultimate Inventory System data; it does not create a database or scene workflow.
- Back up or commit the project before replacing an older integration copy.

## Install the integration

1. Sign in to [Opsive Downloads](https://opsive.com/downloads/) and download the PlayMaker integration. It is not included in the base product's Integrations folder before download.
2. Import the downloaded package after PlayMaker and Ultimate Inventory System have both compiled. Importing it creates the integration files in the project.
3. Confirm that the scripts appear under `Assets/Opsive/UltimateInventorySystem/Integrations/Playmaker` and that the Console has no compile errors.
4. Open a PlayMaker FSM and its Action Browser. Select the **Ultimate Inventory System** category.
5. Search for **Has Item With Definition**, **Use Item From Inventory**, **Add Currency**, and **Open Close Panel**. The integration is ready when these actions appear.

The bridge adds actions rather than a scene component or Ultimate Inventory System Integration Inspector. Configure each action in a normal PlayMaker state.

## Use a Health Potion from an FSM

This example keeps the `PlayMakerFSM`, Ultimate Inventory System **Inventory**, and **Item User** on the same player GameObject. That lets each action use the FSM owner without a separate target reference.

1. Create PlayMaker events named `HAS_POTION`, `NO_POTION`, `USED_POTION`, and `USE_FAILED`.
2. Add a state named **Check Potion** and add **Ultimate Inventory System > Has Item With Definition**.
3. Leave **Target Game Object** set to the owner. Set **Amount** to `1`, **Item Definition** to **Health Potion**, **Check Inherently** and **Count Stacks** to off, and **Item Collection Purpose** to **None** to search the whole Inventory.
4. Set **Success Event** to `HAS_POTION`, **Fail Event** to `NO_POTION`, and leave **Every Frame** off. Connect `HAS_POTION` to a **Use Potion** state and `NO_POTION` to the intended fallback state.
5. Add **Use Item From Inventory** to **Use Potion**. Assign the same owner, the **Item Action Set** containing the potion's consume action, its **Action Index**, **Amount** `1`, **Item Definition** **Health Potion**, and **Item Collection Purpose** **None**.
6. Set **Success Event** to `USED_POTION`, **Fail Event** to `USE_FAILED`, and leave **Every Frame** off. Add transitions for both results.

**Has Item With Definition** only checks the Inventory. **Use Item From Inventory** then finds the Item and asks the selected Ultimate Inventory System Item Action Set to run on the player's Item User. Its event reflects the result returned by that Item Action Set, so verify the potion's visible effect and Item amount in addition to the FSM transition.

## Send an Ultimate Inventory System Item Action to PlayMaker

Use **Play Maker Event Item Action** when a normal Ultimate Inventory System menu or hotbar action should trigger an FSM event.

1. Add a string Item Attribute named `FSMEvent` to the relevant Item or its inherited data. For the Health Potion, set its value to `POTION_USED`.
2. Add **Play Maker Event Item Action** to the Ultimate Inventory System Category Item Action Set used by the menu or hotbar.
3. Leave **Attribute Event Name** as `FSMEvent`, or enter the exact alternative Attribute name. Set **Default Event Name** as a fallback when the Item does not contain that Attribute.
4. Enable **Append Item Name** only when the FSM events include the Item name in the form `<event>_<item name>`. Use **Debug Event Name** while testing if the final event string is unclear.
5. Add `POTION_USED` to the PlayMaker FSM and invoke the Item Action through Ultimate Inventory System.

The Item Action looks first for a `PlayMakerFSM` on the **Item User** GameObject, then on the Item's **Inventory** GameObject. It only sends the event; pair it with a consume, equip, or other Ultimate Inventory System Item Action when the Item itself must also change.

## Choose an action for the outcome

### Items and attributes

| PlayMaker action | Important fields and runtime result |
| --- | --- |
| **Add Item** | **Target Game Object**, **Amount**, **Item Definition** or **Item Definition Variable**, **Item Collection Purpose**, result events, and **Every Frame**. Creates a runtime Item and reports success only when the full amount is added. |
| **Remove Item** | The same target, definition, purpose, result-event, and repeat fields. Reports success when any nonzero amount is removed, even when less than **Amount** was available. |
| **Has Item With Definition** | **Amount**, **Item Definition** or its variable, **Check Inherently**, **Count Stacks**, **Item Collection Purpose**, and result events. Tests for at least the requested amount. |
| **Has Item With Category** | Uses **Item Category** or **Item Category Variable** with the same amount, inheritance, stack, purpose, event, and repeat choices. |
| **Compare Item Amount** | Adds **Operation** to the definition check. The released implementation has unsafe event logic; see the comparison limitation below before using it. |
| **Exchange Item Between Inventories** | **Target Game Object**, **Other Inventory Game Object**, **Amount**, definition or variable, **Give Item**, result events, and **Every Frame**. **Give Item** moves from the target to the other Inventory; off moves in the opposite direction. |
| **Drop Item From Inventory** | **Item Object Spawner ID**, **Amount**, definition or variable, **Item Collection Purpose**, **Remove Item On Drop**, result events, and **Every Frame**. Spawns at the Inventory position. |
| **Use Item From Inventory** | **Item Action Set**, **Action Index**, **Amount**, **Item Definition**, **Check Inherently**, **Item Collection Purpose**, result events, and **Every Frame**. Requires both Inventory and Item User on the target. |
| **Use Item Object** | **Item Object Slot Index**, **Action Index**, result events, and **Every Frame**. Requires **Usable Equipped Items Handler** on the target. |
| **Get Set Item Attribute Value Int**, **Float**, **Bool**, **String**, or **Object** | **Set Value**, **Attribute Name**, **Item Definition**, **Check Inherently**, **Item Collection Purpose**, typed **Value**, result events, and **Every Frame**. Reads the first matching runtime Item or sets that Attribute's override value. |
| **Get Set Item Attribute Value Currency Amounts** | Uses the same Item lookup with **Currencies Value** and **Amounts Value** arrays. The arrays must have equal lengths when setting a value. |

**Item Collection Purpose** **None** searches the entire Inventory. Selecting **Main**, **Equipped**, or another purpose restricts supported actions to that collection. **Check Inherently** includes child Item Definitions or Categories, while **Count Stacks** compares stack count instead of total Item amount.

### Currency

| PlayMaker action | Important fields and runtime result |
| --- | --- |
| **Add Currency** | **Target Game Object**, **Currency**, **Amount**, **Success Event**, **Fail Event**, and **Every Frame**. The target requires **Currency Owner**. |
| **Remove Currency** | Uses the same fields and fails when the Currency Owner cannot remove the requested amount. |
| **Has Currency** | Uses the same fields to test whether the owner has at least the requested amount. |
| **Compare Currency** | Adds **Operation**, but its released event logic is unsafe; use **Has Currency** for an at-least check. |

### Interaction, UI, and saving

| PlayMaker action | Important fields and runtime result |
| --- | --- |
| **Interact** | **Target Game Object**, result events, and **Every Frame**. The target needs both **Inventory** and **Inventory Interactor**. The action requests an interaction and then sends success without inspecting the interactable's result. |
| **Open Close Panel** | **Display Panel Manager ID**, **Panel Unique Name**, **Toggle**, **Close**, **Close Selected**, and **Success Event**. **Toggle** takes precedence; otherwise **Close** chooses close or open. |
| **Save**, **Load**, and **Delete Save** | **Save Index** and **Success Event**. Each requests the Ultimate Inventory System Save System operation, sends success immediately, and finishes. Verify the stored or restored state separately. |

For all actions with **Every Frame**, off executes once when the state starts and then finishes. On repeats the operation every update while the state remains active. Keep it off for Add, Remove, Exchange, Drop, Use, and Currency mutations unless repeated changes are deliberately rate-controlled elsewhere.

## Editor checkpoint

Before entering Play Mode, confirm all of the following:

- PlayMaker compiled before the integration, and the imported folder contains all 21 source files without duplicates.
- The Action Browser shows the Ultimate Inventory System category and its 24 concrete state actions, including the six typed Get/Set Attribute variants.
- The FSM owner or **Target Game Object** has every required Ultimate Inventory System component: Inventory, Item User, Currency Owner, Inventory Interactor, or Usable Equipped Items Handler as appropriate.
- Every Item Definition, Item Category, Currency, and Item Action Set comes from the database used by the target Inventory.
- **Action Index**, collection purpose, manager ID, panel name, spawner ID, and save index match the scene configuration.
- Every **Success Event** and **Fail Event** exists in the FSM and has the intended transition.
- Mutation actions have **Every Frame** off for the first test.
- A Play Maker Event Item Action can find a PlayMakerFSM on the Item User or Inventory GameObject, and its event string matches an FSM event exactly.

## Verify in Play Mode

1. Give the player one Health Potion and enter **Check Potion**. Confirm that the FSM follows `HAS_POTION`.
2. Enter **Use Potion**. Confirm that `USED_POTION` is sent, the configured Ultimate Inventory System Item Action produces its visible effect, and the expected Item amount remains or is consumed according to that action.
3. Remove the potion and run **Check Potion** again. Confirm that the FSM follows `NO_POTION` and does not enter the use state.
4. Invoke the Ultimate Inventory System **Play Maker Event Item Action** from the same player's UI. Confirm that the FSM receives `POTION_USED` on the Item User or Inventory object.
5. If the FSM changes Gold, inspect the actual Currency Owner balance after both a successful and failed removal.
6. If the FSM opens a panel or requests a save, verify the panel state or loaded Inventory data directly rather than treating the success event as confirmation.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| Unity reports missing `HutongGames.PlayMaker` types | Check whether PlayMaker compiled before the integration package was imported. | Install PlayMaker first, remove the incomplete bridge copy, and reimport the `Playmaker.unitypackage` supplied with Ultimate Inventory System Version 1. |
| Ultimate Inventory System actions do not appear in the Action Browser | Check the Console, the imported folder, and the **Ultimate Inventory System** category. | Resolve the first compile error, remove duplicate integration scripts, and reopen the FSM after Unity recompiles. |
| A state finishes without a success or fail transition | Check the target for Inventory and whether the action silently returned before sending an event. | Put the FSM on the Inventory GameObject for the first test or assign a fixed valid target, then verify all required components. |
| An Item or Gold amount changes every frame | Check **Every Frame** on the action and whether its state remains active. | Turn **Every Frame** off for one-shot mutations and transition on the result event. |
| **Use Item From Inventory** finds the potion but sends failure | Check Item User, Item Action Set, Action Index, definition, collection purpose, and the action's own requirements. | Assign the same working Item Action Set used by the Ultimate Inventory System UI and test that exact index directly. |
| **Compare Item Amount** or **Compare Currency** takes conflicting transitions | The released source can send success and then fail in one execution; its less-than paths do not perform a valid less-than comparison. | Use **Has Item With Definition** or **Has Currency** for at-least checks, or maintain a corrected custom comparison action. |
| An exchange ignores the chosen collection or transfers less than requested | The released **Exchange Item Between Inventories** does not use **Item Collection Purpose** and transfers the smaller of the requested and available amounts before sending success. | Validate both complete Inventories before the exchange, or use a custom action when collection-specific or all-or-nothing transfer is required. |
| **Open Close Panel** sends success but no panel changes | Check **Display Panel Manager ID**, **Panel Unique Name**, and the Toggle/Close choices. The released action also sends success when the manager is missing. | Copy the exact manager ID and unique panel name from the scene, then inspect the panel's visible state. |
| **Interact** throws an exception or succeeds without an interaction | Check for both Inventory and Inventory Interactor on the target. | Add and configure Inventory Interactor, then verify a valid interactable is in range; the action does not evaluate the interaction result. |
| **Drop Item From Inventory** fails at the spawner call | Check **Item Object Spawner ID** and whether that global spawner exists before the FSM initializes. | Assign the exact registered ID and retest with one Item and **Remove Item On Drop** off. |
| A save action sends success but loading changes nothing | Check registered Ultimate Inventory System Savers, **Save Index**, and the save file rather than the FSM event. | Complete the Ultimate Inventory System Save System setup and verify a known Inventory change through a fresh save and load. |
| Play Maker Event Item Action logs that no FSM was found | Check the Item User GameObject first, then the Item's Inventory GameObject. | Put the intended PlayMakerFSM on one of those objects and make the Attribute or default event name match its event. |
| A Get/Set Attribute action sends failure | Check the exact Attribute name, typed action variant, Item Definition, inheritance choice, and collection purpose. | Use the variant matching the Attribute type and confirm that the target Inventory contains a matching runtime Item. |

## Related pages

- [Integrations](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/)
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/)
- [Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/)
- [Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/)
- [Currency](https://opsive.com/support/documentation/ultimate-inventory-system/currency/)
- [Interaction system](https://opsive.com/support/documentation/ultimate-inventory-system/interaction-system/)
- [User interface](https://opsive.com/support/documentation/ultimate-inventory-system/ui/)
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)

## Developer and version reference

The verified released package is Ultimate Inventory System `1.3.0`. Its `Playmaker.unitypackage` contains 21 source files, no assembly definition, no integration-version metadata, and no declared PlayMaker version constraint. It compiles directly against `HutongGames.PlayMaker.FsmStateAction`, `FsmOwnerDefault`, the typed FSM variables, `FsmEvent`, and `PlayMakerFSM`. It is a PlayMaker integration, not a Unity Visual Scripting integration.

There are 24 concrete PlayMaker state actions: `AddCurrency`, `AddItem`, `CompareCurrency`, `CompareItemAmount`, `DeleteSave`, `DropItemFromInventory`, `ExchangeItemBetweenInventories`, six `GetSetItemAttributeValue` variants, `HasCurrency`, `HasItemWithCategory`, `HasItemWithDefinition`, `Interact`, `Load`, `OpenClosePanel`, `RemoveCurrency`, `RemoveItem`, `Save`, `UseItemFromInventory`, and `UseItemObject`. The separate `PlayMakerEventItemAction` is an Ultimate Inventory System Item Action rather than a PlayMaker state action.

Most target-based actions resolve and cache their Ultimate Inventory System components in the PlayMaker action's `Awake`, execute in `OnEnter`, and repeat in `OnUpdate` only when **Every Frame** is enabled. Keep target variables stable after FSM initialization; re-entering a state does not make these actions recache a changed target.

The released `CompareItemAmount` and `CompareCurrency` implementations always send their Fail Event after any Success Event and do not correctly evaluate the less-than operations. `ExchangeItemBetweenInventories` does not read its Item Collection Purpose field. `OpenClosePanel`, Save, Load, Delete Save, Interact, and Use Item Object signal that a request was issued, not that the player-facing outcome was confirmed. These are source-level boundaries of the released bridge, not settings that can be corrected in the Inspector.

---

<a id="page-ultimate-inventory-system-integrations-quest-machine"></a>

# Quest Machine

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/quest-machine/)

The [[Quest Machine](https://assetstore.unity.com/packages/tools/game-toolkits/quest-machine-39834?aid=1100lGdc)](https://assetstore.unity.com/packages/templates/systems/quest-machine-39834?aid=1100lGdc) integration lets a quest react to the player's Ultimate Inventory System Items and Currency. For example, a quest can wait until the player has three Health Potions, take those potions when the player returns, and award Gold. Quest Machine owns the quest and its counters; Ultimate Inventory System remains the source of truth for the Inventory and Currency balances.

Pixel Crushers maintains this bridge. The downloaded integration contains Pixel Crushers' integration manual, but it does not declare a minimum or maximum Quest Machine version. Use the bridge supplied for the installed Quest Machine 1.2 release, and test it before updating either product. Do not combine files from different bridge downloads.

## Before you begin

- Install and compile released Ultimate Inventory System Version 1 and Quest Machine before importing the bridge.
- Confirm that the player's Ultimate Inventory System **Inventory** and **Currency Owner** work without Quest Machine.
- Tag the player GameObject **Player**, or decide on the exact GameObject name that each quest field will use. The bridge looks for Inventory and Currency Owner on that object or its children.
- Create the Item Definitions and Currency used by the quest. This page uses **Health Potion** and **Gold**.
- Decide whether Pixel Crushers or Ultimate Inventory System owns saving. Configure only one of the two save routes described below.

Sign in to [Opsive Downloads](https://opsive.com/downloads/) and download the Quest Machine integration after both products compile. The bridge is not included in the base product's Integrations folder before download; importing the matched package creates the integration files in the project.

## Install the bridge

1. Back up the project and remove an older duplicate of the **Opsive UIS Support** folders if you are replacing the integration.
2. Import `QuestMachine.unitypackage`.
3. Confirm that Unity adds support beneath both of these folders:
   - `Assets/Pixel Crushers/Common/Third Party Support/Opsive UIS Support`
   - `Assets/Pixel Crushers/Quest Machine/Third Party Support/Opsive UIS Support`
4. Wait for Unity to compile. Resolve missing Pixel Crushers or Opsive namespaces before configuring a quest.
5. Open `Opsive_UIS_Support.pdf` from the imported Quest Machine support folder. It describes the demo, save-system choices, conditions, actions, and procedural generator included with that exact bridge.

The package also includes `UIS QM Demo.unity`, a handcrafted **Stubbed Toe** quest, and a generated **Fetch** quest. Use the demo to learn the integration, but copy only the components and quest assets that your own scene needs.

## Create a Health Potion collection quest

This example waits for three Health Potions, removes them at turn-in, and awards ten Gold.

1. Add a Quest Machine counter named **Health Potions** to the quest.
2. On the collection node, add **UIS Item Amount Quest Condition** to its condition list.
3. Set **Item Name** to `Health Potion`, leave **Inventory Name** blank to use the Player-tagged GameObject, set **Comparison Mode** to **At Least**, and set **Amount** to `3`.
4. Select the **Health Potions** counter in the condition. Although the source comments call the counter optional, the released bridge updates it without a null check, so every Ultimate Inventory System amount condition should use a counter.
5. On the quest's successful state, add **UIS Remove Item Quest Action**. Set **Item Name** to `Health Potion`, **Amount** to `3`, and **Item Collection Name** to `Bag` if the turn-in must remove from that exact collection. Leave **Inventory Name** blank for the player.
6. Add **UIS Add Currency Quest Action** after the removal action. Set **Currency Name** to `Gold`, **Amount** to `10`, and leave **Currency Owner Name** blank for the player.
7. Add quest content that tells the player to collect three Health Potions and return to the quest giver.

The condition counts the Item Definition across the entire Inventory; it has no Item Collection field. The remove action can target a named collection. If the quest must count only the Bag while the same Item can also exist elsewhere, this bridge does not provide that narrower condition.

## Use the quest conditions and actions

| Goal | Quest Machine type | Important fields and behavior |
| --- | --- | --- |
| Wait for an Item amount | **UIS Item Amount Quest Condition** | **Item Name**, **Inventory Name**, **Comparison Mode**, **Amount**, and a counter. Supports **At Least** and **At Most** and reevaluates when the Inventory updates. |
| Wait for a Currency amount | **UIS Currency Amount Quest Condition** | **Currency Name**, **Currency Owner Name**, **Comparison Mode**, **Amount**, and a counter. See the archived-source limitation below before using it. |
| Give Items | **UIS Add Item Quest Action** | **Item Name**, **Inventory Name**, **Item Collection Name**, and **Amount**. A blank collection uses the Inventory's normal add route. |
| Take Items | **UIS Remove Item Quest Action** | Uses the same four fields. A blank collection searches the Inventory for a matching Item. |
| Give Currency | **UIS Add Currency Quest Action** | **Currency Name**, **Currency Owner Name**, and **Amount**. |
| Take Currency | **UIS Remove Currency Quest Action** | Uses the same three fields. |

Blank **Inventory Name** and **Currency Owner Name** fields resolve the GameObject tagged **Player**. A nonempty field resolves a GameObject with that exact name. Item, Currency, and Item Collection names are also exact and case-sensitive in the bridge's runtime lookups.

Quest actions run synchronously and do not report success back to Quest Machine. Keep the matching condition in front of a removal, and verify the resulting Ultimate Inventory System balance before another quest step assumes the change occurred.

If another system can spend or move the required Items between collection and turn-in, add a second Item amount condition to the turn-in branch. The removal action will not stop the following Gold action when it cannot remove the requested amount.

### Archived Currency condition limitation

Do not rely on **UIS Currency Amount Quest Condition** from the exact bridge archived in Ultimate Inventory System Version 1 `1.3.0` until it passes a Play Mode test or is replaced by a provider-corrected build. In that source revision, the condition resolves Currency Owner into a local variable but does not assign the cached owner used by its comparison. The condition therefore cannot become true as written. The add and remove Currency actions use a separate lookup path and are not affected by that specific defect.

## Generate Ultimate Inventory System-aware quests

The bridge can also adapt Quest Machine's procedural quest generator to Ultimate Inventory System:

1. Add **Ultimate Inventory System Quest Generator Entity** to the quest-giver NPC. At startup it installs the Ultimate Inventory System-aware plan-to-quest builder.
2. Create a generator action through **Create > Pixel Crushers > Quest Machine > Generator > Ultimate Inventory System Get Item Action**, then use that action in the generator's domain and plan.
3. Add **UIS Reward System** to the NPC when generated quests should offer Ultimate Inventory System rewards.
4. Set **Currency** and **Currency Amount** for a Gold budget, and add eligible Item Definitions to **Items**.
5. Give each reward Item Definition a `BuyPrice` attribute of type `CurrencyAmount`. Add an `Icon` Sprite attribute when the generated offer should show an Item image.

For a generated collection step, the bridge creates an Item amount condition and counter. If the player drops below the required amount, it creates a backstep that reactivates the collection step. When the quest succeeds, it removes the requested Items. Generated rewards add Item or Currency actions to the quest's successful state.

The verified reward source consumes its configured Currency budget and Item list while generating rewards. If one **UIS Reward System** creates several quests in the same session, confirm that later quests still have the intended reward pool.

## Choose one save owner

The integration contains two mutually exclusive save routes:

| Save owner | Setup | Important rule |
| --- | --- | --- |
| Pixel Crushers Save System | On the Ultimate Inventory System GameObject, replace **Save System Manager** with **Save System Manager No Disk** and clear **Dont Destroy On Load** on **Inventory System Manager**. Configure the Pixel Crushers **Save System**, a data serializer, a saved-game data store, and **UIS Saver**. | Pixel Crushers stores the combined save. Keep **UIS Saver > Save Slot** at `0` for this bridge revision because its load method always restores Ultimate Inventory System slot 0. |
| Ultimate Inventory System Save System | Keep Ultimate Inventory System as the primary save system and register **Pixel Crushers To UIS Saver** with it. Do not add **UIS Saver**. | Ultimate Inventory System serializes and restores Pixel Crushers saved-game data. Do not also configure Pixel Crushers as a second disk writer. |

If an Opsive character controller is also installed and Pixel Crushers owns saving, add the appropriate controller saver but clear its **Save Inventory** option. **UIS Saver** already owns the Inventory data.

The demo's **Redirect Save Load Button To Test Menu** component is for testing only. Do not include it in a release build.

## Editor checkpoint

Before entering Play Mode, confirm all of the following:

- Unity contains one copy of each **Opsive UIS Support** folder and no compile errors.
- The Player tag or every explicit owner name resolves to the intended GameObject.
- That GameObject or a child has the required Inventory and Currency Owner.
- `Health Potion`, `Gold`, and `Bag` exactly match Ultimate Inventory System names.
- Each Item or Currency amount condition has a valid Quest Machine counter.
- The successful-state actions remove the requested Items before adding the reward.
- Exactly one save system owns the combined Quest Machine and Ultimate Inventory System save.

## Verify in Play Mode

1. Start with no Health Potions and zero Gold. Accept the quest and confirm that the collection node remains active.
2. Add two potions. Confirm that the **Health Potions** counter follows the Ultimate Inventory System amount and that the collection node remains active.
3. Remove one potion. Confirm that the counter returns to one while the active condition continues waiting.
4. Add two more potions. Confirm that the node completes when the amount reaches three.
5. Turn in the quest. Confirm that three Health Potions leave the Bag and ten Gold reaches the player's Currency Owner.
6. Repeat with a misspelled Item name on a copy of the quest. The condition should not complete and Ultimate Inventory System data should remain unchanged.
7. Save, change the quest state and Ultimate Inventory System balances, then load. Confirm that both systems return together exactly once.
8. Reload the scene and repeat the test to catch duplicate persistent managers or duplicate saver routes.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| Unity reports missing Pixel Crushers or Opsive namespaces | Check that Quest Machine and Ultimate Inventory System compiled before the bridge and that only one bridge copy is present. | Remove the incomplete support folders, install both prerequisites, and import one matched package. |
| An Item condition never completes | Check **Item Name**, the selected counter, Player tag or **Inventory Name**, and the Inventory component location. | Correct the exact names, select a valid counter, and place Inventory on the resolved object or a child. |
| A Currency condition never completes | Check whether the installed bridge contains the archived cached-owner defect described above. | Install a provider-corrected bridge or avoid this condition until the exact build passes a focused Play Mode test. |
| An action runs but the Item or Currency does not change | Check the definition name, owner, collection name, available amount, and Ultimate Inventory System restrictions. | Correct the target and verify the Ultimate Inventory System balance immediately after the action; the quest action itself does not return failure. |
| The wrong collection loses an Item | Check whether **Item Collection Name** is blank or misspelled. | Enter the exact collection name, such as `Bag`, on the remove action. |
| A generated reward throws an error or has no value or icon | Check the reward Item Definition for `BuyPrice` and `Icon` attributes with the expected types. | Add a `CurrencyAmount` BuyPrice and, when needed, a Sprite Icon before generating the quest. |
| Later generated quests offer fewer rewards | Check whether the same **UIS Reward System** already consumed its Currency budget or removed entries from its Item list. | Reset or recreate the reward source for the intended generation session and verify each generated offer. |
| Loading duplicates or loses state | Check for two disk writers, both saver routes, duplicate managers, or a nonzero archived **UIS Saver** slot. | Choose one save owner, use unique saver keys, and verify a new slot-0 save before migrating existing saves. |

## Related pages

- [Integrations](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/)
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/)
- [Item Collections](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/)
- [Currency](https://opsive.com/support/documentation/ultimate-inventory-system/currency/)
- [Item Definitions](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-definition/)
- [Save system](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)
- [Events](https://opsive.com/support/documentation/ultimate-inventory-system/events/)
- [Dialogue System integration](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/dialogue-system/)

## Developer and version reference

The released Ultimate Inventory System Version 1 package verified for this page is version `1.3.0`. Its `QuestMachine.unitypackage` contains the four quest actions, two amount conditions and their custom editors, the Ultimate Inventory System-aware generator classes, both save-system adapters, `UIS QM Demo.unity`, example quest assets, and `Opsive_UIS_Support.pdf`. It contains no assembly definition, package manifest, or other metadata that pins a Quest Machine version.

Pixel Crushers' [Quest Machine 1.2 manual](https://www.pixelcrushers.com/quest_machine/Quest_Machine_Manual.pdf) lists Opsive Ultimate Inventory System as a supported third-party integration and directs users to the manual shipped with each bridge. Because Pixel Crushers updates the bridge independently, the source and PDF included with the matched integration package take precedence over copied setup instructions from another revision.

`UISItemAmountQuestCondition` subscribes to the Ultimate Inventory System Inventory update event while it is false; `UISCurrencyAmountQuestCondition` subscribes to the global Currency collection update event. Both support **At Least** and **At Most** comparisons and mirror the current amount into a selected Quest Machine counter. `UISUtility` resolves a blank owner through the Player tag and an explicit owner through Pixel Crushers' hard GameObject lookup, then searches that object and its children.

`UISAddItemQuestAction`, `UISRemoveItemQuestAction`, `UISAddCurrencyQuestAction`, and `UISRemoveCurrencyQuestAction` perform one immediate Ultimate Inventory System operation and return no result to the quest. Their helper warnings are disabled by default because `UISUtility.debug` defaults to `false`.

---

<a id="page-ultimate-inventory-system-integrations-save-system-integration"></a>

# Save System Integration

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/save-system-integration/)

Use the optional Save System integration when a third-party Save System should coordinate persistence while released Ultimate Inventory System Version 1 continues to serialize its own Inventory data through supported saver boundaries.

## Confirm the package boundary

The current Ultimate Inventory System online integration catalog lists **Save System**, but the released Ultimate Inventory System Version 1 package audited for this page does not ship a matching `.unitypackage`. Sign in to [Opsive Downloads](https://opsive.com/downloads/) and download the current Save System bridge after installing the third-party dependency. The bridge is not present in the base product's Integrations folder before that download. Treat the downloaded bridge and its provider documentation as the compatibility authority.

Before import:

1. Verify the Ultimate Inventory System Save System can save and load one Inventory without the third-party product.
2. Verify the third-party Save System can save and load one simple value without Ultimate Inventory System.
3. Record both product versions and back up the project.
4. Import the downloaded bridge after the dependency, then resolve every compile error before changing save objects.

## Choose one save owner

Do not let two automatic managers independently restore the same Inventory. Decide which system owns:

- save-slot selection and metadata;
- when a save or load starts;
- Ultimate Inventory System Inventory serialization and restoration;
- scene-transition timing;
- completion UI and error reporting.

The safest bridge lets the third-party system orchestrate the slot and timing while an Ultimate Inventory System saver produces and consumes the Inventory payload once.

## Build a minimal round trip

1. Give the test Inventory one Health Potion and a known Gold amount.
2. Register only the Ultimate Inventory System object required by the downloaded bridge.
3. Save to a fresh slot through the third-party Save System.
4. Change both values, then load the same slot.
5. Confirm the Inventory contains the original Item and Currency values exactly once.
6. Restart Play Mode and repeat before adding equipment, hotbars, shops, crafting, or multiple players.

## Verify in Play Mode

Test a new save, overwrite, load, missing file, corrupted or rejected file if supported, scene reload, player respawn, and a target-platform build. Observe Ultimate Inventory System events and the third-party completion callback so UI is shown only after restoration finishes.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| Items double after load. | Check whether both Ultimate Inventory System automatic load and the third-party bridge restore the Inventory. | Keep one restore path and disable the duplicate automatic owner. |
| The slot loads before the Inventory exists. | Check manager, scene, and saver initialization order. | Delay restoration until Ultimate Inventory System managers and the target Inventory are registered. |
| The bridge is absent from the released package. | Check the online Integrations route. | Download the current optional bridge; do not invent a package path inside Ultimate Inventory System. |
| Editor saves work but builds do not. | Check file path, serializer, stripping, and platform permissions. | Test a Development Build and follow the third-party Save System's platform requirements. |

## Related pages

- [Ultimate Inventory System Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)
- [Scene Transitions](https://opsive.com/support/documentation/ultimate-inventory-system/scene-transitions/)
- [Spawn Player](https://opsive.com/support/documentation/ultimate-inventory-system/spawn-player/)
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/)

---

<a id="page-ultimate-inventory-system-integrations-state-designer"></a>

# State Designer

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/state-designer/)

The [State Designer](https://assetstore.unity.com/packages/tools/visual-scripting/state-designer-dots-powered-finite-state-machines-369152?aid=1100lGdc) integration lets States and transitions inspect or change released Ultimate Inventory System Version 1 Items, Currency, Item Actions, panels, interactions, and saves without a custom bridge component.

## Before you begin

- Install released Ultimate Inventory System Version 1 and confirm the target Inventory works without State Designer.
- Install State Designer and run a small State Machine.
- Create the Item Definitions, Item Collections, Currency, Item Action Sets, panels, and save objects that the graph will reference.
- Commit or back up the project before replacing an older bridge.

## Install the integration

1. Sign in to [Opsive Downloads](https://opsive.com/downloads/) and download the State Designer integration for Ultimate Inventory System. The bridge is not included in either base product's Integrations folder before this download.
2. Import `UltimateInventorySystemStateDesigner.unitypackage` after both products compile. Importing it creates the integration files in the project.
3. Let Unity compile and search the State Palette for **Has Item With Definition**, **Add Item**, and **Use Item From Inventory**.
4. Put the first test State Machine on the same GameObject as the target Inventory. Add explicit targets only after the local route works.

The bridge adds Actions and Conditions; it does not create or migrate an Ultimate Inventory System database.

## Build a Health Potion State

1. Create Idle and Use Potion States.
2. Add **Has Item With Definition** as the transition Condition into Use Potion. Select **Health Potion** and amount `1`.
3. Add **Use Item From Inventory** to the Use Potion State. Select the potion's Item Action Set, action index, amount, and collection name used by the working Ultimate Inventory System setup.
4. Return to Idle after the Action finishes or fails.
5. Run the graph with and without the potion and inspect the actual Inventory amount after each path.

## Available Actions and Conditions

- **Items:** Add Item, Remove Item, Has Item With Definition, Has Item With Category, Compare Item Amount, Drop Item From Inventory, and Exchange Item Between Inventories.
- **Currency:** Add Currency, Remove Currency, Has Currency, and Compare Currency.
- **Item use and UI:** Use Item From Inventory, Use Item Object, Interact, and Open Close Panel.
- **Persistence:** Save, Load, and Delete Save.

Match every Item Definition and Category to the same Inventory Database used by the target Inventory. Match collection purpose, collection name, panel name, manager ID, slot index, and action index exactly.

## Verify in Play Mode

1. Run the potion State and confirm the Ultimate Inventory System Item Action produces its visible result.
2. Confirm the runtime Inventory changes; an active State or successful Action alone is not proof.
3. Remove the potion and confirm the Condition stays false and the fallback State remains active.
4. Test a missing Currency Owner, Item User, Inventory Interactor, or panel on a copy of the object and confirm the graph does not hide the setup failure.
5. When using Save, Load, or Delete Save, verify the actual file and restored Inventory state with the same save index.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| Ultimate Inventory System nodes are absent from the State Palette. | Check both products, the imported package, duplicates, and the first Console error. | Install both dependencies first, remove the older bridge, and reimport the current package. |
| An Item Condition returns an unexpected amount. | Check collection purpose, inheritance, and whether the node counts stacks or amounts. | Search the whole Inventory first, then add one restriction at a time. |
| Use Item finds the Item but fails. | Check Item User, Item Action Set, action index, collection name, and action requirements. | Run the same Item Action from Ultimate Inventory System first, then copy its working references. |
| Save reports success but data is not restored. | Check save index, registered savers, and the stored file. | Verify the Ultimate Inventory System Save System directly; the Action only requests that operation. |

## Related pages

- [State Designer integration guide](https://opsive.com/support/documentation/state-designer/integrations/ultimate-inventory-system/)
- [Inventory](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/)
- [Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/)
- [Currency](https://opsive.com/support/documentation/ultimate-inventory-system/currency/)
- [Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)

---

<a id="page-ultimate-inventory-system-integrations-opsive-character-controllers"></a>

# Ultimate Character Controller

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/opsive-character-controllers/)

Use the [Ultimate Character Controller](https://assetstore.unity.com/packages/tools/game-toolkits/ultimate-character-controller-233710?aid=1100lGdc) integration when Ultimate Inventory System should own a character's Items and menus while the character controller equips, animates, and uses weapons. For example, an Iron Sword can appear in an Ultimate Inventory System Bag, move into an Equipment collection, spawn its character-item prefab, and become the active Ultimate Character Controller Item Set without maintaining two independent inventories.

This page covers integration version `3.0.5` for released Ultimate Character Controller Version 3 and Ultimate Inventory System Version 1. Its Integration Inspector requires Ultimate Character Controller `3.0.10+` and Ultimate Inventory System `1.2.16+`. The released packages verified for this workflow are Ultimate Character Controller `3.2.0` and Ultimate Inventory System `1.3.0`. Development versions of Ultimate Character Controller Version 4 and Ultimate Inventory System Version 2 use different components and are outside this page's scope.

## Before you begin

- Install both released products and let Unity compile before importing the integration.
- Create or select the Ultimate Inventory System Inventory Database that the scene's **Inventory System Manager** uses. The supplied `EmptyCharacterInventoryDatabase` is a useful starting point because it includes the expected **Equippable**, **Ammo**, **Single Item**, and **Multi Item** categories.
- Create the character with **Tools > Opsive > Ultimate Character Controller > Character Manager**. The integration converts an existing scene character; it does not create one.
- Save the scene and keep a source-control checkpoint. **Setup Character** replaces the standard Ultimate Character Controller Inventory and Item Set Manager with their integrated counterparts and adds the Ultimate Inventory System components described below.

## Install the integration

1. Sign in to [Opsive Downloads](https://opsive.com/downloads/) and download the Ultimate Character Controller integration for Ultimate Inventory System. The bridge is not included in either base product's Integrations folder before this download.
2. Import the downloaded package after both products have compiled. Importing it creates the integration files in the project. Remove duplicate scripts from an older bridge before importing a replacement.
3. Open **Tools > Opsive > Ultimate Inventory System > Integrations Manager**.
4. Select **Integration Inspectors**, then **Ultimate Character Controller**. Confirm that the version and requirement block matches the products installed in the project.

The imported demo at `Assets/Opsive/UltimateCharacterController/Integrations/UltimateInventorySystem/Demo/Demo.unity` is a useful reference for collection layouts, Item Set Rules, pickups, Item Actions, and bindings. Copy the workflow into your own database and scene rather than editing the demo directly.

## Connect a character

1. Put the Ultimate Character Controller character in the scene and select the database used by the scene's Inventory System Manager or Ultimate Inventory System Main Manager.
2. In the Ultimate Inventory System **Integrations Manager**, open **Ultimate Character Controller > Character Setup**.
3. Assign the scene object to **Character**. **Setup Character** becomes available only when the object has **Ultimate Character Locomotion**.
4. Select **Setup Character** and wait for Unity to report that the character was set up successfully.
5. Select the character and inspect the result before configuring Items.

The setup creates these Ultimate Inventory System Item Collections:

| Collection | Purpose in the integration |
| --- | --- |
| **Default** | The main Bag for Items that are not currently equipped. |
| **Equippable Slots** | An equipped Item Slot Collection with **Primary**, **Secondary**, and **Tactical** slots. |
| **Equippable** | An additional bridge collection for equippable Items that do not need the generated slot layout. |
| **Loadout** | Items that the character receives from its configured loadout rather than restored save data. |

It also adds **Character Inventory Bridge**, **Inventory Item Set Manager**, **Inventory Identifier**, **Item User**, **Currency Owner**, **Inventory Interactor**, and **Inventory Bridge Saver**. Existing Ultimate Character Controller Item Set abilities are retained and their Item Categories are remapped to the selected Ultimate Inventory System database where matching categories exist.

## Create an equippable Iron Sword

1. Open **Tools > Opsive > Ultimate Character Controller > Item Manager** and create the Iron Sword's Ultimate Character Controller Character Item prefab. Use Ultimate Inventory System Item Definitions instead of creating a separate Ultimate Character Controller Item Type for the integrated item.
2. In the Ultimate Inventory System database, make the Iron Sword's category inherit from **Equippable** and **Single Item**. **Single Item** supplies a `GameObject` Item Definition Attribute named **Prefabs**. Use **Multi Item** and its `GameObject[]` **Prefabs** Attribute only when one Item Definition needs more than one Character Item prefab, such as a weapon that can occupy either hand.
3. Create the **Iron Sword** Item Definition and assign its Ultimate Character Controller Character Item prefab to **Prefabs**.
4. On **Character Inventory Bridge**, confirm that **Equippable Category** points to **Equippable** and **Character Item Prefabs Attribute Name** is `Prefabs`. The **Default Item Collection Name**, **Bridge Item Collection Names**, and **Loadout Item Collection Names** must match the character's collections exactly.
5. On **Inventory Item Set Manager**, add an Item Set Rule that permits the Iron Sword in the intended Ultimate Character Controller slot and gives the resulting Item Set the state needed by that Character Item.
6. Add the integration's **Character Equip Unequip** Item Action to the Ultimate Inventory System Item Action Set used by the Equipment UI. That action moves the Item between the Default and bridge collections and asks Ultimate Character Controller to equip or unequip the resulting Item Set.

The Inventory remains the source of truth. An Item is added to Ultimate Inventory System first; when an equippable Item enters a bridge collection, **Character Inventory Bridge** reads its **Prefabs** Attribute, creates or finds the corresponding Ultimate Character Controller Character Item, and asks **Inventory Item Set Manager** to recompute valid Item Sets. Ultimate Character Controller then owns the visible Character Item, equip ability, use ability, animation, and slot behavior.

Use **Item Binding** or the integration's **Item Object Binding** when an Item value such as Attack or Durability must control a property on the spawned Character Item. This keeps persistent values on the Ultimate Inventory System Item while the Ultimate Character Controller prefab supplies its gameplay behavior.

## Configure input and menus

**Setup Character** reuses the character's Opsive player input when one is available and assigns it to **Item User > Inventory Input**. The Ultimate Character Controller abilities and Ultimate Inventory System Item Actions should therefore resolve input from the same player object.

- Keep one supported Opsive `IPlayerInput` implementation on the character.
- Confirm that **Item User > Inventory Input** points to that player's input component.
- Use Ultimate Inventory System Item Actions such as **Character Equip Unequip**, **Character Use**, and **Character Drop** for operations that must pass through the bridge.
- Disable character gameplay input while a full-screen Ultimate Inventory System menu is open, but leave the menu's own UI input and close action enabled.

For input backend and menu-gating details, follow the [Ultimate Inventory System input workflow](https://opsive.com/support/documentation/ultimate-inventory-system/input/).

## Save the bridged Inventory

Use **Inventory Bridge Saver** on a converted character. Do not add the standard **Inventory Saver** to that same Inventory; it does not preserve the bridge's Item Set state and is not compatible with this character workflow.

The Ultimate Inventory System **Save System Manager** still needs **Inventory System Manager Item Saver** so runtime Items are serialized once. **Inventory Bridge Saver** records the non-Loadout Item Collections and the active Item Set index for each Item Set group. During loading it unequips and clears the previous bridge state, restores the collections, and then re-equips the saved Item Sets. Leave loadout Items in the **Loadout** collection because that collection is intentionally not restored from the save.

## Editor checkpoint

Before entering Play Mode, confirm all of the following:

- The Integration Inspector reports bridge version `3.0.5` with no compilation errors.
- The character has **Ultimate Character Locomotion**, an Ultimate Inventory System **Inventory**, **Character Inventory Bridge**, **Inventory Item Set Manager**, **Item User**, and **Inventory Bridge Saver**.
- **Default**, **Equippable Slots**, **Equippable**, and **Loadout** exist and their names match the bridge fields.
- **Equippable Category** comes from the same database as the character's Inventory.
- The Iron Sword inherits from the intended Equippable category, exposes the correctly typed **Prefabs** Attribute, and references a valid Ultimate Character Controller Character Item prefab.
- An Item Set Rule accepts the sword in the intended slot.
- **Item User > Inventory Input** resolves the correct player's input.
- The character has a unique **Inventory Identifier** ID, especially in a scene with multiple converted characters.
- The Save System Manager has **Inventory System Manager Item Saver**, and the character does not also have the standard **Inventory Saver**.

## Verify in Play Mode

1. Give the character one Iron Sword in **Default**. Confirm that the Ultimate Inventory System Bag shows it while no sword Character Item is active.
2. Invoke **Character Equip Unequip** from the Ultimate Inventory System Equipment UI. Confirm that the Item moves to the intended bridge collection, the correct Character Item appears in the expected slot, and the corresponding Ultimate Character Controller Item Set becomes active.
3. Use the normal character input. Confirm that the sword's Ultimate Character Controller use ability and animation run while its Ultimate Inventory System Item data remains available to the Inventory and UI.
4. Unequip the sword. Confirm that the Item returns to **Default** and the Ultimate Character Controller Item Set changes according to its rules.
5. Open and close a full-screen Ultimate Inventory System menu. Confirm that character actions stop while the menu owns input and resume after it closes.
6. Equip the sword, save, change the Inventory, and load the same slot. Confirm that the Inventory contents and active Item Set are restored together.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| The integration does not appear or Unity reports missing types | Check the bridge version, both installed product versions, and whether an older integration copy remains in the project. | Install Ultimate Character Controller `3.0.10+` and Ultimate Inventory System `1.2.16+`, remove the duplicate old bridge, then import integration `3.0.5` after both products compile. |
| **Setup Character** is disabled | Check that **Character** is a scene object with **Ultimate Character Locomotion**. | Create or update the character with the Ultimate Character Controller Character Manager, place it in the scene, and assign that scene object. |
| Character Setup warns about missing database categories | Check the selected Inventory Database for categories named **Equippable** and **Ammo**. | Duplicate `EmptyCharacterInventoryDatabase` or add the required categories, then ensure the scene's Inventory System Manager uses that database. |
| The Iron Sword is in the Inventory but no Character Item appears | Check the Item's inherited category, the **Prefabs** Attribute type and value, and **Character Item Prefabs Attribute Name**. | Inherit from **Single Item** for one prefab or **Multi Item** for an array, assign the prefab, and keep the Attribute name synchronized with the bridge. |
| The Character Item appears but cannot become active | Check the prefab's Ultimate Character Controller slot and the Inventory Item Set Manager's rules and category. | Make the slot and Item Set Rule agree, then verify that the rule creates a valid Item Set for the sword. |
| An Ultimate Inventory System Equip action changes the UI but not the character | Check which Item Action the Equipment UI invokes and which collection receives the Item. | Use the integration's **Character Equip Unequip** action and move equippable Items through a collection listed in **Bridge Item Collection Names**. |
| Item Actions or character controls do not respond | Check **Item User > Inventory Input**, the character's Opsive input component, and whether a menu left gameplay input disabled. | Point Item User to the correct player input, remove competing input owners, and restore gameplay input when the menu closes. |
| Loading duplicates Items or restores the wrong equipped set | Check for both **Inventory Saver** and **Inventory Bridge Saver**, then inspect the manager's Item saver. | Keep **Inventory Bridge Saver** on the character, remove the standard Inventory Saver from that Inventory, and add **Inventory System Manager Item Saver** to the Save System Manager. |
| A second character reports a duplicate Inventory Identifier | Check the **Inventory Identifier > ID** values on every converted character. | Give each persistent Inventory a unique ID, or remove Inventory Identifier and Inventory from objects that do not own a saved Inventory. |

## Related pages

- [Complete Ultimate Character Controller integration reference](https://opsive.com/support/documentation/ultimate-character-controller/integrations/ultimate-inventory-system/)
- [Ultimate Character Controller Character Item creation](https://opsive.com/support/documentation/ultimate-character-controller/items-inventory/item-creation/)
- [Ultimate Character Controller Item Set Rules](https://opsive.com/support/documentation/ultimate-character-controller/items-inventory/item-set-rules/)
- [Ultimate Inventory System Item Categories](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-category/)
- [Ultimate Inventory System Item Definitions](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/item-definition/)
- [Ultimate Inventory System Item Collections](https://opsive.com/support/documentation/ultimate-inventory-system/inventory/item-collections/)
- [Ultimate Inventory System Item Actions](https://opsive.com/support/documentation/ultimate-inventory-system/item-actions/)
- [Ultimate Inventory System input](https://opsive.com/support/documentation/ultimate-inventory-system/input/)
- [Ultimate Inventory System Save System](https://opsive.com/support/documentation/ultimate-inventory-system/save-system/)

## Developer and version reference

The released bridge is compiled directly against the Ultimate Character Controller, Ultimate Inventory System, and Opsive Shared assemblies, so both products must be present before its scripts can compile. The verified integration package declares no optional assembly-version fallback.

| Responsibility | Runtime owner |
| --- | --- |
| Item identity, amounts, Item Collections, Currency, and inventory UI | Ultimate Inventory System **Inventory** and related Ultimate Inventory System components |
| Synchronizing bridge collections with Character Items and Item Sets | **Character Inventory Bridge** and **Inventory Item Set Manager** |
| Character Item prefabs, slots, equip/use abilities, animation, and item states | Ultimate Character Controller Version 3 |
| Player input used by Ultimate Inventory System Item Actions | **Item User > Inventory Input**, through Opsive Shared `IPlayerInput` |
| Inventory contents and active Item Set indexes across save/load | **Inventory Bridge Saver** plus **Inventory System Manager Item Saver** |

The integration also supplies `CharacterEquipUnequipItemAction`, `CharacterUseItemAction`, `CharacterDropItemAction`, `CharacterQuantityDropItemAction`, `ItemObjectBinding`, three Ultimate Inventory System-aware Item Set Rule types, pickup support, and Ultimate Character Controller-aware ammo modules. Use those extension points only after the editor workflow above works end to end.

---

<a id="page-ultimate-inventory-system-integrations-unity-localization"></a>

# Unity Localization

[View this page online](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/unity-localization/)

The [Unity Localization](https://docs.unity3d.com/Packages/com.unity.localization@1.5/manual/index.html) integration lets Ultimate Inventory System menus display translated Item names, descriptions, and interface labels without renaming the Item Definitions that gameplay uses. For example, the same Health Potion and Iron Sword can appear in English, French, or Spanish while their Inventory identities remain unchanged.

The released Ultimate Inventory System Version 1 `master` project uses Unity `2022.3.62f3`. Unity lists Localization `1.5.12` as the released package for Unity 2022.3, and the two integration scripts use APIs that remain available in that release. The integration installer has no dependency manifest or version pin, so it will not install Localization for you. An older Unity Editor should use the latest released Localization 1.x version offered for that Editor and must be tested separately.

## Before you begin

- Confirm that the Ultimate Inventory System Inventory, Item Views, Item Description, Shop, and other menus work in one language first.
- Decide which database values will generate localization keys. Keep Item Definition, Item Category, Currency, and Crafting Recipe names stable because Ultimate Inventory System and the integration use them as identifiers.
- Choose a key convention before translating. This page uses `Health Potion`, `Health Potion_Description`, `Iron Sword`, and `Iron Sword_Description`.
- Decide which Locales the first release supports. The included demo provides English, French, and Spanish examples.

## Install and configure localization

1. Open **Window > Package Manager** and install `com.unity.localization`. For the released Ultimate Inventory System master project on Unity 2022.3, use the released Localization 1.5 line.
2. Sign in to [Opsive Downloads](https://opsive.com/downloads/), download the Unity Localization integration, and import it. The bridge is not included in the base product's Integrations folder before download; importing it creates the integration files in the project.
3. Confirm that Unity adds `LocalizeItemView.cs`, `AutoLocalizeStringEvent.cs`, and the demo beneath `Assets/Opsive/UltimateInventorySystem/Integrations/UnityLocalization`.
4. Open **Edit > Project Settings > Localization**. Create a project-owned **Localization Settings** asset or assign the one your project already uses.
5. Add the supported Locales and configure the startup selector that chooses the initial Locale.
6. Open **Window > Asset Management > Localization Tables** and create two String Table Collections: one for database-derived content and one for fixed interface text.

![Project Settings Localization panel with Active Settings empty and a Localization Settings asset available in the picker](https://opsive.com/wp-content/uploads/2021/10/LocalizationSettings.png?v=d6ca3f83b416)

Only one Localization Settings asset is active in Project Settings. You may temporarily assign the demo's asset to inspect `Localization Demo.unity`, but replace that reference with your project-owned settings before deleting the demo or shipping the game.

The included demo has these two collections:

- `LocalizationTable_UltimateInventorySystem_LocalizedDemo_InventoryDatabase`
- `LocalizationTable_UltimateInventorySystem_LocalizedDemo_UI`

![Localization Tables window showing Potion, Wood, and Wooden Sword keys with English, French, and Spanish values](https://opsive.com/wp-content/uploads/2021/10/LocalizationTable-1.png?v=dd82a98554ac)

## Create the Item and interface keys

Use the database-content table for Item names, descriptions, categories, and recipe names. Use the interface table for stable labels such as Buy, Sell, Cancel, Equipment, and Bag.

| Key | English example | Purpose |
| --- | --- | --- |
| `Health Potion` | Health Potion | Item name generated from `{0}`. |
| `Health Potion_Description` | Restores health when consumed. | Description generated from `{0}_Description`. |
| `Iron Sword` | Iron Sword | Item name generated from `{0}`. |
| `Iron Sword_Description` | A dependable one-handed weapon. | Description generated from `{0}_Description`. |
| `Buy` | Buy | Fixed Shop label. |
| `Cancel` | Cancel | Fixed confirmation-panel label. |

The integration's demo includes CSV files for both collections. For an existing project, export the Inventory Database through the Ultimate Inventory System Import/Export workflow, copy the relevant names and descriptions into a Localization CSV, and then import that CSV into the String Table Collection. Unity's current [CSV workflow](https://docs.unity3d.com/Packages/com.unity.localization@1.5/manual/CSV.html) requires a **Key** or **Id** column.

Do not translate the actual Ultimate Inventory System object names. Translate the values in the String Tables. This keeps save data, Item lookups, recipes, Shops, and other systems pointed at the same database objects in every Locale.

## Localize an Item View

**Localize Item View** must be on the same GameObject as the Ultimate Inventory System Item View or Item Description so the View discovers and updates it. **Auto Localize String Event** normally sits on the Text or TextMesh Pro label that it updates, which may be a child GameObject:

1. Add **Auto Localize String Event** to the GameObject that has the target Unity UI Text or TextMesh Pro label.
2. Set its **Table Collection** to the database-content String Table Collection. The Ultimate Inventory System module changes only the table entry, so this table reference must already be configured.
3. Add **Localize Item View** to the Ultimate Inventory System View GameObject. Assign **Text** and the matching **Localize String Event**.
4. For an Item name, leave **Attribute Name** empty and set **Key Format** to `{0}`. A blank Key Format also uses the Item name.
5. For a description, set **Attribute Name** to `Description`, enable **Clear On Attribute Missing**, and set **Key Format** to `{0}_Description`.
6. Treat **Default Text Value** as another table entry key. Create that entry in every Locale; the source does not use this field as literal fallback text.
7. Enable **Replace White Space With Underscores** only when the String Table uses keys such as `Health_Potion`. The setting must match every imported key.

![Localize Item View Inspector with Localize String Event, attribute, default, clear, key-format, and whitespace fields](https://opsive.com/wp-content/uploads/2021/10/Localize_ItemView-1.png?v=5cbdb0b319f6)

The format tokens are:

| Token | Value |
| --- | --- |
| `{0}` | Item name |
| `{1}` | Attribute value converted to text |
| `{2}` | Item Definition name |
| `{3}` | Item Category name |
| `{4}` | Attribute name |

**Disable On Clear** can hide a selected GameObject when no Item is available or when a required attribute is missing. When an Item becomes available again, the integration reactivates that GameObject.

![Name and Description Localize Item View components using key formats {0} and {0}_Description](https://opsive.com/wp-content/uploads/2021/10/Localization_ItemView_Description-1.png?v=240e4aa09032)

### Prevent Item Description text conflicts

The standard **Item Description** component writes directly to **Item Name Text** and **Description Text**. If those fields remain assigned, it can overwrite the localized result with the database language.

Clear both direct text references and let the two **Localize Item View** modules write the name and description. Keep **Item Description > Description Attribute Name** set to `Description`, and separately set the description module's **Attribute Name** to `Description`; the latter field controls whether **Clear On Attribute Missing** runs.

## Localize fixed and changing labels

Use **Auto Localize String Event** for labels whose key is known in advance, such as Buy, Sell, Bag, and Equipment. Set the table and entry in its **String Reference**. At runtime it finds a Unity UI Text or TextMesh Pro component on the same GameObject when its text target is unassigned, then writes each localized value to that label.

![Auto Localize String Event targeting the inventory database table, Wood entry, and a TextMesh Pro label](https://opsive.com/wp-content/uploads/2021/10/AutoLocalize.png?v=098f82748615)

For an Ultimate Inventory System component that chooses a label dynamically, connect its String event to `AutoLocalizeStringEvent.SetTableEntryReference`. The included **Confirm Cancel Panel** prefab routes **On Confirm Text Change (String)** and **On Cancel Text Change (String)** this way.

![Confirm Cancel Panel routing confirm and cancel text-change events to AutoLocalizeStringEvent.SetTableEntryReference](https://opsive.com/wp-content/uploads/2021/10/ConfirmCancelPanel.png?v=bf7a6df3644d)

## How Locale changes update the UI

`AutoLocalizeStringEvent` extends Unity's **Localize String Event**. Unity refreshes that component when the selected Locale or its String Reference changes, and the integration writes the refreshed value to the assigned text target. An open Shop or Crafting Menu should therefore change language without being rebuilt.

![Spanish Shop menu with localized navigation, Item names, description, quantity, total cost, and action controls](https://opsive.com/wp-content/uploads/2021/10/ShopSpanish-1024x576.png)

![French Crafting menu with localized recipes, ingredients, prices, and the selected Wizard Wand description](https://opsive.com/wp-content/uploads/2021/10/CraftingFrench-1-1024x577.png)

The demo exposes Unity Localization's Game view Locale selector for English, French, and Spanish. A shipped game needs its own language selector or startup-locale policy.

![Game view Locale selector listing English, French, and Spanish](https://opsive.com/wp-content/uploads/2021/10/LocaleDropdown-1.png?v=7f7bb80301ed)

Only configured labels change. The bridge does not automatically find every Ultimate Inventory System Text component, translate database objects, or localize Sprites, audio, and other assets. Unity supports localized assets, but this installer contains no Ultimate Inventory System asset-localization module; add a project-specific component when an Item attribute must choose a localized asset.

## Editor checkpoint

Before entering Play Mode, confirm all of the following:

- Unity has one copy of the integration scripts and no missing Localization namespaces.
- **Edit > Project Settings > Localization** references the project-owned Localization Settings asset.
- Every supported Locale exists in both String Table Collections.
- Health Potion, Iron Sword, description, and interface keys use one consistent spacing and suffix convention.
- Every **Localize Item View** has its Text and Localize String Event assigned.
- Every Localize String Event has the correct **Table Collection**; the Ultimate Inventory System module does not set it.
- Every nonempty **Default Text Value** exists as a key in the same table.
- **Item Description > Item Name Text** and **Description Text** are empty where localized modules own those labels.
- Fixed Shop, Crafting, Bag, and Equipment labels have an Auto Localize String Event or equivalent Unity localization component.

## Verify in Play Mode

1. Start in English and open the Bag. Select Health Potion and Iron Sword; confirm that each name and description comes from the database-content table.
2. Open the Shop and confirm that Buy, Sell, Cancel, prices, Item names, and descriptions use their intended tables.
3. Change to Spanish while the Shop remains open. Confirm that configured labels update immediately and that the selected Item does not change.
4. Change to French while the Crafting Menu remains open. Confirm that the recipe, ingredients, and selected Item description update without reopening the panel.
5. Select an Item with no Description attribute. Confirm that **Clear On Attribute Missing**, **Default Text Value**, and **Disable On Clear** produce the intended empty or fallback state.
6. Remove one translation on a test copy of the table. Confirm that the configured Unity fallback behavior is visible and no untranslated database text overwrites it.
7. Test a player build as well as the Editor. Locale initialization, table loading, and platform behavior can differ from the Game view selector.

## Troubleshooting

| Symptom | Check | Fix |
| --- | --- | --- |
| Unity reports missing `UnityEngine.Localization` namespaces | Check whether Localization was installed before the integration. | Install the Editor-compatible `com.unity.localization` 1.x package, then reimport one integration copy. |
| Item names remain in the database language | Check for Localize Item View, its Text and event references, and the String Reference table. | Add or reconnect both integration components and set the correct Table Collection. |
| A translated description briefly changes back | Check **Item Description > Item Name Text** and **Description Text**. | Clear the direct text references so only Localize Item View writes those labels. |
| Text changes only after closing and reopening a panel | Check that Auto Localize String Event is enabled and targets the actual Text or TMP component. | Put it on the same GameObject as the label or assign the text target explicitly. |
| The wrong or no entry appears | Compare Key Format, spaces, underscores, suffix, capitalization, and Table Collection with the table key. | Make the generated key exactly match the imported key and keep one naming convention. |
| Clearing an Item shows a raw key or blank text | Check whether **Default Text Value** is empty or missing from the selected table. | Add that value as a localized table key, or leave it empty intentionally. |
| One button remains in English | Check whether the label is fixed UI text rather than an Item View value. | Add Auto Localize String Event or another Unity localization component to that specific label. |
| Localization breaks after removing the demo | Check whether Project Settings still references the deleted demo Localization Settings or its Locales. | Assign the project-owned settings and tables before deleting demo content. |
| Localized Sprites or audio do not change | Check whether a string-only integration component was used. | Use Unity's localized-asset workflow and write an Ultimate Inventory System-specific binding for the relevant attribute. |
| WebGL hangs or cannot resolve an Ultimate Inventory System-localized label | Check whether the project uses the shipped synchronous `LocalizeItemView.GetLocalizedString()` path. | Replace or extend the module with an asynchronous localized-string workflow; Unity does not support `WaitForCompletion` on WebGL. |

## Related pages

- [Integrations](https://opsive.com/support/documentation/ultimate-inventory-system/integrations/)
- [UI](https://opsive.com/support/documentation/ultimate-inventory-system/ui/)
- [Item View](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-view/)
- [Item Description](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/item-description/)
- [Attributes](https://opsive.com/support/documentation/ultimate-inventory-system/attributes/)
- [Import and export](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/import-export/)
- [UI Designer](https://opsive.com/support/documentation/ultimate-inventory-system/editor-window/ui-designer/)

## Developer and version reference

The released Ultimate Inventory System Version 1 package verified for this page is version `1.3.0` on Unity `2022.3.62f3`. Its `Localization.unitypackage` contains exactly two runtime scripts, five localized demo prefabs, one demo scene, three Locale assets, two String Table Collections, and two CSV files. It contains no assembly definition or package manifest that pins `com.unity.localization`.

Unity currently lists Localization `1.5.12` as released for Unity 2022.3. The verified integration APIs remain present in that package: `LocalizeStringEvent.StringReference`, `RefreshString()`, and the protected virtual `UpdateString(string)` method. This source-level check is not a promise that every older serialized demo asset will upgrade without review; test the imported prefabs after changing Localization versions.

`LocalizeItemView.SetValue` builds a key from the current Item and optional attribute, assigns `StringReference.TableEntryReference`, and then calls `GetLocalizedString()` synchronously. `Clear` uses **Default Text Value** as another entry reference. Unity documents that synchronous call as using `WaitForCompletion`, which is unsupported on WebGL and can also make first-use table loading visible. Preloading the relevant String Tables can reduce first-use work on supported platforms; replace this module with an asynchronous implementation for WebGL.

`AutoLocalizeStringEvent.Awake` finds Unity UI Text and, when TextMesh Pro support is present, TMP Text on the same GameObject if its serialized target is empty. Its `UpdateString` override writes every refreshed value to that target. `SetTableEntryReference(string)` changes the entry and calls `RefreshString()`, which is why it can be connected directly to Ultimate Inventory System String UnityEvents.
