9#include "GameFramework/PhysicsVolume.h"
10#include "GameFramework/GameNetworkManager.h"
11#include "GameFramework/Character.h"
12#include "GameFramework/GameState.h"
13#include "Components/PrimitiveComponent.h"
14#include "Animation/AnimMontage.h"
15#include "DrawDebugHelpers.h"
21#include "Navigation/PathFollowingComponent.h"
22#include "AI/Navigation/AvoidanceManager.h"
23#include "Components/CapsuleComponent.h"
24#include "Components/BrushComponent.h"
27#include "Engine/DemoNetDriver.h"
28#include "Engine/NetworkObjectList.h"
39DECLARE_CYCLE_STAT(TEXT(
"Char ReplicateMoveToServer"), STAT_CharacterMovementReplicateMoveToServer, STATGROUP_Character);
40DECLARE_CYCLE_STAT(TEXT(
"Char CallServerMove"), STAT_CharacterMovementCallServerMove, STATGROUP_Character);
41DECLARE_CYCLE_STAT(TEXT(
"Char CombineNetMove"), STAT_CharacterMovementCombineNetMove, STATGROUP_Character);
46DECLARE_CYCLE_STAT(TEXT(
"Char NavProjectLocation"), STAT_CharNavProjectLocation, STATGROUP_Character);
47DECLARE_CYCLE_STAT(TEXT(
"Char AdjustFloorHeight"), STAT_CharAdjustFloorHeight, STATGROUP_Character);
56#if DO_CHECK && !UE_BUILD_SHIPPING
57#define devCodeVR( Code ) checkCode( Code )
70 TEXT(
"vre.RotationCorrectionThreshold"),
72 TEXT(
"Error threshold value before correcting a clients rotation.\n")
73 TEXT(
"Rotation is replicated at 2 decimal precision, so values less than 0.01 won't matter."),
96 if (!bClientSimulation && !CanCrouchInCurrentState())
102 if (CharacterOwner->GetCapsuleComponent()->GetUnscaledCapsuleHalfHeight() == CrouchedHalfHeight)
104 if (!bClientSimulation)
106 CharacterOwner->bIsCrouched =
true;
108 CharacterOwner->OnStartCrouch(0.f, 0.f);
112 if (bClientSimulation && CharacterOwner->GetLocalRole() == ROLE_SimulatedProxy)
117 VRRootCapsule->
SetCapsuleSizeVR(DefaultCharacter->GetCapsuleComponent()->GetUnscaledCapsuleRadius(), DefaultCharacter->GetCapsuleComponent()->GetUnscaledCapsuleHalfHeight());
119 CharacterOwner->GetCapsuleComponent()->SetCapsuleSize(DefaultCharacter->GetCapsuleComponent()->GetUnscaledCapsuleRadius(), DefaultCharacter->GetCapsuleComponent()->GetUnscaledCapsuleHalfHeight());
121 bShrinkProxyCapsule =
true;
125 const float ComponentScale = CharacterOwner->GetCapsuleComponent()->GetShapeScale();
126 const float OldUnscaledHalfHeight = CharacterOwner->GetCapsuleComponent()->GetUnscaledCapsuleHalfHeight();
127 const float OldUnscaledRadius = CharacterOwner->GetCapsuleComponent()->GetUnscaledCapsuleRadius();
129 const float ClampedCrouchedHalfHeight = FMath::Max3(0.f, OldUnscaledRadius, CrouchedHalfHeight);
134 CharacterOwner->GetCapsuleComponent()->SetCapsuleSize(OldUnscaledRadius, ClampedCrouchedHalfHeight);
136 float HalfHeightAdjust = (OldUnscaledHalfHeight - ClampedCrouchedHalfHeight);
137 float ScaledHalfHeightAdjust = HalfHeightAdjust * ComponentScale;
139 if (!bClientSimulation)
142 if (ClampedCrouchedHalfHeight > OldUnscaledHalfHeight)
145 FCollisionResponseParams ResponseParam;
146 InitCollisionParams(CapsuleParams, ResponseParam);
154 capLocation = UpdatedComponent->GetComponentLocation();
156 const bool bEncroached = GetWorld()->OverlapBlockingTestByChannel(capLocation - FVector(0.f, 0.f, ScaledHalfHeightAdjust), FQuat::Identity,
157 UpdatedComponent->GetCollisionObjectType(), GetPawnCapsuleCollisionShape(SHRINK_None), CapsuleParams, ResponseParam);
165 CharacterOwner->GetCapsuleComponent()->SetCapsuleSize(OldUnscaledRadius, OldUnscaledHalfHeight);
171 if (bCrouchMaintainsBaseLocation)
177 CharacterOwner->bIsCrouched =
true;
180 bForceNextFloorCheck =
true;
183 const float MeshAdjust = ScaledHalfHeightAdjust;
185 HalfHeightAdjust = (DefaultCharacter->GetCapsuleComponent()->GetUnscaledCapsuleHalfHeight() - ClampedCrouchedHalfHeight);
186 ScaledHalfHeightAdjust = HalfHeightAdjust * ComponentScale;
188 AdjustProxyCapsuleSize();
189 CharacterOwner->OnStartCrouch(HalfHeightAdjust, ScaledHalfHeightAdjust);
192 if ( (IsNetMode(NM_ListenServer) && CharacterOwner->GetRemoteRole() == ROLE_AutonomousProxy))
198 ClientData->MeshTranslationOffset -= FVector(0.f, 0.f, MeshAdjust);
199 ClientData->OriginalMeshTranslationOffset = ClientData->MeshTranslationOffset;
214 if (CharacterOwner->GetCapsuleComponent()->GetUnscaledCapsuleHalfHeight() == DefaultCharacter->GetCapsuleComponent()->GetUnscaledCapsuleHalfHeight())
216 if (!bClientSimulation)
218 CharacterOwner->bIsCrouched =
false;
220 CharacterOwner->OnEndCrouch(0.f, 0.f);
224 const float CurrentCrouchedHalfHeight = CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleHalfHeight();
226 const float ComponentScale = CharacterOwner->GetCapsuleComponent()->GetShapeScale();
227 const float OldUnscaledHalfHeight = CharacterOwner->GetCapsuleComponent()->GetUnscaledCapsuleHalfHeight();
228 const float HalfHeightAdjust = DefaultCharacter->GetCapsuleComponent()->GetUnscaledCapsuleHalfHeight() - OldUnscaledHalfHeight;
229 const float ScaledHalfHeightAdjust = HalfHeightAdjust * ComponentScale;
231 FVector PawnLocation = UpdatedComponent->GetComponentLocation();
239 check(CharacterOwner->GetCapsuleComponent());
241 if (!bClientSimulation)
244 const UWorld* MyWorld = GetWorld();
245 const float SweepInflation = KINDA_SMALL_NUMBER * 10.f;
247 FCollisionResponseParams ResponseParam;
248 InitCollisionParams(CapsuleParams, ResponseParam);
251 const FCollisionShape StandingCapsuleShape = GetPawnCapsuleCollisionShape(SHRINK_HeightCustom, -SweepInflation - ScaledHalfHeightAdjust);
252 const ECollisionChannel CollisionChannel = UpdatedComponent->GetCollisionObjectType();
253 bool bEncroached =
true;
255 if (!bCrouchMaintainsBaseLocation)
258 bEncroached = MyWorld->OverlapBlockingTestByChannel(PawnLocation, FQuat::Identity, CollisionChannel, StandingCapsuleShape, CapsuleParams, ResponseParam);
263 if (ScaledHalfHeightAdjust > 0.f)
266 float PawnRadius, PawnHalfHeight;
267 CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleSize(PawnRadius, PawnHalfHeight);
268 const float ShrinkHalfHeight = PawnHalfHeight - PawnRadius;
269 const float TraceDist = PawnHalfHeight - ShrinkHalfHeight;
270 const FVector Down = FVector(0.f, 0.f, -TraceDist);
273 const FCollisionShape ShortCapsuleShape = GetPawnCapsuleCollisionShape(SHRINK_HeightCustom, ShrinkHalfHeight);
274 const bool bBlockingHit = MyWorld->SweepSingleByChannel(Hit, PawnLocation, PawnLocation + Down, FQuat::Identity, CollisionChannel, ShortCapsuleShape, CapsuleParams);
275 if (Hit.bStartPenetrating)
282 const float DistanceToBase = (Hit.Time * TraceDist) + ShortCapsuleShape.Capsule.HalfHeight;
283 const FVector NewLoc = FVector(PawnLocation.X, PawnLocation.Y, PawnLocation.Z - DistanceToBase + StandingCapsuleShape.Capsule.HalfHeight + SweepInflation + MIN_FLOOR_DIST / 2.f);
284 bEncroached = MyWorld->OverlapBlockingTestByChannel(NewLoc, FQuat::Identity, CollisionChannel, StandingCapsuleShape, CapsuleParams, ResponseParam);
288 UpdatedComponent->MoveComponent(NewLoc - PawnLocation, UpdatedComponent->GetComponentQuat(),
false,
nullptr, EMoveComponentFlags::MOVECOMP_NoFlags, ETeleportType::TeleportPhysics);
297 FVector StandingLocation = PawnLocation + FVector(0.f, 0.f, StandingCapsuleShape.GetCapsuleHalfHeight() - CurrentCrouchedHalfHeight);
298 bEncroached = MyWorld->OverlapBlockingTestByChannel(StandingLocation, FQuat::Identity, CollisionChannel, StandingCapsuleShape, CapsuleParams, ResponseParam);
302 if (IsMovingOnGround())
305 const float MinFloorDist = KINDA_SMALL_NUMBER * 10.f;
306 if (CurrentFloor.bBlockingHit && CurrentFloor.FloorDist > MinFloorDist)
308 StandingLocation.Z -= CurrentFloor.FloorDist - MinFloorDist;
309 bEncroached = MyWorld->OverlapBlockingTestByChannel(StandingLocation, FQuat::Identity, CollisionChannel, StandingCapsuleShape, CapsuleParams, ResponseParam);
319 bForceNextFloorCheck =
true;
329 CharacterOwner->bIsCrouched =
false;
333 bShrinkProxyCapsule =
true;
338 VRRootCapsule->
SetCapsuleSizeVR(DefaultCharacter->GetCapsuleComponent()->GetUnscaledCapsuleRadius(), DefaultCharacter->GetCapsuleComponent()->GetUnscaledCapsuleHalfHeight(),
true);
340 CharacterOwner->GetCapsuleComponent()->SetCapsuleSize(DefaultCharacter->GetCapsuleComponent()->GetUnscaledCapsuleRadius(), DefaultCharacter->GetCapsuleComponent()->GetUnscaledCapsuleHalfHeight(),
true);
342 const float MeshAdjust = ScaledHalfHeightAdjust;
343 AdjustProxyCapsuleSize();
344 CharacterOwner->OnEndCrouch(HalfHeightAdjust, ScaledHalfHeightAdjust);
347 if ((IsNetMode(NM_ListenServer) && CharacterOwner->GetRemoteRole() == ROLE_AutonomousProxy))
353 ClientData->MeshTranslationOffset += FVector(0.f, 0.f, MeshAdjust);
354 ClientData->OriginalMeshTranslationOffset = ClientData->MeshTranslationOffset;
362 check(CharacterOwner != NULL);
363 checkSlow(CharacterOwner->GetLocalRole() < ROLE_Authority || (CharacterOwner->GetRemoteRole() == ROLE_AutonomousProxy && GetNetMode() == NM_ListenServer));
364 checkSlow(GetNetMode() == NM_Client || GetNetMode() == NM_ListenServer);
366 if (!ClientPredictionData)
372 return ClientPredictionData;
378 check(CharacterOwner != NULL);
379 check(CharacterOwner->GetLocalRole() == ROLE_Authority);
380 checkSlow(GetNetMode() < NM_Client);
382 if (!ServerPredictionData)
388 return ServerPredictionData;
398 if (VRC->VRRootReference)
402 LFDiff = VRC->VRRootReference->DifferenceFromLastFrame;
408 LFDiff = FVector::ZeroVector;
428 if (
AVRBaseCharacter * BaseChar = Cast<AVRBaseCharacter>(CharMove->GetCharacterOwner()))
430 if (BaseChar->VRReplicateCapsuleHeight && this->LFDiff.Z > 0.0f && !FMath::IsNearlyEqual(this->LFDiff.Z, CharMove->
VRRootCapsule->GetUnscaledCapsuleHalfHeight()))
432 BaseChar->SetCharacterHalfHeightVR(
LFDiff.Z,
false);
446 QUICK_SCOPE_CYCLE_COUNTER(VRCharacterMovementServerMove_PerformMovement);
450 if (!HasValidData() || !IsActive())
455 bool bAutoAcceptPacket =
false;
470 ServerData->CurrentClientTimeStamp = MoveData.TimeStamp;
471 bAutoAcceptPacket =
true;
475 const float ClientTimeStamp = MoveData.TimeStamp;
476 FVector_NetQuantize10 ClientAccel = MoveData.Acceleration;
477 const uint8 ClientMoveFlags = MoveData.CompressedMoveFlags;
478 const FRotator ClientControlRotation = MoveData.ControlRotation;
482 const float ServerTimeStamp = ServerData->CurrentClientTimeStamp;
484 static const auto CVarNetServerMoveTimestampExpiredWarningThreshold = IConsoleManager::Get().FindConsoleVariable(TEXT(
"net.NetServerMoveTimestampExpiredWarningThreshold"));
485 if (ServerTimeStamp > 1.0f && FMath::Abs(ServerTimeStamp - ClientTimeStamp) > CVarNetServerMoveTimestampExpiredWarningThreshold->GetFloat())
487 UE_LOG(LogNetPlayerMovement,
Warning, TEXT(
"ServerMove: TimeStamp expired: %f, CurrentTimeStamp: %f, Character: %s"), ClientTimeStamp, ServerTimeStamp, *GetNameSafe(CharacterOwner));
491 UE_LOG(LogNetPlayerMovement, Log, TEXT(
"ServerMove: TimeStamp expired: %f, CurrentTimeStamp: %f, Character: %s"), ClientTimeStamp, ServerTimeStamp, *GetNameSafe(CharacterOwner));
497 FVRCharacterScopedMovementUpdate ScopedMovementUpdate(UpdatedComponent, bEnableScopedMovementUpdates ? EScopedUpdate::DeferredUpdates : EScopedUpdate::ImmediateUpdates);
499 bool bServerReadyForClient =
true;
500 APlayerController* PC = Cast<APlayerController>(CharacterOwner->GetController());
503 bServerReadyForClient = PC->NotifyServerReceivedClientData(CharacterOwner, ClientTimeStamp);
504 if (!bServerReadyForClient)
506 ClientAccel = FVector::ZeroVector;
510 const UWorld* MyWorld = GetWorld();
511 float DeltaTime = 0.0f;
515 if (bAutoAcceptPacket)
517 DeltaTime = ServerData->MaxMoveDeltaTime * CharacterOwner->GetActorTimeDilation(*MyWorld);
521 DeltaTime = ServerData->GetServerMoveDeltaTime(ClientTimeStamp, CharacterOwner->GetActorTimeDilation(*MyWorld));
526 ServerData->CurrentClientTimeStamp = ClientTimeStamp;
527 ServerData->ServerAccumulatedClientTimeStamp += DeltaTime;
528 ServerData->ServerTimeStamp = MyWorld->GetTimeSeconds();
529 ServerData->ServerTimeStampLastServerMove = ServerData->ServerTimeStamp;
533 PC->SetControlRotation(ClientControlRotation);
536 if (!bServerReadyForClient)
542 if ((MyWorld->GetWorldSettings()->GetPauserPlayerState() == NULL))
546 PC->UpdateRotation(DeltaTime);
552 bHasRequestedVelocity =
true;
596 MoveAutonomous(ClientTimeStamp, DeltaTime, ClientMoveFlags, ClientAccel);
597 bHasRequestedVelocity =
false;
600 UE_CLOG(CharacterOwner && UpdatedComponent, LogNetPlayerMovement, VeryVerbose, TEXT(
"ServerMove Time %f Acceleration %s Velocity %s Position %s Rotation %s DeltaTime %f Mode %s MovementBase %s.%s (Dynamic:%d)"),
601 ClientTimeStamp, *ClientAccel.ToString(), *Velocity.ToString(), *UpdatedComponent->GetComponentLocation().ToString(), *UpdatedComponent->GetComponentRotation().ToCompactString(), DeltaTime, *GetMovementName(),
602 *GetNameSafe(GetMovementBase()), *CharacterOwner->GetBasedMovement().BoneName.ToString(), MovementBaseUtility::IsDynamicBase(GetMovementBase()) ? 1 : 0);
607 const uint8 CurrentPackedMovementMode = PackNetworkMovementMode();
608 if (CurrentPackedMovementMode != MoveData.MovementMode)
610 TEnumAsByte<EMovementMode> NetMovementMode(MOVE_None);
611 TEnumAsByte<EMovementMode> NetGroundMode(MOVE_None);
612 uint8 NetCustomMode(0);
613 UnpackNetworkMovementMode(MoveData.MovementMode, NetMovementMode, NetCustomMode, NetGroundMode);
616 if (NetMovementMode == EMovementMode::MOVE_Custom || MovementMode == EMovementMode::MOVE_Custom)
619 SetMovementMode(NetMovementMode, NetCustomMode);
624 if (MoveData.NetworkMoveType == FCharacterNetworkMoveData::ENetworkMoveType::NewMove)
626 ServerMoveHandleClientErrorVR(ClientTimeStamp, DeltaTime, ClientAccel, MoveData.Location, ClientControlRotation.Yaw, MoveData.MovementBase, MoveData.MovementBaseBoneName, MoveData.MovementMode);
819 if (Hit.Normal.Z > KINDA_SMALL_NUMBER && !Hit.Normal.Equals(Hit.ImpactNormal))
821 FVector PawnLocation = UpdatedComponent->GetComponentLocation();
825 if (
IsWithinEdgeTolerance(PawnLocation, Hit.ImpactPoint, CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleRadius()))
836 SCOPE_CYCLE_COUNTER(STAT_CharPhysWalking);
838 if (deltaTime < MIN_TICK_TIME)
843 if (!CharacterOwner || (!CharacterOwner->Controller && !bRunPhysicsWithNoController && !HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity() && (CharacterOwner->GetLocalRole() != ROLE_SimulatedProxy)))
845 Acceleration = FVector::ZeroVector;
846 Velocity = FVector::ZeroVector;
850 if (!UpdatedComponent->IsQueryCollisionEnabled())
852 SetMovementMode(MOVE_Walking);
856 devCodeVR(ensureMsgf(!Velocity.ContainsNaN(), TEXT(
"PhysWalking: Velocity contains NaN before Iteration (%s)\n%s"), *GetPathNameSafe(
this), *Velocity.ToString()));
858 bJustTeleported =
false;
859 bool bCheckedFall =
false;
860 bool bTriedLedgeMove =
false;
861 float remainingTime = deltaTime;
867 while ((remainingTime >= MIN_TICK_TIME) && (Iterations < MaxSimulationIterations) && CharacterOwner && (CharacterOwner->Controller || bRunPhysicsWithNoController || HasAnimRootMotion() || CurrentRootMotion.HasOverrideVelocity() || (CharacterOwner->GetLocalRole() == ROLE_SimulatedProxy)))
870 bJustTeleported =
false;
871 const float timeTick = GetSimulationTimeStep(remainingTime, Iterations);
872 remainingTime -= timeTick;
875 UPrimitiveComponent *
const OldBase = GetMovementBase();
876 const FVector PreviousBaseLocation = (OldBase != NULL) ? OldBase->GetComponentLocation() : FVector::ZeroVector;
877 const FVector OldLocation = UpdatedComponent->GetComponentLocation();
882 const FFindFloorResult OldFloor = CurrentFloor;
884 RestorePreAdditiveRootMotionVelocity();
888 MaintainHorizontalGroundVelocity();
889 const FVector OldVelocity = Velocity;
890 Acceleration.Z = 0.f;
893 if (!HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity())
895 CalcVelocity(timeTick, GroundFriction,
false, GetMaxBrakingDeceleration());
896 devCodeVR(ensureMsgf(!Velocity.ContainsNaN(), TEXT(
"PhysWalking: Velocity contains NaN after CalcVelocity (%s)\n%s"), *GetPathNameSafe(
this), *Velocity.ToString()));
899 ApplyRootMotionToVelocity(timeTick);
902 devCodeVR(ensureMsgf(!Velocity.ContainsNaN(), TEXT(
"PhysWalking: Velocity contains NaN after Root Motion application (%s)\n%s"), *GetPathNameSafe(
this), *Velocity.ToString()));
908 StartNewPhysics(remainingTime + timeTick, Iterations - 1);
913 const FVector MoveVelocity = Velocity;
915 const FVector Delta = timeTick * MoveVelocity;
917 const bool bZeroDelta = Delta.IsNearlyZero();
918 FStepDownResult StepDownResult;
950 const float DesiredDist = Delta.Size();
951 if (DesiredDist > KINDA_SMALL_NUMBER)
953 const float ActualDist = (UpdatedComponent->GetComponentLocation() - OldLocation).Size2D();
954 remainingTime += timeTick * (1.f - FMath::Min(1.f, ActualDist / DesiredDist));
957 StartNewPhysics(remainingTime, Iterations);
960 else if (IsSwimming())
963 StartSwimmingVR(OldCapsuleLocation, OldVelocity, timeTick, remainingTime, Iterations);
970 if (StepDownResult.bComputedFloor)
972 CurrentFloor = StepDownResult.FloorResult;
976 FindFloor(UpdatedComponent->GetComponentLocation(), CurrentFloor, bZeroDelta, NULL);
980 const bool bCheckLedges = !CanWalkOffLedges();
981 if (bCheckLedges && !CurrentFloor.IsWalkableFloor())
984 const FVector GravDir = FVector(0.f, 0.f, -1.f);
985 const FVector NewDelta = bTriedLedgeMove ? FVector::ZeroVector : GetLedgeMove(OldCapsuleLocation, Delta, GravDir);
986 if (!NewDelta.IsZero())
989 RevertMove(OldLocation, OldBase, PreviousBaseLocation, OldFloor,
false);
992 bTriedLedgeMove =
true;
995 Velocity = NewDelta / timeTick;
996 remainingTime += timeTick;
1010 bCheckedFall =
true;
1013 RevertMove(OldLocation, OldBase, PreviousBaseLocation, OldFloor,
true);
1014 remainingTime = 0.f;
1022 if (CurrentFloor.IsWalkableFloor())
1024 if (ShouldCatchAir(OldFloor, CurrentFloor))
1027 HandleWalkingOffLedge(OldFloor.HitResult.ImpactNormal, OldFloor.HitResult.Normal, OldLocation, timeTick);
1028 if (IsMovingOnGround())
1031 StartFalling(Iterations, remainingTime, timeTick, Delta, OldLocation);
1036 AdjustFloorHeight();
1037 SetBase(CurrentFloor.HitResult.Component.Get(), CurrentFloor.HitResult.BoneName);
1039 else if (CurrentFloor.HitResult.bStartPenetrating && remainingTime <= 0.f)
1043 FHitResult Hit(CurrentFloor.HitResult);
1044 Hit.TraceEnd = Hit.TraceStart + FVector(0.f, 0.f, MAX_FLOOR_DIST);
1046 ResolvePenetration(RequestedAdjustment, Hit, UpdatedComponent->GetComponentQuat());
1047 bForceNextFloorCheck =
true;
1054 StartSwimmingVR(OldCapsuleLocation, Velocity, timeTick, remainingTime, Iterations);
1059 if (!CurrentFloor.IsWalkableFloor() && !CurrentFloor.HitResult.bStartPenetrating)
1061 const bool bMustJump = bJustTeleported || bZeroDelta || (OldBase == NULL || (!OldBase->IsQueryCollisionEnabled() && MovementBaseUtility::IsDynamicBase(OldBase)));
1062 if ((bMustJump || !bCheckedFall) && CheckFall(OldFloor, CurrentFloor.HitResult, Delta, OldLocation, remainingTime, timeTick, Iterations, bMustJump))
1067 bCheckedFall =
true;
1073 if (IsMovingOnGround())
1077 if (!bJustTeleported && timeTick >= MIN_TICK_TIME)
1079 if (!HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity())
1082 Velocity = ((UpdatedComponent->GetComponentLocation() - OldLocation) / timeTick);
1083 MaintainHorizontalGroundVelocity();
1091 if (UpdatedComponent->GetComponentLocation() == OldLocation)
1094 remainingTime = 0.f;
1099 if (IsMovingOnGround())
1101 MaintainHorizontalGroundVelocity();
1107 if (!bEnablePhysicsInteraction)
1112 if (OtherComp != NULL && OtherComp->IsAnySimulatingPhysics())
1114 FVector OtherLoc = OtherComp->GetComponentLocation();
1117 OtherLoc = rCap->OffsetComponentToWorld.GetLocation();
1121 FVector ImpulseDir = FVector(OtherLoc.X - Loc.X, OtherLoc.Y - Loc.Y, 0.25f).GetSafeNormal();
1122 ImpulseDir = (ImpulseDir + Velocity.GetSafeNormal2D()) * 0.5f;
1123 ImpulseDir.Normalize();
1125 FName BoneName = NAME_None;
1126 if (OtherBodyIndex != INDEX_NONE)
1128 BoneName = ((USkinnedMeshComponent*)OtherComp)->GetBoneName(OtherBodyIndex);
1131 float TouchForceFactorModified = TouchForceFactor;
1133 if (bTouchForceScaledToMass)
1135 FBodyInstance* BI = OtherComp->GetBodyInstance(BoneName);
1136 TouchForceFactorModified *= BI ? BI->GetBodyMass() : 1.0f;
1139 float ImpulseStrength = FMath::Clamp(Velocity.Size2D() * TouchForceFactorModified,
1140 MinTouchForce > 0.0f ? MinTouchForce : -FLT_MAX,
1141 MaxTouchForce > 0.0f ? MaxTouchForce : FLT_MAX);
1143 FVector Impulse = ImpulseDir * ImpulseStrength;
1145 OtherComp->AddImpulse(Impulse, BoneName);
1152 SCOPE_CYCLE_COUNTER(STAT_CharacterMovementReplicateMoveToServer);
1153 check(CharacterOwner != NULL);
1156 APlayerController* PC = Cast<APlayerController>(CharacterOwner->GetController());
1157 if (PC && PC->AcknowledgedPawn != CharacterOwner)
1164 if (PC && PC->Player ==
nullptr)
1176 DeltaTime = ClientData->UpdateTimeStampAndDeltaTime(DeltaTime, *CharacterOwner, *
this);
1181 FSavedMovePtr OldMove = NULL;
1182 if (ClientData->LastAckedMove.IsValid())
1184 for (int32 i = 0; i < ClientData->SavedMoves.Num() - 1; i++)
1186 const FSavedMovePtr& CurrentMove = ClientData->SavedMoves[i];
1187 if (CurrentMove->IsImportantMove(ClientData->LastAckedMove))
1189 OldMove = CurrentMove;
1196 FSavedMovePtr NewMovePtr = ClientData->CreateSavedMove();
1198 if (NewMove ==
nullptr)
1203 NewMove->SetMoveFor(CharacterOwner, DeltaTime, NewAcceleration, *ClientData);
1204 const UWorld* MyWorld = GetWorld();
1211 if (
bAllowMovementMerging && PendingMove->CanCombineWith(NewMovePtr, CharacterOwner, ClientData->MaxMoveDeltaTime * CharacterOwner->GetActorTimeDilation(*MyWorld)))
1213 QUICK_SCOPE_CYCLE_COUNTER(STAT_VRCharacterMovementComponent_CombineNetMove);
1217 FVector OldStartLocation = PendingMove->GetRevertedLocation();
1220 FVector OverlapLocation = OldStartLocation;
1224 const bool bAttachedToObject = (NewMovePtr->StartAttachParent !=
nullptr);
1225 if (bAttachedToObject || !OverlapTest(OverlapLocation, PendingMove->StartRotation.Quaternion(), UpdatedComponent->GetCollisionObjectType(), GetPawnCapsuleCollisionShape(SHRINK_None), CharacterOwner))
1235 UE_LOG(LogVRCharacterMovement, VeryVerbose, TEXT(
"CombineMove: add delta %f + %f and revert from %f %f to %f %f"), DeltaTime, ClientData->PendingMove->DeltaTime, UpdatedComponent->GetComponentLocation().X, UpdatedComponent->GetComponentLocation().Y, OverlapLocation.X, OverlapLocation.Y);
1237 NewMove->CombineWith(PendingMove, CharacterOwner, PC, OldStartLocation);
1244 CharacterOwner->FaceRotation(PC->GetControlRotation(), NewMove->DeltaTime);
1248 NewMove->SetInitialPosition(CharacterOwner);
1251 if (ClientData->SavedMoves.Num() > 0 && ClientData->SavedMoves.Last() == ClientData->PendingMove)
1253 const bool bAllowShrinking =
false;
1254 ClientData->SavedMoves.Pop(bAllowShrinking);
1256 ClientData->FreeMove(ClientData->PendingMove);
1257 ClientData->PendingMove =
nullptr;
1258 PendingMove =
nullptr;
1262 UE_LOG(LogVRCharacterMovement, Verbose, TEXT(
"Not combining move [would collide at start location]"));
1272 Acceleration = NewMove->Acceleration.GetClampedToMaxSize(GetMaxAcceleration());
1273 AnalogInputModifier = ComputeAnalogInputModifier();
1276 CharacterOwner->ClientRootMotionParams.Clear();
1277 CharacterOwner->SavedRootMotion.Clear();
1280 NewMove->PostUpdate(CharacterOwner, FSavedMove_Character::PostUpdate_Record);
1283 if (CharacterOwner->IsReplicatingMovement())
1285 check(NewMove == NewMovePtr.Get());
1286 ClientData->SavedMoves.Push(NewMovePtr);
1288 static const auto CVarNetEnableMoveCombining = IConsoleManager::Get().FindConsoleVariable(TEXT(
"p.NetEnableMoveCombining"));
1289 const bool bCanDelayMove = (CVarNetEnableMoveCombining->GetInt() != 0) && CanDelaySendingMove(NewMovePtr);
1291 if (bCanDelayMove && ClientData->PendingMove.IsValid() ==
false)
1295 const float NetMoveDelta = FMath::Clamp(GetClientNetSendDeltaTime(PC, ClientData, NewMovePtr), 1.f / 120.f, 1.f / 5.f);
1297 if ((MyWorld->TimeSeconds - ClientData->ClientUpdateTime) * MyWorld->GetWorldSettings()->GetEffectiveTimeDilation() < NetMoveDelta)
1300 ClientData->PendingMove = NewMovePtr;
1305 ClientData->ClientUpdateTime = MyWorld->TimeSeconds;
1307 UE_CLOG(CharacterOwner&& UpdatedComponent, LogVRCharacterMovement, VeryVerbose, TEXT(
"ClientMove Time %f Acceleration %s Velocity %s Position %s Rotation %s DeltaTime %f Mode %s MovementBase %s.%s (Dynamic:%d) DualMove? %d"),
1308 NewMove->TimeStamp, *NewMove->Acceleration.ToString(), *Velocity.ToString(), *UpdatedComponent->GetComponentLocation().ToString(), *UpdatedComponent->GetComponentRotation().ToCompactString(), NewMove->DeltaTime, *GetMovementName(),
1309 *GetNameSafe(NewMove->EndBase.Get()), *NewMove->EndBoneName.ToString(), MovementBaseUtility::IsDynamicBase(NewMove->EndBase.Get()) ? 1 : 0, ClientData->PendingMove.IsValid() ? 1 : 0);
1311 bool bSendServerMove =
true;
1313#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
1316 const float TimeSinceLossStart = (MyWorld->RealTimeSeconds - ClientData->DebugForcedPacketLossTimerStart);
1318 static const auto CVarNetForceClientServerMoveLossDuration = IConsoleManager::Get().FindConsoleVariable(TEXT(
"p.NetForceClientServerMoveLossDuration"));
1319 static const auto CVarNetForceClientServerMoveLossPercent = IConsoleManager::Get().FindConsoleVariable(TEXT(
"p.NetForceClientServerMoveLossPercent"));
1320 if (ClientData->DebugForcedPacketLossTimerStart > 0.f && (TimeSinceLossStart < CVarNetForceClientServerMoveLossDuration->GetFloat()))
1322 bSendServerMove =
false;
1323 UE_LOG(LogVRCharacterMovement, Log, TEXT(
"Drop ServerMove, %.2f time remains"), CVarNetForceClientServerMoveLossDuration->GetFloat() - TimeSinceLossStart);
1325 else if (CVarNetForceClientServerMoveLossPercent->GetFloat() != 0.f && (RandomStream.FRand() < CVarNetForceClientServerMoveLossPercent->GetFloat()))
1327 bSendServerMove =
false;
1328 ClientData->DebugForcedPacketLossTimerStart = (CVarNetForceClientServerMoveLossDuration->GetFloat() > 0) ? MyWorld->RealTimeSeconds : 0.0f;
1329 UE_LOG(LogVRCharacterMovement, Log, TEXT(
"Drop ServerMove, %.2f time remains"), CVarNetForceClientServerMoveLossDuration->GetFloat());
1333 ClientData->DebugForcedPacketLossTimerStart = 0.f;
1338 if (bSendServerMove)
1340 SCOPE_CYCLE_COUNTER(STAT_CharacterMovementCallServerMove);
1341 if (ShouldUsePackedMovementRPCs())
1343 CallServerMovePacked(NewMove, ClientData->PendingMove.Get(), OldMove.Get());
1352 ClientData->PendingMove = NULL;
1364 : Super(ObjectInitializer)
1366 PostPhysicsTickFunction.bCanEverTick =
true;
1367 PostPhysicsTickFunction.bStartWithTickEnabled =
false;
1368 PrimaryComponentTick.TickGroup = TG_PrePhysics;
1377 bRequestedMoveUseAcceleration =
false;
1382 Super::OnRegister();
1386 const UWorld* MyWorld = GetWorld();
1387 const bool bIsReplay = (MyWorld && MyWorld->IsPlayingReplay());
1392 NetworkSmoothingMode = ENetworkSmoothingMode::Exponential;
1399 if (!HasValidData())
1404 if (CharacterOwner && CharacterOwner->IsLocallyControlled())
1417 Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
1429 if (UpdatedPrimitive && RepulsionForce > 0.0f && CharacterOwner !=
nullptr)
1431 const TArray<FOverlapInfo>& Overlaps = UpdatedPrimitive->GetOverlapInfos();
1432 if (Overlaps.Num() > 0)
1434 FCollisionQueryParams QueryParams;
1435 QueryParams.bReturnFaceIndex =
false;
1436 QueryParams.bReturnPhysicalMaterial =
false;
1438 float CapsuleRadius = 0.f;
1439 float CapsuleHalfHeight = 0.f;
1440 CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleSize(CapsuleRadius, CapsuleHalfHeight);
1441 const float RepulsionForceRadius = CapsuleRadius * 1.2f;
1442 const float StopBodyDistance = 2.5f;
1448 MyLocation = UpdatedPrimitive->GetComponentLocation();
1450 for (int32 i = 0; i < Overlaps.Num(); i++)
1452 const FOverlapInfo& Overlap = Overlaps[i];
1454 UPrimitiveComponent* OverlapComp = Overlap.OverlapInfo.Component.Get();
1455 if (!OverlapComp || OverlapComp->Mobility < EComponentMobility::Movable)
1461 FBodyInstance* OverlapBody =
nullptr;
1462 const int32 OverlapBodyIndex = Overlap.GetBodyIndex();
1463 const USkeletalMeshComponent* SkelMeshForBody = (OverlapBodyIndex != INDEX_NONE) ? Cast<USkeletalMeshComponent>(OverlapComp) :
nullptr;
1464 if (SkelMeshForBody !=
nullptr)
1466 OverlapBody = SkelMeshForBody->Bodies.IsValidIndex(OverlapBodyIndex) ? SkelMeshForBody->Bodies[OverlapBodyIndex] :
nullptr;
1470 OverlapBody = OverlapComp->GetBodyInstance();
1475 UE_LOG(LogVRCharacterMovement,
Warning, TEXT(
"%s could not find overlap body for body index %d"), *GetName(), OverlapBodyIndex);
1479 if (!OverlapBody->IsInstanceSimulatingPhysics())
1484 FTransform BodyTransform = OverlapBody->GetUnrealWorldTransform();
1486 FVector BodyVelocity = OverlapBody->GetUnrealWorldVelocity();
1487 FVector BodyLocation = BodyTransform.GetLocation();
1491 bool bHasHit = UpdatedPrimitive->LineTraceComponent(Hit, BodyLocation,
1492 FVector(MyLocation.X, MyLocation.Y, BodyLocation.Z),
1495 FVector HitLoc = Hit.ImpactPoint;
1496 bool bIsPenetrating = Hit.bStartPenetrating || Hit.PenetrationDepth > StopBodyDistance;
1501 HitLoc = BodyLocation;
1502 bIsPenetrating =
true;
1505 const float DistanceNow = (HitLoc - BodyLocation).SizeSquared2D();
1506 const float DistanceLater = (HitLoc - (BodyLocation + BodyVelocity * DeltaSeconds)).SizeSquared2D();
1508 if (bHasHit && DistanceNow < StopBodyDistance && !bIsPenetrating)
1510 OverlapBody->SetLinearVelocity(FVector(0.0f, 0.0f, 0.0f),
false);
1512 else if (DistanceLater <= DistanceNow || bIsPenetrating)
1514 FVector ForceCenter = MyLocation;
1518 ForceCenter.Z = HitLoc.Z;
1522 ForceCenter.Z = FMath::Clamp(BodyLocation.Z, MyLocation.Z - CapsuleHalfHeight, MyLocation.Z + CapsuleHalfHeight);
1525 OverlapBody->AddRadialForceToBody(ForceCenter, RepulsionForceRadius, RepulsionForce * Mass, ERadialImpulseFalloff::RIF_Constant);
1535 Super::SetUpdatedComponent(NewUpdatedComponent);
1537 if (UpdatedComponent)
1549 UpdatedComponent->PrimaryComponentTick.RemovePrerequisite(
this, PrimaryComponentTick);
1553 this->PrimaryComponentTick.AddPrerequisite(UpdatedComponent, UpdatedComponent->PrimaryComponentTick);
1564 if (UpdatedComponent == NULL)
1570 bool bMoveResult = MoveUpdatedComponent(Delta, NewRotation, bSweep, &OutHit, Teleport);
1573 if (OutHit.bStartPenetrating && UpdatedComponent)
1576 if (ResolvePenetration(RequestedAdjustment, OutHit, NewRotation))
1580 bMoveResult = MoveUpdatedComponent(Delta, NewRotation, bSweep, &TempHit, Teleport);
1583 if (TempHit.bStartPenetrating)
1586 OutHit.bStartPenetrating = TempHit.bStartPenetrating;
1595 if (!CurrentFloor.IsWalkableFloor())
1601 const FVector Delta = FVector(InVelocity.X, InVelocity.Y, 0.f) * DeltaSeconds;
1602 FHitResult Hit(1.f);
1603 FVector RampVector = ComputeGroundMovementDelta(Delta, CurrentFloor.HitResult, CurrentFloor.bLineTrace);
1605 float LastMoveTimeSlice = DeltaSeconds;
1607 if (Hit.bStartPenetrating)
1613 if (Hit.bStartPenetrating)
1615 OnCharacterStuckInGeometry(&Hit);
1618 else if (Hit.IsValidBlockingHit())
1621 float PercentTimeApplied = Hit.Time;
1622 if ((Hit.Time > 0.f) && (Hit.Normal.Z > KINDA_SMALL_NUMBER) && IsWalkable(Hit))
1625 const float InitialPercentRemaining = 1.f - PercentTimeApplied;
1626 RampVector = ComputeGroundMovementDelta(Delta * InitialPercentRemaining, Hit,
false);
1627 LastMoveTimeSlice = InitialPercentRemaining * LastMoveTimeSlice;
1630 const float SecondHitPercent = Hit.Time * InitialPercentRemaining;
1631 PercentTimeApplied = FMath::Clamp(PercentTimeApplied + SecondHitPercent, 0.f, 1.f);
1634 if (Hit.IsValidBlockingHit())
1636 if (CanStepUp(Hit) || (CharacterOwner->GetMovementBase() != NULL && CharacterOwner->GetMovementBase()->GetOwner() == Hit.GetActor()))
1639 const FVector PreStepUpLocation = UpdatedComponent->GetComponentLocation();
1640 const FVector GravDir(0.f, 0.f, -1.f);
1643 if (!
StepUp(GravDir, (Delta * (1.f - PercentTimeApplied)) , Hit, OutStepDownResult))
1645 UE_LOG(LogVRCharacterMovement, Verbose, TEXT(
"- StepUp (ImpactNormal %s, Normal %s"), *Hit.ImpactNormal.ToString(), *Hit.Normal.ToString());
1646 HandleImpact(Hit, LastMoveTimeSlice, RampVector);
1652 UE_LOG(LogVRCharacterMovement, Verbose, TEXT(
"+ StepUp (ImpactNormal %s, Normal %s"), *Hit.ImpactNormal.ToString(), *Hit.Normal.ToString());
1653 if (!bMaintainHorizontalGroundVelocity)
1656 bJustTeleported =
true;
1657 const float StepUpTimeSlice = (1.f - PercentTimeApplied) * DeltaSeconds;
1658 if (!HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity() && StepUpTimeSlice >= KINDA_SMALL_NUMBER)
1660 Velocity = (UpdatedComponent->GetComponentLocation() - PreStepUpLocation) / StepUpTimeSlice;
1666 else if (Hit.Component.IsValid() && !Hit.Component.Get()->CanCharacterStepUp(CharacterOwner))
1668 HandleImpact(Hit, LastMoveTimeSlice, RampVector);
1678 SCOPE_CYCLE_COUNTER(STAT_CharStepUp);
1680 if (!CanStepUp(InHit) || MaxStepHeight <= 0.f)
1685 FVector OldLocation;
1690 OldLocation = UpdatedComponent->GetComponentLocation();
1692 float PawnRadius, PawnHalfHeight;
1693 CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleSize(PawnRadius, PawnHalfHeight);
1696 const float InitialImpactZ = InHit.ImpactPoint.Z;
1697 if (InitialImpactZ > OldLocation.Z + (PawnHalfHeight - PawnRadius))
1702 if (GravDir.IsZero())
1708 ensure(GravDir.IsNormalized());
1710 float StepTravelUpHeight = MaxStepHeight;
1711 float StepTravelDownHeight = StepTravelUpHeight;
1712 const float StepSideZ = -1.f * FVector::DotProduct(InHit.ImpactNormal, GravDir);
1713 float PawnInitialFloorBaseZ = OldLocation.Z -PawnHalfHeight;
1714 float PawnFloorPointZ = PawnInitialFloorBaseZ;
1716 if (IsMovingOnGround() && CurrentFloor.IsWalkableFloor())
1719 const float FloorDist = FMath::Max(0.f, CurrentFloor.GetDistanceToFloor());
1720 PawnInitialFloorBaseZ -= FloorDist;
1721 StepTravelUpHeight = FMath::Max(StepTravelUpHeight - FloorDist, 0.f);
1722 StepTravelDownHeight = (MaxStepHeight + MAX_FLOOR_DIST*2.f);
1724 const bool bHitVerticalFace = !
IsWithinEdgeTolerance(InHit.Location, InHit.ImpactPoint, PawnRadius);
1725 if (!CurrentFloor.bLineTrace && !bHitVerticalFace)
1727 PawnFloorPointZ = CurrentFloor.HitResult.ImpactPoint.Z;
1732 PawnFloorPointZ -= CurrentFloor.FloorDist;
1737 if (InitialImpactZ <= PawnInitialFloorBaseZ)
1746 FHitResult SweepUpHit(1.f);
1747 const FQuat PawnRotation = UpdatedComponent->GetComponentQuat();
1748 MoveUpdatedComponent(-GravDir * StepTravelUpHeight, PawnRotation,
true, &SweepUpHit);
1750 if (SweepUpHit.bStartPenetrating)
1759 FHitResult Hit(1.f);
1760 MoveUpdatedComponent(Delta, PawnRotation,
true, &Hit);
1763 if (Hit.bBlockingHit)
1765 if (Hit.bStartPenetrating)
1775 if (SweepUpHit.bBlockingHit && Hit.bBlockingHit)
1777 HandleImpact(SweepUpHit);
1788 const float ForwardHitTime = Hit.Time;
1789 const float ForwardSlideAmount =
SlideAlongSurface(Delta, 1.f - Hit.Time, Hit.Normal, Hit,
true);
1798 if (ForwardHitTime == 0.f && ForwardSlideAmount == 0.f)
1806 MoveUpdatedComponent(GravDir * StepTravelDownHeight, UpdatedComponent->GetComponentQuat(),
true, &Hit);
1809 if (Hit.bStartPenetrating)
1815 FStepDownResult StepDownResult;
1816 if (Hit.IsValidBlockingHit())
1819 const float DeltaZ = Hit.ImpactPoint.Z - PawnFloorPointZ;
1820 if (DeltaZ > MaxStepHeight)
1828 if (!IsWalkable(Hit))
1831 const bool bNormalTowardsMe = (Delta | Hit.ImpactNormal) < 0.f;
1832 if (bNormalTowardsMe)
1841 if (Hit.Location.Z > OldLocation.Z)
1858 if (DeltaZ > 0.f && !CanStepUp(Hit))
1866 if (OutStepDownResult != NULL)
1868 FindFloor(UpdatedComponent->GetComponentLocation(), StepDownResult.FloorResult,
false, &Hit);
1872 if (Hit.Location.Z > OldLocation.Z)
1876 if (!StepDownResult.FloorResult.bBlockingHit && StepSideZ <
MAX_STEP_SIDE_Z)
1883 StepDownResult.bComputedFloor =
true;
1888 if (OutStepDownResult != NULL)
1890 *OutStepDownResult = StepDownResult;
1894 bJustTeleported |= !bMaintainHorizontalGroundVelocity;
1901 const float DistFromCenterSq = (TestImpactPoint - CapsuleLocation).SizeSquared2D();
1903 return DistFromCenterSq < ReducedRadiusSq;
1908 const float DistFromCenterSq = (TestImpactPoint - CapsuleLocation).SizeSquared2D();
1910 return DistFromCenterSq < ReducedRadiusSq;
1915 SCOPE_CYCLE_COUNTER(STAT_CharStepUp);
1917 if (!CanStepUp(InHit) || MaxStepHeight <= 0.f)
1922 FVector OldLocation;
1927 OldLocation = UpdatedComponent->GetComponentLocation();
1929 float PawnRadius, PawnHalfHeight;
1930 CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleSize(PawnRadius, PawnHalfHeight);
1933 const float InitialImpactZ = InHit.ImpactPoint.Z;
1934 if (InitialImpactZ > OldLocation.Z + (PawnHalfHeight - PawnRadius))
1940 if (InitialImpactZ <= OldLocation.Z - PawnHalfHeight)
1945 if (GravDir.IsZero())
1951 ensure(GravDir.IsNormalized());
1953 float StepTravelUpHeight = MaxStepHeight;
1954 float StepTravelDownHeight = StepTravelUpHeight;
1955 const float StepSideZ = -1.f * (InHit.ImpactNormal | GravDir);
1956 float PawnInitialFloorBaseZ = OldLocation.Z - PawnHalfHeight;
1957 float PawnFloorPointZ = PawnInitialFloorBaseZ;
1963 FHitResult SweepUpHit(1.f);
1964 const FQuat PawnRotation = UpdatedComponent->GetComponentQuat();
1965 MoveUpdatedComponent(-GravDir * StepTravelUpHeight, PawnRotation,
true, &SweepUpHit);
1967 if (SweepUpHit.bStartPenetrating)
1975 FHitResult Hit(1.f);
1986 MoveUpdatedComponent(Delta, PawnRotation,
true, &Hit);
1991 if (Hit.bBlockingHit)
1993 if (Hit.bStartPenetrating)
2003 if (SweepUpHit.bBlockingHit && Hit.bBlockingHit)
2006 HandleImpact(SweepUpHit);
2039 MoveUpdatedComponent(GravDir * StepTravelDownHeight, UpdatedComponent->GetComponentQuat(),
true, &Hit);
2042 if (Hit.bStartPenetrating)
2048 FStepDownResult StepDownResult;
2049 if (Hit.IsValidBlockingHit())
2052 const float DeltaZ = Hit.ImpactPoint.Z - PawnFloorPointZ;
2053 if (DeltaZ > MaxStepHeight)
2055 UE_LOG(LogVRCharacterMovement, VeryVerbose, TEXT(
"- Reject StepUp (too high Height %.3f) up from floor base %f"), DeltaZ, PawnInitialFloorBaseZ);
2061 if (!IsWalkable(Hit))
2064 const bool bNormalTowardsMe = (Delta | Hit.ImpactNormal) < 0.f;
2065 if (bNormalTowardsMe)
2074 if (Hit.Location.Z > OldLocation.Z)
2076 UE_LOG(LogVRCharacterMovement, VeryVerbose, TEXT(
"- Reject StepUp (unwalkable normal %s above old position)"), *Hit.ImpactNormal.ToString());
2085 UE_LOG(LogVRCharacterMovement, VeryVerbose, TEXT(
"- Reject StepUp (outside edge tolerance)"));
2091 if (DeltaZ > 0.f && !CanStepUp(Hit))
2093 UE_LOG(LogVRCharacterMovement, VeryVerbose, TEXT(
"- Reject StepUp (up onto surface with !CanStepUp())"));
2099 if (OutStepDownResult != NULL)
2101 FindFloor(UpdatedComponent->GetComponentLocation(), StepDownResult.FloorResult,
false, &Hit);
2105 if (Hit.Location.Z > OldLocation.Z)
2109 if (!StepDownResult.FloorResult.bBlockingHit && StepSideZ <
MAX_STEP_SIDE_Z)
2116 StepDownResult.bComputedFloor =
true;
2121 if (OutStepDownResult != NULL)
2123 *OutStepDownResult = StepDownResult;
2127 bJustTeleported |= !bMaintainHorizontalGroundVelocity;
2134 if (!HasValidData())
2139 const UPrimitiveComponent* MovementBase = CharacterOwner->GetMovementBase();
2140 if (!MovementBaseUtility::UseRelativeLocation(MovementBase))
2145 if (!IsValid(MovementBase) || !IsValid(MovementBase->GetOwner()))
2152 TGuardValue<EMoveComponentFlags> ScopedFlagRestore(MoveComponentFlags, MoveComponentFlags | MOVECOMP_IgnoreBases);
2154 FQuat DeltaQuat = FQuat::Identity;
2155 FVector DeltaPosition = FVector::ZeroVector;
2158 FVector NewBaseLocation;
2159 if (!MovementBaseUtility::GetMovementBaseTransform(MovementBase, CharacterOwner->GetBasedMovement().BoneName, NewBaseLocation, NewBaseQuat))
2165 const bool bRotationChanged = !OldBaseQuat.Equals(NewBaseQuat, 1e-8f);
2166 if (bRotationChanged)
2168 DeltaQuat = NewBaseQuat * OldBaseQuat.Inverse();
2172 if (bRotationChanged || (OldBaseLocation != NewBaseLocation))
2175 const FQuatRotationTranslationMatrix OldLocalToWorld(OldBaseQuat, OldBaseLocation);
2176 const FQuatRotationTranslationMatrix NewLocalToWorld(NewBaseQuat, NewBaseLocation);
2178 if (CharacterOwner->IsMatineeControlled())
2180 FRotationTranslationMatrix HardRelMatrix(CharacterOwner->GetBasedMovement().Rotation, CharacterOwner->GetBasedMovement().Location);
2181 const FMatrix NewWorldTM = HardRelMatrix * NewLocalToWorld;
2182 const FQuat NewWorldRot = bIgnoreBaseRotation ? UpdatedComponent->GetComponentQuat() : NewWorldTM.ToQuat();
2183 MoveUpdatedComponent(NewWorldTM.GetOrigin() - UpdatedComponent->GetComponentLocation(), NewWorldRot,
true);
2187 FQuat FinalQuat = UpdatedComponent->GetComponentQuat();
2189 if (bRotationChanged && !bIgnoreBaseRotation)
2192 const FQuat PawnOldQuat = UpdatedComponent->GetComponentQuat();
2193 const FQuat TargetQuat = DeltaQuat * FinalQuat;
2194 FRotator TargetRotator(TargetQuat);
2195 CharacterOwner->FaceRotation(TargetRotator, 0.f);
2196 FinalQuat = UpdatedComponent->GetComponentQuat();
2198 if (PawnOldQuat.Equals(FinalQuat, 1e-6f))
2202 if (bOrientRotationToMovement || (bUseControllerDesiredRotation && CharacterOwner->Controller))
2204 TargetRotator.Pitch = 0.f;
2205 TargetRotator.Roll = 0.f;
2206 MoveUpdatedComponent(FVector::ZeroVector, TargetRotator,
false);
2207 FinalQuat = UpdatedComponent->GetComponentQuat();
2212 if (CharacterOwner->Controller)
2214 const FQuat PawnDeltaRotation = FinalQuat * PawnOldQuat.Inverse();
2215 FRotator FinalRotation = FinalQuat.Rotator();
2216 UpdateBasedRotation(FinalRotation, PawnDeltaRotation.Rotator());
2217 FinalQuat = UpdatedComponent->GetComponentQuat();
2222 float HalfHeight, Radius;
2223 CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleSize(Radius, HalfHeight);
2225 FVector
const BaseOffset(0.0f, 0.0f, 0.0f);
2226 FVector
const LocalBasePos = OldLocalToWorld.InverseTransformPosition(UpdatedComponent->GetComponentLocation() - BaseOffset);
2227 FVector
const NewWorldPos = ConstrainLocationToPlane(NewLocalToWorld.TransformPosition(LocalBasePos) + BaseOffset);
2228 DeltaPosition = ConstrainDirectionToPlane(NewWorldPos - UpdatedComponent->GetComponentLocation());
2231 if (bFastAttachedMove)
2234 UpdatedComponent->SetWorldLocationAndRotation(NewWorldPos, FinalQuat,
false);
2239 FVector BaseMoveDelta = NewBaseLocation - OldBaseLocation;
2240 if (!bRotationChanged && (BaseMoveDelta.X == 0.f) && (BaseMoveDelta.Y == 0.f))
2242 DeltaPosition.X = 0.f;
2243 DeltaPosition.Y = 0.f;
2246 FHitResult MoveOnBaseHit(1.f);
2247 const FVector OldLocation = UpdatedComponent->GetComponentLocation();
2248 MoveUpdatedComponent(DeltaPosition, FinalQuat,
true, &MoveOnBaseHit);
2249 if ((UpdatedComponent->GetComponentLocation() - (OldLocation + DeltaPosition)).IsNearlyZero() ==
false)
2251 OnUnableToFollowBaseMove(DeltaPosition, OldLocation, MoveOnBaseHit);
2256 if (MovementBase->IsSimulatingPhysics() && CharacterOwner->GetMesh())
2258 CharacterOwner->GetMesh()->ApplyDeltaToAllPhysicsTransforms(DeltaPosition, DeltaQuat);
2265 FVector Result = FVector::ZeroVector;
2269 UPrimitiveComponent* MovementBase = CharacterOwner->GetMovementBase();
2270 if (MovementBaseUtility::IsDynamicBase(MovementBase))
2272 FVector BaseVelocity = MovementBaseUtility::GetMovementBaseVelocity(MovementBase, CharacterOwner->GetBasedMovement().BoneName);
2274 if (bImpartBaseAngularVelocity)
2277 const FVector CharacterBasePosition = (UpdatedComponent->GetComponentLocation());
2278 const FVector BaseTangentialVel = MovementBaseUtility::GetMovementBaseTangentialVelocity(MovementBase, CharacterOwner->GetBasedMovement().BoneName, CharacterBasePosition);
2279 BaseVelocity += BaseTangentialVel;
2282 if (bImpartBaseVelocityX)
2284 Result.X = BaseVelocity.X;
2286 if (bImpartBaseVelocityY)
2288 Result.Y = BaseVelocity.Y;
2290 if (bImpartBaseVelocityZ)
2292 Result.Z = BaseVelocity.Z;
2304 SCOPE_CYCLE_COUNTER(STAT_CharFindFloor);
2307 if (!HasValidData() || !UpdatedComponent->IsQueryCollisionEnabled())
2309 OutFloorResult.Clear();
2314 check(CharacterOwner->GetCapsuleComponent());
2316 FVector UseCapsuleLocation = CapsuleLocation;
2321 const float HeightCheckAdjust = ((IsMovingOnGround() ||
IsClimbing()) ? MAX_FLOOR_DIST + KINDA_SMALL_NUMBER : -MAX_FLOOR_DIST);
2323 float FloorSweepTraceDist = FMath::Max(MAX_FLOOR_DIST, MaxStepHeight + HeightCheckAdjust);
2324 float FloorLineTraceDist = FloorSweepTraceDist;
2325 bool bNeedToValidateFloor =
true;
2328 FFindFloorResult LastFloor = CurrentFloor;
2331 if (FloorLineTraceDist > 0.f || FloorSweepTraceDist > 0.f)
2335 if (bAlwaysCheckFloor || !bCanUseCachedLocation || bForceNextFloorCheck || bJustTeleported)
2337 MutableThis->bForceNextFloorCheck =
false;
2338 ComputeFloorDist(UseCapsuleLocation, FloorLineTraceDist, FloorSweepTraceDist, OutFloorResult, CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleRadius(), DownwardSweepResult);
2343 UPrimitiveComponent* MovementBase = CharacterOwner->GetMovementBase();
2344 const AActor* BaseActor = MovementBase ? MovementBase->GetOwner() : NULL;
2346 const ECollisionChannel CollisionChannel = UpdatedComponent->GetCollisionObjectType();
2348 if (MovementBase != NULL)
2350 MutableThis->bForceNextFloorCheck = !MovementBase->IsQueryCollisionEnabled()
2351 || MovementBase->GetCollisionResponseToChannel(CollisionChannel) != ECR_Block
2352 || MovementBaseUtility::IsDynamicBase(MovementBase);
2355 const bool IsActorBasePendingKill = BaseActor && BaseActor->IsPendingKill();
2357 if (!bForceNextFloorCheck && !IsActorBasePendingKill && MovementBase)
2360 OutFloorResult = CurrentFloor;
2361 bNeedToValidateFloor =
false;
2365 MutableThis->bForceNextFloorCheck =
false;
2366 ComputeFloorDist(UseCapsuleLocation, FloorLineTraceDist, FloorSweepTraceDist, OutFloorResult, CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleRadius(), DownwardSweepResult);
2376 if (OutFloorResult.FloorDist <= -FMath::Max(MAX_FLOOR_DIST, CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleRadius()))
2381 ECollisionResponse FloorResponse;
2382 if (OutFloorResult.HitResult.Component.IsValid())
2385 if (FloorResponse == ECR_Ignore || FloorResponse == ECR_Overlap)
2386 OutFloorResult = LastFloor;
2393 if (bNeedToValidateFloor && OutFloorResult.bBlockingHit && !OutFloorResult.bLineTrace)
2395 const bool bCheckRadius =
true;
2396 if (ShouldComputePerchResult(OutFloorResult.HitResult, bCheckRadius))
2398 float MaxPerchFloorDist = FMath::Max(MAX_FLOOR_DIST, MaxStepHeight + HeightCheckAdjust);
2401 MaxPerchFloorDist += FMath::Max(0.f, PerchAdditionalHeight);
2404 FFindFloorResult PerchFloorResult;
2405 if (ComputePerchResult(GetValidPerchRadius(), OutFloorResult.HitResult, MaxPerchFloorDist, PerchFloorResult))
2408 const float AvgFloorDist = (MIN_FLOOR_DIST + MAX_FLOOR_DIST) * 0.5f;
2409 const float MoveUpDist = (AvgFloorDist - OutFloorResult.FloorDist);
2410 if (MoveUpDist + PerchFloorResult.FloorDist >= MaxPerchFloorDist)
2412 OutFloorResult.FloorDist = AvgFloorDist;
2416 if (!OutFloorResult.bWalkableFloor)
2418 OutFloorResult.SetFromLineTrace(PerchFloorResult.HitResult, OutFloorResult.FloorDist, FMath::Max(OutFloorResult.FloorDist, MIN_FLOOR_DIST),
true);
2424 OutFloorResult.bWalkableFloor =
false;
2434 if (CharacterOwner && GetPhysicsVolume()->bWaterVolume)
2436 const float CollisionHalfHeight = CharacterOwner->GetSimpleCollisionHalfHeight();
2438 if ((CollisionHalfHeight == 0.f) || (Buoyancy == 0.f))
2444 UBrushComponent* VolumeBrushComp = GetPhysicsVolume()->GetBrushComponent();
2445 FHitResult Hit(1.f);
2446 if (VolumeBrushComp)
2458 TraceStart = UpdatedComponent->GetComponentLocation() + FVector(0.f, 0.f, CollisionHalfHeight);
2459 TraceEnd = UpdatedComponent->GetComponentLocation() -FVector(0.f, 0.f, CollisionHalfHeight);
2463 VolumeBrushComp->LineTraceComponent(Hit, TraceStart, TraceEnd, NewTraceParams);
2466 depth = (Hit.Time == 1.f) ? 1.f : (1.f - Hit.Time);
2478 SetNavWalkingPhysics(
false);
2480 bool bCanTeleport =
true;
2483 FVector CollisionFreeLocation;
2487 CollisionFreeLocation = UpdatedComponent->GetComponentLocation();
2490 bCanTeleport = GetWorld()->FindTeleportSpot(CharacterOwner, CollisionFreeLocation, UpdatedComponent->GetComponentRotation());
2502 CharacterOwner->SetActorLocation(CollisionFreeLocation);
2506 SetNavWalkingPhysics(
true);
2510 bWantsToLeaveNavWalking = !bCanTeleport;
2511 return bCanTeleport;
2516 if (deltaTime < MIN_TICK_TIME)
2524 RestorePreAdditiveRootMotionVelocity();
2527 if (!HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity())
2529 if (bCheatFlying && Acceleration.IsZero())
2531 Velocity = FVector::ZeroVector;
2533 const float Friction = 0.5f * GetPhysicsVolume()->FluidFriction;
2534 CalcVelocity(deltaTime, Friction,
true, GetMaxBrakingDeceleration());
2537 ApplyRootMotionToVelocity(deltaTime);
2542 bool bExtremeInput =
false;
2551 bJustTeleported =
false;
2553 FVector OldLocation = UpdatedComponent->GetComponentLocation();
2554 const FVector Adjusted = Velocity * deltaTime;
2555 FHitResult Hit(1.f);
2560 const FVector GravDir = FVector(0.f, 0.f, -1.f);
2561 const FVector VelDir = Velocity.GetSafeNormal();
2562 const float UpDown = GravDir | VelDir;
2564 bool bSteppedUp =
false;
2565 if ((FMath::Abs(Hit.ImpactNormal.Z) < 0.2f) && (UpDown < 0.5f) && (UpDown > -0.2f) && CanStepUp(Hit))
2567 float stepZ = UpdatedComponent->GetComponentLocation().Z;
2571 OldLocation.Z = UpdatedComponent->GetComponentLocation().Z + (OldLocation.Z - stepZ);
2578 HandleImpact(Hit, deltaTime, Adjusted);
2583 if (!bJustTeleported)
2585 if (!HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity())
2588 Velocity = ((UpdatedComponent->GetComponentLocation() - OldLocation)) / deltaTime;
2597 SCOPE_CYCLE_COUNTER(STAT_CharPhysFalling);
2599 if (deltaTime < MIN_TICK_TIME)
2604 FVector FallAcceleration = GetFallingLateralAcceleration(deltaTime);
2605 FallAcceleration.Z = 0.f;
2606 const bool bHasLimitedAirControl = ShouldLimitAirControl(deltaTime, FallAcceleration);
2611 float remainingTime = deltaTime;
2612 while ((remainingTime >= MIN_TICK_TIME) && (Iterations < MaxSimulationIterations))
2615 float timeTick = GetSimulationTimeStep(remainingTime, Iterations);
2616 remainingTime -= timeTick;
2618 const FVector OldLocation = UpdatedComponent->GetComponentLocation();
2621 const FQuat PawnRotation = UpdatedComponent->GetComponentQuat();
2622 bJustTeleported =
false;
2624 RestorePreAdditiveRootMotionVelocity();
2627 const FVector OldVelocity = Velocity;
2630 const float MaxDecel = GetMaxBrakingDeceleration();
2631 if (!HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity())
2636 TGuardValue<FVector> RestoreAcceleration(Acceleration, FallAcceleration);
2638 CalcVelocity(timeTick, FallingLateralFriction,
false, BrakingDecelerationFalling);
2639 Velocity.Z = OldVelocity.Z;
2646 const FVector Gravity(0.f, 0.f, GetGravityZ());
2648 float GravityTime = timeTick;
2651 bool bEndingJumpForce =
false;
2652 if (CharacterOwner->JumpForceTimeRemaining > 0.0f)
2655 const float JumpForceTime = FMath::Min(CharacterOwner->JumpForceTimeRemaining, timeTick);
2656 GravityTime = bApplyGravityWhileJumping ? timeTick : FMath::Max(0.0f, timeTick - JumpForceTime);
2659 CharacterOwner->JumpForceTimeRemaining -= JumpForceTime;
2660 if (CharacterOwner->JumpForceTimeRemaining <= 0.0f)
2662 CharacterOwner->ResetJumpState();
2663 bEndingJumpForce =
true;
2668 Velocity = NewFallVelocity(Velocity, Gravity, GravityTime);
2671 static const auto CVarForceJumpPeakSubstep = IConsoleManager::Get().FindConsoleVariable(TEXT(
"p.ForceJumpPeakSubstep"));
2672 if (CVarForceJumpPeakSubstep->GetInt() != 0 && OldVelocity.Z > 0.f && Velocity.Z <= 0.f && NumJumpApexAttempts < MaxJumpApexAttemptsPerSimulation)
2674 const FVector DerivedAccel = (Velocity - OldVelocity) / timeTick;
2675 if (!FMath::IsNearlyZero(DerivedAccel.Z))
2677 const float TimeToApex = -OldVelocity.Z / DerivedAccel.Z;
2680 const float ApexTimeMinimum = 0.0001f;
2681 if (TimeToApex >= ApexTimeMinimum && TimeToApex < timeTick)
2683 const FVector ApexVelocity = OldVelocity + DerivedAccel * TimeToApex;
2684 Velocity = ApexVelocity;
2688 remainingTime += (timeTick - TimeToApex);
2689 timeTick = TimeToApex;
2691 NumJumpApexAttempts++;
2698 ApplyRootMotionToVelocity(timeTick);
2701 if (bNotifyApex && (Velocity.Z < 0.f))
2704 bNotifyApex =
false;
2709 FVector Adjusted = (0.5f * (OldVelocity + Velocity) * timeTick) + ((
AdditionalVRInputVector / deltaTime) * timeTick);
2714 if (bEndingJumpForce && !bApplyGravityWhileJumping)
2718 const float NonGravityTime = FMath::Max(0.f, timeTick - GravityTime);
2719 Adjusted = ((OldVelocity * NonGravityTime) + (0.5f * (OldVelocity + Velocity) * GravityTime)) ;
2723 FHitResult Hit(1.f);
2726 if (!HasValidData())
2732 float LastMoveTimeSlice = timeTick;
2733 float subTimeTickRemaining = timeTick * (1.f - Hit.Time);
2738 remainingTime += subTimeTickRemaining;
2739 StartSwimmingVR(OldCapsuleLocation, OldVelocity, timeTick, remainingTime, Iterations);
2742 else if (Hit.bBlockingHit)
2747 remainingTime += subTimeTickRemaining;
2755 Adjusted = Velocity * timeTick;
2760 FVector PawnLocation = UpdatedComponent->GetComponentLocation();
2764 FFindFloorResult FloorResult;
2765 FindFloor(PawnLocation, FloorResult,
false, NULL);
2766 if (FloorResult.IsWalkableFloor() && IsValidLandingSpot(PawnLocation, FloorResult.HitResult))
2769 remainingTime += subTimeTickRemaining;
2770 ProcessLanded(FloorResult.HitResult, remainingTime, Iterations);
2775 HandleImpact(Hit, LastMoveTimeSlice, Adjusted);
2778 if (!HasValidData() || !IsFalling())
2786 FVector VelocityNoAirControl = OldVelocity;
2787 FVector AirControlAccel = Acceleration;
2788 if (bHasLimitedAirControl)
2793 TGuardValue<FVector> RestoreAcceleration(Acceleration, FVector::ZeroVector);
2794 TGuardValue<FVector> RestoreVelocity(Velocity, OldVelocity);
2796 CalcVelocity(timeTick, FallingLateralFriction,
false, MaxDecel);
2797 VelocityNoAirControl = FVector(Velocity.X, Velocity.Y, OldVelocity.Z);
2798 VelocityNoAirControl = NewFallVelocity(VelocityNoAirControl, Gravity, GravityTime);
2801 const bool bCheckLandingSpot =
false;
2802 AirControlAccel = (Velocity - VelocityNoAirControl) / timeTick;
2803 const FVector AirControlDeltaV = LimitAirControl(LastMoveTimeSlice, AirControlAccel, Hit, bCheckLandingSpot) * LastMoveTimeSlice;
2804 Adjusted = (VelocityNoAirControl + AirControlDeltaV) * LastMoveTimeSlice;
2807 const FVector OldHitNormal = Hit.Normal;
2808 const FVector OldHitImpactNormal = Hit.ImpactNormal;
2809 FVector Delta = ComputeSlideVector(Adjusted, 1.f - Hit.Time, OldHitNormal, Hit);
2812 if (subTimeTickRemaining > KINDA_SMALL_NUMBER && !bJustTeleported)
2814 const FVector NewVelocity = (Delta / subTimeTickRemaining);
2815 Velocity = HasAnimRootMotion() || CurrentRootMotion.HasOverrideVelocityWithIgnoreZAccumulate() ? FVector(Velocity.X, Velocity.Y, NewVelocity.Z) : NewVelocity;
2818 if (subTimeTickRemaining > KINDA_SMALL_NUMBER && (Delta | Adjusted) > 0.f)
2823 if (Hit.bBlockingHit)
2826 LastMoveTimeSlice = subTimeTickRemaining;
2827 subTimeTickRemaining = subTimeTickRemaining * (1.f - Hit.Time);
2833 remainingTime += subTimeTickRemaining;
2838 HandleImpact(Hit, LastMoveTimeSlice, Delta);
2841 if (!HasValidData() || !IsFalling())
2850 const FVector LastMoveNoAirControl = VelocityNoAirControl * LastMoveTimeSlice;
2851 Delta = ComputeSlideVector(LastMoveNoAirControl, 1.f, OldHitNormal, Hit);
2854 FVector PreTwoWallDelta = Delta;
2855 TwoWallAdjust(Delta, Hit, OldHitNormal);
2858 if (bHasLimitedAirControl)
2860 const bool bCheckLandingSpot =
false;
2861 const FVector AirControlDeltaV = LimitAirControl(subTimeTickRemaining, AirControlAccel, Hit, bCheckLandingSpot) * subTimeTickRemaining;
2864 if (FVector::DotProduct(AirControlDeltaV, OldHitNormal) > 0.f)
2866 Delta += (AirControlDeltaV * subTimeTickRemaining);
2871 if (subTimeTickRemaining > KINDA_SMALL_NUMBER && !bJustTeleported)
2873 const FVector NewVelocity = (Delta / subTimeTickRemaining);
2874 Velocity = HasAnimRootMotion() || CurrentRootMotion.HasOverrideVelocityWithIgnoreZAccumulate() ? FVector(Velocity.X, Velocity.Y, NewVelocity.Z) : NewVelocity;
2878 bool bDitch = ((OldHitImpactNormal.Z > 0.f) && (Hit.ImpactNormal.Z > 0.f) && (FMath::Abs(Delta.Z) <= KINDA_SMALL_NUMBER) && ((Hit.ImpactNormal | OldHitImpactNormal) < 0.f));
2880 if (Hit.Time == 0.f)
2883 FVector SideDelta = (OldHitNormal + Hit.ImpactNormal).GetSafeNormal2D();
2884 if (SideDelta.IsNearlyZero())
2886 SideDelta = FVector(OldHitNormal.Y, -OldHitNormal.X, 0).GetSafeNormal();
2894 remainingTime = 0.f;
2898 else if (GetPerchRadiusThreshold() > 0.f && Hit.Time == 1.f && OldHitImpactNormal.Z >= GetWalkableFloorZ())
2901 const FVector PawnLocation = UpdatedComponent->GetComponentLocation();
2902 const float ZMovedDist = FMath::Abs(PawnLocation.Z - OldLocation.Z);
2903 const float MovedDist2DSq = (PawnLocation - OldLocation).SizeSquared2D();
2904 if (ZMovedDist <= 0.2f * timeTick && MovedDist2DSq <= 4.f * timeTick)
2906 Velocity.X += 0.25f * GetMaxSpeed() * (RandomStream.FRand() - 0.5f);
2907 Velocity.Y += 0.25f * GetMaxSpeed() * (RandomStream.FRand() - 0.5f);
2908 Velocity.Z = FMath::Max<float>(JumpZVelocity * 0.25f, 1.f);
2909 Delta = Velocity * timeTick;
2922 FindFloor(UpdatedComponent->GetComponentLocation(), CurrentFloor,
false, NULL);
2924 if (CurrentFloor.IsWalkableFloor())
2927 if (CurrentFloor.GetDistanceToFloor() < (MIN_FLOOR_DIST + MAX_FLOOR_DIST) / 2)
2930 AdjustFloorHeight();
2932 SetBase(CurrentFloor.HitResult.Component.Get(), CurrentFloor.HitResult.BoneName);
2937 remainingTime += subTimeTickRemaining;
2938 ProcessLanded(CurrentFloor.HitResult, remainingTime, Iterations);
2943 else if (CurrentFloor.HitResult.bStartPenetrating)
2947 FHitResult Hitt(CurrentFloor.HitResult);
2948 Hit.TraceEnd = Hit.TraceStart + FVector(0.f, 0.f, MAX_FLOOR_DIST);
2950 ResolvePenetration(RequestedAdjustment, Hitt, UpdatedComponent->GetComponentQuat());
2951 bForceNextFloorCheck =
true;
2955 if (Velocity.SizeSquared2D() <= KINDA_SMALL_NUMBER * 10.f)
2968 SCOPE_CYCLE_COUNTER(STAT_CharPhysNavWalking);
2970 if (deltaTime < MIN_TICK_TIME)
2976 if ((!CharacterOwner || !CharacterOwner->Controller) && !bRunPhysicsWithNoController && !HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity())
2978 Acceleration = FVector::ZeroVector;
2979 Velocity = FVector::ZeroVector;
2986 RestorePreAdditiveRootMotionVelocity();
2990 MaintainHorizontalGroundVelocity();
2991 devCodeVR(ensureMsgf(!Velocity.ContainsNaN(), TEXT(
"PhysNavWalking: Velocity contains NaN before CalcVelocity (%s)\n%s"), *GetPathNameSafe(
this), *Velocity.ToString()));
2994 Acceleration.Z = 0.f;
2997 CalcVelocity(deltaTime, GroundFriction,
false, BrakingDecelerationWalking);
2998 devCodeVR(ensureMsgf(!Velocity.ContainsNaN(), TEXT(
"PhysNavWalking: Velocity contains NaN after CalcVelocity (%s)\n%s"), *GetPathNameSafe(
this), *Velocity.ToString()));
3001 ApplyRootMotionToVelocity(deltaTime);
3013 FVector DesiredMove = Velocity;
3014 DesiredMove.Z = 0.f;
3018 const FVector DeltaMove = DesiredMove * deltaTime;
3019 const bool bDeltaMoveNearlyZero = DeltaMove.IsNearlyZero();
3021 FVector AdjustedDest = OldLocation + DeltaMove;
3022 FNavLocation DestNavLocation;
3024 bool bSameNavLocation =
false;
3025 if (CachedNavLocation.NodeRef != INVALID_NAVNODEREF)
3027 if (bProjectNavMeshWalking)
3029 const float DistSq2D = (OldLocation - CachedNavLocation.Location).SizeSquared2D();
3030 const float DistZ = FMath::Abs(OldLocation.Z - CachedNavLocation.Location.Z);
3032 const float TotalCapsuleHeight = CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleHalfHeight() * 2.0f;
3033 const float ProjectionScale = (OldLocation.Z > CachedNavLocation.Location.Z) ? NavMeshProjectionHeightScaleUp : NavMeshProjectionHeightScaleDown;
3034 const float DistZThr = TotalCapsuleHeight * FMath::Max(0.f, ProjectionScale);
3036 bSameNavLocation = (DistSq2D <= KINDA_SMALL_NUMBER) && (DistZ < DistZThr);
3040 bSameNavLocation = CachedNavLocation.Location.Equals(OldLocation);
3043 if (bDeltaMoveNearlyZero && bSameNavLocation)
3045 if (
const INavigationDataInterface * NavData = GetNavData())
3047 if (!NavData->IsNodeRefValid(CachedNavLocation.NodeRef))
3049 CachedNavLocation.NodeRef = INVALID_NAVNODEREF;
3050 bSameNavLocation =
false;
3056 if (bDeltaMoveNearlyZero && bSameNavLocation)
3058 DestNavLocation = CachedNavLocation;
3059 UE_LOG(LogVRCharacterMovement, VeryVerbose, TEXT(
"%s using cached navmesh location! (bProjectNavMeshWalking = %d)"), *GetNameSafe(CharacterOwner), bProjectNavMeshWalking);
3063 SCOPE_CYCLE_COUNTER(STAT_CharNavProjectPoint);
3068 if (bSameNavLocation && bProjectNavMeshWalking)
3070 AdjustedDest.Z = CachedNavLocation.Location.Z;
3074 const bool bHasNavigationData = FindNavFloor(AdjustedDest, DestNavLocation);
3075 if (!bHasNavigationData)
3078 SetMovementMode(MOVE_Walking);
3082 CachedNavLocation = DestNavLocation;
3085 if (DestNavLocation.NodeRef != INVALID_NAVNODEREF)
3087 FVector NewLocation(AdjustedDest.X, AdjustedDest.Y, DestNavLocation.Location.Z);
3088 if (bProjectNavMeshWalking)
3090 SCOPE_CYCLE_COUNTER(STAT_CharNavProjectLocation);
3091 const float TotalCapsuleHeight = CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleHalfHeight() * 2.0f;
3092 const float UpOffset = TotalCapsuleHeight * FMath::Max(0.f, NavMeshProjectionHeightScaleUp);
3093 const float DownOffset = TotalCapsuleHeight * FMath::Max(0.f, NavMeshProjectionHeightScaleDown);
3094 NewLocation = ProjectLocationFromNavMesh(deltaTime, OldLocation, NewLocation, UpOffset, DownOffset);
3097 FVector AdjustedDelta = NewLocation - OldLocation;
3099 if (!AdjustedDelta.IsNearlyZero())
3102 FHitResult HitResult;
3113 if (!bJustTeleported && !HasAnimRootMotion() && !CurrentRootMotion.HasVelocity())
3116 MaintainHorizontalGroundVelocity();
3119 bJustTeleported =
false;
3123 StartFalling(Iterations, deltaTime, deltaTime, DeltaMove, OldLocation);
3131 if (deltaTime < MIN_TICK_TIME)
3139 RestorePreAdditiveRootMotionVelocity();
3142 float NetFluidFriction = 0.f;
3144 float NetBuoyancy = Buoyancy * Depth;
3145 float OriginalAccelZ = Acceleration.Z;
3146 bool bLimitedUpAccel =
false;
3148 if (!HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity() && (Velocity.Z > 0.33f * MaxSwimSpeed) && (NetBuoyancy != 0.f))
3151 Velocity.Z = FMath::Max(0.33f * MaxSwimSpeed, Velocity.Z * Depth*Depth);
3153 else if (Depth < 0.65f)
3155 bLimitedUpAccel = (Acceleration.Z > 0.f);
3156 Acceleration.Z = FMath::Min(0.1f, Acceleration.Z);
3160 FVector OldLocation = UpdatedComponent->GetComponentLocation();
3161 bJustTeleported =
false;
3162 if (!HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity())
3164 const float Friction = 0.5f * GetPhysicsVolume()->FluidFriction * Depth;
3165 CalcVelocity(deltaTime, Friction,
true, GetMaxBrakingDeceleration());
3166 Velocity.Z += GetGravityZ() * deltaTime * (1.f - NetBuoyancy);
3169 ApplyRootMotionToVelocity(deltaTime);
3172 FVector Adjusted = Velocity * deltaTime;
3173 FHitResult Hit(1.f);
3174 float remainingTime = deltaTime *
SwimVR(Adjusted, Hit);
3180 StartNewPhysics(remainingTime, Iterations);
3184 if (Hit.Time < 1.f && CharacterOwner)
3186 HandleSwimmingWallHit(Hit, deltaTime);
3187 if (bLimitedUpAccel && (Velocity.Z >= 0.f))
3190 Velocity.Z += OriginalAccelZ * deltaTime;
3191 Adjusted = Velocity * (1.f - Hit.Time)*deltaTime;
3196 StartNewPhysics(remainingTime, Iterations);
3201 const FVector GravDir = FVector(0.f, 0.f, -1.f);
3202 const FVector VelDir = Velocity.GetSafeNormal();
3203 const float UpDown = GravDir | VelDir;
3205 bool bSteppedUp =
false;
3206 if ((FMath::Abs(Hit.ImpactNormal.Z) < 0.2f) && (UpDown < 0.5f) && (UpDown > -0.2f) && CanStepUp(Hit))
3208 float stepZ = UpdatedComponent->GetComponentLocation().Z;
3209 const FVector RealVelocity = Velocity;
3211 bSteppedUp =
StepUp(GravDir, (Adjusted) * (1.f - Hit.Time), Hit);
3218 StartNewPhysics(remainingTime, Iterations);
3221 OldLocation.Z = UpdatedComponent->GetComponentLocation().Z + (OldLocation.Z - stepZ);
3223 Velocity = RealVelocity;
3229 HandleImpact(Hit, deltaTime, Adjusted);
3234 if (!HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity() && !bJustTeleported && ((deltaTime - remainingTime) > KINDA_SMALL_NUMBER) && CharacterOwner)
3236 bool bWaterJump = !GetPhysicsVolume()->bWaterVolume;
3237 float velZ = Velocity.Z;
3238 Velocity = ((UpdatedComponent->GetComponentLocation() - OldLocation)) / (deltaTime - remainingTime);
3245 if (!GetPhysicsVolume()->bWaterVolume && IsSwimming())
3247 SetMovementMode(MOVE_Falling);
3255 StartNewPhysics(remainingTime, Iterations);
3262 if (remainingTime < MIN_TICK_TIME || timeTick < MIN_TICK_TIME)
3269 if (!HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity() && !bJustTeleported)
3271 Velocity = (NewLocation - OldLocation) / timeTick;
3272 Velocity = 2.f*Velocity - OldVelocity;
3273 Velocity = Velocity.GetClampedToMaxSize(GetPhysicsVolume()->TerminalVelocity);
3275 const FVector End = FindWaterLine(NewLocation, OldLocation);
3276 float waterTime = 0.f;
3277 if (End != NewLocation)
3279 const float ActualDist = (NewLocation - OldLocation).Size();
3280 if (ActualDist > KINDA_SMALL_NUMBER)
3282 waterTime = timeTick * (End - NewLocation).Size() / ActualDist;
3283 remainingTime += waterTime;
3285 MoveUpdatedComponent(End - NewLocation, UpdatedComponent->GetComponentQuat(),
true);
3287 if (!HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity() && (Velocity.Z > 2.f*
SWIMBOBSPEED) && (Velocity.Z < 0.f))
3291 if ((remainingTime >= MIN_TICK_TIME) && (Iterations < MaxSimulationIterations))
3301 float airTime = 0.f;
3304 if (!GetPhysicsVolume()->bWaterVolume)
3308 const FVector End = FindWaterLine(Start, NewLoc);
3309 const float DesiredDist = Delta.Size();
3310 if (End != NewLoc && DesiredDist > KINDA_SMALL_NUMBER)
3312 airTime = (End - NewLoc).Size() / DesiredDist;
3313 if (((NewLoc - Start) | (End - NewLoc)) > 0.f)
3325 if (!HasValidData())
3333 FVector CheckNorm = CheckPoint.GetSafeNormal();
3334 float PawnCapsuleRadius, PawnCapsuleHalfHeight;
3335 CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleSize(PawnCapsuleRadius, PawnCapsuleHalfHeight);
3336 CheckPoint = currentLoc + 1.2f * PawnCapsuleRadius * CheckNorm;
3337 FVector Extent(PawnCapsuleRadius, PawnCapsuleRadius, PawnCapsuleHalfHeight);
3338 FHitResult HitInfo(1.f);
3339 FCollisionQueryParams CapsuleParams(SCENE_QUERY_STAT(
CheckWaterJump),
false, CharacterOwner);
3340 FCollisionResponseParams ResponseParam;
3341 InitCollisionParams(CapsuleParams, ResponseParam);
3342 FCollisionShape CapsuleShape = GetPawnCapsuleCollisionShape(SHRINK_None);
3343 const ECollisionChannel CollisionChannel = UpdatedComponent->GetCollisionObjectType();
3344 bool bHit = GetWorld()->SweepSingleByChannel(HitInfo, currentLoc, CheckPoint, FQuat::Identity, CollisionChannel, CapsuleShape, CapsuleParams, ResponseParam);
3346 if (bHit && !Cast<APawn>(HitInfo.GetActor()))
3349 WallNormal = -1.f * HitInfo.ImpactNormal;
3350 FVector Start = currentLoc;
3351 Start.Z += MaxOutOfWaterStepHeight;
3352 CheckPoint = Start + 3.2f * PawnCapsuleRadius * WallNormal;
3353 FCollisionQueryParams LineParams(SCENE_QUERY_STAT(
CheckWaterJump),
true, CharacterOwner);
3354 FCollisionResponseParams LineResponseParam;
3355 InitCollisionParams(LineParams, LineResponseParam);
3356 bHit = GetWorld()->LineTraceSingleByChannel(HitInfo, Start, CheckPoint, CollisionChannel, LineParams, LineResponseParam);
3358 return !bHit || IsWalkable(HitInfo);
3370 SCOPE_CYCLE_COUNTER(STAT_CharProcessLanded);
3372 if (CharacterOwner && CharacterOwner->ShouldNotifyLanded(Hit))
3374 CharacterOwner->Landed(Hit);
3379 if (GetGroundMovementMode() == MOVE_NavWalking)
3386 FNavLocation NavLocation;
3388 const bool bHasNavigationData = FindNavFloor(TestLocation, NavLocation);
3389 if (!bHasNavigationData || NavLocation.NodeRef == INVALID_NAVNODEREF)
3391 SetGroundMovementMode(MOVE_Walking);
3393 UE_LOG(LogVRCharacterMovement, Verbose, TEXT(
"ProcessLanded(): %s tried to go to NavWalking but couldn't find NavMesh! Using Walking instead."), *GetNameSafe(CharacterOwner));
3397 SetPostLandedPhysics(Hit);
3400 IPathFollowingAgentInterface* PFAgent = GetPathFollowingAgent();
3403 PFAgent->OnLanded();
3406 StartNewPhysics(remainingTime, Iterations);
3415 if (bDeferUpdateBasedMovement)
3417 FVRCharacterScopedMovementUpdate ScopedMovementUpdate(UpdatedComponent, bEnableScopedMovementUpdates ? EScopedUpdate::DeferredUpdates : EScopedUpdate::ImmediateUpdates);
3420 bDeferUpdateBasedMovement =
false;
3427 if (!HasValidData() || UpdatedComponent->Mobility != EComponentMobility::Movable || UpdatedComponent->IsSimulatingPhysics())
3432 const bool bIsSimulatedProxy = (CharacterOwner->GetLocalRole() == ROLE_SimulatedProxy);
3433 const FRepMovement& ConstRepMovement = CharacterOwner->GetReplicatedMovement();
3436 if (bIsSimulatedProxy &&
3437 ConstRepMovement.Location.IsZero() &&
3438 ConstRepMovement.Rotation.IsZero() &&
3439 ConstRepMovement.LinearVelocity.IsZero())
3445 if (CharacterOwner->GetReplicatedBasedMovement().IsBaseUnresolved())
3447 UE_LOG(LogVRCharacterMovement, Verbose, TEXT(
"Base for simulated character '%s' is not resolved on client, skipping SimulateMovement"), *CharacterOwner->GetName());
3451 FVector OldVelocity;
3452 FVector OldLocation;
3456 FVRCharacterScopedMovementUpdate ScopedMovementUpdate(UpdatedComponent, bEnableScopedMovementUpdates ? EScopedUpdate::DeferredUpdates : EScopedUpdate::ImmediateUpdates);
3458 bool bHandledNetUpdate =
false;
3459 if (bIsSimulatedProxy)
3462 if (bNetworkUpdateReceived)
3464 bNetworkUpdateReceived =
false;
3465 bHandledNetUpdate =
true;
3466 UE_LOG(LogVRCharacterMovement, Verbose, TEXT(
"Proxy %s received net update"), *GetNameSafe(CharacterOwner));
3467 if (bNetworkMovementModeChanged)
3470 bNetworkMovementModeChanged =
false;
3472 else if (bJustTeleported || bForceNextFloorCheck)
3475 bJustTeleported =
false;
3476 UpdateFloorFromAdjustment();
3479 else if (bForceNextFloorCheck)
3481 UpdateFloorFromAdjustment();
3485 UpdateCharacterStateBeforeMovement(DeltaSeconds);
3487 if (MovementMode != MOVE_None)
3490 HandlePendingLaunch();
3492 ClearAccumulatedForces();
3494 if (MovementMode == MOVE_None)
3499 const bool bSimGravityDisabled = (bIsSimulatedProxy && CharacterOwner->bSimGravityDisabled);
3500 const bool bZeroReplicatedGroundVelocity = (bIsSimulatedProxy && IsMovingOnGround() && ConstRepMovement.LinearVelocity.IsZero());
3504 if (bSimGravityDisabled || bZeroReplicatedGroundVelocity)
3506 Velocity = FVector::ZeroVector;
3510 MaybeUpdateBasedMovement(DeltaSeconds);
3513 OldVelocity = Velocity;
3514 OldLocation = UpdatedComponent->GetComponentLocation();
3516 UpdateProxyAcceleration();
3518 static const auto CVarNetEnableSkipProxyPredictionOnNetUpdate = IConsoleManager::Get().FindConsoleVariable(TEXT(
"p.NetEnableSkipProxyPredictionOnNetUpdate"));
3520 if (!bHandledNetUpdate || !bNetworkSkipProxyPredictionOnNetUpdate || !CVarNetEnableSkipProxyPredictionOnNetUpdate->GetInt())
3522 UE_LOG(LogVRCharacterMovement, Verbose, TEXT(
"Proxy %s simulating movement"), *GetNameSafe(CharacterOwner));
3523 FStepDownResult StepDownResult;
3528 MoveSmooth(Velocity, DeltaSeconds, &StepDownResult);
3532 if (IsMovingOnGround() || MovementMode == MOVE_Falling)
3534 if (StepDownResult.bComputedFloor)
3536 CurrentFloor = StepDownResult.FloorResult;
3540 FindFloor(UpdatedComponent->GetComponentLocation(), CurrentFloor, Velocity.IsZero(), NULL);
3544 CurrentFloor.Clear();
3547 if (!CurrentFloor.IsWalkableFloor())
3549 if (!bSimGravityDisabled)
3552 if (Velocity.Z <= 0.f || bApplyGravityWhileJumping || !CharacterOwner->IsJumpProvidingForce())
3554 Velocity = NewFallVelocity(Velocity, FVector(0.f, 0.f, GetGravityZ()), DeltaSeconds);
3557 SetMovementMode(MOVE_Falling);
3562 if (IsMovingOnGround())
3564 AdjustFloorHeight();
3565 SetBase(CurrentFloor.HitResult.Component.Get(), CurrentFloor.HitResult.BoneName);
3567 else if (MovementMode == MOVE_Falling)
3569 if (CurrentFloor.FloorDist <= MIN_FLOOR_DIST || (bSimGravityDisabled && CurrentFloor.FloorDist <= MAX_FLOOR_DIST))
3572 SetPostLandedPhysics(CurrentFloor.HitResult);
3576 if (!bSimGravityDisabled)
3579 Velocity = NewFallVelocity(Velocity, FVector(0.f, 0.f, GetGravityZ()), DeltaSeconds);
3581 CurrentFloor.Clear();
3589 UE_LOG(LogVRCharacterMovement, Verbose, TEXT(
"Proxy %s SKIPPING simulate movement"), *GetNameSafe(CharacterOwner));
3592 UpdateCharacterStateAfterMovement(DeltaSeconds);
3595 bHasRequestedVelocity =
false;
3597 OnMovementUpdated(DeltaSeconds, OldLocation, OldVelocity);
3601 CallMovementUpdateDelegate(DeltaSeconds, OldLocation, OldVelocity);
3604 UpdateComponentVelocity();
3605 bJustTeleported =
false;
3607 LastUpdateLocation = UpdatedComponent ? UpdatedComponent->GetComponentLocation() : FVector::ZeroVector;
3608 LastUpdateRotation = UpdatedComponent ? UpdatedComponent->GetComponentQuat() : FQuat::Identity;
3609 LastUpdateVelocity = Velocity;
3614 if (!HasValidData())
3621 if (MovementMode == MOVE_Custom)
3623 FVRCharacterScopedMovementUpdate ScopedMovementUpdate(UpdatedComponent, bEnableScopedMovementUpdates ? EScopedUpdate::DeferredUpdates : EScopedUpdate::ImmediateUpdates);
3628 FVector Delta = InVelocity * DeltaSeconds;
3634 FVRCharacterScopedMovementUpdate ScopedMovementUpdate(UpdatedComponent, bEnableScopedMovementUpdates ? EScopedUpdate::DeferredUpdates : EScopedUpdate::ImmediateUpdates);
3636 if (IsMovingOnGround())
3642 FHitResult Hit(1.f);
3645 if (Hit.IsValidBlockingHit())
3647 bool bSteppedUp =
false;
3653 OutStepDownResult = NULL;
3654 if (FMath::Abs(Hit.ImpactNormal.Z) < 0.2f)
3656 const FVector GravDir = FVector(0.f, 0.f, -1.f);
3657 const FVector DesiredDir = Delta.GetSafeNormal();
3658 const float UpDown = GravDir | DesiredDir;
3659 if ((UpDown < 0.5f) && (UpDown > -0.2f))
3661 bSteppedUp =
StepUp(GravDir, Delta * (1.f - Hit.Time), Hit, OutStepDownResult);
3678 if (MoveResponse.IsGoodMove())
3680 ClientAckGoodMove_Implementation(MoveResponse.ClientAdjustment.TimeStamp);
3685 if (MoveResponse.bRootMotionSourceCorrection)
3687 if (FRootMotionSourceGroup* RootMotionSourceGroup = MoveResponse.GetRootMotionSourceGroup(*
this))
3689 ClientAdjustRootMotionSourcePosition_Implementation(
3690 MoveResponse.ClientAdjustment.TimeStamp,
3691 *RootMotionSourceGroup,
3692 MoveResponse.bRootMotionMontageCorrection,
3693 MoveResponse.RootMotionTrackPosition,
3694 MoveResponse.ClientAdjustment.NewLoc,
3695 MoveResponse.RootMotionRotation,
3696 MoveResponse.ClientAdjustment.NewVel.Z,
3697 MoveResponse.ClientAdjustment.NewBase,
3698 MoveResponse.ClientAdjustment.NewBaseBoneName,
3699 MoveResponse.bHasBase,
3700 MoveResponse.ClientAdjustment.bBaseRelativePosition,
3701 MoveResponse.ClientAdjustment.MovementMode);
3704 else if (MoveResponse.bRootMotionMontageCorrection)
3706 ClientAdjustRootMotionPosition_Implementation(
3707 MoveResponse.ClientAdjustment.TimeStamp,
3708 MoveResponse.RootMotionTrackPosition,
3709 MoveResponse.ClientAdjustment.NewLoc,
3710 MoveResponse.RootMotionRotation,
3711 MoveResponse.ClientAdjustment.NewVel.Z,
3712 MoveResponse.ClientAdjustment.NewBase,
3713 MoveResponse.ClientAdjustment.NewBaseBoneName,
3714 MoveResponse.bHasBase,
3715 MoveResponse.ClientAdjustment.bBaseRelativePosition,
3716 MoveResponse.ClientAdjustment.MovementMode);
3721 MoveResponse.ClientAdjustment.TimeStamp,
3722 MoveResponse.ClientAdjustment.NewLoc,
3723 FRotator::CompressAxisToShort(MoveResponse.ClientAdjustment.NewRot.Yaw),
3724 MoveResponse.ClientAdjustment.NewVel,
3725 MoveResponse.ClientAdjustment.NewBase,
3726 MoveResponse.ClientAdjustment.NewBaseBoneName,
3727 MoveResponse.bHasBase,
3728 MoveResponse.ClientAdjustment.bBaseRelativePosition,
3729 MoveResponse.ClientAdjustment.MovementMode);
3737 FVector NewLocation,
3739 FVector NewVelocity,
3740 UPrimitiveComponent* NewBase,
3741 FName NewBaseBoneName,
3743 bool bBaseRelativePosition,
3744 uint8 ServerMovementMode
3747 if (!HasValidData() || !IsActive())
3757 const bool bUnresolvedBase = bHasBase && (NewBase == NULL);
3758 if (bUnresolvedBase)
3760 if (bBaseRelativePosition)
3762 UE_LOG(LogNetPlayerMovement,
Warning, TEXT(
"ClientAdjustPosition_Implementation could not resolve the new relative movement base actor, ignoring server correction! Client currently at world location %s on base %s"),
3763 *UpdatedComponent->GetComponentLocation().ToString(), *GetNameSafe(GetMovementBase()));
3768 UE_LOG(LogNetPlayerMovement, Verbose, TEXT(
"ClientAdjustPosition_Implementation could not resolve the new absolute movement base actor, but WILL use the position!"));
3773 int32 MoveIndex = ClientData->GetSavedMoveIndex(TimeStamp);
3774 if (MoveIndex == INDEX_NONE)
3776 if (ClientData->LastAckedMove.IsValid())
3778 UE_LOG(LogNetPlayerMovement, Log, TEXT(
"ClientAdjustPosition_Implementation could not find Move for TimeStamp: %f, LastAckedTimeStamp: %f, CurrentTimeStamp: %f"), TimeStamp, ClientData->LastAckedMove->TimeStamp, ClientData->CurrentTimeStamp);
3785 float YawValue = FRotator::DecompressAxisFromShort(NewYaw);
3787 if (ClientData->LastAckedMove.IsValid() && !FMath::IsNearlyEqual(ClientData->LastAckedMove->SavedControlRotation.Yaw, YawValue))
3797 myController->SetControlRotation(FRotator(0.f, YawValue, 0.f));
3806 ClientData->AckMove(MoveIndex, *
this);
3808 FVector WorldShiftedNewLocation;
3810 if (bBaseRelativePosition)
3812 FVector BaseLocation;
3814 MovementBaseUtility::GetMovementBaseTransform(NewBase, NewBaseBoneName, BaseLocation, BaseRotation);
3815 WorldShiftedNewLocation = NewLocation + BaseLocation;
3819 WorldShiftedNewLocation = FRepMovement::RebaseOntoLocalOrigin(NewLocation,
this);
3824 OnClientCorrectionReceived(*ClientData, TimeStamp, WorldShiftedNewLocation, NewVelocity, NewBase, NewBaseBoneName, bHasBase, bBaseRelativePosition, ServerMovementMode);
3827 if (UpdatedComponent)
3843 UpdatedComponent->SetWorldLocation(WorldShiftedNewLocation,
false,
nullptr, ETeleportType::TeleportPhysics);
3847 Velocity = NewVelocity;
3850 UPrimitiveComponent* PreviousBase = CharacterOwner->GetMovementBase();
3854 UPrimitiveComponent* FinalBase = NewBase;
3855 FName FinalBaseBoneName = NewBaseBoneName;
3856 if (bUnresolvedBase)
3858 check(NewBase == NULL);
3859 check(!bBaseRelativePosition);
3863 if (PreviousBase && UpdatedComponent)
3865 FindFloor(UpdatedComponent->GetComponentLocation(), CurrentFloor,
false);
3866 if (CurrentFloor.IsWalkableFloor())
3868 FinalBase = CurrentFloor.HitResult.Component.Get();
3869 FinalBaseBoneName = CurrentFloor.HitResult.BoneName;
3873 FinalBase =
nullptr;
3874 FinalBaseBoneName = NAME_None;
3878 SetBase(FinalBase, FinalBaseBoneName);
3881 UpdateFloorFromAdjustment();
3882 bJustTeleported =
true;
3887 LastUpdateLocation = UpdatedComponent ? UpdatedComponent->GetComponentLocation() : FVector::ZeroVector;
3888 LastUpdateRotation = UpdatedComponent ? UpdatedComponent->GetComponentQuat() : FQuat::Identity;
3889 LastUpdateVelocity = Velocity;
3891 UpdateComponentVelocity();
3892 ClientData->bUpdatePosition =
true;
3895bool UVRCharacterMovementComponent::ServerCheckClientErrorVR(
float ClientTimeStamp,
float DeltaTime,
const FVector& Accel,
const FVector& ClientWorldLocation,
float ClientYaw,
const FVector& RelativeClientLocation, UPrimitiveComponent* ClientMovementBase, FName ClientBaseBoneName, uint8 ClientMovementMode)
3898 if (!bIgnoreClientMovementErrorChecksAndCorrection)
3902#if ROOT_MOTION_DEBUG
3903 if (RootMotionSourceDebug::CVarDebugRootMotionSources.GetValueOnAnyThread() == 1)
3905 const FVector LocDiff = UpdatedComponent->GetComponentLocation() - ClientWorldLocation;
3906 FString AdjustedDebugString = FString::Printf(TEXT(
"ServerCheckClientError LocDiff(%.1f) ExceedsAllowablePositionError(%d) TimeStamp(%f)"),
3907 LocDiff.Size(), GetDefault<AGameNetworkManager>()->ExceedsAllowablePositionError(LocDiff), ClientTimeStamp);
3908 RootMotionSourceDebug::PrintOnScreen(*CharacterOwner, AdjustedDebugString);
3912 if (ServerExceedsAllowablePositionError(ClientTimeStamp, DeltaTime, Accel, ClientWorldLocation, RelativeClientLocation, ClientMovementBase, ClientBaseBoneName, ClientMovementMode))
3917#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
3918 static const auto CVarNetForceClientAdjustmentPercent = IConsoleManager::Get().FindConsoleVariable(TEXT(
"p.NetForceClientAdjustmentPercent"));
3919 if (CVarNetForceClientAdjustmentPercent->GetFloat() > SMALL_NUMBER)
3921 if (RandomStream.FRand() < CVarNetForceClientAdjustmentPercent->GetFloat())
3923 UE_LOG(LogVRCharacterMovement, VeryVerbose, TEXT(
"** ServerCheckClientError forced by p.NetForceClientAdjustmentPercent"));
3931#if !UE_BUILD_SHIPPING
3932 static const auto CVarNetShowCorrections = IConsoleManager::Get().FindConsoleVariable(TEXT(
"p.NetShowCorrections"));
3933 if (CVarNetShowCorrections->GetInt() != 0)
3935 UE_LOG(LogVRCharacterMovement,
Warning, TEXT(
"*** Server: %s is set to ignore error checks and corrections."), *GetNameSafe(CharacterOwner));
3951 if (!ShouldUsePackedMovementRPCs())
3953 if (RelativeClientLoc == FVector(1.f, 2.f, 3.f))
3964 APlayerController* PC = Cast<APlayerController>(CharacterOwner->GetController());
3965 if ((ServerData->LastUpdateTime != GetWorld()->TimeSeconds))
3967 const AGameNetworkManager* GameNetworkManager = (
const AGameNetworkManager*)(AGameNetworkManager::StaticClass()->GetDefaultObject());
3968 if (GameNetworkManager->WithinUpdateDelayBounds(PC, ServerData->LastUpdateTime))
3975 FVector ClientLoc = RelativeClientLoc;
3976 if (MovementBaseUtility::UseRelativeLocation(ClientMovementBase))
3978 FVector BaseLocation;
3980 MovementBaseUtility::GetMovementBaseTransform(ClientMovementBase, ClientBaseBoneName, BaseLocation, BaseRotation);
3981 ClientLoc += BaseLocation;
3985 ClientLoc = FRepMovement::RebaseOntoLocalOrigin(ClientLoc,
this);
3990 if (ClientMovementBase ==
nullptr && ClientMovementMode == MOVE_Walking)
3992 ClientMovementBase = CharacterOwner->GetBasedMovement().MovementBase;
3993 ClientBaseBoneName = CharacterOwner->GetBasedMovement().BoneName;
3996 bool bInClientAuthoritativeMovementMode =
false;
3999 TEnumAsByte<EMovementMode> NetMovementMode(MOVE_None);
4000 TEnumAsByte<EMovementMode> NetGroundMode(MOVE_None);
4001 uint8 NetCustomMode(0);
4002 UnpackNetworkMovementMode(ClientMovementMode, NetMovementMode, NetCustomMode, NetGroundMode);
4003 if (NetMovementMode == EMovementMode::MOVE_Custom)
4006 bInClientAuthoritativeMovementMode =
true;
4011 bNetworkLargeClientCorrection = ServerData->bForceClientUpdate;
4013 if (!bInClientAuthoritativeMovementMode && (ServerData->bForceClientUpdate ||
ServerCheckClientErrorVR(ClientTimeStamp, DeltaTime, Accel, ClientLoc, ClientYaw, RelativeClientLoc, ClientMovementBase, ClientBaseBoneName, ClientMovementMode)))
4015 UPrimitiveComponent* MovementBase = CharacterOwner->GetMovementBase();
4016 ServerData->PendingAdjustment.NewVel = Velocity;
4017 ServerData->PendingAdjustment.NewBase = MovementBase;
4018 ServerData->PendingAdjustment.NewBaseBoneName = CharacterOwner->GetBasedMovement().BoneName;
4020 ServerData->PendingAdjustment.NewRot = UpdatedComponent->GetComponentRotation();
4025 CapsuleLoc.Z = UpdatedComponent->GetComponentLocation().Z;
4026 ServerData->PendingAdjustment.NewLoc = FRepMovement::RebaseOntoZeroOrigin(CapsuleLoc,
this);
4031 ServerData->PendingAdjustment.NewLoc = FRepMovement::RebaseOntoZeroOrigin(UpdatedComponent->GetComponentLocation(),
this);
4035 ServerData->PendingAdjustment.bBaseRelativePosition = MovementBaseUtility::UseRelativeLocation(MovementBase);
4036 if (ServerData->PendingAdjustment.bBaseRelativePosition)
4041 FBasedMovementInfo BaseInfo = CharacterOwner->GetBasedMovement();
4042 FVector BaseLocation;
4044 if (!MovementBaseUtility::GetMovementBaseTransform(BaseInfo.MovementBase, BaseInfo.BoneName, BaseLocation, BaseQuat))
4046 ServerData->PendingAdjustment.NewLoc = CharacterOwner->GetBasedMovement().Location;
4050 ServerData->PendingAdjustment.NewLoc = FTransform(BaseQuat, BaseLocation, FVector(1.0f)).InverseTransformPosition(ServerData->PendingAdjustment.NewLoc);
4055 ServerData->PendingAdjustment.NewLoc = CharacterOwner->GetBasedMovement().Location;
4062#if !UE_BUILD_SHIPPING
4063 static const auto CVarNetShowCorrections = IConsoleManager::Get().FindConsoleVariable(TEXT(
"p.NetShowCorrections"));
4064 static const auto CVarNetCorrectionLifetime = IConsoleManager::Get().FindConsoleVariable(TEXT(
"p.NetCorrectionLifetime"));
4065 if (CVarNetShowCorrections->GetInt() != 0)
4067 const FVector LocDiff = UpdatedComponent->GetComponentLocation() - ClientLoc;
4068 const FString BaseString = MovementBase ? MovementBase->GetPathName(MovementBase->GetOutermost()) : TEXT(
"None");
4069 UE_LOG(LogVRCharacterMovement,
Warning, TEXT(
"*** Server: Error for %s at Time=%.3f is %3.3f LocDiff(%s) ClientLoc(%s) ServerLoc(%s) Base: %s Bone: %s Accel(%s) Velocity(%s)"),
4070 *GetNameSafe(CharacterOwner), ClientTimeStamp, LocDiff.Size(), *LocDiff.ToString(), *ClientLoc.ToString(), *UpdatedComponent->GetComponentLocation().ToString(), *BaseString, *ServerData->PendingAdjustment.NewBaseBoneName.ToString(), *Accel.ToString(), *Velocity.ToString());
4071 const float DebugLifetime = CVarNetCorrectionLifetime->GetFloat();
4072 DrawDebugCapsule(GetWorld(), UpdatedComponent->GetComponentLocation(), CharacterOwner->GetSimpleCollisionHalfHeight(), CharacterOwner->GetSimpleCollisionRadius(), FQuat::Identity, FColor(100, 255, 100),
false, DebugLifetime);
4073 DrawDebugCapsule(GetWorld(), ClientLoc, CharacterOwner->GetSimpleCollisionHalfHeight(), CharacterOwner->GetSimpleCollisionRadius(), FQuat::Identity, FColor(255, 100, 100),
false, DebugLifetime);
4077 ServerData->LastUpdateTime = GetWorld()->TimeSeconds;
4078 ServerData->PendingAdjustment.DeltaTime = DeltaTime;
4079 ServerData->PendingAdjustment.TimeStamp = ClientTimeStamp;
4080 ServerData->PendingAdjustment.bAckGoodMove =
false;
4081 ServerData->PendingAdjustment.MovementMode = PackNetworkMovementMode();
4087 if (bInClientAuthoritativeMovementMode || ServerShouldUseAuthoritativePosition(ClientTimeStamp, DeltaTime, Accel, ClientLoc, RelativeClientLoc, ClientMovementBase, ClientBaseBoneName, ClientMovementMode))
4089 const FVector LocDiff = UpdatedComponent->GetComponentLocation() - ClientLoc;
4090 if (!LocDiff.IsZero() || ClientMovementMode != PackNetworkMovementMode() || GetMovementBase() != ClientMovementBase || (CharacterOwner && CharacterOwner->GetBasedMovement().BoneName != ClientBaseBoneName))
4093 UpdatedComponent->SetWorldLocation(ClientLoc,
false);
4099 SetBase(ClientMovementBase, ClientBaseBoneName);
4100 UpdateFloorFromAdjustment();
4105 LastUpdateLocation = UpdatedComponent ? UpdatedComponent->GetComponentLocation() : FVector::ZeroVector;
4106 LastUpdateRotation = UpdatedComponent ? UpdatedComponent->GetComponentQuat() : FQuat::Identity;
4107 LastUpdateVelocity = Velocity;
4112 ServerData->PendingAdjustment.TimeStamp = ClientTimeStamp;
4113 ServerData->PendingAdjustment.bAckGoodMove =
true;
4118 ServerData->bForceClientUpdate =
false;
4127 ECollisionResponse WalkingResponse;
4130 if (WalkingResponse == ECR_Ignore || WalkingResponse == ECR_Overlap)
4132 return FVector::ZeroVector;
4136 FVector Result = Super::GetPenetrationAdjustment(Hit);
4140 const bool bIsProxy = (CharacterOwner->GetLocalRole() == ROLE_SimulatedProxy);
4141 float MaxDistance = bIsProxy ? MaxDepenetrationWithGeometryAsProxy : MaxDepenetrationWithGeometry;
4142 const AActor* HitActor = Hit.GetActor();
4143 if (Cast<APawn>(HitActor))
4145 MaxDistance = bIsProxy ? MaxDepenetrationWithPawnAsProxy : MaxDepenetrationWithPawn;
4148 Result = Result.GetClampedToMaxSize(MaxDistance);
@ VRMOVEACTION_PauseTracking
DECLARE_CYCLE_STAT(TEXT("Char StepUp"), STAT_CharStepUp, STATGROUP_Character)
const float VERTICAL_SLOPE_NORMAL_Z
DEFINE_LOG_CATEGORY(LogVRCharacterMovement)
const float MAX_STEP_SIDE_Z
FVector SetActorLocationVR(FVector NewLoc, bool bTeleport)
UFUNCTION(BlueprintCallable, Category = "BaseVRCharacter|VRLocations")
FVector GetVRLocation() const
UFUNCTION(BlueprintPure, Category = "BaseVRCharacter|VRLocations")
bool VRReplicateCapsuleHeight
UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRBaseCharacter")
virtual void SetCharacterHalfHeightVR(float HalfHeight, bool bUpdateOverlaps=true)
UFUNCTION(BlueprintCallable, Category = "BaseVRCharacter")
FRotator VRCapsuleRotation
virtual void PrepMoveFor(ACharacter *Character) override
virtual void SetInitialPosition(ACharacter *C)
FVector VRCapsuleLocation
virtual void SetInitialPosition(ACharacter *C)
virtual void PrepMoveFor(ACharacter *Character) override
float VRClimbingEdgeRejectDistance
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRMovement|Climbing")
virtual bool VerifyClientTimeStamp(float TimeStamp, FNetworkPredictionData_Server_Character &ServerData) override
virtual void PerformMovement(float DeltaSeconds) override
void RestorePreAdditiveVRMotionVelocity()
virtual void PhysCustom(float deltaTime, int32 Iterations) override
FVector GetActorFeetLocationVR() const
virtual void OnClientCorrectionReceived(class FNetworkPredictionData_Client_Character &ClientData, float TimeStamp, FVector NewLocation, FVector NewVelocity, UPrimitiveComponent *NewBase, FName NewBaseBoneName, bool bHasBase, bool bBaseRelativePosition, uint8 ServerMovementMode) override
FVector AdditionalVRInputVector
FVRMoveActionArray MoveActionArray
virtual float SlideAlongSurface(const FVector &Delta, float Time, const FVector &Normal, FHitResult &Hit, bool bHandleImpact) override
virtual void ComputeFloorDist(const FVector &CapsuleLocation, float LineDistance, float SweepDistance, FFindFloorResult &OutFloorResult, float SweepRadius, const FHitResult *DownwardSweepResult=NULL) const override
virtual void MoveAutonomous(float ClientTimeStamp, float DeltaTime, uint8 CompressedFlags, const FVector &NewAccel) override
EVRConjoinedMovementModes VRReplicatedMovementMode
AVRBaseCharacter * BaseVRCharacterOwner
UPROPERTY(Transient, DuplicateTransient)
bool bUseClientControlRotation
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRBaseCharacterMovementComponent")
bool bDisableSimulatedTickWhenSmoothingMovement
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRBaseCharacterMovementComponent|Smoothing")
void CheckServerAuthedMoveAction()
float VREdgeRejectDistance
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRMovement")
FVector CustomVRInputVector
void RewindVRRelativeMovement()
FVector LastPreAdditiveVRVelocity
float TrackingLossThreshold
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRMovement", meta = (ClampMin = "0....
void ApplyVRMotionToVelocity(float deltaTime)
virtual void ApplyNetworkMovementMode(const uint8 ReceivedMode) override
virtual bool ShouldCheckForValidLandingSpot(float DeltaTime, const FVector &Delta, const FHitResult &Hit) const override
virtual void PhysFalling(float deltaTime, int32 Iterations) override
virtual bool CheckWaterJump(FVector CheckPoint, FVector &WallNormal) override
virtual void PhysSwimming(float deltaTime, int32 Iterations) override
virtual void FindFloor(const FVector &CapsuleLocation, FFindFloorResult &OutFloorResult, bool bCanUseCachedLocation, const FHitResult *DownwardSweepResult=NULL) const
float ImmersionDepth() const override
float SwimVR(FVector Delta, FHitResult &Hit)
virtual void Crouch(bool bClientSimulation=false) override
virtual void ClientHandleMoveResponse(const FCharacterMoveResponseDataContainer &MoveResponse) override
virtual void ApplyRepulsionForce(float DeltaSeconds) override
virtual void UpdateBasedMovement(float DeltaSeconds) override
virtual void UnCrouch(bool bClientSimulation=false) override
UVRCharacterMovementComponent(const FObjectInitializer &ObjectInitializer=FObjectInitializer::Get())
FNetworkPredictionData_Server * GetPredictionData_Server() const override
virtual bool ServerCheckClientErrorVR(float ClientTimeStamp, float DeltaTime, const FVector &Accel, const FVector &ClientWorldLocation, float ClientYaw, const FVector &RelativeClientLocation, UPrimitiveComponent *ClientMovementBase, FName ClientBaseBoneName, uint8 ClientMovementMode)
virtual void PhysNavWalking(float deltaTime, int32 Iterations) override
virtual bool VRClimbStepUp(const FVector &GravDir, const FVector &Delta, const FHitResult &InHit, FStepDownResult *OutStepDownResult=nullptr) override
void MoveSmooth(const FVector &InVelocity, const float DeltaSeconds, FStepDownResult *OutStepDownResult) override
bool bAllowMovementMerging
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "VRCharacterMovementComponent")
virtual void OnRegister() override
virtual void PhysWalking(float deltaTime, int32 Iterations) override
FNetworkPredictionData_Client * GetPredictionData_Client() const override
virtual void MoveAlongFloor(const FVector &InVelocity, float DeltaSeconds, FStepDownResult *OutStepDownResult) override
UVRRootComponent * VRRootCapsule
UPROPERTY(BlueprintReadOnly, Transient, Category = VRMovement)
virtual FBasedPosition GetActorFeetLocationBased() const override
void StartSwimmingVR(FVector OldLocation, FVector OldVelocity, float timeTick, float remainingTime, int32 Iterations)
virtual FVector GetPenetrationAdjustment(const FHitResult &Hit) const override
virtual bool TryToLeaveNavWalking() override
void SimulateMovement(float DeltaSeconds) override
virtual bool IsWithinEdgeTolerance(const FVector &CapsuleLocation, const FVector &TestImpactPoint, const float CapsuleRadius) const override
void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
virtual void CapsuleTouched(UPrimitiveComponent *OverlappedComp, AActor *Other, UPrimitiveComponent *OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult &SweepResult) override
void PostPhysicsTickComponent(float DeltaTime, FCharacterMovementComponentPostPhysicsTickFunction &ThisTickFunction) override
virtual void ProcessLanded(const FHitResult &Hit, float remainingTime, int32 Iterations) override
virtual bool IsWithinClimbingEdgeTolerance(const FVector &CapsuleLocation, const FVector &TestImpactPoint, const float CapsuleRadius) const
virtual void ServerMoveHandleClientErrorVR(float ClientTimeStamp, float DeltaTime, const FVector &Accel, const FVector &RelativeClientLocation, float ClientYaw, UPrimitiveComponent *ClientMovementBase, FName ClientBaseBoneName, uint8 ClientMovementMode)
virtual void ServerMove_PerformMovement(const FCharacterNetworkMoveData &MoveData) override
virtual void ClientAdjustPositionVR_Implementation(float TimeStamp, FVector NewLoc, uint16 NewYaw, FVector NewVel, UPrimitiveComponent *NewBase, FName NewBaseBoneName, bool bHasBase, bool bBaseRelativePosition, uint8 ServerMovementMode)
virtual void SetUpdatedComponent(USceneComponent *NewUpdatedComponent) override
bool bRunClientCorrectionToHMD
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "VRCharacterMovementComponent")
bool StepUp(const FVector &GravDir, const FVector &Delta, const FHitResult &InHit, FStepDownResult *OutStepDownResult=NULL) override
bool SafeMoveUpdatedComponent(const FVector &Delta, const FQuat &NewRotation, bool bSweep, FHitResult &OutHit, ETeleportType Teleport=ETeleportType::None)
virtual void PhysFlying(float deltaTime, int32 Iterations) override
virtual FVector GetImpartedMovementBaseVelocity() const override
virtual void StoreSetTrackingPaused(bool bNewTrackingPaused) override
virtual void ReplicateMoveToServer(float DeltaTime, const FVector &NewAcceleration) override
static FRotator GetHMDPureYaw_I(FRotator HMDRotation)
UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent), ClassGroup = VRExpansionLibrary)
FRotator StoredCameraRotOffset
FORCEINLINE void GenerateOffsetToWorld(bool bUpdateBounds=true, bool bGetPureYaw=true)
FVector DifferenceFromLastFrame
virtual void SetCapsuleSizeVR(float NewRadius, float NewHalfHeight, bool bUpdateOverlaps=true)
UFUNCTION(BlueprintCallable, Category = "Components|Capsule")
FTransform OffsetComponentToWorld
bool bUseWalkingCollisionOverride
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
TEnumAsByte< ECollisionChannel > WalkingCollisionOverride
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
static const FName ImmersionDepthName
FAutoConsoleVariableRef CVarRotationCorrectionThreshold(TEXT("vre.RotationCorrectionThreshold"), fRotationCorrectionThreshold, TEXT("Rotation is replicated at 2 decimal precision, so values less than 0.01 won't matter."), ECVF_Default)
static const FName CrouchTraceName
static float fRotationCorrectionThreshold
FVector_NetQuantize100 VRCapsuleLocation
FVRConditionalMoveRep ConditionalMoveReps
EVRConjoinedMovementModes ReplicatedMovementMode
FVector_NetQuantize100 LFDiff
FVector RequestedVelocity
UPROPERTY(Transient)
FVector CustomVRInputVector
UPROPERTY(Transient)
FVRMoveActionArray MoveActionArray
UPROPERTY(Transient)
TArray< FVRMoveActionContainer > MoveActions
UPROPERTY()
FVector MoveActionLoc
UPROPERTY()
uint8 MoveActionFlags
UPROPERTY()
EVRMoveAction MoveAction
UPROPERTY()
FRotator MoveActionRot
UPROPERTY()