Files
UnrealEngineUWP/Engine/Source/Editor/AnimGraph/Private/AnimStateConduitNode.cpp
thomas sarkanen 57122faf0a AnimNext params in Anim BPs
Added a new anim node: AnimNext Parameters. This injects parameters into the AnimNext stack for all leafwards nodes.

Added a new way of binding to parameters on anim nodes.
- Added indirection to UAnimGraphNode_Base to allow different 'binding types' to be authored by deriving from UAnimGraphNodeBinding
- Added new binding type for AnimNext parameters
- Moved existing binding code (inc UI widget creation) into UAnimGraphNodeBinding_Base
- Binding types can be selected on a per-node or per-anim BP basis

Reworked FParamStack API a little
- Allow for better error checking when pushing/popping stack layers. Pushed layers can now only be subsequently popped by passing in the handle of the pushed layer.
- Standalone layers are now wrapped in an opaque handle rather than returning a unique ptr
- GetParamData APIs now perform more involved type checking, allowing derived object types & type conversions to be implemented

Improved parameter type sandboxing for automated tests. If running low-level type tests while execution was happening on another thread, the editor could crash because of invalidating already-existing types.

Lots of other small fixes to get workflows nicer and end-to-end functionality working

#rb Nicholas.Frechette,Jaime.Cifuentes,Jurre.deBaare

[CL 26455905 by thomas sarkanen in ue5-main branch]
2023-07-19 04:36:34 -04:00

145 lines
4.0 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "AnimStateConduitNode.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "AnimStateTransitionNode.h"
#include "Kismet2/Kismet2NameValidators.h"
#include "Kismet2/CompilerResultsLog.h"
#include "AnimationTransitionGraph.h"
#include "AnimationConduitGraphSchema.h"
#include "AnimGraphNode_TransitionResult.h"
#define LOCTEXT_NAMESPACE "AnimStateConduitNode"
/////////////////////////////////////////////////////
// UAnimStateConduitNode
UAnimStateConduitNode::UAnimStateConduitNode(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
bCanRenameNode = true;
}
void UAnimStateConduitNode::AllocateDefaultPins()
{
CreatePin(EGPD_Input, TEXT("Transition"), TEXT("In"));
CreatePin(EGPD_Output, TEXT("Transition"), TEXT("Out"));
}
void UAnimStateConduitNode::AutowireNewNode(UEdGraphPin* FromPin)
{
Super::AutowireNewNode(FromPin);
if (FromPin)
{
if (GetSchema()->TryCreateConnection(FromPin, GetInputPin()))
{
FromPin->GetOwningNode()->NodeConnectionListChanged();
}
}
}
FText UAnimStateConduitNode::GetNodeTitle(ENodeTitleType::Type TitleType) const
{
return FText::FromString(GetStateName());
}
FText UAnimStateConduitNode::GetTooltipText() const
{
return LOCTEXT("ConduitNodeTooltip", "This is a conduit, which allows specification of a predicate condition for an entire group of transitions");
}
FString UAnimStateConduitNode::GetStateName() const
{
return (BoundGraph != NULL) ? *(BoundGraph->GetName()) : TEXT("(null)");
}
UEdGraphPin* UAnimStateConduitNode::GetInputPin() const
{
return Pins[0];
}
UEdGraphPin* UAnimStateConduitNode::GetOutputPin() const
{
return Pins[1];
}
void UAnimStateConduitNode::PostPlacedNewNode()
{
// Create a new animation graph
check(BoundGraph == NULL);
BoundGraph = FBlueprintEditorUtils::CreateNewGraph(
this,
NAME_None,
UAnimationTransitionGraph::StaticClass(),
UAnimationConduitGraphSchema::StaticClass());
check(BoundGraph);
// Find an interesting name
TSharedPtr<INameValidatorInterface> NameValidator = FNameValidatorFactory::MakeValidator(this);
FBlueprintEditorUtils::RenameGraphWithSuggestion(BoundGraph, NameValidator, TEXT("Conduit"));
// Initialize the transition graph
const UEdGraphSchema* Schema = BoundGraph->GetSchema();
Schema->CreateDefaultNodesForGraph(*BoundGraph);
// Add the new graph as a child of our parent graph
UEdGraph* ParentGraph = GetGraph();
if(ParentGraph->SubGraphs.Find(BoundGraph) == INDEX_NONE)
{
ParentGraph->SubGraphs.Add(BoundGraph);
}
}
void UAnimStateConduitNode::DestroyNode()
{
UEdGraph* GraphToRemove = BoundGraph;
BoundGraph = NULL;
Super::DestroyNode();
if (GraphToRemove)
{
UBlueprint* Blueprint = FBlueprintEditorUtils::FindBlueprintForNodeChecked(this);
FBlueprintEditorUtils::RemoveGraph(Blueprint, GraphToRemove, EGraphRemoveFlags::Recompile);
}
}
void UAnimStateConduitNode::ValidateNodeDuringCompilation(class FCompilerResultsLog& MessageLog) const
{
Super::ValidateNodeDuringCompilation(MessageLog);
UAnimationTransitionGraph* TransGraph = CastChecked<UAnimationTransitionGraph>(BoundGraph);
UAnimGraphNode_TransitionResult* ResultNode = TransGraph->GetResultNode();
check(ResultNode);
if (ResultNode->HasBinding(GET_MEMBER_NAME_CHECKED(FAnimNode_TransitionResult, bCanEnterTransition)))
{
// Rule is bound so nothing more to check
}
else
{
UEdGraphPin* BoolResultPin = ResultNode->Pins[0];
if ((BoolResultPin->LinkedTo.Num() == 0) && (BoolResultPin->DefaultValue.ToBool() == false))
{
MessageLog.Warning(TEXT("@@ will never be taken, please connect something to @@"), this, BoolResultPin);
}
}
}
FString UAnimStateConduitNode::GetDesiredNewNodeName() const
{
return TEXT("Conduit");
}
void UAnimStateConduitNode::PostPasteNode()
{
// Find an interesting name, but try to keep the same if possible
TSharedPtr<INameValidatorInterface> NameValidator = FNameValidatorFactory::MakeValidator(this);
FBlueprintEditorUtils::RenameGraphWithSuggestion(BoundGraph, NameValidator, GetStateName());
Super::PostPasteNode();
}
#undef LOCTEXT_NAMESPACE