Level Streaming Bug

Hi there - our team would like to raise what we believe is a bug in current UE5-Main, as well as two related points of feedback. I’ve tried to include as much useful context, but their to-the-point-of-the-matter is formatted underlined.

Earlier this week we were hitting a bug where client machines with splitscreen players were failing to load into a certain level. Upon further review of the logs, we say it was due to

UNetDriver::ProcessRemoteFunctionForChannelPrivate triggering a ClientReliableBufferOverflow error. This is due to how many calls to UWorld::AddToWorld were taking place which were leading to ServerUpdateLevelVisibility calls for each local PlayerController. To illustrate, the this is the rough callstack:

APlayerController::ServerUpdateLevelVisibility

UWorld::AddToWorld

UWorld::UpdateLevelStreaming

UWorld::BlockTillLevelStreamingCompleted

AWorldSettings::NotifyBeginPlay

AGameStateBase::OnRep_ReplicatedHasBegunPlay

As a reminder, our project is on a fork of UE 5.5.4. This specific level had over 900 ULevels changing visibility around BeginPlay. When a single player was on a network machine, this wasn’t a major issue. However, once more than one player was present via splitscreen, this caused redundant calls to ServerUpdateLevelVisibility. As this is a Reliable RPC, this was leading to quickly hitting the 511 limit for out/unacknowledged bunches.

When looking at our mirror of UE5-Main, we noticed the a commit from Dec 18th 2025: CL 49408961 from Richard Malo.

There was a modification to ULevelStreaming::ServerUpdateLevelVisibility to stop after the first PlayerController. Note that a further change was made for UE-363105 that skips the APlayerController if its NetConnection is a UChildConnection (ie, non-primary player PlayerController).

To mitigate our networking splitscreen bug, we applied the same principle to the ServerUpdateLevelVisibility calls inside UWorld::AddToWorld and RemoveFromWorld: stop after the first PlayerController. This seems like what mainline UE5 would also want to do as well.

[Attachment Removed]

Steps to Reproduce
See details below

[Attachment Removed]

Additional feedback:

  • For our project, we are not using UE to replicate gameplay Actors. Rather, the Halo engine drives the gameplay simulation and entity replication.

    • This means we are not actually dependent on the ‘server’ and clients having acknowledgement/agreement on what ULevels are streamed in.
    • Another engineer made Engine modifications to WorldPartition to cause the ListenServer and Clients to behave as if they’re Standalone.
  • E.g.

  • AWorldDataLayers::CanChangeDataLayerRuntimeState

  • and

  • SetDataLayerRuntimeState

      - .+ Since we support peer\-to\-peer, the ListenServer has aspects which need to behave as a Client still.
      - I tried forcing bClientOnlyVisible behavior in code, but ran into issues with ULevels still getting removed on the Client when the player on the ListenServer walked far enough away.
      - I have not confirmed this isn't due to other changes/configs we have made for the project. Admittedly, I had never looked at or touched this area of UE until this week.
      - However, it seems like instead of bClientOnlyVisible, there should instead be a bLocalOnlyVisible or something else to signify it is relative to the local machine/state. So that everyone, server and client, behaves independently but consistently.
    

[Attachment Removed]

Additional feedback (2/2):

  • It would be great if UE had more formal delineation/representation of network machines besides piggybacking off PlayerControllers.
    • We currently need to use PlayerState / PlayerStateComponents to replicate certain information that is really just general to the remote network machine
      • E.g., how far along a machine is loading the level and before their “Experience” is ready (we have a similar concept inspired from Lyra’s Experience).
      • With splitscreen players, this matter is moot as we could just operate on the primary player, but for simplicity we operate on all PlayerStates and end up setting the state on all local players for a given machine.
      • This is useful for other clients/observers of the game to know (e.g., scoreboard/network status), but of course their underlying UNetConnection is not.
    • This same pattern is of course observed with level streaming and needing to set UpdateLevelVisiblity. You only need to perform the action on the machine itself, but not per-player.
      • So, it seems like this would benefit UE developers in general and not just stitched-engine models like in our project.

[Attachment Removed]

Hi,

I’m currently looking into your bug report and feedback, but in the meanwhile, it looks like another thread was opened on this same topic here: [Content removed]

Unless you’d prefer otherwise, I’ll close this question and continue discussion in that other thread.

Thanks,

Alex

[Attachment Removed]