Files
UnrealEngineUWP/Engine/Source/Editor/AnimGraph/Private/AnimBlueprintCompilerHandler_CachedPose.cpp
Thomas Sarkanen 8b3709fb28 Restricted anim BP compiler subsystem APIs
Removed direct access to currently compiling BP class to restrict unguarded mutation.
Const-corrected various accessors and overrides.
Moved UObject-based compiler subsystems to 'handlers' and removed UObject dependency.
Moved from set of virtual functions on subsystems/handlers to a restricted set of contexts passed to specific multicast delegates that handlers subscribe to.
Removed anim class subsystems.
Moved property access code to engine module (editor code is still in a plugin).
Fixed nativized builds where anim BPs have nativized/non-nativized classes in the hierarchy

#rb Dan.OConnor
#jira none

[CL 14278258 by Thomas Sarkanen in ue5-main branch]
2020-09-09 08:32:25 -04:00

179 lines
7.9 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "AnimBlueprintCompilerHandler_CachedPose.h"
#include "AnimGraphNode_SaveCachedPose.h"
#include "AnimGraphNode_Root.h"
#include "AnimGraphNode_UseCachedPose.h"
#include "Kismet2/CompilerResultsLog.h"
#include "AnimGraphNode_StateMachine.h"
#include "AnimGraphNode_StateResult.h"
#include "AnimationStateMachineGraph.h"
#include "IAnimBlueprintGeneratedClassCompiledData.h"
#include "IAnimBlueprintCompilerCreationContext.h"
#include "IAnimBlueprintCompilationContext.h"
FAnimBlueprintCompilerHandler_CachedPose::FAnimBlueprintCompilerHandler_CachedPose(IAnimBlueprintCompilerCreationContext& InCreationContext)
{
InCreationContext.OnPreProcessAnimationNodes().AddRaw(this, &FAnimBlueprintCompilerHandler_CachedPose::PreProcessAnimationNodes);
InCreationContext.OnPostProcessAnimationNodes().AddRaw(this, &FAnimBlueprintCompilerHandler_CachedPose::PostProcessAnimationNodes);
}
void FAnimBlueprintCompilerHandler_CachedPose::PreProcessAnimationNodes(TArrayView<UAnimGraphNode_Base*> InAnimNodes, IAnimBlueprintCompilationContext& InCompilationContext, IAnimBlueprintGeneratedClassCompiledData& OutCompiledData)
{
for(UAnimGraphNode_Base* Node : InAnimNodes)
{
if(UAnimGraphNode_SaveCachedPose* SavePoseRoot = Cast<UAnimGraphNode_SaveCachedPose>(Node))
{
//@TODO: Ideally we only add these if there is a UseCachedPose node referencing them, but those can be anywhere and are hard to grab
SaveCachedPoseNodes.Add(SavePoseRoot->CacheName, SavePoseRoot);
}
}
}
void FAnimBlueprintCompilerHandler_CachedPose::PostProcessAnimationNodes(TArrayView<UAnimGraphNode_Base*> InAnimNodes, IAnimBlueprintCompilationContext& InCompilationContext, IAnimBlueprintGeneratedClassCompiledData& OutCompiledData)
{
// Build cached pose map
BuildCachedPoseNodeUpdateOrder(InCompilationContext, OutCompiledData);
}
TAutoConsoleVariable<int32> CVarAnimDebugCachePoseNodeUpdateOrder(TEXT("a.Compiler.CachePoseNodeUpdateOrderDebug.Enable"), 0, TEXT("Toggle debugging for CacheNodeUpdateOrder debug during AnimBP compilation"));
void FAnimBlueprintCompilerHandler_CachedPose::BuildCachedPoseNodeUpdateOrder(IAnimBlueprintCompilationContext& InCompilationContext, IAnimBlueprintGeneratedClassCompiledData& OutCompiledData)
{
TArray<UAnimGraphNode_Root*> RootNodes;
InCompilationContext.GetConsolidatedEventGraph()->GetNodesOfClass<UAnimGraphNode_Root>(RootNodes);
// State results are also "root" nodes, need to find the true roots
RootNodes.RemoveAll([](UAnimGraphNode_Root* InPossibleRootNode)
{
return InPossibleRootNode->GetClass() != UAnimGraphNode_Root::StaticClass();
});
const bool bEnableDebug = (CVarAnimDebugCachePoseNodeUpdateOrder.GetValueOnAnyThread() == 1);
for(UAnimGraphNode_Root* RootNode : RootNodes)
{
TArray<UAnimGraphNode_SaveCachedPose*> OrderedSavePoseNodes;
TArray<UAnimGraphNode_Base*> VisitedRootNodes;
UE_CLOG(bEnableDebug, LogAnimation, Display, TEXT("CachePoseNodeOrdering BEGIN"));
CachePoseNodeOrdering_StartNewTraversal(InCompilationContext, RootNode, OrderedSavePoseNodes, VisitedRootNodes);
UE_CLOG(bEnableDebug, LogAnimation, Display, TEXT("CachePoseNodeOrdering END"));
if (bEnableDebug)
{
UE_LOG(LogAnimation, Display, TEXT("Ordered Save Pose Node List:"));
for (UAnimGraphNode_SaveCachedPose* SavedPoseNode : OrderedSavePoseNodes)
{
UE_LOG(LogAnimation, Display, TEXT("\t%s"), *SavedPoseNode->Node.CachePoseName.ToString())
}
UE_LOG(LogAnimation, Display, TEXT("End List"));
}
FCachedPoseIndices& OrderedSavedPoseIndices = OutCompiledData.GetOrderedSavedPoseIndicesMap().FindOrAdd(RootNode->Node.Name);
for(UAnimGraphNode_SaveCachedPose* PoseNode : OrderedSavePoseNodes)
{
if(const int32* NodeIndex = InCompilationContext.GetAllocatedAnimNodeIndices().Find(PoseNode))
{
OrderedSavedPoseIndices.OrderedSavedPoseNodeIndices.Add(*NodeIndex);
}
else
{
InCompilationContext.GetMessageLog().Error(TEXT("Failed to find index for a saved pose node while building ordered pose list."));
}
}
}
}
void FAnimBlueprintCompilerHandler_CachedPose::CachePoseNodeOrdering_StartNewTraversal(IAnimBlueprintCompilationContext& InCompilationContext, UAnimGraphNode_Base* InRootNode, TArray<UAnimGraphNode_SaveCachedPose*> &OrderedSavePoseNodes, TArray<UAnimGraphNode_Base*> VisitedRootNodes)
{
check(InRootNode);
UAnimGraphNode_SaveCachedPose* RootCacheNode = Cast<UAnimGraphNode_SaveCachedPose>(InRootNode);
FString RootName = RootCacheNode ? RootCacheNode->CacheName : InRootNode->GetName();
const bool bEnableDebug = (CVarAnimDebugCachePoseNodeUpdateOrder.GetValueOnAnyThread() == 1);
UE_CLOG(bEnableDebug, LogAnimation, Display, TEXT("StartNewTraversal %s"), *RootName);
// Track which root nodes we've visited to prevent infinite recursion.
VisitedRootNodes.Add(InRootNode);
// Need a list of only what we find here to recurse, we can't do that with the total list
TArray<UAnimGraphNode_SaveCachedPose*> InternalOrderedNodes;
// Traverse whole graph from root collecting SaveCachePose nodes we've touched.
CachePoseNodeOrdering_TraverseInternal(InCompilationContext, InRootNode, InternalOrderedNodes);
// Process nodes that we've touched
UE_CLOG(bEnableDebug, LogAnimation, Display, TEXT("Process Queue for %s"), *RootName);
for (UAnimGraphNode_SaveCachedPose* QueuedCacheNode : InternalOrderedNodes)
{
if (VisitedRootNodes.Contains(QueuedCacheNode))
{
UE_CLOG(bEnableDebug, LogAnimation, Display, TEXT("Process Queue SaveCachePose %s. ALREADY VISITED, INFINITE RECURSION DETECTED! SKIPPING"), *QueuedCacheNode->CacheName);
InCompilationContext.GetMessageLog().Error(*FString::Printf(TEXT("Infinite recursion detected with SaveCachePose %s and %s"), *RootName, *QueuedCacheNode->CacheName));
continue;
}
else
{
OrderedSavePoseNodes.Remove(QueuedCacheNode);
OrderedSavePoseNodes.Add(QueuedCacheNode);
CachePoseNodeOrdering_StartNewTraversal(InCompilationContext, QueuedCacheNode, OrderedSavePoseNodes, VisitedRootNodes);
}
}
UE_CLOG(bEnableDebug, LogAnimation, Display, TEXT("EndNewTraversal %s"), *RootName);
}
void FAnimBlueprintCompilerHandler_CachedPose::CachePoseNodeOrdering_TraverseInternal(IAnimBlueprintCompilationContext& InCompilationContext, UAnimGraphNode_Base* InAnimGraphNode, TArray<UAnimGraphNode_SaveCachedPose*> &OrderedSavePoseNodes)
{
TArray<UAnimGraphNode_Base*> LinkedAnimNodes;
InCompilationContext.GetLinkedAnimNodes(InAnimGraphNode, LinkedAnimNodes);
const bool bEnableDebug = (CVarAnimDebugCachePoseNodeUpdateOrder.GetValueOnAnyThread() == 1);
for (UAnimGraphNode_Base* LinkedNode : LinkedAnimNodes)
{
UE_CLOG(bEnableDebug, LogAnimation, Display, TEXT("\t Processing %s"), *LinkedNode->GetName());
if (UAnimGraphNode_UseCachedPose* UsePoseNode = Cast<UAnimGraphNode_UseCachedPose>(LinkedNode))
{
if (UAnimGraphNode_SaveCachedPose* SaveNode = UsePoseNode->SaveCachedPoseNode.Get())
{
UE_CLOG(bEnableDebug, LogAnimation, Display, TEXT("\t Queueing SaveCachePose %s"), *SaveNode->CacheName);
// Requeue the node we found
OrderedSavePoseNodes.Remove(SaveNode);
OrderedSavePoseNodes.Add(SaveNode);
}
}
else if (UAnimGraphNode_StateMachine* StateMachineNode = Cast<UAnimGraphNode_StateMachine>(LinkedNode))
{
for (UEdGraph* StateGraph : StateMachineNode->EditorStateMachineGraph->SubGraphs)
{
TArray<UAnimGraphNode_StateResult*> ResultNodes;
StateGraph->GetNodesOfClass(ResultNodes);
// We should only get one here but doesn't hurt to loop here in case that changes
for (UAnimGraphNode_StateResult* ResultNode : ResultNodes)
{
CachePoseNodeOrdering_TraverseInternal(InCompilationContext, ResultNode, OrderedSavePoseNodes);
}
}
}
else
{
CachePoseNodeOrdering_TraverseInternal(InCompilationContext, LinkedNode, OrderedSavePoseNodes);
}
}
}
const TMap<FString, UAnimGraphNode_SaveCachedPose*>& FAnimBlueprintCompilerHandler_CachedPose::GetSaveCachedPoseNodes() const
{
return SaveCachedPoseNodes;
}