Advertisement
Davixe

CharacterMovementComponent (GravityVersion UE4.9)

Sep 12th, 2015
3,245
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 270.50 KB | None | 0 0
  1. // Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
  2.  
  3. /*=============================================================================
  4. Movement.cpp: Character movement implementation
  5. gravity version
  6. =============================================================================*/
  7.  
  8. #include "EnginePrivate.h"
  9. #include "GameFramework/PhysicsVolume.h"
  10. #include "GameFramework/GameNetworkManager.h"
  11. #include "GameFramework/Character.h"
  12. #include "GameFramework/CharacterMovementComponent.h"
  13. #include "GameFramework/GameState.h"
  14. #include "Components/PrimitiveComponent.h"
  15. #include "Animation/AnimMontage.h"
  16. #include "PhysicsEngine/DestructibleActor.h"
  17.  
  18. // @todo this is here only due to circular dependency to AIModule. To be removed
  19. #include "Navigation/PathFollowingComponent.h"
  20. #include "AI/Navigation/AvoidanceManager.h"
  21. #include "Components/CapsuleComponent.h"
  22. #include "Components/BrushComponent.h"
  23. #include "Components/DestructibleComponent.h"
  24.  
  25. #include "Engine/DemoNetDriver.h"
  26.  
  27. DEFINE_LOG_CATEGORY_STATIC(LogCharacterMovement, Log, All);
  28. DEFINE_LOG_CATEGORY_STATIC(LogNavMeshMovement, Log, All);
  29.  
  30. /**
  31. * Character stats
  32. */
  33. DECLARE_STATS_GROUP(TEXT("Character"), STATGROUP_Character, STATCAT_Advanced);
  34.  
  35. DECLARE_CYCLE_STAT(TEXT("Char Movement Tick"), STAT_CharacterMovementTick, STATGROUP_Character);
  36. DECLARE_CYCLE_STAT(TEXT("Char Movement Authority Time"), STAT_CharacterMovementAuthority, STATGROUP_Character);
  37. DECLARE_CYCLE_STAT(TEXT("Char Movement Simulated Time"), STAT_CharacterMovementSimulated, STATGROUP_Character);
  38. DECLARE_CYCLE_STAT(TEXT("Char CombineNetMove"), STAT_CharacterMovementCombineNetMove, STATGROUP_Character);
  39. DECLARE_CYCLE_STAT(TEXT("Char SmoothClientPosition"), STAT_CharacterMovementSmoothClientPosition, STATGROUP_Character);
  40. DECLARE_CYCLE_STAT(TEXT("Char Physics Interation"), STAT_CharPhysicsInteraction, STATGROUP_Character);
  41. DECLARE_CYCLE_STAT(TEXT("Char StepUp"), STAT_CharStepUp, STATGROUP_Character);
  42. DECLARE_CYCLE_STAT(TEXT("Char FindFloor"), STAT_CharFindFloor, STATGROUP_Character);
  43. DECLARE_CYCLE_STAT(TEXT("Char AdjustFloorHeight"), STAT_CharAdjustFloorHeight, STATGROUP_Character);
  44. DECLARE_CYCLE_STAT(TEXT("Char Update Acceleration"), STAT_CharUpdateAcceleration, STATGROUP_Character);
  45. DECLARE_CYCLE_STAT(TEXT("Char MoveUpdateDelegate"), STAT_CharMoveUpdateDelegate, STATGROUP_Character);
  46. DECLARE_CYCLE_STAT(TEXT("Char PhysWalking"), STAT_CharPhysWalking, STATGROUP_Character);
  47. DECLARE_CYCLE_STAT(TEXT("Char PhysFalling"), STAT_CharPhysFalling, STATGROUP_Character);
  48. DECLARE_CYCLE_STAT(TEXT("Char PhysNavWalking"), STAT_CharPhysNavWalking, STATGROUP_Character);
  49. DECLARE_CYCLE_STAT(TEXT("Char NavProjectPoint"), STAT_CharNavProjectPoint, STATGROUP_Character);
  50. DECLARE_CYCLE_STAT(TEXT("Char NavProjectLocation"), STAT_CharNavProjectLocation, STATGROUP_Character);
  51.  
  52. // MAGIC NUMBERS
  53. const float MAX_STEP_SIDE_Z = 0.08f;    // maximum z value for the normal on the vertical side of steps
  54. const float SWIMBOBSPEED = -80.f;
  55. const float VERTICAL_SLOPE_NORMAL_Z = 0.001f; // Slope is vertical if Abs(Normal.Z) <= this threshold. Accounts for precision problems that sometimes angle normals slightly off horizontal for vertical surface.
  56.  
  57. const float UCharacterMovementComponent::MIN_TICK_TIME = 0.0002f;
  58. const float UCharacterMovementComponent::MIN_FLOOR_DIST = 1.9f;
  59. const float UCharacterMovementComponent::MAX_FLOOR_DIST = 2.4f;
  60. const float UCharacterMovementComponent::BRAKE_TO_STOP_VELOCITY = 10.f;
  61. const float UCharacterMovementComponent::SWEEP_EDGE_REJECT_DISTANCE = 0.15f;
  62.  
  63. // Statics
  64. namespace CharacterMovementComponentStatics
  65. {
  66.     static const FName CrouchTraceName = FName(TEXT("CrouchTrace"));
  67.     static const FName FindWaterLineName = FName(TEXT("FindWaterLine"));
  68.     static const FName FallingTraceParamsTag = FName(TEXT("PhysFalling"));
  69.     static const FName CheckLedgeDirectionName = FName(TEXT("CheckLedgeDirection"));
  70.     static const FName ProjectLocationName = FName(TEXT("NavProjectLocation"));
  71.     static const FName CheckWaterJumpName = FName(TEXT("CheckWaterJump"));
  72.     static const FName ComputeFloorDistName = FName(TEXT("ComputeFloorDistSweep"));
  73.     static const FName FloorLineTraceName = FName(TEXT("ComputeFloorDistLineTrace"));
  74.     static const FName ImmersionDepthName = FName(TEXT("MovementComp_Character_ImmersionDepth"));
  75. }
  76.  
  77. // CVars
  78. static TAutoConsoleVariable<int32> CVarNetEnableMoveCombining(
  79.     TEXT("p.NetEnableMoveCombining"),
  80.     1,
  81.     TEXT("Whether to enable move combining on the client to reduce bandwidth by combining similar moves.\n")
  82.     TEXT("0: Disable, 1: Enable"),
  83.     ECVF_Default);
  84.  
  85. static TAutoConsoleVariable<float> CVarNetProxyShrinkRadius(
  86.     TEXT("p.NetProxyShrinkRadius"),
  87.     0.01f,
  88.     TEXT("Shrink simulated proxy capsule radius by this amount, to account for network rounding that may cause encroachment.\n")
  89.     TEXT("Changing this value at runtime may require the proxy to re-join for correct behavior.\n")
  90.     TEXT("<= 0: disabled, > 0: shrink by this amount."),
  91.     ECVF_Default);
  92.  
  93. static TAutoConsoleVariable<float> CVarNetProxyShrinkHalfHeight(
  94.     TEXT("p.NetProxyShrinkHalfHeight"),
  95.     0.01f,
  96.     TEXT("Shrink simulated proxy capsule half height by this amount, to account for network rounding that may cause encroachment.\n")
  97.     TEXT("Changing this value at runtime may require the proxy to re-join for correct behavior.\n")
  98.     TEXT("<= 0: disabled, > 0: shrink by this amount."),
  99.     ECVF_Default);
  100.  
  101. #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
  102. static TAutoConsoleVariable<int32> CVarNetShowCorrections(
  103.     TEXT("p.NetShowCorrections"),
  104.     0,
  105.     TEXT("Whether to draw client position corrections (red is incorrect, green is corrected).\n")
  106.     TEXT("0: Disable, 1: Enable"),
  107.     ECVF_Cheat);
  108.  
  109. static TAutoConsoleVariable<float> CVarNetCorrectionLifetime(
  110.     TEXT("p.NetCorrectionLifetime"),
  111.     4.f,
  112.     TEXT("How long a visualized network correction persists.\n")
  113.     TEXT("Time in seconds each visualized network correction persists."),
  114.     ECVF_Cheat);
  115.  
  116. static TAutoConsoleVariable<int32> CVarVisualizeMovement(
  117.     TEXT("p.VisualizeMovement"),
  118.     0,
  119.     TEXT("Whether to draw in-world debug information for character movement.\n")
  120.     TEXT("0: Disable, 1: Enable"),
  121.     ECVF_Cheat);
  122.  
  123. #endif // !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
  124.  
  125. // Version that does not use inverse sqrt estimate, for higher precision.
  126. FORCEINLINE FVector GetSafeNormalPrecise(const FVector& V)
  127. {
  128.     const float VSq = V.SizeSquared();
  129.     if (VSq < SMALL_NUMBER)
  130.     {
  131.         return FVector::ZeroVector;
  132.     }
  133.     else
  134.     {
  135.         return V * (1.f / FMath::Sqrt(VSq));
  136.     }
  137. }
  138.  
  139. // Version that does not use inverse sqrt estimate, for higher precision.
  140. FORCEINLINE FVector GetClampedToMaxSizePrecise(const FVector& V, float MaxSize)
  141. {
  142.     if (MaxSize < KINDA_SMALL_NUMBER)
  143.     {
  144.         return FVector::ZeroVector;
  145.     }
  146.  
  147.     const float VSq = V.SizeSquared();
  148.     if (VSq > FMath::Square(MaxSize))
  149.     {
  150.         return V * (MaxSize / FMath::Sqrt(VSq));
  151.     }
  152.     else
  153.     {
  154.         return V;
  155.     }
  156. }
  157.  
  158.  
  159. void FFindFloorResult::SetFromSweep(const FHitResult& InHit, const float InSweepFloorDist, const bool bIsWalkableFloor)
  160. {
  161.     bBlockingHit = InHit.IsValidBlockingHit();
  162.     bWalkableFloor = bIsWalkableFloor;
  163.     bLineTrace = false;
  164.     FloorDist = InSweepFloorDist;
  165.     LineDist = 0.f;
  166.     HitResult = InHit;
  167. }
  168.  
  169. void FFindFloorResult::SetFromLineTrace(const FHitResult& InHit, const float InSweepFloorDist, const float InLineDist, const bool bIsWalkableFloor)
  170. {
  171.     // We require a sweep that hit if we are going to use a line result.
  172.     check(HitResult.bBlockingHit);
  173.     if (HitResult.bBlockingHit && InHit.bBlockingHit)
  174.     {
  175.         // Override most of the sweep result with the line result, but save some values
  176.         FHitResult OldHit(HitResult);
  177.         HitResult = InHit;
  178.  
  179.         // Restore some of the old values. We want the new normals and hit actor, however.
  180.         HitResult.Time = OldHit.Time;
  181.         HitResult.ImpactPoint = OldHit.ImpactPoint;
  182.         HitResult.Location = OldHit.Location;
  183.         HitResult.TraceStart = OldHit.TraceStart;
  184.         HitResult.TraceEnd = OldHit.TraceEnd;
  185.  
  186.         bLineTrace = true;
  187.         LineDist = InLineDist;
  188.         bWalkableFloor = bIsWalkableFloor;
  189.     }
  190. }
  191.  
  192. void FCharacterMovementComponentPreClothTickFunction::ExecuteTick(float DeltaTime, enum ELevelTick TickType, ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent)
  193. {
  194.     if ( (TickType == LEVELTICK_All) && Target && !Target->HasAnyFlags(RF_PendingKill | RF_Unreachable))
  195.     {
  196.         FScopeCycleCounterUObject ComponentScope(Target);
  197.         FScopeCycleCounterUObject AdditionalScope(Target->AdditionalStatObject());
  198.         Target->PreClothTick(DeltaTime, *this);
  199.     }
  200. }
  201.  
  202. FString FCharacterMovementComponentPreClothTickFunction::DiagnosticMessage()
  203. {
  204.     return Target->GetFullName() + TEXT("[UCharacterMovementComponent::PreClothTick]");
  205. }
  206.  
  207. UCharacterMovementComponent::UCharacterMovementComponent(const FObjectInitializer& ObjectInitializer)
  208.     : Super(ObjectInitializer)
  209. {
  210.     PreClothComponentTick.bCanEverTick = true;
  211.     PreClothComponentTick.bStartWithTickEnabled = false;
  212.     PreClothComponentTick.TickGroup = TG_PreCloth;
  213.  
  214.     GravityScale = 1.f;
  215.     GroundFriction = 8.0f;
  216.     JumpZVelocity = 420.0f;
  217.     JumpOffJumpZFactor = 0.5f;
  218.     RotationRate = FRotator(0.f, 360.0f, 0.0f);
  219.     SetWalkableFloorZ(0.71f);
  220.  
  221.     MaxStepHeight = 45.0f;
  222.     PerchRadiusThreshold = 0.0f;
  223.     PerchAdditionalHeight = 40.f;
  224.  
  225.     MaxFlySpeed = 600.0f;
  226.     MaxWalkSpeed = 600.0f;
  227.     MaxSwimSpeed = 300.0f;
  228.     MaxCustomMovementSpeed = MaxWalkSpeed;
  229.  
  230.     MaxSimulationTimeStep = 0.05f;
  231.     MaxSimulationIterations = 8;
  232.  
  233.     NetworkSimulatedSmoothLocationTime = 0.100f;
  234.     NetworkSimulatedSmoothRotationTime = 0.033f;
  235.  
  236.     CrouchedSpeedMultiplier_DEPRECATED = 0.5f;
  237.     MaxWalkSpeedCrouched = MaxWalkSpeed * CrouchedSpeedMultiplier_DEPRECATED;
  238.     MaxOutOfWaterStepHeight = 40.0f;
  239.     OutofWaterZ = 420.0f;
  240.     AirControl = 0.05f;
  241.     AirControlBoostMultiplier = 2.f;
  242.     AirControlBoostVelocityThreshold = 25.f;
  243.     FallingLateralFriction = 0.f;
  244.     MaxAcceleration = 2048.0f;
  245.     BrakingFrictionFactor = 2.0f; // Historical value, 1 would be more appropriate.
  246.     BrakingDecelerationWalking = MaxAcceleration;
  247.     BrakingDecelerationFalling = 0.f;
  248.     BrakingDecelerationFlying = 0.f;
  249.     BrakingDecelerationSwimming = 0.f;
  250.     LedgeCheckThreshold = 4.0f;
  251.     JumpOutOfWaterPitch = 11.25f;
  252.     UpperImpactNormalScale_DEPRECATED = 0.5f;
  253.  
  254.     Mass = 100.0f;
  255.     bJustTeleported = true;
  256.     CrouchedHalfHeight = 40.0f;
  257.     Buoyancy = 1.0f;
  258.     PendingLaunchVelocity = FVector::ZeroVector;
  259.     DefaultWaterMovementMode = MOVE_Swimming;
  260.     DefaultLandMovementMode = MOVE_Walking;
  261.     GroundMovementMode = MOVE_Walking;
  262.     bForceNextFloorCheck = true;
  263.     bForceBraking_DEPRECATED = false;
  264.     bShrinkProxyCapsule = true;
  265.     bCanWalkOffLedges = true;
  266.     bCanWalkOffLedgesWhenCrouching = false;
  267.     bWantsToLeaveNavWalking = false;
  268.  
  269.     bEnablePhysicsInteraction = true;
  270.     StandingDownwardForceScale = 1.0f;
  271.     InitialPushForceFactor = 500.0f;
  272.     PushForceFactor = 750000.0f;
  273.     PushForcePointZOffsetFactor = -0.75f;
  274.     bPushForceScaledToMass = false;
  275.     bScalePushForceToVelocity = true;
  276.  
  277.     TouchForceFactor = 1.0f;
  278.     bTouchForceScaledToMass = true;
  279.     MinTouchForce = -1.0f;
  280.     MaxTouchForce = 250.0f;
  281.     RepulsionForce = 2.5f;
  282.  
  283.     bUseControllerDesiredRotation = false;
  284.  
  285.     bUseSeparateBrakingFriction = false; // Old default behavior.
  286.  
  287.     bMaintainHorizontalGroundVelocity = true;
  288.     bImpartBaseVelocityX = true;
  289.     bImpartBaseVelocityY = true;
  290.     bImpartBaseVelocityZ = true;
  291.     bImpartBaseAngularVelocity = true;
  292.     bAlwaysCheckFloor = true;
  293.  
  294.     // default character can jump, walk, and swim
  295.     NavAgentProps.bCanJump = true;
  296.     NavAgentProps.bCanWalk = true;
  297.     NavAgentProps.bCanSwim = true;
  298.     ResetMoveState();
  299.  
  300.     ClientPredictionData = NULL;
  301.     ServerPredictionData = NULL;
  302.  
  303.     // This should be greater than tolerated player timeout * 2.
  304.     MinTimeBetweenTimeStampResets = 4.f * 60.f;
  305.  
  306.     bEnableScopedMovementUpdates = true;
  307.  
  308.     bRequestedMoveUseAcceleration = true;
  309.     bUseRVOAvoidance = false;
  310.     bUseRVOPostProcess = false;
  311.     AvoidanceLockVelocity = FVector::ZeroVector;
  312.     AvoidanceLockTimer = 0.0f;
  313.     AvoidanceGroup.bGroup0 = true;
  314.     GroupsToAvoid.Packed = 0xFFFFFFFF;
  315.     GroupsToIgnore.Packed = 0;
  316.     AvoidanceConsiderationRadius = 500.0f;
  317.  
  318.     OldBaseQuat = FQuat::Identity;
  319.     OldBaseLocation = FVector::ZeroVector;
  320.  
  321.     NavMeshProjectionInterval = 0.1f;
  322.     NavMeshProjectionInterpSpeed = 12.f;
  323.     NavMeshProjectionHeightScaleUp = 0.67f;
  324.     NavMeshProjectionHeightScaleDown = 1.0f;
  325.  
  326.     bFallingRemovesSpeedZ = true;
  327.     bIgnoreBaseRollMove = true;
  328.     CustomGravityDirection = FVector::ZeroVector;
  329. }
  330.  
  331. void UCharacterMovementComponent::PostLoad()
  332. {
  333.     Super::PostLoad();
  334.  
  335.     const int32 LinkerUE4Ver = GetLinkerUE4Version();
  336.  
  337.     if (LinkerUE4Ver < VER_UE4_CHARACTER_MOVEMENT_DECELERATION)
  338.     {
  339.         BrakingDecelerationWalking = MaxAcceleration;
  340.     }
  341.  
  342.     if (LinkerUE4Ver < VER_UE4_CHARACTER_BRAKING_REFACTOR)
  343.     {
  344.         // This bool used to apply walking braking in flying and swimming modes.
  345.         if (bForceBraking_DEPRECATED)
  346.         {
  347.             BrakingDecelerationFlying = BrakingDecelerationWalking;
  348.             BrakingDecelerationSwimming = BrakingDecelerationWalking;
  349.         }
  350.     }
  351.  
  352.     if (LinkerUE4Ver < VER_UE4_CHARACTER_MOVEMENT_WALKABLE_FLOOR_REFACTOR)
  353.     {
  354.         // Compute the walkable floor angle, since we have never done so yet.
  355.         UCharacterMovementComponent::SetWalkableFloorZ(WalkableFloorZ);
  356.     }
  357.  
  358.     if (LinkerUE4Ver < VER_UE4_DEPRECATED_MOVEMENTCOMPONENT_MODIFIED_SPEEDS)
  359.     {
  360.         MaxWalkSpeedCrouched = MaxWalkSpeed * CrouchedSpeedMultiplier_DEPRECATED;
  361.         MaxCustomMovementSpeed = MaxWalkSpeed;
  362.     }
  363. }
  364.  
  365.  
  366. #if WITH_EDITOR
  367. void UCharacterMovementComponent::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
  368. {
  369.     Super::PostEditChangeProperty(PropertyChangedEvent);
  370.  
  371.     const UProperty* PropertyThatChanged = PropertyChangedEvent.MemberProperty;
  372.     if (PropertyThatChanged && PropertyThatChanged->GetFName() == GET_MEMBER_NAME_CHECKED(UCharacterMovementComponent, WalkableFloorAngle))
  373.     {
  374.         // Compute WalkableFloorZ from the Angle.
  375.         SetWalkableFloorAngle(WalkableFloorAngle);
  376.     }
  377. }
  378. #endif // WITH_EDITOR
  379.  
  380.  
  381. void UCharacterMovementComponent::OnRegister()
  382. {
  383.     Super::OnRegister();
  384.  
  385. #if WITH_EDITOR
  386.     // Compute WalkableFloorZ from the WalkableFloorAngle.
  387.     // This is only to respond to changes propagated by PostEditChangeProperty, so it's only done in the editor.
  388.     SetWalkableFloorAngle(WalkableFloorAngle);
  389. #endif
  390. }
  391.  
  392.  
  393. void UCharacterMovementComponent::BeginDestroy()
  394. {
  395.     if (ClientPredictionData)
  396.     {
  397.         delete ClientPredictionData;
  398.         ClientPredictionData = NULL;
  399.     }
  400.  
  401.     if (ServerPredictionData)
  402.     {
  403.         delete ServerPredictionData;
  404.         ServerPredictionData = NULL;
  405.     }
  406.  
  407.     Super::BeginDestroy();
  408. }
  409.  
  410. void UCharacterMovementComponent::SetUpdatedComponent(USceneComponent* NewUpdatedComponent)
  411. {
  412.     if (NewUpdatedComponent)
  413.     {
  414.         const ACharacter* NewCharacterOwner = Cast<ACharacter>(NewUpdatedComponent->GetOwner());
  415.         if (NewCharacterOwner == NULL)
  416.         {
  417.             UE_LOG(LogCharacterMovement, Error, TEXT("%s owned by %s must update a component owned by a Character"), *GetName(), *GetNameSafe(NewUpdatedComponent->GetOwner()));
  418.             return;
  419.         }
  420.  
  421.         // check that UpdatedComponent is a Capsule
  422.         if (Cast<UCapsuleComponent>(NewUpdatedComponent) == NULL)
  423.         {
  424.             UE_LOG(LogCharacterMovement, Error, TEXT("%s owned by %s must update a capsule component"), *GetName(), *GetNameSafe(NewUpdatedComponent->GetOwner()));
  425.             return;
  426.         }
  427.     }
  428.  
  429.     if ( bMovementInProgress )
  430.     {
  431.         // failsafe to avoid crashes in CharacterMovement.
  432.         bDeferUpdateMoveComponent = true;
  433.         DeferredUpdatedMoveComponent = NewUpdatedComponent;
  434.         return;
  435.     }
  436.     bDeferUpdateMoveComponent = false;
  437.     DeferredUpdatedMoveComponent = NULL;
  438.  
  439.     UPrimitiveComponent* OldPrimitive = Cast<UPrimitiveComponent>(UpdatedComponent);
  440.     if (IsValid(OldPrimitive) && OldPrimitive->OnComponentBeginOverlap.IsBound())
  441.     {
  442.         OldPrimitive->OnComponentBeginOverlap.RemoveDynamic(this, &UCharacterMovementComponent::CapsuleTouched);
  443.     }
  444.  
  445.     Super::SetUpdatedComponent(NewUpdatedComponent);
  446.     CharacterOwner = Cast<ACharacter>(PawnOwner);
  447.  
  448.     if (UpdatedComponent == NULL)
  449.     {
  450.         StopActiveMovement();
  451.     }
  452.  
  453.     if (IsValid(UpdatedPrimitive) && bEnablePhysicsInteraction)
  454.     {
  455.         UpdatedPrimitive->OnComponentBeginOverlap.AddUniqueDynamic(this, &UCharacterMovementComponent::CapsuleTouched);
  456.     }
  457.  
  458.     if (bUseRVOAvoidance)
  459.     {
  460.         UAvoidanceManager* AvoidanceManager = GetWorld()->GetAvoidanceManager();
  461.         if (AvoidanceManager)
  462.         {
  463.             AvoidanceManager->RegisterMovementComponent(this, AvoidanceWeight);
  464.         }
  465.     }
  466. }
  467.  
  468. bool UCharacterMovementComponent::HasValidData() const
  469. {
  470.     return UpdatedComponent && IsValid(CharacterOwner);
  471. }
  472.  
  473. FCollisionShape UCharacterMovementComponent::GetPawnCapsuleCollisionShape(const EShrinkCapsuleExtent ShrinkMode, const float CustomShrinkAmount) const
  474. {
  475.     FVector Extent = GetPawnCapsuleExtent(ShrinkMode, CustomShrinkAmount);
  476.     return FCollisionShape::MakeCapsule(Extent);
  477. }
  478.  
  479. FVector UCharacterMovementComponent::GetPawnCapsuleExtent(const EShrinkCapsuleExtent ShrinkMode, const float CustomShrinkAmount) const
  480. {
  481.     check(CharacterOwner);
  482.  
  483.     float Radius, HalfHeight;
  484.     CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleSize(Radius, HalfHeight);
  485.     FVector CapsuleExtent(Radius, Radius, HalfHeight);
  486.  
  487.     float RadiusEpsilon = 0.f;
  488.     float HeightEpsilon = 0.f;
  489.  
  490.     switch(ShrinkMode)
  491.     {
  492.     case SHRINK_None:
  493.         return CapsuleExtent;
  494.  
  495.     case SHRINK_RadiusCustom:
  496.         RadiusEpsilon = CustomShrinkAmount;
  497.         break;
  498.  
  499.     case SHRINK_HeightCustom:
  500.         HeightEpsilon = CustomShrinkAmount;
  501.         break;
  502.  
  503.     case SHRINK_AllCustom:
  504.         RadiusEpsilon = CustomShrinkAmount;
  505.         HeightEpsilon = CustomShrinkAmount;
  506.         break;
  507.  
  508.     default:
  509.         UE_LOG(LogCharacterMovement, Warning, TEXT("Unknown EShrinkCapsuleExtent in UCharacterMovementComponent::GetCapsuleExtent"));
  510.         break;
  511.     }
  512.  
  513.     // Don't shrink to zero extent.
  514.     const float MinExtent = KINDA_SMALL_NUMBER * 10.f;
  515.     CapsuleExtent.X = FMath::Max(CapsuleExtent.X - RadiusEpsilon, MinExtent);
  516.     CapsuleExtent.Y = CapsuleExtent.X;
  517.     CapsuleExtent.Z = FMath::Max(CapsuleExtent.Z - HeightEpsilon, MinExtent);
  518.  
  519.     return CapsuleExtent;
  520. }
  521.  
  522.  
  523. bool UCharacterMovementComponent::DoJump(bool bReplayingMoves)
  524. {
  525.     if (CharacterOwner && CharacterOwner->CanJump())
  526.     {
  527.         const FVector JumpDir = GetCapsuleAxisZ();
  528.  
  529.         // If movement isn't constrained or the angle between plane normal and jump direction is between 60 and 120 degrees...
  530.         if (!bConstrainToPlane || FMath::Abs(PlaneConstraintNormal | JumpDir) < 0.5f)
  531.         {
  532.             // Set to zero the vertical component of velocity.
  533.             Velocity = FVector::VectorPlaneProject(Velocity, JumpDir);
  534.  
  535.             // Perform jump.
  536.             Velocity += JumpDir * JumpZVelocity;
  537.             SetMovementMode(MOVE_Falling);
  538.  
  539.             return true;
  540.         }
  541.     }
  542.  
  543.     return false;
  544. }
  545.  
  546. FVector UCharacterMovementComponent::GetImpartedMovementBaseVelocity() const
  547. {
  548.     FVector Result = FVector::ZeroVector;
  549.     if (CharacterOwner)
  550.     {
  551.         UPrimitiveComponent* MovementBase = CharacterOwner->GetMovementBase();
  552.         if (MovementBaseUtility::IsDynamicBase(MovementBase))
  553.         {
  554.             FVector BaseVelocity = MovementBaseUtility::GetMovementBaseVelocity(MovementBase, CharacterOwner->GetBasedMovement().BoneName);
  555.  
  556.             if (bImpartBaseAngularVelocity)
  557.             {
  558.                 const FVector CharacterBasePosition = (UpdatedComponent->GetComponentLocation() - GetCapsuleAxisZ() * CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleHalfHeight());
  559.                 const FVector BaseTangentialVel = MovementBaseUtility::GetMovementBaseTangentialVelocity(MovementBase, CharacterOwner->GetBasedMovement().BoneName, CharacterBasePosition);
  560.                 BaseVelocity += BaseTangentialVel;
  561.             }
  562.  
  563.             if (bImpartBaseVelocityX)
  564.             {
  565.                 Result.X = BaseVelocity.X;
  566.             }
  567.             if (bImpartBaseVelocityY)
  568.             {
  569.                 Result.Y = BaseVelocity.Y;
  570.             }
  571.             if (bImpartBaseVelocityZ)
  572.             {
  573.                 Result.Z = BaseVelocity.Z;
  574.             }
  575.         }
  576.     }
  577.  
  578.     return Result;
  579. }
  580.  
  581. void UCharacterMovementComponent::Launch(FVector const& LaunchVel)
  582. {
  583.     PendingLaunchVelocity = LaunchVel;
  584. }
  585.  
  586. bool UCharacterMovementComponent::HandlePendingLaunch()
  587. {
  588.     if (!PendingLaunchVelocity.IsZero() && HasValidData())
  589.     {
  590.         Velocity = PendingLaunchVelocity;
  591.         SetMovementMode(MOVE_Falling);
  592.         PendingLaunchVelocity = FVector::ZeroVector;
  593.         return true;
  594.     }
  595.  
  596.     return false;
  597. }
  598.  
  599. void UCharacterMovementComponent::JumpOff(AActor* MovementBaseActor)
  600. {
  601.     if ( !bPerformingJumpOff )
  602.     {
  603.         bPerformingJumpOff = true;
  604.         if ( CharacterOwner )
  605.         {
  606.             const float MaxSpeed = GetMaxSpeed() * 0.85f;
  607.             Velocity += GetBestDirectionOffActor(MovementBaseActor) * MaxSpeed;
  608.             const FVector JumpDir = GetCapsuleAxisZ();
  609.             FVector Velocity2D = FVector::VectorPlaneProject(Velocity, JumpDir);
  610.             if (Velocity2D.Size() > MaxSpeed)
  611.             {
  612.                 Velocity2D = FVector::VectorPlaneProject(Velocity.GetSafeNormal() * MaxSpeed, JumpDir);
  613.             }
  614.             Velocity = Velocity2D + JumpDir * (JumpZVelocity * JumpOffJumpZFactor);
  615.             SetMovementMode(MOVE_Falling);
  616.         }
  617.         bPerformingJumpOff = false;
  618.     }
  619. }
  620.  
  621. FVector UCharacterMovementComponent::GetBestDirectionOffActor(AActor* BaseActor) const
  622. {
  623.     // By default, just pick a random direction.  Derived character classes can choose to do more complex calculations,
  624.     // such as finding the shortest distance to move in based on the BaseActor's Bounding Volume.
  625.     const float RandAngle = FMath::DegreesToRadians(GetNetworkSafeRandomAngleDegrees());
  626.     return GetCapsuleRotation().RotateVector(FVector(FMath::Cos(RandAngle), FMath::Sin(RandAngle), 0.5f).GetSafeNormal());
  627. }
  628.  
  629. float UCharacterMovementComponent::GetNetworkSafeRandomAngleDegrees() const
  630. {
  631.     float Angle = FMath::SRand() * 360.f;
  632.  
  633.     if (GetNetMode() > NM_Standalone)
  634.     {
  635.         // Networked game
  636.         // Get a timestamp that is relatively close between client and server (within ping).
  637.         FNetworkPredictionData_Server_Character const* ServerData = (HasPredictionData_Server() ? GetPredictionData_Server_Character() : NULL);
  638.         FNetworkPredictionData_Client_Character const* ClientData = (HasPredictionData_Client() ? GetPredictionData_Client_Character() : NULL);
  639.  
  640.         float TimeStamp = Angle;
  641.         if (ServerData)
  642.         {
  643.             TimeStamp = ServerData->CurrentClientTimeStamp;
  644.         }
  645.         else if (ClientData)
  646.         {
  647.             TimeStamp = ClientData->CurrentTimeStamp;
  648.         }
  649.  
  650.         // Convert to degrees with a faster period.
  651.         const float PeriodMult = 8.0f;
  652.         Angle = TimeStamp * PeriodMult;
  653.         Angle = FMath::Fmod(Angle, 360.f);
  654.     }
  655.  
  656.     return Angle;
  657. }
  658.  
  659.  
  660. void UCharacterMovementComponent::SetDefaultMovementMode()
  661. {
  662.     // check for water volume
  663.     if (CanEverSwim() && IsInWater())
  664.     {
  665.         SetMovementMode(DefaultWaterMovementMode);
  666.     }
  667.     else if ( !CharacterOwner || MovementMode != DefaultLandMovementMode )
  668.     {
  669.         SetMovementMode(DefaultLandMovementMode);
  670.  
  671.         // Avoid 1-frame delay if trying to walk but walking fails at this location.
  672.         if (MovementMode == MOVE_Walking && GetMovementBase() == NULL)
  673.         {
  674.             SetMovementMode(MOVE_Falling);
  675.         }
  676.     }
  677. }
  678.  
  679. void UCharacterMovementComponent::SetGroundMovementMode(EMovementMode NewGroundMovementMode)
  680. {
  681.     // Enforce restriction that it's either Walking or NavWalking.
  682.     if (NewGroundMovementMode != MOVE_Walking && NewGroundMovementMode != MOVE_NavWalking)
  683.     {
  684.         return;
  685.     }
  686.  
  687.     // Set new value
  688.     GroundMovementMode = NewGroundMovementMode;
  689.  
  690.     // Possibly change movement modes if already on ground and choosing the other ground mode.
  691.     const bool bOnGround = (MovementMode == MOVE_Walking || MovementMode == MOVE_NavWalking);
  692.     if (bOnGround && MovementMode != NewGroundMovementMode)
  693.     {
  694.         SetMovementMode(NewGroundMovementMode);
  695.     }
  696. }
  697.  
  698. void UCharacterMovementComponent::SetMovementMode(EMovementMode NewMovementMode, uint8 NewCustomMode)
  699. {
  700.     if (NewMovementMode != MOVE_Custom)
  701.     {
  702.         NewCustomMode = 0;
  703.     }
  704.  
  705.     // If trying to use NavWalking but there is no navmesh, use walking instead.
  706.     if (NewMovementMode == MOVE_NavWalking)
  707.     {
  708.         if (GetNavData() == nullptr)
  709.         {
  710.             NewMovementMode = MOVE_Walking;
  711.         }
  712.     }
  713.  
  714.     // Do nothing if nothing is changing.
  715.     if (MovementMode == NewMovementMode)
  716.     {
  717.         // Allow changes in custom sub-mode.
  718.         if ((NewMovementMode != MOVE_Custom) || (NewCustomMode == CustomMovementMode))
  719.         {
  720.             return;
  721.         }
  722.     }
  723.  
  724.     const EMovementMode PrevMovementMode = MovementMode;
  725.     const uint8 PrevCustomMode = CustomMovementMode;
  726.  
  727.     MovementMode = NewMovementMode;
  728.     CustomMovementMode = NewCustomMode;
  729.  
  730.     // We allow setting movement mode before we have a component to update, in case this happens at startup.
  731.     if (!HasValidData())
  732.     {
  733.         return;
  734.     }
  735.  
  736.     // Handle change in movement mode
  737.     OnMovementModeChanged(PrevMovementMode, PrevCustomMode);
  738.  
  739.     // @todo UE4 do we need to disable ragdoll physics here? Should this function do nothing if in ragdoll?
  740. }
  741.  
  742.  
  743. void UCharacterMovementComponent::OnMovementModeChanged(EMovementMode PreviousMovementMode, uint8 PreviousCustomMode)
  744. {
  745.     if (!HasValidData())
  746.     {
  747.         return;
  748.     }
  749.  
  750.     // Update collision settings if needed
  751.     if (MovementMode == MOVE_NavWalking)
  752.     {
  753.         SetNavWalkingPhysics(true);
  754.         GroundMovementMode = MovementMode;
  755.         // Walking uses only XY velocity
  756.         Velocity.Z = 0.f;
  757.     }
  758.     else if (PreviousMovementMode == MOVE_NavWalking)
  759.     {
  760.         if (MovementMode == DefaultLandMovementMode || IsWalking())
  761.         {
  762.             const bool bCanSwitchMode = TryToLeaveNavWalking();
  763.             if (!bCanSwitchMode)
  764.             {
  765.                 SetMovementMode(MOVE_NavWalking);
  766.                 return;
  767.             }
  768.         }
  769.         else
  770.         {
  771.             SetNavWalkingPhysics(false);
  772.         }
  773.     }
  774.  
  775.     // React to changes in the movement mode.
  776.     if (MovementMode == MOVE_Walking)
  777.     {
  778.         // Walking must be on a walkable floor, with a Base.
  779.         bCrouchMaintainsBaseLocation = true;
  780.         GroundMovementMode = MovementMode;
  781.  
  782.         // make sure we update our new floor/base on initial entry of the walking physics
  783.         FindFloor(UpdatedComponent->GetComponentLocation(), CurrentFloor, false);
  784.         UpdateComponentRotation();
  785.         AdjustFloorHeight();
  786.         SetBaseFromFloor(CurrentFloor);
  787.         // Walking uses only horizontal velocity.
  788.         MaintainHorizontalGroundVelocity();
  789.     }
  790.     else
  791.     {
  792.         CurrentFloor.Clear();
  793.         bCrouchMaintainsBaseLocation = false;
  794.  
  795.         UpdateComponentRotation();
  796.  
  797.         if (MovementMode == MOVE_Falling)
  798.         {
  799.             Velocity += GetImpartedMovementBaseVelocity();
  800.             CharacterOwner->Falling();
  801.         }
  802.  
  803.         SetBase(NULL);
  804.  
  805.         if (MovementMode == MOVE_None)
  806.         {
  807.             // Kill velocity and clear queued up events
  808.             StopMovementKeepPathing();
  809.             CharacterOwner->ClearJumpInput();
  810.         }
  811.     }
  812.  
  813.     CharacterOwner->OnMovementModeChanged(PreviousMovementMode, PreviousCustomMode);
  814.     ensure(GroundMovementMode == MOVE_Walking || GroundMovementMode == MOVE_NavWalking);
  815. };
  816.  
  817.  
  818. namespace PackedMovementModeConstants
  819. {
  820.     const uint32 GroundShift = FMath::CeilLogTwo(MOVE_MAX);
  821.     //const uint32 GroundShift = FMath::FloorLog2(MOVE_MAX) + 1;
  822.     const uint8 CustomModeThr = 2 * (1 << GroundShift);
  823.     const uint8 GroundMask = (1 << GroundShift) - 1;
  824. }
  825.  
  826. uint8 UCharacterMovementComponent::PackNetworkMovementMode() const
  827. {
  828.     if (MovementMode != MOVE_Custom)
  829.     {
  830.         ensure(GroundMovementMode == MOVE_Walking || GroundMovementMode == MOVE_NavWalking);
  831.         const uint8 GroundModeBit = (GroundMovementMode == MOVE_Walking ? 0 : 1);
  832.         return uint8(MovementMode.GetValue()) | (GroundModeBit << PackedMovementModeConstants::GroundShift);
  833.     }
  834.     else
  835.     {
  836.         return CustomMovementMode + PackedMovementModeConstants::CustomModeThr;
  837.     }
  838. }
  839.  
  840.  
  841. void UCharacterMovementComponent::UnpackNetworkMovementMode(const uint8 ReceivedMode, TEnumAsByte<EMovementMode>& OutMode, uint8& OutCustomMode, TEnumAsByte<EMovementMode>& OutGroundMode) const
  842. {
  843.     if (ReceivedMode < PackedMovementModeConstants::CustomModeThr)
  844.     {
  845.         OutMode = TEnumAsByte<EMovementMode>(ReceivedMode & PackedMovementModeConstants::GroundMask);
  846.         OutCustomMode = 0;
  847.         const uint8 GroundModeBit = (ReceivedMode >> PackedMovementModeConstants::GroundShift);
  848.         OutGroundMode = TEnumAsByte<EMovementMode>(GroundModeBit == 0 ? MOVE_Walking : MOVE_NavWalking);
  849.     }
  850.     else
  851.     {
  852.         OutMode = MOVE_Custom;
  853.         OutCustomMode = ReceivedMode - PackedMovementModeConstants::CustomModeThr;
  854.         OutGroundMode = MOVE_Walking;
  855.     }
  856. }
  857.  
  858.  
  859. void UCharacterMovementComponent::ApplyNetworkMovementMode(const uint8 ReceivedMode)
  860. {
  861.     TEnumAsByte<EMovementMode> NetMovementMode(MOVE_None);
  862.     TEnumAsByte<EMovementMode> NetGroundMode(MOVE_None);
  863.     uint8 NetCustomMode(0);
  864.     UnpackNetworkMovementMode(ReceivedMode, NetMovementMode, NetCustomMode, NetGroundMode);
  865.     ensure(NetGroundMode == MOVE_Walking || NetGroundMode == MOVE_NavWalking);
  866.  
  867.     GroundMovementMode = NetGroundMode;
  868.     SetMovementMode(NetMovementMode, NetCustomMode);
  869. }
  870.  
  871. // TODO: deprecated, remove
  872. void UCharacterMovementComponent::PerformAirControl(FVector Direction, float ZDiff)
  873. {
  874.     PerformAirControlForPathFollowing(Direction, ZDiff);
  875. }
  876.  
  877.  
  878. void UCharacterMovementComponent::PerformAirControlForPathFollowing(const FVector& Direction, float ZDiff)
  879. {
  880.     // use air control if low grav or above destination and falling towards it
  881.     if ( CharacterOwner && Velocity.Z < 0.f && (ZDiff < 0.f || GetGravityZ() > 0.9f * GetWorld()->GetDefaultGravityZ()))
  882.     {
  883.         if ( ZDiff > 0.f )
  884.         {
  885.             if ( ZDiff > 2.f * GetMaxJumpHeight() )
  886.             {
  887.                 if (PathFollowingComp.IsValid())
  888.                 {
  889.                     PathFollowingComp->AbortMove(TEXT("missed jump"));
  890.                 }
  891.             }
  892.         }
  893.         else
  894.         {
  895.             if ( (Velocity.X == 0.f) && (Velocity.Y == 0.f) )
  896.             {
  897.                 Acceleration = FVector::ZeroVector;
  898.             }
  899.             else
  900.             {
  901.                 float Dist2D = Direction.Size2D();
  902.                 //Direction.Z = 0.f;
  903.                 Acceleration = Direction.GetSafeNormal() * GetMaxAcceleration();
  904.  
  905.                 if ( (Dist2D < 0.5f * FMath::Abs(Direction.Z)) && ((Velocity | Direction) > 0.5f*FMath::Square(Dist2D)) )
  906.                 {
  907.                     Acceleration *= -1.f;
  908.                 }
  909.  
  910.                 if ( Dist2D < 1.5f*CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleRadius() )
  911.                 {
  912.                     Velocity.X = 0.f;
  913.                     Velocity.Y = 0.f;
  914.                     Acceleration = FVector::ZeroVector;
  915.                 }
  916.                 else if ( (Velocity | Direction) < 0.f )
  917.                 {
  918.                     float M = FMath::Max(0.f, 0.2f - GetWorld()->DeltaTimeSeconds);
  919.                     Velocity.X *= M;
  920.                     Velocity.Y *= M;
  921.                 }
  922.             }
  923.         }
  924.     }
  925. }
  926.  
  927. void UCharacterMovementComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
  928. {
  929.     SCOPE_CYCLE_COUNTER(STAT_CharacterMovementTick);
  930.  
  931.     const FVector InputVector = ConsumeInputVector();
  932.     if (!HasValidData() || ShouldSkipUpdate(DeltaTime))
  933.     {
  934.         return;
  935.     }
  936.  
  937.     Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
  938.  
  939.     // Super tick may destroy/invalidate CharacterOwner or UpdatedComponent, so we need to re-check.
  940.     if (!HasValidData())
  941.     {
  942.         return;
  943.     }
  944.  
  945.     // See if we fell out of the world.
  946.     const bool bIsSimulatingPhysics = UpdatedComponent->IsSimulatingPhysics();
  947.     if (CharacterOwner->Role == ROLE_Authority && (!bCheatFlying || bIsSimulatingPhysics) && !CharacterOwner->CheckStillInWorld())
  948.     {
  949.         return;
  950.     }
  951.  
  952.     // We don't update if simulating physics (eg ragdolls).
  953.     if (bIsSimulatingPhysics)
  954.     {
  955.         return;
  956.     }
  957.  
  958.     if (AvoidanceLockTimer > 0.0f)
  959.     {
  960.         AvoidanceLockTimer -= DeltaTime;
  961.     }
  962.  
  963.     if (CharacterOwner->Role > ROLE_SimulatedProxy)
  964.     {
  965.         // If we are a client we might have received an update from the server.
  966.         const bool bIsClient = (GetNetMode() == NM_Client && CharacterOwner->Role == ROLE_AutonomousProxy);
  967.         if (bIsClient)
  968.         {
  969.             ClientUpdatePositionAfterServerUpdate();
  970.         }
  971.  
  972.         // Allow root motion to move characters that have no controller.
  973.         if( CharacterOwner->IsLocallyControlled() || (!CharacterOwner->Controller && bRunPhysicsWithNoController) || (!CharacterOwner->Controller && CharacterOwner->IsPlayingRootMotion()) )
  974.         {
  975.             {
  976.                 SCOPE_CYCLE_COUNTER(STAT_CharUpdateAcceleration);
  977.  
  978.                 // We need to check the jump state before adjusting input acceleration, to minimize latency
  979.                 // and to make sure acceleration respects our potentially new falling state.
  980.                 CharacterOwner->CheckJumpInput(DeltaTime);
  981.  
  982.                 // apply input to acceleration
  983.                 Acceleration = ScaleInputAcceleration(ConstrainInputAcceleration(InputVector));
  984.                 AnalogInputModifier = ComputeAnalogInputModifier();
  985.             }
  986.  
  987.             if (CharacterOwner->Role == ROLE_Authority)
  988.             {
  989.                 PerformMovement(DeltaTime);
  990.             }
  991.             else if (bIsClient)
  992.             {
  993.                 ReplicateMoveToServer(DeltaTime, Acceleration);
  994.             }
  995.         }
  996.         else if (CharacterOwner->GetRemoteRole() == ROLE_AutonomousProxy)
  997.         {
  998.             // Server ticking for remote client.
  999.             // Between net updates from the client we need to update position if based on another object,
  1000.             // otherwise the object will move on intermediate frames and we won't follow it.
  1001.             MaybeUpdateBasedMovement(DeltaTime);
  1002.             SaveBaseLocation();
  1003.         }
  1004.     }
  1005.     else if (CharacterOwner->Role == ROLE_SimulatedProxy)
  1006.     {
  1007.         AdjustProxyCapsuleSize();
  1008.         SimulatedTick(DeltaTime);
  1009.     }
  1010.  
  1011.     UpdateDefaultAvoidance();
  1012.  
  1013.     if (bEnablePhysicsInteraction)
  1014.     {
  1015.         SCOPE_CYCLE_COUNTER(STAT_CharPhysicsInteraction);
  1016.         ApplyDownwardForce(DeltaTime);
  1017.         ApplyRepulsionForce(DeltaTime);
  1018.     }
  1019.  
  1020. #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
  1021.     const bool bVisualizeMovement = CVarVisualizeMovement.GetValueOnGameThread() > 0;
  1022.     if (bVisualizeMovement)
  1023.     {
  1024.         VisualizeMovement();
  1025.     }
  1026. #endif // !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
  1027.  
  1028. }
  1029.  
  1030. void UCharacterMovementComponent::PreClothTick(float DeltaTime, FCharacterMovementComponentPreClothTickFunction& ThisTickFunction)
  1031. {
  1032.     if(bDeferUpdateBasedMovement)
  1033.     {
  1034.         UpdateBasedMovement(DeltaTime);
  1035.         SaveBaseLocation();
  1036.  
  1037.         bDeferUpdateBasedMovement = false;
  1038.     }
  1039. }
  1040.  
  1041. void UCharacterMovementComponent::AdjustProxyCapsuleSize()
  1042. {
  1043.     if (bShrinkProxyCapsule && CharacterOwner && CharacterOwner->Role == ROLE_SimulatedProxy)
  1044.     {
  1045.         bShrinkProxyCapsule = false;
  1046.  
  1047.         float ShrinkRadius = FMath::Max(0.f, CVarNetProxyShrinkRadius.GetValueOnGameThread());
  1048.         float ShrinkHalfHeight = FMath::Max(0.f, CVarNetProxyShrinkHalfHeight.GetValueOnGameThread());
  1049.  
  1050.         if (ShrinkRadius == 0.f && ShrinkHalfHeight == 0.f)
  1051.         {
  1052.             return;
  1053.         }
  1054.  
  1055.         float Radius, HalfHeight;
  1056.         CharacterOwner->GetCapsuleComponent()->GetUnscaledCapsuleSize(Radius, HalfHeight);
  1057.         const float ComponentScale = CharacterOwner->GetCapsuleComponent()->GetShapeScale();
  1058.  
  1059.         if (ComponentScale <= KINDA_SMALL_NUMBER)
  1060.         {
  1061.             return;
  1062.         }
  1063.  
  1064.         const float NewRadius = FMath::Max(0.f, Radius - ShrinkRadius / ComponentScale);
  1065.         const float NewHalfHeight = FMath::Max(0.f, HalfHeight - ShrinkHalfHeight / ComponentScale);
  1066.  
  1067.         if (NewRadius == 0.f || NewHalfHeight == 0.f)
  1068.         {
  1069.             UE_LOG(LogCharacterMovement, Warning, TEXT("Invalid attempt to shrink Proxy capsule for %s to zero dimension!"), *CharacterOwner->GetName());
  1070.             return;
  1071.         }
  1072.  
  1073.         UE_LOG(LogCharacterMovement, Verbose, TEXT("Shrinking capsule for %s from (r=%.3f, h=%.3f) to (r=%.3f, h=%.3f)"), *CharacterOwner->GetName(),
  1074.             Radius * ComponentScale, HalfHeight * ComponentScale, NewRadius * ComponentScale, NewHalfHeight * ComponentScale);
  1075.  
  1076.         CharacterOwner->GetCapsuleComponent()->SetCapsuleSize(NewRadius, NewHalfHeight, true);
  1077.         CharacterOwner->GetCapsuleComponent()->UpdateBounds();
  1078.     }
  1079. }
  1080.  
  1081.  
  1082. void UCharacterMovementComponent::SimulatedTick(float DeltaSeconds)
  1083. {
  1084.     SCOPE_CYCLE_COUNTER(STAT_CharacterMovementSimulated);
  1085.  
  1086.     // If we are playing a RootMotion AnimMontage.
  1087.     if (CharacterOwner && CharacterOwner->IsPlayingNetworkedRootMotionMontage())
  1088.     {
  1089.         bWasSimulatingRootMotion = true;
  1090.         UE_LOG(LogRootMotion, Verbose, TEXT("UCharacterMovementComponent::SimulatedTick"));
  1091.  
  1092.         // Tick animations before physics.
  1093.         if( CharacterOwner->GetMesh() )
  1094.         {
  1095.             TickCharacterPose(DeltaSeconds);
  1096.  
  1097.             // Make sure animation didn't trigger an event that destroyed us
  1098.             if (!HasValidData())
  1099.             {
  1100.                 return;
  1101.             }
  1102.         }
  1103.  
  1104.         if( RootMotionParams.bHasRootMotion )
  1105.         {
  1106.             const FQuat OldRotationQuat = UpdatedComponent->GetComponentQuat();
  1107.             const FVector OldLocation = UpdatedComponent->GetComponentLocation();
  1108.             SimulateRootMotion(DeltaSeconds, RootMotionParams.RootMotionTransform);
  1109.             // Root Motion has been used, clear
  1110.             RootMotionParams.Clear();
  1111.  
  1112.             // debug
  1113.             if (false)
  1114.             {
  1115.                 const FRotator OldRotation = OldRotationQuat.Rotator();
  1116.                 const FRotator NewRotation = UpdatedComponent->GetComponentRotation();
  1117.                 const FVector NewLocation = UpdatedComponent->GetComponentLocation();
  1118.                 DrawDebugCoordinateSystem(GetWorld(), CharacterOwner->GetMesh()->GetComponentLocation() + FVector(0,0,1), NewRotation, 50.f, false);
  1119.                 DrawDebugLine(GetWorld(), OldLocation, NewLocation, FColor::Red, true, 10.f);
  1120.  
  1121.                 UE_LOG(LogRootMotion, Log,  TEXT("UCharacterMovementComponent::SimulatedTick DeltaMovement Translation: %s, Rotation: %s, MovementBase: %s"),
  1122.                     *(NewLocation - OldLocation).ToCompactString(), *(NewRotation - OldRotation).GetNormalized().ToCompactString(), *GetNameSafe(CharacterOwner->GetMovementBase()) );
  1123.             }
  1124.         }
  1125.  
  1126.         // then, once our position is up to date with our animation,
  1127.         // handle position correction if we have any pending updates received from the server.
  1128.         if( CharacterOwner && (CharacterOwner->RootMotionRepMoves.Num() > 0) )
  1129.         {
  1130.             CharacterOwner->SimulatedRootMotionPositionFixup(DeltaSeconds);
  1131.         }
  1132.     }
  1133.     // Not playing RootMotion AnimMontage
  1134.     else
  1135.     {
  1136.         // if we were simulating root motion, we've been ignoring regular ReplicatedMovement updates.
  1137.         // If we're not simulating root motion anymore, force us to sync our movement properties.
  1138.         // (Root Motion could leave Velocity out of sync w/ ReplicatedMovement)
  1139.         if( bWasSimulatingRootMotion )
  1140.         {
  1141.             bWasSimulatingRootMotion = false;
  1142.             if( CharacterOwner )
  1143.             {
  1144.                 CharacterOwner->RootMotionRepMoves.Empty();
  1145.                 CharacterOwner->OnRep_ReplicatedMovement();
  1146.                 CharacterOwner->OnRep_ReplicatedBasedMovement();
  1147.             }
  1148.         }
  1149.  
  1150.         if (CharacterOwner->bReplicateMovement)
  1151.         {
  1152.             if ((UpdatedComponent->IsSimulatingPhysics()
  1153.                 || (CharacterOwner && CharacterOwner->IsMatineeControlled())
  1154.                 || (CharacterOwner && CharacterOwner->IsPlayingRootMotion())))
  1155.             {
  1156.                 PerformMovement(DeltaSeconds);
  1157.             }
  1158.             else
  1159.             {
  1160.                 SimulateMovement(DeltaSeconds);
  1161.             }
  1162.         }
  1163.     }
  1164.  
  1165.     if( GetNetMode() == NM_Client )
  1166.     {
  1167.         SmoothClientPosition(DeltaSeconds);
  1168.     }
  1169. }
  1170.  
  1171. void UCharacterMovementComponent::SimulateRootMotion(float DeltaSeconds, const FTransform& LocalRootMotionTransform)
  1172. {
  1173.     if( CharacterOwner && CharacterOwner->GetMesh() && (DeltaSeconds > 0.f) )
  1174.     {
  1175.         // Convert Local Space Root Motion to world space. Do it right before used by physics to make sure we use up to date transforms, as translation is relative to rotation.
  1176.         const FTransform WorldSpaceRootMotionTransform = CharacterOwner->GetMesh()->ConvertLocalRootMotionToWorld(LocalRootMotionTransform);
  1177.  
  1178.         // Compute root motion velocity to be used by physics
  1179.         Velocity = CalcRootMotionVelocity(WorldSpaceRootMotionTransform.GetTranslation(), DeltaSeconds, Velocity);
  1180.  
  1181.         // Update replicated movement mode.
  1182.         if (bNetworkMovementModeChanged)
  1183.         {
  1184.             bNetworkMovementModeChanged = false;
  1185.             ApplyNetworkMovementMode(CharacterOwner->GetReplicatedMovementMode());
  1186.         }
  1187.  
  1188.         StartNewPhysics(DeltaSeconds, 0);
  1189.         // fixme laurent - simulate movement seems to have step up issues? investigate as that would be cheaper to use.
  1190.         //      SimulateMovement(DeltaSeconds);
  1191.  
  1192.         // Apply Root Motion rotation after movement is complete.
  1193.         const FQuat RootMotionRotationQuat = WorldSpaceRootMotionTransform.GetRotation();
  1194.         if (!RootMotionRotationQuat.Equals(FQuat::Identity))
  1195.         {
  1196.             const FQuat NewActorRotationQuat = RootMotionRotationQuat * UpdatedComponent->GetComponentQuat();
  1197.             MoveUpdatedComponent(FVector::ZeroVector, NewActorRotationQuat.Rotator(), true);
  1198.         }
  1199.     }
  1200. }
  1201.  
  1202.  
  1203. FVector UCharacterMovementComponent::CalcRootMotionVelocity(const FVector& RootMotionDeltaMove, float DeltaSeconds, const FVector& CurrentVelocity) const
  1204. {
  1205.     FVector RootMotionVelocity = RootMotionDeltaMove / DeltaSeconds;
  1206.  
  1207.     // Do not override Velocity.Z if in falling physics, we want to keep the effect of gravity.
  1208.     if (IsFalling())
  1209.     {
  1210.         const FVector GravityDir = GetGravityDirection(true);
  1211.         RootMotionVelocity = FVector::VectorPlaneProject(RootMotionVelocity, GravityDir) + GravityDir * (Velocity | GravityDir);
  1212.     }
  1213.  
  1214.     return RootMotionVelocity;
  1215. }
  1216.  
  1217.  
  1218. void UCharacterMovementComponent::SimulateMovement(float DeltaSeconds)
  1219. {
  1220.     if (!HasValidData() || UpdatedComponent->Mobility != EComponentMobility::Movable || UpdatedComponent->IsSimulatingPhysics())
  1221.     {
  1222.         return;
  1223.     }
  1224.  
  1225.     const bool bIsSimulatedProxy = (CharacterOwner->Role == ROLE_SimulatedProxy);
  1226.  
  1227.     // Workaround for replication not being updated initially
  1228.     if (bIsSimulatedProxy &&
  1229.         CharacterOwner->ReplicatedMovement.Location.IsZero() &&
  1230.         CharacterOwner->ReplicatedMovement.Rotation.IsZero() &&
  1231.         CharacterOwner->ReplicatedMovement.LinearVelocity.IsZero())
  1232.     {
  1233.         return;
  1234.     }
  1235.  
  1236.     // If base is not resolved on the client, we should not try to simulate at all
  1237.     if (CharacterOwner->GetReplicatedBasedMovement().IsBaseUnresolved())
  1238.     {
  1239.         UE_LOG(LogCharacterMovement, Verbose, TEXT("Base for simulated character '%s' is not resolved on client, skipping SimulateMovement"), *CharacterOwner->GetName());
  1240.         return;
  1241.     }
  1242.  
  1243.     UpdateGravity(DeltaSeconds);
  1244.     FVector OldVelocity;
  1245.     FVector OldLocation;
  1246.  
  1247.     // Scoped updates can improve performance of multiple MoveComponent calls.
  1248.     {
  1249.         FScopedMovementUpdate ScopedMovementUpdate(UpdatedComponent, bEnableScopedMovementUpdates ? EScopedUpdate::DeferredUpdates : EScopedUpdate::ImmediateUpdates);
  1250.  
  1251.         if (bIsSimulatedProxy)
  1252.         {
  1253.             // Handle network changes
  1254.             if (bNetworkUpdateReceived)
  1255.             {
  1256.                 bNetworkUpdateReceived = false;
  1257.                 if (bNetworkMovementModeChanged)
  1258.                 {
  1259.                     bNetworkMovementModeChanged = false;
  1260.                     ApplyNetworkMovementMode(CharacterOwner->GetReplicatedMovementMode());
  1261.                 }
  1262.                 else if (bJustTeleported)
  1263.                 {
  1264.                     // Make sure floor is current. We will continue using the replicated base, if there was one.
  1265.                     bJustTeleported = false;
  1266.                     UpdateFloorFromAdjustment();
  1267.                 }
  1268.             }
  1269.  
  1270.             HandlePendingLaunch();
  1271.         }
  1272.  
  1273.         if (MovementMode == MOVE_None)
  1274.         {
  1275.             return;
  1276.         }
  1277.  
  1278.         Acceleration = Velocity.GetSafeNormal();    // Not currently used for simulated movement
  1279.         AnalogInputModifier = 1.0f;             // Not currently used for simulated movement
  1280.  
  1281.         MaybeUpdateBasedMovement(DeltaSeconds);
  1282.  
  1283.         // simulated pawns predict location
  1284.         OldVelocity = Velocity;
  1285.         OldLocation = UpdatedComponent->GetComponentLocation();
  1286.         FStepDownResult StepDownResult;
  1287.         MoveSmooth(Velocity, DeltaSeconds, &StepDownResult);
  1288.  
  1289.         // consume path following requested velocity
  1290.         bHasRequestedVelocity = false;
  1291.  
  1292.         // if simulated gravity, find floor and check if falling
  1293.         const bool bEnableFloorCheck = (!CharacterOwner->bSimGravityDisabled || !bIsSimulatedProxy);
  1294.         if (bEnableFloorCheck && (IsMovingOnGround() || MovementMode == MOVE_Falling))
  1295.         {
  1296.             const FVector Gravity = GetGravity();
  1297.  
  1298.             if (StepDownResult.bComputedFloor)
  1299.             {
  1300.                 CurrentFloor = StepDownResult.FloorResult;
  1301.             }
  1302.             else
  1303.             {
  1304.                 if (!Gravity.IsZero() && (Velocity | Gravity) >= 0.0f)
  1305.                 {
  1306.                     FindFloor(UpdatedComponent->GetComponentLocation(), CurrentFloor, Velocity.IsZero(), NULL);
  1307.                 }
  1308.                 else
  1309.                 {
  1310.                     CurrentFloor.Clear();
  1311.                 }
  1312.             }
  1313.  
  1314.             if (!CurrentFloor.IsWalkableFloor())
  1315.             {
  1316.                 // No floor, must fall.
  1317.                 Velocity = NewFallVelocity(Velocity, Gravity, DeltaSeconds);
  1318.                 SetMovementMode(MOVE_Falling);
  1319.             }
  1320.             else
  1321.             {
  1322.                 // Walkable floor
  1323.                 if (IsMovingOnGround())
  1324.                 {
  1325.                     AdjustFloorHeight();
  1326.                     SetBase(CurrentFloor.HitResult.Component.Get(), CurrentFloor.HitResult.BoneName);
  1327.                 }
  1328.                 else if (MovementMode == MOVE_Falling)
  1329.                 {
  1330.                     if (CurrentFloor.FloorDist <= MIN_FLOOR_DIST)
  1331.                     {
  1332.                         // Landed
  1333.                         SetMovementMode(MOVE_Walking);
  1334.                     }
  1335.                     else
  1336.                     {
  1337.                         // Continue falling.
  1338.                         Velocity = NewFallVelocity(Velocity, Gravity, DeltaSeconds);
  1339.                         CurrentFloor.Clear();
  1340.                     }
  1341.                 }
  1342.             }
  1343.         }
  1344.  
  1345.         OnMovementUpdated(DeltaSeconds, OldLocation, OldVelocity);
  1346.     } // End scoped movement update
  1347.  
  1348.     // Call custom post-movement events. These happen after the scoped movement completes in case the events want to use the current state of overlaps etc.
  1349.     CallMovementUpdateDelegate(DeltaSeconds, OldLocation, OldVelocity);
  1350.  
  1351.     SaveBaseLocation();
  1352.     UpdateComponentVelocity();
  1353.     bJustTeleported = false;
  1354.  
  1355.     LastUpdateLocation = UpdatedComponent ? UpdatedComponent->GetComponentLocation() : FVector::ZeroVector;
  1356. }
  1357.  
  1358. UPrimitiveComponent* UCharacterMovementComponent::GetMovementBase() const
  1359. {
  1360.     return CharacterOwner ? CharacterOwner->GetMovementBase() : NULL;
  1361. }
  1362.  
  1363. void UCharacterMovementComponent::SetBase( UPrimitiveComponent* NewBase, FName BoneName, bool bNotifyActor )
  1364. {
  1365.     if (CharacterOwner)
  1366.     {
  1367.         CharacterOwner->SetBase(NewBase, NewBase ? BoneName : NAME_None, bNotifyActor);
  1368.     }
  1369. }
  1370.  
  1371. void UCharacterMovementComponent::SetBaseFromFloor(const FFindFloorResult& FloorResult)
  1372. {
  1373.     if (FloorResult.IsWalkableFloor())
  1374.     {
  1375.         SetBase(FloorResult.HitResult.GetComponent(), FloorResult.HitResult.BoneName);
  1376.     }
  1377.     else
  1378.     {
  1379.         SetBase(nullptr);
  1380.     }
  1381. }
  1382.  
  1383. void UCharacterMovementComponent::MaybeUpdateBasedMovement(float DeltaSeconds)
  1384. {
  1385.     bDeferUpdateBasedMovement = false;
  1386.  
  1387.     UPrimitiveComponent* MovementBase = CharacterOwner->GetMovementBase();
  1388.     if (MovementBaseUtility::UseRelativeLocation(MovementBase))
  1389.     {
  1390.         const bool bBaseIsSimulatingPhysics = MovementBase->IsSimulatingPhysics();
  1391.  
  1392.         // Temporarily disabling deferred tick on skeletal mesh components that sim physics.
  1393.         // We need to be consistent on when we read the bone locations for those, and while this reads
  1394.         // the wrong location, the relative changes (which is what we care about) will be accurate.
  1395.         const bool bAllowDefer = (bBaseIsSimulatingPhysics && !Cast<USkeletalMeshComponent>(MovementBase));
  1396.  
  1397.         if (!bBaseIsSimulatingPhysics || !bAllowDefer)
  1398.         {
  1399.             UpdateBasedMovement(DeltaSeconds);
  1400.             PreClothComponentTick.SetTickFunctionEnable(false);
  1401.         }
  1402.         else
  1403.         {
  1404.             // defer movement base update until after physics
  1405.             bDeferUpdateBasedMovement = true;
  1406.             PreClothComponentTick.SetTickFunctionEnable(true);
  1407.         }
  1408.     }
  1409. }
  1410.  
  1411. // todo: deprecated, remove.
  1412. void UCharacterMovementComponent::MaybeSaveBaseLocation()
  1413. {
  1414.     SaveBaseLocation();
  1415. }
  1416.  
  1417. // @todo UE4 - handle lift moving up and down through encroachment
  1418. void UCharacterMovementComponent::UpdateBasedMovement(float DeltaSeconds)
  1419. {
  1420.     if (!HasValidData())
  1421.     {
  1422.         return;
  1423.     }
  1424.  
  1425.     const UPrimitiveComponent* MovementBase = CharacterOwner->GetMovementBase();
  1426.     if (!MovementBaseUtility::UseRelativeLocation(MovementBase))
  1427.     {
  1428.         return;
  1429.     }
  1430.  
  1431.     if (!IsValid(MovementBase) || !IsValid(MovementBase->GetOwner()))
  1432.     {
  1433.         SetBase(NULL);
  1434.         return;
  1435.     }
  1436.  
  1437.     // Ignore collision with bases during these movements.
  1438.     TGuardValue<EMoveComponentFlags> ScopedFlagRestore(MoveComponentFlags, MoveComponentFlags | MOVECOMP_IgnoreBases);
  1439.  
  1440.     FQuat DeltaQuat = FQuat::Identity;
  1441.     FVector DeltaPosition = FVector::ZeroVector;
  1442.  
  1443.     FQuat NewBaseQuat;
  1444.     FVector NewBaseLocation;
  1445.     if (!MovementBaseUtility::GetMovementBaseTransform(MovementBase, CharacterOwner->GetBasedMovement().BoneName, NewBaseLocation, NewBaseQuat))
  1446.     {
  1447.         return;
  1448.     }
  1449.  
  1450.     // Find change in rotation
  1451.     const bool bRotationChanged = !OldBaseQuat.Equals(NewBaseQuat, 1e-8f);
  1452.     if (bRotationChanged)
  1453.     {
  1454.         DeltaQuat = NewBaseQuat * OldBaseQuat.Inverse();
  1455.     }
  1456.  
  1457.     // only if base moved
  1458.     if (bRotationChanged || OldBaseLocation != NewBaseLocation)
  1459.     {
  1460.         // Calculate new transform matrix of base actor (ignoring scale).
  1461.         const FQuatRotationTranslationMatrix OldLocalToWorld(OldBaseQuat, OldBaseLocation);
  1462.         const FQuatRotationTranslationMatrix NewLocalToWorld(NewBaseQuat, NewBaseLocation);
  1463.  
  1464.         if( CharacterOwner->IsMatineeControlled() )
  1465.         {
  1466.             FRotationTranslationMatrix HardRelMatrix(CharacterOwner->GetBasedMovement().Rotation, CharacterOwner->GetBasedMovement().Location);
  1467.             const FMatrix NewWorldTM = HardRelMatrix * NewLocalToWorld;
  1468.             const FQuat NewWorldRot = bIgnoreBaseRotation ? UpdatedComponent->GetComponentQuat() : NewWorldTM.ToQuat();
  1469.             MoveUpdatedComponent( NewWorldTM.GetOrigin() - UpdatedComponent->GetComponentLocation(), NewWorldRot.Rotator(), true );
  1470.         }
  1471.         else
  1472.         {
  1473.             FQuat FinalQuat = UpdatedComponent->GetComponentQuat();
  1474.  
  1475.             if (bRotationChanged && !bIgnoreBaseRotation)
  1476.             {
  1477.                 // Apply change in rotation and pipe through FaceRotation to maintain axis restrictions
  1478.                 const FQuat PawnOldQuat = UpdatedComponent->GetComponentQuat();
  1479.                 const FQuat TargetQuat = DeltaQuat * FinalQuat;
  1480.                 FRotator TargetRotator(TargetQuat);
  1481.                 CharacterOwner->FaceRotation(TargetRotator, 0.f);
  1482.                 FinalQuat = UpdatedComponent->GetComponentQuat();
  1483.  
  1484.                 if (PawnOldQuat.Equals(FinalQuat, 1e-6f))
  1485.                 {
  1486.                     // Nothing changed. This means we probably are using another rotation mechanism (bOrientToMovement etc). We should still follow the base object.
  1487.                     // @todo: This assumes only Yaw is used, currently a valid assumption. This is the only reason FaceRotation() is used above really, aside from being a virtual hook.
  1488.                     if (bOrientRotationToMovement || (bUseControllerDesiredRotation && CharacterOwner->Controller))
  1489.                     {
  1490.                         TargetRotator.Pitch = 0.f;
  1491.                         TargetRotator.Roll = 0.f;
  1492.                         MoveUpdatedComponent(FVector::ZeroVector, TargetRotator, false);
  1493.                         FinalQuat = UpdatedComponent->GetComponentQuat();
  1494.                     }
  1495.                 }
  1496.  
  1497.                 // Pipe through ControlRotation, to affect camera.
  1498.                 if (CharacterOwner->Controller)
  1499.                 {
  1500.                     const FQuat PawnDeltaRotation = FinalQuat * PawnOldQuat.Inverse();
  1501.                     FRotator FinalRotation = FinalQuat.Rotator();
  1502.                     UpdateBasedRotation(FinalRotation, PawnDeltaRotation.Rotator());
  1503.                     FinalQuat = UpdatedComponent->GetComponentQuat();
  1504.                 }
  1505.             }
  1506.  
  1507.             // We need to offset the base of the character here, not its origin, so offset by half height
  1508.             float HalfHeight, Radius;
  1509.             CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleSize(Radius, HalfHeight);
  1510.  
  1511.             const FVector BaseOffset = GetCapsuleAxisZ() * HalfHeight;
  1512.             const FVector LocalBasePos = OldLocalToWorld.InverseTransformPosition(UpdatedComponent->GetComponentLocation() - BaseOffset);
  1513.             const FVector NewWorldPos = ConstrainLocationToPlane(NewLocalToWorld.TransformPosition(LocalBasePos) + BaseOffset);
  1514.             DeltaPosition = ConstrainDirectionToPlane(NewWorldPos - UpdatedComponent->GetComponentLocation());
  1515.  
  1516.             // move attached actor.
  1517.             if (bFastAttachedMove)
  1518.             {
  1519.                 // we're trusting no other obstacle can prevent the move here
  1520.                 UpdatedComponent->SetWorldLocationAndRotation(NewWorldPos, FinalQuat, false);
  1521.             }
  1522.             else
  1523.             {
  1524.                 FHitResult MoveOnBaseHit(1.f);
  1525.                 const FVector OldLocation = UpdatedComponent->GetComponentLocation();
  1526.                 MoveUpdatedComponent(DeltaPosition, FinalQuat.Rotator(), true, &MoveOnBaseHit);
  1527.                 if ((UpdatedComponent->GetComponentLocation() - (OldLocation + DeltaPosition)).IsNearlyZero() == false)
  1528.                 {
  1529.                     OnUnableToFollowBaseMove(DeltaPosition, OldLocation, MoveOnBaseHit);
  1530.                 }
  1531.             }
  1532.         }
  1533.  
  1534.         if (MovementBase->IsSimulatingPhysics() && CharacterOwner->GetMesh())
  1535.         {
  1536.             CharacterOwner->GetMesh()->ApplyDeltaToAllPhysicsTransforms(DeltaPosition, DeltaQuat);
  1537.         }
  1538.     }
  1539. }
  1540.  
  1541.  
  1542. void UCharacterMovementComponent::OnUnableToFollowBaseMove(const FVector& DeltaPosition, const FVector& OldLocation, const FHitResult& MoveOnBaseHit)
  1543. {
  1544.     // no default implementation, left for subclasses to override.
  1545. }
  1546.  
  1547.  
  1548. void UCharacterMovementComponent::UpdateBasedRotation(FRotator& FinalRotation, const FRotator& ReducedRotation)
  1549. {
  1550.     AController* Controller = CharacterOwner ? CharacterOwner->Controller : NULL;
  1551.     float ControllerRoll = 0.f;
  1552.     if( Controller && !bIgnoreBaseRotation )
  1553.     {
  1554.         const FRotator ControllerRot = Controller->GetControlRotation();
  1555.         ControllerRoll = ControllerRot.Roll;
  1556.         Controller->SetControlRotation(ControllerRot + ReducedRotation);
  1557.     }
  1558.  
  1559.     if (bIgnoreBaseRollMove)
  1560. {
  1561.         // Remove roll.
  1562.         FinalRotation.Roll = 0.0f;
  1563.         if (Controller)
  1564.         {
  1565.             FinalRotation.Roll = UpdatedComponent->GetComponentRotation().Roll;
  1566.             FRotator NewRotation = Controller->GetControlRotation();
  1567.             NewRotation.Roll = ControllerRoll;
  1568.             Controller->SetControlRotation(NewRotation);
  1569.         }
  1570.     }
  1571. }
  1572.  
  1573. void UCharacterMovementComponent::DisableMovement()
  1574. {
  1575.     if (CharacterOwner)
  1576.     {
  1577.         SetMovementMode(MOVE_None);
  1578.     }
  1579.     else
  1580.     {
  1581.         MovementMode = MOVE_None;
  1582.         CustomMovementMode = 0;
  1583.     }
  1584. }
  1585.  
  1586. void UCharacterMovementComponent::PerformMovement(float DeltaSeconds)
  1587. {
  1588.     SCOPE_CYCLE_COUNTER(STAT_CharacterMovement);
  1589.     SCOPE_CYCLE_COUNTER(STAT_CharacterMovementAuthority);
  1590.  
  1591.     if (!HasValidData())
  1592.     {
  1593.         return;
  1594.     }
  1595.  
  1596.     // no movement if we can't move, or if currently doing physical simulation on UpdatedComponent
  1597.     if (MovementMode == MOVE_None || UpdatedComponent->Mobility != EComponentMobility::Movable || UpdatedComponent->IsSimulatingPhysics())
  1598.     {
  1599.         return;
  1600.     }
  1601.  
  1602.     UpdateGravity(DeltaSeconds);
  1603.  
  1604.     // Force floor update if we've moved outside of CharacterMovement since last update.
  1605.     bForceNextFloorCheck |= (IsMovingOnGround() && UpdatedComponent->GetComponentLocation() != LastUpdateLocation);
  1606.  
  1607.     FVector OldVelocity;
  1608.     FVector OldLocation;
  1609.  
  1610.     // Scoped updates can improve performance of multiple MoveComponent calls.
  1611.     {
  1612.         FScopedMovementUpdate ScopedMovementUpdate(UpdatedComponent, bEnableScopedMovementUpdates ? EScopedUpdate::DeferredUpdates : EScopedUpdate::ImmediateUpdates);
  1613.  
  1614.         MaybeUpdateBasedMovement(DeltaSeconds);
  1615.  
  1616.         OldVelocity = Velocity;
  1617.         OldLocation = UpdatedComponent->GetComponentLocation();
  1618.  
  1619.         ApplyAccumulatedForces(DeltaSeconds);
  1620.  
  1621.         // Check for a change in crouch state. Players toggle crouch by changing bWantsToCrouch.
  1622.         const bool bAllowedToCrouch = CanCrouchInCurrentState();
  1623.         if ((!bAllowedToCrouch || !bWantsToCrouch) && IsCrouching())
  1624.         {
  1625.             UnCrouch(false);
  1626.         }
  1627.         else if (bWantsToCrouch && bAllowedToCrouch && !IsCrouching())
  1628.         {
  1629.             Crouch(false);
  1630.         }
  1631.  
  1632.         if (MovementMode == MOVE_NavWalking && bWantsToLeaveNavWalking)
  1633.         {
  1634.             TryToLeaveNavWalking();
  1635.         }
  1636.  
  1637.         // Character::LaunchCharacter() has been deferred until now.
  1638.         HandlePendingLaunch();
  1639.  
  1640.         // If using RootMotion, tick animations before running physics.
  1641.         if (!CharacterOwner->bClientUpdating && !CharacterOwner->bServerMoveIgnoreRootMotion && CharacterOwner->IsPlayingRootMotion() && CharacterOwner->GetMesh())
  1642.         {
  1643.             TickCharacterPose(DeltaSeconds);
  1644.  
  1645.             // Make sure animation didn't trigger an event that destroyed us
  1646.             if (!HasValidData())
  1647.             {
  1648.                 return;
  1649.             }
  1650.  
  1651.             // For local human clients, save off root motion data so it can be used by movement networking code.
  1652.             if( CharacterOwner->IsLocallyControlled() && (CharacterOwner->Role == ROLE_AutonomousProxy) && CharacterOwner->IsPlayingNetworkedRootMotionMontage() )
  1653.             {
  1654.                 CharacterOwner->ClientRootMotionParams = RootMotionParams;
  1655.             }
  1656.         }
  1657.  
  1658.         // if we're about to use root motion, convert it to world space first.
  1659.         if (HasRootMotion())
  1660.         {
  1661.             USkeletalMeshComponent * SkelMeshComp = CharacterOwner->GetMesh();
  1662.             if (SkelMeshComp)
  1663.             {
  1664.                 // Convert Local Space Root Motion to world space. Do it right before used by physics to make sure we use up to date transforms, as translation is relative to rotation.
  1665.                 RootMotionParams.Set(SkelMeshComp->ConvertLocalRootMotionToWorld(RootMotionParams.RootMotionTransform));
  1666.  
  1667.                 // Then turn root motion to velocity to be used by various physics modes.
  1668.                 if (DeltaSeconds > 0.f)
  1669.                 {
  1670.                     Velocity = CalcRootMotionVelocity(RootMotionParams.RootMotionTransform.GetTranslation(), DeltaSeconds, Velocity);
  1671.                 }
  1672.  
  1673.                 UE_LOG(LogRootMotion, Log, TEXT("PerformMovement WorldSpaceRootMotion Translation: %s, Rotation: %s, Actor Facing: %s, Velocity: %s")
  1674.                     , *RootMotionParams.RootMotionTransform.GetTranslation().ToCompactString()
  1675.                     , *RootMotionParams.RootMotionTransform.GetRotation().Rotator().ToCompactString()
  1676.                     , *CharacterOwner->GetActorForwardVector().ToCompactString()
  1677.                     , *Velocity.ToCompactString()
  1678.                     );
  1679.             }
  1680.         }
  1681.  
  1682.         // NaN tracking
  1683.         checkf(!Velocity.ContainsNaN(), TEXT("UCharacterMovementComponent::PerformMovement: Velocity contains NaN (%s: %s)\n%s"), *GetPathNameSafe(this), *GetPathNameSafe(GetOuter()), *Velocity.ToString());
  1684.  
  1685.         // Clear jump input now, to allow movement events to trigger it for next update.
  1686.         CharacterOwner->ClearJumpInput();
  1687.  
  1688.         // change position
  1689.         StartNewPhysics(DeltaSeconds, 0);
  1690.  
  1691.         if (!HasValidData())
  1692.         {
  1693.             return;
  1694.         }
  1695.  
  1696.         // uncrouch if no longer allowed to be crouched
  1697.         if (IsCrouching() && !CanCrouchInCurrentState())
  1698.         {
  1699.             UnCrouch(false);
  1700.         }
  1701.  
  1702.         if (!HasRootMotion() && !CharacterOwner->IsMatineeControlled())
  1703.         {
  1704.             PhysicsRotation(DeltaSeconds);
  1705.         }
  1706.  
  1707.         // Apply Root Motion rotation after movement is complete.
  1708.         if (HasRootMotion())
  1709.         {
  1710.             const FRotator OldActorRotation = CharacterOwner->GetActorRotation();
  1711.             const FRotator RootMotionRotation = RootMotionParams.RootMotionTransform.GetRotation().Rotator();
  1712.             if (!RootMotionRotation.IsNearlyZero())
  1713.             {
  1714.                 const FRotator NewActorRotation = (OldActorRotation + RootMotionRotation).GetNormalized();
  1715.                 MoveUpdatedComponent(FVector::ZeroVector, NewActorRotation, true);
  1716.             }
  1717.  
  1718.             // debug
  1719.             if (false)
  1720.             {
  1721.                 const FVector ResultingLocation = UpdatedComponent->GetComponentLocation();
  1722.                 const FRotator ResultingRotation = UpdatedComponent->GetComponentRotation();
  1723.  
  1724.                 // Show current position
  1725.                 DrawDebugCoordinateSystem(GetWorld(), CharacterOwner->GetMesh()->GetComponentLocation() + FVector(0, 0, 1), ResultingRotation, 50.f, false);
  1726.  
  1727.                 // Show resulting delta move.
  1728.                 DrawDebugLine(GetWorld(), OldLocation, ResultingLocation, FColor::Red, true, 10.f);
  1729.  
  1730.                 // Log details.
  1731.                 UE_LOG(LogRootMotion, Warning, TEXT("PerformMovement Resulting DeltaMove Translation: %s, Rotation: %s, MovementBase: %s"),
  1732.                     *(ResultingLocation - OldLocation).ToCompactString(), *(ResultingRotation - OldActorRotation).GetNormalized().ToCompactString(), *GetNameSafe(CharacterOwner->GetMovementBase()));
  1733.  
  1734.                 const FVector RMTranslation = RootMotionParams.RootMotionTransform.GetTranslation();
  1735.                 const FRotator RMRotation = RootMotionParams.RootMotionTransform.GetRotation().Rotator();
  1736.                 UE_LOG(LogRootMotion, Warning, TEXT("PerformMovement Resulting DeltaError Translation: %s, Rotation: %s"),
  1737.                     *(ResultingLocation - OldLocation - RMTranslation).ToCompactString(), *(ResultingRotation - OldActorRotation - RMRotation).GetNormalized().ToCompactString());
  1738.             }
  1739.  
  1740.             // Root Motion has been used, clear
  1741.             RootMotionParams.Clear();
  1742.         }
  1743.  
  1744.         // consume path following requested velocity
  1745.         bHasRequestedVelocity = false;
  1746.  
  1747.         OnMovementUpdated(DeltaSeconds, OldLocation, OldVelocity);
  1748.     } // End scoped movement update
  1749.  
  1750.     // Call external post-movement events. These happen after the scoped movement completes in case the events want to use the current state of overlaps etc.
  1751.     CallMovementUpdateDelegate(DeltaSeconds, OldLocation, OldVelocity);
  1752.  
  1753.     SaveBaseLocation();
  1754.     UpdateComponentVelocity();
  1755.  
  1756.     LastUpdateLocation = UpdatedComponent ? UpdatedComponent->GetComponentLocation() : FVector::ZeroVector;
  1757. }
  1758.  
  1759.  
  1760. void UCharacterMovementComponent::CallMovementUpdateDelegate(float DeltaTime, const FVector& OldLocation, const FVector& OldVelocity)
  1761. {
  1762.     SCOPE_CYCLE_COUNTER(STAT_CharMoveUpdateDelegate);
  1763.  
  1764.     // Update component velocity in case events want to read it
  1765.     UpdateComponentVelocity();
  1766.  
  1767.     // Delegate (for blueprints)
  1768.     if (CharacterOwner)
  1769.     {
  1770.         CharacterOwner->OnCharacterMovementUpdated.Broadcast(DeltaTime, OldLocation, OldVelocity);
  1771.     }
  1772. }
  1773.  
  1774.  
  1775. void UCharacterMovementComponent::OnMovementUpdated(float DeltaTime, const FVector& OldLocation, const FVector& OldVelocity)
  1776. {
  1777.     // empty base implementation, intended for derived classes to override.
  1778. }
  1779.  
  1780.  
  1781. void UCharacterMovementComponent::SaveBaseLocation()
  1782. {
  1783.     if (!HasValidData())
  1784.     {
  1785.         return;
  1786.     }
  1787.  
  1788.     const UPrimitiveComponent* MovementBase = CharacterOwner->GetMovementBase();
  1789.     if (MovementBaseUtility::UseRelativeLocation(MovementBase) && !CharacterOwner->IsMatineeControlled())
  1790.     {
  1791.         // Read transforms into OldBaseLocation, OldBaseQuat
  1792.         MovementBaseUtility::GetMovementBaseTransform(MovementBase, CharacterOwner->GetBasedMovement().BoneName, OldBaseLocation, OldBaseQuat);
  1793.  
  1794.         // Location
  1795.         const FVector RelativeLocation = UpdatedComponent->GetComponentLocation() - OldBaseLocation;
  1796.  
  1797.         // Rotation
  1798.         if (bIgnoreBaseRotation)
  1799.         {
  1800.             // Absolute rotation
  1801.             CharacterOwner->SaveRelativeBasedMovement(RelativeLocation, UpdatedComponent->GetComponentRotation(), false);
  1802.         }
  1803.         else
  1804.         {
  1805.             // Relative rotation
  1806.             const FRotator RelativeRotation = (FQuatRotationMatrix(UpdatedComponent->GetComponentQuat()) * FQuatRotationMatrix(OldBaseQuat).GetTransposed()).Rotator();
  1807.             CharacterOwner->SaveRelativeBasedMovement(RelativeLocation, RelativeRotation, true);
  1808.         }
  1809.     }
  1810. }
  1811.  
  1812.  
  1813. bool UCharacterMovementComponent::CanCrouchInCurrentState() const
  1814. {
  1815.     if (!CanEverCrouch())
  1816.     {
  1817.         return false;
  1818.     }
  1819.  
  1820.     return IsFalling() || IsMovingOnGround();
  1821. }
  1822.  
  1823.  
  1824. void UCharacterMovementComponent::Crouch(bool bClientSimulation)
  1825. {
  1826.     if (!HasValidData())
  1827.     {
  1828.         return;
  1829.     }
  1830.  
  1831.     if (!CanCrouchInCurrentState())
  1832.     {
  1833.         return;
  1834.     }
  1835.  
  1836.     // See if collision is already at desired size.
  1837.     if (CharacterOwner->GetCapsuleComponent()->GetUnscaledCapsuleHalfHeight() == CrouchedHalfHeight)
  1838.     {
  1839.         if (!bClientSimulation)
  1840.         {
  1841.             CharacterOwner->bIsCrouched = true;
  1842.         }
  1843.         CharacterOwner->OnStartCrouch(0.f, 0.f);
  1844.         return;
  1845.     }
  1846.  
  1847.     if (bClientSimulation && CharacterOwner->Role == ROLE_SimulatedProxy)
  1848.     {
  1849.         // Restore collision size before crouching.
  1850.         ACharacter* DefaultCharacter = CharacterOwner->GetClass()->GetDefaultObject<ACharacter>();
  1851.         CharacterOwner->GetCapsuleComponent()->SetCapsuleSize(DefaultCharacter->GetCapsuleComponent()->GetUnscaledCapsuleRadius(), DefaultCharacter->GetCapsuleComponent()->GetUnscaledCapsuleHalfHeight());
  1852.         bShrinkProxyCapsule = true;
  1853.     }
  1854.  
  1855.     // Change collision size to crouching dimensions.
  1856.     const float ComponentScale = CharacterOwner->GetCapsuleComponent()->GetShapeScale();
  1857.     const float OldUnscaledHalfHeight = CharacterOwner->GetCapsuleComponent()->GetUnscaledCapsuleHalfHeight();
  1858.     CharacterOwner->GetCapsuleComponent()->SetCapsuleSize(CharacterOwner->GetCapsuleComponent()->GetUnscaledCapsuleRadius(), CrouchedHalfHeight);
  1859.     float HalfHeightAdjust = (OldUnscaledHalfHeight - CrouchedHalfHeight);
  1860.     float ScaledHalfHeightAdjust = HalfHeightAdjust * ComponentScale;
  1861.  
  1862.     if (!bClientSimulation)
  1863.     {
  1864.         const FVector CapsuleDown = GetCapsuleAxisZ() * -1.0f;
  1865.  
  1866.         // Crouching to a larger height? (this is rare)
  1867.         if (CrouchedHalfHeight > OldUnscaledHalfHeight)
  1868.         {
  1869.             FCollisionQueryParams CapsuleParams(CharacterMovementComponentStatics::CrouchTraceName, false, CharacterOwner);
  1870.             FCollisionResponseParams ResponseParam;
  1871.             InitCollisionParams(CapsuleParams, ResponseParam);
  1872.             const bool bEncroached = GetWorld()->OverlapBlockingTestByChannel(UpdatedComponent->GetComponentLocation() - FVector(0.f, 0.f, ScaledHalfHeightAdjust), FQuat::Identity,
  1873.                 UpdatedComponent->GetCollisionObjectType(), GetPawnCapsuleCollisionShape(SHRINK_None), CapsuleParams, ResponseParam);
  1874.  
  1875.             // If encroached, cancel
  1876.             if (bEncroached)
  1877.             {
  1878.                 CharacterOwner->GetCapsuleComponent()->SetCapsuleSize(CharacterOwner->GetCapsuleComponent()->GetUnscaledCapsuleRadius(), OldUnscaledHalfHeight);
  1879.                 return;
  1880.             }
  1881.         }
  1882.  
  1883.         if (bCrouchMaintainsBaseLocation)
  1884.         {
  1885.             // Intentionally not using MoveUpdatedComponent, where a horizontal plane constraint would prevent the base of the capsule from staying at the same spot.
  1886.             UpdatedComponent->MoveComponent(CapsuleDown * ScaledHalfHeightAdjust, CharacterOwner->GetActorRotation(), true);
  1887.         }
  1888.  
  1889.         CharacterOwner->bIsCrouched = true;
  1890.     }
  1891.  
  1892.     bForceNextFloorCheck = true;
  1893.  
  1894.     // OnStartCrouch takes the change from the Default size, not the current one (though they are usually the same).
  1895.     ACharacter* DefaultCharacter = CharacterOwner->GetClass()->GetDefaultObject<ACharacter>();
  1896.     HalfHeightAdjust = (DefaultCharacter->GetCapsuleComponent()->GetUnscaledCapsuleHalfHeight() - CrouchedHalfHeight);
  1897.     ScaledHalfHeightAdjust = HalfHeightAdjust * ComponentScale;
  1898.  
  1899.     AdjustProxyCapsuleSize();
  1900.     CharacterOwner->OnStartCrouch( HalfHeightAdjust, ScaledHalfHeightAdjust );
  1901. }
  1902.  
  1903.  
  1904. void UCharacterMovementComponent::UnCrouch(bool bClientSimulation)
  1905. {
  1906.     if (!HasValidData())
  1907.     {
  1908.         return;
  1909.     }
  1910.  
  1911.     ACharacter* DefaultCharacter = CharacterOwner->GetClass()->GetDefaultObject<ACharacter>();
  1912.  
  1913.     // See if collision is already at desired size.
  1914.     if (CharacterOwner->GetCapsuleComponent()->GetUnscaledCapsuleHalfHeight() == DefaultCharacter->GetCapsuleComponent()->GetUnscaledCapsuleHalfHeight())
  1915.     {
  1916.         if (!bClientSimulation)
  1917.         {
  1918.             CharacterOwner->bIsCrouched = false;
  1919.         }
  1920.         CharacterOwner->OnEndCrouch(0.f, 0.f);
  1921.         return;
  1922.     }
  1923.  
  1924.     const float CurrentCrouchedHalfHeight = CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleHalfHeight();
  1925.  
  1926.     const float ComponentScale = CharacterOwner->GetCapsuleComponent()->GetShapeScale();
  1927.     const float OldUnscaledHalfHeight = CharacterOwner->GetCapsuleComponent()->GetUnscaledCapsuleHalfHeight();
  1928.     const float HalfHeightAdjust = DefaultCharacter->GetCapsuleComponent()->GetUnscaledCapsuleHalfHeight() - OldUnscaledHalfHeight;
  1929.     const float ScaledHalfHeightAdjust = HalfHeightAdjust * ComponentScale;
  1930.     const FVector PawnLocation = UpdatedComponent->GetComponentLocation();
  1931.  
  1932.     // Grow to uncrouched size.
  1933.     check(CharacterOwner->GetCapsuleComponent());
  1934.     bool bUpdateOverlaps = false;
  1935.     CharacterOwner->GetCapsuleComponent()->SetCapsuleSize(DefaultCharacter->GetCapsuleComponent()->GetUnscaledCapsuleRadius(), DefaultCharacter->GetCapsuleComponent()->GetUnscaledCapsuleHalfHeight(), bUpdateOverlaps);
  1936.     CharacterOwner->GetCapsuleComponent()->UpdateBounds(); // Force an update of the bounds with the new dimensions.
  1937.  
  1938.     if (!bClientSimulation)
  1939.     {
  1940.         // Try to stay in place and see if the larger capsule fits. We use a slightly taller capsule to avoid penetration.
  1941.         const float SweepInflation = KINDA_SMALL_NUMBER * 10.f;
  1942.         const FQuat CapsuleRotation = GetCapsuleRotation();
  1943.         const FVector CapsuleDown = GetCapsuleAxisZ() * -1.0f;
  1944.         FCollisionQueryParams CapsuleParams(CharacterMovementComponentStatics::CrouchTraceName, false, CharacterOwner);
  1945.         FCollisionResponseParams ResponseParam;
  1946.         InitCollisionParams(CapsuleParams, ResponseParam);
  1947.         const FCollisionShape StandingCapsuleShape = GetPawnCapsuleCollisionShape(SHRINK_HeightCustom, -SweepInflation); // Shrink by negative amount, so actually grow it.
  1948.         const ECollisionChannel CollisionChannel = UpdatedComponent->GetCollisionObjectType();
  1949.         bool bEncroached = true;
  1950.  
  1951.         if (!bCrouchMaintainsBaseLocation)
  1952.         {
  1953.             // Expand in place.
  1954.             bEncroached = GetWorld()->OverlapBlockingTestByChannel(PawnLocation, CapsuleRotation, CollisionChannel, StandingCapsuleShape, CapsuleParams, ResponseParam);
  1955.  
  1956.             if (bEncroached)
  1957.             {
  1958.                 // Try adjusting capsule position to see if we can avoid encroachment.
  1959.                 if (ScaledHalfHeightAdjust > 0.0f)
  1960.                 {
  1961.                     // Shrink to a short capsule, sweep down to base to find where that would hit something, and then try to stand up from there.
  1962.                     float PawnRadius, PawnHalfHeight;
  1963.                     CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleSize(PawnRadius, PawnHalfHeight);
  1964.                     const float ShrinkHalfHeight = PawnHalfHeight - PawnRadius;
  1965.                     const float TraceDist = PawnHalfHeight - ShrinkHalfHeight;
  1966.  
  1967.                     FHitResult Hit(1.0f);
  1968.                     const FCollisionShape ShortCapsuleShape = GetPawnCapsuleCollisionShape(SHRINK_HeightCustom, ShrinkHalfHeight);
  1969.                     const bool bBlockingHit = GetWorld()->SweepSingleByChannel(Hit, PawnLocation, PawnLocation + CapsuleDown * TraceDist, CapsuleRotation, CollisionChannel, ShortCapsuleShape, CapsuleParams);
  1970.  
  1971.                     if (Hit.bStartPenetrating)
  1972.                     {
  1973.                         bEncroached = true;
  1974.                     }
  1975.                     else
  1976.                     {
  1977.                         // Compute where the base of the sweep ended up, and see if we can stand there.
  1978.                         const float DistanceToBase = (Hit.Time * TraceDist) + ShortCapsuleShape.Capsule.HalfHeight;
  1979.                         const FVector NewLoc = PawnLocation - CapsuleDown * (-DistanceToBase + PawnHalfHeight + SweepInflation + MIN_FLOOR_DIST / 2.0f);
  1980.                         bEncroached = GetWorld()->OverlapBlockingTestByChannel(NewLoc, CapsuleRotation, CollisionChannel, StandingCapsuleShape, CapsuleParams, ResponseParam);
  1981.                         if (!bEncroached)
  1982.                         {
  1983.                             // Intentionally not using MoveUpdatedComponent, where a horizontal plane constraint would prevent the base of the capsule from staying at the same spot.
  1984.                             UpdatedComponent->MoveComponent(NewLoc - PawnLocation, UpdatedComponent->GetComponentQuat(), false);
  1985.                         }
  1986.                     }
  1987.                 }
  1988.             }
  1989.         }
  1990.         else
  1991.         {
  1992.             // Expand while keeping base location the same.
  1993.             FVector StandingLocation = PawnLocation - CapsuleDown * (StandingCapsuleShape.GetCapsuleHalfHeight() - CurrentCrouchedHalfHeight);
  1994.             bEncroached = GetWorld()->OverlapBlockingTestByChannel(StandingLocation, CapsuleRotation, CollisionChannel, StandingCapsuleShape, CapsuleParams, ResponseParam);
  1995.  
  1996.             if (bEncroached)
  1997.             {
  1998.                 if (IsMovingOnGround())
  1999.                 {
  2000.                     // Something might be just barely overhead, try moving down closer to the floor to avoid it.
  2001.                     const float MinFloorDist = KINDA_SMALL_NUMBER * 10.0f;
  2002.                     if (CurrentFloor.bBlockingHit && CurrentFloor.FloorDist > MinFloorDist)
  2003.                     {
  2004.                         StandingLocation += CapsuleDown * (CurrentFloor.FloorDist - MinFloorDist);
  2005.                         bEncroached = GetWorld()->OverlapBlockingTestByChannel(StandingLocation, CapsuleRotation, CollisionChannel, StandingCapsuleShape, CapsuleParams, ResponseParam);
  2006.                     }
  2007.                 }
  2008.             }
  2009.  
  2010.             if (!bEncroached)
  2011.             {
  2012.                 // Commit the change in location.
  2013.                 UpdatedComponent->MoveComponent(StandingLocation - PawnLocation, UpdatedComponent->GetComponentQuat(), false);
  2014.                 bForceNextFloorCheck = true;
  2015.             }
  2016.         }
  2017.  
  2018.         // If still encroached then abort.
  2019.         if (bEncroached)
  2020.         {
  2021.             CharacterOwner->GetCapsuleComponent()->SetCapsuleSize(CharacterOwner->GetCapsuleComponent()->GetUnscaledCapsuleRadius(), OldUnscaledHalfHeight, false);
  2022.             CharacterOwner->GetCapsuleComponent()->UpdateBounds(); // Update bounds again back to old value.
  2023.             return;
  2024.         }
  2025.  
  2026.         CharacterOwner->bIsCrouched = false;
  2027.     }
  2028.     else
  2029.     {
  2030.         bShrinkProxyCapsule = true;
  2031.     }
  2032.  
  2033.     // Now call SetCapsuleSize() to cause touch/untouch events.
  2034.     bUpdateOverlaps = true;
  2035.     CharacterOwner->GetCapsuleComponent()->SetCapsuleSize(DefaultCharacter->GetCapsuleComponent()->GetUnscaledCapsuleRadius(), DefaultCharacter->GetCapsuleComponent()->GetUnscaledCapsuleHalfHeight(), bUpdateOverlaps);
  2036.  
  2037.     AdjustProxyCapsuleSize();
  2038.     CharacterOwner->OnEndCrouch(HalfHeightAdjust, ScaledHalfHeightAdjust);
  2039. }
  2040.  
  2041. void UCharacterMovementComponent::StartNewPhysics(float deltaTime, int32 Iterations)
  2042. {
  2043.     if ((deltaTime < MIN_TICK_TIME) || (Iterations >= MaxSimulationIterations) || !HasValidData())
  2044.     {
  2045.         return;
  2046.     }
  2047.  
  2048.     if (UpdatedComponent->IsSimulatingPhysics())
  2049.     {
  2050.         UE_LOG(LogCharacterMovement, Log, TEXT("UCharacterMovementComponent::StartNewPhysics: UpdateComponent (%s) is simulating physics - aborting."), *UpdatedComponent->GetPathName());
  2051.         return;
  2052.     }
  2053.  
  2054.     const bool bSavedMovementInProgress = bMovementInProgress;
  2055.     bMovementInProgress = true;
  2056.  
  2057.     switch (MovementMode)
  2058.     {
  2059.     case MOVE_None:
  2060.         break;
  2061.     case MOVE_Walking:
  2062.         PhysWalking(deltaTime, Iterations);
  2063.         break;
  2064.     case MOVE_NavWalking:
  2065.         PhysNavWalking(deltaTime, Iterations);
  2066.         break;
  2067.     case MOVE_Falling:
  2068.         PhysFalling(deltaTime, Iterations);
  2069.         break;
  2070.     case MOVE_Flying:
  2071.         PhysFlying(deltaTime, Iterations);
  2072.         break;
  2073.     case MOVE_Swimming:
  2074.         PhysSwimming(deltaTime, Iterations);
  2075.         break;
  2076.     case MOVE_Custom:
  2077.         PhysCustom(deltaTime, Iterations);
  2078.         break;
  2079.     default:
  2080.         UE_LOG(LogCharacterMovement, Warning, TEXT("%s has unsupported movement mode %d"), *CharacterOwner->GetName(), int32(MovementMode));
  2081.         SetMovementMode(MOVE_None);
  2082.         break;
  2083.     }
  2084.  
  2085.     bMovementInProgress = bSavedMovementInProgress;
  2086.     if (bDeferUpdateMoveComponent)
  2087.     {
  2088.         SetUpdatedComponent(DeferredUpdatedMoveComponent);
  2089.     }
  2090. }
  2091.  
  2092. float UCharacterMovementComponent::GetGravityZ() const
  2093. {
  2094.     return Super::GetGravityZ() * GravityScale;
  2095. }
  2096.  
  2097. float UCharacterMovementComponent::GetMaxSpeed() const
  2098. {
  2099.     switch (MovementMode)
  2100.     {
  2101.     case MOVE_Walking:
  2102.     case MOVE_NavWalking:
  2103.         return IsCrouching() ? MaxWalkSpeedCrouched : MaxWalkSpeed;
  2104.     case MOVE_Falling:
  2105.         return MaxWalkSpeed;
  2106.     case MOVE_Swimming:
  2107.         return MaxSwimSpeed;
  2108.     case MOVE_Flying:
  2109.         return MaxFlySpeed;
  2110.     case MOVE_Custom:
  2111.         return MaxCustomMovementSpeed;
  2112.     case MOVE_None:
  2113.     default:
  2114.         return 0.f;
  2115.     }
  2116. }
  2117.  
  2118.  
  2119. bool UCharacterMovementComponent::ResolvePenetrationImpl(const FVector& Adjustment, const FHitResult& Hit, const FQuat& NewRotation)
  2120. {
  2121.     // If movement occurs, mark that we teleported, so we don't incorrectly adjust velocity based on a potentially very different movement than our movement direction.
  2122.     bJustTeleported |= Super::ResolvePenetrationImpl(Adjustment, Hit, NewRotation);
  2123.     return bJustTeleported;
  2124. }
  2125.  
  2126.  
  2127. float UCharacterMovementComponent::SlideAlongSurface(const FVector& Delta, float Time, const FVector& Normal, FHitResult& Hit, bool bHandleImpact)
  2128. {
  2129.     if (!Hit.bBlockingHit)
  2130.     {
  2131.         return 0.f;
  2132.     }
  2133.  
  2134.     FVector NewNormal = Normal;
  2135.     if (IsMovingOnGround())
  2136.     {
  2137.         const FVector CapsuleUp = GetCapsuleAxisZ();
  2138.         const float Dot = NewNormal | CapsuleUp;
  2139.  
  2140.         // We don't want to be pushed up an unwalkable surface.
  2141.         if (Dot > 0.0f)
  2142.         {
  2143.             if (!IsWalkable(Hit))
  2144.             {
  2145.                 NewNormal = FVector::VectorPlaneProject(NewNormal, CapsuleUp).GetSafeNormal();
  2146.             }
  2147.         }
  2148.         else if (Dot < -KINDA_SMALL_NUMBER)
  2149.         {
  2150.             // Don't push down into the floor when the impact is on the upper portion of the capsule.
  2151.             if (CurrentFloor.FloorDist < MIN_FLOOR_DIST && CurrentFloor.bBlockingHit)
  2152.             {
  2153.                 const FVector FloorNormal = CurrentFloor.HitResult.Normal;
  2154.                 const bool bFloorOpposedToMovement = (Delta | FloorNormal) < 0.0f && (FloorNormal | CapsuleUp) < 1.0f - DELTA;
  2155.                 if (bFloorOpposedToMovement)
  2156.                 {
  2157.                     NewNormal = FloorNormal;
  2158.                 }
  2159.  
  2160.                 NewNormal = FVector::VectorPlaneProject(NewNormal, CapsuleUp).GetSafeNormal();
  2161.             }
  2162.         }
  2163.     }
  2164.  
  2165.     return Super::SlideAlongSurface(Delta, Time, NewNormal, Hit, bHandleImpact);
  2166. }
  2167.  
  2168.  
  2169. void UCharacterMovementComponent::TwoWallAdjust(FVector& Delta, const FHitResult& Hit, const FVector& OldHitNormal) const
  2170. {
  2171.     const FVector InDelta = Delta;
  2172.     Super::TwoWallAdjust(Delta, Hit, OldHitNormal);
  2173.  
  2174.     if (IsMovingOnGround())
  2175.     {
  2176.         const FVector CapsuleUp = GetCapsuleAxisZ();
  2177.         const float DotDelta = Delta | CapsuleUp;
  2178.  
  2179.         // Allow slides up walkable surfaces, but not unwalkable ones (treat those as vertical barriers).
  2180.         if (DotDelta > 0.0f)
  2181.         {
  2182.             const float DotHitNormal = Hit.Normal | CapsuleUp;
  2183.  
  2184.             if (DotHitNormal > KINDA_SMALL_NUMBER && (DotHitNormal >= GetWalkableFloorZ() || IsWalkable(Hit)))
  2185.             {
  2186.                 // Maintain horizontal velocity.
  2187.                 const float Time = (1.0f - Hit.Time);
  2188.                 const FVector ScaledDelta = Delta.GetSafeNormal() * InDelta.Size();
  2189.                 Delta = (FVector::VectorPlaneProject(InDelta, CapsuleUp) + CapsuleUp * ((ScaledDelta | CapsuleUp) / DotHitNormal)) * Time;
  2190.             }
  2191.             else
  2192.             {
  2193.                 Delta = FVector::VectorPlaneProject(Delta, CapsuleUp);
  2194.             }
  2195.         }
  2196.         else if (DotDelta < 0.0f)
  2197.         {
  2198.             // Don't push down into the floor.
  2199.             if (CurrentFloor.FloorDist < MIN_FLOOR_DIST && CurrentFloor.bBlockingHit)
  2200.             {
  2201.                 Delta = FVector::VectorPlaneProject(Delta, CapsuleUp);
  2202.             }
  2203.         }
  2204.     }
  2205. }
  2206.  
  2207.  
  2208. FVector UCharacterMovementComponent::ComputeSlideVector(const FVector& Delta, const float Time, const FVector& Normal, const FHitResult& Hit) const
  2209. {
  2210.     FVector Result = Super::ComputeSlideVector(Delta, Time, Normal, Hit);
  2211.  
  2212.     // prevent boosting up slopes
  2213.     if (IsFalling())
  2214.     {
  2215.         Result = HandleSlopeBoosting(Result, Delta, Time, Normal, Hit);
  2216.     }
  2217.  
  2218.     return Result;
  2219. }
  2220.  
  2221.  
  2222. FVector UCharacterMovementComponent::HandleSlopeBoosting(const FVector& SlideResult, const FVector& Delta, const float Time, const FVector& Normal, const FHitResult& Hit) const
  2223. {
  2224.     const FVector CapsuleUp = GetCapsuleAxisZ();
  2225.     FVector Result = SlideResult;
  2226.     const float Dot = Result | CapsuleUp;
  2227.  
  2228.     // Prevent boosting up slopes.
  2229.     if (Dot > 0.0f)
  2230.     {
  2231.         // Don't move any higher than we originally intended.
  2232.         const float ZLimit = (Delta | CapsuleUp) * Time;
  2233.         if (Dot - ZLimit > KINDA_SMALL_NUMBER)
  2234.         {
  2235.             if (ZLimit > 0.0f)
  2236.             {
  2237.                 // Rescale the entire vector (not just the Z component) otherwise we change the direction and likely head right back into the impact.
  2238.                 const float UpPercent = ZLimit / Dot;
  2239.                 Result *= UpPercent;
  2240.             }
  2241.             else
  2242.             {
  2243.                 // We were heading down but were going to deflect upwards. Just make the deflection horizontal.
  2244.                 Result = FVector::ZeroVector;
  2245.             }
  2246.  
  2247.             // Make remaining portion of original result horizontal and parallel to impact normal.
  2248.             const FVector RemainderXY = FVector::VectorPlaneProject(SlideResult - Result, CapsuleUp);
  2249.             const FVector NormalXY = FVector::VectorPlaneProject(Normal, CapsuleUp).GetSafeNormal();
  2250.             const FVector Adjust = Super::ComputeSlideVector(RemainderXY, 1.0f, NormalXY, Hit);
  2251.             Result += Adjust;
  2252.         }
  2253.     }
  2254.  
  2255.     return Result;
  2256. }
  2257.  
  2258.  
  2259. // TODO: deprecated, remove.
  2260. FVector UCharacterMovementComponent::AdjustUpperHemisphereImpact(const FVector& Delta, const FHitResult& Hit) const
  2261. {
  2262.     const float ZScale = FMath::Clamp(1.f - (FMath::Abs(Hit.Normal.Z) * UpperImpactNormalScale_DEPRECATED), 0.f, 1.f);
  2263.     return FVector(Delta.X, Delta.Y, Delta.Z * ZScale);
  2264. }
  2265.  
  2266.  
  2267. FVector UCharacterMovementComponent::NewFallVelocity(const FVector& InitialVelocity, const FVector& Gravity, float DeltaTime) const
  2268. {
  2269.     FVector Result = InitialVelocity;
  2270.  
  2271.     if (!Gravity.IsZero())
  2272.     {
  2273.         // Apply gravity.
  2274.         Result += Gravity * DeltaTime;
  2275.  
  2276.         const FVector GravityDir = Gravity.GetSafeNormal();
  2277.         const float TerminalLimit = FMath::Abs(GetPhysicsVolume()->TerminalVelocity);
  2278.  
  2279.         // Don't exceed terminal velocity.
  2280.         if ((Result | GravityDir) > TerminalLimit)
  2281.         {
  2282.             Result = FVector::PointPlaneProject(Result, FVector::ZeroVector, GravityDir) + GravityDir * TerminalLimit;
  2283.         }
  2284.     }
  2285.  
  2286.     return Result;
  2287. }
  2288.  
  2289.  
  2290. float UCharacterMovementComponent::ImmersionDepth() const
  2291. {
  2292.     float Depth = 0.0f;
  2293.  
  2294.     if (CharacterOwner && GetPhysicsVolume()->bWaterVolume)
  2295.     {
  2296.         const float CollisionHalfHeight = CharacterOwner->GetSimpleCollisionHalfHeight();
  2297.  
  2298.         if (CollisionHalfHeight == 0.0f || Buoyancy == 0.0f)
  2299.         {
  2300.             Depth = 1.0f;
  2301.         }
  2302.         else
  2303.         {
  2304.             UBrushComponent* VolumeBrushComp = GetPhysicsVolume()->GetBrushComponent();
  2305.             FHitResult Hit(1.0f);
  2306.  
  2307.             if (VolumeBrushComp)
  2308.             {
  2309.                 const FVector CapsuleHalfHeight = GetCapsuleAxisZ() * CollisionHalfHeight;
  2310.                 const FVector TraceStart = UpdatedComponent->GetComponentLocation() + CapsuleHalfHeight;
  2311.                 const FVector TraceEnd = UpdatedComponent->GetComponentLocation() - CapsuleHalfHeight;
  2312.  
  2313.                 const static FName MovementComp_Character_ImmersionDepthName(TEXT("MovementComp_Character_ImmersionDepth"));
  2314.                 FCollisionQueryParams NewTraceParams(CharacterMovementComponentStatics::ImmersionDepthName, true);
  2315.                 VolumeBrushComp->LineTraceComponent(Hit, TraceStart, TraceEnd, NewTraceParams);
  2316.             }
  2317.  
  2318.             Depth = (Hit.Time == 1.0f) ? 1.0f : (1.0f - Hit.Time);
  2319.         }
  2320.     }
  2321.  
  2322.     return Depth;
  2323. }
  2324.  
  2325. bool UCharacterMovementComponent::IsFlying() const
  2326. {
  2327.     return (MovementMode == MOVE_Flying) && UpdatedComponent;
  2328. }
  2329.  
  2330. bool UCharacterMovementComponent::IsMovingOnGround() const
  2331. {
  2332.     return ((MovementMode == MOVE_Walking) || (MovementMode == MOVE_NavWalking)) && UpdatedComponent;
  2333. }
  2334.  
  2335. bool UCharacterMovementComponent::IsFalling() const
  2336. {
  2337.     return (MovementMode == MOVE_Falling) && UpdatedComponent;
  2338. }
  2339.  
  2340. bool UCharacterMovementComponent::IsSwimming() const
  2341. {
  2342.     return (MovementMode == MOVE_Swimming) && UpdatedComponent;
  2343. }
  2344.  
  2345. bool UCharacterMovementComponent::IsCrouching() const
  2346. {
  2347.     return CharacterOwner && CharacterOwner->bIsCrouched;
  2348. }
  2349.  
  2350. void UCharacterMovementComponent::CalcVelocity(float DeltaTime, float Friction, bool bFluid, float BrakingDeceleration)
  2351. {
  2352.     // Do not update velocity when using root motion
  2353.     if (!HasValidData() || HasRootMotion() || DeltaTime < MIN_TICK_TIME)
  2354.     {
  2355.         return;
  2356.     }
  2357.  
  2358.     Friction = FMath::Max(0.f, Friction);
  2359.     const float MaxAccel = GetMaxAcceleration();
  2360.     float MaxSpeed = GetMaxSpeed();
  2361.  
  2362.     // Check if path following requested movement
  2363.     bool bZeroRequestedAcceleration = true;
  2364.     FVector RequestedAcceleration = FVector::ZeroVector;
  2365.     float RequestedSpeed = 0.0f;
  2366.     if (ApplyRequestedMove(DeltaTime, MaxAccel, MaxSpeed, Friction, BrakingDeceleration, RequestedAcceleration, RequestedSpeed))
  2367.     {
  2368.         RequestedAcceleration = RequestedAcceleration.GetClampedToMaxSize(MaxAccel);
  2369.         bZeroRequestedAcceleration = false;
  2370.     }
  2371.  
  2372.     if (bForceMaxAccel)
  2373.     {
  2374.         // Force acceleration at full speed.
  2375.         // In consideration order for direction: Acceleration, then Velocity, then Pawn's rotation.
  2376.         if (Acceleration.SizeSquared() > SMALL_NUMBER)
  2377.         {
  2378.             Acceleration = Acceleration.GetSafeNormal() * MaxAccel;
  2379.         }
  2380.         else
  2381.         {
  2382.             Acceleration = MaxAccel * (Velocity.SizeSquared() < SMALL_NUMBER ? UpdatedComponent->GetForwardVector() : Velocity.GetSafeNormal());
  2383.         }
  2384.  
  2385.         AnalogInputModifier = 1.f;
  2386.     }
  2387.  
  2388.     // Path following above didn't care about the analog modifier, but we do for everything else below, so get the fully modified value.
  2389.     // Use max of requested speed and max speed if we modified the speed in ApplyRequestedMove above.
  2390.     MaxSpeed = FMath::Max(RequestedSpeed, MaxSpeed * AnalogInputModifier);
  2391.  
  2392.     // Apply braking or deceleration
  2393.     const bool bZeroAcceleration = Acceleration.IsZero();
  2394.     const bool bVelocityOverMax = IsExceedingMaxSpeed(MaxSpeed);
  2395.  
  2396.     // Only apply braking if there is no acceleration, or we are over our max speed and need to slow down to it.
  2397.     if ((bZeroAcceleration && bZeroRequestedAcceleration) || bVelocityOverMax)
  2398.     {
  2399.         const FVector OldVelocity = Velocity;
  2400.  
  2401.         const float ActualBrakingFriction = (bUseSeparateBrakingFriction ? BrakingFriction : Friction);
  2402.         ApplyVelocityBraking(DeltaTime, ActualBrakingFriction, BrakingDeceleration);
  2403.  
  2404.         // Don't allow braking to lower us below max speed if we started above it.
  2405.         if (bVelocityOverMax && Velocity.SizeSquared() < FMath::Square(MaxSpeed) && FVector::DotProduct(Acceleration, OldVelocity) > 0.0f)
  2406.         {
  2407.             Velocity = OldVelocity.GetSafeNormal() * MaxSpeed;
  2408.         }
  2409.     }
  2410.     else if (!bZeroAcceleration)
  2411.     {
  2412.         // Friction affects our ability to change direction. This is only done for input acceleration, not path following.
  2413.         const FVector AccelDir = Acceleration.GetSafeNormal();
  2414.         const float VelSize = Velocity.Size();
  2415.         Velocity = Velocity - (Velocity - AccelDir * VelSize) * FMath::Min(DeltaTime * Friction, 1.f);
  2416.     }
  2417.  
  2418.     // Apply fluid friction
  2419.     if (bFluid)
  2420.     {
  2421.         Velocity = Velocity * (1.f - FMath::Min(Friction * DeltaTime, 1.f));
  2422.     }
  2423.  
  2424.     // Apply acceleration
  2425.     const float NewMaxSpeed = (IsExceedingMaxSpeed(MaxSpeed)) ? Velocity.Size() : MaxSpeed;
  2426.     Velocity += Acceleration * DeltaTime;
  2427.     Velocity += RequestedAcceleration * DeltaTime;
  2428.     Velocity = Velocity.GetClampedToMaxSize(NewMaxSpeed);
  2429.  
  2430.     if (bUseRVOAvoidance)
  2431.     {
  2432.         CalcAvoidanceVelocity(DeltaTime);
  2433.     }
  2434. }
  2435.  
  2436.  
  2437. bool UCharacterMovementComponent::ApplyRequestedMove(float DeltaTime, float MaxAccel, float MaxSpeed, float Friction, float BrakingDeceleration, FVector& OutAcceleration, float& OutRequestedSpeed)
  2438. {
  2439.     if (bHasRequestedVelocity)
  2440.     {
  2441.         const float RequestedSpeedSquared = RequestedVelocity.SizeSquared();
  2442.         if (RequestedSpeedSquared < KINDA_SMALL_NUMBER)
  2443.         {
  2444.             return false;
  2445.         }
  2446.  
  2447.         // Compute requested speed from path following
  2448.         float RequestedSpeed = FMath::Sqrt(RequestedSpeedSquared);
  2449.         const FVector RequestedMoveDir = RequestedVelocity / RequestedSpeed;
  2450.         RequestedSpeed = (bRequestedMoveWithMaxSpeed ? MaxSpeed : FMath::Min(MaxSpeed, RequestedSpeed));
  2451.  
  2452.         // Compute actual requested velocity
  2453.         const FVector MoveVelocity = RequestedMoveDir * RequestedSpeed;
  2454.  
  2455.         // Compute acceleration. Use MaxAccel to limit speed increase, 1% buffer.
  2456.         FVector NewAcceleration = FVector::ZeroVector;
  2457.         const float CurrentSpeedSq = Velocity.SizeSquared();
  2458.         if (bRequestedMoveUseAcceleration && CurrentSpeedSq < FMath::Square(RequestedSpeed * 1.01f))
  2459.         {
  2460.             // Turn in the same manner as with input acceleration.
  2461.             const float VelSize = FMath::Sqrt(CurrentSpeedSq);
  2462.             Velocity = Velocity - (Velocity - RequestedMoveDir * VelSize) * FMath::Min(DeltaTime * Friction, 1.f);
  2463.  
  2464.             // How much do we need to accelerate to get to the new velocity?
  2465.             NewAcceleration = ((MoveVelocity - Velocity) / DeltaTime);
  2466.             NewAcceleration = NewAcceleration.GetClampedToMaxSize(MaxAccel);
  2467.         }
  2468.         else
  2469.         {
  2470.             // Just set velocity directly.
  2471.             // If decelerating we do so instantly, so we don't slide through the destination if we can't brake fast enough.
  2472.             Velocity = MoveVelocity;
  2473.         }
  2474.  
  2475.         // Copy to out params
  2476.         OutRequestedSpeed = RequestedSpeed;
  2477.         OutAcceleration = NewAcceleration;
  2478.         return true;
  2479.     }
  2480.  
  2481.     return false;
  2482. }
  2483.  
  2484. void UCharacterMovementComponent::RequestDirectMove(const FVector& MoveVelocity, bool bForceMaxSpeed)
  2485. {
  2486.     if (MoveVelocity.SizeSquared() < KINDA_SMALL_NUMBER)
  2487.     {
  2488.         return;
  2489.     }
  2490.  
  2491.     if (IsFalling())
  2492.     {
  2493.         const FVector FallVelocity = MoveVelocity.GetClampedToMaxSize(GetMaxSpeed());
  2494.         PerformAirControlForPathFollowing(FallVelocity, FallVelocity.Z);
  2495.         return;
  2496.     }
  2497.  
  2498.     RequestedVelocity = MoveVelocity;
  2499.     bHasRequestedVelocity = true;
  2500.     bRequestedMoveWithMaxSpeed = bForceMaxSpeed;
  2501.  
  2502.     if (IsMovingOnGround())
  2503.     {
  2504.         RequestedVelocity.Z = 0.0f;
  2505.     }
  2506. }
  2507.  
  2508. bool UCharacterMovementComponent::CanStartPathFollowing() const
  2509. {
  2510.     if (!HasValidData() || HasRootMotion())
  2511.     {
  2512.         return false;
  2513.     }
  2514.  
  2515.     if (CharacterOwner)
  2516.     {
  2517.         if (CharacterOwner->GetRootComponent() && CharacterOwner->GetRootComponent()->IsSimulatingPhysics())
  2518.         {
  2519.             return false;
  2520.         }
  2521.         else if (CharacterOwner->IsMatineeControlled())
  2522.         {
  2523.             return false;
  2524.         }
  2525.     }
  2526.  
  2527.     return Super::CanStartPathFollowing();
  2528. }
  2529.  
  2530. bool UCharacterMovementComponent::CanStopPathFollowing() const
  2531. {
  2532.     return !IsFalling();
  2533. }
  2534.  
  2535. void UCharacterMovementComponent::CalcAvoidanceVelocity(float DeltaTime)
  2536. {
  2537.     SCOPE_CYCLE_COUNTER(STAT_AI_ObstacleAvoidance);
  2538.  
  2539.     UAvoidanceManager* AvoidanceManager = GetWorld()->GetAvoidanceManager();
  2540.     if (AvoidanceWeight >= 1.0f || AvoidanceManager == NULL || GetCharacterOwner() == NULL)
  2541.     {
  2542.         return;
  2543.     }
  2544.  
  2545.     if (GetCharacterOwner()->Role != ROLE_Authority)
  2546.     {
  2547.         return;
  2548.     }
  2549.  
  2550. #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
  2551.     const bool bShowDebug = AvoidanceManager->IsDebugEnabled(AvoidanceUID);
  2552. #endif
  2553.  
  2554.     //Adjust velocity only if we're in "Walking" mode. We should also check if we're dazed, being knocked around, maybe off-navmesh, etc.
  2555.     UCapsuleComponent *OurCapsule = GetCharacterOwner()->GetCapsuleComponent();
  2556.     if (!Velocity.IsZero() && IsMovingOnGround() && OurCapsule)
  2557.     {
  2558.         //See if we're doing a locked avoidance move already, and if so, skip the testing and just do the move.
  2559.         if (AvoidanceLockTimer > 0.0f)
  2560.         {
  2561.             Velocity = AvoidanceLockVelocity;
  2562. #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
  2563.             if (bShowDebug)
  2564.             {
  2565.                 DrawDebugLine(GetWorld(), GetActorFeetLocation(), GetActorFeetLocation() + Velocity, FColor::Blue, true, 0.5f, SDPG_MAX);
  2566.             }
  2567. #endif
  2568.         }
  2569.         else
  2570.         {
  2571.             FVector NewVelocity = AvoidanceManager->GetAvoidanceVelocityForComponent(this);
  2572.             if (bUseRVOPostProcess)
  2573.             {
  2574.                 PostProcessAvoidanceVelocity(NewVelocity);
  2575.             }
  2576.  
  2577.             if (!NewVelocity.Equals(Velocity))      //Really want to branch hint that this will probably not pass
  2578.             {
  2579.                 //Had to divert course, lock this avoidance move in for a short time. This will make us a VO, so unlocked others will know to avoid us.
  2580.                 Velocity = NewVelocity;
  2581.                 SetAvoidanceVelocityLock(AvoidanceManager, AvoidanceManager->LockTimeAfterAvoid);
  2582. #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
  2583.                 if (bShowDebug)
  2584.                 {
  2585.                     DrawDebugLine(GetWorld(), GetActorFeetLocation(), GetActorFeetLocation() + Velocity, FColor::Red, true, 0.05f, SDPG_MAX, 10.0f);
  2586.                 }
  2587. #endif
  2588.             }
  2589.             else
  2590.             {
  2591.                 //Although we didn't divert course, our velocity for this frame is decided. We will not reciprocate anything further, so treat as a VO for the remainder of this frame.
  2592.                 SetAvoidanceVelocityLock(AvoidanceManager, AvoidanceManager->LockTimeAfterClean);   //10 ms of lock time should be adequate.
  2593. #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
  2594.                 if (bShowDebug)
  2595.                 {
  2596.                     //DrawDebugLine(GetWorld(), GetActorLocation(), GetActorLocation() + Velocity, FColor::Green, true, 0.05f, SDPG_MAX, 10.0f);
  2597.                 }
  2598. #endif
  2599.             }
  2600.         }
  2601.         //RickH - We might do better to do this later in our update
  2602.         AvoidanceManager->UpdateRVO(this);
  2603.  
  2604.         bWasAvoidanceUpdated = true;
  2605.     }
  2606. #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
  2607.     else if (bShowDebug)
  2608.     {
  2609.         DrawDebugLine(GetWorld(), GetActorFeetLocation(), GetActorFeetLocation() + Velocity, FColor::Yellow, true, 0.05f, SDPG_MAX);
  2610.     }
  2611.  
  2612.     if (bShowDebug)
  2613.     {
  2614.         FVector UpLine(0,0,500);
  2615.         DrawDebugLine(GetWorld(), GetActorFeetLocation(), GetActorFeetLocation() + UpLine, (AvoidanceLockTimer > 0.01f) ? FColor::Red : FColor::Blue, true, 0.05f, SDPG_MAX, 5.0f);
  2616.     }
  2617. #endif
  2618. }
  2619.  
  2620. void UCharacterMovementComponent::PostProcessAvoidanceVelocity(FVector& NewVelocity)
  2621. {
  2622.     // empty in base class
  2623. }
  2624.  
  2625. void UCharacterMovementComponent::UpdateDefaultAvoidance()
  2626. {
  2627.     if (!bUseRVOAvoidance)
  2628.     {
  2629.         return;
  2630.     }
  2631.  
  2632.     SCOPE_CYCLE_COUNTER(STAT_AI_ObstacleAvoidance);
  2633.  
  2634.     UAvoidanceManager* AvoidanceManager = GetWorld()->GetAvoidanceManager();
  2635.     if (AvoidanceManager && !bWasAvoidanceUpdated)
  2636.     {
  2637.         if (UCapsuleComponent *OurCapsule = GetCharacterOwner()->GetCapsuleComponent())
  2638.         {
  2639.             AvoidanceManager->UpdateRVO(this);
  2640.  
  2641.             //Consider this a clean move because we didn't even try to avoid.
  2642.             SetAvoidanceVelocityLock(AvoidanceManager, AvoidanceManager->LockTimeAfterClean);
  2643.         }
  2644.     }
  2645.  
  2646.     bWasAvoidanceUpdated = false;       //Reset for next frame
  2647. }
  2648.  
  2649. void UCharacterMovementComponent::SetRVOAvoidanceUID(int32 UID)
  2650. {
  2651.     AvoidanceUID = UID;
  2652. }
  2653.  
  2654. int32 UCharacterMovementComponent::GetRVOAvoidanceUID()
  2655. {
  2656.     return AvoidanceUID;
  2657. }
  2658.  
  2659. void UCharacterMovementComponent::SetRVOAvoidanceWeight(float Weight)
  2660. {
  2661.     AvoidanceWeight = Weight;
  2662. }
  2663.  
  2664. float UCharacterMovementComponent::GetRVOAvoidanceWeight()
  2665. {
  2666.     return AvoidanceWeight;
  2667. }
  2668.  
  2669. FVector UCharacterMovementComponent::GetRVOAvoidanceOrigin()
  2670. {
  2671.     return GetActorFeetLocation();
  2672. }
  2673.  
  2674. float UCharacterMovementComponent::GetRVOAvoidanceRadius()
  2675. {
  2676.     UCapsuleComponent* CapsuleComp = GetCharacterOwner()->GetCapsuleComponent();
  2677.     return CapsuleComp ? CapsuleComp->GetScaledCapsuleRadius() : 0.0f;
  2678. }
  2679.  
  2680. float UCharacterMovementComponent::GetRVOAvoidanceConsiderationRadius()
  2681. {
  2682.     return AvoidanceConsiderationRadius;
  2683. }
  2684.  
  2685. float UCharacterMovementComponent::GetRVOAvoidanceHeight()
  2686. {
  2687.     UCapsuleComponent* CapsuleComp = GetCharacterOwner()->GetCapsuleComponent();
  2688.     return CapsuleComp ? CapsuleComp->GetScaledCapsuleHalfHeight() : 0.0f;
  2689. }
  2690.  
  2691. FVector UCharacterMovementComponent::GetVelocityForRVOConsideration()
  2692. {
  2693.     return Velocity;
  2694. }
  2695.  
  2696. int32 UCharacterMovementComponent::GetAvoidanceGroupMask()
  2697. {
  2698.     return AvoidanceGroup.Packed;
  2699. }
  2700.  
  2701. int32 UCharacterMovementComponent::GetGroupsToAvoidMask()
  2702. {
  2703.     return GroupsToAvoid.Packed;
  2704. }
  2705.  
  2706. int32 UCharacterMovementComponent::GetGroupsToIgnoreMask()
  2707. {
  2708.     return GroupsToIgnore.Packed;
  2709. }
  2710.  
  2711. void UCharacterMovementComponent::SetAvoidanceVelocityLock(class UAvoidanceManager* Avoidance, float Duration)
  2712. {
  2713.     Avoidance->OverrideToMaxWeight(AvoidanceUID, Duration);
  2714.     AvoidanceLockVelocity = Velocity;
  2715.     AvoidanceLockTimer = Duration;
  2716. }
  2717.  
  2718. void UCharacterMovementComponent::NotifyBumpedPawn(APawn* BumpedPawn)
  2719. {
  2720.     Super::NotifyBumpedPawn(BumpedPawn);
  2721.  
  2722. #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
  2723.     UAvoidanceManager* Avoidance = GetWorld()->GetAvoidanceManager();
  2724.     const bool bShowDebug = Avoidance && Avoidance->IsDebugEnabled(AvoidanceUID);
  2725.     if (bShowDebug)
  2726.     {
  2727.         DrawDebugLine(GetWorld(), GetActorFeetLocation(), GetActorFeetLocation() + FVector(0,0,500), (AvoidanceLockTimer > 0) ? FColor(255,64,64) : FColor(64,64,255), true, 2.0f, SDPG_MAX, 20.0f);
  2728.     }
  2729. #endif
  2730.  
  2731.     // Unlock avoidance move. This mostly happens when two pawns who are locked into avoidance moves collide with each other.
  2732.     AvoidanceLockTimer = 0.0f;
  2733. }
  2734.  
  2735. float UCharacterMovementComponent::GetMaxJumpHeight() const
  2736. {
  2737.     const float Gravity = GetGravityZ();
  2738.     if (FMath::Abs(Gravity) > KINDA_SMALL_NUMBER)
  2739.     {
  2740.         return FMath::Square(JumpZVelocity) / (-2.f * Gravity);
  2741.     }
  2742.     else
  2743.     {
  2744.         return 0.f;
  2745.     }
  2746. }
  2747.  
  2748. // TODO: deprecated, remove.
  2749. float UCharacterMovementComponent::GetModifiedMaxAcceleration() const
  2750. {
  2751.     // Allow calling old deprecated function to maintain old behavior until it is removed.
  2752.     PRAGMA_DISABLE_DEPRECATION_WARNINGS
  2753.         return CharacterOwner ? MaxAcceleration * GetMaxSpeedModifier() : 0.f;
  2754.     PRAGMA_ENABLE_DEPRECATION_WARNINGS
  2755. }
  2756.  
  2757. // TODO: deprecated, remove.
  2758. float UCharacterMovementComponent::K2_GetModifiedMaxAcceleration() const
  2759. {
  2760.     // Allow calling old deprecated function to maintain old behavior until it is removed.
  2761.     PRAGMA_DISABLE_DEPRECATION_WARNINGS
  2762.         return GetModifiedMaxAcceleration();
  2763.     PRAGMA_ENABLE_DEPRECATION_WARNINGS
  2764. }
  2765.  
  2766.  
  2767. float UCharacterMovementComponent::GetMaxAcceleration() const
  2768. {
  2769.     return MaxAcceleration;
  2770. }
  2771.  
  2772. FVector UCharacterMovementComponent::GetCurrentAcceleration() const
  2773. {
  2774.     return Acceleration;
  2775. }
  2776.  
  2777. void UCharacterMovementComponent::ApplyVelocityBraking(float DeltaTime, float Friction, float BrakingDeceleration)
  2778. {
  2779.     if (Velocity.IsZero() || !HasValidData() || HasRootMotion() || DeltaTime < MIN_TICK_TIME)
  2780.     {
  2781.         return;
  2782.     }
  2783.  
  2784.     const float FrictionFactor = FMath::Max(0.f, BrakingFrictionFactor);
  2785.     Friction = FMath::Max(0.f, Friction * FrictionFactor);
  2786.     BrakingDeceleration = FMath::Max(0.f, BrakingDeceleration);
  2787.     const bool bZeroFriction = (Friction == 0.f);
  2788.     const bool bZeroBraking = (BrakingDeceleration == 0.f);
  2789.  
  2790.     if (bZeroFriction && bZeroBraking)
  2791.     {
  2792.         return;
  2793.     }
  2794.  
  2795.     const FVector OldVel = Velocity;
  2796.  
  2797.     // subdivide braking to get reasonably consistent results at lower frame rates
  2798.     // (important for packet loss situations w/ networking)
  2799.     float RemainingTime = DeltaTime;
  2800.     const float MaxTimeStep = (1.0f / 33.0f);
  2801.  
  2802.     // Decelerate to brake to a stop
  2803.     const FVector RevAccel = (bZeroBraking ? FVector::ZeroVector : (-BrakingDeceleration * Velocity.GetSafeNormal()));
  2804.     while( RemainingTime >= MIN_TICK_TIME )
  2805.     {
  2806.         // Zero friction uses constant deceleration, so no need for iteration.
  2807.         const float dt = ((RemainingTime > MaxTimeStep && !bZeroFriction) ? FMath::Min(MaxTimeStep, RemainingTime * 0.5f) : RemainingTime);
  2808.         RemainingTime -= dt;
  2809.  
  2810.         // apply friction and braking
  2811.         Velocity = Velocity + ((-Friction) * Velocity + RevAccel) * dt ;
  2812.  
  2813.         // Don't reverse direction
  2814.         if ((Velocity | OldVel) <= 0.f)
  2815.         {
  2816.             Velocity = FVector::ZeroVector;
  2817.             return;
  2818.         }
  2819.     }
  2820.  
  2821.     // Clamp to zero if nearly zero, or if below min threshold and braking.
  2822.     const float VSizeSq = Velocity.SizeSquared();
  2823.     if (VSizeSq <= KINDA_SMALL_NUMBER || (!bZeroBraking && VSizeSq <= FMath::Square(BRAKE_TO_STOP_VELOCITY)))
  2824.     {
  2825.         Velocity = FVector::ZeroVector;
  2826.     }
  2827. }
  2828.  
  2829. void UCharacterMovementComponent::PhysFlying(float deltaTime, int32 Iterations)
  2830. {
  2831.     if (deltaTime < MIN_TICK_TIME)
  2832.     {
  2833.         return;
  2834.     }
  2835.  
  2836.     // Abort if no valid gravity can be obtained.
  2837.     const FVector GravityDir = GetGravityDirection();
  2838.     if (GravityDir.IsZero())
  2839.     {
  2840.         Acceleration = FVector::ZeroVector;
  2841.         Velocity = FVector::ZeroVector;
  2842.         return;
  2843.     }
  2844.  
  2845.     if (!HasRootMotion())
  2846.     {
  2847.         if (bCheatFlying && Acceleration.IsZero())
  2848.         {
  2849.             Velocity = FVector::ZeroVector;
  2850.         }
  2851.  
  2852.         const float Friction = 0.5f * GetPhysicsVolume()->FluidFriction;
  2853.         CalcVelocity(deltaTime, Friction, true, BrakingDecelerationFlying);
  2854.     }
  2855.  
  2856.     Iterations++;
  2857.     bJustTeleported = false;
  2858.  
  2859.     FVector OldLocation = UpdatedComponent->GetComponentLocation();
  2860.     const FVector Adjusted = Velocity * deltaTime;
  2861.     FHitResult Hit(1.f);
  2862.     SafeMoveUpdatedComponent(Adjusted, UpdatedComponent->GetComponentQuat(), true, Hit);
  2863.  
  2864.     if (CharacterOwner && Hit.Time < 1.0f)
  2865.     {
  2866.         const float UpDown = GravityDir | Velocity.GetSafeNormal();
  2867.         bool bSteppedUp = false;
  2868.  
  2869.         if (UpDown < 0.5f && UpDown > -0.2f && FMath::Abs(Hit.ImpactNormal | GravityDir) < 0.2f && CanStepUp(Hit))
  2870.         {
  2871.             const FVector StepLocation = UpdatedComponent->GetComponentLocation();
  2872.  
  2873.             bSteppedUp = StepUp(GravityDir, Adjusted * (1.0f - Hit.Time), Hit);
  2874.             if (bSteppedUp)
  2875.             {
  2876.                 OldLocation += GravityDir * ((UpdatedComponent->GetComponentLocation() - StepLocation) | GravityDir);
  2877.             }
  2878.         }
  2879.  
  2880.         if (!bSteppedUp)
  2881.         {
  2882.             // Adjust and try again.
  2883.             HandleImpact(Hit, deltaTime, Adjusted);
  2884.             SlideAlongSurface(Adjusted, 1.0f - Hit.Time, Hit.Normal, Hit, true);
  2885.         }
  2886.     }
  2887.  
  2888.     if (CharacterOwner && !bJustTeleported && !HasRootMotion())
  2889.     {
  2890.         Velocity = (UpdatedComponent->GetComponentLocation() - OldLocation) / deltaTime;
  2891.     }
  2892. }
  2893.  
  2894.  
  2895. void UCharacterMovementComponent::PhysSwimming(float deltaTime, int32 Iterations)
  2896. {
  2897.     if (deltaTime < MIN_TICK_TIME)
  2898.     {
  2899.         return;
  2900.     }
  2901.  
  2902.     // Abort if no valid gravity can be obtained.
  2903.     const FVector GravityDir = GetGravityDirection();
  2904.     if (GravityDir.IsZero())
  2905.     {
  2906.         Acceleration = FVector::ZeroVector;
  2907.         Velocity = FVector::ZeroVector;
  2908.         return;
  2909.     }
  2910.  
  2911.     const float Depth = ImmersionDepth();
  2912.     const float NetBuoyancy = Buoyancy * Depth;
  2913.     const float Dot = Velocity | GravityDir;
  2914.     if (!HasRootMotion() && NetBuoyancy != 0.0f && Dot < GetMaxSpeed() * -0.5f)
  2915.     {
  2916.         // Damp velocity out of water.
  2917.         Velocity = FVector::VectorPlaneProject(Velocity, GravityDir) + GravityDir * (Dot * Depth);
  2918.     }
  2919.  
  2920.     Iterations++;
  2921.     FVector OldLocation = UpdatedComponent->GetComponentLocation();
  2922.     bJustTeleported = false;
  2923.  
  2924.     if (!HasRootMotion())
  2925.     {
  2926.         const float Friction = 0.5f * GetPhysicsVolume()->FluidFriction * Depth;
  2927.         CalcVelocity(deltaTime, Friction, true, BrakingDecelerationSwimming);
  2928.  
  2929.         Velocity += GravityDir * (deltaTime * (1.0f - NetBuoyancy));
  2930.     }
  2931.  
  2932.     const FVector Adjusted = Velocity * deltaTime;
  2933.     FHitResult Hit(1.0f);
  2934.     const float remainingTime = deltaTime * Swim(Adjusted, Hit);
  2935.  
  2936.     // May have left water; if so, script might have set new physics mode.
  2937.     if (!IsSwimming())
  2938.     {
  2939.         StartNewPhysics(remainingTime, Iterations);
  2940.         return;
  2941.     }
  2942.  
  2943.     if (CharacterOwner && Hit.Time < 1.0f)
  2944.     {
  2945.         const float UpDown = GravityDir | Velocity.GetSafeNormal();
  2946.         bool bSteppedUp = false;
  2947.  
  2948.         if (UpDown < 0.5f && UpDown > -0.2f && FMath::Abs(Hit.ImpactNormal | GravityDir) < 0.2f && CanStepUp(Hit))
  2949.         {
  2950.             const FVector StepLocation = UpdatedComponent->GetComponentLocation();
  2951.             const FVector RealVelocity = Velocity;
  2952.             Velocity = FVector::VectorPlaneProject(Velocity, GravityDir) - GravityDir; // HACK: since will be moving up, in case pawn leaves the water.
  2953.  
  2954.             bSteppedUp = StepUp(GravityDir, Adjusted * (1.0f - Hit.Time), Hit);
  2955.             if (bSteppedUp)
  2956.             {
  2957.                 // May have left water; if so, script might have set new physics mode.
  2958.                 if (!IsSwimming())
  2959.                 {
  2960.                     StartNewPhysics(remainingTime, Iterations);
  2961.                     return;
  2962.                 }
  2963.  
  2964.                 OldLocation += GravityDir * ((UpdatedComponent->GetComponentLocation() - StepLocation) | GravityDir);
  2965.             }
  2966.  
  2967.             Velocity = RealVelocity;
  2968.         }
  2969.  
  2970.         if (!bSteppedUp)
  2971.         {
  2972.             // Adjust and try again.
  2973.             HandleImpact(Hit, deltaTime, Adjusted);
  2974.             SlideAlongSurface(Adjusted, 1.0f - Hit.Time, Hit.Normal, Hit, true);
  2975.         }
  2976.     }
  2977.  
  2978.     if (CharacterOwner && !HasRootMotion() && !bJustTeleported && (deltaTime - remainingTime) > KINDA_SMALL_NUMBER)
  2979.     {
  2980.        
  2981.         const float VelZ = Velocity | GravityDir;
  2982.         Velocity = (UpdatedComponent->GetComponentLocation() - OldLocation) / (deltaTime - remainingTime);
  2983.  
  2984.         if (!GetPhysicsVolume()->bWaterVolume)
  2985.         {
  2986.             Velocity = FVector::VectorPlaneProject(Velocity, GravityDir) + GravityDir * VelZ;
  2987.         }
  2988.     }
  2989.  
  2990.     if (!GetPhysicsVolume()->bWaterVolume && IsSwimming())
  2991.     {
  2992.         // In case script didn't change physics mode (with zone change).
  2993.         SetMovementMode(MOVE_Falling);
  2994.     }
  2995.  
  2996.     // May have left water; if so, script might have set new physics mode.
  2997.     if (!IsSwimming())
  2998.     {
  2999.         StartNewPhysics(remainingTime, Iterations);
  3000.     }
  3001. }
  3002.  
  3003.  
  3004. void UCharacterMovementComponent::StartSwimming(const FVector& OldLocation, const FVector& OldVelocity, float timeTick, float remainingTime, int32 Iterations)
  3005. {
  3006.     if (!CharacterOwner || remainingTime < MIN_TICK_TIME || timeTick < MIN_TICK_TIME)
  3007.     {
  3008.         return;
  3009.     }
  3010.  
  3011.     if( !HasRootMotion() && !bJustTeleported )
  3012.     {
  3013.         Velocity = (UpdatedComponent->GetComponentLocation() - OldLocation)/timeTick; //actual average velocity
  3014.         Velocity = 2.f*Velocity - OldVelocity; //end velocity has 2* accel of avg
  3015.         Velocity = Velocity.GetClampedToMaxSize(GetPhysicsVolume()->TerminalVelocity);
  3016.     }
  3017.     const FVector End = FindWaterLine(UpdatedComponent->GetComponentLocation(), OldLocation);
  3018.     float waterTime = 0.f;
  3019.     if (End != UpdatedComponent->GetComponentLocation())
  3020.     {
  3021.         const float ActualDist = (UpdatedComponent->GetComponentLocation() - OldLocation).Size();
  3022.         if (ActualDist > KINDA_SMALL_NUMBER)
  3023.         {
  3024.             waterTime = timeTick * (End - UpdatedComponent->GetComponentLocation()).Size() / ActualDist;
  3025.             remainingTime += waterTime;
  3026.         }
  3027.         MoveUpdatedComponent(End - CharacterOwner->GetActorLocation(), CharacterOwner->GetActorRotation(), true);
  3028.     }
  3029.     const FVector GravityDir = GetGravityDirection();
  3030.     if (!HasRootMotion() && !GravityDir.IsZero())
  3031.     {
  3032.         const float Dot = Velocity | GravityDir;
  3033.         if (Dot > 0.0f && Dot < SWIMBOBSPEED * -2.0f)
  3034.         {
  3035.             // Apply smooth bobbing.
  3036.             Velocity = FVector::VectorPlaneProject(Velocity, GravityDir) + GravityDir * ((SWIMBOBSPEED - Velocity.Size2D() * 0.7f) * -1.0f);
  3037.         }
  3038.     }
  3039.  
  3040.     if (remainingTime >= MIN_TICK_TIME && Iterations < MaxSimulationIterations)
  3041.     {
  3042.         PhysSwimming(remainingTime, Iterations);
  3043.     }
  3044. }
  3045.  
  3046. float UCharacterMovementComponent::Swim(const FVector& Delta, FHitResult& Hit)
  3047. {
  3048.     FVector Start = UpdatedComponent->GetComponentLocation();
  3049.     float airTime = 0.f;
  3050.     SafeMoveUpdatedComponent(Delta, UpdatedComponent->GetComponentQuat(), true, Hit);
  3051.  
  3052.     if ( !GetPhysicsVolume()->bWaterVolume) //then left water
  3053.     {
  3054.         const FVector End = FindWaterLine(Start,UpdatedComponent->GetComponentLocation());
  3055.         const float DesiredDist = Delta.Size();
  3056.         if (End != UpdatedComponent->GetComponentLocation() && DesiredDist > KINDA_SMALL_NUMBER)
  3057.         {
  3058.             airTime = (End - UpdatedComponent->GetComponentLocation()).Size() / DesiredDist;
  3059.             if ( ((UpdatedComponent->GetComponentLocation() - Start) | (End - UpdatedComponent->GetComponentLocation())) > 0.f )
  3060.             {
  3061.                 airTime = 0.f;
  3062.             }
  3063.             SafeMoveUpdatedComponent(End - UpdatedComponent->GetComponentLocation(), UpdatedComponent->GetComponentQuat(), true, Hit);
  3064.         }
  3065.     }
  3066.     return airTime;
  3067. }
  3068.  
  3069. FVector UCharacterMovementComponent::FindWaterLine(const FVector& InWater, const FVector& OutofWater) const
  3070. {
  3071.     FVector Result = OutofWater;
  3072.  
  3073.     TArray<FHitResult> Hits;
  3074.     GetWorld()->LineTraceMultiByChannel(Hits, OutofWater, InWater, UpdatedComponent->GetCollisionObjectType(), FCollisionQueryParams(CharacterMovementComponentStatics::FindWaterLineName, true, CharacterOwner));
  3075.  
  3076.     for( int32 HitIdx = 0; HitIdx < Hits.Num(); HitIdx++ )
  3077.     {
  3078.         const FHitResult& Check = Hits[HitIdx];
  3079.         if (!CharacterOwner->IsOwnedBy(Check.GetActor()) && !Check.Component.Get()->IsWorldGeometry())
  3080.         {
  3081.             APhysicsVolume *W = Cast<APhysicsVolume>(Check.GetActor());
  3082.             if (W && W->bWaterVolume)
  3083.             {
  3084.                 FVector Dir = (InWater - OutofWater).GetSafeNormal();
  3085.                 Result = Check.Location;
  3086.                 if (W == GetPhysicsVolume())
  3087.                     Result += 0.1f * Dir;
  3088.                 else
  3089.                     Result -= 0.1f * Dir;
  3090.                 break;
  3091.             }
  3092.         }
  3093.     }
  3094.  
  3095.     return Result;
  3096. }
  3097.  
  3098. void UCharacterMovementComponent::NotifyJumpApex()
  3099. {
  3100.     if (CharacterOwner)
  3101.     {
  3102.         CharacterOwner->NotifyJumpApex();
  3103.     }
  3104. }
  3105.  
  3106.  
  3107. FVector UCharacterMovementComponent::GetFallingLateralAcceleration(float DeltaTime, const FVector& GravDir) const
  3108. {
  3109.     // No vertical acceleration.
  3110.     FVector FallAcceleration = FVector::VectorPlaneProject(Acceleration, GravDir);
  3111.  
  3112.     // Bound acceleration, falling object has minimal ability to impact acceleration.
  3113.     if (!HasRootMotion() && FallAcceleration.SizeSquared() > 0.0f)
  3114.     {
  3115.         float FallAirControl = AirControl;
  3116.  
  3117.         // Allow a burst of initial acceleration.
  3118.         if (FallAirControl != 0.0f && AirControlBoostMultiplier > 0.0f &&
  3119.             FVector::VectorPlaneProject(Velocity, GravDir).SizeSquared() < FMath::Square(AirControlBoostVelocityThreshold))
  3120.         {
  3121.             FallAirControl = FMath::Min(1.0f, AirControlBoostMultiplier * FallAirControl);
  3122.         }
  3123.  
  3124.         FallAcceleration *= FallAirControl;
  3125.         FallAcceleration = FallAcceleration.GetClampedToMaxSize(GetMaxAcceleration());
  3126.     }
  3127.  
  3128.     return FallAcceleration;
  3129. }
  3130.  
  3131.  
  3132. FVector UCharacterMovementComponent::GetAirControl(float DeltaTime, float TickAirControl, const FVector& FallAcceleration) const
  3133. {
  3134.     // Boost
  3135.     if (TickAirControl != 0.f)
  3136.     {
  3137.         TickAirControl = BoostAirControl(DeltaTime, TickAirControl, FallAcceleration);
  3138.     }
  3139.  
  3140.     return TickAirControl * FallAcceleration;
  3141. }
  3142.  
  3143.  
  3144. float UCharacterMovementComponent::BoostAirControl(float DeltaTime, float TickAirControl, const FVector& FallAcceleration) const
  3145. {
  3146.     // Allow a burst of initial acceleration.
  3147.     if (AirControlBoostMultiplier > 0.0f && FVector::VectorPlaneProject(Velocity, GetGravityDirection(true)).SizeSquared() < FMath::Square(AirControlBoostVelocityThreshold))
  3148.     {
  3149.         TickAirControl = FMath::Min(1.0f, AirControlBoostMultiplier * TickAirControl);
  3150.     }
  3151.  
  3152.     return TickAirControl;
  3153. }
  3154.  
  3155.  
  3156. void UCharacterMovementComponent::PhysFalling(float deltaTime, int32 Iterations)
  3157. {
  3158.     SCOPE_CYCLE_COUNTER(STAT_CharPhysFalling);
  3159.  
  3160.     if (deltaTime < MIN_TICK_TIME)
  3161.     {
  3162.         return;
  3163.     }
  3164.  
  3165.     // Abort if no valid gravity can be obtained.
  3166.     const FVector GravityDir = GetGravityDirection();
  3167.     if (GravityDir.IsZero())
  3168.     {
  3169.         Acceleration = FVector::ZeroVector;
  3170.         Velocity = FVector::ZeroVector;
  3171.         return;
  3172.     }
  3173.  
  3174.     FVector FallAcceleration = GetFallingLateralAcceleration(deltaTime, GravityDir);
  3175.     const bool bHasAirControl = FallAcceleration.SizeSquared() > 0.0f;
  3176.  
  3177.     float RemainingTime = deltaTime;
  3178.     while (RemainingTime >= MIN_TICK_TIME && Iterations < MaxSimulationIterations)
  3179.     {
  3180.         Iterations++;
  3181.         const float TimeTick = GetSimulationTimeStep(RemainingTime, Iterations);
  3182.         RemainingTime -= TimeTick;
  3183.  
  3184.         const FVector OldLocation = UpdatedComponent->GetComponentLocation();
  3185.         const FQuat PawnRotation = UpdatedComponent->GetComponentQuat();
  3186.         bJustTeleported = false;
  3187.  
  3188.         FVector OldVelocity = Velocity;
  3189.         FVector VelocityNoAirControl = Velocity;
  3190.  
  3191.         // Apply input
  3192.         if (!HasRootMotion())
  3193.         {
  3194.             const FVector OldVelocityZ = GravityDir * (Velocity | GravityDir);
  3195.             // Compute VelocityNoAirControl
  3196.             if (bHasAirControl)
  3197.             {
  3198.                 // Find velocity *without* acceleration.
  3199.                 TGuardValue<FVector> RestoreAcceleration(Acceleration, FVector::ZeroVector);
  3200.                 TGuardValue<FVector> RestoreVelocity(Velocity, Velocity);
  3201.  
  3202.                 Velocity = FVector::VectorPlaneProject(Velocity, GravityDir);
  3203.                 CalcVelocity(TimeTick, FallingLateralFriction, false, BrakingDecelerationFalling);
  3204.                 VelocityNoAirControl = FVector::VectorPlaneProject(Velocity, GravityDir) + OldVelocityZ;
  3205.             }
  3206.  
  3207.             // Compute Velocity.
  3208.             {
  3209.                 // Acceleration = FallAcceleration for CalcVelocity(), but we restore it after using it.
  3210.                 TGuardValue<FVector> RestoreAcceleration(Acceleration, FallAcceleration);
  3211.  
  3212.                 Velocity = FVector::VectorPlaneProject(Velocity, GravityDir);
  3213.                 CalcVelocity(TimeTick, FallingLateralFriction, false, BrakingDecelerationFalling);
  3214.                 Velocity = FVector::VectorPlaneProject(Velocity, GravityDir) + OldVelocityZ;
  3215.             }
  3216.  
  3217.             // Just copy Velocity to VelocityNoAirControl if they are the same (ie no acceleration).
  3218.             if (!bHasAirControl)
  3219.             {
  3220.                 VelocityNoAirControl = Velocity;
  3221.             }
  3222.         }
  3223.  
  3224.         // Apply gravity.
  3225.         const FVector Gravity = GetGravity();
  3226.         Velocity = NewFallVelocity(Velocity, Gravity, TimeTick);
  3227.         VelocityNoAirControl = NewFallVelocity(VelocityNoAirControl, Gravity, TimeTick);
  3228.         const FVector AirControlAccel = (Velocity - VelocityNoAirControl) / TimeTick;
  3229.  
  3230.         if (bNotifyApex && CharacterOwner->Controller && ((Velocity | GravityDir) * -1.0f) <= 0.0f)
  3231.         {
  3232.             // Just passed jump apex since now going down.
  3233.             bNotifyApex = false;
  3234.             NotifyJumpApex();
  3235.         }
  3236.  
  3237.  
  3238.         // Move now.
  3239.         FHitResult Hit(1.0f);
  3240.         FVector Adjusted = 0.5f * (OldVelocity + Velocity) * TimeTick;
  3241.         SafeMoveUpdatedComponent(Adjusted, PawnRotation, true, Hit);
  3242.  
  3243.         if (!HasValidData())
  3244.         {
  3245.             return;
  3246.         }
  3247.  
  3248.         float LastMoveTimeSlice = TimeTick;
  3249.         float SubTimeTickRemaining = TimeTick * (1.0f - Hit.Time);
  3250.  
  3251.         if (IsSwimming())
  3252.         {
  3253.             // Just entered water.
  3254.             RemainingTime += SubTimeTickRemaining;
  3255.             StartSwimming(OldLocation, OldVelocity, TimeTick, RemainingTime, Iterations);
  3256.             return;
  3257.         }
  3258.         else if (Hit.bBlockingHit)
  3259.         {
  3260.             if (IsValidLandingSpot(UpdatedComponent->GetComponentLocation(), Hit))
  3261.             {
  3262.                 RemainingTime += SubTimeTickRemaining;
  3263.                 ProcessLanded(Hit, RemainingTime, Iterations);
  3264.                 return;
  3265.             }
  3266.             else
  3267.             {
  3268.                 // Compute impact deflection based on final velocity, not integration step.
  3269.                 // This allows us to compute a new velocity from the deflected vector, and ensures the full gravity effect is included in the slide result.
  3270.                 Adjusted = Velocity * TimeTick;
  3271.  
  3272.                 // See if we can convert a normally invalid landing spot (based on the hit result) to a usable one.
  3273.                 if (!Hit.bStartPenetrating && ShouldCheckForValidLandingSpot(TimeTick, Adjusted, Hit))
  3274.                 {
  3275.                     const FVector PawnLocation = UpdatedComponent->GetComponentLocation();
  3276.                     FFindFloorResult FloorResult;
  3277.                     FindFloor(PawnLocation, FloorResult, false);
  3278.                     if (FloorResult.IsWalkableFloor() && IsValidLandingSpot(PawnLocation, FloorResult.HitResult))
  3279.                     {
  3280.                         RemainingTime += SubTimeTickRemaining;
  3281.                         ProcessLanded(FloorResult.HitResult, RemainingTime, Iterations);
  3282.                         return;
  3283.                     }
  3284.                 }
  3285.  
  3286.                 HandleImpact(Hit, LastMoveTimeSlice, Adjusted);
  3287.  
  3288.                 // If we've changed physics mode, abort.
  3289.                 if (!HasValidData() || !IsFalling())
  3290.                 {
  3291.                     return;
  3292.                 }
  3293.  
  3294.                 // Limit air control based on what we hit.
  3295.                 // We moved to the impact point using air control, but may want to deflect from there based on a limited air control acceleration.
  3296.                 if (bHasAirControl)
  3297.                 {
  3298.                     const FVector AirControlDeltaV = LimitAirControl(LastMoveTimeSlice, AirControlAccel, Hit, GravityDir, false) * LastMoveTimeSlice;
  3299.                     Adjusted = (VelocityNoAirControl + AirControlDeltaV) * LastMoveTimeSlice;
  3300.                 }
  3301.  
  3302.                 const FVector OldHitNormal = Hit.Normal;
  3303.                 const FVector OldHitImpactNormal = Hit.ImpactNormal;
  3304.                 FVector Delta = ComputeSlideVector(Adjusted, 1.0f - Hit.Time, OldHitNormal, Hit);
  3305.  
  3306.                 // Compute velocity after deflection (only gravity component for RootMotion).
  3307.                 if (SubTimeTickRemaining > KINDA_SMALL_NUMBER && !bJustTeleported)
  3308.                 {
  3309.                     const FVector NewVelocity = (Delta / SubTimeTickRemaining);
  3310.  
  3311.                     if (!HasRootMotion())
  3312.                     {
  3313.                         Velocity = NewVelocity;
  3314.                     }
  3315.                     else
  3316.                     {
  3317.                         Velocity = FVector::VectorPlaneProject(Velocity, GravityDir) + GravityDir * (NewVelocity | GravityDir);
  3318.                     }
  3319.                 }
  3320.  
  3321.                 if (SubTimeTickRemaining > KINDA_SMALL_NUMBER && (Delta | Adjusted) > 0.0f)
  3322.                 {
  3323.                     // Move in deflected direction.
  3324.                     SafeMoveUpdatedComponent(Delta, PawnRotation, true, Hit);
  3325.  
  3326.                     if (Hit.bBlockingHit)
  3327.                     {
  3328.                         // Hit second wall.
  3329.                         LastMoveTimeSlice = SubTimeTickRemaining;
  3330.                         SubTimeTickRemaining *= (1.0f - Hit.Time);
  3331.  
  3332.                         if (IsValidLandingSpot(UpdatedComponent->GetComponentLocation(), Hit))
  3333.                         {
  3334.                             RemainingTime += SubTimeTickRemaining;
  3335.                             ProcessLanded(Hit, RemainingTime, Iterations);
  3336.                             return;
  3337.                         }
  3338.  
  3339.                         HandleImpact(Hit, LastMoveTimeSlice, Delta);
  3340.  
  3341.                         // If we've changed physics mode, abort.
  3342.                         if (!HasValidData() || !IsFalling())
  3343.                         {
  3344.                             return;
  3345.                         }
  3346.  
  3347.                         // Act as if there was no air control on the last move when computing new deflection.
  3348.                         if (bHasAirControl && (Hit.Normal | GravityDir) < -VERTICAL_SLOPE_NORMAL_Z)
  3349.                         {
  3350.                             Delta = ComputeSlideVector(VelocityNoAirControl * LastMoveTimeSlice, 1.0f, OldHitNormal, Hit);
  3351.                         }
  3352.  
  3353.                         FVector PreTwoWallDelta = Delta;
  3354.                         TwoWallAdjust(Delta, Hit, OldHitNormal);
  3355.  
  3356.                         // Limit air control, but allow a slide along the second wall.
  3357.                         if (bHasAirControl)
  3358.                         {
  3359.                             const FVector AirControlDeltaV = LimitAirControl(SubTimeTickRemaining, AirControlAccel, Hit, GravityDir, false) * SubTimeTickRemaining;
  3360.  
  3361.                             // Only allow if not back in to first wall.
  3362.                             if ((AirControlDeltaV | OldHitNormal) > 0.0f)
  3363.                             {
  3364.                                 Delta += (AirControlDeltaV * SubTimeTickRemaining);
  3365.                             }
  3366.                         }
  3367.  
  3368.                         // Compute velocity after deflection (only gravity component for RootMotion).
  3369.                         if (SubTimeTickRemaining > KINDA_SMALL_NUMBER && !bJustTeleported)
  3370.                         {
  3371.                             const FVector NewVelocity = (Delta / SubTimeTickRemaining);
  3372.  
  3373.                             if (!HasRootMotion())
  3374.                             {
  3375.                                 Velocity = NewVelocity;
  3376.                             }
  3377.                             else
  3378.                             {
  3379.                                 Velocity = FVector::VectorPlaneProject(Velocity, GravityDir) + GravityDir * (NewVelocity | GravityDir);
  3380.                             }
  3381.                         }
  3382.  
  3383.                         // bDitch=true means that pawn is straddling two slopes, neither of which he can stand on.
  3384.                         bool bDitch = ((OldHitImpactNormal | GravityDir) < 0.0f && (Hit.ImpactNormal | GravityDir) < 0.0f &&
  3385.                             FMath::Abs(Delta | GravityDir) <= KINDA_SMALL_NUMBER && (Hit.ImpactNormal | OldHitImpactNormal) < 0.0f);
  3386.  
  3387.                         SafeMoveUpdatedComponent(Delta, PawnRotation, true, Hit);
  3388.  
  3389.                         if (Hit.Time == 0.0f)
  3390.                         {
  3391.                             // if we are stuck then try to side step
  3392.                             FVector SideDelta = FVector::VectorPlaneProject(OldHitNormal + Hit.ImpactNormal, GravityDir).GetSafeNormal();
  3393.                             if (SideDelta.IsNearlyZero())
  3394.                             {
  3395.                                 SideDelta = GravityDir ^ (FVector::VectorPlaneProject(OldHitNormal, GravityDir).GetSafeNormal());
  3396.                             }
  3397.  
  3398.                             SafeMoveUpdatedComponent(SideDelta, PawnRotation, true, Hit);
  3399.                         }
  3400.  
  3401.                         if (bDitch || IsValidLandingSpot(UpdatedComponent->GetComponentLocation(), Hit) || Hit.Time == 0.0f)
  3402.                         {
  3403.                             RemainingTime = 0.0f;
  3404.                             ProcessLanded(Hit, RemainingTime, Iterations);
  3405.  
  3406.                             return;
  3407.                         }
  3408.                         else if (GetPerchRadiusThreshold() > 0.0f && Hit.Time == 1.0f && (OldHitImpactNormal | GravityDir) <= -GetWalkableFloorZ())
  3409.                         {
  3410.                             // We might be in a virtual 'ditch' within our perch radius. This is rare.
  3411.                             const FVector PawnLocation = UpdatedComponent->GetComponentLocation();
  3412.                             const float ZMovedDist = FMath::Abs((PawnLocation - OldLocation) | GravityDir);
  3413.                             const float MovedDist2DSq = (FVector::VectorPlaneProject(PawnLocation - OldLocation, GravityDir)).SizeSquared();
  3414.  
  3415.                             if (ZMovedDist <= 0.2f * TimeTick && MovedDist2DSq <= 4.0f * TimeTick)
  3416.                             {
  3417.                                 Velocity.X += 0.25f * GetMaxSpeed() * (FMath::FRand() - 0.5f);
  3418.                                 Velocity.Y += 0.25f * GetMaxSpeed() * (FMath::FRand() - 0.5f);
  3419.                                 Velocity.Z += 0.25f * GetMaxSpeed() * (FMath::FRand() - 0.5f);
  3420.                                 Velocity = FVector::VectorPlaneProject(Velocity, GravityDir) + GravityDir * (FMath::Max<float>(JumpZVelocity * 0.25f, 1.0f) * -1.0f);
  3421.                                 Delta = Velocity * TimeTick;
  3422.  
  3423.                                 SafeMoveUpdatedComponent(Delta, PawnRotation, true, Hit);
  3424.                             }
  3425.                         }
  3426.                     }
  3427.                 }
  3428.             }
  3429.         }
  3430.  
  3431.         if ((FVector::VectorPlaneProject(Velocity, GravityDir)).SizeSquared() <= KINDA_SMALL_NUMBER * 10.0f)
  3432.         {
  3433.             Velocity = GravityDir * (Velocity | GravityDir);
  3434.         }
  3435.     }
  3436. }
  3437.  
  3438.  
  3439. // Note: Deprecated for 4.9
  3440. bool UCharacterMovementComponent::FindAirControlImpact(float DeltaTime, float AdditionalTime, const FVector& FallVelocity, const FVector& FallAcceleration, const FVector& Gravity, FHitResult& OutHitResult) const
  3441. {
  3442.     // Test for slope to avoid using air control to climb walls.
  3443.     FVector TestWalk = Velocity * DeltaTime;
  3444.     if (AdditionalTime > 0.f)
  3445.     {
  3446.         const FVector PostGravityVelocity = NewFallVelocity(FallVelocity, Gravity, AdditionalTime);
  3447.         TestWalk += ((FallAcceleration * AdditionalTime) + PostGravityVelocity) * AdditionalTime;
  3448.     }
  3449.  
  3450.     if (!TestWalk.IsZero())
  3451.     {
  3452.         FCollisionQueryParams CapsuleQuery(CharacterMovementComponentStatics::FallingTraceParamsTag, false, CharacterOwner);
  3453.         FCollisionResponseParams ResponseParam;
  3454.         InitCollisionParams(CapsuleQuery, ResponseParam);
  3455.         const FVector CapsuleLocation = UpdatedComponent->GetComponentLocation();
  3456.         const FCollisionShape CapsuleShape = GetPawnCapsuleCollisionShape(SHRINK_None);
  3457.  
  3458.         if (GetWorld()->SweepSingleByChannel(OutHitResult, CapsuleLocation, CapsuleLocation + TestWalk, GetCapsuleRotation(), UpdatedComponent->GetCollisionObjectType(), CapsuleShape, CapsuleQuery, ResponseParam))
  3459.         {
  3460.             return true;
  3461.         }
  3462.     }
  3463.  
  3464.     return false;
  3465. }
  3466.  
  3467.  
  3468. FVector UCharacterMovementComponent::LimitAirControl(float DeltaTime, const FVector& FallAcceleration, const FHitResult& HitResult, const FVector& GravDir, bool bCheckForValidLandingSpot) const
  3469. {
  3470.     FVector Result = FallAcceleration;
  3471.  
  3472.     if (HitResult.IsValidBlockingHit() && (HitResult.Normal | GravDir) < -VERTICAL_SLOPE_NORMAL_Z)
  3473.     {
  3474.         if ((!bCheckForValidLandingSpot || !IsValidLandingSpot(HitResult.Location, HitResult)) && (FallAcceleration | HitResult.Normal) < 0.0f)
  3475.         {
  3476.             // If acceleration is into the wall, limit contribution.
  3477.             // Allow movement parallel to the wall, but not into it because that may push us up.
  3478.             const FVector Normal2D = FVector::VectorPlaneProject(HitResult.Normal, GravDir).GetSafeNormal();
  3479.             Result = FVector::VectorPlaneProject(FallAcceleration, Normal2D);
  3480.         }
  3481.     }
  3482.     else if (HitResult.bStartPenetrating)
  3483.     {
  3484.         // Allow movement out of penetration.
  3485.         return ((Result | HitResult.Normal) > 0.0f ? Result : FVector::ZeroVector);
  3486.     }
  3487.  
  3488.     return Result;
  3489. }
  3490.  
  3491. bool UCharacterMovementComponent::CheckLedgeDirection(const FVector& OldLocation, const FVector& SideStep, const FVector& GravDir) const
  3492. {
  3493.     const FVector SideDest = OldLocation + SideStep;
  3494.     const FQuat CapsuleRotation = GetCapsuleRotation();
  3495.     FCollisionQueryParams CapsuleParams(CharacterMovementComponentStatics::CheckLedgeDirectionName, false, CharacterOwner);
  3496.     FCollisionResponseParams ResponseParam;
  3497.     InitCollisionParams(CapsuleParams, ResponseParam);
  3498.     const FCollisionShape CapsuleShape = GetPawnCapsuleCollisionShape(SHRINK_None);
  3499.     const ECollisionChannel CollisionChannel = UpdatedComponent->GetCollisionObjectType();
  3500.     FHitResult Result(1.f);
  3501.     GetWorld()->SweepSingleByChannel(Result, OldLocation, SideDest, CapsuleRotation, CollisionChannel, CapsuleShape, CapsuleParams, ResponseParam);
  3502.  
  3503.     if (!Result.bBlockingHit || IsWalkable(Result))
  3504.     {
  3505.         if (!Result.bBlockingHit)
  3506.         {
  3507.             GetWorld()->SweepSingleByChannel(Result, SideDest, SideDest + GravDir * (MaxStepHeight + LedgeCheckThreshold), CapsuleRotation, CollisionChannel, CapsuleShape, CapsuleParams, ResponseParam);
  3508.         }
  3509.  
  3510.         if ((Result.Time < 1.f) && IsWalkable(Result))
  3511.         {
  3512.             return true;
  3513.         }
  3514.     }
  3515.     return false;
  3516. }
  3517.  
  3518.  
  3519. FVector UCharacterMovementComponent::GetLedgeMove(const FVector& OldLocation, const FVector& Delta, const FVector& GravDir) const
  3520. {
  3521.     if (!HasValidData() || Delta.IsZero())
  3522.     {
  3523.         return FVector::ZeroVector;
  3524.     }
  3525.  
  3526.     FVector SideDir = FVector::VectorPlaneProject(Delta, GravDir);
  3527.     SideDir = FQuat(GravDir, PI * 0.5f).RotateVector(SideDir);
  3528.     // try left
  3529.     if ( CheckLedgeDirection(OldLocation, SideDir, GravDir) )
  3530.     {
  3531.         return SideDir;
  3532.     }
  3533.  
  3534.     // try right
  3535.     SideDir *= -1.f;
  3536.     if ( CheckLedgeDirection(OldLocation, SideDir, GravDir) )
  3537.     {
  3538.         return SideDir;
  3539.     }
  3540.  
  3541.     return FVector::ZeroVector;
  3542. }
  3543.  
  3544.  
  3545. bool UCharacterMovementComponent::CanWalkOffLedges() const
  3546. {
  3547.     if (!bCanWalkOffLedgesWhenCrouching && IsCrouching())
  3548.     {
  3549.         return false;
  3550.     }
  3551.  
  3552.     return bCanWalkOffLedges;
  3553. }
  3554.  
  3555. bool UCharacterMovementComponent::CheckFall(const FFindFloorResult& OldFloor, const FHitResult& Hit, const FVector& Delta, const FVector& OldLocation, float remainingTime, float timeTick, int32 Iterations, bool bMustJump)
  3556. {
  3557.     if (!HasValidData())
  3558.     {
  3559.         return false;
  3560.     }
  3561.  
  3562.     if (bMustJump || CanWalkOffLedges())
  3563.     {
  3564.         CharacterOwner->OnWalkingOffLedge(OldFloor.HitResult.ImpactNormal, OldFloor.HitResult.Normal, OldLocation, timeTick);
  3565.         if (IsMovingOnGround())
  3566.         {
  3567.             // If still walking, then fall. If not, assume the user set a different mode they want to keep.
  3568.             StartFalling(Iterations, remainingTime, timeTick, Delta, OldLocation);
  3569.         }
  3570.         return true;
  3571.     }
  3572.     return false;
  3573. }
  3574.  
  3575. void UCharacterMovementComponent::StartFalling(int32 Iterations, float remainingTime, float timeTick, const FVector& Delta, const FVector& subLoc)
  3576. {
  3577.     const float DesiredDist = Delta.Size();
  3578.  
  3579.     if (DesiredDist < KINDA_SMALL_NUMBER)
  3580.     {
  3581.         remainingTime = 0.0f;
  3582.     }
  3583.     else
  3584.     {
  3585.         const float ActualDist = (UpdatedComponent->GetComponentLocation() - subLoc).Size();
  3586.         remainingTime += timeTick * (1.0f - FMath::Min(1.0f, ActualDist / DesiredDist));
  3587.     }
  3588.  
  3589.     const FVector GravityDir = GetGravityDirection();
  3590.     if (bFallingRemovesSpeedZ && !GravityDir.IsZero())
  3591.     {
  3592.         Velocity = FVector::VectorPlaneProject(Velocity, GravityDir);
  3593.     }
  3594.  
  3595.     if (IsMovingOnGround())
  3596.     {
  3597.         // This is to catch cases where the first frame of PIE is executed, and the
  3598.         // level is not yet visible. In those cases, the player will fall out of the
  3599.         // world... So, don't set MOVE_Falling straight away.
  3600.         if ( !GIsEditor || (GetWorld()->HasBegunPlay() && (GetWorld()->GetTimeSeconds() >= 1.f)) )
  3601.         {
  3602.             SetMovementMode(MOVE_Falling); //default behavior if script didn't change physics
  3603.         }
  3604.         else
  3605.         {
  3606.             // Make sure that the floor check code continues processing during this delay.
  3607.             bForceNextFloorCheck = true;
  3608.         }
  3609.     }
  3610.     StartNewPhysics(remainingTime,Iterations);
  3611. }
  3612.  
  3613.  
  3614. void UCharacterMovementComponent::RevertMove(const FVector& OldLocation, UPrimitiveComponent* OldBase, const FVector& PreviousBaseLocation, const FFindFloorResult& OldFloor, bool bFailMove)
  3615. {
  3616.     //UE_LOG(LogCharacterMovement, Log, TEXT("RevertMove from %f %f %f to %f %f %f"), CharacterOwner->Location.X, CharacterOwner->Location.Y, CharacterOwner->Location.Z, OldLocation.X, OldLocation.Y, OldLocation.Z);
  3617.     UpdatedComponent->SetWorldLocation(OldLocation, false);
  3618.  
  3619.     //UE_LOG(LogCharacterMovement, Log, TEXT("Now at %f %f %f"), CharacterOwner->Location.X, CharacterOwner->Location.Y, CharacterOwner->Location.Z);
  3620.     bJustTeleported = false;
  3621.     // if our previous base couldn't have moved or changed in any physics-affecting way, restore it
  3622.     if (IsValid(OldBase) &&
  3623.         (!MovementBaseUtility::IsDynamicBase(OldBase) ||
  3624.         (OldBase->Mobility == EComponentMobility::Static) ||
  3625.         (OldBase->GetComponentLocation() == PreviousBaseLocation)
  3626.         )
  3627.         )
  3628.     {
  3629.         CurrentFloor = OldFloor;
  3630.         SetBase(OldBase, OldFloor.HitResult.BoneName);
  3631.     }
  3632.     else
  3633.     {
  3634.         SetBase(NULL);
  3635.     }
  3636.  
  3637.     if ( bFailMove )
  3638.     {
  3639.         // end movement now
  3640.         Velocity = FVector::ZeroVector;
  3641.         Acceleration = FVector::ZeroVector;
  3642.         //UE_LOG(LogCharacterMovement, Log, TEXT("%s FAILMOVE RevertMove"), *CharacterOwner->GetName());
  3643.  
  3644.         if (PathFollowingComp.IsValid())
  3645.         {
  3646.             PathFollowingComp->AbortMove(TEXT("RevertMove"));
  3647.         }
  3648.     }
  3649. }
  3650.  
  3651.  
  3652. FVector UCharacterMovementComponent::ComputeGroundMovementDelta(const FVector& Delta, const FVector& DeltaPlaneNormal, const FHitResult& RampHit, const bool bHitFromLineTrace) const
  3653. {
  3654.     const FVector FloorNormal = RampHit.ImpactNormal;
  3655.  
  3656.     if (!bHitFromLineTrace && FMath::Abs(Delta | FloorNormal) > THRESH_NORMALS_ARE_ORTHOGONAL && IsWalkable(RampHit))
  3657.     {
  3658.         // Compute a vector that moves parallel to the surface, by projecting the horizontal movement direction onto the ramp.
  3659.         // We can't just project Delta onto the plane defined by FloorNormal because the direction changes on spherical geometry.
  3660.         const FVector DeltaNormal = Delta.GetSafeNormal();
  3661.         FVector NewDelta = FQuat(DeltaPlaneNormal ^ DeltaNormal, FMath::Acos(FloorNormal | DeltaPlaneNormal)).RotateVector(Delta);
  3662.  
  3663.         if (bMaintainHorizontalGroundVelocity)
  3664.         {
  3665.             const FVector NewDeltaNormal = NewDelta.GetSafeNormal();
  3666.             NewDelta = NewDeltaNormal * (Delta.Size() / (DeltaNormal | NewDeltaNormal));
  3667.         }
  3668.  
  3669.         return NewDelta;
  3670.     }
  3671.  
  3672.     return Delta;
  3673. }
  3674.  
  3675. void UCharacterMovementComponent::OnCharacterStuckInGeometry()
  3676. {
  3677.     UE_LOG(LogCharacterMovement, Log, TEXT("%s is stuck and failed to move!"), *CharacterOwner->GetName());
  3678.  
  3679.     // Don't update velocity based on our (failed) change in position this update since we're stuck.
  3680.     bJustTeleported = true;
  3681. }
  3682.  
  3683. void UCharacterMovementComponent::MoveAlongFloor(const FVector& InVelocity, float DeltaSeconds, FStepDownResult* OutStepDownResult)
  3684. {
  3685.  
  3686.     if (!CurrentFloor.IsWalkableFloor())
  3687.     {
  3688.         return;
  3689.     }
  3690.  
  3691.     // Move along the current floor
  3692.     const FVector CapsuleUp = GetCapsuleAxisZ();
  3693.     const FVector Delta = FVector::VectorPlaneProject(InVelocity, CapsuleUp) * DeltaSeconds;
  3694.     FHitResult Hit(1.0f);
  3695.     FVector RampVector = ComputeGroundMovementDelta(Delta, CapsuleUp, CurrentFloor.HitResult, CurrentFloor.bLineTrace);
  3696.     SafeMoveUpdatedComponent(RampVector, UpdatedComponent->GetComponentQuat(), true, Hit);
  3697.     float LastMoveTimeSlice = DeltaSeconds;
  3698.  
  3699.     if (Hit.bStartPenetrating)
  3700.     {
  3701.         // Allow this hit to be used as an impact we can deflect off, otherwise we do nothing the rest of the update and appear to hitch.
  3702.         HandleImpact(Hit);
  3703.         SlideAlongSurface(Delta, 1.0f, Hit.Normal, Hit, true);
  3704.  
  3705.         if (Hit.bStartPenetrating)
  3706.         {
  3707.             OnCharacterStuckInGeometry();
  3708.         }
  3709.     }
  3710.     else if (Hit.IsValidBlockingHit())
  3711.     {
  3712.         // We impacted something (most likely another ramp, but possibly a barrier).
  3713.         float PercentTimeApplied = Hit.Time;
  3714.         if (Hit.Time > 0.0f && (Hit.Normal | CapsuleUp) > KINDA_SMALL_NUMBER && IsWalkable(Hit))
  3715.         {
  3716.             // Another walkable ramp.
  3717.             const float InitialPercentRemaining = 1.0f - PercentTimeApplied;
  3718.             RampVector = ComputeGroundMovementDelta(Delta * InitialPercentRemaining, CapsuleUp, Hit, false);
  3719.             LastMoveTimeSlice = InitialPercentRemaining * LastMoveTimeSlice;
  3720.             SafeMoveUpdatedComponent(RampVector, UpdatedComponent->GetComponentQuat(), true, Hit);
  3721.  
  3722.             const float SecondHitPercent = Hit.Time * InitialPercentRemaining;
  3723.             PercentTimeApplied = FMath::Clamp(PercentTimeApplied + SecondHitPercent, 0.0f, 1.0f);
  3724.         }
  3725.  
  3726.         if (Hit.IsValidBlockingHit())
  3727.         {
  3728.             if (CanStepUp(Hit) || (CharacterOwner->GetMovementBase() != NULL && CharacterOwner->GetMovementBase()->GetOwner() == Hit.GetActor()))
  3729.             {
  3730.                 // Hit a barrier, try to step up.
  3731.                 if (!StepUp(CapsuleUp * -1.0f, Delta * (1.0f - PercentTimeApplied), Hit, OutStepDownResult))
  3732.                 {
  3733.                     UE_LOG(LogCharacterMovement, Verbose, TEXT("- StepUp (ImpactNormal %s, Normal %s"), *Hit.ImpactNormal.ToString(), *Hit.Normal.ToString());
  3734.                     HandleImpact(Hit, LastMoveTimeSlice, RampVector);
  3735.                     SlideAlongSurface(Delta, 1.0f - PercentTimeApplied, Hit.Normal, Hit, true);
  3736.                 }
  3737.                 else
  3738.                 {
  3739.                     // Don't recalculate velocity based on this height adjustment, if considering vertical adjustments.
  3740.                     UE_LOG(LogCharacterMovement, Verbose, TEXT("+ StepUp (ImpactNormal %s, Normal %s"), *Hit.ImpactNormal.ToString(), *Hit.Normal.ToString());
  3741.                     bJustTeleported |= !bMaintainHorizontalGroundVelocity;
  3742.                 }
  3743.             }
  3744.             else if (Hit.Component.IsValid() && !Hit.Component.Get()->CanCharacterStepUp(CharacterOwner))
  3745.             {
  3746.                 HandleImpact(Hit, LastMoveTimeSlice, RampVector);
  3747.                 SlideAlongSurface(Delta, 1.0f - PercentTimeApplied, Hit.Normal, Hit, true);
  3748.             }
  3749.         }
  3750.     }
  3751. }
  3752.  
  3753.  
  3754. void UCharacterMovementComponent::MaintainHorizontalGroundVelocity()
  3755. {
  3756.     if (bMaintainHorizontalGroundVelocity)
  3757.     {
  3758.         // Just remove the vertical component.
  3759.         Velocity = FVector::VectorPlaneProject(Velocity, GetCapsuleAxisZ());
  3760.     }
  3761.     else
  3762.     {
  3763.         // Project the vector and maintain its original magnitude.
  3764.         Velocity = FVector::VectorPlaneProject(Velocity, GetCapsuleAxisZ()).GetSafeNormal() * Velocity.Size();
  3765.     }
  3766. }
  3767.  
  3768.  
  3769. void UCharacterMovementComponent::PhysWalking(float deltaTime, int32 Iterations)
  3770. {
  3771.     SCOPE_CYCLE_COUNTER(STAT_CharPhysWalking);
  3772.  
  3773.  
  3774.     if (deltaTime < MIN_TICK_TIME)
  3775.     {
  3776.         return;
  3777.     }
  3778.  
  3779.     if (!CharacterOwner || (!CharacterOwner->Controller && !bRunPhysicsWithNoController && !HasRootMotion()))
  3780.     {
  3781.         Acceleration = FVector::ZeroVector;
  3782.         Velocity = FVector::ZeroVector;
  3783.         return;
  3784.     }
  3785.  
  3786.     if (!UpdatedComponent->IsCollisionEnabled())
  3787.     {
  3788.         SetMovementMode(MOVE_Walking);
  3789.         return;
  3790.     }
  3791.  
  3792.     checkf(!Velocity.ContainsNaN(), TEXT("PhysWalking: Velocity contains NaN before Iteration (%s: %s)\n%s"), *GetPathNameSafe(this), *GetPathNameSafe(GetOuter()), *Velocity.ToString());
  3793.  
  3794.     bJustTeleported = false;
  3795.     bool bCheckedFall = false;
  3796.     bool bTriedLedgeMove = false;
  3797.     float RemainingTime = deltaTime;
  3798.  
  3799.     // Perform the move.
  3800.     while (RemainingTime >= MIN_TICK_TIME && Iterations < MaxSimulationIterations && CharacterOwner && (CharacterOwner->Controller || bRunPhysicsWithNoController || HasRootMotion()))
  3801.     {
  3802.         Iterations++;
  3803.         bJustTeleported = false;
  3804.         const float TimeTick = GetSimulationTimeStep(RemainingTime, Iterations);
  3805.         RemainingTime -= TimeTick;
  3806.  
  3807.         // Save current values.
  3808.         UPrimitiveComponent* const OldBase = GetMovementBase();
  3809.         const FVector PreviousBaseLocation = (OldBase != NULL) ? OldBase->GetComponentLocation() : FVector::ZeroVector;
  3810.         const FVector OldLocation = UpdatedComponent->GetComponentLocation();
  3811.         const FFindFloorResult OldFloor = CurrentFloor;
  3812.  
  3813.         // Acceleration is already horizontal; ensure velocity is also horizontal.
  3814.         MaintainHorizontalGroundVelocity();
  3815.  
  3816.         const FVector OldVelocity = Velocity;
  3817.  
  3818.         // Apply acceleration.
  3819.         if (!HasRootMotion())
  3820.         {
  3821.             CalcVelocity(TimeTick, GroundFriction, false, BrakingDecelerationWalking);
  3822.         }
  3823.         checkf(!Velocity.ContainsNaN(), TEXT("PhysWalking: Velocity contains NaN after CalcVelocity (%s: %s)\n%s"), *GetPathNameSafe(this), *GetPathNameSafe(GetOuter()), *Velocity.ToString());
  3824.  
  3825.         // Compute move parameters.
  3826.         const FVector MoveVelocity = Velocity;
  3827.         const FVector Delta = TimeTick * MoveVelocity;
  3828.         const bool bZeroDelta = Delta.IsNearlyZero();
  3829.         FStepDownResult StepDownResult;
  3830.  
  3831.         if (bZeroDelta)
  3832.         {
  3833.             RemainingTime = 0.0f;
  3834.         }
  3835.         else
  3836.         {
  3837.             // Try to move forward.
  3838.             MoveAlongFloor(MoveVelocity, TimeTick, &StepDownResult);
  3839.  
  3840.             if (IsFalling())
  3841.             {
  3842.                 // Pawn decided to jump up.
  3843.                 const float DesiredDist = Delta.Size();
  3844.                 if (DesiredDist > KINDA_SMALL_NUMBER)
  3845.                 {
  3846.                     const float ActualDist = FVector::VectorPlaneProject(UpdatedComponent->GetComponentLocation() - OldLocation, GetCapsuleAxisZ()).Size();
  3847.                     RemainingTime += TimeTick * (1.0f - FMath::Min(1.0f, ActualDist / DesiredDist));
  3848.                 }
  3849.  
  3850.                 StartNewPhysics(RemainingTime, Iterations);
  3851.                 return;
  3852.             }
  3853.             else if (IsSwimming())
  3854.             {
  3855.                 //Just entered water.
  3856.                 StartSwimming(OldLocation, OldVelocity, TimeTick, RemainingTime, Iterations);
  3857.                 return;
  3858.             }
  3859.         }
  3860.  
  3861.         // Update floor; StepUp might have already done it for us.
  3862.         if (StepDownResult.bComputedFloor)
  3863.         {
  3864.             CurrentFloor = StepDownResult.FloorResult;
  3865.         }
  3866.         else
  3867.         {
  3868.             FindFloor(UpdatedComponent->GetComponentLocation(), CurrentFloor, bZeroDelta, NULL);
  3869.         }
  3870.  
  3871.         // Check for ledges here.
  3872.         const bool bCheckLedges = !CanWalkOffLedges();
  3873.         if (bCheckLedges && !CurrentFloor.IsWalkableFloor())
  3874.         {
  3875.             // Calculate possible alternate movement.
  3876.             const FVector NewDelta = bTriedLedgeMove ? FVector::ZeroVector : GetLedgeMove(OldLocation, Delta, GetCapsuleAxisZ() * -1.0f);
  3877.             if (!NewDelta.IsZero())
  3878.             {
  3879.                 // First revert this move.
  3880.                 RevertMove(OldLocation, OldBase, PreviousBaseLocation, OldFloor, false);
  3881.  
  3882.                 // Avoid repeated ledge moves if the first one fails.
  3883.                 bTriedLedgeMove = true;
  3884.  
  3885.                 // Try new movement direction.
  3886.                 Velocity = NewDelta / TimeTick;
  3887.                 RemainingTime += TimeTick;
  3888.                 continue;
  3889.             }
  3890.             else
  3891.             {
  3892.                 // see if it is OK to jump
  3893.                 // @todo collision : only thing that can be problem is that oldbase has world collision on
  3894.                 bool bMustJump = bZeroDelta || (OldBase == NULL || (!OldBase->IsCollisionEnabled() && MovementBaseUtility::IsDynamicBase(OldBase)));
  3895.                 if ((bMustJump || !bCheckedFall) && CheckFall(OldFloor, CurrentFloor.HitResult, Delta, OldLocation, RemainingTime, TimeTick, Iterations, bMustJump))
  3896.                 {
  3897.                     return;
  3898.                 }
  3899.                 bCheckedFall = true;
  3900.  
  3901.                 // Revert this move.
  3902.                 RevertMove(OldLocation, OldBase, PreviousBaseLocation, OldFloor, true);
  3903.                 RemainingTime = 0.0f;
  3904.                 break;
  3905.             }
  3906.         }
  3907.         else
  3908.         {
  3909.             // Validate the floor check.
  3910.             if (CurrentFloor.IsWalkableFloor())
  3911.             {
  3912.                 if (ShouldCatchAir(OldFloor, CurrentFloor))
  3913.                 {
  3914.                     CharacterOwner->OnWalkingOffLedge(OldFloor.HitResult.ImpactNormal, OldFloor.HitResult.Normal, OldLocation, TimeTick);
  3915.                     if (IsMovingOnGround())
  3916.                     {
  3917.                         // If still walking, then fall. If not, assume the user set a different mode they want to keep.
  3918.                         StartFalling(Iterations, RemainingTime, TimeTick, Delta, OldLocation);
  3919.                     }
  3920.                     return;
  3921.                 }
  3922.  
  3923.                 AdjustFloorHeight();
  3924.                 SetBase(CurrentFloor.HitResult.Component.Get(), CurrentFloor.HitResult.BoneName);
  3925.             }
  3926.             else if (CurrentFloor.HitResult.bStartPenetrating && RemainingTime <= 0.0f)
  3927.             {
  3928.                 // The floor check failed because it started in penetration.
  3929.                 // We do not want to try to move downward because the downward sweep failed, rather we'd like to try to pop out of the floor.
  3930.                 FHitResult Hit(CurrentFloor.HitResult);
  3931.                 Hit.TraceEnd = Hit.TraceStart + GetCapsuleAxisZ() * MAX_FLOOR_DIST;
  3932.                 const FVector RequestedAdjustment = GetPenetrationAdjustment(Hit);
  3933.                 ResolvePenetration(RequestedAdjustment, Hit, UpdatedComponent->GetComponentQuat());
  3934.             }
  3935.  
  3936.             // Check if just entered water.
  3937.             if (IsSwimming())
  3938.             {
  3939.                 StartSwimming(OldLocation, Velocity, TimeTick, RemainingTime, Iterations);
  3940.                 return;
  3941.             }
  3942.  
  3943.             // See if we need to start falling.
  3944.             if (!CurrentFloor.IsWalkableFloor() && !CurrentFloor.HitResult.bStartPenetrating)
  3945.             {
  3946.                 const bool bMustJump = bJustTeleported || bZeroDelta || (OldBase == NULL || (!OldBase->IsCollisionEnabled() && MovementBaseUtility::IsDynamicBase(OldBase)));
  3947.                 if ((bMustJump || !bCheckedFall) && CheckFall(OldFloor, CurrentFloor.HitResult, Delta, OldLocation, RemainingTime, TimeTick, Iterations, bMustJump) )
  3948.                 {
  3949.                     return;
  3950.                 }
  3951.                 bCheckedFall = true;
  3952.             }
  3953.         }
  3954.  
  3955.         // Allow overlap events and such to change physics state and velocity.
  3956.         if (IsMovingOnGround())
  3957.         {
  3958.             // Make velocity reflect actual move.
  3959.             if (!bJustTeleported && !HasRootMotion() && TimeTick >= MIN_TICK_TIME)
  3960.             {
  3961.                 Velocity = (UpdatedComponent->GetComponentLocation() - OldLocation) / TimeTick;
  3962.             }
  3963.         }
  3964.  
  3965.         // If we didn't move at all this iteration then abort (since future iterations will also be stuck).
  3966.         if (UpdatedComponent->GetComponentLocation() == OldLocation)
  3967.         {
  3968.             RemainingTime = 0.f;
  3969.             break;
  3970.         }
  3971.     }
  3972.  
  3973.     if (IsMovingOnGround())
  3974.     {
  3975.         MaintainHorizontalGroundVelocity();
  3976.     }
  3977. }
  3978.  
  3979. void UCharacterMovementComponent::PhysNavWalking(float deltaTime, int32 Iterations)
  3980. {
  3981.     SCOPE_CYCLE_COUNTER(STAT_CharPhysNavWalking);
  3982.  
  3983.     if (deltaTime < MIN_TICK_TIME)
  3984.     {
  3985.         return;
  3986.     }
  3987.  
  3988.     if ((!CharacterOwner || !CharacterOwner->Controller) && !bRunPhysicsWithNoController && !HasRootMotion())
  3989.     {
  3990.         Acceleration = FVector::ZeroVector;
  3991.         Velocity = FVector::ZeroVector;
  3992.         return;
  3993.     }
  3994.  
  3995.     // Ensure velocity is horizontal.
  3996.     MaintainHorizontalGroundVelocity();
  3997.     checkf(!Velocity.ContainsNaN(), TEXT("PhysNavWalking: Velocity contains NaN before CalcVelocity (%s: %s)\n%s"), *GetPathNameSafe(this), *GetPathNameSafe(GetOuter()), *Velocity.ToString());
  3998.  
  3999.     //bound acceleration
  4000.     Acceleration.Z = 0.f;
  4001.     if (!HasRootMotion())
  4002.     {
  4003.         CalcVelocity(deltaTime, GroundFriction, false, BrakingDecelerationWalking);
  4004.         checkf(!Velocity.ContainsNaN(), TEXT("PhysNavWalking: Velocity contains NaN after CalcVelocity (%s: %s)\n%s"), *GetPathNameSafe(this), *GetPathNameSafe(GetOuter()), *Velocity.ToString());
  4005.     }
  4006.  
  4007.     Iterations++;
  4008.  
  4009.     FVector DesiredMove = Velocity;
  4010.     DesiredMove.Z = 0.f;
  4011.  
  4012.     const FVector OldLocation = GetActorFeetLocation();
  4013.     const FVector DeltaMove = DesiredMove * deltaTime;
  4014.  
  4015.     FVector AdjustedDest = OldLocation + DeltaMove;
  4016.     FNavLocation DestNavLocation;
  4017.  
  4018.     bool bSameNavLocation = false;
  4019.     if (CachedNavLocation.NodeRef != INVALID_NAVNODEREF)
  4020.     {
  4021.         if (bProjectNavMeshWalking)
  4022.         {
  4023.             const float DistSq2D = (OldLocation - CachedNavLocation.Location).SizeSquared2D();
  4024.             const float DistZ = FMath::Abs(OldLocation.Z - CachedNavLocation.Location.Z);
  4025.  
  4026.             const float TotalCapsuleHeight = CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleHalfHeight() * 2.0f;
  4027.             const float ProjectionScale = (OldLocation.Z > CachedNavLocation.Location.Z) ? NavMeshProjectionHeightScaleUp : NavMeshProjectionHeightScaleDown;
  4028.             const float DistZThr = TotalCapsuleHeight * FMath::Max(0.f, ProjectionScale);
  4029.  
  4030.             bSameNavLocation = (DistSq2D <= KINDA_SMALL_NUMBER) && (DistZ < DistZThr);
  4031.         }
  4032.         else
  4033.         {
  4034.             bSameNavLocation = CachedNavLocation.Location.Equals(OldLocation);
  4035.         }
  4036.     }
  4037.  
  4038.  
  4039.     if (DeltaMove.IsNearlyZero() && bSameNavLocation)
  4040.     {
  4041.         DestNavLocation = CachedNavLocation;
  4042.         UE_LOG(LogNavMeshMovement, VeryVerbose, TEXT("%s using cached navmesh location! (bProjectNavMeshWalking = %d)"), *GetNameSafe(CharacterOwner), bProjectNavMeshWalking);
  4043.     }
  4044.     else
  4045.     {
  4046.         SCOPE_CYCLE_COUNTER(STAT_CharNavProjectPoint);
  4047.  
  4048.         // Start the trace from the Z location of the last valid trace.
  4049.         // Otherwise if we are projecting our location to the underlying geometry and it's far above or below the navmesh,
  4050.         // we'll follow that geometry's plane out of range of valid navigation.
  4051.         if (bSameNavLocation && bProjectNavMeshWalking)
  4052.         {
  4053.             AdjustedDest.Z = CachedNavLocation.Location.Z;
  4054.         }
  4055.  
  4056.         // Find the point on the NavMesh
  4057.         const bool bHasNavigationData = FindNavFloor(AdjustedDest, DestNavLocation);
  4058.         if (!bHasNavigationData)
  4059.         {
  4060.             SetMovementMode(MOVE_Walking);
  4061.             return;
  4062.         }
  4063.  
  4064.         CachedNavLocation = DestNavLocation;
  4065.     }
  4066.  
  4067.     if (DestNavLocation.NodeRef != INVALID_NAVNODEREF)
  4068.     {
  4069.         FVector NewLocation(AdjustedDest.X, AdjustedDest.Y, DestNavLocation.Location.Z);
  4070.         if (bProjectNavMeshWalking)
  4071.         {
  4072.             SCOPE_CYCLE_COUNTER(STAT_CharNavProjectLocation);
  4073.             const float TotalCapsuleHeight = CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleHalfHeight() * 2.0f;
  4074.             const float UpOffset = TotalCapsuleHeight * FMath::Max(0.f, NavMeshProjectionHeightScaleUp);
  4075.             const float DownOffset = TotalCapsuleHeight * FMath::Max(0.f, NavMeshProjectionHeightScaleDown);
  4076.             NewLocation = ProjectLocationFromNavMesh(deltaTime, OldLocation, NewLocation, UpOffset, DownOffset);
  4077.         }
  4078.  
  4079.         FVector AdjustedDelta = NewLocation - OldLocation;
  4080.  
  4081.         if (!AdjustedDelta.IsNearlyZero())
  4082.         {
  4083.             const bool bSweep = UpdatedPrimitive ? UpdatedPrimitive->bGenerateOverlapEvents : false;
  4084.             FHitResult HitResult;
  4085.             SafeMoveUpdatedComponent(AdjustedDelta, UpdatedComponent->GetComponentQuat(), bSweep, HitResult);
  4086.         }
  4087.  
  4088.         // Update velocity to reflect actual move
  4089.         if (!bJustTeleported && !HasRootMotion())
  4090.         {
  4091.             Velocity = (GetActorFeetLocation() - OldLocation) / deltaTime;
  4092.             MaintainHorizontalGroundVelocity();
  4093.         }
  4094.  
  4095.         bJustTeleported = false;
  4096.     }
  4097.     else
  4098.     {
  4099.         StartFalling(Iterations, deltaTime, deltaTime, DeltaMove, OldLocation);
  4100.     }
  4101. }
  4102.  
  4103. bool UCharacterMovementComponent::FindNavFloor(const FVector& TestLocation, FNavLocation& NavFloorLocation) const
  4104. {
  4105.     const ANavigationData* NavData = GetNavData();
  4106.     if (NavData == nullptr)
  4107.     {
  4108.         return false;
  4109.     }
  4110.  
  4111.     INavAgentInterface* MyNavAgent = CastChecked<INavAgentInterface>(CharacterOwner);
  4112.     float SearchRadius = 0.0f;
  4113.     float SearchHeight = 100.0f;
  4114.     if (MyNavAgent)
  4115.     {
  4116.         const FNavAgentProperties& AgentProps = MyNavAgent->GetNavAgentPropertiesRef();
  4117.         SearchRadius = AgentProps.AgentRadius * 2.0f;
  4118.         SearchHeight = AgentProps.AgentHeight * AgentProps.NavWalkingSearchHeightScale;
  4119.     }
  4120.  
  4121.     NavData->ProjectPoint(TestLocation, NavFloorLocation, FVector(SearchRadius, SearchRadius, SearchHeight));
  4122.     return true;
  4123. }
  4124.  
  4125. FVector UCharacterMovementComponent::ProjectLocationFromNavMesh(float DeltaSeconds, const FVector& CurrentFeetLocation, const FVector& TargetNavLocation, float UpOffset, float DownOffset)
  4126. {
  4127.     SCOPE_CYCLE_COUNTER(STAT_CharNavProjectLocation);
  4128.  
  4129.     FVector NewLocation = TargetNavLocation;
  4130.  
  4131.     const float ZOffset = -(DownOffset + UpOffset);
  4132.     if (ZOffset > -SMALL_NUMBER)
  4133.     {
  4134.         return NewLocation;
  4135.     }
  4136.  
  4137.     const FVector TraceStart = FVector(TargetNavLocation.X, TargetNavLocation.Y, TargetNavLocation.Z + UpOffset);
  4138.     const FVector TraceEnd   = FVector(TargetNavLocation.X, TargetNavLocation.Y, TargetNavLocation.Z - DownOffset);
  4139.  
  4140.     // We can skip this trace if we are checking at the same location as the last trace (ie, we haven't moved).
  4141.     const bool bCachedLocationStillValid = (CachedProjectedNavMeshHitResult.bBlockingHit &&
  4142.         CachedProjectedNavMeshHitResult.TraceStart == TraceStart &&
  4143.         CachedProjectedNavMeshHitResult.TraceEnd == TraceEnd);
  4144.  
  4145.     NavMeshProjectionTimer -= DeltaSeconds;
  4146.     if (NavMeshProjectionTimer <= 0.0f)
  4147.     {
  4148.         if (!bCachedLocationStillValid || bAlwaysCheckFloor)
  4149.         {
  4150.             UE_LOG(LogNavMeshMovement, VeryVerbose, TEXT("ProjectLocationFromNavMesh(): %s interval: %.3f velocity: %s"), *GetNameSafe(CharacterOwner), NavMeshProjectionInterval, *Velocity.ToString());
  4151.  
  4152.             // raycast to underlying mesh to allow us to more closely follow geometry
  4153.             // we use static objects here as a best approximation to accept only objects that
  4154.             // influence navmesh generation
  4155.             FCollisionQueryParams Params(CharacterMovementComponentStatics::ProjectLocationName, false);
  4156.             FCollisionResponseParams ResponseParams(ECR_Ignore); // ignore everything
  4157.             ResponseParams.CollisionResponse.SetResponse(ECC_WorldStatic, ECR_Block); // get blocked only by WorldStatic
  4158.             GetWorld()->LineTraceSingleByChannel(CachedProjectedNavMeshHitResult, TraceStart, TraceEnd, ECC_WorldStatic, Params, ResponseParams);
  4159.  
  4160.             // discard result if we were already inside something
  4161.             if (CachedProjectedNavMeshHitResult.bStartPenetrating)
  4162.             {
  4163.                 CachedProjectedNavMeshHitResult.Reset();
  4164.             }
  4165.         }
  4166.         else
  4167.         {
  4168.             UE_LOG(LogNavMeshMovement, VeryVerbose, TEXT("ProjectLocationFromNavMesh(): %s interval: %.3f velocity: %s [SKIP TRACE]"), *GetNameSafe(CharacterOwner), NavMeshProjectionInterval, *Velocity.ToString());
  4169.         }
  4170.  
  4171.         // Wrap around to maintain same relative offset to tick time changes.
  4172.         // Prevents large framerate spikes from aligning multiple characters to the same frame (if they start staggered, they will now remain staggered).
  4173.         float ModTime = 0.f;
  4174.         if (NavMeshProjectionInterval > SMALL_NUMBER)
  4175.         {
  4176.             ModTime = FMath::Fmod(-NavMeshProjectionTimer, NavMeshProjectionInterval);
  4177.         }
  4178.  
  4179.         NavMeshProjectionTimer = NavMeshProjectionInterval - ModTime;
  4180.     }
  4181.  
  4182.     // Project to last plane we found.
  4183.     if (CachedProjectedNavMeshHitResult.bBlockingHit)
  4184.     {
  4185.         if (bCachedLocationStillValid && FMath::IsNearlyEqual(CurrentFeetLocation.Z, CachedProjectedNavMeshHitResult.ImpactPoint.Z, 0.01f))
  4186.         {
  4187.             // Already at destination.
  4188.             NewLocation.Z = CurrentFeetLocation.Z;
  4189.         }
  4190.         else
  4191.         {
  4192.             //const FVector ProjectedPoint = FMath::LinePlaneIntersection(TraceStart, TraceEnd, CachedProjectedNavMeshHitResult.ImpactPoint, CachedProjectedNavMeshHitResult.Normal);
  4193.             //float ProjectedZ = ProjectedPoint.Z;
  4194.  
  4195.             // Optimized assuming we only care about Z coordinate of result.
  4196.             const FVector& PlaneOrigin = CachedProjectedNavMeshHitResult.ImpactPoint;
  4197.             const FVector& PlaneNormal = CachedProjectedNavMeshHitResult.Normal;
  4198.             float ProjectedZ = TraceStart.Z + ZOffset * (((PlaneOrigin - TraceStart)|PlaneNormal) / (ZOffset * PlaneNormal.Z));
  4199.  
  4200.             // Limit to not be too far above or below NavMesh location
  4201.             ProjectedZ = FMath::Clamp(ProjectedZ, TraceEnd.Z, TraceStart.Z);
  4202.  
  4203.             // Interp for smoother updates (less "pop" when trace hits something new). 0 interp speed is instant.
  4204.             const float InterpSpeed = FMath::Max(0.f, NavMeshProjectionInterpSpeed);
  4205.             ProjectedZ = FMath::FInterpTo(CurrentFeetLocation.Z, ProjectedZ, DeltaSeconds, InterpSpeed);
  4206.             ProjectedZ = FMath::Clamp(ProjectedZ, TraceEnd.Z, TraceStart.Z);
  4207.  
  4208.             // Final result
  4209.             NewLocation.Z = ProjectedZ;
  4210.         }
  4211.     }
  4212.  
  4213.     return NewLocation;
  4214. }
  4215.  
  4216.  
  4217. const ANavigationData* UCharacterMovementComponent::GetNavData() const
  4218. {
  4219.     UNavigationSystem* NavSys = UNavigationSystem::GetCurrent(GetWorld());
  4220.     if (NavSys == nullptr || !HasValidData())
  4221.     {
  4222.         return nullptr;
  4223.     }
  4224.  
  4225.     const ANavigationData* NavData = nullptr;
  4226.     INavAgentInterface* MyNavAgent = CastChecked<INavAgentInterface>(CharacterOwner);
  4227.     if (MyNavAgent)
  4228.     {
  4229.         const FNavAgentProperties& AgentProps = MyNavAgent->GetNavAgentPropertiesRef();
  4230.         NavData = NavSys->GetNavDataForProps(AgentProps);
  4231.     }
  4232.     if (NavData == nullptr)
  4233.     {
  4234.         NavData = NavSys->GetMainNavData();
  4235.     }
  4236.  
  4237.     // Only RecastNavMesh supported
  4238.     const ARecastNavMesh* NavMeshData = Cast<const ARecastNavMesh>(NavData);
  4239.     if (NavMeshData == nullptr)
  4240.     {
  4241.         return nullptr;
  4242.     }
  4243.  
  4244.     return NavData;
  4245. }
  4246.  
  4247.  
  4248. void UCharacterMovementComponent::PhysCustom(float deltaTime, int32 Iterations)
  4249. {
  4250.     if (CharacterOwner)
  4251.     {
  4252.         CharacterOwner->K2_UpdateCustomMovement(deltaTime);
  4253.     }
  4254. }
  4255.  
  4256.  
  4257. bool UCharacterMovementComponent::ShouldCatchAir(const FFindFloorResult& OldFloor, const FFindFloorResult& NewFloor)
  4258. {
  4259.     return false;
  4260. }
  4261.  
  4262. void UCharacterMovementComponent::AdjustFloorHeight()
  4263. {
  4264.     SCOPE_CYCLE_COUNTER(STAT_CharAdjustFloorHeight);
  4265.  
  4266.     // If we have a floor check that hasn't hit anything, don't adjust height.
  4267.     if (!CurrentFloor.bBlockingHit)
  4268.     {
  4269.         return;
  4270.     }
  4271.  
  4272.     const float OldFloorDist = CurrentFloor.FloorDist;
  4273.     if (CurrentFloor.bLineTrace && OldFloorDist < MIN_FLOOR_DIST)
  4274.     {
  4275.         // This would cause us to scale unwalkable walls
  4276.         return;
  4277.     }
  4278.  
  4279.     // Move up or down to maintain floor height.
  4280.     if (OldFloorDist < MIN_FLOOR_DIST || OldFloorDist > MAX_FLOOR_DIST)
  4281.     {
  4282.         FHitResult AdjustHit(1.f);
  4283.         const float AvgFloorDist = (MIN_FLOOR_DIST + MAX_FLOOR_DIST) * 0.5f;
  4284.         const float MoveDist = AvgFloorDist - OldFloorDist;
  4285.         const FVector CapsuleUp = GetCapsuleAxisZ();
  4286.         const FVector InitialLocation = UpdatedComponent->GetComponentLocation();
  4287.  
  4288.         SafeMoveUpdatedComponent(CapsuleUp * MoveDist, UpdatedComponent->GetComponentQuat(), true, AdjustHit);
  4289.         UE_LOG(LogCharacterMovement, VeryVerbose, TEXT("Adjust floor height %.3f (Hit = %d)"), MoveDist, AdjustHit.bBlockingHit);
  4290.  
  4291.         if (!AdjustHit.IsValidBlockingHit())
  4292.         {
  4293.             CurrentFloor.FloorDist += MoveDist;
  4294.         }
  4295.         else if (MoveDist > 0.0f)
  4296.         {
  4297.             CurrentFloor.FloorDist += (InitialLocation - UpdatedComponent->GetComponentLocation()) | CapsuleUp;
  4298.         }
  4299.         else
  4300.         {
  4301.             checkSlow(MoveDist < 0.0f);
  4302.  
  4303.             CurrentFloor.FloorDist = (AdjustHit.Location - UpdatedComponent->GetComponentLocation()) | CapsuleUp;
  4304.             if (IsWalkable(AdjustHit))
  4305.             {
  4306.                 CurrentFloor.SetFromSweep(AdjustHit, CurrentFloor.FloorDist, true);
  4307.             }
  4308.         }
  4309.  
  4310.         // Don't recalculate velocity based on this height adjustment, if considering vertical adjustments.
  4311.         // Also avoid it if we moved out of penetration.
  4312.         bJustTeleported |= !bMaintainHorizontalGroundVelocity || OldFloorDist < 0.0f;
  4313.     }
  4314. }
  4315.  
  4316.  
  4317. void UCharacterMovementComponent::StopActiveMovement()
  4318. {
  4319.     Super::StopActiveMovement();
  4320.  
  4321.     Acceleration = FVector::ZeroVector;
  4322.     bHasRequestedVelocity = false;
  4323.     RequestedVelocity = FVector::ZeroVector;
  4324. }
  4325.  
  4326. void UCharacterMovementComponent::ProcessLanded(const FHitResult& Hit, float remainingTime, int32 Iterations)
  4327. {
  4328.     if (CharacterOwner && CharacterOwner->ShouldNotifyLanded(Hit))
  4329.     {
  4330.         CharacterOwner->Landed(Hit);
  4331.     }
  4332.     if (IsFalling())
  4333.     {
  4334.         if (GroundMovementMode == MOVE_NavWalking)
  4335.         {
  4336.             // verify navmesh projection and current floor
  4337.             // otherwise movement will be stuck in infinite loop:
  4338.             // navwalking -> (no navmesh) -> falling -> (standing on something) -> navwalking -> ....
  4339.  
  4340.             const FVector TestLocation = GetActorFeetLocation();
  4341.             FNavLocation NavLocation;
  4342.  
  4343.             const bool bHasNavigationData = FindNavFloor(TestLocation, NavLocation);
  4344.             if (!bHasNavigationData || NavLocation.NodeRef == INVALID_NAVNODEREF)
  4345.             {
  4346.                 GroundMovementMode = MOVE_Walking;
  4347.                 UE_LOG(LogNavMeshMovement, Verbose, TEXT("ProcessLanded(): %s tried to go to NavWalking but couldn't find NavMesh! Using Walking instead."), *GetNameSafe(CharacterOwner));
  4348.             }
  4349.         }
  4350.  
  4351.         SetPostLandedPhysics(Hit);
  4352.     }
  4353.     if (PathFollowingComp.IsValid())
  4354.     {
  4355.         PathFollowingComp->OnLanded();
  4356.     }
  4357.  
  4358.     StartNewPhysics(remainingTime, Iterations);
  4359. }
  4360.  
  4361. void UCharacterMovementComponent::SetPostLandedPhysics(const FHitResult& Hit)
  4362. {
  4363.     if (CharacterOwner)
  4364.     {
  4365.         if (GetPhysicsVolume()->bWaterVolume && CanEverSwim())
  4366.         {
  4367.             SetMovementMode(MOVE_Swimming);
  4368.         }
  4369.         else
  4370.         {
  4371.             const FVector PreImpactAccel = Acceleration + (IsFalling() ? GetGravity() : FVector::ZeroVector);
  4372.             const FVector PreImpactVelocity = Velocity;
  4373.  
  4374.             if (DefaultLandMovementMode == MOVE_Walking ||
  4375.                 DefaultLandMovementMode == MOVE_NavWalking ||
  4376.                 DefaultLandMovementMode == MOVE_Falling)
  4377.             {
  4378.                 SetMovementMode(GroundMovementMode);
  4379.             }
  4380.             else
  4381.             {
  4382.                 SetDefaultMovementMode();
  4383.             }
  4384.  
  4385.             ApplyImpactPhysicsForces(Hit, PreImpactAccel, PreImpactVelocity);
  4386.         }
  4387.     }
  4388. }
  4389.  
  4390. void UCharacterMovementComponent::SetNavWalkingPhysics(bool bEnable)
  4391. {
  4392.     if (UpdatedPrimitive)
  4393.     {
  4394.         if (bEnable)
  4395.         {
  4396.             UpdatedPrimitive->SetCollisionResponseToChannel(ECC_WorldStatic, ECR_Ignore);
  4397.             UpdatedPrimitive->SetCollisionResponseToChannel(ECC_WorldDynamic, ECR_Ignore);
  4398.             CachedProjectedNavMeshHitResult.Reset();
  4399.  
  4400.             // Stagger timed updates so many different characters spawned at the same time don't update on the same frame.
  4401.             // Initially we want an immediate update though, so set time to a negative randomized range.
  4402.             NavMeshProjectionTimer = (NavMeshProjectionInterval > 0.f) ? FMath::FRandRange(-NavMeshProjectionInterval, 0.f) : 0.f;
  4403.         }
  4404.         else
  4405.         {
  4406.             UPrimitiveComponent* DefaultCapsule = nullptr;
  4407.             if (CharacterOwner && CharacterOwner->GetCapsuleComponent() == UpdatedComponent)
  4408.             {
  4409.                 ACharacter* DefaultCharacter = CharacterOwner->GetClass()->GetDefaultObject<ACharacter>();
  4410.                 DefaultCapsule = DefaultCharacter ? DefaultCharacter->GetCapsuleComponent() : nullptr;
  4411.             }
  4412.  
  4413.             if (DefaultCapsule)
  4414.             {
  4415.                 UpdatedPrimitive->SetCollisionResponseToChannel(ECC_WorldStatic, DefaultCapsule->GetCollisionResponseToChannel(ECC_WorldStatic));
  4416.                 UpdatedPrimitive->SetCollisionResponseToChannel(ECC_WorldDynamic, DefaultCapsule->GetCollisionResponseToChannel(ECC_WorldDynamic));
  4417.             }
  4418.             else
  4419.             {
  4420.                 UE_LOG(LogCharacterMovement, Warning, TEXT("Can't revert NavWalking collision settings for %s.%s"),
  4421.                     *GetNameSafe(CharacterOwner), *GetNameSafe(UpdatedComponent));
  4422.             }
  4423.         }
  4424.     }
  4425. }
  4426.  
  4427. bool UCharacterMovementComponent::TryToLeaveNavWalking()
  4428. {
  4429.     SetNavWalkingPhysics(false);
  4430.  
  4431.     bool bCanTeleport = true;
  4432.     if (CharacterOwner)
  4433.     {
  4434.         FVector CollisionFreeLocation = UpdatedComponent->GetComponentLocation();
  4435.         bCanTeleport = GetWorld()->FindTeleportSpot(CharacterOwner, CollisionFreeLocation, UpdatedComponent->GetComponentRotation());
  4436.         if (bCanTeleport)
  4437.         {
  4438.             CharacterOwner->SetActorLocation(CollisionFreeLocation);
  4439.         }
  4440.         else
  4441.         {
  4442.             SetNavWalkingPhysics(true);
  4443.         }
  4444.     }
  4445.  
  4446.     bWantsToLeaveNavWalking = !bCanTeleport;
  4447.     return bCanTeleport;
  4448. }
  4449.  
  4450. void UCharacterMovementComponent::OnTeleported()
  4451. {
  4452.     bJustTeleported = true;
  4453.     if (!HasValidData())
  4454.     {
  4455.         return;
  4456.     }
  4457.  
  4458.     // Find floor at current location
  4459.     UpdateFloorFromAdjustment();
  4460.     SaveBaseLocation();
  4461.  
  4462.     // Validate it. We don't want to pop down to walking mode from very high off the ground, but we'd like to keep walking if possible.
  4463.     UPrimitiveComponent* OldBase = CharacterOwner->GetMovementBase();
  4464.     UPrimitiveComponent* NewBase = NULL;
  4465.  
  4466.     if (OldBase && CurrentFloor.IsWalkableFloor() && CurrentFloor.FloorDist <= MAX_FLOOR_DIST && (Velocity | GetCapsuleAxisZ()) <= 0.0f)
  4467.     {
  4468.         // Close enough to land or just keep walking.
  4469.         NewBase = CurrentFloor.HitResult.Component.Get();
  4470.     }
  4471.     else
  4472.     {
  4473.         CurrentFloor.Clear();
  4474.     }
  4475.  
  4476.     // If we were walking but no longer have a valid base or floor, start falling.
  4477.     if (!CurrentFloor.IsWalkableFloor() || (OldBase && !NewBase))
  4478.     {
  4479.         if (DefaultLandMovementMode == MOVE_Walking)
  4480.         {
  4481.             SetMovementMode(MOVE_Falling);
  4482.         }
  4483.         else
  4484.         {
  4485.             SetDefaultMovementMode();
  4486.         }
  4487.     }
  4488. }
  4489.  
  4490.  
  4491. /** Internal. */
  4492. FVector CharAngularVelocity(FRotator const& OldRot, FRotator const& NewRot, float DeltaTime)
  4493. {
  4494.     FVector RetAngVel(0.f);
  4495.  
  4496.     if (OldRot != NewRot)
  4497.     {
  4498.         float const InvDeltaTime = 1.f / DeltaTime;
  4499.         FQuat const DeltaQRot = (NewRot - OldRot).Quaternion();
  4500.  
  4501.         FVector Axis;
  4502.         float Angle;
  4503.         DeltaQRot.ToAxisAndAngle(Axis, Angle);
  4504.  
  4505.         RetAngVel = Axis * Angle * InvDeltaTime;
  4506.         check(!RetAngVel.ContainsNaN());
  4507.     }
  4508.  
  4509.     return RetAngVel;
  4510. }
  4511.  
  4512. FRotator UCharacterMovementComponent::GetDeltaRotation(float DeltaTime) const
  4513. {
  4514.     return (RotationRate * DeltaTime);
  4515. }
  4516.  
  4517. FRotator UCharacterMovementComponent::ComputeOrientToMovementRotation(const FRotator& CurrentRotation, float DeltaTime, FRotator& DeltaRotation) const
  4518. {
  4519.     if (Acceleration.SizeSquared() < KINDA_SMALL_NUMBER)
  4520.     {
  4521.         // AI path following request can orient us in that direction (it's effectively an acceleration)
  4522.         if (bHasRequestedVelocity && RequestedVelocity.SizeSquared() > KINDA_SMALL_NUMBER)
  4523.         {
  4524.             return RequestedVelocity.GetSafeNormal().Rotation();
  4525.         }
  4526.  
  4527.         // Don't change rotation if there is no acceleration.
  4528.         return CurrentRotation;
  4529.     }
  4530.  
  4531.     // Rotate toward direction of acceleration.
  4532.     return Acceleration.GetSafeNormal().Rotation();
  4533. }
  4534.  
  4535. void UCharacterMovementComponent::PhysicsRotation(float DeltaTime)
  4536. {
  4537.     if (!(bOrientRotationToMovement || bUseControllerDesiredRotation))
  4538.     {
  4539.         return;
  4540.     }
  4541.  
  4542.     if (!HasValidData() || (!CharacterOwner->Controller && !bRunPhysicsWithNoController))
  4543.     {
  4544.         return;
  4545.     }
  4546.  
  4547.     const FRotator CurrentRotation = UpdatedComponent->GetComponentRotation(); // Normalized
  4548.     FRotator DeltaRot = GetDeltaRotation(DeltaTime);
  4549.     FRotator DesiredRotation = CurrentRotation;
  4550.  
  4551.     if (bOrientRotationToMovement)
  4552.     {
  4553.         DesiredRotation = ComputeOrientToMovementRotation(CurrentRotation, DeltaTime, DeltaRot);
  4554.     }
  4555.     else if (CharacterOwner->Controller && bUseControllerDesiredRotation)
  4556.     {
  4557.         DesiredRotation = CharacterOwner->Controller->GetDesiredRotation();
  4558.     }
  4559.     else
  4560.     {
  4561.         return;
  4562.     }
  4563.  
  4564.     // Always remain vertical when walking or falling.
  4565.     if (IsMovingOnGround() || IsFalling())
  4566.     {
  4567.         DesiredRotation.Pitch = 0.f;
  4568.         DesiredRotation.Yaw = FRotator::NormalizeAxis(DesiredRotation.Yaw);
  4569.         DesiredRotation.Roll = 0.f;
  4570.     }
  4571.     else
  4572.     {
  4573.         DesiredRotation.Normalize();
  4574.     }
  4575.  
  4576.     // Accumulate a desired new rotation.
  4577.     const float AngleTolerance = 1e-3f;
  4578.  
  4579.     if (!CurrentRotation.Equals(DesiredRotation, AngleTolerance))
  4580.     {
  4581.         // PITCH
  4582.         if (!FMath::IsNearlyEqual(CurrentRotation.Pitch, DesiredRotation.Pitch, AngleTolerance))
  4583.         {
  4584.             DesiredRotation.Pitch = FMath::FixedTurn(CurrentRotation.Pitch, DesiredRotation.Pitch, DeltaRot.Pitch);
  4585.         }
  4586.  
  4587.         // YAW
  4588.         if (!FMath::IsNearlyEqual(CurrentRotation.Yaw, DesiredRotation.Yaw, AngleTolerance))
  4589.         {
  4590.             DesiredRotation.Yaw = FMath::FixedTurn(CurrentRotation.Yaw, DesiredRotation.Yaw, DeltaRot.Yaw);
  4591.         }
  4592.  
  4593.         // ROLL
  4594.         if (!FMath::IsNearlyEqual(CurrentRotation.Roll, DesiredRotation.Roll, AngleTolerance))
  4595.         {
  4596.             DesiredRotation.Roll = FMath::FixedTurn(CurrentRotation.Roll, DesiredRotation.Roll, DeltaRot.Roll);
  4597.         }
  4598.  
  4599.         // Set the new rotation.
  4600.         MoveUpdatedComponent( FVector::ZeroVector, DesiredRotation, true );
  4601.     }
  4602. }
  4603.  
  4604.  
  4605. void UCharacterMovementComponent::PhysicsVolumeChanged(APhysicsVolume* NewVolume)
  4606. {
  4607.     if (!HasValidData())
  4608.     {
  4609.         return;
  4610.     }
  4611.  
  4612.     if (NewVolume && NewVolume->bWaterVolume)
  4613.     {
  4614.         // Just entered water.
  4615.         if (!CanEverSwim())
  4616.         {
  4617.             // AI needs to stop any current moves.
  4618.             if (PathFollowingComp.IsValid())
  4619.             {
  4620.                 PathFollowingComp->AbortMove(TEXT("water"));
  4621.             }
  4622.         }
  4623.         else if (!IsSwimming())
  4624.         {
  4625.             SetMovementMode(MOVE_Swimming);
  4626.         }
  4627.     }
  4628.     else if (IsSwimming())
  4629.     {
  4630.  
  4631.         SetMovementMode(MOVE_Falling);
  4632.  
  4633.         // Just left the water, check if should jump out.
  4634.         const FVector GravityDir = GetGravityDirection(true);
  4635.         FVector JumpDir = FVector::ZeroVector;
  4636.         FVector WallNormal = FVector::ZeroVector;
  4637.  
  4638.         if ((Acceleration | GravityDir) < 0.0f && ShouldJumpOutOfWater(JumpDir, GravityDir) && (JumpDir | Acceleration) > 0.0f && CheckWaterJump(JumpDir, GravityDir, WallNormal))
  4639.         {
  4640.             JumpOutOfWater(WallNormal);
  4641.             Velocity = FVector::VectorPlaneProject(Velocity, GravityDir) - GravityDir * OutofWaterZ; // Set here so physics uses this for remainder of tick.
  4642.         }
  4643.     }
  4644. }
  4645.  
  4646.  
  4647. bool UCharacterMovementComponent::ShouldJumpOutOfWater(FVector& JumpDir, const FVector& GravDir)
  4648. {
  4649.     // If pawn is going up and looking up, then make it jump.
  4650.     AController* OwnerController = CharacterOwner->GetController();
  4651.     if (OwnerController && (Velocity | GravDir) < 0.0f)
  4652.     {
  4653.         const FVector ControllerDir = OwnerController->GetControlRotation().Vector();
  4654.         if ((ControllerDir | GravDir) < FMath::Cos(FMath::DegreesToRadians(JumpOutOfWaterPitch + 90.0f)))
  4655.         {
  4656.             JumpDir = ControllerDir;
  4657.             return true;
  4658.         }
  4659.     }
  4660.  
  4661.     return false;
  4662. }
  4663.  
  4664.  
  4665. void UCharacterMovementComponent::JumpOutOfWater(const FVector& WallNormal) {}
  4666.  
  4667.  
  4668. bool UCharacterMovementComponent::CheckWaterJump(const FVector& JumpDir, const FVector& GravDir, FVector& WallNormal) const
  4669. {
  4670.     if (!HasValidData())
  4671.     {
  4672.         return false;
  4673.     }
  4674.  
  4675.     // Check if there is a wall directly in front of the swimming pawn.
  4676.     float PawnCapsuleRadius, PawnCapsuleHalfHeight;
  4677.     CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleSize(PawnCapsuleRadius, PawnCapsuleHalfHeight);
  4678.     FVector CheckPoint = UpdatedComponent->GetComponentLocation() + FVector::VectorPlaneProject(JumpDir, GravDir).GetSafeNormal() * (PawnCapsuleRadius * 1.2f);
  4679.     FCollisionQueryParams CapsuleParams(CharacterMovementComponentStatics::CheckWaterJumpName, false, CharacterOwner);
  4680.     const FCollisionShape CapsuleShape = GetPawnCapsuleCollisionShape(SHRINK_None);
  4681.     const ECollisionChannel CollisionChannel = UpdatedComponent->GetCollisionObjectType();
  4682.     FCollisionResponseParams ResponseParam;
  4683.     InitCollisionParams(CapsuleParams, ResponseParam);
  4684.  
  4685.     FHitResult HitInfo(1.0f);
  4686.     bool bHit = GetWorld()->SweepSingleByChannel(HitInfo, UpdatedComponent->GetComponentLocation(), CheckPoint, GetCapsuleRotation(), CollisionChannel, CapsuleShape, CapsuleParams, ResponseParam);
  4687.  
  4688.     if (bHit && !Cast<APawn>(HitInfo.GetActor()))
  4689.     {
  4690.         // Hit a wall, check if it's low enough.
  4691.         WallNormal = HitInfo.ImpactNormal * -1.0f;
  4692.         const FVector Start = UpdatedComponent->GetComponentLocation() + GravDir * -MaxOutOfWaterStepHeight;
  4693.         CheckPoint = Start + WallNormal * (PawnCapsuleRadius * 3.2f);
  4694.  
  4695.         FCollisionQueryParams LineParams(CharacterMovementComponentStatics::CheckWaterJumpName, true, CharacterOwner);
  4696.         FCollisionResponseParams LineResponseParam;
  4697.         InitCollisionParams(LineParams, LineResponseParam);
  4698.         HitInfo.Reset(1.0f, false);
  4699.         bHit = GetWorld()->LineTraceSingleByChannel(HitInfo, Start, CheckPoint, CollisionChannel, LineParams, LineResponseParam);
  4700.  
  4701.         // If no high obstruction, or it's a valid floor, then pawn can jump out of water.
  4702.         return !bHit || IsWalkable(HitInfo);
  4703.     }
  4704.  
  4705.     return false;
  4706. }
  4707.  
  4708. void UCharacterMovementComponent::AddImpulse(FVector Impulse, bool bVelocityChange)
  4709. {
  4710.     if (HasValidData() && !Impulse.IsZero())
  4711.     {
  4712.         // handle scaling by mass
  4713.         FVector FinalImpulse = Impulse;
  4714.         if (!bVelocityChange)
  4715.         {
  4716.             if (Mass > SMALL_NUMBER)
  4717.             {
  4718.                 FinalImpulse = FinalImpulse / Mass;
  4719.             }
  4720.             else
  4721.             {
  4722.                 UE_LOG(LogCharacterMovement, Warning, TEXT("Attempt to apply impulse to zero or negative Mass in CharacterMovement"));
  4723.             }
  4724.         }
  4725.  
  4726.         PendingImpulseToApply += FinalImpulse;
  4727.     }
  4728. }
  4729.  
  4730. void UCharacterMovementComponent::AddForce(FVector Force)
  4731. {
  4732.     if (HasValidData() && !Force.IsZero())
  4733.     {
  4734.         if (Mass > SMALL_NUMBER)
  4735.         {
  4736.             PendingForceToApply += Force / Mass;
  4737.         }
  4738.         else
  4739.         {
  4740.             UE_LOG(LogCharacterMovement, Warning, TEXT("Attempt to apply force to zero or negative Mass in CharacterMovement"));
  4741.         }
  4742.     }
  4743. }
  4744.  
  4745. void UCharacterMovementComponent::MoveSmooth(const FVector& InVelocity, const float DeltaSeconds, FStepDownResult* OutStepDownResult)
  4746. {
  4747.     if (!HasValidData())
  4748.     {
  4749.         return;
  4750.     }
  4751.  
  4752.     // Custom movement mode.
  4753.     // Custom movement may need an update even if there is zero velocity.
  4754.     if (MovementMode == MOVE_Custom)
  4755.     {
  4756.         FScopedMovementUpdate ScopedMovementUpdate(UpdatedComponent, bEnableScopedMovementUpdates ? EScopedUpdate::DeferredUpdates : EScopedUpdate::ImmediateUpdates);
  4757.         PhysCustom(DeltaSeconds, 0);
  4758.         return;
  4759.     }
  4760.  
  4761.     FVector Delta = InVelocity * DeltaSeconds;
  4762.     if (Delta.IsZero())
  4763.     {
  4764.         return;
  4765.     }
  4766.  
  4767.     FScopedMovementUpdate ScopedMovementUpdate(UpdatedComponent, bEnableScopedMovementUpdates ? EScopedUpdate::DeferredUpdates : EScopedUpdate::ImmediateUpdates);
  4768.  
  4769.     if (IsMovingOnGround())
  4770.     {
  4771.         MoveAlongFloor(InVelocity, DeltaSeconds, OutStepDownResult);
  4772.     }
  4773.     else
  4774.     {
  4775.         FHitResult Hit(1.0f);
  4776.         SafeMoveUpdatedComponent(Delta, UpdatedComponent->GetComponentQuat(), true, Hit);
  4777.  
  4778.         if (Hit.IsValidBlockingHit())
  4779.         {
  4780.             bool bSteppedUp = false;
  4781.  
  4782.             if (IsFlying())
  4783.             {
  4784.                 if (CanStepUp(Hit))
  4785.                 {
  4786.                     OutStepDownResult = NULL; // No need for a floor when not walking.
  4787.                     const FVector CapsuleDown = GetCapsuleAxisZ() * -1.0f;
  4788.  
  4789.                     if (FMath::Abs(Hit.ImpactNormal | CapsuleDown) < 0.2f)
  4790.                     {
  4791.                         const float UpDown = CapsuleDown | Delta.GetSafeNormal();
  4792.                         if (UpDown < 0.5f && UpDown > -0.2f)
  4793.                         {
  4794.                             bSteppedUp = StepUp(CapsuleDown, Delta * (1.0f - Hit.Time), Hit, OutStepDownResult);
  4795.                         }
  4796.                     }
  4797.                 }
  4798.             }
  4799.  
  4800.             // If StepUp failed, try sliding.
  4801.             if (!bSteppedUp)
  4802.             {
  4803.                 SlideAlongSurface(Delta, 1.0f - Hit.Time, Hit.Normal, Hit, false);
  4804.             }
  4805.         }
  4806.     }
  4807. }
  4808.  
  4809.  
  4810. bool UCharacterMovementComponent::IsWalkable(const FHitResult& Hit) const
  4811. {
  4812.     if (!Hit.IsValidBlockingHit())
  4813.     {
  4814.         // No hit, or starting in penetration.
  4815.         return false;
  4816.     }
  4817.  
  4818.     float TestWalkableZ = GetWalkableFloorZ();
  4819.  
  4820.     // See if this component overrides the walkable floor z.
  4821.     const UPrimitiveComponent* HitComponent = Hit.Component.Get();
  4822.     if (HitComponent)
  4823.     {
  4824.         const FWalkableSlopeOverride& SlopeOverride = HitComponent->GetWalkableSlopeOverride();
  4825.         TestWalkableZ = SlopeOverride.ModifyWalkableFloorZ(TestWalkableZ);
  4826.     }
  4827.  
  4828.     // Can't walk on this surface if it is too steep.
  4829.     if ((Hit.ImpactNormal | GetCapsuleAxisZ()) < TestWalkableZ)
  4830.     {
  4831.         return false;
  4832.     }
  4833.  
  4834.     return true;
  4835. }
  4836.  
  4837. void UCharacterMovementComponent::SetWalkableFloorAngle(float InWalkableFloorAngle)
  4838. {
  4839.     WalkableFloorAngle = FMath::Clamp(InWalkableFloorAngle, 0.f, 90.0f);
  4840.     WalkableFloorZ = FMath::Cos(FMath::DegreesToRadians(WalkableFloorAngle));
  4841. }
  4842.  
  4843. void UCharacterMovementComponent::SetWalkableFloorZ(float InWalkableFloorZ)
  4844. {
  4845.     WalkableFloorZ = FMath::Clamp(InWalkableFloorZ, 0.f, 1.f);
  4846.     WalkableFloorAngle = FMath::RadiansToDegrees(FMath::Acos(WalkableFloorZ));
  4847. }
  4848.  
  4849. float UCharacterMovementComponent::K2_GetWalkableFloorAngle() const
  4850. {
  4851.     return GetWalkableFloorAngle();
  4852. }
  4853.  
  4854. float UCharacterMovementComponent::K2_GetWalkableFloorZ() const
  4855. {
  4856.     return GetWalkableFloorZ();
  4857. }
  4858.  
  4859.  
  4860.  
  4861. bool UCharacterMovementComponent::IsWithinEdgeTolerance(const FVector& CapsuleLocation, const FVector& CapsuleDown, const FVector& TestImpactPoint, const float CapsuleRadius) const
  4862. {
  4863.     const float DistFromCenterSq = (CapsuleLocation + CapsuleDown * ((TestImpactPoint - CapsuleLocation) | CapsuleDown) - TestImpactPoint).SizeSquared();
  4864.     const float ReducedRadiusSq = FMath::Square(FMath::Max(KINDA_SMALL_NUMBER, CapsuleRadius - SWEEP_EDGE_REJECT_DISTANCE));
  4865.     return DistFromCenterSq < ReducedRadiusSq;
  4866. }
  4867.  
  4868.  
  4869. void UCharacterMovementComponent::ComputeFloorDist(const FVector& CapsuleLocation, float LineDistance, float SweepDistance, FFindFloorResult& OutFloorResult, float SweepRadius, const FHitResult* DownwardSweepResult) const
  4870. {
  4871.     OutFloorResult.Clear();
  4872.  
  4873.     // No collision, no floor...
  4874.     if (!UpdatedComponent->IsCollisionEnabled())
  4875.     {
  4876.         return;
  4877.     }
  4878.  
  4879.     float PawnRadius, PawnHalfHeight;
  4880.     CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleSize(PawnRadius, PawnHalfHeight);
  4881.  
  4882.     const FVector CapsuleDown = GetCapsuleAxisZ() * -1.0f;
  4883.  
  4884.     bool bSkipSweep = false;
  4885.     if (DownwardSweepResult != NULL && DownwardSweepResult->IsValidBlockingHit())
  4886.     {
  4887.         const float Dot = CapsuleDown | ((DownwardSweepResult->TraceEnd - DownwardSweepResult->TraceStart).GetSafeNormal());
  4888.  
  4889.         // Only if the supplied sweep was vertical and downward.
  4890.         if (Dot >= THRESH_NORMALS_ARE_PARALLEL)
  4891.         {
  4892.             // Reject hits that are barely on the cusp of the radius of the capsule.
  4893.             if (IsWithinEdgeTolerance(DownwardSweepResult->Location, CapsuleDown, DownwardSweepResult->ImpactPoint, PawnRadius))
  4894.             {
  4895.                 // Don't try a redundant sweep, regardless of whether this sweep is usable.
  4896.                 bSkipSweep = true;
  4897.  
  4898.                 const bool bIsWalkable = IsWalkable(*DownwardSweepResult);
  4899.                 const float FloorDist = (CapsuleLocation - DownwardSweepResult->Location).Size();
  4900.                 OutFloorResult.SetFromSweep(*DownwardSweepResult, FloorDist, bIsWalkable);
  4901.  
  4902.                 if (bIsWalkable)
  4903.                 {
  4904.                     // Use the supplied downward sweep as the floor hit result.
  4905.                     return;
  4906.                 }
  4907.             }
  4908.         }
  4909.     }
  4910.  
  4911.     // We require the sweep distance to be >= the line distance, otherwise the HitResult can't be interpreted as the sweep result.
  4912.     if (SweepDistance < LineDistance)
  4913.     {
  4914.         check(SweepDistance >= LineDistance);
  4915.         return;
  4916.     }
  4917.  
  4918.     bool bBlockingHit = false;
  4919.     FCollisionQueryParams QueryParams(NAME_None, false, CharacterOwner);
  4920.     FCollisionResponseParams ResponseParam;
  4921.     InitCollisionParams(QueryParams, ResponseParam);
  4922.     const ECollisionChannel CollisionChannel = UpdatedComponent->GetCollisionObjectType();
  4923.  
  4924.     // Sweep test.
  4925.     if (!bSkipSweep && SweepDistance > 0.0f && SweepRadius > 0.0f)
  4926.     {
  4927.         // Use a shorter height to avoid sweeps giving weird results if we start on a surface.
  4928.         // This also allows us to adjust out of penetrations.
  4929.         const float ShrinkScale = 0.9f;
  4930.         const float ShrinkScaleOverlap = 0.1f;
  4931.         float ShrinkHeight = (PawnHalfHeight - PawnRadius) * (1.0f - ShrinkScale);
  4932.         float TraceDist = SweepDistance + ShrinkHeight;
  4933.         QueryParams.TraceTag = CharacterMovementComponentStatics::ComputeFloorDistName;
  4934.         FCollisionShape CapsuleShape = FCollisionShape::MakeCapsule(SweepRadius, PawnHalfHeight - ShrinkHeight);
  4935.  
  4936.         FHitResult Hit(1.f);
  4937.         bBlockingHit = FloorSweepTest(Hit, CapsuleLocation, CapsuleLocation + CapsuleDown * TraceDist, CollisionChannel, CapsuleShape, QueryParams, ResponseParam);
  4938.  
  4939.         if (bBlockingHit)
  4940.         {
  4941.             // Reject hits adjacent to us, we only care about hits on the bottom portion of our capsule.
  4942.             // Check 2D distance to impact point, reject if within a tolerance from radius.
  4943.             if (Hit.bStartPenetrating || !IsWithinEdgeTolerance(CapsuleLocation, CapsuleDown, Hit.ImpactPoint, CapsuleShape.Capsule.Radius))
  4944.             {
  4945.                 // Use a capsule with a slightly smaller radius and shorter height to avoid the adjacent object.
  4946.                 ShrinkHeight = (PawnHalfHeight - PawnRadius) * (1.0f - ShrinkScaleOverlap);
  4947.                 TraceDist = SweepDistance + ShrinkHeight;
  4948.                 CapsuleShape.Capsule.Radius = FMath::Max(0.0f, CapsuleShape.Capsule.Radius - SWEEP_EDGE_REJECT_DISTANCE - KINDA_SMALL_NUMBER);
  4949.                 CapsuleShape.Capsule.HalfHeight = FMath::Max(PawnHalfHeight - ShrinkHeight, CapsuleShape.Capsule.Radius);
  4950.                 Hit.Reset(1.0f, false);
  4951.  
  4952.                 bBlockingHit = FloorSweepTest(Hit, CapsuleLocation, CapsuleLocation + CapsuleDown * TraceDist, CollisionChannel, CapsuleShape, QueryParams, ResponseParam);
  4953.             }
  4954.  
  4955.             // Reduce hit distance by ShrinkHeight because we shrank the capsule for the trace.
  4956.             // We allow negative distances here, because this allows us to pull out of penetrations.
  4957.             const float MaxPenetrationAdjust = FMath::Max(MAX_FLOOR_DIST, PawnRadius);
  4958.             const float SweepResult = FMath::Max(-MaxPenetrationAdjust, Hit.Time * TraceDist - ShrinkHeight);
  4959.  
  4960.             OutFloorResult.SetFromSweep(Hit, SweepResult, false);
  4961.             if (Hit.IsValidBlockingHit() && IsWalkable(Hit) && SweepResult <= SweepDistance)
  4962.             {
  4963.                 // Hit within test distance.
  4964.                 OutFloorResult.bWalkableFloor = true;
  4965.                 return;
  4966.             }
  4967.         }
  4968.     }
  4969.  
  4970.     // Since we require a longer sweep than line trace, we don't want to run the line trace if the sweep missed everything.
  4971.     // We do however want to try a line trace if the sweep was stuck in penetration.
  4972.     if (!OutFloorResult.bBlockingHit && !OutFloorResult.HitResult.bStartPenetrating)
  4973.     {
  4974.         OutFloorResult.FloorDist = SweepDistance;
  4975.         return;
  4976.     }
  4977.  
  4978.     // Line trace.
  4979.     if (LineDistance > 0.0f)
  4980.     {
  4981.         const float ShrinkHeight = PawnHalfHeight;
  4982.         const FVector LineTraceStart = CapsuleLocation;
  4983.         const float TraceDist = LineDistance + ShrinkHeight;
  4984.  
  4985.         QueryParams.TraceTag = CharacterMovementComponentStatics::FloorLineTraceName;
  4986.  
  4987.         FHitResult Hit(1.0f);
  4988.         bBlockingHit = GetWorld()->LineTraceSingleByChannel(Hit, LineTraceStart, LineTraceStart + CapsuleDown * TraceDist,
  4989.             CollisionChannel, QueryParams, ResponseParam);
  4990.  
  4991.         if (bBlockingHit && Hit.Time > 0.0f)
  4992.         {
  4993.             // Reduce hit distance by ShrinkHeight because we started the trace higher than the base.
  4994.             // We allow negative distances here, because this allows us to pull out of penetrations.
  4995.             const float MaxPenetrationAdjust = FMath::Max(MAX_FLOOR_DIST, PawnRadius);
  4996.             const float LineResult = FMath::Max(-MaxPenetrationAdjust, Hit.Time * TraceDist - ShrinkHeight);
  4997.  
  4998.             OutFloorResult.bBlockingHit = true;
  4999.             if (LineResult <= LineDistance && IsWalkable(Hit))
  5000.             {
  5001.                 OutFloorResult.SetFromLineTrace(Hit, OutFloorResult.FloorDist, LineResult, true);
  5002.                 return;
  5003.             }
  5004.         }
  5005.     }
  5006.  
  5007.     // No hits were acceptable.
  5008.     OutFloorResult.bWalkableFloor = false;
  5009.     OutFloorResult.FloorDist = SweepDistance;
  5010. }
  5011.  
  5012.  
  5013. void UCharacterMovementComponent::FindFloor(const FVector& CapsuleLocation, FFindFloorResult& OutFloorResult, bool bZeroDelta, const FHitResult* DownwardSweepResult) const
  5014. {
  5015.     SCOPE_CYCLE_COUNTER(STAT_CharFindFloor);
  5016.  
  5017.     // No collision, no floor...
  5018.     if (!HasValidData() || !UpdatedComponent->IsCollisionEnabled())
  5019.     {
  5020.         OutFloorResult.Clear();
  5021.         return;
  5022.     }
  5023.  
  5024.     check(CharacterOwner->GetCapsuleComponent());
  5025.  
  5026.     // Increase height check slightly if walking, to prevent floor height adjustment from later invalidating the floor result.
  5027.     const float HeightCheckAdjust = (IsMovingOnGround() ? MAX_FLOOR_DIST + KINDA_SMALL_NUMBER : -MAX_FLOOR_DIST);
  5028.  
  5029.     float FloorSweepTraceDist = FMath::Max(MAX_FLOOR_DIST, MaxStepHeight + HeightCheckAdjust);
  5030.     float FloorLineTraceDist = FloorSweepTraceDist;
  5031.     bool bNeedToValidateFloor = true;
  5032.  
  5033.     // Sweep floor
  5034.     if (FloorLineTraceDist > 0.f || FloorSweepTraceDist > 0.f)
  5035.     {
  5036.         UCharacterMovementComponent* MutableThis = const_cast<UCharacterMovementComponent*>(this);
  5037.  
  5038.         if (bAlwaysCheckFloor || !bZeroDelta || bForceNextFloorCheck || bJustTeleported)
  5039.         {
  5040.             MutableThis->bForceNextFloorCheck = false;
  5041.             ComputeFloorDist(CapsuleLocation, FloorLineTraceDist, FloorSweepTraceDist, OutFloorResult, CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleRadius(), DownwardSweepResult);
  5042.         }
  5043.         else
  5044.         {
  5045.             // Force floor check if base has collision disabled or if it does not block us.
  5046.             UPrimitiveComponent* MovementBase = CharacterOwner->GetMovementBase();
  5047.             const AActor* BaseActor = MovementBase ? MovementBase->GetOwner() : NULL;
  5048.             const ECollisionChannel CollisionChannel = UpdatedComponent->GetCollisionObjectType();
  5049.  
  5050.             if (MovementBase != NULL)
  5051.             {
  5052.                 MutableThis->bForceNextFloorCheck = !MovementBase->IsCollisionEnabled()
  5053.                     || MovementBase->GetCollisionResponseToChannel(CollisionChannel) != ECR_Block
  5054.                     || MovementBaseUtility::IsDynamicBase(MovementBase);
  5055.             }
  5056.  
  5057.             const bool IsActorBasePendingKill = BaseActor && BaseActor->IsPendingKill();
  5058.  
  5059.             if (!bForceNextFloorCheck && !IsActorBasePendingKill && MovementBase)
  5060.             {
  5061.                 //UE_LOG(LogCharacterMovement, Log, TEXT("%s SKIP check for floor"), *CharacterOwner->GetName());
  5062.                 OutFloorResult = CurrentFloor;
  5063.                 bNeedToValidateFloor = false;
  5064.             }
  5065.             else
  5066.             {
  5067.                 MutableThis->bForceNextFloorCheck = false;
  5068.                 ComputeFloorDist(CapsuleLocation, FloorLineTraceDist, FloorSweepTraceDist, OutFloorResult, CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleRadius(), DownwardSweepResult);
  5069.             }
  5070.         }
  5071.     }
  5072.  
  5073.     // OutFloorResult.HitResult is now the result of the vertical floor check.
  5074.     // See if we should try to "perch" at this location.
  5075.     if (bNeedToValidateFloor && OutFloorResult.bBlockingHit && !OutFloorResult.bLineTrace)
  5076.     {
  5077.         const bool bCheckRadius = true;
  5078.         if (ShouldComputePerchResult(OutFloorResult.HitResult, bCheckRadius))
  5079.         {
  5080.             float MaxPerchFloorDist = FMath::Max(MAX_FLOOR_DIST, MaxStepHeight + HeightCheckAdjust);
  5081.             if (IsMovingOnGround())
  5082.             {
  5083.                 MaxPerchFloorDist += FMath::Max(0.f, PerchAdditionalHeight);
  5084.             }
  5085.  
  5086.             FFindFloorResult PerchFloorResult;
  5087.             if (ComputePerchResult(GetValidPerchRadius(), OutFloorResult.HitResult, MaxPerchFloorDist, PerchFloorResult))
  5088.             {
  5089.                 // Don't allow the floor distance adjustment to push us up too high, or we will move beyond the perch distance and fall next time.
  5090.                 const float AvgFloorDist = (MIN_FLOOR_DIST + MAX_FLOOR_DIST) * 0.5f;
  5091.                 const float MoveUpDist = (AvgFloorDist - OutFloorResult.FloorDist);
  5092.                 if (MoveUpDist + PerchFloorResult.FloorDist >= MaxPerchFloorDist)
  5093.                 {
  5094.                     OutFloorResult.FloorDist = AvgFloorDist;
  5095.                 }
  5096.  
  5097.                 // If the regular capsule is on an unwalkable surface but the perched one would allow us to stand, override the normal to be one that is walkable.
  5098.                 if (!OutFloorResult.bWalkableFloor)
  5099.                 {
  5100.                     OutFloorResult.SetFromLineTrace(PerchFloorResult.HitResult, OutFloorResult.FloorDist, FMath::Min(PerchFloorResult.FloorDist, PerchFloorResult.LineDist), true);
  5101.                 }
  5102.             }
  5103.             else
  5104.             {
  5105.                 // We had no floor (or an invalid one because it was unwalkable), and couldn't perch here, so invalidate floor (which will cause us to start falling).
  5106.                 OutFloorResult.bWalkableFloor = false;
  5107.             }
  5108.         }
  5109.     }
  5110. }
  5111.  
  5112.  
  5113. bool UCharacterMovementComponent::FloorSweepTest(FHitResult& OutHit, const FVector& Start, const FVector& End, ECollisionChannel TraceChannel,
  5114.     const FCollisionShape& CollisionShape, const FCollisionQueryParams& Params, const FCollisionResponseParams& ResponseParam) const
  5115. {
  5116.     const bool bBlockingHit = GetWorld()->SweepSingleByChannel(OutHit, Start, End, GetCapsuleRotation(), TraceChannel, CollisionShape, Params, ResponseParam);
  5117.  
  5118.     if (bBlockingHit && bUseFlatBaseForFloorChecks)
  5119.     {
  5120.         FHitResult Hit(1.0f);
  5121.         const FVector SweepAxis = (End - Start).GetSafeNormal();
  5122.         const float SweepSize = (End - Start).Size();
  5123.  
  5124.         // Search for floor gaps.
  5125.         if (!GetWorld()->LineTraceSingleByChannel(Hit, Start, Start + SweepAxis * (SweepSize + CollisionShape.GetCapsuleHalfHeight()), TraceChannel, Params, ResponseParam))
  5126.         {
  5127.             // Get the intersection point of the sweep axis and the impact plane.
  5128.             const FVector IntersectionPoint = FMath::LinePlaneIntersection(Start, End, OutHit.ImpactPoint, OutHit.ImpactNormal);
  5129.  
  5130.             // Calculate the new 'time' of impact along the sweep axis direction.
  5131.             const float NewTime = (IntersectionPoint + SweepAxis * (CollisionShape.GetCapsuleHalfHeight() * -1.0f) - Start).Size() / SweepSize;
  5132.  
  5133.             // Always keep the lowest 'time'.
  5134.             OutHit.Time = FMath::Min(OutHit.Time, NewTime);
  5135.         }
  5136.     }
  5137.  
  5138.     return bBlockingHit;
  5139. }
  5140.  
  5141.  
  5142. bool UCharacterMovementComponent::IsValidLandingSpot(const FVector& CapsuleLocation, const FHitResult& Hit) const
  5143. {
  5144.     if (!Hit.bBlockingHit)
  5145.     {
  5146.         return false;
  5147.     }
  5148.  
  5149.     const FVector CapsuleDown = GetCapsuleAxisZ() * -1.0f;
  5150.  
  5151.     // Skip some checks if penetrating. Penetration will be handled by the FindFloor call (using a smaller capsule).
  5152.     if (!Hit.bStartPenetrating)
  5153.     {
  5154.         // Reject unwalkable floor normals.
  5155.         if (!IsWalkable(Hit))
  5156.         {
  5157.             return false;
  5158.         }
  5159.  
  5160.         float PawnRadius, PawnHalfHeight;
  5161.         CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleSize(PawnRadius, PawnHalfHeight);
  5162.  
  5163.         // Get the axis of the capsule bounded by the following two end points.
  5164.         const FVector BottomPoint = Hit.Location + CapsuleDown * FMath::Max(0.0f, PawnHalfHeight - PawnRadius);
  5165.         const FVector TopPoint = Hit.Location - CapsuleDown;
  5166.         const FVector Segment = TopPoint - BottomPoint;
  5167.  
  5168.         // Project the impact point on the segment.
  5169.         const float Alpha = ((Hit.ImpactPoint - BottomPoint) | Segment) / Segment.SizeSquared();
  5170.  
  5171.         // Reject hits that are above our lower hemisphere (can happen when sliding "down" a vertical surface).
  5172.         if (Alpha >= 0.0f)
  5173.         {
  5174.             return false;
  5175.         }
  5176.  
  5177.         // Reject hits that are barely on the cusp of the radius of the capsule.
  5178.         if (!IsWithinEdgeTolerance(Hit.Location, CapsuleDown, Hit.ImpactPoint, PawnRadius))
  5179.         {
  5180.             return false;
  5181.         }
  5182.     }
  5183.     else
  5184.     {
  5185.         // Penetrating.
  5186.         if ((Hit.Normal | CapsuleDown) > -KINDA_SMALL_NUMBER)
  5187.         {
  5188.             // Normal is nearly horizontal or downward, that's a penetration adjustment next to a vertical or overhanging wall. Don't pop to the floor.
  5189.             return false;
  5190.         }
  5191.     }
  5192.  
  5193.     FFindFloorResult FloorResult;
  5194.     FindFloor(CapsuleLocation, FloorResult, false, &Hit);
  5195.  
  5196.     // Reject invalid surfaces.
  5197.     if (!FloorResult.IsWalkableFloor())
  5198.     {
  5199.         return false;
  5200.     }
  5201.  
  5202.     return true;
  5203. }
  5204.  
  5205.  
  5206. bool UCharacterMovementComponent::ShouldCheckForValidLandingSpot(float DeltaTime, const FVector& Delta, const FHitResult& Hit) const
  5207. {
  5208.     const FVector CapsuleUp = GetCapsuleAxisZ();
  5209.  
  5210.     // See if we hit an edge of a surface on the lower portion of the capsule.
  5211.     // In this case the normal will not equal the impact normal, and a downward sweep may find a walkable surface on top of the edge.
  5212.     if ((Hit.Normal | CapsuleUp) > KINDA_SMALL_NUMBER && !Hit.Normal.Equals(Hit.ImpactNormal) &&
  5213.         IsWithinEdgeTolerance(UpdatedComponent->GetComponentLocation(), CapsuleUp * -1.0f, Hit.ImpactPoint, CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleRadius()))
  5214.     {
  5215.         return true;
  5216.     }
  5217.  
  5218.     return false;
  5219. }
  5220.  
  5221.  
  5222. float UCharacterMovementComponent::GetPerchRadiusThreshold() const
  5223. {
  5224.     // Don't allow negative values.
  5225.     return FMath::Max(0.f, PerchRadiusThreshold);
  5226. }
  5227.  
  5228.  
  5229. float UCharacterMovementComponent::GetValidPerchRadius() const
  5230. {
  5231.     if (CharacterOwner)
  5232.     {
  5233.         const float PawnRadius = CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleRadius();
  5234.         return FMath::Clamp(PawnRadius - GetPerchRadiusThreshold(), 0.1f, PawnRadius);
  5235.     }
  5236.     return 0.f;
  5237. }
  5238.  
  5239.  
  5240. bool UCharacterMovementComponent::ShouldComputePerchResult(const FHitResult& InHit, bool bCheckRadius) const
  5241. {
  5242.     if (!InHit.IsValidBlockingHit())
  5243.     {
  5244.         return false;
  5245.     }
  5246.  
  5247.     // Don't try to perch if the edge radius is very small.
  5248.     if (GetPerchRadiusThreshold() <= SWEEP_EDGE_REJECT_DISTANCE)
  5249.     {
  5250.         return false;
  5251.     }
  5252.  
  5253.     if (bCheckRadius)
  5254.     {
  5255.         const FVector CapsuleDown = GetCapsuleAxisZ() * -1.0f;
  5256.         const float DistFromCenterSq = (InHit.Location + CapsuleDown * ((InHit.ImpactPoint - InHit.Location) | CapsuleDown) - InHit.ImpactPoint).SizeSquared();
  5257.         const float StandOnEdgeRadiusSq = FMath::Square(GetValidPerchRadius());
  5258.         if (DistFromCenterSq <= StandOnEdgeRadiusSq)
  5259.         {
  5260.             // Already within perch radius.
  5261.             return false;
  5262.         }
  5263.     }
  5264.  
  5265.     return true;
  5266. }
  5267.  
  5268.  
  5269. bool UCharacterMovementComponent::ComputePerchResult(const float TestRadius, const FHitResult& InHit, const float InMaxFloorDist, FFindFloorResult& OutPerchFloorResult) const
  5270. {
  5271.     if (InMaxFloorDist <= 0.0f)
  5272.     {
  5273.         return 0.0f;
  5274.     }
  5275.  
  5276.     // Sweep further than actual requested distance, because a reduced capsule radius means we could miss some hits that the normal radius would contact.
  5277.     float PawnRadius, PawnHalfHeight;
  5278.     CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleSize(PawnRadius, PawnHalfHeight);
  5279.  
  5280.     const FVector CapsuleDown = GetCapsuleAxisZ() * -1.0f;
  5281.     const float InHitAboveBase = (InHit.Location + CapsuleDown * ((InHit.ImpactPoint - InHit.Location) | CapsuleDown) -
  5282.         (InHit.Location + CapsuleDown * PawnHalfHeight)).Size();
  5283.     const float PerchLineDist = FMath::Max(0.0f, InMaxFloorDist - InHitAboveBase);
  5284.     const float PerchSweepDist = FMath::Max(0.0f, InMaxFloorDist);
  5285.  
  5286.     const float ActualSweepDist = PerchSweepDist + PawnRadius;
  5287.     ComputeFloorDist(InHit.Location, PerchLineDist, ActualSweepDist, OutPerchFloorResult, TestRadius);
  5288.  
  5289.     if (!OutPerchFloorResult.IsWalkableFloor())
  5290.     {
  5291.         return false;
  5292.     }
  5293.     else if (InHitAboveBase + OutPerchFloorResult.FloorDist > InMaxFloorDist)
  5294.     {
  5295.         // Hit something past max distance.
  5296.         OutPerchFloorResult.bWalkableFloor = false;
  5297.         return false;
  5298.     }
  5299.  
  5300.     return true;
  5301. }
  5302.  
  5303.  
  5304. bool UCharacterMovementComponent::CanStepUp(const FHitResult& Hit) const
  5305. {
  5306.     if (!Hit.IsValidBlockingHit() || !HasValidData() || MovementMode == MOVE_Falling)
  5307.     {
  5308.         return false;
  5309.     }
  5310.  
  5311.     // No component for "fake" hits when we are on a known good base.
  5312.     const UPrimitiveComponent* HitComponent = Hit.Component.Get();
  5313.     if (!HitComponent)
  5314.     {
  5315.         return true;
  5316.     }
  5317.  
  5318.     if (!HitComponent->CanCharacterStepUp(CharacterOwner))
  5319.     {
  5320.         return false;
  5321.     }
  5322.  
  5323.     // No actor for "fake" hits when we are on a known good base.
  5324.     const AActor* HitActor = Hit.GetActor();
  5325.     if (!HitActor)
  5326.     {
  5327.         return true;
  5328.     }
  5329.  
  5330.     if (!HitActor->CanBeBaseForCharacter(CharacterOwner))
  5331.     {
  5332.         return false;
  5333.     }
  5334.  
  5335.     return true;
  5336. }
  5337.  
  5338.  
  5339. bool UCharacterMovementComponent::StepUp(const FVector& GravDir, const FVector& Delta, const FHitResult& Hit, FStepDownResult* OutStepDownResult)
  5340. {
  5341.     SCOPE_CYCLE_COUNTER(STAT_CharStepUp);
  5342.  
  5343.     if (MaxStepHeight <= 0.0f || !CanStepUp(Hit))
  5344.     {
  5345.         return false;
  5346.     }
  5347.  
  5348.     const FVector OldLocation = UpdatedComponent->GetComponentLocation();
  5349.     float PawnRadius, PawnHalfHeight;
  5350.     CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleSize(PawnRadius, PawnHalfHeight);
  5351.  
  5352.     const FVector CapsuleDown = GetCapsuleAxisZ() * -1.0f;
  5353.  
  5354.     // Get the axis of the capsule bounded by the following two end points.
  5355.     const FVector BottomPoint = OldLocation + CapsuleDown * PawnHalfHeight;
  5356.     const FVector TopPoint = OldLocation - CapsuleDown * FMath::Max(0.0f, PawnHalfHeight - PawnRadius);
  5357.     const FVector Segment = TopPoint - BottomPoint;
  5358.  
  5359.     // Project the impact point on the segment.
  5360.     const float Alpha = ((Hit.ImpactPoint - BottomPoint) | Segment) / Segment.SizeSquared();
  5361.  
  5362.     // Don't bother stepping up if top of capsule is hitting something or if the impact is below us.
  5363.     if (Alpha > 1.0f || Alpha <= 0.0f)
  5364.     {
  5365.         return false;
  5366.     }
  5367.  
  5368.     const float StepSideZ = (Hit.ImpactNormal | GravDir) * -1.0f;
  5369.     float StepTravelUpHeight = MaxStepHeight;
  5370.     float StepTravelDownHeight = StepTravelUpHeight;
  5371.     FVector PawnInitialFloorBase = OldLocation + CapsuleDown * PawnHalfHeight;
  5372.     FVector PawnFloorPoint = PawnInitialFloorBase;
  5373.  
  5374.     if (IsMovingOnGround() && CurrentFloor.IsWalkableFloor())
  5375.     {
  5376.         // Since we float a variable amount off the floor, we need to enforce max step height off the actual point of impact with the floor.
  5377.         const float FloorDist = FMath::Max(0.0f, CurrentFloor.FloorDist);
  5378.         PawnInitialFloorBase += CapsuleDown * FloorDist;
  5379.         StepTravelUpHeight = FMath::Max(StepTravelUpHeight - FloorDist, 0.0f);
  5380.         StepTravelDownHeight = (MaxStepHeight + MAX_FLOOR_DIST * 2.0f);
  5381.  
  5382.         const bool bHitVerticalFace = !IsWithinEdgeTolerance(Hit.Location, CapsuleDown, Hit.ImpactPoint, PawnRadius);
  5383.         if (!CurrentFloor.bLineTrace && !bHitVerticalFace)
  5384.         {
  5385.             PawnFloorPoint = CurrentFloor.HitResult.ImpactPoint;
  5386.         }
  5387.         else
  5388.         {
  5389.             // Base floor point is the base of the capsule moved down by how far we are hovering over the surface we are hitting.
  5390.             PawnFloorPoint += CapsuleDown * CurrentFloor.FloorDist;
  5391.         }
  5392.     }
  5393.  
  5394.     // Scope our movement updates, and do not apply them until all intermediate moves are completed.
  5395.     FScopedMovementUpdate ScopedStepUpMovement(UpdatedComponent, EScopedUpdate::DeferredUpdates);
  5396.  
  5397.     const FRotator PawnRotation = CharacterOwner->GetActorRotation();
  5398.  
  5399.     // Step up, treat as vertical wall.
  5400.     FHitResult SweepUpHit(1.0f);
  5401.     SafeMoveUpdatedComponent(GravDir * -StepTravelUpHeight, PawnRotation, true, SweepUpHit);
  5402.  
  5403.     // Step forward.
  5404.     FHitResult SweepHit(1.0f);
  5405.     SafeMoveUpdatedComponent(Delta, PawnRotation, true, SweepHit);
  5406.  
  5407.     // If we hit something above us and also something ahead of us, we should notify about the upward hit as well.
  5408.     // The forward hit will be handled later (in the bSteppedOver case below).
  5409.     // In the case of hitting something above but not forward, we are not blocked from moving so we don't need the notification.
  5410.     if (SweepUpHit.bBlockingHit && SweepHit.bBlockingHit)
  5411.     {
  5412.         HandleImpact(SweepUpHit);
  5413.     }
  5414.  
  5415.     // Check result of forward movement.
  5416.     if (SweepHit.bBlockingHit)
  5417.     {
  5418.         if (SweepHit.bStartPenetrating)
  5419.         {
  5420.             // Undo movement.
  5421.             ScopedStepUpMovement.RevertMove();
  5422.             return false;
  5423.         }
  5424.  
  5425.         // Pawn ran into a wall.
  5426.         HandleImpact(SweepHit);
  5427.         if (IsFalling())
  5428.         {
  5429.             return true;
  5430.         }
  5431.  
  5432.         // Adjust and try again.
  5433.         const float ForwardSweepFwdHitTime = SweepHit.Time;
  5434.         const float ForwardSlideAmount = SlideAlongSurface(Delta, 1.0f - SweepHit.Time, SweepHit.Normal, SweepHit, true);
  5435.  
  5436.         if (IsFalling())
  5437.         {
  5438.             ScopedStepUpMovement.RevertMove();
  5439.             return false;
  5440.         }
  5441.  
  5442.         // If both the forward SweepFwdHit and the deflection got us nowhere, there is no point in this step up.
  5443.         if (ForwardSweepFwdHitTime == 0.0f && ForwardSlideAmount == 0.0f)
  5444.         {
  5445.             ScopedStepUpMovement.RevertMove();
  5446.             return false;
  5447.         }
  5448.     }
  5449.  
  5450.     // Step down.
  5451.     SafeMoveUpdatedComponent(GravDir * StepTravelDownHeight, UpdatedComponent->GetComponentQuat(), true, SweepHit);
  5452.  
  5453.     // If step down was initially penetrating abort the step up.
  5454.     if (SweepHit.bStartPenetrating)
  5455.     {
  5456.         ScopedStepUpMovement.RevertMove();
  5457.         return false;
  5458.     }
  5459.  
  5460.     FStepDownResult StepDownResult;
  5461.     if (SweepHit.IsValidBlockingHit())
  5462.     {
  5463.         // See if this step sequence would have allowed us to travel higher than our max step height allows.
  5464.         const float DeltaZ = (PawnFloorPoint - SweepHit.ImpactPoint) | CapsuleDown;
  5465.         if (DeltaZ > MaxStepHeight)
  5466.         {
  5467.             ScopedStepUpMovement.RevertMove();
  5468.             return false;
  5469.         }
  5470.  
  5471.         // Reject unwalkable surface normals here.
  5472.         if (!IsWalkable(SweepHit))
  5473.         {
  5474.             // Reject if normal opposes movement direction.
  5475.             const bool bNormalTowardsMe = (Delta | SweepHit.ImpactNormal) < 0.0f;
  5476.             if (bNormalTowardsMe)
  5477.             {
  5478.                 ScopedStepUpMovement.RevertMove();
  5479.                 return false;
  5480.             }
  5481.  
  5482.             // Also reject if we would end up being higher than our starting location by stepping down.
  5483.             // It's fine to step down onto an unwalkable normal below us, we will just slide off. Rejecting those moves would prevent us from being able to walk off the edge.
  5484.             if (((OldLocation - SweepHit.Location) | CapsuleDown) > 0.0f)
  5485.             {
  5486.                 ScopedStepUpMovement.RevertMove();
  5487.                 return false;
  5488.             }
  5489.         }
  5490.  
  5491.         // Reject moves where the downward sweep hit something very close to the edge of the capsule. This maintains consistency with FindFloor as well.
  5492.         if (!IsWithinEdgeTolerance(SweepHit.Location, CapsuleDown, SweepHit.ImpactPoint, PawnRadius))
  5493.         {
  5494.             ScopedStepUpMovement.RevertMove();
  5495.             return false;
  5496.         }
  5497.  
  5498.         // Don't step up onto invalid surfaces if traveling higher.
  5499.         if (DeltaZ > 0.0f && !CanStepUp(SweepHit))
  5500.         {
  5501.             ScopedStepUpMovement.RevertMove();
  5502.             return false;
  5503.         }
  5504.  
  5505.         // See if we can validate the floor as a result of this step down. In almost all cases this should succeed, and we can avoid computing the floor outside this method.
  5506.         if (OutStepDownResult != NULL)
  5507.         {
  5508.             FindFloor(UpdatedComponent->GetComponentLocation(), StepDownResult.FloorResult, false, &SweepHit);
  5509.  
  5510.             // Reject unwalkable normals if we end up higher than our initial height.
  5511.             // It's fine to walk down onto an unwalkable surface, don't reject those moves.
  5512.             if (((OldLocation - SweepHit.Location) | CapsuleDown) > 0.0f)
  5513.             {
  5514.                 // We should reject the floor result if we are trying to step up an actual step where we are not able to perch (this is rare).
  5515.                 // In those cases we should instead abort the step up and try to slide along the stair.
  5516.                 if (!StepDownResult.FloorResult.bBlockingHit && StepSideZ < MAX_STEP_SIDE_Z)
  5517.                 {
  5518.                     ScopedStepUpMovement.RevertMove();
  5519.                     return false;
  5520.                 }
  5521.             }
  5522.  
  5523.             StepDownResult.bComputedFloor = true;
  5524.         }
  5525.     }
  5526.  
  5527.     // Copy step down result.
  5528.     if (OutStepDownResult != NULL)
  5529.     {
  5530.         *OutStepDownResult = StepDownResult;
  5531.     }
  5532.  
  5533.     // Don't recalculate velocity based on this height adjustment, if considering vertical adjustments.
  5534.     bJustTeleported |= !bMaintainHorizontalGroundVelocity;
  5535.  
  5536.     return true;
  5537. }
  5538.  
  5539. void UCharacterMovementComponent::HandleImpact(const FHitResult& Impact, float TimeSlice, const FVector& MoveDelta)
  5540. {
  5541.     if (CharacterOwner)
  5542.     {
  5543.         CharacterOwner->MoveBlockedBy(Impact);
  5544.     }
  5545.  
  5546.     if (PathFollowingComp.IsValid())
  5547.     {
  5548.         // Also notify path following!
  5549.         PathFollowingComp->OnMoveBlockedBy(Impact);
  5550.     }
  5551.  
  5552.     APawn* OtherPawn = Cast<APawn>(Impact.GetActor());
  5553.     if (OtherPawn)
  5554.     {
  5555.         NotifyBumpedPawn(OtherPawn);
  5556.     }
  5557.  
  5558.     if (bEnablePhysicsInteraction)
  5559.     {
  5560.         const FVector ForceAccel = Acceleration + (IsFalling() ? GetGravity() : FVector::ZeroVector);
  5561.         ApplyImpactPhysicsForces(Impact, ForceAccel, Velocity);
  5562.     }
  5563. }
  5564.  
  5565. void UCharacterMovementComponent::ApplyImpactPhysicsForces(const FHitResult& Impact, const FVector& ImpactAcceleration, const FVector& ImpactVelocity)
  5566. {
  5567.     if (bEnablePhysicsInteraction && Impact.bBlockingHit)
  5568.     {
  5569.         UPrimitiveComponent* ImpactComponent = Impact.GetComponent();
  5570.         if (ImpactComponent != NULL && ImpactComponent->IsAnySimulatingPhysics())
  5571.         {
  5572.             FVector ForcePoint = Impact.ImpactPoint;
  5573.             FBodyInstance* BI = ImpactComponent->GetBodyInstance(Impact.BoneName);
  5574.             float BodyMass = 1.0f;
  5575.  
  5576.             if (BI != NULL)
  5577.             {
  5578.                 BodyMass = FMath::Max(BI->GetBodyMass(), 1.0f);
  5579.  
  5580.                 FVector Center, Extents;
  5581.                 BI->GetBodyBounds().GetCenterAndExtents(Center, Extents);
  5582.  
  5583.                 if (!Extents.IsNearlyZero())
  5584.                 {
  5585.                     const FVector CapsuleUp = GetCapsuleAxisZ();
  5586.  
  5587.                     // Project impact point onto the horizontal plane defined by center and gravity, then offset from there.
  5588.                     ForcePoint = FVector::PointPlaneProject(ForcePoint, Center, CapsuleUp) +
  5589.                         CapsuleUp * (FMath::Abs(Extents | CapsuleUp) * PushForcePointZOffsetFactor);
  5590.                 }
  5591.             }
  5592.  
  5593.             FVector Force = Impact.ImpactNormal * -1.0f;
  5594.             float PushForceModificator = 1.0f;
  5595.             const FVector ComponentVelocity = ImpactComponent->GetPhysicsLinearVelocity();
  5596.             const FVector VirtualVelocity = ImpactAcceleration.IsZero() ? ImpactVelocity : ImpactAcceleration.GetSafeNormal() * GetMaxSpeed();
  5597.             float Dot = 0.0f;
  5598.  
  5599.             if (bScalePushForceToVelocity && !ComponentVelocity.IsNearlyZero())
  5600.             {
  5601.                 Dot = ComponentVelocity | VirtualVelocity;
  5602.  
  5603.                 if (Dot > 0.0f && Dot < 1.0f)
  5604.                 {
  5605.                     PushForceModificator *= Dot;
  5606.                 }
  5607.             }
  5608.  
  5609.             if (bPushForceScaledToMass)
  5610.             {
  5611.                 PushForceModificator *= BodyMass;
  5612.             }
  5613.  
  5614.             Force *= PushForceModificator;
  5615.  
  5616.             if (ComponentVelocity.IsNearlyZero())
  5617.             {
  5618.                 Force *= InitialPushForceFactor;
  5619.                 ImpactComponent->AddImpulseAtLocation(Force, ForcePoint, Impact.BoneName);
  5620.             }
  5621.             else
  5622.             {
  5623.                 Force *= PushForceFactor;
  5624.                 ImpactComponent->AddForceAtLocation(Force, ForcePoint, Impact.BoneName);
  5625.             }
  5626.         }
  5627.     }
  5628. }
  5629.  
  5630. FString UCharacterMovementComponent::GetMovementName() const
  5631. {
  5632.     if (CharacterOwner)
  5633.     {
  5634.         if (CharacterOwner->GetRootComponent() && CharacterOwner->GetRootComponent()->IsSimulatingPhysics())
  5635.         {
  5636.             return TEXT("Rigid Body");
  5637.         }
  5638.         else if (CharacterOwner->IsMatineeControlled())
  5639.         {
  5640.             return TEXT("Matinee");
  5641.         }
  5642.     }
  5643.  
  5644.     // Using character movement
  5645.     switch (MovementMode)
  5646.     {
  5647.     case MOVE_None:             return TEXT("NULL"); break;
  5648.     case MOVE_Walking:          return TEXT("Walking"); break;
  5649.     case MOVE_NavWalking:       return TEXT("NavWalking"); break;
  5650.     case MOVE_Falling:          return TEXT("Falling"); break;
  5651.     case MOVE_Swimming:         return TEXT("Swimming"); break;
  5652.     case MOVE_Flying:           return TEXT("Flying"); break;
  5653.     case MOVE_Custom:           return TEXT("Custom"); break;
  5654.     default:                    break;
  5655.     }
  5656.     return TEXT("Unknown");
  5657. }
  5658.  
  5659. void UCharacterMovementComponent::DisplayDebug(UCanvas* Canvas, const FDebugDisplayInfo& DebugDisplay, float& YL, float& YPos)
  5660. {
  5661.     if (CharacterOwner == NULL)
  5662.     {
  5663.         return;
  5664.     }
  5665.  
  5666.     const float XPos = 8.0f;
  5667.     UFont* RenderFont = GEngine->GetSmallFont();
  5668.     Canvas->SetDrawColor(255, 255, 255);
  5669.  
  5670.     FString Text = FString::Printf(TEXT("---------- CHARACTER MOVEMENT ----------"));
  5671.     YL = Canvas->DrawText(RenderFont, Text, XPos, YPos);
  5672.     YPos += YL;
  5673.  
  5674.     Text = FString::Printf(TEXT("Updated Component %s with radius %f and half-height %f"), *UpdatedPrimitive->GetName(),
  5675.         UpdatedPrimitive->GetCollisionShape().GetCapsuleRadius(), UpdatedPrimitive->GetCollisionShape().GetCapsuleHalfHeight());
  5676.     YL = Canvas->DrawText(RenderFont, Text, XPos, YPos);
  5677.     YPos += YL;
  5678.  
  5679.     Text = FString::Printf(TEXT("Floor %s   Crouching %s"), *CurrentFloor.HitResult.ImpactNormal.ToString(), IsCrouching() ? TEXT("True") : TEXT("False"));
  5680.     YL = Canvas->DrawText(RenderFont, Text, XPos, YPos);
  5681.     YPos += YL;
  5682.  
  5683.     const APhysicsVolume* PhysicsVolume = GetPhysicsVolume();
  5684.     const UPrimitiveComponent* BaseComponent = CharacterOwner->GetMovementBase();
  5685.     const AActor* BaseActor = BaseComponent ? BaseComponent->GetOwner() : NULL;
  5686.  
  5687.     Text = FString::Printf(TEXT("Physics %s in physicsVolume %s on base %s component %s gravity %s"), *GetMovementName(), (PhysicsVolume ? *PhysicsVolume->GetName() : TEXT("None")),
  5688.         (BaseActor ? *BaseActor->GetName() : TEXT("None")), (BaseComponent ? *BaseComponent->GetName() : TEXT("None")), *GetGravity().ToString());
  5689.     YL = Canvas->DrawText(RenderFont, Text, XPos, YPos);
  5690.     YPos += YL;
  5691.  
  5692.     Text = FString::Printf(TEXT("Rotation %s   AxisX %s   AxisZ %s"), *UpdatedComponent->GetComponentRotation().ToString(), *GetCapsuleAxisX().ToString(), *GetCapsuleAxisZ().ToString());
  5693.     YL = Canvas->DrawText(RenderFont, Text, XPos, YPos);
  5694.     YPos += YL;
  5695.  
  5696.     Text = FString::Printf(TEXT("Velocity %s   Speed %f   Speed2D %f   MaxSpeed %f"), *Velocity.ToString(), Velocity.Size(), Velocity.Size2D(), GetMaxSpeed());
  5697.     YL = Canvas->DrawText(RenderFont, Text, XPos, YPos);
  5698.     YPos += YL;
  5699.  
  5700.     Text = FString::Printf(TEXT("Acceleration %s   MaxAcceleration %f   bForceMaxAccel %s   AirControl %f"), *Acceleration.ToString(), GetMaxAcceleration(),
  5701.         bForceMaxAccel ? TEXT("True") : TEXT("False"), AirControl);
  5702.     YL = Canvas->DrawText(RenderFont, Text, XPos, YPos);
  5703.     YPos += YL;
  5704.  
  5705.     Text = FString::Printf(TEXT("----------------------------------------"));
  5706.     YL = Canvas->DrawText(RenderFont, Text, XPos, YPos);
  5707.     YPos += YL;
  5708. }
  5709.  
  5710. void UCharacterMovementComponent::VisualizeMovement() const
  5711. {
  5712.     if (CharacterOwner == nullptr)
  5713.     {
  5714.         return;
  5715.     }
  5716.  
  5717. #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
  5718.     const FVector TopOfCapsule = GetActorLocation() + FVector(0.f, 0.f, CharacterOwner->GetSimpleCollisionHalfHeight());
  5719.  
  5720.     // Velocity
  5721.     {
  5722.         const FColor DebugColor = FColor::Green;
  5723.         const FVector DebugLocation = TopOfCapsule;
  5724.         DrawDebugDirectionalArrow(GetWorld(), DebugLocation, DebugLocation + Velocity,
  5725.             100.f, DebugColor, false, -1.f, (uint8)'\000', 10.f);
  5726.  
  5727.         FString DebugText = FString::Printf(TEXT("Velocity: %s (Speed: %.2f)"), *Velocity.ToCompactString(), Velocity.Size());
  5728.         DrawDebugString(GetWorld(), DebugLocation + FVector(0.f, 0.f, 5.f), DebugText, nullptr, DebugColor, 0.f, true);
  5729.     }
  5730.  
  5731.     // Acceleration
  5732.     {
  5733.         const FColor DebugColor = FColor::Yellow;
  5734.         const float MaxAccelerationLineLength = 200.f;
  5735.         const float CurrentMaxAccel = GetMaxAcceleration();
  5736.         const float CurrentAccelAsPercentOfMaxAccel = CurrentMaxAccel > 0.f ? Acceleration.Size() / CurrentMaxAccel : 1.f;
  5737.         const FVector DebugLocation = TopOfCapsule + FVector(0.f, 0.f, 15.f);
  5738.         DrawDebugDirectionalArrow(GetWorld(), DebugLocation,
  5739.             DebugLocation + Acceleration.GetSafeNormal(SMALL_NUMBER) * CurrentAccelAsPercentOfMaxAccel * MaxAccelerationLineLength,
  5740.             25.f, DebugColor, false, -1.f, (uint8)'\000', 8.f);
  5741.  
  5742.         FString DebugText = FString::Printf(TEXT("Acceleration: %s"), *Acceleration.ToCompactString());
  5743.         DrawDebugString(GetWorld(), DebugLocation + FVector(0.f, 0.f, 5.f), DebugText, nullptr, DebugColor, 0.f, true);
  5744.     }
  5745.  
  5746.     // Movement Mode
  5747.     {
  5748.         const FColor DebugColor = FColor::Blue;
  5749.         const FVector DebugLocation = TopOfCapsule + FVector(0.f, 0.f, 35.f);
  5750.         FString DebugText = FString::Printf(TEXT("MovementMode: %s"), *GetMovementName());
  5751.         DrawDebugString(GetWorld(), DebugLocation, DebugText, nullptr, DebugColor, 0.f, true);
  5752.     }
  5753. #endif // !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
  5754. }
  5755.  
  5756. void UCharacterMovementComponent::ForceReplicationUpdate()
  5757. {
  5758.     if (HasPredictionData_Server())
  5759.     {
  5760.         GetPredictionData_Server_Character()->LastUpdateTime = GetWorld()->TimeSeconds - 10.f;
  5761.     }
  5762. }
  5763.  
  5764.  
  5765. FVector UCharacterMovementComponent::ConstrainInputAcceleration(const FVector& InputAcceleration) const
  5766. {
  5767.     FVector NewAccel = InputAcceleration;
  5768.  
  5769.     // Walking or falling pawns ignore up/down sliding.
  5770.     if (IsMovingOnGround() || IsFalling())
  5771.     {
  5772.         NewAccel = FVector::VectorPlaneProject(NewAccel, GetCapsuleAxisZ());
  5773.     }
  5774.  
  5775.     return NewAccel;
  5776. }
  5777.  
  5778.  
  5779. FVector UCharacterMovementComponent::ScaleInputAcceleration(const FVector& InputAcceleration) const
  5780. {
  5781.     return GetMaxAcceleration() * InputAcceleration.GetClampedToMaxSize(1.0f);
  5782. }
  5783.  
  5784.  
  5785. FVector UCharacterMovementComponent::RoundAcceleration(FVector InAccel) const
  5786. {
  5787.     // Match FVector_NetQuantize10 (1 decimal place of precision).
  5788.     InAccel.X = FMath::RoundToFloat(InAccel.X * 10.f) / 10.f;
  5789.     InAccel.Y = FMath::RoundToFloat(InAccel.Y * 10.f) / 10.f;
  5790.     InAccel.Z = FMath::RoundToFloat(InAccel.Z * 10.f) / 10.f;
  5791.     return InAccel;
  5792. }
  5793.  
  5794.  
  5795. float UCharacterMovementComponent::ComputeAnalogInputModifier() const
  5796. {
  5797.     const float MaxAccel = GetMaxAcceleration();
  5798.     if (Acceleration.SizeSquared() > 0.f && MaxAccel > SMALL_NUMBER)
  5799.     {
  5800.         return FMath::Clamp(Acceleration.Size() / MaxAccel, 0.f, 1.f);
  5801.     }
  5802.  
  5803.     return 0.f;
  5804. }
  5805.  
  5806. float UCharacterMovementComponent::GetAnalogInputModifier() const
  5807. {
  5808.     return AnalogInputModifier;
  5809. }
  5810.  
  5811.  
  5812. float UCharacterMovementComponent::GetSimulationTimeStep(float RemainingTime, int32 Iterations) const
  5813. {
  5814.     if (RemainingTime > MaxSimulationTimeStep)
  5815.     {
  5816.         if (Iterations < MaxSimulationIterations)
  5817.         {
  5818.             // Subdivide moves to be no longer than MaxSimulationTimeStep seconds
  5819.             RemainingTime = FMath::Min(MaxSimulationTimeStep, RemainingTime * 0.5f);
  5820.         }
  5821.         else
  5822.         {
  5823.             // If this is the last iteration, just use all the remaining time. This is usually better than cutting things short, as the simulation won't move far enough otherwise.
  5824.             // Print a throttled warning.
  5825. #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
  5826.             static uint32 s_WarningCount = 0;
  5827.             if ((s_WarningCount++ < 100) || (GFrameCounter & 15) == 0)
  5828.             {
  5829.                 UE_LOG(LogCharacterMovement, Warning, TEXT("GetSimulationTimeStep() - Max iterations %d hit while remaining time %.6f > MaxSimulationTimeStep (%.3f) for '%s'"), MaxSimulationIterations, RemainingTime, MaxSimulationTimeStep, *GetNameSafe(CharacterOwner));
  5830.             }
  5831. #endif
  5832.         }
  5833.     }
  5834.  
  5835.     // no less than MIN_TICK_TIME (to avoid potential divide-by-zero during simulation).
  5836.     return FMath::Max(MIN_TICK_TIME, RemainingTime);
  5837. }
  5838.  
  5839.  
  5840. void UCharacterMovementComponent::SmoothCorrection(const FVector& OldLocation, const FQuat& OldRotation)
  5841. {
  5842.     if (!HasValidData() || GetNetMode() != NM_Client)
  5843.     {
  5844.         return;
  5845.     }
  5846.  
  5847.     FNetworkPredictionData_Client_Character* ClientData = GetPredictionData_Client_Character();
  5848.     if (ClientData && ClientData->bSmoothNetUpdates)
  5849.     {
  5850.         if (!ClientData->bUseLinearSmoothing && GetWorld() && GetWorld()->DemoNetDriver && GetWorld()->DemoNetDriver->ServerConnection)
  5851.         {
  5852.             ClientData->bUseLinearSmoothing = true;
  5853.  
  5854.             // Really large since we want to smooth most of the time during playback
  5855.             // We do however want to compensate for large deltas (like teleporting, etc)
  5856.             ClientData->MaxSmoothNetUpdateDist  = 512.0f;
  5857.             ClientData->NoSmoothNetUpdateDist   = 512.0f;
  5858.         }
  5859.  
  5860.         float DistSq = (OldLocation - UpdatedComponent->GetComponentLocation()).SizeSquared();
  5861.         if (DistSq > FMath::Square(ClientData->MaxSmoothNetUpdateDist))
  5862.         {
  5863.             ClientData->MeshTranslationOffset = (DistSq > FMath::Square(ClientData->NoSmoothNetUpdateDist))
  5864.                 ? FVector::ZeroVector
  5865.                 : ClientData->MeshTranslationOffset + ClientData->MaxSmoothNetUpdateDist * (OldLocation - UpdatedComponent->GetComponentLocation()).GetSafeNormal();
  5866.         }
  5867.         else
  5868.         {
  5869.             ClientData->MeshTranslationOffset = ClientData->MeshTranslationOffset + OldLocation - UpdatedComponent->GetComponentLocation();
  5870.         }
  5871.  
  5872.         // Take difference between where we were rotated before, and where we're going
  5873.         ClientData->MeshRotationOffset = (UpdatedComponent->GetComponentQuat().Inverse() * OldRotation) * ClientData->MeshRotationOffset;
  5874.  
  5875.         if (ClientData->bUseLinearSmoothing)
  5876.         {
  5877.             ClientData->OriginalMeshTranslationOffset   = ClientData->MeshTranslationOffset;
  5878.             ClientData->OriginalMeshRotationOffset      = ClientData->MeshRotationOffset;
  5879.             ClientData->LastCorrectionDelta             = ClientData->CurrentSmoothTime;
  5880.             ClientData->CurrentSmoothTime               = 0;
  5881.         }
  5882.     }
  5883. }
  5884.  
  5885.  
  5886. void UCharacterMovementComponent::SmoothClientPosition(float DeltaSeconds)
  5887. {
  5888.     SCOPE_CYCLE_COUNTER(STAT_CharacterMovementSmoothClientPosition);
  5889.     if (!HasValidData() || GetNetMode() != NM_Client)
  5890.     {
  5891.         return;
  5892.     }
  5893.  
  5894.     FNetworkPredictionData_Client_Character* ClientData = GetPredictionData_Client_Character();
  5895.     if (ClientData && ClientData->bSmoothNetUpdates && CharacterOwner->GetMesh() && !CharacterOwner->GetMesh()->IsSimulatingPhysics())
  5896.     {
  5897.         if (ClientData->bUseLinearSmoothing)
  5898.         {
  5899.             ClientData->CurrentSmoothTime += DeltaSeconds;
  5900.  
  5901.             if (ClientData->LastCorrectionDelta < SMALL_NUMBER || ClientData->CurrentSmoothTime >= ClientData->LastCorrectionDelta)
  5902.             {
  5903.                 // This is either:
  5904.                 //  1. The very first update
  5905.                 //  2. Time between updates was really small
  5906.                 //  3. We've arrived at the target position
  5907.                 ClientData->MeshTranslationOffset   = FVector::ZeroVector;
  5908.                 ClientData->MeshRotationOffset      = FQuat::Identity;
  5909.             }
  5910.             else
  5911.             {
  5912.                 // Linearly interpolate between correction updates
  5913.                 const float LerpPercent = ClientData->CurrentSmoothTime / ClientData->LastCorrectionDelta;
  5914.  
  5915.                 ClientData->MeshTranslationOffset   = FMath::Lerp( ClientData->OriginalMeshTranslationOffset, FVector::ZeroVector, LerpPercent );
  5916.                 ClientData->MeshRotationOffset      = FQuat::Slerp( ClientData->OriginalMeshRotationOffset, FQuat::Identity, LerpPercent );
  5917.             }
  5918.         }
  5919.         else
  5920.         {
  5921.             // Smooth interpolation of mesh translation to avoid popping of other client pawns unless under a low tick rate.
  5922.             // Faster interpolation if stopped.
  5923.             const float SmoothLocationTime = Velocity.IsZero() ? 0.5f*ClientData->SmoothNetUpdateTime : ClientData->SmoothNetUpdateTime;
  5924.             if (DeltaSeconds < SmoothLocationTime)
  5925.             {
  5926.                 // Slowly decay translation offset
  5927.                 ClientData->MeshTranslationOffset = (ClientData->MeshTranslationOffset * (1.f - DeltaSeconds / SmoothLocationTime));
  5928.             }
  5929.             else
  5930.             {
  5931.                 ClientData->MeshTranslationOffset = FVector::ZeroVector;
  5932.             }
  5933.  
  5934.             // Smooth rotation
  5935.             if (DeltaSeconds < ClientData->SmoothNetUpdateRotationTime)
  5936.             {
  5937.                 // Slowly decay rotation offset
  5938.                 ClientData->MeshRotationOffset = FQuat::Slerp(ClientData->MeshRotationOffset, FQuat::Identity, DeltaSeconds / ClientData->SmoothNetUpdateRotationTime);
  5939.             }
  5940.             else
  5941.             {
  5942.                 ClientData->MeshRotationOffset = FQuat::Identity;
  5943.             }
  5944.         }
  5945.  
  5946.         if (IsMovingOnGround())
  5947.         {
  5948.             // Don't smooth Z position if walking on ground.
  5949.             ClientData->MeshTranslationOffset = FVector::VectorPlaneProject(ClientData->MeshTranslationOffset, GetCapsuleAxisZ());
  5950.         }
  5951.  
  5952.         const FVector NewRelTranslation = UpdatedComponent->GetComponentToWorld().InverseTransformVectorNoScale(ClientData->MeshTranslationOffset) + CharacterOwner->GetBaseTranslationOffset();
  5953.         const FQuat NewRelRotation = ClientData->MeshRotationOffset * CharacterOwner->GetBaseRotationOffset();
  5954.         CharacterOwner->GetMesh()->SetRelativeLocationAndRotation(NewRelTranslation, NewRelRotation);
  5955.     }
  5956. }
  5957.  
  5958.  
  5959. bool UCharacterMovementComponent::ClientUpdatePositionAfterServerUpdate()
  5960. {
  5961.     if (!HasValidData())
  5962.     {
  5963.         return false;
  5964.     }
  5965.  
  5966.     FNetworkPredictionData_Client_Character* ClientData = GetPredictionData_Client_Character();
  5967.     check(ClientData);
  5968.  
  5969.     if (!ClientData->bUpdatePosition)
  5970.     {
  5971.         return false;
  5972.     }
  5973.  
  5974.     ClientData->bUpdatePosition = false;
  5975.  
  5976.     // Don't do any network position updates on things running PHYS_RigidBody
  5977.     if (CharacterOwner->GetRootComponent() && CharacterOwner->GetRootComponent()->IsSimulatingPhysics())
  5978.     {
  5979.         return false;
  5980.     }
  5981.  
  5982.     if (ClientData->SavedMoves.Num() == 0)
  5983.     {
  5984.         UE_LOG(LogNetPlayerMovement, VeryVerbose, TEXT("ClientUpdatePositionAfterServerUpdate No saved moves to replay"), ClientData->SavedMoves.Num());
  5985.         return false;
  5986.     }
  5987.  
  5988.     // Save important values that might get affected by the replay.
  5989.     const float SavedAnalogInputModifier = AnalogInputModifier;
  5990.     const FRootMotionMovementParams BackupRootMotionParams = RootMotionParams;
  5991.     const bool bRealJump = CharacterOwner->bPressedJump;
  5992.     const bool bRealCrouch = bWantsToCrouch;
  5993.     const bool bRealForceMaxAccel = bForceMaxAccel;
  5994.     CharacterOwner->bClientWasFalling = (MovementMode == MOVE_Falling);
  5995.     CharacterOwner->bClientUpdating = true;
  5996.     bForceNextFloorCheck = true;
  5997.  
  5998.     // Replay moves that have not yet been acked.
  5999.     UE_LOG(LogNetPlayerMovement, VeryVerbose, TEXT("ClientUpdatePositionAfterServerUpdate Replaying Moves (%d)"), ClientData->SavedMoves.Num());
  6000.     for (int32 i=0; i<ClientData->SavedMoves.Num(); i++)
  6001.     {
  6002.         const FSavedMovePtr& CurrentMove = ClientData->SavedMoves[i];
  6003.         CurrentMove->PrepMoveFor(CharacterOwner);
  6004.         MoveAutonomous(CurrentMove->TimeStamp, CurrentMove->DeltaTime, CurrentMove->GetCompressedFlags(), CurrentMove->Acceleration);
  6005.         CurrentMove->PostUpdate(CharacterOwner, FSavedMove_Character::PostUpdate_Replay);
  6006.     }
  6007.  
  6008.     if (ClientData->PendingMove.IsValid())
  6009.     {
  6010.         ClientData->PendingMove->bForceNoCombine = true;
  6011.     }
  6012.  
  6013.     // Restore saved values.
  6014.     AnalogInputModifier = SavedAnalogInputModifier;
  6015.     RootMotionParams = BackupRootMotionParams;
  6016.     CharacterOwner->bClientResimulateRootMotion = false;
  6017.     CharacterOwner->bClientUpdating = false;
  6018.     CharacterOwner->bPressedJump = bRealJump;
  6019.     bWantsToCrouch = bRealCrouch;
  6020.     bForceMaxAccel = bRealForceMaxAccel;
  6021.     bForceNextFloorCheck = true;
  6022.  
  6023.     return (ClientData->SavedMoves.Num() > 0);
  6024. }
  6025.  
  6026.  
  6027. void UCharacterMovementComponent::ForcePositionUpdate(float DeltaTime)
  6028. {
  6029.     if (!HasValidData() || MovementMode == MOVE_None || UpdatedComponent->Mobility != EComponentMobility::Movable)
  6030.     {
  6031.         return;
  6032.     }
  6033.  
  6034.     check(CharacterOwner->Role == ROLE_Authority);
  6035.     check(CharacterOwner->GetRemoteRole() == ROLE_AutonomousProxy);
  6036.  
  6037.     if (!Velocity.IsZero())
  6038.     {
  6039.         PerformMovement(DeltaTime);
  6040.     }
  6041. }
  6042.  
  6043.  
  6044. FNetworkPredictionData_Client* UCharacterMovementComponent::GetPredictionData_Client() const
  6045. {
  6046.     // Should only be called on client in network games
  6047.     check(CharacterOwner != NULL);
  6048.     check(CharacterOwner->Role < ROLE_Authority);
  6049.     check(GetNetMode() == NM_Client);
  6050.  
  6051.     if (!ClientPredictionData)
  6052.     {
  6053.         UCharacterMovementComponent* MutableThis = const_cast<UCharacterMovementComponent*>(this);
  6054.         MutableThis->ClientPredictionData = new FNetworkPredictionData_Client_Character(*this);
  6055.     }
  6056.  
  6057.     return ClientPredictionData;
  6058. }
  6059.  
  6060. FNetworkPredictionData_Server* UCharacterMovementComponent::GetPredictionData_Server() const
  6061. {
  6062.     // Should only be called on server in network games
  6063.     check(CharacterOwner != NULL);
  6064.     check(CharacterOwner->Role == ROLE_Authority);
  6065.     check(GetNetMode() < NM_Client);
  6066.  
  6067.     if (!ServerPredictionData)
  6068.     {
  6069.         UCharacterMovementComponent* MutableThis = const_cast<UCharacterMovementComponent*>(this);
  6070.         MutableThis->ServerPredictionData = new FNetworkPredictionData_Server_Character();
  6071.     }
  6072.  
  6073.     return ServerPredictionData;
  6074. }
  6075.  
  6076.  
  6077. FNetworkPredictionData_Client_Character* UCharacterMovementComponent::GetPredictionData_Client_Character() const
  6078. {
  6079.     return static_cast<class FNetworkPredictionData_Client_Character*>(GetPredictionData_Client());
  6080. }
  6081.  
  6082.  
  6083. FNetworkPredictionData_Server_Character* UCharacterMovementComponent::GetPredictionData_Server_Character() const
  6084. {
  6085.     return static_cast<class FNetworkPredictionData_Server_Character*>(GetPredictionData_Server());
  6086. }
  6087.  
  6088.  
  6089. void UCharacterMovementComponent::ResetPredictionData_Client()
  6090. {
  6091.     if (ClientPredictionData)
  6092.     {
  6093.         delete ClientPredictionData;
  6094.         ClientPredictionData = NULL;
  6095.     }
  6096. }
  6097.  
  6098. void UCharacterMovementComponent::ResetPredictionData_Server()
  6099. {
  6100.     if (ServerPredictionData)
  6101.     {
  6102.         delete ServerPredictionData;
  6103.         ServerPredictionData = NULL;
  6104.     }
  6105. }
  6106.  
  6107. float FNetworkPredictionData_Client_Character::UpdateTimeStampAndDeltaTime(float DeltaTime, class ACharacter & CharacterOwner, class UCharacterMovementComponent & CharacterMovementComponent)
  6108. {
  6109.     // Reset TimeStamp regularly to combat float accuracy decreasing over time.
  6110.     if (CurrentTimeStamp > CharacterMovementComponent.MinTimeBetweenTimeStampResets)
  6111.     {
  6112.         UE_LOG(LogNetPlayerMovement, Log, TEXT("Resetting Client's TimeStamp %f"), CurrentTimeStamp);
  6113.         CurrentTimeStamp = 0.f;
  6114.  
  6115.         // Mark all buffered moves as having old time stamps, so we make sure to not resend them.
  6116.         // That would confuse the server.
  6117.         for (int32 MoveIndex = 0; MoveIndex<SavedMoves.Num(); MoveIndex++)
  6118.         {
  6119.             const FSavedMovePtr& CurrentMove = SavedMoves[MoveIndex];
  6120.             SavedMoves[MoveIndex]->bOldTimeStampBeforeReset = true;
  6121.         }
  6122.         // Do LastAckedMove as well. No need to do PendingMove as that move is part of the SavedMoves array.
  6123.         if (LastAckedMove.IsValid())
  6124.         {
  6125.             LastAckedMove->bOldTimeStampBeforeReset = true;
  6126.         }
  6127.     }
  6128.  
  6129.     // Update Current TimeStamp.
  6130.     CurrentTimeStamp += DeltaTime;
  6131.     float ClientDeltaTime = DeltaTime;
  6132.  
  6133.     // Server uses TimeStamps to derive DeltaTime which introduces some rounding errors.
  6134.     // Make sure we do the same, so MoveAutonomous uses the same inputs and is deterministic!!
  6135.     if (SavedMoves.Num() > 0)
  6136.     {
  6137.         const FSavedMovePtr& PreviousMove = SavedMoves.Last();
  6138.         if (!PreviousMove->bOldTimeStampBeforeReset)
  6139.         {
  6140.             // How server will calculate its deltatime to update physics.
  6141.             const float ServerDeltaTime = CurrentTimeStamp - PreviousMove->TimeStamp;
  6142.             // Have client always use the Server's DeltaTime. Otherwise our physics simulation will differ and we'll trigger too many position corrections and increase our network traffic.
  6143.             ClientDeltaTime = ServerDeltaTime;
  6144.         }
  6145.     }
  6146.  
  6147.     return CharacterOwner.CustomTimeDilation * FMath::Min(ClientDeltaTime, MaxResponseTime * CharacterOwner.GetWorldSettings()->GetEffectiveTimeDilation());
  6148. }
  6149.  
  6150. void UCharacterMovementComponent::ReplicateMoveToServer(float DeltaTime, const FVector& NewAcceleration)
  6151. {
  6152.     check(CharacterOwner != NULL);
  6153.  
  6154.     // Can only start sending moves if our controllers are synced up over the network, otherwise we flood the reliable buffer.
  6155.     APlayerController* PC = Cast<APlayerController>(CharacterOwner->GetController());
  6156.     if (PC && PC->AcknowledgedPawn != CharacterOwner)
  6157.     {
  6158.         return;
  6159.     }
  6160.  
  6161.     FNetworkPredictionData_Client_Character* ClientData = GetPredictionData_Client_Character();
  6162.     if (!ClientData)
  6163.     {
  6164.         return;
  6165.     }
  6166.  
  6167.     // Update our delta time for physics simulation.
  6168.     DeltaTime = ClientData->UpdateTimeStampAndDeltaTime(DeltaTime, *CharacterOwner, *this);
  6169.  
  6170.     // Find the oldest (unacknowledged) important move (OldMove).
  6171.     // Don't include the last move because it may be combined with the next new move.
  6172.     // A saved move is interesting if it differs significantly from the last acknowledged move
  6173.     FSavedMovePtr OldMove = NULL;
  6174.     if (ClientData->LastAckedMove.IsValid())
  6175.     {
  6176.         for (int32 i = 0; i < ClientData->SavedMoves.Num() - 1; i++)
  6177.         {
  6178.             const FSavedMovePtr& CurrentMove = ClientData->SavedMoves[i];
  6179.             if (CurrentMove->IsImportantMove(ClientData->LastAckedMove))
  6180.             {
  6181.                 OldMove = CurrentMove;
  6182.                 break;
  6183.             }
  6184.         }
  6185.     }
  6186.  
  6187.     // Get a SavedMove object to store the movement in.
  6188.     FSavedMovePtr NewMove = ClientData->CreateSavedMove();
  6189.     if (NewMove.IsValid() == false)
  6190.     {
  6191.         return;
  6192.     }
  6193.  
  6194.     NewMove->SetMoveFor(CharacterOwner, DeltaTime, NewAcceleration, *ClientData);
  6195.  
  6196.     // see if the two moves could be combined
  6197.     // do not combine moves which have different TimeStamps (before and after reset).
  6198.     if (ClientData->PendingMove.IsValid() && !ClientData->PendingMove->bOldTimeStampBeforeReset && ClientData->PendingMove->CanCombineWith(NewMove, CharacterOwner, ClientData->MaxResponseTime * CharacterOwner->GetWorldSettings()->GetEffectiveTimeDilation()))
  6199.     {
  6200.         SCOPE_CYCLE_COUNTER(STAT_CharacterMovementCombineNetMove);
  6201.  
  6202.         // Only combine and move back to the start location if we don't move back in to a spot that would make us collide with something new.
  6203.         const FVector OldStartLocation = ClientData->PendingMove->GetRevertedLocation();
  6204.         if (!OverlapTest(OldStartLocation, ClientData->PendingMove->StartRotation.Quaternion(), UpdatedComponent->GetCollisionObjectType(), GetPawnCapsuleCollisionShape(SHRINK_None), CharacterOwner))
  6205.         {
  6206.             FScopedMovementUpdate ScopedMovementUpdate(UpdatedComponent, EScopedUpdate::DeferredUpdates);
  6207.             UE_LOG(LogNetPlayerMovement, 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, OldStartLocation.X, OldStartLocation.Y);
  6208.  
  6209.             // to combine move, first revert pawn position to PendingMove start position, before playing combined move on client
  6210.             const bool bNoCollisionCheck = true;
  6211.             UpdatedComponent->SetWorldLocationAndRotation(OldStartLocation, ClientData->PendingMove->StartRotation, false);
  6212.             Velocity = ClientData->PendingMove->StartVelocity;
  6213.  
  6214.             SetBase(ClientData->PendingMove->StartBase.Get(), ClientData->PendingMove->StartBoneName);
  6215.             CurrentFloor = ClientData->PendingMove->StartFloor;
  6216.  
  6217.             // Now that we have reverted to the old position, prepare a new move from that position,
  6218.             // using our current velocity, acceleration, and rotation, but applied over the combined time from the old and new move.
  6219.  
  6220.             NewMove->DeltaTime += ClientData->PendingMove->DeltaTime;
  6221.  
  6222.             if (PC)
  6223.             {
  6224.                 // We reverted position to that at the start of the pending move (above), however some code paths expect rotation to be set correctly
  6225.                 // before character movement occurs (via FaceRotation), so try that now. The bOrientRotationToMovement path happens later as part of PerformMovement() and PhysicsRotation().
  6226.                 CharacterOwner->FaceRotation(PC->GetControlRotation(), NewMove->DeltaTime);
  6227.             }
  6228.  
  6229.             SaveBaseLocation();
  6230.             NewMove->SetInitialPosition(CharacterOwner);
  6231.  
  6232.             // Remove pending move from move list. It would have to be the last move on the list.
  6233.             if (ClientData->SavedMoves.Num() > 0 && ClientData->SavedMoves.Last() == ClientData->PendingMove)
  6234.             {
  6235.                 ClientData->SavedMoves.Pop();
  6236.             }
  6237.             ClientData->FreeMove(ClientData->PendingMove);
  6238.             ClientData->PendingMove = NULL;
  6239.         }
  6240.         else
  6241.         {
  6242.             //UE_LOG(LogNet, Log, TEXT("Not combining move, would collide at start location"));
  6243.         }
  6244.     }
  6245.  
  6246.     // Acceleration should match what we send to the server, plus any other restrictions the server also enforces (see MoveAutonomous).
  6247.     Acceleration = NewMove->Acceleration.GetClampedToMaxSize(GetMaxAcceleration());
  6248.     AnalogInputModifier = ComputeAnalogInputModifier(); // recompute since acceleration may have changed.
  6249.  
  6250.     // Perform the move locally
  6251.     //Acceleration = NewMove->Acceleration;
  6252.     //AnalogInputModifier = ComputeAnalogInputModifier(); // recompute since acceleration may have changed.
  6253.     CharacterOwner->ClientRootMotionParams.Clear();
  6254.     PerformMovement(NewMove->DeltaTime);
  6255.  
  6256.     NewMove->PostUpdate(CharacterOwner, FSavedMove_Character::PostUpdate_Record);
  6257.  
  6258.     // Add NewMove to the list
  6259.     if (CharacterOwner->bReplicateMovement)
  6260.     {
  6261.         ClientData->SavedMoves.Push(NewMove);
  6262.  
  6263.         const bool bCanDelayMove = (CVarNetEnableMoveCombining.GetValueOnGameThread() != 0) && CanDelaySendingMove(NewMove);
  6264.  
  6265.         if (bCanDelayMove && ClientData->PendingMove.IsValid() == false)
  6266.         {
  6267.             // Decide whether to hold off on move
  6268.             // send moves more frequently in small games where server isn't likely to be saturated
  6269.             float NetMoveDelta;
  6270.             UPlayer* Player = (PC ? PC->Player : NULL);
  6271.  
  6272.             if (Player && (Player->CurrentNetSpeed > 10000) && (GetWorld()->GameState != NULL) && (GetWorld()->GameState->PlayerArray.Num() <= 10))
  6273.             {
  6274.                 NetMoveDelta = 0.011f;
  6275.             }
  6276.             else if (Player && CharacterOwner->GetWorldSettings()->GameNetworkManagerClass)
  6277.             {
  6278.                 NetMoveDelta = FMath::Max(0.0222f, 2 * GetDefault<AGameNetworkManager>(CharacterOwner->GetWorldSettings()->GameNetworkManagerClass)->MoveRepSize / Player->CurrentNetSpeed);
  6279.             }
  6280.             else
  6281.             {
  6282.                 NetMoveDelta = 0.011f;
  6283.             }
  6284.  
  6285.             if ((GetWorld()->TimeSeconds - ClientData->ClientUpdateTime) * CharacterOwner->GetWorldSettings()->GetEffectiveTimeDilation() < NetMoveDelta)
  6286.             {
  6287.                 // Delay sending this move.
  6288.                 ClientData->PendingMove = NewMove;
  6289.                 return;
  6290.             }
  6291.         }
  6292.  
  6293.         ClientData->ClientUpdateTime = GetWorld()->TimeSeconds;
  6294.  
  6295.         UE_LOG(LogNetPlayerMovement, Verbose, TEXT("Client ReplicateMove Time %f Acceleration %s Position %s DeltaTime %f"),
  6296.             NewMove->TimeStamp, *NewMove->Acceleration.ToString(), *UpdatedComponent->GetComponentLocation().ToString(), DeltaTime);
  6297.  
  6298.         // Send move to server if this character is replicating movement
  6299.         CallServerMove(NewMove.Get(), OldMove.Get());
  6300.     }
  6301.  
  6302.     ClientData->PendingMove = NULL;
  6303. }
  6304.  
  6305.  
  6306. inline uint32 PackYawAndPitchTo32(const float Yaw, const float Pitch)
  6307. {
  6308.     const uint32 YawShort = FRotator::CompressAxisToShort(Yaw);
  6309.     const uint32 PitchShort = FRotator::CompressAxisToShort(Pitch);
  6310.     const uint32 Rotation32 = (YawShort << 16) | PitchShort;
  6311.     return Rotation32;
  6312. }
  6313.  
  6314.  
  6315. void UCharacterMovementComponent::CallServerMove
  6316. (
  6317. const class FSavedMove_Character* NewMove,
  6318. const class FSavedMove_Character* OldMove
  6319. )
  6320. {
  6321.     check(NewMove != NULL);
  6322.  
  6323.     // Compress rotation down to 5 bytes
  6324.     const uint32 ClientYawPitchINT = PackYawAndPitchTo32(NewMove->SavedControlRotation.Yaw, NewMove->SavedControlRotation.Pitch);
  6325.     const uint8 ClientRollBYTE = FRotator::CompressAxisToByte(NewMove->SavedControlRotation.Roll);
  6326.  
  6327.     // Determine if we send absolute or relative location
  6328.     UPrimitiveComponent* ClientMovementBase = NewMove->EndBase.Get();
  6329.     const FName ClientBaseBone = NewMove->EndBoneName;
  6330.     const FVector SendLocation = MovementBaseUtility::UseRelativeLocation(ClientMovementBase) ? NewMove->SavedRelativeLocation : NewMove->SavedLocation;
  6331.  
  6332.     // send old move if it exists
  6333.     if (OldMove)
  6334.     {
  6335.         ServerMoveOld(OldMove->TimeStamp, OldMove->Acceleration, OldMove->GetCompressedFlags());
  6336.     }
  6337.  
  6338.     FNetworkPredictionData_Client_Character* ClientData = GetPredictionData_Client_Character();
  6339.     if (ClientData->PendingMove.IsValid())
  6340.     {
  6341.         const uint32 OldClientYawPitchINT = PackYawAndPitchTo32(ClientData->PendingMove->SavedControlRotation.Yaw, ClientData->PendingMove->SavedControlRotation.Pitch);
  6342.  
  6343.         // If we delayed a move without root motion, and our new move has root motion, send these through a special function, so the server knows how to process them.
  6344.         if ((ClientData->PendingMove->RootMotionMontage == NULL) && (NewMove->RootMotionMontage != NULL))
  6345.         {
  6346.             // send two moves simultaneously
  6347.             ServerMoveDualHybridRootMotion
  6348.                 (
  6349.                 ClientData->PendingMove->TimeStamp,
  6350.                 ClientData->PendingMove->Acceleration,
  6351.                 ClientData->PendingMove->GetCompressedFlags(),
  6352.                 OldClientYawPitchINT,
  6353.                 NewMove->TimeStamp,
  6354.                 NewMove->Acceleration,
  6355.                 SendLocation,
  6356.                 NewMove->GetCompressedFlags(),
  6357.                 ClientRollBYTE,
  6358.                 ClientYawPitchINT,
  6359.                 ClientMovementBase,
  6360.                 ClientBaseBone,
  6361.                 NewMove->MovementMode
  6362.                 );
  6363.         }
  6364.         else
  6365.         {
  6366.             // send two moves simultaneously
  6367.             ServerMoveDual
  6368.                 (
  6369.                 ClientData->PendingMove->TimeStamp,
  6370.                 ClientData->PendingMove->Acceleration,
  6371.                 ClientData->PendingMove->GetCompressedFlags(),
  6372.                 OldClientYawPitchINT,
  6373.                 NewMove->TimeStamp,
  6374.                 NewMove->Acceleration,
  6375.                 SendLocation,
  6376.                 NewMove->GetCompressedFlags(),
  6377.                 ClientRollBYTE,
  6378.                 ClientYawPitchINT,
  6379.                 ClientMovementBase,
  6380.                 ClientBaseBone,
  6381.                 NewMove->MovementMode
  6382.                 );
  6383.         }
  6384.     }
  6385.     else
  6386.     {
  6387.         ServerMove
  6388.             (
  6389.             NewMove->TimeStamp,
  6390.             NewMove->Acceleration,
  6391.             SendLocation,
  6392.             NewMove->GetCompressedFlags(),
  6393.             ClientRollBYTE,
  6394.             ClientYawPitchINT,
  6395.             ClientMovementBase,
  6396.             ClientBaseBone,
  6397.             NewMove->MovementMode
  6398.             );
  6399.     }
  6400.  
  6401.  
  6402.     APlayerController* PC = Cast<APlayerController>(CharacterOwner->GetController());
  6403.     APlayerCameraManager* PlayerCameraManager = (PC ? PC->PlayerCameraManager : NULL);
  6404.     if (PlayerCameraManager != NULL && PlayerCameraManager->bUseClientSideCameraUpdates)
  6405.     {
  6406.         PlayerCameraManager->bShouldSendClientSideCameraUpdate = true;
  6407.     }
  6408. }
  6409.  
  6410.  
  6411.  
  6412. void UCharacterMovementComponent::ServerMoveOld_Implementation
  6413. (
  6414. float OldTimeStamp,
  6415. FVector_NetQuantize10 OldAccel,
  6416. uint8 OldMoveFlags
  6417. )
  6418. {
  6419.     if (!HasValidData() || !IsComponentTickEnabled())
  6420.     {
  6421.         return;
  6422.     }
  6423.  
  6424.     FNetworkPredictionData_Server_Character* ServerData = GetPredictionData_Server_Character();
  6425.     check(ServerData);
  6426.  
  6427.     if (!VerifyClientTimeStamp(OldTimeStamp, *ServerData))
  6428.     {
  6429.         return;
  6430.     }
  6431.  
  6432.     UE_LOG(LogNetPlayerMovement, Log, TEXT("Recovered move from OldTimeStamp %f, DeltaTime: %f"), OldTimeStamp, OldTimeStamp - ServerData->CurrentClientTimeStamp);
  6433.     const float MaxResponseTime = ServerData->MaxResponseTime * CharacterOwner->GetWorldSettings()->GetEffectiveTimeDilation();
  6434.  
  6435.     MoveAutonomous(OldTimeStamp, FMath::Min(OldTimeStamp - ServerData->CurrentClientTimeStamp, MaxResponseTime), OldMoveFlags, OldAccel);
  6436.  
  6437.     ServerData->CurrentClientTimeStamp = OldTimeStamp;
  6438. }
  6439.  
  6440.  
  6441. void UCharacterMovementComponent::ServerMoveDual_Implementation(
  6442.     float TimeStamp0,
  6443.     FVector_NetQuantize10 InAccel0,
  6444.     uint8 PendingFlags,
  6445.     uint32 View0,
  6446.     float TimeStamp,
  6447.     FVector_NetQuantize10 InAccel,
  6448.     FVector_NetQuantize100 ClientLoc,
  6449.     uint8 NewFlags,
  6450.     uint8 ClientRoll,
  6451.     uint32 View,
  6452.     UPrimitiveComponent* ClientMovementBase,
  6453.     FName ClientBaseBone,
  6454.     uint8 ClientMovementMode)
  6455. {
  6456.     ServerMove_Implementation(TimeStamp0, InAccel0, FVector(1.f, 2.f, 3.f), PendingFlags, ClientRoll, View0, ClientMovementBase, ClientBaseBone, ClientMovementMode);
  6457.     ServerMove_Implementation(TimeStamp, InAccel, ClientLoc, NewFlags, ClientRoll, View, ClientMovementBase, ClientBaseBone, ClientMovementMode);
  6458. }
  6459.  
  6460. void UCharacterMovementComponent::ServerMoveDualHybridRootMotion_Implementation(
  6461.     float TimeStamp0,
  6462.     FVector_NetQuantize10 InAccel0,
  6463.     uint8 PendingFlags,
  6464.     uint32 View0,
  6465.     float TimeStamp,
  6466.     FVector_NetQuantize10 InAccel,
  6467.     FVector_NetQuantize100 ClientLoc,
  6468.     uint8 NewFlags,
  6469.     uint8 ClientRoll,
  6470.     uint32 View,
  6471.     UPrimitiveComponent* ClientMovementBase,
  6472.     FName ClientBaseBone,
  6473.     uint8 ClientMovementMode)
  6474. {
  6475.     // First move received didn't use root motion, process it as such.
  6476.     CharacterOwner->bServerMoveIgnoreRootMotion = CharacterOwner->IsPlayingNetworkedRootMotionMontage();
  6477.     ServerMove_Implementation(TimeStamp0, InAccel0, FVector(1.f, 2.f, 3.f), PendingFlags, ClientRoll, View0, ClientMovementBase, ClientBaseBone, ClientMovementMode);
  6478.     CharacterOwner->bServerMoveIgnoreRootMotion = false;
  6479.  
  6480.     ServerMove_Implementation(TimeStamp, InAccel, ClientLoc, NewFlags, ClientRoll, View, ClientMovementBase, ClientBaseBone, ClientMovementMode);
  6481. }
  6482.  
  6483. bool UCharacterMovementComponent::VerifyClientTimeStamp(float TimeStamp, FNetworkPredictionData_Server_Character & ServerData)
  6484. {
  6485.     // Very large deltas happen around a TimeStamp reset.
  6486.     const float DeltaTimeStamp = (TimeStamp - ServerData.CurrentClientTimeStamp);
  6487.     if (FMath::Abs(DeltaTimeStamp) > (MinTimeBetweenTimeStampResets * 0.5f))
  6488.     {
  6489.         // Client is resetting TimeStamp to increase accuracy.
  6490.         if (DeltaTimeStamp < 0.f)
  6491.         {
  6492.             UE_LOG(LogNetPlayerMovement, Log, TEXT("TimeStamp reset detected. CurrentTimeStamp: %f, new TimeStamp: %f"), ServerData.CurrentClientTimeStamp, TimeStamp);
  6493.             ServerData.CurrentClientTimeStamp = 0.f;
  6494.             return true;
  6495.         }
  6496.         else
  6497.         {
  6498.             // We already reset the TimeStamp, but we just got an old outdated move before the switch.
  6499.             // Just ignore it.
  6500.             UE_LOG(LogNetPlayerMovement, Log, TEXT("TimeStamp expired. Before TimeStamp Reset. CurrentTimeStamp: %f, TimeStamp: %f"), ServerData.CurrentClientTimeStamp, TimeStamp);
  6501.             return false;
  6502.         }
  6503.     }
  6504.  
  6505.     // If TimeStamp is in the past, move is outdated, ignore it.
  6506.     if (TimeStamp <= ServerData.CurrentClientTimeStamp)
  6507.     {
  6508.         UE_LOG(LogNetPlayerMovement, Log, TEXT("TimeStamp expired. %f, CurrentTimeStamp: %f"), TimeStamp, ServerData.CurrentClientTimeStamp);
  6509.         return false;
  6510.     }
  6511.  
  6512.     UE_LOG(LogNetPlayerMovement, VeryVerbose, TEXT("TimeStamp %f Accepted! CurrentTimeStamp: %f"), TimeStamp, ServerData.CurrentClientTimeStamp);
  6513.     return true;
  6514. }
  6515.  
  6516. void UCharacterMovementComponent::ServerMove_Implementation(
  6517.     float TimeStamp,
  6518.     FVector_NetQuantize10 InAccel,
  6519.     FVector_NetQuantize100 ClientLoc,
  6520.     uint8 MoveFlags,
  6521.     uint8 ClientRoll,
  6522.     uint32 View,
  6523.     UPrimitiveComponent* ClientMovementBase,
  6524.     FName ClientBaseBoneName,
  6525.     uint8 ClientMovementMode)
  6526. {
  6527.     if (!HasValidData() || !IsComponentTickEnabled())
  6528.     {
  6529.         return;
  6530.     }
  6531.  
  6532.     FNetworkPredictionData_Server_Character* ServerData = GetPredictionData_Server_Character();
  6533.     check(ServerData);
  6534.  
  6535.     if (!VerifyClientTimeStamp(TimeStamp, *ServerData))
  6536.     {
  6537.         return;
  6538.     }
  6539.  
  6540.     bool bServerReadyForClient = true;
  6541.     APlayerController* PC = Cast<APlayerController>(CharacterOwner->GetController());
  6542.     if (PC)
  6543.     {
  6544.         bServerReadyForClient = PC->NotifyServerReceivedClientData(CharacterOwner, TimeStamp);
  6545.         if (!bServerReadyForClient)
  6546.         {
  6547.             InAccel = FVector::ZeroVector;
  6548.         }
  6549.     }
  6550.  
  6551.     // View components
  6552.     const uint16 ViewPitch = (View & 65535);
  6553.     const uint16 ViewYaw = (View >> 16);
  6554.  
  6555.     const FVector Accel = InAccel;
  6556.     // Save move parameters.
  6557.     const float DeltaTime = ServerData->GetServerMoveDeltaTime(TimeStamp) * CharacterOwner->CustomTimeDilation;
  6558.  
  6559.     ServerData->CurrentClientTimeStamp = TimeStamp;
  6560.     ServerData->ServerTimeStamp = GetWorld()->TimeSeconds;
  6561.     FRotator ViewRot;
  6562.     ViewRot.Pitch = FRotator::DecompressAxisFromShort(ViewPitch);
  6563.     ViewRot.Yaw = FRotator::DecompressAxisFromShort(ViewYaw);
  6564.     ViewRot.Roll = FRotator::DecompressAxisFromByte(ClientRoll);
  6565.  
  6566.     if (PC)
  6567.     {
  6568.         PC->SetControlRotation(ViewRot);
  6569.     }
  6570.  
  6571.     if (!bServerReadyForClient)
  6572.     {
  6573.         return;
  6574.     }
  6575.  
  6576.     // Perform actual movement
  6577.     if ((CharacterOwner->GetWorldSettings()->Pauser == NULL) && (DeltaTime > 0.f))
  6578.     {
  6579.         if (PC)
  6580.         {
  6581.             PC->UpdateRotation(DeltaTime);
  6582.         }
  6583.  
  6584.         MoveAutonomous(TimeStamp, DeltaTime, MoveFlags, Accel);
  6585.     }
  6586.  
  6587.     UE_LOG(LogNetPlayerMovement, Verbose, TEXT("ServerMove Time %f Acceleration %s Position %s DeltaTime %f"),
  6588.         TimeStamp, *Accel.ToString(), *UpdatedComponent->GetComponentLocation().ToString(), DeltaTime);
  6589.  
  6590.     ServerMoveHandleClientError(TimeStamp, DeltaTime, Accel, ClientLoc, ClientMovementBase, ClientBaseBoneName, ClientMovementMode);
  6591. }
  6592.  
  6593.  
  6594. void UCharacterMovementComponent::ServerMoveHandleClientError(float ClientTimeStamp, float DeltaTime, const FVector& Accel, const FVector& RelativeClientLoc, UPrimitiveComponent* ClientMovementBase, FName ClientBaseBoneName, uint8 ClientMovementMode)
  6595. {
  6596.     if (RelativeClientLoc == FVector(1.f, 2.f, 3.f)) // first part of double servermove
  6597.     {
  6598.         return;
  6599.     }
  6600.  
  6601.     FNetworkPredictionData_Server_Character* ServerData = GetPredictionData_Server_Character();
  6602.     check(ServerData);
  6603.  
  6604.     // Don't prevent more recent updates from being sent if received this frame.
  6605.     // We're going to send out an update anyway, might as well be the most recent one.
  6606.     APlayerController* PC = Cast<APlayerController>(CharacterOwner->GetController());
  6607.     if ((ServerData->LastUpdateTime != GetWorld()->TimeSeconds) && GetDefault<AGameNetworkManager>()->WithinUpdateDelayBounds(PC, ServerData->LastUpdateTime))
  6608.     {
  6609.         return;
  6610.     }
  6611.  
  6612.     // Offset may be relative to base component
  6613.     FVector ClientLoc = RelativeClientLoc;
  6614.     if (MovementBaseUtility::UseRelativeLocation(ClientMovementBase))
  6615.     {
  6616.         FVector BaseLocation;
  6617.         FQuat BaseRotation;
  6618.         MovementBaseUtility::GetMovementBaseTransform(ClientMovementBase, ClientBaseBoneName, BaseLocation, BaseRotation);
  6619.         ClientLoc += BaseLocation;
  6620.     }
  6621.  
  6622.     // Compute the client error from the server's position
  6623.     // If client has accumulated a noticeable positional error, correct him.
  6624.     if (ServerData->bForceClientUpdate || ServerCheckClientError(ClientTimeStamp, DeltaTime, Accel, ClientLoc, RelativeClientLoc, ClientMovementBase, ClientBaseBoneName, ClientMovementMode))
  6625.     {
  6626.         UPrimitiveComponent* MovementBase = CharacterOwner->GetMovementBase();
  6627.         ServerData->PendingAdjustment.NewVel = Velocity;
  6628.         ServerData->PendingAdjustment.NewBase = MovementBase;
  6629.         ServerData->PendingAdjustment.NewBaseBoneName = CharacterOwner->GetBasedMovement().BoneName;
  6630.         ServerData->PendingAdjustment.NewLoc = UpdatedComponent->GetComponentLocation();
  6631.         ServerData->PendingAdjustment.NewRot = UpdatedComponent->GetComponentRotation();
  6632.  
  6633.         ServerData->PendingAdjustment.bBaseRelativePosition = MovementBaseUtility::UseRelativeLocation(MovementBase);
  6634.         if (ServerData->PendingAdjustment.bBaseRelativePosition)
  6635.         {
  6636.             // Relative location
  6637.             ServerData->PendingAdjustment.NewLoc = CharacterOwner->GetBasedMovement().Location;
  6638.  
  6639.             // TODO: this could be a relative rotation, but all client corrections ignore rotation right now except the root motion one, which would need to be updated.
  6640.             //ServerData->PendingAdjustment.NewRot = CharacterOwner->GetBasedMovement().Rotation;
  6641.         }
  6642.  
  6643.  
  6644. #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
  6645.         if (CVarNetShowCorrections.GetValueOnGameThread() != 0)
  6646.         {
  6647.             const FVector LocDiff = UpdatedComponent->GetComponentLocation() - ClientLoc;
  6648.             UE_LOG(LogNetPlayerMovement, Warning, TEXT("******** Client Error at %f is %f Accel %s LocDiff %s ClientLoc %s, ServerLoc: %s, Base: %s, Bone: %s"),
  6649.                 ClientTimeStamp, LocDiff.Size(), *Accel.ToString(), *LocDiff.ToString(), *ClientLoc.ToString(), *UpdatedComponent->GetComponentLocation().ToString(), *GetNameSafe(MovementBase), *ServerData->PendingAdjustment.NewBaseBoneName.ToString());
  6650.             const float DebugLifetime = CVarNetCorrectionLifetime.GetValueOnGameThread();
  6651.             DrawDebugCapsule(GetWorld(), UpdatedComponent->GetComponentLocation(), CharacterOwner->GetSimpleCollisionHalfHeight(), CharacterOwner->GetSimpleCollisionRadius(), FQuat::Identity, FColor(100, 255, 100), true, DebugLifetime);
  6652.             DrawDebugCapsule(GetWorld(), ClientLoc, CharacterOwner->GetSimpleCollisionHalfHeight(), CharacterOwner->GetSimpleCollisionRadius(), FQuat::Identity, FColor(255, 100, 100), true, DebugLifetime);
  6653.         }
  6654. #endif
  6655.  
  6656.         ServerData->LastUpdateTime = GetWorld()->TimeSeconds;
  6657.         ServerData->PendingAdjustment.DeltaTime = DeltaTime;
  6658.         ServerData->PendingAdjustment.TimeStamp = ClientTimeStamp;
  6659.         ServerData->PendingAdjustment.bAckGoodMove = false;
  6660.         ServerData->PendingAdjustment.MovementMode = PackNetworkMovementMode();
  6661.     }
  6662.     else
  6663.     {
  6664.         if (GetDefault<AGameNetworkManager>()->ClientAuthorativePosition)
  6665.         {
  6666.             const FVector LocDiff = UpdatedComponent->GetComponentLocation() - ClientLoc;
  6667.             if (!LocDiff.IsZero() || ClientMovementMode != PackNetworkMovementMode())
  6668.             {
  6669.                 // Just set the position. On subsequent moves we will resolve initially overlapping conditions.
  6670.                 UpdatedComponent->SetWorldLocation(ClientLoc, false);
  6671.  
  6672.                 // Trust the client's movement mode.
  6673.                 ApplyNetworkMovementMode(ClientMovementMode);
  6674.  
  6675.                 // Update base and floor at new location.
  6676.                 SetBase(ClientMovementBase, ClientBaseBoneName);
  6677.                 UpdateFloorFromAdjustment();
  6678.  
  6679.                 // Even if base has not changed, we need to recompute the relative offsets (since we've moved).
  6680.                 SaveBaseLocation();
  6681.             }
  6682.         }
  6683.  
  6684.         // acknowledge receipt of this successful servermove()
  6685.         ServerData->PendingAdjustment.TimeStamp = ClientTimeStamp;
  6686.         ServerData->PendingAdjustment.bAckGoodMove = true;
  6687.     }
  6688.  
  6689.     ServerData->bForceClientUpdate = false;
  6690. }
  6691.  
  6692. bool UCharacterMovementComponent::ServerCheckClientError(float ClientTimeStamp, float DeltaTime, const FVector& Accel, const FVector& ClientWorldLocation, const FVector& RelativeClientLocation, UPrimitiveComponent* ClientMovementBase, FName ClientBaseBoneName, uint8 ClientMovementMode)
  6693. {
  6694.     // Check location difference against global setting
  6695.     const FVector LocDiff = UpdatedComponent->GetComponentLocation() - ClientWorldLocation;
  6696.     if (GetDefault<AGameNetworkManager>()->ExceedsAllowablePositionError(LocDiff))
  6697.     {
  6698.         return true;
  6699.     }
  6700.  
  6701.     // Check for disagreement in movement mode
  6702.     const uint8 CurrentPackedMovementMode = PackNetworkMovementMode();
  6703.     if (CurrentPackedMovementMode != ClientMovementMode)
  6704.     {
  6705.         return true;
  6706.     }
  6707.  
  6708.     return false;
  6709. }
  6710.  
  6711.  
  6712. bool UCharacterMovementComponent::ServerMove_Validate(float TimeStamp, FVector_NetQuantize10 InAccel, FVector_NetQuantize100 ClientLoc, uint8 MoveFlags, uint8 ClientRoll, uint32 View, UPrimitiveComponent* ClientMovementBase, FName ClientBaseBoneName, uint8 ClientMovementMode)
  6713. {
  6714.     return true;
  6715. }
  6716.  
  6717. bool UCharacterMovementComponent::ServerMoveDual_Validate(float TimeStamp0, FVector_NetQuantize10 InAccel0, uint8 PendingFlags, uint32 View0, float TimeStamp, FVector_NetQuantize10 InAccel, FVector_NetQuantize100 ClientLoc, uint8 NewFlags, uint8 ClientRoll, uint32 View, UPrimitiveComponent* ClientMovementBase, FName ClientBaseBoneName, uint8 ClientMovementMode)
  6718. {
  6719.     return true;
  6720. }
  6721.  
  6722. bool UCharacterMovementComponent::ServerMoveDualHybridRootMotion_Validate(float TimeStamp0, FVector_NetQuantize10 InAccel0, uint8 PendingFlags, uint32 View0, float TimeStamp, FVector_NetQuantize10 InAccel, FVector_NetQuantize100 ClientLoc, uint8 NewFlags, uint8 ClientRoll, uint32 View, UPrimitiveComponent* ClientMovementBase, FName ClientBaseBoneName, uint8 ClientMovementMode)
  6723. {
  6724.     return true;
  6725. }
  6726.  
  6727. bool UCharacterMovementComponent::ServerMoveOld_Validate(float OldTimeStamp, FVector_NetQuantize10 OldAccel, uint8 OldMoveFlags)
  6728. {
  6729.     return true;
  6730. }
  6731.  
  6732.  
  6733.  
  6734. void UCharacterMovementComponent::MoveAutonomous
  6735. (
  6736. float ClientTimeStamp,
  6737. float DeltaTime,
  6738. uint8 CompressedFlags,
  6739. const FVector& NewAccel
  6740. )
  6741. {
  6742.     if (!HasValidData())
  6743.     {
  6744.         return;
  6745.     }
  6746.  
  6747.     UpdateFromCompressedFlags(CompressedFlags);
  6748.     CharacterOwner->CheckJumpInput(DeltaTime);
  6749.  
  6750.     Acceleration = ConstrainInputAcceleration(NewAccel);
  6751.     Acceleration = Acceleration.GetClampedToMaxSize(GetMaxAcceleration());
  6752.     AnalogInputModifier = ComputeAnalogInputModifier();
  6753.  
  6754.     PerformMovement(DeltaTime);
  6755.  
  6756.     // Check if data is valid as PerformMovement can mark character for pending kill
  6757.     if (!HasValidData())
  6758.     {
  6759.         return;
  6760.     }
  6761.  
  6762.     // If not playing root motion, tick animations after physics. We do this here to keep events, notifies, states and transitions in sync with client updates.
  6763.     if (!CharacterOwner->bClientUpdating && !CharacterOwner->IsPlayingRootMotion() && CharacterOwner->GetMesh())
  6764.     {
  6765.         TickCharacterPose(DeltaTime);
  6766.         // TODO: SaveBaseLocation() in case tick moves us?
  6767.     }
  6768. }
  6769.  
  6770.  
  6771. void UCharacterMovementComponent::UpdateFloorFromAdjustment()
  6772. {
  6773.     if (!HasValidData())
  6774.     {
  6775.         return;
  6776.     }
  6777.  
  6778.     // If walking, try to update the cached floor so it is current. This is necessary for UpdateBasedMovement() and MoveAlongFloor() to work properly.
  6779.     // If base is now NULL, presumably we are no longer walking. If we had a valid floor but don't find one now, we'll likely start falling.
  6780.     if (CharacterOwner->GetMovementBase())
  6781.     {
  6782.         FindFloor(UpdatedComponent->GetComponentLocation(), CurrentFloor, false);
  6783.     }
  6784.     else
  6785.     {
  6786.         CurrentFloor.Clear();
  6787.     }
  6788.  
  6789.     bForceNextFloorCheck = true;
  6790. }
  6791.  
  6792.  
  6793. void UCharacterMovementComponent::SendClientAdjustment()
  6794. {
  6795.     if (!HasValidData())
  6796.     {
  6797.         return;
  6798.     }
  6799.  
  6800.     FNetworkPredictionData_Server_Character* ServerData = GetPredictionData_Server_Character();
  6801.     check(ServerData);
  6802.  
  6803.     if (ServerData->PendingAdjustment.TimeStamp <= 0.f)
  6804.     {
  6805.         return;
  6806.     }
  6807.  
  6808.     if (ServerData->PendingAdjustment.bAckGoodMove == true)
  6809.     {
  6810.         // just notify client this move was received
  6811.         ClientAckGoodMove(ServerData->PendingAdjustment.TimeStamp);
  6812.     }
  6813.     else
  6814.     {
  6815.         if (CharacterOwner->IsPlayingNetworkedRootMotionMontage())
  6816.         {
  6817.             FRotator Rotation = ServerData->PendingAdjustment.NewRot.GetNormalized();
  6818.             FVector_NetQuantizeNormal CompressedRotation(Rotation.Pitch / 180.f, Rotation.Yaw / 180.f, Rotation.Roll / 180.f);
  6819.             ClientAdjustRootMotionPosition
  6820.                 (
  6821.                 ServerData->PendingAdjustment.TimeStamp,
  6822.                 CharacterOwner->GetRootMotionAnimMontageInstance()->GetPosition(),
  6823.                 ServerData->PendingAdjustment.NewLoc,
  6824.                 CompressedRotation,
  6825.                 ServerData->PendingAdjustment.NewVel.Z,
  6826.                 ServerData->PendingAdjustment.NewBase,
  6827.                 ServerData->PendingAdjustment.NewBaseBoneName,
  6828.                 ServerData->PendingAdjustment.NewBase != NULL,
  6829.                 ServerData->PendingAdjustment.bBaseRelativePosition,
  6830.                 PackNetworkMovementMode()
  6831.                 );
  6832.         }
  6833.         else if (ServerData->PendingAdjustment.NewVel.IsZero())
  6834.         {
  6835.             ClientVeryShortAdjustPosition
  6836.                 (
  6837.                 ServerData->PendingAdjustment.TimeStamp,
  6838.                 ServerData->PendingAdjustment.NewLoc,
  6839.                 ServerData->PendingAdjustment.NewBase,
  6840.                 ServerData->PendingAdjustment.NewBaseBoneName,
  6841.                 ServerData->PendingAdjustment.NewBase != NULL,
  6842.                 ServerData->PendingAdjustment.bBaseRelativePosition,
  6843.                 PackNetworkMovementMode()
  6844.                 );
  6845.         }
  6846.         else
  6847.         {
  6848.             ClientAdjustPosition
  6849.                 (
  6850.                 ServerData->PendingAdjustment.TimeStamp,
  6851.                 ServerData->PendingAdjustment.NewLoc,
  6852.                 ServerData->PendingAdjustment.NewVel,
  6853.                 ServerData->PendingAdjustment.NewBase,
  6854.                 ServerData->PendingAdjustment.NewBaseBoneName,
  6855.                 ServerData->PendingAdjustment.NewBase != NULL,
  6856.                 ServerData->PendingAdjustment.bBaseRelativePosition,
  6857.                 PackNetworkMovementMode()
  6858.                 );
  6859.         }
  6860.     }
  6861.  
  6862.     ServerData->PendingAdjustment.TimeStamp = 0;
  6863.     ServerData->PendingAdjustment.bAckGoodMove = false;
  6864.     ServerData->bForceClientUpdate = false;
  6865. }
  6866.  
  6867.  
  6868. void UCharacterMovementComponent::ClientVeryShortAdjustPosition_Implementation
  6869. (
  6870. float TimeStamp,
  6871. FVector NewLoc,
  6872. UPrimitiveComponent* NewBase,
  6873. FName NewBaseBoneName,
  6874. bool bHasBase,
  6875. bool bBaseRelativePosition,
  6876. uint8 ServerMovementMode
  6877. )
  6878. {
  6879.     if (HasValidData())
  6880.     {
  6881.         ClientAdjustPosition(TimeStamp, NewLoc, FVector::ZeroVector, NewBase, NewBaseBoneName, bHasBase, bBaseRelativePosition, ServerMovementMode);
  6882.     }
  6883. }
  6884.  
  6885.  
  6886. void UCharacterMovementComponent::ClientAdjustPosition_Implementation
  6887. (
  6888. float TimeStamp,
  6889. FVector NewLocation,
  6890. FVector NewVelocity,
  6891. UPrimitiveComponent* NewBase,
  6892. FName NewBaseBoneName,
  6893. bool bHasBase,
  6894. bool bBaseRelativePosition,
  6895. uint8 ServerMovementMode
  6896. )
  6897. {
  6898.     if (!HasValidData() || !IsComponentTickEnabled())
  6899.     {
  6900.         return;
  6901.     }
  6902.  
  6903.  
  6904.     FNetworkPredictionData_Client_Character* ClientData = GetPredictionData_Client_Character();
  6905.     check(ClientData);
  6906.  
  6907.     // Make sure the base actor exists on this client.
  6908.     const bool bUnresolvedBase = bHasBase && (NewBase == NULL);
  6909.     if (bUnresolvedBase)
  6910.     {
  6911.         if (bBaseRelativePosition)
  6912.         {
  6913.             UE_LOG(LogNetPlayerMovement, Warning, TEXT("ClientAdjustPosition_Implementation could not resolve the new relative movement base actor, ignoring server correction!"));
  6914.             return;
  6915.         }
  6916.         else
  6917.         {
  6918.             UE_LOG(LogNetPlayerMovement, Verbose, TEXT("ClientAdjustPosition_Implementation could not resolve the new absolute movement base actor, but WILL use the position!"));
  6919.         }
  6920.     }
  6921.  
  6922.     // Ack move if it has not expired.
  6923.     int32 MoveIndex = ClientData->GetSavedMoveIndex(TimeStamp);
  6924.     if (MoveIndex == INDEX_NONE)
  6925.     {
  6926.         if (ClientData->LastAckedMove.IsValid())
  6927.         {
  6928.             UE_LOG(LogNetPlayerMovement, Log, TEXT("ClientAdjustPosition_Implementation could not find Move for TimeStamp: %f, LastAckedTimeStamp: %f, CurrentTimeStamp: %f"), TimeStamp, ClientData->LastAckedMove->TimeStamp, ClientData->CurrentTimeStamp);
  6929.         }
  6930.         return;
  6931.     }
  6932.     ClientData->AckMove(MoveIndex);
  6933.  
  6934.     //  Received Location is relative to dynamic base
  6935.     if (bBaseRelativePosition)
  6936.     {
  6937.         FVector BaseLocation;
  6938.         FQuat BaseRotation;
  6939.         MovementBaseUtility::GetMovementBaseTransform(NewBase, NewBaseBoneName, BaseLocation, BaseRotation); // TODO: error handling if returns false
  6940.         NewLocation += BaseLocation;
  6941.     }
  6942.  
  6943. #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
  6944.     static const auto CVarShowCorrections = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("p.NetShowCorrections"));
  6945.     if (CVarShowCorrections && CVarShowCorrections->GetValueOnGameThread() != 0)
  6946.     {
  6947.         UE_LOG(LogNetPlayerMovement, Warning, TEXT("******** ClientAdjustPosition Time %f velocity %s position %s NewBase: %s NewBone: %s SavedMoves %d"), TimeStamp, *NewVelocity.ToString(), *NewLocation.ToString(), *GetNameSafe(NewBase), *NewBaseBoneName.ToString(), ClientData->SavedMoves.Num());
  6948.         static const auto CVarCorrectionLifetime = IConsoleManager::Get().FindTConsoleVariableDataFloat(TEXT("p.NetCorrectionLifetime"));
  6949.         const float DebugLifetime = CVarCorrectionLifetime ? CVarCorrectionLifetime->GetValueOnGameThread() : 1.f;
  6950.         DrawDebugCapsule(GetWorld(), UpdatedComponent->GetComponentLocation(), CharacterOwner->GetSimpleCollisionHalfHeight(), CharacterOwner->GetSimpleCollisionRadius(), FQuat::Identity, FColor(255, 100, 100), true, DebugLifetime);
  6951.         DrawDebugCapsule(GetWorld(), NewLocation, CharacterOwner->GetSimpleCollisionHalfHeight(), CharacterOwner->GetSimpleCollisionRadius(), FQuat::Identity, FColor(100, 255, 100), true, DebugLifetime);
  6952.     }
  6953. #endif //!(UE_BUILD_SHIPPING || UE_BUILD_TEST)
  6954.  
  6955.     // Trust the server's positioning.
  6956.     UpdatedComponent->SetWorldLocation(NewLocation, false);
  6957.     Velocity = NewVelocity;
  6958.  
  6959.     // Trust the server's movement mode
  6960.     UPrimitiveComponent* PreviousBase = CharacterOwner->GetMovementBase();
  6961.     ApplyNetworkMovementMode(ServerMovementMode);
  6962.  
  6963.     // Set base component
  6964.     UPrimitiveComponent* FinalBase = NewBase;
  6965.     FName FinalBaseBoneName = NewBaseBoneName;
  6966.     if (bUnresolvedBase)
  6967.     {
  6968.         check(NewBase == NULL);
  6969.         check(!bBaseRelativePosition);
  6970.  
  6971.         // We had an unresolved base from the server
  6972.         // If walking, we'd like to continue walking if possible, to avoid falling for a frame, so try to find a base where we moved to.
  6973.         if (PreviousBase)
  6974.         {
  6975.             FindFloor(UpdatedComponent->GetComponentLocation(), CurrentFloor, false);
  6976.             if (CurrentFloor.IsWalkableFloor())
  6977.             {
  6978.                 FinalBase = CurrentFloor.HitResult.Component.Get();
  6979.                 FinalBaseBoneName = CurrentFloor.HitResult.BoneName;
  6980.             }
  6981.             else
  6982.             {
  6983.                 FinalBase = nullptr;
  6984.                 FinalBaseBoneName = NAME_None;
  6985.             }
  6986.         }
  6987.     }
  6988.     SetBase(FinalBase, FinalBaseBoneName);
  6989.  
  6990.     // Update floor at new location
  6991.     UpdateFloorFromAdjustment();
  6992.     bJustTeleported = true;
  6993.  
  6994.     // Even if base has not changed, we need to recompute the relative offsets (since we've moved).
  6995.     SaveBaseLocation();
  6996.  
  6997.     UpdateComponentVelocity();
  6998.     ClientData->bUpdatePosition = true;
  6999. }
  7000.  
  7001. void UCharacterMovementComponent::ClientAdjustRootMotionPosition_Implementation(
  7002.     float TimeStamp,
  7003.     float ServerMontageTrackPosition,
  7004.     FVector ServerLoc,
  7005.     FVector_NetQuantizeNormal ServerRotation,
  7006.     float ServerVelZ,
  7007.     UPrimitiveComponent * ServerBase,
  7008.     FName ServerBaseBoneName,
  7009.     bool bHasBase,
  7010.     bool bBaseRelativePosition,
  7011.     uint8 ServerMovementMode)
  7012. {
  7013.     if (!HasValidData() || !IsComponentTickEnabled())
  7014.     {
  7015.         return;
  7016.     }
  7017.  
  7018.     // Call ClientAdjustPosition first. This will Ack the move if it's not outdated.
  7019.     ClientAdjustPosition(TimeStamp, ServerLoc, FVector(0.f, 0.f, ServerVelZ), ServerBase, ServerBaseBoneName, bHasBase, bBaseRelativePosition, ServerMovementMode);
  7020.  
  7021.     FNetworkPredictionData_Client_Character* ClientData = GetPredictionData_Client_Character();
  7022.     check(ClientData);
  7023.  
  7024.     // If this adjustment wasn't acknowledged (because outdated), then abort.
  7025.     if (!ClientData->LastAckedMove.IsValid() || (ClientData->LastAckedMove->TimeStamp != TimeStamp))
  7026.     {
  7027.         return;
  7028.     }
  7029.  
  7030.     // We're going to replay Root Motion. This is relative to the Pawn's rotation, so we need to reset that as well.
  7031.     FRotator DecompressedRot(ServerRotation.X * 180.f, ServerRotation.Y * 180.f, ServerRotation.Z * 180.f);
  7032.     CharacterOwner->SetActorRotation(DecompressedRot);
  7033.     const FVector ServerLocation(ServerLoc);
  7034.     UE_LOG(LogRootMotion, Log, TEXT("ClientAdjustRootMotionPosition_Implementation TimeStamp: %f, ServerMontageTrackPosition: %f, ServerLocation: %s, ServerRotation: %s, ServerVelZ: %f, ServerBase: %s"),
  7035.         TimeStamp, ServerMontageTrackPosition, *ServerLocation.ToCompactString(), *DecompressedRot.ToCompactString(), ServerVelZ, *GetNameSafe(ServerBase));
  7036.  
  7037.     // DEBUG - get some insight on where errors came from
  7038.     if (false)
  7039.     {
  7040.         const FVector DeltaLocation = ServerLocation - ClientData->LastAckedMove->SavedLocation;
  7041.         const FRotator DeltaRotation = (DecompressedRot - ClientData->LastAckedMove->SavedRotation).GetNormalized();
  7042.         const float DeltaTrackPosition = (ServerMontageTrackPosition - ClientData->LastAckedMove->RootMotionTrackPosition);
  7043.         const float DeltaVelZ = (ServerVelZ - ClientData->LastAckedMove->SavedVelocity.Z);
  7044.  
  7045.         UE_LOG(LogRootMotion, Log, TEXT("\tErrors DeltaLocation: %s, DeltaRotation: %s, DeltaTrackPosition: %f"),
  7046.             *DeltaLocation.ToCompactString(), *DeltaRotation.ToCompactString(), DeltaTrackPosition);
  7047.     }
  7048.  
  7049.     // Server disagrees with Client on the Root Motion AnimMontage Track position.
  7050.     if (CharacterOwner->bClientResimulateRootMotion || (ServerMontageTrackPosition != ClientData->LastAckedMove->RootMotionTrackPosition))
  7051.     {
  7052.         UE_LOG(LogRootMotion, Warning, TEXT("\tServer disagrees with Client's track position!! ServerTrackPosition: %f, ClientTrackPosition: %f, DeltaTrackPosition: %f. TimeStamp: %f"),
  7053.             ServerMontageTrackPosition, ClientData->LastAckedMove->RootMotionTrackPosition, (ServerMontageTrackPosition - ClientData->LastAckedMove->RootMotionTrackPosition), TimeStamp);
  7054.  
  7055.         // Not much we can do there unfortunately, just jump to server's track position.
  7056.         FAnimMontageInstance * RootMotionMontageInstance = CharacterOwner->GetRootMotionAnimMontageInstance();
  7057.         if (RootMotionMontageInstance)
  7058.         {
  7059.             RootMotionMontageInstance->SetPosition(ServerMontageTrackPosition);
  7060.             CharacterOwner->bClientResimulateRootMotion = true;
  7061.         }
  7062.     }
  7063. }
  7064.  
  7065. void UCharacterMovementComponent::ClientAckGoodMove_Implementation(float TimeStamp)
  7066. {
  7067.     if (!HasValidData() || !IsComponentTickEnabled())
  7068.     {
  7069.         return;
  7070.     }
  7071.  
  7072.     FNetworkPredictionData_Client_Character* ClientData = GetPredictionData_Client_Character();
  7073.     check(ClientData);
  7074.  
  7075.  
  7076.     // Ack move if it has not expired.
  7077.     int32 MoveIndex = ClientData->GetSavedMoveIndex(TimeStamp);
  7078.     if (MoveIndex == INDEX_NONE)
  7079.     {
  7080.         if (ClientData->LastAckedMove.IsValid())
  7081.         {
  7082.             UE_LOG(LogNetPlayerMovement, Warning, TEXT("ClientAckGoodMove_Implementation could not find Move for TimeStamp: %f, LastAckedTimeStamp: %f, CurrentTimeStamp: %f"), TimeStamp, ClientData->LastAckedMove->TimeStamp, ClientData->CurrentTimeStamp);
  7083.         }
  7084.         return;
  7085.     }
  7086.     ClientData->AckMove(MoveIndex);
  7087. }
  7088.  
  7089. void UCharacterMovementComponent::CapsuleTouched(AActor* Other, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
  7090. {
  7091.     if (!bEnablePhysicsInteraction)
  7092.     {
  7093.         return;
  7094.     }
  7095.  
  7096.     if (OtherComp != NULL && OtherComp->IsAnySimulatingPhysics())
  7097.     {
  7098.         const FVector OtherLoc = OtherComp->GetComponentLocation();
  7099.         const FVector Loc = UpdatedComponent->GetComponentLocation();
  7100.         const FVector CapsuleUp = GetCapsuleAxisZ();
  7101.  
  7102.         FVector ImpulseDir = FVector::VectorPlaneProject(OtherLoc - Loc, CapsuleUp) + CapsuleUp * 0.25f;
  7103.         ImpulseDir = (ImpulseDir.GetSafeNormal() + FVector::VectorPlaneProject(Velocity, CapsuleUp).GetSafeNormal()) * 0.5f;
  7104.         ImpulseDir.Normalize();
  7105.  
  7106.         FName BoneName = NAME_None;
  7107.         if (OtherBodyIndex != INDEX_NONE)
  7108.         {
  7109.             BoneName = ((USkinnedMeshComponent*)OtherComp)->GetBoneName(OtherBodyIndex);
  7110.         }
  7111.  
  7112.         float TouchForceFactorModified = TouchForceFactor;
  7113.  
  7114.         if (bTouchForceScaledToMass)
  7115.         {
  7116.             FBodyInstance* BI = OtherComp->GetBodyInstance(BoneName);
  7117.             TouchForceFactorModified *= BI ? BI->GetBodyMass() : 1.0f;
  7118.         }
  7119.  
  7120.         float ImpulseStrength = FMath::Clamp(FVector::VectorPlaneProject(Velocity, CapsuleUp).Size() * TouchForceFactorModified,
  7121.             MinTouchForce > 0.0f ? MinTouchForce : -FLT_MAX, MaxTouchForce > 0.0f ? MaxTouchForce : FLT_MAX);
  7122.  
  7123.         FVector Impulse = ImpulseDir * ImpulseStrength;
  7124.  
  7125.         OtherComp->AddImpulse(Impulse, BoneName);
  7126.     }
  7127. }
  7128.  
  7129. void UCharacterMovementComponent::SetAvoidanceGroup(int32 GroupFlags)
  7130. {
  7131.     AvoidanceGroup.SetFlagsDirectly(GroupFlags);
  7132. }
  7133.  
  7134. void UCharacterMovementComponent::SetGroupsToAvoid(int32 GroupFlags)
  7135. {
  7136.     GroupsToAvoid.SetFlagsDirectly(GroupFlags);
  7137. }
  7138.  
  7139. void UCharacterMovementComponent::SetGroupsToIgnore(int32 GroupFlags)
  7140. {
  7141.     GroupsToIgnore.SetFlagsDirectly(GroupFlags);
  7142. }
  7143.  
  7144. void UCharacterMovementComponent::SetAvoidanceEnabled(bool bEnable)
  7145. {
  7146.     if (bUseRVOAvoidance != bEnable)
  7147.     {
  7148.         bUseRVOAvoidance = bEnable;
  7149.  
  7150.         // this is a safety check - it's possible to not have CharacterOwner at this point if this function gets
  7151.         // called too early
  7152.         ensure(GetCharacterOwner());
  7153.         if (GetCharacterOwner() != nullptr)
  7154.         {
  7155.             UAvoidanceManager* AvoidanceManager = GetWorld()->GetAvoidanceManager();
  7156.             if (AvoidanceManager && bEnable && AvoidanceUID == 0)
  7157.             {
  7158.                 AvoidanceManager->RegisterMovementComponent(this, AvoidanceWeight);
  7159.             }
  7160.         }
  7161.     }
  7162. }
  7163.  
  7164. void UCharacterMovementComponent::ApplyDownwardForce(float DeltaSeconds)
  7165. {
  7166.     if (StandingDownwardForceScale != 0.0f && CurrentFloor.HitResult.IsValidBlockingHit())
  7167.     {
  7168.         UPrimitiveComponent* BaseComp = CurrentFloor.HitResult.GetComponent();
  7169.         const FVector Gravity = GetGravity();
  7170.  
  7171.         if (BaseComp && BaseComp->IsAnySimulatingPhysics() && !Gravity.IsZero())
  7172.         {
  7173.             BaseComp->AddForceAtLocation(Gravity * Mass * StandingDownwardForceScale, CurrentFloor.HitResult.ImpactPoint, CurrentFloor.HitResult.BoneName);
  7174.         }
  7175.     }
  7176. }
  7177.  
  7178. void UCharacterMovementComponent::ApplyRepulsionForce(float DeltaSeconds)
  7179. {
  7180.     if (UpdatedPrimitive && RepulsionForce > 0.0f)
  7181.     {
  7182.         FCollisionQueryParams QueryParams;
  7183.         QueryParams.bReturnFaceIndex = false;
  7184.         QueryParams.bReturnPhysicalMaterial = false;
  7185.  
  7186.         const FCollisionShape CollisionShape = UpdatedPrimitive->GetCollisionShape();
  7187.         const float CapsuleHalfHeight = CollisionShape.GetCapsuleHalfHeight();
  7188.         const float RepulsionForceRadius = CollisionShape.GetCapsuleRadius() * 1.2f;
  7189.         const FVector CapsuleDown = GetCapsuleAxisZ() * -1.0f;
  7190.         const float StopBodyDistance = 2.5f;
  7191.  
  7192.         const TArray<FOverlapInfo>& Overlaps = UpdatedPrimitive->GetOverlapInfos();
  7193.         const FVector MyLocation = UpdatedPrimitive->GetComponentLocation();
  7194.  
  7195.         for (int32 i = 0; i < Overlaps.Num(); i++)
  7196.         {
  7197.             const FOverlapInfo& Overlap = Overlaps[i];
  7198.  
  7199.             UPrimitiveComponent* OverlapComp = Overlap.OverlapInfo.Component.Get();
  7200.             if (!OverlapComp || OverlapComp->Mobility < EComponentMobility::Movable)
  7201.             {
  7202.                 continue;
  7203.             }
  7204.  
  7205.             FName BoneName = NAME_None;
  7206.             if (Overlap.GetBodyIndex() != INDEX_NONE && OverlapComp->IsA(USkinnedMeshComponent::StaticClass()))
  7207.             {
  7208.                 BoneName = ((USkinnedMeshComponent*)OverlapComp)->GetBoneName(Overlap.GetBodyIndex());
  7209.             }
  7210.  
  7211.             // Use the body instead of the component for cases where we have multi-body overlaps enabled.
  7212.             FBodyInstance* OverlapBody = OverlapComp->GetBodyInstance(BoneName);
  7213.  
  7214.             if (!OverlapBody)
  7215.             {
  7216.                 UE_LOG(LogCharacterMovement, Warning, TEXT("%s could not find overlap body for bone %s"), *GetName(), *BoneName.ToString());
  7217.                 continue;
  7218.             }
  7219.  
  7220.             // Early out if this is not a destructible and the body is not simulated.
  7221.             bool bIsCompDestructible = OverlapComp->IsA(UDestructibleComponent::StaticClass());
  7222.             if (!bIsCompDestructible && !OverlapBody->IsInstanceSimulatingPhysics())
  7223.             {
  7224.                 continue;
  7225.             }
  7226.  
  7227.             const FVector BodyVelocity = OverlapBody->GetUnrealWorldVelocity();
  7228.             const FVector BodyLocation = OverlapBody->GetUnrealWorldTransform().GetLocation();
  7229.             const FVector LineTraceEnd = MyLocation + CapsuleDown * ((BodyLocation - MyLocation) | CapsuleDown);
  7230.  
  7231.             // Trace to get the hit location on the capsule.
  7232.             FHitResult Hit(1.0f);
  7233.             bool bHasHit = UpdatedPrimitive->LineTraceComponent(Hit, BodyLocation, LineTraceEnd, QueryParams);
  7234.  
  7235.             FVector HitLoc = Hit.ImpactPoint;
  7236.             bool bIsPenetrating = Hit.bStartPenetrating || Hit.PenetrationDepth > StopBodyDistance;
  7237.  
  7238.             // If we didn't hit the capsule, we're inside the capsule.
  7239.             if (!bHasHit)
  7240.             {
  7241.                 HitLoc = BodyLocation;
  7242.                 bIsPenetrating = true;
  7243.             }
  7244.  
  7245.             const float DistanceNow = FVector::VectorPlaneProject(HitLoc - BodyLocation, CapsuleDown).SizeSquared();
  7246.             const float DistanceLater = FVector::VectorPlaneProject(HitLoc - (BodyLocation + BodyVelocity * DeltaSeconds), CapsuleDown).SizeSquared();
  7247.  
  7248.             if (bHasHit && DistanceNow < StopBodyDistance && !bIsPenetrating)
  7249.             {
  7250.                 OverlapBody->SetLinearVelocity(FVector(0.0f, 0.0f, 0.0f), false);
  7251.             }
  7252.             else if (DistanceLater <= DistanceNow || bIsPenetrating)
  7253.             {
  7254.                 FVector ForceCenter = MyLocation;
  7255.  
  7256.                 if (bHasHit)
  7257.                 {
  7258.                     ForceCenter += CapsuleDown * ((HitLoc - MyLocation) | CapsuleDown);
  7259.                 }
  7260.                 else
  7261.                 {
  7262.                     // Get the axis of the capsule bounded by the following two end points.
  7263.                     const FVector BottomPoint = ForceCenter + CapsuleDown * CapsuleHalfHeight;
  7264.                     const FVector TopPoint = ForceCenter - CapsuleDown * CapsuleHalfHeight;
  7265.                     const FVector Segment = TopPoint - BottomPoint;
  7266.  
  7267.                     // Project the foreign body location on the segment.
  7268.                     const float Alpha = ((BodyLocation - BottomPoint) | Segment) / Segment.SizeSquared();
  7269.  
  7270.                     if (Alpha < 0.0f)
  7271.                     {
  7272.                         ForceCenter = BottomPoint;
  7273.                     }
  7274.                     else if (Alpha > 1.0f)
  7275.                     {
  7276.                         ForceCenter = TopPoint;
  7277.                     }
  7278.                 }
  7279.  
  7280.                 OverlapBody->AddRadialForceToBody(ForceCenter, RepulsionForceRadius, RepulsionForce * Mass, ERadialImpulseFalloff::RIF_Constant);
  7281.             }
  7282.         }
  7283.     }
  7284. }
  7285.  
  7286. void UCharacterMovementComponent::ApplyAccumulatedForces(float DeltaSeconds)
  7287. {
  7288.     if ((!PendingImpulseToApply.IsZero() || !PendingForceToApply.IsZero()) && IsMovingOnGround())
  7289.     {
  7290.         const FVector Impulse = PendingImpulseToApply + PendingForceToApply * DeltaSeconds + GetGravity() * DeltaSeconds;
  7291.  
  7292.         // Check to see if applied momentum is enough to overcome gravity.
  7293.         if ((Impulse | GetCapsuleAxisZ()) > SMALL_NUMBER)
  7294.         {
  7295.             SetMovementMode(MOVE_Falling);
  7296.         }
  7297.     }
  7298.  
  7299.     Velocity += PendingImpulseToApply + PendingForceToApply * DeltaSeconds;
  7300.  
  7301.     PendingImpulseToApply = FVector::ZeroVector;
  7302.     PendingForceToApply = FVector::ZeroVector;
  7303. }
  7304.  
  7305. void UCharacterMovementComponent::AddRadialForce(const FVector& Origin, float Radius, float Strength, enum ERadialImpulseFalloff Falloff)
  7306. {
  7307.     FVector Delta = UpdatedComponent->GetComponentLocation() - Origin;
  7308.     const float DeltaMagnitude = Delta.Size();
  7309.  
  7310.     // Do nothing if outside radius
  7311.     if (DeltaMagnitude > Radius)
  7312.     {
  7313.         return;
  7314.     }
  7315.  
  7316.     Delta = Delta.GetSafeNormal();
  7317.  
  7318.     float ForceMagnitude = Strength;
  7319.     if (Falloff == RIF_Linear && Radius > 0.0f)
  7320.     {
  7321.         ForceMagnitude *= (1.0f - (DeltaMagnitude / Radius));
  7322.     }
  7323.  
  7324.     AddForce(Delta * ForceMagnitude);
  7325. }
  7326.  
  7327. void UCharacterMovementComponent::AddRadialImpulse(const FVector& Origin, float Radius, float Strength, enum ERadialImpulseFalloff Falloff, bool bVelChange)
  7328. {
  7329.     FVector Delta = UpdatedComponent->GetComponentLocation() - Origin;
  7330.     const float DeltaMagnitude = Delta.Size();
  7331.  
  7332.     // Do nothing if outside radius
  7333.     if (DeltaMagnitude > Radius)
  7334.     {
  7335.         return;
  7336.     }
  7337.  
  7338.     Delta = Delta.GetSafeNormal();
  7339.  
  7340.     float ImpulseMagnitude = Strength;
  7341.     if (Falloff == RIF_Linear && Radius > 0.0f)
  7342.     {
  7343.         ImpulseMagnitude *= (1.0f - (DeltaMagnitude / Radius));
  7344.     }
  7345.  
  7346.     AddImpulse(Delta * ImpulseMagnitude, bVelChange);
  7347. }
  7348.  
  7349. void UCharacterMovementComponent::RegisterComponentTickFunctions(bool bRegister)
  7350. {
  7351.     Super::RegisterComponentTickFunctions(bRegister);
  7352.  
  7353.     if (bRegister)
  7354.     {
  7355.         if (SetupActorComponentTickFunction(&PreClothComponentTick))
  7356.         {
  7357.             PreClothComponentTick.Target = this;
  7358.         }
  7359.     }
  7360.     else
  7361.     {
  7362.         if (PreClothComponentTick.IsTickFunctionRegistered())
  7363.         {
  7364.             PreClothComponentTick.UnRegisterTickFunction();
  7365.         }
  7366.     }
  7367. }
  7368.  
  7369. void UCharacterMovementComponent::TickCharacterPose(float DeltaTime)
  7370. {
  7371.     check(CharacterOwner && CharacterOwner->GetMesh());
  7372.  
  7373.     // Keep track of if we're playing root motion, just in case the root motion montage ends this frame.
  7374.     bool bWasPlayingRootMotion = CharacterOwner->IsPlayingRootMotion();
  7375.  
  7376.     CharacterOwner->GetMesh()->TickPose(DeltaTime, true);
  7377.  
  7378.     // Grab root motion now that we have ticked the pose
  7379.     if (CharacterOwner->IsPlayingRootMotion() || bWasPlayingRootMotion)
  7380.     {
  7381.         FRootMotionMovementParams RootMotion = CharacterOwner->GetMesh()->ConsumeRootMotion();
  7382.         if (RootMotion.bHasRootMotion)
  7383.         {
  7384.             RootMotionParams.Accumulate(RootMotion);
  7385.         }
  7386.  
  7387.         // Debugging
  7388.         {
  7389.             FAnimMontageInstance* RootMotionMontageInstance = CharacterOwner->GetRootMotionAnimMontageInstance();
  7390.             UE_LOG(LogRootMotion, Log, TEXT("UCharacterMovementComponent::TickCharacterPose Role: %s, RootMotionMontage: %s, MontagePos: %f, DeltaTime: %f, ExtractedRootMotion: %s, AccumulatedRootMotion: %s")
  7391.                 , *UEnum::GetValueAsString(TEXT("Engine.ENetRole"), CharacterOwner->Role)
  7392.                 , *GetNameSafe(RootMotionMontageInstance ? RootMotionMontageInstance->Montage : NULL)
  7393.                 , RootMotionMontageInstance ? RootMotionMontageInstance->GetPosition() : -1.f
  7394.                 , DeltaTime
  7395.                 , *RootMotion.RootMotionTransform.GetTranslation().ToCompactString()
  7396.                 , *RootMotionParams.RootMotionTransform.GetTranslation().ToCompactString()
  7397.                 );
  7398.         }
  7399.     }
  7400. }
  7401.  
  7402. FNetworkPredictionData_Client_Character::FNetworkPredictionData_Client_Character(const UCharacterMovementComponent& ClientMovement)
  7403.     : ClientUpdateTime(0.f)
  7404.     , CurrentTimeStamp(0.f)
  7405.     , PendingMove(NULL)
  7406.     , LastAckedMove(NULL)
  7407.     , MaxFreeMoveCount(32)
  7408.     , MaxSavedMoveCount(96)
  7409.     , bUpdatePosition(false)
  7410.     , bSmoothNetUpdates(false)
  7411.     , MeshTranslationOffset(ForceInitToZero)
  7412.     , MeshRotationOffset(FQuat::Identity)
  7413.     , OriginalMeshTranslationOffset(ForceInitToZero)
  7414.     , OriginalMeshRotationOffset(FQuat::Identity)
  7415.     , LastCorrectionDelta(0.f)
  7416.     , CurrentSmoothTime(0.f)
  7417.     , bUseLinearSmoothing(false)
  7418.     , MaxSmoothNetUpdateDist(0.f)
  7419.     , NoSmoothNetUpdateDist(0.f)
  7420.     , SmoothNetUpdateTime(0.f)
  7421.     , SmoothNetUpdateRotationTime(0.f)
  7422.     , MaxResponseTime(0.f)
  7423. {
  7424.     bSmoothNetUpdates = true;
  7425.     MaxSmoothNetUpdateDist = 84.0;
  7426.     NoSmoothNetUpdateDist = 128.0;
  7427.     SmoothNetUpdateTime = ClientMovement.NetworkSimulatedSmoothLocationTime;
  7428.     SmoothNetUpdateRotationTime = ClientMovement.NetworkSimulatedSmoothRotationTime;
  7429.  
  7430.     MaxResponseTime = 0.125f;
  7431. }
  7432.  
  7433.  
  7434. FNetworkPredictionData_Client_Character::~FNetworkPredictionData_Client_Character()
  7435. {
  7436.     SavedMoves.Empty();
  7437.     FreeMoves.Empty();
  7438.     PendingMove = NULL;
  7439.     LastAckedMove = NULL;
  7440. }
  7441.  
  7442.  
  7443. FSavedMovePtr FNetworkPredictionData_Client_Character::CreateSavedMove()
  7444. {
  7445.     if (SavedMoves.Num() >= MaxSavedMoveCount)
  7446.     {
  7447.         UE_LOG(LogNetPlayerMovement, Warning, TEXT("CreateSavedMove: Hit limit of %d saved moves (timing out or very bad ping?)"), SavedMoves.Num());
  7448.         // Free all saved moves
  7449.         for (int32 i = 0; i < SavedMoves.Num(); i++)
  7450.         {
  7451.             FreeMove(SavedMoves[i]);
  7452.         }
  7453.         SavedMoves.Reset();
  7454.     }
  7455.  
  7456.     if (FreeMoves.Num() == 0)
  7457.     {
  7458.         // No free moves, allocate a new one.
  7459.         FSavedMovePtr NewMove = AllocateNewMove();
  7460.         check(NewMove.IsValid());
  7461.         NewMove->Clear();
  7462.         return NewMove;
  7463.     }
  7464.     else
  7465.     {
  7466.         // Pull from the free pool
  7467.         FSavedMovePtr FirstFree = FreeMoves.Pop();
  7468.         FirstFree->Clear();
  7469.         return FirstFree;
  7470.     }
  7471. }
  7472.  
  7473.  
  7474. FSavedMovePtr FNetworkPredictionData_Client_Character::AllocateNewMove()
  7475. {
  7476.     return FSavedMovePtr(new FSavedMove_Character());
  7477. }
  7478.  
  7479.  
  7480. void FNetworkPredictionData_Client_Character::FreeMove(const FSavedMovePtr& Move)
  7481. {
  7482.     if (Move.IsValid())
  7483.     {
  7484.         // Only keep a pool of a limited number of moves.
  7485.         if (FreeMoves.Num() < MaxFreeMoveCount)
  7486.         {
  7487.             FreeMoves.Push(Move);
  7488.         }
  7489.  
  7490.         // Shouldn't keep a reference to the move on the free list.
  7491.         if (PendingMove == Move)
  7492.         {
  7493.             PendingMove = NULL;
  7494.         }
  7495.         if (LastAckedMove == Move)
  7496.         {
  7497.             LastAckedMove = NULL;
  7498.         }
  7499.     }
  7500. }
  7501.  
  7502. int32 FNetworkPredictionData_Client_Character::GetSavedMoveIndex(float TimeStamp) const
  7503. {
  7504.     if (SavedMoves.Num() > 0)
  7505.     {
  7506.         // If LastAckedMove isn't using an old TimeStamp (before reset), we can prevent the iteration if incoming TimeStamp is outdated
  7507.         if (LastAckedMove.IsValid() && !LastAckedMove->bOldTimeStampBeforeReset && (TimeStamp <= LastAckedMove->TimeStamp))
  7508.         {
  7509.             return INDEX_NONE;
  7510.         }
  7511.  
  7512.         // Otherwise see if we can find this move.
  7513.         for (int32 Index = 0; Index<SavedMoves.Num(); Index++)
  7514.         {
  7515.             const FSavedMovePtr& CurrentMove = SavedMoves[Index];
  7516.             if (CurrentMove->TimeStamp == TimeStamp)
  7517.             {
  7518.                 return Index;
  7519.             }
  7520.         }
  7521.     }
  7522.     return INDEX_NONE;
  7523. }
  7524.  
  7525. void FNetworkPredictionData_Client_Character::AckMove(int32 AckedMoveIndex)
  7526. {
  7527.     // It is important that we know the move exists before we go deleting outdated moves.
  7528.     // Timestamps are not guaranteed to be increasing order all the time, since they can be reset!
  7529.     if (AckedMoveIndex != INDEX_NONE)
  7530.     {
  7531.         // Keep reference to LastAckedMove
  7532.         const FSavedMovePtr& AckedMove = SavedMoves[AckedMoveIndex];
  7533.         UE_LOG(LogNetPlayerMovement, VeryVerbose, TEXT("AckedMove Index: %2d (%2d moves). TimeStamp: %f, CurrentTimeStamp: %f"), AckedMoveIndex, SavedMoves.Num(), AckedMove->TimeStamp, CurrentTimeStamp);
  7534.         if (LastAckedMove.IsValid())
  7535.         {
  7536.             FreeMove(LastAckedMove);
  7537.         }
  7538.         LastAckedMove = AckedMove;
  7539.  
  7540.         // Free expired moves.
  7541.         for (int32 MoveIndex = 0; MoveIndex<AckedMoveIndex; MoveIndex++)
  7542.         {
  7543.             const FSavedMovePtr& Move = SavedMoves[MoveIndex];
  7544.             FreeMove(Move);
  7545.         }
  7546.  
  7547.         // And finally cull all of those, so only the unacknowledged moves remain in SavedMoves.
  7548.         SavedMoves.RemoveAt(0, AckedMoveIndex + 1);
  7549.     }
  7550. }
  7551.  
  7552. FNetworkPredictionData_Server_Character::FNetworkPredictionData_Server_Character()
  7553.     : PendingAdjustment()
  7554.     , CurrentClientTimeStamp(0.f)
  7555.     , LastUpdateTime(0.f)
  7556.     , MaxResponseTime(0.125f)
  7557.     , bForceClientUpdate(false)
  7558. {
  7559. }
  7560.  
  7561.  
  7562. FNetworkPredictionData_Server_Character::~FNetworkPredictionData_Server_Character()
  7563. {
  7564. }
  7565.  
  7566.  
  7567. float FNetworkPredictionData_Server_Character::GetServerMoveDeltaTime(float TimeStamp) const
  7568. {
  7569.     const float DeltaTime = FMath::Min(MaxResponseTime, TimeStamp - CurrentClientTimeStamp);
  7570.     return DeltaTime;
  7571. }
  7572.  
  7573.  
  7574. FSavedMove_Character::FSavedMove_Character()
  7575. {
  7576.     AccelMagThreshold = 1.f;
  7577.     AccelDotThreshold = 0.9f;
  7578.     AccelDotThresholdCombine = 0.996f; // approx 5 degrees.
  7579. }
  7580.  
  7581. FSavedMove_Character::~FSavedMove_Character()
  7582. {
  7583. }
  7584.  
  7585. void FSavedMove_Character::Clear()
  7586. {
  7587.     bPressedJump = false;
  7588.     bWantsToCrouch = false;
  7589.     bForceMaxAccel = false;
  7590.     bForceNoCombine = false;
  7591.     bOldTimeStampBeforeReset = false;
  7592.  
  7593.     TimeStamp = 0.f;
  7594.     DeltaTime = 0.f;
  7595.     CustomTimeDilation = 1.0f;
  7596.     JumpKeyHoldTime = 0.0f;
  7597.     MovementMode = 0;
  7598.  
  7599.     StartLocation = FVector::ZeroVector;
  7600.     StartRelativeLocation = FVector::ZeroVector;
  7601.     StartVelocity = FVector::ZeroVector;
  7602.     StartFloor = FFindFloorResult();
  7603.     StartRotation = FRotator::ZeroRotator;
  7604.     StartControlRotation = FRotator::ZeroRotator;
  7605.     StartBaseRotation = FQuat::Identity;
  7606.     StartCapsuleRadius = 0.f;
  7607.     StartCapsuleHalfHeight = 0.f;
  7608.     StartBase = NULL;
  7609.     StartBoneName = NAME_None;
  7610.  
  7611.     SavedLocation = FVector::ZeroVector;
  7612.     SavedRotation = FRotator::ZeroRotator;
  7613.     SavedRelativeLocation = FVector::ZeroVector;
  7614.     Acceleration = FVector::ZeroVector;
  7615.     SavedControlRotation = FRotator::ZeroRotator;
  7616.     EndBase = NULL;
  7617.     EndBoneName = NAME_None;
  7618.  
  7619.     RootMotionMontage = NULL;
  7620.     RootMotionTrackPosition = 0.f;
  7621.     RootMotionMovement.Clear();
  7622. }
  7623.  
  7624.  
  7625. void FSavedMove_Character::SetMoveFor(ACharacter* Character, float InDeltaTime, FVector const& NewAccel, class FNetworkPredictionData_Client_Character & ClientData)
  7626. {
  7627.     DeltaTime = InDeltaTime;
  7628.  
  7629.     SetInitialPosition(Character);
  7630.  
  7631.     AccelMag = NewAccel.Size();
  7632.     AccelNormal = (AccelMag > SMALL_NUMBER ? NewAccel / AccelMag : FVector::ZeroVector);
  7633.  
  7634.     // Round value, so that client and server match exactly (and so we can send with less bandwidth). This rounded value is copied back to the client in ReplicateMoveToServer.
  7635.     // This is done after the AccelMag and AccelNormal are computed above, because those are only used client-side for combining move logic and need to remain accurate.
  7636.     Acceleration = Character->GetCharacterMovement()->RoundAcceleration(NewAccel);
  7637.  
  7638.     bPressedJump = Character->bPressedJump;
  7639.     JumpKeyHoldTime = Character->JumpKeyHoldTime;
  7640.     bWantsToCrouch = Character->GetCharacterMovement()->bWantsToCrouch;
  7641.     bForceMaxAccel = Character->GetCharacterMovement()->bForceMaxAccel;
  7642.     MovementMode = Character->GetCharacterMovement()->PackNetworkMovementMode();
  7643.  
  7644.     TimeStamp = ClientData.CurrentTimeStamp;
  7645. }
  7646.  
  7647. void FSavedMove_Character::SetInitialPosition(ACharacter* Character)
  7648. {
  7649.     StartLocation = Character->GetActorLocation();
  7650.     StartRotation = Character->GetActorRotation();
  7651.     StartVelocity = Character->GetCharacterMovement()->Velocity;
  7652.     UPrimitiveComponent* const MovementBase = Character->GetMovementBase();
  7653.     StartBase = MovementBase;
  7654.     StartBaseRotation = FQuat::Identity;
  7655.     StartFloor = Character->GetCharacterMovement()->CurrentFloor;
  7656.     CustomTimeDilation = Character->CustomTimeDilation;
  7657.     StartBoneName = Character->GetBasedMovement().BoneName;
  7658.  
  7659.     if (MovementBaseUtility::UseRelativeLocation(MovementBase))
  7660.     {
  7661.         StartRelativeLocation = Character->GetBasedMovement().Location;
  7662.         FVector StartBaseLocation_Unused;
  7663.         MovementBaseUtility::GetMovementBaseTransform(MovementBase, StartBoneName, StartBaseLocation_Unused, StartBaseRotation);
  7664.     }
  7665.  
  7666.     StartControlRotation = Character->GetControlRotation().Clamp();
  7667.     Character->GetCapsuleComponent()->GetScaledCapsuleSize(StartCapsuleRadius, StartCapsuleHalfHeight);
  7668. }
  7669.  
  7670. void FSavedMove_Character::PostUpdate(ACharacter* Character, FSavedMove_Character::EPostUpdateMode PostUpdateMode)
  7671. {
  7672.     // Common code for both recording and after a replay.
  7673.     {
  7674.         MovementMode = Character->GetCharacterMovement()->PackNetworkMovementMode();
  7675.         SavedLocation = Character->GetActorLocation();
  7676.         SavedRotation = Character->GetActorRotation();
  7677.         UPrimitiveComponent* const MovementBase = Character->GetMovementBase();
  7678.         EndBase = MovementBase;
  7679.         EndBoneName = Character->GetBasedMovement().BoneName;
  7680.         if (MovementBaseUtility::UseRelativeLocation(MovementBase))
  7681.         {
  7682.             SavedRelativeLocation = Character->GetBasedMovement().Location;
  7683.         }
  7684.  
  7685.         SavedControlRotation = Character->GetControlRotation().Clamp();
  7686.     }
  7687.  
  7688.     // Only save RootMotion params when initially recording
  7689.     if (PostUpdateMode == PostUpdate_Record)
  7690.     {
  7691.         const FAnimMontageInstance* RootMotionMontageInstance = Character->GetRootMotionAnimMontageInstance();
  7692.         if (RootMotionMontageInstance)
  7693.         {
  7694.             RootMotionMontage = RootMotionMontageInstance->Montage;
  7695.             RootMotionTrackPosition = RootMotionMontageInstance->GetPosition();
  7696.             RootMotionMovement = Character->ClientRootMotionParams;
  7697.         }
  7698.     }
  7699. }
  7700.  
  7701. bool FSavedMove_Character::IsImportantMove(const FSavedMovePtr& LastAckedMove) const
  7702. {
  7703.     // Check if any important movement flags have changed status.
  7704.     if ((bPressedJump != LastAckedMove->bPressedJump) || (bWantsToCrouch != LastAckedMove->bWantsToCrouch))
  7705.     {
  7706.         return true;
  7707.     }
  7708.  
  7709.     if (MovementMode != LastAckedMove->MovementMode)
  7710.     {
  7711.         return true;
  7712.     }
  7713.  
  7714.     // check if acceleration has changed significantly
  7715.     if (Acceleration != LastAckedMove->Acceleration)
  7716.     {
  7717.         // Compare magnitude and orientation
  7718.         if ((FMath::Abs(AccelMag - LastAckedMove->AccelMag) > AccelMagThreshold) || ((AccelNormal | LastAckedMove->AccelNormal) < AccelDotThreshold))
  7719.         {
  7720.             return true;
  7721.         }
  7722.     }
  7723.     return false;
  7724. }
  7725.  
  7726. FVector FSavedMove_Character::GetRevertedLocation() const
  7727. {
  7728.     const UPrimitiveComponent* MovementBase = StartBase.Get();
  7729.     if (MovementBaseUtility::UseRelativeLocation(MovementBase))
  7730.     {
  7731.         FVector BaseLocation; FQuat BaseRotation;
  7732.         MovementBaseUtility::GetMovementBaseTransform(MovementBase, StartBoneName, BaseLocation, BaseRotation);
  7733.         return BaseLocation + StartRelativeLocation;
  7734.     }
  7735.  
  7736.     return StartLocation;
  7737. }
  7738.  
  7739. bool UCharacterMovementComponent::CanDelaySendingMove(const FSavedMovePtr& NewMove)
  7740. {
  7741.     return true;
  7742. }
  7743.  
  7744. bool FSavedMove_Character::CanCombineWith(const FSavedMovePtr& NewMove, ACharacter* Character, float MaxDelta) const
  7745. {
  7746.     if (bForceNoCombine || NewMove->bForceNoCombine)
  7747.     {
  7748.         return false;
  7749.     }
  7750.  
  7751.     // Cannot combine moves which contain root motion for now.
  7752.     // @fixme laurent - we should be able to combine most of them though, but current scheme of resetting pawn location and resimulating forward doesn't work.
  7753.     // as we don't want to tick montage twice (so we don't fire events twice). So we need to rearchitecture this so we tick only the second part of the move, and reuse the first part.
  7754.     if ((RootMotionMontage != NULL) || (NewMove->RootMotionMontage != NULL))
  7755.     {
  7756.         return false;
  7757.     }
  7758.  
  7759.     if (NewMove->Acceleration.IsZero())
  7760.     {
  7761.         return Acceleration.IsZero()
  7762.             && StartVelocity.IsZero()
  7763.             && NewMove->StartVelocity.IsZero()
  7764.             && !bPressedJump && !NewMove->bPressedJump
  7765.             && bWantsToCrouch == NewMove->bWantsToCrouch
  7766.             && StartBase == NewMove->StartBase
  7767.             && StartBoneName == NewMove->StartBoneName
  7768.             && MovementMode == NewMove->MovementMode
  7769.             && StartCapsuleRadius == NewMove->StartCapsuleRadius
  7770.             && StartCapsuleHalfHeight == NewMove->StartCapsuleHalfHeight
  7771.             && StartBaseRotation.Equals(NewMove->StartBaseRotation) // only if base hasn't rotated
  7772.             && (CustomTimeDilation == NewMove->CustomTimeDilation);
  7773.     }
  7774.     else
  7775.     {
  7776.         return (NewMove->DeltaTime + DeltaTime < MaxDelta)
  7777.             && !bPressedJump && !NewMove->bPressedJump
  7778.             && bWantsToCrouch == NewMove->bWantsToCrouch
  7779.             && StartBase == NewMove->StartBase
  7780.             && StartBoneName == NewMove->StartBoneName
  7781.             && MovementMode == NewMove->MovementMode
  7782.             && StartCapsuleRadius == NewMove->StartCapsuleRadius
  7783.             && StartCapsuleHalfHeight == NewMove->StartCapsuleHalfHeight
  7784.             && FVector::Coincident(AccelNormal, NewMove->AccelNormal, AccelDotThresholdCombine)
  7785.             && StartBaseRotation.Equals(NewMove->StartBaseRotation) // only if base hasn't rotated
  7786.             && (CustomTimeDilation == NewMove->CustomTimeDilation);
  7787.     }
  7788. }
  7789.  
  7790. void FSavedMove_Character::PrepMoveFor(ACharacter* Character)
  7791. {
  7792.     if (RootMotionMontage != NULL)
  7793.     {
  7794.         // If we need to resimulate Root Motion, then do so.
  7795.         if (Character->bClientResimulateRootMotion)
  7796.         {
  7797.             // Make sure RootMotion montage matches what we are playing now.
  7798.             FAnimMontageInstance * RootMotionMontageInstance = Character->GetRootMotionAnimMontageInstance();
  7799.             if (RootMotionMontageInstance && (RootMotionMontage == RootMotionMontageInstance->Montage))
  7800.             {
  7801.                 RootMotionMovement.Clear();
  7802.                 RootMotionTrackPosition = RootMotionMontageInstance->GetPosition();
  7803.                 RootMotionMontageInstance->SimulateAdvance(DeltaTime, RootMotionTrackPosition, RootMotionMovement);
  7804.                 RootMotionMontageInstance->SetPosition(RootMotionTrackPosition);
  7805.             }
  7806.         }
  7807.         Character->GetCharacterMovement()->RootMotionParams = RootMotionMovement;
  7808.     }
  7809.  
  7810.     Character->GetCharacterMovement()->bForceMaxAccel = bForceMaxAccel;
  7811.     Character->JumpKeyHoldTime = JumpKeyHoldTime;
  7812. }
  7813.  
  7814.  
  7815. uint8 FSavedMove_Character::GetCompressedFlags() const
  7816. {
  7817.     uint8 Result = 0;
  7818.  
  7819.     if (bPressedJump)
  7820.     {
  7821.         Result |= FLAG_JumpPressed;
  7822.     }
  7823.  
  7824.     if (bWantsToCrouch)
  7825.     {
  7826.         Result |= FLAG_WantsToCrouch;
  7827.     }
  7828.  
  7829.     return Result;
  7830. }
  7831.  
  7832. void UCharacterMovementComponent::UpdateFromCompressedFlags(uint8 Flags)
  7833. {
  7834.     if (!CharacterOwner)
  7835.     {
  7836.         return;
  7837.     }
  7838.  
  7839.     const bool bWasJumping = CharacterOwner->bPressedJump;
  7840.  
  7841.     CharacterOwner->bPressedJump = ((Flags & FSavedMove_Character::FLAG_JumpPressed) != 0);
  7842.     bWantsToCrouch = ((Flags & FSavedMove_Character::FLAG_WantsToCrouch) != 0);
  7843.  
  7844.     // Reset JumpKeyHoldTime when player presses Jump key on server as well.
  7845.     if (!bWasJumping && CharacterOwner->bPressedJump)
  7846.     {
  7847.         CharacterOwner->JumpKeyHoldTime = 0.0f;
  7848.     }
  7849. }
  7850.  
  7851. bool UCharacterMovementComponent::MoveUpdatedComponent(const FVector& Delta, const FRotator& NewRotation, bool bSweep, FHitResult* OutHit)
  7852. {
  7853.     if (UpdatedComponent)
  7854.     {
  7855.         return Super::MoveUpdatedComponent(Delta, ConstrainComponentRotation(NewRotation), bSweep, OutHit);
  7856.     }
  7857.  
  7858.     return false;
  7859. }
  7860.  
  7861. FRotator UCharacterMovementComponent::ConstrainComponentRotation(const FRotator& Rotation) const
  7862. {
  7863.     // Keep current Z rotation axis of capsule, try to keep X axis of rotation.
  7864.     return FRotationMatrix::MakeFromZX(GetCapsuleAxisZ(), Rotation.Vector()).Rotator();
  7865. }
  7866.  
  7867. FVector UCharacterMovementComponent::GetComponentDesiredAxisZ() const
  7868. {
  7869.     return GetGravityDirection(true) * -1.0f;
  7870. }
  7871.  
  7872. void UCharacterMovementComponent::UpdateComponentRotation()
  7873. {
  7874.     if (!UpdatedComponent)
  7875.     {
  7876.         return;
  7877.     }
  7878.  
  7879.     const FVector DesiredCapsuleUp = GetComponentDesiredAxisZ();
  7880.  
  7881.     // Abort if angle between new and old capsule 'up' axis almost equals to 0 degrees.
  7882.     if ((DesiredCapsuleUp | GetCapsuleAxisZ()) >= THRESH_NORMALS_ARE_PARALLEL)
  7883.     {
  7884.         return;
  7885.     }
  7886.  
  7887.     // Take desired Z rotation axis of capsule, try to keep current X rotation axis of capsule.
  7888.     const FMatrix RotationMatrix = FRotationMatrix::MakeFromZX(DesiredCapsuleUp, GetCapsuleAxisX());
  7889.  
  7890.     // Intentionally not using MoveUpdatedComponent to bypass constraints.
  7891.     UpdatedComponent->MoveComponent(FVector::ZeroVector, RotationMatrix.Rotator(), true);
  7892. }
  7893.  
  7894. FORCEINLINE FQuat UCharacterMovementComponent::GetCapsuleRotation() const
  7895. {
  7896.     return UpdatedComponent->GetComponentQuat();
  7897. }
  7898.  
  7899. FORCEINLINE FVector UCharacterMovementComponent::GetCapsuleAxisX() const
  7900. {
  7901.     // Fast simplification of FQuat::RotateVector() with FVector(1,0,0).
  7902.     const FQuat CapsuleRotation = GetCapsuleRotation();
  7903.     const FVector QuatVector(CapsuleRotation.X, CapsuleRotation.Y, CapsuleRotation.Z);
  7904.  
  7905.     return FVector(FMath::Square(CapsuleRotation.W) - QuatVector.SizeSquared(), CapsuleRotation.Z * CapsuleRotation.W * 2.0f,
  7906.         CapsuleRotation.Y * CapsuleRotation.W * -2.0f) + QuatVector * (CapsuleRotation.X * 2.0f);
  7907. }
  7908.  
  7909. FORCEINLINE FVector UCharacterMovementComponent::GetCapsuleAxisZ() const
  7910. {
  7911.     // Fast simplification of FQuat::RotateVector() with FVector(0,0,1).
  7912.     const FQuat CapsuleRotation = GetCapsuleRotation();
  7913.     const FVector QuatVector(CapsuleRotation.X, CapsuleRotation.Y, CapsuleRotation.Z);
  7914.  
  7915.     return FVector(CapsuleRotation.Y * CapsuleRotation.W * 2.0f, CapsuleRotation.X * CapsuleRotation.W * -2.0f,
  7916.         FMath::Square(CapsuleRotation.W) - QuatVector.SizeSquared()) + QuatVector * (CapsuleRotation.Z * 2.0f);
  7917. }
  7918.  
  7919. void UCharacterMovementComponent::UpdateGravity(float DeltaTime)
  7920. {
  7921.     UpdateComponentRotation();
  7922. }
  7923.  
  7924. FVector UCharacterMovementComponent::GetGravity() const
  7925. {
  7926.     if (!CustomGravityDirection.IsZero())
  7927.     {
  7928.         return CustomGravityDirection * (FMath::Abs(Super::GetGravityZ()) * GravityScale);
  7929.     }
  7930.  
  7931.     return FVector(0.0f, 0.0f, GetGravityZ());
  7932. }
  7933.  
  7934. FVector UCharacterMovementComponent::GetGravityDirection(bool bAvoidZeroGravity) const
  7935. {
  7936.     // Gravity direction can be influenced by the custom gravity scale value.
  7937.     if (GravityScale != 0.0f)
  7938.     {
  7939.         if (!CustomGravityDirection.IsZero())
  7940.         {
  7941.             return CustomGravityDirection * ((GravityScale > 0.0f) ? 1.0f : -1.0f);
  7942.         }
  7943.  
  7944.         const float WorldGravityZ = Super::GetGravityZ();
  7945.         if (bAvoidZeroGravity || WorldGravityZ != 0.0f)
  7946.         {
  7947.             return FVector(0.0f, 0.0f, ((WorldGravityZ > 0.0f) ? 1.0f : -1.0f) * ((GravityScale > 0.0f) ? 1.0f : -1.0f));
  7948.         }
  7949.     }
  7950.     else if (bAvoidZeroGravity)
  7951.     {
  7952.         if (!CustomGravityDirection.IsZero())
  7953.         {
  7954.             return CustomGravityDirection;
  7955.         }
  7956.  
  7957.         return FVector(0.0f, 0.0f, (Super::GetGravityZ() > 0.0f) ? 1.0f : -1.0f);
  7958.     }
  7959.  
  7960.     return FVector::ZeroVector;
  7961. }
  7962.  
  7963. float UCharacterMovementComponent::GetGravityMagnitude() const
  7964. {
  7965.     return FMath::Abs(GetGravityZ());
  7966. }
  7967.  
  7968. void UCharacterMovementComponent::SetGravityDirection(FVector NewGravityDirection)
  7969. {
  7970.     CustomGravityDirection = NewGravityDirection.GetSafeNormal();
  7971. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement