Clone An Actor Including Attached Components?

Hi, I’ve been looking for a way to clone actor instances so that each clone behaves in exactly the same way. The actors I want to clone have custom UActorComponents that modify the behaviour of the parent class, so I would like these components and their properties to be copied over to the actor clones. I set it up this way to make it very easy for level designers to add change the behaviour of actors (no blueprints, no C++).

I have seen similar questions here, but none have solutions that work. I have created a custom blueprint node in C++ that uses the UWorld::SpawnActorAbsolute() method, with a non-NULL template parameter. It crashes at the UActorComponent::InitializeComponent() method.

Is there an existing workaround for this? Thanks for any feedback on this issue.

EDIT:

As a workaround, would serializing the object to be cloned then deserializing it into a new actor instance work? Something like [get actor to be cloned] => [serialize the actor] => [create new actor] => [apply serialized data to new actor]? How would one go about doing this in C++?

Hey rb3-

Are you trying to spawn a copy of an actor in game or are you trying to duplicate an actor in the level inside the editor. If you want to spawn a copy of an actor you should be able to use Spawn Actor and set what class the spawned actor belongs to. If you are trying to duplicate something in the editor, then with the actor selected and the translation widget showing, you can hold Alt and drag one of the translation arrows to drag out a duplicate of the actor.

Cheers

Hi, I’m trying to spawn a copy of an actor in game. Yeah, I have already tried that, and it causes a crash:

auto world = aActor->GetWorld( );

if( world ) {
	FActorSpawnParameters spawnParameters;
	//Uncommenting the lines below causes an assertion in UActorComponent::InitializeComponent()
	//spawnParameters.Name = aActor->GetFName( );
	//spawnParameters.Template = aActor;
	spawnParameters.Owner = aActor->GetOwner( );
	spawnParameters.Instigator = aActor->GetInstigator( );
	spawnParameters.SpawnCollisionHandlingOverride = aCollisionHandlingOverride;

	auto clone = world->SpawnActorAbsolute<AActor>( aActor->GetClass( ), aSpawnTransform, spawnParameters );
}

Could you post the code that you’re using to spawn the actor? I’m not sure if, in the snippet posted, if aActor is a variable or if it is supposed to be a reference to the AActor class. Additionally 'm not sure what aCollisionHandlingOverride is. It may be simplest to upload the project to dropdox and then send me a PM on the forums with a link to download it.

Hi, thanks for the reply. I’m actually using that snippet in a function, to be called from blueprint as a node. My project is 2+ Gb large, so I can’t really upload it to my dropbox. Here is the declaration for the function:

UCLASS( )
class RIM_API URIMUtilities : public UBlueprintFunctionLibrary
{
	GENERATED_BODY( )

public:
	UFUNCTION( BlueprintCallable, Category = "RIM Utilities" )
	static class AActor* CloneActor( AActor* Actor, FTransform SpawnTransform, ESpawnActorCollisionHandlingMethod CollisionHandlingOverride );
};

…and here’s the implementation:

AActor* URIMUtilities::CloneActor( AActor* aActor, FTransform aSpawnTransform, ESpawnActorCollisionHandlingMethod aCollisionHandlingOverride ) {
	if( aActor == NULL ) {
		return NULL;
	}

	auto world = aActor->GetWorld( );

	if( !world ) {
		return NULL;
	}

	FActorSpawnParameters spawnParameters;
	spawnParameters.Name = aActor->GetFName( );
	spawnParameters.Template = aActor;
	spawnParameters.Owner = aActor->GetOwner( );
	spawnParameters.Instigator = aActor->GetInstigator( );
	spawnParameters.SpawnCollisionHandlingOverride = aCollisionHandlingOverride;

	return world->SpawnActorAbsolute<AActor>( aActor->GetClass( ), aSpawnTransform, spawnParameters );
}

I copied the code into an actor class and was able to call the function without a crash. If this code is calling a crash for you when called can you post the callstack and log files from the crash to provide additional information.

Using UE 4.9.1, I am calling this function in a blueprintable component, attached to the default third-person character. It also crashes when I attach the component to a default cube. When I set “spawnParameters.Name”, this the call stack:

