// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "ControlRigBlueprint.h" #include "EdGraph/EdGraph.h" #include "Graph/ControlRigGraphNode.h" #include "Rigs/RigHierarchy.h" #include "Rigs/RigHierarchyController.h" #include "RigVMModel/RigVMGraph.h" #include "RigVMCore/RigVM.h" #include "ControlRigGraph.generated.h" class UControlRigBlueprint; class UControlRigGraphSchema; class UControlRig; class URigVMController; struct FRigCurveContainer; DECLARE_MULTICAST_DELEGATE_OneParam(FControlRigGraphNodeClicked, UControlRigGraphNode*); UCLASS() class CONTROLRIGDEVELOPER_API UControlRigGraph : public UEdGraph, public IRigVMEditorSideObject { GENERATED_BODY() public: UControlRigGraph(); /** IRigVMEditorSideObject interface */ virtual FRigVMClient* GetRigVMClient() const override; virtual FString GetRigVMNodePath() const override; virtual void HandleRigVMGraphRenamed(const FString& InOldNodePath, const FString& InNewNodePath) override; /** Set up this graph */ void Initialize(UControlRigBlueprint* InBlueprint); /** Get the skeleton graph schema */ const UControlRigGraphSchema* GetControlRigGraphSchema(); #if WITH_EDITORONLY_DATA /** Customize blueprint changes based on backwards compatibility */ virtual void Serialize(FArchive& Ar) override; #endif #if WITH_EDITOR const TArray>* GetBoneNameList(URigVMPin* InPin = nullptr) const { return GetElementNameList(ERigElementType::Bone); } const TArray>* GetControlNameList(URigVMPin* InPin = nullptr) const { return GetElementNameList(ERigElementType::Control); } const TArray>* GetControlNameListWithoutAnimationChannels(URigVMPin* InPin = nullptr) const { return &ControlNameListWithoutAnimationChannels; } const TArray>* GetNullNameList(URigVMPin* InPin = nullptr) const { return GetElementNameList(ERigElementType::Null); } const TArray>* GetCurveNameList(URigVMPin* InPin = nullptr) const { return GetElementNameList(ERigElementType::Curve); } void CacheNameLists(URigHierarchy* InHierarchy, const FRigVMDrawContainer* DrawContainer, TArray> ShapeLibraries); const TArray>* GetElementNameList(ERigElementType InElementType = ERigElementType::Bone) const; const TArray>* GetElementNameList(URigVMPin* InPin = nullptr) const; const TArray> GetSelectedElementsNameList() const; const TArray>* GetDrawingNameList(URigVMPin* InPin = nullptr) const; const TArray>* GetEntryNameList(URigVMPin* InPin = nullptr) const; const TArray>* GetShapeNameList(URigVMPin* InPin = nullptr) const; bool bSuspendModelNotifications; bool bIsTemporaryGraphForCopyPaste; UEdGraphNode* FindNodeForModelNodeName(const FName& InModelNodeName, const bool bCacheIfRequired = true); UControlRigBlueprint* GetBlueprint() const; URigVMGraph* GetModel() const; URigVMController* GetController() const; bool IsRootGraph() const { return GetRootGraph() == this; } const UControlRigGraph* GetRootGraph() const; void HandleModifiedEvent(ERigVMGraphNotifType InNotifType, URigVMGraph* InGraph, UObject* InSubject); void ConsumeQueuedNotifications(); int32 GetInstructionIndex(const UControlRigGraphNode* InNode, bool bAsInput); UPROPERTY() FString ModelNodePath; UPROPERTY() bool bIsFunctionDefinition; private: template static bool IncludeElementInNameList(const T* InElement) { return true; } template void CacheNameListForHierarchy(URigHierarchy* InHierarchy, TArray>& OutNameList, bool bFilter = true) { TArray Names; for (auto Element : *InHierarchy) { if(Element->IsA()) { if(!bFilter || IncludeElementInNameList(Cast(Element))) { Names.Add(Element->GetName().ToString()); } } } Names.Sort(); OutNameList.Reset(); OutNameList.Add(MakeShared(FName(NAME_None).ToString())); for (const FString& Name : Names) { OutNameList.Add(MakeShared(Name)); } } template void CacheNameList(const T& ElementList, TArray>& OutNameList) { TArray Names; for (auto Element : ElementList) { Names.Add(Element.Name.ToString()); } Names.Sort(); OutNameList.Reset(); OutNameList.Add(MakeShared(FName(NAME_None).ToString())); for (const FString& Name : Names) { OutNameList.Add(MakeShared(Name)); } } TMap>> ElementNameLists; TArray> ControlNameListWithoutAnimationChannels; TArray> DrawingNameList; TArray> EntryNameList; TArray> ShapeNameList; int32 LastHierarchyTopologyVersion; bool bIsSelecting; FControlRigGraphNodeClicked OnGraphNodeClicked; TMap> CachedInstructionIndices; void RemoveNode(UEdGraphNode* InNode); #endif #if WITH_EDITORONLY_DATA UPROPERTY(transient) TObjectPtr TemplateController; #endif #if WITH_EDITOR URigVMController* GetTemplateController(); protected: void HandleVMCompiledEvent(UObject* InCompiledObject, URigVM* InVM); private: static TArray> EmptyElementNameList; TMap ModelNodePathToEdNode; mutable TWeakObjectPtr CachedModelGraph; friend class UControlRigUnitNodeSpawner; friend class UControlRigVariableNodeSpawner; friend class UControlRigParameterNodeSpawner; friend class UControlRigRerouteNodeSpawner; friend class UControlRigBranchNodeSpawner; friend class UControlRigIfNodeSpawner; friend class UControlRigSelectNodeSpawner; friend class UControlRigTemplateNodeSpawner; friend class UControlRigEnumNodeSpawner; friend class UControlRigFunctionRefNodeSpawner; friend class UControlRigArrayNodeSpawner; friend class UControlRigInvokeEntryNodeSpawner; #endif friend class UControlRigGraphNode; friend class FControlRigEditor; friend class SControlRigGraphNode; friend class UControlRigBlueprint; }; template<> inline bool UControlRigGraph::IncludeElementInNameList(const FRigControlElement* InElement) { return !InElement->IsAnimationChannel(); }