Catch 22 situation with FObjectFinder and constructor

I’m porting a non-UE game to UE and I have a class “Building”. Usually, I’d pass the BuildingType (an enum, let’s say) to the constructor and in the constructor I could specify the static mesh in code.

However, UE doesn’t allow arguments in constructors.

So, from what I gather I have to do something like this:

ABuilding* building = GetWorld()->Spawn<ABuilding>(...)
building->SetBuilding(EBuildingType) // Set the static mesh after construction.

Unfortunately, I can’t use ConstructorHelpers::FObjectFinder in that SetBuilding method to choose the static mesh because the construction phase has already passed at that point. Hence the Catch-22 situation.

At the moment I’m spawning the buildings from a Blueprint that has a pre-made TMap that I pick the building from.

Is there a way I can get the BuildingType into the constructor beforehand?

This is hard to explain, so apologies in advance if this isn’t clear.

So I think you can declare a class variable in the constructor, so in your header you want to set

UStaticMeshComponent* BuildingStaticMesh;

Then in your constructor you call FObjectFinder

static ConstructorHelpers::FObjectFinder<UStaticMesh>MeshAsset(TEXT("StaticMesh'/Game/Sphere.Sphere'"));
UStaticMesh* Asset = MeshAsset.Object;

Then in any function in your class you can call

BuildingStaticMesh->SetStaticMesh(Asset);

You can preload as many meshes as you want this way, and then set them outside of the constructor as you please.

Hi there, thanks for replying.

Sadly, It’s not the usage or understanding of FObjectFinder that’s the problem. **I need to pass an argument into the constructor so that the right mesh is selected. **

e,g,

ABuilding::ABuilding(BuildingType bt /* <-- CAN'T DO THIS */) {
	if(bt == House) {
		static ConstructorHelpers::FObjectFinder<UStaticMesh>MeshAsset(TEXT("StaticMesh'/Game/Meshes/House.House'"));
		// set mesh...
	}
	else if(bt == Castle) {
		static ConstructorHelpers::FObjectFinder<UStaticMesh>MeshAsset(TEXT("StaticMesh'/Game/Meshes/Castle.Castle'"));
		// set mesh...
	}
	else if(bt == Port) {
		static ConstructorHelpers::FObjectFinder<UStaticMesh>MeshAsset(TEXT("StaticMesh'/Game/Meshes/Port.Port'"));
		// set mesh...
	}
	// etc.
}

I’m thinking of maybe just having a separate static global class or function library that pre-loads all the meshes in its constructor with FObjectFinder and then can hand them over, e.g., UStaticMesh* mesh = MeshLibrary::GetBuildingMesh(BuildingType).

Aha! I did some more research and it turns out I don’t need to use ConstructorHelpers::FObjectFinder at all.

It seems that from anywhere you can use StaticLoadObject

There was another AnswerHub query with a similar problem:
Load Static Mesh With Path in c++

I switched the code to this and now it works fine!

UStaticMesh* newMesh = nullptr;

if(building == Hovel)
	newMesh = Cast<UStaticMesh>(StaticLoadObject(UStaticMesh::StaticClass(), nullptr, TEXT("StaticMesh'/Game/Meshes/Hovel.Hovel'")));
else if(building == Castle)
	newMesh = Cast<UStaticMesh>(StaticLoadObject(UStaticMesh::StaticClass(), nullptr, TEXT("StaticMesh'/Game/Meshes/Castle.Castle'")));
else if(building == Port)
	newMesh = Cast<UStaticMesh>(StaticLoadObject(UStaticMesh::StaticClass(), nullptr, TEXT("StaticMesh'/Game/Meshes/Port.Port'")));

Yeah, you’re supposed to be able to pass variables prior to construction using deferred actor spawning, but that hasn’t seemed to work so far for me.