Calling construction script on spawned actor

I have a base actor class (AInteractableBase) from which several actors derive from. One of the main things this base class does is creating a dynamic material in the construction script, which is applied to the actor’s base mesh (EmissiveMesh).

My problem is when I try to spawn one of these actors from my GameMode.
This is my situation.

GameMode holds a TSubclassOf variable (LostBackpackObjectClass), whose EmissiveMesh is set to None.
When required, GameMode needs to create an instance of AInteractableBase (LostBackpackObject).
The mesh at this point is set with a certain mesh which uses a certain material. This is why LostBackpackObject, by default, doesn’t have an EmissiveMesh set: it changes every time I spawn it.
And this is where I’m stuck.

Since there is no default EmissiveMesh and associated material, the construction script doesn’t work, and when I finally set the EmissiveMesh I don’t have a dynamic material anymore.
I even tried manually calling the construction script from my code but it’s totally useless.

backpackMesh=gameInstance->GetLostBackpackMesh();
if(backpackMesh)
{
      LostBackpackObject = Cast<AInteractableBase>(GetWorld()->SpawnActor(LostBackpackObjectClass));
      // Modifying the mesh
      LostBackpackObject->SetEmissiveMesh(backpackMesh);
      LostBackpackObject->SetActorLocation(gameInstance->GetDeathLocation());
      // Uselessly calling the construction script
      LostBackpackObject->OnConstruction(LostBackpackObject->GetTransform());
}

And then I get all the errors

If I however set a default mesh and material for my AInteractableBase object, everything works fine, but now I’m forced using a default material, with embarassing results:

I would put the cast in an if statement if it fails.

backpackMesh=gameInstance->GetLostBackpackMesh();
if(backpackMesh)
{
     if(LostBackpackObject = Cast<AInteractableBase>){
(GetWorld()->SpawnActor(LostBackpackObjectClass));
      // Modifying the mesh
      LostBackpackObject->SetEmissiveMesh(backpackMesh);
      LostBackpackObject->SetActorLocation(gameInstance->GetDeathLocation());
      // Uselessly calling the construction script
      LostBackpackObject->OnConstruction(LostBackpackObject->GetTransform());
}
}

Personally I would make all AInteractable implement an IInteractable interface and then just call it’s function via the interface.
No need to make this area of code handle what is part of the interactables job.

The spawning works, so that if statement always passes. It’s just the material that doesn’t get its dynamic version.

As for the interface, I am using an IInteractableInterface actually :smiley:
I guess I could expand it a bit.

At any rate, I ended up giving up and just have SetEmissiveMesh as a BlueprintNativeEvent and basically calling the entire construction script code from scratch. it’s not too expensive since this would only be called when the player respawns so yeah, at least it works.

I just hoped to have a more clean way to achieve that.

Usage :

ASomeActor* Actor = GetWorld()->SpawnActorDeferred<ASomeActor>(ASomeActor::StaticClass(), SpawnTransform);
if (Actor)
{
	Actor->SomeParam = 42;
	Actor->FinishSpawning(SpawnTransform);
}
2 Likes

You are my ■■■■■■■ HERO.

This is… perfect! It even helps me solve another completely (well, almost) unrelated issue I was working on. Thank you!