Advertisement
Guest User

ue4 character movement component

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