188 if (
const UWorld* World = GetOwningWorld())
190 if (World->GetNetMode() == ENetMode::NM_Client)
192 return FPhysicsReplication::ApplyRigidBodyState(DeltaSeconds, BI, PhysicsTarget, ErrorCorrection, PingSecondsOneWay);
196 static const auto CVarSkipPhysicsReplication = IConsoleManager::Get().FindConsoleVariable(TEXT(
"p.SkipPhysicsReplication"));
197 if (CVarSkipPhysicsReplication->GetInt())
202 if (!BI->IsInstanceSimulatingPhysics())
237 bool bRestoredState =
true;
238 const FRigidBodyState NewState = PhysicsTarget.TargetState;
239 const float NewQuatSizeSqr = NewState.Quaternion.SizeSquared();
242 if (!BI->IsInstanceSimulatingPhysics())
244 UE_LOG(LogPhysics,
Warning, TEXT(
"Physics replicating on non-simulated body. (%s)"), *BI->GetBodyDebugName());
245 return bRestoredState;
247 else if (NewQuatSizeSqr < KINDA_SMALL_NUMBER)
249 UE_LOG(LogPhysics,
Warning, TEXT(
"Invalid zero quaternion set for body. (%s)"), *BI->GetBodyDebugName());
250 return bRestoredState;
252 else if (FMath::Abs(NewQuatSizeSqr - 1.f) > KINDA_SMALL_NUMBER)
254 UE_LOG(LogPhysics,
Warning, TEXT(
"Quaternion (%f %f %f %f) with non-unit magnitude detected. (%s)"),
255 NewState.Quaternion.X, NewState.Quaternion.Y, NewState.Quaternion.Z, NewState.Quaternion.W, *BI->GetBodyDebugName());
256 return bRestoredState;
260 static const auto CVarNetPingExtrapolation = IConsoleManager::Get().FindConsoleVariable(TEXT(
"p.NetPingExtrapolation"));
261 const float NetPingExtrapolation = CVarNetPingExtrapolation->GetFloat() >= 0.0f ? CVarNetPingExtrapolation->GetFloat() : ErrorCorrection.PingExtrapolation;
263 static const auto CVarNetPingLimit = IConsoleManager::Get().FindConsoleVariable(TEXT(
"p.NetPingLimit"));
264 const float NetPingLimit = CVarNetPingLimit->GetFloat() > 0.0f ? CVarNetPingLimit->GetFloat() : ErrorCorrection.PingLimit;
266 static const auto CVarErrorPerLinearDifference = IConsoleManager::Get().FindConsoleVariable(TEXT(
"p.ErrorPerLinearDifference"));
267 const float ErrorPerLinearDiff = CVarErrorPerLinearDifference->GetFloat() >= 0.0f ? CVarErrorPerLinearDifference->GetFloat() : ErrorCorrection.ErrorPerLinearDifference;
269 static const auto CVarErrorPerAngularDifference = IConsoleManager::Get().FindConsoleVariable(TEXT(
"p.ErrorPerAngularDifference"));
270 const float ErrorPerAngularDiff = CVarErrorPerAngularDifference->GetFloat() >= 0.0f ? CVarErrorPerAngularDifference->GetFloat() : ErrorCorrection.ErrorPerAngularDifference;
272 static const auto CVarMaxRestoredStateError = IConsoleManager::Get().FindConsoleVariable(TEXT(
"p.MaxRestoredStateError"));
273 const float MaxRestoredStateError = CVarMaxRestoredStateError->GetFloat() >= 0.0f ? CVarMaxRestoredStateError->GetFloat() : ErrorCorrection.MaxRestoredStateError;
275 static const auto CVarErrorAccumulation = IConsoleManager::Get().FindConsoleVariable(TEXT(
"p.ErrorAccumulationSeconds"));
276 const float ErrorAccumulationSeconds = CVarErrorAccumulation->GetFloat() >= 0.0f ? CVarErrorAccumulation->GetFloat() : ErrorCorrection.ErrorAccumulationSeconds;
278 static const auto CVarErrorAccumulationDistanceSq = IConsoleManager::Get().FindConsoleVariable(TEXT(
"p.ErrorAccumulationDistanceSq"));
279 const float ErrorAccumulationDistanceSq = CVarErrorAccumulationDistanceSq->GetFloat() >= 0.0f ? CVarErrorAccumulationDistanceSq->GetFloat() : ErrorCorrection.ErrorAccumulationDistanceSq;
281 static const auto CVarErrorAccumulationSimilarity = IConsoleManager::Get().FindConsoleVariable(TEXT(
"p.ErrorAccumulationSimilarity"));
282 const float ErrorAccumulationSimilarity = CVarErrorAccumulationSimilarity->GetFloat() >= 0.0f ? CVarErrorAccumulationSimilarity->GetFloat() : ErrorCorrection.ErrorAccumulationSimilarity;
284 static const auto CVarLinSet = IConsoleManager::Get().FindConsoleVariable(TEXT(
"p.PositionLerp"));
285 const float PositionLerp = CVarLinSet->GetFloat() >= 0.0f ? CVarLinSet->GetFloat() : ErrorCorrection.PositionLerp;
287 static const auto CVarLinLerp = IConsoleManager::Get().FindConsoleVariable(TEXT(
"p.LinearVelocityCoefficient"));
288 const float LinearVelocityCoefficient = CVarLinLerp->GetFloat() >= 0.0f ? CVarLinLerp->GetFloat() : ErrorCorrection.LinearVelocityCoefficient;
290 static const auto CVarAngSet = IConsoleManager::Get().FindConsoleVariable(TEXT(
"p.AngleLerp"));
291 const float AngleLerp = CVarAngSet->GetFloat() >= 0.0f ? CVarAngSet->GetFloat() : ErrorCorrection.AngleLerp;
293 static const auto CVarAngLerp = IConsoleManager::Get().FindConsoleVariable(TEXT(
"p.AngularVelocityCoefficient"));
294 const float AngularVelocityCoefficient = CVarAngLerp->GetFloat() >= 0.0f ? CVarAngLerp->GetFloat() : ErrorCorrection.AngularVelocityCoefficient;
296 static const auto CVarMaxLinearHardSnapDistance = IConsoleManager::Get().FindConsoleVariable(TEXT(
"p.MaxLinearHardSnapDistance"));
297 const float MaxLinearHardSnapDistance = CVarMaxLinearHardSnapDistance->GetFloat() >= 0.f ? CVarMaxLinearHardSnapDistance->GetFloat() : ErrorCorrection.MaxLinearHardSnapDistance;
300 FRigidBodyState CurrentState;
301 BI->GetRigidBodyState(CurrentState);
308 const float PingSeconds = FMath::Clamp(PingSecondsOneWay, 0.f, NetPingLimit);
309 const float ExtrapolationDeltaSeconds = PingSeconds * NetPingExtrapolation;
310 const FVector ExtrapolationDeltaPos = NewState.LinVel * ExtrapolationDeltaSeconds;
311 const FVector_NetQuantize100 TargetPos = NewState.Position + ExtrapolationDeltaPos;
312 float NewStateAngVel;
313 FVector NewStateAngVelAxis;
314 NewState.AngVel.FVector::ToDirectionAndLength(NewStateAngVelAxis, NewStateAngVel);
315 NewStateAngVel = FMath::DegreesToRadians(NewStateAngVel);
316 const FQuat ExtrapolationDeltaQuaternion = FQuat(NewStateAngVelAxis, NewStateAngVel * ExtrapolationDeltaSeconds);
317 FQuat TargetQuat = ExtrapolationDeltaQuaternion * NewState.Quaternion;
328 ComputeDeltasVR(CurrentState.Position, CurrentState.Quaternion, TargetPos, TargetQuat, LinDiff, LinDiffSize, AngDiffAxis, AngDiff, AngDiffSize);
333 const bool bShouldSleep = (NewState.Flags & ERigidBodyFlags::Sleeping) != 0;
334 const bool bWasAwake = BI->IsInstanceAwake();
335 const bool bAutoWake =
false;
337 const float Error = (LinDiffSize * ErrorPerLinearDiff) + (AngDiffSize * ErrorPerAngularDiff);
338 bRestoredState =
Error < MaxRestoredStateError;
341 PhysicsTarget.AccumulatedErrorSeconds = 0.0f;
364 const float PrevProgress = FVector::DotProduct(
365 FVector(CurrentState.Position) - PhysicsTarget.PrevPos,
366 (PhysicsTarget.PrevPosTarget - PhysicsTarget.PrevPos).GetSafeNormal());
371 const float PrevSimilarity = FVector::DotProduct(
372 TargetPos - FVector(CurrentState.Position),
373 PhysicsTarget.PrevPosTarget - PhysicsTarget.PrevPos);
377 if (PrevProgress < ErrorAccumulationDistanceSq &&
378 PrevSimilarity > ErrorAccumulationSimilarity)
380 PhysicsTarget.AccumulatedErrorSeconds += DeltaSeconds;
384 PhysicsTarget.AccumulatedErrorSeconds = FMath::Max(PhysicsTarget.AccumulatedErrorSeconds - DeltaSeconds, 0.0f);
388 static const auto CVarAlwaysHardSnap = IConsoleManager::Get().FindConsoleVariable(TEXT(
"p.AlwaysHardSnap"));
389 const bool bHardSnap =
390 LinDiffSize > MaxLinearHardSnapDistance ||
391 PhysicsTarget.AccumulatedErrorSeconds > ErrorAccumulationSeconds ||
392 CVarAlwaysHardSnap->GetInt();
394 const FTransform IdealWorldTM(TargetQuat, TargetPos);
399 PhysicsTarget.AccumulatedErrorSeconds = 0.0f;
400 bRestoredState =
true;
401 BI->SetBodyTransform(IdealWorldTM, ETeleportType::ResetPhysics, bAutoWake);
404 BI->SetLinearVelocity(NewState.LinVel,
false, bAutoWake);
405 BI->SetAngularVelocityInRadians(FMath::DegreesToRadians(NewState.AngVel),
false, bAutoWake);
411 if (AsyncCallbackServer ==
nullptr)
414 const FVector NewLinVel = FVector(NewState.LinVel) + (LinDiff * LinearVelocityCoefficient * DeltaSeconds);
415 const FVector NewAngVel = FVector(NewState.AngVel) + (AngDiffAxis * AngDiff * AngularVelocityCoefficient * DeltaSeconds);
417 const FVector NewPos = FMath::Lerp(FVector(CurrentState.Position), FVector(TargetPos), PositionLerp);
418 const FQuat NewAng = FQuat::Slerp(CurrentState.Quaternion, TargetQuat, AngleLerp);
420 BI->SetBodyTransform(FTransform(NewAng, NewPos), ETeleportType::ResetPhysics);
421 BI->SetLinearVelocity(NewLinVel,
false);
422 BI->SetAngularVelocityInRadians(FMath::DegreesToRadians(NewAngVel),
false);
428 FAsyncPhysicsDesiredState AsyncDesiredState;
429 AsyncDesiredState.WorldTM = IdealWorldTM;
430 AsyncDesiredState.LinearVelocity = NewState.LinVel;
431 AsyncDesiredState.AngularVelocity = NewState.AngVel;
432 AsyncDesiredState.Proxy =
static_cast<FSingleParticlePhysicsProxy*
>(BI->GetPhysicsActorHandle());
433 AsyncDesiredState.ObjectState = AsyncDesiredState.Proxy->GetGameThreadAPI().ObjectState();
434 AsyncDesiredState.bShouldSleep = bShouldSleep;
435 CurAsyncDataVR->Buffer.Add(AsyncDesiredState);
441#if !UE_BUILD_SHIPPING
442 static const auto CVarNetShowCorrections = IConsoleManager::Get().FindConsoleVariable(TEXT(
"p.NetShowCorrections"));
443 if (CVarNetShowCorrections->GetInt() != 0)
445 PhysicsTarget.ErrorHistory.bAutoAdjustMinMax =
false;
446 PhysicsTarget.ErrorHistory.MinValue = 0.0f;
447 PhysicsTarget.ErrorHistory.MaxValue = 1.0f;
448 PhysicsTarget.ErrorHistory.AddSample(PhysicsTarget.AccumulatedErrorSeconds / ErrorAccumulationSeconds);
449 if (UWorld* OwningWorld = GetOwningWorld())
451 FColor Color = FColor::White;
452 static const auto CVarNetCorrectionLifetime = IConsoleManager::Get().FindConsoleVariable(TEXT(
"p.NetCorrectionLifetime"));
453 DrawDebugDirectionalArrow(OwningWorld, CurrentState.Position, TargetPos, 5.0f, Color,
true, CVarNetCorrectionLifetime->GetFloat(), 0, 1.5f);
456 DrawDebugFloatHistory(*OwningWorld, PhysicsTarget.ErrorHistory, NewPos + FVector(0.0f, 0.0f, 100.0f), FVector2D(100.0f, 50.0f), FColor::White);
469 if (AsyncCallbackServer ==
nullptr)
471 BI->PutInstanceToSleep();
476 PhysicsTarget.PrevPosTarget = TargetPos;
477 PhysicsTarget.PrevPos = FVector(CurrentState.Position);
479 return bRestoredState;
485 if (
const UWorld* World = GetOwningWorld())
487 if (World->GetNetMode() == ENetMode::NM_Client)
489 return FPhysicsReplication::OnTick(DeltaSeconds, ComponentsToTargets);
494 using namespace Chaos;
495 if (AsyncCallbackServer ==
nullptr)
499 AsyncCallbackServer = Solver->CreateAndRegisterSimCallbackObject_External<FPhysicsReplicationAsyncCallbackVR>();
504 const FRigidBodyErrorCorrection& PhysicErrorCorrection = UPhysicsSettings::Get()->PhysicErrorCorrection;
507 using namespace Chaos;
508 if (AsyncCallbackServer)
510 PrepareAsyncData_ExternalVR(PhysicErrorCorrection);
515 const float LocalPing = 0.0f;
524 for (
auto Itr = ComponentsToTargets.CreateIterator(); Itr; ++Itr)
535if (UPrimitiveComponent* PrimComp = Itr.Key().Get())
537 bool bRemoveItr =
false;
539 if (FBodyInstance* BI = PrimComp->GetBodyInstance(Itr.Value().BoneName))
541 FReplicatedPhysicsTarget& PhysicsTarget = Itr.Value();
542 FRigidBodyState& UpdatedState = PhysicsTarget.TargetState;
543 bool bUpdated =
false;
544 if (
AActor* OwningActor = PrimComp->GetOwner())
548 if (!OwningActor->GetNetOwningPlayer())
563 float OwnerPing = 0.0f;
579 const float PingSecondsOneWay = 0.0f;
582 if (UpdatedState.Flags & ERigidBodyFlags::NeedsUpdate)
584 const bool bRestoredState =
ApplyRigidBodyState(DeltaSeconds, BI, PhysicsTarget, PhysicErrorCorrection, PingSecondsOneWay);
587 static const auto CVarSkipSkeletalRepOptimization = IConsoleManager::Get().FindConsoleVariable(TEXT(
"p.SkipSkeletalRepOptimization"));
588 if (CVarSkipSkeletalRepOptimization->GetInt() == 0 || Cast<USkeletalMeshComponent>(PrimComp) ==
nullptr)
590 PrimComp->SyncComponentToRBPhysics();
594 if (bRestoredState || ((UpdatedState.Flags & ERigidBodyFlags::Sleeping) != 0))
606 OnTargetRestored(Itr.Key().Get(), Itr.Value());
612 CurAsyncDataVR =
nullptr;