Bug in UReplicationGraphNode_DynamicSpatialFrequency: Actor WorldLocation not updated, causing relevance and NetChannel flapping

Summary:

UReplicationGraphNode_DynamicSpatialFrequency does not update the actor’s WorldLocation in the GlobalActorReplicationInfoMap, resulting in all distance-based relevance and update frequency calculations using an incorrect default location (typically (0,0,0)). This leads to replicated actors being incorrectly treated as irrelevant or distant, causing repeated client-side destruction and respawning. The symptoms include PostNetInit() being called every frame on affected actors, and inconsistent calls to EndPlay().

Observed Behavior:

  • GlobalActorReplicationInfo.WorldLocation is never updated by UReplicationGraphNode_DynamicSpatialFrequency.
  • All actors are treated as if located at (0,0,0) for spatial distance checks.
  • Actors constantly become “distant” and are removed from relevance, only to be re-added next frame.

Expected Behavior:

  • The actor’s actual world location should be updated every frame (or before replication gather).
  • Distance and frequency logic should behave correctly, resulting in stable actor relevance.
  • NetChannel should persist as long as the actor is actually relevant to the client.

Proposed Fix:

Update the constructor and override PrepareForReplication() on UReplicationGraphNode_DynamicSpatialFrequency to ensure actor locations are correctly updated:

`UReplicationGraphNode_DynamicSpatialFrequency::UReplicationGraphNode_DynamicSpatialFrequency()
{
bRequiresPrepareForReplicationCall = true;
}

void UReplicationGraphNode_DynamicSpatialFrequency::PrepareForReplication()
{
FGlobalActorReplicationInfoMap* GlobalRepMap = GraphGlobals->GlobalActorReplicationInfoMap;
repCheck(GlobalRepMap);

for (FActorRepListType& Actor : ReplicationActorList)
{
FGlobalActorReplicationInfo& GlobalInfo = GlobalRepMap->Get(Actor);
if (IsValid(Actor))
{
FGlobalActorReplicationInfo& ActorRepInfo = GlobalRepMap->Get(Actor);
ActorRepInfo.WorldLocation = Actor->GetActorLocation();
}
}
}`This aligns with the behavior of other spatial nodes in the replication graph (e.g., UReplicationGraphNode_GridSpatialization2D) and ensures relevance calculations are based on correct actor positions.

Best regards,

Peter Freese

Steps to Reproduce

  1. In a project using the Replication Graph, add a UReplicationGraphNode_DynamicSpatialFrequency node to the graph, and add an actor to the UReplicationGraphNode_DynamicSpatialFrequency node.
  2. Place the actor in the world far from the origin (e.g., at (10000, 0, 0)).
  3. Run the game with a connected client.
  4. Observe the behavior on the client:
    1. The actor repeatedly disappears and reappears.
    2. PostNetInit() is called every frame.
    3. EndPlay() is not called reliably.
    4. The actor’s NetChannel is constantly being torn down and rebuilt.

Hi,

Thank you for the report, and apologies for the delay in getting back to you.

While this behavior may be unexpected, I believe it is by design. The dynamic spatial frequency node can be used as the “DynamicNode” of grid cells within the GridSpatialization2D node. This can be set up by setting CreateDynamicNodeOverride on the UReplicationGraphNode_GridCell to a lambda that creates a DSF node as a child node of the grid cell. This is how Fortnite’s replication graph handles its DSF nodes, as in this case, the GridSpatialization2D node will handle updating the WorldLocation of actors in the grid without the DSF node needing to to do.

That said, I do agree that for a DSF node being used as a global node on the graph, it is unexpected that all the actors routed here would be treated as being located at the origin. I’ve opened a new internal task to look more into better supporting this use case in the base UReplicationGraphNode_DynamicSpatialFrequency class, so this can be done without needing to create a derived class that implements custom handling to update the WorldLocation.

In the meanwhile, your change here definitely seems reasonable. If you run into any other problems though, please don’t hesitate to reach out.

Thanks,

Alex