第一次提交

This commit is contained in:
不明不惑
2026-03-03 01:23:02 +08:00
commit 3e434877e8
1053 changed files with 102411 additions and 0 deletions

View File

@@ -0,0 +1,753 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#include "GMS_MoverMovementSystemComponent.h"
#include "PoseSearch/PoseSearchTrajectoryPredictor.h"
#include "Runtime/Launch/Resources/Version.h"
#include "GameFramework/Pawn.h"
#include "Components/SkeletalMeshComponent.h"
#include "MoverComponent.h"
#include "MoverPoseSearchTrajectoryPredictor.h"
#include "BoneControllers/AnimNode_OffsetRootBone.h"
#include "Components/CapsuleComponent.h"
#include "DefaultMovementSet/CharacterMoverComponent.h"
#include "DefaultMovementSet/NavMoverComponent.h"
#include "DefaultMovementSet/Settings/CommonLegacyMovementSettings.h"
#include "Locomotions/GMS_MainAnimInstance.h"
#include "MoveLibrary/MovementMixer.h"
#include "Mover/GMS_MoverStructLibrary.h"
#include "Mover/Modifers/GMS_MovementStateModifer.h"
#include "Net/UnrealNetwork.h"
#include "Net/Core/PushModel/PushModel.h"
#include "Settings/GMS_SettingObjectLibrary.h"
#include "Utility/GMS_Constants.h"
#include "Utility/GMS_Log.h"
#include "Utility/GMS_Math.h"
#include "Utility/GMS_Utility.h"
#include "Utility/GMS_Vector.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(GMS_MoverMovementSystemComponent)
UGMS_MoverMovementSystemComponent::UGMS_MoverMovementSystemComponent(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
SetIsReplicatedByDefault(true);
PrimaryComponentTick.bCanEverTick = true;
bWantsInitializeComponent = true;
bReplicateUsingRegisteredSubObjectList = true;
MovementModeToTagMapping = {
{TEXT("None"), GMS_MovementModeTags::None},
{TEXT("Walking"), GMS_MovementModeTags::Grounded},
{TEXT("NavWalking"), GMS_MovementModeTags::Grounded},
{TEXT("Falling"), GMS_MovementModeTags::InAir},
{TEXT("Swimming"), GMS_MovementModeTags::Swimming},
{TEXT("Flying"), GMS_MovementModeTags::Flying},
};
}
void UGMS_MoverMovementSystemComponent::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
FDoRepLifetimeParams Parameters;
Parameters.bIsPushBased = true;
Parameters.Condition = COND_SkipOwner;
DOREPLIFETIME_WITH_PARAMS_FAST(ThisClass, MovementState, Parameters)
DOREPLIFETIME_WITH_PARAMS_FAST(ThisClass, RotationMode, Parameters)
}
void UGMS_MoverMovementSystemComponent::InitializeComponent()
{
Super::InitializeComponent();
MovementState = DesiredMovementState;
RotationMode = DesiredRotationMode;
MoverComponent = OwnerPawn->FindComponentByClass<UMoverComponent>();
if (MoverComponent)
{
TrajectoryPredictor = NewObject<UMoverTrajectoryPredictor>(this, UMoverTrajectoryPredictor::StaticClass());
TrajectoryPredictor->Setup(MoverComponent);
MoverComponent->InputProducer = this;
if (!MoverComponent->MovementMixer)
{
// Prevent crash by early create this object on initialzie component.
MoverComponent->MovementMixer = NewObject<UMovementMixer>(this, TEXT("Default Movement Mixer"));
}
// Make sure this component are ticking after the mover component so this component can access the most up-to-date mover state.
AddTickPrerequisiteComponent(MoverComponent);
}
NavMoverComponent = OwnerPawn->FindComponentByClass<UNavMoverComponent>();
MeshComponent = OwnerPawn->FindComponentByClass<USkeletalMeshComponent>();
if (MeshComponent)
{
AnimationInstance = MeshComponent->GetAnimInstance();
// Make sure the mesh and animation blueprint are ticking after the character so they can access the most up-to-date character state.
MeshComponent->AddTickPrerequisiteComponent(this);
}
}
// Called when the game starts
void UGMS_MoverMovementSystemComponent::BeginPlay()
{
Super::BeginPlay();
//This callback fires only on predicting client and server, not simulated pawn.
MoverComponent->OnMovementModeChanged.AddDynamic(this, &ThisClass::OnMoverMovementModeChanged);
RefreshMovementSetSetting();
MoverComponent->OnPreSimulationTick.AddDynamic(this, &ThisClass::OnMoverPreSimulationTick);
}
void UGMS_MoverMovementSystemComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
if (IsValid(MoverComponent))
{
MoverComponent->OnMovementModeChanged.RemoveDynamic(this, &ThisClass::OnMoverMovementModeChanged);
}
Super::EndPlay(EndPlayReason);
}
// Called every frame
void UGMS_MoverMovementSystemComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
DECLARE_SCOPE_CYCLE_COUNTER(TEXT("UGMS_MoverMovementSystemComponent::TickComponent"), STAT_GMS_MovementSystem_Tick, STATGROUP_GMS)
TRACE_CPUPROFILER_EVENT_SCOPE_STR(__FUNCTION__)
if (!GetMovementDefinition().IsValid() || !IsValid(AnimationInstance) || !IsValid(ControlSetting))
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
return;
}
RefreshMovementBase();
RefreshInput(DeltaTime);
RefreshLocomotionEarly();
RefreshView(DeltaTime);
RefreshLocomotion(DeltaTime);
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
RefreshLocomotionLate(DeltaTime);
}
void UGMS_MoverMovementSystemComponent::OnMoverPreSimulationTick(const FMoverTimeStep& TimeStep, const FMoverInputCmdContext& InputCmd)
{
const FCharacterDefaultInputs* CharacterInputs = InputCmd.InputCollection.FindDataByType<FCharacterDefaultInputs>();
const FGMS_MoverMovementControlInputs* ControlInputs = InputCmd.InputCollection.FindDataByType<FGMS_MoverMovementControlInputs>();
if (ControlInputs)
{
// update movement state, settings. before actually do it.
ApplyMovementState(ControlInputs->DesiredMovementState);
ApplyRotationMode(ControlInputs->DesiredRotationMode);
}
}
void UGMS_MoverMovementSystemComponent::OnMoverMovementModeChanged(const FName& PreviousMovementModeName, const FName& NewMovementModeName)
{
// Use the mover movement mode to set the locomotion mode to the right value.
if (NewMovementModeName != NAME_None)
{
if (MovementModeToTagMapping.Contains(NewMovementModeName) && MovementModeToTagMapping[NewMovementModeName].IsValid())
{
if (LocomotionMode != MovementModeToTagMapping[NewMovementModeName])
{
SetLocomotionMode(MovementModeToTagMapping[NewMovementModeName]);
}
}
else
{
GMS_CLOG(Error, "No locomotion mode mapping for MovementMode:%s", *NewMovementModeName.ToString());
}
}
}
void UGMS_MoverMovementSystemComponent::ApplyMovementSetting()
{
if (IsValid(MoverComponent) && IsValid(ControlSetting))
{
if (const FGMS_MovementStateSetting* TempMS = ControlSetting->GetMovementStateSetting(DesiredMovementState, true))
{
if (UCommonLegacyMovementSettings* LegacyMovementSettings = MoverComponent->FindSharedSettings_Mutable<UCommonLegacyMovementSettings>())
{
LegacyMovementSettings->MaxSpeed = TempMS->Speed;
LegacyMovementSettings->Acceleration = TempMS->Acceleration;
LegacyMovementSettings->Deceleration = TempMS->BrakingDeceleration;
}
}
}
}
void UGMS_MoverMovementSystemComponent::RefreshView(float DeltaTime)
{
ViewState.PreviousYawAngle = UE_REAL_TO_FLOAT(ViewState.Rotation.Yaw);
if (OwnerPawn->IsLocallyControlled() || (OwnerPawn->GetLocalRole() >= ROLE_Authority && IsValid(OwnerPawn->GetController())))
{
// The character movement component already sends the view rotation to the
// server if movement is replicated, so we don't have to do this ourselves.
SetReplicatedViewRotation(OwnerPawn->GetViewRotation().GetNormalized(), true);
}
ViewState.Rotation = ReplicatedViewRotation;
// Set the yaw speed by comparing the current and previous view yaw angle, divided by
// delta seconds. This represents the speed the camera is rotating from left to right.
if (DeltaTime > UE_SMALL_NUMBER)
{
ViewState.YawSpeed = FMath::Abs(UE_REAL_TO_FLOAT(ViewState.Rotation.Yaw - ViewState.PreviousYawAngle)) / DeltaTime;
}
}
void UGMS_MoverMovementSystemComponent::ServerSetReplicatedViewRotation_Implementation(const FRotator& NewViewRotation)
{
Super::ServerSetReplicatedViewRotation_Implementation(NewViewRotation);
// Mover doesn't send control rotation to server, so we do it.
if (OwnerPawn->GetController() && !OwnerPawn->GetController()->GetControlRotation().Equals(NewViewRotation))
{
OwnerPawn->GetController()->SetControlRotation(NewViewRotation);
}
}
TScriptInterface<IPoseSearchTrajectoryPredictorInterface> UGMS_MoverMovementSystemComponent::GetTrajectoryPredictor() const
{
return TrajectoryPredictor;
}
bool UGMS_MoverMovementSystemComponent::IsCrouching() const
{
if (UCharacterMoverComponent* CharacterMover = Cast<UCharacterMoverComponent>(MoverComponent))
{
return CharacterMover->IsCrouching();
}
return false;
}
float UGMS_MoverMovementSystemComponent::GetMaxSpeed() const
{
const UCommonLegacyMovementSettings* CommonLegacySettings = MoverComponent->FindSharedSettings<UCommonLegacyMovementSettings>();
return CommonLegacySettings->MaxSpeed;
}
float UGMS_MoverMovementSystemComponent::GetScaledCapsuleRadius() const
{
if (UCapsuleComponent* Capsule = Cast<UCapsuleComponent>(MoverComponent->GetUpdatedComponent()))
{
return Capsule->GetScaledCapsuleRadius();
}
return GetDefault<UCapsuleComponent>()->GetUnscaledCapsuleRadius();
}
float UGMS_MoverMovementSystemComponent::GetScaledCapsuleHalfHeight() const
{
if (UCapsuleComponent* Capsule = Cast<UCapsuleComponent>(MoverComponent->GetUpdatedComponent()))
{
return Capsule->GetScaledCapsuleHalfHeight();
}
return GetDefault<UCapsuleComponent>()->GetUnscaledCapsuleHalfHeight();
}
float UGMS_MoverMovementSystemComponent::GetMaxAcceleration() const
{
const UCommonLegacyMovementSettings* CommonLegacySettings = MoverComponent->FindSharedSettings<UCommonLegacyMovementSettings>();
return CommonLegacySettings->Acceleration;
}
float UGMS_MoverMovementSystemComponent::GetMaxBrakingDeceleration() const
{
const UCommonLegacyMovementSettings* CommonLegacySettings = MoverComponent->FindSharedSettings<UCommonLegacyMovementSettings>();
return CommonLegacySettings->Deceleration;
}
float UGMS_MoverMovementSystemComponent::GetWalkableFloorZ() const
{
const UCommonLegacyMovementSettings* CommonLegacySettings = MoverComponent->FindSharedSettings<UCommonLegacyMovementSettings>();
return CommonLegacySettings->MaxWalkSlopeCosine;
}
float UGMS_MoverMovementSystemComponent::GetGravityZ() const
{
return MoverComponent->GetGravityAcceleration().Z;
}
USkeletalMeshComponent* UGMS_MoverMovementSystemComponent::GetMesh() const
{
return MeshComponent;
}
bool UGMS_MoverMovementSystemComponent::IsMovingOnGround() const
{
return IsValid(MoverComponent) ? MoverComponent->HasGameplayTag(Mover_IsOnGround, true) : false;
}
void UGMS_MoverMovementSystemComponent::RefreshLocomotionEarly()
{
}
void UGMS_MoverMovementSystemComponent::RefreshLocomotion(float DeltaTime)
{
LocomotionState.Velocity = MoverComponent->GetVelocity();
// Determine if the character is moving by getting its speed. The speed equals the length
// of the horizontal velocity, so it does not take vertical movement into account. If the
// character is moving, update the last velocity rotation. This value is saved because it might
// be useful to know the last orientation of a movement even after the character has stopped.
LocomotionState.Speed = UE_REAL_TO_FLOAT(LocomotionState.Velocity.Size2D());
static constexpr auto HasSpeedThreshold{1.0f};
LocomotionState.bHasVelocity = LocomotionState.Speed >= HasSpeedThreshold;
if (LocomotionState.bHasVelocity)
{
LocomotionState.VelocityYawAngle = UE_REAL_TO_FLOAT(UGMS_Vector::DirectionToAngleXY(LocomotionState.Velocity));
}
// Character is moving if has speed and current acceleration, or if the speed is greater than the moving speed threshold.
LocomotionState.bMoving = (LocomotionState.bHasInput && LocomotionState.bHasVelocity) ||
LocomotionState.Speed > ControlSetting->MovingSpeedThreshold;
}
void UGMS_MoverMovementSystemComponent::RefreshDynamicMovementState()
{
}
void UGMS_MoverMovementSystemComponent::RefreshLocomotionLate(float DeltaTime)
{
if (!LocomotionMode.IsValid())
{
RefreshTargetYawAngleUsingActorRotation();
}
}
void UGMS_MoverMovementSystemComponent::RefreshTargetYawAngleUsingActorRotation()
{
const auto YawAngle{UE_REAL_TO_FLOAT(OwnerPawn->GetActorRotation().Yaw)};
SetTargetYawAngle(YawAngle);
}
void UGMS_MoverMovementSystemComponent::SetTargetYawAngle(const float TargetYawAngle)
{
LocomotionState.TargetYawAngle = FRotator3f::NormalizeAxis(TargetYawAngle);
RefreshViewRelativeTargetYawAngle();
LocomotionState.SmoothTargetYawAngle = LocomotionState.TargetYawAngle;
}
void UGMS_MoverMovementSystemComponent::RefreshViewRelativeTargetYawAngle()
{
LocomotionState.ViewRelativeTargetYawAngle = FRotator3f::NormalizeAxis(UE_REAL_TO_FLOAT(
ViewState.Rotation.Yaw - LocomotionState.TargetYawAngle));
}
FGMS_PredictGroundMovementPivotLocationParams UGMS_MoverMovementSystemComponent::GetPredictGroundMovementPivotLocationParams() const
{
FGMS_PredictGroundMovementPivotLocationParams Params;
if (MoverComponent)
{
if (const UCommonLegacyMovementSettings* CommonLegacySettings = MoverComponent->FindSharedSettings<UCommonLegacyMovementSettings>())
{
Params.Acceleration = MoverComponent->GetMovementIntent() * CommonLegacySettings->Acceleration;
Params.Velocity = MoverComponent->GetVelocity();
Params.GroundFriction = CommonLegacySettings->GroundFriction;
}
}
return Params;
}
FGMS_PredictGroundMovementStopLocationParams UGMS_MoverMovementSystemComponent::GetPredictGroundMovementStopLocationParams() const
{
FGMS_PredictGroundMovementStopLocationParams Params;
if (MoverComponent)
{
if (const UCommonLegacyMovementSettings* CommonLegacySettings = MoverComponent->FindSharedSettings<UCommonLegacyMovementSettings>())
{
Params.Velocity = MoverComponent->GetVelocity();
Params.bUseSeparateBrakingFriction = true;
Params.BrakingFriction = CommonLegacySettings->BrakingFriction;
Params.GroundFriction = CommonLegacySettings->GroundFriction;
Params.BrakingFrictionFactor = CommonLegacySettings->BrakingFrictionFactor;
Params.BrakingDecelerationWalking = CommonLegacySettings->Deceleration;
}
}
return Params;
}
void UGMS_MoverMovementSystemComponent::RefreshMovementBase()
{
UPrimitiveComponent* BasePrimitive = MoverComponent->GetMovementBase();
FName BaseBoneName = MoverComponent->GetMovementBaseBoneName();
if (BasePrimitive != MovementBase.Primitive || BaseBoneName != MovementBase.BoneName)
{
MovementBase.Primitive = BasePrimitive;
MovementBase.BoneName = BaseBoneName;
MovementBase.bBaseChanged = true;
}
else
{
MovementBase.bBaseChanged = false;
}
MovementBase.bHasRelativeLocation = UBasedMovementUtils::IsADynamicBase(BasePrimitive);
MovementBase.bHasRelativeRotation = MovementBase.bHasRelativeLocation && bUseBaseRelativeMovement;
const auto PreviousRotation{MovementBase.Rotation};
UBasedMovementUtils::GetMovementBaseTransform(BasePrimitive, BaseBoneName,
MovementBase.Location, MovementBase.Rotation);
MovementBase.DeltaRotation = MovementBase.bHasRelativeLocation && !MovementBase.bBaseChanged
? (MovementBase.Rotation * PreviousRotation.Inverse()).Rotator()
: FRotator::ZeroRotator;
}
void UGMS_MoverMovementSystemComponent::ProduceInput_Implementation(int32 SimTimeMs, FMoverInputCmdContext& InputCmdResult)
{
InputCmdResult = OnProduceInput(static_cast<float>(SimTimeMs), InputCmdResult);
}
#pragma region MovementState
const FGameplayTag& UGMS_MoverMovementSystemComponent::GetDesiredMovementState() const
{
return DesiredMovementState;
}
void UGMS_MoverMovementSystemComponent::SetDesiredMovement(const FGameplayTag& NewDesiredMovement)
{
DesiredMovementState = NewDesiredMovement;
}
const FGameplayTag& UGMS_MoverMovementSystemComponent::GetMovementState() const
{
return MovementState;
}
void UGMS_MoverMovementSystemComponent::ApplyMovementState(const FGameplayTag& NewMovementState)
{
if (MovementState == NewMovementState || GetOwner()->GetLocalRole() < ROLE_AutonomousProxy)
{
return;
}
FGameplayTag Prev = MovementState;
MovementState = NewMovementState;
MARK_PROPERTY_DIRTY_FROM_NAME(ThisClass, MovementState, this)
OnMovementStateChanged(Prev);
}
#pragma endregion
#pragma region RotationMode
const FGameplayTag& UGMS_MoverMovementSystemComponent::GetDesiredRotationMode() const
{
return DesiredRotationMode;
}
void UGMS_MoverMovementSystemComponent::SetDesiredRotationMode(const FGameplayTag& NewDesiredRotationMode)
{
DesiredRotationMode = NewDesiredRotationMode;
}
const FGameplayTag& UGMS_MoverMovementSystemComponent::GetRotationMode() const
{
return RotationMode;
}
void UGMS_MoverMovementSystemComponent::ApplyRotationMode(const FGameplayTag& NewRotationMode)
{
if (RotationMode == NewRotationMode || GetOwner()->GetLocalRole() < ROLE_AutonomousProxy)
{
return;
}
FGameplayTag Prev = RotationMode;
RotationMode = NewRotationMode;
MARK_PROPERTY_DIRTY_FROM_NAME(ThisClass, RotationMode, this)
OnRotationModeChanged(Prev);
}
#pragma endregion
FVector UGMS_MoverMovementSystemComponent::GetMovementIntent() const
{
if (const FCharacterDefaultInputs* CharacterInputs = MoverComponent->GetLastInputCmd().InputCollection.FindDataByType<FCharacterDefaultInputs>())
{
return CharacterInputs->GetMoveInput_WorldSpace();
}
return MoverComponent->GetMovementIntent();
}
FVector UGMS_MoverMovementSystemComponent::AdjustOrientationIntent(float DeltaSeconds, const FVector& OrientationIntent) const
{
FVector Intent = OrientationIntent;
if (GetRotationMode() == GMS_RotationModeTags::VelocityDirection)
{
if (const FGMS_VelocityDirectionSetting_RateBased* Setting = GetControlSetting()->VelocityDirectionSetting.GetPtr<FGMS_VelocityDirectionSetting_RateBased>())
{
float YawDelta = CachedTurnInput.Yaw * DeltaSeconds * Setting->TurnRate;
Intent.Z += YawDelta;
}
}
if (GetRotationMode() == GMS_RotationModeTags::ViewDirection)
{
// Use curve to drive actor rotation only if no root bone rotation. 仅在没有使用根骨旋转时采用曲线驱动Actor旋转。
if (UGMS_MainAnimInstance* AnimInst = Cast<UGMS_MainAnimInstance>(MainAnimInstance))
{
if (AnimInst->GetOffsetRootBoneRotationMode() == EOffsetRootBoneMode::Release)
{
const float CurveValue = AnimationInstance->GetCurveValue(UGMS_Constants::RotationYawSpeedCurveName());
const float DeltaYawAngle{CurveValue * DeltaSeconds};
if (FMath::Abs(DeltaYawAngle) > UE_SMALL_NUMBER)
{
Intent = Intent.RotateAngleAxis(DeltaYawAngle, FVector::ZAxisVector);
}
}
}
}
return Intent;
}
FMoverInputCmdContext UGMS_MoverMovementSystemComponent::OnProduceInput_Implementation(float DeltaMs, FMoverInputCmdContext InputCmdResult)
{
check(OwnerPawn)
FCharacterDefaultInputs& CharacterInputs = InputCmdResult.InputCollection.FindOrAddMutableDataByType<FCharacterDefaultInputs>();
FGMS_MoverMovementControlInputs& ControlInputs = InputCmdResult.InputCollection.FindOrAddMutableDataByType<FGMS_MoverMovementControlInputs>();
ControlInputs.DesiredMovementSet = MovementSet;
ControlInputs.DesiredRotationMode = DesiredRotationMode;
ControlInputs.DesiredMovementState = DesiredMovementState;
if (OwnerPawn->Controller == nullptr)
{
if (OwnerPawn->GetLocalRole() == ROLE_Authority && OwnerPawn->GetRemoteRole() == ROLE_SimulatedProxy)
{
static const FCharacterDefaultInputs DoNothingInput;
// If we get here, that means this pawn is not currently possessed and we're choosing to provide default do-nothing input
CharacterInputs = DoNothingInput;
}
// We don't have a local controller so we can't run the code below. This is ok. Simulated proxies will just use previous input when extrapolating
return InputCmdResult;
}
CharacterInputs.ControlRotation = FRotator::ZeroRotator;
// APlayerController* PC = Cast<APlayerController>(OwnerPawn->Controller);
// if (PC)
// {
// CharacterInputs.ControlRotation = PC->GetControlRotation();
// }
CharacterInputs.ControlRotation = ViewState.Rotation;
bool bRequestedNavMovement = false;
if (NavMoverComponent)
{
bRequestedNavMovement = NavMoverComponent->ConsumeNavMovementData(CachedMoveInputIntent, CachedMoveInputVelocity);
}
// setup move input based on velocity/raw input.
{
// Favor velocity input
bool bUsingInputIntentForMove = CachedMoveInputVelocity.IsZero();
if (bUsingInputIntentForMove)
{
const FVector FinalDirectionalIntent = CharacterInputs.ControlRotation.RotateVector(CachedMoveInputIntent);
// FRotator Rotator = CharacterInputs.ControlRotation;
// FVector FinalDirectionalIntent;
// if (const UCharacterMoverComponent* MoverComp = Cast<UCharacterMoverComponent>(MoverComponent))
// {
// if (MoverComp->IsOnGround() || MoverComp->IsFalling())
// {
// const FVector RotationProjectedOntoUpDirection = FVector::VectorPlaneProject(Rotator.Vector(), MoverComp->GetUpDirection()).GetSafeNormal();
// Rotator = RotationProjectedOntoUpDirection.Rotation();
// }
// FinalDirectionalIntent = Rotator.RotateVector(CachedMoveInputIntent);
// }
CharacterInputs.SetMoveInput(EMoveInputType::DirectionalIntent, FinalDirectionalIntent);
}
else
{
CharacterInputs.SetMoveInput(EMoveInputType::Velocity, CachedMoveInputVelocity);
}
// Normally cached input is cleared by OnMoveCompleted input event but that won't be called if movement came from nav movement
if (bRequestedNavMovement)
{
CachedMoveInputIntent = FVector::ZeroVector;
CachedMoveInputVelocity = FVector::ZeroVector;
}
}
static float RotationMagMin(1e-3);
const bool bHasAffirmativeMoveInput = (CharacterInputs.GetMoveInput().Size() >= RotationMagMin);
// Figure out intended orientation
CharacterInputs.OrientationIntent = FVector::ZeroVector;
// setup orientation.
{
const bool bVelocityDirection = GetRotationMode() == GMS_RotationModeTags::VelocityDirection;
const bool bViewDirection = !bVelocityDirection;
if (!bHasAffirmativeMoveInput && bVelocityDirection)
{
if (const FGMS_VelocityDirectionSetting_RateBased* Setting = GetControlSetting()->VelocityDirectionSetting.GetPtr<FGMS_VelocityDirectionSetting_RateBased>())
{
const float DeltaSeconds = DeltaMs * 0.001f;
CharacterInputs.OrientationIntent = AdjustOrientationIntent(DeltaSeconds, MoverComponent->GetTargetOrientation().Vector());
}
else if (bMaintainLastInputOrientation)
{
// There is no movement intent, so use the last-known affirmative move input
CharacterInputs.OrientationIntent = LastAffirmativeMoveInput;
}
}
if (bHasAffirmativeMoveInput && bVelocityDirection)
{
if (const FGMS_VelocityDirectionSetting_RateBased* Setting = GetControlSetting()->VelocityDirectionSetting.GetPtr<FGMS_VelocityDirectionSetting_RateBased>())
{
const float DeltaSeconds = DeltaMs * 0.001f;
CharacterInputs.OrientationIntent = AdjustOrientationIntent(DeltaSeconds, MoverComponent->GetTargetOrientation().Vector());
}
else
{
// set the intent to the actors movement direction
CharacterInputs.OrientationIntent = CharacterInputs.GetMoveInput().GetSafeNormal();
}
}
if (!bHasAffirmativeMoveInput && bViewDirection)
{
if (GetControlSetting()->ViewDirectionSetting.Get().bEnableRotationWhenNotMoving)
{
// set intent to the the control rotation - often a player's camera rotation
CharacterInputs.OrientationIntent = CharacterInputs.ControlRotation.Vector().GetSafeNormal();
}
else
{
const float DeltaSeconds = DeltaMs * 0.001f;
CharacterInputs.OrientationIntent = AdjustOrientationIntent(DeltaSeconds, MoverComponent->GetTargetOrientation().Vector());
}
}
if (bHasAffirmativeMoveInput && bViewDirection)
{
// set intent to the control rotation - often a player's camera rotation
CharacterInputs.OrientationIntent = CharacterInputs.ControlRotation.Vector().GetSafeNormal();
}
}
if (bHasAffirmativeMoveInput)
{
LastAffirmativeMoveInput = CharacterInputs.GetMoveInput();
}
if (bShouldRemainVertical)
{
// canceling out any z intent if the actor is supposed to remain vertical
CharacterInputs.OrientationIntent = CharacterInputs.OrientationIntent.GetSafeNormal2D();
}
CharacterInputs.bIsJumpPressed = bIsJumpPressed;
CharacterInputs.bIsJumpJustPressed = bIsJumpJustPressed;
if (bShouldToggleFlying)
{
if (!bIsFlyingActive)
{
CharacterInputs.SuggestedMovementMode = DefaultModeNames::Flying;
}
else
{
CharacterInputs.SuggestedMovementMode = DefaultModeNames::Falling;
}
bIsFlyingActive = !bIsFlyingActive;
}
else
{
CharacterInputs.SuggestedMovementMode = NAME_None;
}
// Convert inputs to be relative to the current movement base (depending on options and state)
CharacterInputs.bUsingMovementBase = false;
if (bUseBaseRelativeMovement)
{
if (const UCharacterMoverComponent* MoverComp = OwnerPawn->GetComponentByClass<UCharacterMoverComponent>())
{
if (UPrimitiveComponent* MovementBasePtr = MoverComp->GetMovementBase())
{
FName MovementBaseBoneName = MoverComp->GetMovementBaseBoneName();
FVector RelativeMoveInput, RelativeOrientDir;
UBasedMovementUtils::TransformWorldDirectionToBased(MovementBasePtr, MovementBaseBoneName, CharacterInputs.GetMoveInput(), RelativeMoveInput);
UBasedMovementUtils::TransformWorldDirectionToBased(MovementBasePtr, MovementBaseBoneName, CharacterInputs.OrientationIntent, RelativeOrientDir);
CharacterInputs.SetMoveInput(CharacterInputs.GetMoveInputType(), RelativeMoveInput);
CharacterInputs.OrientationIntent = RelativeOrientDir;
CharacterInputs.bUsingMovementBase = true;
CharacterInputs.MovementBase = MovementBasePtr;
CharacterInputs.MovementBaseBoneName = MovementBaseBoneName;
}
}
}
// Clear/consume temporal movement inputs. We are not consuming others in the event that the game world is ticking at a lower rate than the Mover simulation.
// In that case, we want most input to carry over between simulation frames.
{
bIsJumpJustPressed = false;
bShouldToggleFlying = false;
}
return InputCmdResult;
}
#if WITH_EDITOR
EDataValidationResult UGMS_MoverMovementSystemComponent::IsDataValid(class FDataValidationContext& Context) const
{
// if (IsTemplate() && InputProducerClass.IsNull())
// {
// Context.AddError(FText::FromString("Input Producer Class is required!"));
// return EDataValidationResult::Invalid;
// }
return Super::IsDataValid(Context);
}
#endif