UE4Editor-Engine.dll!UActorComponent::InitializeComponent() Line 623	C++
UE4Editor-Engine.dll!UMovementComponent::InitializeComponent() Line 91	C++
UE4Editor-Engine.dll!AActor::InitializeComponents() Line 3743	C++
UE4Editor-Engine.dll!AActor::PostActorConstruction() Line 2599	C++
UE4Editor-Engine.dll!AActor::FinishSpawning(const FTransform & UserTransform={...}, bool bIsDefaultTransform) Line 2578	C++
UE4Editor-Engine.dll!AActor::PostSpawnInitialize(const FTransform & UserSpawnTransform={...}, AActor * InOwner, APawn * InInstigator, bool bRemoteOwned=false, bool bNoFail=false, bool bDeferConstruction=false) Line 2534	C++
UE4Editor-Engine.dll!UWorld::SpawnActor(UClass * Class, const FTransform * UserTransformPtr=0x000000924779d130, const FActorSpawnParameters & SpawnParameters={...}) Line 430	C++
UE4Editor-Engine.dll!UWorld::SpawnActorAbsolute(UClass * Class=0x0000009259072080, const FTransform & AbsoluteTransform, const FActorSpawnParameters & SpawnParameters={...}) Line 252	C++
UE4Editor-RIM-Win64-DebugGame.dll!URIMUtilities::CloneActor(AActor * aActor=0x0000009201355600, FTransform aSpawnTransform={...}, ESpawnActorCollisionHandlingMethod aCollisionHandlingOverride=Undefined) Line 145	C++
...

…and when I comment out the “spawnParameters.Name” line, but leave the “spawnParameters.Template” line, this is the call stack:

UE4Editor-Core.dll!FMallocTBB::Realloc(void * Ptr, unsigned __int64 NewSize, unsigned int Alignment) Line 93	C++
UE4Editor-Core.dll!FPaths::CollapseRelativeDirectories(FString & InPath) Line 614	C++
UE4Editor-Core.dll!FPaths::ConvertRelativePathToFull(const FString & BasePath, const FString & InPath) Line 778	C++
UE4Editor-Core.dll!FPaths::ConvertRelativePathToFull(const FString & InPath) Line 762	C++
UE4Editor-Core.dll!FWindowsPlatformFile::NormalizeFilename(const wchar_t * Filename) Line 455	C++
UE4Editor-Core.dll!FWindowsPlatformFile::GetTimeStamp(const wchar_t * Filename) Line 519	C++
UE4Editor-Core.dll!FFileManagerGeneric::GetTimeStamp(const wchar_t * Filename) Line 461	C++
UE4Editor-CoreUObject.dll!FPackageName::FindPackageFileWithoutExtension(const FString & InPackageFilename, FString & OutFilename) Line 590	C++
UE4Editor-CoreUObject.dll!FPackageName::DoesPackageExist(const FString & LongPackageName, const FGuid * Guid, FString * OutFilename) Line 632	C++
UE4Editor-UnrealEd.dll!UCookOnTheFlyServer::Cache(const FName & PackageName) Line 792	C++
UE4Editor-UnrealEd.dll!UCookOnTheFlyServer::MarkPackageDirtyForCooker(UPackage * Package) Line 2248	C++
UE4Editor-UnrealEd.dll!TBaseUObjectMethodDelegateInstance<0,UCookOnTheFlyServer,void __cdecl(UObject * __ptr64)>::ExecuteIfSafe(UObject * <Params_0>) Line 772	C++
UE4Editor-CoreUObject.dll!TBaseMulticastDelegate<void,UObject * __ptr64>::Broadcast(UObject * <Params_0>) Line 809	C++
UE4Editor-CoreUObject.dll!UObject::Modify(bool bAlwaysMarkDirty) Line 850	C++
...
UE4Editor-Engine.dll!AActor::RegisterAllComponents() Line 3566	C++
...
UE4Editor-RIM-Win64-DebugGame.dll!URIMUtilities::CloneActor(AActor * aActor, FTransform aSpawnTransform, ESpawnActorCollisionHandlingMethod aCollisionHandlingOverride) Line 145    C++
...

Hey rb3-

I was able to reproduce the crash you mentioned and found that this bug has already been reported for investigation (UE-20951). As you mentioned, commenting out the .Name and the .Template lines will allow the actor to spawn without crashing.

Cheers

Hi , thanks for all the feedback. Is there another way I can clone an actor for now? Will serializing then deserializing the actor into another actor have the same effect? How would I do that? Thanks!

One solution you could use would be to spawn an actor of the same class as the one you’d like to clone, and then get a reference to the base actor so that you can copy any values you want to be the same from the base actor to the new actor.

i wanted such logics for my flash back character in my time rewinder component and the way i copied my actor was first spawn a character of the same class and then just iterate through it’s properties as such :



hope this helps