Currently there’s no built in system to do saving at the level you need for a game like fortnite. Fortnite built a custom solution, on top of some features in the engine that can be used. We’re going to work on a comprehensive example of how to build a save/load system, but it isn’t ready yet. I’ll make sure to let people know when that information is available. There is a Simple Save Game system that works really well for simpler games, there are some questions on AnswerHub that go into detail for that system such as this one.
For fortnite, we assigned each of our objects that we wanted to save a custom GUID, but other UE4 developers have used a similar system using just the object’s full path, as that should stay the same. So, you have a system to identify an actor uniquely. Then, we’re using a system built on the SaveGame property flag to actually serialize the actors. 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();
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:
AFooActor *NewActor = GetWorld()->SpawnActor<AFooActor>(ActorRecord->ActorClass, TempVector, TempRotator, SpawnInfo );
FMemoryReader MemoryReader(ActorRecord->ActorData, true);
FFortniteSaveGameArchive Ar(MemoryReader);
NewActor->Serialize(Ar);
This works well for actors that are self contained, if you have references between actors you can fix those up inside the archive handler, and if you maintain the object’s full path before and after they should hook up automatically, if you do a two step process where you create every actor, then in a second run serialize the records on top.