Adding static meshes to StaticMeshComponent in BP

First post here, hopefully i can get some help resolving an issue(s). Apologies, if i sound like a beginner just started learning. Would appreciate any guidance :slight_smile:

What i’m trying to do:-

I made a toolbar button to run this tool for now. I have a bunch of static mesh assets in my project. I’m trying to create a blueprint of actor class where i want to add a few static mesh component slots, add my static meshes in there and set a relative location for each static mesh that has been added.

I’ve so far been able to create the blueprint,and add static mesh components, just having trouble figuring out how to connect the static mesh components to the static meshes, and set their location, inside the blueprint.

Assets are located at /Game/Assets/TestAsset1,2,3…

On a side note when i try to create a UStaticMeshComponent using CreateDefaultSubobject, it keeps saying its undefined even though i have #include “Components/StaticMeshComponent.h” . What iam i doing wrong in this scenario?

UStaticMeshComponent* mesh1 = CreateDefaultSubobject(TEXT(“StaticMesh”));

What is working:-

UBlueprint* newBlueprint = FKismetEditorUtilities::CreateBlueprint(AActor::StaticClass(), OuterForAsset, fname, BPTYPE_Normal, BlueprintClass, BlueprintGeneratedClass, FName("GeneratingBlueprintTest"));
FAssetRegistryModule::AssetCreated(newBlueprint);
FAssetEditorManager::Get().OpenEditorForAsset(newBlueprint);
OuterForAsset->SetDirtyFlag(true);
USCS_Node* NewNode = newBlueprint->SimpleConstructionScript->CreateNode(UStaticMeshComponent::StaticClass(), "Test_SM_Cmp1");

USCS_Node* RootNode = newBlueprint->SimpleConstructionScript->GetDefaultSceneRootNode();
RootNode->AddChildNode(NewNode);

FKismetEditorUtilities::GenerateBlueprintSkeleton(newBlueprint, true);
FKismetEditorUtilities::CompileBlueprint(newBlueprint);

You are 90% there.

CreateDefaultSubobject is what is called a template function in C++ meaning you have to supply the parameters that the template expects so the compiler can generate the actual function. This particular template simply wants the typename of your component as template argument which in practice looks like this:

mesh1 = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("mesh1"));

The name is arbitrary. After that you can quite easily do what you want like so:

  ConstructorHelpers::FObjectFinder<UStaticMesh>MeshAsset(TEXT("StaticMesh'/Game/Assets/TestAsset1.TestAsset1'"));
  mesh1->SetStaticMesh(MeshAsset.Object);
  mesh1->SetRelativeLocation({20.f, 30.f, 40.f});

To make your life easier, you can get the path in the exact format that FObjectFinder expects by right clicking on your mesh in the asset browser and selecting ‘Copy Reference’.

Firstly thank you for such a quick reply :).

This is super helpful, I realized a couple of things that i had not paid attention to previously.

  • CreateDefaultSubobject , only works inside constructor, apparently NewObject is the way to do it outside the constructor.
  • FObjectFinder is also limited in scope to the constructor, so I had to use :-
    StaticLoadObject(UStaticMeshComponent::StaticClass(), NULL,TEXT(“StaticMesh’/Game/Assets/TestAsset1.TestAsset1’”));

So no errors, but StaticLoadObject keeps giving me a warning
LogUObjectGlobals: Warning: Failed to find object ‘StaticMesh’/Game/Assets/TestAsset1.TestAsset1’

Any thoughts?

What would be the cleanest way of adding the mesh1 to the blueprint?

Okay got the Uobject linked and working :slight_smile:

#include “ComponentAssetBroker.h”

UObject* uobj= StaticLoadObject(UStaticMeshComponent::StaticClass(), NULL,TEXT("/Game/Assets/TestAsset1.TestAsset1"));

FComponentAssetBrokerage::AssignAssetToComponent(NewNode1->ComponentTemplate, uobj);

But with this method i’m trying to figure out how to set the location.

Learning about TWeakObjectPtr to access the component.

Right CreateDefaultSubobject only works in the constructor. Outside the constructor you would use

mesh1 = NewObject<UStaticMeshComponent>(GetOwner(), UStaticMeshComponent::StaticClass(), TEXT("mesh1"));
  mesh1 ->RegisterComponent();

But I am not sure this would work for you either. Looking over your question again now I am not even sure what you are trying to do. Are you developing an editor plug-in or is it just some excercise? Where and how are you calling this code?

Also StaticLoadObject expects the fully qualified path if you don’t give it an outer.

EDIT: you figured it out.

You can use a weak object pointer just like a normal one but don’t use it without checking if it is nullptr first because it doesn’t keep the object it points to from being garbage collected.

You are absolutely correct, i’m doing a terrible job of explaining what i’m trying to do.

So I made a toolbar button plugin that when clicked. Grabs a bunch of assets in a folder along with some transforms i’m supplying and assembles all those into a blueprint actor. Something similar to a prefab in unity.

So as i read and understood more i learnt:-

  • The USCS_Node that i’m using to add the component like
    RootNode->AddNode(NewNode1); // Where the RootNode is the root node of the newly created blueprint

This doesn’t actually add anything till i call CompileBlueprint() from Kismet. So i have 2 options :-

  • Figure out simple construction script way of setting transforms.
  • Compile the blueprint, then grab it as a UBlueprintGeneratedClass and parse through the components and set transform.

Looking into first option now :).

Thank you again for your time and patience, seems like the first thing i need to do is know how to ask the right questions :). I did it this toolbar button method to figure out how to do it and create 1 blueprint actor so that i can run it and test the process. Is there a better way to test code when you are working/learning?

You made me curious and I have actually tried it out myself. This is how you do it:

  auto MeshAsset = static_cast<UStaticMesh*>(StaticLoadObject(UStaticMesh::StaticClass(), nullptr, TEXT("/Game/Assets/TestAsset1.TestAsset1")));
  auto MeshComp = static_cast<UStaticMeshComponent*>(NewNode->ComponentTemplate);
  MeshComp->SetStaticMesh(MeshAsset);
  MeshComp->SetRelativeLocation({20.f, 30.f, 40.f});

Also my first time creating a Blueprint from C++, pretty cool.

This works! Where is the “buy this human a beer” button :). I mean this , thank you for all this help, really have helped me learn a lot.

Please let me know if there is a way to contact you because I’d indeed buy you the aforementioned beverage :).