Add component to blueprint in c++

Greetings, dear community.

I am trying to do this:

But in code. My logic is simple: if this is available through gui as main function - it must be easily achievable through code.

Currently, this is how I generate my template blueprint:



	FString AssetName = "TEST_BP";
	FString PackagePath = "/Game/Blueprints";

	const FString PackageName = PackagePath + TEXT("/") + AssetName;
	FName CallingContext = FName("ContentBrowserNewAsset");
	UPackage* Pkg = CreatePackage(NULL, *PackageName);
	UObject* NewObj = NULL;
	EObjectFlags Flags = RF_Public | RF_Standalone;
	UClass* ParentClass = AActor::StaticClass();

	UClass* BlueprintClass = nullptr;
	UClass* BlueprintGeneratedClass = nullptr;

	IKismetCompilerInterface& KismetCompilerModule = FModuleManager::LoadModuleChecked<IKismetCompilerInterface>("KismetCompiler");
	KismetCompilerModule.GetBlueprintTypesForClass(ParentClass, BlueprintClass, BlueprintGeneratedClass);

	UBlueprint* Blueprint = FKismetEditorUtilities::CreateBlueprint(ParentClass, Pkg, FName(*AssetName), BPTYPE_Normal, BlueprintClass, BlueprintGeneratedClass, CallingContext);



This is how the TEST_BP blueprint was created (above in screenshot).

Now I need to somehow replicate the “Add Component” action.
Your help is greatly appreciated.

There are a few steps to create components in C++:

Firstly, changed GNERATED_BODY() to GENERATED_UCLASS_BODY() in the .h file

Second, change the constructor to: AMyActor::AMyActor(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { … }

Lastly, use the ObjectInitializer to create components using CreateDefaultSubobject

Like:



	MySkMesh = ObjectInitializer.CreateDefaultSubobject<USkeletalMeshComponent>(this, TEXT("MySkMesh"));
	MySkMesh->AttachParent = GetCapsuleComponent();


Thanks for your response. It does not answer my question, however.

So, lets say I have a blueprint pointer, as in example above. How would I attach the created component to blueprint?

To clarify (just in case)

I need to be able to have the **same ** workflow in code as I do in the gui for creating components for blueprints. I want to be able to take a blueprint that was created from AActor template, and have arbitrary components added to it (again, just like in gui). I need a completely hardcode-free method (no stuff init in constructors, no creation to hardcoded pointers in custom classes). I do not need a custom derived class from AActor for my needs - AActor works just fine for what I’m doing. I just need to be able to say some_blueprint->AddComponent(<somecomponent>);

Is this possible at all? The more I look into how code is laid out in the SSCSEditor, the more if feels like the developers have only intended this work flow for the gui. Please, tell me that I’m wrong, because otherwise it would be ridiculous :slight_smile:

I haven’t attempted to do this, but have you tried FKismetEditorUtilities::AddComponentsToBlueprint?

Like you say, this is possible from C++, since the editor is doing it in C++. If the above doesn’t work, you’d just need to put a breakpoint in the editor code (you’d want a source build and DebugEditor config) to catch it at the point you add a component to a blueprint in-editor, and then trace through to see exactly what it does.

Hey kamrann,

Thanks, will try that!

I’m using a compiled build, but it has debug symbols, so I am able to debug the code to some extent (it does not show all code flow correctly, ie, sometimes will show a pointer as non-null when it is null). I have tracked all the calls in the selection widget, and I think I know what’s up.

If your suggested function call will not work, I will try and rip out all component adding functionality from the widget and rewrite it such manner that a user would be able to easily add components to the blueprint from anywhere in code. If I succeed I will make a post about it.

How did you solve it? How do I get a pointer to the UBlueprint?

For anyone look for a solution for this, the code below seems to work for me in 4.19.




//Creating a blueprint

UBlueprintFactory* Factory = NewObject<UBlueprintFactory>();
IAssetTools& AssetTools = FModuleManager::GetModuleChecked<FAssetToolsModule>("AssetTools").Get();

UObject* Object = nullptr;
Object = AssetTools.CreateAsset(
NewFileName,
NewFilePath,
UBlueprint::StaticClass(),
Cast<UFactory>(Factory)
);

UBlueprint* Blueprint = Cast<UBlueprint>(Object);

// Adding a Hierarichal Instance Static Mesh, but I believe this can be any actorcomponents (Not tried)

USCS_Node* Node = Blueprint->SimpleConstructionScript->CreateNode(UHierarchicalInstancedStaticMeshComponent::StaticClass(), TEXT("HISM"));
Blueprint->SimpleConstructionScript->AddNode(Node);
FKismetEditorUtilities::CompileBlueprint(Blueprint);



Hope this helps someone.

Regards
Raz

1 Like

Hi! I know this is pretty old, but I hope someone will help me.
Im trying to add an InstancedStaticMesh component to blueprint. And it works, the issue is that I cant set up static mesh for it.


FString AssetName = SelectedObject->GetName();
UBlueprint* MyBP = Cast<UBlueprint>(SelectedObject);
AActor* MyActor = MyBP->SimpleConstructionScript->GetComponentEditorActorInstance();


//Generate InstancedMesh
UStaticMesh* cubeMesh = LoadObject<UStaticMesh>(nullptr, TEXT("StaticMesh'/Game/Geometry/Meshes/1M_Cube.1M_Cube'"));
UInstancedStaticMeshComponent* ISMC = NewObject<UInstancedStaticMeshComponent>(MyActor);
ISMC->RegisterComponent();
ISMC->SetStaticMesh(cubeMesh);
ISMC->SetFlags(RF_Transactional);

USCS_Node* Node = MyBP->SimpleConstructionScript->CreateNode(UInstancedStaticMeshComponent::StaticClass(), TEXT("ISM"));
MyBP->SimpleConstructionScript->AddNode(Node);
FKismetEditorUtilities::CompileBlueprint(MyBP);

So the question is how to apply ISMC to node, so this appears correctly in blueprint?

Hey. This is old but if someone’s looking for solution for Mike_M’s problem this is how I’ve done it:

USCS_Node* BPNode = ActorBP->SimpleConstructionScript->CreateNode(USkeletalMeshComponent::StaticClass(), TEXT("SkeletalMeshComponent"));
					ActorBP->SimpleConstructionScript->AddNode(BPNode);
					FKismetEditorUtilities::CompileBlueprint(ActorBP);

auto* MeshComponent = Cast<USkeletalMeshComponent>(BPNode->ComponentTemplate);
MeshComponent->SkeletalMesh = SkeletalMesh;

So don’t create new object, take it from the node

2 Likes