Hello [mention removed],
Apologies for the delayed response. I’ve looked into your case and have a working solution for UE 5.5.
You can create a clone of an actor from its CDO by taking a source actor class and selectively copying only the components you want. This is done by defining a list of allowed component classes. You can then use FProperty::CopyCompleteValue_InContainer to properly duplicate the property values from the source component to the cloned component.
To preserve the parent-child hierarchy for scene components, you iterate over the cloned components and attach them to the corresponding cloned parent if it exists, or to a root component otherwise. The AttachParent/AttachChildren properties are not copied directly, since the hierarchy is restored manually using SetupAttachment.
Finally, the cloned components need to be registered to make them functional in the scene.
Here is a working example for a PreviewCloneActor that clones another existing actor at runtime:
APreviewCloneActor.h
UCLASS()
class CLONEACTORCASE_API APreviewCloneActor : public AActor
{
GENERATED_BODY()
public:
APreviewCloneActor();
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Preview")
TObjectPtr<class USceneComponent> PreviewRoot;
/*Clone only the allowed component classes from SourceActor into *this* actor.
* - Defaults come from the source component's archetype (BP template) first.
* - (Optional) Apply instance overrides on top.
*/
UFUNCTION(BlueprintCallable, Category = "Preview Clone")
bool CloneFromSource(
AActor* SourceActor,
const TArray<TSubclassOf<UActorComponent>>& AllowedComponentClasses,
bool bIncludeInstanceOverrides = true);
};
APreviewCloneActor.cpp
// PreviewCloneActor.cpp
#include "PreviewCloneActor.h"
// Copy properties excluding attachment fields
static void CopyPropertiesSameClassFiltered(const UObject* Src, UObject* Dst)
{
if (!Src || !Dst || Src->GetClass() != Dst->GetClass()) return;
static const FName NAME_AttachParent(TEXT("AttachParent"));
static const FName NAME_AttachChildren(TEXT("AttachChildren"));
static const FName NAME_AttachSocketName(TEXT("AttachSocketName"));
for (TFieldIterator<FProperty> It(Src->GetClass(), EFieldIterationFlags::IncludeSuper); It; ++It)
{
// Skip things the engine doesn't normally duplicate/serialize
FProperty* Prop = *It;
if (Prop->HasAnyPropertyFlags(CPF_Transient | CPF_DuplicateTransient | CPF_SkipSerialization))
continue;
// Skip attachment relationships for scene components (this is handled separately)
if (Src->IsA<USceneComponent>() && (Prop->GetFName() == NAME_AttachParent || Prop->GetFName() == NAME_AttachChildren || Prop->GetFName() == NAME_AttachSocketName))
continue;
// Copy the property value
Prop->CopyCompleteValue_InContainer(Dst, Src);
}
}
APreviewCloneActor::APreviewCloneActor()
{
PrimaryActorTick.bCanEverTick = false;
PreviewRoot = CreateDefaultSubobject<USceneComponent>(TEXT("PreviewRoot"));
SetRootComponent(PreviewRoot);
}
bool APreviewCloneActor::CloneFromSource(
AActor* SourceActor,
const TArray<TSubclassOf<UActorComponent>>& AllowedComponentClasses,
bool bIncludeInstanceOverrides)
{
if (!SourceActor || !PreviewRoot)
return false;
// Collect allowed components from source actor
TArray<UActorComponent*> AllowedComps;
for (UActorComponent* Comp : SourceActor->GetComponents())
{
if (!Comp)
continue;
for (const TSubclassOf<UActorComponent>& AllowedClass : AllowedComponentClasses)
{
if (Comp->IsA(*AllowedClass))
{
AllowedComps.Add(Comp);
break;
}
}
}
// Clone each allowed component
TMap<const UActorComponent*, UActorComponent*> SourceToClone;
for (UActorComponent* SrcComp : AllowedComps)
{
UActorComponent* DstComp = NewObject<UActorComponent>(
this,
SrcComp->GetClass(),
MakeUniqueObjectName(this, SrcComp->GetClass(), SrcComp->GetFName()),
RF_Transient
);
if (!DstComp)
continue;
// Copy BP template properties
if (const UObject* Archetype = SrcComp->GetArchetype())
CopyPropertiesSameClassFiltered(Archetype, DstComp);
// Optionally copy instance overrides
if (bIncludeInstanceOverrides)
CopyPropertiesSameClassFiltered(SrcComp, DstComp);
// Configure primitive component properties
if (UPrimitiveComponent* Prim = Cast<UPrimitiveComponent>(DstComp))
{
Prim->SetGenerateOverlapEvents(false);
Prim->SetCollisionEnabled(ECollisionEnabled::NoCollision);
}
SourceToClone.Add(SrcComp, DstComp);
}
// Recreate hierarchy (for derived SceneComponents)
for (UActorComponent* SrcComp : AllowedComps)
{
USceneComponent* SrcScene = Cast<USceneComponent>(SrcComp);
USceneComponent* DstScene = Cast<USceneComponent>(SourceToClone[SrcComp]);
if (!SrcScene || !DstScene)
continue;
// Attach to cloned parent if it exists, else attach to PreviewRoot
USceneComponent* SrcParent = SrcScene->GetAttachParent();
if (SrcParent && SourceToClone.Contains(SrcParent))
{
DstScene->SetupAttachment(Cast<USceneComponent>(SourceToClone[SrcParent]));
}
else
{
DstScene->SetupAttachment(PreviewRoot);
}
}
// Register cloned components
for (auto& Pair : SourceToClone)
{
if (UActorComponent* DstComp = Pair.Value)
{
if (!DstComp->IsRegistered())
DstComp->RegisterComponent();
}
}
return true;
}
With this approach you can control which components are cloned and the parent-child hierarchy is preserved for scene components.
The cloning method also includes an optional parameter to apply instance-specific overrides, allowing the clone to inherit runtime changes from the level instead of just the default template values.
This workflow has been tested on a simple Blueprint containing multiple components, with cloning limited to static meshes.
[Image Removed]
[Image Removed]
Please let me know if this information helps.
Best,
Francisco