Inventory System

The Inventory System package was heavily refactored in the 1.5.x architecture shift.

It now follows a more modular runtime layout and is designed to work well with the Data package and CatalogKey-driven authoring patterns.

What This System Solves

  • defining items and item instances
  • moving items between inventories/slots
  • building UI views (inventory, equipment, tooltips)
  • composing item behavior (equip, consume, stat preview, etc.) via features

Item database (IInventoryItemDatabase)

UI and inventory code take IInventoryItemDatabase (lookup definitions, icons, CreateItem, etc.). Resolve it with ServiceLocator.Get<IInventoryItemDatabase>() after registration.

Default implementation: InventoryItemDatabaseSO — a ScriptableObject that reads item definitions from IAssetCatalog<InventoryItemDefinitionSO> / ICatalog registered under the items provider id (same pattern as samples). Use the asset as-is, subclass it, or provide your own IInventoryItemDatabase and register that instance against the interface.

The old InventoryItemDatabase type name is removed; migrate your ItemDatabase (or similar) to InventoryItemDatabaseSO or IInventoryItemDatabase.

Item definition assets (InventoryItemDefinitionSO)

Definitions are always DataSO<InventoryItemDefinition> via InventoryItemDefinitionSO. There is no InventoryItemDefinitionSO<T>—catalogs and samples expect that concrete SO type.

  • Optional thin subclass for menu naming only: class EquipmentSO : InventoryItemDefinitionSO { } with [CreateAssetMenu(...)].
  • Equipment stats / slot type: use EquipableFeature (and related RPG bridge features) on InventoryItemDefinition.Features, instead of a parallel generic definition type on the SO.

Key Ideas

  • Data-first definitions: item “definitions” are authored as data (good for JSON, remote content, versioning).
  • Key-based asset lookup: fields like icons can be stored as keys (e.g. CatalogKey) while still showing rich inspector previews.
  • Feature composition: items gain gameplay capabilities by attaching feature modules, instead of relying on deep inheritance trees.

Tooltips: stat lines moved to features

Inventory tooltips no longer call a virtual like GetItemStatDisplayLines on definitions. The slot tooltip builder calls InventoryItem.BuildItemTooltipStats, which loops InventoryItemDefinition.Features and, for each IItemFeature, calls BuildTooltipContent(VisualElement host, in ItemTooltipContext context).

Migrate custom stat/ingredient lines by implementing IItemFeature (plus IFeature.CloneFeature), add an instance to the item definition’s Features list, and build VisualElement children on the host (see ItemTierFeature for a small example, EquipableFeature for RPG stat text). Use ItemTooltipContext for IInventoryItemDatabase, optional attribute-name filtering, and equipment comparison via GetComparison.

Note: InventoryItemDefinition.Features is typed as List<IFeature> (the base interface). If your project has other IFeature sub-interfaces (e.g. unit feature definitions), the Inspector dropdown will show all types. To restrict the dropdown to inventory features only, change the list type to List<IItemFeature> and register a [CustomPropertyDrawer(typeof(IItemFeature), true)] that scans only for IItemFeature types. See Sub-interface type filtering for the full pattern.

ItemTierFeature tooltips resolve the tier line through IValueCatalog registered under InventoryConstants.ItemTierCatalogId (GetDisplayValue on the effective CatalogKey, fallback to the raw key). Slot USS on the Background button adds a slug derived from that display when available (e.g. common from Common), otherwise from the key (e.g. 0 stays 0). Style tier chrome in USS against those slugs; ClearSlotVisual removes slugs and legacy raw-key classes for all keys listed in the tier ICatalog.

Slot click and the tooltip (0.3.2)

A slot click closes the tooltip, runs your OnClick handler, then re-shows the tooltip — right for inspect-style clicks, wrong when the handler moved, replaced, or consumed from the item (place-into-loadout flows): the stale tooltip floated over the new state until the pointer left the slot. Since 0.3.2 the re-show requires the same item instance at the same amount; handlers that mutate the slot get a clean close with no re-show. No consumer changes needed — delete any deferred close-all workarounds.

Grid data modes (0.4.2)

The 0.4.1 release carried only a version bump; these modes ship in 0.4.2.

InventoryViewPagination reads its items in one of two ways, chosen at construction:

  • Bound (inventory given): the view pages the live InventoryBase.Items and re-reads them on Refresh(). Attach it to the screen or modal view with AttachToView(uiView) and it also rebuilds on every show — fade-in and occlusion reveal alike — so a grid built at scene boot never pages a stale snapshot. SetItemList on a bound view is a caller bug and logs an error (it was a silent no-op before 0.4.2).
  • Unbound (inventory: null): the view pages whatever list you pass to SetItemList — a gift picker showing only giftable items, a shop stock, a reward roll. Call Refresh() after mutating that list in place.
csharp
// bound: live inventory, refreshes itself on every show var grid = new InventoryViewPagination(itemDatabase, player.Inventory, slotTemplate, gameObject, root, container, tooltip); grid.AttachToView(UIView); // unbound: a curated list var picker = new InventoryViewPagination(itemDatabase, null, slotTemplate, gameObject, root, container, tooltip); picker.SetItemList(giftableItems);

Filter chips (0.4.3)

ShowOnlyFilterButtons (hide filter chips by index) is removed. Declare the group's universe on the grid instead: view.SetFilterOptions(0, new[] { FilterIds.Meal, FilterIds.Potion }). Values outside the set are ignored, their chips are hidden, and with nothing active the grid shows the union of the allowed values, so no click sequence can widen a curated view (Luna GridViewBase, 2.1.4).

Suggested Mental Model

  • Definition: “what this item type is” (static data)
  • Instance: “a concrete owned item” (runtime state like stack count, durability, rolled stats)
  • Slot: “a location that can hold an item” (inventory slot, equipment slot, hotbar slot)
  • Feature: “optional behavior attached to a definition/instance” (equipable, consumable, stat provider, etc.)

Package Layout (Common Areas)

  • Runtime/Item/Core: definitions, references, item databases
  • Runtime/Item/Features: feature modules (compose behavior)
  • Runtime/Item/Slot: slot controllers, visuals, tooltip builders
  • Runtime/UI: inventory/equipment UI controllers and views
  • Runtime/ItemStats: stat line data and controllers (UI-friendly formatting)
  • Data.DropTable/Runtime: weighted drop sources and roll helpers — see Drop Table

Integration Points

  • Data Package: makes “definitions as data” practical (default vs actual workflows, JSON tools).
  • Data Catalogs + CatalogKey: decouple definitions from direct Unity asset references while keeping authoring comfortable.
  • RPGStats (optional): when you want item features to drive stat deltas, comparisons, and equipment rules.

What Changed in 1.5.0 (High-Level)

  • inventory became more modular (separated responsibilities and assemblies)
  • moved toward feature-driven item behavior
  • stronger emphasis on key-based references and data-driven definitions

Settings

Theme

Light

Contrast

Material

Dark

Dim

Material Dark

System

Sidebar(Light & Contrast only)

Light
Dark

Font Family

DM Sans

Wix

Inclusive Sans

AR One Sans

Direction

LTR
RTL