Update to 5.6, lots of Cleanup

This commit is contained in:
Simeon "Waldo" Wallrath 2025-09-05 15:32:59 +02:00
parent f036c2a1fb
commit d29dbbbe45
141 changed files with 859 additions and 505 deletions

View file

@ -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(

View file

@ -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
{

View file

@ -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));
}
}
}
}

View file

@ -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

View file

@ -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();
}

View file

@ -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;
}
}

View file

@ -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)

View file

@ -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
{

View file

@ -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;

View file

@ -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();

View file

@ -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
{

View file

@ -185,7 +185,7 @@ void AVRBaseCharacter::PostInitializeComponents()
Super::PostInitializeComponents();
if (IsValid(this))
if (IsValidChecked(this))
{
if (NetSmoother)
{

View file

@ -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();
}

View file

@ -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)
{

View file

@ -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)
{

View file

@ -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;
}

View file

@ -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())

View file

@ -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)

View file

@ -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)

View file

@ -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;
};

View file

@ -93,11 +93,11 @@ public:
SetupPlayerInputComponent(InputComponent);
InputComponent->RegisterComponent();
if (UInputDelegateBinding::SupportsInputDelegate(GetClass()))
{
//if (UInputDelegateBinding::SupportsInputDelegate(GetClass()))
//{
InputComponent->bBlockInput = bBlockInput;
UInputDelegateBinding::BindInputDelegates(GetClass(), InputComponent);
}
//}
}
}

View file

@ -108,11 +108,11 @@ public:
SetupPlayerInputComponent(InputComponent);
InputComponent->RegisterComponent();
if (UInputDelegateBinding::SupportsInputDelegate(GetClass()))
{
//if (UInputDelegateBinding::SupportsInputDelegate(GetClass()))
//{
InputComponent->bBlockInput = bBlockInput;
UInputDelegateBinding::BindInputDelegates(GetClass(), InputComponent);
}
//}
}
}

View file

@ -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")

View file

@ -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",