UWorldPartitionStreamingPolicy::UpdateStreamingSources check fail due to size mismatch in LocalStreamingSources and CurrentState.StreamingSources

Hey,

So we have a performance test which basically does a fly-through of the world, with the client connecting to a server (development cooked builds).

On tear-down we get this crash / check fail.

On the face of it, it looks like it’s due to the hashes incorrectly matching up, so rather than replacing the existing current state, it tries to do a delta update.

After adding a bit of logging:

!!!!!! OH NO !!!!!!
LocalStreamingSources.Num() != CurrentState.StreamingSources.Num()
Hash = 0x12d6cbfe
LocalStreamingSources
-------------
.Num = 1
[0].Name = GamePlayerController_0
CurrentState.StreamingSources
-------------
.Num = 0

While this is in of itself sort of weird and probably has deeper implications the actual fast path seems to do more work?

const UWorldPartitionSubsystem* WorldPartitionSubsystem = GetWorld()->GetSubsystem<UWorldPartitionSubsystem>();
	const uint32 NewUpdateStreamingSourcesHash = WorldPartitionSubsystem->GetStreamingSourcesHash();
	if (bCanOptimizeUpdate && (UpdateStreamingSourcesHash == NewUpdateStreamingSourcesHash))
	{
		TArray<FWorldPartitionStreamingSource> LocalStreamingSources;
		WorldPartitionSubsystem->GetStreamingSources(WorldPartition, LocalStreamingSources);
		check(LocalStreamingSources.Num() == CurrentState.StreamingSources.Num());
		const FTransform WorldToLocal = WorldPartition->GetInstanceTransform().Inverse();
		for (int32 i=0; i<LocalStreamingSources.Num(); i++)
		{
			check(CurrentState.StreamingSources[i].Name == LocalStreamingSources[i].Name);
			CurrentState.StreamingSources[i].Velocity = WorldToLocal.TransformVector(LocalStreamingSources[i].Velocity);
		}
		return;
	}
 
	CurrentState.StreamingSources.Reset();
	WorldPartitionSubsystem->GetStreamingSources(WorldPartition, CurrentState.StreamingSources);
	UpdateStreamingSourcesHash = NewUpdateStreamingSourcesHash;

If the hashes match, `WorldPartitionSubsystem->GetStreamingSources` is called and the existing sources velocity is updated via a transform.

If they don’t match `WorldPartitionSubsystem->GetStreamingSources` is called, without any transform.

Is this correct? It certainly seems like a weird thing to do?

Locally I “fixed” this by changing `bCanOptimizeUpdate` to be false at the top of the function, not sure if that’s actually valid?

Many thanks,

Alister

Hi Alistair,

Are you running with wp.Runtime.UpdateStreaming.EnableAsyncUpdate activated? If so, could you reproduce the problem with the debugger attached and share the PNG of the Parallel Stack? This looks like a race condition where the StreamingSource array in the Subsystem is being modified concurrently to UWorldPartitionStreamingPolicy::UpdateStreamingSources().

Martin

Hey Martin,

`wp.Runtime.UpdateStreaming.EnableAsyncUpdate` is not enabled.

But in an annoying turn of events, when I now remove my fix, it doesn’t seem to crash anymore (use to be a 10/10).

We think we have found the source of the problem but haven’t confirmed it yet. You can keep on using the workaround until we have a firm fix.

Hi Alister,

A fix was submitted in our main branch (CL 46949279).

Richard