Saving and loading
EDInventorySave serialises a container to bytes and reads it back, with versioning and migration so
a save written by an older build still loads.
Saving
TArray<uint8> Blob;
EDInventorySave::SaveContainer(*Container, Blob);
That captures the entries, their stack counts, per-stack state, dynamic tags and slot addresses. Promoted item instances are saved too.
Loading
FEDDemoSubsystemAllocator Allocator(UEDInventorySubsystem::Get(this));
EDInventorySave::LoadContainer(*Container, Blob, Allocator);
Loading needs a handle allocator because handles are server-allocated identity. Passing the world subsystem's allocator means loaded items get handles that cannot collide with anything allocated since. Restoring raw handles instead is how you end up with two items that are the same item.
Loading replaces the container's contents and broadcasts a Reset change, so observers re-read rather
than trying to diff.
Key blobs by container tag
Save one blob per container, keyed by the container's type tag:
for (const UEDContainer* Container : Containers)
{
if (Container->GetContainerType().IsValid())
{
FEDContainerBlob Blob;
EDInventorySave::SaveContainer(*Container, Blob.Bytes);
Save->ContainerBlobs.Add(Container->GetContainerType().GetTagName(), MoveTemp(Blob));
}
}
The tag is the container's identity. It survives renaming a component, re-ordering a list, and re-authoring an asset — none of which is true of a component name or an array index.
Iterating container components misses every container gained at runtime — including the grid inside a worn backpack. Ask the inventory for its containers instead, or a player's bag quietly fails to save and they lose whatever was in it.
Loading into a container that already has a type
LoadContainer restores the type stored in the blob. An older save may have none, and blanking a
container's type would silently detach every filter and lookup keyed on it — so an empty saved tag
leaves the configured one alone.
If you see containers losing their identity after a load, that is the case to check first.
Several containers of a kind
Once an actor can have two containers with the same tag — two quivers — a tag is no longer a unique key. Save the container id alongside the tag and restore by id, falling back to the tag for older saves.
Versioning
Blobs carry a version, and migration runs on load. Adding a field to an entry means bumping the
version and handling the old shape; the header for EDInventorySave documents the current version and
what changed.
Replicated formats — the transaction error enum, NetSerialize layouts, the FastArray entry shape —
get the same scrutiny for the same reason: changing one breaks saves and network compatibility with
running clients.
JSON export
There is a debug JSON exporter as well. It is for reading a container in a bug report, not for persistence — it is not versioned and not intended to be loaded back.
Where next
- Replication
- Items and fragments — what per-stack state is