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. A RemoveItem result is the amount actually removed. An AddItem result usually measures acceptance but is subject to the Return Overflow limitation below. 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.

With Return Overflow enabled, a partial addition with a known source can replace the returned Amount with the amount returned to that source. For example, a request of 3 can store 1 in the destination and return Amount 2 after the other 2 return to the origin. This is a return-value limitation: inspect destination state or its per-stack add events when the exact accepted amount matters, or keep Return Overflow disabled and handle the remainder explicitly.

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 For removal, read ItemInfo.Amount as removed and ItemStack.Amount as remaining. For addition, also check Return Overflow, which can replace the returned amount with the amount returned to the source.
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.

Use the Item Info API

Construct values without losing context

Create a bare request when only Item and Amount matter:

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:

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.

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:

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:

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 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.

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.