// Copyright Epic Games, Inc. All Rights Reserved. #include "AnimGraphNode_AssetPlayerBase.h" #include "EdGraphSchema_K2.h" #include "Animation/AnimComposite.h" #include "Animation/BlendSpaceBase.h" #include "Animation/AimOffsetBlendSpace.h" #include "Animation/AimOffsetBlendSpace1D.h" #include "AnimGraphNode_SequencePlayer.h" #include "AnimGraphNode_SequenceEvaluator.h" #include "AnimGraphNode_RotationOffsetBlendSpace.h" #include "AnimGraphNode_BlendSpacePlayer.h" #include "AnimGraphNode_BlendSpaceEvaluator.h" #include "Animation/PoseAsset.h" #include "AnimGraphNode_PoseBlendNode.h" #include "AnimGraphNode_PoseByName.h" #include "AnimGraphNode_PoseDriver.h" #include "UObject/UObjectIterator.h" #include "Animation/AnimLayerInterface.h" #include "IAnimBlueprintCompilerHandlerCollection.h" #include "AnimBlueprintCompilerHandler_Base.h" #include "IAnimBlueprintGeneratedClassCompiledData.h" #include "IAnimBlueprintCompilationContext.h" #include "Animation/AnimSync.h" #include "Animation/AnimAttributes.h" #include "UObject/UE5MainStreamObjectVersion.h" #define LOCTEXT_NAMESPACE "UAnimGraphNode_AssetPlayerBase" void UAnimGraphNode_AssetPlayerBase::Serialize(FArchive& Ar) { Super::Serialize(Ar); Ar.UsingCustomVersion(FUE5MainStreamObjectVersion::GUID); if(Ar.CustomVer(FUE5MainStreamObjectVersion::GUID) < FUE5MainStreamObjectVersion::AnimSyncGroupsExplicitSyncMethod) { if(SyncGroup.GroupName != NAME_None) { SyncGroup.Method = EAnimSyncMethod::SyncGroup; } } } void UAnimGraphNode_AssetPlayerBase::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) { Super::PostEditChangeProperty(PropertyChangedEvent); if(PropertyChangedEvent.GetPropertyName() == GET_MEMBER_NAME_CHECKED(FAnimationGroupReference, Method)) { if(SyncGroup.Method != EAnimSyncMethod::SyncGroup) { SyncGroup.GroupName = NAME_None; SyncGroup.GroupRole = EAnimGroupRole::CanBeLeader; } } } void UAnimGraphNode_AssetPlayerBase::PinConnectionListChanged(UEdGraphPin* Pin) { Super::PinConnectionListChanged(Pin); if (Pin->PinType.PinCategory == UEdGraphSchema_K2::PC_Object) { // recache visualization now an asset pin's connection is changed if (const UEdGraphSchema* Schema = GetSchema()) { Schema->ForceVisualizationCacheClear(); } } } void UAnimGraphNode_AssetPlayerBase::PinDefaultValueChanged(UEdGraphPin* Pin) { Super::PinDefaultValueChanged(Pin); if (Pin->PinType.PinCategory == UEdGraphSchema_K2::PC_Object) { // recache visualization now an asset pin's default value has changed if (const UEdGraphSchema* Schema = GetSchema()) { Schema->ForceVisualizationCacheClear(); } } } void UAnimGraphNode_AssetPlayerBase::OnProcessDuringCompilation(IAnimBlueprintCompilationContext& InCompilationContext, IAnimBlueprintGeneratedClassCompiledData& OutCompiledData) { UBlueprint* Blueprint = GetBlueprint(); // Process Asset Player nodes to, if necessary cache off their node index for retrieval at runtime (used for evaluating Automatic Rule Transitions when using Layer nodes) auto ProcessGraph = [this, &OutCompiledData](UEdGraph* Graph) { // Make sure we do not process the default AnimGraph static const FName DefaultAnimGraphName("AnimGraph"); if (Graph->GetFName() != DefaultAnimGraphName) { FString GraphName = Graph->GetName(); // Also make sure we do not process any empty stub graphs if (!GraphName.Contains(ANIM_FUNC_DECORATOR)) { if (Graph->Nodes.ContainsByPredicate([this, &OutCompiledData](UEdGraphNode* Node) { return Node->NodeGuid == NodeGuid; })) { if (int32* IndexPtr = OutCompiledData.GetAnimBlueprintDebugData().NodeGuidToIndexMap.Find(NodeGuid)) { FGraphAssetPlayerInformation& Info = OutCompiledData.GetGraphAssetPlayerInformation().FindOrAdd(FName(*GraphName)); Info.PlayerNodeIndices.AddUnique(*IndexPtr); } } } } }; // Check for any definition of a layer graph for (UEdGraph* Graph : Blueprint->FunctionGraphs) { ProcessGraph(Graph); } // Check for any implemented AnimLayer interface graphs for (FBPInterfaceDescription& InterfaceDesc : Blueprint->ImplementedInterfaces) { // Only process Anim Layer interfaces if (InterfaceDesc.Interface->IsChildOf()) { for (UEdGraph* Graph : InterfaceDesc.Graphs) { ProcessGraph(Graph); } } } } void UAnimGraphNode_AssetPlayerBase::ValidateAnimNodeDuringCompilation(USkeleton* ForSkeleton, FCompilerResultsLog& MessageLog) { Super::ValidateAnimNodeDuringCompilation(ForSkeleton, MessageLog); if(SyncGroup.Method == EAnimSyncMethod::SyncGroup && SyncGroup.GroupName == NAME_None) { MessageLog.Error(*LOCTEXT("NoSyncGroupSupplied", "Node @@ is set to use sync groups, but no sync group has been supplied").ToString(), this); } } void UAnimGraphNode_AssetPlayerBase::GetOutputLinkAttributes(FNodeAttributeArray& OutAttributes) const { OutAttributes.Add(UE::Anim::FAttributes::Curves); OutAttributes.Add(UE::Anim::FAttributes::Attributes); if(SyncGroup.Method == EAnimSyncMethod::Graph) { OutAttributes.Add(UE::Anim::FAnimSync::Attribute); } } UClass* GetNodeClassForAsset(const UClass* AssetClass) { UClass* NodeClass = nullptr; // Iterate over all classes.. for (TObjectIterator ClassIt; ClassIt; ++ClassIt) { UClass *Class = *ClassIt; // Look for AnimGraphNode classes if (Class->IsChildOf(UAnimGraphNode_Base::StaticClass())) { // See if this node is the 'primary handler' for this asset type const UAnimGraphNode_Base* NodeCDO = Class->GetDefaultObject(); if (NodeCDO->SupportsAssetClass(AssetClass) == EAnimAssetHandlerType::PrimaryHandler) { NodeClass = Class; break; } } } return NodeClass; } bool SupportNodeClassForAsset(const UClass* AssetClass, UClass* NodeClass) { // Get node CDO const UAnimGraphNode_Base* NodeCDO = NodeClass->GetDefaultObject(); // See if this node supports this asset type (primary or not) return (NodeCDO->SupportsAssetClass(AssetClass) != EAnimAssetHandlerType::NotSupported); } #undef LOCTEXT_NAMESPACE