Hi,
By default, the engine does just replicate all subobjects with the owning actor as their outer, regardless of whether they have a different outer on the server. A while ago, that handling in Read/WriteContentBlockHeader was added to try and create replicated subobjects on the client with their correct outer.
However, your reading of that comment is correct. The default implementation of AActor::ReplicateSubobjects replicates the lowest subobjects first, before their outers. This means that when processing the bunch on the client, the lower subobjects are created first before their outer has been read in and created. Because the outer doesn’t exist on the client yet, the engine falls back to the default behavior of assigning the actor as the outer.
We didn’t change the behavior of ReplicateSubobjects, as certain projects/features may have been relying on subobjects being replicated in this order (the log message was also not made an error or warning because of this). Instead, the project itself would need to override ReplicateSubobjects on their actors in order to replicate higher level components/subobjects before lower ones.
That being said, there’s unfortunately no way to enforce any specific ordering when using the registered subobjects list. We do generally recommend using the registered subobjects list now, and if you’re using Iris, it is required to use this (although in Iris, subobjects should have the expected outer on the client anyway).
We do have an open task to rework the replicated subobject outer handling with the registered subobjects list, although I can’t provide any estimate as to when that may happen.
In the meanwhile, I’ve heard of projects working around the issue by having a replicated reference property on the object that points to the subobjects “true” outer. This way, you can use this property to access the “true” outer, even if the actor is the object’s outer on the client.
Thanks,
Alex