// 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& Popups) const { GetStateInfoPopup(GraphNode, Popups); } FSlateColor SGraphNodeAnimStateAlias::GetBorderBackgroundColor_Internal(FLinearColor InactiveStateColor, FLinearColor ActiveStateColorDim, FLinearColor ActiveStateColorBright) const { UAnimBlueprint* AnimBlueprint = Cast(FBlueprintEditorUtils::FindBlueprintForNode(GraphNode)); if (AnimBlueprint) { UAnimInstance* ActiveObject = Cast(AnimBlueprint->GetObjectBeingDebugged()); UAnimBlueprintGeneratedClass* Class = AnimBlueprint->GetAnimBlueprintGeneratedClass(); // Display various types of debug data if ((ActiveObject != NULL) && (Class != NULL)) { UAnimationStateMachineGraph* StateMachineGraph = CastChecked(GraphNode->GetGraph()); UAnimStateAliasNode* StateAliasNode = CastChecked(GraphNode); if (FStateMachineDebugData* DebugInfo = Class->GetAnimBlueprintDebugData().StateMachineDebugData.Find(StateMachineGraph)) { TArray> StatesToCheck; // Check transitions associated with our state alias. TArray 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* 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(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 SGraphNodeAnimStateAlias::GetComplexTooltip() { return nullptr; } void SGraphNodeAnimStateAlias::GetStateInfoPopup(UEdGraphNode* GraphNode, TArray& Popups) { UAnimBlueprint* AnimBlueprint = Cast(FBlueprintEditorUtils::FindBlueprintForNode(GraphNode)); if (AnimBlueprint) { UAnimInstance* ActiveObject = Cast(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(GraphNode->GetGraph()); UAnimStateAliasNode* StateAliasNode = CastChecked(GraphNode); if (FStateMachineDebugData* DebugInfo = Class->GetAnimBlueprintDebugData().StateMachineDebugData.Find(StateMachineGraph)) { TArray> StatesToCheck; // Check transitions associated with our state alias. TArray 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* 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