How to add component to existing actor in level with Python/Blueprint?

In the level editor in the Details panel there is a button “Add Component”. And you can add any component to an existing actor.

But how can you add a component (StaticMeshComponent) to actor with a Python or Blueprint Script or maybe c++?

Cant find anything in references. It looks like it should be implemented.

Unfortunately a lot of the logic needed to correctly add an instanced component to an actor (both in a level and in a BP) for the editor is currently tied to the UI flow itself.

We have an open issue (UE-64131) to untangle that logic so it can be shared by the UI and scripting, however I can’t say at this point when that will happen.

If you’re curious about investigating more yourself, then SSCSEditor is the class that handles the UI. In this case a subset of the code dealing with the EComponentEditorMode::ActorInstance path of SSCSEditor::AddNewComponent will likely be required.

I’m trying to wrap my head around all of this. So in order to get that functionality we would need to write some c++ code to implement that feature? Currently the SSCSEditor is currently not available to BP or python?

I’m also trying to understand the best way to get this done. Can adding a component to existing actor or creating a fresh actor with components in level be done with c++ if not with python? And would I follow this order to do it :

  1. World->SpawnActor<AActor>(Class, Transform, SpawnParameters)
  2. Actor->PostSpawnInitialize(Transform, Actor, Pawn, bRemoteOwned, bNoFail, bDeferConstruction)
  3. Actor->PostActorCreated() or PostLoad()
  4. ActorComponent->OnComponentCreated()
  5. Actor->PreInitializeComponents()
  6. ActorComponent->InitializeComponent()
  7. Actor->PostInitializeComponents()
  8. **OnActorSpawned() ??? **( Not sure what this is or if it is important )
  9. BeginPlay() ???

If so could I just UFunction these in a custom cpp and h files, compile them to make them accessible in python?

I made this function and it works fine:



//You pass to it class of component, otherwise it creates StaticMeshComponent
UActorComponent* UBlackMesaLifeBlueprintLibrary::AddComponent(AActor* a,USceneComponent *future_parent, FName name, UStaticMesh* mesh, UClass* NewComponentClass)
{

    UActorComponent* retComponent = 0;
    if (!NewComponentClass)
    {
        //DuplicateObject<UStaticMeshComponent>(dup_source,a,name)
        UStaticMeshComponent* NewComponent = NewObject<UStaticMeshComponent>(a, name);// , EObjectFlags::RF_DefaultSubObject);
        //UStaticMeshComponent* NewComponent = DuplicateObject<UStaticMeshComponent>(dup_source, a, name/*ActorCmp, NewActor, NewName*/);
        //a->AddOwnedComponent(NewComponent);
        FTransform CmpTransform;// = dup_source->GetComponentToWorld();
        NewComponent->SetStaticMesh(mesh);
        NewComponent->AttachToComponent(future_parent, FAttachmentTransformRules::KeepWorldTransform);
        NewComponent->SetComponentToWorld(CmpTransform);
        a->AddInstanceComponent(NewComponent);
        NewComponent->OnComponentCreated();
        NewComponent->RegisterComponent();

        a->RerunConstructionScripts();
        retComponent = NewComponent;

    }
    else {
        UActorComponent* NewComponent = NewObject<UActorComponent>(a, NewComponentClass, name);
        FTransform CmpTransform;// = dup_source->GetComponentToWorld();
        //NewComponent->AttachToComponent(sc, FAttachmentTransformRules::KeepWorldTransform);
        // Do Scene Attachment if this new Comnponent is a USceneComponent
        if (USceneComponent* NewSceneComponent = Cast<USceneComponent>(NewComponent))
        {
            if(future_parent !=0)
                NewSceneComponent->AttachToComponent(future_parent, FAttachmentTransformRules::KeepWorldTransform);
            else
                NewSceneComponent->AttachToComponent(a->GetRootComponent(), FAttachmentTransformRules::KeepWorldTransform);

            NewSceneComponent->SetComponentToWorld(CmpTransform);
        }
        a->AddInstanceComponent(NewComponent);
        NewComponent->OnComponentCreated();
        NewComponent->RegisterComponent();

        a->RerunConstructionScripts();
        retComponent = NewComponent;
    }

    return retComponent;
}


2 Likes

What milestones has this code? Is it incorrect? I had no problems so far with it.

Hey YanDaik,

Thanks for sharing that snippet of code.

I have an editor utility widget that gets the current selection and does stuff to it, but it only works in the world outliner, not in a blueprint actor outliner. Is that the same issue as the one above?

Thanks for posting this YanDaik, just what I needed to get started with adding a component to an actor. I changed a few bits to suit my own needs but the overall idea works perfectly. I’m sure you probably know this, but if not, a small tip that maybe useful: instead of using UClass* as a parameter, use TSubclassOf<UActorComponent> . This will enforce that the class chosen will be derived from UActorComponent and will limit the choices available in Blueprint. Thanks again

With Unreal Engine 5.0 this functionality has been added with support for Blueprints and Python. Check out this snippet to see an example of adding a point light component to a blueprint and actors in the level.

1 Like

Thanks Ben for the blueprint snippets - they work as expected :smiley:

But when I try convert the BP into python the component doesn’t seem to get attached. Can you tell what I’m doing wrong?

so_subsystem = unreal.get_engine_subsystem(unreal.SubobjectDataSubsystem)  
for actor in unreal.VRScoutingInteractor.get_selected_actors():
    root_sub_object = so_subsystem.k2_gather_subobject_data_for_instance(actor)[0]
    new_sub_object = so_subsystem.add_new_subobject(unreal.AddNewSubobjectParams(
        parent_handle=root_sub_object,
        new_class=unreal.PointLightComponent,
    ))
    print(f"created {new_sub_object}")

# LogPython: created (<Struct 'SubobjectDataHandle' (0x000008ED0C7C12D0) {}>, Text(""))
3 Likes

no use in 5.0.3

What do you mean by no use ? How would you add a Suboject in 5.0.3 ? I’m running into the same issue where subsystem.add_new_subobject(AddNewSubobjectParam()) does nothing…

@Lukeha is there any update for this Python problem?

@BenjaFriend22 Could you please give a example in Python scripts?

@Shawn_Wsa I think it was just a bug in 5.0. When I run the exact python snippet above in 5.2 the point light component is attached to the selected actor as expected