第一次提交

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,26 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#include "Nodes/GMS_AnimGraphNode_CurvesBlend.h"
#define LOCTEXT_NAMESPACE "GMS_CurvesBlendAnimationGraphNode"
#include UE_INLINE_GENERATED_CPP_BY_NAME(GMS_AnimGraphNode_CurvesBlend)
FText UGMS_AnimGraphNode_CurvesBlend::GetNodeTitle(const ENodeTitleType::Type TitleType) const
{
return LOCTEXT("Title", "Blend Curves");
}
FText UGMS_AnimGraphNode_CurvesBlend::GetTooltipText() const
{
return LOCTEXT("Tooltip", "Blend Curves");
}
FString UGMS_AnimGraphNode_CurvesBlend::GetNodeCategory() const
{
return FString{TEXTVIEW("GMS|Blends")};
}
#undef LOCTEXT_NAMESPACE

View File

@@ -0,0 +1,106 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#include "Nodes/GMS_AnimGraphNode_GameplayTagsBlend.h"
#include "GameplayTagsManager.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(GMS_AnimGraphNode_GameplayTagsBlend)
#define LOCTEXT_NAMESPACE "GMS_AnimGraphNode_GameplayTagsBlend"
UGMS_AnimGraphNode_GameplayTagsBlend::UGMS_AnimGraphNode_GameplayTagsBlend()
{
Node.AddPose();
}
void UGMS_AnimGraphNode_GameplayTagsBlend::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
if (PropertyChangedEvent.GetPropertyName() == GET_MEMBER_NAME_CHECKED(FGMS_AnimNode_GameplayTagsBlend, Tags))
{
ReconstructNode();
}
Super::PostEditChangeProperty(PropertyChangedEvent);
}
FText UGMS_AnimGraphNode_GameplayTagsBlend::GetNodeTitle(const ENodeTitleType::Type TitleType) const
{
return LOCTEXT("Title", "Blend Poses by Gameplay Tag");
}
FText UGMS_AnimGraphNode_GameplayTagsBlend::GetTooltipText() const
{
return LOCTEXT("Tooltip", "Blend Poses by Gameplay Tag");
}
void UGMS_AnimGraphNode_GameplayTagsBlend::ReallocatePinsDuringReconstruction(TArray<UEdGraphPin*>& PreviousPins)
{
Node.RefreshPoses();
Super::ReallocatePinsDuringReconstruction(PreviousPins);
}
FString UGMS_AnimGraphNode_GameplayTagsBlend::GetNodeCategory() const
{
return FString{TEXTVIEW("GMS|Blends")};
}
FName GetSimpleTagName(const FGameplayTag& Tag)
{
const auto TagNode{UGameplayTagsManager::Get().FindTagNode(Tag)};
return TagNode.IsValid() ? TagNode->GetSimpleTagName() : NAME_None;
}
void UGMS_AnimGraphNode_GameplayTagsBlend::CustomizePinData(UEdGraphPin* Pin, const FName SourcePropertyName, const int32 PinIndex) const
{
Super::CustomizePinData(Pin, SourcePropertyName, PinIndex);
bool bBlendPosePin;
bool bBlendTimePin;
GetBlendPinProperties(Pin, bBlendPosePin, bBlendTimePin);
if (!bBlendPosePin && !bBlendTimePin)
{
return;
}
Pin->PinFriendlyName = PinIndex <= 0
? LOCTEXT("Default", "Default")
: PinIndex > Node.Tags.Num()
? LOCTEXT("Invalid", "Invalid")
: FText::AsCultureInvariant(GetSimpleTagName(Node.Tags[PinIndex - 1]).ToString());
if (bBlendPosePin)
{
static const FTextFormat BlendPosePinFormat{LOCTEXT("Pose", "{PinName} Pose")};
Pin->PinFriendlyName = FText::Format(BlendPosePinFormat, {{FString{TEXTVIEW("PinName")}, Pin->PinFriendlyName}});
}
else if (bBlendTimePin)
{
static const FTextFormat BlendTimePinFormat{LOCTEXT("BlendTime", "{PinName} Blend Time")};
Pin->PinFriendlyName = FText::Format(BlendTimePinFormat, {{FString{TEXTVIEW("PinName")}, Pin->PinFriendlyName}});
}
}
void UGMS_AnimGraphNode_GameplayTagsBlend::GetBlendPinProperties(const UEdGraphPin* Pin, bool& bBlendPosePin, bool& bBlendTimePin)
{
const auto PinFullName{Pin->PinName.ToString()};
const auto SeparatorIndex{PinFullName.Find(TEXT("_"), ESearchCase::CaseSensitive)};
if (SeparatorIndex <= 0)
{
bBlendPosePin = false;
bBlendTimePin = false;
return;
}
const auto PinName{PinFullName.Left(SeparatorIndex)};
bBlendPosePin = PinName == TEXTVIEW("BlendPose");
bBlendTimePin = PinName == TEXTVIEW("BlendTime");
}
#undef LOCTEXT_NAMESPACE

