Generate FGuid that is stable

I have a custom instanced (default to instanced, edit inline new) UObject property that is a drop-in helper for generating a stable FGuid for each object it belongs to within a level.

The goal is to generate the FGuid ONCE and then have it stay the same between sessions. I can’t generate the FGuid from actor path or name because those are unreliable. The property is declared like this where ever it is needed:

UPROPERTY(EditInstanceOnly, Instanced)
TObjectPtr<UStableIdProvider> IdProvider{nullptr};

The UStableIdProvider instance is instantiated in the constructor with CreateDefaultSubObject. It has one UPROPERTY:

UPROPERTY(EditAnywhere)
FGuid StableId;

I am using PostInitProperties to ensure the Id is valid, but only if it isn’t invalid (and only on instances, not on the template).

void UStableIdProvider::PostInitProperties()
{
Super::PostInitProperties();

if (!IsTemplate() && !StableId.IsValid())
StableId = FGuid::NewGuid();
}

However if I modify the owning actor/component in any way, the value ‘churns’ (I have logged the value and it continually changes while edits are being made).

I’ve tried using PostEditImport and PostLoad to do the same thing. But they don’t appear to trigger the FGuid generation at all.

I’m completely lost on how to generate this value once exactly for any level actor/component and then save that value so it’s consistent between sessions. It would need to generate on adding the actor to the level (either that or somehow tell the editor the actor needs to be saved once generated).

Please help D:

My Guess is that the instanced uobject itself is being recreated overwriting the previous one. if so im not sure how you could stop that?

I have a component that has this instanced object. I noticed if the component is part of the BP CDO it has this problem, but if I add the component to the actor in the level editor, THAT version of the component has a stable FGuid.

I believe BP CDO components are torn down/recreated on every edit, but I thought UPROPERTY were serialised between old/new instances of the component.

Can’t you use AActor::ActorGuid or AActor::ActorInstanceGuid? If not, maybe look at how those two are generated and serialized in Actor.cpp via for example AActor::Serialize.

Level-placed actors should have stable names. It’s the dynamically spawned ones that are not.

Using an instanced object is what prevents it from persisting its own data. For instanced objects the only data saved are the default properties set in BP editor (template), which are then retrieved when instances are created. To persist instanced data you could use PerObjectConfig which stores per-instance ini config sections, but they are indexed by object name so it’s kinda moot if you do indeed have an issue with names.

I’d suggest replacing your instanced object with a non-instanced ActorComponent, it should be able to save its properties just like any other actor or component, as long as it’s placed in the level.

Well the problem with a component is this is FOR components. Some actors have 5/6 components that need stable Ids.

Using an instanced object is what prevents it from persisting its own data. For instanced objects the only data saved are the default properties set in BP editor (template), which are then retrieved when instances are created.

This doesn’t seem right. I have quite a few Instanced UObject properties and I can safely edit their values manually for any instance of the actor without those values resetting to BP default. They’re persistent between sessions and can be different between actor instances.

Could the issue be that I’m generating that FGuid programatically rather than through the detail panel, notifying unreal that the property values are different and need to be serialised for that instance (which doesn’t happen when generating in code)?

The most confusing issue with this one is:

  1. Components with the provider that are part of the BP CDO don’t have a stable Id (continually regenerates).

  2. Components added to the actor in the level DO have a stable Id (generates once, is persistent between sessions).

I believe the Guid’s Unreal provides are only stable for a given session, they are different next time you load the level.