Design an inventory system for a multiplayer Unreal Engine game. Players carry many items — stackable consumables and unique stateful items (durability, ammo) — and designers must define new item types without a programmer or a recompile. The same item type appears in many inventories, so item definitions should be shared rather than duplicated per copy. Inventory contents must be authoritative on the server and not trustable from the client (a client must not be able to grant itself items). The inventory UI must update when items are added, removed, or moved without polling every frame, and the system should scale to large inventories without re-sending the whole contents on every small change. Describe where inventory state and item definitions live, how the UI stays in sync, where authority lives, and the trade-offs of your approach.
Put an UInventoryComponent on the owner holding an array of item entries; describe items as UItemDataAsset and reference them by id. Replicate the entry array server-side; the UI binds to a change delegate so adding or moving items rebuilds slots.
- ✗Spawning a full Actor per item instead of referencing a lightweight shared DataAsset definition
- ✗Polling the inventory every tick from the UI instead of binding to a change delegate
- ✗Putting inventory state on the client and trusting it, instead of replicating from the server
- →How would you handle item stacking and split/merge operations across slots?
- →Why use a
FastArraySerializerfor the entry array instead of a plain replicatedTArray?
Key classes
UItemDataAsset— immutable item definition: icon, name, type, max stack size, effects. Authored by a designer, exists as a single shared instance.FInventoryEntry— aUSTRUCTholding a reference to theUItemDataAsset(or itsid), stack count, and slot index.UInventoryComponent— aUActorComponenton the owner (Pawn/PlayerState), holds aTArray<FInventoryEntry>and exposes the API:AddItem,RemoveItem,MoveItem.UInventoryWidget— a UMG widget bound to anOnInventoryChangeddelegate.
Data model
An inventory entry references the definition rather than copying it. Stackable items live in one entry with a Quantity field; unique stateful items (durability, ammo) get their own entry with an extra FInstanceData blob.
Data flow
- Client presses "pick up" → Server RPC on
UInventoryComponent. - The server validates (capacity, distance) and mutates
TArray<FInventoryEntry>. - The array replicates; the client
OnRepfires and callsOnInventoryChanged. - The widget rebuilds slots only from that delegate — never by polling in
Tick.
Replication
The entry array must be Replicated. For large inventories use FFastArraySerializer — it replicates only changed entries (deltas) instead of the whole array. The UItemDataAsset definition itself is not replicated: it exists on every machine, only the reference travels.
Designer-facing config
Each item is its own UItemDataAsset asset in the Content Browser. The designer sets stack, type, and effects without a programmer. A starting loadout is an array of references on the default UInventoryComponent.
Trade-offs
- Component vs. logic in the Pawn: a component is reusable (NPC chests, vendors) but adds a layer of indirection.
- DataAsset vs. DataTable: DataAsset is better for complex nested data and asset references; DataTable suits flat tabular data and bulk editing.