Files
UnrealEngineUWP/Engine/Source/Editor/AnimGraph/Private/AnimBlueprintExtension_StateMachine.cpp

560 lines
24 KiB
C++
Raw Permalink Normal View History

// Copyright Epic Games, Inc. All Rights Reserved.
Anim node data/compiler refactor Per-node constant data is now held on a generated struct as part of sparse class data. Per-node mutable data (i.e. pin links/property access mappings) is now held on a generated 'mutable data' struct that is compiled as part of the generated class. The anim BP compiler is now extended more conventionally using UAnimBlueprintExtension, derived from UBlueprintExtension. This directly replaces the older 'compiler handler' pattern that was added in an emergency fashion for 4.26. Anim graph nodes now request their required extensions and these are held on the UAnimBlueprint in the UBlueprint::Extensions array. The Extensions array is potentially refreshed with any node addition or removal. The Extensions array is force-refreshed each time an anim BP is compiled for the first time to deal with newly added or removed requirements. Const-corrected a bunch of UAnimInstance/FAnimInstanceProxy APIs that rely on (now truly) const data. Added a split state/constant version of FInputScaleBiasClamp to allow some of its data to be split into constants. Tweaked alignment/ordering of FPoseLinkBase to save a few bytes per pose link. Deprecated FAnimNode_Base::OverrideAsset in favor of a more UAnimGraphNode_Base-based approach. Individual nodes can still have runtime overrides via specific accessors. The new approach will also give us the oppurtunity to override multiple assets per node if required in the future. Moved property access into Engine module & removed event support from it - this was never used. Reworked property access compilation API a little - construction/lifetime was a bit confusing previously. Optimized path used to create UK2Node_StructMemberSet nodes in per-node custom events. When using mutable data, the structure used is large and very sparsely connected (i.e. only a few properties are written) so we only create pins that are actually going to be used, rather than creating all of them and conly connecting a few. Patched the following nodes to use the new data approach: - Asset players (sequences, blendspaces, aim offsets) - Blend lists - Ref poses - Roots #rb Jurre.deBaare, Martin.Wilson, Keith.Yerex [CL 16090510 by Thomas Sarkanen in ue5-main branch]
2021-04-22 04:57:09 -04:00
#include "AnimBlueprintExtension_StateMachine.h"
#include "Animation/AnimBlueprintGeneratedClass.h"
#include "K2Node_AnimGetter.h"
#include "K2Node_TransitionRuleGetter.h"
#include "Kismet2/CompilerResultsLog.h"
#include "AnimGraphNode_Base.h"
#include "K2Node_StructMemberGet.h"
#include "AnimStateNode.h"
#include "AnimStateTransitionNode.h"
#include "AnimGraphNode_StateMachineBase.h"
#include "EdGraphUtilities.h"
#include "AnimationStateMachineSchema.h"
#include "IAnimBlueprintGeneratedClassCompiledData.h"
#include "IAnimBlueprintCompilerCreationContext.h"
#include "IAnimBlueprintCompilationContext.h"
Anim node data/compiler refactor Per-node constant data is now held on a generated struct as part of sparse class data. Per-node mutable data (i.e. pin links/property access mappings) is now held on a generated 'mutable data' struct that is compiled as part of the generated class. The anim BP compiler is now extended more conventionally using UAnimBlueprintExtension, derived from UBlueprintExtension. This directly replaces the older 'compiler handler' pattern that was added in an emergency fashion for 4.26. Anim graph nodes now request their required extensions and these are held on the UAnimBlueprint in the UBlueprint::Extensions array. The Extensions array is potentially refreshed with any node addition or removal. The Extensions array is force-refreshed each time an anim BP is compiled for the first time to deal with newly added or removed requirements. Const-corrected a bunch of UAnimInstance/FAnimInstanceProxy APIs that rely on (now truly) const data. Added a split state/constant version of FInputScaleBiasClamp to allow some of its data to be split into constants. Tweaked alignment/ordering of FPoseLinkBase to save a few bytes per pose link. Deprecated FAnimNode_Base::OverrideAsset in favor of a more UAnimGraphNode_Base-based approach. Individual nodes can still have runtime overrides via specific accessors. The new approach will also give us the oppurtunity to override multiple assets per node if required in the future. Moved property access into Engine module & removed event support from it - this was never used. Reworked property access compilation API a little - construction/lifetime was a bit confusing previously. Optimized path used to create UK2Node_StructMemberSet nodes in per-node custom events. When using mutable data, the structure used is large and very sparsely connected (i.e. only a few properties are written) so we only create pins that are actually going to be used, rather than creating all of them and conly connecting a few. Patched the following nodes to use the new data approach: - Asset players (sequences, blendspaces, aim offsets) - Blend lists - Ref poses - Roots #rb Jurre.deBaare, Martin.Wilson, Keith.Yerex [CL 16090510 by Thomas Sarkanen in ue5-main branch]
2021-04-22 04:57:09 -04:00
#define LOCTEXT_NAMESPACE "AnimBlueprintExtension_StateMachine"
Anim node data/compiler refactor Per-node constant data is now held on a generated struct as part of sparse class data. Per-node mutable data (i.e. pin links/property access mappings) is now held on a generated 'mutable data' struct that is compiled as part of the generated class. The anim BP compiler is now extended more conventionally using UAnimBlueprintExtension, derived from UBlueprintExtension. This directly replaces the older 'compiler handler' pattern that was added in an emergency fashion for 4.26. Anim graph nodes now request their required extensions and these are held on the UAnimBlueprint in the UBlueprint::Extensions array. The Extensions array is potentially refreshed with any node addition or removal. The Extensions array is force-refreshed each time an anim BP is compiled for the first time to deal with newly added or removed requirements. Const-corrected a bunch of UAnimInstance/FAnimInstanceProxy APIs that rely on (now truly) const data. Added a split state/constant version of FInputScaleBiasClamp to allow some of its data to be split into constants. Tweaked alignment/ordering of FPoseLinkBase to save a few bytes per pose link. Deprecated FAnimNode_Base::OverrideAsset in favor of a more UAnimGraphNode_Base-based approach. Individual nodes can still have runtime overrides via specific accessors. The new approach will also give us the oppurtunity to override multiple assets per node if required in the future. Moved property access into Engine module & removed event support from it - this was never used. Reworked property access compilation API a little - construction/lifetime was a bit confusing previously. Optimized path used to create UK2Node_StructMemberSet nodes in per-node custom events. When using mutable data, the structure used is large and very sparsely connected (i.e. only a few properties are written) so we only create pins that are actually going to be used, rather than creating all of them and conly connecting a few. Patched the following nodes to use the new data approach: - Asset players (sequences, blendspaces, aim offsets) - Blend lists - Ref poses - Roots #rb Jurre.deBaare, Martin.Wilson, Keith.Yerex [CL 16090510 by Thomas Sarkanen in ue5-main branch]
2021-04-22 04:57:09 -04:00
void UAnimBlueprintExtension_StateMachine::HandleBeginCompilation(IAnimBlueprintCompilerCreationContext& InCreationContext)
{
InCreationContext.RegisterKnownGraphSchema(UAnimationStateMachineSchema::StaticClass());
}
Anim node data/compiler refactor Per-node constant data is now held on a generated struct as part of sparse class data. Per-node mutable data (i.e. pin links/property access mappings) is now held on a generated 'mutable data' struct that is compiled as part of the generated class. The anim BP compiler is now extended more conventionally using UAnimBlueprintExtension, derived from UBlueprintExtension. This directly replaces the older 'compiler handler' pattern that was added in an emergency fashion for 4.26. Anim graph nodes now request their required extensions and these are held on the UAnimBlueprint in the UBlueprint::Extensions array. The Extensions array is potentially refreshed with any node addition or removal. The Extensions array is force-refreshed each time an anim BP is compiled for the first time to deal with newly added or removed requirements. Const-corrected a bunch of UAnimInstance/FAnimInstanceProxy APIs that rely on (now truly) const data. Added a split state/constant version of FInputScaleBiasClamp to allow some of its data to be split into constants. Tweaked alignment/ordering of FPoseLinkBase to save a few bytes per pose link. Deprecated FAnimNode_Base::OverrideAsset in favor of a more UAnimGraphNode_Base-based approach. Individual nodes can still have runtime overrides via specific accessors. The new approach will also give us the oppurtunity to override multiple assets per node if required in the future. Moved property access into Engine module & removed event support from it - this was never used. Reworked property access compilation API a little - construction/lifetime was a bit confusing previously. Optimized path used to create UK2Node_StructMemberSet nodes in per-node custom events. When using mutable data, the structure used is large and very sparsely connected (i.e. only a few properties are written) so we only create pins that are actually going to be used, rather than creating all of them and conly connecting a few. Patched the following nodes to use the new data approach: - Asset players (sequences, blendspaces, aim offsets) - Blend lists - Ref poses - Roots #rb Jurre.deBaare, Martin.Wilson, Keith.Yerex [CL 16090510 by Thomas Sarkanen in ue5-main branch]
2021-04-22 04:57:09 -04:00
void UAnimBlueprintExtension_StateMachine::HandleStartCompilingClass(const UClass* InClass, IAnimBlueprintCompilationBracketContext& InCompilationContext, IAnimBlueprintGeneratedClassCompiledData& OutCompiledData)
{
FoundGetterNodes.Empty();
RootTransitionGetters.Empty();
RootGraphAnimGetters.Empty();
}
void UAnimBlueprintExtension_StateMachine::HandlePreProcessAnimationNodes(TArrayView<UAnimGraphNode_Base*> InAnimNodes, IAnimBlueprintCompilationContext& InCompilationContext, IAnimBlueprintGeneratedClassCompiledData& OutCompiledData)
{
InCompilationContext.GetConsolidatedEventGraph()->GetNodesOfClass<UK2Node_TransitionRuleGetter>(RootTransitionGetters);
// Get anim getters from the root anim graph (processing the nodes below will collect them in nested graphs)
InCompilationContext.GetConsolidatedEventGraph()->GetNodesOfClass<UK2Node_AnimGetter>(RootGraphAnimGetters);
}
Anim node data/compiler refactor Per-node constant data is now held on a generated struct as part of sparse class data. Per-node mutable data (i.e. pin links/property access mappings) is now held on a generated 'mutable data' struct that is compiled as part of the generated class. The anim BP compiler is now extended more conventionally using UAnimBlueprintExtension, derived from UBlueprintExtension. This directly replaces the older 'compiler handler' pattern that was added in an emergency fashion for 4.26. Anim graph nodes now request their required extensions and these are held on the UAnimBlueprint in the UBlueprint::Extensions array. The Extensions array is potentially refreshed with any node addition or removal. The Extensions array is force-refreshed each time an anim BP is compiled for the first time to deal with newly added or removed requirements. Const-corrected a bunch of UAnimInstance/FAnimInstanceProxy APIs that rely on (now truly) const data. Added a split state/constant version of FInputScaleBiasClamp to allow some of its data to be split into constants. Tweaked alignment/ordering of FPoseLinkBase to save a few bytes per pose link. Deprecated FAnimNode_Base::OverrideAsset in favor of a more UAnimGraphNode_Base-based approach. Individual nodes can still have runtime overrides via specific accessors. The new approach will also give us the oppurtunity to override multiple assets per node if required in the future. Moved property access into Engine module & removed event support from it - this was never used. Reworked property access compilation API a little - construction/lifetime was a bit confusing previously. Optimized path used to create UK2Node_StructMemberSet nodes in per-node custom events. When using mutable data, the structure used is large and very sparsely connected (i.e. only a few properties are written) so we only create pins that are actually going to be used, rather than creating all of them and conly connecting a few. Patched the following nodes to use the new data approach: - Asset players (sequences, blendspaces, aim offsets) - Blend lists - Ref poses - Roots #rb Jurre.deBaare, Martin.Wilson, Keith.Yerex [CL 16090510 by Thomas Sarkanen in ue5-main branch]
2021-04-22 04:57:09 -04:00
void UAnimBlueprintExtension_StateMachine::HandlePostProcessAnimationNodes(TArrayView<UAnimGraphNode_Base*> InAnimNodes, IAnimBlueprintCompilationContext& InCompilationContext, IAnimBlueprintGeneratedClassCompiledData& OutCompiledData)
{
// Process the getter nodes in the graph if there were any
for (auto GetterIt = RootTransitionGetters.CreateIterator(); GetterIt; ++GetterIt)
{
ProcessTransitionGetter(*GetterIt, nullptr, InCompilationContext, OutCompiledData); // transition nodes should not appear at top-level
}
// Wire root getters
for(UK2Node_AnimGetter* RootGraphGetter : RootGraphAnimGetters)
{
AutoWireAnimGetter(RootGraphGetter, nullptr, InCompilationContext, OutCompiledData);
}
// Wire nested getters
for(UK2Node_AnimGetter* Getter : FoundGetterNodes)
{
AutoWireAnimGetter(Getter, nullptr, InCompilationContext, OutCompiledData);
}
}
Anim node data/compiler refactor Per-node constant data is now held on a generated struct as part of sparse class data. Per-node mutable data (i.e. pin links/property access mappings) is now held on a generated 'mutable data' struct that is compiled as part of the generated class. The anim BP compiler is now extended more conventionally using UAnimBlueprintExtension, derived from UBlueprintExtension. This directly replaces the older 'compiler handler' pattern that was added in an emergency fashion for 4.26. Anim graph nodes now request their required extensions and these are held on the UAnimBlueprint in the UBlueprint::Extensions array. The Extensions array is potentially refreshed with any node addition or removal. The Extensions array is force-refreshed each time an anim BP is compiled for the first time to deal with newly added or removed requirements. Const-corrected a bunch of UAnimInstance/FAnimInstanceProxy APIs that rely on (now truly) const data. Added a split state/constant version of FInputScaleBiasClamp to allow some of its data to be split into constants. Tweaked alignment/ordering of FPoseLinkBase to save a few bytes per pose link. Deprecated FAnimNode_Base::OverrideAsset in favor of a more UAnimGraphNode_Base-based approach. Individual nodes can still have runtime overrides via specific accessors. The new approach will also give us the oppurtunity to override multiple assets per node if required in the future. Moved property access into Engine module & removed event support from it - this was never used. Reworked property access compilation API a little - construction/lifetime was a bit confusing previously. Optimized path used to create UK2Node_StructMemberSet nodes in per-node custom events. When using mutable data, the structure used is large and very sparsely connected (i.e. only a few properties are written) so we only create pins that are actually going to be used, rather than creating all of them and conly connecting a few. Patched the following nodes to use the new data approach: - Asset players (sequences, blendspaces, aim offsets) - Blend lists - Ref poses - Roots #rb Jurre.deBaare, Martin.Wilson, Keith.Yerex [CL 16090510 by Thomas Sarkanen in ue5-main branch]
2021-04-22 04:57:09 -04:00
UK2Node_CallFunction* UAnimBlueprintExtension_StateMachine::SpawnCallAnimInstanceFunction(IAnimBlueprintCompilationContext& InCompilationContext, UEdGraphNode* SourceNode, FName FunctionName)
{
//@TODO: SKELETON: This is a call on a parent function (UAnimInstance::StaticClass() specifically), should we treat it as self or not?
UK2Node_CallFunction* FunctionCall = InCompilationContext.SpawnIntermediateNode<UK2Node_CallFunction>(SourceNode);
FunctionCall->FunctionReference.SetSelfMember(FunctionName);
FunctionCall->AllocateDefaultPins();
return FunctionCall;
}
Anim node data/compiler refactor Per-node constant data is now held on a generated struct as part of sparse class data. Per-node mutable data (i.e. pin links/property access mappings) is now held on a generated 'mutable data' struct that is compiled as part of the generated class. The anim BP compiler is now extended more conventionally using UAnimBlueprintExtension, derived from UBlueprintExtension. This directly replaces the older 'compiler handler' pattern that was added in an emergency fashion for 4.26. Anim graph nodes now request their required extensions and these are held on the UAnimBlueprint in the UBlueprint::Extensions array. The Extensions array is potentially refreshed with any node addition or removal. The Extensions array is force-refreshed each time an anim BP is compiled for the first time to deal with newly added or removed requirements. Const-corrected a bunch of UAnimInstance/FAnimInstanceProxy APIs that rely on (now truly) const data. Added a split state/constant version of FInputScaleBiasClamp to allow some of its data to be split into constants. Tweaked alignment/ordering of FPoseLinkBase to save a few bytes per pose link. Deprecated FAnimNode_Base::OverrideAsset in favor of a more UAnimGraphNode_Base-based approach. Individual nodes can still have runtime overrides via specific accessors. The new approach will also give us the oppurtunity to override multiple assets per node if required in the future. Moved property access into Engine module & removed event support from it - this was never used. Reworked property access compilation API a little - construction/lifetime was a bit confusing previously. Optimized path used to create UK2Node_StructMemberSet nodes in per-node custom events. When using mutable data, the structure used is large and very sparsely connected (i.e. only a few properties are written) so we only create pins that are actually going to be used, rather than creating all of them and conly connecting a few. Patched the following nodes to use the new data approach: - Asset players (sequences, blendspaces, aim offsets) - Blend lists - Ref poses - Roots #rb Jurre.deBaare, Martin.Wilson, Keith.Yerex [CL 16090510 by Thomas Sarkanen in ue5-main branch]
2021-04-22 04:57:09 -04:00
void UAnimBlueprintExtension_StateMachine::ProcessTransitionGetter(UK2Node_TransitionRuleGetter* Getter, UAnimStateTransitionNode* TransitionNode, IAnimBlueprintCompilationContext& InCompilationContext, IAnimBlueprintGeneratedClassCompiledData& OutCompiledData)
{
// Get common elements for multiple getters
UEdGraphPin* OutputPin = Getter->GetOutputPin();
UEdGraphPin* SourceTimePin = NULL;
UAnimationAsset* AnimAsset= NULL;
int32 PlayerNodeIndex = INDEX_NONE;
if (UAnimGraphNode_Base* SourcePlayerNode = Getter->AssociatedAnimAssetPlayerNode)
{
// This check should never fail as the source state is always processed first before handling it's rules
UAnimGraphNode_Base* TrueSourceNode = InCompilationContext.GetMessageLog().FindSourceObjectTypeChecked<UAnimGraphNode_Base>(SourcePlayerNode);
UAnimGraphNode_Base* UndertypedPlayerNode = InCompilationContext.GetSourceNodeToProcessedNodeMap().FindRef(TrueSourceNode);
if (UndertypedPlayerNode == NULL)
{
InCompilationContext.GetMessageLog().Error(TEXT("ICE: Player node @@ was not processed prior to handling a transition getter @@ that used it"), SourcePlayerNode, Getter);
return;
}
// Make sure the node is still relevant
UEdGraph* PlayerGraph = UndertypedPlayerNode->GetGraph();
if (!PlayerGraph->Nodes.Contains(UndertypedPlayerNode))
{
InCompilationContext.GetMessageLog().Error(TEXT("@@ is not associated with a node in @@; please delete and recreate it"), Getter, PlayerGraph);
}
// Make sure the referenced AnimAsset player has been allocated
PlayerNodeIndex = InCompilationContext.GetAllocationIndexOfNode(UndertypedPlayerNode);
if (PlayerNodeIndex == INDEX_NONE)
{
InCompilationContext.GetMessageLog().Error(*LOCTEXT("BadAnimAssetNodeUsedInGetter", "@@ doesn't have a valid associated AnimAsset node. Delete and recreate it").ToString(), Getter);
}
// Grab the AnimAsset, and time pin if needed
UScriptStruct* TimePropertyInStructType = NULL;
const TCHAR* TimePropertyName = NULL;
if (UndertypedPlayerNode->DoesSupportTimeForTransitionGetter())
{
AnimAsset = UndertypedPlayerNode->GetAnimationAsset();
TimePropertyInStructType = UndertypedPlayerNode->GetTimePropertyStruct();
TimePropertyName = UndertypedPlayerNode->GetTimePropertyName();
}
else
{
InCompilationContext.GetMessageLog().Error(TEXT("@@ is associated with @@, which is an unexpected type"), Getter, UndertypedPlayerNode);
}
bool bNeedTimePin = false;
// Determine if we need to read the current time variable from the specified sequence player
switch (Getter->GetterType)
{
case ETransitionGetter::AnimationAsset_GetCurrentTime:
case ETransitionGetter::AnimationAsset_GetCurrentTimeFraction:
case ETransitionGetter::AnimationAsset_GetTimeFromEnd:
case ETransitionGetter::AnimationAsset_GetTimeFromEndFraction:
bNeedTimePin = true;
break;
default:
bNeedTimePin = false;
break;
}
if (bNeedTimePin && (PlayerNodeIndex != INDEX_NONE) && (TimePropertyName != NULL) && (TimePropertyInStructType != NULL))
{
const FProperty* NodeProperty = InCompilationContext.GetAllocatedPropertiesByIndex().FindChecked(PlayerNodeIndex);
// Create a struct member read node to grab the current position of the sequence player node
UK2Node_StructMemberGet* TimeReadNode = InCompilationContext.SpawnIntermediateNode<UK2Node_StructMemberGet>(Getter, InCompilationContext.GetConsolidatedEventGraph());
TimeReadNode->VariableReference.SetSelfMember(NodeProperty->GetFName());
TimeReadNode->StructType = TimePropertyInStructType;
TimeReadNode->AllocatePinsForSingleMemberGet(TimePropertyName);
SourceTimePin = TimeReadNode->FindPinChecked(TimePropertyName);
}
}
// Expand it out
UK2Node_CallFunction* GetterHelper = NULL;
switch (Getter->GetterType)
{
case ETransitionGetter::AnimationAsset_GetCurrentTime:
if ((AnimAsset != NULL) && (SourceTimePin != NULL))
{
GetterHelper = SpawnCallAnimInstanceFunction(InCompilationContext, Getter, TEXT("GetInstanceAssetPlayerTime"));
GetterHelper->FindPinChecked(TEXT("AssetPlayerIndex"))->DefaultValue = FString::FromInt(PlayerNodeIndex);
}
else
{
if (Getter->AssociatedAnimAssetPlayerNode)
{
InCompilationContext.GetMessageLog().Error(TEXT("Please replace @@ with Get Relevant Anim Time. @@ has no animation asset"), Getter, Getter->AssociatedAnimAssetPlayerNode);
}
else
{
InCompilationContext.GetMessageLog().Error(TEXT("@@ is not asscociated with an asset player"), Getter);
}
}
break;
case ETransitionGetter::AnimationAsset_GetLength:
if (AnimAsset != NULL)
{
GetterHelper = SpawnCallAnimInstanceFunction(InCompilationContext, Getter, TEXT("GetInstanceAssetPlayerLength"));
GetterHelper->FindPinChecked(TEXT("AssetPlayerIndex"))->DefaultValue = FString::FromInt(PlayerNodeIndex);
}
else
{
if (Getter->AssociatedAnimAssetPlayerNode)
{
InCompilationContext.GetMessageLog().Error(TEXT("Please replace @@ with Get Relevant Anim Length. @@ has no animation asset"), Getter, Getter->AssociatedAnimAssetPlayerNode);
}
else
{
InCompilationContext.GetMessageLog().Error(TEXT("@@ is not asscociated with an asset player"), Getter);
}
}
break;
case ETransitionGetter::AnimationAsset_GetCurrentTimeFraction:
if ((AnimAsset != NULL) && (SourceTimePin != NULL))
{
GetterHelper = SpawnCallAnimInstanceFunction(InCompilationContext, Getter, TEXT("GetInstanceAssetPlayerTimeFraction"));
GetterHelper->FindPinChecked(TEXT("AssetPlayerIndex"))->DefaultValue = FString::FromInt(PlayerNodeIndex);
}
else
{
if (Getter->AssociatedAnimAssetPlayerNode)
{
InCompilationContext.GetMessageLog().Error(TEXT("Please replace @@ with Get Relevant Anim Time Fraction. @@ has no animation asset"), Getter, Getter->AssociatedAnimAssetPlayerNode);
}
else
{
InCompilationContext.GetMessageLog().Error(TEXT("@@ is not asscociated with an asset player"), Getter);
}
}
break;
case ETransitionGetter::AnimationAsset_GetTimeFromEnd:
if ((AnimAsset != NULL) && (SourceTimePin != NULL))
{
GetterHelper = SpawnCallAnimInstanceFunction(InCompilationContext, Getter, TEXT("GetInstanceAssetPlayerTimeFromEnd"));
GetterHelper->FindPinChecked(TEXT("AssetPlayerIndex"))->DefaultValue = FString::FromInt(PlayerNodeIndex);
}
else
{
if (Getter->AssociatedAnimAssetPlayerNode)
{
InCompilationContext.GetMessageLog().Error(TEXT("Please replace @@ with Get Relevant Anim Time Remaining. @@ has no animation asset"), Getter, Getter->AssociatedAnimAssetPlayerNode);
}
else
{
InCompilationContext.GetMessageLog().Error(TEXT("@@ is not asscociated with an asset player"), Getter);
}
}
break;
case ETransitionGetter::AnimationAsset_GetTimeFromEndFraction:
if ((AnimAsset != NULL) && (SourceTimePin != NULL))
{
GetterHelper = SpawnCallAnimInstanceFunction(InCompilationContext, Getter, TEXT("GetInstanceAssetPlayerTimeFromEndFraction"));
GetterHelper->FindPinChecked(TEXT("AssetPlayerIndex"))->DefaultValue = FString::FromInt(PlayerNodeIndex);
}
else
{
if (Getter->AssociatedAnimAssetPlayerNode)
{
InCompilationContext.GetMessageLog().Error(TEXT("Please replace @@ with Get Relevant Anim Time Remaining Fraction. @@ has no animation asset"), Getter, Getter->AssociatedAnimAssetPlayerNode);
}
else
{
InCompilationContext.GetMessageLog().Error(TEXT("@@ is not asscociated with an asset player"), Getter);
}
}
break;
case ETransitionGetter::CurrentTransitionDuration:
{
check(TransitionNode);
if(UAnimStateNode* SourceStateNode = InCompilationContext.GetMessageLog().FindSourceObjectTypeChecked<UAnimStateNode>(TransitionNode->GetPreviousState()))
{
if(UObject* SourceTransitionNode = InCompilationContext.GetMessageLog().FindSourceObject(TransitionNode))
{
if(FStateMachineDebugData* DebugData = OutCompiledData.GetAnimBlueprintDebugData().StateMachineDebugData.Find(SourceStateNode->GetGraph()))
{
if(int32* pStateIndex = DebugData->NodeToStateIndex.Find(SourceStateNode))
{
const int32 StateIndex = *pStateIndex;
// This check should never fail as all animation nodes should be processed before getters are
UAnimGraphNode_Base* CompiledMachineInstanceNode = InCompilationContext.GetSourceNodeToProcessedNodeMap().FindChecked(DebugData->MachineInstanceNode.Get());
const int32 MachinePropertyIndex = InCompilationContext.GetAllocatedAnimNodeIndices().FindChecked(CompiledMachineInstanceNode);
int32 TransitionPropertyIndex = INDEX_NONE;
for(auto TransIt = DebugData->NodeToTransitionIndex.CreateConstIterator(); TransIt; ++TransIt)
{
const UEdGraphNode* CurrTransNode = TransIt.Key().Get();
if(CurrTransNode == SourceTransitionNode)
{
TransitionPropertyIndex = TransIt.Value();
break;
}
}
if(TransitionPropertyIndex != INDEX_NONE)
{
GetterHelper = SpawnCallAnimInstanceFunction(InCompilationContext, Getter, TEXT("GetInstanceTransitionCrossfadeDuration"));
GetterHelper->FindPinChecked(TEXT("MachineIndex"))->DefaultValue = FString::FromInt(MachinePropertyIndex);
GetterHelper->FindPinChecked(TEXT("TransitionIndex"))->DefaultValue = FString::FromInt(TransitionPropertyIndex);
}
}
}
}
}
}
break;
case ETransitionGetter::ArbitraryState_GetBlendWeight:
{
if (Getter->AssociatedStateNode)
{
if (UAnimStateNode* SourceStateNode = InCompilationContext.GetMessageLog().FindSourceObjectTypeChecked<UAnimStateNode>(Getter->AssociatedStateNode))
{
if (FStateMachineDebugData* DebugData = OutCompiledData.GetAnimBlueprintDebugData().StateMachineDebugData.Find(SourceStateNode->GetGraph()))
{
if (int32* pStateIndex = DebugData->NodeToStateIndex.Find(SourceStateNode))
{
const int32 StateIndex = *pStateIndex;
//const int32 MachineIndex = DebugData->MachineIndex;
// This check should never fail as all animation nodes should be processed before getters are
UAnimGraphNode_Base* CompiledMachineInstanceNode = InCompilationContext.GetSourceNodeToProcessedNodeMap().FindChecked(DebugData->MachineInstanceNode.Get());
const int32 MachinePropertyIndex = InCompilationContext.GetAllocatedAnimNodeIndices().FindChecked(CompiledMachineInstanceNode);
GetterHelper = SpawnCallAnimInstanceFunction(InCompilationContext, Getter, TEXT("GetInstanceStateWeight"));
GetterHelper->FindPinChecked(TEXT("MachineIndex"))->DefaultValue = FString::FromInt(MachinePropertyIndex);
GetterHelper->FindPinChecked(TEXT("StateIndex"))->DefaultValue = FString::FromInt(StateIndex);
}
}
}
}
if (GetterHelper == NULL)
{
InCompilationContext.GetMessageLog().Error(TEXT("@@ is not associated with a valid state"), Getter);
}
}
break;
case ETransitionGetter::CurrentState_ElapsedTime:
{
check(TransitionNode);
if (UAnimStateNode* SourceStateNode = InCompilationContext.GetMessageLog().FindSourceObjectTypeChecked<UAnimStateNode>(TransitionNode->GetPreviousState()))
{
if (FStateMachineDebugData* DebugData = OutCompiledData.GetAnimBlueprintDebugData().StateMachineDebugData.Find(SourceStateNode->GetGraph()))
{
// This check should never fail as all animation nodes should be processed before getters are
UAnimGraphNode_Base* CompiledMachineInstanceNode = InCompilationContext.GetSourceNodeToProcessedNodeMap().FindChecked(DebugData->MachineInstanceNode.Get());
const int32 MachinePropertyIndex = InCompilationContext.GetAllocatedAnimNodeIndices().FindChecked(CompiledMachineInstanceNode);
GetterHelper = SpawnCallAnimInstanceFunction(InCompilationContext, Getter, TEXT("GetInstanceCurrentStateElapsedTime"));
GetterHelper->FindPinChecked(TEXT("MachineIndex"))->DefaultValue = FString::FromInt(MachinePropertyIndex);
}
}
if (GetterHelper == NULL)
{
InCompilationContext.GetMessageLog().Error(TEXT("@@ is not associated with a valid state"), Getter);
}
}
break;
case ETransitionGetter::CurrentState_GetBlendWeight:
{
check(TransitionNode);
if (UAnimStateNode* SourceStateNode = InCompilationContext.GetMessageLog().FindSourceObjectTypeChecked<UAnimStateNode>(TransitionNode->GetPreviousState()))
{
{
if (FStateMachineDebugData* DebugData = OutCompiledData.GetAnimBlueprintDebugData().StateMachineDebugData.Find(SourceStateNode->GetGraph()))
{
if (int32* pStateIndex = DebugData->NodeToStateIndex.Find(SourceStateNode))
{
const int32 StateIndex = *pStateIndex;
//const int32 MachineIndex = DebugData->MachineIndex;
// This check should never fail as all animation nodes should be processed before getters are
UAnimGraphNode_Base* CompiledMachineInstanceNode = InCompilationContext.GetSourceNodeToProcessedNodeMap().FindChecked(DebugData->MachineInstanceNode.Get());
const int32 MachinePropertyIndex = InCompilationContext.GetAllocatedAnimNodeIndices().FindChecked(CompiledMachineInstanceNode);
GetterHelper = SpawnCallAnimInstanceFunction(InCompilationContext, Getter, TEXT("GetInstanceStateWeight"));
GetterHelper->FindPinChecked(TEXT("MachineIndex"))->DefaultValue = FString::FromInt(MachinePropertyIndex);
GetterHelper->FindPinChecked(TEXT("StateIndex"))->DefaultValue = FString::FromInt(StateIndex);
}
}
}
}
if (GetterHelper == NULL)
{
InCompilationContext.GetMessageLog().Error(TEXT("@@ is not associated with a valid state"), Getter);
}
}
break;
default:
InCompilationContext.GetMessageLog().Error(TEXT("Unrecognized getter type on @@"), Getter);
break;
}
// Finish wiring up a call function if needed
if (GetterHelper != NULL)
{
check(GetterHelper->IsNodePure());
UEdGraphPin* NewReturnPin = GetterHelper->FindPinChecked(TEXT("ReturnValue"));
InCompilationContext.GetMessageLog().NotifyIntermediatePinCreation(NewReturnPin, OutputPin);
NewReturnPin->CopyPersistentDataFromOldPin(*OutputPin);
}
// Remove the getter from the equation
Getter->BreakAllNodeLinks();
}
Anim node data/compiler refactor Per-node constant data is now held on a generated struct as part of sparse class data. Per-node mutable data (i.e. pin links/property access mappings) is now held on a generated 'mutable data' struct that is compiled as part of the generated class. The anim BP compiler is now extended more conventionally using UAnimBlueprintExtension, derived from UBlueprintExtension. This directly replaces the older 'compiler handler' pattern that was added in an emergency fashion for 4.26. Anim graph nodes now request their required extensions and these are held on the UAnimBlueprint in the UBlueprint::Extensions array. The Extensions array is potentially refreshed with any node addition or removal. The Extensions array is force-refreshed each time an anim BP is compiled for the first time to deal with newly added or removed requirements. Const-corrected a bunch of UAnimInstance/FAnimInstanceProxy APIs that rely on (now truly) const data. Added a split state/constant version of FInputScaleBiasClamp to allow some of its data to be split into constants. Tweaked alignment/ordering of FPoseLinkBase to save a few bytes per pose link. Deprecated FAnimNode_Base::OverrideAsset in favor of a more UAnimGraphNode_Base-based approach. Individual nodes can still have runtime overrides via specific accessors. The new approach will also give us the oppurtunity to override multiple assets per node if required in the future. Moved property access into Engine module & removed event support from it - this was never used. Reworked property access compilation API a little - construction/lifetime was a bit confusing previously. Optimized path used to create UK2Node_StructMemberSet nodes in per-node custom events. When using mutable data, the structure used is large and very sparsely connected (i.e. only a few properties are written) so we only create pins that are actually going to be used, rather than creating all of them and conly connecting a few. Patched the following nodes to use the new data approach: - Asset players (sequences, blendspaces, aim offsets) - Blend lists - Ref poses - Roots #rb Jurre.deBaare, Martin.Wilson, Keith.Yerex [CL 16090510 by Thomas Sarkanen in ue5-main branch]
2021-04-22 04:57:09 -04:00
void UAnimBlueprintExtension_StateMachine::AutoWireAnimGetter(class UK2Node_AnimGetter* Getter, UAnimStateTransitionNode* InTransitionNode, IAnimBlueprintCompilationContext& InCompilationContext, IAnimBlueprintGeneratedClassCompiledData& OutCompiledData)
{
UEdGraphPin* ReferencedNodeTimePin = nullptr;
int32 ReferencedNodeIndex = INDEX_NONE;
int32 SubNodeIndex = INDEX_NONE;
UAnimGraphNode_Base* ProcessedNodeCheck = NULL;
if(UAnimGraphNode_Base* SourceNode = Getter->SourceNode)
{
UAnimGraphNode_Base* ActualSourceNode = InCompilationContext.GetMessageLog().FindSourceObjectTypeChecked<UAnimGraphNode_Base>(SourceNode);
if(UAnimGraphNode_Base* ProcessedSourceNode = InCompilationContext.GetSourceNodeToProcessedNodeMap().FindRef(ActualSourceNode))
{
ProcessedNodeCheck = ProcessedSourceNode;
ReferencedNodeIndex = InCompilationContext.GetAllocationIndexOfNode(ProcessedSourceNode);
if(ProcessedSourceNode->DoesSupportTimeForTransitionGetter())
{
UScriptStruct* TimePropertyInStructType = ProcessedSourceNode->GetTimePropertyStruct();
const TCHAR* TimePropertyName = ProcessedSourceNode->GetTimePropertyName();
if(ReferencedNodeIndex != INDEX_NONE && TimePropertyName && TimePropertyInStructType)
{
FProperty* NodeProperty = InCompilationContext.GetAllocatedPropertiesByIndex().FindChecked(ReferencedNodeIndex);
UK2Node_StructMemberGet* ReaderNode = InCompilationContext.SpawnIntermediateNode<UK2Node_StructMemberGet>(Getter, InCompilationContext.GetConsolidatedEventGraph());
ReaderNode->VariableReference.SetSelfMember(NodeProperty->GetFName());
ReaderNode->StructType = TimePropertyInStructType;
ReaderNode->AllocatePinsForSingleMemberGet(TimePropertyName);
ReferencedNodeTimePin = ReaderNode->FindPinChecked(TimePropertyName);
}
}
}
}
if(Getter->SourceStateNode)
{
UObject* SourceObject = InCompilationContext.GetMessageLog().FindSourceObject(Getter->SourceStateNode);
if(UAnimStateNode* SourceStateNode = Cast<UAnimStateNode>(SourceObject))
{
if(FStateMachineDebugData* DebugData = OutCompiledData.GetAnimBlueprintDebugData().StateMachineDebugData.Find(SourceStateNode->GetGraph()))
{
if(int32* StateIndexPtr = DebugData->NodeToStateIndex.Find(SourceStateNode))
{
SubNodeIndex = *StateIndexPtr;
}
}
}
else if(UAnimStateTransitionNode* TransitionNode = Cast<UAnimStateTransitionNode>(SourceObject))
{
if(FStateMachineDebugData* DebugData = OutCompiledData.GetAnimBlueprintDebugData().StateMachineDebugData.Find(TransitionNode->GetGraph()))
{
TArray<int32> TransitionIndices;
DebugData->NodeToTransitionIndex.MultiFind(TransitionNode, TransitionIndices);
const int32 TransNum = TransitionIndices.Num();
if (TransNum > 0)
{
SubNodeIndex = TransitionIndices[0];
}
}
}
}
check(Getter->IsNodePure());
for(UEdGraphPin* Pin : Getter->Pins)
{
// Hook up autowired parameters / pins
if(Pin->PinName == TEXT("CurrentTime"))
{
Pin->MakeLinkTo(ReferencedNodeTimePin);
}
else if(Pin->PinName == TEXT("AssetPlayerIndex") || Pin->PinName == TEXT("MachineIndex"))
{
Pin->DefaultValue = FString::FromInt(ReferencedNodeIndex);
}
else if(Pin->PinName == TEXT("StateIndex") || Pin->PinName == TEXT("TransitionIndex"))
{
Pin->DefaultValue = FString::FromInt(SubNodeIndex);
}
}
}
Anim node data/compiler refactor Per-node constant data is now held on a generated struct as part of sparse class data. Per-node mutable data (i.e. pin links/property access mappings) is now held on a generated 'mutable data' struct that is compiled as part of the generated class. The anim BP compiler is now extended more conventionally using UAnimBlueprintExtension, derived from UBlueprintExtension. This directly replaces the older 'compiler handler' pattern that was added in an emergency fashion for 4.26. Anim graph nodes now request their required extensions and these are held on the UAnimBlueprint in the UBlueprint::Extensions array. The Extensions array is potentially refreshed with any node addition or removal. The Extensions array is force-refreshed each time an anim BP is compiled for the first time to deal with newly added or removed requirements. Const-corrected a bunch of UAnimInstance/FAnimInstanceProxy APIs that rely on (now truly) const data. Added a split state/constant version of FInputScaleBiasClamp to allow some of its data to be split into constants. Tweaked alignment/ordering of FPoseLinkBase to save a few bytes per pose link. Deprecated FAnimNode_Base::OverrideAsset in favor of a more UAnimGraphNode_Base-based approach. Individual nodes can still have runtime overrides via specific accessors. The new approach will also give us the oppurtunity to override multiple assets per node if required in the future. Moved property access into Engine module & removed event support from it - this was never used. Reworked property access compilation API a little - construction/lifetime was a bit confusing previously. Optimized path used to create UK2Node_StructMemberSet nodes in per-node custom events. When using mutable data, the structure used is large and very sparsely connected (i.e. only a few properties are written) so we only create pins that are actually going to be used, rather than creating all of them and conly connecting a few. Patched the following nodes to use the new data approach: - Asset players (sequences, blendspaces, aim offsets) - Blend lists - Ref poses - Roots #rb Jurre.deBaare, Martin.Wilson, Keith.Yerex [CL 16090510 by Thomas Sarkanen in ue5-main branch]
2021-04-22 04:57:09 -04:00
int32 UAnimBlueprintExtension_StateMachine::ExpandGraphAndProcessNodes(UEdGraph* SourceGraph, UAnimGraphNode_Base* SourceRootNode, IAnimBlueprintCompilationContext& InCompilationContext, IAnimBlueprintGeneratedClassCompiledData& OutCompiledData, UAnimStateTransitionNode* TransitionNode, TArray<UEdGraphNode*>* ClonedNodes)
{
// Clone the nodes from the source graph
// Note that we outer this graph to the ConsolidatedEventGraph to allow ExpansionStep to
// correctly retrieve the context for any expanded function calls (custom make/break structs etc.)
UEdGraph* ClonedGraph = FEdGraphUtilities::CloneGraph(SourceGraph, InCompilationContext.GetConsolidatedEventGraph(), &InCompilationContext.GetMessageLog(), true);
// Grab all the animation nodes and find the corresponding root node in the cloned set
UAnimGraphNode_Base* TargetRootNode = nullptr;
TArray<UAnimGraphNode_Base*> AnimNodeList;
TArray<UK2Node_TransitionRuleGetter*> Getters;
TArray<UK2Node_AnimGetter*> AnimGetterNodes;
for (auto NodeIt = ClonedGraph->Nodes.CreateIterator(); NodeIt; ++NodeIt)
{
UEdGraphNode* Node = *NodeIt;
if (UK2Node_TransitionRuleGetter* GetterNode = Cast<UK2Node_TransitionRuleGetter>(Node))
{
Getters.Add(GetterNode);
}
else if(UK2Node_AnimGetter* NewGetterNode = Cast<UK2Node_AnimGetter>(Node))
{
AnimGetterNodes.Add(NewGetterNode);
}
else if (UAnimGraphNode_Base* TestNode = Cast<UAnimGraphNode_Base>(Node))
{
AnimNodeList.Add(TestNode);
//@TODO: There ought to be a better way to determine this
if (InCompilationContext.GetMessageLog().FindSourceObject(TestNode) == InCompilationContext.GetMessageLog().FindSourceObject(SourceRootNode))
{
TargetRootNode = TestNode;
}
}
if (ClonedNodes != NULL)
{
ClonedNodes->Add(Node);
}
}
check(TargetRootNode);
// Run another expansion pass to catch the graph we just added (this is slightly wasteful
InCompilationContext.ExpansionStep(ClonedGraph, false);
// Validate graph now we have expanded/pruned
InCompilationContext.ValidateGraphIsWellFormed(ClonedGraph);
// Move the cloned nodes into the consolidated event graph
const bool bIsLoading = InCompilationContext.GetBlueprint()->bIsRegeneratingOnLoad || IsAsyncLoading();
const bool bIsCompiling = InCompilationContext.GetBlueprint()->bBeingCompiled;
ClonedGraph->MoveNodesToAnotherGraph(InCompilationContext.GetConsolidatedEventGraph(), bIsLoading, bIsCompiling);
// Process any animation nodes
{
TArray<UAnimGraphNode_Base*> RootSet;
RootSet.Add(TargetRootNode);
InCompilationContext.PruneIsolatedAnimationNodes(RootSet, AnimNodeList);
InCompilationContext.ProcessAnimationNodes(AnimNodeList);
}
// Process the getter nodes in the graph if there were any
for (auto GetterIt = Getters.CreateIterator(); GetterIt; ++GetterIt)
{
ProcessTransitionGetter(*GetterIt, TransitionNode, InCompilationContext, OutCompiledData);
}
// Wire anim getter nodes
for(UK2Node_AnimGetter* GetterNode : AnimGetterNodes)
{
FoundGetterNodes.Add(GetterNode);
}
// Returns the index of the processed cloned version of SourceRootNode
return InCompilationContext.GetAllocationIndexOfNode(TargetRootNode);
}
#undef LOCTEXT_NAMESPACE