// Copyright Epic Games, Inc. All Rights Reserved. #include "AnimGraphNode_PoseBlendNode.h" #include "EdGraphSchema_K2_Actions.h" #include "Modules/ModuleManager.h" #include "ToolMenus.h" #include "AnimGraphCommands.h" #include "AssetRegistry/ARFilter.h" #include "AssetRegistry/AssetRegistryModule.h" #include "BlueprintActionFilter.h" #include "BlueprintActionDatabaseRegistrar.h" #include "BlueprintNodeSpawner.h" #define LOCTEXT_NAMESPACE "PoseBlendNode" // Action to add a pose asset blend node to the graph struct FNewPoseBlendNodeAction : public FEdGraphSchemaAction_K2NewNode { protected: FAssetData AssetInfo; public: FNewPoseBlendNodeAction(const FAssetData& InAssetInfo, FText Title) : FEdGraphSchemaAction_K2NewNode(LOCTEXT("PoseAsset", "PoseAssets"), Title, LOCTEXT("EvalCurvesToMakePose", "Evaluates curves to produce a pose from pose asset"), 0, FText::FromString(InAssetInfo.GetObjectPathString())) { AssetInfo = InAssetInfo; UAnimGraphNode_PoseBlendNode* Template = NewObject(); NodeTemplate = Template; } virtual UEdGraphNode* PerformAction(class UEdGraph* ParentGraph, UEdGraphPin* FromPin, const FVector2f& Location, bool bSelectNewNode = true) override { UAnimGraphNode_PoseBlendNode* SpawnedNode = CastChecked(FEdGraphSchemaAction_K2NewNode::PerformAction(ParentGraph, FromPin, Location, bSelectNewNode)); SpawnedNode->Node.PoseAsset = Cast(AssetInfo.GetAsset()); return SpawnedNode; } }; ///////////////////////////////////////////////////// // UAnimGraphNode_PoseBlendNode UAnimGraphNode_PoseBlendNode::UAnimGraphNode_PoseBlendNode(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { } void UAnimGraphNode_PoseBlendNode::GetAllAnimationSequencesReferred(TArray& AnimationAssets) const { if(Node.PoseAsset) { HandleAnimReferenceCollection(Node.PoseAsset, AnimationAssets); } } void UAnimGraphNode_PoseBlendNode::ReplaceReferredAnimations(const TMap& AnimAssetReplacementMap) { HandleAnimReferenceReplacement(Node.PoseAsset, AnimAssetReplacementMap); } FText UAnimGraphNode_PoseBlendNode::GetTooltipText() const { // FText::Format() is slow, so we utilize the cached list title return GetNodeTitle(ENodeTitleType::ListView); } FText UAnimGraphNode_PoseBlendNode::GetNodeTitleForPoseAsset(ENodeTitleType::Type TitleType, UPoseAsset* InPoseAsset) const { FFormatNamedArguments Args; Args.Add(TEXT("PoseAssetName"), FText::FromString(InPoseAsset->GetName())); return FText::Format(LOCTEXT("PoseByName_Title", "{PoseAssetName}"), Args); } FText UAnimGraphNode_PoseBlendNode::GetNodeTitle(ENodeTitleType::Type TitleType) const { if (Node.PoseAsset == nullptr) { // we may have a valid variable connected or default pin value UEdGraphPin* PosePin = FindPin(GET_MEMBER_NAME_STRING_CHECKED(FAnimNode_PoseBlendNode, PoseAsset)); if (PosePin && PosePin->LinkedTo.Num() > 0) { return LOCTEXT("PoseByName_TitleVariable", "Pose"); } else if (PosePin && PosePin->DefaultObject != nullptr) { return GetNodeTitleForPoseAsset(TitleType, CastChecked(PosePin->DefaultObject)); } else { return LOCTEXT("PoseByName_TitleNONE", "Pose (None)"); } } else { return GetNodeTitleForPoseAsset(TitleType, Node.PoseAsset); } } void UAnimGraphNode_PoseBlendNode::GetMenuActions(FBlueprintActionDatabaseRegistrar& InActionRegistrar) const { GetMenuActionsHelper( InActionRegistrar, GetClass(), { UPoseAsset::StaticClass() }, { }, [](const FAssetData& InAssetData, UClass* InClass) { if(InAssetData.IsValid()) { return GetTitleGivenAssetInfo(FText::FromName(InAssetData.AssetName)); } else { return LOCTEXT("PlayerDesc", "Evaluate Pose"); } }, [](const FAssetData& InAssetData, UClass* InClass) { if(InAssetData.IsValid()) { return GetTitleGivenAssetInfo(FText::FromName(InAssetData.AssetName)); } else { return LOCTEXT("PlayerDescTooltip", "Evaluate Pose Asset"); } }, [](UEdGraphNode* InNewNode, bool bInIsTemplateNode, const FAssetData InAssetData) { UAnimGraphNode_AssetPlayerBase::SetupNewNode(InNewNode, bInIsTemplateNode, InAssetData); }); } FText UAnimGraphNode_PoseBlendNode::GetTitleGivenAssetInfo(const FText& AssetName) { FFormatNamedArguments Args; Args.Add(TEXT("AssetName"), AssetName); return FText::Format(LOCTEXT("PoseAssetNodeTitle", "Evaluate Pose {AssetName}"), Args); } FText UAnimGraphNode_PoseBlendNode::GetMenuCategory() const { return LOCTEXT("PoseAssetCategory_Label", "Animation|Poses"); } bool UAnimGraphNode_PoseBlendNode::DoesSupportTimeForTransitionGetter() const { return false; } void UAnimGraphNode_PoseBlendNode::GetNodeContextMenuActions(UToolMenu* Menu, UGraphNodeContextMenuContext* Context) const { if (!Context->bIsDebugging) { // add an option to convert to single frame { FToolMenuSection& Section = Menu->AddSection("AnimGraphNodePoseBlender", LOCTEXT("PoseBlenderHeading", "Pose Blender")); Section.AddMenuEntry(FAnimGraphCommands::Get().ConvertToPoseByName); } } } EAnimAssetHandlerType UAnimGraphNode_PoseBlendNode::SupportsAssetClass(const UClass* AssetClass) const { if (AssetClass->IsChildOf(UPoseAsset::StaticClass())) { return EAnimAssetHandlerType::PrimaryHandler; } else { return EAnimAssetHandlerType::NotSupported; } } #undef LOCTEXT_NAMESPACE