Reliable Identification of Actors on Level Instances for Save System

Hello,

We’re working on a open world game with Save System. Currently we’re going down the rabbit hole of actor identification.

Like other developers, we decided to introduce GUIDs for actors in order to identify them for save system. GUIDs have to be editable, so we can recreate an actor in case we need to change the class.

Everything works fine until Level Instances step in. If we have multiple copies of the same level instance placed onto Main World, technically we have multiple actors with the same GUID.

In order to fix that we serialize the level instance GUID into the Actor during cooking. So we have two GUIDs (GUID of LI + GUID of Actor inside LI) per actor.

The only caveat is the inability to move actors between level instances.

The simplest (and the least efficient solution) will be implementing the separate redirector system. However, it’s highly inefficient since we might need to update multiple actors. Maintaining of a huge map might quickly become painful.

Another solution is to store the whole LI hierarchy, so we can preserve old IDs (by forcing a new LI to “return” the old ID). There are multiple other edge cases:

  • LI hierarchy flattening (removing intermediary level instances)
  • LI hierarchy growing (adding intermediary level instances)

Our desirable requirements:

  1. Actor GUIDs have to be persistent between builds
  2. We should be able to set any GUID to any actor (to preserve full compatibility of older save files)
  3. We should be able to move actors between level instances
  4. Existing level instances can be merged/separated without breaking GUIDs
  5. Having multiple copies of the same LI is allowed
  6. LIs can contain nested LIs, including multiple copies of the same LI
  7. Avoid redirector tables if possible

Is there any way to make GUIDs actually unique and editable without dark magic and having too much restrictions in terms of compatibility?

Thanks in advance!

it depends on your save system, for mine i just register the actor the first time its spawned.
ie

BeginPlay->WasWorldLoaded?->DestroyActor else RegsiterActor

OnLoad SpawnActor from save data

We want to achieve reliable versioning. For example, we have to be able to delete static actors or change their properties.

So, we need some identification to be able to survive version change or level instance hierarchy change

I think you need to consider a system that assigns GUIDs at runtime (It seems there is no other way to solve the problems of level instances).

And then - ALL your dynamic objects should be loaded (spawned) ONLY from the save file (or from the default level for first load).

this bites everyone with LIs and saves. baking LI GUID into the actor at cook is the usual trap because copies diverge.

pattern that holds up: store a persistent actor GUID on the actor itself, but resolve uniqueness at runtime as OuterChain + GUID. on load iterate World Partition / LevelInstance outer chain for each actor and build a save key as hash of LI instance id + actor GUID. let the save system register actors on BeginPlay if not loaded, and respawn from save data on load.

that lets you move actors between LIs by just remapping the outer chain and avoids a giant redirector map. Epic’s SaveGame + FSoftObjectPath approach in World Partition does similar, worth looking at.