// ©2023 Batty Bovine Productions, LLC. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "ComboActionGraphSchema.generated.h" class FComboActionNodeVisitorCycleChecker { public: /** Check whether a loop in the graph would be caused by linking the passed-in nodes */ bool CheckForLoop(UEdGraphNode *StartNode, UEdGraphNode *EndNode) { VisitedNodes.Add(StartNode); if (!QuiCheckDirectConnections(StartNode, EndNode)) { return false; } return TraverseInputNodesToRoot(EndNode); } private: bool TraverseInputNodesToRoot(UEdGraphNode *Node) { VisitedNodes.Add(Node); for (int32 PinIndex = 0; PinIndex < Node->Pins.Num(); ++PinIndex) { UEdGraphPin *MyPin = Node->Pins[PinIndex]; if (MyPin->Direction == EGPD_Output) { for (int32 LinkedPinIndex = 0; LinkedPinIndex < MyPin->LinkedTo.Num(); ++LinkedPinIndex) { UEdGraphPin *OtherPin = MyPin->LinkedTo[LinkedPinIndex]; if (OtherPin) { UEdGraphNode *OtherNode = OtherPin->GetOwningNode(); if (VisitedNodes.Contains(OtherNode)) { return false; } else { return TraverseInputNodesToRoot(OtherNode); } } } } } return true; } bool QuiCheckDirectConnections(UEdGraphNode *A, UEdGraphNode *B) { for (auto Itr : B->Pins) { if (A->Pins.Contains(Itr)) { return false; } } for (auto Itr : A->Pins) { if (B->Pins.Contains(Itr)) { return false; } } return true; } TSet VisitedNodes; }; /** Action to add a node to the graph */ USTRUCT() struct FAssetSchemaAction_ComboActionGraphSchema_NewNode : public FEdGraphSchemaAction { GENERATED_BODY(); public: FAssetSchemaAction_ComboActionGraphSchema_NewNode() : NodeTemplate(nullptr){} FAssetSchemaAction_ComboActionGraphSchema_NewNode(const FText &InNodeCategory, const FText &InMenuDesc, const FText &InToolTip, const int32 InGrouping) : FEdGraphSchemaAction(InNodeCategory, InMenuDesc, InToolTip, InGrouping), NodeTemplate(nullptr){} virtual UEdGraphNode *PerformAction(class UEdGraph *ParentGraph, UEdGraphPin *FromPin, const FVector2D Location, bool bSelectNewNode = true) override; virtual void AddReferencedObjects(FReferenceCollector &Collector) override; class UEdComboActionGraphNode *NodeTemplate; }; USTRUCT() struct FAssetSchemaAction_ComboActionGraphSchema_NewEdge : public FEdGraphSchemaAction { GENERATED_BODY(); public: FAssetSchemaAction_ComboActionGraphSchema_NewEdge() : NodeTemplate(nullptr) {} FAssetSchemaAction_ComboActionGraphSchema_NewEdge(const FText &InNodeCategory, const FText &InMenuDesc, const FText &InToolTip, const int32 InGrouping) : FEdGraphSchemaAction(InNodeCategory, InMenuDesc, InToolTip, InGrouping), NodeTemplate(nullptr) {} virtual UEdGraphNode *PerformAction(class UEdGraph *ParentGraph, UEdGraphPin *FromPin, const FVector2D Location, bool bSelectNewNode = true) override; virtual void AddReferencedObjects(FReferenceCollector &Collector) override; class UEdComboActionGraphEdge *NodeTemplate; }; UCLASS(MinimalAPI) class UComboActionGraphSchema : public UEdGraphSchema { GENERATED_BODY() public: void GetBreakLinkToSubMenuActions(class UToolMenu* Menu, class UEdGraphPin* InGraphPin); virtual EGraphType GetGraphType(const UEdGraph* TestEdGraph) const override { return EGraphType::GT_StateMachine; } virtual void GetGraphContextActions(FGraphContextMenuBuilder& ContextMenuBuilder) const override; virtual void GetContextMenuActions(class UToolMenu* Menu, class UGraphNodeContextMenuContext* Context) const override; virtual const FPinConnectionResponse CanCreateConnection(const UEdGraphPin* A, const UEdGraphPin* B) const override; virtual bool CreateAutomaticConversionNodeAndConnections(UEdGraphPin* A, UEdGraphPin* B) const override; virtual class FConnectionDrawingPolicy* CreateConnectionDrawingPolicy(int32 InBackLayerID, int32 InFrontLayerID, float InZoomFactor, const FSlateRect& InClippingRect, class FSlateWindowElementList& InDrawElements, class UEdGraph* InGraphObj) const override; virtual FLinearColor GetPinTypeColor(const FEdGraphPinType& PinType) const override; virtual void BreakNodeLinks(UEdGraphNode& TargetNode) const override; virtual void BreakPinLinks(UEdGraphPin& TargetPin, bool bSendsNodeNotifcation) const override; virtual void BreakSinglePinLink(UEdGraphPin* SourcePin, UEdGraphPin* TargetPin) const override; virtual UEdGraphPin* DropPinOnNode(UEdGraphNode* InTargetNode, const FName& InSourcePinName, const FEdGraphPinType& InSourcePinType, EEdGraphPinDirection InSourcePinDirection) const override; virtual bool SupportsDropPinOnNode(UEdGraphNode* InTargetNode, const FEdGraphPinType& InSourcePinType, EEdGraphPinDirection InSourcePinDirection, FText& OutErrorMessage) const override; virtual bool IsCacheVisualizationOutOfDate(int32 InVisualizationCacheID) const override; virtual int32 GetCurrentVisualizationCacheID() const override; virtual void ForceVisualizationCacheClear() const override; virtual void CreateDefaultNodesForGraph(UEdGraph& Graph) const override; private: static int32 CurrentCacheRefreshID; };