// ©2023 Batty Bovine Productions, LLC. All Rights Reserved. #include "ComboActionGraphEditorUtilities.h" #include "ComboActionGraph.h" #include "K2Node_Event.h" #include "Ed/AssetEditor_ComboActionGraph.h" #include "Ed/EdComboActionGraph.h" #include "Ed/EdComboActionGraphNode.h" #include "Kismet2/BlueprintEditorUtils.h" #include "Kismet2/KismetEditorUtilities.h" #include "Kismet2/SClassPickerDialog.h" #include "Layout/AssetEditorTabs.h" bool FComboActionGraphEditorUtilities::PickChildrenOfClass(const FText &TitleText, UClass *&OutChosenClass, UClass *Class) { // Create filter TSharedPtr Filter = MakeShareable(new FComboActionClassViewerFilter); Filter->AllowedChildrenOfClasses.Add(Class); // Fill in options FClassViewerInitializationOptions Options; Options.Mode = EClassViewerMode::ClassPicker; Options.bShowUnloadedBlueprints = true; Options.ClassFilters.Add(Filter.ToSharedRef()); Options.DisplayMode = EClassViewerDisplayMode::TreeView; Options.bShowNoneOption = false; Options.InitiallySelectedClass = Class; Options.bExpandRootNodes = true; Options.NameTypeToDisplay = EClassViewerNameTypeToDisplay::DisplayName; return SClassPickerDialog::PickClass(TitleText, Options, OutChosenClass, Class); } bool FComboActionGraphEditorUtilities::OpenBlueprintEditor(UBlueprint *Blueprint, EComboActionBlueprintOpenType OpenType, FName FunctionNameToOpen, bool bForceFullEditor, bool bAddBlueprintFunctionIfItDoesNotExist) { if (!Blueprint) { return false; } Blueprint->bForceFullEditor = bForceFullEditor; // Find Function Graph UObject *ObjectToFocusOn = nullptr; if (OpenType != EComboActionBlueprintOpenType::None && FunctionNameToOpen != NAME_None) { UClass* Class = Blueprint->GeneratedClass; check(Class); if (OpenType == EComboActionBlueprintOpenType::Function) { ObjectToFocusOn = bAddBlueprintFunctionIfItDoesNotExist ? FComboActionGraphEditorUtilities::BlueprintGetOrAddFunction(Blueprint, FunctionNameToOpen, Class) : FComboActionGraphEditorUtilities::BlueprintGetFunction(Blueprint, FunctionNameToOpen, Class); } else if (OpenType == EComboActionBlueprintOpenType::Event) { ObjectToFocusOn = bAddBlueprintFunctionIfItDoesNotExist ? FComboActionGraphEditorUtilities::BlueprintGetOrAddEvent(Blueprint, FunctionNameToOpen, Class) : FComboActionGraphEditorUtilities::BlueprintGetEvent(Blueprint, FunctionNameToOpen, Class); } } // Default to the last uber graph if (ObjectToFocusOn == nullptr) { ObjectToFocusOn = Blueprint->GetLastEditedUberGraph(); } if (ObjectToFocusOn) { FKismetEditorUtilities::BringKismetToFocusAttentionOnObject(ObjectToFocusOn); return true; } return FComboActionGraphEditorUtilities::OpenEditorForAsset(Blueprint); } UEdGraph *FComboActionGraphEditorUtilities::BlueprintGetOrAddFunction(UBlueprint *Blueprint, FName FunctionName, UClass *FunctionClassSignature) { if (!Blueprint || Blueprint->BlueprintType != BPTYPE_Normal) { return nullptr; } // Find existing function if (UEdGraph *GraphFunction = BlueprintGetFunction(Blueprint, FunctionName, FunctionClassSignature)) { return GraphFunction; } // Create a new function UEdGraph *NewGraph = FBlueprintEditorUtils::CreateNewGraph(Blueprint, FunctionName, UEdGraph::StaticClass(), UEdGraphSchema_K2::StaticClass()); FBlueprintEditorUtils::AddFunctionGraph(Blueprint, NewGraph, /*bIsUserCreated=*/ false, FunctionClassSignature); Blueprint->LastEditedDocuments.Add(NewGraph); return NewGraph; } UEdGraph *FComboActionGraphEditorUtilities::BlueprintGetFunction(UBlueprint *Blueprint, FName FunctionName, UClass *FunctionClassSignature) { if (!Blueprint || Blueprint->BlueprintType != BPTYPE_Normal) { return nullptr; } // Find existing function for (UEdGraph *GraphFunction : Blueprint->FunctionGraphs) { if (FunctionName == GraphFunction->GetFName()) { return GraphFunction; } } // Find in the implemented Interfaces Graphs for (const FBPInterfaceDescription &Interface : Blueprint->ImplementedInterfaces) { for (UEdGraph *GraphFunction : Interface.Graphs) { if (FunctionName == GraphFunction->GetFName()) { return GraphFunction; } } } return nullptr; } UK2Node_Event *FComboActionGraphEditorUtilities::BlueprintGetOrAddEvent(UBlueprint *Blueprint, FName EventName, UClass *EventClassSignature) { if (!Blueprint || Blueprint->BlueprintType != EBlueprintType::BPTYPE_Normal) { return nullptr; } // Find existing event if (UK2Node_Event *EventNode = FComboActionGraphEditorUtilities::BlueprintGetEvent(Blueprint, EventName, EventClassSignature)) { return EventNode; } // Create a New Event if (Blueprint->UbergraphPages.Num()) { int32 NodePositionY = 0; UK2Node_Event* NodeEvent = FKismetEditorUtilities::AddDefaultEventNode( Blueprint, Blueprint->UbergraphPages[0], EventName, EventClassSignature, NodePositionY ); NodeEvent->SetEnabledState(ENodeEnabledState::Enabled); NodeEvent->NodeComment = ""; NodeEvent->bCommentBubbleVisible = false; return NodeEvent; } return nullptr; } UK2Node_Event *FComboActionGraphEditorUtilities::BlueprintGetEvent(UBlueprint *Blueprint, FName EventName, UClass *EventClassSignature) { if (!Blueprint || Blueprint->BlueprintType != EBlueprintType::BPTYPE_Normal) { return nullptr; } TArray AllEvents; FBlueprintEditorUtils::GetAllNodesOfClass(Blueprint, AllEvents); for (UK2Node_Event *EventNode : AllEvents) { if (EventNode->bOverrideFunction && EventNode->EventReference.GetMemberName() == EventName) { return EventNode; } } return nullptr; } bool FComboActionGraphEditorUtilities::OpenEditorForAsset(const UObject* Asset) { if (!IsValid(Asset) || !GEditor) { return false; } return GEditor->GetEditorSubsystem()->OpenEditorForAsset(const_cast(Asset)); } bool FComboActionGraphEditorUtilities::OpenEditorAndJumpToGraphNode(TWeakPtr DialogueEditorPtr, const UEdGraphNode *GraphNode, bool bFocusIfOpen) { if (!IsValid(GraphNode)) { return false; } if (!DialogueEditorPtr.IsValid()) { return false; } // Open if not already. UComboActionGraph *Dialogue = FComboActionGraphEditorUtilities::GetActionFromGraphNode(GraphNode); if (!FComboActionGraphEditorUtilities::OpenEditorForAsset(Dialogue)) { return false; } // Could still fail focus on the graph node if (IAssetEditorInstance *EditorInstance = FindEditorForAsset(Dialogue, bFocusIfOpen)) { EditorInstance->FocusWindow(const_cast(GraphNode)); UEdComboActionGraph *GraphEditor = Cast(Dialogue->EdGraph); if (GraphEditor) { TSet SelectedNodes; SelectedNodes.Add(GraphNode); GraphEditor->SelectNodeSet(SelectedNodes); DialogueEditorPtr.Pin()->JumpToNode(GraphNode); } return true; } return false; } UComboActionGraph *FComboActionGraphEditorUtilities::GetActionFromGraphNode(const UEdGraphNode *GraphNode) { if (const UEdComboActionGraphNode *ComboActionBaseNode = Cast(GraphNode)) { return ComboActionBaseNode->GetEdComboActionGraph()->GetComboActionGraph(); } if (const UEdComboActionGraph *ComboActionGraph = Cast(GraphNode->GetGraph())) { return Cast(ComboActionGraph->GetComboActionGraph()); } return nullptr; } IAssetEditorInstance *FComboActionGraphEditorUtilities::FindEditorForAsset(UObject* Asset, bool bFocusIfOpen) { if (!IsValid(Asset) || !GEditor) { return nullptr; } return GEditor->GetEditorSubsystem()->FindEditorForAsset(Asset, bFocusIfOpen); }