The inventory manager
UEDInventoryManagerComponent is the inventory of an actor: every container it carries, in one
component, answering questions about the actor rather than about any one bag.
Why one component
The alternative — a component per container — means every system that touches the inventory has to know how many bags exist and thread a reference to each one. Adding a stash becomes a component, a variable, and an edit to everything that counts items.
Here, adding a stash is a line in an array. And "how many arrows do I have" spans the quiver, the pack and the bag being worn without the caller knowing those exist.
Setup
Inventory = CreateDefaultSubobject<UEDInventoryManagerComponent>(TEXT("Inventory"));
Inventory->InitialContainers = { HotbarDef, MainDef, EquipmentDef };
Inventory->InitialItems.Add(FEDInitialItem{ StarterSword, 1, EquipmentTag });
| Property | Meaning |
|---|---|
| Initial Containers | Built on the authority at BeginPlay, in this order. |
| Initial Items | Granted once every container exists — so an item that belongs in the quiver is never put in the pack just because the quiver was declared second. |
| Default Container Query | Which container catches an item nothing else claims. |
| Stranded Item Handler Classes | What happens to contents when a container is removed. |
| Watched Definitions | Narrows the total-changed event. Empty reports everything. |
| Max Session Distance | How far the actor may get from an open world container before it closes. |
Finding it
UEDInventoryManagerComponent* Inv = UEDInventoryManagerComponent::Find(SomeActor);
Find asks IEDInventoryOwner first and falls back to the actor's components. Implement the
interface when the answer is not the obvious one — a Pawn forwarding to its PlayerState so the
inventory survives a respawn.
Asking about containers
UEDContainer* Hotbar = Inv->GetContainer(HotbarTag); // first match, hierarchical
Inv->GetContainersByTag(BagTag, OutContainers); // all of a kind
UEDContainer* One = Inv->GetContainerById(SavedGuid); // exactly one
Inv->GetContainersByItem(BackpackHandle, OutContainers); // what an item brought
Inv->GetContainers(OutContainers); // everything
Inv->GetContainersWithTags(TraitTags, OutContainers); // by descriptive tags on the definition
GetContainerDefinition(Tag) gives back the asset a container was built from, which is what a UI
needs for a tab label or icon.
Acting on the whole inventory
These span every container and are authority-only.
| Call | Behaviour |
|---|---|
TryAddItem(Definition, Count, PreferredContainer) | Routed by data when no container is named. All-or-nothing per container — it does not spread one stack across several. |
TryRemoveItems(Definition, Count) | Spends across containers, smallest piles first. All-or-nothing overall. |
TryRemoveItem(Handle) | Removes one specific stack, wherever it is. |
TryMoveToContainer(Handle, TargetTag, Count) | Moves between this actor's own containers. |
GetItemCount / HasItem | Summed across everything. |
FindItem(Handle, OutEntry) | Which container holds a handle. |
FindContainerFor(Definition, Count) | Where an item would go — the honest answer for a "cannot carry that" prompt. |
Naming a container turns a hint into an instruction: if that container refuses, the call fails rather than quietly putting the item elsewhere. That distinction matters for "equip this", which should fail loudly.
Gaining and losing containers at runtime
UEDContainer* Satchel = Inv->AddContainer(SatchelDefinition); // a quest reward
Inv->RemoveContainer(Satchel); // taken away again
Inv->RemoveContainerById(Guid);
Inv->RemoveContainerByTag(Tag); // the first of a kind
A container that belongs to an item is added with AddNestedContainer(Definition, OwningItem) and
cannot be removed on its own — RemoveContainer refuses it and says so. Removing it directly
would leave the item convinced it still had storage, with nothing to reopen it. Move or remove the
item and its container follows. See Nested containers.
What happens to the contents
Removing a container offers each item to stranded-item handlers in order; the first that takes it owns it.
| Handler | What it does |
|---|---|
UEDStrandedItemHandler_Rehome (default) | Puts the item in another container the owner has, using the same placement rules a pickup would. |
| your own | Subclass UEDStrandedItemHandler in C++ or Blueprint — drop it at the player's feet, mail it, charge storage. |
Anything no handler accepts is destroyed and logged as a warning. At that point the game has not said what should happen to a player's things, and neither silently deleting them nor leaking the container is an acceptable default.
Events
| Event | Fires when |
|---|---|
OnInventoryChanged | Anything in any container changed. One binding covers containers gained later. |
OnStackCountChanged | An item's actor-wide total changed. Quest counters, ammo readouts, pickup toasts. |
OnContainersChanged | A container was added or removed — or became identifiable on a client. |
OnInitializationFinished | Setup finished, or gave up. |
OnSessionOpened / OnSessionClosed | A world container was opened or closed. |
WhenReady(Callback) runs a callback once the inventory is usable, immediately if it already is.
Every system that touches an inventory at startup hits the same race — containers are built in
BeginPlay on the server and arrive later still on clients — and polling for it is what everybody
writes instead, always slightly wrong.
Open containers
The manager also tracks which containers elsewhere in the world this actor has open, because that is a question about the actor too.
Inv->OpenSession(ChestContainer); // safe from a client; the server validates range
Inv->CloseSession(ChestContainer);
Inv->HasOpenSession(ChestContainer);
The server owns the list and re-checks the distance, so walking away closes the screen through
OnSessionClosed instead of leaving a chest usable from across the map. MaxSessionDistance sets the
leash; 0 disables it. Nothing ticks until something is open.
Where next
- Placement and routing — how a container is chosen
- Transactions — what the
Try*calls actually run - Replication — what a client is allowed to believe