Instantiating Blueprint-based components in C++

This seems like it should be a common thing to need to do, but it’s causing me an unreasonable amount of grief.

In general, in my project, I’ve been building abstract C++ base classes which are then inherited by blueprint classes which are actually used in the game. I’d like to be able to have actors and components “self-assemble” by having them create the standard components I know they need in their constructors.

The problem, of course, is that since the blueprint classes don’t yet exist at compile time, I can’t reference their class type directly in code. Also, I’d prefer to avoid writing explicit path references into the code, since then if I move anything, everything breaks.

My plan was, in the C++ base class, to have a TSubclassOf variable which can be used by the blueprint child-class to specify which blueprint class the C++ parent class should spawn. For example, my player pawn needs to spawn some hand controllers, which are components. So the player pawn C++ base class has:

UPROPERTY(EditDefaultsOnly, Category = ComponentClasses)
TSubclassOf<UHandControllerComponent_Base> HandControllerComponentClass;
UPROPERTY(BlueprintReadOnly, Category = Components)
UHandControllerComponent_Base* Hand_Left;

To specify the class of hand controllers it will spawn (which are blueprint classes which inherit from the UHandControllerComponent native base class.)

HandControllerComponent is then set to be a reference to the blueprint hand controller class in the class defaults in the editor.

In the Pawn’s constructor, I build the new HandControllerComponents using CreateDefaultSubObject and the class type provided by HandControllerComponentClass:

if (IsValid(HandControllerComponentClass))
	UE_LOG(VRArenaGeneral, Log, TEXT("Generating hand components"));
	Hand_Left = (UHandControllerComponent_Base*)CreateDefaultSubobject(TEXT("Hand_Left"), UHandControllerComponent_Base::StaticClass(), HandControllerComponentClass->StaticClass(), false, false, false);
	if (!IsValid(Hand_Left))
		UE_LOG(VRArenaGeneral, Error, TEXT("Hand component creation failed"));
	UE_LOG(VRArenaGeneral, Error, TEXT("No HandControllerComponent class specified for Pawn."));

However, the code always dumps out to the “No HandControllerComponent class specified for Pawn” error. I’ve verified that the HandControllerComponentClass are set in the defaults of the pawn I’m spawning.

This suggests to me that for some reason, values set in the default class properties aren’t yet available when the constructor runs, which means I’m screwed since I have no way to hardcode that class reference. I could do this later, but my understanding is that that has some serious negative effects on being able to work with the blueprint classes in the editor.

What is the correct way to do this? (Construct an actor out of blueprint classes in C++)

So I do the same thing what your attempting to do. Where I build my abstract classes in C++ then extend them via Blueprints. How I set it up so I can change out meshes and have it essentially self construct is pretty simple.

In the .h:

/** StaticMesh component that will be the visuals for our flying ship */
	UPROPERTY(Category = Mesh, VisibleDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
	class UStaticMeshComponent* HullMesh;

then the .cpp:

// Create static mesh component
	HullMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("HullMesh"));
	RootComponent = HullMesh;

So now when I extend the class via blueprints, in the detail panel I have a little box where I can drop in the mesh I wish it to have. I can also operate on the mesh now, without actually ever telling it what mesh it’s going to have.

Hope this helps!

EDIT: I think I might’ve misunderstood you, but if you don’t want to set up the reference to the actual mesh every time, you can then extend the blueprint that assigns the meshes with another blueprint, and they it will fully self construct any time you create the blueprint.

The difference is that I’m not trying to change data on an existing component, I’m trying to instantiate an entirely new component of a class which doesn’t exist at compile time (since it’s a blueprint component.)

The idea is that the code will treat the component like its native base class (which is what the TSubclassOf declaration is for) but the component will actually be a member of a blueprint class which extends that. So I can easily add new “end of line” functionality to the component in blueprint.

The problem is that since blueprint classes can’t be seen by code, I need to pass the type of class I’m spawning back to native code from the editor (where it exists). So I have a variable, which belongs to the native base class, but which is set in the default class properties of the child blueprint class to tell it what it needs to create.

The problem is that this data set in the default properties doesn’t seem to exist yet at the time the constructor runs, which is when I need to instantiate the object. (Presumably this is being set in the blueprint class’ constructor, which is running after the base class’ constructor?)

I have what appears to be a solution. It’s not ideal, but it works.

I’ve set up a global engine data singleton (see here) which is now where the TSubclassOf HandControllerComponentClass variable lives.

I’m getting some errors where for some reason the engine hasn’t initialized when my constructors first run for some reason (causing the GEngine variable to be null, making the global data singleton inaccessible) but everything appears to work OK despite this. (The copies of the objects instantiated in the level create their components just fine, so I don’t know what it is that’s running a constructor before the engine exists. I’ll have to dig into that later.)

It’d be nicer to have the class type for the components I’m creating on the thing that’s creating them, but this is good enough for now.

Well, scratch that. When I open up my project, the components I’m instancing fail to generate and all their child components “fall off” and attach to the root. If I hit compile on the actor, they then generate. So it looks like the errors from above are them trying to compile the first time before the engine initializes, which breaks stuff.

The obvious solution, moving the primary game module to load at PostEngineInit, causes a crash. Presumably the engine doesn’t like no game module being loaded.

If I have to, I can break my self-assembling actors out into game modules to load later, but that’s less than ideal for workflow.

Tim Lincoln solved this problem in another issue, here:

In short:
Build references to the BP classes using TSubtypeOf in a game data singleton.
Then access the game data singleton via a path reference using FObjectFinder. (Can’t use the GEngine pointer to get it because it’s null.)