Iris: Initial SubObject Replication Ordering Issue

Iris is unable to replicate a UObject subobject this is not outered directly to the RootObject when the RootObject is dynamic and the UObject is static.

Here are the relevant logs from the object failing to instantiate on the client side:

Error: BeginInstantiateFromRemote Failed to find Outer [NetRefHandle (Id=...):(RepSystemId=?)](NOT_IN_CACHE) for dynamic subobject NetRefHandle (Id=...):(RepSystemId=?)

UNetSubObjectFactory::InstantiateNetObjectFromHeader NetRefHandle (Id=...):(RepSystemId=?): Failed to find static or stable name object referenced by SubObject: [NetRefHandle (Id=...):(RepSystemId=?)](EMPTY).[NetRefHandle (Id=...):(RepSystemId=?)](...), Owner: RootObject ... (InternalIndex: ...) (NetRefHandle (Id=...):(RepSystemId=1)), RootObject: /...

LogIris: Error: FReplicationReader::ReadObject Failed to read object batch handle: NetRefHandle (Id=...):(RepSystemId=?) skipping batch data

LogIris: Error: ReplicationBridge(0)::OnErrorWithNetRefHandleReported: ReplicationDisabled from client ConnectionId:1 ViewTarget: ... Named: [UNetConnection] RemoteAddr: ..., Name: RGINetConnection_14, Driver: Name:GameNetDriver Def:GameNetDriver ..., IsServer: YES, PC: ..., Owner: ..., UniqueId: .... Problematic object was RootObject ...(InternalIndex: ...) (NetRefHandle (Id=...):(RepSystemId=0))

Iris’ FReplicationWriter::WriteObjectAndSubObjects calls FReplicationConditionals::GetSubObjectsToReplicate which has a comment about how it tries to mimic the legacy replication by inserting SubObject before their parent, however, unlike legacy replication, the client will not deserialize the outer before its inner objects. This leads to the errors above where an object will fail to instantiate because the outer object is replicated after its inner object from the order given by GetSubObjectsToReplicate. Using Kanh’s Topological sorting algorithm to ensure outer are replicated prior to their inner objects fixes the issue for our project.

My questions are:

  • Is this a known issue/limitation?
  • Does the solution sound reasonable?
  • Are we doing something wrong here?
    • Several of our object types are using their Outer to determine a hierarchy without having to define a member property, is this a pattern we can keep using?
      [Attachment Removed]

Steps to Reproduce
Have Iris enabled for the project.

Create a CDO with the following hierarchy:

ParentComp (UActorComponent)

ChildObject (UObject derived, instanced, Outer: ParentComp)

ParentComp should register ChildObject to the replication list from its own UActorComponent::RegisterReplicationFragments

Have ParentComp injected through UGameFeatureAction::AddComponents to a replicated object (e.g. PlayerPawn).

Notice the errors given on intial replication and ChildObject is not instantiated. This also leads to the disabling of replication for the owning actor

[Attachment Removed]

Hi,

I don’t believe your project is doing anything wrong. This is a known issue with Iris (see NetTestStableSubobjects.cpp in EngineTest, specifically the comments in UNetTestDynamicActorComponent::BeginPlay), and we have an open internal task to look into it further.

Your solution does seem reasonable, and there was a recent change that added an optional parameter to control whether subobjects replicate before or after their parent, with the default still being to replicate a component’s subobjects before the component itself (CL 50592689 in UE5/Main).

Thanks,

Alex

[Attachment Removed]

Thank you, glad to know this was already on the radar and that something is coming.

[Attachment Removed]