Update to 5.6, lots of Cleanup
This commit is contained in:
		
							parent
							
								
									f036c2a1fb
								
							
						
					
					
						commit
						d29dbbbe45
					
				
					 141 changed files with 859 additions and 505 deletions
				
			
		| 
						 | 
				
			
			@ -10,6 +10,10 @@ namespace UnrealBuildTool.Rules
 | 
			
		|||
        public OpenXRExpansionPlugin(ReadOnlyTargetRules Target) 
 | 
			
		||||
				: base(Target)
 | 
			
		||||
        {
 | 
			
		||||
			PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
 | 
			
		||||
            DefaultBuildSettings = BuildSettingsVersion.Latest;
 | 
			
		||||
            IncludeOrderVersion = EngineIncludeOrderVersion.Latest;
 | 
			
		||||
 | 
			
		||||
            SetupIrisSupport(Target);
 | 
			
		||||
 | 
			
		||||
            PublicDependencyModuleNames.AddRange(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -373,6 +373,11 @@ bool FVRCharacterNetworkMoveData::Serialize(UCharacterMovementComponent& Charact
 | 
			
		|||
		{
 | 
			
		||||
			bRepRollAndPitch = (Roll != 0 || Pitch != 0);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			bool bCanRepRollAndPitch = (CharacterOwner && (CharacterOwner->bUseControllerRotationRoll || CharacterOwner->bUseControllerRotationPitch));
 | 
			
		||||
			bRepRollAndPitch = bCanRepRollAndPitch && (Roll != 0 || Pitch != 0);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,6 +19,7 @@
 | 
			
		|||
#include "UObject/UObjectGlobals.h" // for FindObject<>
 | 
			
		||||
#include "IXRTrackingSystem.h"
 | 
			
		||||
#include "IXRSystemAssets.h"
 | 
			
		||||
#include "SceneView.h"
 | 
			
		||||
#include "DrawDebugHelpers.h"
 | 
			
		||||
#include "TimerManager.h"
 | 
			
		||||
#include "VRBaseCharacter.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -249,7 +250,7 @@ void UGripMotionControllerComponent::RegisterEndPhysicsTick(bool bRegister)
 | 
			
		|||
void UGripMotionControllerComponent::EndPhysicsTickComponent(FGripComponentEndPhysicsTickFunction& ThisTickFunction)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	if (!IsValid(this))
 | 
			
		||||
	if (!IsValidChecked(this))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	// Now check if we should turn off any post physics ticking
 | 
			
		||||
| 
						 | 
				
			
			@ -4310,7 +4311,7 @@ bool UGripMotionControllerComponent::TeleportMoveGrippedActor(AActor * GrippedAc
 | 
			
		|||
 | 
			
		||||
	FBPActorGripInformation * GripInfo = LocallyGrippedObjects.FindByKey(GrippedActorToMove);
 | 
			
		||||
	if (!GripInfo)
 | 
			
		||||
		GrippedObjects.FindByKey(GrippedActorToMove);
 | 
			
		||||
		GripInfo = GrippedObjects.FindByKey(GrippedActorToMove);
 | 
			
		||||
 | 
			
		||||
	if (GripInfo)
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			@ -4327,7 +4328,7 @@ bool UGripMotionControllerComponent::TeleportMoveGrippedComponent(UPrimitiveComp
 | 
			
		|||
 | 
			
		||||
	FBPActorGripInformation * GripInfo = LocallyGrippedObjects.FindByKey(ComponentToMove);
 | 
			
		||||
	if (!GripInfo)
 | 
			
		||||
		GrippedObjects.FindByKey(ComponentToMove);
 | 
			
		||||
		GripInfo = GrippedObjects.FindByKey(ComponentToMove);
 | 
			
		||||
 | 
			
		||||
	if (GripInfo)
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			@ -6017,7 +6018,7 @@ void UGripMotionControllerComponent::CleanUpBadPhysicsHandles()
 | 
			
		|||
	{
 | 
			
		||||
		FBPActorGripInformation * GripInfo = LocallyGrippedObjects.FindByKey(PhysicsGrips[g].GripID);
 | 
			
		||||
		if(!GripInfo)
 | 
			
		||||
			GrippedObjects.FindByKey(PhysicsGrips[g].GripID);
 | 
			
		||||
			GripInfo = GrippedObjects.FindByKey(PhysicsGrips[g].GripID);
 | 
			
		||||
 | 
			
		||||
		if (!GripInfo)
 | 
			
		||||
		{
 | 
			
		||||
| 
						 | 
				
			
			@ -6156,44 +6157,48 @@ bool UGripMotionControllerComponent::DestroyPhysicsHandle(const FBPActorGripInfo
 | 
			
		|||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	UPrimitiveComponent *root = Grip.GetGrippedComponent();
 | 
			
		||||
	AActor * pActor = Grip.GetGrippedActor();
 | 
			
		||||
 | 
			
		||||
	if (!root && pActor)
 | 
			
		||||
		root = Cast<UPrimitiveComponent>(pActor->GetRootComponent());
 | 
			
		||||
 | 
			
		||||
	if (root)
 | 
			
		||||
	if (IsValid(Grip.GrippedObject))
 | 
			
		||||
	{
 | 
			
		||||
		if (FBodyInstance * rBodyInstance = root->GetBodyInstance(Grip.GrippedBoneName))
 | 
			
		||||
 | 
			
		||||
		UPrimitiveComponent* root = Grip.GetGrippedComponent();
 | 
			
		||||
		AActor* pActor = Grip.GetGrippedActor();
 | 
			
		||||
 | 
			
		||||
		if (!root && pActor)
 | 
			
		||||
			root = Cast<UPrimitiveComponent>(pActor->GetRootComponent());
 | 
			
		||||
 | 
			
		||||
		if (root)
 | 
			
		||||
		{
 | 
			
		||||
			// #TODO: Should this be done on drop instead?
 | 
			
		||||
			// Remove event registration
 | 
			
		||||
			if (!bSkipUnregistering)
 | 
			
		||||
			if (FBodyInstance* rBodyInstance = root->GetBodyInstance(Grip.GrippedBoneName))
 | 
			
		||||
			{
 | 
			
		||||
				if (rBodyInstance->OnRecalculatedMassProperties().IsBoundToObject(this))
 | 
			
		||||
				// #TODO: Should this be done on drop instead?
 | 
			
		||||
				// Remove event registration
 | 
			
		||||
				if (!bSkipUnregistering)
 | 
			
		||||
				{
 | 
			
		||||
					rBodyInstance->OnRecalculatedMassProperties().RemoveAll(this);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (HandleInfo->bSetCOM)
 | 
			
		||||
			{
 | 
			
		||||
				// Reset center of mass to zero
 | 
			
		||||
				// Get our original values
 | 
			
		||||
				FVector vel = rBodyInstance->GetUnrealWorldVelocity();
 | 
			
		||||
				FVector aVel = rBodyInstance->GetUnrealWorldAngularVelocityInRadians();
 | 
			
		||||
				FVector originalCOM = rBodyInstance->GetCOMPosition();
 | 
			
		||||
 | 
			
		||||
				if (rBodyInstance->IsValidBodyInstance() && rBodyInstance->BodySetup.IsValid())
 | 
			
		||||
				{
 | 
			
		||||
					rBodyInstance->UpdateMassProperties();
 | 
			
		||||
					if (rBodyInstance->OnRecalculatedMassProperties().IsBoundToObject(this))
 | 
			
		||||
					{
 | 
			
		||||
						rBodyInstance->OnRecalculatedMassProperties().RemoveAll(this);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (rBodyInstance->IsInstanceSimulatingPhysics())
 | 
			
		||||
				if (HandleInfo->bSetCOM)
 | 
			
		||||
				{
 | 
			
		||||
					// Offset the linear velocity by the new COM position and set it
 | 
			
		||||
					vel += FVector::CrossProduct(aVel, rBodyInstance->GetCOMPosition() - originalCOM);
 | 
			
		||||
					rBodyInstance->SetLinearVelocity(vel, false);
 | 
			
		||||
					// Reset center of mass to zero
 | 
			
		||||
					// Get our original values
 | 
			
		||||
					FVector vel = rBodyInstance->GetUnrealWorldVelocity();
 | 
			
		||||
					FVector aVel = rBodyInstance->GetUnrealWorldAngularVelocityInRadians();
 | 
			
		||||
					FVector originalCOM = rBodyInstance->GetCOMPosition();
 | 
			
		||||
 | 
			
		||||
					if (rBodyInstance->IsValidBodyInstance() && rBodyInstance->BodySetup.IsValid())
 | 
			
		||||
					{
 | 
			
		||||
						rBodyInstance->UpdateMassProperties();
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					if (rBodyInstance->IsInstanceSimulatingPhysics())
 | 
			
		||||
					{
 | 
			
		||||
						// Offset the linear velocity by the new COM position and set it
 | 
			
		||||
						vel += FVector::CrossProduct(aVel, rBodyInstance->GetCOMPosition() - originalCOM);
 | 
			
		||||
						rBodyInstance->SetLinearVelocity(vel, false);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -7224,8 +7229,15 @@ void UGripMotionControllerComponent::ApplyTrackingParameters(FVector& OriginalPo
 | 
			
		|||
 | 
			
		||||
					if (IsValid(AttachChar) && !AttachChar->bRetainRoomscale)
 | 
			
		||||
					{
 | 
			
		||||
						FRotator StoredCameraRotOffset = UVRExpansionFunctionLibrary::GetHMDPureYaw_I(curRot.Rotator());
 | 
			
		||||
						LastLocationForLateUpdate += StoredCameraRotOffset.RotateVector(FVector(AttachChar->VRRootReference->VRCapsuleOffset.X, AttachChar->VRRootReference->VRCapsuleOffset.Y, 0.0f));
 | 
			
		||||
						if (AttachChar->VRMovementReference && AttachChar->VRMovementReference->GetReplicatedMovementMode() == EVRConjoinedMovementModes::C_VRMOVE_Seated)
 | 
			
		||||
						{
 | 
			
		||||
 | 
			
		||||
						}
 | 
			
		||||
						else
 | 
			
		||||
						{
 | 
			
		||||
							FRotator StoredCameraRotOffset = UVRExpansionFunctionLibrary::GetHMDPureYaw_I(curRot.Rotator());
 | 
			
		||||
							LastLocationForLateUpdate += StoredCameraRotOffset.RotateVector(FVector(AttachChar->VRRootReference->VRCapsuleOffset.X, AttachChar->VRRootReference->VRCapsuleOffset.Y, 0.0f));
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -7238,8 +7250,15 @@ void UGripMotionControllerComponent::ApplyTrackingParameters(FVector& OriginalPo
 | 
			
		|||
 | 
			
		||||
					if (!AttachChar->bRetainRoomscale && IsLocallyControlled())
 | 
			
		||||
					{
 | 
			
		||||
						FRotator StoredCameraRotOffset = UVRExpansionFunctionLibrary::GetHMDPureYaw_I(AttachChar->VRReplicatedCamera->GetRelativeRotation());
 | 
			
		||||
						LastLocationForLateUpdate += StoredCameraRotOffset.RotateVector(FVector(AttachChar->VRRootReference->VRCapsuleOffset.X, AttachChar->VRRootReference->VRCapsuleOffset.Y, 0.0f));
 | 
			
		||||
						if (AttachChar->VRMovementReference && AttachChar->VRMovementReference->GetReplicatedMovementMode() == EVRConjoinedMovementModes::C_VRMOVE_Seated)
 | 
			
		||||
						{
 | 
			
		||||
 | 
			
		||||
						}
 | 
			
		||||
						else
 | 
			
		||||
						{
 | 
			
		||||
							FRotator StoredCameraRotOffset = UVRExpansionFunctionLibrary::GetHMDPureYaw_I(AttachChar->VRReplicatedCamera->GetRelativeRotation());
 | 
			
		||||
							LastLocationForLateUpdate += StoredCameraRotOffset.RotateVector(FVector(AttachChar->VRRootReference->VRCapsuleOffset.X, AttachChar->VRRootReference->VRCapsuleOffset.Y, 0.0f));
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,6 +10,7 @@
 | 
			
		|||
 | 
			
		||||
#include "CoreMinimal.h"
 | 
			
		||||
#include "PhysicsEngine/BodyInstance.h"
 | 
			
		||||
#include "PhysicsReplicationLOD.h"
 | 
			
		||||
#include "Components/PrimitiveComponent.h"
 | 
			
		||||
#include "Components/SkeletalMeshComponent.h"
 | 
			
		||||
#include "UObject/ObjectMacros.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -43,6 +44,12 @@ namespace VRPhysicsReplicationStatics
 | 
			
		|||
 | 
			
		||||
// Hacky work around for them not exporting these....
 | 
			
		||||
#if WITH_EDITOR
 | 
			
		||||
 | 
			
		||||
namespace RenderInterpolationCVars
 | 
			
		||||
{
 | 
			
		||||
	bool bRenderInterpDebugDrawResimTrigger = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace PhysicsReplicationCVars
 | 
			
		||||
{
 | 
			
		||||
	int32 SkipSkeletalRepOptimization = 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -51,6 +58,9 @@ namespace PhysicsReplicationCVars
 | 
			
		|||
#endif
 | 
			
		||||
 | 
			
		||||
	int32 EnableDefaultReplication = 0;
 | 
			
		||||
	int32 DebugDrawShowRepMode = 0;
 | 
			
		||||
	float DebugDrawLifeTime = 3.0f;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	namespace DefaultReplicationCVars
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			@ -61,6 +71,8 @@ namespace PhysicsReplicationCVars
 | 
			
		|||
 | 
			
		||||
	namespace ResimulationCVars
 | 
			
		||||
	{
 | 
			
		||||
		//extern bool bApplyPredictiveInterpolationWhenBehindServer;
 | 
			
		||||
 | 
			
		||||
		bool bRuntimeCorrectionEnabled = false;
 | 
			
		||||
		bool bRuntimeVelocityCorrection = false;
 | 
			
		||||
		bool bRuntimeCorrectConnectedBodies = true;
 | 
			
		||||
| 
						 | 
				
			
			@ -72,15 +84,20 @@ namespace PhysicsReplicationCVars
 | 
			
		|||
 | 
			
		||||
		// Inside of NetworkPhysicsComponent - UPDATE AS CHANGE
 | 
			
		||||
		int32 RedundantInputs = 2;
 | 
			
		||||
		int32 RedundantRemoteInputs = 1;
 | 
			
		||||
		int32 RedundantStates = 0;
 | 
			
		||||
		bool bAllowRewindToClosestState = true;
 | 
			
		||||
		bool bCompareStateToTriggerRewind = false;
 | 
			
		||||
		bool bCompareStateToTriggerRewindIncludeSimProxies = false;
 | 
			
		||||
		bool bCompareInputToTriggerRewind = false;
 | 
			
		||||
		bool bEnableUnreliableFlow = true;
 | 
			
		||||
		bool bEnableReliableFlow = false;
 | 
			
		||||
		bool bApplyDataInsteadOfMergeData = false;
 | 
			
		||||
		bool bAllowInputExtrapolation = true;
 | 
			
		||||
		bool bValidateDataOnGameThread = false;
 | 
			
		||||
		bool bApplySimProxyStateAtRuntime = false;
 | 
			
		||||
		bool bApplySimProxyInputAtRuntime = true;
 | 
			
		||||
		bool bApplyPredictiveInterpolationWhenBehindServer = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	namespace PredictiveInterpolationCVars
 | 
			
		||||
| 
						 | 
				
			
			@ -129,6 +146,9 @@ namespace PhysicsReplicationCVars
 | 
			
		|||
		float DrawDebugZOffset = 50.0f;
 | 
			
		||||
		float SleepSecondsClearTarget = 15.0f;
 | 
			
		||||
		int32 TargetTickAlignmentClampMultiplier = 2;
 | 
			
		||||
		int32 TeleportDetectionEnabled = 1;
 | 
			
		||||
		float TeleportDetectionMinDistance = 200.0f;
 | 
			
		||||
		float TeleportDetectionVelocityMultiplier = 1.3f;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -373,13 +393,13 @@ void FPhysicsReplicationVR::RemoveReplicatedTarget(UPrimitiveComponent* Componen
 | 
			
		|||
{
 | 
			
		||||
 | 
			
		||||
	// Skip all of the custom logic if we aren't the server
 | 
			
		||||
	if (const UWorld* World = GetOwningWorld())
 | 
			
		||||
	/*if (const UWorld* World = GetOwningWorld())
 | 
			
		||||
	{
 | 
			
		||||
		if (World->GetNetMode() == ENetMode::NM_Client)
 | 
			
		||||
		{
 | 
			
		||||
			return FPhysicsReplication::RemoveReplicatedTarget(Component);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	}*/
 | 
			
		||||
 | 
			
		||||
	if (Component == nullptr)
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			@ -659,7 +679,7 @@ bool FPhysicsReplicationVR::ApplyRigidBodyState(float DeltaSeconds, FBodyInstanc
 | 
			
		|||
			{
 | 
			
		||||
				if (bHardsnapLegacyInPT)
 | 
			
		||||
				{
 | 
			
		||||
					if (Chaos::FSingleParticlePhysicsProxy* Proxy = static_cast<Chaos::FSingleParticlePhysicsProxy*>(BI->GetPhysicsActorHandle()))
 | 
			
		||||
					if (Chaos::FSingleParticlePhysicsProxy* Proxy = static_cast<Chaos::FSingleParticlePhysicsProxy*>(BI->GetPhysicsActor()))
 | 
			
		||||
					{
 | 
			
		||||
						if (Chaos::FPBDRigidsSolver* Solver = Proxy->GetSolver<Chaos::FPBDRigidsSolver>())
 | 
			
		||||
						{
 | 
			
		||||
| 
						 | 
				
			
			@ -715,7 +735,7 @@ bool FPhysicsReplicationVR::ApplyRigidBodyState(float DeltaSeconds, FBodyInstanc
 | 
			
		|||
				AsyncInputData.TargetState = NewState;
 | 
			
		||||
				AsyncInputData.TargetState.Position = IdealWorldTM.GetLocation();
 | 
			
		||||
				AsyncInputData.TargetState.Quaternion = IdealWorldTM.GetRotation();
 | 
			
		||||
				AsyncInputData.Proxy = static_cast<Chaos::FSingleParticlePhysicsProxy*>(BI->GetPhysicsActorHandle());
 | 
			
		||||
				AsyncInputData.Proxy = static_cast<Chaos::FSingleParticlePhysicsProxy*>(BI->GetPhysicsActor());
 | 
			
		||||
				AsyncInputData.ErrorCorrection = { ErrorCorrection.LinearVelocityCoefficient, ErrorCorrection.AngularVelocityCoefficient, ErrorCorrection.PositionLerp, ErrorCorrection.AngleLerp };
 | 
			
		||||
 | 
			
		||||
				AsyncInputData.LatencyOneWay = PingSeconds;
 | 
			
		||||
| 
						 | 
				
			
			@ -746,7 +766,7 @@ bool FPhysicsReplicationVR::ApplyRigidBodyState(float DeltaSeconds, FBodyInstanc
 | 
			
		|||
			{
 | 
			
		||||
				FColor Color = FColor::White;
 | 
			
		||||
				static const auto CVarNetCorrectionLifetime = IConsoleManager::Get().FindConsoleVariable(TEXT("p.NetCorrectionLifetime"));
 | 
			
		||||
				DrawDebugDirectionalArrow(OwningWorld, CurrentState.Position, TargetPos, 5.0f, Color, true, CVarNetCorrectionLifetime->GetFloat(), 0, 1.5f);
 | 
			
		||||
				DrawDebugDirectionalArrow(OwningWorld, CurrentState.Position, TargetPos, 5.0f, Color, false, CVarNetCorrectionLifetime->GetFloat(), 0, 1.5f);
 | 
			
		||||
#if 0
 | 
			
		||||
				//todo: do we show this in async mode?
 | 
			
		||||
				DrawDebugFloatHistory(*OwningWorld, PhysicsTarget.ErrorHistory, NewPos + FVector(0.0f, 0.0f, 100.0f), FVector2D(100.0f, 50.0f), FColor::White);
 | 
			
		||||
| 
						 | 
				
			
			@ -791,6 +811,12 @@ void FPhysicsReplicationVR::OnTick(float DeltaSeconds, TMap<TWeakObjectPtr<UPrim
 | 
			
		|||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Don't tick unless we have data to process
 | 
			
		||||
	if (ComponentsToTargets.Num() == 0 && ReplicatedTargetsQueueVR.Num() == 0)
 | 
			
		||||
	{
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	using namespace Chaos;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1033,13 +1059,15 @@ void FPhysicsReplicationAsyncVR::FetchObjectSettings(Chaos::FConstPhysicsObjectH
 | 
			
		|||
 | 
			
		||||
void FPhysicsReplicationAsyncVR::OnPostInitialize_Internal()
 | 
			
		||||
{
 | 
			
		||||
	Chaos::FPBDRigidsSolver* RigidsSolver = static_cast<Chaos::FPBDRigidsSolver*>(GetSolver());
 | 
			
		||||
	Chaos::FPBDRigidsSolver& RigidsSolver = GetSolver()->CastChecked();
 | 
			
		||||
	RigidsSolver.SetPhysicsReplication_Internal(this);
 | 
			
		||||
	//Chaos::FPBDRigidsSolver* RigidsSolver = static_cast<Chaos::FPBDRigidsSolver*>(GetSolver());
 | 
			
		||||
 | 
			
		||||
	if (ensure(RigidsSolver))
 | 
			
		||||
	/*if (ensure(RigidsSolver))
 | 
			
		||||
	{
 | 
			
		||||
		// This doesn't even do anything currently, nothing gets it #TODO: CHECK BACK ON THIS
 | 
			
		||||
		//RigidsSolver->SetPhysicsReplication(this);
 | 
			
		||||
	}
 | 
			
		||||
	}*/
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FPhysicsReplicationAsyncVR::OnPreSimulate_Internal()
 | 
			
		||||
| 
						 | 
				
			
			@ -1049,35 +1077,34 @@ void FPhysicsReplicationAsyncVR::OnPreSimulate_Internal()
 | 
			
		|||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (const FPhysicsReplicationAsyncInput* AsyncInput = GetConsumerInput_Internal())
 | 
			
		||||
	Chaos::FPBDRigidsSolver* RigidsSolver = static_cast<Chaos::FPBDRigidsSolver*>(GetSolver());
 | 
			
		||||
	check(RigidsSolver);
 | 
			
		||||
 | 
			
		||||
	// Early out if this is a resim frame
 | 
			
		||||
	Chaos::FRewindData* RewindData = RigidsSolver->GetRewindData();
 | 
			
		||||
	const bool bRewindDataExist = RewindData != nullptr;
 | 
			
		||||
	if (bRewindDataExist && RewindData->IsResim())
 | 
			
		||||
	{
 | 
			
		||||
		Chaos::FPBDRigidsSolver* RigidsSolver = static_cast<Chaos::FPBDRigidsSolver*>(GetSolver());
 | 
			
		||||
		check(RigidsSolver);
 | 
			
		||||
 | 
			
		||||
		// Early out if this is a resim frame
 | 
			
		||||
		Chaos::FRewindData* RewindData = RigidsSolver->GetRewindData();
 | 
			
		||||
		const bool bRewindDataExist = RewindData != nullptr;
 | 
			
		||||
		if (bRewindDataExist && RewindData->IsResim())
 | 
			
		||||
		//static const auto CVarPostResimWaitForUpdate = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.PostResimWaitForUpdate"));
 | 
			
		||||
		// TODO, Handle the transition from post-resim to interpolation better (disabled by default, resim vs replication interaction is handled via FPhysicsReplicationAsync::CacheResimInteractions)
 | 
			
		||||
		if (SettingsCurrent.PredictiveInterpolationSettings.GetPostResimWaitForUpdate() && RewindData->IsFinalResim())
 | 
			
		||||
		{
 | 
			
		||||
			// TODO, Handle the transition from post-resim to interpolation better (disabled by default, resim vs replication interaction is handled via FPhysicsReplicationAsync::CacheResimInteractions)
 | 
			
		||||
			static const auto CVarPostResimWaitForUpdate = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.PostResimWaitForUpdate"));
 | 
			
		||||
			if (CVarPostResimWaitForUpdate->GetBool() && RewindData->IsFinalResim())
 | 
			
		||||
			for (auto Itr = ObjectToTarget.CreateIterator(); Itr; ++Itr)
 | 
			
		||||
			{
 | 
			
		||||
				for (auto Itr = ObjectToTarget.CreateIterator(); Itr; ++Itr)
 | 
			
		||||
				{
 | 
			
		||||
					FReplicatedPhysicsTargetAsync& Target = Itr.Value();
 | 
			
		||||
				FReplicatedPhysicsTargetAsync& Target = Itr.Value();
 | 
			
		||||
 | 
			
		||||
					// If final resim frame, mark interpolated targets as waiting for up to date data from the server.
 | 
			
		||||
					if (Target.RepMode == EPhysicsReplicationMode::PredictiveInterpolation)
 | 
			
		||||
					{
 | 
			
		||||
						Target.SetWaiting(RigidsSolver->GetCurrentFrame() + Target.FrameOffset, Target.RepModeOverride);
 | 
			
		||||
					}
 | 
			
		||||
				// If final resim frame, mark interpolated targets as waiting for up to date data from the server.
 | 
			
		||||
				if (Target.RepMode == EPhysicsReplicationMode::PredictiveInterpolation)
 | 
			
		||||
				{
 | 
			
		||||
					Target.SetWaiting(RigidsSolver->GetCurrentFrame() + Target.FrameOffset, Target.RepModeOverride);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (const FPhysicsReplicationAsyncInput* AsyncInput = GetConsumerInput_Internal())
 | 
			
		||||
	{
 | 
			
		||||
		// Update async targets with target input
 | 
			
		||||
		for (const FPhysicsRepAsyncInputData& Input : AsyncInput->InputData)
 | 
			
		||||
		{
 | 
			
		||||
| 
						 | 
				
			
			@ -1100,15 +1127,27 @@ void FPhysicsReplicationAsyncVR::OnPreSimulate_Internal()
 | 
			
		|||
 | 
			
		||||
			UpdateRewindDataTarget(Input);
 | 
			
		||||
			UpdateAsyncTarget(Input, RigidsSolver);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (Chaos::FPBDRigidsSolver::IsNetworkPhysicsPredictionEnabled())
 | 
			
		||||
		{
 | 
			
		||||
			CacheResimInteractions();
 | 
			
		||||
		}
 | 
			
		||||
			DebugDrawReplicationMode(Input);
 | 
			
		||||
 | 
			
		||||
		ApplyTargetStatesAsync(GetDeltaTime_Internal(), AsyncInput->ErrorCorrection, AsyncInput->InputData);
 | 
			
		||||
			// Deprecated, legacy BodyInstance flow for Default Replication
 | 
			
		||||
			if (Input.Proxy != nullptr)
 | 
			
		||||
			{
 | 
			
		||||
				Chaos::FSingleParticlePhysicsProxy* Proxy = Input.Proxy;
 | 
			
		||||
				Chaos::FRigidBodyHandle_Internal* Handle = Proxy->GetPhysicsThreadAPI();
 | 
			
		||||
 | 
			
		||||
				const FPhysicsRepErrorCorrectionData& UsedErrorCorrection = Input.ErrorCorrection.IsSet() ? Input.ErrorCorrection.GetValue() : AsyncInput->ErrorCorrection;
 | 
			
		||||
				DefaultReplication_DEPRECATED(Handle, Input, GetDeltaTime_Internal(), UsedErrorCorrection);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (Chaos::FPBDRigidsSolver::IsNetworkPhysicsPredictionEnabled())
 | 
			
		||||
	{
 | 
			
		||||
		CacheResimInteractions();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ApplyTargetStatesAsync(GetDeltaTime_Internal());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FReplicatedPhysicsTargetAsync* FPhysicsReplicationAsyncVR::AddObjectToReplication(Chaos::FConstPhysicsObjectHandle PhysicsObject)
 | 
			
		||||
| 
						 | 
				
			
			@ -1201,6 +1240,7 @@ void FPhysicsReplicationAsyncVR::UpdateAsyncTarget(const FPhysicsRepAsyncInputDa
 | 
			
		|||
		Target->PrevLinVel = Input.TargetState.LinVel;
 | 
			
		||||
		Target->RepModeOverride = Input.RepMode;
 | 
			
		||||
	}
 | 
			
		||||
	check(Target);
 | 
			
		||||
 | 
			
		||||
	/** Target Update Description
 | 
			
		||||
	* @param Input = incoming state target for replication.
 | 
			
		||||
| 
						 | 
				
			
			@ -1247,6 +1287,9 @@ void FPhysicsReplicationAsyncVR::UpdateAsyncTarget(const FPhysicsRepAsyncInputDa
 | 
			
		|||
		// Set if the target is allowed to be altered after this update
 | 
			
		||||
		Target->bAllowTargetAltering = !(Target->TargetState.Flags & ERigidBodyFlags::Sleeping) && !(Input.TargetState.Flags & ERigidBodyFlags::Sleeping);
 | 
			
		||||
 | 
			
		||||
		// Cache previous linear velocity
 | 
			
		||||
		const FVector PrevLinVel = Target->TargetState.LinVel;
 | 
			
		||||
 | 
			
		||||
		// Set Target->ReceiveInterval from either SendInterval or the number of physics ticks between receiving input states
 | 
			
		||||
		if (SendInterval > 0)
 | 
			
		||||
		{
 | 
			
		||||
| 
						 | 
				
			
			@ -1259,11 +1302,7 @@ void FPhysicsReplicationAsyncVR::UpdateAsyncTarget(const FPhysicsRepAsyncInputDa
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		// Update target from input and reset properties
 | 
			
		||||
		PRAGMA_DISABLE_DEPRECATION_WARNINGS
 | 
			
		||||
			Target->PrevServerFrame = Target->bWaiting ? Input.ServerFrame : Target->ServerFrame; // DEPRECATED UE5.4
 | 
			
		||||
		Target->PrevReceiveFrame = (Target->ReceiveFrame == INDEX_NONE) ? (RigidsSolver->GetCurrentFrame() - 1) : Target->ReceiveFrame; // DEPRECATED UE5.4
 | 
			
		||||
		PRAGMA_ENABLE_DEPRECATION_WARNINGS
 | 
			
		||||
			Target->ServerFrame = Input.ServerFrame;
 | 
			
		||||
		Target->ServerFrame = Input.ServerFrame;
 | 
			
		||||
		Target->ReceiveFrame = CurrentFrame;
 | 
			
		||||
		Target->TargetState = Input.TargetState;
 | 
			
		||||
		Target->RepMode = Input.RepMode;
 | 
			
		||||
| 
						 | 
				
			
			@ -1274,7 +1313,13 @@ void FPhysicsReplicationAsyncVR::UpdateAsyncTarget(const FPhysicsRepAsyncInputDa
 | 
			
		|||
		// Update waiting state
 | 
			
		||||
		Target->UpdateWaiting(Input.ServerFrame);
 | 
			
		||||
 | 
			
		||||
		if (Input.RepMode == EPhysicsReplicationMode::PredictiveInterpolation)
 | 
			
		||||
		// Apply full Replication LOD on received target
 | 
			
		||||
		ApplyPhysicsReplicationLOD(Input.PhysicsObject, *Target, EPhysicsReplicationLODFlags::LODFlag_All);
 | 
			
		||||
 | 
			
		||||
		// Check if target is valid to use for resimulation and perform actions if not
 | 
			
		||||
		CheckTargetResimValidity(*Target);
 | 
			
		||||
 | 
			
		||||
		if (Target->RepMode == EPhysicsReplicationMode::PredictiveInterpolation)
 | 
			
		||||
		{
 | 
			
		||||
 | 
			
		||||
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
 | 
			
		||||
| 
						 | 
				
			
			@ -1284,16 +1329,13 @@ void FPhysicsReplicationAsyncVR::UpdateAsyncTarget(const FPhysicsRepAsyncInputDa
 | 
			
		|||
				const FVector Offset = FVector(0.0f, 0.0f, 50.0f);
 | 
			
		||||
				// Port this?
 | 
			
		||||
				//const FVector Offset = FVector(0.0f, 0.0f, PhysicsReplicationCVars::PredictiveInterpolationCVars::DrawDebugZOffset);
 | 
			
		||||
 | 
			
		||||
				static const auto CVarNetCorrectionLifetime = IConsoleManager::Get().FindConsoleVariable(TEXT("p.NetCorrectionLifetime"));
 | 
			
		||||
				static const auto CVarNetCorrectionLifetime = IConsoleManager::Get().FindConsoleVariable(TEXT("p.Net.DebugDraw.LifeTime"));
 | 
			
		||||
				Chaos::FDebugDrawQueue::GetInstance().DrawDebugBox(Input.TargetState.Position + Offset, FVector(15.0f, 15.0f, 15.0f), Input.TargetState.Quaternion, FColor::MakeRandomSeededColor(Input.ServerFrame), false, CVarNetCorrectionLifetime->GetFloat(), 0, 1.0f);
 | 
			
		||||
			}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
			// Cache the position we received this target at, Predictive Interpolation will alter the target state but use this as the source position for reconciliation.
 | 
			
		||||
			Target->PrevPosTarget = Input.TargetState.Position;
 | 
			
		||||
			Target->PrevRotTarget = Input.TargetState.Quaternion;
 | 
			
		||||
 | 
			
		||||
			// TickCount is 0 by default at this point and when LOD is used, TickCount will be 0 if no LOD alignment was performed, in this case perform the normal target alignment
 | 
			
		||||
			if (Target->TickCount == 0)
 | 
			
		||||
			{
 | 
			
		||||
				/** Target Alignment Feature
 | 
			
		||||
				* With variable network conditions state inputs from the server can arrive both later or earlier than expected.
 | 
			
		||||
| 
						 | 
				
			
			@ -1331,6 +1373,34 @@ void FPhysicsReplicationAsyncVR::UpdateAsyncTarget(const FPhysicsRepAsyncInputDa
 | 
			
		|||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			static const auto CVarTeleportDetectionEnabled = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.TeleportDetection.Enabled"));
 | 
			
		||||
			// Teleport detection, we don't have specific data that tells us a teleport has happened on the server, so try to detect it by examining the previous and next state
 | 
			
		||||
			if (CVarTeleportDetectionEnabled->GetBool() == 1 && !bFirstTarget && SendInterval > 0 && RigidsSolver->IsUsingFixedDt())
 | 
			
		||||
			{
 | 
			
		||||
				const FVector PosOffset = (Input.TargetState.Position - Target->PrevPosTarget);
 | 
			
		||||
				static const auto CVarTeleportDetectionMinDistance = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.TeleportDetection.MinDistance"));
 | 
			
		||||
				if (PosOffset.SizeSquared() > (CVarTeleportDetectionMinDistance->GetFloat() * CVarTeleportDetectionMinDistance->GetFloat()))
 | 
			
		||||
				{
 | 
			
		||||
					const FVector Velocity = Input.TargetState.LinVel.SizeSquared() > PrevLinVel.SizeSquared() ? Input.TargetState.LinVel : PrevLinVel;
 | 
			
		||||
					const float DeltaSeconds = (SendInterval * RigidsSolver->GetAsyncDeltaTime());
 | 
			
		||||
					static const auto CVarTeleportDetectionVelocityMultiplier = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.TeleportDetection.VelocityMultiplier"));
 | 
			
		||||
					const float PossibleDistanceSquared = (Velocity * (DeltaSeconds * CVarTeleportDetectionVelocityMultiplier->GetFloat())).SizeSquared();
 | 
			
		||||
 | 
			
		||||
					if (PossibleDistanceSquared < PosOffset.SizeSquared())
 | 
			
		||||
					{
 | 
			
		||||
						// A teleport has most likely happened, set accumulated error seconds to above limit for hard snapping
 | 
			
		||||
						// TODO: Don't piggyback on AccumulatedErrorSeconds (potentially implement ERigidBodyFlags::Teleported)
 | 
			
		||||
 | 
			
		||||
						static const auto CVarErrorAcumulationSeconds = IConsoleManager::Get().FindConsoleVariable(TEXT("p.ErrorAccumulationSeconds"));
 | 
			
		||||
						Target->AccumulatedErrorSeconds = CVarErrorAcumulationSeconds->GetFloat() + 1.0f;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Cache the position we received this target at, Predictive Interpolation will alter the target state but use this as the source position for reconciliation.
 | 
			
		||||
			Target->PrevPosTarget = Input.TargetState.Position;
 | 
			
		||||
			Target->PrevRotTarget = Input.TargetState.Quaternion;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1344,6 +1414,14 @@ void FPhysicsReplicationAsyncVR::CacheResimInteractions()
 | 
			
		|||
	static const auto CVarResimDisableReplicationOnInteraction = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.Resim.DisableReplicationOnInteraction"));
 | 
			
		||||
	if (!CVarResimDisableReplicationOnInteraction->GetBool())
 | 
			
		||||
	{
 | 
			
		||||
		ParticlesInResimIslands.Empty();
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (UsePhysicsReplicationLOD())
 | 
			
		||||
	{
 | 
			
		||||
		// This will be handled by the LOD system
 | 
			
		||||
		ParticlesInResimIslands.Empty();
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1353,9 +1431,12 @@ void FPhysicsReplicationAsyncVR::CacheResimInteractions()
 | 
			
		|||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ParticlesInResimIslands.Empty(FMath::CeilToInt(static_cast<float>(ParticlesInResimIslands.Num()) * 0.9f));
 | 
			
		||||
	ResimIslands.Reset();
 | 
			
		||||
	ResimIslandsParticles.Reset();
 | 
			
		||||
	ParticlesInResimIslands.Reset();
 | 
			
		||||
 | 
			
		||||
	Chaos::Private::FPBDIslandManager& IslandManager = RigidsSolver->GetEvolution()->GetIslandManager();
 | 
			
		||||
	Chaos::FWritePhysicsObjectInterface_Internal Interface = Chaos::FPhysicsObjectInternalInterface::GetWrite();
 | 
			
		||||
	Chaos::FReadPhysicsObjectInterface_Internal Interface = Chaos::FPhysicsObjectInternalInterface::GetRead();
 | 
			
		||||
	for (auto Itr = ObjectToTarget.CreateIterator(); Itr; ++Itr)
 | 
			
		||||
	{
 | 
			
		||||
		FReplicatedPhysicsTargetAsync& Target = Itr.Value();
 | 
			
		||||
| 
						 | 
				
			
			@ -1365,7 +1446,9 @@ void FPhysicsReplicationAsyncVR::CacheResimInteractions()
 | 
			
		|||
			if (Chaos::FGeometryParticleHandle* Handle = Interface.GetParticle(POHandle))
 | 
			
		||||
			{
 | 
			
		||||
				// Get a list of particles from the same island as a resim particle is in, i.e. particles interacting with a resim particle
 | 
			
		||||
				for (const Chaos::FGeometryParticleHandle* InteractParticle : IslandManager.FindParticlesInIslands(IslandManager.FindParticleIslands(Handle)))
 | 
			
		||||
				IslandManager.FindParticleIslands(Handle, OUT ResimIslands);
 | 
			
		||||
				IslandManager.FindParticlesInIslands(ResimIslands, OUT ResimIslandsParticles);
 | 
			
		||||
				for (const Chaos::FGeometryParticleHandle* InteractParticle : ResimIslandsParticles)
 | 
			
		||||
				{
 | 
			
		||||
					ParticlesInResimIslands.Add(InteractParticle->GetHandleIdx());
 | 
			
		||||
				}
 | 
			
		||||
| 
						 | 
				
			
			@ -1374,66 +1457,152 @@ void FPhysicsReplicationAsyncVR::CacheResimInteractions()
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FPhysicsReplicationAsyncVR::ApplyTargetStatesAsync(const float DeltaSeconds, const FPhysicsRepErrorCorrectionData& ErrorCorrection, const TArray<FPhysicsRepAsyncInputData>& InputData)
 | 
			
		||||
void FPhysicsReplicationAsyncVR::ApplyTargetStatesAsync(const float DeltaSeconds)
 | 
			
		||||
{
 | 
			
		||||
	using namespace Chaos;
 | 
			
		||||
 | 
			
		||||
	// Deprecated, legacy BodyInstance flow
 | 
			
		||||
	for (const FPhysicsRepAsyncInputData& Input : InputData)
 | 
			
		||||
	{
 | 
			
		||||
		if (Input.Proxy != nullptr)
 | 
			
		||||
	/** Helper function to remove replicated target*/
 | 
			
		||||
	auto RemoveTargetHelper = [this](TMap<Chaos::FConstPhysicsObjectHandle, FReplicatedPhysicsTargetAsync>::TIterator Itr, FGeometryParticleHandle* Handle)
 | 
			
		||||
		{
 | 
			
		||||
			Chaos::FSingleParticlePhysicsProxy* Proxy = Input.Proxy;
 | 
			
		||||
			Chaos::FRigidBodyHandle_Internal* Handle = Proxy->GetPhysicsThreadAPI();
 | 
			
		||||
 | 
			
		||||
			const FPhysicsRepErrorCorrectionData& UsedErrorCorrection = Input.ErrorCorrection.IsSet() ? Input.ErrorCorrection.GetValue() : ErrorCorrection;
 | 
			
		||||
			DefaultReplication_DEPRECATED(Handle, Input, DeltaSeconds, UsedErrorCorrection);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
			if (Handle)
 | 
			
		||||
			{
 | 
			
		||||
				ReplicatedParticleIDs.Remove(Handle->ParticleID());
 | 
			
		||||
			}
 | 
			
		||||
			Itr.RemoveCurrent();
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
	// PhysicsObject flow
 | 
			
		||||
	Chaos::FWritePhysicsObjectInterface_Internal Interface = Chaos::FPhysicsObjectInternalInterface::GetWrite();
 | 
			
		||||
	for (auto Itr = ObjectToTarget.CreateIterator(); Itr; ++Itr)
 | 
			
		||||
	for (TMap<Chaos::FConstPhysicsObjectHandle, FReplicatedPhysicsTargetAsync>::TIterator Itr = ObjectToTarget.CreateIterator(); Itr; ++Itr)
 | 
			
		||||
	{
 | 
			
		||||
		bool bRemoveItr = true; // Remove current cached replication target unless replication logic tells us to store it for next tick
 | 
			
		||||
		FParticleID ParticleID;
 | 
			
		||||
 | 
			
		||||
		Chaos::FConstPhysicsObjectHandle& POHandle = Itr.Key();
 | 
			
		||||
		if (FGeometryParticleHandle* Handle = Interface.GetParticle(POHandle))
 | 
			
		||||
		FGeometryParticleHandle* Handle = Interface.GetParticle(POHandle);
 | 
			
		||||
		if (!Handle)
 | 
			
		||||
		{
 | 
			
		||||
			FReplicatedPhysicsTargetAsync& Target = Itr.Value();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
			if (FPBDRigidParticleHandle* RigidHandle = Handle->CastToRigidParticle())
 | 
			
		||||
			{
 | 
			
		||||
				ParticleID = RigidHandle->ParticleID();
 | 
			
		||||
 | 
			
		||||
				// Cache custom settings for this object if there are any
 | 
			
		||||
				FetchObjectSettings(POHandle);
 | 
			
		||||
 | 
			
		||||
				const EPhysicsReplicationMode RepMode = Target.IsWaiting() ? Target.RepModeOverride : Target.RepMode;
 | 
			
		||||
				switch (RepMode)
 | 
			
		||||
				{
 | 
			
		||||
				case EPhysicsReplicationMode::Default:
 | 
			
		||||
					bRemoveItr = DefaultReplication(RigidHandle, Target, DeltaSeconds);
 | 
			
		||||
					break;
 | 
			
		||||
 | 
			
		||||
				case EPhysicsReplicationMode::PredictiveInterpolation:
 | 
			
		||||
					bRemoveItr = PredictiveInterpolation(RigidHandle, Target, DeltaSeconds);
 | 
			
		||||
					break;
 | 
			
		||||
 | 
			
		||||
				case EPhysicsReplicationMode::Resimulation:
 | 
			
		||||
					bRemoveItr = ResimulationReplication(RigidHandle, Target, DeltaSeconds);
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
				Target.TickCount++;
 | 
			
		||||
			}
 | 
			
		||||
			RemoveTargetHelper(Itr, nullptr);
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		FPBDRigidParticleHandle* RigidHandle = Handle->CastToRigidParticle();
 | 
			
		||||
		if (!RigidHandle)
 | 
			
		||||
		{
 | 
			
		||||
			RemoveTargetHelper(Itr, Handle);
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		FReplicatedPhysicsTargetAsync& Target = Itr.Value();
 | 
			
		||||
 | 
			
		||||
		// Cache custom settings for this object if there are any
 | 
			
		||||
		FetchObjectSettings(POHandle);
 | 
			
		||||
 | 
			
		||||
		// Apply limited Replication LOD
 | 
			
		||||
		ApplyPhysicsReplicationLOD(POHandle, Target, EPhysicsReplicationLODFlags::LODFlag_IslandCheck);
 | 
			
		||||
 | 
			
		||||
		const EPhysicsReplicationMode RepMode = Target.IsWaiting() ? Target.RepModeOverride : Target.RepMode;
 | 
			
		||||
		switch (RepMode)
 | 
			
		||||
		{
 | 
			
		||||
		case EPhysicsReplicationMode::Default:
 | 
			
		||||
			bRemoveItr = DefaultReplication(RigidHandle, Target, DeltaSeconds);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case EPhysicsReplicationMode::PredictiveInterpolation:
 | 
			
		||||
			bRemoveItr = PredictiveInterpolation(RigidHandle, Target, DeltaSeconds);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case EPhysicsReplicationMode::Resimulation:
 | 
			
		||||
			bRemoveItr = ResimulationReplication(RigidHandle, Target, DeltaSeconds);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		Target.TickCount++;
 | 
			
		||||
 | 
			
		||||
		if (bRemoveItr)
 | 
			
		||||
		{
 | 
			
		||||
			ReplicatedParticleIDs.Remove(ParticleID);
 | 
			
		||||
			Itr.RemoveCurrent();
 | 
			
		||||
			RemoveTargetHelper(Itr, RigidHandle);
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FPhysicsReplicationAsyncVR::CheckTargetResimValidity(FReplicatedPhysicsTargetAsync& Target)
 | 
			
		||||
{
 | 
			
		||||
	if (Target.RepMode != EPhysicsReplicationMode::Resimulation)
 | 
			
		||||
	{
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Chaos::FPBDRigidsSolver* RigidsSolver = static_cast<Chaos::FPBDRigidsSolver*>(GetSolver());
 | 
			
		||||
	if (RigidsSolver == nullptr)
 | 
			
		||||
	{
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Chaos::FRewindData* RewindData = RigidsSolver->GetRewindData();
 | 
			
		||||
	if (RewindData == nullptr)
 | 
			
		||||
	{
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const int32 LocalFrame = Target.ServerFrame - Target.FrameOffset;
 | 
			
		||||
	if (!RewindData->IsFrameWithinRewindHistory(LocalFrame))
 | 
			
		||||
	{
 | 
			
		||||
 | 
			
		||||
		static const auto CVarResimApplyPredictiveInterpolationWhenBehindServer = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.Resim.ApplyPredictiveInterpolationWhenBehindServer"));
 | 
			
		||||
 | 
			
		||||
		if (LocalFrame < RewindData->GetEarliestFrame_Internal())
 | 
			
		||||
		{
 | 
			
		||||
			// Client is far ahead of the server, switch over to Predictive Interpolation since it can't use incoming target states from the server to perform resimulations with
 | 
			
		||||
 | 
			
		||||
			Target.RepMode = EPhysicsReplicationMode::PredictiveInterpolation;
 | 
			
		||||
		}
 | 
			
		||||
		else if (CVarResimApplyPredictiveInterpolationWhenBehindServer->GetBool())
 | 
			
		||||
		{
 | 
			
		||||
			/** NOTE: If the server is ahead of the client we receive target states for frames we have not yet simulated on the client, target states are stored in FRewindData still though.
 | 
			
		||||
			* If PhysicsReplicationCVars::ResimulationCVars::bApplyPredictiveInterpolationWhenBehindServer is true switch over to using PredictiveInterpolation temporarily.
 | 
			
		||||
			* else FRewindData::CompareTargetsToLastFrame will check for already cached targets to resim with when the server has simulated the corresponding frame */
 | 
			
		||||
 | 
			
		||||
			Target.RepMode = EPhysicsReplicationMode::PredictiveInterpolation;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		UE_LOG(LogPhysics, Warning, TEXT("FPhysicsReplication received target frame (%d) out of rewind data bounds (%d, %d) - %s - Target will use EPhysicsReplicationMode: %s"),
 | 
			
		||||
			LocalFrame, RewindData->GetEarliestFrame_Internal(), RewindData->CurrentFrame(), (LocalFrame < RewindData->GetEarliestFrame_Internal()) ? TEXT("Client is far ahead of the server, server might be dropping frames.") : TEXT("Client is behind the server, client might be dropping frames."), *UEnum::GetValueAsString(Target.RepMode));
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FPhysicsReplicationAsyncVR::ApplyPhysicsReplicationLOD(Chaos::FConstPhysicsObjectHandle PhysicsObjectHandle, FReplicatedPhysicsTargetAsync& Target, const uint32 LODFLags)
 | 
			
		||||
{
 | 
			
		||||
	Chaos::FPBDRigidsSolver& RigidsSolver = GetSolver()->CastChecked();
 | 
			
		||||
 | 
			
		||||
	IPhysicsReplicationLODAsync* PhysRepLod = RigidsSolver.GetPhysicsReplicationLOD_Internal();
 | 
			
		||||
	if (!PhysRepLod || !PhysRepLod->IsEnabled())
 | 
			
		||||
	{
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	FPhysicsRepLodData* LodData = PhysRepLod->GetLODData_Internal(PhysicsObjectHandle, LODFLags);
 | 
			
		||||
	if (LodData && LodData->DataAssigned)
 | 
			
		||||
	{
 | 
			
		||||
		// Apply recommended replication mode
 | 
			
		||||
		Target.RepMode = LodData->ReplicationMode;
 | 
			
		||||
 | 
			
		||||
		if (Target.RepMode == EPhysicsReplicationMode::PredictiveInterpolation)
 | 
			
		||||
		{
 | 
			
		||||
			const bool bShouldSleep = (Target.TargetState.Flags & ERigidBodyFlags::Sleeping) != 0;
 | 
			
		||||
			int32 TargetClientFrame = (Target.ServerFrame - Target.FrameOffset);
 | 
			
		||||
 | 
			
		||||
			// If we use Predicitve Interpolation and we should not sleep and the aligned frame from LOD is ahead of the target, perform LOD aligment extrapolation
 | 
			
		||||
			if (!bShouldSleep && LodData->AlignedFrame > TargetClientFrame)
 | 
			
		||||
			{
 | 
			
		||||
				// Calculate how far to forward predict and extrapolate target by that amount
 | 
			
		||||
				const int32 FullPredictionFrames = RigidsSolver.GetCurrentFrame() - TargetClientFrame;
 | 
			
		||||
				const float FullPredictionTime = (FullPredictionFrames * GetDeltaTime_Internal());
 | 
			
		||||
				const float AlignedPredictionTime = FullPredictionTime - LodData->AlignedTime;
 | 
			
		||||
				FPhysicsReplicationAsyncVR::ExtrapolateTarget(Target, AlignedPredictionTime);
 | 
			
		||||
 | 
			
		||||
				// Update tick count based on LOD alignment
 | 
			
		||||
				Target.TickCount = LodData->AlignedFrame - TargetClientFrame;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1775,11 +1944,6 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
 | 
			
		|||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (Target.IsWaiting())
 | 
			
		||||
	{
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Chaos::FPBDRigidsSolver* RigidsSolver = static_cast<Chaos::FPBDRigidsSolver*>(GetSolver());
 | 
			
		||||
	if (RigidsSolver == nullptr)
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			@ -1803,8 +1967,8 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
 | 
			
		|||
		const FVector Offset = FVector(0.0f, 0.0f, 50.0f);
 | 
			
		||||
		const FVector StartPos = Target.TargetState.Position + Offset;
 | 
			
		||||
		const int32 SizeMultiplier = FMath::Clamp(Target.TickCount, -4, 30);
 | 
			
		||||
		static const auto CVarNetCorrectionLifetime = IConsoleManager::Get().FindConsoleVariable(TEXT("p.NetCorrectionLifetime"));
 | 
			
		||||
		Chaos::FDebugDrawQueue::GetInstance().DrawDebugBox(StartPos, FVector(5.0f + SizeMultiplier * 0.75f, 5.0f + SizeMultiplier * 0.75f, 5.0f + SizeMultiplier * 0.75f), Target.TargetState.Quaternion, FColor::MakeRandomSeededColor(Target.ServerFrame), false, CVarNetCorrectionLifetime->GetFloat(), 0, 1.0f);
 | 
			
		||||
		static const auto CVarDebugdrawLifetime = IConsoleManager::Get().FindConsoleVariable(TEXT("p.Net.DebugDraw.LifeTime"));
 | 
			
		||||
		Chaos::FDebugDrawQueue::GetInstance().DrawDebugBox(StartPos, FVector(5.0f + SizeMultiplier * 0.75f, 5.0f + SizeMultiplier * 0.75f, 5.0f + SizeMultiplier * 0.75f), Target.TargetState.Quaternion, FColor::MakeRandomSeededColor(Target.ServerFrame), false, CVarDebugdrawLifetime->GetFloat(), 0, 1.0f);
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1864,6 +2028,11 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
 | 
			
		|||
		return bClearTarget;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	// If waiting on an up to date state, early out but allow target clearing since we might not receive a new state if target is already set to sleep for example
 | 
			
		||||
	if (Target.IsWaiting())
 | 
			
		||||
	{
 | 
			
		||||
		return EndReplicationHelper(Target, true);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static const auto CVarEarlyOutWithVelocity = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.EarlyOutWithVelocity"));
 | 
			
		||||
	static const auto CVarEarlyOutDistanceSqr = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.EarlyOutDistanceSqr"));
 | 
			
		||||
| 
						 | 
				
			
			@ -1909,8 +2078,41 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
 | 
			
		|||
	const FVector TargetLinVel = FVector(Target.TargetState.LinVel);
 | 
			
		||||
	const FVector TargetAngVel = FVector(FMath::DegreesToRadians(Target.TargetState.AngVel)); // Radians
 | 
			
		||||
 | 
			
		||||
	/** --- Reconciliation ---
 | 
			
		||||
	* If target velocities are low enough, check the traveled direction and distance from previous frame and compare with replicated linear velocity.
 | 
			
		||||
	/** --- Reconciliation --- */
 | 
			
		||||
	static const auto CVarKinematicHardSnap = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.KinematicHardSnap"));
 | 
			
		||||
	static const auto CVarErrorAccumulationSeconds = IConsoleManager::Get().FindConsoleVariable(TEXT("p.ErrorAccumulationSeconds"));
 | 
			
		||||
	static const auto CVarAlwaysHardSnap = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.AlwaysHardSnap"));
 | 
			
		||||
	const bool bHardSnap = (!bCanSimulate && CVarKinematicHardSnap->GetBool())
 | 
			
		||||
		|| Target.AccumulatedErrorSeconds > CVarErrorAccumulationSeconds->GetFloat()
 | 
			
		||||
		|| CVarAlwaysHardSnap->GetBool();
 | 
			
		||||
 | 
			
		||||
	if (bHardSnap)
 | 
			
		||||
	{
 | 
			
		||||
		Target.AccumulatedErrorSeconds = 0.0f;
 | 
			
		||||
 | 
			
		||||
		if (Handle->IsKinematic())
 | 
			
		||||
		{
 | 
			
		||||
			// Set a FKinematicTarget to hard snap kinematic object
 | 
			
		||||
			const Chaos::FKinematicTarget KinTarget = Chaos::FKinematicTarget::MakePositionTarget(Target.PrevPosTarget, Target.PrevRotTarget); // Uses EKinematicTargetMode::Position
 | 
			
		||||
			RigidsSolver->GetEvolution()->SetParticleKinematicTarget(Handle, KinTarget);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			// Set XRVW to hard snap dynamic object and force recalculation of friction
 | 
			
		||||
			const bool bCorrectConnectedBodies = SettingsCurrent.PredictiveInterpolationSettings.GetCorrectConnectedBodies();
 | 
			
		||||
			RigidsSolver->GetEvolution()->ApplyParticleTransformCorrection(Handle, Target.PrevPosTarget, Target.PrevRotTarget, bCorrectConnectedBodies, /*bInRecalculateFrictionOnConnectedBodies*/ true, ReplicatedParticleIDs);
 | 
			
		||||
			Handle->SetV(TargetLinVel);
 | 
			
		||||
			Handle->SetW(TargetAngVel);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Cache data for next replication
 | 
			
		||||
		Target.PrevLinVel = FVector(Target.TargetState.LinVel);
 | 
			
		||||
 | 
			
		||||
		// End replication and go to sleep if that's requested
 | 
			
		||||
		return EndReplicationHelper(Target, true);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** If target velocities are low enough, check the traveled direction and distance from previous frame and compare with replicated linear velocity.
 | 
			
		||||
	* If the object isn't moving enough along the replicated velocity it's considered stuck and needs reconciliation.
 | 
			
		||||
	* SoftSnap is performed each tick while there is a registered error, if enough time pass HardSnap forces the object into the correct state. */
 | 
			
		||||
	static const auto CVarVelocityBased = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.VelocityBased"));
 | 
			
		||||
| 
						 | 
				
			
			@ -1919,7 +2121,7 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
 | 
			
		|||
	static const auto CVarDisableErrorVelocityLimits = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.DisableErrorVelocityLimits"));
 | 
			
		||||
	static const auto CVarErrorAccLinVelMaxLimit = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.ErrorAccLinVelMaxLimit"));
 | 
			
		||||
	static const auto CVarErrorAccAngVelMaxLimit = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.ErrorAccAngVelMaxLimit"));
 | 
			
		||||
	if (CVarDisableErrorVelocityLimits->GetBool() ||
 | 
			
		||||
	if ( CVarDisableErrorVelocityLimits->GetBool() ||
 | 
			
		||||
		(TargetLinVel.Size() < CVarErrorAccLinVelMaxLimit->GetFloat() && TargetAngVel.Size() < CVarErrorAccAngVelMaxLimit->GetFloat()))
 | 
			
		||||
	{
 | 
			
		||||
		const FVector PrevDiff = CurrentState.Position - Target.PrevPos;
 | 
			
		||||
| 
						 | 
				
			
			@ -1952,43 +2154,8 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
 | 
			
		|||
	{
 | 
			
		||||
		bSoftSnap = false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static const auto CVarErrorAccumulationSeconds = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.ErrorAccumulationSeconds"));
 | 
			
		||||
	static const auto CVarAlwaysHardSnap = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.AlwaysHardSnap"));
 | 
			
		||||
	static const auto CVarKinematicHardSnap = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.KinematicHardSnap"));
 | 
			
		||||
 | 
			
		||||
	const bool bHardSnap = (!bCanSimulate && CVarKinematicHardSnap->GetBool())
 | 
			
		||||
		|| Target.AccumulatedErrorSeconds > CVarErrorAccumulationSeconds->GetFloat()
 | 
			
		||||
		|| CVarAlwaysHardSnap->GetBool();
 | 
			
		||||
 | 
			
		||||
	if (bHardSnap)
 | 
			
		||||
	{
 | 
			
		||||
		Target.AccumulatedErrorSeconds = 0.0f;
 | 
			
		||||
 | 
			
		||||
		if (Handle->IsKinematic())
 | 
			
		||||
		{
 | 
			
		||||
			// Set a FKinematicTarget to hard snap kinematic object
 | 
			
		||||
			const Chaos::FKinematicTarget KinTarget = Chaos::FKinematicTarget::MakePositionTarget(Target.PrevPosTarget, Target.PrevRotTarget); // Uses EKinematicTargetMode::Position
 | 
			
		||||
			RigidsSolver->GetEvolution()->SetParticleKinematicTarget(Handle, KinTarget);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			// Set XRVW to hard snap dynamic object and force recalculation of friction
 | 
			
		||||
			const bool bCorrectConnectedBodies = SettingsCurrent.PredictiveInterpolationSettings.GetCorrectConnectedBodies();
 | 
			
		||||
			RigidsSolver->GetEvolution()->ApplyParticleTransformCorrection(Handle, Target.PrevPosTarget, Target.PrevRotTarget, bCorrectConnectedBodies, /*bInRecalculateFrictionOnConnectedBodies*/ true, ReplicatedParticleIDs);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
			Handle->SetV(TargetLinVel);
 | 
			
		||||
			Handle->SetW(TargetAngVel);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Cache data for next replication
 | 
			
		||||
		Target.PrevLinVel = FVector(Target.TargetState.LinVel);
 | 
			
		||||
 | 
			
		||||
		// End replication and go to sleep if that's requested
 | 
			
		||||
		return EndReplicationHelper(Target, true);
 | 
			
		||||
	}
 | 
			
		||||
	else if (Handle->IsKinematic()) // Smooth Kinematic Replication
 | 
			
		||||
	
 | 
			
		||||
	if (Handle->IsKinematic()) // Smooth Kinematic Replication
 | 
			
		||||
	{
 | 
			
		||||
		static const auto CVarKinematicPrediction = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.KinematicPrediction"));
 | 
			
		||||
		const bool bKinematicPrediction = CVarKinematicPrediction->GetBool();
 | 
			
		||||
| 
						 | 
				
			
			@ -2035,8 +2202,8 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
 | 
			
		|||
				const FVector Offset = FVector(0.0f, 0.0f, CVarDrawDebugZOffset->GetFloat());
 | 
			
		||||
				const FVector Pos = KinTargetPos + Offset;
 | 
			
		||||
				const int32 SizeMultiplier = FMath::Clamp(Target.TickCount, -4, 30);
 | 
			
		||||
				static const auto CVarNetCorrectionLifetime = IConsoleManager::Get().FindConsoleVariable(TEXT("p.NetCorrectionLifetime"));
 | 
			
		||||
				Chaos::FDebugDrawQueue::GetInstance().DrawDebugSphere(Pos, 3.0f + SizeMultiplier * 0.75f, 8, FColor::MakeRandomSeededColor(Target.ServerFrame), false, CVarNetCorrectionLifetime->GetFloat(), 0, 1.0f);
 | 
			
		||||
				static const auto CVarDebugdrawLifetime = IConsoleManager::Get().FindConsoleVariable(TEXT("p.Net.DebugDraw.LifeTime"));
 | 
			
		||||
				Chaos::FDebugDrawQueue::GetInstance().DrawDebugSphere(Pos, 3.0f + SizeMultiplier * 0.75f, 8, FColor::MakeRandomSeededColor(Target.ServerFrame), false, CVarDebugdrawLifetime->GetFloat(), 0, 1.0f);
 | 
			
		||||
			}
 | 
			
		||||
#endif
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -2214,7 +2381,12 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
 | 
			
		|||
void FPhysicsReplicationAsyncVR::ExtrapolateTarget(FReplicatedPhysicsTargetAsync& Target, const int32 ExtrapolateFrames, const float DeltaSeconds)
 | 
			
		||||
{
 | 
			
		||||
	const float ExtrapolationTime = DeltaSeconds * static_cast<float>(ExtrapolateFrames);
 | 
			
		||||
	FPhysicsReplicationAsyncVR::ExtrapolateTarget(Target, ExtrapolationTime);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Static function to extrapolate a target for N Seconds */
 | 
			
		||||
void FPhysicsReplicationAsyncVR::ExtrapolateTarget(FReplicatedPhysicsTargetAsync& Target, const float ExtrapolationTime)
 | 
			
		||||
{
 | 
			
		||||
	// Extrapolate target position
 | 
			
		||||
	Target.TargetState.Position = Target.TargetState.Position + Target.TargetState.LinVel * ExtrapolationTime;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2242,15 +2414,15 @@ bool FPhysicsReplicationAsyncVR::ResimulationReplication(Chaos::FPBDRigidParticl
 | 
			
		|||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (Target.ServerFrame <= 0)
 | 
			
		||||
	{
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const int32 LocalFrame = Target.ServerFrame - Target.FrameOffset;
 | 
			
		||||
 | 
			
		||||
	if (LocalFrame >= RewindData->CurrentFrame() || LocalFrame < RewindData->GetEarliestFrame_Internal())
 | 
			
		||||
	if (!RewindData->IsFrameWithinRewindHistory(LocalFrame))
 | 
			
		||||
	{
 | 
			
		||||
		if (LocalFrame > 0 && (RewindData->CurrentFrame() - RewindData->GetEarliestFrame_Internal()) == RewindData->Capacity())
 | 
			
		||||
		{
 | 
			
		||||
			UE_LOG(LogPhysics, Warning, TEXT("FPhysicsReplication::ResimulationReplication target frame (%d) out of rewind data bounds (%d,%d)"),
 | 
			
		||||
				LocalFrame, RewindData->GetEarliestFrame_Internal(), RewindData->CurrentFrame());
 | 
			
		||||
		}
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2269,11 +2441,24 @@ bool FPhysicsReplicationAsyncVR::ResimulationReplication(Chaos::FPBDRigidParticl
 | 
			
		|||
	const bool bCompareW = Chaos::FPhysicsSolverBase::GetResimulationErrorAngularVelocityThresholdEnabled() || SettingsCurrent.ResimulationSettings.bOverrideResimulationErrorAngularVelocityThreshold;
 | 
			
		||||
	bool bShouldTriggerResim = false;
 | 
			
		||||
 | 
			
		||||
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
 | 
			
		||||
	// Debugging
 | 
			
		||||
	FColor DebugColor = FColor::Black;
 | 
			
		||||
	bool bResimV = false;
 | 
			
		||||
	bool bResimW = false;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	// Check for positional discrepancy in Distance between client and server
 | 
			
		||||
	if (bCompareX)
 | 
			
		||||
	{
 | 
			
		||||
		const float ResimPositionErrorThreshold = SettingsCurrent.ResimulationSettings.GetResimulationErrorPositionThreshold(Chaos::FPhysicsSolverBase::GetResimulationErrorPositionThreshold());
 | 
			
		||||
		bShouldTriggerResim = Chaos::FRewindData::CheckVectorThreshold(Target.TargetState.Position, PastState.GetX(), ResimPositionErrorThreshold);
 | 
			
		||||
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
 | 
			
		||||
		if (bShouldTriggerResim)
 | 
			
		||||
		{
 | 
			
		||||
			DebugColor = FColor::Orange;
 | 
			
		||||
		}
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Check for linear velocity discrepancy in Distance / s between client and server
 | 
			
		||||
| 
						 | 
				
			
			@ -2281,13 +2466,25 @@ bool FPhysicsReplicationAsyncVR::ResimulationReplication(Chaos::FPBDRigidParticl
 | 
			
		|||
	{
 | 
			
		||||
		const float ResimLinVelocityErrorThreshold = SettingsCurrent.ResimulationSettings.GetResimulationErrorLinearVelocityThreshold(Chaos::FPhysicsSolverBase::GetResimulationErrorLinearVelocityThreshold());
 | 
			
		||||
		bShouldTriggerResim = Chaos::FRewindData::CheckVectorThreshold(Target.TargetState.LinVel, PastState.GetV(), ResimLinVelocityErrorThreshold);
 | 
			
		||||
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
 | 
			
		||||
		if (bShouldTriggerResim)
 | 
			
		||||
		{
 | 
			
		||||
			bResimV = true;
 | 
			
		||||
		}
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Check for angular velocity discrepancy in Degrees / s between client and server
 | 
			
		||||
	if (!bShouldTriggerResim && bCompareW)
 | 
			
		||||
	{
 | 
			
		||||
		const float ResimAngVelocityErrorThreshold = SettingsCurrent.ResimulationSettings.GetResimulationErrorAngularVelocityThreshold(Chaos::FPhysicsSolverBase::GetResimulationErrorAngularVelocityThreshold());
 | 
			
		||||
		bShouldTriggerResim = Chaos::FRewindData::CheckVectorThreshold(FMath::DegreesToRadians(Target.TargetState.AngVel), PastState.GetW(), ResimAngVelocityErrorThreshold);
 | 
			
		||||
		bShouldTriggerResim = Chaos::FRewindData::CheckVectorThreshold(Target.TargetState.AngVel, FMath::RadiansToDegrees(PastState.GetW()), ResimAngVelocityErrorThreshold);
 | 
			
		||||
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
 | 
			
		||||
		if (bShouldTriggerResim)
 | 
			
		||||
		{
 | 
			
		||||
			bResimW = true;
 | 
			
		||||
		}
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Check for rotational discrepancy in Degrees between client and server
 | 
			
		||||
| 
						 | 
				
			
			@ -2295,6 +2492,12 @@ bool FPhysicsReplicationAsyncVR::ResimulationReplication(Chaos::FPBDRigidParticl
 | 
			
		|||
	{
 | 
			
		||||
		const float ResimRotationErrorThreshold = SettingsCurrent.ResimulationSettings.GetResimulationErrorRotationThreshold(Chaos::FPhysicsSolverBase::GetResimulationErrorRotationThreshold());
 | 
			
		||||
		bShouldTriggerResim = Chaos::FRewindData::CheckQuaternionThreshold(Target.TargetState.Quaternion, PastState.GetR(), ResimRotationErrorThreshold);
 | 
			
		||||
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
 | 
			
		||||
		if (bShouldTriggerResim)
 | 
			
		||||
		{
 | 
			
		||||
			DebugColor = FColor::Magenta;
 | 
			
		||||
		}
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2311,16 +2514,51 @@ bool FPhysicsReplicationAsyncVR::ResimulationReplication(Chaos::FPBDRigidParticl
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	static const auto CVarResimDrawDebug = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.Resim.DrawDebug"));
 | 
			
		||||
	if (CVarResimDrawDebug->GetBool())
 | 
			
		||||
	static const auto CVarRenderInterpDebugDrawResimTrigger = IConsoleManager::Get().FindConsoleVariable(TEXT("p.RenderInterp.DebugDraw.ResimTrigger"));
 | 
			
		||||
	if (CVarResimDrawDebug->GetBool() || CVarRenderInterpDebugDrawResimTrigger->GetBool())
 | 
			
		||||
	{
 | 
			
		||||
		static constexpr float BoxSize = 5.0f;
 | 
			
		||||
		const float ColorLerp = bShouldTriggerResim ? 1.0f : 0.0f;
 | 
			
		||||
		const FColor DebugColor = FLinearColor::LerpUsingHSV(FLinearColor::Green, FLinearColor::Red, ColorLerp).ToFColor(false);
 | 
			
		||||
		if (bShouldTriggerResim)
 | 
			
		||||
		{
 | 
			
		||||
			FVector Box = CVarRenderInterpDebugDrawResimTrigger->GetBool() ? FVector(6, 3, 2) : FVector(40, 20, 10);
 | 
			
		||||
			const float DrawThickness = CVarRenderInterpDebugDrawResimTrigger->GetBool() ? 0.5f : 1.5f;
 | 
			
		||||
 | 
			
		||||
		static const auto CVarNetCorrectionLifetime = IConsoleManager::Get().FindConsoleVariable(TEXT("p.NetCorrectionLifetime"));
 | 
			
		||||
		Chaos::FDebugDrawQueue::GetInstance().DrawDebugBox(Target.TargetState.Position, FVector(BoxSize, BoxSize, BoxSize), Target.TargetState.Quaternion, FColor::Orange, true, CVarNetCorrectionLifetime->GetFloat(), 0, 1.0f);
 | 
			
		||||
		Chaos::FDebugDrawQueue::GetInstance().DrawDebugBox(PastState.GetX(), FVector(6, 6, 6), PastState.GetR(), DebugColor, true, CVarNetCorrectionLifetime->GetFloat(), 0, 1.0f);
 | 
			
		||||
		Chaos::FDebugDrawQueue::GetInstance().DrawDebugDirectionalArrow(PastState.GetX(), Target.TargetState.Position, 5.0f, FColor::MakeRandomSeededColor(LocalFrame), true, CVarNetCorrectionLifetime->GetFloat(), 0, 0.5f);
 | 
			
		||||
			static const auto CVarDebugdrawLifetime = IConsoleManager::Get().FindConsoleVariable(TEXT("p.Net.DebugDraw.LifeTime"));
 | 
			
		||||
			if (CVarRenderInterpDebugDrawResimTrigger->GetBool()) // Resim debug draw extension for render interpolation 
 | 
			
		||||
			{
 | 
			
		||||
				Chaos::FDebugDrawQueue::GetInstance().DrawDebugBox(PastState.GetX(), Box, PastState.GetR(), FColor::White, false, CVarDebugdrawLifetime->GetFloat(), 0, DrawThickness);
 | 
			
		||||
				Chaos::FDebugDrawQueue::GetInstance().DrawDebugBox(Target.TargetState.Position, Box, Target.TargetState.Quaternion, DebugColor, false, CVarDebugdrawLifetime->GetFloat(), 0, DrawThickness);
 | 
			
		||||
 | 
			
		||||
				Chaos::FDebugDrawQueue::GetInstance().DrawDebugDirectionalArrow(Handle->GetX(), PastState.GetX(), 5.0f, FColor::White, false, CVarDebugdrawLifetime->GetFloat(), 0, DrawThickness);
 | 
			
		||||
				Chaos::FDebugDrawQueue::GetInstance().DrawDebugDirectionalArrow(PastState.GetX(), Target.TargetState.Position, 5.0f, FColor::Black, false, CVarDebugdrawLifetime->GetFloat(), 0, DrawThickness);
 | 
			
		||||
 | 
			
		||||
				if (bResimV)
 | 
			
		||||
				{
 | 
			
		||||
					const FVector DiffV = Target.TargetState.LinVel - PastState.GetV();
 | 
			
		||||
					Chaos::FDebugDrawQueue::GetInstance().DrawDebugDirectionalArrow(Target.TargetState.Position, Target.TargetState.Position + DiffV, 5.0f, FColor::Orange, false, CVarDebugdrawLifetime->GetFloat(), 0, DrawThickness);
 | 
			
		||||
				}
 | 
			
		||||
				if (bResimW)
 | 
			
		||||
				{
 | 
			
		||||
					const FVector DiffW = Target.TargetState.AngVel - FMath::RadiansToDegrees(PastState.GetW());
 | 
			
		||||
					Chaos::FDebugDrawQueue::GetInstance().DrawDebugDirectionalArrow(Target.TargetState.Position + DiffW, Target.TargetState.Position, 5.0f, FColor::Magenta, false, CVarDebugdrawLifetime->GetFloat(), 0, DrawThickness);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			else // Resim trigger debug draw
 | 
			
		||||
			{
 | 
			
		||||
				Chaos::FDebugDrawQueue::GetInstance().DrawDebugBox(Handle->GetX(), Box, PastState.GetR(), FColor::White, false, CVarDebugdrawLifetime->GetFloat(), 0, DrawThickness);
 | 
			
		||||
				Chaos::FDebugDrawQueue::GetInstance().DrawDebugBox(Handle->GetX() + (Target.TargetState.Position - PastState.GetX()), Box, Target.TargetState.Quaternion, DebugColor, false, CVarDebugdrawLifetime->GetFloat(), 0, DrawThickness);
 | 
			
		||||
 | 
			
		||||
				if (bResimV)
 | 
			
		||||
				{
 | 
			
		||||
					const FVector DiffV = Target.TargetState.LinVel - PastState.GetV();
 | 
			
		||||
					Chaos::FDebugDrawQueue::GetInstance().DrawDebugDirectionalArrow(Handle->GetX(), Handle->GetX() + DiffV, 5.0f, FColor::Orange, false, CVarDebugdrawLifetime->GetFloat(), 0, DrawThickness);
 | 
			
		||||
				}
 | 
			
		||||
				if (bResimW)
 | 
			
		||||
				{
 | 
			
		||||
					const FVector DiffW = Target.TargetState.AngVel - FMath::RadiansToDegrees(PastState.GetW());
 | 
			
		||||
					Chaos::FDebugDrawQueue::GetInstance().DrawDebugDirectionalArrow(Handle->GetX() + DiffW, Handle->GetX(), 5.0f, FColor::Magenta, false, CVarDebugdrawLifetime->GetFloat(), 0, DrawThickness);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2332,12 +2570,8 @@ bool FPhysicsReplicationAsyncVR::ResimulationReplication(Chaos::FPBDRigidParticl
 | 
			
		|||
 | 
			
		||||
	if (bShouldTriggerResim && Target.TickCount == 0 && LocalFrame > RewindData->GetBlockedResimFrame())
 | 
			
		||||
	{
 | 
			
		||||
		// Trigger resimulation
 | 
			
		||||
		RigidsSolver->GetEvolution()->GetIslandManager().SetParticleResimFrame(Handle, LocalFrame);
 | 
			
		||||
 | 
			
		||||
		int32 ResimFrame = RewindData->GetResimFrame();
 | 
			
		||||
		ResimFrame = (ResimFrame == INDEX_NONE) ? LocalFrame : FMath::Min(ResimFrame, LocalFrame);
 | 
			
		||||
		RewindData->SetResimFrame(ResimFrame);
 | 
			
		||||
		// Request resimulation
 | 
			
		||||
		RewindData->RequestResimulation(LocalFrame, Handle);
 | 
			
		||||
	}
 | 
			
		||||
	else if (SettingsCurrent.ResimulationSettings.GetRuntimeCorrectionEnabled())
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			@ -2381,8 +2615,8 @@ bool FPhysicsReplicationAsyncVR::ResimulationReplication(Chaos::FPBDRigidParticl
 | 
			
		|||
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
 | 
			
		||||
				if (CVarResimDrawDebug->GetBool())
 | 
			
		||||
				{
 | 
			
		||||
					static const auto CVarNetCorrectionLifetime = IConsoleManager::Get().FindConsoleVariable(TEXT("p.NetCorrectionLifetime"));
 | 
			
		||||
					Chaos::FDebugDrawQueue::GetInstance().DrawDebugDirectionalArrow(Handle->GetX(), CorrectedX, 5.0f, FColor::MakeRandomSeededColor(LocalFrame), true, CVarNetCorrectionLifetime->GetFloat(), 0, 0.5f);
 | 
			
		||||
					static const auto CVarDebugdrawLifetime = IConsoleManager::Get().FindConsoleVariable(TEXT("p.Net.DebugDraw.LifeTime"));
 | 
			
		||||
					Chaos::FDebugDrawQueue::GetInstance().DrawDebugDirectionalArrow(Handle->GetX(), CorrectedX, 5.0f, FColor::MakeRandomSeededColor(LocalFrame), true, CVarDebugdrawLifetime->GetFloat(), 0, 0.5f);
 | 
			
		||||
				}
 | 
			
		||||
#endif
 | 
			
		||||
				// Apply correction to position and rotation
 | 
			
		||||
| 
						 | 
				
			
			@ -2406,14 +2640,90 @@ bool FPhysicsReplicationAsyncVR::ResimulationReplication(Chaos::FPBDRigidParticl
 | 
			
		|||
			RigidsSolver->GetEvolution()->ApplySleepOnConnectedParticles(Handle);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else if (Target.IsWaiting())
 | 
			
		||||
	{
 | 
			
		||||
		// Don't clear the target if we are waiting for a specific target frame and not sleeping
 | 
			
		||||
		bClearTarget = false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	return bClearTarget;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FPhysicsReplicationAsyncVR::DebugDrawReplicationMode(const FPhysicsRepAsyncInputData& Input)
 | 
			
		||||
{
 | 
			
		||||
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
 | 
			
		||||
 | 
			
		||||
	static const auto CVarDebugDrawShowRepMode = IConsoleManager::Get().FindConsoleVariable(TEXT("p.Net.DebugDraw.ShowRepMode"));
 | 
			
		||||
	if (!CVarDebugDrawShowRepMode->GetBool())
 | 
			
		||||
	{
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (Input.PhysicsObject == nullptr && Input.Proxy == nullptr)
 | 
			
		||||
	{
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	FColor DebugColor = FColor::White;
 | 
			
		||||
	FVector BoxExtent = FVector(10.0f, 10.0f, 10.0f);
 | 
			
		||||
	FQuat Rotation = FQuat::Identity;
 | 
			
		||||
 | 
			
		||||
	if (Input.PhysicsObject)
 | 
			
		||||
	{
 | 
			
		||||
		if (FReplicatedPhysicsTargetAsync* Target = ObjectToTarget.Find(Input.PhysicsObject))
 | 
			
		||||
		{
 | 
			
		||||
			Chaos::FReadPhysicsObjectInterface_Internal Interface = Chaos::FPhysicsObjectInternalInterface::GetRead();
 | 
			
		||||
			if (Chaos::FGeometryParticleHandle* Handle = Interface.GetParticle(Input.PhysicsObject))
 | 
			
		||||
			{
 | 
			
		||||
				BoxExtent = Handle->LocalBounds().Extents() * 0.5f;
 | 
			
		||||
				Rotation = Handle->GetR();
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			const EPhysicsReplicationMode RepMode = Target->IsWaiting() ? Target->RepModeOverride : Target->RepMode;
 | 
			
		||||
			switch (RepMode)
 | 
			
		||||
			{
 | 
			
		||||
			case EPhysicsReplicationMode::PredictiveInterpolation:
 | 
			
		||||
				DebugColor = FColor::Yellow;
 | 
			
		||||
				break;
 | 
			
		||||
			case EPhysicsReplicationMode::Resimulation:
 | 
			
		||||
				DebugColor = FColor::Red;
 | 
			
		||||
				break;
 | 
			
		||||
			case EPhysicsReplicationMode::Default:
 | 
			
		||||
			default:
 | 
			
		||||
				DebugColor = FColor::Cyan;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else if (Input.Proxy != nullptr)
 | 
			
		||||
	{
 | 
			
		||||
		// Legacy Default physics replication
 | 
			
		||||
 | 
			
		||||
		Chaos::FSingleParticlePhysicsProxy* Proxy = Input.Proxy;
 | 
			
		||||
		Chaos::FRigidBodyHandle_Internal* Handle = Proxy->GetPhysicsThreadAPI();
 | 
			
		||||
 | 
			
		||||
		Rotation = Handle->GetR();
 | 
			
		||||
		DebugColor = FColor::Green;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static const auto CVarDebugdrawLifetime = IConsoleManager::Get().FindConsoleVariable(TEXT("p.Net.DebugDraw.LifeTime"));
 | 
			
		||||
	Chaos::FDebugDrawQueue::GetInstance().DrawDebugBox(Input.TargetState.Position, BoxExtent, Rotation, DebugColor, false, CVarDebugdrawLifetime->GetFloat(), 0, 1.0f);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FName FPhysicsReplicationAsyncVR::GetFNameForStatId() const
 | 
			
		||||
{
 | 
			
		||||
	const static FLazyName StaticName("FPhysicsReplicationAsyncCallback");
 | 
			
		||||
	return StaticName;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool FPhysicsReplicationAsyncVR::UsePhysicsReplicationLOD()
 | 
			
		||||
{
 | 
			
		||||
	Chaos::FPBDRigidsSolver& RigidsSolver = GetSolver()->CastChecked();
 | 
			
		||||
 | 
			
		||||
	IPhysicsReplicationLODAsync* PhysRepLod = RigidsSolver.GetPhysicsReplicationLOD_Internal();
 | 
			
		||||
	return PhysRepLod && PhysRepLod->IsEnabled();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#pragma endregion // FPhysicsReplicationAsync
 | 
			
		||||
| 
						 | 
				
			
			@ -725,11 +725,11 @@ void AGrippableStaticMeshActor::OnRep_ReplicatedMovement()
 | 
			
		|||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (VRGripInterfaceSettings.HoldingControllers.Num() > 0)
 | 
			
		||||
	/*if (VRGripInterfaceSettings.HoldingControllers.Num() > 0)
 | 
			
		||||
	{
 | 
			
		||||
		ShouldWeSkipAttachmentReplication();
 | 
			
		||||
		int gg = 0;
 | 
			
		||||
	}
 | 
			
		||||
	}*/
 | 
			
		||||
 | 
			
		||||
	Super::OnRep_ReplicatedMovement();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -206,7 +206,8 @@ bool UHandSocketComponent::GetAnimationSequenceAsPoseSnapShot(UAnimSequence* InA
 | 
			
		|||
		const FReferenceSkeleton& RefSkeleton = (TargetMesh) ? TargetMesh->GetSkinnedAsset()->GetRefSkeleton() : InAnimationSequence->GetSkeleton()->GetReferenceSkeleton();
 | 
			
		||||
		FTransform LocalTransform;
 | 
			
		||||
 | 
			
		||||
		const TArray<FTrackToSkeletonMap>& TrackMap = InAnimationSequence->GetCompressedTrackToSkeletonMapTable();
 | 
			
		||||
		//const TArray<FTrackToSkeletonMap>& TrackMap = InAnimationSequence->GetCompressedTrackToSkeletonMapTable();
 | 
			
		||||
		const TArray<FTrackToSkeletonMap>& TrackMap = InAnimationSequence->GetCompressedData().Get().CompressedTrackToSkeletonMapTable;
 | 
			
		||||
		int32 TrackIndex = INDEX_NONE;
 | 
			
		||||
 | 
			
		||||
		OutPoseSnapShot.LocalTransforms.Reserve(OutPoseSnapShot.BoneNames.Num());
 | 
			
		||||
| 
						 | 
				
			
			@ -237,8 +238,9 @@ bool UHandSocketComponent::GetAnimationSequenceAsPoseSnapShot(UAnimSequence* InA
 | 
			
		|||
 | 
			
		||||
			if (TrackIndex != INDEX_NONE && (!bSkipRootBone || TrackIndex != 0))
 | 
			
		||||
			{
 | 
			
		||||
				double TrackLocation = 0.0f;			
 | 
			
		||||
				InAnimationSequence->GetBoneTransform(LocalTransform, FSkeletonPoseBoneIndex(TrackMap[TrackIndex].BoneTreeIndex), TrackLocation, false);
 | 
			
		||||
				//double TrackLocation = 0.0f;
 | 
			
		||||
				// FAnimExtraContext default is fine, its a zero track location
 | 
			
		||||
				InAnimationSequence->GetBoneTransform(LocalTransform, FSkeletonPoseBoneIndex(TrackMap[TrackIndex].BoneTreeIndex), FAnimExtractContext(), false);
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
| 
						 | 
				
			
			@ -317,7 +319,7 @@ bool UHandSocketComponent::GetBlendedPoseSnapShot(FPoseSnapshot& PoseSnapShot, U
 | 
			
		|||
		const FReferenceSkeleton& RefSkeleton = (TargetMesh) ? TargetMesh->GetSkinnedAsset()->GetRefSkeleton() : HandTargetAnimation->GetSkeleton()->GetReferenceSkeleton();
 | 
			
		||||
		FTransform LocalTransform;
 | 
			
		||||
 | 
			
		||||
		const TArray<FTrackToSkeletonMap>& TrackMap = HandTargetAnimation->GetCompressedTrackToSkeletonMapTable();
 | 
			
		||||
		const TArray<FTrackToSkeletonMap>& TrackMap = HandTargetAnimation->GetCompressedData().Get().CompressedTrackToSkeletonMapTable;
 | 
			
		||||
		int32 TrackIndex = INDEX_NONE;
 | 
			
		||||
 | 
			
		||||
		for (int32 BoneNameIndex = 0; BoneNameIndex < PoseSnapShot.BoneNames.Num(); ++BoneNameIndex)
 | 
			
		||||
| 
						 | 
				
			
			@ -345,8 +347,9 @@ bool UHandSocketComponent::GetBlendedPoseSnapShot(FPoseSnapshot& PoseSnapShot, U
 | 
			
		|||
 | 
			
		||||
			if (TrackIndex != INDEX_NONE && (!bSkipRootBone || TrackIndex != 0))
 | 
			
		||||
			{
 | 
			
		||||
				double TrackLocation = 0.0f;
 | 
			
		||||
				HandTargetAnimation->GetBoneTransform(LocalTransform, FSkeletonPoseBoneIndex(TrackMap[TrackIndex].BoneTreeIndex), TrackLocation, false);
 | 
			
		||||
				//double TrackLocation = 0.0f;
 | 
			
		||||
				// FAnimExtraContext default is fine, its a zero track location
 | 
			
		||||
				HandTargetAnimation->GetBoneTransform(LocalTransform, FSkeletonPoseBoneIndex(TrackMap[TrackIndex].BoneTreeIndex), FAnimExtractContext(), false);
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
| 
						 | 
				
			
			@ -609,7 +612,7 @@ FTransform UHandSocketComponent::GetBoneTransformAtTime(UAnimSequence* MyAnimSeq
 | 
			
		|||
 | 
			
		||||
	if (const IAnimationDataModel* AnimModel = AnimController.GetModel())
 | 
			
		||||
	{
 | 
			
		||||
		const TArray<FTrackToSkeletonMap>& TrackMap = MyAnimSequence->GetCompressedTrackToSkeletonMapTable();
 | 
			
		||||
		const TArray<FTrackToSkeletonMap>& TrackMap = MyAnimSequence->GetCompressedData().Get().CompressedTrackToSkeletonMapTable;
 | 
			
		||||
 | 
			
		||||
		int32 TrackIndex = INDEX_NONE;
 | 
			
		||||
		if (BoneIdx != INDEX_NONE && BoneIdx < TrackMap.Num() && TrackMap[BoneIdx].BoneTreeIndex == BoneIdx)
 | 
			
		||||
| 
						 | 
				
			
			@ -635,7 +638,9 @@ FTransform UHandSocketComponent::GetBoneTransformAtTime(UAnimSequence* MyAnimSeq
 | 
			
		|||
			FSkeletonPoseBoneIndex BoneIndex(TrackMap[TrackIndex].BoneTreeIndex);
 | 
			
		||||
			if (BoneIndex.IsValid())
 | 
			
		||||
			{
 | 
			
		||||
				MyAnimSequence->GetBoneTransform(BoneTransform, BoneIndex, /*AnimTime*/ tracklen, bUseRawDataOnly);
 | 
			
		||||
				FAnimExtractContext NewContext;
 | 
			
		||||
				NewContext.CurrentTime = tracklen;
 | 
			
		||||
				MyAnimSequence->GetBoneTransform(BoneTransform, BoneIndex, /*AnimTime*/ NewContext, bUseRawDataOnly);
 | 
			
		||||
				return BoneTransform;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -561,6 +561,7 @@ void UInversePhysicsSkeletalMeshComponent::RegisterEndPhysicsTick(bool bRegister
 | 
			
		|||
	// For testing if the engine fix is live yet or not
 | 
			
		||||
	//return Super::RegisterEndPhysicsTick(bRegister);
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	if (bRegister != EndPhysicsTickFunctionVR.IsTickFunctionRegistered())
 | 
			
		||||
	{
 | 
			
		||||
		if (bRegister)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1117,7 +1117,7 @@ void UAISense_Sight_VR::RemoveAllQueriesByListener(const FPerceptionListener& Li
 | 
			
		|||
	SCOPE_CYCLE_COUNTER(STAT_AI_Sense_Sight_RemoveByListener);
 | 
			
		||||
	UE_MT_SCOPED_WRITE_ACCESS(QueriesListAccessDetector);
 | 
			
		||||
 | 
			
		||||
	const uint32 ListenerId = Listener.GetListenerID();
 | 
			
		||||
	const FPerceptionListenerID ListenerId = Listener.GetListenerID();
 | 
			
		||||
 | 
			
		||||
	auto RemoveQuery = [&ListenerId, &OnRemoveFunc](TArray<FAISightQueryVR>& SightQueries, const int32 QueryIndex)->EReverseForEachResult
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			@ -1185,7 +1185,7 @@ void UAISense_Sight_VR::RemoveAllQueriesToTarget_Internal(const FAISightTargetVR
 | 
			
		|||
 | 
			
		||||
void UAISense_Sight_VR::OnListenerForgetsActor(const FPerceptionListener& Listener, AActor& ActorToForget)
 | 
			
		||||
{
 | 
			
		||||
	const uint32 ListenerId = Listener.GetListenerID();
 | 
			
		||||
	const FPerceptionListenerID ListenerId = Listener.GetListenerID();
 | 
			
		||||
	const uint32 TargetId = ActorToForget.GetUniqueID();
 | 
			
		||||
 | 
			
		||||
	auto ForgetPreviousResult = [&ListenerId, &TargetId](FAISightQueryVR& SightQuery)->EForEachResult
 | 
			
		||||
| 
						 | 
				
			
			@ -1212,7 +1212,7 @@ void UAISense_Sight_VR::OnListenerForgetsAll(const FPerceptionListener& Listener
 | 
			
		|||
{
 | 
			
		||||
	UE_MT_SCOPED_WRITE_ACCESS(QueriesListAccessDetector);
 | 
			
		||||
 | 
			
		||||
	const uint32 ListenerId = Listener.GetListenerID();
 | 
			
		||||
	const FPerceptionListenerID ListenerId = Listener.GetListenerID();
 | 
			
		||||
 | 
			
		||||
	auto ForgetPreviousResult = [&ListenerId](FAISightQueryVR& SightQuery)->EForEachResult
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -103,7 +103,7 @@ bool UVRGameViewportClient::InputKey(const FInputKeyEventArgs& EventArgs)
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool UVRGameViewportClient::InputAxis(FViewport* tViewport, FInputDeviceId InputDevice, FKey Key, float Delta, float DeltaTime, int32 NumSamples, bool bGamepad)
 | 
			
		||||
bool UVRGameViewportClient::InputAxis(const FInputKeyEventArgs& Args)
 | 
			
		||||
{		
 | 
			
		||||
	// Remap the old int32 ControllerId value to the new InputDeviceId
 | 
			
		||||
	IPlatformInputDeviceMapper& DeviceMapper = IPlatformInputDeviceMapper::Get();
 | 
			
		||||
| 
						 | 
				
			
			@ -111,8 +111,8 @@ bool UVRGameViewportClient::InputAxis(FViewport* tViewport, FInputDeviceId Input
 | 
			
		|||
	const int32 NumLocalPlayers = World->GetGameInstance()->GetNumLocalPlayers();
 | 
			
		||||
 | 
			
		||||
	// Early out if a gamepad or not a mouse event (vr controller) or ignoring input or is default setup / no GEngine
 | 
			
		||||
	if (((!Key.IsMouseButton() && !bGamepad) || (bGamepad && !IsValidGamePadKey(Key))) || NumLocalPlayers < 2 || GameInputMethod == EVRGameInputMethod::GameInput_Default || IgnoreInput())
 | 
			
		||||
		return Super::InputAxis(tViewport, InputDevice, Key, Delta, DeltaTime, NumSamples, bGamepad);
 | 
			
		||||
	if (((!Args.Key.IsMouseButton() && !Args.IsGamepad()) || (Args.IsGamepad() && !IsValidGamePadKey(Args.Key))) || NumLocalPlayers < 2 || GameInputMethod == EVRGameInputMethod::GameInput_Default || IgnoreInput())
 | 
			
		||||
		return Super::InputAxis(Args);
 | 
			
		||||
 | 
			
		||||
	if (GameInputMethod == EVRGameInputMethod::GameInput_KeyboardAndMouseToPlayer2)
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			@ -123,7 +123,9 @@ bool UVRGameViewportClient::InputAxis(FViewport* tViewport, FInputDeviceId Input
 | 
			
		|||
		FInputDeviceId DeviceId = INPUTDEVICEID_NONE;
 | 
			
		||||
		DeviceMapper.RemapControllerIdToPlatformUserAndDevice(ControllerId, UserId, DeviceId);
 | 
			
		||||
 | 
			
		||||
		return Super::InputAxis(tViewport, DeviceId, Key, Delta, DeltaTime, NumSamples, bGamepad);
 | 
			
		||||
		FInputKeyEventArgs NewArgs = Args;
 | 
			
		||||
		NewArgs.InputDevice = DeviceId;
 | 
			
		||||
		return Super::InputAxis(NewArgs);
 | 
			
		||||
	}
 | 
			
		||||
	else // Shared keyboard and mouse
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			@ -134,7 +136,9 @@ bool UVRGameViewportClient::InputAxis(FViewport* tViewport, FInputDeviceId Input
 | 
			
		|||
			FInputDeviceId DeviceId = INPUTDEVICEID_NONE;
 | 
			
		||||
			DeviceMapper.RemapControllerIdToPlatformUserAndDevice(i, UserId, DeviceId);
 | 
			
		||||
 | 
			
		||||
			bRetVal = Super::InputAxis(tViewport, DeviceId, Key, Delta, DeltaTime, NumSamples, bGamepad) || bRetVal;
 | 
			
		||||
			FInputKeyEventArgs NewArgs = Args;
 | 
			
		||||
			NewArgs.InputDevice = DeviceId;
 | 
			
		||||
			bRetVal = Super::InputAxis(NewArgs) || bRetVal;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return bRetVal;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -449,7 +449,7 @@ void ARenderTargetReplicationProxy::SendInitMessage()
 | 
			
		|||
 | 
			
		||||
void ARenderTargetReplicationProxy::SendNextDataBlob()
 | 
			
		||||
{
 | 
			
		||||
	if (!IsValid(this) || !this->GetOwner() || !IsValid(this->GetOwner()))
 | 
			
		||||
	if (!IsValidChecked(this) || !this->GetOwner() || !IsValid(this->GetOwner()))
 | 
			
		||||
	{	
 | 
			
		||||
		TextureStore.Reset();
 | 
			
		||||
		TextureStore.PackedData.Empty();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -210,7 +210,7 @@ void UReplicatedVRCameraComponent::UpdateTracking(float DeltaTime)
 | 
			
		|||
					FRotator StoredCameraRotOffset = FRotator::ZeroRotator;
 | 
			
		||||
					if (AttachChar->VRMovementReference && AttachChar->VRMovementReference->GetReplicatedMovementMode() == EVRConjoinedMovementModes::C_VRMOVE_Seated)
 | 
			
		||||
					{
 | 
			
		||||
						AttachChar->SeatInformation.InitialRelCameraTransform.Rotator();
 | 
			
		||||
						//StoredCameraRotOffset = AttachChar->SeatInformation.InitialRelCameraTransform.Rotator();
 | 
			
		||||
					}
 | 
			
		||||
					else
 | 
			
		||||
					{
 | 
			
		||||
| 
						 | 
				
			
			@ -250,7 +250,7 @@ void UReplicatedVRCameraComponent::RunNetworkedSmoothing(float DeltaTime)
 | 
			
		|||
		FRotator StoredCameraRotOffset = FRotator::ZeroRotator;
 | 
			
		||||
		if (AttachChar->VRMovementReference && AttachChar->VRMovementReference->GetReplicatedMovementMode() == EVRConjoinedMovementModes::C_VRMOVE_Seated)
 | 
			
		||||
		{
 | 
			
		||||
			AttachChar->SeatInformation.InitialRelCameraTransform.Rotator();
 | 
			
		||||
			//StoredCameraRotOffset = AttachChar->SeatInformation.InitialRelCameraTransform.Rotator();
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
| 
						 | 
				
			
			@ -480,12 +480,12 @@ void UReplicatedVRCameraComponent::HandleXRCamera(float DeltaTime)
 | 
			
		|||
							//FRotator OffsetRotator = 
 | 
			
		||||
							if (AttachChar->VRMovementReference && AttachChar->VRMovementReference->GetReplicatedMovementMode() != EVRConjoinedMovementModes::C_VRMOVE_Seated)
 | 
			
		||||
							{
 | 
			
		||||
								AttachChar->SeatInformation.InitialRelCameraTransform.Rotator();
 | 
			
		||||
								//AttachChar->SeatInformation.InitialRelCameraTransform.Rotator();
 | 
			
		||||
 | 
			
		||||
								FRotator StoredCameraRotOffset = FRotator::ZeroRotator;
 | 
			
		||||
								if (AttachChar->VRMovementReference->GetReplicatedMovementMode() == EVRConjoinedMovementModes::C_VRMOVE_Seated)
 | 
			
		||||
								{
 | 
			
		||||
									AttachChar->SeatInformation.InitialRelCameraTransform.Rotator();
 | 
			
		||||
									//StoredCameraRotOffset = AttachChar->SeatInformation.InitialRelCameraTransform.Rotator();
 | 
			
		||||
								}
 | 
			
		||||
								else
 | 
			
		||||
								{
 | 
			
		||||
| 
						 | 
				
			
			@ -536,7 +536,7 @@ void UReplicatedVRCameraComponent::OnRep_ReplicatedCameraTransform()
 | 
			
		|||
		FRotator StoredCameraRotOffset = FRotator::ZeroRotator;
 | 
			
		||||
		if (AttachChar->VRMovementReference && AttachChar->VRMovementReference->GetReplicatedMovementMode() == EVRConjoinedMovementModes::C_VRMOVE_Seated)
 | 
			
		||||
		{
 | 
			
		||||
			AttachChar->SeatInformation.InitialRelCameraTransform.Rotator();
 | 
			
		||||
			//StoredCameraRotOffset = AttachChar->SeatInformation.InitialRelCameraTransform.Rotator();
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -185,7 +185,7 @@ void AVRBaseCharacter::PostInitializeComponents()
 | 
			
		|||
 | 
			
		||||
	Super::PostInitializeComponents();
 | 
			
		||||
 | 
			
		||||
	if (IsValid(this))
 | 
			
		||||
	if (IsValidChecked(this))
 | 
			
		||||
	{
 | 
			
		||||
		if (NetSmoother)
 | 
			
		||||
		{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1721,6 +1721,17 @@ void UVRBaseCharacterMovementComponent::SimulatedTick(float DeltaSeconds)
 | 
			
		|||
			const FQuat NewCapsuleRotation = UpdatedComponent->GetComponentQuat();
 | 
			
		||||
			if (Mesh == CharacterOwner->GetMesh() && !NewCapsuleRotation.Equals(OldRotationQuat, 1e-6f) && ClientPredictionData)
 | 
			
		||||
			{
 | 
			
		||||
				// #TODO: The below is new in 5.6, i don't have saved capsule rotation, don't think i need this change for base char
 | 
			
		||||
				/* 
 | 
			
		||||
									// Add delta rotation to the target rotation and original offset. Otherwise this object will move back toward the old rotation.
 | 
			
		||||
					const FQuat RotationDelta = NewCapsuleRotation - SavedCapsuleRotation;
 | 
			
		||||
					ClientPredictionData->MeshRotationTarget += RotationDelta;
 | 
			
		||||
					ClientPredictionData->OriginalMeshRotationOffset += RotationDelta;
 | 
			
		||||
 | 
			
		||||
					// Update the MeshRotationOffset to match the capsule rotation.
 | 
			
		||||
					ClientPredictionData->MeshRotationOffset = NewCapsuleRotation;
 | 
			
		||||
				*/
 | 
			
		||||
 | 
			
		||||
				// Smoothing should lerp toward this new rotation target, otherwise it will just try to go back toward the old rotation.
 | 
			
		||||
				ClientPredictionData->MeshRotationTarget = NewCapsuleRotation;
 | 
			
		||||
				Mesh->SetRelativeLocationAndRotation(SavedMeshRelativeLocation, CharacterOwner->GetBaseRotationOffset());
 | 
			
		||||
| 
						 | 
				
			
			@ -1941,13 +1952,18 @@ void UVRBaseCharacterMovementComponent::MoveAutonomous(
 | 
			
		|||
		static const auto CVarEnableQueuedAnimEventsOnServer = IConsoleManager::Get().FindConsoleVariable(TEXT("a.EnableQueuedAnimEventsOnServer"));
 | 
			
		||||
		if (CVarEnableQueuedAnimEventsOnServer->GetInt())
 | 
			
		||||
		{
 | 
			
		||||
			if (const UAnimInstance* AnimInstance = OwnerMesh->GetAnimInstance())
 | 
			
		||||
			if (UAnimInstance* AnimInstance = OwnerMesh->GetAnimInstance())
 | 
			
		||||
			{
 | 
			
		||||
				if (OwnerMesh->VisibilityBasedAnimTickOption <= EVisibilityBasedAnimTickOption::AlwaysTickPose && AnimInstance->NeedsUpdate())
 | 
			
		||||
				{
 | 
			
		||||
					// If we are doing a full graph update on the server but its doing a parallel update,
 | 
			
		||||
					// trigger events right away since these are notifies queued from the montage update and we could be receiving multiple ServerMoves per frame.
 | 
			
		||||
					// trigger events right away since these are notifies queued from the montage update, and we could be receiving multiple ServerMoves per frame.
 | 
			
		||||
					OwnerMesh->ConditionallyDispatchQueuedAnimEvents();
 | 
			
		||||
 | 
			
		||||
					// We need to manually clear the anim notify queue (since normally its only is cleared in PreUpdateAnimation()) otherwise if animation ticks, the notifies queued from the ServerMove would fire twice.
 | 
			
		||||
					AnimInstance->ClearQueuedAnimEvents(false);
 | 
			
		||||
 | 
			
		||||
					// When animation ticks, we want its queued events to be triggered.
 | 
			
		||||
					OwnerMesh->AllowQueuedAnimEventsNextDispatch();
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -1955,7 +1971,7 @@ void UVRBaseCharacterMovementComponent::MoveAutonomous(
 | 
			
		|||
		else
 | 
			
		||||
		{
 | 
			
		||||
			// Revert back to old behavior if wanted/needed.
 | 
			
		||||
			if (OwnerMesh->ShouldOnlyTickMontages(DeltaTime))
 | 
			
		||||
			if (OwnerMesh->ShouldOnlyTickMontages(DeltaTime) || OwnerMesh->ShouldOnlyTickMontagesAndRefreshBones(DeltaTime))
 | 
			
		||||
			{
 | 
			
		||||
				OwnerMesh->ConditionallyDispatchQueuedAnimEvents();
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -123,7 +123,7 @@ void UVRCharacterMovementComponent::Crouch(bool bClientSimulation)
 | 
			
		|||
	{
 | 
			
		||||
		if (!bClientSimulation)
 | 
			
		||||
		{
 | 
			
		||||
			CharacterOwner->bIsCrouched = true;
 | 
			
		||||
			CharacterOwner->SetIsCrouched(true);
 | 
			
		||||
		}
 | 
			
		||||
		CharacterOwner->OnStartCrouch(0.f, 0.f);
 | 
			
		||||
		return;
 | 
			
		||||
| 
						 | 
				
			
			@ -195,7 +195,7 @@ void UVRCharacterMovementComponent::Crouch(bool bClientSimulation)
 | 
			
		|||
			//UpdatedComponent->MoveComponent(ScaledHalfHeightAdjust * GetGravityDirection(), UpdatedComponent->GetComponentQuat(), true, nullptr, EMoveComponentFlags::MOVECOMP_NoFlags, ETeleportType::TeleportPhysics);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		CharacterOwner->bIsCrouched = true;
 | 
			
		||||
		CharacterOwner->SetIsCrouched(true);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bForceNextFloorCheck = true;
 | 
			
		||||
| 
						 | 
				
			
			@ -240,7 +240,7 @@ void UVRCharacterMovementComponent::UnCrouch(bool bClientSimulation)
 | 
			
		|||
	{
 | 
			
		||||
		if (!bClientSimulation)
 | 
			
		||||
		{
 | 
			
		||||
			CharacterOwner->bIsCrouched = false;
 | 
			
		||||
			CharacterOwner->SetIsCrouched(false);
 | 
			
		||||
		}
 | 
			
		||||
		CharacterOwner->OnEndCrouch(0.f, 0.f);
 | 
			
		||||
		return;
 | 
			
		||||
| 
						 | 
				
			
			@ -341,7 +341,11 @@ void UVRCharacterMovementComponent::UnCrouch(bool bClientSimulation)
 | 
			
		|||
			if (!bEncroached)
 | 
			
		||||
			{
 | 
			
		||||
				// Commit the change in location.
 | 
			
		||||
				//UpdatedComponent->MoveComponent(StandingLocation - PawnLocation, UpdatedComponent->GetComponentQuat(), false, nullptr, EMoveComponentFlags::MOVECOMP_NoFlags, ETeleportType::TeleportPhysics);
 | 
			
		||||
				if (!BaseVRCharacterOwner || !BaseVRCharacterOwner->bRetainRoomscale)
 | 
			
		||||
				{
 | 
			
		||||
					// we actually move this when not using retained roomscale
 | 
			
		||||
					//UpdatedComponent->MoveComponent(StandingLocation - PawnLocation, UpdatedComponent->GetComponentQuat(), false, nullptr, EMoveComponentFlags::MOVECOMP_NoFlags, ETeleportType::TeleportPhysics);
 | 
			
		||||
				}
 | 
			
		||||
				bForceNextFloorCheck = true;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -352,7 +356,7 @@ void UVRCharacterMovementComponent::UnCrouch(bool bClientSimulation)
 | 
			
		|||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		CharacterOwner->bIsCrouched = false;
 | 
			
		||||
		CharacterOwner->SetIsCrouched(false);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			@ -881,7 +885,7 @@ void UVRCharacterMovementComponent::PhysWalking(float deltaTime, int32 Iteration
 | 
			
		|||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!CharacterOwner || (!CharacterOwner->Controller && !bRunPhysicsWithNoController && !HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity() && (CharacterOwner->GetLocalRole() != ROLE_SimulatedProxy)))
 | 
			
		||||
	if (!CharacterOwner || (!CharacterOwner->GetController() && !bRunPhysicsWithNoController && !HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity() && (CharacterOwner->GetLocalRole() != ROLE_SimulatedProxy)))
 | 
			
		||||
	{
 | 
			
		||||
		Acceleration = FVector::ZeroVector;
 | 
			
		||||
		Velocity = FVector::ZeroVector;
 | 
			
		||||
| 
						 | 
				
			
			@ -908,7 +912,7 @@ void UVRCharacterMovementComponent::PhysWalking(float deltaTime, int32 Iteration
 | 
			
		|||
	RewindVRRelativeMovement();
 | 
			
		||||
 | 
			
		||||
	// Perform the move
 | 
			
		||||
	while ((remainingTime >= MIN_TICK_TIME) && (Iterations < MaxSimulationIterations) && CharacterOwner && (CharacterOwner->Controller || bRunPhysicsWithNoController || HasAnimRootMotion() || CurrentRootMotion.HasOverrideVelocity() || (CharacterOwner->GetLocalRole() == ROLE_SimulatedProxy)))
 | 
			
		||||
	while ((remainingTime >= MIN_TICK_TIME) && (Iterations < MaxSimulationIterations) && CharacterOwner && (CharacterOwner->GetController() || bRunPhysicsWithNoController || HasAnimRootMotion() || CurrentRootMotion.HasOverrideVelocity() || (CharacterOwner->GetLocalRole() == ROLE_SimulatedProxy)))
 | 
			
		||||
	{
 | 
			
		||||
		Iterations++;
 | 
			
		||||
		bJustTeleported = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -1085,7 +1089,7 @@ void UVRCharacterMovementComponent::PhysWalking(float deltaTime, int32 Iteration
 | 
			
		|||
				}
 | 
			
		||||
 | 
			
		||||
				AdjustFloorHeight();
 | 
			
		||||
				SetBase(CurrentFloor.HitResult.Component.Get(), CurrentFloor.HitResult.BoneName);
 | 
			
		||||
				SetBaseFromFloor(CurrentFloor);
 | 
			
		||||
			}
 | 
			
		||||
			else if (CurrentFloor.HitResult.bStartPenetrating && remainingTime <= 0.f)
 | 
			
		||||
			{
 | 
			
		||||
| 
						 | 
				
			
			@ -2275,7 +2279,7 @@ void UVRCharacterMovementComponent::UpdateBasedMovement(float DeltaSeconds)
 | 
			
		|||
			{
 | 
			
		||||
				// Nothing changed. This means we probably are using another rotation mechanism (bOrientToMovement etc). We should still follow the base object.
 | 
			
		||||
				// @todo: This assumes only Yaw is used, currently a valid assumption. This is the only reason FaceRotation() is used above really, aside from being a virtual hook.
 | 
			
		||||
				if (bOrientRotationToMovement || (bUseControllerDesiredRotation && CharacterOwner->Controller))
 | 
			
		||||
				if (bOrientRotationToMovement || (bUseControllerDesiredRotation && CharacterOwner->GetController()))
 | 
			
		||||
				{
 | 
			
		||||
					// Custom gravity automatically aligns the character to the gravity direction, so we shouldn't zero out pitch and roll.
 | 
			
		||||
					if (!HasCustomGravity())
 | 
			
		||||
| 
						 | 
				
			
			@ -2289,7 +2293,7 @@ void UVRCharacterMovementComponent::UpdateBasedMovement(float DeltaSeconds)
 | 
			
		|||
			}
 | 
			
		||||
 | 
			
		||||
			// Pipe through ControlRotation, to affect camera.
 | 
			
		||||
			if (CharacterOwner->Controller)
 | 
			
		||||
			if (CharacterOwner->GetController())
 | 
			
		||||
			{
 | 
			
		||||
				const FQuat PawnDeltaRotation = FinalQuat * PawnOldQuat.Inverse();
 | 
			
		||||
				FRotator FinalRotation = FinalQuat.Rotator();
 | 
			
		||||
| 
						 | 
				
			
			@ -3195,7 +3199,7 @@ void UVRCharacterMovementComponent::PhysNavWalking(float deltaTime, int32 Iterat
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	// Root motion not for VR
 | 
			
		||||
	if ((!CharacterOwner || !CharacterOwner->Controller) && !bRunPhysicsWithNoController && !HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity())
 | 
			
		||||
	if ((!CharacterOwner || !CharacterOwner->GetController()) && !bRunPhysicsWithNoController && !HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity())
 | 
			
		||||
	{
 | 
			
		||||
		Acceleration = FVector::ZeroVector;
 | 
			
		||||
		Velocity = FVector::ZeroVector;
 | 
			
		||||
| 
						 | 
				
			
			@ -3814,7 +3818,7 @@ void UVRCharacterMovementComponent::SimulateMovement(float DeltaSeconds)
 | 
			
		|||
					if (IsMovingOnGround())
 | 
			
		||||
					{
 | 
			
		||||
						AdjustFloorHeight();
 | 
			
		||||
						SetBase(CurrentFloor.HitResult.Component.Get(), CurrentFloor.HitResult.BoneName);
 | 
			
		||||
						SetBaseFromFloor(CurrentFloor);
 | 
			
		||||
					}
 | 
			
		||||
					else if (MovementMode == MOVE_Falling)
 | 
			
		||||
					{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -544,7 +544,7 @@ void UVRGestureComponent::DrawDebugGesture(UObject* WorldContextObject, FTransfo
 | 
			
		|||
			FVector MirrorVector = FVector(1.f, -1.f, 1.f); // Only mirroring on Y axis to flip Left/Right
 | 
			
		||||
 | 
			
		||||
															// this means foreground lines can't be persistent 
 | 
			
		||||
			ULineBatchComponent* const LineBatcher = (InWorld ? ((DepthPriority == SDPG_Foreground) ? InWorld->ForegroundLineBatcher : ((bPersistentLines || (LifeTime > 0.f)) ? InWorld->PersistentLineBatcher : InWorld->LineBatcher)) : NULL);
 | 
			
		||||
			ULineBatchComponent* const LineBatcher = (InWorld ? ((DepthPriority == SDPG_Foreground) ? InWorld->GetLineBatcher(UWorld::ELineBatcherType::Foreground) : ((bPersistentLines || (LifeTime > 0.f)) ? InWorld->GetLineBatcher(UWorld::ELineBatcherType::WorldPersistent) : InWorld->GetLineBatcher(UWorld::ELineBatcherType::World))) : NULL);
 | 
			
		||||
 | 
			
		||||
			if (LineBatcher != NULL)
 | 
			
		||||
			{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -52,7 +52,7 @@ void UVRPathFollowingComponent::GetDebugStringTokens(TArray<FString>& Tokens, TA
 | 
			
		|||
	Tokens.Add(GetStatusDesc());
 | 
			
		||||
	Flags.Add(EPathFollowingDebugTokens::Description);
 | 
			
		||||
 | 
			
		||||
	if (Status != EPathFollowingStatus::Moving)
 | 
			
		||||
	if (GetStatus() != EPathFollowingStatus::Moving)
 | 
			
		||||
	{
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,6 +11,7 @@
 | 
			
		|||
#include "Engine/ScopedMovementUpdate.h"
 | 
			
		||||
#include "SceneManagement.h"
 | 
			
		||||
#include "PrimitiveSceneProxy.h"
 | 
			
		||||
#include "SceneView.h"
 | 
			
		||||
//#include "DrawDebugHelpers.h"
 | 
			
		||||
#include "IHeadMountedDisplay.h"
 | 
			
		||||
#include "IXRTrackingSystem.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -962,7 +963,7 @@ bool UVRRootComponent::MoveComponentImpl(const FVector& Delta, const FQuat& NewR
 | 
			
		|||
	//CSV_SCOPED_TIMING_STAT(PrimitiveComponent, MoveComponentTime);
 | 
			
		||||
 | 
			
		||||
	// static things can move before they are registered (e.g. immediately after streaming), but not after.
 | 
			
		||||
	if (!IsValid(this) || (this->Mobility == EComponentMobility::Static && IsRegistered()))//|| CheckStaticMobilityAndWarn(PrimitiveComponentStatics::MobilityWarnText))
 | 
			
		||||
	if (!IsValidChecked(this) || (this->Mobility == EComponentMobility::Static && IsRegistered()))//|| CheckStaticMobilityAndWarn(PrimitiveComponentStatics::MobilityWarnText))
 | 
			
		||||
	{
 | 
			
		||||
		if (OutHit)
 | 
			
		||||
		{
 | 
			
		||||
| 
						 | 
				
			
			@ -1233,7 +1234,7 @@ bool UVRRootComponent::MoveComponentImpl(const FVector& Delta, const FQuat& NewR
 | 
			
		|||
 | 
			
		||||
	// Handle blocking hit notifications. Avoid if pending kill (which could happen after overlaps).
 | 
			
		||||
	const bool bAllowHitDispatch = !BlockingHit.bStartPenetrating || !(MoveFlags & MOVECOMP_DisableBlockingOverlapDispatch);
 | 
			
		||||
	if (BlockingHit.bBlockingHit && bAllowHitDispatch && IsValid(this))
 | 
			
		||||
	if (BlockingHit.bBlockingHit && bAllowHitDispatch && IsValidChecked(this))
 | 
			
		||||
	{
 | 
			
		||||
		check(bFilledHitResult);
 | 
			
		||||
		if (IsDeferringMovementUpdates())
 | 
			
		||||
| 
						 | 
				
			
			@ -1329,7 +1330,7 @@ bool UVRRootComponent::UpdateOverlapsImpl(const TOverlapArrayView* NewPendingOve
 | 
			
		|||
			TInlineOverlapPointerArray NewOverlappingComponentPtrs;
 | 
			
		||||
 | 
			
		||||
			// If pending kill, we should not generate any new overlaps. Also not if overlaps were just disabled during BeginComponentOverlap.
 | 
			
		||||
			if (IsValid(this) && GetGenerateOverlapEvents())
 | 
			
		||||
			if (IsValidChecked(this) && GetGenerateOverlapEvents())
 | 
			
		||||
			{
 | 
			
		||||
				// 4.17 converted to auto cvar
 | 
			
		||||
				static const auto CVarAllowCachedOverlaps = IConsoleManager::Get().FindConsoleVariable(TEXT("p.AllowCachedOverlaps"));
 | 
			
		||||
| 
						 | 
				
			
			@ -1553,7 +1554,7 @@ bool UVRRootComponent::IsLocallyControlled() const
 | 
			
		|||
		// Simulated proxies should already have the new height from the server
 | 
			
		||||
		if (!owningVRChar->bRetainRoomscale && (owningVRChar->GetNetMode() < ENetMode::NM_Client || IsLocallyControlled()))
 | 
			
		||||
		{
 | 
			
		||||
			MoveComponent(this->GetComponentQuat().GetUpVector() * (Offset * this->GetComponentScale().Z), GetComponentQuat(), true, nullptr, EMoveComponentFlags::MOVECOMP_NoFlags, ETeleportType::TeleportPhysics);
 | 
			
		||||
			MoveComponent(this->GetComponentQuat().GetUpVector() * (Offset * this->GetComponentScale().Z), GetComponentQuat(), false, nullptr, EMoveComponentFlags::MOVECOMP_NoFlags, ETeleportType::TeleportPhysics);
 | 
			
		||||
		}
 | 
			
		||||
		/*else
 | 
			
		||||
		{
 | 
			
		||||
| 
						 | 
				
			
			@ -1581,7 +1582,7 @@ bool UVRRootComponent::IsLocallyControlled() const
 | 
			
		|||
 | 
			
		||||
void UVRRootComponent::UpdatePhysicsVolume(bool bTriggerNotifiers)
 | 
			
		||||
{
 | 
			
		||||
	if (GetShouldUpdatePhysicsVolume() && IsValid(this))
 | 
			
		||||
	if (GetShouldUpdatePhysicsVolume() && IsValidChecked(this))
 | 
			
		||||
	{
 | 
			
		||||
		//	SCOPE_CYCLE_COUNTER(STAT_UpdatePhysicsVolume);
 | 
			
		||||
		if (UWorld * MyWorld = GetWorld())
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,6 +11,8 @@
 | 
			
		|||
#include "VRRootComponent.h"
 | 
			
		||||
#include "TextureResource.h"
 | 
			
		||||
#include "Engine/Texture.h"
 | 
			
		||||
#include "Engine/Texture2D.h"
 | 
			
		||||
#include "SceneView.h"
 | 
			
		||||
#include "Engine/GameInstance.h"
 | 
			
		||||
#include "SceneManagement.h"
 | 
			
		||||
#include "Materials/Material.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -27,6 +29,8 @@
 | 
			
		|||
#include "Engine/Engine.h"
 | 
			
		||||
#include "Engine/GameViewportClient.h"
 | 
			
		||||
#include "Engine/TextureRenderTarget2D.h"
 | 
			
		||||
#include "ImageUtils.h"
 | 
			
		||||
#include "ImageCoreUtils.h"
 | 
			
		||||
//#include "Widgets/SWindow.h"
 | 
			
		||||
#include "Framework/Application/SlateApplication.h"
 | 
			
		||||
#include "Kismet/KismetSystemLibrary.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -415,6 +419,8 @@ UVRStereoWidgetComponent::~UVRStereoWidgetComponent()
 | 
			
		|||
 | 
			
		||||
void UVRStereoWidgetComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
 | 
			
		||||
{
 | 
			
		||||
	Super::EndPlay(EndPlayReason);
 | 
			
		||||
 | 
			
		||||
	if (EndPlayReason == EEndPlayReason::EndPlayInEditor || EndPlayReason == EEndPlayReason::Quit)
 | 
			
		||||
	{
 | 
			
		||||
		//FStereoLayerAdditionalFlagsManager::Destroy();
 | 
			
		||||
| 
						 | 
				
			
			@ -431,6 +437,12 @@ void UVRStereoWidgetComponent::BeginDestroy()
 | 
			
		|||
		LayerId = IStereoLayers::FLayerDesc::INVALID_LAYER_ID;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (IsValid(TextureRef))
 | 
			
		||||
	{
 | 
			
		||||
		TextureRef->RemoveFromRoot();
 | 
			
		||||
		TextureRef = nullptr;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Super::BeginDestroy();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -601,7 +613,14 @@ void UVRStereoWidgetComponent::TickComponent(float DeltaTime, enum ELevelTick Ti
 | 
			
		|||
 | 
			
		||||
									if (AVRCharacter* VRChar = Cast<AVRCharacter>(mpawn))
 | 
			
		||||
									{
 | 
			
		||||
										HMDLoc += UVRExpansionFunctionLibrary::GetHMDPureYaw_I(HMDRot.Rotator()).RotateVector(FVector(VRChar->VRRootReference->VRCapsuleOffset.X, VRChar->VRRootReference->VRCapsuleOffset.Y, 0.0f));
 | 
			
		||||
										if (VRChar->VRMovementReference && VRChar->VRMovementReference->GetReplicatedMovementMode() == EVRConjoinedMovementModes::C_VRMOVE_Seated)
 | 
			
		||||
										{
 | 
			
		||||
 | 
			
		||||
										}
 | 
			
		||||
										else
 | 
			
		||||
										{
 | 
			
		||||
											HMDLoc += UVRExpansionFunctionLibrary::GetHMDPureYaw_I(HMDRot.Rotator()).RotateVector(FVector(VRChar->VRRootReference->VRCapsuleOffset.X, VRChar->VRRootReference->VRCapsuleOffset.Y, 0.0f));
 | 
			
		||||
										}
 | 
			
		||||
									}
 | 
			
		||||
 | 
			
		||||
									DeltaTrans = FTransform(FQuat::Identity, HMDLoc, FVector(1.0f));
 | 
			
		||||
| 
						 | 
				
			
			@ -711,8 +730,12 @@ void UVRStereoWidgetComponent::TickComponent(float DeltaTime, enum ELevelTick Ti
 | 
			
		|||
 | 
			
		||||
		if (RenderTarget)
 | 
			
		||||
		{
 | 
			
		||||
			LayerDsec.Texture = RenderTarget->GetResource()->TextureRHI;
 | 
			
		||||
			// TODO 5.7 need to figure out how to replace this in some way that isn't so fing slow
 | 
			
		||||
			//PRAGMA_DISABLE_DEPRECATION_WARNINGS
 | 
			
		||||
			//LayerDsec.Texture = RenderTarget->GetResource()->TextureRHI;
 | 
			
		||||
			LayerDsec.TextureObj = RenderTarget;
 | 
			
		||||
			LayerDsec.Flags |= (RenderTarget->GetMaterialType() == MCT_TextureExternal) ? IStereoLayers::LAYER_FLAG_TEX_EXTERNAL : 0;
 | 
			
		||||
			//PRAGMA_ENABLE_DEPRECATION_WARNINGS
 | 
			
		||||
		}
 | 
			
		||||
		// Forget the left texture implementation
 | 
			
		||||
		//if (LeftTexture)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,7 +35,8 @@
 | 
			
		|||
 | 
			
		||||
#pragma region FPhysicsReplicationAsync
 | 
			
		||||
 | 
			
		||||
class FPhysicsReplicationAsyncVR : public Chaos::TSimCallbackObject<
 | 
			
		||||
class FPhysicsReplicationAsyncVR : public IPhysicsReplicationAsync,
 | 
			
		||||
	public Chaos::TSimCallbackObject<
 | 
			
		||||
	FPhysicsReplicationAsyncInput,
 | 
			
		||||
	Chaos::FSimCallbackNoOutput,
 | 
			
		||||
	Chaos::ESimCallbackOptions::Presimulate | Chaos::ESimCallbackOptions::PhysicsObjectUnregister>
 | 
			
		||||
| 
						 | 
				
			
			@ -45,7 +46,9 @@ class FPhysicsReplicationAsyncVR : public Chaos::TSimCallbackObject<
 | 
			
		|||
	virtual void OnPreSimulate_Internal() override;
 | 
			
		||||
	virtual void OnPhysicsObjectUnregistered_Internal(Chaos::FConstPhysicsObjectHandle PhysicsObject) override;
 | 
			
		||||
 | 
			
		||||
	virtual void ApplyTargetStatesAsync(const float DeltaSeconds, const FPhysicsRepErrorCorrectionData& ErrorCorrection, const TArray<FPhysicsRepAsyncInputData>& TargetStates);
 | 
			
		||||
	virtual void ApplyTargetStatesAsync(const float DeltaSeconds);
 | 
			
		||||
	UE_DEPRECATED(5.6, "Deprecated, call the function with just @param DeltaSeconds instead.")
 | 
			
		||||
		virtual void ApplyTargetStatesAsync(const float DeltaSeconds, const FPhysicsRepErrorCorrectionData& ErrorCorrection, const TArray<FPhysicsRepAsyncInputData>& TargetStates) { ApplyTargetStatesAsync(DeltaSeconds); };
 | 
			
		||||
 | 
			
		||||
	// Replication functions
 | 
			
		||||
	virtual void DefaultReplication_DEPRECATED(Chaos::FRigidBodyHandle_Internal* Handle, const FPhysicsRepAsyncInputData& State, const float DeltaSeconds, const FPhysicsRepErrorCorrectionData& ErrorCorrection);
 | 
			
		||||
| 
						 | 
				
			
			@ -54,7 +57,7 @@ class FPhysicsReplicationAsyncVR : public Chaos::TSimCallbackObject<
 | 
			
		|||
	virtual bool ResimulationReplication(Chaos::FPBDRigidParticleHandle* Handle, FReplicatedPhysicsTargetAsync& Target, const float DeltaSeconds);
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	virtual void RegisterSettings(Chaos::FConstPhysicsObjectHandle PhysicsObject, FNetworkPhysicsSettingsAsync InSettings);
 | 
			
		||||
	virtual void RegisterSettings(Chaos::FConstPhysicsObjectHandle PhysicsObject, FNetworkPhysicsSettingsAsync InSettings) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	float LatencyOneWay;
 | 
			
		||||
| 
						 | 
				
			
			@ -63,6 +66,8 @@ private:
 | 
			
		|||
	FNetworkPhysicsSettingsAsync SettingsDefault;
 | 
			
		||||
	TMap<Chaos::FConstPhysicsObjectHandle, FReplicatedPhysicsTargetAsync> ObjectToTarget;
 | 
			
		||||
	TMap<Chaos::FConstPhysicsObjectHandle, FNetworkPhysicsSettingsAsync> ObjectToSettings;
 | 
			
		||||
	TArray<const Chaos::Private::FPBDIsland*> ResimIslands;
 | 
			
		||||
	TArray<const Chaos::FGeometryParticleHandle*> ResimIslandsParticles;
 | 
			
		||||
	TArray<int32> ParticlesInResimIslands;
 | 
			
		||||
	TArray<Chaos::FParticleID> ReplicatedParticleIDs;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -74,7 +79,15 @@ private:
 | 
			
		|||
	void CacheResimInteractions();
 | 
			
		||||
	// Sets SettingsCurrent to either the objects custom settings or to the default settings
 | 
			
		||||
	void FetchObjectSettings(Chaos::FConstPhysicsObjectHandle PhysicsObject);
 | 
			
		||||
	bool UsePhysicsReplicationLOD();
 | 
			
		||||
	void CheckTargetResimValidity(FReplicatedPhysicsTargetAsync& Target);
 | 
			
		||||
	void ApplyPhysicsReplicationLOD(Chaos::FConstPhysicsObjectHandle PhysicsObjectHandle, FReplicatedPhysicsTargetAsync& Target, const uint32 LODFlags);
 | 
			
		||||
	void DebugDrawReplicationMode(const FPhysicsRepAsyncInputData& Input);
 | 
			
		||||
 | 
			
		||||
	/** Static function to extrapolate a target for N ticks using X DeltaSeconds */
 | 
			
		||||
	static void ExtrapolateTarget(FReplicatedPhysicsTargetAsync& Target, const int32 ExtrapolateFrames, const float DeltaSeconds);
 | 
			
		||||
	/** Static function to extrapolate a target for N Seconds */
 | 
			
		||||
	static void ExtrapolateTarget(FReplicatedPhysicsTargetAsync& Target, const float ExtrapolationTime);
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	void Setup(FRigidBodyErrorCorrection ErrorCorrection)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -61,5 +61,5 @@ public:
 | 
			
		|||
 | 
			
		||||
	virtual void PostInitProperties() override;
 | 
			
		||||
	virtual bool InputKey(const FInputKeyEventArgs& EventArgs) override;
 | 
			
		||||
	virtual bool InputAxis(FViewport* tViewport, FInputDeviceId InputDevice, FKey Key, float Delta, float DeltaTime, int32 NumSamples = 1, bool bGamepad = false) override;
 | 
			
		||||
	virtual bool InputAxis(const FInputKeyEventArgs& Args) override;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -93,11 +93,11 @@ public:
 | 
			
		|||
						SetupPlayerInputComponent(InputComponent);
 | 
			
		||||
						InputComponent->RegisterComponent();
 | 
			
		||||
 | 
			
		||||
						if (UInputDelegateBinding::SupportsInputDelegate(GetClass()))
 | 
			
		||||
						{
 | 
			
		||||
						//if (UInputDelegateBinding::SupportsInputDelegate(GetClass()))
 | 
			
		||||
						//{
 | 
			
		||||
							InputComponent->bBlockInput = bBlockInput;
 | 
			
		||||
							UInputDelegateBinding::BindInputDelegates(GetClass(), InputComponent);
 | 
			
		||||
						}
 | 
			
		||||
						//}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -108,11 +108,11 @@ public:
 | 
			
		|||
						SetupPlayerInputComponent(InputComponent);
 | 
			
		||||
						InputComponent->RegisterComponent();
 | 
			
		||||
 | 
			
		||||
						if (UInputDelegateBinding::SupportsInputDelegate(GetClass()))
 | 
			
		||||
						{
 | 
			
		||||
						//if (UInputDelegateBinding::SupportsInputDelegate(GetClass()))
 | 
			
		||||
						//{
 | 
			
		||||
							InputComponent->bBlockInput = bBlockInput;
 | 
			
		||||
							UInputDelegateBinding::BindInputDelegates(GetClass(), InputComponent);
 | 
			
		||||
						}
 | 
			
		||||
						//}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -181,6 +181,9 @@ public:
 | 
			
		|||
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "StereoLayer", Meta = (GetOptions = "EditorFlagCollector.GetFlagNames"))
 | 
			
		||||
		TArray<FName> AdditionalFlags;
 | 
			
		||||
 | 
			
		||||
	UPROPERTY()
 | 
			
		||||
	TObjectPtr<class UTexture2D> TextureRef = nullptr;
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
	/** Texture displayed on the stereo layer (is stereocopic textures are supported on the platfrom and more than one texture is provided, this will be the right eye) **/
 | 
			
		||||
	//UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "StereoLayer")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,6 +11,8 @@ public class VRExpansionPlugin : ModuleRules
 | 
			
		|||
 | 
			
		||||
    public VRExpansionPlugin(ReadOnlyTargetRules Target) : base(Target)
 | 
			
		||||
    {
 | 
			
		||||
        DefaultBuildSettings = BuildSettingsVersion.Latest;
 | 
			
		||||
        IncludeOrderVersion = EngineIncludeOrderVersion.Latest;
 | 
			
		||||
        PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
 | 
			
		||||
        //bEnforceIWYU = true;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -83,6 +85,7 @@ public class VRExpansionPlugin : ModuleRules
 | 
			
		|||
               // "CoreUObject",
 | 
			
		||||
                //"Engine",
 | 
			
		||||
                "InputCore",
 | 
			
		||||
                "ImageCore", // For new stereo layer stuff
 | 
			
		||||
                //"FLEX", remove comment if building in the NVIDIA flex branch - NOTE when put in place FLEX only listed win32 and win64 at compatible platforms
 | 
			
		||||
                //"HeadMountedDisplay",
 | 
			
		||||
                "RHI",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue