Server Streaming breaks Mass Replication / LoD

We tracked the issue to UMassLODSubsystem::SynchronizeViewers(). The issue seems to be that with ServerStreaming every PlayerController is also a StreamingSource. If the very first call to AddPlayerViewer(*PlayerController) early outs, that same PlayerController will be added as a StreamingSourceViewer, “poisoning” the LocalViewerMap logic and preventing that viewer from being “upgraded” to a PlayerControllerViewer (setting ViewerInfo.ActorViewer = PlayerController) on subsequent calls to SynchronizeViewers(). With that field unset we’ll not call UMassReplicationSubsystem::AddClient() later, and not replicate low-fidelity entities.

The following logic avoid this, but will try to upgrade “ignored players” every call.

`if (bGatherPlayerControllers)
{
// Now go through all current player controllers and add if they do not exist
for (FConstPlayerControllerIterator PlayerIterator = World->GetPlayerControllerIterator(); PlayerIterator; ++PlayerIterator)
{
APlayerController* PlayerController = (*PlayerIterator).Get();
check(PlayerController);

// Check if the controller already exists by trying to remove it from the map which was filled up with controllers we were tracking
if (LocalViewerMap.Remove(GetTypeHash(PlayerController->GetFName())) == 0)
{
// If not add it to the list
AddPlayerViewer(*PlayerController);
}
// If ServerStreaming is enabled, every PlayerController is also a StreamingSource. If the very first
// AddPlayerViewer() no-ops due to the early out that “ignores players that don’t have a pawn nor a camera”,
// then we still add that PlayerController as a StreamingSource viewer below.
// Subsequent calls to UMassLODSubsystem::SynchronizeViewers() will add an entry to LocalViewerMap for that
// StreamingSource viewer, preventing the call to AddPlayerViewer, which would “upgrade” the viewer to a
// PlayerController viewer by setting ViewerInfo.ActorViewer.
// Without that upgrade we won’t replicate the MassBubble to the client, and Mass LOD will not work: Agents
// don’t show on the client as low LOD until they are rehydrated as High-LOD and pop in as replicated actors.
// This change attempts to upgrade every PlayerController every time, which isn’t great but avoids the issue.
else if (WorldPartition->IsServerStreamingEnabled())
{
const int32 HashValue = GetTypeHash(PlayerController->GetFName());
FMassViewerHandle& ViewerHandle = ViewerMap.FindOrAdd(HashValue, FMassViewerHandle());
if (ViewerHandle.IsValid())
{
// We are only interested to set the player controller if it was not already set.
const int32 ViewerHandleIdx = GetValidViewerIdx(ViewerHandle);
check(ViewerHandleIdx != INDEX_NONE);

FViewerInfo& ViewerInfo = Viewers[ViewerHandleIdx];
if(ViewerInfo.ActorViewer == nullptr)
{
AddPlayerViewer(*PlayerController); // We call AddPlayerViewer() to handle all the early out checks.
}
}
}
//
}
}`

Steps to Reproduce

  • Setup a WP level with Mass, configured to show low-fidelity static meshes at a distance and real actors nearby.
  • Use very different static meshes so the transition stands out.
  • Confirm that the entities get promoted to actors and demotes as you move around.
  • Once you turn on ServerStreaming the low-fidelity representation disappears

Hi Christian,

Apologies this has bounced around a bit. I think this could be one for the mass team as I can’t see a simulation relevant context here. I’ll check into and find an owner for this.

Best

Geoff Stacey

EPIC Games

Hi Christian,

I’ve triaged this to the AI queue (as the team which primarily develops/owns mass) - I’ll email my colleague to give him a heads up as well.

Best

Geoff

Hello!

We had run into this previously for Lego FN. We introduced a CVar for MassLODSubsystem to include all player controllers regardless of current camera/pawn. The CL# is 29665207 in UE5 Main, but I believe it should be present in the 5.4 stream as well at CL 30834909. The CVar name is bLODSubsystemIncludeAllPlayerControllers.

Does enabling that CVar address the issue you are having? It is always possible that we did not account for an edge case that you are encountering.

-James

Thank you!