Files
UnrealEngineUWP/Engine/Source/Editor/AnimGraph/Private/AnimBlueprintExtension.cpp
thomas sarkanen d708b24c66 Anim node references
Added the abiity to tag and retrieve any anim graph node (similar to how we could reference linked anim graph nodes previously).
Ported linked anim graph nodes to use the new system
Added the ability to reference any anim graph node by tag (via a new custom node, spawnable from the context menu, with the appearance of an actor reference in a level blueprint)
Added tag display and editing in the bottom-right of anim graph nodes
Added new override point to SGraphNodeK2Var to allow for title widget parameters to be overriden by child classes

#jira UE-126286 - Anim node functions: Add anim node references
#rb Jurre.deBaare

#ROBOMERGE-AUTHOR: thomas.sarkanen
#ROBOMERGE-SOURCE: CL 17472894 in //UE5/Main/...
#ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v870-17433530)

[CL 17472913 by thomas sarkanen in ue5-release-engine-test branch]
2021-09-09 11:42:21 -04:00

291 lines
9.7 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "AnimBlueprintExtension.h"
#include "Animation/AnimSubsystem.h"
#include "Animation/AnimSubsystemInstance.h"
#include "IAnimBlueprintCopyTermDefaultsContext.h"
#include "Animation/AnimBlueprint.h"
#include "Templates/SubclassOf.h"
#include "AnimBlueprintExtension_Base.h"
#include "AnimBlueprintExtension_Attributes.h"
#include "AnimBlueprintExtension_PropertyAccess.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "AnimBlueprintExtension_NodeRelevancy.h"
#include "AnimBlueprintExtension_Tag.h"
// Set used to refresh extensions. Checks that an extension has a reference from an anim node for each refresh.
static TSet<TSubclassOf<UAnimBlueprintExtension>> RefreshSet;
static bool GIsRefreshingExtensions = false;
UAnimBlueprintExtension* UAnimBlueprintExtension::RequestExtension(UAnimBlueprint* InAnimBlueprint, TSubclassOf<UAnimBlueprintExtension> InExtensionType)
{
// Do not use RequestExtension when a blueprint is being compiled. Extensions should be consistent throughout all compilation stages.
check(!InAnimBlueprint->bBeingCompiled);
if(GIsRefreshingExtensions)
{
RefreshSet.Add(InExtensionType);
}
// Look for an existing extension
if(UAnimBlueprintExtension* ExistingExtension = GetExtension(InAnimBlueprint, InExtensionType))
{
return ExistingExtension;
}
// Not found, create one
UAnimBlueprintExtension* NewExtension = NewObject<UAnimBlueprintExtension>(InAnimBlueprint, InExtensionType.Get());
InAnimBlueprint->Extensions.Add(NewExtension);
return NewExtension;
}
UAnimBlueprintExtension* UAnimBlueprintExtension::GetExtension(UAnimBlueprint* InAnimBlueprint, TSubclassOf<UAnimBlueprintExtension> InExtensionType)
{
// Look for an existing extension
for(UBlueprintExtension* Extension : InAnimBlueprint->Extensions)
{
if(Extension && Extension->GetClass() == InExtensionType)
{
return CastChecked<UAnimBlueprintExtension>(Extension);
}
}
return nullptr;
}
TArray<UAnimBlueprintExtension*> UAnimBlueprintExtension::GetExtensions(UAnimBlueprint* InAnimBlueprint)
{
TArray<UAnimBlueprintExtension*> Extensions;
for(UBlueprintExtension* Extension : InAnimBlueprint->Extensions)
{
if(Extension && Extension->GetClass()->IsChildOf(UAnimBlueprintExtension::StaticClass()))
{
Extensions.Add(CastChecked<UAnimBlueprintExtension>(Extension));
}
}
return Extensions;
}
void UAnimBlueprintExtension::RequestExtensionsForNode(UAnimGraphNode_Base* InAnimGraphNode)
{
if(UAnimBlueprint* AnimBlueprint = InAnimGraphNode->GetAnimBlueprint())
{
TArray<TSubclassOf<UAnimBlueprintExtension>> ExtensionClasses =
{
UAnimBlueprintExtension_Base::StaticClass(),
UAnimBlueprintExtension_Attributes::StaticClass(),
UAnimBlueprintExtension_PropertyAccess::StaticClass()
};
if(InAnimGraphNode->InitialUpdateFunction.ResolveMember<UFunction>(InAnimGraphNode->GetBlueprintClassFromNode()) != nullptr ||
InAnimGraphNode->BecomeRelevantFunction.ResolveMember<UFunction>(InAnimGraphNode->GetBlueprintClassFromNode()) != nullptr)
{
ExtensionClasses.Add(UAnimBlueprintExtension_NodeRelevancy::StaticClass());
}
if(InAnimGraphNode->Tag != NAME_None)
{
ExtensionClasses.Add(UAnimBlueprintExtension_Tag::StaticClass());
}
InAnimGraphNode->GetRequiredExtensions(ExtensionClasses);
for(const TSubclassOf<UAnimBlueprintExtension>& ExtensionClass : ExtensionClasses)
{
// Request any subsystem that we need to compile
RequestExtension(AnimBlueprint, ExtensionClass);
}
}
}
void UAnimBlueprintExtension::RefreshExtensions(UAnimBlueprint* InAnimBlueprint)
{
GIsRefreshingExtensions = true;
RefreshSet.Empty();
TArray<UAnimGraphNode_Base*> AllNodes;
FBlueprintEditorUtils::GetAllNodesOfClass<UAnimGraphNode_Base>(InAnimBlueprint, AllNodes);
for(UAnimGraphNode_Base* Node : AllNodes)
{
RequestExtensionsForNode(Node);
}
// Remove all extensions that are no longer needed
InAnimBlueprint->Extensions.RemoveAll([](UBlueprintExtension* InExtension)
{
if(UAnimBlueprintExtension* AnimBlueprintExtension = Cast<UAnimBlueprintExtension>(InExtension))
{
return !RefreshSet.Contains(AnimBlueprintExtension->GetClass());
}
return false;
});
RefreshSet.Empty();
GIsRefreshingExtensions = false;
}
void UAnimBlueprintExtension::ForEachExtension(UAnimBlueprint* InAnimBlueprint, TFunctionRef<void(UAnimBlueprintExtension*)> InFunction)
{
for (UBlueprintExtension* BlueprintExtension : InAnimBlueprint->Extensions)
{
if(UAnimBlueprintExtension* AnimBlueprintExtension = Cast<UAnimBlueprintExtension>(BlueprintExtension))
{
InFunction(AnimBlueprintExtension);
}
}
}
const UScriptStruct* UAnimBlueprintExtension::GetInstanceDataType() const
{
UScriptStruct* FoundStruct = FAnimSubsystemInstance::StaticStruct();
for (TFieldIterator<FProperty> PropIt(GetClass(), EFieldIteratorFlags::IncludeSuper); PropIt; ++PropIt)
{
if (FStructProperty* StructProp = CastField<FStructProperty>(*PropIt))
{
if (StructProp->Struct->IsChildOf(FAnimSubsystemInstance::StaticStruct()))
{
FoundStruct = StructProp->Struct;
break;
}
}
}
return FoundStruct;
}
const UScriptStruct* UAnimBlueprintExtension::GetClassDataType() const
{
UScriptStruct* FoundStruct = FAnimSubsystem::StaticStruct();
for (TFieldIterator<FProperty> PropIt(GetClass(), EFieldIteratorFlags::IncludeSuper); PropIt; ++PropIt)
{
if (FStructProperty* StructProp = CastField<FStructProperty>(*PropIt))
{
if (StructProp->Struct->IsChildOf(FAnimSubsystem::StaticStruct()))
{
FoundStruct = StructProp->Struct;
break;
}
}
}
return FoundStruct;
}
const FStructProperty* UAnimBlueprintExtension::GetInstanceDataProperty() const
{
for (TFieldIterator<FProperty> PropIt(GetClass(), EFieldIteratorFlags::IncludeSuper); PropIt; ++PropIt)
{
if (FStructProperty* StructProp = CastField<FStructProperty>(*PropIt))
{
if (StructProp->Struct->IsChildOf(FAnimSubsystemInstance::StaticStruct()))
{
return StructProp;
}
}
}
return nullptr;
}
const FStructProperty* UAnimBlueprintExtension::GetClassDataProperty() const
{
for (TFieldIterator<FProperty> PropIt(GetClass(), EFieldIteratorFlags::IncludeSuper); PropIt; ++PropIt)
{
if (FStructProperty* StructProp = CastField<FStructProperty>(*PropIt))
{
if (StructProp->Struct->IsChildOf(FAnimSubsystem::StaticStruct()))
{
return StructProp;
}
}
}
return nullptr;
}
UAnimBlueprint* UAnimBlueprintExtension::GetAnimBlueprint() const
{
return CastChecked<UAnimBlueprint>(GetOuter());
}
void* UAnimBlueprintExtension::GetClassDataInternal()
{
if(const FStructProperty* Property = GetClassDataProperty())
{
return Property->ContainerPtrToValuePtr<void>(this);
}
static FAnimSubsystem Default;
return &Default;
}
void* UAnimBlueprintExtension::GetInstanceDataInternal()
{
if(const FStructProperty* Property = GetInstanceDataProperty())
{
return Property->ContainerPtrToValuePtr<void>(this);
}
static FAnimSubsystemInstance Default;
return &Default;
}
void UAnimBlueprintExtension::BeginCompilation(IAnimBlueprintCompilerCreationContext& InCreationContext)
{
HandleBeginCompilation(InCreationContext);
}
void UAnimBlueprintExtension::StartCompilingClass(const UClass* InClass, IAnimBlueprintCompilationBracketContext& InCompilationContext, IAnimBlueprintGeneratedClassCompiledData& OutCompiledData)
{
HandleStartCompilingClass(InClass, InCompilationContext, OutCompiledData);
}
void UAnimBlueprintExtension::PreProcessAnimationNodes(TArrayView<UAnimGraphNode_Base*> InAnimNodes, IAnimBlueprintCompilationContext& InCompilationContext, IAnimBlueprintGeneratedClassCompiledData& OutCompiledData)
{
HandlePreProcessAnimationNodes(InAnimNodes, InCompilationContext, OutCompiledData);
}
void UAnimBlueprintExtension::PostProcessAnimationNodes(TArrayView<UAnimGraphNode_Base*> InAnimNodes, IAnimBlueprintCompilationContext& InCompilationContext, IAnimBlueprintGeneratedClassCompiledData& OutCompiledData)
{
HandlePostProcessAnimationNodes(InAnimNodes, InCompilationContext, OutCompiledData);
}
void UAnimBlueprintExtension::FinishCompilingClass(const UClass* InClass, IAnimBlueprintCompilationBracketContext& InCompilationContext, IAnimBlueprintGeneratedClassCompiledData& OutCompiledData)
{
HandleFinishCompilingClass(InClass, InCompilationContext, OutCompiledData);
}
void UAnimBlueprintExtension::PostExpansionStep(const UEdGraph* InGraph, IAnimBlueprintPostExpansionStepContext& InCompilationContext, IAnimBlueprintGeneratedClassCompiledData& OutCompiledData)
{
HandlePostExpansionStep(InGraph, InCompilationContext, OutCompiledData);
}
void UAnimBlueprintExtension::CopyTermDefaultsToDefaultObject(UObject* InDefaultObject, IAnimBlueprintCopyTermDefaultsContext& InCompilationContext, IAnimBlueprintExtensionCopyTermDefaultsContext& InPerExtensionContext)
{
if(InPerExtensionContext.GetTargetProperty() && InPerExtensionContext.GetDestinationPtr() && InPerExtensionContext.GetSourcePtr())
{
InPerExtensionContext.GetTargetProperty()->CopyCompleteValue(InPerExtensionContext.GetDestinationPtr(), InPerExtensionContext.GetSourcePtr());
}
HandleCopyTermDefaultsToDefaultObject(InDefaultObject, InCompilationContext, InPerExtensionContext);
}
void UAnimBlueprintExtension::CopyTermDefaultsToSparseClassData(IAnimBlueprintCopyTermDefaultsContext& InCompilationContext, IAnimBlueprintExtensionCopyTermDefaultsContext& InPerExtensionContext)
{
if(InPerExtensionContext.GetTargetProperty() && InPerExtensionContext.GetDestinationPtr() && InPerExtensionContext.GetSourcePtr())
{
InPerExtensionContext.GetTargetProperty()->CopyCompleteValue(InPerExtensionContext.GetDestinationPtr(), InPerExtensionContext.GetSourcePtr());
}
HandleCopyTermDefaultsToSparseClassData(InCompilationContext, InPerExtensionContext);
}
void UAnimBlueprintExtension::EndCompilation()
{
HandleEndCompilation();
}