Add component to actor in C++ (the final word!)

Hello! There are a ton of semi-outdated answers on this all over Google, so I am hoping this thread can be the definitive answer to this seemingly simple question. There seem to be differences between runtime and in the default constructor also.

So starting with RUNTIME:

We can all agree the up-to-date way to create the component is using NewObject, such as this:

 UPrimitiveComponent* NewComp = NewObject<UPrimitiveComponent>(MyActor);

Now it looks like we need a combination of:

NewComp->RegisterComponent();
NewComp->AttachToActor(MyActor);
MyActor->AddInstanceComponent(NewComp);

However, sources are varying as far as which ones are required and under which circumstances (some talk about USceneComponent requiring some of these more than simple UActorComponent?)

Note: AttachTo(), which is seen in many examples, has been deprecated in favor of the more specific AttachToComponent() & AttachToActor()

The questions being:

  1. What are the required steps for runtime creation/attachment of components?
  2. If any of those above are optional, why and under which circumstances/for which types of components?
  3. Is there any difference for components created in an actor’s constructor, other than creating the component using CreateDefaultSubobject<USceneComponent>("...");

Any insights on these would be fantastic, consider that myself and future generations of Googlers will be thankful. :grinning:

12 Likes

Why not use AActor::AddComponentByClass to add a component during runtime? I think AddInstanceComponent still needs to be called to get it to show in the editor details panel.

2 Likes

That’s a good one, thanks. Using it would cover the “attachment” part as it looks like it has built-in functionnality for that (although it relies on Component->bAutoRegister which is not that documented).

Otherwise, the other questions still stand on AddInstanceComponent, RegisterComponent and constructor mechanics…

It depends on component type :wink:

. If your component doesn’t need to “talk” to the
engine (rendering/collision/navigation/replication) then you don’t even need to register it.

Simply put, if a component inherits from USceneComponent then a call to RegisterComponent () is required.

If you want the actor’s transformation to affect the component as well, you need to use AttachTo* function. (implicitly requires registration)

InstanceComponent…
From what I understand, InstanceComponent is just a convention, some standardization of access to “optional” components. Actor does not have to own such a component.

In Actor constructor you can only use CreateDefaultSubobject. This creates a kind of “shape” of a Actor. Adds given component to related UClass, so any instance of this Actor have its ‘by default’. Unlike instanced components, which may only contain certain instances of a given actor.

1 Like

Thank you @Emaer, that’s almost all of it!

So I’m still not sure what AddInstanceComponent does (?).

Well it does this:

void AActor::AddInstanceComponent(UActorComponent* Component)
{
	Component->CreationMethod = EComponentCreationMethod::Instance;
	InstanceComponents.AddUnique(Component);
}

Sets the CreationMethod to Instance and adds it to the InstanceComponents set which is:

Array of ActorComponents that have been added by the user on a per-instance basis.

and FWIW it looks like the only references to GetInstanceComponents are in the Editor source folder, so if you are creating the component at runtime I don’t think anything is going to care about the creation method.

1 Like

That matches with my research and I did read a couple of comments mentioning “AddInstanceComponent() if you want to see your component in the editor”.

Thank you all, here is the summary (please reply if there are any issues with this and I will update!):

RUNTIME Best way:

  1. AActor::AddComponentByClass(), followed by AActor::FinishAddComponent() (only necessary if you specified true for bDeferredFinish)
    → This is what Blueprints use and does everything you need under the hood.
    → e.g. will do RegisterComponent() (if the component sets bAutoRegister, which is the default) and handle attachments (i.e. set as root, or attach to currrent root; otherwise manual attachment can be specified then handled yourself)

  2. MyActor->AddInstanceComponent(NewComp) should probably also be added, but seems to be used only to make any new components show up correctly in the editor

Constructor (CDO) Best way (the only way):

  1. CreateDefaultSubobject
    My only remaining question is if there are any caveats since this is in a CDO ( are there any restrictions to things that can be done here, obviously the game would not be running at this point but I would be curious to know if there are any rules somewhere on this, etc.)
16 Likes

Blockquote AActor::AddComponentByClass() , followed by AActor::FinishAddComponent()

I second this. I found it’s important to be aware of bDeferredFinish and that some component’s may need special initialization prior to InitializeComponent().

For example, attempting to AddComponentByClass() without bDeferredFinish == true for UPhysicalAnimationComponent will lead to UPhysicalAnimationComponent::InitComponent() but the UPhysicalAnimationComponent::SkeletalMeshComponent is not yet set. And InitComponent() is private so it cannot be called elsewhere. This lead to the game freezing and never crashing.

There is also AActor::AddComponent() which takes a UObject and appears to duplicate it, but I think the Add+FinishAdd method is cleaner.

