Push Model Validation Edge Case in UNetworkPhysicsComponent

Hello! I believe I have found an unhandled edge case when using the push model replication in UNetworkPhysicsComponent that makes the validation fails.

In UNetworkPhysicsComponent::NetworkMarshaledData, when using legacy data, the following piece of code doesn’t take into account a newly emptied data history array, which then leads to an ensure being triggered in CompareParentProperties (“Push Model Property changed value, but was not marked dirty!”).

// Only replicate data to owning client if bDataAltered is true i.e. the input has been altered by the server
ReplicatedInputs.History->ResizeDataHistory(AsyncOutput->InputData->CountAlteredData(/*bIncludeUnimportant*/ true, /*bIncludeImportant*/ bEnableReliableFlow == false), EAllowShrinking::Yes);
ReplicatedInputs.History->SetRecordDataIncremental(true); // Only record data that is newer than already cached data

// Server sends inputs through property replication to owning client
if (AsyncOutput->InputData->CopyAlteredData(*ReplicatedInputs.History, /*bIncludeUnimportant*/ true, /*bIncludeImportant*/ bEnableReliableFlow == false)
{
  MARK_PROPERTY_DIRTY_FROM_NAME(UNetworkPhysicsComponent, ReplicatedInputs, this);
}

If the data history array contained any data and was then resized with an “altered data count” of 0, TNetRewindHistory::CopyAlteredData won’t copy anything and will return false by default which will fail to dirty the property and trigger the push model validation ensure.

I fixed the issue locally by making sure a newly emptied data history array is dirtied:

const int32 OldHistorySize = ReplicatedInputs.History->GetHistorySize();

// Only replicate data to owning client if bDataAltered is true i.e. the input has been altered by the server
ReplicatedInputs.History->ResizeDataHistory(AsyncOutput->InputData->CountAlteredData(/*bIncludeUnimportant*/ true, /*bIncludeImportant*/ bEnableReliableFlow == false), EAllowShrinking::Yes);
ReplicatedInputs.History->SetRecordDataIncremental(true); // Only record data that is newer than already cached data

// Server sends inputs through property replication to owning client
if (AsyncOutput->InputData->CopyAlteredData(*ReplicatedInputs.History, /*bIncludeUnimportant*/ true, /*bIncludeImportant*/ bEnableReliableFlow == false)
	|| (OldHistorySize != 0 && ReplicatedInputs.History->GetHistorySize() == 0))
{
   MARK_PROPERTY_DIRTY_FROM_NAME(UNetworkPhysicsComponent, ReplicatedInputs, this);
}

Thanks!

[Attachment Removed]

Hello Jérémie, I do not hit that push validation ensure in UE 5.8 with RepGraph or with Iris and the idea for when to call dirty is correct, we don’t need to replicate to the client when the array goes from 1 to 0 since the property is only ever used one time on receive, so it doesn’t matter if it lingers at 1 element while it’s actually 0 on the server.

Your workaround is valid to stop the ensure from happening though yes so keep it around as long as you need it.

[Attachment Removed]