Files
UnrealEngine/Engine/Source/Editor/AnimGraph/Private/AnimStateAliasNode.cpp
2025-05-18 13:04:45 +08:00

187 lines
4.8 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "AnimStateAliasNode.h"
#include "AnimStateNode.h"
#include "Containers/Array.h"
#include "EdGraph/EdGraph.h"
#include "EdGraph/EdGraphPin.h"
#include "EdGraph/EdGraphSchema.h"
#include "HAL/Platform.h"
#include "HAL/PlatformCrt.h"
#include "Internationalization/Internationalization.h"
#include "Kismet2/CompilerResultsLog.h"
#include "Kismet2/Kismet2NameValidators.h"
#include "Templates/Casts.h"
#include "Templates/SharedPointer.h"
#include "UObject/Object.h"
#include "UObject/WeakObjectPtr.h"
class FArchive;
#define LOCTEXT_NAMESPACE "AnimStateAliasNode"
/////////////////////////////////////////////////////
// UAnimStateAliasNode
UAnimStateAliasNode::UAnimStateAliasNode(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
bCanRenameNode = true;
StateAliasName = TEXT("Alias");
}
void UAnimStateAliasNode::Serialize(FArchive& Ar)
{
Super::Serialize(Ar);
RebuildAliasedStateNodeReferences();
}
void UAnimStateAliasNode::AllocateDefaultPins()
{
CreatePin(EGPD_Input, TEXT("Transition"), TEXT("In"));
CreatePin(EGPD_Output, TEXT("Transition"), TEXT("Out"));
}
void UAnimStateAliasNode::ValidateNodeDuringCompilation(class FCompilerResultsLog& MessageLog) const
{
Super::ValidateNodeDuringCompilation(MessageLog);
if ((GetInputPin()->LinkedTo.Num() > 0) && (bGlobalAlias || AliasedStateNodes.Num() != 1))
{
MessageLog.Error(*LOCTEXT("AliasAsEntryState", "A alias (@@) used as a transition's target must alias a single state").ToString(), this);
}
}
void UAnimStateAliasNode::AutowireNewNode(UEdGraphPin* FromPin)
{
Super::AutowireNewNode(FromPin);
if (FromPin)
{
if (GetSchema()->TryCreateConnection(FromPin, GetInputPin()))
{
FromPin->GetOwningNode()->NodeConnectionListChanged();
}
}
}
void UAnimStateAliasNode::PostPasteNode()
{
Super::PostPasteNode();
// Find an interesting name, but try to keep the same if possible
TSharedPtr<INameValidatorInterface> NameValidator = FNameValidatorFactory::MakeValidator(this);
NameValidator->FindValidString(StateAliasName);
}
void UAnimStateAliasNode::PostPlacedNewNode()
{
// Find an interesting name, but try to keep the same if possible
TSharedPtr<INameValidatorInterface> NameValidator = FNameValidatorFactory::MakeValidator(this);
NameValidator->FindValidString(StateAliasName);
}
FText UAnimStateAliasNode::GetNodeTitle(ENodeTitleType::Type TitleType) const
{
return FText::FromString(GetStateName());
}
FText UAnimStateAliasNode::GetTooltipText() const
{
return LOCTEXT("ConduitNodeTooltip", "This is a conduit, which allows specification of a predicate condition for an entire group of transitions");
}
FString UAnimStateAliasNode::GetStateName() const
{
return StateAliasName;
}
void UAnimStateAliasNode::OnRenameNode(const FString& NewName)
{
StateAliasName = NewName;
}
UEdGraphPin* UAnimStateAliasNode::GetInputPin() const
{
return Pins[0];
}
UEdGraphPin* UAnimStateAliasNode::GetOutputPin() const
{
return Pins[1];
}
FString UAnimStateAliasNode::GetDesiredNewNodeName() const
{
return TEXT("Alias");
}
UObject* UAnimStateAliasNode::GetJumpTargetForDoubleClick() const
{
return GetAliasedState();
}
const TSet<TWeakObjectPtr<UAnimStateNodeBase>>& UAnimStateAliasNode::GetAliasedStates() const
{
return AliasedStateNodes;
}
TSet<TWeakObjectPtr<UAnimStateNodeBase>>& UAnimStateAliasNode::GetAliasedStates()
{
return AliasedStateNodes;
}
UAnimStateNodeBase* UAnimStateAliasNode::GetAliasedState() const
{
// If we alias more than one state, we return null
if (bGlobalAlias || (AliasedStateNodes.Num() != 1))
{
return nullptr;
}
if (UAnimStateNodeBase* AliasedState = AliasedStateNodes.CreateConstIterator()->Get())
{
if (IsValidChecked(AliasedState))
{
if (const UEdGraph* Graph = GetGraph())
{
TArray<UAnimStateNodeBase*> StateNodes;
Graph->GetNodesOfClassEx<UAnimStateNode, UAnimStateNodeBase>(StateNodes);
return StateNodes.Contains(AliasedState) ? AliasedState : nullptr;
}
}
}
return nullptr;
}
void UAnimStateAliasNode::RebuildAliasedStateNodeReferences()
{
TSet<TWeakObjectPtr<UAnimStateNodeBase>> NewAliasedStateNodes;
// We don't use UEdGraphNode::GetGraph because this may be called during deletion and we don't want to assert on a missing graph.
if (const UEdGraph* Graph = Cast<UEdGraph>(GetOuter()))
{
TArray<UAnimStateNodeBase*> StateNodes;
Graph->GetNodesOfClassEx<UAnimStateNode, UAnimStateNodeBase>(StateNodes);
TSet<UAnimStateNodeBase*> StateNodesSet(StateNodes);
for (auto StateNodeIt = AliasedStateNodes.CreateIterator(); StateNodeIt; ++StateNodeIt)
{
UAnimStateNodeBase* AliasedState = StateNodeIt->Get();
// Keep only nodes that are still in the graph
if (IsValid(AliasedState) && StateNodesSet.Contains(AliasedState))
{
NewAliasedStateNodes.Add(*StateNodeIt);
}
}
AliasedStateNodes = NewAliasedStateNodes;
}
}
#undef LOCTEXT_NAMESPACE