What is the best way to handle Saving/Loading an Array of Objects?

There is currently no good tutorial on how to do a custom save game setup for your game, so it will require a good bit of custom coding on your part. But here’s some info that may help out:

For fortnite, we’re using a system built on the SaveGame property flag. If you set the ArIsSaveGame archive flag on an archiver, it will only serialize properties that have that flag set on them. Some of the basic properties are set this way in the engine, and you can then tag your game specific properties.

So, you need to set up a savegame archive. For fortnite, we’re using a proxy wrapper based on the Objects-as-strings proxy wrapper:

struct FFortniteSaveGameArchive : public FObjectAndNameAsStringProxyArchive
{
    FFortniteSaveGameArchive(FArchive& InInnerArchive)
        :   FObjectAndNameAsStringProxyArchive(InInnerArchive)
    { 
        ArIsSaveGame = true;
    }
};

Then, you can use that proxy archive to serialize a record for an actor or object you wish to. Here’s our save code, that writes to a simple struct that has the actor’s class, transform, and a TArray storing the bytestream:

ActorRecord->ActorClass = Actor->GetClass();
ActorRecord->ActorTransform = Actor->GetTransform();
ActorRecord->ActorName = Actor->GetName();
 
FMemoryWriter MemoryWriter(ActorRecord->ActorData, true);
 
// use a wrapper archive that converts FNames and UObject*'s to strings that can be read back in
FFortniteSaveGameArchive Ar(MemoryWriter);
 
// serialize the object
Actor->Serialize(Ar);

And here’s our code that restores that actor:

FActorSpawnParameters SpawnParameters;
SpawnParameters.Name = ActorRecord->ActorName;
AFooActor *NewActor = GetWorld()->SpawnActor<AFooActor>(ActorRecord->ActorClass, TempVector, TempRotator, SpawnParameters);
 
FMemoryReader MemoryReader(ActorRecord->ActorData, true);
FFortniteSaveGameArchive Ar(MemoryReader);
NewActor->Serialize(Ar);

So we’re using this system for Fortnite, which has a complicated system of procedural generation. Basically there’s a state machine that handles either generating the actors randonly, or restoring from a record like above. We also use a similar technique to save a player’s inventory, but instead of saving a whole actor we just serialize a specific Struct, which is a great place to put your array of objects:

FMemoryWriter MemoryWriter(PlayerRecord->BackpackData, true);
FFortniteSaveGameArchive Ar(MemoryWriter);
Inventory->Serialize(Ar);
5 Likes