Hi Vladislav,
Let me first address the case where “cac.ExperimentalAllowPerInstanceChildActorProperties” is disabled. In that situation, the behavior you are observing is expected. Child Actor Components spawn new actors when registered into the world and despawn them when unregistered. This means that any changes made to those spawned actors cannot aren’t expected to be persisted from one world to another (including the Editor world and the PIE world), since each world has its own actor spawned from scratch by the Child Actor Component. The expected way to change the properties of the actor that should be spawned is to add the Child Actor Component to a Blueprint and make the desired changes to the “Child Actor Template” that becomes available after setting the “Child Actor Class”.
Note that the Editor makes an effort to try to prevent the user from making changes to an actor spawned from a Child Actor Component, for example by making it unselectable so that its properties cannot be changed in the details panel (which is something the experimental setting does change). In theory, it should not be possible to make any changes that could possibly be saved into the level and reloaded when starting a “Standalone Game” session, so if you see that happening, that might actually be a bug.
Also note that, once you enable “cac.ExperimentalAllowPerInstanceChildActorProperties”, make changes to a child actor, and save the level, these changes will be applied when reloading the level or starting a “Standalone Game” session, even if the experimental setting is later disabled. However, if you simply resave the level while the setting is disabled, all those changes will be forgotten again.
Ok, now let’s consider the case where “cac.ExperimentalAllowPerInstanceChildActorProperties” is enabled. In that situation, changes to child actor instances spawned by child actor components are allowed, and the Editor must know how to save these changes with the level and later restore them after reloading the level (including when launching Standalone Game) and registering any Child Actor Components. For PIE, the current Editor world is duplicated to create the PIE world, and there it makes sense to also duplicate any existing Child Actors. So, using flag NonPIEDuplicateTransient does seem appropriate and necessary as you pointed out, otherwise some other mechanism would have to exist to copy over the changes after spawning new child actors on the PIE world.
After thinking about this for a while, I decided to check the recent changes made to how Child Actors work. And I found that, up to UE 5.5, flag NonPIEDuplicateTransient was indeed the one that was used. It was actually changed to DuplicateTransient by the following commit (which was integrated into 5.6) in an attempt to address some crashes in world-partition levels:
Revision: 723ba584d1fd69bcb8f39e05040b3945eadbf8bb
Date: 28/11/2024 10:05:02 (integrated in 5.6)
CL: 38476333 on ue5-main
ChildActorComponent:
- Change child actors from NonPIEDuplicateTransient to DuplicateTransient to avoid duplicating them when duplicating the world in PIE.
- We don't need to duplicate child actors in PIE because they will be recreated when the component will be registered to the world.
- Was causing issues for partitioned worlds when child actors were dirty and unsaved, resulting in child actors being recreated leaving child actors outered to the unsaved actor container.
- Change the duplicated unsaved actor container outer to be the level package instead of the level object, to avoid actors in it returning the outer level when calling AActor::GetLevel().
- AActor::GetLevel() should be changed to return Cast<ULevel>(GetOuter()) instead of GetTypedOuter<ULevel>(), will make this change in anotrher changelist to minimize risk.
- Dont't include child actors in the unsaved actor container since they will be recreated during child actor component world registration.
This fixes a couple of different crashes related to unsaved child actors and unsaved child actor Blueprint classes.
We can see from the second bullet point above that the engine devs assumed what I mentioned in the first paragraph: child actors shouldn’t need to be duplicated and can simply be recreated from scratch by their components on the PIE world (there is probably some protection to keep this re-creation from happening when the duplication took place, I did not check). But, as I mentioned before, that does not hold true when “cac.ExperimentalAllowPerInstanceChildActorProperties” is enabled, so this commit ended up breaking the behavior in that scenario.
Alright. One thing to note is that, if you do not use world partitioning, you can probably apply your suggested fix (which effectively reverts some of the changes of the commit above) without any problems. Unfortunately, however, it seems that your suggestion cannot currently be applied in the general case, since it would be fixing an experimental feature while bringing back important crashes related to child actors with world-partition. There might be other ways to solve these crashes, but this would require further investigation.
For now, I will file an internal bug report about this regression and link it to this topic so that the engine devs can take a look and give it some thought. Do you have any additional questions, or would you like to make any further considerations about this issue?
Best regards,
Vitor