Programmatically add components to Blueprint

Hello,

I am trying to programmatically set up a data driven system that would allow me create blueprints during startup based on some data.

I am generating blueprints successfully, but I cannot understand how to add components to them.

Let’s say I have a blueprint based on AActor:

UBlueprint* Blueprint = FKismetEditorUtilities::CreateBlueprint(classnew, Package, BPName, BPTYPE_Normal, BlueprintClass, BlueprintGeneratedClass, FName("LevelEditorActions"));

Now I will create the node with the actual component:

USCS_Node* node = Blueprint->SimpleConstructionScript->CreateNode(UStaticMeshComponent::StaticClass(), NAME_None);

And at this point I am not sure what I should do. I tracked down all the calls in visual GUI for blueprint component addition, and got to the this point (in SSCSEditor.cpp, line 4725)

// Add the new node to the editor tree
NewNodePtr = AddTreeNode(NewNode, SceneRootNodePtr, false);

This is the function that seems to attach the created component to the scene root.

Long story short, how do you attach a component to a blueprint programmatically?

Update:

I found a function in Kismet called AddComponentsToBlueprint, here is the definition:

static void AddComponentsToBlueprint
(
    UBlueprint * Blueprint,
    const TArray< UActorComponent * > & Components,
    bool bHarvesting,
    class USCS_Node * OptionalNewRootNode
)

So, for first element I send in my blueprint. Now I create a new USkeletalMesh object and add it to array:

USkeletalMeshComponent* smc = NewObject<USkeletalMesh>();
TArray< UActorComponent * >  Components;
Components.Add(smc);

And I make the pass. The pass fails, because inside of the function, each component is being checked whether it has a parent Actor or not!

At this point, I am in a circular dependency: The BP that was created from type cannot have components added, because the components need an actor defined.

However! When I add components to an archetype (template) blueprint, it works totally fine in the gui! Therefore, it must be possible to do this in the engine, as this is the “default” behavior offered to the user.

Your help is greatly appreciated.

bump bump bump

As nobody was able to help me with this, I took the “do it yourself” approach and solved my problem by rewriting the SSCSEdtior and BlueprintEditor tools to fit my needs. Resolved.

Exactly as mentioned above :slight_smile: I ripped out the parts of blueprint editor and SSCS Editor, and wrote my own BlueprintEditor class based on them. Currently, my Blueprint Editor supports the following functionality:
Add component
Remove component
Find component
Rename component
Compile blueprint

If you look very closely at the SSCS Editor, you will see that most of its stuff will go away if you want to rewrite it. Realistically, you need the root comp node pointer, blueprint pointer and the default actor pointer in your class. All widgets, guis and dragndroppers can be taken out.

I can post my solution if you are interested, but I’m not sure how to do it on answerhub

Could you share what you did to solve your problem? I am running into the exact same issue.
Thanks! :slight_smile:

Thanks for the quick reply! :slight_smile:

Could you just post your Add Component code?

Thanks!

Sure here it is.

UActorComponent* BlueprintEditor::AddComponent(UClass* NewComponentClass, FName VariableName)
{
check(Blueprint != nullptr && Blueprint->SimpleConstructionScript != nullptr);

	Blueprint->Modify();

	const FName NewVariableName = (VariableName == "" ? NAME_None : VariableName);
	USCS_Node* NewNode = Blueprint->SimpleConstructionScript->CreateNode(NewComponentClass, NewVariableName);

	FSCSEditorTreeNodePtrType NewNodePtr;

	// Add the new node to the editor tree
	NewNodePtr = AddTreeNode(NewNode, SceneRootNodePtr, false);

	// Potentially adjust variable names for any child blueprints
	if (NewNode->VariableName != NAME_None)
	{
		FBlueprintEditorUtils::ValidateBlueprintChildVariables(Blueprint, NewNode->VariableName);
	}

	UpdateTree();

	return NewNode->ComponentTemplate;
}

The formattings all messed up. but you get the idea.

Awesome, thanks! One last question if you have time…what is SceneRootNodePtr getting set to?

Thanks again!

SceneRootNodePtr is being set to the root component of the blueprint. It determines the entire tree hierarchy of all components and how they are attached to each other. In the GUI tool, you get a default component always set as Scene component. I ovverrid this behavior so that the initially the blueprint is componentless, and the root is the first component that you create.

Here’s what I did to create and attach a (Blueprint) component to a (Blueprint) actor via C++.

I want a Blueprint component of type UnitBuffComponent (parent C++ class BuffComponentBase) to be attached to a Blueprint charachter CombatCharacter_BP (parent C++ class CombatCharacter). This particular function is BlueprintCallable and is actually called from Blueprint passing the target component class as a parameter.

UBuffComponentBase* ACombatCharacter::CreateBuffComponent( TSubclassOf<class UBuffComponentBase>  in_componentClass )
{
	UBuffComponentBase* newBuff;

	newBuff = NewObject<UBuffComponentBase>( this, in_componentClass );

	if (newBuff)
	{
		newBuff->RegisterComponent();
		return newBuff;
	}
	return NULL;
}

I’m keeping references to all characters in a C++ member variable array, so I also could have called the method in C++.
In that case, if I wanted to attach a Blueprint component, I’d have to create a reference to the component class in the constructor via ConstructorHelpers::FClassFinder. And if the component I wanted to attach was a C++ component, I could pass the class in using UMyBuffComponent::StaticClass().

I realize you’ve already found a workaround, but maybe this’ll help someone else.

Thanks for all your help! I have been trying to get this to work all last night and this morning but just can’t get it working…any chance you would share your BlueprintEditor class you made?

Thanks again! :slight_smile:

Does your method allow for programatically adding static and skeletal mesh components to a BP Actor in the Editor, not at runtime? I’ve posted a similar question here, but I’m stuck on needing an instance of the actor to operate on using a construction or spawn event as opposed to some sort of “Editor” event. I was really hoping this would be where Epic would provide some useful Blutility functionality, but that doesn’t appear to be the case. Am I missing something?

Great you are . I stuck in this mess for a day. Thank you very much!

Hi. Your answer amazing. but I’m not familiar with editor code. How can I access sscseditor in actor

Hi. Your solution is amazing. I know SSESEditor addnewcomponent work for adding component in levelveiwport. Problem is I’m newby in unreal editor. So I can’t understand your answer well. Where am I start for understand editor and how can I access SSESEditor?

This is from a while ago but this also helped me with my question. Mine isn’t an entire editor, just a scripted action when you right click a static mesh and want to create an actor with the mesh component.

https://forums.unrealengine.com/development-discussion/python-scripting/1854370-how-to-create-a-new-actor-blueprint-with-a-static-mesh-component