MakeUniqueObjectName creates different names for editor and package builds

I am new to UE and I was trying to make some basic actor with a static mesh when I ran into a naming problem. When your actor has a component, you have to call CreateDefaultSubobject in actor’s ctr with project-unique name, otherwise you’ll get an error during editor or packaged game startup. And there is a function called MakeUniqueObjectName that as I thought eliminates the need to invent a new name every time.

Here is my code. ACat.cpp:

ACat::ACat()
{
	Mesh = CreateDefaultSubobject<UStaticMeshComponent>(
		MakeUniqueObjectName(this, UStaticMeshComponent::StaticClass())
	);
	SetRootComponent(Mesh);
}

where Mesh is UStaticMeshComponent*. UE is 5.1.

In editor, I placed ACat right from the content browser to the level and set it’s static mesh. Everything was alright, my mesh component got StaticMeshComponent_0 name displayed in editor. But when I ran packaged game, the object’s static mesh was not shown.

I’ve done a bit of debugging, and tl;dr, mesh component in packed version got another name, like StaticMeshComponent_2426563 - some large number, which originates from another branch of MakeUniqueObjectName, and thus the mesh was not loaded.

Longer explanation: at initial stage of loading, engine run ctrs and creates CDOs for every class and register all names, including special hash tables that map pair of (object name, pointer to owner) to an object. Then, when loading level, it creates asynchronously loaded package with linker that step by step loads our actual objects as follows: it initialize ExportMap, which is a list of all entities (like instances of actors) in our level that should be loaded, and ImportMap, which is a list of all external entities (like classes and CDOs) that are used by our exports. For exports, it construct objects again, running ctr and creating subobjects, including my static mesh component with yet another name, but this name don’t matter. For imports, it tries to find existing object (class or CDO), by searching in hash tables, and in my case, it unsuccessfully tries to search for StaticMeshComponent_0 that was originally in the editor, but not in packaged game. Then linker serializes the exports, which is an exact moment when our arbitrary properties are applied on an instance of an object. Linker fails serialization of mesh component for my ACat instance and thus leaving it nullptr and therefore I can’t see my cat.

Is something wrong with my use of MakeUniqueObjectName for names of subobject? It seems there is a flag EUniqueObjectNameOptions::GloballyUnique for the function that makes it generate same names as in editor (still not the same code), but I am not sure.

You don’t need a globally unique name for subobjects, just an unique name within the parent object.
The full path name to an actor component generally looks like this

MapName:PersistentLevel.ActorName:ComponentName

So you can probably just give it something like

Mesh = CreateDefaultSubobject<UStaticMeshComponent>(this, "Mesh");

And in the end its fully qualified name will be unique because the actor’s name will be unique

MyMap:PersistentLevel.Cat_123456:Mesh
1 Like

You are right. It should be a unique name within the parent. It seems that when I was testing naming, I tried to create two components with the same name within the same object, and was getting an error.

Then, simple

Mesh = CreateDefaultSubobject<UStaticMeshComponent>("Mesh");

will do. There is no CreateDefaultSubobject(Parent*, Name) overload.