2019-12-26 15:33:43 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2019-05-22 12:00:20 -04:00
2019-09-23 07:23:26 -04:00
# include "AnimGraphNode_LinkedAnimLayer.h"
2019-05-22 12:00:20 -04:00
# include "Widgets/Text/STextBlock.h"
# include "Widgets/Input/SCheckBox.h"
# include "EdGraphSchema_K2.h"
# include "Kismet2/CompilerResultsLog.h"
# include "Kismet2/BlueprintEditorUtils.h"
# include "PropertyHandle.h"
# include "DetailLayoutBuilder.h"
# include "DetailCategoryBuilder.h"
2019-09-23 07:23:26 -04:00
# include "Animation/AnimNode_LinkedInputPose.h"
2019-05-22 12:00:20 -04:00
# include "PropertyCustomizationHelpers.h"
# include "ScopedTransaction.h"
# include "AnimationGraphSchema.h"
# include "Widgets/Layout/SBox.h"
# include "UObject/CoreRedirects.h"
# include "Kismet2/KismetEditorUtilities.h"
2019-08-12 05:41:21 -04:00
# include "AnimationStateGraph.h"
2021-05-24 06:55:32 -04:00
# include "BlueprintNodeSpawner.h"
2019-09-26 06:05:49 -04:00
# include "UObject/FortniteMainBranchObjectVersion.h"
2021-05-24 06:55:32 -04:00
# include "BlueprintActionDatabaseRegistrar.h"
# include "AssetRegistry/AssetRegistryModule.h"
2019-05-22 12:00:20 -04:00
2019-09-23 07:23:26 -04:00
# define LOCTEXT_NAMESPACE "LinkedAnimLayerNode"
2019-05-22 12:00:20 -04:00
2019-09-26 06:05:49 -04:00
void UAnimGraphNode_LinkedAnimLayer : : Serialize ( FArchive & Ar )
{
Super : : Serialize ( Ar ) ;
Ar . UsingCustomVersion ( FFortniteMainBranchObjectVersion : : GUID ) ;
if ( Ar . IsLoading ( ) )
{
if ( Ar . CustomVer ( FFortniteMainBranchObjectVersion : : GUID ) < FFortniteMainBranchObjectVersion : : AnimLayerGuidConformation )
{
if ( ! InterfaceGuid . IsValid ( ) )
{
InterfaceGuid = GetGuidForLayer ( ) ;
}
}
}
}
2019-09-26 09:15:50 -04:00
void UAnimGraphNode_LinkedAnimLayer : : ReconstructNode ( )
{
if ( SetObjectBeingDebuggedHandle . IsValid ( ) )
{
GetBlueprint ( ) - > OnSetObjectBeingDebugged ( ) . Remove ( SetObjectBeingDebuggedHandle ) ;
}
SetObjectBeingDebuggedHandle = GetBlueprint ( ) - > OnSetObjectBeingDebugged ( ) . AddUObject ( this , & UAnimGraphNode_LinkedAnimLayer : : HandleSetObjectBeingDebugged ) ;
Super : : ReconstructNode ( ) ;
}
2021-05-24 06:55:32 -04:00
FSlateIcon UAnimGraphNode_LinkedAnimLayer : : GetIconAndTint ( FLinearColor & OutColor ) const
{
return FSlateIcon ( " EditorStyle " , " ClassIcon.AnimLayerInterface " ) ;
}
2019-09-23 07:23:26 -04:00
FText UAnimGraphNode_LinkedAnimLayer : : GetTooltipText ( ) const
2019-05-22 12:00:20 -04:00
{
2019-09-23 07:23:26 -04:00
return LOCTEXT ( " ToolTip " , " Runs another linked animation layer graph to process animation " ) ;
2019-05-22 12:00:20 -04:00
}
2019-09-26 09:15:50 -04:00
FAnimNode_LinkedAnimLayer * UAnimGraphNode_LinkedAnimLayer : : GetPreviewNode ( ) const
{
FAnimNode_LinkedAnimLayer * PreviewNode = nullptr ;
USkeletalMeshComponent * Component = nullptr ;
// look for a valid component in the object being debugged,
// we might be set to something other than the preview.
UObject * ObjectBeingDebugged = GetAnimBlueprint ( ) - > GetObjectBeingDebugged ( ) ;
if ( ObjectBeingDebugged )
{
UAnimInstance * InstanceBeingDebugged = Cast < UAnimInstance > ( ObjectBeingDebugged ) ;
if ( InstanceBeingDebugged )
{
Component = InstanceBeingDebugged - > GetSkelMeshComponent ( ) ;
}
}
if ( Component ! = nullptr & & Component - > GetAnimInstance ( ) ! = nullptr )
{
PreviewNode = static_cast < FAnimNode_LinkedAnimLayer * > ( FindDebugAnimNode ( Component ) ) ;
}
return PreviewNode ;
}
2019-09-23 07:23:26 -04:00
FText UAnimGraphNode_LinkedAnimLayer : : GetNodeTitle ( ENodeTitleType : : Type TitleType ) const
2019-05-22 12:00:20 -04:00
{
UClass * TargetClass = * Node . Interface ;
2019-09-26 09:15:50 -04:00
UAnimBlueprint * TargetAnimBlueprintInterface = TargetClass ? CastChecked < UAnimBlueprint > ( TargetClass - > ClassGeneratedBy ) : nullptr ;
2019-05-22 12:00:20 -04:00
if ( TitleType = = ENodeTitleType : : MenuTitle )
{
2019-09-26 09:15:50 -04:00
return LOCTEXT ( " NodeTitle " , " Linked Anim Layer " ) ;
2019-05-22 12:00:20 -04:00
}
else
{
2021-05-24 06:55:32 -04:00
bool bIsSelf = TargetAnimBlueprintInterface = = nullptr ;
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " NodeType " ) , LOCTEXT ( " NodeTitle " , " Linked Anim Layer " ) ) ;
Args . Add ( TEXT ( " TargetClass " ) , bIsSelf ? LOCTEXT ( " ClassSelf " , " Self " ) : FText : : FromString ( TargetAnimBlueprintInterface - > GetName ( ) ) ) ;
2021-04-28 01:58:36 -04:00
Args . Add ( TEXT ( " Layer " ) , ( Node . Layer = = NAME_None ) ? LOCTEXT ( " LayerNone " , " None " ) : FText : : FromName ( Node . Layer ) ) ;
2019-09-26 09:15:50 -04:00
if ( TitleType = = ENodeTitleType : : ListView )
2021-05-24 06:55:32 -04:00
{
if ( bIsSelf )
{
return FText : : Format ( LOCTEXT ( " TitleListViewFormatSelf " , " {Layer} " ) , Args ) ;
}
else
{
return FText : : Format ( LOCTEXT ( " TitleListViewFormat " , " {TargetClass} - {Layer} " ) , Args ) ;
}
}
else
{
if ( FAnimNode_LinkedAnimLayer * PreviewNode = GetPreviewNode ( ) )
{
if ( UAnimInstance * PreviewAnimInstance = PreviewNode - > GetTargetInstance < UAnimInstance > ( ) )
{
if ( UClass * PreviewTargetClass = PreviewAnimInstance - > GetClass ( ) )
{
bIsSelf = PreviewTargetClass = = GetAnimBlueprint ( ) - > GeneratedClass ;
Args . Add ( TEXT ( " TargetClass " ) , PreviewTargetClass = = GetAnimBlueprint ( ) - > GeneratedClass ? LOCTEXT ( " ClassSelf " , " Self " ) : FText : : FromName ( PreviewTargetClass - > GetFName ( ) ) ) ;
}
}
}
if ( bIsSelf )
{
return FText : : Format ( LOCTEXT ( " TitleOtherFormatSelf " , " {Layer} \n {NodeType} " ) , Args ) ;
}
else
{
return FText : : Format ( LOCTEXT ( " TitleOtherFormat " , " {TargetClass} - {Layer} \n {NodeType} " ) , Args ) ;
}
}
2019-05-22 12:00:20 -04:00
}
}
2019-09-23 07:23:26 -04:00
void UAnimGraphNode_LinkedAnimLayer : : ValidateAnimNodeDuringCompilation ( USkeleton * ForSkeleton , FCompilerResultsLog & MessageLog )
2019-05-22 12:00:20 -04:00
{
Super : : ValidateAnimNodeDuringCompilation ( ForSkeleton , MessageLog ) ;
if ( Node . Layer = = NAME_None )
{
2019-09-23 07:23:26 -04:00
MessageLog . Error ( * LOCTEXT ( " NoLayerError " , " Linked anim layer node @@ does not specify a layer. " ) . ToString ( ) , this ) ;
2019-05-22 12:00:20 -04:00
}
else
{
UAnimBlueprint * CurrentBlueprint = Cast < UAnimBlueprint > ( GetBlueprint ( ) ) ;
// check layer actually exists in the interface
UClass * TargetClass = * Node . Interface ;
if ( TargetClass = = nullptr )
{
// If no interface specified, use this class
if ( CurrentBlueprint )
{
TargetClass = * CurrentBlueprint - > SkeletonGeneratedClass ;
}
}
2019-05-24 10:11:07 -04:00
else
{
// check we implement this interface
bool bImplementsInterface = false ;
2019-05-30 07:17:42 -04:00
if ( CurrentBlueprint )
2019-05-24 10:11:07 -04:00
{
2019-05-30 07:17:42 -04:00
for ( FBPInterfaceDescription & InterfaceDesc : CurrentBlueprint - > ImplementedInterfaces )
2019-05-24 10:11:07 -04:00
{
2019-05-30 07:17:42 -04:00
if ( InterfaceDesc . Interface . Get ( ) = = TargetClass )
{
bImplementsInterface = true ;
break ;
}
2019-05-24 10:11:07 -04:00
}
}
if ( ! bImplementsInterface )
{
// Its possible we have a left-over interface referenced here that needs clearing now we are a 'self' layer
if ( GetInterfaceForLayer ( ) = = nullptr )
{
Node . Interface = nullptr ;
// No interface any more, use this class
if ( CurrentBlueprint )
{
TargetClass = * CurrentBlueprint - > SkeletonGeneratedClass ;
}
}
else
{
2019-09-23 07:23:26 -04:00
MessageLog . Error ( * LOCTEXT ( " MissingInterfaceError " , " Linked anim layer node @@ uses interface @@ that this blueprint does not implement. " ) . ToString ( ) , this , Node . Interface . Get ( ) ) ;
2019-05-24 10:11:07 -04:00
}
}
}
2019-05-22 12:00:20 -04:00
if ( TargetClass )
{
bool bFoundFunction = false ;
IAnimClassInterface * AnimClassInterface = IAnimClassInterface : : GetFromClass ( TargetClass ) ;
for ( const FAnimBlueprintFunction & AnimBlueprintFunction : AnimClassInterface - > GetAnimBlueprintFunctions ( ) )
{
if ( AnimBlueprintFunction . Name = = Node . Layer )
{
bFoundFunction = true ;
}
}
if ( ! bFoundFunction )
{
2019-09-23 07:23:26 -04:00
MessageLog . Error ( * FText : : Format ( LOCTEXT ( " MissingLayerError " , " Linked anim layer node @@ uses invalid layer '{0}'. " ) , FText : : FromName ( Node . Layer ) ) . ToString ( ) , this ) ;
2019-05-22 12:00:20 -04:00
}
}
if ( CurrentBlueprint )
{
2019-09-23 07:23:26 -04:00
UAnimGraphNode_LinkedAnimLayer * OriginalThis = Cast < UAnimGraphNode_LinkedAnimLayer > ( MessageLog . FindSourceObject ( this ) ) ;
2019-05-22 12:00:20 -04:00
// check layer is only used once in this blueprint
auto CheckGraph = [ this , OriginalThis , & MessageLog ] ( const UEdGraph * InGraph )
{
2019-09-23 07:23:26 -04:00
TArray < UAnimGraphNode_LinkedAnimLayer * > LayerNodes ;
2019-05-22 12:00:20 -04:00
InGraph - > GetNodesOfClass ( LayerNodes ) ;
2019-09-23 07:23:26 -04:00
for ( const UAnimGraphNode_LinkedAnimLayer * LayerNode : LayerNodes )
2019-05-22 12:00:20 -04:00
{
if ( LayerNode ! = OriginalThis )
{
if ( LayerNode - > Node . Layer = = Node . Layer )
{
2019-09-23 07:23:26 -04:00
MessageLog . Error ( * FText : : Format ( LOCTEXT ( " DuplicateLayerError " , " Linked anim layer node @@ also uses layer '{0}', layers can be used only once in an animation blueprint. " ) , FText : : FromName ( Node . Layer ) ) . ToString ( ) , this ) ;
2019-05-22 12:00:20 -04:00
}
}
}
} ;
TArray < UEdGraph * > Graphs ;
CurrentBlueprint - > GetAllGraphs ( Graphs ) ;
2019-08-12 05:41:21 -04:00
auto ValidateOuterGraph = [ this , OriginalThis , & MessageLog ] ( const UEdGraph * InGraph )
{
static const FName DefaultAnimGraphName ( " AnimGraph " ) ;
if ( InGraph - > Nodes . Contains ( OriginalThis ) )
{
if ( ! InGraph - > IsA < UAnimationStateGraph > ( ) & & InGraph - > GetFName ( ) ! = DefaultAnimGraphName )
{
2019-09-23 07:23:26 -04:00
MessageLog . Error ( * FText : : Format ( LOCTEXT ( " NestedLayer " , " Linked anim layer node @@ is part of Animation Layer Graph '{0}', layers cannot be nested. " ) , FText : : FromName ( InGraph - > GetFName ( ) ) ) . ToString ( ) , this ) ;
2019-08-12 05:41:21 -04:00
}
}
} ;
2019-05-22 12:00:20 -04:00
for ( const UEdGraph * Graph : Graphs )
{
CheckGraph ( Graph ) ;
2019-08-12 05:41:21 -04:00
ValidateOuterGraph ( Graph ) ;
2019-05-22 12:00:20 -04:00
}
}
}
}
2019-09-23 07:23:26 -04:00
UObject * UAnimGraphNode_LinkedAnimLayer : : GetJumpTargetForDoubleClick ( ) const
2019-05-22 12:00:20 -04:00
{
auto JumpTargetFromClass = [ this ] ( UClass * InClass )
{
UObject * JumpTargetObject = nullptr ;
UAnimBlueprint * TargetAnimBlueprint = InClass ? CastChecked < UAnimBlueprint > ( InClass - > ClassGeneratedBy ) : nullptr ;
if ( TargetAnimBlueprint = = nullptr | | TargetAnimBlueprint = = Cast < UAnimBlueprint > ( GetBlueprint ( ) ) )
{
// jump to graph in self
TArray < UEdGraph * > Graphs ;
GetBlueprint ( ) - > GetAllGraphs ( Graphs ) ;
UEdGraph * * FoundGraph = Graphs . FindByPredicate ( [ this ] ( UEdGraph * InGraph ) { return InGraph - > GetFName ( ) = = Node . Layer ; } ) ;
if ( FoundGraph )
{
JumpTargetObject = * FoundGraph ;
}
}
else if ( TargetAnimBlueprint )
{
// jump to graph in other BP
TArray < UEdGraph * > Graphs ;
TargetAnimBlueprint - > GetAllGraphs ( Graphs ) ;
UEdGraph * * FoundGraph = Graphs . FindByPredicate ( [ this ] ( UEdGraph * InGraph ) { return InGraph - > GetFName ( ) = = Node . Layer ; } ) ;
if ( FoundGraph )
{
JumpTargetObject = * FoundGraph ;
}
else
{
JumpTargetObject = TargetAnimBlueprint ;
}
}
return JumpTargetObject ;
} ;
// First try a concrete class, if any
UObject * JumpTargetObject = JumpTargetFromClass ( * Node . InstanceClass ) ;
if ( JumpTargetObject = = nullptr )
{
// then try the interface
JumpTargetObject = JumpTargetFromClass ( * Node . Interface ) ;
}
return JumpTargetObject ;
}
2019-09-23 07:23:26 -04:00
void UAnimGraphNode_LinkedAnimLayer : : JumpToDefinition ( ) const
2019-05-22 12:00:20 -04:00
{
if ( UEdGraph * HyperlinkTarget = Cast < UEdGraph > ( GetJumpTargetForDoubleClick ( ) ) )
{
FKismetEditorUtilities : : BringKismetToFocusAttentionOnObject ( HyperlinkTarget ) ;
}
else
{
Super : : JumpToDefinition ( ) ;
}
}
2019-09-23 07:23:26 -04:00
bool UAnimGraphNode_LinkedAnimLayer : : HasExternalDependencies ( TArray < class UStruct * > * OptionalOutput /*= NULL*/ ) const
2019-05-22 12:00:20 -04:00
{
UClass * InterfaceClassToUse = * Node . Interface ;
// Add our interface class. If that changes we need a recompile
if ( InterfaceClassToUse & & OptionalOutput )
{
OptionalOutput - > AddUnique ( InterfaceClassToUse ) ;
}
bool bSuperResult = Super : : HasExternalDependencies ( OptionalOutput ) ;
return InterfaceClassToUse | | bSuperResult ;
}
2019-09-23 07:23:26 -04:00
void UAnimGraphNode_LinkedAnimLayer : : CustomizeDetails ( IDetailLayoutBuilder & DetailBuilder )
2019-05-22 12:00:20 -04:00
{
// We dont allow multi-select here
if ( DetailBuilder . GetSelectedObjects ( ) . Num ( ) > 1 )
{
DetailBuilder . HideCategory ( TEXT ( " Settings " ) ) ;
return ;
}
IDetailCategoryBuilder & CategoryBuilder = DetailBuilder . EditCategory ( TEXT ( " Settings " ) ) ;
// Hide Tag
TSharedRef < IPropertyHandle > TagHandle = DetailBuilder . GetProperty ( TEXT ( " Node.Tag " ) , GetClass ( ) ) ;
TagHandle - > MarkHiddenByCustomization ( ) ;
// Customize Layer
{
TSharedRef < IPropertyHandle > LayerHandle = DetailBuilder . GetProperty ( TEXT ( " Node.Layer " ) , GetClass ( ) ) ;
if ( LayerHandle - > IsValidHandle ( ) )
{
2019-09-23 07:23:26 -04:00
LayerHandle - > SetOnPropertyValueChanged ( FSimpleDelegate : : CreateUObject ( this , & UAnimGraphNode_LinkedAnimLayer : : OnLayerChanged , & DetailBuilder ) ) ;
2019-05-22 12:00:20 -04:00
}
LayerHandle - > MarkHiddenByCustomization ( ) ;
2019-05-24 10:11:07 -04:00
// Check layers available in this BP
2019-05-22 12:00:20 -04:00
FDetailWidgetRow & LayerWidgetRow = CategoryBuilder . AddCustomRow ( LOCTEXT ( " FilterStringLayer " , " Layer " ) ) ;
LayerWidgetRow . NameContent ( )
[
LayerHandle - > CreatePropertyNameWidget ( )
]
. ValueContent ( )
. MinDesiredWidth ( 150.0f )
[
2019-05-24 10:11:07 -04:00
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
[
SNew ( SBox )
. Visibility_Lambda ( [ this ] ( ) { return HasAvailableLayers ( ) ? EVisibility : : Visible : EVisibility : : Collapsed ; } )
[
PropertyCustomizationHelpers : : MakePropertyComboBox (
LayerHandle ,
2019-09-23 07:23:26 -04:00
FOnGetPropertyComboBoxStrings : : CreateUObject ( this , & UAnimGraphNode_LinkedAnimLayer : : GetLayerNames ) ,
FOnGetPropertyComboBoxValue : : CreateUObject ( this , & UAnimGraphNode_LinkedAnimLayer : : GetLayerName )
2019-05-24 10:11:07 -04:00
)
]
]
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
[
SNew ( STextBlock )
. Visibility_Lambda ( [ this ] ( ) { return ! HasAvailableLayers ( ) ? EVisibility : : Visible : EVisibility : : Collapsed ; } )
. Font ( IDetailLayoutBuilder : : GetDetailFont ( ) )
. Text ( LOCTEXT ( " NoLayersWarning " , " No available layers. " ) )
. ToolTipText ( LOCTEXT ( " NoLayersWarningTooltip " , " This Animation Blueprint has no layers to choose from. \n To add some, either implement an Animation Layer Interface via the Class Settings, or add an animation layer in the My Blueprint tab. " ) )
]
2019-05-22 12:00:20 -04:00
] ;
}
2019-08-08 11:18:26 -04:00
GenerateExposedPinsDetails ( DetailBuilder ) ;
2019-05-24 13:21:02 -04:00
UAnimGraphNode_CustomProperty : : CustomizeDetails ( DetailBuilder ) ;
2019-05-24 10:11:07 -04:00
// Customize InstanceClass with unique visibility (identical to parent class apart from this)
2019-05-22 12:00:20 -04:00
{
2019-05-24 10:11:07 -04:00
TSharedRef < IPropertyHandle > ClassHandle = DetailBuilder . GetProperty ( TEXT ( " Node.InstanceClass " ) , GetClass ( ) ) ;
ClassHandle - > MarkHiddenByCustomization ( ) ;
2019-05-22 12:00:20 -04:00
2019-05-24 10:11:07 -04:00
FDetailWidgetRow & ClassWidgetRow = CategoryBuilder . AddCustomRow ( LOCTEXT ( " FilterStringInstanceClass " , " Instance Class " ) ) ;
ClassWidgetRow . NameContent ( )
[
ClassHandle - > CreatePropertyNameWidget ( )
]
. ValueContent ( )
. MinDesiredWidth ( 250.0f )
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
[
SNew ( SObjectPropertyEntryBox )
. Visibility_Lambda ( [ this ] ( ) { return HasValidNonSelfLayer ( ) ? EVisibility : : Visible : EVisibility : : Collapsed ; } )
2019-09-23 07:23:26 -04:00
. ObjectPath_UObject ( this , & UAnimGraphNode_LinkedAnimLayer : : GetCurrentInstanceBlueprintPath )
2019-05-24 10:11:07 -04:00
. AllowedClass ( UAnimBlueprint : : StaticClass ( ) )
. NewAssetFactories ( TArray < UFactory * > ( ) )
2019-09-23 07:23:26 -04:00
. OnShouldFilterAsset ( FOnShouldFilterAsset : : CreateUObject ( this , & UAnimGraphNode_LinkedAnimLayer : : OnShouldFilterInstanceBlueprint ) )
. OnObjectChanged ( FOnSetObject : : CreateUObject ( this , & UAnimGraphNode_LinkedAnimLayer : : OnSetInstanceBlueprint , & DetailBuilder ) )
2019-05-24 10:11:07 -04:00
]
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
[
SNew ( STextBlock )
. Visibility_Lambda ( [ this ] ( ) { return ! HasValidNonSelfLayer ( ) ? EVisibility : : Visible : EVisibility : : Collapsed ; } )
. Font ( IDetailLayoutBuilder : : GetDetailFont ( ) )
. Text ( LOCTEXT ( " SelfLayersWarning " , " Uses layer in this Blueprint. " ) )
2019-09-23 07:23:26 -04:00
. ToolTipText ( LOCTEXT ( " SelfLayersWarningTooltip " , " This linked anim layer node refers to a layer only in this blueprint, so cannot be overriden by an external blueprint implementation. \n Change to use a layer from an implemented interface to allow this override. " ) )
2019-05-24 10:11:07 -04:00
]
] ;
2019-05-22 12:00:20 -04:00
}
}
2019-09-23 07:23:26 -04:00
bool UAnimGraphNode_LinkedAnimLayer : : OnShouldFilterInstanceBlueprint ( const FAssetData & AssetData ) const
2019-05-22 12:00:20 -04:00
{
if ( Super : : OnShouldFilterInstanceBlueprint ( AssetData ) )
{
return true ;
}
if ( UAnimBlueprint * CurrentBlueprint = Cast < UAnimBlueprint > ( GetBlueprint ( ) ) )
{
2019-05-24 10:11:07 -04:00
TArray < TSubclassOf < UInterface > > AnimInterfaces ;
for ( const FBPInterfaceDescription & InterfaceDesc : CurrentBlueprint - > ImplementedInterfaces )
{
if ( InterfaceDesc . Interface & & InterfaceDesc . Interface - > IsChildOf < UAnimLayerInterface > ( ) )
{
if ( Node . Layer = = NAME_None | | InterfaceDesc . Interface - > FindFunctionByName ( Node . Layer ) )
{
AnimInterfaces . Add ( InterfaceDesc . Interface ) ;
}
}
}
2019-05-22 12:00:20 -04:00
// Check interface compatibility
2019-05-24 10:11:07 -04:00
if ( AnimInterfaces . Num ( ) > 0 )
2019-05-22 12:00:20 -04:00
{
bool bMatchesInterface = false ;
const FString ImplementedInterfaces = AssetData . GetTagValueRef < FString > ( FBlueprintTags : : ImplementedInterfaces ) ;
if ( ! ImplementedInterfaces . IsEmpty ( ) )
{
FString FullInterface ;
FString RemainingString ;
FString InterfacePath ;
FString CurrentString = * ImplementedInterfaces ;
while ( CurrentString . Split ( TEXT ( " , " ) , & FullInterface , & RemainingString ) & & ! bMatchesInterface )
{
if ( ! CurrentString . StartsWith ( TEXT ( " Graphs=( " ) ) )
{
if ( FullInterface . Split ( TEXT ( " \" " ) , & CurrentString , & InterfacePath , ESearchCase : : CaseSensitive ) )
{
// The interface paths in metadata end with "', so remove those
InterfacePath . RemoveFromEnd ( TEXT ( " \" ' " ) ) ;
FCoreRedirectObjectName ResolvedInterfaceName = FCoreRedirects : : GetRedirectedName ( ECoreRedirectFlags : : Type_Class , FCoreRedirectObjectName ( InterfacePath ) ) ;
2019-05-24 10:11:07 -04:00
// Verify against all interfaces we currently implement
for ( TSubclassOf < UInterface > AnimInterface : AnimInterfaces )
{
bMatchesInterface | = ResolvedInterfaceName . ObjectName = = AnimInterface - > GetFName ( ) ;
}
2019-05-22 12:00:20 -04:00
}
}
CurrentString = RemainingString ;
}
}
if ( ! bMatchesInterface )
{
return true ;
}
}
2019-05-24 10:11:07 -04:00
else
{
// No interfaces, so no compatible BPs
return true ;
}
2019-05-22 12:00:20 -04:00
}
return false ;
}
2019-09-23 07:23:26 -04:00
FString UAnimGraphNode_LinkedAnimLayer : : GetCurrentInstanceBlueprintPath ( ) const
2019-05-22 12:00:20 -04:00
{
UClass * InterfaceClass = * Node . InstanceClass ;
if ( InterfaceClass )
{
UBlueprint * ActualBlueprint = UBlueprint : : GetBlueprintFromClass ( InterfaceClass ) ;
if ( ActualBlueprint )
{
return ActualBlueprint - > GetPathName ( ) ;
}
}
return FString ( ) ;
}
2019-12-13 11:07:03 -05:00
void UAnimGraphNode_LinkedAnimLayer : : GetExposableProperties ( TArray < FProperty * > & OutExposableProperties ) const
2019-05-22 12:00:20 -04:00
{
UClass * TargetClass = GetTargetSkeletonClass ( ) ;
if ( TargetClass )
{
// add only sub-input properties
IAnimClassInterface * AnimClassInterface = IAnimClassInterface : : GetFromClass ( TargetClass ) ;
for ( const FAnimBlueprintFunction & AnimBlueprintFunction : AnimClassInterface - > GetAnimBlueprintFunctions ( ) )
{
// Check name matches.
if ( AnimBlueprintFunction . Name = = Node . GetDynamicLinkFunctionName ( ) )
{
2019-12-13 11:07:03 -05:00
for ( const TFieldPath < FProperty > & Property : AnimBlueprintFunction . InputProperties )
2019-05-22 12:00:20 -04:00
{
2019-12-13 11:07:03 -05:00
OutExposableProperties . Add ( Property . Get ( ) ) ;
2019-05-22 12:00:20 -04:00
}
}
}
}
}
2019-09-23 07:23:26 -04:00
void UAnimGraphNode_LinkedAnimLayer : : GetLayerNames ( TArray < TSharedPtr < FString > > & OutStrings , TArray < TSharedPtr < SToolTip > > & OutToolTips , TArray < bool > & OutRestrictedItems )
2019-05-22 12:00:20 -04:00
{
2019-05-24 10:11:07 -04:00
// If no interface specified, use this class
if ( UAnimBlueprint * CurrentBlueprint = Cast < UAnimBlueprint > ( GetBlueprint ( ) ) )
2019-05-22 12:00:20 -04:00
{
2019-05-24 10:11:07 -04:00
UClass * TargetClass = * CurrentBlueprint - > SkeletonGeneratedClass ;
if ( TargetClass )
2019-05-22 12:00:20 -04:00
{
2019-05-24 10:11:07 -04:00
IAnimClassInterface * AnimClassInterface = IAnimClassInterface : : GetFromClass ( TargetClass ) ;
for ( const FAnimBlueprintFunction & AnimBlueprintFunction : AnimClassInterface - > GetAnimBlueprintFunctions ( ) )
2019-05-22 12:00:20 -04:00
{
2019-05-24 10:11:07 -04:00
if ( AnimBlueprintFunction . Name ! = UEdGraphSchema_K2 : : GN_AnimGraph )
{
OutStrings . Add ( MakeShared < FString > ( AnimBlueprintFunction . Name . ToString ( ) ) ) ;
OutToolTips . Add ( nullptr ) ;
OutRestrictedItems . Add ( false ) ;
}
2019-05-22 12:00:20 -04:00
}
}
}
}
2019-09-23 07:23:26 -04:00
FString UAnimGraphNode_LinkedAnimLayer : : GetLayerName ( ) const
2019-05-22 12:00:20 -04:00
{
return Node . Layer . ToString ( ) ;
}
2019-12-13 11:07:03 -05:00
bool UAnimGraphNode_LinkedAnimLayer : : IsStructuralProperty ( FProperty * InProperty ) const
2019-05-22 12:00:20 -04:00
{
return Super : : IsStructuralProperty ( InProperty ) | |
2019-09-23 07:23:26 -04:00
InProperty - > GetFName ( ) = = GET_MEMBER_NAME_CHECKED ( FAnimNode_LinkedAnimLayer , Layer ) ;
2019-05-22 12:00:20 -04:00
}
2019-09-23 07:23:26 -04:00
UClass * UAnimGraphNode_LinkedAnimLayer : : GetTargetSkeletonClass ( ) const
2019-05-22 12:00:20 -04:00
{
UClass * SuperTargetSkeletonClass = Super : : GetTargetSkeletonClass ( ) ;
if ( SuperTargetSkeletonClass = = nullptr )
{
2019-05-24 10:11:07 -04:00
// If no concrete class specified, use this class
2019-05-22 12:00:20 -04:00
if ( UAnimBlueprint * CurrentBlueprint = Cast < UAnimBlueprint > ( GetBlueprint ( ) ) )
{
SuperTargetSkeletonClass = * CurrentBlueprint - > SkeletonGeneratedClass ;
}
}
return SuperTargetSkeletonClass ;
}
2019-09-23 07:23:26 -04:00
TSubclassOf < UInterface > UAnimGraphNode_LinkedAnimLayer : : GetInterfaceForLayer ( ) const
2019-05-24 10:11:07 -04:00
{
if ( UAnimBlueprint * CurrentBlueprint = Cast < UAnimBlueprint > ( GetBlueprint ( ) ) )
{
2019-12-13 11:07:03 -05:00
// Find layer with this name in interfaces
for ( FBPInterfaceDescription & InterfaceDesc : CurrentBlueprint - > ImplementedInterfaces )
2019-05-24 10:11:07 -04:00
{
2019-12-13 11:07:03 -05:00
for ( UEdGraph * InterfaceGraph : InterfaceDesc . Graphs )
2019-05-24 10:11:07 -04:00
{
2019-12-13 11:07:03 -05:00
if ( InterfaceGraph - > GetFName ( ) = = Node . Layer )
{
return InterfaceDesc . Interface ;
}
2019-05-24 10:11:07 -04:00
}
}
}
return nullptr ;
}
2019-09-26 13:01:46 -04:00
void UAnimGraphNode_LinkedAnimLayer : : UpdateGuidForLayer ( )
2019-09-26 06:05:49 -04:00
{
if ( ! InterfaceGuid . IsValid ( ) )
{
InterfaceGuid = GetGuidForLayer ( ) ;
}
}
2019-09-26 13:01:46 -04:00
FGuid UAnimGraphNode_LinkedAnimLayer : : GetGuidForLayer ( ) const
2019-09-26 06:05:49 -04:00
{
if ( UAnimBlueprint * CurrentBlueprint = Cast < UAnimBlueprint > ( GetBlueprint ( ) ) )
{
// Find layer with this name in interfaces
for ( FBPInterfaceDescription & InterfaceDesc : CurrentBlueprint - > ImplementedInterfaces )
{
for ( UEdGraph * InterfaceGraph : InterfaceDesc . Graphs )
{
if ( InterfaceGraph - > GetFName ( ) = = Node . Layer )
{
return InterfaceGraph - > InterfaceGuid ;
}
}
}
}
return FGuid ( ) ;
}
2019-09-23 07:23:26 -04:00
void UAnimGraphNode_LinkedAnimLayer : : OnLayerChanged ( IDetailLayoutBuilder * DetailBuilder )
2019-05-24 10:11:07 -04:00
{
OnStructuralPropertyChanged ( DetailBuilder ) ;
// Get the interface for this layer. If null, then we are using a 'self' layer.
Node . Interface = GetInterfaceForLayer ( ) ;
2019-09-26 06:05:49 -04:00
// Update the Guid for conforming
InterfaceGuid = GetGuidForLayer ( ) ;
2019-05-24 10:11:07 -04:00
if ( Node . Interface . Get ( ) = = nullptr )
{
// Self layers cannot have override implementations
Node . InstanceClass = nullptr ;
}
}
2019-09-23 07:23:26 -04:00
bool UAnimGraphNode_LinkedAnimLayer : : HasAvailableLayers ( ) const
2019-05-24 10:11:07 -04:00
{
if ( UAnimBlueprint * CurrentBlueprint = Cast < UAnimBlueprint > ( GetBlueprint ( ) ) )
{
UClass * TargetClass = * CurrentBlueprint - > SkeletonGeneratedClass ;
if ( TargetClass )
{
IAnimClassInterface * AnimClassInterface = IAnimClassInterface : : GetFromClass ( TargetClass ) ;
for ( const FAnimBlueprintFunction & AnimBlueprintFunction : AnimClassInterface - > GetAnimBlueprintFunctions ( ) )
{
if ( AnimBlueprintFunction . Name ! = UEdGraphSchema_K2 : : GN_AnimGraph )
{
return true ;
}
}
}
}
return false ;
}
2019-09-23 07:23:26 -04:00
bool UAnimGraphNode_LinkedAnimLayer : : HasValidNonSelfLayer ( ) const
2019-05-24 10:11:07 -04:00
{
if ( UAnimBlueprint * CurrentBlueprint = Cast < UAnimBlueprint > ( GetBlueprint ( ) ) )
{
if ( Node . Interface . Get ( ) )
{
for ( const FBPInterfaceDescription & InterfaceDesc : CurrentBlueprint - > ImplementedInterfaces )
{
if ( InterfaceDesc . Interface & & InterfaceDesc . Interface - > IsChildOf < UAnimLayerInterface > ( ) )
{
if ( InterfaceDesc . Interface - > FindFunctionByName ( Node . Layer ) )
{
return true ;
}
}
}
}
}
return false ;
}
2019-09-26 09:15:50 -04:00
void UAnimGraphNode_LinkedAnimLayer : : HandleSetObjectBeingDebugged ( UObject * InDebugObj )
{
2019-10-21 10:16:30 -04:00
if ( HasValidBlueprint ( ) )
2019-09-26 09:15:50 -04:00
{
2019-10-21 10:16:30 -04:00
NodeTitleChangedEvent . Broadcast ( ) ;
FAnimNode_LinkedAnimLayer * PreviewNode = GetPreviewNode ( ) ;
if ( PreviewNode )
{
PreviewNode - > OnInstanceChanged ( ) . AddUObject ( this , & UAnimGraphNode_LinkedAnimLayer : : HandleInstanceChanged ) ;
}
2019-09-26 09:15:50 -04:00
}
}
void UAnimGraphNode_LinkedAnimLayer : : HandleInstanceChanged ( )
{
NodeTitleChangedEvent . Broadcast ( ) ;
}
2021-05-24 06:55:32 -04:00
void UAnimGraphNode_LinkedAnimLayer : : SetupFromLayerId ( FName InLayer )
{
Node . Layer = InLayer ;
// Get the interface for this layer. If null, then we are using a 'self' layer.
Node . Interface = GetInterfaceForLayer ( ) ;
// Update the Guid for conforming
InterfaceGuid = GetGuidForLayer ( ) ;
if ( Node . Interface . Get ( ) = = nullptr )
{
// Self layers cannot have override implementations
Node . InstanceClass = nullptr ;
}
}
void UAnimGraphNode_LinkedAnimLayer : : GetMenuActions ( FBlueprintActionDatabaseRegistrar & ActionRegistrar ) const
{
// Anim graph node base class will allow us to spawn an 'empty' node
UAnimGraphNode_Base : : GetMenuActions ( ActionRegistrar ) ;
auto MakeAnimBlueprintAction = [ ] ( TSubclassOf < UEdGraphNode > const NodeClass , const FName & InLayerId )
{
auto SetNodeLayerId = [ ] ( UEdGraphNode * NewNode , bool bIsTemplateNode , FName InLayerId )
{
UAnimGraphNode_LinkedAnimLayer * LinkedAnimGraphNode = CastChecked < UAnimGraphNode_LinkedAnimLayer > ( NewNode ) ;
LinkedAnimGraphNode - > SetupFromLayerId ( InLayerId ) ;
} ;
UBlueprintNodeSpawner * NodeSpawner = UBlueprintNodeSpawner : : Create ( NodeClass ) ;
check ( NodeSpawner ! = nullptr ) ;
NodeSpawner - > CustomizeNodeDelegate = UBlueprintNodeSpawner : : FCustomizeNodeDelegate : : CreateStatic ( SetNodeLayerId , InLayerId ) ;
NodeSpawner - > DefaultMenuSignature . Category = LOCTEXT ( " LinkedAnimLayerCategory " , " Linked Anim Layers " ) ;
NodeSpawner - > DefaultMenuSignature . MenuName = NodeSpawner - > DefaultMenuSignature . Tooltip = FText : : Format ( LOCTEXT ( " LinkedAnimGraphMenuFormat " , " {0} - Linked Anim Layer " ) , FText : : FromName ( InLayerId ) ) ;
return NodeSpawner ;
} ;
if ( const UObject * RegistrarTarget = ActionRegistrar . GetActionKeyFilter ( ) )
{
if ( const UAnimBlueprint * TargetAnimBlueprint = Cast < UAnimBlueprint > ( RegistrarTarget ) )
{
UClass * TargetClass = * TargetAnimBlueprint - > SkeletonGeneratedClass ;
if ( TargetClass )
{
UClass * NodeClass = GetClass ( ) ;
IAnimClassInterface * AnimClassInterface = IAnimClassInterface : : GetFromClass ( TargetClass ) ;
for ( const FAnimBlueprintFunction & AnimBlueprintFunction : AnimClassInterface - > GetAnimBlueprintFunctions ( ) )
{
if ( AnimBlueprintFunction . Name ! = UEdGraphSchema_K2 : : GN_AnimGraph )
{
if ( UFunction * Function = TargetClass - > FindFunctionByName ( AnimBlueprintFunction . Name ) )
{
if ( UBlueprintNodeSpawner * NodeSpawner = MakeAnimBlueprintAction ( NodeClass , AnimBlueprintFunction . Name ) )
{
ActionRegistrar . AddBlueprintAction ( Function , NodeSpawner ) ;
}
}
}
}
}
}
}
}
2019-05-22 12:00:20 -04:00
# undef LOCTEXT_NAMESPACE