View File

@@ -0,0 +1,111 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#include "Nodes/GMS_AnimGraphNode_LayeredBoneBlend.h"
#include "ToolMenus.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "AnimGraphCommands.h"
#include "ScopedTransaction.h"
#include "Kismet2/CompilerResultsLog.h"
#include "UObject/UE5ReleaseStreamObjectVersion.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(GMS_AnimGraphNode_LayeredBoneBlend)
/////////////////////////////////////////////////////
// UGMS_AnimGraphNode_LayeredBoneBlend
#define LOCTEXT_NAMESPACE "A3Nodes"
UGMS_AnimGraphNode_LayeredBoneBlend::UGMS_AnimGraphNode_LayeredBoneBlend(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
Node.AddPose();
}
FLinearColor UGMS_AnimGraphNode_LayeredBoneBlend::GetNodeTitleColor() const
{
return FLinearColor(0.2f, 0.8f, 0.3f);
}
FText UGMS_AnimGraphNode_LayeredBoneBlend::GetTooltipText() const
{
return LOCTEXT("AnimGraphNode_LayeredBoneBlend_Tooltip", "Generic Layered blend per bone");
}
FText UGMS_AnimGraphNode_LayeredBoneBlend::GetNodeTitle(ENodeTitleType::Type TitleType) const
{
return LOCTEXT("AnimGraphNode_LayeredBoneBlend_Title", "Generic Layered blend per bone");
}
FString UGMS_AnimGraphNode_LayeredBoneBlend::GetNodeCategory() const
{
return TEXT("Animation|Blends");
}
void UGMS_AnimGraphNode_LayeredBoneBlend::AddPinToBlendByFilter()
{
FScopedTransaction Transaction( LOCTEXT("AddPinToBlend", "AddPinToBlendByFilter") );
Modify();
Node.AddPose();
ReconstructNode();
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(GetBlueprint());
}
void UGMS_AnimGraphNode_LayeredBoneBlend::RemovePinFromBlendByFilter(UEdGraphPin* Pin)
{
FScopedTransaction Transaction( LOCTEXT("RemovePinFromBlend", "RemovePinFromBlendByFilter") );
Modify();
FProperty* AssociatedProperty;
int32 ArrayIndex;
GetPinAssociatedProperty(GetFNodeType(), Pin, /*out*/ AssociatedProperty, /*out*/ ArrayIndex);
if (ArrayIndex != INDEX_NONE)
{
//@TODO: ANIMREFACTOR: Need to handle moving pins below up correctly
// setting up removed pins info
RemovedPinArrayIndex = ArrayIndex;
Node.RemovePose(ArrayIndex);
ReconstructNode();
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(GetBlueprint());
}
}
void UGMS_AnimGraphNode_LayeredBoneBlend::GetNodeContextMenuActions(UToolMenu* Menu, UGraphNodeContextMenuContext* Context) const
{
if (!Context->bIsDebugging)
{
{
FToolMenuSection& Section = Menu->AddSection("AnimGraphNodeLayeredBoneblend", LOCTEXT("LayeredBoneBlend", "Generic Layered Bone Blend"));
if (Context->Pin != NULL)
{
// we only do this for normal BlendList/BlendList by enum, BlendList by Bool doesn't support add/remove pins
if (Context->Pin->Direction == EGPD_Input)
{
//@TODO: Only offer this option on arrayed pins
Section.AddMenuEntry(FAnimGraphCommands::Get().RemoveBlendListPin);
}
}
else
{
Section.AddMenuEntry(FAnimGraphCommands::Get().AddBlendListPin);
}
}
}
}
void UGMS_AnimGraphNode_LayeredBoneBlend::ValidateAnimNodeDuringCompilation(class USkeleton* ForSkeleton, class FCompilerResultsLog& MessageLog)
{
UAnimGraphNode_Base::ValidateAnimNodeDuringCompilation(ForSkeleton, MessageLog);
// ensure to cache the per-bone blend weights
if (!Node.ArePerBoneBlendWeightsValid(ForSkeleton))
{
Node.RebuildPerBoneBlendWeights(ForSkeleton);
}
}
#undef LOCTEXT_NAMESPACE

