REPRO STEPS
Run the repro in Play in Editor with a client server setup.
Have a replicated actor with a replicated static mesh component.
Give it a staticmesh.
Give the actor another replicated variable with an OnRep.
In the OnRep for that other variable, on the client, call SetMaterial on the static mesh component
On the server, on the same frame, change the mesh with SetStaticMesh, and also change the other replicated variable.
Observe that the ensure in OutdatedKnownStaticMeshDetected gets triggered on the Client.
COMMENTARY
We ran in to this issue in 5.4. Our use case was very much like what was described in the repro. A developer in a blueprint wanted to change the mesh and the material at the same time on a replicated actor. The UStaticMeshComponent handles the StaticMesh pointer but Material, being non-replicated, needs to be driven through another replicated actor variable.
Im hoping for an easy way to make this non-fragile for other developers.
Hopefully these details help you reconstruct the repro if it isnt as simple with the steps I provided.
Consider how UStaticMeshComponent works.
If StaticMesh is changed, it is in a problematic state until NotifyIfStaticMeshChanged() is called, and will do OutdatedKnownStaticMeshDetected() if you call GetStaticMesh().
OnRep_StaticMesh will call SetStaticMesh(NewStaticMesh) which will result in the UStaticMeshComponent::GetStaticMesh being ok to call again.
Now consider how replication for an actor works, roughly:
- Get Data from server about actor (UActorChannel::ProcessBunch)
- Sets all the variables in the actor and its components (in UActorChannel::ProcessBunch calling Replicator->ReceivedBunch)
- Calls all the rep-notifies, starting with the actor followed by the components. (In UActorChannel::ProcessBunch iterates ReplicationMap calling PostReceivedBunch)
When we comine all this, we see that step 2 will modify UStaticMeshComponent::StaticMesh, but not call OnRep_StaticMesh until step 3. All the other onrep code for the Actor and potentially other components will run before OnRep_StaticMesh has fixed up UStaticMeshComponent and so doing things such as SetMaterial will call GetStaticMesh and lead to OutdatedKnownStaticMeshDetected() even through replication is about to call OnRep_StaticMesh and fix it.