FastArraySerializer - Writing unused bits of undirtied items in packets send to clients

Hello

We use MassEntity, an optimization we did for our game is to keep agents in the network bubble without removing them (and unspawning the entities). This enable us to pre-replicate every entities and send their networkID/config only once at the start, so during gameplay we never have to replicate it again (we also have entities that don’t move unless moved by something else and replicating its initial position would also improve performance).

This works, however when an entity in the fastarray is dirtied and replicated over the network, we can see a lot of these “disabled” entities (just cached in the fastarray, waiting for a PostReplicatedChange to enable itself again) writing some bits of data in the packets received by the clients.

Looks like it’s not the actual data but bits that correspond to the first property of each member of the replicated struct. We can see using UnrealInsights that it sends 3 bits/entity for a bunch a them (looks like it’s not all entities)

It our case it sends a “Agent” bit and 2 bit for “ReplicationID”, see the screenshots.

3 bits doesn’t look like a lot, but we can have 1000 items in the fastarray, so this adds up.

Are this bits sent required for the actual serialization/replication of the fastarray ? (ReplicationID is the member in FFastArraySerializerItem and is not even replicated)

If none of the item in the array gets dirtied, nothing is sent over the network and this works as expected

Note that we use Iris and the delta compression is enabled for the bubble

Thanks,

Anthony

Hi,

I don’t believe this data is required to be sent, as this seems to be a side effect of how the change mask for fast array properties is handled. From the PollAllState function for TFastArrayReplicationFragment:

// We currently use a simple modulo scheme for bits in the changemask // A single bit might represent several entries in the array which all will be considered dirty, it is up to the serializer to handle this // The first bit is used by the owning property we need to offset by one and deduct one from the usable bits FNetBitArrayView MemberChangeMask = UE::Net::Private::GetMemberChangeMask(ReplicationState->GetStateBuffer(), ReplicationStateDescriptor);The number of bits used is defined by IrisFastArrayChangeMaskBits in FIrisFastArraySerializer, which by default is set to 63. This means that for a very large array with around 650 elements, marking one item as dirty can result in around 10 elements being considered dirty by the change mask. Depending on the properties in the fast array item struct, it looks as though you can end up with a handful of bits being written for these when FStructNetSerializer::Serialize serializes the struct’s members for these elements that haven’t changed. In my own testing, increasing the number of change mask bits seemed to reduce the number of extra elements that got serialized.

I’ve opened a new issue for this, UE-268558, which should be visible in the public tracker in a day or so.

Thanks,

Alex

It makes sense now !

Thank you very much,

Anthony