When bSyncInputsForSimProxy is enabled on UMoverComponent, calling UPoseSearchTrajectoryLibrary::PoseSearchGenerateTransformTrajectoryWithPredictor on a Simulated Proxy client causes a crash in Chaos physics (PBDRigidsSolver::PushPhysicsState).
The root cause is that UMoverComponent::GetPredictedTrajectory internally calls SetGravityOverride() to temporarily modify and then restore the MoverComponent’s gravity state. Since PoseSearchGenerateTransformTrajectoryWithPredictor is marked BlueprintThreadSafe and is called from the Animation Worker Thread, this write to MoverComponent members creates a race condition with the Game Thread’s physics update.
When bSyncInputsForSimProxy is disabled, GetLastInputCmd() returns empty/default input on the Simulated Proxy, so GenerateMove produces near-zero movement and the prediction loop completes almost instantly — the race window is negligible. When enabled, GetLastInputCmd() returns real synced input, GenerateMove produces meaningful movement across ~20-30 iterations, significantly widening the race window and making the crash reproducible.
The call chain on the Simulated Proxy is:
[Animation Worker Thread]
PoseSearchGenerateTransformTrajectoryWithPredictor() // marked BlueprintThreadSafe
→ UMoverTrajectoryPredictor::Predict()
→ UMoverComponent::GetPredictedTrajectory()
→ SetGravityOverride(true, FVector::ZeroVector) //
non-thread-safe WRITE
→ GenerateMove() × N iterations // reads modified state
→ SetGravityOverride(origValue, origAccel) //
non-thread-safe WRITE (restore)
SetGravityOverride modifies 4 member variables on UMoverComponent (bHasGravityOverride, GravityAccelOverride, WorldToGravityTransform, GravityToWorldTransform) without any synchronization, while the Game Thread is concurrently running physics updates.
Additionally, the IPoseSearchTrajectoryPredictorInterface::Predict virtual function is not declared const, which appears to be a consequence of this implementation pattern — the interface’s const-correctness was sacrificed to accommodate the temporary state mutation inside GetPredictedTrajectory.
[Attachment Removed]