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

190 lines
7.2 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "AnimationStateNodes/SGraphNodeAnimStateAlias.h"
#include "AnimStateAliasNode.h"
#include "AnimStateNodeBase.h"
#include "Animation/AnimBlueprint.h"
#include "Animation/AnimBlueprintGeneratedClass.h"
#include "Animation/AnimInstance.h"
#include "AnimationStateMachineGraph.h"
#include "AnimationStateNodes/SGraphNodeAnimState.h"
#include "AnimationStateNodes/SGraphNodeAnimTransition.h"
#include "Containers/ContainerAllocationPolicies.h"
#include "Containers/Map.h"
#include "Containers/Set.h"
#include "EdGraph/EdGraphNode.h"
#include "Engine/Blueprint.h"
#include "HAL/PlatformCrt.h"
#include "Internationalization/Internationalization.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "Math/UnrealMathSSE.h"
#include "Styling/AppStyle.h"
#include "Templates/Casts.h"
#include "UObject/WeakObjectPtr.h"
#include "UObject/WeakObjectPtrTemplates.h"
class SToolTip;
struct FGraphInformationPopupInfo;
struct FNodeInfoContext;
struct FSlateBrush;
#define LOCTEXT_NAMESPACE "SGraphNodeAnimStateAlias"
/////////////////////////////////////////////////////
// SGraphNodeAnimStateAlias
void SGraphNodeAnimStateAlias::Construct(const FArguments& InArgs, UAnimStateAliasNode* InNode)
{
SGraphNodeAnimState::Construct(SGraphNodeAnimState::FArguments(), InNode);
}
void SGraphNodeAnimStateAlias::GetNodeInfoPopups(FNodeInfoContext* Context, TArray<FGraphInformationPopupInfo>& Popups) const
{
GetStateInfoPopup(GraphNode, Popups);
}
FSlateColor SGraphNodeAnimStateAlias::GetBorderBackgroundColor_Internal(FLinearColor InactiveStateColor, FLinearColor ActiveStateColorDim, FLinearColor ActiveStateColorBright) const
{
UAnimBlueprint* AnimBlueprint = Cast<UAnimBlueprint>(FBlueprintEditorUtils::FindBlueprintForNode(GraphNode));
if (AnimBlueprint)
{
UAnimInstance* ActiveObject = Cast<UAnimInstance>(AnimBlueprint->GetObjectBeingDebugged());
UAnimBlueprintGeneratedClass* Class = AnimBlueprint->GetAnimBlueprintGeneratedClass();
// Display various types of debug data
if ((ActiveObject != NULL) && (Class != NULL))
{
UAnimationStateMachineGraph* StateMachineGraph = CastChecked<UAnimationStateMachineGraph>(GraphNode->GetGraph());
UAnimStateAliasNode* StateAliasNode = CastChecked<UAnimStateAliasNode>(GraphNode);
if (FStateMachineDebugData* DebugInfo = Class->GetAnimBlueprintDebugData().StateMachineDebugData.Find(StateMachineGraph))
{
TArray<int32, TInlineAllocator<16>> StatesToCheck;
// Check transitions associated with our state alias.
TArray<FStateMachineDebugData::FStateAliasTransitionStateIndexPair> TransitionStatePairs;
DebugInfo->StateAliasNodeToTransitionStatePairs.MultiFind(StateAliasNode, TransitionStatePairs);
const int32 PairsNum = TransitionStatePairs.Num();
for (int32 Index = 0; Index < PairsNum; ++Index)
{
auto& TransStatePair = TransitionStatePairs[Index];
if (SGraphNodeAnimTransition::IsTransitionActive(TransStatePair.TransitionIndex, *Class, *StateMachineGraph, *ActiveObject))
{
// Add the prev/next state we are aliasing that's associated with this transition.
StatesToCheck.Add(TransStatePair.AssociatedStateIndex);
}
}
// Use the highest aliased state's weight that has an active transition in/out of this alias.
float Weight = 0.0f;
for (const int32 StateIndex : StatesToCheck)
{
if (TWeakObjectPtr<UAnimStateNodeBase>* StateNodeWeakPtr = DebugInfo->StateIndexToNode.Find(StateIndex))
{
if (StateAliasNode->GetAliasedStates().Contains(*StateNodeWeakPtr))
{
for (const FStateMachineStateDebugData& StateData : Class->GetAnimBlueprintDebugData().StateData)
{
if (StateData.StateMachineIndex == DebugInfo->MachineIndex && StateData.StateIndex == StateIndex)
{
Weight = FMath::Max(Weight, StateData.Weight);
}
}
}
}
}
if (Weight > 0.0f)
{
return FMath::Lerp<FLinearColor>(ActiveStateColorDim, ActiveStateColorBright, Weight);
}
}
}
}
// Override inactive state color for aliases.
return FLinearColor(0.45f, 0.33f, 0.37f);
}
FText SGraphNodeAnimStateAlias::GetPreviewCornerText() const
{
return FText();
}
const FSlateBrush* SGraphNodeAnimStateAlias::GetNameIcon() const
{
return FAppStyle::GetBrush(TEXT("Graph.AliasNode.Icon"));
}
TSharedPtr<SToolTip> SGraphNodeAnimStateAlias::GetComplexTooltip()
{
return nullptr;
}
void SGraphNodeAnimStateAlias::GetStateInfoPopup(UEdGraphNode* GraphNode, TArray<FGraphInformationPopupInfo>& Popups)
{
UAnimBlueprint* AnimBlueprint = Cast<UAnimBlueprint>(FBlueprintEditorUtils::FindBlueprintForNode(GraphNode));
if (AnimBlueprint)
{
UAnimInstance* ActiveObject = Cast<UAnimInstance>(AnimBlueprint->GetObjectBeingDebugged());
UAnimBlueprintGeneratedClass* Class = AnimBlueprint->GetAnimBlueprintGeneratedClass();
static const FLinearColor PopupColor(1.f, 0.5f, 0.25f);
// Display various types of debug data
if ((ActiveObject != NULL) && (Class != NULL))
{
UAnimationStateMachineGraph* StateMachineGraph = CastChecked<UAnimationStateMachineGraph>(GraphNode->GetGraph());
UAnimStateAliasNode* StateAliasNode = CastChecked<UAnimStateAliasNode>(GraphNode);
if (FStateMachineDebugData* DebugInfo = Class->GetAnimBlueprintDebugData().StateMachineDebugData.Find(StateMachineGraph))
{
TArray<int32, TInlineAllocator<16>> StatesToCheck;
// Check transitions associated with our state alias.
TArray<FStateMachineDebugData::FStateAliasTransitionStateIndexPair> TransitionStatePairs;
DebugInfo->StateAliasNodeToTransitionStatePairs.MultiFind(StateAliasNode, TransitionStatePairs);
const int32 PairsNum = TransitionStatePairs.Num();
for (int32 Index = 0; Index < PairsNum; ++Index)
{
auto& TransStatePair = TransitionStatePairs[Index];
if (SGraphNodeAnimTransition::IsTransitionActive(TransStatePair.TransitionIndex, *Class, *StateMachineGraph, *ActiveObject))
{
// Add the prev/next state we are aliasing that's associated with this transition.
StatesToCheck.Add(TransStatePair.AssociatedStateIndex);
}
}
// Display the name and weight of any state we are aliasing that has an active incoming/outgoing transition from this alias
for (const int32 StateIndex : StatesToCheck)
{
if (TWeakObjectPtr<UAnimStateNodeBase>* StateNodeWeakPtr = DebugInfo->StateIndexToNode.Find(StateIndex))
{
if (UAnimStateNodeBase* StateNode = StateNodeWeakPtr->Get())
{
if (StateAliasNode->bGlobalAlias || StateAliasNode->GetAliasedStates().Contains(StateNode))
{
for (const FStateMachineStateDebugData& StateData : Class->GetAnimBlueprintDebugData().StateData)
{
if (StateData.StateMachineIndex == DebugInfo->MachineIndex && StateData.StateIndex == StateIndex)
{
FText StateText;
StateText = FText::Format(LOCTEXT("ActiveAliasedStateFormat", "{0}(Alias) {1}\nActive for {2}s"),
FText::FromString(StateNode->GetStateName()),
FText::AsPercent(StateData.Weight),
FText::AsNumber(StateData.ElapsedTime));
Popups.Emplace(nullptr, PopupColor, StateText.ToString());
break;
}
}
}
}
}
}
}
}
}
}
#undef LOCTEXT_NAMESPACE