第一次提交
This commit is contained in:
@@ -0,0 +1,277 @@
|
||||
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
|
||||
|
||||
|
||||
#include "Settings/GMS_SettingObjectLibrary.h"
|
||||
#include "Locomotions/GMS_AnimLayer.h"
|
||||
#include "Animation/BlendSpace.h"
|
||||
#include "Locomotions/GMS_AnimLayer_Additive.h"
|
||||
#include "Locomotions/GMS_AnimLayer_Overlay.h"
|
||||
#include "Locomotions/GMS_AnimLayer_SkeletalControls.h"
|
||||
#include "Locomotions/GMS_AnimLayer_States.h"
|
||||
#include "Locomotions/GMS_AnimLayer_View_Default.h"
|
||||
#include "Misc/DataValidation.h"
|
||||
#include "Utility/GMS_Utility.h"
|
||||
|
||||
#include UE_INLINE_GENERATED_CPP_BY_NAME(GMS_SettingObjectLibrary)
|
||||
|
||||
#pragma region CommonSettings
|
||||
|
||||
#if WITH_EDITOR
|
||||
#include "UObject/ObjectSaveContext.h"
|
||||
|
||||
void UGMS_MovementDefinition::PreSave(FObjectPreSaveContext SaveContext)
|
||||
{
|
||||
Super::PreSave(SaveContext);
|
||||
}
|
||||
|
||||
EDataValidationResult UGMS_MovementDefinition::IsDataValid(class FDataValidationContext& Context) const
|
||||
{
|
||||
for (const TTuple<FGameplayTag, FGMS_MovementSetSetting>& Pair : MovementSets)
|
||||
{
|
||||
if (Pair.Value.ControlSetting == nullptr)
|
||||
{
|
||||
Context.AddError(FText::FromString(FString::Format(TEXT("ControlSetting is required on {0}!!!"), {Pair.Key.GetTagName().ToString()})));
|
||||
}
|
||||
|
||||
if (Pair.Value.bUseInstancedStatesSetting && Pair.Value.AnimLayerSetting_States && Pair.Value.AnimLayerSetting_States->IsDataValid(Context) == EDataValidationResult::Invalid)
|
||||
{
|
||||
return EDataValidationResult::Invalid;
|
||||
}
|
||||
|
||||
if (Pair.Value.bUseInstancedOverlaySetting && Pair.Value.AnimLayerSetting_Overlay && Pair.Value.AnimLayerSetting_Overlay->IsDataValid(Context) == EDataValidationResult::Invalid)
|
||||
{
|
||||
return EDataValidationResult::Invalid;
|
||||
}
|
||||
|
||||
if (Pair.Value.AnimLayerSetting_Additive && Pair.Value.AnimLayerSetting_Additive->IsDataValid(Context) == EDataValidationResult::Invalid)
|
||||
{
|
||||
return EDataValidationResult::Invalid;
|
||||
}
|
||||
|
||||
if (Pair.Value.AnimLayerSetting_View && Pair.Value.AnimLayerSetting_View->IsDataValid(Context) == EDataValidationResult::Invalid)
|
||||
{
|
||||
return EDataValidationResult::Invalid;
|
||||
}
|
||||
|
||||
if (Pair.Value.AnimLayerSetting_SkeletalControls && Pair.Value.AnimLayerSetting_SkeletalControls->IsDataValid(Context) == EDataValidationResult::Invalid)
|
||||
{
|
||||
return EDataValidationResult::Invalid;
|
||||
}
|
||||
}
|
||||
return Super::IsDataValid(Context);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
FGameplayTag UGMS_MovementControlSetting_Default::MatchStateTagBySpeed(float Speed, float Threshold) const
|
||||
{
|
||||
for (const FGMS_MovementStateSetting& MovementState : MovementStates)
|
||||
{
|
||||
if (MovementState.Speed > 0.0f && MovementState.Speed < Speed + Threshold)
|
||||
{
|
||||
return MovementState.Tag;
|
||||
}
|
||||
}
|
||||
return FGameplayTag::EmptyTag;
|
||||
}
|
||||
|
||||
bool UGMS_MovementControlSetting_Default::GetStateByIndex(const int32& Index, FGMS_MovementStateSetting& OutSetting) const
|
||||
{
|
||||
if (MovementStates.IsValidIndex(Index))
|
||||
{
|
||||
OutSetting = MovementStates[Index];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UGMS_MovementControlSetting_Default::GetStateBySpeedLevel(const int32& Level, FGMS_MovementStateSetting& OutSetting) const
|
||||
{
|
||||
if (SpeedLevelToArrayIndex.Contains(Level))
|
||||
{
|
||||
OutSetting = MovementStates[SpeedLevelToArrayIndex[Level]];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UGMS_MovementControlSetting_Default::GetStateByTag(const FGameplayTag& Tag, FGMS_MovementStateSetting& OutSetting) const
|
||||
{
|
||||
if (auto Setting = GetMovementStateSetting(Tag))
|
||||
{
|
||||
OutSetting = *Setting;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const FGMS_MovementStateSetting* UGMS_MovementControlSetting_Default::GetMovementStateSetting(const FGameplayTag& Tag) const
|
||||
{
|
||||
if (!Tag.IsValid())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return MovementStates.FindByPredicate([Tag](const FGMS_MovementStateSetting& Setting)
|
||||
{
|
||||
return Setting.Tag.IsValid() && Setting.Tag == Tag;
|
||||
});
|
||||
}
|
||||
|
||||
const FGMS_MovementStateSetting* UGMS_MovementControlSetting_Default::GetMovementStateSetting(const FGameplayTag& Tag, bool bHasFallback) const
|
||||
{
|
||||
if (auto Setting = GetMovementStateSetting(Tag))
|
||||
{
|
||||
return Setting;
|
||||
}
|
||||
|
||||
if (bHasFallback)
|
||||
{
|
||||
checkf(!MovementStates.IsEmpty(), TEXT("%s: MovementStates can't be empty!"), *GetNameSafe(this))
|
||||
return &MovementStates.Last();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region ControlSettings
|
||||
|
||||
#if WITH_EDITOR
|
||||
|
||||
float UGMS_MovementControlSetting_Default::MigrateRotationInterpolationSpeed(float Old)
|
||||
{
|
||||
if (Old <= 0.0f)
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
// larger old value, smaller new value.
|
||||
return FMath::GetMappedRangeValueClamped(FVector2f{0.0f, 20.0f}, FVector2f{0.3f, 0.1f}, Old);
|
||||
}
|
||||
|
||||
void UGMS_MovementControlSetting_Default::PreSave(FObjectPreSaveContext SaveContext)
|
||||
{
|
||||
Super::PreSave(SaveContext);
|
||||
|
||||
SpeedLevelToArrayIndex.Empty();
|
||||
|
||||
MovementStates.Sort([](const FGMS_MovementStateSetting& A, const FGMS_MovementStateSetting& B)
|
||||
{
|
||||
return A.SpeedLevel < B.SpeedLevel;
|
||||
});
|
||||
|
||||
for (int i = 0; i < MovementStates.Num(); ++i)
|
||||
{
|
||||
FGMS_MovementStateSetting& Setting = MovementStates[i];
|
||||
Setting.EditorFriendlyName = FString::Format(TEXT("State({0}) SpeedLevel({1}) Speed({2})"), {UGMS_Utility::GetSimpleTagName(Setting.Tag).ToString(), Setting.SpeedLevel, Setting.Speed});
|
||||
SpeedLevelToArrayIndex.Emplace(Setting.SpeedLevel, i);
|
||||
}
|
||||
|
||||
// Migration code for GMS1.5, TODO remove in 1.6
|
||||
PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
||||
if (MovementStates.Num() > 0)
|
||||
{
|
||||
const FGMS_MovementStateSetting& LastMovementState = MovementStates[MovementStates.Num() - 1];
|
||||
|
||||
// migrate velocity direction setting.
|
||||
if (!VelocityDirectionSetting.IsValid())
|
||||
{
|
||||
if (LastMovementState.VelocityDirectionSetting.DirectionMode != EGMS_VelocityDirectionMode_DEPRECATED::TurningCircle)
|
||||
{
|
||||
FGMS_VelocityDirectionSetting_Default Temp;
|
||||
Temp.bEnableRotationWhenNotMoving = LastMovementState.VelocityDirectionSetting.bEnableRotationWhenNotMoving;
|
||||
Temp.TargetYawAngleRotationSpeed = LastMovementState.TargetYawAngleRotationSpeed;
|
||||
Temp.RotationInterpolationSpeed = MigrateRotationInterpolationSpeed(LastMovementState.RotationInterpolationSpeed);
|
||||
Temp.bOrientateToMoveInputIntent = LastMovementState.VelocityDirectionSetting.DirectionMode == EGMS_VelocityDirectionMode_DEPRECATED::OrientToInputDirection;
|
||||
|
||||
VelocityDirectionSetting.InitializeAs<FGMS_VelocityDirectionSetting_Default>(Temp);
|
||||
}
|
||||
else if (LastMovementState.VelocityDirectionSetting.DirectionMode == EGMS_VelocityDirectionMode_DEPRECATED::TurningCircle)
|
||||
{
|
||||
FGMS_VelocityDirectionSetting_RateBased Temp;
|
||||
Temp.bEnableRotationWhenNotMoving = LastMovementState.VelocityDirectionSetting.bEnableRotationWhenNotMoving;
|
||||
Temp.TurnRate = LastMovementState.VelocityDirectionSetting.TurningRate;
|
||||
VelocityDirectionSetting.InitializeAs<FGMS_VelocityDirectionSetting_RateBased>(Temp);
|
||||
}
|
||||
}
|
||||
|
||||
// migrate view direction setting.
|
||||
if (!ViewDirectionSetting.IsValid())
|
||||
{
|
||||
if (LastMovementState.ViewDirectionSetting.DirectionMode == EGMS_ViewDirectionMode_DEPRECATED::Aiming)
|
||||
{
|
||||
FGMS_ViewDirectionSetting_Aiming Temp;
|
||||
Temp.bEnableRotationWhenNotMoving = LastMovementState.ViewDirectionSetting.bRotateToViewDirectionWhileNotMoving;
|
||||
Temp.TargetYawAngleRotationSpeed = LastMovementState.TargetYawAngleRotationSpeed;
|
||||
Temp.RotationInterpolationSpeed = MigrateRotationInterpolationSpeed(LastMovementState.RotationInterpolationSpeed);
|
||||
Temp.MinAimingYawAngleLimit = LastMovementState.ViewDirectionSetting.MinAimingYawAngleLimit;
|
||||
|
||||
ViewDirectionSetting.InitializeAs<FGMS_ViewDirectionSetting_Aiming>(Temp);
|
||||
}
|
||||
else if (LastMovementState.ViewDirectionSetting.DirectionMode == EGMS_ViewDirectionMode_DEPRECATED::Default)
|
||||
{
|
||||
FGMS_ViewDirectionSetting_Default Temp;
|
||||
Temp.bEnableRotationWhenNotMoving = LastMovementState.ViewDirectionSetting.bRotateToViewDirectionWhileNotMoving;
|
||||
Temp.TargetYawAngleRotationSpeed = LastMovementState.TargetYawAngleRotationSpeed;
|
||||
Temp.RotationInterpolationSpeed = MigrateRotationInterpolationSpeed(LastMovementState.RotationInterpolationSpeed);
|
||||
ViewDirectionSetting.InitializeAs<FGMS_ViewDirectionSetting_Default>(Temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
||||
|
||||
// Safety guard if still invalid.
|
||||
if (!VelocityDirectionSetting.IsValid())
|
||||
{
|
||||
VelocityDirectionSetting.InitializeAs(FGMS_VelocityDirectionSetting_Default());
|
||||
}
|
||||
if (!ViewDirectionSetting.IsValid())
|
||||
{
|
||||
ViewDirectionSetting.InitializeAs(FGMS_ViewDirectionSetting_Default());
|
||||
}
|
||||
}
|
||||
|
||||
EDataValidationResult UGMS_MovementControlSetting_Default::IsDataValid(class FDataValidationContext& Context) const
|
||||
{
|
||||
for (int32 i = 0; i < MovementStates.Num(); i++)
|
||||
{
|
||||
const FGMS_MovementStateSetting& MRSetting = MovementStates[i];
|
||||
if (!MRSetting.Tag.IsValid())
|
||||
{
|
||||
Context.AddError(FText::FromString(FString::Format(TEXT("Invalid tag at index({0}) of MovementStates"), {i})));
|
||||
return EDataValidationResult::Invalid;
|
||||
}
|
||||
if (MRSetting.AllowedRotationModes.IsEmpty())
|
||||
{
|
||||
Context.AddError(FText::FromString(
|
||||
FString::Format(TEXT("AllowedRotationModes at index({0}) of MovementStates can't be empty!"), {i})));
|
||||
return EDataValidationResult::Invalid;
|
||||
}
|
||||
}
|
||||
if (!ViewDirectionSetting.IsValid())
|
||||
{
|
||||
Context.AddError(FText::FromString(TEXT("Invalid view direction setting")));
|
||||
return EDataValidationResult::Invalid;
|
||||
}
|
||||
if (ViewDirectionSetting.IsValid() && ViewDirectionSetting.GetScriptStruct() == FGMS_ViewDirectionSetting::StaticStruct())
|
||||
{
|
||||
Context.AddError(FText::FromString(FString::Format(TEXT("View direction setting({0}) was deprecated!"), {FGMS_ViewDirectionSetting::StaticStruct()->GetName()})));
|
||||
return EDataValidationResult::Invalid;
|
||||
}
|
||||
|
||||
if (!VelocityDirectionSetting.IsValid())
|
||||
{
|
||||
Context.AddError(FText::FromString(TEXT("Invalid velocity direction setting")));
|
||||
return EDataValidationResult::Invalid;
|
||||
}
|
||||
if (VelocityDirectionSetting.IsValid() && VelocityDirectionSetting.GetScriptStruct() == FGMS_VelocityDirectionSetting::StaticStruct())
|
||||
{
|
||||
Context.AddError(FText::FromString(FString::Format(TEXT("Velocity direction setting({0}) was deprecated!"), {FGMS_VelocityDirectionSetting::StaticStruct()->GetName()})));
|
||||
return EDataValidationResult::Invalid;
|
||||
}
|
||||
|
||||
return Super::IsDataValid(Context);
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma endregion
|
||||
Reference in New Issue
Block a user