we’ve recently noticed that we accidently placed the wrong type of object.
We figured we could replace the Objects fairly easily using the Replace Actors feature since the correct object is a child of the incorrect one.
Unfortunately the object contains a Spline that is modified and does not seem to get copied over when replacing the actor.
A quick look at the code suggest that in fact all components get destroyed before the copy is even attempted.
Is there a better workflow for what we are trying to accomplish here?
For this case we can create a Blutility that does the replacement, but a generic way to do this would be appreciated since the majority of our Actors make use of splines in some way.
There does exist a delegate, but at that point the components are already gone.
I did not even realize the engine does not have functions for copying splines. We have our own spline function library which has options for this and make use of that quite frequently.
The real issue is more that when replacing an actor with another actor properties of all components are lost even if the replacement is a child of the original.
I’ve since found the ConvertActors feature. But this also has some rather severe limitations where only native component properties can be copied and it also requires a custom c++ base class.
The matrix property editor may be helpful in this regard, as if you were to make your own function it would use similar logic, as you can only copy over properties that exist on both objects. Though I don’t know how useful a solution this is if you ended up needing to create something that handles C++ properties as well.
You can also manually copy everything from the property editor window by pointing it at one object before and after, but this could end up being a slow process.
I believe creating a custom Blutility would be the best solution here, as these are the most generic options I could find.
Let me know if either of those solutions are useful!
“But I would much prefer this to be part of the normal replace actor functionality as that is what people already know.”
Recently, we have made a change so that direct properties on the actor itself can be copied over, see CL 48950061. I’m asking if we’d consider extending that to component properties too. I’ll give an update once I know more.
My apologies for the confusion, copying over direct properties of the actors was already in a long time. I’m logging a feature request to extend this to component properties.
Feel free to try out the following engine modification: Move the OldActor->DestroyConstructedComponents() call down to just before World->EditorDestroyActor(OldActor, true).
The DestroyConstructedComponents call was introduced to fix UE-95760 and is necessary - removing that call reintroduces that bug. However, during my quick tests it looks like moving that call downward is alright. This way, the CopyPropertiesForUnrelatedActors will process components (subobjects in general) too. This engine change needs further testing internally to get integrated, but you can consider adopting it already.
Blutility works. But it has significant limitations in terms of discovery and usability.
Let me clarify my questions:
Why does replacing an actor delete all component properties? At least when its replaced with a child blueprint there is no reason to delete the components before copying the properties
Can we add some ways for handling generic Actor Replacement? Currently there is only FEditorDelegates::OnEditorActorReplaced which gets called after the Old Actor has already lost all of its components
I believe you can achieve what you need using Core Redirects, specifically Class Redirects with InstanceOnly=true. Your situation sounds similar to the following description in the docs:
(Optional) If present and set to true, indicates that the original class still exists and can be referenced, but any existing instances of the old class (such as Actors or Components placed in Levels) should be remapped to the new class. This is especially useful when your project has a specialized version of a class that exists in the engine, but your Levels are full of instances of the original class, and you want to change them all to the project-specific version.
Please try this: assuming your parent blueprint is named “BP_Parent” and your child blueprint is named “BP_Child”, add the following section to any project config file (e.g. <ProjectPath>/Config/DefaultGame.ini):
On the snippet above, replace <Path>, “BP_Parent” and “BP_Child” with the actual names and path in your project. Also, be mindful of the 2 exact locations where the “_C” suffix should appear.
The class redirect above should replace the parent class of any actor instances from “BP_Parent_C” to “BP_Child_C”. If it works, just re-save all affected levels to make the change permanent. Afterwards, you can remove the class redirect from the ini file.
this solution will likely work but is even worse in terms of usability and discovery. Additionally it forces the change onto all existing actors instead of only a subset.
We’ve long since implemented a solution using Blutility.
But I would much prefer this to be part of the normal replace actor functionality as that is what people already know.
Teaching everyone that we have a special replacement function that should always be used seems like wasted effort (or even impossible for our modders).
I see. My idea was meant as a one-time fix to unblock you if you were still blocked by this. But I understand it is not a good solution for frequent use (by the way, you could apply the replacement per-level by re-saving only the desired levels before removing the ClassRedirect, but indeed not selectively per-actor).
It seems that this ticket was escalated to the engine devs, so I’ll leave it for them now.