[Iris] Multiple Actors Having a Shared Sub-Object Dependency

A little background on how we got here I think is required,

We’ve got a large shared inventory for the players. Each item is a unique UObject instance because it’s a lot easier to track state changes to a given object this way. Originally we were using a FastArrayReplication before moving to Iris - but we moved away from that approach because when a new client would come along, they’d suddenly get the full array dump and it would overload the channel size for a single update. So - we created wrapper actors instead, one actor per item AItemInstanceWrapper, and an item can represent N number in a stack - but due to not wanting to refactor everything the actors were just ignored. They were (before iris) simply always replicated by the replication graph to all users.

The items, themselves are always moving around, they are in different forms, sometimes a player is holding it, sometimes they throw it, sometimes it’s on a shelf. No matter what state it’s in, the Actor and the subobject itemInstance do not worry about that state - for the most part.

Instead - what happens is that the Item instance is told about some other temporary actor, e.g. maybe it’s temporarily owned by an another actor the player is holding. in this situation the ItemInstance is NOT a subobject of the HoldActor, it is merely referenced by it. Similarly when it’s thrown, one item from the ItemInstance stack may be split of, shoved into a new ItemInstance, given a new AItemInstanceWrapper, and then a new AThrownItem gets created and is given the ItemInstance as a reference and thrown into the world.

This brings us to the problem - If this problem occurred before in the legacy system, we were blind to it, but,

We throw an Item, splitting it from the stack. This does what i mentioned above. But - AThrownActor, referencing the ItemInstance (but isn’t the subobject owner), gets the OnRep event for the ItemInstance before any of the properties set replicated for it. Then some time later, the AItemInstanceWrapper (the proper subobject owner of ItemInstance) gets its OnRep for the ItemInstance, and at that point the ItemInstance is wholly replicated.

I thought that I could simply add ItemInstance to both actors ReplicatedSubObject list, but got the error about it not owning it - so that was a bust.

Any solutions? here’s what I’m hoping there are solutions for, and I hope to uncover unknown features of Iris.

Iris seems to internally handle dependencies for ordering updates - can I somehow tell Iris, that I need ItemInstance to be depended on in AThrownActor the same as it is for AItemInstanceWrapper, because I don’t want to get the OnRep before the thing has actually been repped and setup.

Can non-actors be directly replicated yet? Or would ItemInstance need to become an Actor directly? I feel like this would solve it, but is an annoying refactor.

Umm - Open to other ideas?

Hi,

Apologies for the delay in getting back to you. Iris does not change any of the guarantees made around the order in which actors are sent/received and when OnReps are called, so I don’t believe there’s any way to ensure the ItemInstance is received and setup before the OnRep on AThrownActor is called.

There have been some changes made recently to better support replicating UObjects as their own root object. I’m currently asking around to gather some more information on those changes.

Thanks,

Alex

Thanks Alex - yeah any info you have on making objects other than Actors root level objects would solve a great many issues that currently overly require everything be an actor.

Hi,

So for replicating a UObject as its own root object, you should be able to create your own NetObjectFactory and registering it to the replication bridge to handle this (you can see the current factory implementations at UNetActorFactory, UNetSubObjectFactory, and UReplicatedTestObjectFactory). Something that’s been discussed is having a built-in factory for handling this, but I couldn’t say when or if that would be available.

Also, just to clarify, could you provide some more information on the problem you’re seeing? When you say that you’re seeing the “OnRep event for the ItemInstance before any of the properties set replicated for it,” is the issue that the OnRep on the AItemInstanceWrapper needs to perform some handling before the OnRep on the AThrownActor? Or are you seeing the AThrownActor OnRep called with the ItemInstance before the ItemInstance has received and applied any of its initially replicated property values?

Thanks,

Alex

Thanks, ill try that out.

Server:

So AThrownActor has a property pointing at UItemInstance. UItemInstance is a subobject of AItemInstanceWrapper. Both AThrownActor and AItemInstanceWrapper in this senario are created on the server…Im pretty sure AThrownActor in this senario is created first, but im not sure. But AThrownActor is created, UItemInstace is created, Along with AItemInstanceWrapper, UItemInstance is assigned to AItemInstanceWrapper and also to AThrownActor, and now we wait for the client to get them.

Client:

AThrownActor_MyItem_OnRep() is called first, It now has a *valid* ptr to UItemInstance, however if you examine any of the properties of UItemInstance they’re all the default values.

AItemInstanceWrapper_BeginPlay() is called

AItemInstanceWrapper_MyItem_OnRep() is called, looking at its UItemInstance, it’s the *same* ptr, but now it’s filled in with the actual data it needs to have.

FYI - we always run with, because we don’t want new replicated class references to hitch the GT. In case that is possibly contributing factor.

net.AllowAsyncLoading=1

Hi,

Thank you for the additional information, I just wanted to make sure we had a good understanding of the problem.

If you have any more questions or run into any problems with the net object factory, please don’t hesitate to reach out.

Thanks,

Alex