Thank you so much for this. I was struggling for a hard minute because I needed to add a component that needed setup after construction but before being added to the world. FinishAddComponent() did the trick.

Hello everyone, is there solution for UE 5.2?
I still could not make component shows in editor window. It created, shows in viewport, but unclickable and dont shows in editor panel.

There is one of variant of code I used to make it work

USkeletalMeshComponent* SkeletalMeshComponent =
NewObject(
Actor,
USkeletalMeshComponent::StaticClass());

// We register the skeleton resource (which is not meant to be transient to
// the engine).
SkeletalMeshComponent->SetSkeletalMesh(SkeletalMesh);

// We register the components and attach them to the editor
// We are adding at runtime so its necessary to manually register to the engine.
SkeletalMeshComponent->AttachToComponent(
Actor->GetRootComponent(),
FAttachmentTransformRules::KeepRelativeTransform);

// Manually called because the component won’t appear in the list without this
// call.
Actor->AddInstanceComponent(SkeletalMeshComponent);

// Registration is required at runtime since we don’t add during construction
SkeletalMeshComponent->RegisterComponent();

Component creation called in actor during PreInitializationComponent

1 Like

After some debugging I could understand how to make it.
Warning! This is very bad voodoo, dont do it until you will be sure you need it.

So, add two dependencies into Build.cs

