Hello,
After upgrading from UE 4.7 to UE 5.8.1, we encountered three issues with Mass Replication and a custom UMassReplicatorBase.
1. Custom replicator queries fail with the processing queue
UMassReplicationProcessor copies its entity query and then lets each replicator add requirements. The processing queue appears to identify registered queries by address, so it does not recognize the copied query.
Our workaround is:
[ConsoleVariables]
mass.UseProcessingQueue=0
This restores replication but disables the new Mass processing queue globally.
2. Destroyed replicated entities retain valid client handles
Destroying a replicated entity can trigger:
Assertion failed: !AgentData.Handle.IsValid()
This replicated agent should have been removed from this client and was not
The destruction observer marks the entity as pending destruction, but the destroyed entity is excluded from the entity collections processed by UMassReplicationProcessor. Its replicator removal callback is therefore not called, leaving a valid handle in FMassClientReplicationInfo::AgentsData.
Our workaround is a removal observer that removes both the bubble item and the cached client data:
void UReplicationAgentCleanup::ConfigureQueries(
const TSharedRef<FMassEntityManager>& EntityManager)
{
EntityQuery.AddRequirement<FMassNetworkIDFragment>(
EMassFragmentAccess::ReadOnly);
EntityQuery.AddSharedRequirement<FMassReplicationSharedFragment>(
EMassFragmentAccess::ReadOnly);
EntityQuery.AddSubsystemRequirement<UMassReplicationSubsystem>(
EMassFragmentAccess::ReadWrite);
}
EntityQuery.ForEachEntityChunk(
Context,
[](FMassExecutionContext& ChunkContext)
{
UMassReplicationSubsystem& ReplicationSubsystem =
ChunkContext.GetMutableSubsystemChecked<
UMassReplicationSubsystem>();
const TConstArrayView<FMassNetworkIDFragment> NetworkIDs =
ChunkContext.GetFragmentView<FMassNetworkIDFragment>();
for (FMassExecutionContext::FEntityIterator EntityIt =
ChunkContext.CreateEntityIterator();
EntityIt;
++EntityIt)
{
const FMassEntityHandle Entity =
ChunkContext.GetEntity(EntityIt);
Bubble.RemoveAgent(NetworkIDs[EntityIt].NetID);
for (const FMassClientHandle ClientHandle :
ReplicationSubsystem.GetClientReplicationHandles())
{
ReplicationSubsystem
.GetMutableClientReplicationInfoChecked(ClientHandle)
.AgentsData.Remove(Entity);
}
}
});
Replication cleanup should not depend on a destroyed entity still being present in a spatial entity collection.
3. Different replication parameters share the same fragment
Two archetypes using the same bubble and replicator classes, but different FMassReplicationParameters, can receive the same FMassReplicationSharedFragment.
The first-created fragment’s runtime state is reused because the original parameters are not part of the shared-fragment identity. This causes the second archetype to use settings such as the first archetype’s LOD distances.
Our workaround is a custom replication trait that uses FMassReplicationParameters as the hashing helper:
FMassReplicationSharedFragment ReplicationFragment;
ReplicationFragment.LODCalculator.Initialize(
Params.LODDistance,
Params.BufferHysteresisOnDistancePercentage / 100.0f,
Params.LODMaxCountPerViewer);
ReplicationFragment.BubbleInfoClassHandle =
ReplicationSubsystem->GetBubbleInfoClassHandle(
Params.BubbleInfoClass);
ReplicationFragment.CachedReplicator =
Params.ReplicatorClass.GetDefaultObject();
const FSharedStruct& SharedFragment =
EntityManager
.GetOrCreateSharedFragment<FMassReplicationSharedFragment>(
FConstStructView::Make(Params),
ReplicationFragment);
BuildContext.AddSharedFragment(SharedFragment);
This gives the expected behavior:
- Identical replication parameters share a fragment.
- Different replication parameters create separate fragments.
The fragment is initialized manually because the parameterized FMassReplicationSharedFragment constructor is not exported from the MassReplication module.
Are these known UE 5.8 issues, and are fixes planned for a future update?