How to replace a component with a different class (Same actor)

Is there a way in the editor to take an existing component that you added, and change it to a subclass of that same component? The only way I see to do it is to completely remove the component and create a new one, and then I have to go through every script where the old one was referenced and fix it manually. This can be a nightmare if you have a lot of existing blueprint code.

2 Likes

Hi, did u find a way?

Found a way to do this by calling the following static function from within an AssetActionUtility blueprint

void UMyGenericUtils::MigrateComponents(UObject* Object)
{
	UBlueprint* Blueprint = Cast<UBlueprint>(Object);
	if (Blueprint && Blueprint->SimpleConstructionScript)
	{
		const TArray<USCS_Node*>& ScsNodes = Blueprint->SimpleConstructionScript->GetAllNodes();
		TArray<USCS_Node*> OldComponents = {};
		for (const auto ScsNode : ScsNodes)
		{
			if (ScsNode)
			{
				if (const auto SceneComponent = Cast<USceneComponent>(ScsNode->ComponentTemplate))
				{
                                       // Change this logic to your own to target the components you want
					if (SceneComponent->GetName().Contains("Socket")
						&& !SceneComponent->GetName().Contains("Sockets"))
					{
						OldComponents.Add(ScsNode);
					}
				}
			}
		}

		for (const auto OldNode : OldComponents)
		{
			USCS_Node* NewNode = Blueprint->SimpleConstructionScript->CreateNode(
				UBuildingSocket::StaticClass(),
				FName(OldNode->ComponentTemplate->GetName().Replace(TEXT("_GEN_VARIABLE"), TEXT(""))));
                        // Add parent node so that we can SetupAttachment and add a transform
			auto ParentNode = Blueprint->SimpleConstructionScript->FindParentNode(OldNode);
			if (ParentNode) NewNode->SetParent(ParentNode);
			USceneComponent* OldComp = Cast<USceneComponent>(OldNode->ComponentTemplate);
			USceneComponent* NewComp = Cast<USceneComponent>(NewNode->ComponentTemplate);
			NewComp->SetRelativeTransform(OldComp->GetRelativeTransform());
			NewComp->ComponentTags = OldComp->ComponentTags;
			Blueprint->SimpleConstructionScript->AddNode(NewNode);
			// Blueprint->SimpleConstructionScript->RemoveNode(OldNode);
		}
	}
	else
	{
		UE_LOGFMT(MyLogDefault, Error, "Could not cast to blueprint");
	}
}

Make sure the BP you wish to migrate is closed before running or else it wont work. This will auto increment the component names as well so that it doesn’t overwrite the existing ones, so uncomment the RemoveNode line after you are satisfied with your changes.

This doesn’t work well, there are weird problems with root bone .
I’m trying to replace all ISMC to HISMC.

There is something like this for the character movement component.

@smmehl0311’s method didn’t work for me, but it led to this solution.

  1. Call this function from a AssetActionUtility blueprint with the classes you want to convert from and to:
void UMyBlueprintLibrary::MigrateBlueprintComponents(UBlueprint *BPToMigrate, TSubclassOf<UActorComponent> OldClass, TSubclassOf<UActorComponent> NewClass) {

	if (BPToMigrate && BPToMigrate->SimpleConstructionScript) {
		USimpleConstructionScript* SCS = BPToMigrate->SimpleConstructionScript;
		const TArray<USCS_Node*>& ScsNodes = SCS->GetAllNodes();
		
		for (const auto ScsNode : ScsNodes) {
			UActorComponent* component = ScsNode->ComponentTemplate;
			
			if (component->IsA(OldClass)) {
				ScsNode->ComponentClass = NewClass;

				FObjectDuplicationParameters dup(component, component->GetOuter());
				dup.DestClass = NewClass;
				ScsNode->ComponentTemplate = CastChecked<UActorComponent>(StaticDuplicateObjectEx(dup));
			}
		}
	}
}
  1. Open the blueprint in question; you should see that the component’s type has changed! Now, rename the affected component(s). The new name can be anything; it’s the renaming itself that’s important.
  2. For every blueprint affected by the rename, including the original one (you can filter for Modified in the content browser) open it and do File->Refresh All Nodes. Without this step, attempts to access the component will return None.

Caveats: This only works for converting a component to a child class. Blueprints that inherit from the modified blueprint and have changed properties on the component might have those properties reset.