PrivateDependencyModuleNames.AddRange(new string[]
			{ "  "UnrealEd", "Kismet", "SubobjectEditor"  });

Then call next code in some function called by blueprint editor. PreInitializeComponents should be fine.

USkeletalMeshComponent* SkeletalMeshComponent =
		NewObject<USkeletalMeshComponent>(
			this,
			USkeletalMeshComponent::StaticClass());

	 

	// We register the components and attach them to the editor
	// We are adding at runtime so its necessary to manually register to the engine.
	SkeletalMeshComponent->AttachToComponent(
		GetRootComponent(),
		FAttachmentTransformRules::KeepRelativeTransform);

	// Manually called because the component won't appear in the list without this
	// call.
	Actor->AddInstanceComponent(SkeletalMeshComponent);


Dont register component, this have no point inside editor.

Then, the real magic have begin.

FBlueprintEditorModule& BlueprintEditorModule = FModuleManager::LoadModuleChecked<
			FBlueprintEditorModule>("Kismet");
		IBlueprintEditor& EditorRef = BlueprintEditorModule.GetBlueprintEditors()[0].Get();
		FBlueprintEditor& DerivedRef = static_cast<FBlueprintEditor&>(EditorRef);
		SSubobjectEditor* SS = DerivedRef.GetSubobjectEditor().Get();
		AMyActor* Context = Cast<AMyActor>(SS->GetObjectContext());// get context
		USkeletalMeshComponent* SkeletalMeshComponent =
		NewObject<USkeletalMeshComponent>(
			Context ,
			USkeletalMeshComponent::StaticClass());
SkeletalMeshComponent->AttachToComponent(
	Context->GetRootComponent(),
		FAttachmentTransformRules::KeepRelativeTransform);
Context ->AddInstanceComponent(SkeletalMeshComponent);
		SS->UpdateTree();//update component tab

If you do everything right, runtime created components appears in blueprint viewport AND blueprint component tab.

1 Like

Thanks all for your suggestions.

Just to say the final word, the following code is confirmed to work on UE5.3

#if WITH_EDITOR
#include "UnrealEd.h"
#endif

...

#if WITH_EDITOR
...
UBoxComponent* BoxComponent = NewObject<UBoxComponent>(this, TEXT("NewBoxComponent"));
if (IsValid(BoxComponent))
{
   AddInstanceComponent(BoxComponent);
   BoxComponent->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepRelativeTransform);
   // deselect/select this actor to update Editor details
   USelection* Selection = GEditor->GetSelectedActors();
   Selection->Deselect(this);
   GEditor->SelectActor(this, true, true);
}
...
#endif
4 Likes

Though AActor::AddComponentByClass() is tempting to use, you should note that epic says specifically not to call this function directly:

1 Like

Unless I’m mistaken, I believe that note only applies to UK2Node_AddComponentByClass, which is the Blueprint side of AddComponentByClass, but AddComponentByClass is fine for C++ use. (?)

1 Like

I would agree if AddComponentByClass didn’t say BlueprintInternalUseOnly = "true"

Hey! So I spent the whole day trying to add this component…

the “MyActor->AddInstanceComponent(NewComp);” did not work for me, I’m using UE5.3. It was creating a diferent instance component in the same place of my existing component and ended up bugging out the whole character blueprint and having to create a new character.

The solution that worked for me was to add only the “CreateDefaultSubobject(TEXT(“YourComponentName”))” and then AddOwnedComponent( UActorComponent * Component ). Dont forget that you need to restart the whole project for changes to take effect. This is the tread that I followed: Create and Attach Custom Actor Component - #6 by ErayT

I was wondering too if it would be safe to use AddComponentByClass to easily create components at runtime, and was confused by the DO NOT USE DIRECTLY comment and BlueprintInternalUseOnly flag…

I think the comment is only relevant for UK2Node_AddComponentByClass or otherwise it would have been placed in the function comment body directly, not in the @see note.

It seems this function is safe to use in C++, since it is called in some places in some built-in plugins of the engine (see examples below).

Moreover, it looks like using this function automatically adds replication and per-instance serialization (game save) support for the created component, and is using the bAutoRegister flag of the component to register it or not.


Some examples:

  • In PCG (Procedural Content Generation) unit tests:
UPCGUnitTestDummyComponent* Component = Cast< UPCGUnitTestDummyComponent>(TestData.TestActor->AddComponentByClass(Settings->ComponentClass, false, FTransform::Identity, false));
  • In LiDAR Point Cloud plugin:
ULidarPointCloudComponent* PCC = (ULidarPointCloudComponent*)TargetActor->AddComponentByClass(ULidarPointCloudComponent::StaticClass(), true, Component->GetComponentTransform(), false);
PCC->SetPointCloud(Component->GetPointCloud());
PCC->SetWorldTransform(Component->GetComponentTransform());
PCC->AttachToComponent(TargetActor->GetRootComponent(), FAttachmentTransformRules(EAttachmentRule::KeepWorld, false));
  • In Smart Objects plugin for preview meshes:
UStaticMeshComponent* MeshComponent = Cast<UStaticMeshComponent>(Actor->AddComponentByClass(UStaticMeshComponent::StaticClass(), true, FTransform::Identity, false));
if (MeshComponent)
{
	MeshComponent->SetStaticMesh(InStaticMesh);
}

EDIT

After some research in the source code, it does not seems to be the best way to create C++ components at runtime.

In fact, the component is added to the BlueprintCreateComponents array for serialization and marked as created by user construction script (in blueprint).
It seems the serialization will be valid only if the archetype of the component is a component CDO or an actor’s DefaultSubObject component.
Also, this array gets occasionally wiped and refilled using the actor’s construction script.

From looking into how the UGameFrameworkComponentManager of the Modular Gameplay plugin handles the runtime component creation, I think the only required setup are those 2 lines:

UActorComponent* NewComp = NewObject<UActorComponent>(ActorInstance, ComponentClass);
NewComp->RegisterComponent();

You should also manage the attachment for USceneComponents, and also prevent creation of replicated components on client actors (no authority).
Replication is handled inside RegisterComponent().
I don’t know if we need to call something to support game save (e.g. AddInstancedComponent?).

A generic function to create runtime actor components would looks like that:

UActorComponent* CreateComponentOnInstance(AActor* ActorInstance, TSubclassOf<UActorComponent> ComponentClass, USceneComponent* OptionalParentForSceneComponent = nullptr)
{
	if (!ActorInstance || !ComponentClass)
		return nullptr;

	// Don't create component on a template actor (CDO or Archetype)
	if (ActorInstance->IsTemplate())
		return nullptr;

	// For multiplayer games, create component only on server if component is replicating
	const UActorComponent* ComponentCDO = ComponentClass->GetDefaultObject<UActorComponent>();
	if (ComponentCDO->GetIsReplicated() && !ActorInstance->HasAuthority())
		return nullptr;

	UActorComponent* NewComp = NewObject<UActorComponent>(ActorInstance, ComponentClass);

	// Handles USceneComponent attachment
	if (USceneComponent* NewSceneComp = Cast<USceneComponent>(NewComp))
	{
		USceneComponent* ParentComponent = OptionalParentForSceneComponent;
		if (!ParentComponent)
			ParentComponent = ActorInstance->GetRootComponent();

		if (ParentComponent)
		{
			// Parent component should always be owned by the passed in actor instance!
			check(ParentComponent->GetOwner() != ActorInstance);
			NewSceneComp->SetupAttachment(ParentComponent);
		}
		else
		{
			// Set component directly as root if no root component on the actor
			ActorInstance->SetRootComponent(NewSceneComp);
		}
	}

	NewComp->RegisterComponent();
	return NewComp;
}
3 Likes

To make the instanced component appear in the tree, you can do this instead of manually re-selecting the actor:

SelectedActor->AddInstanceComponent(NewComponent);

// Broadcast edit notifications so that level editor details are refreshed (e.g. components tree)
FLevelEditorModule& LevelEditor = FModuleManager::LoadModuleChecked<FLevelEditorModule>(TEXT("LevelEditor"));
LevelEditor.BroadcastComponentsEdited();