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"
2022-10-26 12:57:32 -04:00
# include "Components/SkeletalMeshComponent.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"
2021-10-12 21:21:22 -04:00
# include "ObjectEditorUtils.h"
2021-05-24 06:55:32 -04:00
# include "AssetRegistry/AssetRegistryModule.h"
2023-08-14 11:44:09 -04:00
# include "EditorClassUtils.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
2022-03-10 21:02:48 -05:00
namespace LinkedAnimLayerGraphNodeConstants
{
2022-04-06 00:23:18 -04:00
FLinearColor TitleColorSelfLayer ( 0.2f , 0.07f , 0.6f ) ;
FLinearColor TitleColorLinkedLayer ( 0.45f , 0.f , 0.7f ) ;
2022-03-10 21:02:48 -05: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
{
2022-05-09 13:12:28 -04:00
return FSlateIcon ( FAppStyle : : GetAppStyleSetName ( ) , " ClassIcon.AnimLayerInterface " ) ;
2021-05-24 06:55:32 -04:00
}
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
2022-05-18 07:36:32 -04:00
const FText DefaultNodeTitle = LOCTEXT ( " NodeTitle " , " Linked Anim Layer " ) ;
2019-05-22 12:00:20 -04:00
if ( TitleType = = ENodeTitleType : : MenuTitle )
{
2022-05-18 07:36:32 -04:00
return DefaultNodeTitle ;
2019-05-22 12:00:20 -04:00
}
else
{
2021-05-24 06:55:32 -04:00
bool bIsSelf = TargetAnimBlueprintInterface = = nullptr ;
FFormatNamedArguments Args ;
2022-05-18 07:36:32 -04:00
Args . Add ( TEXT ( " NodeType " ) , bIsSelf ? LOCTEXT ( " SelfLayerNodeTitle " , " Anim Layer (self) " ) : DefaultNodeTitle ) ;
2021-05-24 06:55:32 -04:00
Args . Add ( TEXT ( " TargetClass " ) , bIsSelf ? LOCTEXT ( " ClassSelf " , " Self " ) : FText : : FromString ( TargetAnimBlueprintInterface - > GetName ( ) ) ) ;
2022-09-29 20:38:46 -04:00
Args . Add ( TEXT ( " Layer " ) , ( GetLayerName ( ) = = NAME_None ) ? LOCTEXT ( " LayerNone " , " None " ) : FText : : FromName ( GetLayerName ( ) ) ) ;
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 ) ;
2022-09-29 20:38:46 -04:00
if ( GetLayerName ( ) = = NAME_None )
2019-05-22 12:00:20 -04:00
{
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 ( ) )
{
2022-09-29 20:38:46 -04:00
if ( AnimBlueprintFunction . Name = = GetLayerName ( ) )
2019-05-22 12:00:20 -04:00
{
bFoundFunction = true ;
}
}
if ( ! bFoundFunction )
{
2022-09-29 20:38:46 -04:00
MessageLog . Error ( * FText : : Format ( LOCTEXT ( " MissingLayerError " , " Linked anim layer node @@ uses invalid layer '{0}'. " ) , FText : : FromName ( GetLayerName ( ) ) ) . 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
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 " ) ;
2022-09-27 06:56:42 -04:00
if ( ! InGraph - > IsA < UAnimationStateGraph > ( ) & & InGraph - > GetFName ( ) ! = DefaultAnimGraphName & & InGraph - > InterfaceGuid . IsValid ( ) & & OriginalThis - > InterfaceGuid . IsValid ( ) )
2019-08-12 05:41:21 -04:00
{
2022-09-27 06:56:42 -04:00
MessageLog . Error ( * FText : : Format ( LOCTEXT ( " NestedLayer " , " Linked anim layer node @@ is part of Animation Layer Graph '{0}', linked layers cannot be nested. " ) , FText : : FromName ( InGraph - > GetFName ( ) ) ) . ToString ( ) , this ) ;
2019-08-12 05:41:21 -04:00
}
} ;
2022-09-27 06:56:42 -04:00
// Gather all linked anim layer node instances in this blueprint
TArray < UAnimGraphNode_LinkedAnimLayer * > AllLayerNodes ;
for ( const UEdGraph * Graph : Graphs )
2019-05-22 12:00:20 -04:00
{
2022-09-27 06:56:42 -04:00
Graph - > GetNodesOfClass ( AllLayerNodes ) ;
}
// Check for duplicates
for ( const UAnimGraphNode_LinkedAnimLayer * LayerNode : AllLayerNodes )
{
if ( LayerNode ! = OriginalThis )
{
2022-09-29 20:38:46 -04:00
if ( LayerNode - > GetLayerName ( ) = = GetLayerName ( ) )
2022-09-27 06:56:42 -04:00
{
MessageLog . Error ( * FText : : Format ( LOCTEXT ( " DuplicateLayerError " , " Linked anim layer node @@ is also used by graph '{0}', layers can be used only once in an animation blueprint. " ) , FText : : FromName ( LayerNode - > GetGraph ( ) - > GetFName ( ) ) ) . ToString ( ) , this ) ;
}
}
}
// Check for circular references and indirect nesting
for ( const UEdGraph * Graph : Graphs )
{
if ( Graph - > GetFName ( ) = = OriginalThis - > Node . Layer )
{
TArray < const UEdGraph * > GraphStack ;
bool bWithinLinkedAnimLayer = OriginalThis - > InterfaceGuid . IsValid ( ) ;
UEdGraph * OuterGraph = OriginalThis - > GetGraph ( ) ;
// If our outer graph is a linked layer interface function that has no instance in the blueprint, we need to validate it for nesting as it can still be instanciated through the application of a linked layer
if ( OuterGraph - > InterfaceGuid . IsValid ( ) )
{
bool bCheckOuter = false ;
for ( const UAnimGraphNode_LinkedAnimLayer * LayerNode : AllLayerNodes )
{
if ( LayerNode - > Node . Layer = = OuterGraph - > GetFName ( ) )
{
bCheckOuter = false ;
break ;
}
}
// Check outer graph for nested linked layers
if ( bCheckOuter )
{
static const FName DefaultAnimGraphName ( " AnimGraph " ) ;
if ( OuterGraph - > GetFName ( ) ! = DefaultAnimGraphName )
{
ValidateOuterGraph ( OuterGraph ) ;
// Add outer graph to graph stack
GraphStack . Add ( OuterGraph ) ;
// If outer graph is a linked layer interface, account for it to properly detect nesting
bWithinLinkedAnimLayer = bWithinLinkedAnimLayer | | OuterGraph - > InterfaceGuid . IsValid ( ) ;
}
}
}
ValidateCircularRefAndNesting ( Graph , Graphs , GraphStack , bWithinLinkedAnimLayer , MessageLog ) ;
}
2019-05-22 12:00:20 -04:00
}
}
}
}
2022-09-27 06:56:42 -04:00
void UAnimGraphNode_LinkedAnimLayer : : ValidateCircularRefAndNesting ( const UEdGraph * CurrentGraph , const TArray < UEdGraph * > & AllGraphs , TArray < const UEdGraph * > GraphStack , bool bWithinLinkedLayerGraph , FCompilerResultsLog & MessageLog )
{
// Build graph chain string
2023-03-10 13:06:34 -05:00
auto BuildGraphChainString = [ ] ( const TArray < const UEdGraph * > & GraphStack ) - > FString
2022-09-27 06:56:42 -04:00
{
TStringBuilder < 1024 > GraphChain ;
bool bFirst = true ;
for ( const UEdGraph * Graph : GraphStack )
{
if ( ! bFirst )
{
GraphChain < < TEXT ( " -> " ) ;
}
GraphChain < < * Graph - > GetName ( ) ;
bFirst = false ;
}
2023-03-10 13:06:34 -05:00
return FString ( GraphChain ) ;
2022-09-27 06:56:42 -04:00
} ;
2019-05-22 12:00:20 -04:00
2022-09-27 06:56:42 -04:00
// If a graph is already in the stack we have a circular reference
if ( GraphStack . Contains ( CurrentGraph ) )
{
// Add the redundant graph so the error is easier to understand
GraphStack . Add ( CurrentGraph ) ;
MessageLog . Error ( * FText : : Format ( LOCTEXT ( " CircularLayerReference " , " Anim layer node @@ in Graph '{0}' has a circular dependency '{1}'. " ) , FText : : FromName ( Node . Layer ) , FText : : FromString ( BuildGraphChainString ( GraphStack ) ) ) . ToString ( ) , this ) ;
return ;
}
GraphStack . Add ( CurrentGraph ) ;
// Find layer nodes and recursively check their graphs
TArray < UAnimGraphNode_LinkedAnimLayer * > LayerNodes ;
CurrentGraph - > GetNodesOfClass ( LayerNodes ) ;
for ( const UAnimGraphNode_LinkedAnimLayer * LayerNode : LayerNodes )
{
// Check for linked anim layer nesting
if ( bWithinLinkedLayerGraph & & LayerNode - > InterfaceGuid . IsValid ( ) )
{
if ( GraphStack . Num ( ) = = 1 )
{
MessageLog . Error ( * FText : : Format ( LOCTEXT ( " NestedLayer " , " Linked anim layer node @@ is part of Animation Layer Graph '{0}', linked layers cannot be nested. " ) , FText : : FromName ( CurrentGraph - > GetFName ( ) ) ) . ToString ( ) , LayerNode ) ;
}
else
{
2022-10-04 12:04:24 -04:00
MessageLog . Error ( * FText : : Format ( LOCTEXT ( " IndirectlyNestedLayer " , " Linked anim layer node @@ is indirectly nested inside another Linked Anim Layer Graph '{0}', linked layers cannot be nested. " ) , FText : : FromString ( BuildGraphChainString ( GraphStack ) ) ) . ToString ( ) , LayerNode ) ;
2022-09-27 06:56:42 -04:00
}
}
for ( const UEdGraph * Graph : AllGraphs )
{
if ( Graph - > GetFName ( ) = = LayerNode - > Node . Layer )
{
ValidateCircularRefAndNesting ( Graph , AllGraphs , GraphStack , bWithinLinkedLayerGraph | | LayerNode - > InterfaceGuid . IsValid ( ) , MessageLog ) ;
}
}
}
} ;
2022-08-26 13:15:55 -04:00
void UAnimGraphNode_LinkedAnimLayer : : GetLinkTarget ( UObject * & OutTargetGraph , UBlueprint * & OutTargetBlueprint ) const
{
OutTargetGraph = nullptr ;
OutTargetBlueprint = nullptr ;
auto JumpTargetFromClass = [ this ] ( UClass * InClass , UObject * & OutTargetGraph , UBlueprint * & OutTargetBlueprint )
{
2019-05-22 12:00:20 -04:00
UAnimBlueprint * TargetAnimBlueprint = InClass ? CastChecked < UAnimBlueprint > ( InClass - > ClassGeneratedBy ) : nullptr ;
2022-08-24 14:14:53 -04:00
while ( TargetAnimBlueprint ! = nullptr )
2019-05-22 12:00:20 -04:00
{
2022-08-24 14:14:53 -04:00
// jump to graph in other BP, going up the parent BP hierarchy until we find it
2019-05-22 12:00:20 -04:00
TArray < UEdGraph * > Graphs ;
TargetAnimBlueprint - > GetAllGraphs ( Graphs ) ;
2022-09-29 20:38:46 -04:00
UEdGraph * * FoundGraph = Graphs . FindByPredicate ( [ this ] ( UEdGraph * InGraph ) { return InGraph - > GetFName ( ) = = GetLayerName ( ) ; } ) ;
2022-08-24 14:14:53 -04:00
if ( FoundGraph )
2019-05-22 12:00:20 -04:00
{
2022-08-26 13:15:55 -04:00
OutTargetBlueprint = TargetAnimBlueprint ;
OutTargetGraph = * FoundGraph ;
return ;
2019-05-22 12:00:20 -04:00
}
else
{
2022-08-24 14:14:53 -04:00
TargetAnimBlueprint = UAnimBlueprint : : GetParentAnimBlueprint ( TargetAnimBlueprint ) ;
2019-05-22 12:00:20 -04:00
}
}
2022-08-24 14:14:53 -04:00
// jump to graph in self
TArray < UEdGraph * > Graphs ;
GetBlueprint ( ) - > GetAllGraphs ( Graphs ) ;
2022-09-29 20:38:46 -04:00
UEdGraph * * FoundGraph = Graphs . FindByPredicate ( [ this ] ( UEdGraph * InGraph ) { return InGraph - > GetFName ( ) = = GetLayerName ( ) ; } ) ;
2022-08-24 14:14:53 -04:00
if ( FoundGraph )
{
2022-08-26 13:15:55 -04:00
OutTargetBlueprint = nullptr ;
OutTargetGraph = * FoundGraph ;
return ;
2022-08-24 14:14:53 -04:00
}
2019-05-22 12:00:20 -04:00
} ;
// First try a concrete class, if any
2022-08-24 14:14:53 -04:00
const FAnimNode_LinkedAnimGraph * RuntimeNode = GetLinkedAnimGraphNode ( ) ;
if ( UObject * TargetInstance = RuntimeNode - > GetTargetInstance < UObject > ( ) )
{
2022-08-26 13:15:55 -04:00
JumpTargetFromClass ( TargetInstance - > GetClass ( ) , OutTargetGraph , OutTargetBlueprint ) ;
2022-08-24 14:14:53 -04:00
}
2022-08-26 13:15:55 -04:00
if ( OutTargetGraph = = nullptr )
2022-08-24 14:14:53 -04:00
{
2022-08-26 13:15:55 -04:00
JumpTargetFromClass ( RuntimeNode - > InstanceClass , OutTargetGraph , OutTargetBlueprint ) ;
2022-08-24 14:14:53 -04:00
}
2022-08-26 13:15:55 -04:00
if ( OutTargetGraph = = nullptr )
2019-05-22 12:00:20 -04:00
{
// then try the interface
2022-08-26 13:15:55 -04:00
JumpTargetFromClass ( * Node . Interface , OutTargetGraph , OutTargetBlueprint ) ;
2019-05-22 12:00:20 -04:00
}
2022-08-26 13:15:55 -04:00
}
UObject * UAnimGraphNode_LinkedAnimLayer : : GetJumpTargetForDoubleClick ( ) const
{
UObject * TargetGraph ;
UBlueprint * TargetBlueprint ;
GetLinkTarget ( TargetGraph , TargetBlueprint ) ;
return TargetGraph ;
2019-05-22 12:00:20 -04:00
}
2019-09-23 07:23:26 -04:00
void UAnimGraphNode_LinkedAnimLayer : : JumpToDefinition ( ) const
2019-05-22 12:00:20 -04:00
{
2022-08-26 13:15:55 -04:00
UObject * TargetGraph ;
UBlueprint * TargetBlueprint ;
GetLinkTarget ( TargetGraph , TargetBlueprint ) ;
if ( UAnimationGraph * HyperlinkTarget = Cast < UAnimationGraph > ( TargetGraph ) )
2019-05-22 12:00:20 -04:00
{
FKismetEditorUtilities : : BringKismetToFocusAttentionOnObject ( HyperlinkTarget ) ;
2022-08-26 13:15:55 -04:00
if ( TargetBlueprint ! = nullptr )
{
const FAnimNode_LinkedAnimGraph * RuntimeNode = GetLinkedAnimGraphNode ( ) ;
if ( UObject * TargetInstance = RuntimeNode - > GetTargetInstance < UObject > ( ) )
{
TargetBlueprint - > SetObjectBeingDebugged ( TargetInstance ) ;
}
}
2019-05-22 12:00:20 -04:00
}
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 ) ,
2022-09-29 20:38:46 -04:00
FOnGetPropertyComboBoxValue : : CreateUObject ( this , & UAnimGraphNode_LinkedAnimLayer : : GetLayerNameString )
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
}
}
2022-01-18 14:18:19 -05:00
bool UAnimGraphNode_LinkedAnimLayer : : OnShouldFilterInstanceBlueprint ( const FAssetData & InAssetData ) const
2019-05-22 12:00:20 -04:00
{
2022-01-18 14:18:19 -05:00
if ( Super : : OnShouldFilterInstanceBlueprint ( InAssetData ) )
2019-05-22 12:00:20 -04:00
{
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 > ( ) )
{
2022-09-29 20:38:46 -04:00
if ( GetLayerName ( ) = = NAME_None | | InterfaceDesc . Interface - > FindFunctionByName ( GetLayerName ( ) ) )
2019-05-24 10:11:07 -04:00
{
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
{
2022-01-18 14:18:19 -05:00
const FAssetRegistryModule & AssetRegistryModule = FModuleManager : : LoadModuleChecked < FAssetRegistryModule > ( " AssetRegistry " ) ;
FAssetData CurrentAssetData = InAssetData ;
2019-05-22 12:00:20 -04:00
bool bMatchesInterface = false ;
2022-01-18 14:18:19 -05:00
do
2019-05-22 12:00:20 -04:00
{
2023-08-14 11:44:09 -04:00
TArray < FString > InterfacePaths ;
FEditorClassUtils : : GetImplementedInterfaceClassPathsFromAsset ( CurrentAssetData , InterfacePaths ) ;
2022-01-18 14:18:19 -05:00
2023-08-14 11:44:09 -04:00
for ( const FString & InterfacePath : InterfacePaths )
2019-05-22 12:00:20 -04:00
{
2023-08-14 11:44:09 -04:00
FTopLevelAssetPath AssetPath ( InterfacePath ) ;
FCoreRedirectObjectName ResolvedInterfaceName = FCoreRedirects : : GetRedirectedName ( ECoreRedirectFlags : : Type_Class , FCoreRedirectObjectName ( AssetPath ) ) ;
// Verify against all interfaces we currently implement
for ( TSubclassOf < UInterface > AnimInterface : AnimInterfaces )
2019-05-22 12:00:20 -04:00
{
2023-08-14 11:44:09 -04:00
bMatchesInterface | = ResolvedInterfaceName . ObjectName = = AnimInterface - > GetFName ( ) ;
2022-01-18 14:18:19 -05:00
}
2019-05-22 12:00:20 -04:00
}
2022-01-18 14:18:19 -05:00
// If we didn't find a matching interface, check the parent class
if ( ! bMatchesInterface )
{
const FString ParentClassFromData = CurrentAssetData . GetTagValueRef < FString > ( FBlueprintTags : : ParentClassPath ) ;
const FString ClassObjectPath = FPackageName : : ExportTextPathToObjectPath ( ParentClassFromData ) ;
2022-09-07 00:40:02 -04:00
const FString BlueprintPath = ClassObjectPath . LeftChop ( 2 ) ; // Chop off _C
CurrentAssetData = AssetRegistryModule . Get ( ) . GetAssetByObjectPath ( FSoftObjectPath ( BlueprintPath ) ) ;
2022-01-18 14:18:19 -05:00
}
// Only continue checking if the parent is an anim blueprint
Deprecating ANY_PACKAGE.
This change consists of multiple changes:
Core:
- Deprecation of ANY_PACKAGE macro. Added ANY_PACKAGE_DEPRECATED macro which can still be used for backwards compatibility purposes (only used in CoreUObject)
- Deprecation of StaticFindObjectFast* functions that take bAnyPackage parameter
- Added UStruct::GetStructPathName function that returns FTopLevelAssetPath representing the path name (package + object FName, super quick compared to UObject::GetPathName) + wrapper UClass::GetClassPathName to make it look better when used with UClasses
- Added (Static)FindFirstObject* functions that find a first object given its Name (no Outer). These functions are used in places I consider valid to do global UObject (UClass) lookups like parsing command line parameters / checking for unique object names
- Added static UClass::TryFindType function which serves a similar purpose as FindFirstObject however it's going to throw a warning (with a callstack / maybe ensure in the future?) if short class name is provided. This function is used in places that used to use short class names but now should have been converted to use path names to catch any potential regressions and or edge cases I missed.
- Added static UClass::TryConvertShortNameToPathName utility function
- Added static UClass::TryFixShortClassNameExportPath utility function
- Object text export paths will now also include class path (Texture2D'/Game/Textures/Grass.Grass' -> /Script/Engine.Texture2D'/Game/Textures/Grass.Grass')
- All places that manually generated object export paths for objects will now use FObjectPropertyBase::GetExportPath
- Added a new startup test that checks for short type names in UClass/FProperty MetaData values
AssetRegistry:
- Deprecated any member variables (FAssetData / FARFilter) or functions that use FNames to represent class names and replaced them with FTopLevelAssetPath
- Added new member variables and new function overloads that use FTopLevelAssetPath to represent class names
- This also applies to a few other modules' APIs to match AssetRegistry changes
Everything else:
- Updated code that used ANY_PACKAGE (depending on the use case) to use FindObject(nullptr, PathToObject), UClass::TryFindType (used when path name is expected, warns if it's a short name) or FindFirstObject (usually for finding types based on user input but there's been a few legitimate use cases not related to user input)
- Updated code that used AssetRegistry API to use FTopLevelAssetPaths and USomeClass::StaticClass()->GetClassPathName() instead of GetFName()
- Updated meta data and hardcoded FindObject(ANY_PACKAGE, "EEnumNameOrClassName") calls to use path names
#jira UE-99463
#rb many.people
[FYI] Marcus.Wassmer
#preflight 629248ec2256738f75de9b32
#codereviewnumbers 20320742, 20320791, 20320799, 20320756, 20320809, 20320830, 20320840, 20320846, 20320851, 20320863, 20320780, 20320765, 20320876, 20320786
#ROBOMERGE-OWNER: robert.manuszewski
#ROBOMERGE-AUTHOR: robert.manuszewski
#ROBOMERGE-SOURCE: CL 20430220 via CL 20433854 via CL 20435474 via CL 20435484
#ROBOMERGE-BOT: UE5 (Release-Engine-Staging -> Main) (v949-20362246)
[CL 20448496 by robert manuszewski in ue5-main branch]
2022-06-01 03:46:59 -04:00
} while ( ! bMatchesInterface & & ( CurrentAssetData . AssetClassPath = = UAnimBlueprint : : StaticClass ( ) - > GetClassPathName ( ) ) ) ;
2019-05-22 12:00:20 -04:00
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 ( ) ;
}
2021-10-12 21:21:22 -04:00
void UAnimGraphNode_LinkedAnimLayer : : CreateCustomPins ( TArray < UEdGraphPin * > * OldPins )
2019-05-22 12:00:20 -04:00
{
2021-10-12 21:21:22 -04:00
if ( UClass * TargetSkeletonClass = GetTargetSkeletonClass ( ) )
2019-05-22 12:00:20 -04:00
{
2021-10-12 21:21:22 -04:00
const UEdGraphSchema_K2 * K2Schema = GetDefault < UEdGraphSchema_K2 > ( ) ;
TArray < FOptionalPinFromProperty > OldCustomPinProperties = CustomPinProperties ;
CustomPinProperties . Empty ( ) ;
2019-05-22 12:00:20 -04:00
// add only sub-input properties
2021-10-12 21:21:22 -04:00
IAnimClassInterface * AnimClassInterface = IAnimClassInterface : : GetFromClass ( TargetSkeletonClass ) ;
2019-05-22 12:00:20 -04:00
for ( const FAnimBlueprintFunction & AnimBlueprintFunction : AnimClassInterface - > GetAnimBlueprintFunctions ( ) )
{
// Check name matches.
if ( AnimBlueprintFunction . Name = = Node . GetDynamicLinkFunctionName ( ) )
{
2021-10-27 15:14:40 -04:00
for ( const FAnimBlueprintFunction : : FInputPropertyData & PropertyData : AnimBlueprintFunction . InputPropertyData )
2019-05-22 12:00:20 -04:00
{
2021-10-27 15:14:40 -04:00
// Use function property here as during compilation (especially compile-on-load) the class property may not be available
if ( FProperty * Property = PropertyData . FunctionProperty )
2021-10-12 21:21:22 -04:00
{
2021-10-27 15:14:40 -04:00
const FName PinName = Property - > GetFName ( ) ;
FOptionalPinFromProperty OptionalPin ;
OptionalPin . PropertyName = PinName ;
OptionalPin . PropertyFriendlyName = UEditorEngine : : GetFriendlyName ( Property ) ;
OptionalPin . bShowPin = OldCustomPinProperties . ContainsByPredicate ( [ PinName ] ( const FOptionalPinFromProperty & InOptionalPin ) { return InOptionalPin . bShowPin & & InOptionalPin . PropertyName = = PinName ; } ) ;
OptionalPin . PropertyTooltip = Property - > GetToolTipText ( ) ;
OptionalPin . CategoryName = FObjectEditorUtils : : GetCategoryFName ( Property ) ;
OptionalPin . bCanToggleVisibility = true ;
OptionalPin . bIsOverrideEnabled = false ;
CustomPinProperties . Add ( OptionalPin ) ;
if ( OptionalPin . bShowPin )
2021-10-12 21:21:22 -04:00
{
2021-10-27 15:14:40 -04:00
FEdGraphPinType PinType ;
if ( K2Schema - > ConvertPropertyToPinType ( Property , /*out*/ PinType ) )
{
UEdGraphPin * NewPin = CreatePin ( EGPD_Input , PinType , PinName ) ;
NewPin - > PinFriendlyName = FText : : FromString ( OptionalPin . PropertyFriendlyName . IsEmpty ( ) ? PinName . ToString ( ) : OptionalPin . PropertyFriendlyName ) ;
K2Schema - > ConstructBasicPinTooltip ( * NewPin , OptionalPin . PropertyTooltip , NewPin - > PinToolTip ) ;
K2Schema - > SetPinAutogeneratedDefaultValueBasedOnType ( NewPin ) ;
}
2021-10-12 21:21:22 -04:00
}
}
2019-05-22 12:00:20 -04:00
}
}
}
}
}
2021-10-12 21:21:22 -04:00
FProperty * UAnimGraphNode_LinkedAnimLayer : : GetPinProperty ( FName InPinName ) const
{
if ( UClass * TargetSkeletonClass = GetTargetSkeletonClass ( ) )
{
// add only sub-input properties
IAnimClassInterface * AnimClassInterface = IAnimClassInterface : : GetFromClass ( TargetSkeletonClass ) ;
for ( const FAnimBlueprintFunction & AnimBlueprintFunction : AnimClassInterface - > GetAnimBlueprintFunctions ( ) )
{
// Check name matches.
if ( AnimBlueprintFunction . Name = = Node . GetDynamicLinkFunctionName ( ) )
{
2021-10-27 15:14:40 -04:00
for ( const FAnimBlueprintFunction : : FInputPropertyData & PropertyData : AnimBlueprintFunction . InputPropertyData )
2021-10-12 21:21:22 -04:00
{
2021-10-27 15:14:40 -04:00
FProperty * Property = PropertyData . FunctionProperty ;
2021-10-12 21:21:22 -04:00
if ( Property & & Property - > GetFName ( ) = = InPinName )
{
return Property ;
}
}
}
}
}
return Super : : GetPinProperty ( InPinName ) ;
}
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
}
}
}
}
2022-09-29 20:38:46 -04:00
FString UAnimGraphNode_LinkedAnimLayer : : GetLayerNameString ( ) const
2019-05-22 12:00:20 -04:00
{
2022-09-29 20:38:46 -04:00
return FunctionReference . GetMemberName ( ) . ToString ( ) ;
2019-05-22 12:00:20 -04:00
}
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
}
2022-03-10 21:02:48 -05:00
FLinearColor UAnimGraphNode_LinkedAnimLayer : : GetDefaultNodeTitleColor ( ) const
{
2022-04-06 00:23:18 -04:00
if ( HasValidNonSelfLayer ( ) )
{
return LinkedAnimLayerGraphNodeConstants : : TitleColorLinkedLayer ;
}
else
{
return LinkedAnimLayerGraphNodeConstants : : TitleColorSelfLayer ;
}
2022-03-10 21:02:48 -05: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 ( ) ) )
{
2022-01-18 00:02:46 -05:00
// Find layer with this name in interfaces
for ( FBPInterfaceDescription & InterfaceDesc : CurrentBlueprint - > ImplementedInterfaces )
{
for ( UEdGraph * InterfaceGraph : InterfaceDesc . Graphs )
2019-05-24 10:11:07 -04:00
{
2022-09-29 20:38:46 -04:00
if ( InterfaceGraph - > GetFName ( ) = = GetLayerName ( ) )
2019-05-24 10:11:07 -04:00
{
2022-01-18 00:02:46 -05:00
return InterfaceDesc . Interface ;
2019-05-24 10:11:07 -04:00
}
}
}
2022-01-18 00:02:46 -05:00
}
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 ( ) ;
}
}
2022-09-29 20:38:46 -04:00
void UAnimGraphNode_LinkedAnimLayer : : SetLayerName ( FName InName )
{
Node . Layer = InName ;
if ( UClass * TargetClass = GetTargetClass ( ) )
{
2022-11-29 12:34:49 -05:00
FGuid FunctionGuid ;
FBlueprintEditorUtils : : GetFunctionGuidFromClassByFieldName ( FBlueprintEditorUtils : : GetMostUpToDateClass ( TargetClass ) , InName , FunctionGuid ) ;
2023-01-16 08:46:32 -05:00
FunctionReference . SetExternalMember ( InName , TargetClass , FunctionGuid ) ;
2022-09-29 20:38:46 -04:00
}
else
{
FunctionReference . SetSelfMember ( InName ) ;
}
}
FName UAnimGraphNode_LinkedAnimLayer : : GetLayerName ( ) const
{
ensure ( FunctionReference . GetMemberName ( ) = = Node . Layer ) ;
return FunctionReference . GetMemberName ( ) ;
}
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 )
{
2022-09-29 20:38:46 -04:00
if ( InterfaceGraph - > GetFName ( ) = = GetLayerName ( ) )
2019-09-26 06:05:49 -04:00
{
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 ) ;
2022-11-29 12:34:49 -05:00
UClass * TargetClass = GetTargetClass ( ) ;
if ( TargetClass )
{
FGuid FunctionGuid ;
FBlueprintEditorUtils : : GetFunctionGuidFromClassByFieldName ( FBlueprintEditorUtils : : GetMostUpToDateClass ( TargetClass ) , Node . Layer , FunctionGuid ) ;
2023-01-16 08:46:32 -05:00
FunctionReference . SetExternalMember ( Node . Layer , TargetClass , FunctionGuid ) ;
2022-11-29 12:34:49 -05:00
}
else
{
FunctionReference . SetSelfMember ( Node . Layer ) ;
}
2019-05-24 10:11:07 -04:00
// 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 > ( ) )
{
2022-09-29 20:38:46 -04:00
if ( InterfaceDesc . Interface - > FindFunctionByName ( GetLayerName ( ) ) )
2019-05-24 10:11:07 -04:00
{
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 ;
2022-11-29 12:34:18 -05:00
// Set to self member first, so we have a valid name in the member reference (otherwise GetInterfaceForLayer will fail)
// We will override this below
FunctionReference . SetSelfMember ( InLayer ) ;
2021-05-24 06:55:32 -04:00
// 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 ;
}
2022-09-29 20:38:46 -04:00
// Set up function reference
UClass * TargetClass = GetTargetClass ( ) ;
if ( TargetClass )
{
2022-11-29 12:34:49 -05:00
FGuid FunctionGuid ;
FBlueprintEditorUtils : : GetFunctionGuidFromClassByFieldName ( FBlueprintEditorUtils : : GetMostUpToDateClass ( TargetClass ) , InLayer , FunctionGuid ) ;
FunctionReference . SetExternalMember ( InLayer , TargetClass , FunctionGuid ) ;
2022-09-29 20:38:46 -04:00
}
else
{
FunctionReference . SetSelfMember ( InLayer ) ;
}
2021-05-24 06:55:32 -04:00
}
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 )
{
2022-01-18 00:02:46 -05:00
// Accept interfaces
if ( TargetAnimBlueprint - > BlueprintType = = BPTYPE_Interface )
2021-05-24 06:55:32 -04:00
{
2022-01-18 00:02:46 -05:00
IAnimClassInterface * AnimClassInterface = IAnimClassInterface : : GetFromClass ( TargetClass ) ;
for ( const FAnimBlueprintFunction & AnimBlueprintFunction : AnimClassInterface - > GetAnimBlueprintFunctions ( ) )
2021-05-24 06:55:32 -04:00
{
2022-01-18 00:02:46 -05:00
if ( AnimBlueprintFunction . Name ! = UEdGraphSchema_K2 : : GN_AnimGraph )
2021-05-24 06:55:32 -04:00
{
2022-01-18 00:02:46 -05:00
if ( UFunction * Function = TargetClass - > FindFunctionByName ( AnimBlueprintFunction . Name ) )
2021-05-24 06:55:32 -04:00
{
2022-01-18 00:02:46 -05:00
if ( UBlueprintNodeSpawner * NodeSpawner = MakeAnimBlueprintAction ( GetClass ( ) , AnimBlueprintFunction . Name ) )
{
ActionRegistrar . AddBlueprintAction ( Function , NodeSpawner ) ;
}
}
}
}
}
else
{
// Accept 'self' layers
IAnimClassInterface * AnimClassInterface = IAnimClassInterface : : GetFromClass ( TargetClass ) ;
for ( const FAnimBlueprintFunction & AnimBlueprintFunction : AnimClassInterface - > GetAnimBlueprintFunctions ( ) )
{
if ( AnimBlueprintFunction . Name ! = UEdGraphSchema_K2 : : GN_AnimGraph )
{
const bool bIsSelfLayer = [ TargetAnimBlueprint , & AnimBlueprintFunction ] ( )
{
for ( const FBPInterfaceDescription & InterfaceDesc : TargetAnimBlueprint - > ImplementedInterfaces )
{
for ( UEdGraph * InterfaceGraph : InterfaceDesc . Graphs )
{
if ( InterfaceGraph - > GetFName ( ) = = AnimBlueprintFunction . Name )
{
return false ;
}
}
}
return true ;
} ( ) ;
if ( bIsSelfLayer )
{
if ( UFunction * Function = TargetClass - > FindFunctionByName ( AnimBlueprintFunction . Name ) )
{
if ( UBlueprintNodeSpawner * NodeSpawner = MakeAnimBlueprintAction ( GetClass ( ) , AnimBlueprintFunction . Name ) )
{
ActionRegistrar . AddBlueprintAction ( Function , NodeSpawner ) ;
}
}
2021-05-24 06:55:32 -04:00
}
}
}
}
}
}
}
}
2022-01-18 00:02:46 -05:00
bool UAnimGraphNode_LinkedAnimLayer : : IsActionFilteredOut ( class FBlueprintActionFilter const & Filter )
{
bool bIsFilteredOut = false ;
FBlueprintActionContext const & FilterContext = Filter . Context ;
for ( UBlueprint * Blueprint : FilterContext . Blueprints )
{
if ( UAnimBlueprint * AnimBlueprint = Cast < UAnimBlueprint > ( Blueprint ) )
{
if ( UClass * TargetClass = * AnimBlueprint - > SkeletonGeneratedClass )
{
// Accept only functions contained in this BP
bool bImplemented = false ;
IAnimClassInterface * AnimClassInterface = IAnimClassInterface : : GetFromClass ( TargetClass ) ;
for ( const FAnimBlueprintFunction & AnimBlueprintFunction : AnimClassInterface - > GetAnimBlueprintFunctions ( ) )
{
2022-09-29 20:38:46 -04:00
if ( GetLayerName ( ) = = AnimBlueprintFunction . Name )
2022-01-18 00:02:46 -05:00
{
bImplemented = true ;
break ;
}
}
if ( ! bImplemented )
{
bIsFilteredOut = true ;
}
}
}
}
return bIsFilteredOut ;
}
2022-08-24 14:14:53 -04:00
FAnimNode_LinkedAnimGraph * UAnimGraphNode_LinkedAnimLayer : : GetLinkedAnimGraphNode ( )
{
FAnimNode_LinkedAnimLayer * const RuntimeLinkedAnimGraphNode = GetDebuggedAnimNode < FAnimNode_LinkedAnimLayer > ( ) ;
return RuntimeLinkedAnimGraphNode ? RuntimeLinkedAnimGraphNode : & Node ;
}
const FAnimNode_LinkedAnimGraph * UAnimGraphNode_LinkedAnimLayer : : GetLinkedAnimGraphNode ( ) const
{
const FAnimNode_LinkedAnimGraph * const RuntimeLinkedAnimGraphNode = GetDebuggedAnimNode < FAnimNode_LinkedAnimLayer > ( ) ;
return RuntimeLinkedAnimGraphNode ? RuntimeLinkedAnimGraphNode : & Node ;
}
2022-09-29 20:38:46 -04:00
void UAnimGraphNode_LinkedAnimLayer : : HandleFunctionReferenceChanged ( FName InNewName )
{
Node . Layer = InNewName ;
ensure ( FunctionReference . GetMemberName ( ) = = Node . Layer ) ;
}
2022-08-24 14:14:53 -04:00
2019-05-22 12:00:20 -04:00
# undef LOCTEXT_NAMESPACE