├── .gitignore ├── ComboGraph.uplugin ├── LICENSE-MIT ├── README.md ├── Resources ├── Documentation │ ├── ComboGraphExample1.png │ └── ComboGraphExample2.png ├── Icon.png └── Icon128.png └── Source ├── ComboGraphEditor ├── ComboGraphEditor.Build.cs ├── Private │ ├── AssetEditorToolbar_ComboGraph.cpp │ ├── AssetEditor_ComboGraph.cpp │ ├── AssetSchemaActions │ │ ├── AssetSchemaAction_ComboGraph_NewEdge.cpp │ │ └── AssetSchemaAction_ComboGraph_NewNode.cpp │ ├── AssetTypeActions_ComboGraph.cpp │ ├── ComboGraphEditorStyle.cpp │ ├── ComboGraphEditorSummoner.cpp │ ├── ComboGraphModule.cpp │ ├── DragDropActions │ │ └── ComboEditorDragDropAction.cpp │ ├── DrawingPolicy │ │ └── ComboGraphConnectionDrawingPolicy.cpp │ ├── EdGraphSchema_ComboGraph.cpp │ ├── EdGraph_ComboGraph.cpp │ ├── EdNode_ComboGraphEdge.cpp │ ├── EdNode_ComboGraphNode.cpp │ ├── EditorCommands_ComboGraph.cpp │ ├── Factories │ │ ├── ComboGraphFactory.cpp │ │ └── GraphPanelNodeFactory_ComboGraph.cpp │ ├── Pins │ │ └── ComboGraphPin.cpp │ ├── SEdNode_ComboGraphEdge.cpp │ ├── SEdNode_ComboGraphNode.cpp │ └── Validators │ │ └── ComboGraphAssetValidator.cpp └── Public │ ├── AssetEditorToolbar_ComboGraph.h │ ├── AssetEditor_ComboGraph.h │ ├── AssetSchemaActions │ ├── AssetSchemaAction_ComboGraph_NewEdge.h │ └── AssetSchemaAction_ComboGraph_NewNode.h │ ├── AssetTypeActions_ComboGraph.h │ ├── ComboGraphEditorStyle.h │ ├── ComboGraphEditorSummoner.h │ ├── ComboGraphModule.h │ ├── DragDropActions │ └── ComboEditorDragDropAction.h │ ├── DrawingPolicy │ └── ComboGraphConnectionDrawingPolicy.h │ ├── EdGraphSchema_ComboGraph.h │ ├── EdGraph_ComboGraph.h │ ├── EdNode_ComboGraphEdge.h │ ├── EdNode_ComboGraphNode.h │ ├── EditorCommands_ComboGraph.h │ ├── Factories │ ├── ComboGraphFactory.h │ └── GraphPanelNodeFactory_ComboGraph.h │ ├── Pins │ └── ComboGraphPin.h │ ├── SEdNode_ComboGraphEdge.h │ ├── SEdNode_ComboGraphNode.h │ └── Validators │ └── ComboGraphAssetValidator.h └── ComboGraphRuntime ├── ComboGraphRuntime.Build.cs ├── Private ├── Animations │ └── NotifyStates │ │ └── CanContinueComboNotifyState.cpp ├── ComboGraph.cpp ├── ComboGraphEdge.cpp ├── ComboGraphRuntime.cpp ├── ComboGraphRuntimeLog.cpp ├── Components │ └── ComboHandlerComponent.cpp └── Nodes │ ├── ComboGraphEnderNode.cpp │ ├── ComboGraphMidlerNode.cpp │ ├── ComboGraphNode.cpp │ └── ComboGraphOpenerNode.cpp └── Public ├── Animations └── NotifyStates │ └── CanContinueComboNotifyState.h ├── ComboGraph.h ├── ComboGraphEdge.h ├── ComboGraphRuntime.h ├── ComboGraphRuntimeLog.h ├── Components └── ComboHandlerComponent.h ├── Interfaces └── ComboHandlerInterface.h └── Nodes ├── ComboGraphEnderNode.h ├── ComboGraphMidlerNode.h ├── ComboGraphNode.h ├── ComboGraphOpenerNode.h └── ComboNodeType.h /.gitignore: -------------------------------------------------------------------------------- 1 | Binaries 2 | DerivedDataCache 3 | Intermediate 4 | Saved 5 | Build 6 | *.sdf 7 | *.sln 8 | *.suo 9 | *.opensdf 10 | *.opendb 11 | *.db 12 | /docs/sphinx-build-result 13 | /.vs 14 | /.idea -------------------------------------------------------------------------------- /ComboGraph.uplugin: -------------------------------------------------------------------------------- 1 | { 2 | "FileVersion": 3, 3 | "Version": 1, 4 | "VersionName": "0.1", 5 | "FriendlyName": "ComboGraph", 6 | "Description": "Create combos with graph-based nodes", 7 | "Category": "Other", 8 | "CreatedBy": "apokrif6", 9 | "CreatedByURL": "https://apokrif6.github.io/", 10 | "DocsURL": "", 11 | "MarketplaceURL": "", 12 | "SupportURL": "", 13 | "CanContainContent": true, 14 | "IsBetaVersion": false, 15 | "IsExperimentalVersion": false, 16 | "Installed": false, 17 | "Modules": [ 18 | { 19 | "Name": "ComboGraphRuntime", 20 | "Type": "Runtime", 21 | "LoadingPhase": "PreDefault" 22 | }, 23 | { 24 | "Name": "ComboGraphEditor", 25 | "Type": "Editor", 26 | "LoadingPhase": "PreDefault" 27 | } 28 | ] 29 | } -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Eugen Berencian 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ComboGraph 2 | 3 | The `ComboGraph` plugin which provides a system for defining and handling combo sequences in Unreal 4 | Engine. It brings new fully functional blueprint-based graph to create complex combo chains. 5 | 6 | Main idea is not creating new production-ready solution, but rather to provide core functionality for developers who 7 | wants to build their own system. 8 | 9 | --- 10 | 11 | ## 🌟 Features 12 | 13 | - Define combo sequences using nodes in a blueprint-based graph. 14 | - Handle input actions to trigger combos. 15 | - Play animations for each combo step. 16 | - Support for different types of combo nodes (Opener, Midler, Ender). 17 | 18 | ## 🚀 Installation 19 | 20 | - Clone or download the `ComboGraph` plugin into your project's `Plugins` directory. 21 | - Open your project in Unreal Engine. 22 | - Enable the `ComboGraph` plugin in the Plugins window. 23 | 24 | ## ⚔️ Usage 25 | 26 | How to properly setup system: 27 | 28 | - Create a new `ComboGraph` and define your combo sequences with nodes. 29 | - Every node should have set `InputAction` and `ComboMontage` properties. Montage also should have set `UCanContinueComboNotifyState` which will be window to continue combo. 30 | - Implement `IComboHandlerInterface` for your character. 31 | - Set the `ComboGraph` and `ComboInputMappingContext` properties on the `UComboHandlerComponent`. 32 | - Now you can try to use it. 33 | 34 | ## 📙 Examples 35 | 36 | Those are examples of combo sequences implemented with `ComboGraph` plugin 37 | 38 | ![ComboGraph Example 1](/Resources/Documentation/ComboGraphExample1.png) 39 | 40 | ![ComboGraph Example 2](/Resources/Documentation/ComboGraphExample2.png) 41 | 42 | ## 🎬 Showcase 43 | 44 | [![Showcase video](https://img.youtube.com/vi/tODbzmV0z-w/0.jpg)](https://youtu.be/tODbzmV0z-w) 45 | 46 | ## 📄 Technical Documentation 47 | 48 | ### Core 49 | 50 | Functionality is separated into two main modules: `ComboGraphEditor` and `ComboGraphRuntime`. 51 | 52 | First one is responsible for editor-related logic, like creating nodes and connections. 53 | It also handle basic commands, drag and drop, and other editor-related stuff. 54 | 55 | Second one is responsible for runtime logic, like handling input actions and playing animations. 56 | 57 | ### Combo Graph Node 58 | 59 | The `UComboGraphNode` class is the parent class for all combo sequence nodes. It includes properties for input actions, 60 | animations, and connections to other nodes. 61 | 62 | ### Combo Node Types 63 | 64 | Combo nodes are defined using the `EComboNodeType` enum: 65 | 66 | - `None`: No specific type. 67 | - `Opener`: The starting node of a combo. 68 | - `Midler`: A middle node in a combo sequence. 69 | - `Ender`: The ending node of a combo. 70 | 71 | By default, connection policy is predefined, but can be overriden with `UComboGraphEnderNode::CanCreateConnectionFrom` and `UComboGraphNode::CanCreateConnectionTo` 72 | 73 | ### Connection Policy Table 74 | 75 | | **Node Type** | **Can Connect From** | **Can Connect To** | 76 | |---------------|----------------------------------|--------------------------------| 77 | | **Opener** | Can't be connected from anything | Midler | 78 | | **Midler** | Opener, Midler | Midler, Ender | 79 | | **Ender** | Midler | Can't be connected to anything | 80 | 81 | ### ComboHandlerComponent 82 | 83 | The `UComboHandlerComponent` class handles the logic for processing combo sequences. It binds input actions, finds 84 | suitable combo nodes, and plays animations. 85 | -------------------------------------------------------------------------------- /Resources/Documentation/ComboGraphExample1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apokrif6/ComboGraph/81b751c7d7ee293a363e86f38e42326221f1939c/Resources/Documentation/ComboGraphExample1.png -------------------------------------------------------------------------------- /Resources/Documentation/ComboGraphExample2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apokrif6/ComboGraph/81b751c7d7ee293a363e86f38e42326221f1939c/Resources/Documentation/ComboGraphExample2.png -------------------------------------------------------------------------------- /Resources/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apokrif6/ComboGraph/81b751c7d7ee293a363e86f38e42326221f1939c/Resources/Icon.png -------------------------------------------------------------------------------- /Resources/Icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apokrif6/ComboGraph/81b751c7d7ee293a363e86f38e42326221f1939c/Resources/Icon128.png -------------------------------------------------------------------------------- /Source/ComboGraphEditor/ComboGraphEditor.Build.cs: -------------------------------------------------------------------------------- 1 | // Copyright Epic Games, Inc. All Rights Reserved. 2 | 3 | using UnrealBuildTool; 4 | 5 | public class ComboGraphEditor : ModuleRules 6 | { 7 | public ComboGraphEditor(ReadOnlyTargetRules Target) : base(Target) 8 | { 9 | PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; 10 | 11 | PublicIncludePaths.AddRange( 12 | new string[] 13 | { 14 | } 15 | ); 16 | 17 | 18 | PrivateIncludePaths.AddRange( 19 | new string[] 20 | { 21 | "ComboGraphEditor/Private", 22 | "ComboGraphEditor/Public" 23 | } 24 | ); 25 | 26 | 27 | PublicDependencyModuleNames.AddRange( 28 | new string[] 29 | { 30 | "Core", "Kismet", "EditorStyle", "AssetTools", "GraphEditor", "ToolMenus", "Core", "CoreUObject", 31 | "Engine", "UnrealEd", "DataValidation" 32 | } 33 | ); 34 | 35 | 36 | PrivateDependencyModuleNames.AddRange( 37 | new string[] 38 | { 39 | "ComboGraphRuntime", 40 | "Slate", 41 | "SlateCore", 42 | "InputCore", 43 | "LevelEditor" 44 | } 45 | ); 46 | 47 | 48 | DynamicallyLoadedModuleNames.AddRange( 49 | new string[] 50 | { 51 | } 52 | ); 53 | } 54 | } -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Private/AssetEditorToolbar_ComboGraph.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #include "AssetEditorToolbar_ComboGraph.h" 4 | 5 | #include "AssetEditor_ComboGraph.h" 6 | 7 | #define LOCTEXT_NAMESPACE "AssetEditorToolbar_ComboGraph" 8 | 9 | void FAssetEditorToolbar_ComboGraph::AddComboGraphToolbar(TSharedPtr Extender) 10 | { 11 | check(ComboGraphEditor.IsValid()); 12 | const TSharedPtr ComboGraphEditorPtr = ComboGraphEditor.Pin(); 13 | 14 | const TSharedPtr ToolbarExtender = MakeShareable(new FExtender); 15 | ToolbarExtender->AddToolBarExtension("Asset", EExtensionHook::After, ComboGraphEditorPtr->GetToolkitCommands(), 16 | FToolBarExtensionDelegate::CreateSP( 17 | this, &FAssetEditorToolbar_ComboGraph::FillComboGraphToolbar)); 18 | ComboGraphEditorPtr->AddToolbarExtender(ToolbarExtender); 19 | } 20 | 21 | void FAssetEditorToolbar_ComboGraph::FillComboGraphToolbar(FToolBarBuilder& ToolbarBuilder) const 22 | { 23 | check(ComboGraphEditor.IsValid()); 24 | } 25 | 26 | #undef LOCTEXT_NAMESPACE 27 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Private/AssetEditor_ComboGraph.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | 4 | #include "AssetEditor_ComboGraph.h" 5 | 6 | #include "AssetEditorToolbar_ComboGraph.h" 7 | #include "ComboGraph.h" 8 | #include "EdGraphSchema_ComboGraph.h" 9 | #include "EdGraph_ComboGraph.h" 10 | #include "EditorCommands_ComboGraph.h" 11 | #include "EditorValidatorHelpers.h" 12 | #include "EditorValidatorSubsystem.h" 13 | #include "EdNode_ComboGraphNode.h" 14 | #include "GraphEditorActions.h" 15 | #include "AssetRegistry/IAssetRegistry.h" 16 | #include "Framework/Commands/GenericCommands.h" 17 | #include "Kismet2/BlueprintEditorUtils.h" 18 | #include "UObject/ObjectSaveContext.h" 19 | 20 | #define LOCTEXT_NAMESPACE "ComboGraphEditor" 21 | 22 | struct FComboGraphAssetEditorTabs 23 | { 24 | static const FName ViewportID; 25 | static const FName ComboGraphPropertyID; 26 | }; 27 | 28 | const FName FComboGraphAssetEditorTabs::ViewportID(TEXT("Viewport")); 29 | const FName FComboGraphAssetEditorTabs::ComboGraphPropertyID(TEXT("ComboGraphProperty")); 30 | 31 | FAssetEditor_ComboGraph::FAssetEditor_ComboGraph() 32 | : EditingComboGraph(nullptr) 33 | { 34 | if (UEditorEngine* Editor = Cast(GEngine)) 35 | Editor->RegisterForUndo(this); 36 | 37 | OnPackageSavedDelegateHandle = UPackage::PackageSavedWithContextEvent.AddRaw( 38 | this, &FAssetEditor_ComboGraph::OnPackageSaved); 39 | } 40 | 41 | FAssetEditor_ComboGraph::~FAssetEditor_ComboGraph() 42 | { 43 | if (UEditorEngine* Editor = Cast(GEngine)) 44 | Editor->UnregisterForUndo(this); 45 | 46 | UPackage::PackageSavedWithContextEvent.Remove(OnPackageSavedDelegateHandle); 47 | } 48 | 49 | void FAssetEditor_ComboGraph::InitComboGraphEditor(const EToolkitMode::Type Mode, 50 | const TSharedPtr& InitToolkitHost, 51 | UComboGraph* ComboGraph) 52 | { 53 | EditingComboGraph = ComboGraph; 54 | CreateNewGraph(); 55 | 56 | FGenericCommands::Register(); 57 | FGraphEditorCommands::Register(); 58 | FEditorCommands_ComboGraph::Register(); 59 | 60 | if (!ToolbarBuilder.IsValid()) 61 | { 62 | ToolbarBuilder = MakeShareable(new FAssetEditorToolbar_ComboGraph(SharedThis(this))); 63 | } 64 | 65 | CreateInternalWidgets(); 66 | 67 | const TSharedPtr ToolbarExtender = MakeShareable(new FExtender); 68 | 69 | ToolbarBuilder->AddComboGraphToolbar(ToolbarExtender); 70 | 71 | const TSharedRef StandaloneDefaultLayout = FTabManager::NewLayout( 72 | "Standalone_ComboGraphEditor_Layout") 73 | ->AddArea 74 | ( 75 | FTabManager::NewPrimaryArea()->SetOrientation(Orient_Vertical) 76 | ->Split 77 | ( 78 | FTabManager::NewSplitter() 79 | ->SetOrientation(Orient_Horizontal)->SetSizeCoefficient(0.9f) 80 | ->Split 81 | ( 82 | FTabManager::NewStack() 83 | ->SetSizeCoefficient(0.65f) 84 | ->AddTab(FComboGraphAssetEditorTabs::ViewportID, 85 | ETabState::OpenedTab)-> 86 | SetHideTabWell(true) 87 | ) 88 | ->Split 89 | ( 90 | FTabManager::NewSplitter()->SetOrientation(Orient_Vertical) 91 | ->Split 92 | ( 93 | FTabManager::NewStack() 94 | ->SetSizeCoefficient(0.7f) 95 | ->AddTab( 96 | TEXT("ComboGraphProperty"), 97 | ETabState::OpenedTab)-> 98 | SetHideTabWell( 99 | true) 100 | ) 101 | ) 102 | ) 103 | ); 104 | 105 | constexpr bool bCreateDefaultStandaloneMenu = true; 106 | constexpr bool bCreateDefaultToolbar = true; 107 | InitAssetEditor(Mode, InitToolkitHost, TEXT("ComboGraphEditorApp"), StandaloneDefaultLayout, 108 | bCreateDefaultStandaloneMenu, bCreateDefaultToolbar, EditingComboGraph, false); 109 | 110 | RegenerateMenusAndToolbars(); 111 | 112 | EditingComboGraph->EdGraph->GetSchema()->ForceVisualizationCacheClear(); 113 | } 114 | 115 | TSharedRef FAssetEditor_ComboGraph::CreateGraphEditorWidget(UEdGraph* InGraph) 116 | { 117 | SGraphEditor::FGraphEditorEvents InEvents; 118 | InEvents.OnSelectionChanged = SGraphEditor::FOnSelectionChanged::CreateSP( 119 | this, &FAssetEditor_ComboGraph::OnSelectedNodesChanged); 120 | InEvents.OnNodeDoubleClicked = FSingleNodeEvent::CreateSP(this, &FAssetEditor_ComboGraph::OnNodeDoubleClicked); 121 | InEvents.OnTextCommitted = FOnNodeTextCommitted::CreateSP(this, &FAssetEditor_ComboGraph::OnNodeTitleCommitted); 122 | 123 | CreateEditorCommands(); 124 | 125 | const TSharedRef TitleBarWidget = 126 | SNew(SBorder) 127 | .BorderImage(FAppStyle::GetBrush(TEXT("Graph.TitleBackground"))) 128 | .HAlign(HAlign_Fill) 129 | [ 130 | SNew(SHorizontalBox) 131 | + SHorizontalBox::Slot() 132 | .HAlign(HAlign_Center) 133 | .FillWidth(1.f) 134 | [ 135 | SNew(STextBlock) 136 | .Text(LOCTEXT("ComboGraphLabel", "Combo Graph")) 137 | .TextStyle(FAppStyle::Get(), TEXT("GraphBreadcrumbButtonText")) 138 | ] 139 | ]; 140 | 141 | return SNew(SGraphEditor) 142 | .AdditionalCommands(GraphEditorCommands) 143 | .IsEditable(true) 144 | .Appearance(this, &FAssetEditor_ComboGraph::GetGraphAppearance) 145 | .TitleBar(TitleBarWidget) 146 | .GraphToEdit(InGraph) 147 | .GraphEvents(InEvents) 148 | .AutoExpandActionMenu(true) 149 | .ShowGraphStateOverlay(false); 150 | } 151 | 152 | void FAssetEditor_ComboGraph::OnSelectedNodesChanged(const TSet& Objects) const 153 | { 154 | TArray Selection; 155 | 156 | for (UObject* SelectionEntry : Objects) 157 | { 158 | Selection.Add(SelectionEntry); 159 | } 160 | 161 | Selection.IsEmpty() ? PropertyWidget->SetObject(EditingComboGraph) : PropertyWidget->SetObjects(Selection); 162 | } 163 | 164 | void FAssetEditor_ComboGraph::OnNodeDoubleClicked(UEdGraphNode* EdGraphNode) const 165 | { 166 | } 167 | 168 | void FAssetEditor_ComboGraph::OnNodeTitleCommitted(const FText& Text, ETextCommit::Type Arg, 169 | UEdGraphNode* EdGraphNode) const 170 | { 171 | } 172 | 173 | bool FAssetEditor_ComboGraph::InEditingMode(bool bGraphIsEditable) const 174 | { 175 | return bGraphIsEditable; 176 | } 177 | 178 | FGraphAppearanceInfo FAssetEditor_ComboGraph::GetGraphAppearance() const 179 | { 180 | FGraphAppearanceInfo AppearanceInfo; 181 | AppearanceInfo.CornerText = LOCTEXT("AppearanceCornerText", "COMBO GRAPH"); 182 | 183 | return AppearanceInfo; 184 | } 185 | 186 | FString FAssetEditor_ComboGraph::GetReferencerName() const 187 | { 188 | return TEXT("FAssetEditor_LTComboGraph"); 189 | } 190 | 191 | FName FAssetEditor_ComboGraph::GetToolkitFName() const 192 | { 193 | return FName("FComboGraphEditor"); 194 | } 195 | 196 | FText FAssetEditor_ComboGraph::GetBaseToolkitName() const 197 | { 198 | return LOCTEXT("ComboGraphEditorAppLabel", "Combo Graph Editor"); 199 | } 200 | 201 | FLinearColor FAssetEditor_ComboGraph::GetWorldCentricTabColorScale() const 202 | { 203 | return FColor::Purple; 204 | } 205 | 206 | FString FAssetEditor_ComboGraph::GetWorldCentricTabPrefix() const 207 | { 208 | return TEXT("ComboGraphEditor"); 209 | } 210 | 211 | void FAssetEditor_ComboGraph::OnPackageSaved(const FString& PackageFileName, UPackage* Outer, 212 | FObjectPostSaveContext SavedContext) const 213 | { 214 | RebuildComboGraph(); 215 | } 216 | 217 | void FAssetEditor_ComboGraph::SaveAsset_Execute() 218 | { 219 | if (EditingComboGraph) 220 | { 221 | RebuildComboGraph(); 222 | } 223 | 224 | FAssetEditorToolkit::SaveAsset_Execute(); 225 | } 226 | 227 | void FAssetEditor_ComboGraph::AddReferencedObjects(FReferenceCollector& Collector) 228 | { 229 | Collector.AddReferencedObject(EditingComboGraph); 230 | Collector.AddReferencedObject(EditingComboGraph->EdGraph); 231 | } 232 | 233 | void FAssetEditor_ComboGraph::CreateNewGraph() const 234 | { 235 | if (!EditingComboGraph->EdGraph) 236 | { 237 | EditingComboGraph->EdGraph = CastChecked(FBlueprintEditorUtils::CreateNewGraph( 238 | EditingComboGraph, NAME_None, UEdGraph_ComboGraph::StaticClass(), 239 | UEdGraphSchema_ComboGraph::StaticClass())); 240 | EditingComboGraph->EdGraph->bAllowDeletion = false; 241 | 242 | const UEdGraphSchema* Schema = EditingComboGraph->EdGraph->GetSchema(); 243 | Schema->CreateDefaultNodesForGraph(*EditingComboGraph->EdGraph); 244 | } 245 | } 246 | 247 | void FAssetEditor_ComboGraph::CreateInternalWidgets() 248 | { 249 | ViewportWidget = CreateGraphEditorWidget(EditingComboGraph->EdGraph); 250 | 251 | FDetailsViewArgs Args; 252 | Args.bHideSelectionTip = true; 253 | 254 | FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked("PropertyEditor"); 255 | PropertyWidget = PropertyModule.CreateDetailView(Args); 256 | PropertyWidget->SetObject(EditingComboGraph); 257 | PropertyWidget->OnFinishedChangingProperties(). 258 | AddSP(this, &FAssetEditor_ComboGraph::OnFinishedChangingProperties); 259 | } 260 | 261 | void FAssetEditor_ComboGraph::OnFinishedChangingProperties(const FPropertyChangedEvent& PropertyChangedEvent) 262 | { 263 | if (EditingComboGraph == nullptr) 264 | return; 265 | 266 | FARFilter Filter; 267 | Filter.PackageNames = {FName(*EditingComboGraph->GetPackage()->GetName())}; 268 | Filter.bIncludeOnlyOnDiskAssets = false; 269 | 270 | const IAssetRegistry& AssetRegistry = IAssetRegistry::GetChecked(); 271 | 272 | TArray Assets; 273 | AssetRegistry.GetAssets(Filter, Assets); 274 | 275 | FValidateAssetsSettings Settings; 276 | Settings.bSkipExcludedDirectories = true; 277 | Settings.bShowIfNoFailures = false; 278 | Settings.ValidationUsecase = EDataValidationUsecase::Save; 279 | Settings.bLoadAssetsForValidation = false; 280 | Settings.MessageLogPageTitle = LOCTEXT("DataValidation.ValidateOnSaveAssetComboGraph", "Validate Combo Graph"); 281 | 282 | FValidateAssetsResults Results; 283 | 284 | FMessageLog DataValidationLog(UE::DataValidation::MessageLogName); 285 | const FText SavedAsset = Assets.Num() == 1 286 | ? FText::FromName(Assets[0].AssetName) 287 | : LOCTEXT("MultipleErrors", "multiple assets"); 288 | DataValidationLog.NewPage( 289 | FText::Format(LOCTEXT("DataValidationLogPage", "Combo Graph Validation: {0}"), SavedAsset)); 290 | 291 | 292 | if (GEditor->GetEditorSubsystem()->ValidateAssetsWithSettings(Assets, Settings, Results) 293 | > 0) 294 | { 295 | const FText ErrorMessageNotification = FText::Format( 296 | LOCTEXT("ComboGraphValidationFailureNotification", 297 | "Combo Graph Validation failed when saving {0}, check log"), 298 | SavedAsset); 299 | DataValidationLog.Notify(ErrorMessageNotification, EMessageSeverity::Warning, true); 300 | 301 | return; 302 | } 303 | 304 | EditingComboGraph->EdGraph->GetSchema()->ForceVisualizationCacheClear(); 305 | } 306 | 307 | void FAssetEditor_ComboGraph::RegisterTabSpawners(const TSharedRef& InTabManager) 308 | { 309 | WorkspaceMenuCategory = InTabManager->AddLocalWorkspaceMenuCategory( 310 | LOCTEXT("WorkspaceMenu_ComboGraphEditor", "Combo Graph Editor")); 311 | const auto WorkspaceMenuCategoryRef = WorkspaceMenuCategory.ToSharedRef(); 312 | 313 | FAssetEditorToolkit::RegisterTabSpawners(InTabManager); 314 | 315 | InTabManager->RegisterTabSpawner(FComboGraphAssetEditorTabs::ViewportID, 316 | FOnSpawnTab::CreateSP(this, &FAssetEditor_ComboGraph::SpawnTab_Viewport)) 317 | .SetDisplayName(LOCTEXT("GraphCanvasTab", "Viewport")) 318 | .SetGroup(WorkspaceMenuCategoryRef) 319 | .SetIcon(FSlateIcon(FAppStyle::GetAppStyleSetName(), "GraphEditor.EventGraph_16x")); 320 | 321 | InTabManager->RegisterTabSpawner(FComboGraphAssetEditorTabs::ComboGraphPropertyID, 322 | FOnSpawnTab::CreateSP(this, &FAssetEditor_ComboGraph::SpawnTab_Details)) 323 | .SetDisplayName(LOCTEXT("DetailsTab", "Property")) 324 | .SetGroup(WorkspaceMenuCategoryRef) 325 | .SetIcon(FSlateIcon(FAppStyle::GetAppStyleSetName(), "LevelEditor.Tabs.Details")); 326 | } 327 | 328 | void FAssetEditor_ComboGraph::UnregisterTabSpawners(const TSharedRef& InTabManager) 329 | { 330 | FAssetEditorToolkit::UnregisterTabSpawners(InTabManager); 331 | 332 | InTabManager->UnregisterTabSpawner(FComboGraphAssetEditorTabs::ViewportID); 333 | InTabManager->UnregisterTabSpawner(FComboGraphAssetEditorTabs::ComboGraphPropertyID); 334 | } 335 | 336 | TSharedRef FAssetEditor_ComboGraph::SpawnTab_Viewport(const FSpawnTabArgs& Args) 337 | { 338 | check(Args.GetTabId() == FComboGraphAssetEditorTabs::ViewportID); 339 | 340 | TSharedRef SpawnedTab = SNew(SDockTab) 341 | .Label(LOCTEXT("ViewportTab_Title", "Viewport")); 342 | 343 | if (ViewportWidget.IsValid()) 344 | { 345 | SpawnedTab->SetContent(ViewportWidget.ToSharedRef()); 346 | } 347 | 348 | return SpawnedTab; 349 | } 350 | 351 | TSharedRef FAssetEditor_ComboGraph::SpawnTab_Details(const FSpawnTabArgs& Args) const 352 | { 353 | check(Args.GetTabId() == FComboGraphAssetEditorTabs::ComboGraphPropertyID); 354 | 355 | return SNew(SDockTab).Label(LOCTEXT("Details_Title", "Property"))[PropertyWidget.ToSharedRef()]; 356 | } 357 | 358 | void FAssetEditor_ComboGraph::CreateEditorCommands() 359 | { 360 | if (GraphEditorCommands.IsValid()) 361 | { 362 | return; 363 | } 364 | 365 | GraphEditorCommands = MakeShareable(new FUICommandList); 366 | 367 | GraphEditorCommands->MapAction(FGenericCommands::Get().Delete, 368 | FExecuteAction::CreateRaw(this, &FAssetEditor_ComboGraph::DeleteSelectedNodes), 369 | FCanExecuteAction::CreateRaw(this, &FAssetEditor_ComboGraph::CanDeleteNodes) 370 | ); 371 | 372 | GraphEditorCommands->MapAction(FGenericCommands::Get().Rename, 373 | FExecuteAction::CreateSP(this, &FAssetEditor_ComboGraph::RenameNode), 374 | FCanExecuteAction::CreateSP(this, &FAssetEditor_ComboGraph::CanRenameNode) 375 | ); 376 | } 377 | 378 | void FAssetEditor_ComboGraph::RebuildComboGraph() const 379 | { 380 | if (!EditingComboGraph) 381 | { 382 | UE_LOG(LogTemp, Warning, TEXT("Can't rebuild Combo Graph. EditingComboGraph is null")); 383 | return; 384 | } 385 | 386 | UEdGraph_ComboGraph* ComboGraph = Cast(EditingComboGraph->EdGraph); 387 | check(ComboGraph != nullptr); 388 | 389 | ComboGraph->RebuildComboGraph(); 390 | } 391 | 392 | FGraphPanelSelectionSet FAssetEditor_ComboGraph::GetSelectedNodes() const 393 | { 394 | FGraphPanelSelectionSet CurrentSelection; 395 | if (const TSharedPtr FocusedGraphEd = ViewportWidget; FocusedGraphEd.IsValid()) 396 | { 397 | CurrentSelection = FocusedGraphEd->GetSelectedNodes(); 398 | } 399 | 400 | return CurrentSelection; 401 | } 402 | 403 | void FAssetEditor_ComboGraph::DeleteSelectedNodes() 404 | { 405 | const TSharedPtr CurrentGraphEditor = ViewportWidget; 406 | if (!CurrentGraphEditor.IsValid()) return; 407 | 408 | const FScopedTransaction Transaction(FGenericCommands::Get().Delete->GetDescription()); 409 | 410 | CurrentGraphEditor->GetCurrentGraph()->Modify(); 411 | 412 | const FGraphPanelSelectionSet SelectedNodes = CurrentGraphEditor->GetSelectedNodes(); 413 | CurrentGraphEditor->ClearSelectionSet(); 414 | 415 | for (FGraphPanelSelectionSet::TConstIterator NodeIt(SelectedNodes); NodeIt; ++NodeIt) 416 | { 417 | UEdGraphNode* EdNode = Cast(*NodeIt); 418 | if (!EdNode || !EdNode->CanUserDeleteNode()) 419 | continue; 420 | 421 | if (UEdNode_ComboGraphNode* EdNode_Node = Cast(EdNode)) 422 | { 423 | EdNode_Node->Modify(); 424 | 425 | if (const UEdGraphSchema* Schema = EdNode_Node->GetSchema()) 426 | { 427 | Schema->BreakNodeLinks(*EdNode_Node); 428 | } 429 | 430 | EdNode_Node->DestroyNode(); 431 | } 432 | else 433 | { 434 | EdNode->Modify(); 435 | EdNode->DestroyNode(); 436 | } 437 | } 438 | } 439 | 440 | bool FAssetEditor_ComboGraph::CanDeleteNodes() const 441 | { 442 | const FGraphPanelSelectionSet SelectedNodes = GetSelectedNodes(); 443 | for (FGraphPanelSelectionSet::TConstIterator SelectedIter(SelectedNodes); SelectedIter; ++SelectedIter) 444 | { 445 | if (const UEdGraphNode* Node = Cast(*SelectedIter); 446 | Node && Node->CanUserDeleteNode()) 447 | { 448 | return true; 449 | } 450 | } 451 | 452 | return false; 453 | } 454 | 455 | void FAssetEditor_ComboGraph::RenameNode() 456 | { 457 | if (const TSharedPtr CurrentGraphEditor = ViewportWidget; 458 | CurrentGraphEditor.IsValid()) 459 | { 460 | const FGraphPanelSelectionSet SelectedNodes = GetSelectedNodes(); 461 | for (FGraphPanelSelectionSet::TConstIterator NodeIt(SelectedNodes); NodeIt; ++NodeIt) 462 | { 463 | if (const UEdGraphNode* SelectedNode = Cast(*NodeIt); 464 | SelectedNode && SelectedNode->bCanRenameNode) 465 | { 466 | CurrentGraphEditor->IsNodeTitleVisible(SelectedNode, true); 467 | break; 468 | } 469 | } 470 | } 471 | } 472 | 473 | bool FAssetEditor_ComboGraph::CanRenameNode() const 474 | { 475 | const UEdGraph_ComboGraph* EdGraph = Cast(EditingComboGraph->EdGraph); 476 | check(EdGraph); 477 | 478 | const UComboGraph* Graph = EdGraph->GetComboGraph(); 479 | check(Graph) 480 | 481 | return GetSelectedNodes().Num() == 1; 482 | } 483 | 484 | #undef LOCTEXT_NAMESPACE 485 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Private/AssetSchemaActions/AssetSchemaAction_ComboGraph_NewEdge.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | 4 | #include "AssetSchemaActions/AssetSchemaAction_ComboGraph_NewEdge.h" 5 | 6 | #include "ComboGraphEdge.h" 7 | #include "EdNode_ComboGraphEdge.h" 8 | 9 | #define LOCTEXT_NAMESPACE "AssetSchema_ComboGraph" 10 | 11 | UEdGraphNode* FAssetSchemaAction_ComboGraph_NewEdge::PerformAction(UEdGraph* ParentGraph, UEdGraphPin* FromPin, 12 | const FVector2D Location, bool bSelectNewNode) 13 | { 14 | UEdGraphNode* ResultNode = nullptr; 15 | 16 | if (NodeTemplate) 17 | { 18 | const FScopedTransaction Transaction(LOCTEXT("ComboGraphEditorNewEdge", "Combo Graph Editor: New Edge")); 19 | ParentGraph->Modify(); 20 | if (FromPin != nullptr) 21 | FromPin->Modify(); 22 | 23 | NodeTemplate->Rename(nullptr, ParentGraph); 24 | ParentGraph->AddNode(NodeTemplate, true, bSelectNewNode); 25 | 26 | NodeTemplate->CreateNewGuid(); 27 | NodeTemplate->PostPlacedNewNode(); 28 | NodeTemplate->AllocateDefaultPins(); 29 | NodeTemplate->AutowireNewNode(FromPin); 30 | 31 | NodeTemplate->NodePosX = Location.X; 32 | NodeTemplate->NodePosY = Location.Y; 33 | 34 | NodeTemplate->ComboGraphEdge->SetFlags(RF_Transactional); 35 | NodeTemplate->SetFlags(RF_Transactional); 36 | 37 | ResultNode = NodeTemplate; 38 | } 39 | 40 | return ResultNode; 41 | } 42 | 43 | void FAssetSchemaAction_ComboGraph_NewEdge::AddReferencedObjects(FReferenceCollector& Collector) 44 | { 45 | FEdGraphSchemaAction::AddReferencedObjects(Collector); 46 | Collector.AddReferencedObject(NodeTemplate); 47 | } 48 | 49 | #undef LOCTEXT_NAMESPACE 50 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Private/AssetSchemaActions/AssetSchemaAction_ComboGraph_NewNode.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #include "AssetSchemaActions/AssetSchemaAction_ComboGraph_NewNode.h" 4 | 5 | #include "Nodes/ComboGraphNode.h" 6 | #include "EdNode_ComboGraphNode.h" 7 | 8 | #define LOCTEXT_NAMESPACE "AssetSchema_ComboGraph" 9 | 10 | UEdGraphNode* FAssetSchemaAction_ComboGraph_NewNode::PerformAction(UEdGraph* ParentGraph, UEdGraphPin* FromPin, 11 | const FVector2D Location, bool bSelectNewNode) 12 | { 13 | UEdGraphNode* ResultNode = nullptr; 14 | 15 | if (NodeTemplate) 16 | { 17 | const FScopedTransaction Transaction(LOCTEXT("ComboGraphEditorNewNode", "Combo Graph Editor: New Node")); 18 | ParentGraph->Modify(); 19 | if (FromPin) 20 | { 21 | FromPin->Modify(); 22 | } 23 | 24 | NodeTemplate->Rename(nullptr, ParentGraph); 25 | ParentGraph->AddNode(NodeTemplate, true, bSelectNewNode); 26 | 27 | NodeTemplate->CreateNewGuid(); 28 | NodeTemplate->PostPlacedNewNode(); 29 | NodeTemplate->AllocateDefaultPins(); 30 | NodeTemplate->AutowireNewNode(FromPin); 31 | 32 | NodeTemplate->NodePosX = Location.X; 33 | NodeTemplate->NodePosY = Location.Y; 34 | 35 | NodeTemplate->ComboGraphNode->SetFlags(RF_Transactional); 36 | NodeTemplate->GetGraph()->SetFlags(RF_Transactional); 37 | NodeTemplate->SetFlags(RF_Transactional); 38 | 39 | ResultNode = NodeTemplate; 40 | } 41 | 42 | return ResultNode; 43 | } 44 | 45 | void FAssetSchemaAction_ComboGraph_NewNode::AddReferencedObjects(FReferenceCollector& Collector) 46 | { 47 | FEdGraphSchemaAction::AddReferencedObjects(Collector); 48 | Collector.AddReferencedObject(NodeTemplate); 49 | } 50 | 51 | #undef LOCTEXT_NAMESPACE 52 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Private/AssetTypeActions_ComboGraph.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | 4 | 5 | #include "AssetTypeActions_ComboGraph.h" 6 | 7 | #include "AssetEditor_ComboGraph.h" 8 | #include "ComboGraph.h" 9 | 10 | #define LOCTEXT_NAMESPACE "AssetTypeActions_ComboGraph" 11 | 12 | FAssetTypeActions_ComboGraph::FAssetTypeActions_ComboGraph(EAssetTypeCategories::Type InAssetCategory) : 13 | MyAssetCategory(InAssetCategory) 14 | { 15 | } 16 | 17 | FText FAssetTypeActions_ComboGraph::GetName() const 18 | { 19 | return LOCTEXT("FComboGraphAssetTypeActionsName", "Combo Graph"); 20 | } 21 | 22 | FColor FAssetTypeActions_ComboGraph::GetTypeColor() const 23 | { 24 | return FColor(147, 112, 219); 25 | } 26 | 27 | UClass* FAssetTypeActions_ComboGraph::GetSupportedClass() const 28 | { 29 | return UComboGraph::StaticClass(); 30 | } 31 | 32 | void FAssetTypeActions_ComboGraph::OpenAssetEditor(const TArray& InObjects, 33 | TSharedPtr EditWithinLevelEditor) 34 | { 35 | const EToolkitMode::Type Mode = EditWithinLevelEditor.IsValid() 36 | ? EToolkitMode::WorldCentric 37 | : EToolkitMode::Standalone; 38 | 39 | for (auto ObjIt = InObjects.CreateConstIterator(); ObjIt; ++ObjIt) 40 | { 41 | if (UComboGraph* Graph = Cast(*ObjIt)) 42 | { 43 | const TSharedRef NewGraphEditor(new FAssetEditor_ComboGraph()); 44 | NewGraphEditor->InitComboGraphEditor(Mode, EditWithinLevelEditor, Graph); 45 | } 46 | } 47 | } 48 | 49 | uint32 FAssetTypeActions_ComboGraph::GetCategories() 50 | { 51 | return MyAssetCategory; 52 | } 53 | 54 | #undef LOCTEXT_NAMESPACE 55 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Private/ComboGraphEditorStyle.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | 4 | #include "ComboGraphEditorStyle.h" 5 | 6 | #include "Styling/SlateStyle.h" 7 | #include "Styling/SlateStyleRegistry.h" 8 | 9 | TSharedPtr FComboGraphEditorStyle::StyleSet = nullptr; 10 | 11 | #define IMAGE_BRUSH( RelativePath, ... ) FSlateImageBrush( StyleSet->RootToContentDir( RelativePath, TEXT(".png") ), __VA_ARGS__ ) 12 | 13 | void FComboGraphEditorStyle::Initialize() 14 | { 15 | const FVector2D Icon64X64(64.f, 64.f); 16 | const FVector2D Icon16X16(16.0f, 16.0f); 17 | 18 | if (StyleSet.IsValid()) 19 | return; 20 | 21 | StyleSet = MakeShareable(new FSlateStyleSet("ComboGraphEditorStyle")); 22 | 23 | StyleSet->SetContentRoot(FPaths::ProjectPluginsDir() / TEXT("ComboGraph/Resources")); 24 | 25 | StyleSet->Set("ClassThumbnail.EdGraph_ComboGraph", new IMAGE_BRUSH(TEXT("Icon"), Icon64X64)); 26 | StyleSet->Set("ClassIcon.EdGraph_ComboGraph", new IMAGE_BRUSH(TEXT("Icon"), Icon16X16)); 27 | 28 | FSlateStyleRegistry::RegisterSlateStyle(*StyleSet.Get()); 29 | } 30 | 31 | void FComboGraphEditorStyle::Shutdown() 32 | { 33 | if (StyleSet.IsValid()) 34 | { 35 | FSlateStyleRegistry::UnRegisterSlateStyle(*StyleSet.Get()); 36 | ensure(StyleSet.IsUnique()); 37 | StyleSet.Reset(); 38 | } 39 | } 40 | 41 | const FName& FComboGraphEditorStyle::GetStyleSetName() 42 | { 43 | return StyleSet->GetStyleSetName(); 44 | } 45 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Private/ComboGraphEditorSummoner.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | 4 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Private/ComboGraphModule.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Epic Games, Inc. All Rights Reserved. 2 | 3 | #include "ComboGraphModule.h" 4 | 5 | #include "AssetToolsModule.h" 6 | #include "AssetTypeActions_ComboGraph.h" 7 | #include "ComboGraphEditorStyle.h" 8 | #include "IAssetTools.h" 9 | #include "Factories/GraphPanelNodeFactory_ComboGraph.h" 10 | 11 | #define LOCTEXT_NAMESPACE "FComboGraphModule" 12 | 13 | TSharedPtr GraphPanelNodeFactory_ComboGraph; 14 | 15 | void FComboGraphModule::StartupModule() 16 | { 17 | FComboGraphEditorStyle::Initialize(); 18 | 19 | GraphPanelNodeFactory_ComboGraph = MakeShareable(new FGraphPanelNodeFactory_ComboGraph()); 20 | FEdGraphUtilities::RegisterVisualNodeFactory(GraphPanelNodeFactory_ComboGraph); 21 | 22 | IAssetTools& AssetTools = FModuleManager::LoadModuleChecked("AssetTools").Get(); 23 | 24 | ComboGraphGraphAssetCategoryBit = AssetTools.RegisterAdvancedAssetCategory( 25 | FName(TEXT("ComboGraph")), LOCTEXT("ComboGraphAssetCategory", "ComboGraph")); 26 | 27 | RegisterAssetTypeAction( 28 | AssetTools, MakeShareable(new FAssetTypeActions_ComboGraph(ComboGraphGraphAssetCategoryBit))); 29 | } 30 | 31 | void FComboGraphModule::ShutdownModule() 32 | { 33 | FComboGraphEditorStyle::Shutdown(); 34 | 35 | if (FModuleManager::Get().IsModuleLoaded("AssetTools")) 36 | { 37 | IAssetTools& AssetTools = FModuleManager::GetModuleChecked("AssetTools").Get(); 38 | 39 | for (TSharedPtr CreatedAssetTypeAction : CreatedAssetTypeActions) 40 | { 41 | AssetTools.UnregisterAssetTypeActions(CreatedAssetTypeAction.ToSharedRef()); 42 | } 43 | } 44 | 45 | if (GraphPanelNodeFactory_ComboGraph.IsValid()) 46 | { 47 | FEdGraphUtilities::UnregisterVisualNodeFactory(GraphPanelNodeFactory_ComboGraph); 48 | GraphPanelNodeFactory_ComboGraph.Reset(); 49 | } 50 | } 51 | 52 | void FComboGraphModule::RegisterAssetTypeAction(IAssetTools& AssetTools, const TSharedRef& Action) 53 | { 54 | AssetTools.RegisterAssetTypeActions(Action); 55 | CreatedAssetTypeActions.Add(Action); 56 | } 57 | 58 | IMPLEMENT_MODULE(FComboGraphModule, ComboGraph) 59 | 60 | #undef LOCTEXT_NAMESPACE 61 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Private/DragDropActions/ComboEditorDragDropAction.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | 4 | #include "DragDropActions/ComboEditorDragDropAction.h" 5 | 6 | #include "EdNode_ComboGraphNode.h" 7 | #include "SGraphPanel.h" 8 | 9 | TSharedRef FComboEditorDragDropAction::New(const TSharedRef& InGraphPanel, 10 | const FDraggedPinTable& InStartingPins) 11 | { 12 | TSharedRef Operation = MakeShareable( 13 | new FComboEditorDragDropAction(InGraphPanel, InStartingPins)); 14 | Operation->Construct(); 15 | 16 | return Operation; 17 | } 18 | 19 | FComboEditorDragDropAction::FComboEditorDragDropAction(const TSharedRef& InGraphPanel, 20 | const FDraggedPinTable& InDraggedPins) 21 | { 22 | GraphPanel = InGraphPanel; 23 | DraggingPins = InDraggedPins; 24 | 25 | if (DraggingPins.Num() > 0) 26 | { 27 | if (const UEdGraphPin* PinObj = FDraggedPinTable::TConstIterator(DraggingPins)->GetPinObj(*GraphPanel); 28 | PinObj && PinObj->Direction == EGPD_Input) 29 | { 30 | DecoratorAdjust *= FVector2D(-1.0f, 1.0f); 31 | } 32 | } 33 | 34 | for (const FGraphPinHandle& DraggedPin : DraggingPins) 35 | { 36 | GraphPanel->OnBeginMakingConnection(DraggedPin); 37 | } 38 | } 39 | 40 | void FComboEditorDragDropAction::HoverTargetChanged() 41 | { 42 | TArray UniqueMessages; 43 | 44 | if (const UEdGraphPin* TargetPinObj = GetHoveredPin()) 45 | { 46 | TArray ValidSourcePins; 47 | ValidateGraphPinList(ValidSourcePins); 48 | 49 | for (const UEdGraphPin* StartingPin : ValidSourcePins) 50 | { 51 | if (TargetPinObj != StartingPin) 52 | { 53 | const UEdGraph* Graph = StartingPin->GetOwningNode()->GetGraph(); 54 | 55 | const FPinConnectionResponse Response = Graph->GetSchema()->CanCreateConnection( 56 | StartingPin, TargetPinObj); 57 | 58 | if (Response.Response == CONNECT_RESPONSE_DISALLOW) 59 | { 60 | TSharedPtr NodeWidget = TargetPinObj->GetOwningNode()->DEPRECATED_NodeWidget.Pin(); 61 | if (NodeWidget.IsValid()) 62 | { 63 | NodeWidget->NotifyDisallowedPinConnection(StartingPin, TargetPinObj); 64 | } 65 | } 66 | 67 | UniqueMessages.AddUnique(Response); 68 | } 69 | } 70 | } 71 | else if (const UEdNode_ComboGraphNode* TargetNodeObj = Cast(GetHoveredNode())) 72 | { 73 | TArray ValidSourcePins; 74 | ValidateGraphPinList(ValidSourcePins); 75 | 76 | for (const UEdGraphPin* StartingPin : ValidSourcePins) 77 | { 78 | FPinConnectionResponse Response; 79 | FText ResponseText; 80 | 81 | const UEdGraphSchema* Schema = StartingPin->GetSchema(); 82 | const UEdGraphPin* TargetPin = TargetNodeObj->GetInputPin(); 83 | 84 | if (Schema && TargetPin) 85 | { 86 | Response = Schema->CanCreateConnection(StartingPin, TargetPin); 87 | if (Response.Response == CONNECT_RESPONSE_DISALLOW) 88 | { 89 | TSharedPtr NodeWidget = TargetPin->GetOwningNode()->DEPRECATED_NodeWidget.Pin(); 90 | if (NodeWidget.IsValid()) 91 | { 92 | NodeWidget->NotifyDisallowedPinConnection(StartingPin, TargetPinObj); 93 | } 94 | } 95 | } 96 | else 97 | { 98 | #define LOCTEXT_NAMESPACE "AssetSchema_ComboGraph" 99 | Response = FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, 100 | LOCTEXT("PinError", "EdNode_ComboGraphNode is invalid")); 101 | #undef LOCTEXT_NAMESPACE 102 | } 103 | 104 | UniqueMessages.AddUnique(Response); 105 | } 106 | } 107 | else if (const UEdGraph* CurrentHoveredGraph = GetHoveredGraph()) 108 | { 109 | TArray ValidSourcePins; 110 | ValidateGraphPinList(ValidSourcePins); 111 | 112 | for (UEdGraphPin* StartingPinObj : ValidSourcePins) 113 | { 114 | FPinConnectionResponse Response = CurrentHoveredGraph->GetSchema()->CanCreateNewNodes(StartingPinObj); 115 | if (!Response.Message.IsEmpty()) 116 | { 117 | UniqueMessages.AddUnique(Response); 118 | } 119 | } 120 | } 121 | 122 | if (UniqueMessages.Num() == 0) 123 | { 124 | SetSimpleFeedbackMessage( 125 | FAppStyle::GetBrush(TEXT("Graph.ConnectorFeedback.NewNode")), 126 | FLinearColor::White, 127 | NSLOCTEXT("GraphEditor.Feedback", "PlaceNewNode", "Place a new node.")); 128 | } 129 | else 130 | { 131 | const TSharedRef FeedbackBox = SNew(SVerticalBox); 132 | for (auto ResponseIt = UniqueMessages.CreateConstIterator(); ResponseIt; ++ResponseIt) 133 | { 134 | const FSlateBrush* StatusSymbol = nullptr; 135 | 136 | switch (ResponseIt->Response) 137 | { 138 | case CONNECT_RESPONSE_MAKE: 139 | case CONNECT_RESPONSE_BREAK_OTHERS_A: 140 | case CONNECT_RESPONSE_BREAK_OTHERS_B: 141 | case CONNECT_RESPONSE_BREAK_OTHERS_AB: 142 | StatusSymbol = FAppStyle::GetBrush(TEXT("Graph.ConnectorFeedback.OK")); 143 | break; 144 | 145 | case CONNECT_RESPONSE_MAKE_WITH_CONVERSION_NODE: 146 | StatusSymbol = FAppStyle::GetBrush(TEXT("Graph.ConnectorFeedback.ViaCast")); 147 | break; 148 | 149 | case CONNECT_RESPONSE_DISALLOW: 150 | default: 151 | StatusSymbol = FAppStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error")); 152 | break; 153 | } 154 | 155 | FeedbackBox->AddSlot() 156 | .AutoHeight() 157 | [ 158 | SNew(SHorizontalBox) 159 | + SHorizontalBox::Slot() 160 | .AutoWidth() 161 | .Padding(3.0f) 162 | .VAlign(VAlign_Center) 163 | [ 164 | SNew(SImage).Image(StatusSymbol) 165 | ] 166 | + SHorizontalBox::Slot() 167 | .AutoWidth() 168 | .VAlign(VAlign_Center) 169 | [ 170 | SNew(STextBlock).Text(ResponseIt->Message) 171 | ] 172 | ]; 173 | } 174 | 175 | SetFeedbackMessage(FeedbackBox); 176 | } 177 | } 178 | 179 | void FComboEditorDragDropAction::OnDrop(bool bDropWasHandled, const FPointerEvent& MouseEvent) 180 | { 181 | GraphPanel->OnStopMakingConnection(); 182 | GraphPanel->OnEndRelinkConnection(); 183 | 184 | FGraphEditorDragDropAction::OnDrop(bDropWasHandled, MouseEvent); 185 | } 186 | 187 | void FComboEditorDragDropAction::OnDragged(const FDragDropEvent& DragDropEvent) 188 | { 189 | const FVector2D TargetPosition = DragDropEvent.GetScreenSpacePosition(); 190 | 191 | CursorDecoratorWindow->MoveWindowTo(DragDropEvent.GetScreenSpacePosition() + DecoratorAdjust); 192 | 193 | GraphPanel->RequestDeferredPan(TargetPosition); 194 | } 195 | 196 | FReply FComboEditorDragDropAction::DroppedOnPin(FVector2D ScreenPosition, FVector2D GraphPosition) 197 | { 198 | TArray ValidSourcePins; 199 | ValidateGraphPinList(ValidSourcePins); 200 | 201 | const FScopedTransaction Transaction(NSLOCTEXT("UnrealEd", "GraphEd_CreateConnection", "Create Pin Link")); 202 | 203 | UEdGraphPin* PinB = GetHoveredPin(); 204 | bool bError = false; 205 | TSet NodeList; 206 | 207 | for (UEdGraphPin* PinA : ValidSourcePins) 208 | { 209 | if (PinA && PinB) 210 | { 211 | if (const UEdGraph* MyGraphObj = PinA->GetOwningNode()->GetGraph(); 212 | MyGraphObj->GetSchema()->TryCreateConnection(PinA, PinB)) 213 | { 214 | if (!PinA->IsPendingKill()) 215 | { 216 | NodeList.Add(PinA->GetOwningNode()); 217 | } 218 | if (!PinB->IsPendingKill()) 219 | { 220 | NodeList.Add(PinB->GetOwningNode()); 221 | } 222 | } 223 | } 224 | else 225 | { 226 | bError = true; 227 | } 228 | } 229 | 230 | for (auto It = NodeList.CreateConstIterator(); It; ++It) 231 | { 232 | UEdGraphNode* Node = *It; 233 | Node->NodeConnectionListChanged(); 234 | } 235 | 236 | if (bError) 237 | { 238 | return FReply::Unhandled(); 239 | } 240 | 241 | return FReply::Handled(); 242 | } 243 | 244 | FReply FComboEditorDragDropAction::DroppedOnNode(FVector2D ScreenPosition, FVector2D GraphPosition) 245 | { 246 | bool bHandledPinDropOnNode = false; 247 | 248 | if (UEdGraphNode* NodeOver = GetHoveredNode()) 249 | { 250 | TArray ValidSourcePins; 251 | ValidateGraphPinList(ValidSourcePins); 252 | 253 | if (ValidSourcePins.Num()) 254 | { 255 | for (UEdGraphPin* SourcePin : ValidSourcePins) 256 | { 257 | FText ResponseText; 258 | if (SourcePin->GetOwningNode() != NodeOver && SourcePin->GetSchema()->SupportsDropPinOnNode( 259 | NodeOver, SourcePin->PinType, SourcePin->Direction, ResponseText)) 260 | { 261 | bHandledPinDropOnNode = true; 262 | 263 | const FName PinName = SourcePin->PinFriendlyName.IsEmpty() 264 | ? SourcePin->PinName 265 | : *SourcePin->PinFriendlyName.ToString(); 266 | 267 | const FScopedTransaction Transaction((SourcePin->Direction == EGPD_Output) 268 | ? NSLOCTEXT("UnrealEd", "AddInParam", "Add In Parameter") 269 | : NSLOCTEXT( 270 | "UnrealEd", "AddOutParam", "Add Out Parameter")); 271 | 272 | UEdGraphPin* EdGraphPin = NodeOver->GetSchema()->DropPinOnNode( 273 | GetHoveredNode(), PinName, SourcePin->PinType, SourcePin->Direction); 274 | 275 | if (SourcePin->GetOwningNodeUnchecked() && EdGraphPin) 276 | { 277 | SourcePin->Modify(); 278 | EdGraphPin->Modify(); 279 | SourcePin->GetSchema()->TryCreateConnection(SourcePin, EdGraphPin); 280 | } 281 | } 282 | 283 | if (!bHandledPinDropOnNode && !ResponseText.IsEmpty()) 284 | { 285 | bHandledPinDropOnNode = true; 286 | } 287 | } 288 | } 289 | } 290 | 291 | return bHandledPinDropOnNode ? FReply::Handled() : FReply::Unhandled(); 292 | } 293 | 294 | FReply FComboEditorDragDropAction::DroppedOnPanel(const TSharedRef& Panel, FVector2D ScreenPosition, 295 | FVector2D GraphPosition, UEdGraph& Graph) 296 | { 297 | TArray PinObjects; 298 | ValidateGraphPinList(PinObjects); 299 | 300 | const TSharedPtr WidgetToFocus = GraphPanel->SummonContextMenu( 301 | ScreenPosition, GraphPosition, nullptr, nullptr, PinObjects); 302 | 303 | return WidgetToFocus.IsValid() 304 | ? FReply::Handled().SetUserFocus(WidgetToFocus.ToSharedRef(), EFocusCause::SetDirectly) 305 | : FReply::Handled(); 306 | } 307 | 308 | void FComboEditorDragDropAction::ValidateGraphPinList(TArray& OutValidPins) 309 | { 310 | OutValidPins.Empty(DraggingPins.Num()); 311 | for (const FGraphPinHandle& PinHandle : DraggingPins) 312 | { 313 | if (UEdGraphPin* GraphPin = PinHandle.GetPinObj(*GraphPanel)) 314 | { 315 | OutValidPins.Add(GraphPin); 316 | } 317 | } 318 | } 319 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Private/DrawingPolicy/ComboGraphConnectionDrawingPolicy.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | 4 | #include "DrawingPolicy/ComboGraphConnectionDrawingPolicy.h" 5 | 6 | #include "EdNode_ComboGraphNode.h" 7 | #include "EdNode_ComboGraphEdge.h" 8 | 9 | FComboGraphConnectionDrawingPolicy::FComboGraphConnectionDrawingPolicy(int32 InBackLayerID, int32 InFrontLayerID, 10 | float ZoomFactor, 11 | const FSlateRect& InClippingRect, 12 | FSlateWindowElementList& InDrawElements, 13 | UEdGraph* InGraphObj) 14 | : FConnectionDrawingPolicy(InBackLayerID, InFrontLayerID, ZoomFactor, InClippingRect, InDrawElements), 15 | Graph(InGraphObj) 16 | { 17 | } 18 | 19 | void FComboGraphConnectionDrawingPolicy::DetermineWiringStyle(UEdGraphPin* OutputPin, UEdGraphPin* InputPin, 20 | FConnectionParams& Params) 21 | { 22 | Params.AssociatedPin1 = OutputPin; 23 | Params.AssociatedPin2 = InputPin; 24 | Params.WireThickness = 1.5f; 25 | 26 | if (HoveredPins.Num() > 0) 27 | { 28 | ApplyHoverDeemphasis(OutputPin, InputPin, Params.WireThickness, Params.WireColor); 29 | } 30 | } 31 | 32 | void FComboGraphConnectionDrawingPolicy::Draw(TMap, FArrangedWidget>& InPinGeometries, 33 | FArrangedChildren& ArrangedNodes) 34 | { 35 | NodeWidgetMap.Empty(); 36 | 37 | for (int32 NodeIndex = 0; NodeIndex < ArrangedNodes.Num(); ++NodeIndex) 38 | { 39 | FArrangedWidget& CurWidget = ArrangedNodes[NodeIndex]; 40 | const TSharedRef ChildNode = StaticCastSharedRef(CurWidget.Widget); 41 | NodeWidgetMap.Add(ChildNode->GetNodeObj(), NodeIndex); 42 | } 43 | 44 | FConnectionDrawingPolicy::Draw(InPinGeometries, ArrangedNodes); 45 | } 46 | 47 | void FComboGraphConnectionDrawingPolicy::DrawSplineWithArrow(const FGeometry& StartGeom, const FGeometry& EndGeom, 48 | const FConnectionParams& Params) 49 | { 50 | const FVector2D StartCenter = FGeometryHelper::CenterOf(StartGeom); 51 | const FVector2D EndCenter = FGeometryHelper::CenterOf(EndGeom); 52 | const FVector2D SeedPoint = (StartCenter + EndCenter) * 0.5f; 53 | 54 | const FVector2D StartAnchorPoint = FGeometryHelper::FindClosestPointOnGeom(StartGeom, SeedPoint); 55 | const FVector2D EndAnchorPoint = FGeometryHelper::FindClosestPointOnGeom(EndGeom, SeedPoint); 56 | 57 | DrawSplineWithArrow(StartAnchorPoint, EndAnchorPoint, Params); 58 | } 59 | 60 | void FComboGraphConnectionDrawingPolicy::DrawSplineWithArrow(const FVector2D& StartPoint, const FVector2D& EndPoint, 61 | const FConnectionParams& Params) 62 | { 63 | const FVector2D& P0 = Params.bUserFlag1 ? EndPoint : StartPoint; 64 | const FVector2D& P1 = Params.bUserFlag1 ? StartPoint : EndPoint; 65 | 66 | Internal_DrawLineWithArrow(P0, P1, Params); 67 | } 68 | 69 | void FComboGraphConnectionDrawingPolicy::DrawPreviewConnector(const FGeometry& PinGeometry, const FVector2D& StartPoint, 70 | const FVector2D& EndPoint, UEdGraphPin* Pin) 71 | { 72 | FConnectionParams Params; 73 | DetermineWiringStyle(Pin, nullptr, Params); 74 | 75 | if (Pin->Direction == EGPD_Output) 76 | { 77 | DrawSplineWithArrow(FGeometryHelper::FindClosestPointOnGeom(PinGeometry, EndPoint), EndPoint, Params); 78 | } 79 | else 80 | { 81 | DrawSplineWithArrow(FGeometryHelper::FindClosestPointOnGeom(PinGeometry, StartPoint), StartPoint, Params); 82 | } 83 | } 84 | 85 | FVector2D FComboGraphConnectionDrawingPolicy::ComputeSplineTangent(const FVector2D& Start, const FVector2D& End) const 86 | { 87 | const FVector2D Delta = End - Start; 88 | const FVector2D NormDelta = Delta.GetSafeNormal(); 89 | 90 | return NormDelta; 91 | } 92 | 93 | void FComboGraphConnectionDrawingPolicy::DetermineLinkGeometry(FArrangedChildren& ArrangedNodes, 94 | TSharedRef& OutputPinWidget, 95 | UEdGraphPin* OutputPin, UEdGraphPin* InputPin, 96 | FArrangedWidget*& StartWidgetGeometry, 97 | FArrangedWidget*& EndWidgetGeometry) 98 | { 99 | if (UEdNode_ComboGraphEdge* EdgeNode = Cast(InputPin->GetOwningNode())) 100 | { 101 | const UEdNode_ComboGraphNode* Start = EdgeNode->GetStartNode(); 102 | const UEdNode_ComboGraphNode* End = EdgeNode->GetEndNode(); 103 | if (Start && End) 104 | { 105 | const int32* StartNodeIndex = NodeWidgetMap.Find(Start); 106 | const int32* EndNodeIndex = NodeWidgetMap.Find(End); 107 | if (StartNodeIndex && EndNodeIndex) 108 | { 109 | StartWidgetGeometry = &ArrangedNodes[*StartNodeIndex]; 110 | EndWidgetGeometry = &ArrangedNodes[*EndNodeIndex]; 111 | } 112 | } 113 | } 114 | else 115 | { 116 | StartWidgetGeometry = PinGeometries->Find(OutputPinWidget); 117 | 118 | if (const TSharedPtr* TargetWidget = PinToPinWidgetMap.Find(InputPin)) 119 | { 120 | const TSharedRef InputWidget = TargetWidget->ToSharedRef(); 121 | EndWidgetGeometry = PinGeometries->Find(InputWidget); 122 | } 123 | } 124 | } 125 | 126 | void FComboGraphConnectionDrawingPolicy::Internal_DrawLineWithArrow(const FVector2D& StartAnchorPoint, 127 | const FVector2D& EndAnchorPoint, 128 | const FConnectionParams& Params) 129 | { 130 | constexpr float LineSeparationAmount = 4.5f; 131 | 132 | const FVector2D DeltaPos = EndAnchorPoint - StartAnchorPoint; 133 | const FVector2D UnitDelta = DeltaPos.GetSafeNormal(); 134 | const FVector2D Normal = FVector2D(DeltaPos.Y, -DeltaPos.X).GetSafeNormal(); 135 | 136 | const FVector2D DirectionBias = Normal * LineSeparationAmount; 137 | const FVector2D LengthBias = ArrowRadius.X * UnitDelta; 138 | const FVector2D StartPoint = StartAnchorPoint + DirectionBias + LengthBias; 139 | const FVector2D EndPoint = EndAnchorPoint + DirectionBias - LengthBias; 140 | 141 | DrawConnection(WireLayerID, StartPoint, EndPoint, Params); 142 | 143 | const FVector2D ArrowDrawPos = EndPoint - ArrowRadius; 144 | const float AngleInRadians = FMath::Atan2(DeltaPos.Y, DeltaPos.X); 145 | 146 | FSlateDrawElement::MakeRotatedBox( 147 | DrawElementsList, 148 | ArrowLayerID, 149 | FPaintGeometry(ArrowDrawPos, ArrowImage->ImageSize * ZoomFactor, ZoomFactor), 150 | ArrowImage, 151 | ESlateDrawEffect::None, 152 | AngleInRadians, 153 | TOptional(), 154 | FSlateDrawElement::RelativeToElement, 155 | Params.WireColor 156 | ); 157 | } 158 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Private/EdGraphSchema_ComboGraph.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | 4 | #include "EdGraphSchema_ComboGraph.h" 5 | 6 | #include "ComboGraph.h" 7 | #include "ComboGraphEdge.h" 8 | #include "EdNode_ComboGraphEdge.h" 9 | #include "EdNode_ComboGraphNode.h" 10 | #include "ToolMenu.h" 11 | #include "AssetSchemaActions/AssetSchemaAction_ComboGraph_NewEdge.h" 12 | #include "AssetSchemaActions/AssetSchemaAction_ComboGraph_NewNode.h" 13 | #include "DrawingPolicy/ComboGraphConnectionDrawingPolicy.h" 14 | #include "Framework/Commands/GenericCommands.h" 15 | #include "Nodes/ComboGraphNode.h" 16 | 17 | #define LOCTEXT_NAMESPACE "AssetSchema_ComboGraph" 18 | 19 | void UEdGraphSchema_ComboGraph::CreateDefaultNodesForGraph(UEdGraph& Graph) const 20 | { 21 | Super::CreateDefaultNodesForGraph(Graph); 22 | } 23 | 24 | void UEdGraphSchema_ComboGraph::GetGraphContextActions(FGraphContextMenuBuilder& ContextMenuBuilder) const 25 | { 26 | UComboGraph* Graph = CastChecked(ContextMenuBuilder.CurrentGraph->GetOuter()); 27 | 28 | if (!Graph->NodeType) 29 | return; 30 | 31 | const FText AddToolTip = LOCTEXT("NewComboGraphNodeTooltip", "Add combo node here :)"); 32 | 33 | TSet> Visited; 34 | 35 | FText Desc = Graph->NodeType.GetDefaultObject()->ContextMenuName; 36 | 37 | if (Desc.IsEmpty()) 38 | { 39 | FString Title = Graph->NodeType->GetName(); 40 | Title.RemoveFromEnd("_C"); 41 | Desc = FText::FromString(Title); 42 | } 43 | 44 | if (!Graph->NodeType->HasAnyClassFlags(CLASS_Abstract)) 45 | { 46 | const TSharedPtr NewNodeAction( 47 | new FAssetSchemaAction_ComboGraph_NewNode( 48 | LOCTEXT("ComboGraphNodeAction", "Combo Graph Node"), Desc, AddToolTip, 0)); 49 | NewNodeAction->NodeTemplate = NewObject(ContextMenuBuilder.OwnerOfTemporaries); 50 | NewNodeAction->NodeTemplate->ComboGraphNode = NewObject( 51 | NewNodeAction->NodeTemplate, Graph->NodeType); 52 | NewNodeAction->NodeTemplate->ComboGraphNode->Graph = Graph; 53 | ContextMenuBuilder.AddAction(NewNodeAction); 54 | 55 | Visited.Add(Graph->NodeType); 56 | } 57 | 58 | for (TObjectIterator It; It; ++It) 59 | { 60 | if (It->IsChildOf(Graph->NodeType) && !It->HasAnyClassFlags(CLASS_Abstract) && !Visited.Contains(*It)) 61 | { 62 | TSubclassOf NodeType = *It; 63 | 64 | //Remove REINST assets caused by recompiling blueprint 65 | //Remove SKEL assets which are SkeletonClass generated by BlueprintCompilationManager 66 | if (It->GetName().StartsWith("REINST") || It->GetName().StartsWith("SKEL")) 67 | continue; 68 | 69 | if (!Graph->GetClass()->IsChildOf(NodeType.GetDefaultObject()->CompatibleGraphType)) 70 | continue; 71 | 72 | Desc = NodeType.GetDefaultObject()->ContextMenuName; 73 | 74 | if (Desc.IsEmpty()) 75 | { 76 | FString Title = NodeType->GetName(); 77 | Title.RemoveFromEnd("_C"); 78 | Desc = FText::FromString(Title); 79 | } 80 | 81 | TSharedPtr Action( 82 | new FAssetSchemaAction_ComboGraph_NewNode( 83 | LOCTEXT("ComboGraphNodeAction", "Combo Graph Node"), Desc, AddToolTip, 0)); 84 | Action->NodeTemplate = NewObject(ContextMenuBuilder.OwnerOfTemporaries); 85 | Action->NodeTemplate->ComboGraphNode = NewObject(Action->NodeTemplate, NodeType); 86 | Action->NodeTemplate->ComboGraphNode->Graph = Graph; 87 | ContextMenuBuilder.AddAction(Action); 88 | 89 | Visited.Add(NodeType); 90 | } 91 | } 92 | } 93 | 94 | void UEdGraphSchema_ComboGraph::GetContextMenuActions(UToolMenu* Menu, UGraphNodeContextMenuContext* Context) const 95 | { 96 | if (Context->Node) 97 | { 98 | { 99 | FToolMenuSection& Section = Menu->AddSection("ComboGraphAssetGraphSchemaNodeActions", 100 | LOCTEXT("ClassActionsMenuHeader", "Node Actions")); 101 | Section.AddMenuEntry(FGenericCommands::Get().Delete); 102 | Section.AddMenuEntry(FGenericCommands::Get().Rename); 103 | } 104 | } 105 | 106 | Super::GetContextMenuActions(Menu, Context); 107 | } 108 | 109 | const FPinConnectionResponse UEdGraphSchema_ComboGraph::CanCreateConnection(const UEdGraphPin* A, 110 | const UEdGraphPin* B) const 111 | { 112 | if (A->GetOwningNode() == B->GetOwningNode()) 113 | { 114 | return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, 115 | LOCTEXT("PinErrorSameNode", "Can't connect node to itself")); 116 | } 117 | 118 | const UEdGraphPin* Out = A; 119 | const UEdGraphPin* In = B; 120 | 121 | const UEdNode_ComboGraphNode* EdNodeOut = Cast(Out->GetOwningNode()); 122 | const UEdNode_ComboGraphNode* EdNodeIn = Cast(In->GetOwningNode()); 123 | 124 | if (!EdNodeOut || !EdNodeIn) 125 | { 126 | return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, 127 | LOCTEXT("PinError", "EdNode_ComboGraphNode is invalid")); 128 | } 129 | 130 | FText ErrorMessage; 131 | if (!EdNodeOut->ComboGraphNode->CanCreateConnectionTo(EdNodeIn->ComboGraphNode, 132 | EdNodeOut->GetOutputPin()->LinkedTo.Num(), ErrorMessage)) 133 | { 134 | return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, ErrorMessage); 135 | } 136 | 137 | if (!EdNodeIn->ComboGraphNode->CanCreateConnectionFrom(EdNodeOut->ComboGraphNode, 138 | EdNodeIn->GetInputPin()->LinkedTo.Num(), ErrorMessage)) 139 | { 140 | return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, ErrorMessage); 141 | } 142 | 143 | if (EdNodeOut->ComboGraphNode->GetGraph()->bEdgeEnabled) 144 | { 145 | return FPinConnectionResponse(CONNECT_RESPONSE_MAKE_WITH_CONVERSION_NODE, 146 | LOCTEXT("PinConnect", "Connect nodes with edge")); 147 | } 148 | 149 | return FPinConnectionResponse(CONNECT_RESPONSE_MAKE, LOCTEXT("PinConnect", "Connect nodes")); 150 | } 151 | 152 | bool UEdGraphSchema_ComboGraph::TryCreateConnection(UEdGraphPin* A, UEdGraphPin* B) const 153 | { 154 | const UEdNode_ComboGraphNode* NodeA = Cast(A->GetOwningNode()); 155 | const UEdNode_ComboGraphNode* NodeB = Cast(B->GetOwningNode()); 156 | 157 | for (const UEdGraphPin* TestPin : NodeA->GetOutputPin()->LinkedTo) 158 | { 159 | UEdGraphNode* ChildNode = TestPin->GetOwningNode(); 160 | if (UEdNode_ComboGraphEdge* EdNode_Edge = Cast(ChildNode)) 161 | { 162 | ChildNode = EdNode_Edge->GetEndNode(); 163 | } 164 | 165 | if (ChildNode == NodeB) 166 | return false; 167 | } 168 | 169 | if (NodeA && NodeB) 170 | { 171 | return Super::TryCreateConnection(NodeA->GetOutputPin(), NodeB->GetInputPin()); 172 | } 173 | 174 | return false; 175 | } 176 | 177 | bool UEdGraphSchema_ComboGraph::CreateAutomaticConversionNodeAndConnections(UEdGraphPin* A, UEdGraphPin* B) const 178 | { 179 | UEdNode_ComboGraphNode* NodeA = Cast(A->GetOwningNode()); 180 | UEdNode_ComboGraphNode* NodeB = Cast(B->GetOwningNode()); 181 | 182 | if (!NodeA || !NodeA->GetOutputPin() || !NodeB || !NodeB->GetInputPin()) 183 | return false; 184 | 185 | const UComboGraph* Graph = NodeA->ComboGraphNode->GetGraph(); 186 | 187 | const FVector2D InitPos((NodeA->NodePosX + NodeB->NodePosX) / 2, (NodeA->NodePosY + NodeB->NodePosY) / 2); 188 | 189 | FAssetSchemaAction_ComboGraph_NewEdge Action; 190 | Action.NodeTemplate = NewObject(NodeA->GetGraph()); 191 | Action.NodeTemplate->SetEdge(NewObject(Action.NodeTemplate, Graph->EdgeType)); 192 | UEdNode_ComboGraphEdge* EdgeNode = Cast( 193 | Action.PerformAction(NodeA->GetGraph(), nullptr, InitPos, false)); 194 | 195 | EdgeNode->CreateConnections(NodeA, NodeB); 196 | 197 | return true; 198 | } 199 | 200 | TSharedPtr UEdGraphSchema_ComboGraph::GetCreateCommentAction() const 201 | { 202 | return Super::GetCreateCommentAction(); 203 | } 204 | 205 | void UEdGraphSchema_ComboGraph::GetBreakLinkToSubMenuActions(UToolMenu* Menu, UEdGraphPin* InGraphPin) 206 | { 207 | TMap LinkTitleCount; 208 | 209 | FToolMenuSection& Section = Menu->FindOrAddSection("ComboGraphAssetGraphSchemaPinActions"); 210 | 211 | for (TArray::TConstIterator Links(InGraphPin->LinkedTo); Links; ++Links) 212 | { 213 | const UEdGraphPin* Pin = *Links; 214 | FString TitleString = Pin->GetOwningNode()->GetNodeTitle(ENodeTitleType::ListView).ToString(); 215 | FText Title = FText::FromString(TitleString); 216 | if (Pin->PinName != TEXT("")) 217 | { 218 | TitleString = FString::Printf(TEXT("%s (%s)"), *TitleString, *Pin->PinName.ToString()); 219 | 220 | FFormatNamedArguments Args; 221 | Args.Add(TEXT("NodeTitle"), Title); 222 | Args.Add(TEXT("PinName"), Pin->GetDisplayName()); 223 | Title = FText::Format(LOCTEXT("BreakDescPin", "{NodeTitle} ({PinName})"), Args); 224 | } 225 | 226 | uint32& Count = LinkTitleCount.FindOrAdd(TitleString); 227 | 228 | FText Description; 229 | FFormatNamedArguments Args; 230 | Args.Add(TEXT("NodeTitle"), Title); 231 | Args.Add(TEXT("NumberOfNodes"), Count); 232 | 233 | if (Count == 0) 234 | { 235 | Description = FText::Format(LOCTEXT("BreakDesc", "Break link to {NodeTitle}"), Args); 236 | } 237 | else 238 | { 239 | Description = FText::Format(LOCTEXT("BreakDescMulti", "Break link to {NodeTitle} ({NumberOfNodes})"), Args); 240 | } 241 | ++Count; 242 | 243 | Section.AddMenuEntry(NAME_None, Description, Description, FSlateIcon(), FUIAction( 244 | FExecuteAction::CreateUObject(this, &UEdGraphSchema_ComboGraph::BreakSinglePinLink, 245 | const_cast(InGraphPin), *Links))); 246 | } 247 | } 248 | 249 | FConnectionDrawingPolicy* UEdGraphSchema_ComboGraph::CreateConnectionDrawingPolicy(int32 InBackLayerID, 250 | int32 InFrontLayerID, float InZoomFactor, const FSlateRect& InClippingRect, FSlateWindowElementList& InDrawElements, 251 | UEdGraph* InGraphObj) const 252 | { 253 | return new FComboGraphConnectionDrawingPolicy(InBackLayerID, InFrontLayerID, InZoomFactor, InClippingRect, 254 | InDrawElements, InGraphObj); 255 | } 256 | 257 | #undef LOCTEXT_NAMESPACE 258 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Private/EdGraph_ComboGraph.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | 4 | #include "EdGraph_ComboGraph.h" 5 | 6 | #include "ComboGraph.h" 7 | #include "ComboGraphEdge.h" 8 | #include "EdGraphSchema_ComboGraph.h" 9 | #include "EdNode_ComboGraphEdge.h" 10 | #include "EdNode_ComboGraphNode.h" 11 | #include "Nodes/ComboGraphNode.h" 12 | 13 | UEdGraph_ComboGraph::UEdGraph_ComboGraph() 14 | { 15 | Schema = UEdGraphSchema_ComboGraph::StaticClass(); 16 | } 17 | 18 | UEdGraph_ComboGraph::~UEdGraph_ComboGraph() 19 | { 20 | } 21 | 22 | void UEdGraph_ComboGraph::RebuildComboGraph() 23 | { 24 | UComboGraph* ComboGraph = GetComboGraph(); 25 | 26 | Clear(); 27 | 28 | for (int i = 0; i < Nodes.Num(); ++i) 29 | { 30 | if (UEdNode_ComboGraphNode* EdNode = Cast(Nodes[i])) 31 | { 32 | if (!EdNode->ComboGraphNode) 33 | continue; 34 | 35 | UComboGraphNode* ComboGraphNode = EdNode->ComboGraphNode; 36 | 37 | NodeMap.Add(ComboGraphNode, EdNode); 38 | 39 | ComboGraph->AllNodes.Add(ComboGraphNode); 40 | 41 | for (int PinIdx = 0; PinIdx < EdNode->Pins.Num(); ++PinIdx) 42 | { 43 | UEdGraphPin* Pin = EdNode->Pins[PinIdx]; 44 | 45 | if (Pin->Direction != EGPD_Output) 46 | continue; 47 | 48 | for (int LinkToIdx = 0; LinkToIdx < Pin->LinkedTo.Num(); ++LinkToIdx) 49 | { 50 | UComboGraphNode* ChildNode = nullptr; 51 | if (const UEdNode_ComboGraphNode* EdNode_Child = Cast( 52 | Pin->LinkedTo[LinkToIdx]->GetOwningNode())) 53 | { 54 | ChildNode = EdNode_Child->ComboGraphNode; 55 | } 56 | else if (UEdNode_ComboGraphEdge* EdNode_Edge = Cast( 57 | Pin->LinkedTo[LinkToIdx]->GetOwningNode())) 58 | { 59 | if (const UEdNode_ComboGraphNode* EdNode_ChildEndNode = EdNode_Edge->GetEndNode()) 60 | { 61 | ChildNode = EdNode_ChildEndNode->ComboGraphNode; 62 | } 63 | } 64 | 65 | if (ChildNode) 66 | { 67 | ComboGraphNode->ChildrenNodes.Add(ChildNode); 68 | 69 | ChildNode->ParentNodes.Add(ComboGraphNode); 70 | } 71 | else 72 | { 73 | UE_LOG(LogTemp, Error, TEXT("UEdGraph_ComboGraph::RebuildComboGraph can't find child node")) 74 | } 75 | } 76 | } 77 | } 78 | else if (UEdNode_ComboGraphEdge* EdgeNode = Cast(Nodes[i])) 79 | { 80 | const UEdNode_ComboGraphNode* StartNode = EdgeNode->GetStartNode(); 81 | const UEdNode_ComboGraphNode* EndNode = EdgeNode->GetEndNode(); 82 | UComboGraphEdge* Edge = EdgeNode->ComboGraphEdge; 83 | 84 | if (!StartNode || !EndNode || !Edge) 85 | { 86 | UE_LOG(LogTemp, Error, TEXT("UEdGraph_ComboGraph::RebuildComboGraph add edge failed.")) 87 | continue; 88 | } 89 | 90 | EdgeMap.Add(Edge, EdgeNode); 91 | 92 | Edge->ComboGraph = ComboGraph; 93 | Edge->Rename(nullptr, ComboGraph, REN_DontCreateRedirectors | REN_DoNotDirty); 94 | Edge->StartNode = StartNode->ComboGraphNode; 95 | Edge->EndNode = EndNode->ComboGraphNode; 96 | Edge->StartNode->Edges.Add(Edge->EndNode, Edge); 97 | } 98 | } 99 | 100 | for (UComboGraphNode* ComboGraphNode : ComboGraph->AllNodes) 101 | { 102 | ComboGraphNode->Graph = ComboGraph; 103 | ComboGraphNode->Rename(nullptr, ComboGraph, REN_DontCreateRedirectors | REN_DoNotDirty); 104 | } 105 | } 106 | 107 | TObjectPtr UEdGraph_ComboGraph::GetComboGraph() const 108 | { 109 | return CastChecked(GetOuter()); 110 | } 111 | 112 | bool UEdGraph_ComboGraph::Modify(bool bAlwaysMarkDirty) 113 | { 114 | const bool Result = Super::Modify(bAlwaysMarkDirty); 115 | 116 | GetComboGraph()->Modify(); 117 | 118 | for (UEdGraphNode* EdGraphNode : Nodes) 119 | { 120 | EdGraphNode->Modify(); 121 | } 122 | 123 | return Result; 124 | } 125 | 126 | void UEdGraph_ComboGraph::PostEditUndo() 127 | { 128 | Super::PostEditUndo(); 129 | 130 | NotifyGraphChanged(); 131 | } 132 | 133 | void UEdGraph_ComboGraph::Clear() 134 | { 135 | UComboGraph* Graph = GetComboGraph(); 136 | 137 | Graph->ClearGraph(); 138 | NodeMap.Reset(); 139 | EdgeMap.Reset(); 140 | 141 | for (UEdGraphNode* EdGraphNode : Nodes) 142 | { 143 | if (const UEdNode_ComboGraphNode* EdNode = Cast(EdGraphNode)) 144 | { 145 | if (UComboGraphNode* ComboGraphNode = EdNode->ComboGraphNode) 146 | { 147 | ComboGraphNode->ParentNodes.Reset(); 148 | ComboGraphNode->ChildrenNodes.Reset(); 149 | ComboGraphNode->Edges.Reset(); 150 | } 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Private/EdNode_ComboGraphEdge.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #include "EdNode_ComboGraphEdge.h" 4 | 5 | #include "ComboGraphEdge.h" 6 | #include "EdNode_ComboGraphNode.h" 7 | 8 | #define LOCTEXT_NAMESPACE "EdNode_ComboGraphEdge" 9 | 10 | UEdNode_ComboGraphEdge::UEdNode_ComboGraphEdge() 11 | { 12 | } 13 | 14 | void UEdNode_ComboGraphEdge::AllocateDefaultPins() 15 | { 16 | UEdGraphPin* Inputs = CreatePin(EGPD_Input, TEXT("Edge"), FName(), TEXT("In")); 17 | Inputs->bHidden = true; 18 | 19 | UEdGraphPin* Outputs = CreatePin(EGPD_Output, TEXT("Edge"), FName(), TEXT("Out")); 20 | Outputs->bHidden = true; 21 | } 22 | 23 | FText UEdNode_ComboGraphEdge::GetNodeTitle(ENodeTitleType::Type TitleType) const 24 | { 25 | return ComboGraphEdge ? ComboGraphEdge->GetNodeTitle() : Super::GetNodeTitle(TitleType); 26 | } 27 | 28 | void UEdNode_ComboGraphEdge::PinConnectionListChanged(UEdGraphPin* Pin) 29 | { 30 | if (Pin->LinkedTo.Num() == 0) 31 | { 32 | Modify(); 33 | 34 | if (UEdGraph* ParentGraph = GetGraph()) 35 | { 36 | ParentGraph->Modify(); 37 | } 38 | 39 | DestroyNode(); 40 | } 41 | } 42 | 43 | void UEdNode_ComboGraphEdge::PrepareForCopying() 44 | { 45 | ComboGraphEdge->Rename(nullptr, this, REN_DontCreateRedirectors | REN_DoNotDirty); 46 | } 47 | 48 | void UEdNode_ComboGraphEdge::CreateConnections(const UEdNode_ComboGraphNode* Start, UEdNode_ComboGraphNode* End) 49 | { 50 | Pins[0]->Modify(); 51 | Pins[0]->LinkedTo.Empty(); 52 | 53 | Start->GetOutputPin()->Modify(); 54 | Pins[0]->MakeLinkTo(Start->GetOutputPin()); 55 | 56 | Pins[1]->Modify(); 57 | Pins[1]->LinkedTo.Empty(); 58 | 59 | End->GetInputPin()->Modify(); 60 | Pins[1]->MakeLinkTo(End->GetInputPin()); 61 | } 62 | 63 | UEdNode_ComboGraphNode* UEdNode_ComboGraphEdge::GetStartNode() 64 | { 65 | if (Pins[0]->LinkedTo.Num() > 0) 66 | { 67 | return Cast(Pins[0]->LinkedTo[0]->GetOwningNode()); 68 | } 69 | 70 | return nullptr; 71 | } 72 | 73 | UEdNode_ComboGraphNode* UEdNode_ComboGraphEdge::GetEndNode() 74 | { 75 | if (Pins[1]->LinkedTo.Num() > 0) 76 | { 77 | return Cast(Pins[1]->LinkedTo[0]->GetOwningNode()); 78 | } 79 | 80 | return nullptr; 81 | } 82 | 83 | #undef LOCTEXT_NAMESPACE 84 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Private/EdNode_ComboGraphNode.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | 4 | #include "EdNode_ComboGraphNode.h" 5 | #include "Nodes/ComboGraphNode.h" 6 | 7 | UEdNode_ComboGraphNode::UEdNode_ComboGraphNode(): ComboGraphNode(nullptr), SEdNode(nullptr) 8 | { 9 | bCanRenameNode = true; 10 | } 11 | 12 | UEdNode_ComboGraphNode::~UEdNode_ComboGraphNode() 13 | { 14 | } 15 | 16 | UEdGraphPin* UEdNode_ComboGraphNode::GetInputPin() const 17 | { 18 | return Pins[0]; 19 | } 20 | 21 | UEdGraphPin* UEdNode_ComboGraphNode::GetOutputPin() const 22 | { 23 | return Pins[1]; 24 | } 25 | 26 | FLinearColor UEdNode_ComboGraphNode::GetBackgroundColor() const 27 | { 28 | return ComboGraphNode ? ComboGraphNode->GetBackgroundColor() : FLinearColor::Black; 29 | } 30 | 31 | void UEdNode_ComboGraphNode::AllocateDefaultPins() 32 | { 33 | check(Pins.Num() == 0); 34 | 35 | CreatePin(EGPD_Input, "MultipleNodes", FName(), TEXT("In")); 36 | CreatePin(EGPD_Output, "MultipleNodes", FName(), TEXT("Out")); 37 | } 38 | 39 | void UEdNode_ComboGraphNode::AutowireNewNode(UEdGraphPin* FromPin) 40 | { 41 | Super::AutowireNewNode(FromPin); 42 | 43 | if (FromPin) 44 | { 45 | if (GetSchema()->TryCreateConnection(FromPin, GetInputPin())) 46 | { 47 | FromPin->GetOwningNode()->NodeConnectionListChanged(); 48 | } 49 | } 50 | } 51 | 52 | FText UEdNode_ComboGraphNode::GetNodeTitle(ENodeTitleType::Type TitleType) const 53 | { 54 | if (!ComboGraphNode) 55 | { 56 | return Super::GetNodeTitle(TitleType); 57 | } 58 | 59 | return ComboGraphNode->GetNodeTitle(); 60 | } 61 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Private/EditorCommands_ComboGraph.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | 4 | #include "EditorCommands_ComboGraph.h" 5 | 6 | #define LOCTEXT_NAMESPACE "EditorCommands_ComboGraph" 7 | 8 | void FEditorCommands_ComboGraph::RegisterCommands() 9 | { 10 | UI_COMMAND(GraphSettings, "Graph Settings", "Graph Settings", EUserInterfaceActionType::Button, FInputChord()); 11 | UI_COMMAND(AutoArrange, "Auto Arrange", "Auto Arrange", EUserInterfaceActionType::Button, FInputChord()); 12 | } 13 | 14 | #undef LOCTEXT_NAMESPACE 15 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Private/Factories/ComboGraphFactory.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | 4 | #include "Factories/ComboGraphFactory.h" 5 | 6 | #include "ClassViewerFilter.h" 7 | #include "ClassViewerModule.h" 8 | #include "ComboGraph.h" 9 | #include "EdGraph_ComboGraph.h" 10 | #include "Kismet2/KismetEditorUtilities.h" 11 | #include "Kismet2/SClassPickerDialog.h" 12 | 13 | #define LOCTEXT_NAMESPACE "ComboGraphFactory" 14 | 15 | class FAssetClassParentFilter : public IClassViewerFilter 16 | { 17 | public: 18 | FAssetClassParentFilter() 19 | : DisallowedClassFlags(CLASS_None), bDisallowBlueprintBase(false) 20 | { 21 | } 22 | 23 | TSet AllowedChildrenOfClasses; 24 | 25 | EClassFlags DisallowedClassFlags; 26 | 27 | bool bDisallowBlueprintBase; 28 | 29 | virtual bool IsClassAllowed(const FClassViewerInitializationOptions& InInitOptions, const UClass* InClass, 30 | TSharedRef InFilterFuncs) override 31 | { 32 | const bool bAllowed = !InClass->HasAnyClassFlags(DisallowedClassFlags) 33 | && InFilterFuncs->IfInChildOfClassesSet(AllowedChildrenOfClasses, InClass) != EFilterReturn::Failed; 34 | 35 | if (bAllowed && bDisallowBlueprintBase) 36 | { 37 | if (FKismetEditorUtilities::CanCreateBlueprintOfClass(InClass)) 38 | { 39 | return false; 40 | } 41 | } 42 | 43 | return bAllowed; 44 | } 45 | 46 | virtual bool IsUnloadedClassAllowed(const FClassViewerInitializationOptions& InInitOptions, 47 | const TSharedRef InUnloadedClassData, 48 | TSharedRef InFilterFuncs) override 49 | { 50 | if (bDisallowBlueprintBase) 51 | { 52 | return false; 53 | } 54 | 55 | return !InUnloadedClassData->HasAnyClassFlags(DisallowedClassFlags) 56 | && InFilterFuncs->IfInChildOfClassesSet(AllowedChildrenOfClasses, InUnloadedClassData) != 57 | EFilterReturn::Failed; 58 | } 59 | }; 60 | 61 | UComboGraphFactory::UComboGraphFactory(const FObjectInitializer& ObjectInitializer) 62 | : Super(ObjectInitializer) 63 | { 64 | SupportedClass = UComboGraph::StaticClass(); 65 | bCreateNew = true; 66 | bEditAfterNew = true; 67 | } 68 | 69 | bool UComboGraphFactory::ConfigureProperties() 70 | { 71 | ComboGraphClass = nullptr; 72 | 73 | FClassViewerInitializationOptions Options; 74 | Options.Mode = EClassViewerMode::ClassPicker; 75 | 76 | const TSharedRef Filter = MakeShareable(new FAssetClassParentFilter); 77 | Options.ClassFilters.Add(Filter); 78 | 79 | Filter->DisallowedClassFlags = CLASS_Abstract | CLASS_Deprecated | CLASS_NewerVersionExists | CLASS_HideDropDown; 80 | Filter->AllowedChildrenOfClasses.Add(StaticClass()); 81 | 82 | const FText TitleText = LOCTEXT("CreateComboGraphAssetOptions", "Pick Combo Graph Class"); 83 | UClass* ChosenClass = nullptr; 84 | const bool bPressedOk = 85 | SClassPickerDialog::PickClass(TitleText, Options, ChosenClass, StaticClass()); 86 | 87 | if (bPressedOk) 88 | { 89 | ComboGraphClass = ChosenClass; 90 | } 91 | 92 | return bPressedOk; 93 | } 94 | 95 | UObject* UComboGraphFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, 96 | UObject* Context, FFeedbackContext* Warn) 97 | { 98 | if (ComboGraphClass) 99 | { 100 | return NewObject(InParent, ComboGraphClass, Name, Flags | RF_Transactional); 101 | } 102 | 103 | return NewObject(InParent, Class, Name, Flags | RF_Transactional); 104 | } 105 | 106 | #undef LOCTEXT_NAMESPACE 107 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Private/Factories/GraphPanelNodeFactory_ComboGraph.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | 4 | #include "Factories/GraphPanelNodeFactory_ComboGraph.h" 5 | 6 | #include "EdNode_ComboGraphEdge.h" 7 | #include "EdNode_ComboGraphNode.h" 8 | #include "SEdNode_ComboGraphEdge.h" 9 | #include "SEdNode_ComboGraphNode.h" 10 | 11 | TSharedPtr FGraphPanelNodeFactory_ComboGraph::CreateNode(UEdGraphNode* Node) const 12 | { 13 | if (UEdNode_ComboGraphNode* EdNode_ComboGraphNode = Cast(Node)) 14 | { 15 | return SNew(SEdNode_ComboGraphNode, EdNode_ComboGraphNode); 16 | } 17 | 18 | if (UEdNode_ComboGraphEdge* EdNode_Edge = Cast(Node)) 19 | { 20 | return SNew(SEdNode_ComboGraphEdge, EdNode_Edge); 21 | } 22 | 23 | return nullptr; 24 | } 25 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Private/Pins/ComboGraphPin.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Private/SEdNode_ComboGraphEdge.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | 4 | #include "SEdNode_ComboGraphEdge.h" 5 | 6 | #include "EdNode_ComboGraphNode.h" 7 | #include "ComboGraphEdge.h" 8 | #include "ConnectionDrawingPolicy.h" 9 | #include "EdNode_ComboGraphEdge.h" 10 | #include "Widgets/Text/SInlineEditableTextBlock.h" 11 | 12 | #define LOCTEXT_NAMESPACE "SComboGraphEdge" 13 | 14 | void SEdNode_ComboGraphEdge::Construct(const FArguments& InArgs, UEdNode_ComboGraphEdge* InNode) 15 | { 16 | GraphNode = InNode; 17 | UpdateGraphNode(); 18 | } 19 | 20 | bool SEdNode_ComboGraphEdge::RequiresSecondPassLayout() const 21 | { 22 | return true; 23 | } 24 | 25 | void SEdNode_ComboGraphEdge::PerformSecondPassLayout(const TMap>& NodeToWidgetLookup) const 26 | { 27 | UEdNode_ComboGraphEdge* EdgeNode = CastChecked(GraphNode); 28 | 29 | FGeometry StartGeometry; 30 | FGeometry EndGeometry; 31 | 32 | const UEdNode_ComboGraphNode* Start = EdgeNode->GetStartNode(); 33 | const UEdNode_ComboGraphNode* End = EdgeNode->GetEndNode(); 34 | if (Start && End) 35 | { 36 | const TSharedRef& FromWidget = NodeToWidgetLookup.FindChecked(Start); 37 | const TSharedRef& ToWidget = NodeToWidgetLookup.FindChecked(End); 38 | 39 | StartGeometry = FGeometry(FVector2D(Start->NodePosX, Start->NodePosY), FVector2D::ZeroVector, 40 | FromWidget->GetDesiredSize(), 1.0f); 41 | EndGeometry = FGeometry(FVector2D(End->NodePosX, End->NodePosY), FVector2D::ZeroVector, 42 | ToWidget->GetDesiredSize(), 1.0f); 43 | } 44 | 45 | PositionBetweenTwoNodesWithOffset(StartGeometry, EndGeometry, 0, 1); 46 | } 47 | 48 | void SEdNode_ComboGraphEdge::UpdateGraphNode() 49 | { 50 | InputPins.Empty(); 51 | OutputPins.Empty(); 52 | 53 | RightNodeBox.Reset(); 54 | LeftNodeBox.Reset(); 55 | 56 | const TSharedPtr NodeTitle = SNew(SNodeTitle, GraphNode); 57 | 58 | ContentScale.Bind(this, &SGraphNode::GetContentScale); 59 | GetOrAddSlot(ENodeZone::Center) 60 | .HAlign(HAlign_Center) 61 | .VAlign(VAlign_Center) 62 | [ 63 | SNew(SOverlay) 64 | + SOverlay::Slot() 65 | [ 66 | SNew(SImage) 67 | .Image(FAppStyle::GetBrush("Graph.TransitionNode.ColorSpill")) 68 | .ColorAndOpacity(this, &SEdNode_ComboGraphEdge::GetEdgeColor) 69 | ] 70 | + SOverlay::Slot() 71 | [ 72 | SNew(SImage) 73 | .Image(this, &SEdNode_ComboGraphEdge::GetEdgeImage) 74 | .Visibility(this, &SEdNode_ComboGraphEdge::GetEdgeImageVisibility) 75 | ] 76 | + SOverlay::Slot() 77 | .Padding(FMargin(4.0f, 4.0f, 4.0f, 4.0f)) 78 | [ 79 | SNew(SVerticalBox) 80 | + SVerticalBox::Slot() 81 | .HAlign(HAlign_Center) 82 | .AutoHeight() 83 | + SVerticalBox::Slot() 84 | .AutoHeight() 85 | [ 86 | SAssignNew(InlineEditableText, SInlineEditableTextBlock) 87 | .ColorAndOpacity(FLinearColor::Black) 88 | .Visibility(this, &SEdNode_ComboGraphEdge::GetEdgeTitleVisibility) 89 | .Font(FCoreStyle::GetDefaultFontStyle("Regular", 12)) 90 | .Text(NodeTitle.Get(), &SNodeTitle::GetHeadTitle) 91 | .OnTextCommitted(this, &SEdNode_ComboGraphEdge::OnNameTextCommited) 92 | ] 93 | + SVerticalBox::Slot() 94 | .AutoHeight() 95 | [ 96 | NodeTitle.ToSharedRef() 97 | ] 98 | ] 99 | ]; 100 | } 101 | 102 | void SEdNode_ComboGraphEdge::PositionBetweenTwoNodesWithOffset(const FGeometry& StartGeom, const FGeometry& EndGeom, 103 | int32 NodeIndex, int32 MaxNodes) const 104 | { 105 | const FVector2D StartCenter = FGeometryHelper::CenterOf(StartGeom); 106 | const FVector2D EndCenter = FGeometryHelper::CenterOf(EndGeom); 107 | const FVector2D SeedPoint = (StartCenter + EndCenter) * 0.5f; 108 | 109 | const FVector2D StartAnchorPoint = FGeometryHelper::FindClosestPointOnGeom(StartGeom, SeedPoint); 110 | const FVector2D EndAnchorPoint = FGeometryHelper::FindClosestPointOnGeom(EndGeom, SeedPoint); 111 | 112 | constexpr float Height = 30.0f; 113 | 114 | const FVector2D DesiredNodeSize = GetDesiredSize(); 115 | 116 | FVector2D DeltaPos(EndAnchorPoint - StartAnchorPoint); 117 | 118 | if (DeltaPos.IsNearlyZero()) 119 | { 120 | DeltaPos = FVector2D(10.0f, 0.0f); 121 | } 122 | 123 | const FVector2D Normal = FVector2D(DeltaPos.Y, -DeltaPos.X).GetSafeNormal(); 124 | 125 | const FVector2D NewCenter = StartAnchorPoint + 0.5f * DeltaPos + Height * Normal; 126 | 127 | const FVector2D DeltaNormal = DeltaPos.GetSafeNormal(); 128 | 129 | constexpr float MultiNodeSpace = 0.2f; 130 | constexpr float MultiNodeStep = 1.f + MultiNodeSpace; 131 | 132 | const float MultiNodeStart = -((MaxNodes - 1) * MultiNodeStep) / 2.f; 133 | const float MultiNodeOffset = MultiNodeStart + NodeIndex * MultiNodeStep; 134 | 135 | const FVector2D NewCorner = NewCenter - 0.5f * DesiredNodeSize + DeltaNormal * MultiNodeOffset * DesiredNodeSize. 136 | Size(); 137 | 138 | GraphNode->NodePosX = NewCorner.X; 139 | GraphNode->NodePosY = NewCorner.Y; 140 | } 141 | 142 | void SEdNode_ComboGraphEdge::OnNameTextCommited(const FText& InText, ETextCommit::Type CommitInfo) 143 | { 144 | SGraphNode::OnNameTextCommited(InText, CommitInfo); 145 | 146 | if (UEdNode_ComboGraphEdge* CurrentNode = CastChecked(GraphNode); 147 | CurrentNode && CurrentNode->ComboGraphEdge) 148 | { 149 | const FScopedTransaction Transaction(LOCTEXT("ComboGraphEditorRenameEdge", "Combo Graph Editor: Rename Edge")); 150 | CurrentNode->Modify(); 151 | CurrentNode->ComboGraphEdge->SetNodeTitle(InText); 152 | UpdateGraphNode(); 153 | } 154 | } 155 | 156 | FSlateColor SEdNode_ComboGraphEdge::GetEdgeColor() const 157 | { 158 | if (const UEdNode_ComboGraphEdge* EdgeNode = CastChecked(GraphNode); 159 | EdgeNode->ComboGraphEdge) 160 | { 161 | return EdgeNode->ComboGraphEdge->GetEdgeColor(); 162 | } 163 | 164 | return FLinearColor(0.9f, 0.9f, 0.9f, 1.0f); 165 | } 166 | 167 | const FSlateBrush* SEdNode_ComboGraphEdge::GetEdgeImage() const 168 | { 169 | return FAppStyle::GetBrush("Graph.TransitionNode.Icon"); 170 | } 171 | 172 | EVisibility SEdNode_ComboGraphEdge::GetEdgeImageVisibility() const 173 | { 174 | if (const UEdNode_ComboGraphEdge* EdgeNode = CastChecked(GraphNode); 175 | EdgeNode->ComboGraphEdge && EdgeNode->ComboGraphEdge->bShouldDrawTitle) 176 | { 177 | return EVisibility::Hidden; 178 | } 179 | 180 | return EVisibility::Visible; 181 | } 182 | 183 | EVisibility SEdNode_ComboGraphEdge::GetEdgeTitleVisibility() const 184 | { 185 | if (const UEdNode_ComboGraphEdge* EdgeNode = CastChecked(GraphNode); 186 | EdgeNode->ComboGraphEdge && EdgeNode->ComboGraphEdge->bShouldDrawTitle) 187 | { 188 | return EVisibility::Visible; 189 | } 190 | 191 | return EVisibility::Collapsed; 192 | } 193 | 194 | #undef LOCTEXT_NAMESPACE 195 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Private/SEdNode_ComboGraphNode.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | 4 | #include "SEdNode_ComboGraphNode.h" 5 | 6 | #include "EdNode_ComboGraphNode.h" 7 | #include "GraphEditorSettings.h" 8 | #include "SCommentBubble.h" 9 | #include "Nodes/ComboGraphNode.h" 10 | #include "Pins/ComboGraphPin.h" 11 | #include "Widgets/Text/SInlineEditableTextBlock.h" 12 | 13 | #define LOCTEXT_NAMESPACE "EdNode_ComboGraph" 14 | 15 | void SEdNode_ComboGraphNode::Construct(const FArguments& InArgs, UEdNode_ComboGraphNode* InNode) 16 | { 17 | GraphNode = InNode; 18 | UpdateGraphNode(); 19 | InNode->SEdNode = this; 20 | } 21 | 22 | void SEdNode_ComboGraphNode::UpdateGraphNode() 23 | { 24 | InputPins.Empty(); 25 | OutputPins.Empty(); 26 | 27 | RightNodeBox.Reset(); 28 | LeftNodeBox.Reset(); 29 | 30 | const FSlateBrush* NodeTypeIcon = GetNameIcon(); 31 | 32 | constexpr FLinearColor TitleShadowColor(0.6f, 0.6f, 0.6f); 33 | 34 | TSharedPtr ErrorText; 35 | TSharedPtr NodeBody; 36 | const TSharedPtr NodeTitle = SNew(SNodeTitle, GraphNode); 37 | 38 | ContentScale.Bind(this, &SGraphNode::GetContentScale); 39 | GetOrAddSlot(ENodeZone::Center) 40 | .HAlign(HAlign_Fill) 41 | .VAlign(VAlign_Center) 42 | [ 43 | SNew(SBorder) 44 | .BorderImage(FAppStyle::GetBrush("Graph.StateNode.Body")) 45 | .Padding(0.0f) 46 | .BorderBackgroundColor(this, &SEdNode_ComboGraphNode::GetBorderBackgroundColor) 47 | [ 48 | SNew(SOverlay) 49 | + SOverlay::Slot() 50 | .HAlign(HAlign_Fill) 51 | .VAlign(VAlign_Fill) 52 | [ 53 | SNew(SVerticalBox) 54 | + SVerticalBox::Slot() 55 | .FillHeight(1) 56 | [ 57 | SAssignNew(LeftNodeBox, SVerticalBox) 58 | ] 59 | + SVerticalBox::Slot() 60 | .FillHeight(1) 61 | [ 62 | SAssignNew(RightNodeBox, SVerticalBox) 63 | ] 64 | ] 65 | + SOverlay::Slot() 66 | .HAlign(HAlign_Center) 67 | .VAlign(VAlign_Center) 68 | .Padding(8.0f) 69 | [ 70 | SNew(SBorder) 71 | .BorderImage(FAppStyle::GetBrush("Graph.StateNode.ColorSpill")) 72 | .BorderBackgroundColor(TitleShadowColor) 73 | .HAlign(HAlign_Center) 74 | .VAlign(VAlign_Center) 75 | .Visibility(EVisibility::SelfHitTestInvisible) 76 | .Padding(6.0f) 77 | [ 78 | SAssignNew(NodeBody, SVerticalBox) 79 | + SVerticalBox::Slot() 80 | .AutoHeight() 81 | [ 82 | SNew(SHorizontalBox) 83 | + SHorizontalBox::Slot() 84 | .AutoWidth() 85 | [ 86 | SAssignNew(ErrorText, SErrorText) 87 | .BackgroundColor(this, &SEdNode_ComboGraphNode::GetErrorColor) 88 | .ToolTipText(this, &SEdNode_ComboGraphNode::GetErrorMsgToolTip) 89 | ] 90 | + SHorizontalBox::Slot() 91 | .AutoWidth() 92 | .VAlign(VAlign_Center) 93 | [ 94 | SNew(SImage) 95 | .Image(NodeTypeIcon) 96 | ] 97 | + SHorizontalBox::Slot() 98 | .Padding(FMargin(4.0f, 0.0f, 4.0f, 0.0f)) 99 | [ 100 | SNew(SVerticalBox) 101 | + SVerticalBox::Slot() 102 | .AutoHeight() 103 | [ 104 | SAssignNew(InlineEditableText, SInlineEditableTextBlock) 105 | .Style(FAppStyle::Get(), "Graph.StateNode.NodeTitleInlineEditableText") 106 | .Text(NodeTitle.Get(), &SNodeTitle::GetHeadTitle) 107 | .OnVerifyTextChanged(this, &SEdNode_ComboGraphNode::OnVerifyNameTextChanged) 108 | .OnTextCommitted(this, &SEdNode_ComboGraphNode::OnNameTextCommited) 109 | .IsReadOnly(this, &SEdNode_ComboGraphNode::IsNameReadOnly) 110 | .IsSelected(this, &SEdNode_ComboGraphNode::IsSelectedExclusively) 111 | ] 112 | + SVerticalBox::Slot() 113 | .AutoHeight() 114 | [ 115 | NodeTitle.ToSharedRef() 116 | ] 117 | ] 118 | ] 119 | ] 120 | ] 121 | ] 122 | ]; 123 | 124 | TSharedPtr CommentBubble; 125 | const FSlateColor CommentColor = GetDefault()->DefaultCommentNodeTitleColor; 126 | 127 | SAssignNew(CommentBubble, SCommentBubble) 128 | .GraphNode(GraphNode) 129 | .Text(this, &SGraphNode::GetNodeComment) 130 | .OnTextCommitted(this, &SGraphNode::OnCommentTextCommitted) 131 | .ColorAndOpacity(CommentColor) 132 | .AllowPinning(true) 133 | .EnableTitleBarBubble(true) 134 | .EnableBubbleCtrls(true) 135 | .GraphLOD(this, &SGraphNode::GetCurrentLOD) 136 | .IsGraphNodeHovered(this, &SGraphNode::IsHovered); 137 | 138 | GetOrAddSlot(ENodeZone::TopCenter) 139 | .SlotOffset(TAttribute(CommentBubble.Get(), &SCommentBubble::GetOffset)) 140 | .SlotSize(TAttribute(CommentBubble.Get(), &SCommentBubble::GetSize)) 141 | .AllowScaling(TAttribute(CommentBubble.Get(), &SCommentBubble::IsScalingAllowed)) 142 | .VAlign(VAlign_Top) 143 | [ 144 | CommentBubble.ToSharedRef() 145 | ]; 146 | 147 | ErrorReporting = ErrorText; 148 | ErrorReporting->SetError(ErrorMsg); 149 | CreatePinWidgets(); 150 | } 151 | 152 | void SEdNode_ComboGraphNode::OnNameTextCommited(const FText& InText, ETextCommit::Type CommitInfo) 153 | { 154 | SGraphNode::OnNameTextCommited(InText, CommitInfo); 155 | 156 | if (UEdNode_ComboGraphNode* MyNode = CastChecked(GraphNode); 157 | MyNode && MyNode->ComboGraphNode) 158 | { 159 | const FScopedTransaction Transaction(LOCTEXT("ComboGraphEditorRenameNode", "Combo Graph Editor: Rename Node")); 160 | MyNode->Modify(); 161 | MyNode->ComboGraphNode->Modify(); 162 | MyNode->ComboGraphNode->SetNodeTitle(InText); 163 | UpdateGraphNode(); 164 | } 165 | } 166 | 167 | FSlateColor SEdNode_ComboGraphNode::GetBorderBackgroundColor() const 168 | { 169 | const UEdNode_ComboGraphNode* MyNode = CastChecked(GraphNode); 170 | return MyNode->GetBackgroundColor(); 171 | } 172 | 173 | FSlateColor SEdNode_ComboGraphNode::GetBackgroundColor() const 174 | { 175 | return FLinearColor(0.1f, 0.1f, 0.1f); 176 | } 177 | 178 | const FSlateBrush* SEdNode_ComboGraphNode::GetNameIcon() const 179 | { 180 | return FAppStyle::GetBrush(TEXT("BTEditor.Graph.BTNode.Icon")); 181 | } 182 | 183 | void SEdNode_ComboGraphNode::CreatePinWidgets() 184 | { 185 | UEdNode_ComboGraphNode* StateNode = CastChecked(GraphNode); 186 | 187 | for (int32 PinIdx = 0; PinIdx < StateNode->Pins.Num(); PinIdx++) 188 | { 189 | if (UEdGraphPin* MyPin = StateNode->Pins[PinIdx]; 190 | MyPin && !MyPin->bHidden) 191 | { 192 | TSharedPtr NewPin = SNew(SComboGraphPin, MyPin); 193 | 194 | AddPin(NewPin.ToSharedRef()); 195 | } 196 | } 197 | } 198 | 199 | void SEdNode_ComboGraphNode::AddPin(const TSharedRef& PinToAdd) 200 | { 201 | PinToAdd->SetOwner(SharedThis(this)); 202 | 203 | if (const UEdGraphPin* PinObj = PinToAdd->GetPinObj(); 204 | PinObj && PinObj->bAdvancedView) 205 | { 206 | PinToAdd->SetVisibility(TAttribute(PinToAdd, &SGraphPin::IsPinVisibleAsAdvanced)); 207 | } 208 | 209 | TSharedPtr PinBox; 210 | if (PinToAdd->GetDirection() == EGPD_Input) 211 | { 212 | PinBox = LeftNodeBox; 213 | InputPins.Add(PinToAdd); 214 | } 215 | else 216 | { 217 | PinBox = RightNodeBox; 218 | OutputPins.Add(PinToAdd); 219 | } 220 | 221 | if (PinBox) 222 | { 223 | PinBox->AddSlot() 224 | .HAlign(HAlign_Fill) 225 | .VAlign(VAlign_Fill) 226 | .FillHeight(1.0f) 227 | [ 228 | PinToAdd 229 | ]; 230 | } 231 | } 232 | 233 | #undef LOCTEXT_NAMESPACE 234 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Private/Validators/ComboGraphAssetValidator.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | 4 | #include "Validators/ComboGraphAssetValidator.h" 5 | 6 | #include "ComboGraph.h" 7 | #include "InputAction.h" 8 | #include "Misc/DataValidation.h" 9 | #include "Nodes/ComboGraphNode.h" 10 | #include "Nodes/ComboNodeType.h" 11 | 12 | #define LOCTEXT_NAMESPACE "ComboGraphEditorAssetValidator" 13 | 14 | bool UComboGraphAssetValidator::CanValidateAsset_Implementation(const FAssetData& InAssetData, UObject* InObject, 15 | FDataValidationContext& InContext) const 16 | { 17 | return InObject && InObject->IsA(); 18 | } 19 | 20 | EDataValidationResult UComboGraphAssetValidator::ValidateLoadedAsset_Implementation(const FAssetData& InAssetData, 21 | UObject* InAsset, FDataValidationContext& Context) 22 | { 23 | const UComboGraph* ComboGraph = Cast(InAsset); 24 | if (!ComboGraph) return EDataValidationResult::NotValidated; 25 | 26 | TMap Openers; 27 | 28 | for (UComboGraphNode* Node : ComboGraph->AllNodes) 29 | { 30 | if (Node->GetComboNodeType() == EComboNodeType::Opener && Node->InputAction) 31 | { 32 | if (const UComboGraphNode* FoundOpenerWithDuplicatedInputAction = Openers.FindRef(Node->InputAction); 33 | FoundOpenerWithDuplicatedInputAction) 34 | { 35 | const FText DuplicatedInputActionForOpenerError = FText::Format( 36 | LOCTEXT("ComboGraphValidationFailureDuplicatedInputActions", 37 | "Opener {0} can't have duplicated {1} Input Action. It is used by {2}"), 38 | Node->GetNodeTitle(), FText::FromString(Node->InputAction->GetName()), 39 | FoundOpenerWithDuplicatedInputAction->GetNodeTitle()); 40 | Context.AddError(DuplicatedInputActionForOpenerError); 41 | 42 | //reset property to avoid wrong data setup 43 | Node->InputAction = nullptr; 44 | } 45 | 46 | Openers.Add(Node->InputAction, Node); 47 | } 48 | } 49 | 50 | return Context.GetNumErrors() == 0 ? EDataValidationResult::Valid : EDataValidationResult::Invalid; 51 | } 52 | 53 | #undef LOCTEXT_NAMESPACE 54 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Public/AssetEditorToolbar_ComboGraph.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | 7 | class FToolBarBuilder; 8 | class FExtender; 9 | class FAssetEditor_ComboGraph; 10 | 11 | class COMBOGRAPHEDITOR_API FAssetEditorToolbar_ComboGraph : public TSharedFromThis 12 | { 13 | public: 14 | explicit FAssetEditorToolbar_ComboGraph(const TSharedPtr& InComboGraphEditor) 15 | : ComboGraphEditor(InComboGraphEditor) 16 | { 17 | } 18 | 19 | void AddComboGraphToolbar(TSharedPtr Extender); 20 | 21 | private: 22 | void FillComboGraphToolbar(FToolBarBuilder& ToolbarBuilder) const; 23 | 24 | protected: 25 | TWeakPtr ComboGraphEditor; 26 | }; 27 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Public/AssetEditor_ComboGraph.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Toolkits/AssetEditorToolkit.h" 7 | 8 | class UComboGraph; 9 | struct FGraphAppearanceInfo; 10 | class SGraphEditor; 11 | class FAssetEditorToolbar_ComboGraph; 12 | class UEdGraph_ComboGraph; 13 | 14 | class COMBOGRAPHEDITOR_API FAssetEditor_ComboGraph : public FAssetEditorToolkit, public FGCObject, 15 | public FEditorUndoClient 16 | { 17 | public: 18 | FAssetEditor_ComboGraph(); 19 | virtual ~FAssetEditor_ComboGraph() override; 20 | 21 | void InitComboGraphEditor(const EToolkitMode::Type Mode, const TSharedPtr& InitToolkitHost, 22 | UComboGraph* ComboGraph); 23 | 24 | TSharedRef CreateGraphEditorWidget(UEdGraph* InGraph); 25 | 26 | void OnSelectedNodesChanged(const TSet& Objects) const; 27 | 28 | void OnNodeDoubleClicked(UEdGraphNode* EdGraphNode) const; 29 | 30 | void OnNodeTitleCommitted(const FText& Text, ETextCommit::Type Arg, UEdGraphNode* EdGraphNode) const; 31 | 32 | bool InEditingMode(bool bGraphIsEditable) const; 33 | 34 | FGraphAppearanceInfo GetGraphAppearance() const; 35 | 36 | virtual FString GetReferencerName() const override; 37 | 38 | virtual FName GetToolkitFName() const override; 39 | 40 | virtual FText GetBaseToolkitName() const override; 41 | 42 | virtual FLinearColor GetWorldCentricTabColorScale() const override; 43 | 44 | virtual FString GetWorldCentricTabPrefix() const override; 45 | 46 | void OnPackageSaved(const FString& PackageFileName, UPackage* Outer, FObjectPostSaveContext SavedContext) const; 47 | 48 | virtual void SaveAsset_Execute() override; 49 | 50 | virtual void AddReferencedObjects(FReferenceCollector& Collector) override; 51 | 52 | protected: 53 | void CreateNewGraph() const; 54 | 55 | void CreateInternalWidgets(); 56 | 57 | void OnFinishedChangingProperties(const FPropertyChangedEvent& PropertyChangedEvent); 58 | 59 | virtual void RegisterTabSpawners(const TSharedRef& InTabManager) override; 60 | 61 | virtual void UnregisterTabSpawners(const TSharedRef& InTabManager) override; 62 | 63 | TSharedRef SpawnTab_Viewport(const FSpawnTabArgs& Args); 64 | 65 | TSharedRef SpawnTab_Details(const FSpawnTabArgs& Args) const; 66 | 67 | TSharedPtr ViewportWidget; 68 | 69 | TSharedPtr PropertyWidget; 70 | 71 | TObjectPtr EditingComboGraph; 72 | 73 | TSharedPtr ToolbarBuilder; 74 | 75 | FDelegateHandle OnPackageSavedDelegateHandle; 76 | 77 | TSharedPtr GraphEditorCommands; 78 | 79 | private: 80 | void CreateEditorCommands(); 81 | 82 | void RebuildComboGraph() const; 83 | 84 | #pragma region CommandList 85 | FGraphPanelSelectionSet GetSelectedNodes() const; 86 | 87 | void DeleteSelectedNodes(); 88 | 89 | bool CanDeleteNodes() const; 90 | 91 | void RenameNode(); 92 | 93 | bool CanRenameNode() const; 94 | #pragma region endregion 95 | }; 96 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Public/AssetSchemaActions/AssetSchemaAction_ComboGraph_NewEdge.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "UObject/Object.h" 7 | #include "AssetSchemaAction_ComboGraph_NewEdge.generated.h" 8 | class UEdNode_ComboGraphEdge; 9 | 10 | USTRUCT() 11 | struct COMBOGRAPHEDITOR_API FAssetSchemaAction_ComboGraph_NewEdge : public FEdGraphSchemaAction 12 | { 13 | GENERATED_USTRUCT_BODY() 14 | 15 | FAssetSchemaAction_ComboGraph_NewEdge(): NodeTemplate(nullptr) 16 | { 17 | } 18 | 19 | FAssetSchemaAction_ComboGraph_NewEdge(const FText& InNodeCategory, const FText& InMenuDesc, 20 | const FText& InToolTip, const int32 InGrouping) 21 | : FEdGraphSchemaAction(InNodeCategory, InMenuDesc, InToolTip, InGrouping), NodeTemplate(nullptr) 22 | { 23 | } 24 | 25 | virtual UEdGraphNode* PerformAction(UEdGraph* ParentGraph, UEdGraphPin* FromPin, const FVector2D Location, 26 | bool bSelectNewNode = true) override; 27 | 28 | 29 | virtual void AddReferencedObjects(FReferenceCollector& Collector) override; 30 | 31 | UPROPERTY() 32 | TObjectPtr NodeTemplate; 33 | }; 34 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Public/AssetSchemaActions/AssetSchemaAction_ComboGraph_NewNode.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "EdGraph/EdGraphSchema.h" 7 | #include "UObject/Object.h" 8 | #include "AssetSchemaAction_ComboGraph_NewNode.generated.h" 9 | 10 | class UEdNode_ComboGraphNode; 11 | 12 | USTRUCT() 13 | struct COMBOGRAPHEDITOR_API FAssetSchemaAction_ComboGraph_NewNode : public FEdGraphSchemaAction 14 | { 15 | GENERATED_USTRUCT_BODY() 16 | 17 | FAssetSchemaAction_ComboGraph_NewNode(): NodeTemplate(nullptr) 18 | { 19 | } 20 | 21 | FAssetSchemaAction_ComboGraph_NewNode(const FText& InNodeCategory, const FText& InMenuDesc, const FText& InToolTip, 22 | const int32 InGrouping) 23 | : FEdGraphSchemaAction(InNodeCategory, InMenuDesc, InToolTip, InGrouping), NodeTemplate(nullptr) 24 | { 25 | } 26 | 27 | virtual UEdGraphNode* PerformAction(UEdGraph* ParentGraph, UEdGraphPin* FromPin, const FVector2D Location, 28 | bool bSelectNewNode = true) override; 29 | 30 | virtual void AddReferencedObjects(FReferenceCollector& Collector) override; 31 | 32 | UPROPERTY() 33 | TObjectPtr NodeTemplate; 34 | }; 35 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Public/AssetTypeActions_ComboGraph.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "AssetTypeActions_Base.h" 7 | 8 | class COMBOGRAPHEDITOR_API FAssetTypeActions_ComboGraph : public FAssetTypeActions_Base 9 | { 10 | public: 11 | explicit FAssetTypeActions_ComboGraph(EAssetTypeCategories::Type InAssetCategory); 12 | 13 | virtual FText GetName() const override; 14 | 15 | virtual FColor GetTypeColor() const override; 16 | 17 | virtual UClass* GetSupportedClass() const override; 18 | 19 | virtual void OpenAssetEditor(const TArray& InObjects, 20 | TSharedPtr EditWithinLevelEditor = TSharedPtr()) override; 21 | 22 | virtual uint32 GetCategories() override; 23 | 24 | private: 25 | EAssetTypeCategories::Type MyAssetCategory; 26 | }; 27 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Public/ComboGraphEditorStyle.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Styling/SlateStyle.h" 7 | 8 | class COMBOGRAPHEDITOR_API FComboGraphEditorStyle 9 | { 10 | public: 11 | static void Initialize(); 12 | static void Shutdown(); 13 | 14 | static const FName& GetStyleSetName(); 15 | 16 | private: 17 | static TSharedPtr StyleSet; 18 | }; 19 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Public/ComboGraphEditorSummoner.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "WorkflowOrientedApp/WorkflowUObjectDocuments.h" 6 | 7 | class SGraphEditor; 8 | 9 | struct FComboGraphEditorSummoner : FDocumentTabFactoryForObjects 10 | { 11 | DECLARE_DELEGATE_RetVal_OneParam(TSharedRef, FOnCreateGraphEditorWidget, UEdGraph*); 12 | 13 | FComboGraphEditorSummoner(TSharedPtr InTestEditorPtr, 14 | FOnCreateGraphEditorWidget CreateGraphEditorWidgetCallback); 15 | 16 | virtual void OnTabActivated(TSharedPtr Tab) const override; 17 | 18 | virtual void OnTabRefreshed(TSharedPtr Tab) const override; 19 | 20 | protected: 21 | virtual TAttribute ConstructTabNameForObject(UEdGraph* DocumentID) const override; 22 | 23 | virtual TSharedRef 24 | CreateTabBodyForObject(const FWorkflowTabSpawnInfo& Info, UEdGraph* DocumentID) const override; 25 | }; 26 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Public/ComboGraphModule.h: -------------------------------------------------------------------------------- 1 | // Copyright Epic Games, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "AssetTypeCategories.h" 7 | #include "Modules/ModuleManager.h" 8 | 9 | struct FGraphPanelNodeFactory; 10 | class IAssetTypeActions; 11 | class IAssetTools; 12 | 13 | class FComboGraphModule : public IModuleInterface 14 | { 15 | public: 16 | virtual void StartupModule() override; 17 | virtual void ShutdownModule() override; 18 | 19 | private: 20 | void RegisterAssetTypeAction(IAssetTools& AssetTools, const TSharedRef& Action); 21 | 22 | TArray> CreatedAssetTypeActions; 23 | 24 | EAssetTypeCategories::Type ComboGraphGraphAssetCategoryBit; 25 | }; 26 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Public/DragDropActions/ComboEditorDragDropAction.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "GraphEditorDragDropAction.h" 7 | 8 | struct FGraphPinHandle; 9 | 10 | class FComboEditorDragDropAction : public FGraphEditorDragDropAction 11 | { 12 | public: 13 | DRAG_DROP_OPERATOR_TYPE(FDragConnection, FGraphEditorDragDropAction) 14 | 15 | typedef TArray FDraggedPinTable; 16 | 17 | static TSharedRef New(const TSharedRef& InGraphPanel, 18 | const FDraggedPinTable& InStartingPins); 19 | 20 | virtual void HoverTargetChanged() override; 21 | 22 | virtual void OnDrop(bool bDropWasHandled, const FPointerEvent& MouseEvent) override; 23 | 24 | virtual void OnDragged(const FDragDropEvent& DragDropEvent) override; 25 | 26 | virtual FReply DroppedOnPin(FVector2D ScreenPosition, FVector2D GraphPosition) override; 27 | 28 | virtual FReply DroppedOnNode(FVector2D ScreenPosition, FVector2D GraphPosition) override; 29 | 30 | virtual FReply DroppedOnPanel(const TSharedRef& Panel, FVector2D ScreenPosition, FVector2D GraphPosition, 31 | UEdGraph& Graph) override; 32 | 33 | void ValidateGraphPinList(TArray& OutValidPins); 34 | 35 | protected: 36 | FComboEditorDragDropAction(const TSharedRef& InGraphPanel, const FDraggedPinTable& InDraggedPins); 37 | 38 | TSharedPtr GraphPanel; 39 | FDraggedPinTable DraggingPins; 40 | 41 | FVector2D DecoratorAdjust; 42 | }; 43 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Public/DrawingPolicy/ComboGraphConnectionDrawingPolicy.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "ConnectionDrawingPolicy.h" 7 | 8 | class COMBOGRAPHEDITOR_API FComboGraphConnectionDrawingPolicy : public FConnectionDrawingPolicy 9 | { 10 | public: 11 | FComboGraphConnectionDrawingPolicy(int32 InBackLayerID, int32 InFrontLayerID, float ZoomFactor, 12 | const FSlateRect& InClippingRect, FSlateWindowElementList& InDrawElements, 13 | UEdGraph* InGraphObj); 14 | 15 | virtual void 16 | DetermineWiringStyle(UEdGraphPin* OutputPin, UEdGraphPin* InputPin, FConnectionParams& Params) override; 17 | 18 | virtual void Draw(TMap, FArrangedWidget>& InPinGeometries, 19 | FArrangedChildren& ArrangedNodes) override; 20 | 21 | virtual void DrawSplineWithArrow(const FGeometry& StartGeom, const FGeometry& EndGeom, 22 | const FConnectionParams& Params) override; 23 | 24 | virtual void DrawSplineWithArrow(const FVector2D& StartPoint, const FVector2D& EndPoint, 25 | const FConnectionParams& Params) override; 26 | 27 | virtual void DrawPreviewConnector(const FGeometry& PinGeometry, const FVector2D& StartPoint, 28 | const FVector2D& EndPoint, UEdGraphPin* Pin) override; 29 | 30 | virtual FVector2D ComputeSplineTangent(const FVector2D& Start, const FVector2D& End) const override; 31 | 32 | virtual void DetermineLinkGeometry(FArrangedChildren& ArrangedNodes, TSharedRef& OutputPinWidget, 33 | UEdGraphPin* OutputPin, UEdGraphPin* InputPin, 34 | FArrangedWidget*& StartWidgetGeometry, 35 | FArrangedWidget*& EndWidgetGeometry) override; 36 | 37 | protected: 38 | TObjectPtr Graph; 39 | 40 | TMap NodeWidgetMap; 41 | 42 | void Internal_DrawLineWithArrow(const FVector2D& StartAnchorPoint, const FVector2D& EndAnchorPoint, 43 | const FConnectionParams& Params); 44 | }; 45 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Public/EdGraphSchema_ComboGraph.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "EdGraph/EdGraphSchema.h" 7 | #include "EdGraphSchema_ComboGraph.generated.h" 8 | 9 | /** 10 | * 11 | */ 12 | UCLASS() 13 | class COMBOGRAPHEDITOR_API UEdGraphSchema_ComboGraph : public UEdGraphSchema 14 | { 15 | GENERATED_BODY() 16 | 17 | virtual void CreateDefaultNodesForGraph(UEdGraph& Graph) const override; 18 | 19 | virtual void GetGraphContextActions(FGraphContextMenuBuilder& ContextMenuBuilder) const override; 20 | 21 | virtual void GetContextMenuActions(UToolMenu* Menu, UGraphNodeContextMenuContext* Context) const override; 22 | 23 | virtual const FPinConnectionResponse CanCreateConnection(const UEdGraphPin* A, const UEdGraphPin* B) const override; 24 | 25 | virtual bool TryCreateConnection(UEdGraphPin* A, UEdGraphPin* B) const override; 26 | 27 | virtual bool CreateAutomaticConversionNodeAndConnections(UEdGraphPin* A, UEdGraphPin* B) const override; 28 | 29 | virtual TSharedPtr GetCreateCommentAction() const override; 30 | 31 | void GetBreakLinkToSubMenuActions(UToolMenu* Menu, UEdGraphPin* InGraphPin); 32 | 33 | virtual FConnectionDrawingPolicy* CreateConnectionDrawingPolicy(int32 InBackLayerID, int32 InFrontLayerID, 34 | float InZoomFactor, 35 | const FSlateRect& InClippingRect, 36 | FSlateWindowElementList& InDrawElements, 37 | UEdGraph* InGraphObj) const override; 38 | }; 39 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Public/EdGraph_ComboGraph.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "EdGraph/EdGraph.h" 7 | #include "EdGraph_ComboGraph.generated.h" 8 | 9 | class UEdNode_ComboGraphEdge; 10 | class UEdNode_ComboGraphNode; 11 | class UComboGraphEdge; 12 | class UComboGraphNode; 13 | class UComboGraph; 14 | /** 15 | * 16 | */ 17 | UCLASS() 18 | class COMBOGRAPHEDITOR_API UEdGraph_ComboGraph : public UEdGraph 19 | { 20 | GENERATED_BODY() 21 | 22 | public: 23 | UEdGraph_ComboGraph(); 24 | virtual ~UEdGraph_ComboGraph() override; 25 | 26 | TObjectPtr GetComboGraph() const; 27 | 28 | virtual void RebuildComboGraph(); 29 | 30 | virtual bool Modify(bool bAlwaysMarkDirty = true) override; 31 | 32 | virtual void PostEditUndo() override; 33 | 34 | UPROPERTY(Transient) 35 | TMap, TObjectPtr> NodeMap; 36 | 37 | UPROPERTY(Transient) 38 | TMap, TObjectPtr> EdgeMap; 39 | 40 | protected: 41 | void Clear(); 42 | }; 43 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Public/EdNode_ComboGraphEdge.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "EdGraph/EdGraphNode.h" 7 | #include "EdNode_ComboGraphEdge.generated.h" 8 | 9 | class UEdNode_ComboGraphNode; 10 | class UComboGraphEdge; 11 | 12 | /** 13 | * 14 | */ 15 | UCLASS(MinimalAPI) 16 | class UEdNode_ComboGraphEdge : public UEdGraphNode 17 | { 18 | GENERATED_BODY() 19 | 20 | public: 21 | UEdNode_ComboGraphEdge(); 22 | 23 | UPROPERTY() 24 | TObjectPtr Graph = nullptr; 25 | 26 | UPROPERTY(VisibleAnywhere, Instanced, Category = "ComboGraph") 27 | TObjectPtr ComboGraphEdge = nullptr; 28 | 29 | void SetEdge(UComboGraphEdge* NewEdge) { ComboGraphEdge = NewEdge; } 30 | 31 | virtual void AllocateDefaultPins() override; 32 | 33 | virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override; 34 | 35 | virtual void PinConnectionListChanged(UEdGraphPin* Pin) override; 36 | 37 | virtual void PrepareForCopying() override; 38 | 39 | virtual UEdGraphPin* GetInputPin() const { return Pins[0]; } 40 | 41 | virtual UEdGraphPin* GetOutputPin() const { return Pins[1]; } 42 | 43 | void CreateConnections(const UEdNode_ComboGraphNode* Start, UEdNode_ComboGraphNode* End); 44 | 45 | UEdNode_ComboGraphNode* GetStartNode(); 46 | 47 | UEdNode_ComboGraphNode* GetEndNode(); 48 | }; 49 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Public/EdNode_ComboGraphNode.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "EdGraph/EdGraphNode.h" 7 | #include "EdNode_ComboGraphNode.generated.h" 8 | 9 | class UComboGraphNode; 10 | class SEdNode_ComboGraphNode; 11 | /** 12 | * 13 | */ 14 | UCLASS(MinimalAPI) 15 | class UEdNode_ComboGraphNode : public UEdGraphNode 16 | { 17 | GENERATED_BODY() 18 | 19 | public: 20 | UEdNode_ComboGraphNode(); 21 | virtual ~UEdNode_ComboGraphNode() override; 22 | 23 | UPROPERTY(VisibleAnywhere, Instanced, Category = "ComboGraph") 24 | TObjectPtr ComboGraphNode; 25 | 26 | SEdNode_ComboGraphNode* SEdNode; 27 | 28 | UEdGraphPin* GetInputPin() const; 29 | 30 | UEdGraphPin* GetOutputPin() const; 31 | 32 | virtual FLinearColor GetBackgroundColor() const; 33 | 34 | virtual void AllocateDefaultPins() override; 35 | 36 | virtual void AutowireNewNode(UEdGraphPin* FromPin) override; 37 | 38 | virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override; 39 | }; 40 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Public/EditorCommands_ComboGraph.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Framework/Commands/Commands.h" 7 | 8 | class COMBOGRAPHEDITOR_API FEditorCommands_ComboGraph : public TCommands 9 | { 10 | public: 11 | FEditorCommands_ComboGraph(): TCommands("ComboGraphEditor", 12 | NSLOCTEXT("Contexts", "ComboGraphEditor", "Combo Graph Editor"), 13 | NAME_None, FAppStyle::GetAppStyleSetName()) 14 | { 15 | } 16 | 17 | TSharedPtr GraphSettings; 18 | TSharedPtr AutoArrange; 19 | 20 | virtual void RegisterCommands() override; 21 | }; 22 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Public/Factories/ComboGraphFactory.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Factories/Factory.h" 7 | #include "UObject/Object.h" 8 | #include "ComboGraphFactory.generated.h" 9 | 10 | class UEdGraph_ComboGraph; 11 | /** 12 | * 13 | */ 14 | UCLASS(MinimalAPI, hidecategories=Object) 15 | class UComboGraphFactory : public UFactory 16 | { 17 | GENERATED_UCLASS_BODY() 18 | 19 | UPROPERTY(EditAnywhere, Category = DataAsset) 20 | TSubclassOf ComboGraphClass; 21 | 22 | virtual bool ConfigureProperties() override; 23 | virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, 24 | UObject* Context, FFeedbackContext* Warn) override; 25 | }; 26 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Public/Factories/GraphPanelNodeFactory_ComboGraph.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "EdGraphUtilities.h" 6 | 7 | class COMBOGRAPHEDITOR_API FGraphPanelNodeFactory_ComboGraph : public FGraphPanelNodeFactory 8 | { 9 | virtual TSharedPtr CreateNode(UEdGraphNode* Node) const override; 10 | }; 11 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Public/Pins/ComboGraphPin.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "SGraphPin.h" 7 | #include "DragDropActions/ComboEditorDragDropAction.h" 8 | 9 | class SComboGraphPin : public SGraphPin 10 | { 11 | public: 12 | SLATE_BEGIN_ARGS(SComboGraphPin) 13 | { 14 | } 15 | 16 | SLATE_END_ARGS() 17 | 18 | void Construct(const FArguments& InArgs, UEdGraphPin* InPin) 19 | { 20 | this->SetCursor(EMouseCursor::Default); 21 | 22 | bShowLabel = true; 23 | 24 | GraphPinObj = InPin; 25 | check(GraphPinObj != nullptr); 26 | 27 | const UEdGraphSchema* Schema = GraphPinObj->GetSchema(); 28 | check(Schema); 29 | 30 | SBorder::Construct(SBorder::FArguments() 31 | .BorderImage(this, &SComboGraphPin::GetPinBorder) 32 | .BorderBackgroundColor(this, &SComboGraphPin::GetPinColor) 33 | .OnMouseButtonDown(this, &SComboGraphPin::OnPinMouseDown) 34 | .Cursor(this, &SComboGraphPin::GetPinCursor) 35 | .Padding(FMargin(5.0f)) 36 | ); 37 | } 38 | 39 | protected: 40 | virtual FSlateColor GetPinColor() const override 41 | { 42 | return FLinearColor(0.02f, 0.02f, 0.02f); 43 | } 44 | 45 | virtual TSharedRef GetDefaultValueWidget() override 46 | { 47 | return SNew(STextBlock); 48 | } 49 | 50 | const FSlateBrush* GetPinBorder() const 51 | { 52 | return FAppStyle::GetBrush(TEXT("Graph.StateNode.Body")); 53 | } 54 | 55 | virtual TSharedRef SpawnPinDragEvent(const TSharedRef& InGraphPanel, 56 | const TArray>& 57 | InStartingPins) override 58 | { 59 | FComboEditorDragDropAction::FDraggedPinTable PinHandles; 60 | PinHandles.Reserve(InStartingPins.Num()); 61 | for (const TSharedRef& PinWidget : InStartingPins) 62 | { 63 | PinHandles.Add(PinWidget->GetPinObj()); 64 | } 65 | 66 | return FComboEditorDragDropAction::New(InGraphPanel, PinHandles); 67 | } 68 | }; 69 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Public/SEdNode_ComboGraphEdge.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "SGraphNode.h" 7 | #include "EdGraph/EdGraphNode.h" 8 | 9 | class UEdNode_ComboGraphEdge; 10 | /** 11 | * 12 | */ 13 | class COMBOGRAPHEDITOR_API SEdNode_ComboGraphEdge : public SGraphNode 14 | { 15 | public: 16 | SLATE_BEGIN_ARGS(SEdNode_ComboGraphEdge) 17 | { 18 | } 19 | 20 | SLATE_END_ARGS() 21 | 22 | void Construct(const FArguments& InArgs, UEdNode_ComboGraphEdge* InNode); 23 | 24 | virtual bool RequiresSecondPassLayout() const override; 25 | 26 | virtual void PerformSecondPassLayout(const TMap>& NodeToWidgetLookup) const override; 27 | 28 | virtual void UpdateGraphNode() override; 29 | 30 | void PositionBetweenTwoNodesWithOffset(const FGeometry& StartGeom, const FGeometry& EndGeom, int32 NodeIndex, 31 | int32 MaxNodes) const; 32 | 33 | void OnNameTextCommited(const FText& InText, ETextCommit::Type CommitInfo); 34 | 35 | protected: 36 | FSlateColor GetEdgeColor() const; 37 | 38 | const FSlateBrush* GetEdgeImage() const; 39 | 40 | EVisibility GetEdgeImageVisibility() const; 41 | 42 | EVisibility GetEdgeTitleVisibility() const; 43 | 44 | private: 45 | TSharedPtr TextEntryWidget; 46 | }; 47 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Public/SEdNode_ComboGraphNode.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "SGraphNode.h" 7 | 8 | class UEdNode_ComboGraphNode; 9 | 10 | class COMBOGRAPHEDITOR_API SEdNode_ComboGraphNode : public SGraphNode 11 | { 12 | public: 13 | SLATE_BEGIN_ARGS(SEdNode_ComboGraphNode) 14 | { 15 | } 16 | 17 | SLATE_END_ARGS() 18 | 19 | void Construct(const FArguments& InArgs, UEdNode_ComboGraphNode* InNode); 20 | 21 | virtual void UpdateGraphNode() override; 22 | 23 | void OnNameTextCommited(const FText& InText, ETextCommit::Type CommitInfo); 24 | 25 | virtual FSlateColor GetBorderBackgroundColor() const; 26 | 27 | virtual FSlateColor GetBackgroundColor() const; 28 | 29 | virtual const FSlateBrush* GetNameIcon() const; 30 | 31 | virtual void CreatePinWidgets() override; 32 | 33 | virtual void AddPin(const TSharedRef& PinToAdd) override; 34 | }; 35 | -------------------------------------------------------------------------------- /Source/ComboGraphEditor/Public/Validators/ComboGraphAssetValidator.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "EditorValidatorBase.h" 7 | 8 | #include "ComboGraphAssetValidator.generated.h" 9 | 10 | /** 11 | * 12 | */ 13 | UCLASS() 14 | class COMBOGRAPHEDITOR_API UComboGraphAssetValidator : public UEditorValidatorBase 15 | { 16 | GENERATED_BODY() 17 | 18 | public: 19 | virtual bool CanValidateAsset_Implementation(const FAssetData& InAssetData, UObject* InObject, 20 | FDataValidationContext& InContext) const override; 21 | 22 | virtual EDataValidationResult ValidateLoadedAsset_Implementation(const FAssetData& InAssetData, UObject* InAsset, 23 | FDataValidationContext& Context) override; 24 | }; 25 | -------------------------------------------------------------------------------- /Source/ComboGraphRuntime/ComboGraphRuntime.Build.cs: -------------------------------------------------------------------------------- 1 | using UnrealBuildTool; 2 | 3 | public class ComboGraphRuntime : ModuleRules 4 | { 5 | public ComboGraphRuntime(ReadOnlyTargetRules Target) : base(Target) 6 | { 7 | PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; 8 | 9 | PrivateIncludePaths.AddRange( 10 | new string[] 11 | { 12 | "ComboGraphRuntime/Private" 13 | } 14 | ); 15 | 16 | PublicDependencyModuleNames.AddRange( 17 | new string[] 18 | { 19 | "Core", 20 | "CoreUObject", 21 | "Engine", 22 | "EnhancedInput" 23 | } 24 | ); 25 | 26 | PrivateDependencyModuleNames.AddRange( 27 | new string[] 28 | { 29 | "Slate", 30 | "SlateCore", 31 | "AnimGraphRuntime" 32 | } 33 | ); 34 | } 35 | } -------------------------------------------------------------------------------- /Source/ComboGraphRuntime/Private/Animations/NotifyStates/CanContinueComboNotifyState.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | 4 | #include "Animations/NotifyStates/CanContinueComboNotifyState.h" 5 | 6 | #include "ComboGraphRuntimeLog.h" 7 | #include "Components/ComboHandlerComponent.h" 8 | #include "Interfaces/ComboHandlerInterface.h" 9 | 10 | void UCanContinueComboNotifyState::NotifyBegin(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, 11 | float TotalDuration, const FAnimNotifyEventReference& EventReference) 12 | { 13 | if (UNLIKELY(!MeshComp)) 14 | { 15 | UE_LOG(ComboGraphRuntimeLog, Warning, TEXT("[%hs]: get invalid MeshComp"), __FUNCTION__) 16 | return; 17 | } 18 | 19 | Super::NotifyBegin(MeshComp, Animation, TotalDuration, EventReference); 20 | 21 | if (!MeshComp->GetOwner()) 22 | { 23 | UE_LOG(ComboGraphRuntimeLog, Display, TEXT("[%hs]: no Owner for MeshCom"), __FUNCTION__) 24 | return; 25 | } 26 | 27 | if (const IComboHandlerInterface* AsComboHandlerInterface = Cast(MeshComp->GetOwner())) 28 | { 29 | AsComboHandlerInterface->GetComboHandlerComponent()->SetCanContinueCombo(true); 30 | } 31 | else 32 | { 33 | UE_LOG(ComboGraphRuntimeLog, Warning, 34 | TEXT("[%hs]: used for character %s which is not implement IComboHandlerInterface"), __FUNCTION__, 35 | *MeshComp->GetOwner()->GetName()) 36 | } 37 | } 38 | 39 | void UCanContinueComboNotifyState::NotifyEnd(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, 40 | const FAnimNotifyEventReference& EventReference) 41 | { 42 | if (UNLIKELY(!MeshComp)) 43 | { 44 | UE_LOG(ComboGraphRuntimeLog, Warning, TEXT("[%hs]: get invalid MeshComp"), __FUNCTION__) 45 | return; 46 | } 47 | 48 | Super::NotifyEnd(MeshComp, Animation, EventReference); 49 | 50 | if (!MeshComp->GetOwner()) 51 | { 52 | UE_LOG(ComboGraphRuntimeLog, Display, TEXT("[%hs]: no Owner for MeshCom"), __FUNCTION__) 53 | return; 54 | } 55 | 56 | if (const IComboHandlerInterface* AsComboHandlerInterface = Cast(MeshComp->GetOwner())) 57 | { 58 | AsComboHandlerInterface->GetComboHandlerComponent()->SetCanContinueCombo(false); 59 | } 60 | else 61 | { 62 | UE_LOG(ComboGraphRuntimeLog, Warning, 63 | TEXT("[%hs]: used for character %s which is not implement IComboHandlerInterface"), __FUNCTION__, 64 | *MeshComp->GetOwner()->GetName()) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Source/ComboGraphRuntime/Private/ComboGraph.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | 4 | #include "ComboGraph.h" 5 | #include "ComboGraphEdge.h" 6 | #include "Nodes/ComboGraphNode.h" 7 | 8 | UComboGraph::UComboGraph() 9 | { 10 | NodeType = UComboGraphNode::StaticClass(); 11 | EdgeType = UComboGraphEdge::StaticClass(); 12 | 13 | bEdgeEnabled = true; 14 | 15 | #if WITH_EDITORONLY_DATA 16 | EdGraph = nullptr; 17 | #endif 18 | } 19 | 20 | void UComboGraph::ClearGraph() 21 | { 22 | for (UComboGraphNode* ComboGraphNode : AllNodes) 23 | { 24 | ComboGraphNode->ParentNodes.Empty(); 25 | ComboGraphNode->ChildrenNodes.Empty(); 26 | ComboGraphNode->Edges.Empty(); 27 | } 28 | 29 | AllNodes.Empty(); 30 | } 31 | -------------------------------------------------------------------------------- /Source/ComboGraphRuntime/Private/ComboGraphEdge.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | 4 | #include "ComboGraphEdge.h" 5 | 6 | UComboGraphEdge::UComboGraphEdge() 7 | { 8 | } 9 | 10 | UComboGraphEdge::~UComboGraphEdge() 11 | { 12 | } 13 | -------------------------------------------------------------------------------- /Source/ComboGraphRuntime/Private/ComboGraphRuntime.cpp: -------------------------------------------------------------------------------- 1 | #include "ComboGraphRuntime.h" 2 | 3 | #define LOCTEXT_NAMESPACE "FComboGraphRuntimeModule" 4 | 5 | void FComboGraphRuntimeModule::StartupModule() 6 | { 7 | 8 | } 9 | 10 | void FComboGraphRuntimeModule::ShutdownModule() 11 | { 12 | 13 | } 14 | 15 | #undef LOCTEXT_NAMESPACE 16 | 17 | IMPLEMENT_MODULE(FComboGraphRuntimeModule, ComboGraphRuntime) -------------------------------------------------------------------------------- /Source/ComboGraphRuntime/Private/ComboGraphRuntimeLog.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | 4 | #include "ComboGraphRuntimeLog.h" 5 | 6 | DEFINE_LOG_CATEGORY(ComboGraphRuntimeLog); -------------------------------------------------------------------------------- /Source/ComboGraphRuntime/Private/Components/ComboHandlerComponent.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | 4 | #include "Components/ComboHandlerComponent.h" 5 | 6 | #include "ComboGraph.h" 7 | #include "ComboGraphRuntimeLog.h" 8 | #include "EnhancedInputComponent.h" 9 | #include "EnhancedInputSubsystems.h" 10 | #include "InputAction.h" 11 | #include "InputMappingContext.h" 12 | #include "PlayMontageCallbackProxy.h" 13 | #include "GameFramework/Character.h" 14 | #include "Nodes/ComboGraphOpenerNode.h" 15 | 16 | UComboHandlerComponent::UComboHandlerComponent() 17 | { 18 | PrimaryComponentTick.bCanEverTick = false; 19 | } 20 | 21 | void UComboHandlerComponent::BeginPlay() 22 | { 23 | Super::BeginPlay(); 24 | 25 | if (!ComboInputMappingContext) 26 | { 27 | UE_LOG(ComboGraphRuntimeLog, Error, TEXT("[%s - %hs]: have invalid ComboInputMappingContext"), 28 | *GetOwner()->GetName(), __FUNCTION__) 29 | return; 30 | } 31 | 32 | OwnerCharacter = Cast(GetOwner()); 33 | if (!OwnerCharacter) 34 | { 35 | UE_LOG(ComboGraphRuntimeLog, Error, TEXT("[%s - %hs]: can't process combos for non-character owner"), 36 | *GetOwner()->GetName(), __FUNCTION__) 37 | return; 38 | } 39 | 40 | const APlayerController* PlayerController = Cast(OwnerCharacter->GetInstigatorController()); 41 | if (!PlayerController) 42 | { 43 | UE_LOG(ComboGraphRuntimeLog, Error, TEXT("[%s - %hs]: can't bind inputs to owner without PlayerController"), 44 | *OwnerCharacter->GetName(), __FUNCTION__) 45 | return; 46 | } 47 | 48 | UEnhancedInputLocalPlayerSubsystem* EnhancedInputLocalPlayerSubsystem = ULocalPlayer::GetSubsystem< 49 | UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()); 50 | if (!EnhancedInputLocalPlayerSubsystem) 51 | { 52 | UE_LOG(ComboGraphRuntimeLog, Error, 53 | TEXT("[%s - %hs]: can't bind inputs to owner without EnhancedInputLocalPlayerSubsystem"), 54 | *OwnerCharacter->GetName(), __FUNCTION__) 55 | return; 56 | } 57 | 58 | EnhancedInputLocalPlayerSubsystem->AddMappingContext(ComboInputMappingContext, 0); 59 | 60 | UEnhancedInputComponent* EnhancedInputComponent = Cast(OwnerCharacter->InputComponent); 61 | if (!EnhancedInputComponent) 62 | { 63 | UE_LOG(ComboGraphRuntimeLog, Error, 64 | TEXT("[%s - %hs]: can't bind inputs to owner without UEnhancedInputComponent"), *GetOwner()->GetName(), 65 | __FUNCTION__) 66 | return; 67 | } 68 | 69 | //prevent duplicated mappings (e.g. AttackOne for gamepad and keyboard should be treated as one input) 70 | TSet BoundActions; 71 | for (const FEnhancedActionKeyMapping& Mapping : ComboInputMappingContext->GetMappings()) 72 | { 73 | if (Mapping.Action && !BoundActions.Contains(Mapping.Action)) 74 | { 75 | BoundActions.Add(Mapping.Action); 76 | 77 | EnhancedInputComponent->BindAction(Mapping.Action, TriggerEventToProcessCombo, this, 78 | &ThisClass::OnAnyInputActionTriggered); 79 | } 80 | } 81 | } 82 | 83 | void UComboHandlerComponent::OnAnyInputActionTriggered(const FInputActionInstance& ActionInstance) 84 | { 85 | ProcessComboAttack(ActionInstance.GetSourceAction()); 86 | } 87 | 88 | void UComboHandlerComponent::ProcessComboAttack(const UInputAction* InputAction) 89 | { 90 | if (bIsComboActive) 91 | { 92 | if (!bCanContinueCombo) 93 | { 94 | UE_LOG(ComboGraphRuntimeLog, Display, TEXT("[%s - %hs]: can't continue combo"), 95 | *GetOwner()->GetName(), __FUNCTION__) 96 | return; 97 | } 98 | 99 | CurrentComboGraphAttack = FindNextAttackForCombo(CurrentComboGraphAttack, InputAction); 100 | } 101 | else 102 | { 103 | CurrentComboGraphAttack = FindOpenerForInputAction(InputAction); 104 | } 105 | 106 | if (!CurrentComboGraphAttack) 107 | { 108 | UE_LOG(ComboGraphRuntimeLog, Display, TEXT("[%s - %hs]: could not suitable CurrentComboGraphAttack"), 109 | *GetOwner()->GetName(), __FUNCTION__) 110 | return; 111 | } 112 | 113 | PlayComboMontage(CurrentComboGraphAttack); 114 | } 115 | 116 | UComboGraphNode* UComboHandlerComponent::FindOpenerForInputAction(const UInputAction* InputAction) const 117 | { 118 | if (!ComboGraph) 119 | { 120 | UE_LOG(ComboGraphRuntimeLog, Error, TEXT("[%s - %hs]: have invalid ComboGraph"), *GetOwner()->GetName(), 121 | __FUNCTION__) 122 | return nullptr; 123 | } 124 | 125 | for (UComboGraphNode* ComboGraphNode : ComboGraph->AllNodes) 126 | { 127 | if (ComboGraphNode->IsA() && ComboGraphNode->InputAction == InputAction) 128 | { 129 | return ComboGraphNode; 130 | } 131 | } 132 | 133 | UE_LOG(ComboGraphRuntimeLog, Display, TEXT("[%s - %hs]: can't find opener with %s InputAction"), 134 | *GetOwner()->GetName(), __FUNCTION__, *InputAction->GetName()) 135 | return nullptr; 136 | } 137 | 138 | UComboGraphNode* UComboHandlerComponent::FindNextAttackForCombo(const UComboGraphNode* CurrentComboGraphNode, 139 | const UInputAction* InputAction) const 140 | { 141 | if (!CurrentComboGraphNode) 142 | { 143 | UE_LOG(ComboGraphRuntimeLog, Warning, TEXT("[%s - %hs]: get invalid CurrentComboGraphNode"), 144 | *GetOwner()->GetName(), __FUNCTION__) 145 | return nullptr; 146 | } 147 | 148 | for (UComboGraphNode* ComboGraphNode : CurrentComboGraphNode->ChildrenNodes) 149 | { 150 | if (ComboGraphNode->InputAction == InputAction) 151 | { 152 | return ComboGraphNode; 153 | } 154 | } 155 | 156 | UE_LOG(ComboGraphRuntimeLog, Display, TEXT("[%s - %hs]: can't find next combo sequence attack"), 157 | *GetOwner()->GetName(), 158 | __FUNCTION__) 159 | return nullptr; 160 | } 161 | 162 | void UComboHandlerComponent::PlayComboMontage(const UComboGraphNode* ComboGraphNode) 163 | { 164 | if (!ComboGraphNode) 165 | { 166 | UE_LOG(ComboGraphRuntimeLog, Warning, TEXT("[%s - %hs]: get invalid ComboGraphNode"), *GetOwner()->GetName(), 167 | __FUNCTION__) 168 | return; 169 | } 170 | 171 | if (!ComboGraphNode->ComboMontage) 172 | { 173 | UE_LOG(ComboGraphRuntimeLog, Warning, TEXT("[%s - %hs]: get ComboGraphNode %s with invalid ComboMontage"), 174 | *GetOwner()->GetName(), __FUNCTION__, *ComboGraphNode->GetName()) 175 | return; 176 | } 177 | 178 | PlayMontageCallbackProxy = UPlayMontageCallbackProxy::CreateProxyObjectForPlayMontage( 179 | OwnerCharacter->GetMesh(), ComboGraphNode->ComboMontage); 180 | PlayMontageCallbackProxy->OnBlendOut.AddDynamic(this, &ThisClass::OnMontageBlendOut); 181 | PlayMontageCallbackProxy->OnInterrupted.AddDynamic(this, &ThisClass::OnMontageInterrupted); 182 | PlayMontageCallbackProxy->OnCompleted.AddDynamic(this, &ThisClass::OnMontageCompleted); 183 | 184 | bIsComboActive |= true; 185 | 186 | UE_LOG(ComboGraphRuntimeLog, Display, TEXT("[%s - %hs]: play combo montage %s"), *GetOwner()->GetName(), 187 | __FUNCTION__, *ComboGraphNode->ComboMontage->GetName()) 188 | } 189 | 190 | void UComboHandlerComponent::OnMontageBlendOut(FName NotifyName) 191 | { 192 | UE_LOG(ComboGraphRuntimeLog, Display, TEXT("[%s - %hs]: combo sequence get montage blend out"), 193 | *GetOwner()->GetName(), __FUNCTION__) 194 | } 195 | 196 | void UComboHandlerComponent::OnMontageInterrupted(FName NotifyName) 197 | { 198 | UE_LOG(ComboGraphRuntimeLog, Display, TEXT("[%s - %hs]: combo sequence get montage interrupted"), 199 | *GetOwner()->GetName(), __FUNCTION__) 200 | 201 | bIsComboActive = false; 202 | } 203 | 204 | void UComboHandlerComponent::OnMontageCompleted(FName NotifyName) 205 | { 206 | UE_LOG(ComboGraphRuntimeLog, Display, TEXT("[%s - %hs]: combo sequence get montage completed"), 207 | *GetOwner()->GetName(), __FUNCTION__) 208 | 209 | bIsComboActive = false; 210 | } 211 | -------------------------------------------------------------------------------- /Source/ComboGraphRuntime/Private/Nodes/ComboGraphEnderNode.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | 4 | #include "..\..\Public\Nodes\ComboGraphEnderNode.h" 5 | #include "ComboGraph.h" 6 | 7 | #define LOCTEXT_NAMESPACE "ComboGraphNode" 8 | 9 | UComboGraphEnderNode::UComboGraphEnderNode() 10 | { 11 | #if WITH_EDITORONLY_DATA 12 | CompatibleGraphType = UComboGraph::StaticClass(); 13 | 14 | BackgroundColor = FColor::Green; 15 | 16 | ContextMenuName = LOCTEXT("ContextMenuName", "Ender"); 17 | #endif 18 | 19 | ComboNodeType = EComboNodeType::Ender; 20 | } 21 | 22 | UComboGraphEnderNode::~UComboGraphEnderNode() 23 | { 24 | } 25 | 26 | #if WITH_EDITOR 27 | FText UComboGraphEnderNode::GetNodeTitle() const 28 | { 29 | return NodeTitle.IsEmpty() ? LOCTEXT("NodeDesc", "Ender") : NodeTitle; 30 | } 31 | 32 | bool UComboGraphEnderNode::CanCreateConnectionFrom(UComboGraphNode* Other, int32 NumberOfParentNodes, 33 | FText& ErrorMessage) 34 | { 35 | return Other->GetComboNodeType() == EComboNodeType::Midler; 36 | } 37 | 38 | bool UComboGraphEnderNode::CanCreateConnectionTo(UComboGraphNode* Other, int32 NumberOfChildrenNodes, 39 | FText& ErrorMessage) 40 | { 41 | return false; 42 | } 43 | #endif 44 | 45 | #undef LOCTEXT_NAMESPACE 46 | -------------------------------------------------------------------------------- /Source/ComboGraphRuntime/Private/Nodes/ComboGraphMidlerNode.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | 4 | #include "Nodes/ComboGraphMidlerNode.h" 5 | #include "ComboGraph.h" 6 | 7 | #define LOCTEXT_NAMESPACE "ComboGraphNode" 8 | 9 | UComboGraphMidlerNode::UComboGraphMidlerNode() 10 | { 11 | #if WITH_EDITORONLY_DATA 12 | CompatibleGraphType = UComboGraph::StaticClass(); 13 | 14 | BackgroundColor = FColor::Red; 15 | 16 | ContextMenuName = LOCTEXT("ContextMenuName", "Midler"); 17 | #endif 18 | 19 | ComboNodeType = EComboNodeType::Midler; 20 | } 21 | 22 | UComboGraphMidlerNode::~UComboGraphMidlerNode() 23 | { 24 | } 25 | 26 | #if WITH_EDITOR 27 | FText UComboGraphMidlerNode::GetNodeTitle() const 28 | { 29 | return NodeTitle.IsEmpty() ? LOCTEXT("NodeDesc", "Midler") : NodeTitle; 30 | } 31 | 32 | bool UComboGraphMidlerNode::CanCreateConnectionFrom(UComboGraphNode* Other, int32 NumberOfParentNodes, 33 | FText& ErrorMessage) 34 | { 35 | return Other->GetComboNodeType() == EComboNodeType::Opener || Other->GetComboNodeType() == EComboNodeType::Midler; 36 | } 37 | 38 | bool UComboGraphMidlerNode::CanCreateConnectionTo(UComboGraphNode* Other, int32 NumberOfChildrenNodes, 39 | FText& ErrorMessage) 40 | { 41 | return Other->GetComboNodeType() == EComboNodeType::Midler || Other->GetComboNodeType() == EComboNodeType::Ender; 42 | } 43 | #endif 44 | 45 | #undef LOCTEXT_NAMESPACE 46 | -------------------------------------------------------------------------------- /Source/ComboGraphRuntime/Private/Nodes/ComboGraphNode.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | 4 | #include "Nodes/ComboGraphNode.h" 5 | #include "ComboGraph.h" 6 | 7 | #define LOCTEXT_NAMESPACE "ComboGraphNode" 8 | 9 | UComboGraphNode::UComboGraphNode() 10 | { 11 | #if WITH_EDITORONLY_DATA 12 | CompatibleGraphType = UComboGraph::StaticClass(); 13 | 14 | ContextMenuName = LOCTEXT("ContextMenuName", "Combo Graph Node"); 15 | #endif 16 | } 17 | 18 | UComboGraphNode::~UComboGraphNode() 19 | { 20 | } 21 | 22 | UComboGraphEdge* UComboGraphNode::GetEdge(UComboGraphNode* ChildNode) 23 | { 24 | return Edges.Contains(ChildNode) ? Edges.FindChecked(ChildNode) : nullptr; 25 | } 26 | 27 | #if WITH_EDITOR 28 | FText UComboGraphNode::GetNodeTitle() const 29 | { 30 | return NodeTitle.IsEmpty() ? LOCTEXT("NodeDesc", "Combo Graph Node") : NodeTitle; 31 | } 32 | 33 | bool UComboGraphNode::CanCreateConnectionTo(UComboGraphNode* Other, int32 NumberOfChildrenNodes, FText& ErrorMessage) 34 | { 35 | return CanCreateConnection(Other, ErrorMessage); 36 | } 37 | 38 | bool UComboGraphNode::CanCreateConnectionFrom(UComboGraphNode* Other, int32 NumberOfParentNodes, FText& ErrorMessage) 39 | { 40 | return CanCreateConnection(Other, ErrorMessage); 41 | } 42 | #endif 43 | 44 | #undef LOCTEXT_NAMESPACE 45 | -------------------------------------------------------------------------------- /Source/ComboGraphRuntime/Private/Nodes/ComboGraphOpenerNode.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | 4 | #include "..\..\Public\Nodes\ComboGraphOpenerNode.h" 5 | #include "ComboGraph.h" 6 | 7 | #define LOCTEXT_NAMESPACE "ComboGraphNode" 8 | 9 | UComboGraphOpenerNode::UComboGraphOpenerNode() 10 | { 11 | #if WITH_EDITORONLY_DATA 12 | CompatibleGraphType = UComboGraph::StaticClass(); 13 | 14 | BackgroundColor = FColor::Cyan; 15 | 16 | ContextMenuName = LOCTEXT("ContextMenuName", "Opener"); 17 | #endif 18 | 19 | ComboNodeType = EComboNodeType::Opener; 20 | } 21 | 22 | UComboGraphOpenerNode::~UComboGraphOpenerNode() 23 | { 24 | } 25 | 26 | #if WITH_EDITOR 27 | FText UComboGraphOpenerNode::GetNodeTitle() const 28 | { 29 | return NodeTitle.IsEmpty() ? LOCTEXT("NodeDesc", "Opener") : NodeTitle; 30 | } 31 | 32 | bool UComboGraphOpenerNode::CanCreateConnectionFrom(UComboGraphNode* Other, int32 NumberOfParentNodes, 33 | FText& ErrorMessage) 34 | { 35 | return false; 36 | } 37 | 38 | bool UComboGraphOpenerNode::CanCreateConnectionTo(UComboGraphNode* Other, int32 NumberOfChildrenNodes, 39 | FText& ErrorMessage) 40 | { 41 | return Other->GetComboNodeType() == EComboNodeType::Midler; 42 | } 43 | #endif 44 | 45 | #undef LOCTEXT_NAMESPACE 46 | -------------------------------------------------------------------------------- /Source/ComboGraphRuntime/Public/Animations/NotifyStates/CanContinueComboNotifyState.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Animation/AnimNotifies/AnimNotifyState.h" 7 | #include "CanContinueComboNotifyState.generated.h" 8 | 9 | /** 10 | * Should be used with Anim Montage to define interval when we can continue combo 11 | */ 12 | UCLASS() 13 | class COMBOGRAPHRUNTIME_API UCanContinueComboNotifyState : public UAnimNotifyState 14 | { 15 | GENERATED_BODY() 16 | 17 | virtual void NotifyBegin(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, float TotalDuration, 18 | const FAnimNotifyEventReference& EventReference) override; 19 | 20 | virtual void NotifyEnd(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, 21 | const FAnimNotifyEventReference& EventReference) override; 22 | }; 23 | -------------------------------------------------------------------------------- /Source/ComboGraphRuntime/Public/ComboGraph.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "UObject/Object.h" 7 | #include "ComboGraph.generated.h" 8 | 9 | class UComboGraphEdge; 10 | class UComboGraphNode; 11 | 12 | /** 13 | * Class for store ComboGraph editor related data 14 | */ 15 | UCLASS(BlueprintType) 16 | class COMBOGRAPHRUNTIME_API UComboGraph : public UObject 17 | { 18 | GENERATED_BODY() 19 | 20 | public: 21 | UComboGraph(); 22 | 23 | UPROPERTY() 24 | TSubclassOf NodeType; 25 | 26 | UPROPERTY() 27 | TSubclassOf EdgeType; 28 | 29 | UPROPERTY() 30 | bool bEdgeEnabled; 31 | 32 | UPROPERTY(BlueprintReadOnly, Category = "ComboGraph") 33 | TArray> AllNodes; 34 | 35 | void ClearGraph(); 36 | 37 | #if WITH_EDITORONLY_DATA 38 | UPROPERTY() 39 | TObjectPtr EdGraph; 40 | #endif 41 | }; 42 | -------------------------------------------------------------------------------- /Source/ComboGraphRuntime/Public/ComboGraphEdge.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "UObject/Object.h" 7 | #include "ComboGraphEdge.generated.h" 8 | 9 | class UComboGraphNode; 10 | class UComboGraph; 11 | 12 | /** 13 | * Combo sequence node edge 14 | */ 15 | UCLASS(Blueprintable) 16 | class COMBOGRAPHRUNTIME_API UComboGraphEdge : public UObject 17 | { 18 | GENERATED_BODY() 19 | 20 | public: 21 | UComboGraphEdge(); 22 | virtual ~UComboGraphEdge() override; 23 | 24 | UPROPERTY() 25 | TObjectPtr ComboGraph = nullptr; 26 | 27 | UPROPERTY() 28 | TObjectPtr StartNode = nullptr; 29 | 30 | UPROPERTY() 31 | TObjectPtr EndNode = nullptr; 32 | 33 | UFUNCTION(Category = "ComboGraphEdge") 34 | UComboGraph* GetComboGraph() const { return ComboGraph; } 35 | 36 | #if WITH_EDITORONLY_DATA 37 | UPROPERTY(EditDefaultsOnly, Category = "ComboGraphEdge") 38 | bool bShouldDrawTitle = false; 39 | 40 | UPROPERTY(EditDefaultsOnly, Category = "ComboGraphEdge") 41 | FLinearColor EdgeColour = FLinearColor{0.9f, 0.9f, 0.9f, 1.0f}; 42 | 43 | UPROPERTY() 44 | FText NodeTitle; 45 | #endif 46 | 47 | #if WITH_EDITOR 48 | virtual FText GetNodeTitle() const { return NodeTitle; } 49 | 50 | FLinearColor GetEdgeColor() const { return EdgeColour; } 51 | 52 | virtual void SetNodeTitle(const FText& NewTitle) { NodeTitle = NewTitle; } 53 | #endif 54 | }; 55 | -------------------------------------------------------------------------------- /Source/ComboGraphRuntime/Public/ComboGraphRuntime.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreMinimal.h" 4 | #include "Modules/ModuleManager.h" 5 | 6 | /** 7 | * ComboGraph module 8 | */ 9 | class FComboGraphRuntimeModule final : public IModuleInterface 10 | { 11 | public: 12 | virtual void StartupModule() override; 13 | virtual void ShutdownModule() override; 14 | 15 | static FComboGraphRuntimeModule& Get() 16 | { 17 | return FModuleManager::LoadModuleChecked("ComboGraphRuntime"); 18 | } 19 | 20 | static bool IsAvailable() 21 | { 22 | return FModuleManager::Get().IsModuleLoaded("ComboGraphRuntime"); 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /Source/ComboGraphRuntime/Public/ComboGraphRuntimeLog.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | DECLARE_LOG_CATEGORY_EXTERN(ComboGraphRuntimeLog, Log, All); -------------------------------------------------------------------------------- /Source/ComboGraphRuntime/Public/Components/ComboHandlerComponent.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "EnhancedInputComponent.h" 7 | #include "Components/ActorComponent.h" 8 | #include "ComboHandlerComponent.generated.h" 9 | 10 | enum class ETriggerEvent : uint8; 11 | struct FInputActionInstance; 12 | class UInputMappingContext; 13 | class UPlayMontageCallbackProxy; 14 | class UComboGraphNode; 15 | class UInputAction; 16 | class UComboGraph; 17 | /** 18 | * Main component to store and handle ComboGraph related data and logic 19 | */ 20 | UCLASS(ClassGroup=("Combo Graph"), Within=Character, meta=(BlueprintSpawnableComponent)) 21 | class COMBOGRAPHRUNTIME_API UComboHandlerComponent : public UActorComponent 22 | { 23 | GENERATED_BODY() 24 | 25 | public: 26 | UComboHandlerComponent(); 27 | 28 | virtual void BeginPlay() override; 29 | 30 | bool GetCanContinueCombo() const { return bCanContinueCombo; } 31 | 32 | void SetCanContinueCombo(const bool InCanContinueCombo) { bCanContinueCombo = InCanContinueCombo; } 33 | 34 | UComboGraph* GetComboGraph() const { return ComboGraph; } 35 | 36 | bool GetIsComboActive() const { return bIsComboActive; } 37 | 38 | protected: 39 | /** 40 | * ComboGraphAsset with defined combo sequences 41 | */ 42 | UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Combo") 43 | TObjectPtr ComboGraph; 44 | 45 | /** 46 | * All inputs which need to be considered as part of combo attacks should be in this mapping context 47 | * Component binds on every Input Action inside it 48 | */ 49 | UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Combo") 50 | TObjectPtr ComboInputMappingContext; 51 | 52 | /** 53 | * Component binds to this event at Input Actions to process combo 54 | * By default it is Completed, but if you want to handle all InputActions by yourself, you can change it to Triggered 55 | */ 56 | UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Combo") 57 | ETriggerEvent TriggerEventToProcessCombo = ETriggerEvent::Completed; 58 | 59 | private: 60 | /** 61 | * Main method for handling the Input Action 62 | * Finds and plays suitable opener if no combo is active 63 | * Or finds the corresponding attack in current combo sequence and continue combo 64 | */ 65 | void ProcessComboAttack(const UInputAction* InputAction); 66 | 67 | /** 68 | * Bound to EnhancedInputComponent and called for every Input Action for specified mapping context 69 | */ 70 | void OnAnyInputActionTriggered(const FInputActionInstance& ActionInstance); 71 | 72 | /** 73 | * Looking for openers with specific Input Action 74 | */ 75 | UComboGraphNode* FindOpenerForInputAction(const UInputAction* InputAction) const; 76 | 77 | /** 78 | * Looking for suitable attack in combo sequence for specific Input Action 79 | */ 80 | UComboGraphNode* FindNextAttackForCombo(const UComboGraphNode* CurrentComboGraphNode, 81 | const UInputAction* InputAction) const; 82 | 83 | /** 84 | * Create MontageCallbackProxy and play montage 85 | */ 86 | void PlayComboMontage(const UComboGraphNode* ComboGraphNode); 87 | 88 | /** 89 | * Cached owner character 90 | */ 91 | UPROPERTY() 92 | ACharacter* OwnerCharacter = nullptr; 93 | 94 | /** 95 | * Ongoing node in current combo sequence 96 | */ 97 | UPROPERTY() 98 | UComboGraphNode* CurrentComboGraphAttack = nullptr; 99 | 100 | /** 101 | * Callback for ongoing attack montage 102 | */ 103 | UPROPERTY() 104 | UPlayMontageCallbackProxy* PlayMontageCallbackProxy = nullptr; 105 | 106 | /** 107 | * If any combo is active 108 | */ 109 | bool bIsComboActive = false; 110 | 111 | /** 112 | * Can we continue ongoing combo sequence 113 | */ 114 | bool bCanContinueCombo = false; 115 | 116 | #pragma region Delegates 117 | UFUNCTION() 118 | void OnMontageBlendOut(FName NotifyName); 119 | 120 | UFUNCTION() 121 | void OnMontageInterrupted(FName NotifyName); 122 | 123 | UFUNCTION() 124 | void OnMontageCompleted(FName NotifyName); 125 | #pragma endregion Delegates 126 | }; 127 | -------------------------------------------------------------------------------- /Source/ComboGraphRuntime/Public/Interfaces/ComboHandlerInterface.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "UObject/Interface.h" 7 | #include "ComboHandlerInterface.generated.h" 8 | 9 | class UComboHandlerComponent; 10 | 11 | UINTERFACE() 12 | class UComboHandlerInterface : public UInterface 13 | { 14 | GENERATED_BODY() 15 | }; 16 | 17 | /** 18 | * Implement this interface for character which should use ComboGraph 19 | */ 20 | class COMBOGRAPHRUNTIME_API IComboHandlerInterface 21 | { 22 | GENERATED_BODY() 23 | 24 | public: 25 | virtual UComboHandlerComponent* GetComboHandlerComponent() const = 0; 26 | }; 27 | -------------------------------------------------------------------------------- /Source/ComboGraphRuntime/Public/Nodes/ComboGraphEnderNode.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "ComboGraphNode.h" 7 | #include "ComboGraphEnderNode.generated.h" 8 | 9 | /** 10 | * Combo sequence ender node 11 | * Can connect only with midlers 12 | */ 13 | UCLASS() 14 | class COMBOGRAPHRUNTIME_API UComboGraphEnderNode : public UComboGraphNode 15 | { 16 | GENERATED_BODY() 17 | 18 | public: 19 | UComboGraphEnderNode(); 20 | virtual ~UComboGraphEnderNode() override; 21 | 22 | #if WITH_EDITOR 23 | virtual FText GetNodeTitle() const override; 24 | 25 | virtual bool 26 | CanCreateConnectionFrom(UComboGraphNode* Other, int32 NumberOfParentNodes, FText& ErrorMessage) override; 27 | 28 | virtual bool 29 | CanCreateConnectionTo(UComboGraphNode* Other, int32 NumberOfChildrenNodes, FText& ErrorMessage) override; 30 | #endif 31 | }; 32 | -------------------------------------------------------------------------------- /Source/ComboGraphRuntime/Public/Nodes/ComboGraphMidlerNode.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "ComboGraphNode.h" 7 | #include "ComboGraphMidlerNode.generated.h" 8 | 9 | /** 10 | * Combo sequence midler node 11 | * Can connect with all node types 12 | */ 13 | UCLASS() 14 | class COMBOGRAPHRUNTIME_API UComboGraphMidlerNode : public UComboGraphNode 15 | { 16 | GENERATED_BODY() 17 | 18 | public: 19 | UComboGraphMidlerNode(); 20 | virtual ~UComboGraphMidlerNode() override; 21 | 22 | #if WITH_EDITOR 23 | virtual FText GetNodeTitle() const override; 24 | 25 | virtual bool 26 | CanCreateConnectionFrom(UComboGraphNode* Other, int32 NumberOfParentNodes, FText& ErrorMessage) override; 27 | 28 | virtual bool 29 | CanCreateConnectionTo(UComboGraphNode* Other, int32 NumberOfChildrenNodes, FText& ErrorMessage) override; 30 | #endif 31 | }; 32 | -------------------------------------------------------------------------------- /Source/ComboGraphRuntime/Public/Nodes/ComboGraphNode.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "ComboNodeType.h" 7 | #include "UObject/Object.h" 8 | #include "ComboGraphNode.generated.h" 9 | 10 | enum class EComboNodeAnimationInterruptionType : uint8; 11 | class UComboGraphEdge; 12 | class UInputAction; 13 | class UComboGraph; 14 | 15 | /** 16 | * Parent for all combo sequence nodes 17 | */ 18 | UCLASS(Blueprintable, Abstract) 19 | class COMBOGRAPHRUNTIME_API UComboGraphNode : public UObject 20 | { 21 | GENERATED_BODY() 22 | 23 | public: 24 | UComboGraphNode(); 25 | virtual ~UComboGraphNode() override; 26 | 27 | UPROPERTY(EditDefaultsOnly, Category = "Combo") 28 | TObjectPtr InputAction = nullptr; 29 | 30 | UPROPERTY(EditDefaultsOnly, Category = "Combo") 31 | TObjectPtr ComboMontage = nullptr; 32 | 33 | UPROPERTY() 34 | TObjectPtr Graph = nullptr; 35 | 36 | UPROPERTY() 37 | TArray> ParentNodes; 38 | 39 | UPROPERTY() 40 | TArray> ChildrenNodes; 41 | 42 | UPROPERTY() 43 | TMap, TObjectPtr> Edges; 44 | 45 | UFUNCTION(BlueprintCallable, Category = "ComboGraphNode") 46 | virtual UComboGraphEdge* GetEdge(UComboGraphNode* ChildNode); 47 | 48 | UFUNCTION(BlueprintCallable, Category = "ComboGraphNode") 49 | UComboGraph* GetGraph() const { return Graph; } 50 | 51 | #if WITH_EDITORONLY_DATA 52 | UPROPERTY() 53 | FText NodeTitle; 54 | 55 | UPROPERTY() 56 | FLinearColor BackgroundColor; 57 | 58 | UPROPERTY() 59 | TSubclassOf CompatibleGraphType; 60 | 61 | UPROPERTY() 62 | FText ContextMenuName; 63 | #endif 64 | 65 | #if WITH_EDITOR 66 | virtual FLinearColor GetBackgroundColor() const { return BackgroundColor; } 67 | 68 | virtual bool IsNameEditable() const { return true; } 69 | 70 | virtual FText GetNodeTitle() const; 71 | 72 | virtual void SetNodeTitle(const FText& NewTitle) { NodeTitle = NewTitle; } 73 | 74 | virtual bool CanCreateConnection(UComboGraphNode* Other, FText& ErrorMessage) { return true; } 75 | 76 | virtual bool CanCreateConnectionTo(UComboGraphNode* Other, int32 NumberOfChildrenNodes, FText& ErrorMessage); 77 | 78 | virtual bool CanCreateConnectionFrom(UComboGraphNode* Other, int32 NumberOfParentNodes, FText& ErrorMessage); 79 | #endif 80 | 81 | EComboNodeType GetComboNodeType() const { return ComboNodeType; } 82 | 83 | protected: 84 | EComboNodeType ComboNodeType = EComboNodeType::None; 85 | }; 86 | -------------------------------------------------------------------------------- /Source/ComboGraphRuntime/Public/Nodes/ComboGraphOpenerNode.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "ComboGraphNode.h" 7 | #include "ComboGraphOpenerNode.generated.h" 8 | 9 | /** 10 | * Combo sequence opener node 11 | * Can connect only with midlers 12 | */ 13 | UCLASS() 14 | class COMBOGRAPHRUNTIME_API UComboGraphOpenerNode : public UComboGraphNode 15 | { 16 | GENERATED_BODY() 17 | 18 | public: 19 | UComboGraphOpenerNode(); 20 | virtual ~UComboGraphOpenerNode() override; 21 | 22 | #if WITH_EDITOR 23 | virtual FText GetNodeTitle() const override; 24 | 25 | virtual bool 26 | CanCreateConnectionFrom(UComboGraphNode* Other, int32 NumberOfParentNodes, FText& ErrorMessage) override; 27 | 28 | virtual bool 29 | CanCreateConnectionTo(UComboGraphNode* Other, int32 NumberOfChildrenNodes, FText& ErrorMessage) override; 30 | #endif 31 | }; 32 | -------------------------------------------------------------------------------- /Source/ComboGraphRuntime/Public/Nodes/ComboNodeType.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Eugen Berencian. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | /** 6 | * Define combo sequence node types 7 | */ 8 | UENUM(BlueprintType) 9 | enum class EComboNodeType : uint8 10 | { 11 | None, 12 | Opener, 13 | Midler, 14 | Ender 15 | }; 16 | --------------------------------------------------------------------------------