View File

@@ -0,0 +1,287 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#include "Nodes/GMS_AnimGraphNode_OrientationWarping.h"
#include "Animation/AnimRootMotionProvider.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "Kismet2/CompilerResultsLog.h"
#include "DetailCategoryBuilder.h"
#include "DetailLayoutBuilder.h"
#include "PropertyHandle.h"
#include "ScopedTransaction.h"
#define LOCTEXT_NAMESPACE "GMS_AnimGraphNode_OrientationWarping"
#include UE_INLINE_GENERATED_CPP_BY_NAME(GMS_AnimGraphNode_OrientationWarping)
UGMS_AnimGraphNode_OrientationWarping::UGMS_AnimGraphNode_OrientationWarping(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
}
FText UGMS_AnimGraphNode_OrientationWarping::GetControllerDescription() const
{
return LOCTEXT("OrientationWarping", "Generic Orientation Warping");
}
FText UGMS_AnimGraphNode_OrientationWarping::GetTooltipText() const
{
return LOCTEXT("OrientationWarpingTooltip", "Rotates the root and lower body by the specified angle, while counter rotating the upper body to maintain the forward facing direction.");
}
FText UGMS_AnimGraphNode_OrientationWarping::GetNodeTitle(ENodeTitleType::Type TitleType) const
{
return GetControllerDescription();
}
FLinearColor UGMS_AnimGraphNode_OrientationWarping::GetNodeTitleColor() const
{
return FLinearColor(FColor(0.f, 255.f, 0.f));
}
FString UGMS_AnimGraphNode_OrientationWarping::GetNodeCategory() const
{
return TEXT("GMS|Animation Warping");
}
void UGMS_AnimGraphNode_OrientationWarping::CustomizePinData(UEdGraphPin* Pin, FName SourcePropertyName, int32 ArrayIndex) const
{
Super::CustomizePinData(Pin, SourcePropertyName, ArrayIndex);
return; //直接返回,编辑器模式下不根据配置情况动态隐藏/显示属性
// if (Pin->PinName == GET_MEMBER_NAME_STRING_CHECKED(FGMS_AnimNode_OrientationWarping, OrientationAngle))
// {
// Pin->bHidden = (Node.Mode == EWarpingEvaluationMode::Graph);
// }
//
// if (Pin->PinName == GET_MEMBER_NAME_STRING_CHECKED(FGMS_AnimNode_OrientationWarping, LocomotionAngle))
// {
// Pin->bHidden = (Node.Mode == EWarpingEvaluationMode::Manual);
// }
//
// if (Pin->PinName == GET_MEMBER_NAME_STRING_CHECKED(FGMS_AnimNode_OrientationWarping, LocomotionAngleDeltaThreshold))
// {
// Pin->bHidden = (Node.Mode == EWarpingEvaluationMode::Manual);
// }
}
void UGMS_AnimGraphNode_OrientationWarping::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder)
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_FUNC()
Super::CustomizeDetails(DetailBuilder);
return; //直接返回,编辑器模式下不根据配置情况动态隐藏/显示属性
// DetailBuilder.SortCategories([](const TMap<FName, IDetailCategoryBuilder*>& CategoryMap)
// {
// for (const TPair<FName, IDetailCategoryBuilder*>& Pair : CategoryMap)
// {
// int32 SortOrder = Pair.Value->GetSortOrder();
// const FName CategoryName = Pair.Key;
//
// if (CategoryName == "Evaluation")
// {
// SortOrder += 1;
// }
// else if (CategoryName == "Settings")
// {
// SortOrder += 2;
// }
// else if (CategoryName == "Debug")
// {
// SortOrder += 3;
// }
// else
// {
// const int32 ValueSortOrder = Pair.Value->GetSortOrder();
// if (ValueSortOrder >= SortOrder && ValueSortOrder < SortOrder + 10)
// {
// SortOrder += 10;
// }
// else
// {
// continue;
// }
// }
//
// Pair.Value->SetSortOrder(SortOrder);
// }
// });
//
// TSharedRef<IPropertyHandle> NodeHandle = DetailBuilder.GetProperty(FName(TEXT("Node")), GetClass());
//
// if (Node.Mode == EWarpingEvaluationMode::Graph)
// {
// DetailBuilder.HideProperty(NodeHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FGMS_AnimNode_OrientationWarping, OrientationAngle)));
// }
//
// if (Node.Mode == EWarpingEvaluationMode::Manual)
// {
// DetailBuilder.HideProperty(NodeHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FGMS_AnimNode_OrientationWarping, LocomotionAngle)));
// DetailBuilder.HideProperty(NodeHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FGMS_AnimNode_OrientationWarping, LocomotionAngleDeltaThreshold)));
// DetailBuilder.HideProperty(NodeHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FGMS_AnimNode_OrientationWarping, MinRootMotionSpeedThreshold)));
// }
}
void UGMS_AnimGraphNode_OrientationWarping::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent)
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_FUNC()
Super::PostEditChangeProperty(PropertyChangedEvent);
return; //直接返回,编辑器模式下不根据配置情况动态隐藏/显示属性
// bool bRequiresNodeReconstruct = false;
// FProperty* ChangedProperty = PropertyChangedEvent.Property;
//
// if (ChangedProperty)
// {
// // Evaluation mode
// if (ChangedProperty->GetFName() == GET_MEMBER_NAME_STRING_CHECKED(FGMS_AnimNode_OrientationWarping, Mode))
// {
// FScopedTransaction Transaction(LOCTEXT("ChangeEvaluationMode", "Change Evaluation Mode"));
// Modify();
//
// // Break links to pins going away
// for (int32 PinIndex = 0; PinIndex < Pins.Num(); ++PinIndex)
// {
// UEdGraphPin* Pin = Pins[PinIndex];
// if (Pin->PinName == GET_MEMBER_NAME_STRING_CHECKED(FGMS_AnimNode_OrientationWarping, OrientationAngle))
// {
// if (Node.Mode == EWarpingEvaluationMode::Graph)
// {
// Pin->BreakAllPinLinks();
// }
// }
// else if (Pin->PinName == GET_MEMBER_NAME_STRING_CHECKED(FGMS_AnimNode_OrientationWarping, LocomotionAngle))
// {
// if (Node.Mode == EWarpingEvaluationMode::Manual)
// {
// Pin->BreakAllPinLinks();
// }
// }
// else if (Pin->PinName == GET_MEMBER_NAME_STRING_CHECKED(FGMS_AnimNode_OrientationWarping, LocomotionAngleDeltaThreshold))
// {
// if (Node.Mode == EWarpingEvaluationMode::Manual)
// {
// Pin->BreakAllPinLinks();
// }
// }
// else if (Pin->PinName == GET_MEMBER_NAME_STRING_CHECKED(FGMS_AnimNode_OrientationWarping, MinRootMotionSpeedThreshold))
// {
// if (Node.Mode == EWarpingEvaluationMode::Manual)
// {
// Pin->BreakAllPinLinks();
// }
// }
// }
//
// bRequiresNodeReconstruct = true;
// }
// }
//
// if (bRequiresNodeReconstruct)
// {
// ReconstructNode();
// FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(GetBlueprint());
// }
}
void UGMS_AnimGraphNode_OrientationWarping::GetInputLinkAttributes(FNodeAttributeArray& OutAttributes) const
{
if (Node.Mode == EWarpingEvaluationMode::Graph)
{
OutAttributes.Add(UE::Anim::IAnimRootMotionProvider::AttributeName);
}
}
void UGMS_AnimGraphNode_OrientationWarping::GetOutputLinkAttributes(FNodeAttributeArray& OutAttributes) const
{
if (Node.Mode == EWarpingEvaluationMode::Graph)
{
OutAttributes.Add(UE::Anim::IAnimRootMotionProvider::AttributeName);
}
}
void UGMS_AnimGraphNode_OrientationWarping::ValidateAnimNodeDuringCompilation(USkeleton* ForSkeleton, FCompilerResultsLog& MessageLog)
{
return Super::ValidateAnimNodeDuringCompilation(ForSkeleton, MessageLog); //直接返回,编辑器模式下不做任何校验。
// auto HasInvalidBoneName = [](const FName& BoneName)
// {
// return BoneName == NAME_None;
// };
//
// auto HasInvalidBoneIndex = [&](const FName& BoneName)
// {
// return ForSkeleton && ForSkeleton->GetReferenceSkeleton().FindBoneIndex(BoneName) == INDEX_NONE;
// };
//
// auto InvalidBoneNameMessage = [&](const FName& BoneName)
// {
// FFormatNamedArguments Args;
// Args.Add(TEXT("BoneName"), FText::FromName(BoneName));
// const FText Message = FText::Format(NSLOCTEXT("OrientationWarping", "Invalid{BoneName}BoneName", "@@ - {BoneName} bone not found in Skeleton"), Args);
// MessageLog.Warning(*Message.ToString(), this);
// };
//
// auto InvalidBoneIndexMessage = [&](const FName& BoneName)
// {
// FFormatNamedArguments Args;
// Args.Add(TEXT("BoneName"), FText::FromName(BoneName));
// const FText Message = FText::Format(NSLOCTEXT("OrientationWarping", "Invalid{BoneName}BoneInSkeleton", "@@ - {BoneName} bone definition is required"), Args);
// MessageLog.Warning(*Message.ToString(), this);
// };
//
// if (Node.RotationAxis == EAxis::None)
// {
// MessageLog.Warning(*NSLOCTEXT("OrientationWarping", "InvalidRotationAxis", "@@ - Rotation Axis choice of X, Y, or Z is required").ToString(), this);
// }
//
// if (Node.SpineBones.IsEmpty())
// {
// MessageLog.Warning(*NSLOCTEXT("OrientationWarping", "InvalidSpineBones", "@@ - Spine bone definitions are required").ToString(), this);
// }
// else
// {
// for (const auto& Bone : Node.SpineBones)
// {
// if (HasInvalidBoneName(Bone.BoneName))
// {
// InvalidBoneIndexMessage("Spine");
// }
// else if (HasInvalidBoneIndex(Bone.BoneName))
// {
// InvalidBoneNameMessage(Bone.BoneName);
// }
// }
// }
//
// if (HasInvalidBoneName(Node.IKFootRootBone.BoneName))
// {
// InvalidBoneIndexMessage("IK Foot Root");
// }
// else if (HasInvalidBoneIndex(Node.IKFootRootBone.BoneName))
// {
// InvalidBoneNameMessage(Node.IKFootRootBone.BoneName);
// }
//
// if (Node.SpineBones.IsEmpty())
// {
// MessageLog.Warning(*NSLOCTEXT("OrientationWarping", "InvalidIKFootBones", "@@ - IK Foot bone definitions are required").ToString(), this);
// }
// else
// {
// for (const auto& Bone : Node.IKFootBones)
// {
// if (HasInvalidBoneName(Bone.BoneName))
// {
// InvalidBoneIndexMessage("IK Foot");
// }
// else if (HasInvalidBoneIndex(Bone.BoneName))
// {
// InvalidBoneNameMessage(Bone.BoneName);
// }
// }
// }
//
// Super::ValidateAnimNodeDuringCompilation(ForSkeleton, MessageLog);
}
#undef LOCTEXT_NAMESPACE