FYI - about upgrades to 5.8 - there’s a few issues with replication. I didn’t see a lot of notes regarding changes, but diving in! (Invalid handles, queries registration, templates not found) etc
#1 - First up - probably not the correct fix…
FYI - about upgrades to 5.8 - there’s a few issues with replication. I didn’t see a lot of notes regarding changes, but diving in! (Invalid handles, queries registration, templates not found) etc
#1 - First up - probably not the correct fix…
What i’m noticing is im spawning two items dynamically, the second one is always corrupted. (I’ve tried different objects). Claude is blaming Epic – im not yet, but just noting what it said :P.
After upgrading from UE 5.7.1 to 5.8 (source build), client-side Mass Entity replication receives corrupted FMassEntityTemplateID data via FastArrayDeltaSerialize. The server writes correct data into the FastArray item, but the client deserializes a completely different ConfigGuid and TotalHash, causing SpawnEntities to fail because the template is not registered.
This is reproducible with any Mass replication bubble type (tested with both ProjectileBallistic and CoreCombatant serializers). The issue does not occur on the first replicated item in a given FastArray — it manifests when a second (or subsequent) item is added to the same FastArray while the first item still exists.
TClientBubbleHandlerBase / FMassClientBubbleSerializerBase / AMassClientBubbleInfoBase (same pattern as Epic’s MassCrowd plugin — MassCrowdBubble.h)PostReplicatedAdd → SpawnEntities(TemplateID) — succeedsUMassEntityConfigAssetPostReplicatedAdd with corrupted FMassEntityTemplateID data — crashes at checkf(EntityTemplate, TEXT("SpawnEntities: TemplateID must have been registered!"))Both items are added to the FastArray with identical, correct data:
AddAgent SERVER: ArrayIdx=0 TemplateHash=0x84CD22C3E91187A9 GUID=[57e4511444ec3cba4b63bdadd1eba884:0] ReplicationID=1 ArraySize=1
AddAgent SERVER: ArrayIdx=1 TemplateHash=0x84CD22C3E91187A9 GUID=[57e4511444ec3cba4b63bdadd1eba884:0] ReplicationID=2 ArraySize=2
PostReplicatedAddEntities CLIENT: Idx=0 TemplateHash=0x84CD22C3E91187A9 GUID=[57e4511444ec3cba4b63bdadd1eba884:0] ← CORRECT
PostReplicatedAddEntities CLIENT: Idx=1 TemplateHash=0xC0577DB9DD9FC505 GUID=[62c6a591c045ec970bb8d7ac40760b2b:0] ← CORRUPTED
ConfigGuid (an FGuid, 16 bytes) is completely different on the client — not a bit flip, not an endianness issue, entirely different bytesTotalHash is correctly derived from the corrupted ConfigGuid (i.e., TotalHash was recomputed from the wrong GUID, not independently corrupted)ConfigGuid, FlavorHash, TotalHash) are UPROPERTY() members of FMassEntityTemplateID and should be fully replicatedRemoveAtSwap vs RemoveAt in RemoveAgentImpl makes no difference (tested both)DestroyTemplate is never called (breakpoint verified)FProjectileBallistic_FastArrayItem : FMassFastArrayItemBase : FFastArraySerializerItem
├── UPROPERTY(NotReplicated) FMassReplicatedAgentHandle Handle
└── UPROPERTY() FReplicated_ProjectileBallistic_AgentData Agent : FReplicatedAgentBase
├── UPROPERTY() FMassNetworkID NetID
├── UPROPERTY() FMassEntityTemplateID TemplateID ← corrupted on client
│ ├── UPROPERTY() FGuid ConfigGuid ← wrong bytes
│ ├── UPROPERTY() uint32 FlavorHash
│ └── UPROPERTY() uint64 TotalHash ← recomputed from wrong ConfigGuid
├── UPROPERTY() FullTransformData
├── UPROPERTY() BallisticData
├── UPROPERTY() IdentityData
└── UPROPERTY() DeadReckoningData
USTRUCT()
struct FProjectileBallistic_ClientBubbleSerializer : public FMassClientBubbleSerializerBase
{
GENERATED_BODY()
FProjectileBallistic_ClientBubbleSerializer()
{
m_oBubble.Initialize(m_aProjectiles, *this);
}
bool NetDeltaSerialize(FNetDeltaSerializeInfo& oDeltaParams)
{
return FFastArraySerializer::FastArrayDeltaSerialize<FProjectileBallistic_FastArrayItem,
FProjectileBallistic_ClientBubbleSerializer>(m_aProjectiles, oDeltaParams, *this);
}
// ...
UPROPERTY(Transient)
TArray<FProjectileBallistic_FastArrayItem> m_aProjectiles;
};
template<>
struct TStructOpsTypeTraits<FProjectileBallistic_ClientBubbleSerializer>
: public TStructOpsTypeTraitsBase2<FProjectileBallistic_ClientBubbleSerializer>
{
enum { WithNetDeltaSerializer = true, WithCopy = false };
};
This is structurally identical to FMassCrowdClientBubbleSerializer in Engine/Plugins/AI/MassCrowd/Source/MassCrowd/Public/MassCrowdBubble.h.
| Hypothesis | Ruled out by |
|---|---|
| Template destroyed between spawns | Breakpoint on FMassEntityTemplateRegistry::DestroyTemplate — never hit |
| Wrong EntityConfig asset | Server log shows same asset, same GUID, same hash for both spawns |
| TotalHash not a UPROPERTY (not serialized) | Confirmed UPROPERTY() at MassEntityTemplate.h:94 |
| RemoveAtSwap corrupting array slots | Changed to RemoveAt — same result |
| Cross-replicator handle confusion | Fixed separately (bool-returning RemoveEntity callback) — unrelated |
| Client registry missing the template | Template is registered (first spawn succeeds with identical hash) |
| Unstable ConfigGuid on asset | Server logs show stable GUID 57E45114... across all spawns within a session |
Downgraded the checkf in UMassSpawnerSubsystem::SpawnEntities(FMassEntityTemplateID, ...) to skip and log a warning when the template is not found. The entity doesn’t spawn on the client that frame, but the server remains authoritative so gameplay is unaffected.
The client should receive identical FMassEntityTemplateID data to what the server wrote into the FastArray item. All UPROPERTY fields should be correctly serialized and deserialized by FastArrayDeltaSerialize regardless of how many items are in the array.