2020-09-01 14:07:48 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
2021-04-22 04:57:09 -04:00
# include "AnimBlueprintExtension_StateMachine.h"
2020-09-01 14:07:48 -04:00
# 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"
2020-09-09 08:32:25 -04:00
# include "IAnimBlueprintGeneratedClassCompiledData.h"
# include "IAnimBlueprintCompilerCreationContext.h"
# include "IAnimBlueprintCompilationContext.h"
2020-09-01 14:07:48 -04:00
2021-04-22 04:57:09 -04:00
# define LOCTEXT_NAMESPACE "AnimBlueprintExtension_StateMachine"
2020-09-01 14:07:48 -04:00
2021-04-22 04:57:09 -04:00
void UAnimBlueprintExtension_StateMachine : : HandleBeginCompilation ( IAnimBlueprintCompilerCreationContext & InCreationContext )
2020-09-01 14:07:48 -04:00
{
2020-09-09 08:32:25 -04:00
InCreationContext . RegisterKnownGraphSchema ( UAnimationStateMachineSchema : : StaticClass ( ) ) ;
2020-09-01 14:07:48 -04:00
}
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 )
2020-09-01 14:07:48 -04:00
{
2020-09-09 08:32:25 -04:00
InCompilationContext . GetConsolidatedEventGraph ( ) - > GetNodesOfClass < UK2Node_TransitionRuleGetter > ( RootTransitionGetters ) ;
2020-09-01 14:07:48 -04:00
// Get anim getters from the root anim graph (processing the nodes below will collect them in nested graphs)
2020-09-09 08:32:25 -04:00
InCompilationContext . GetConsolidatedEventGraph ( ) - > GetNodesOfClass < UK2Node_AnimGetter > ( RootGraphAnimGetters ) ;
2020-09-01 14:07:48 -04:00
}
2021-04-22 04:57:09 -04:00
void UAnimBlueprintExtension_StateMachine : : HandlePostProcessAnimationNodes ( TArrayView < UAnimGraphNode_Base * > InAnimNodes , IAnimBlueprintCompilationContext & InCompilationContext , IAnimBlueprintGeneratedClassCompiledData & OutCompiledData )
2020-09-01 14:07:48 -04:00
{
// Process the getter nodes in the graph if there were any
for ( auto GetterIt = RootTransitionGetters . CreateIterator ( ) ; GetterIt ; + + GetterIt )
{
2020-09-09 08:32:25 -04:00
ProcessTransitionGetter ( * GetterIt , nullptr , InCompilationContext , OutCompiledData ) ; // transition nodes should not appear at top-level
2020-09-01 14:07:48 -04:00
}
// Wire root getters
for ( UK2Node_AnimGetter * RootGraphGetter : RootGraphAnimGetters )
{
2020-09-09 08:32:25 -04:00
AutoWireAnimGetter ( RootGraphGetter , nullptr , InCompilationContext , OutCompiledData ) ;
2020-09-01 14:07:48 -04:00
}
// Wire nested getters
for ( UK2Node_AnimGetter * Getter : FoundGetterNodes )
{
2020-09-09 08:32:25 -04:00
AutoWireAnimGetter ( Getter , nullptr , InCompilationContext , OutCompiledData ) ;
2020-09-01 14:07:48 -04:00
}
}
2021-04-22 04:57:09 -04:00
UK2Node_CallFunction * UAnimBlueprintExtension_StateMachine : : SpawnCallAnimInstanceFunction ( IAnimBlueprintCompilationContext & InCompilationContext , UEdGraphNode * SourceNode , FName FunctionName )
2020-09-01 14:07:48 -04:00
{
//@TODO: SKELETON: This is a call on a parent function (UAnimInstance::StaticClass() specifically), should we treat it as self or not?
2020-09-09 08:32:25 -04:00
UK2Node_CallFunction * FunctionCall = InCompilationContext . SpawnIntermediateNode < UK2Node_CallFunction > ( SourceNode ) ;
2020-09-01 14:07:48 -04:00
FunctionCall - > FunctionReference . SetSelfMember ( FunctionName ) ;
FunctionCall - > AllocateDefaultPins ( ) ;
return FunctionCall ;
}
2021-04-22 04:57:09 -04:00
void UAnimBlueprintExtension_StateMachine : : ProcessTransitionGetter ( UK2Node_TransitionRuleGetter * Getter , UAnimStateTransitionNode * TransitionNode , IAnimBlueprintCompilationContext & InCompilationContext , IAnimBlueprintGeneratedClassCompiledData & OutCompiledData )
2020-09-01 14:07:48 -04:00
{
// 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
2020-09-09 08:32:25 -04:00
UAnimGraphNode_Base * TrueSourceNode = InCompilationContext . GetMessageLog ( ) . FindSourceObjectTypeChecked < UAnimGraphNode_Base > ( SourcePlayerNode ) ;
UAnimGraphNode_Base * UndertypedPlayerNode = InCompilationContext . GetSourceNodeToProcessedNodeMap ( ) . FindRef ( TrueSourceNode ) ;
2020-09-01 14:07:48 -04:00
if ( UndertypedPlayerNode = = NULL )
{
2020-09-09 08:32:25 -04:00
InCompilationContext . GetMessageLog ( ) . Error ( TEXT ( " ICE: Player node @@ was not processed prior to handling a transition getter @@ that used it " ) , SourcePlayerNode , Getter ) ;
2020-09-01 14:07:48 -04:00
return ;
}
// Make sure the node is still relevant
UEdGraph * PlayerGraph = UndertypedPlayerNode - > GetGraph ( ) ;
if ( ! PlayerGraph - > Nodes . Contains ( UndertypedPlayerNode ) )
{
2020-09-09 08:32:25 -04:00
InCompilationContext . GetMessageLog ( ) . Error ( TEXT ( " @@ is not associated with a node in @@; please delete and recreate it " ) , Getter , PlayerGraph ) ;
2020-09-01 14:07:48 -04:00
}
// Make sure the referenced AnimAsset player has been allocated
2020-09-09 08:32:25 -04:00
PlayerNodeIndex = InCompilationContext . GetAllocationIndexOfNode ( UndertypedPlayerNode ) ;
2020-09-01 14:07:48 -04:00
if ( PlayerNodeIndex = = INDEX_NONE )
{
2020-09-09 08:32:25 -04:00
InCompilationContext . GetMessageLog ( ) . Error ( * LOCTEXT ( " BadAnimAssetNodeUsedInGetter " , " @@ doesn't have a valid associated AnimAsset node. Delete and recreate it " ) . ToString ( ) , Getter ) ;
2020-09-01 14:07:48 -04:00
}
// 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
{
2020-09-09 08:32:25 -04:00
InCompilationContext . GetMessageLog ( ) . Error ( TEXT ( " @@ is associated with @@, which is an unexpected type " ) , Getter , UndertypedPlayerNode ) ;
2020-09-01 14:07:48 -04:00
}
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 ) )
{
2020-09-09 08:32:25 -04:00
const FProperty * NodeProperty = InCompilationContext . GetAllocatedPropertiesByIndex ( ) . FindChecked ( PlayerNodeIndex ) ;
2020-09-01 14:07:48 -04:00
// Create a struct member read node to grab the current position of the sequence player node
2020-09-09 08:32:25 -04:00
UK2Node_StructMemberGet * TimeReadNode = InCompilationContext . SpawnIntermediateNode < UK2Node_StructMemberGet > ( Getter , InCompilationContext . GetConsolidatedEventGraph ( ) ) ;
2020-09-01 14:07:48 -04:00
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 ) )
{
2020-09-09 08:32:25 -04:00
GetterHelper = SpawnCallAnimInstanceFunction ( InCompilationContext , Getter , TEXT ( " GetInstanceAssetPlayerTime " ) ) ;
2020-09-01 14:07:48 -04:00
GetterHelper - > FindPinChecked ( TEXT ( " AssetPlayerIndex " ) ) - > DefaultValue = FString : : FromInt ( PlayerNodeIndex ) ;
}
else
{
if ( Getter - > AssociatedAnimAssetPlayerNode )
{
2020-09-09 08:32:25 -04:00
InCompilationContext . GetMessageLog ( ) . Error ( TEXT ( " Please replace @@ with Get Relevant Anim Time. @@ has no animation asset " ) , Getter , Getter - > AssociatedAnimAssetPlayerNode ) ;
2020-09-01 14:07:48 -04:00
}
else
{
2020-09-09 08:32:25 -04:00
InCompilationContext . GetMessageLog ( ) . Error ( TEXT ( " @@ is not asscociated with an asset player " ) , Getter ) ;
2020-09-01 14:07:48 -04:00
}
}
break ;
case ETransitionGetter : : AnimationAsset_GetLength :
if ( AnimAsset ! = NULL )
{
2020-09-09 08:32:25 -04:00
GetterHelper = SpawnCallAnimInstanceFunction ( InCompilationContext , Getter , TEXT ( " GetInstanceAssetPlayerLength " ) ) ;
2020-09-01 14:07:48 -04:00
GetterHelper - > FindPinChecked ( TEXT ( " AssetPlayerIndex " ) ) - > DefaultValue = FString : : FromInt ( PlayerNodeIndex ) ;
}
else
{
if ( Getter - > AssociatedAnimAssetPlayerNode )
{
2020-09-09 08:32:25 -04:00
InCompilationContext . GetMessageLog ( ) . Error ( TEXT ( " Please replace @@ with Get Relevant Anim Length. @@ has no animation asset " ) , Getter , Getter - > AssociatedAnimAssetPlayerNode ) ;
2020-09-01 14:07:48 -04:00
}
else
{
2020-09-09 08:32:25 -04:00
InCompilationContext . GetMessageLog ( ) . Error ( TEXT ( " @@ is not asscociated with an asset player " ) , Getter ) ;
2020-09-01 14:07:48 -04:00
}
}
break ;
case ETransitionGetter : : AnimationAsset_GetCurrentTimeFraction :
if ( ( AnimAsset ! = NULL ) & & ( SourceTimePin ! = NULL ) )
{
2020-09-09 08:32:25 -04:00
GetterHelper = SpawnCallAnimInstanceFunction ( InCompilationContext , Getter , TEXT ( " GetInstanceAssetPlayerTimeFraction " ) ) ;
2020-09-01 14:07:48 -04:00
GetterHelper - > FindPinChecked ( TEXT ( " AssetPlayerIndex " ) ) - > DefaultValue = FString : : FromInt ( PlayerNodeIndex ) ;
}
else
{
if ( Getter - > AssociatedAnimAssetPlayerNode )
{
2020-09-09 08:32:25 -04:00
InCompilationContext . GetMessageLog ( ) . Error ( TEXT ( " Please replace @@ with Get Relevant Anim Time Fraction. @@ has no animation asset " ) , Getter , Getter - > AssociatedAnimAssetPlayerNode ) ;
2020-09-01 14:07:48 -04:00
}
else
{
2020-09-09 08:32:25 -04:00
InCompilationContext . GetMessageLog ( ) . Error ( TEXT ( " @@ is not asscociated with an asset player " ) , Getter ) ;
2020-09-01 14:07:48 -04:00
}
}
break ;
case ETransitionGetter : : AnimationAsset_GetTimeFromEnd :
if ( ( AnimAsset ! = NULL ) & & ( SourceTimePin ! = NULL ) )
{
2020-09-09 08:32:25 -04:00
GetterHelper = SpawnCallAnimInstanceFunction ( InCompilationContext , Getter , TEXT ( " GetInstanceAssetPlayerTimeFromEnd " ) ) ;
2020-09-01 14:07:48 -04:00
GetterHelper - > FindPinChecked ( TEXT ( " AssetPlayerIndex " ) ) - > DefaultValue = FString : : FromInt ( PlayerNodeIndex ) ;
}
else
{
if ( Getter - > AssociatedAnimAssetPlayerNode )
{
2020-09-09 08:32:25 -04:00
InCompilationContext . GetMessageLog ( ) . Error ( TEXT ( " Please replace @@ with Get Relevant Anim Time Remaining. @@ has no animation asset " ) , Getter , Getter - > AssociatedAnimAssetPlayerNode ) ;
2020-09-01 14:07:48 -04:00
}
else
{
2020-09-09 08:32:25 -04:00
InCompilationContext . GetMessageLog ( ) . Error ( TEXT ( " @@ is not asscociated with an asset player " ) , Getter ) ;
2020-09-01 14:07:48 -04:00
}
}
break ;
case ETransitionGetter : : AnimationAsset_GetTimeFromEndFraction :
if ( ( AnimAsset ! = NULL ) & & ( SourceTimePin ! = NULL ) )
{
2020-09-09 08:32:25 -04:00
GetterHelper = SpawnCallAnimInstanceFunction ( InCompilationContext , Getter , TEXT ( " GetInstanceAssetPlayerTimeFromEndFraction " ) ) ;
2020-09-01 14:07:48 -04:00
GetterHelper - > FindPinChecked ( TEXT ( " AssetPlayerIndex " ) ) - > DefaultValue = FString : : FromInt ( PlayerNodeIndex ) ;
}
else
{
if ( Getter - > AssociatedAnimAssetPlayerNode )
{
2020-09-09 08:32:25 -04:00
InCompilationContext . GetMessageLog ( ) . Error ( TEXT ( " Please replace @@ with Get Relevant Anim Time Remaining Fraction. @@ has no animation asset " ) , Getter , Getter - > AssociatedAnimAssetPlayerNode ) ;
2020-09-01 14:07:48 -04:00
}
else
{
2020-09-09 08:32:25 -04:00
InCompilationContext . GetMessageLog ( ) . Error ( TEXT ( " @@ is not asscociated with an asset player " ) , Getter ) ;
2020-09-01 14:07:48 -04:00
}
}
break ;
case ETransitionGetter : : CurrentTransitionDuration :
{
check ( TransitionNode ) ;
2020-09-09 08:32:25 -04:00
if ( UAnimStateNode * SourceStateNode = InCompilationContext . GetMessageLog ( ) . FindSourceObjectTypeChecked < UAnimStateNode > ( TransitionNode - > GetPreviousState ( ) ) )
2020-09-01 14:07:48 -04:00
{
2020-09-09 08:32:25 -04:00
if ( UObject * SourceTransitionNode = InCompilationContext . GetMessageLog ( ) . FindSourceObject ( TransitionNode ) )
2020-09-01 14:07:48 -04:00
{
2020-09-09 08:32:25 -04:00
if ( FStateMachineDebugData * DebugData = OutCompiledData . GetAnimBlueprintDebugData ( ) . StateMachineDebugData . Find ( SourceStateNode - > GetGraph ( ) ) )
2020-09-01 14:07:48 -04:00
{
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
2020-09-09 08:32:25 -04:00
UAnimGraphNode_Base * CompiledMachineInstanceNode = InCompilationContext . GetSourceNodeToProcessedNodeMap ( ) . FindChecked ( DebugData - > MachineInstanceNode . Get ( ) ) ;
const int32 MachinePropertyIndex = InCompilationContext . GetAllocatedAnimNodeIndices ( ) . FindChecked ( CompiledMachineInstanceNode ) ;
2020-09-01 14:07:48 -04:00
int32 TransitionPropertyIndex = INDEX_NONE ;
2021-03-19 14:32:13 -04:00
for ( auto TransIt = DebugData - > NodeToTransitionIndex . CreateConstIterator ( ) ; TransIt ; + + TransIt )
2020-09-01 14:07:48 -04:00
{
2021-03-19 14:32:13 -04:00
const UEdGraphNode * CurrTransNode = TransIt . Key ( ) . Get ( ) ;
2020-09-01 14:07:48 -04:00
if ( CurrTransNode = = SourceTransitionNode )
{
TransitionPropertyIndex = TransIt . Value ( ) ;
break ;
}
}
if ( TransitionPropertyIndex ! = INDEX_NONE )
{
2020-09-09 08:32:25 -04:00
GetterHelper = SpawnCallAnimInstanceFunction ( InCompilationContext , Getter , TEXT ( " GetInstanceTransitionCrossfadeDuration " ) ) ;
2020-09-01 14:07:48 -04:00
GetterHelper - > FindPinChecked ( TEXT ( " MachineIndex " ) ) - > DefaultValue = FString : : FromInt ( MachinePropertyIndex ) ;
GetterHelper - > FindPinChecked ( TEXT ( " TransitionIndex " ) ) - > DefaultValue = FString : : FromInt ( TransitionPropertyIndex ) ;
}
}
}
}
}
}
break ;
case ETransitionGetter : : ArbitraryState_GetBlendWeight :
{
if ( Getter - > AssociatedStateNode )
{
2020-09-09 08:32:25 -04:00
if ( UAnimStateNode * SourceStateNode = InCompilationContext . GetMessageLog ( ) . FindSourceObjectTypeChecked < UAnimStateNode > ( Getter - > AssociatedStateNode ) )
2020-09-01 14:07:48 -04:00
{
2020-09-09 08:32:25 -04:00
if ( FStateMachineDebugData * DebugData = OutCompiledData . GetAnimBlueprintDebugData ( ) . StateMachineDebugData . Find ( SourceStateNode - > GetGraph ( ) ) )
2020-09-01 14:07:48 -04:00
{
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
2020-09-09 08:32:25 -04:00
UAnimGraphNode_Base * CompiledMachineInstanceNode = InCompilationContext . GetSourceNodeToProcessedNodeMap ( ) . FindChecked ( DebugData - > MachineInstanceNode . Get ( ) ) ;
const int32 MachinePropertyIndex = InCompilationContext . GetAllocatedAnimNodeIndices ( ) . FindChecked ( CompiledMachineInstanceNode ) ;
2020-09-01 14:07:48 -04:00
2020-09-09 08:32:25 -04:00
GetterHelper = SpawnCallAnimInstanceFunction ( InCompilationContext , Getter , TEXT ( " GetInstanceStateWeight " ) ) ;
2020-09-01 14:07:48 -04:00
GetterHelper - > FindPinChecked ( TEXT ( " MachineIndex " ) ) - > DefaultValue = FString : : FromInt ( MachinePropertyIndex ) ;
GetterHelper - > FindPinChecked ( TEXT ( " StateIndex " ) ) - > DefaultValue = FString : : FromInt ( StateIndex ) ;
}
}
}
}
if ( GetterHelper = = NULL )
{
2020-09-09 08:32:25 -04:00
InCompilationContext . GetMessageLog ( ) . Error ( TEXT ( " @@ is not associated with a valid state " ) , Getter ) ;
2020-09-01 14:07:48 -04:00
}
}
break ;
case ETransitionGetter : : CurrentState_ElapsedTime :
{
check ( TransitionNode ) ;
2020-09-09 08:32:25 -04:00
if ( UAnimStateNode * SourceStateNode = InCompilationContext . GetMessageLog ( ) . FindSourceObjectTypeChecked < UAnimStateNode > ( TransitionNode - > GetPreviousState ( ) ) )
2020-09-01 14:07:48 -04:00
{
2020-09-09 08:32:25 -04:00
if ( FStateMachineDebugData * DebugData = OutCompiledData . GetAnimBlueprintDebugData ( ) . StateMachineDebugData . Find ( SourceStateNode - > GetGraph ( ) ) )
2020-09-01 14:07:48 -04:00
{
// This check should never fail as all animation nodes should be processed before getters are
2020-09-09 08:32:25 -04:00
UAnimGraphNode_Base * CompiledMachineInstanceNode = InCompilationContext . GetSourceNodeToProcessedNodeMap ( ) . FindChecked ( DebugData - > MachineInstanceNode . Get ( ) ) ;
const int32 MachinePropertyIndex = InCompilationContext . GetAllocatedAnimNodeIndices ( ) . FindChecked ( CompiledMachineInstanceNode ) ;
2020-09-01 14:07:48 -04:00
2020-09-09 08:32:25 -04:00
GetterHelper = SpawnCallAnimInstanceFunction ( InCompilationContext , Getter , TEXT ( " GetInstanceCurrentStateElapsedTime " ) ) ;
2020-09-01 14:07:48 -04:00
GetterHelper - > FindPinChecked ( TEXT ( " MachineIndex " ) ) - > DefaultValue = FString : : FromInt ( MachinePropertyIndex ) ;
}
}
if ( GetterHelper = = NULL )
{
2020-09-09 08:32:25 -04:00
InCompilationContext . GetMessageLog ( ) . Error ( TEXT ( " @@ is not associated with a valid state " ) , Getter ) ;
2020-09-01 14:07:48 -04:00
}
}
break ;
case ETransitionGetter : : CurrentState_GetBlendWeight :
{
check ( TransitionNode ) ;
2020-09-09 08:32:25 -04:00
if ( UAnimStateNode * SourceStateNode = InCompilationContext . GetMessageLog ( ) . FindSourceObjectTypeChecked < UAnimStateNode > ( TransitionNode - > GetPreviousState ( ) ) )
2020-09-01 14:07:48 -04:00
{
{
2020-09-09 08:32:25 -04:00
if ( FStateMachineDebugData * DebugData = OutCompiledData . GetAnimBlueprintDebugData ( ) . StateMachineDebugData . Find ( SourceStateNode - > GetGraph ( ) ) )
2020-09-01 14:07:48 -04:00
{
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
2020-09-09 08:32:25 -04:00
UAnimGraphNode_Base * CompiledMachineInstanceNode = InCompilationContext . GetSourceNodeToProcessedNodeMap ( ) . FindChecked ( DebugData - > MachineInstanceNode . Get ( ) ) ;
const int32 MachinePropertyIndex = InCompilationContext . GetAllocatedAnimNodeIndices ( ) . FindChecked ( CompiledMachineInstanceNode ) ;
2020-09-01 14:07:48 -04:00
2020-09-09 08:32:25 -04:00
GetterHelper = SpawnCallAnimInstanceFunction ( InCompilationContext , Getter , TEXT ( " GetInstanceStateWeight " ) ) ;
2020-09-01 14:07:48 -04:00
GetterHelper - > FindPinChecked ( TEXT ( " MachineIndex " ) ) - > DefaultValue = FString : : FromInt ( MachinePropertyIndex ) ;
GetterHelper - > FindPinChecked ( TEXT ( " StateIndex " ) ) - > DefaultValue = FString : : FromInt ( StateIndex ) ;
}
}
}
}
if ( GetterHelper = = NULL )
{
2020-09-09 08:32:25 -04:00
InCompilationContext . GetMessageLog ( ) . Error ( TEXT ( " @@ is not associated with a valid state " ) , Getter ) ;
2020-09-01 14:07:48 -04:00
}
}
break ;
default :
2020-09-09 08:32:25 -04:00
InCompilationContext . GetMessageLog ( ) . Error ( TEXT ( " Unrecognized getter type on @@ " ) , Getter ) ;
2020-09-01 14:07:48 -04:00
break ;
}
// Finish wiring up a call function if needed
if ( GetterHelper ! = NULL )
{
check ( GetterHelper - > IsNodePure ( ) ) ;
UEdGraphPin * NewReturnPin = GetterHelper - > FindPinChecked ( TEXT ( " ReturnValue " ) ) ;
2020-09-09 08:32:25 -04:00
InCompilationContext . GetMessageLog ( ) . NotifyIntermediatePinCreation ( NewReturnPin , OutputPin ) ;
2020-09-01 14:07:48 -04:00
NewReturnPin - > CopyPersistentDataFromOldPin ( * OutputPin ) ;
}
// Remove the getter from the equation
Getter - > BreakAllNodeLinks ( ) ;
}
2021-04-22 04:57:09 -04:00
void UAnimBlueprintExtension_StateMachine : : AutoWireAnimGetter ( class UK2Node_AnimGetter * Getter , UAnimStateTransitionNode * InTransitionNode , IAnimBlueprintCompilationContext & InCompilationContext , IAnimBlueprintGeneratedClassCompiledData & OutCompiledData )
2020-09-01 14:07:48 -04:00
{
UEdGraphPin * ReferencedNodeTimePin = nullptr ;
int32 ReferencedNodeIndex = INDEX_NONE ;
int32 SubNodeIndex = INDEX_NONE ;
UAnimGraphNode_Base * ProcessedNodeCheck = NULL ;
if ( UAnimGraphNode_Base * SourceNode = Getter - > SourceNode )
{
2020-09-09 08:32:25 -04:00
UAnimGraphNode_Base * ActualSourceNode = InCompilationContext . GetMessageLog ( ) . FindSourceObjectTypeChecked < UAnimGraphNode_Base > ( SourceNode ) ;
2020-09-01 14:07:48 -04:00
2020-09-09 08:32:25 -04:00
if ( UAnimGraphNode_Base * ProcessedSourceNode = InCompilationContext . GetSourceNodeToProcessedNodeMap ( ) . FindRef ( ActualSourceNode ) )
2020-09-01 14:07:48 -04:00
{
ProcessedNodeCheck = ProcessedSourceNode ;
2020-09-09 08:32:25 -04:00
ReferencedNodeIndex = InCompilationContext . GetAllocationIndexOfNode ( ProcessedSourceNode ) ;
2020-09-01 14:07:48 -04:00
if ( ProcessedSourceNode - > DoesSupportTimeForTransitionGetter ( ) )
{
UScriptStruct * TimePropertyInStructType = ProcessedSourceNode - > GetTimePropertyStruct ( ) ;
const TCHAR * TimePropertyName = ProcessedSourceNode - > GetTimePropertyName ( ) ;
if ( ReferencedNodeIndex ! = INDEX_NONE & & TimePropertyName & & TimePropertyInStructType )
{
2020-09-09 08:32:25 -04:00
FProperty * NodeProperty = InCompilationContext . GetAllocatedPropertiesByIndex ( ) . FindChecked ( ReferencedNodeIndex ) ;
2020-09-01 14:07:48 -04:00
2020-09-09 08:32:25 -04:00
UK2Node_StructMemberGet * ReaderNode = InCompilationContext . SpawnIntermediateNode < UK2Node_StructMemberGet > ( Getter , InCompilationContext . GetConsolidatedEventGraph ( ) ) ;
2020-09-01 14:07:48 -04:00
ReaderNode - > VariableReference . SetSelfMember ( NodeProperty - > GetFName ( ) ) ;
ReaderNode - > StructType = TimePropertyInStructType ;
ReaderNode - > AllocatePinsForSingleMemberGet ( TimePropertyName ) ;
ReferencedNodeTimePin = ReaderNode - > FindPinChecked ( TimePropertyName ) ;
}
}
}
}
if ( Getter - > SourceStateNode )
{
2020-09-09 08:32:25 -04:00
UObject * SourceObject = InCompilationContext . GetMessageLog ( ) . FindSourceObject ( Getter - > SourceStateNode ) ;
2020-09-01 14:07:48 -04:00
if ( UAnimStateNode * SourceStateNode = Cast < UAnimStateNode > ( SourceObject ) )
{
2020-09-09 08:32:25 -04:00
if ( FStateMachineDebugData * DebugData = OutCompiledData . GetAnimBlueprintDebugData ( ) . StateMachineDebugData . Find ( SourceStateNode - > GetGraph ( ) ) )
2020-09-01 14:07:48 -04:00
{
if ( int32 * StateIndexPtr = DebugData - > NodeToStateIndex . Find ( SourceStateNode ) )
{
SubNodeIndex = * StateIndexPtr ;
}
}
}
else if ( UAnimStateTransitionNode * TransitionNode = Cast < UAnimStateTransitionNode > ( SourceObject ) )
{
2020-09-09 08:32:25 -04:00
if ( FStateMachineDebugData * DebugData = OutCompiledData . GetAnimBlueprintDebugData ( ) . StateMachineDebugData . Find ( TransitionNode - > GetGraph ( ) ) )
2020-09-01 14:07:48 -04:00
{
2021-03-19 14:32:13 -04:00
TArray < int32 > TransitionIndices ;
DebugData - > NodeToTransitionIndex . MultiFind ( TransitionNode , TransitionIndices ) ;
const int32 TransNum = TransitionIndices . Num ( ) ;
if ( TransNum > 0 )
2020-09-01 14:07:48 -04:00
{
2021-03-19 14:32:13 -04:00
SubNodeIndex = TransitionIndices [ 0 ] ;
2020-09-01 14:07:48 -04:00
}
}
}
}
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 ) ;
}
}
}
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 )
2020-09-01 14:07:48 -04:00
{
// Clone the nodes from the source graph
2020-09-09 08:32:25 -04:00
// Note that we outer this graph to the ConsolidatedEventGraph to allow ExpansionStep to
2020-09-01 14:07:48 -04:00
// correctly retrieve the context for any expanded function calls (custom make/break structs etc.)
2020-09-09 08:32:25 -04:00
UEdGraph * ClonedGraph = FEdGraphUtilities : : CloneGraph ( SourceGraph , InCompilationContext . GetConsolidatedEventGraph ( ) , & InCompilationContext . GetMessageLog ( ) , true ) ;
2020-09-01 14:07:48 -04:00
// 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
2020-09-09 08:32:25 -04:00
if ( InCompilationContext . GetMessageLog ( ) . FindSourceObject ( TestNode ) = = InCompilationContext . GetMessageLog ( ) . FindSourceObject ( SourceRootNode ) )
2020-09-01 14:07:48 -04:00
{
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
2020-09-09 08:32:25 -04:00
InCompilationContext . ExpansionStep ( ClonedGraph , false ) ;
2020-09-01 14:07:48 -04:00
// Validate graph now we have expanded/pruned
2020-09-09 08:32:25 -04:00
InCompilationContext . ValidateGraphIsWellFormed ( ClonedGraph ) ;
2020-09-01 14:07:48 -04:00
// Move the cloned nodes into the consolidated event graph
2020-09-09 08:32:25 -04:00
const bool bIsLoading = InCompilationContext . GetBlueprint ( ) - > bIsRegeneratingOnLoad | | IsAsyncLoading ( ) ;
const bool bIsCompiling = InCompilationContext . GetBlueprint ( ) - > bBeingCompiled ;
ClonedGraph - > MoveNodesToAnotherGraph ( InCompilationContext . GetConsolidatedEventGraph ( ) , bIsLoading , bIsCompiling ) ;
2020-09-01 14:07:48 -04:00
// Process any animation nodes
{
TArray < UAnimGraphNode_Base * > RootSet ;
RootSet . Add ( TargetRootNode ) ;
2020-09-09 08:32:25 -04:00
InCompilationContext . PruneIsolatedAnimationNodes ( RootSet , AnimNodeList ) ;
2020-09-01 14:07:48 -04:00
2020-09-09 08:32:25 -04:00
InCompilationContext . ProcessAnimationNodes ( AnimNodeList ) ;
2020-09-01 14:07:48 -04:00
}
// Process the getter nodes in the graph if there were any
for ( auto GetterIt = Getters . CreateIterator ( ) ; GetterIt ; + + GetterIt )
{
2020-09-09 08:32:25 -04:00
ProcessTransitionGetter ( * GetterIt , TransitionNode , InCompilationContext , OutCompiledData ) ;
2020-09-01 14:07:48 -04:00
}
// Wire anim getter nodes
for ( UK2Node_AnimGetter * GetterNode : AnimGetterNodes )
{
FoundGetterNodes . Add ( GetterNode ) ;
}
// Returns the index of the processed cloned version of SourceRootNode
2020-09-09 08:32:25 -04:00
return InCompilationContext . GetAllocationIndexOfNode ( TargetRootNode ) ;
2020-09-01 14:07:48 -04:00
}
# undef LOCTEXT_NAMESPACE