Skip to main content

Placement and routing

Try Add Item with no named container is answered by data. No code decides that a potion reaches the belt before the pack.

The order

  1. The item's preferences — its Container Placement fragment: an ordered list of containers it wants, plus a query for containers it will tolerate at all.
  2. Container priority — highest first, among containers that will take it.
  3. The container's own word — its Item Query, its rules, its remaining capacity. All three have to agree, so a container may want an item and still be full.

Only when all of that passes does the item land.

Authoring the item side

Add a Container Placement Fragment to the definition:

FieldMeaning
Preferred ContainersOrdered tags. The first that accepts wins.
Container QueryContainers this item tolerates at all. Empty means anywhere.

A health potion:

Preferred Containers:  Inventory.Container.Hotbar
Inventory.Container.Main
Container Query: (empty)

It reaches for the belt, falls back to the pack, and will live anywhere if both are full.

Ammunition that must never sit in the equipment paperdoll:

Preferred Containers:  Inventory.Container.Quiver
Container Query: any tags match → Inventory.Container.Quiver,
Inventory.Container.Main

Authoring the container side

Priority orders containers for items that expressed no preference. In the demo: hotbar 100, main grid 50, equipment −100. A picked-up item fills the belt, then the pack, and only reaches equipment if everything else is full.

Item Query is the container's veto, matched against the item's category plus its tags:

Equipment container → any tags match → Inventory.Slot

Only items carrying a slot tag are ever routed there.

A permissive slot is not a permissive container

An off-hand slot with empty Accepted Tags takes any item — that is what an off-hand is. Without a container-level Item Query, that one slot turns the whole paperdoll into overflow storage for everything the player picks up. The layout says what fits in a slot; the query says what the container will accept at all. You want both.

Naming a container

Inventory->TryAddItem(Sword, 1, EquipmentTag);

Naming a container is an instruction, not a hint. If that container refuses, the call fails rather than putting the item somewhere else. That is what you want for "equip this": failing loudly beats silently stuffing a sword into the backpack.

Asking before doing

UEDContainer* Where = Inventory->FindContainerFor(Definition, Count);
if (!Where)
{
ShowMessage(TEXT("You cannot carry any more."));
}

FindContainerFor applies the same rules TryAddItem does and returns nullptr when nothing will take it — the honest answer for a "cannot carry" prompt, rather than trying and reacting to failure.

For a reason as well as an answer, ask a specific container:

const FEDPlacementCheckResult Check = Container->EvaluateAddItem(Definition, Count);
// Check.bCanAdd, Check.Error, Check.Reason (player-readable text)

Where an item sits inside a container

Container choice and slot choice are different steps. Once a container is chosen, its layout picks the address:

  • List — the first free index.
  • Slot — the first free slot that accepts it, preferring slots that name what they take over slots that take anything.
  • Grid — the first free footprint, rotating the item if it only fits the other way round.

Passing an explicit address makes it an instruction: an illegal placement fails with InvalidPlacement rather than sliding the item elsewhere.

Total caps

A Stack fragment's Maximum Quantity caps how many of an item an actor may hold in total, across every container. TryAddItem respects it, so "you can carry ten bandages" needs no code.

Where next