From 68c86a703db04b80467b18a9440200bbda448190 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 2 Aug 2021 18:32:44 +0200 Subject: [PATCH 001/338] intial UE 5 support --- Flow.uplugin | 2 +- Source/FlowEditor/FlowEditor.Build.cs | 1 + Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Flow.uplugin b/Flow.uplugin index e8919641e..35a7e2571 100644 --- a/Flow.uplugin +++ b/Flow.uplugin @@ -9,7 +9,7 @@ "DocsURL" : "https://github.com/MothCocoon/FlowGraph/wiki", "MarketplaceURL" : "", "SupportURL": "https://discord.gg/zMtMQ2vUUa", - "EngineVersion": "4.26.0", + "EngineVersion": "5.0", "EnabledByDefault" : true, "CanContainContent" : false, "IsBetaVersion" : false, diff --git a/Source/FlowEditor/FlowEditor.Build.cs b/Source/FlowEditor/FlowEditor.Build.cs index cf40227dd..61dc7b14c 100644 --- a/Source/FlowEditor/FlowEditor.Build.cs +++ b/Source/FlowEditor/FlowEditor.Build.cs @@ -22,6 +22,7 @@ public FlowEditor(ReadOnlyTargetRules Target) : base(Target) "CoreUObject", "DetailCustomizations", "DeveloperSettings", + "EditorFramework", "EditorStyle", "Engine", "GraphEditor", diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp index 77a96f83b..caebf7cf8 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp @@ -50,7 +50,7 @@ void SFlowPaletteItem::Construct(const FArguments& InArgs, FCreateWidgetForActio const bool bIsReadOnly = false; const TSharedRef IconWidget = CreateIconWidget(IconToolTip, IconBrush, IconColor); - const TSharedRef NameSlotWidget = CreateTextSlotWidget(NameFont, InCreateData, bIsReadOnly); + const TSharedRef NameSlotWidget = CreateTextSlotWidget(InCreateData, bIsReadOnly); const TSharedRef HotkeyDisplayWidget = CreateHotkeyDisplayWidget(NameFont, HotkeyChord); // Create the actual widget From e02b4228d1d5f6c732d3907dcfcf18e8e5d4db55 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Wed, 4 Aug 2021 21:04:09 +0200 Subject: [PATCH 002/338] new nodes: On Actor Registered, On Actor Unregistered --- .../World/FlowNode_ComponentObserver.cpp | 16 +++++++---- .../World/FlowNode_OnActorRegistered.cpp | 20 ++++++++++++++ .../World/FlowNode_OnActorUnregistered.cpp | 27 +++++++++++++++++++ .../Nodes/World/FlowNode_OnActorRegistered.h | 18 +++++++++++++ .../World/FlowNode_OnActorUnregistered.h | 19 +++++++++++++ 5 files changed, 95 insertions(+), 5 deletions(-) create mode 100644 Source/Flow/Private/Nodes/World/FlowNode_OnActorRegistered.cpp create mode 100644 Source/Flow/Private/Nodes/World/FlowNode_OnActorUnregistered.cpp create mode 100644 Source/Flow/Public/Nodes/World/FlowNode_OnActorRegistered.h create mode 100644 Source/Flow/Public/Nodes/World/FlowNode_OnActorUnregistered.h diff --git a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp index 2d4e76b61..cd7537f9e 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp @@ -60,9 +60,9 @@ void UFlowNode_ComponentObserver::StartObserving() } GetFlowSubsystem()->OnComponentRegistered.AddDynamic(this, &UFlowNode_ComponentObserver::OnComponentRegistered); - GetFlowSubsystem()->OnComponentTagAdded.AddDynamic(this, &UFlowNode_ComponentObserver::OnComponentTagAdded); - GetFlowSubsystem()->OnComponentUnregistered.AddDynamic(this, &UFlowNode_ComponentObserver::OnComponentUnregistered); + + GetFlowSubsystem()->OnComponentTagAdded.AddDynamic(this, &UFlowNode_ComponentObserver::OnComponentTagAdded); GetFlowSubsystem()->OnComponentTagRemoved.AddDynamic(this, &UFlowNode_ComponentObserver::OnComponentTagRemoved); } @@ -70,6 +70,9 @@ void UFlowNode_ComponentObserver::StopObserving() { GetFlowSubsystem()->OnComponentRegistered.RemoveAll(this); GetFlowSubsystem()->OnComponentUnregistered.RemoveAll(this); + + GetFlowSubsystem()->OnComponentTagAdded.RemoveAll(this); + GetFlowSubsystem()->OnComponentTagRemoved.RemoveAll(this); } void UFlowNode_ComponentObserver::OnComponentRegistered(UFlowComponent* Component) @@ -109,7 +112,7 @@ void UFlowNode_ComponentObserver::OnComponentTagRemoved(UFlowComponent* Componen void UFlowNode_ComponentObserver::OnEventReceived() { TriggerFirstOutput(false); - + SuccessCount++; if (SuccessLimit > 0 && SuccessCount == SuccessLimit) { @@ -121,9 +124,12 @@ void UFlowNode_ComponentObserver::Cleanup() { StopObserving(); - for (const TPair, TWeakObjectPtr>& RegisteredActor : RegisteredActors) + if (RegisteredActors.Num() > 0) { - ForgetActor(RegisteredActor.Key, RegisteredActor.Value); + for (const TPair, TWeakObjectPtr>& RegisteredActor : RegisteredActors) + { + ForgetActor(RegisteredActor.Key, RegisteredActor.Value); + } } RegisteredActors.Empty(); diff --git a/Source/Flow/Private/Nodes/World/FlowNode_OnActorRegistered.cpp b/Source/Flow/Private/Nodes/World/FlowNode_OnActorRegistered.cpp new file mode 100644 index 000000000..d8440a0e7 --- /dev/null +++ b/Source/Flow/Private/Nodes/World/FlowNode_OnActorRegistered.cpp @@ -0,0 +1,20 @@ +#include "Nodes/World/FlowNode_OnActorRegistered.h" + +UFlowNode_OnActorRegistered::UFlowNode_OnActorRegistered(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ +} + +void UFlowNode_OnActorRegistered::ExecuteInput(const FName& PinName) +{ + Super::ExecuteInput(PinName); +} + +void UFlowNode_OnActorRegistered::ObserveActor(TWeakObjectPtr Actor, TWeakObjectPtr Component) +{ + if (!RegisteredActors.Contains(Actor)) + { + RegisteredActors.Emplace(Actor, Component); + OnEventReceived(); + } +} diff --git a/Source/Flow/Private/Nodes/World/FlowNode_OnActorUnregistered.cpp b/Source/Flow/Private/Nodes/World/FlowNode_OnActorUnregistered.cpp new file mode 100644 index 000000000..db89089e8 --- /dev/null +++ b/Source/Flow/Private/Nodes/World/FlowNode_OnActorUnregistered.cpp @@ -0,0 +1,27 @@ +#include "Nodes/World/FlowNode_OnActorUnregistered.h" + +UFlowNode_OnActorUnregistered::UFlowNode_OnActorUnregistered(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ +} + +void UFlowNode_OnActorUnregistered::ExecuteInput(const FName& PinName) +{ + Super::ExecuteInput(PinName); +} + +void UFlowNode_OnActorUnregistered::ObserveActor(TWeakObjectPtr Actor, TWeakObjectPtr Component) +{ + if (!RegisteredActors.Contains(Actor)) + { + RegisteredActors.Emplace(Actor, Component); + } +} + +void UFlowNode_OnActorUnregistered::ForgetActor(TWeakObjectPtr Actor, TWeakObjectPtr Component) +{ + if (ActivationState == EFlowNodeState::Active) + { + OnEventReceived(); + } +} diff --git a/Source/Flow/Public/Nodes/World/FlowNode_OnActorRegistered.h b/Source/Flow/Public/Nodes/World/FlowNode_OnActorRegistered.h new file mode 100644 index 000000000..ae1da3b69 --- /dev/null +++ b/Source/Flow/Public/Nodes/World/FlowNode_OnActorRegistered.h @@ -0,0 +1,18 @@ +#pragma once + +#include "Nodes/World/FlowNode_ComponentObserver.h" +#include "FlowNode_OnActorRegistered.generated.h" + +/** + * Triggers output when Flow Component with matching Identity Tag appears in the world + */ +UCLASS(NotBlueprintable, meta = (DisplayName = "On Actor Registered")) +class FLOW_API UFlowNode_OnActorRegistered : public UFlowNode_ComponentObserver +{ + GENERATED_UCLASS_BODY() + +protected: + virtual void ExecuteInput(const FName& PinName) override; + + virtual void ObserveActor(TWeakObjectPtr Actor, TWeakObjectPtr Component) override; +}; diff --git a/Source/Flow/Public/Nodes/World/FlowNode_OnActorUnregistered.h b/Source/Flow/Public/Nodes/World/FlowNode_OnActorUnregistered.h new file mode 100644 index 000000000..ffd4a246a --- /dev/null +++ b/Source/Flow/Public/Nodes/World/FlowNode_OnActorUnregistered.h @@ -0,0 +1,19 @@ +#pragma once + +#include "Nodes/World/FlowNode_ComponentObserver.h" +#include "FlowNode_OnActorUnregistered.generated.h" + +/** + * Triggers output when Flow Component with matching Identity Tag disappears from the world + */ +UCLASS(NotBlueprintable, meta = (DisplayName = "On Actor Unregistered")) +class FLOW_API UFlowNode_OnActorUnregistered : public UFlowNode_ComponentObserver +{ + GENERATED_UCLASS_BODY() + +protected: + virtual void ExecuteInput(const FName& PinName) override; + + virtual void ObserveActor(TWeakObjectPtr Actor, TWeakObjectPtr Component) override; + virtual void ForgetActor(TWeakObjectPtr Actor, TWeakObjectPtr Component) override; +}; From 4403621a236b2a19d4f11e009ad66c7cbff02873 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Thu, 5 Aug 2021 14:17:56 +0200 Subject: [PATCH 003/338] added option to hide Asset Toolbar above Level Editor --- Source/FlowEditor/Private/FlowEditorModule.cpp | 12 ++++++++---- .../FlowEditor/Private/Graph/FlowGraphSettings.cpp | 1 + Source/FlowEditor/Public/Graph/FlowGraphSettings.h | 3 +++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Source/FlowEditor/Private/FlowEditorModule.cpp b/Source/FlowEditor/Private/FlowEditorModule.cpp index fdc871db6..15bfb7355 100644 --- a/Source/FlowEditor/Private/FlowEditorModule.cpp +++ b/Source/FlowEditor/Private/FlowEditorModule.cpp @@ -5,6 +5,7 @@ #include "Asset/FlowAssetDetails.h" #include "Asset/FlowAssetEditor.h" #include "Graph/FlowGraphConnectionDrawingPolicy.h" +#include "Graph/FlowGraphSettings.h" #include "LevelEditor/SLevelEditorFlow.h" #include "MovieScene/FlowTrackEditor.h" #include "Nodes/AssetTypeActions_FlowNodeBlueprint.h" @@ -47,11 +48,14 @@ void FFlowEditorModule::StartupModule() FlowAssetExtensibility.Init(); // add Flow Toolbar - if (FLevelEditorModule* LevelEditorModule = FModuleManager::GetModulePtr(TEXT("LevelEditor"))) + if (UFlowGraphSettings::Get()->bShowAssetToolbarAboveLevelEditor) { - TSharedPtr MenuExtender = MakeShareable(new FExtender()); - MenuExtender->AddToolBarExtension("Game", EExtensionHook::After, nullptr, FToolBarExtensionDelegate::CreateRaw(this, &FFlowEditorModule::CreateFlowToolbar)); - LevelEditorModule->GetToolBarExtensibilityManager()->AddExtender(MenuExtender); + if (FLevelEditorModule* LevelEditorModule = FModuleManager::GetModulePtr(TEXT("LevelEditor"))) + { + TSharedPtr MenuExtender = MakeShareable(new FExtender()); + MenuExtender->AddToolBarExtension("Game", EExtensionHook::After, nullptr, FToolBarExtensionDelegate::CreateRaw(this, &FFlowEditorModule::CreateFlowToolbar)); + LevelEditorModule->GetToolBarExtensibilityManager()->AddExtender(MenuExtender); + } } // register Flow sequence track diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp index 623695d38..98348af51 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp @@ -7,6 +7,7 @@ UFlowGraphSettings::UFlowGraphSettings(const FObjectInitializer& ObjectInitializ , NodeDescriptionBackground(FLinearColor(0.0625f, 0.0625f, 0.0625f, 1.0f)) , NodeStatusBackground(FLinearColor(0.12f, 0.12f, 0.12f, 1.0f)) , NodePreloadedBackground(FLinearColor(0.12f, 0.12f, 0.12f, 1.0f)) + , bShowAssetToolbarAboveLevelEditor(true) , InactiveWireColor(FLinearColor(0.364f, 0.364f, 0.364f, 1.0f)) , InactiveWireThickness(1.5f) , RecentWireDuration(3.0f) diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h index ef693731d..bb9d2f495 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h @@ -38,6 +38,9 @@ class UFlowGraphSettings final : public UDeveloperSettings UPROPERTY(EditAnywhere, config, Category = "NodePopups") FLinearColor NodePreloadedBackground; + UPROPERTY(EditAnywhere, config, Category = "World") + bool bShowAssetToolbarAboveLevelEditor; + UPROPERTY(EditAnywhere, config, Category = "Wires") FLinearColor InactiveWireColor; From 64a22ce684025b8784f94453063f7c583a749a46 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Thu, 5 Aug 2021 15:34:53 +0200 Subject: [PATCH 004/338] fixed registering asset toolbar --- Source/FlowEditor/Private/FlowEditorModule.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/FlowEditor/Private/FlowEditorModule.cpp b/Source/FlowEditor/Private/FlowEditorModule.cpp index 15bfb7355..72c1489b2 100644 --- a/Source/FlowEditor/Private/FlowEditorModule.cpp +++ b/Source/FlowEditor/Private/FlowEditorModule.cpp @@ -53,7 +53,7 @@ void FFlowEditorModule::StartupModule() if (FLevelEditorModule* LevelEditorModule = FModuleManager::GetModulePtr(TEXT("LevelEditor"))) { TSharedPtr MenuExtender = MakeShareable(new FExtender()); - MenuExtender->AddToolBarExtension("Game", EExtensionHook::After, nullptr, FToolBarExtensionDelegate::CreateRaw(this, &FFlowEditorModule::CreateFlowToolbar)); + MenuExtender->AddToolBarExtension("Play", EExtensionHook::After, nullptr, FToolBarExtensionDelegate::CreateRaw(this, &FFlowEditorModule::CreateFlowToolbar)); LevelEditorModule->GetToolBarExtensibilityManager()->AddExtender(MenuExtender); } } From cefa15625d282149d0d0222360e61c532fa438cd Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Thu, 5 Aug 2021 15:35:45 +0200 Subject: [PATCH 005/338] removed High Detail layout since it doesn't apply to UE5 level editor toolbar --- .../Private/LevelEditor/SLevelEditorFlow.cpp | 31 ++----------------- 1 file changed, 3 insertions(+), 28 deletions(-) diff --git a/Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp b/Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp index ca076ec83..00bb77d10 100644 --- a/Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp +++ b/Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp @@ -4,9 +4,7 @@ #include "FlowWorldSettings.h" #include "Editor.h" -#include "Framework/MultiBox/MultiBoxDefs.h" #include "PropertyCustomizationHelpers.h" -#include "SLevelOfDetailBranchNode.h" #define LOCTEXT_NAMESPACE "SLevelEditorFlow" @@ -33,7 +31,9 @@ void SLevelEditorFlow::CreateFlowWidget() FlowPath = FName(); } - const TSharedRef FlowWidget = SNew(SHorizontalBox) + ChildSlot + [ + SNew(SHorizontalBox) + SHorizontalBox::Slot() .AutoWidth() [ @@ -42,31 +42,6 @@ void SLevelEditorFlow::CreateFlowWidget() .DisplayThumbnail(false) .OnObjectChanged(this, &SLevelEditorFlow::OnFlowChanged) .ObjectPath(this, &SLevelEditorFlow::GetFlowPath) - ]; - - ChildSlot - [ - SNew(SLevelOfDetailBranchNode) - .UseLowDetailSlot(FMultiBoxSettings::UseSmallToolBarIcons) - .LowDetail() - [ - SNew(SHorizontalBox) - + SHorizontalBox::Slot() - .AutoWidth() - [ - FlowWidget - ] - ] - .HighDetail() - [ - SNew(SVerticalBox) - + SVerticalBox::Slot() - .AutoHeight() - .VAlign(VAlign_Top) - .Padding(5.0f) - [ - FlowWidget - ] ] ]; } From 6b4a923371299ab927087be0a47d5d6913bb7cb2 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Thu, 5 Aug 2021 15:46:32 +0200 Subject: [PATCH 006/338] removed zombie tab, it appears that we don't need to manually add Toolbar Tab in UE5 --- .../Private/Asset/FlowAssetEditor.cpp | 48 ++++++++----------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index 8866a0d35..e1742c220 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -188,43 +188,33 @@ void FFlowAssetEditor::InitFlowAssetEditor(const EToolkitMode::Type Mode, const CreateWidgets(); BindGraphCommands(); - const TSharedRef StandaloneDefaultLayout = FTabManager::NewLayout("FlowAssetEditor_Layout_v2") + const TSharedRef StandaloneDefaultLayout = FTabManager::NewLayout("FlowAssetEditor_Layout_v3") ->AddArea ( - FTabManager::NewPrimaryArea()->SetOrientation(Orient_Vertical) + FTabManager::NewPrimaryArea()->SetOrientation(Orient_Horizontal) ->Split - ( - FTabManager::NewStack() - ->SetSizeCoefficient(0.1f) - ->AddTab(GetToolbarTabId(), ETabState::OpenedTab)->SetHideTabWell(true) - ) + ( + FTabManager::NewStack() + ->SetSizeCoefficient(0.225f) + ->AddTab(DetailsTab, ETabState::OpenedTab) + ) ->Split - ( - FTabManager::NewSplitter()->SetOrientation(Orient_Horizontal)->SetSizeCoefficient(0.9f) - ->Split - ( - FTabManager::NewStack() - ->SetSizeCoefficient(0.225f) - ->AddTab(DetailsTab, ETabState::OpenedTab) - ) - ->Split - ( - FTabManager::NewStack() - ->SetSizeCoefficient(0.65f) - ->AddTab(GraphTab, ETabState::OpenedTab)->SetHideTabWell(true) - ) - ->Split - ( - FTabManager::NewStack() - ->SetSizeCoefficient(0.125f) - ->AddTab(PaletteTab, ETabState::OpenedTab) - ) - ) + ( + FTabManager::NewStack() + ->SetSizeCoefficient(0.65f) + ->AddTab(GraphTab, ETabState::OpenedTab)->SetHideTabWell(true) + ) + ->Split + ( + FTabManager::NewStack() + ->SetSizeCoefficient(0.125f) + ->AddTab(PaletteTab, ETabState::OpenedTab) + ) ); const bool bCreateDefaultStandaloneMenu = true; const bool bCreateDefaultToolbar = true; - FAssetEditorToolkit::InitAssetEditor(Mode, InitToolkitHost, TEXT("FlowEditorApp"), StandaloneDefaultLayout, bCreateDefaultStandaloneMenu, bCreateDefaultToolbar, ObjectToEdit, false); + InitAssetEditor(Mode, InitToolkitHost, TEXT("FlowEditorApp"), StandaloneDefaultLayout, bCreateDefaultStandaloneMenu, bCreateDefaultToolbar, ObjectToEdit, false); FFlowToolbarCommands::Register(); From b0743895f75c8b142021aab3adf1d2c04d6258b8 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Thu, 5 Aug 2021 15:49:35 +0200 Subject: [PATCH 007/338] adjusted padding --- Source/FlowEditor/Private/Asset/FlowDebuggerToolbar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/FlowEditor/Private/Asset/FlowDebuggerToolbar.cpp b/Source/FlowEditor/Private/Asset/FlowDebuggerToolbar.cpp index 087020ded..ef0c9c6ae 100644 --- a/Source/FlowEditor/Private/Asset/FlowDebuggerToolbar.cpp +++ b/Source/FlowEditor/Private/Asset/FlowDebuggerToolbar.cpp @@ -107,7 +107,7 @@ void SFlowBreadcrumb::Construct(const FArguments& InArgs, TWeakPtr Date: Sun, 15 Aug 2021 11:12:55 +0200 Subject: [PATCH 008/338] const correctness --- Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp | 2 +- Source/FlowEditor/Private/Nodes/FlowNodeBlueprintFactory.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp index 7599caf26..de20dc7cb 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -37,7 +37,7 @@ UFlowGraphSchema::UFlowGraphSchema(const FObjectInitializer& ObjectInitializer) void UFlowGraphSchema::SubscribeToAssetChanges() { - FAssetRegistryModule& AssetRegistry = FModuleManager::LoadModuleChecked(AssetRegistryConstants::ModuleName); + const FAssetRegistryModule& AssetRegistry = FModuleManager::LoadModuleChecked(AssetRegistryConstants::ModuleName); AssetRegistry.Get().OnFilesLoaded().AddStatic(&UFlowGraphSchema::GatherFlowNodes); AssetRegistry.Get().OnAssetAdded().AddStatic(&UFlowGraphSchema::OnAssetAdded); AssetRegistry.Get().OnAssetRemoved().AddStatic(&UFlowGraphSchema::RemoveAsset); diff --git a/Source/FlowEditor/Private/Nodes/FlowNodeBlueprintFactory.cpp b/Source/FlowEditor/Private/Nodes/FlowNodeBlueprintFactory.cpp index 402526c0a..5e086a72d 100644 --- a/Source/FlowEditor/Private/Nodes/FlowNodeBlueprintFactory.cpp +++ b/Source/FlowEditor/Private/Nodes/FlowNodeBlueprintFactory.cpp @@ -147,7 +147,7 @@ class SFlowNodeBlueprintCreateDialog final : public SCompoundWidget Options.DisplayMode = EClassViewerDisplayMode::TreeView; Options.bIsBlueprintBaseOnly = true; - TSharedPtr Filter = MakeShareable(new FFlowNodeBlueprintParentFilter); + const TSharedPtr Filter = MakeShareable(new FFlowNodeBlueprintParentFilter); // All child child classes of UFlowNode are valid Filter->AllowedChildrenOfClasses.Add(UFlowNode::StaticClass()); @@ -240,7 +240,7 @@ UFlowNodeBlueprintFactory::UFlowNodeBlueprintFactory(const FObjectInitializer& O bool UFlowNodeBlueprintFactory::ConfigureProperties() { - TSharedRef Dialog = SNew(SFlowNodeBlueprintCreateDialog); + const TSharedRef Dialog = SNew(SFlowNodeBlueprintCreateDialog); return Dialog->ConfigureProperties(this); } From 1aa1792b8ab147ef3b325d8bca0ea55204feeff4 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 15 Aug 2021 11:13:08 +0200 Subject: [PATCH 009/338] fixed API deprecation warning --- Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index e1742c220..9883d38c2 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -137,7 +137,6 @@ TSharedRef FFlowAssetEditor::SpawnTab_Details(const FSpawnTabArgs& Arg check(Args.GetTabId() == DetailsTab); return SNew(SDockTab) - .Icon(FEditorStyle::GetBrush("LevelEditor.Tabs.Details")) .Label(LOCTEXT("FlowDetailsTitle", "Details")) [ DetailsView.ToSharedRef() @@ -164,11 +163,10 @@ TSharedRef FFlowAssetEditor::SpawnTab_Palette(const FSpawnTabArgs& Arg check(Args.GetTabId() == PaletteTab); return SNew(SDockTab) - .Icon(FEditorStyle::GetBrush("Kismet.Tabs.Palette")) .Label(LOCTEXT("FlowPaletteTitle", "Palette")) - [ - Palette.ToSharedRef() - ]; + [ + Palette.ToSharedRef() + ]; } void FFlowAssetEditor::InitFlowAssetEditor(const EToolkitMode::Type Mode, const TSharedPtr& InitToolkitHost, UObject* ObjectToEdit) From edf0760acd4411e64f0d5af465cbe0c5a054780a Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 16 Aug 2021 22:27:21 +0200 Subject: [PATCH 010/338] removing flawed UI customization --- .../FlowEditor/Private/FlowEditorModule.cpp | 6 +- .../Customizations/FlowPinCustomization.cpp | 78 ------------------- .../Customizations/FlowPinCustomization.h | 20 ----- 3 files changed, 1 insertion(+), 103 deletions(-) delete mode 100644 Source/FlowEditor/Private/Nodes/Customizations/FlowPinCustomization.cpp delete mode 100644 Source/FlowEditor/Private/Nodes/Customizations/FlowPinCustomization.h diff --git a/Source/FlowEditor/Private/FlowEditorModule.cpp b/Source/FlowEditor/Private/FlowEditorModule.cpp index 72c1489b2..1251342fa 100644 --- a/Source/FlowEditor/Private/FlowEditorModule.cpp +++ b/Source/FlowEditor/Private/FlowEditorModule.cpp @@ -15,8 +15,6 @@ #include "Nodes/Customizations/FlowNode_CustomOutputDetails.h" #include "Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.h" -#include "Nodes/Customizations/FlowPinCustomization.h" - #include "FlowAsset.h" #include "Nodes/Route/FlowNode_CustomInput.h" #include "Nodes/Route/FlowNode_CustomOutput.h" @@ -52,7 +50,7 @@ void FFlowEditorModule::StartupModule() { if (FLevelEditorModule* LevelEditorModule = FModuleManager::GetModulePtr(TEXT("LevelEditor"))) { - TSharedPtr MenuExtender = MakeShareable(new FExtender()); + const TSharedPtr MenuExtender = MakeShareable(new FExtender()); MenuExtender->AddToolBarExtension("Play", EExtensionHook::After, nullptr, FToolBarExtensionDelegate::CreateRaw(this, &FFlowEditorModule::CreateFlowToolbar)); LevelEditorModule->GetToolBarExtensibilityManager()->AddExtender(MenuExtender); } @@ -142,8 +140,6 @@ void FFlowEditorModule::RegisterPropertyCustomizations() const { FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked("PropertyEditor"); - PropertyModule.RegisterCustomPropertyTypeLayout("FlowPin", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FFlowPinCustomization::MakeInstance)); - // notify on customization change PropertyModule.NotifyCustomizationModuleChanged(); } diff --git a/Source/FlowEditor/Private/Nodes/Customizations/FlowPinCustomization.cpp b/Source/FlowEditor/Private/Nodes/Customizations/FlowPinCustomization.cpp deleted file mode 100644 index 1f7e44742..000000000 --- a/Source/FlowEditor/Private/Nodes/Customizations/FlowPinCustomization.cpp +++ /dev/null @@ -1,78 +0,0 @@ -#include "FlowPinCustomization.h" -#include "Nodes/FlowPin.h" - -#include "PropertyEditing.h" -#include "Widgets/Input/SEditableTextBox.h" - -#define LOCTEXT_NAMESPACE "FlowPinCustomization" - -void FFlowPinCustomization::CustomizeHeader(TSharedRef StructPropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils) -{ -} - -void FFlowPinCustomization::CustomizeChildren(TSharedRef StructPropertyHandle, IDetailChildrenBuilder& StructBuilder, IPropertyTypeCustomizationUtils& StructCustomizationUtils) -{ - TArray Objects; - StructPropertyHandle->GetOuterObjects(Objects); - const FFlowPin* FlowPin = reinterpret_cast(StructPropertyHandle->GetValueBaseAddress(reinterpret_cast(Objects[0]))); - - uint32 PropertyChildNum = -1; - if (StructPropertyHandle->GetNumChildren(PropertyChildNum) == FPropertyAccess::Success) - { - for (uint32 i = 0; i < PropertyChildNum; ++i) - { - TSharedPtr ChildHandle = StructPropertyHandle->GetChildHandle(i); - - if (ChildHandle.IsValid() && ChildHandle->GetProperty()) - { - const FName PropertyName = ChildHandle->GetProperty()->GetFName(); - if (PropertyName == GET_MEMBER_NAME_CHECKED(FFlowPin, PinName)) - { - StructBuilder.AddCustomRow(LOCTEXT("PinNameValue", "PinNameValue")) - .NameContent() - [ - StructPropertyHandle->CreatePropertyNameWidget() - ] - .ValueContent() - .MinDesiredWidth(125.0f) - .MaxDesiredWidth(125.0f) - [ - SNew(SEditableTextBox) - .Text(FText::FromName(FlowPin->PinName)) - .OnTextCommitted_Static(&FFlowPinCustomization::OnPinNameCommitted, ChildHandle.ToSharedRef()) - .OnVerifyTextChanged_Static(&FFlowPinCustomization::VerifyNewPinName) - ]; - } - else - { - StructBuilder.AddProperty(ChildHandle.ToSharedRef()); - } - } - } - } -} - -void FFlowPinCustomization::OnPinNameCommitted(const FText& InText, ETextCommit::Type InCommitType, TSharedRef PropertyHandle) -{ - TArray Objects; - PropertyHandle->GetParentHandle()->GetOuterObjects(Objects); - if (FFlowPin* FlowText = reinterpret_cast(PropertyHandle->GetValueBaseAddress(reinterpret_cast(Objects[0])))) - { - FlowText->PinName = *InText.ToString(); - } -} - -bool FFlowPinCustomization::VerifyNewPinName(const FText& InNewText, FText& OutErrorMessage) -{ - const FName NewString = *InNewText.ToString(); - - if (NewString.IsNone()) - { - OutErrorMessage = LOCTEXT("VerifyTextFailed", "Pin Name can't be None!"); - return false; - } - - return true; -} - -#undef LOCTEXT_NAMESPACE diff --git a/Source/FlowEditor/Private/Nodes/Customizations/FlowPinCustomization.h b/Source/FlowEditor/Private/Nodes/Customizations/FlowPinCustomization.h deleted file mode 100644 index 883fd7ef2..000000000 --- a/Source/FlowEditor/Private/Nodes/Customizations/FlowPinCustomization.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include "IPropertyTypeCustomization.h" -#include "Templates/SharedPointer.h" - -class FFlowPinCustomization final : public IPropertyTypeCustomization -{ -public: - static TSharedRef MakeInstance() - { - return MakeShareable(new FFlowPinCustomization()); - } - - virtual void CustomizeHeader(TSharedRef StructPropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils) override; - virtual void CustomizeChildren(TSharedRef StructPropertyHandle, IDetailChildrenBuilder& StructBuilder, IPropertyTypeCustomizationUtils& StructCustomizationUtils) override; - -private: - static void OnPinNameCommitted(const FText& InText, ETextCommit::Type InCommitType, TSharedRef PropertyHandle); - static bool VerifyNewPinName(const FText& InNewText, FText& OutErrorMessage); -}; From 53ed6cae16f2995d9b865e7fa2eb864ea4bdb8be Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 16 Aug 2021 23:10:41 +0200 Subject: [PATCH 011/338] allow to hide Flow Asset and Flow Node from "Create Asset" menu --- .../Asset/AssetTypeActions_FlowAsset.cpp | 3 ++- .../Private/Graph/FlowGraphSettings.cpp | 4 +++- .../AssetTypeActions_FlowNodeBlueprint.cpp | 3 ++- .../Public/Graph/FlowGraphSettings.h | 18 +++++++++++++++--- 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/Source/FlowEditor/Private/Asset/AssetTypeActions_FlowAsset.cpp b/Source/FlowEditor/Private/Asset/AssetTypeActions_FlowAsset.cpp index 180d87a0b..060b57260 100644 --- a/Source/FlowEditor/Private/Asset/AssetTypeActions_FlowAsset.cpp +++ b/Source/FlowEditor/Private/Asset/AssetTypeActions_FlowAsset.cpp @@ -1,5 +1,6 @@ #include "Asset/AssetTypeActions_FlowAsset.h" #include "FlowEditorModule.h" +#include "Graph/FlowGraphSettings.h" #include "FlowAsset.h" @@ -14,7 +15,7 @@ FText FAssetTypeActions_FlowAsset::GetName() const uint32 FAssetTypeActions_FlowAsset::GetCategories() { - return FFlowEditorModule::FlowAssetCategory; + return UFlowGraphSettings::Get()->bExposeFlowAssetCreation ? FFlowEditorModule::FlowAssetCategory : 0; } UClass* FAssetTypeActions_FlowAsset::GetSupportedClass() const diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp index 98348af51..b1bb137c8 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp @@ -2,12 +2,14 @@ UFlowGraphSettings::UFlowGraphSettings(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) + , bExposeFlowAssetCreation(true) + , bExposeFlowNodeCreation(true) + , bShowAssetToolbarAboveLevelEditor(true) , bShowDefaultPinNames(false) , ExecPinColorModifier(0.75f, 0.75f, 0.75f, 1.0f) , NodeDescriptionBackground(FLinearColor(0.0625f, 0.0625f, 0.0625f, 1.0f)) , NodeStatusBackground(FLinearColor(0.12f, 0.12f, 0.12f, 1.0f)) , NodePreloadedBackground(FLinearColor(0.12f, 0.12f, 0.12f, 1.0f)) - , bShowAssetToolbarAboveLevelEditor(true) , InactiveWireColor(FLinearColor(0.364f, 0.364f, 0.364f, 1.0f)) , InactiveWireThickness(1.5f) , RecentWireDuration(3.0f) diff --git a/Source/FlowEditor/Private/Nodes/AssetTypeActions_FlowNodeBlueprint.cpp b/Source/FlowEditor/Private/Nodes/AssetTypeActions_FlowNodeBlueprint.cpp index b12dcdc9d..f6086b3ab 100644 --- a/Source/FlowEditor/Private/Nodes/AssetTypeActions_FlowNodeBlueprint.cpp +++ b/Source/FlowEditor/Private/Nodes/AssetTypeActions_FlowNodeBlueprint.cpp @@ -1,6 +1,7 @@ #include "Nodes/AssetTypeActions_FlowNodeBlueprint.h" #include "Nodes/FlowNodeBlueprintFactory.h" #include "FlowEditorModule.h" +#include "Graph/FlowGraphSettings.h" #include "Nodes/FlowNodeBlueprint.h" @@ -13,7 +14,7 @@ FText FAssetTypeActions_FlowNodeBlueprint::GetName() const uint32 FAssetTypeActions_FlowNodeBlueprint::GetCategories() { - return FFlowEditorModule::FlowAssetCategory; + return UFlowGraphSettings::Get()->bExposeFlowNodeCreation ? FFlowEditorModule::FlowAssetCategory : 0; } UClass* FAssetTypeActions_FlowNodeBlueprint::GetSupportedClass() const diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h index bb9d2f495..e33e7de87 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h @@ -14,6 +14,21 @@ class UFlowGraphSettings final : public UDeveloperSettings GENERATED_UCLASS_BODY() static UFlowGraphSettings* Get() { return CastChecked(UFlowGraphSettings::StaticClass()->GetDefaultObject()); } + /** Show Flow Asset in Flow category of "Create Asset" menu? + * Requires restart after making a change. */ + UPROPERTY(EditAnywhere, config, Category = "Default UI") + bool bExposeFlowAssetCreation; + + /** Show Flow Node blueprint in Flow category of "Create Asset" menu? + * Requires restart after making a change. */ + UPROPERTY(EditAnywhere, config, Category = "Default UI") + bool bExposeFlowNodeCreation; + + /** Show Flow Asset toolbar? + * Requires restart after making a change. */ + UPROPERTY(EditAnywhere, config, Category = "Default UI") + bool bShowAssetToolbarAboveLevelEditor; + /** Hide specific nodes from the Flow Palette without changing the source code. * Requires restart after making a change. */ UPROPERTY(EditAnywhere, config, Category = "Nodes") @@ -37,9 +52,6 @@ class UFlowGraphSettings final : public UDeveloperSettings UPROPERTY(EditAnywhere, config, Category = "NodePopups") FLinearColor NodePreloadedBackground; - - UPROPERTY(EditAnywhere, config, Category = "World") - bool bShowAssetToolbarAboveLevelEditor; UPROPERTY(EditAnywhere, config, Category = "Wires") FLinearColor InactiveWireColor; From 0d4fcdc7660f0a5ee398dd2a3a1d4af4c0ae8be3 Mon Sep 17 00:00:00 2001 From: Constantine Romakhov <34831419+Solessfir@users.noreply.github.com> Date: Thu, 19 Aug 2021 17:28:23 +0300 Subject: [PATCH 012/338] Fixed Engine version string in Flow.uplugin could not be parsed (#51) --- Flow.uplugin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.uplugin b/Flow.uplugin index 35a7e2571..7b536820b 100644 --- a/Flow.uplugin +++ b/Flow.uplugin @@ -9,7 +9,7 @@ "DocsURL" : "https://github.com/MothCocoon/FlowGraph/wiki", "MarketplaceURL" : "", "SupportURL": "https://discord.gg/zMtMQ2vUUa", - "EngineVersion": "5.0", + "EngineAssociation": "5.0", "EnabledByDefault" : true, "CanContainContent" : false, "IsBetaVersion" : false, From 00d93cee8305ee5d4bfc094926a5f446423ab9cf Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 23 Aug 2021 23:50:20 +0200 Subject: [PATCH 013/338] using Viewport Stats Subsystem to display permanent error messages --- Source/Flow/Private/Nodes/FlowNode.cpp | 34 ++++++++++++++++++++------ Source/Flow/Public/FlowTypes.h | 7 ++++++ Source/Flow/Public/Nodes/FlowNode.h | 2 +- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 48353f6bd..eb5ee2f57 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -6,6 +6,7 @@ #include "FlowTypes.h" #include "Engine/Engine.h" +#include "Engine/ViewportStatsSubsystem.h" #include "Engine/World.h" #include "Misc/App.h" #include "Misc/Paths.h" @@ -15,10 +16,10 @@ FFlowPin UFlowNode::DefaultInputPin(TEXT("In")); FFlowPin UFlowNode::DefaultOutputPin(TEXT("Out")); -FString UFlowNode::MissingIdentityTag = TEXT("Missing Identity Tag!"); -FString UFlowNode::MissingNotifyTag = TEXT("Missing Notify Tag!"); -FString UFlowNode::MissingClass = TEXT("Missing class!"); -FString UFlowNode::NoActorsFound = TEXT("No actors found!"); +FString UFlowNode::MissingIdentityTag = TEXT("Missing Identity Tag"); +FString UFlowNode::MissingNotifyTag = TEXT("Missing Notify Tag"); +FString UFlowNode::MissingClass = TEXT("Missing class"); +FString UFlowNode::NoActorsFound = TEXT("No actors found"); UFlowNode::UFlowNode(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) @@ -356,7 +357,7 @@ void UFlowNode::TriggerOutput(const FName& PinName, const bool bFinish /*= false { Finish(); } - + #if !UE_BUILD_SHIPPING if (OutputPins.Contains(PinName)) { @@ -551,12 +552,31 @@ FString UFlowNode::GetProgressAsString(float Value) return TempString; } -void UFlowNode::LogError(FString Message) const +void UFlowNode::LogError(FString Message, const EFlowOnScreenMessageType OnScreenMessageType) const { const FString TemplatePath = GetFlowAsset()->TemplateAsset->GetPathName(); Message += TEXT(" in node ") + GetName() + TEXT(", asset ") + FPaths::GetPath(TemplatePath) + TEXT("/") + FPaths::GetBaseFilename(TemplatePath); - GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, Message); + if (OnScreenMessageType == EFlowOnScreenMessageType::Permanent) + { + if (GetWorld()) + { + if (UViewportStatsSubsystem* StatsSubsystem = GetWorld()->GetSubsystem()) + { + StatsSubsystem->AddDisplayDelegate([this, Message](FText& OutText, FLinearColor& OutColor) + { + OutText = FText::FromString(Message); + OutColor = FLinearColor::Red; + return !IsPendingKill() && ActivationState != EFlowNodeState::NeverActivated; + }); + } + } + } + else + { + GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, Message); + } + UE_LOG(LogFlow, Error, TEXT("%s"), *Message); } diff --git a/Source/Flow/Public/FlowTypes.h b/Source/Flow/Public/FlowTypes.h index b1a6b390a..383444480 100644 --- a/Source/Flow/Public/FlowTypes.h +++ b/Source/Flow/Public/FlowTypes.h @@ -41,3 +41,10 @@ enum class EFlowNetMode : uint8 ServerOnly UMETA(ToolTip = "Executed on the server"), SinglePlayerOnly UMETA(ToolTip = "Executed only in the single player, not available in multiplayer.") }; + +UENUM(BlueprintType) +enum class EFlowOnScreenMessageType : uint8 +{ + Temporary, + Permanent +}; diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 66103f648..300c48743 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -331,7 +331,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte static FString GetProgressAsString(float Value); UFUNCTION(BlueprintCallable, Category = "FlowNode") - void LogError(FString Message) const; + void LogError(FString Message, const EFlowOnScreenMessageType OnScreenMessageType = EFlowOnScreenMessageType::Permanent) const; UFUNCTION(BlueprintCallable, Category = "FlowNode") void SaveInstance(FFlowNodeSaveData& NodeRecord); From a3e54eea1fc496a8222278c6623637455441b7e7 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 3 Sep 2021 00:50:26 +0200 Subject: [PATCH 014/338] copy-paste fixed --- Source/Flow/Private/FlowSubsystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index 10e079aae..9a18dc264 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -321,7 +321,7 @@ void UFlowSubsystem::UnregisterComponent(UFlowComponent* Component) void UFlowSubsystem::OnIdentityTagRemoved(UFlowComponent* Component, const FGameplayTag& RemovedTag) { - FlowComponentRegistry.Emplace(RemovedTag, Component); + FlowComponentRegistry.Remove(RemovedTag, Component); // broadcast OnComponentUnregistered only if this component isn't present in the registry anymore if (Component->IdentityTags.Num() > 0) From f07ec269ce8d8349986791eda3bacfbf0fe15a0f Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 3 Sep 2021 00:50:39 +0200 Subject: [PATCH 015/338] const correctness --- Source/Flow/Private/FlowComponent.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Source/Flow/Private/FlowComponent.cpp b/Source/Flow/Private/FlowComponent.cpp index 813707933..fabcfd9a7 100644 --- a/Source/Flow/Private/FlowComponent.cpp +++ b/Source/Flow/Private/FlowComponent.cpp @@ -290,9 +290,9 @@ void UFlowComponent::NotifyActor(const FGameplayTag ActorTag, const FGameplayTag { if (IsFlowNetMode(NetMode) && NotifyTag.IsValid() && HasBegunPlay()) { - if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) + if (const UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) { - for (TWeakObjectPtr& Component : FlowSubsystem->GetComponents(ActorTag)) + for (const TWeakObjectPtr& Component : FlowSubsystem->GetComponents(ActorTag)) { Component->ReceiveNotify.Broadcast(this, NotifyTag); } @@ -308,11 +308,11 @@ void UFlowComponent::NotifyActor(const FGameplayTag ActorTag, const FGameplayTag void UFlowComponent::OnRep_NotifyTagsFromAnotherComponent() { - if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) + if (const UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) { for (const FNotifyTagReplication& Notify : NotifyTagsFromAnotherComponent) { - for (TWeakObjectPtr& Component : FlowSubsystem->GetComponents(Notify.ActorTag)) + for (const TWeakObjectPtr& Component : FlowSubsystem->GetComponents(Notify.ActorTag)) { Component->ReceiveNotify.Broadcast(this, Notify.NotifyTag); } @@ -341,7 +341,7 @@ void UFlowComponent::FinishRootFlow(const EFlowFinishPolicy FinishPolicy) UFlowAsset* UFlowComponent::GetRootFlowInstance() { - if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) + if (const UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) { return FlowSubsystem->GetRootFlow(this); } From 1ec1c929b46faa2dd185ca74eeba88db73f19dc0 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 3 Sep 2021 00:51:36 +0200 Subject: [PATCH 016/338] added Identity Match Type, improves Component Observer --- .../World/FlowNode_ComponentObserver.cpp | 16 ++++----- Source/Flow/Public/FlowTypes.h | 35 +++++++++++++++++-- .../Nodes/World/FlowNode_ComponentObserver.h | 21 ++++++----- 3 files changed, 54 insertions(+), 18 deletions(-) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp index cd7537f9e..c2554dedf 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp @@ -3,6 +3,7 @@ UFlowNode_ComponentObserver::UFlowNode_ComponentObserver(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) + , IdentityMatchType(EFlowTagContainerMatchType::HasAnyExact) , SuccessLimit(1) , SuccessCount(0) { @@ -60,10 +61,9 @@ void UFlowNode_ComponentObserver::StartObserving() } GetFlowSubsystem()->OnComponentRegistered.AddDynamic(this, &UFlowNode_ComponentObserver::OnComponentRegistered); - GetFlowSubsystem()->OnComponentUnregistered.AddDynamic(this, &UFlowNode_ComponentObserver::OnComponentUnregistered); - GetFlowSubsystem()->OnComponentTagAdded.AddDynamic(this, &UFlowNode_ComponentObserver::OnComponentTagAdded); GetFlowSubsystem()->OnComponentTagRemoved.AddDynamic(this, &UFlowNode_ComponentObserver::OnComponentTagRemoved); + GetFlowSubsystem()->OnComponentUnregistered.AddDynamic(this, &UFlowNode_ComponentObserver::OnComponentUnregistered); } void UFlowNode_ComponentObserver::StopObserving() @@ -77,7 +77,7 @@ void UFlowNode_ComponentObserver::StopObserving() void UFlowNode_ComponentObserver::OnComponentRegistered(UFlowComponent* Component) { - if (!RegisteredActors.Contains(Component->GetOwner()) && Component->IdentityTags.HasAnyExact(IdentityTags)) + if (!RegisteredActors.Contains(Component->GetOwner()) && FlowTypes::HasMatchingTags(Component->IdentityTags, IdentityTags, IdentityMatchType) == true) { ObserveActor(Component->GetOwner(), Component); } @@ -85,24 +85,24 @@ void UFlowNode_ComponentObserver::OnComponentRegistered(UFlowComponent* Componen void UFlowNode_ComponentObserver::OnComponentTagAdded(UFlowComponent* Component, const FGameplayTagContainer& AddedTags) { - if (!RegisteredActors.Contains(Component->GetOwner()) && AddedTags.HasAnyExact(IdentityTags)) + if (!RegisteredActors.Contains(Component->GetOwner()) && FlowTypes::HasMatchingTags(Component->IdentityTags, IdentityTags, IdentityMatchType) == true) { ObserveActor(Component->GetOwner(), Component); } } -void UFlowNode_ComponentObserver::OnComponentUnregistered(UFlowComponent* Component) +void UFlowNode_ComponentObserver::OnComponentTagRemoved(UFlowComponent* Component, const FGameplayTagContainer& RemovedTags) { - if (RegisteredActors.Contains(Component->GetOwner()) && Component->IdentityTags.HasAnyExact(IdentityTags)) + if (RegisteredActors.Contains(Component->GetOwner()) && FlowTypes::HasMatchingTags(Component->IdentityTags, IdentityTags, IdentityMatchType) == false) { RegisteredActors.Remove(Component->GetOwner()); ForgetActor(Component->GetOwner(), Component); } } -void UFlowNode_ComponentObserver::OnComponentTagRemoved(UFlowComponent* Component, const FGameplayTagContainer& RemovedTags) +void UFlowNode_ComponentObserver::OnComponentUnregistered(UFlowComponent* Component) { - if (RegisteredActors.Contains(Component->GetOwner()) && RemovedTags.HasAnyExact(IdentityTags)) + if (RegisteredActors.Contains(Component->GetOwner())) { RegisteredActors.Remove(Component->GetOwner()); ForgetActor(Component->GetOwner(), Component); diff --git a/Source/Flow/Public/FlowTypes.h b/Source/Flow/Public/FlowTypes.h index 383444480..026cc6596 100644 --- a/Source/Flow/Public/FlowTypes.h +++ b/Source/Flow/Public/FlowTypes.h @@ -1,5 +1,7 @@ #pragma once +#include "GameplayTagContainer.h" + #include "FlowSave.h" #include "FlowTypes.generated.h" @@ -35,13 +37,42 @@ enum class EFlowFinishPolicy : uint8 UENUM(BlueprintType) enum class EFlowNetMode : uint8 { - Any UMETA(ToolTip = "Any networking mode"), + Any UMETA(ToolTip = "Any networking mode."), Authority UMETA(ToolTip = "Executed on the server or in the single-player (standalone)."), ClientOnly UMETA(ToolTip = "Executed locally, on the single client."), - ServerOnly UMETA(ToolTip = "Executed on the server"), + ServerOnly UMETA(ToolTip = "Executed on the server."), SinglePlayerOnly UMETA(ToolTip = "Executed only in the single player, not available in multiplayer.") }; +UENUM(BlueprintType) +enum class EFlowTagContainerMatchType : uint8 +{ + HasAny UMETA(ToolTip = "Check if container A contains ANY of the tags in the specified container B."), + HasAnyExact UMETA(ToolTip = "Check if container A contains ANY of the tags in the specified container B, only allowing exact matches."), + HasAll UMETA(ToolTip = "Check if container A contains ALL of the tags in the specified container B."), + HasAllExact UMETA(ToolTip = "Check if container A contains ALL of the tags in the specified container B, only allowing exact matches") +}; + +namespace FlowTypes +{ + FORCEINLINE_DEBUGGABLE bool HasMatchingTags(const FGameplayTagContainer& Container, const FGameplayTagContainer& OtherContainer, const EFlowTagContainerMatchType MatchType) + { + switch (MatchType) + { + case EFlowTagContainerMatchType::HasAny: + return Container.HasAny(OtherContainer); + case EFlowTagContainerMatchType::HasAnyExact: + return Container.HasAnyExact(OtherContainer); + case EFlowTagContainerMatchType::HasAll: + return Container.HasAll(OtherContainer); + case EFlowTagContainerMatchType::HasAllExact: + return Container.HasAllExact(OtherContainer); + default: + return false; + } + } +} + UENUM(BlueprintType) enum class EFlowOnScreenMessageType : uint8 { diff --git a/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h b/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h index d19b647d4..351ea5276 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h @@ -15,13 +15,18 @@ UCLASS(Abstract, NotBlueprintable) class FLOW_API UFlowNode_ComponentObserver : public UFlowNode { GENERATED_UCLASS_BODY() - - friend class FFlowNode_ComponentObserverDetails; + friend class FFlowNode_ComponentObserverDetails; + protected: UPROPERTY(EditAnywhere, Category = "ObservedComponent") FGameplayTagContainer IdentityTags; + // Container A: Identity Tags in Flow Component + // Container B: Identity Tags listed above + UPROPERTY(EditAnywhere, Category = "ObservedComponent") + EFlowTagContainerMatchType IdentityMatchType; + // This node will become Completed, if Success Limit > 0 and Success Count reaches this limit // Set this to zero, if you'd like receive events indefinitely (node would finish work only if explicitly Stopped) UPROPERTY(EditAnywhere, Category = "Lifetime", meta = (ClampMin = 0)) @@ -30,12 +35,12 @@ class FLOW_API UFlowNode_ComponentObserver : public UFlowNode // This node will become Completed, if Success Limit > 0 and Success Count reaches this limit UPROPERTY(VisibleAnywhere, Category = "Lifetime") int32 SuccessCount; - + TMap, TWeakObjectPtr> RegisteredActors; protected: virtual void PostLoad() override; - + virtual void ExecuteInput(const FName& PinName) override; virtual void OnLoad_Implementation() override; @@ -46,20 +51,20 @@ class FLOW_API UFlowNode_ComponentObserver : public UFlowNode virtual void OnComponentRegistered(UFlowComponent* Component); UFUNCTION() - virtual void OnComponentTagAdded(UFlowComponent* Component, const FGameplayTagContainer& AddedTags); + virtual void OnComponentTagAdded(UFlowComponent* Component, const FGameplayTagContainer& AddedTags); UFUNCTION() - virtual void OnComponentUnregistered(UFlowComponent* Component); + virtual void OnComponentTagRemoved(UFlowComponent* Component, const FGameplayTagContainer& RemovedTags); UFUNCTION() - virtual void OnComponentTagRemoved(UFlowComponent* Component, const FGameplayTagContainer& RemovedTags); + virtual void OnComponentUnregistered(UFlowComponent* Component); virtual void ObserveActor(TWeakObjectPtr Actor, TWeakObjectPtr Component) {} virtual void ForgetActor(TWeakObjectPtr Actor, TWeakObjectPtr Component) {} UFUNCTION() virtual void OnEventReceived(); - + virtual void Cleanup() override; #if WITH_EDITOR From 214ecfb49c3d97622e5c9a95b7b8ff617f37f4ef Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 3 Sep 2021 00:52:25 +0200 Subject: [PATCH 017/338] exposed NetMode parameter, passing it to NotifyFromGraph() --- Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp | 7 ++++--- Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h | 3 +++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp b/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp index 6f1f67309..a2f5d71bb 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp @@ -6,6 +6,7 @@ UFlowNode_NotifyActor::UFlowNode_NotifyActor(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) + , NetMode(EFlowNetMode::Authority) { #if WITH_EDITOR Category = TEXT("Notifies"); @@ -30,11 +31,11 @@ void UFlowNode_NotifyActor::PostLoad() void UFlowNode_NotifyActor::ExecuteInput(const FName& PinName) { - if (UFlowSubsystem* FlowSubsystem = GetWorld()->GetGameInstance()->GetSubsystem()) + if (const UFlowSubsystem* FlowSubsystem = GetWorld()->GetGameInstance()->GetSubsystem()) { - for (TWeakObjectPtr& Component : FlowSubsystem->GetComponents(IdentityTags, EGameplayContainerMatchType::Any)) + for (const TWeakObjectPtr& Component : FlowSubsystem->GetComponents(IdentityTags, EGameplayContainerMatchType::Any)) { - Component->NotifyFromGraph(NotifyTags); + Component->NotifyFromGraph(NotifyTags, NetMode); } } diff --git a/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h b/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h index ae0201d80..6d0f1a428 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h @@ -20,6 +20,9 @@ class FLOW_API UFlowNode_NotifyActor : public UFlowNode UPROPERTY(EditAnywhere, Category = "ObservedComponent") FGameplayTagContainer NotifyTags; + UPROPERTY(EditAnywhere, Category = "ObservedComponent") + EFlowNetMode NetMode; + virtual void PostLoad() override; virtual void ExecuteInput(const FName& PinName) override; From 3100f2c527531f4d1b0e76296e5de002ae457ca4 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 5 Sep 2021 18:53:14 +0200 Subject: [PATCH 018/338] updated Reikon acknowledgement --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 92374bc1c..9b45dab38 100644 --- a/README.md +++ b/README.md @@ -17,11 +17,13 @@ It's a design-agnostic event node editor. ## In-depth video presentation This 24-minute presentation breaks down the concept of the Flow Graph. It goes through everything written in this ReadMe but in greater detail. -[![Introducing Flow Graph for Unreal Engine](https://img.youtube.com/vi/Rj76JP1f-I4/0.jpg)](https://www.youtube.com/watch?v=Rj76JP1f-I4) +[![Introducing Flow Graph for Unreal Engine](https://img.youtube.com/vi/Rj76JP1f-I4/0.jpg)](https://www.youtube.com/watch?v=BAqhccgKx_k) ## Acknowledgements -I feel it's important to mention that I didn't invent anything new here, with the Flow Graph. It's an old and proven concept. I'm just one of many developers who decided it would be crazy useful to adopt it for Unreal Engine. And this time, also to make it publically available as the open-source project. +I got an opportunity to work on something like the Flow Graph at Reikon Games. They shared my enthusiasm for providing the plugin as open source and as such allowed me to publish this work and keep expanding it as a personal project. Kudos, guys! +Reikon badly wanted to build a better tool for implementing game flow rather than level blueprints or existing Marketplace plug-ins. I was very much interested in this since the studio was just starting with the production of a new title. And we did exactly that, created a node editor dedicated to scripting game flow. Kudos to Dariusz Murawski - a programmer who spent a few months with me to establish the working system and editor. And who had to endure my never-ending feedback and requests. + +I feel it's important to mention that I didn't invent anything new here, with the Flow Graph. It's an old and proven concept. I'm just one of many developers who decided it would be crazy useful to adopt it for Unreal Engine. And this time, also to make it publicly available as an open-source project. * Such simple graph-based tools for scripting game screenplay are utilized for a long time. Traditionally, RPG games needed such tools as there a lot of stories, quests, dialogues. * The best narrative toolset I had the opportunity to work with is what CD Projekt RED built for The Witcher series. Sadly, you can't download the modding toolkit for The Witcher 2 - yeah, it was publically available for some time. Still... you can watch the GDC talk by Piotr Tomsiński on [Cinematic Dialogues in The Witcher 3: Wild Hunt](https://www.youtube.com/watch?v=chf3REzAjgI) - it includes a brief presentation how Quest and Dialogue editors look like. It wouldn't be possible to create such an amazing narrative game without this kind of toolset. I did miss that so much when I moved to the Unreal Engine... -* Finally got an opportunity to work on something like this at [Reikon Games](http://www.reikongames.com/). They badly wanted to build a better tool for implementing game flow than level blueprints or existing Marketplace plug-ins. I was very much interested in this since the studio was just starting with the production of the new title. And we did exactly that, created a node editor dedicated to scripting game flow. Kudos to Dariusz Murawski - a programmer who spent a few months with me to establish the working system and editor. And who had to endure my never-ending feedback and requests. * At some point I felt comfortable enough with programming editor tools so I decided to build my own version of such toolset, meant to be published as an open-source project. I am thankful to Reikon bosses they see no issues with me releasing Flow Graph, which is "obviously" similar to our internal tool in many ways. I mean, it's so simple concept of "single node representing a single game feature"... and it's based on the same UE4 node graph API. Some corporations might have an issue with that. From f9f66eb16b52d87f1373c7092167156d883e7584 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 5 Sep 2021 22:20:01 +0200 Subject: [PATCH 019/338] ue5-main fixes --- Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp | 6 ++---- .../FlowEditor/Private/Nodes/FlowNodeBlueprintFactory.cpp | 2 +- Source/FlowEditor/Public/Graph/FlowGraphSchema.h | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp index de20dc7cb..bf0cbfa88 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -14,7 +14,6 @@ #include "AssetRegistryModule.h" #include "Developer/ToolMenus/Public/ToolMenus.h" #include "EdGraph/EdGraph.h" -#include "Misc/HotReloadInterface.h" #include "ScopedTransaction.h" #include "UObject/UObjectIterator.h" @@ -42,8 +41,7 @@ void UFlowGraphSchema::SubscribeToAssetChanges() AssetRegistry.Get().OnAssetAdded().AddStatic(&UFlowGraphSchema::OnAssetAdded); AssetRegistry.Get().OnAssetRemoved().AddStatic(&UFlowGraphSchema::RemoveAsset); - IHotReloadInterface& HotReloadSupport = FModuleManager::LoadModuleChecked("HotReload"); - HotReloadSupport.OnHotReload().AddStatic(&UFlowGraphSchema::OnHotReload); + FCoreUObjectDelegates::ReloadCompleteDelegate.AddStatic(&UFlowGraphSchema::OnHotReload); if (GEditor) { @@ -298,7 +296,7 @@ void UFlowGraphSchema::GatherFlowNodes() RefreshNodeList(); } -void UFlowGraphSchema::OnHotReload(bool bWasTriggeredAutomatically) +void UFlowGraphSchema::OnHotReload(EReloadCompleteReason ReloadCompleteReason) { GatherFlowNodes(); } diff --git a/Source/FlowEditor/Private/Nodes/FlowNodeBlueprintFactory.cpp b/Source/FlowEditor/Private/Nodes/FlowNodeBlueprintFactory.cpp index 5e086a72d..8dfd6cbd6 100644 --- a/Source/FlowEditor/Private/Nodes/FlowNodeBlueprintFactory.cpp +++ b/Source/FlowEditor/Private/Nodes/FlowNodeBlueprintFactory.cpp @@ -151,7 +151,7 @@ class SFlowNodeBlueprintCreateDialog final : public SCompoundWidget // All child child classes of UFlowNode are valid Filter->AllowedChildrenOfClasses.Add(UFlowNode::StaticClass()); - Options.ClassFilter = Filter; + Options.ClassFilters = {Filter.ToSharedRef()}; ParentClassContainer->ClearChildren(); ParentClassContainer->AddSlot() diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h index f961eb174..2e394887a 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h @@ -45,7 +45,7 @@ class FLOWEDITOR_API UFlowGraphSchema : public UEdGraphSchema static bool IsFlowNodePlaceable(const UClass* Class); static void GatherFlowNodes(); - static void OnHotReload(bool bWasTriggeredAutomatically); + static void OnHotReload(EReloadCompleteReason ReloadCompleteReason); static void OnAssetAdded(const FAssetData& AssetData); static void AddAsset(const FAssetData& AssetData, const bool bBatch); From e4493e2e45bb9cc5ae14497a348d6989d40b0004 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 20 Sep 2021 23:26:20 +0200 Subject: [PATCH 020/338] prevent starting Flow from the obsolete AWorldSettings actor that still exists in the world --- Source/Flow/Private/FlowWorldSettings.cpp | 17 +++++++++++++++++ Source/Flow/Public/FlowWorldSettings.h | 1 + 2 files changed, 18 insertions(+) diff --git a/Source/Flow/Private/FlowWorldSettings.cpp b/Source/Flow/Private/FlowWorldSettings.cpp index 4a0fcf988..225401c14 100644 --- a/Source/Flow/Private/FlowWorldSettings.cpp +++ b/Source/Flow/Private/FlowWorldSettings.cpp @@ -20,3 +20,20 @@ void AFlowWorldSettings::PostLoad() FlowComponent->RootFlow = FlowAsset_DEPRECATED; } } + +void AFlowWorldSettings::PostInitializeComponents() +{ + Super::PostInitializeComponents(); + + Super::PostInitializeComponents(); + + if (const UWorld* World = GetWorld()) + { + // prevent starting Flow from the obsolete AWorldSettings actor that still exists in the world + // i.e. instance of class that is parent to the class set in Project Settings + if (World->GetWorldSettings() != this) + { + GetFlowComponent()->bAutoStartRootFlow = false; + } + } +} diff --git a/Source/Flow/Public/FlowWorldSettings.h b/Source/Flow/Public/FlowWorldSettings.h index 97402469f..d07e32eaf 100644 --- a/Source/Flow/Public/FlowWorldSettings.h +++ b/Source/Flow/Public/FlowWorldSettings.h @@ -21,6 +21,7 @@ class FLOW_API AFlowWorldSettings : public AWorldSettings UFlowComponent* GetFlowComponent() const { return FlowComponent; } virtual void PostLoad() override; + virtual void PostInitializeComponents() override; private: UPROPERTY() From 48283811ceab57dd670182bb5228b3bb61b22622 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 24 Sep 2021 13:57:54 +0200 Subject: [PATCH 021/338] typo fix --- Source/Flow/Private/FlowWorldSettings.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Source/Flow/Private/FlowWorldSettings.cpp b/Source/Flow/Private/FlowWorldSettings.cpp index 225401c14..441a894bd 100644 --- a/Source/Flow/Private/FlowWorldSettings.cpp +++ b/Source/Flow/Private/FlowWorldSettings.cpp @@ -25,8 +25,6 @@ void AFlowWorldSettings::PostInitializeComponents() { Super::PostInitializeComponents(); - Super::PostInitializeComponents(); - if (const UWorld* World = GetWorld()) { // prevent starting Flow from the obsolete AWorldSettings actor that still exists in the world From 72474978270629aaee4618beffe700c0732c87eb Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 24 Sep 2021 14:07:41 +0200 Subject: [PATCH 022/338] exposed engine's Playback Settings --- .../Private/Nodes/World/FlowNode_PlayLevelSequence.cpp | 6 +++--- .../Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h | 8 +++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp index da1bb26b4..09e415b1a 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp @@ -108,7 +108,7 @@ void UFlowNode_PlayLevelSequence::FlushContent() } } -void UFlowNode_PlayLevelSequence::CreatePlayer(const FMovieSceneSequencePlaybackSettings& PlaybackSettings) +void UFlowNode_PlayLevelSequence::CreatePlayer() { LoadedSequence = LoadAsset(Sequence); if (LoadedSequence) @@ -131,7 +131,7 @@ void UFlowNode_PlayLevelSequence::ExecuteInput(const FName& PinName) if (GetFlowSubsystem()->GetWorld() && LoadedSequence) { - CreatePlayer(FMovieSceneSequencePlaybackSettings()); + CreatePlayer(); TriggerOutput(TEXT("PreStart")); @@ -165,7 +165,7 @@ void UFlowNode_PlayLevelSequence::OnLoad_Implementation() if (GetFlowSubsystem()->GetWorld() && LoadedSequence) { - CreatePlayer(FMovieSceneSequencePlaybackSettings()); + CreatePlayer(); SequencePlayer->OnFinished.AddDynamic(this, &UFlowNode_PlayLevelSequence::OnPlaybackFinished); SequencePlayer->SetPlayRate(TimeDilation); diff --git a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h index 4ef7e914b..baa77747f 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h @@ -21,7 +21,6 @@ UCLASS(NotBlueprintable, meta = (DisplayName = "Play Level Sequence")) class FLOW_API UFlowNode_PlayLevelSequence : public UFlowNode { GENERATED_UCLASS_BODY() - friend struct FFlowTrackExecutionToken; static FFlowNodeLevelSequenceEvent OnPlaybackStarted; @@ -30,6 +29,9 @@ class FLOW_API UFlowNode_PlayLevelSequence : public UFlowNode UPROPERTY(EditAnywhere, Category = "Sequence") TSoftObjectPtr Sequence; + UPROPERTY(EditAnywhere, Category = "Sequence") + FMovieSceneSequencePlaybackSettings PlaybackSettings; + protected: UPROPERTY() ULevelSequence* LoadedSequence; @@ -57,11 +59,11 @@ class FLOW_API UFlowNode_PlayLevelSequence : public UFlowNode virtual void PreloadContent() override; virtual void FlushContent() override; - void CreatePlayer(const FMovieSceneSequencePlaybackSettings& PlaybackSettings); + void CreatePlayer(); protected: virtual void ExecuteInput(const FName& PinName) override; - + virtual void OnSave_Implementation() override; virtual void OnLoad_Implementation() override; From 6013d68107d3aad1e14ae6c28c5a0ba4107a88c0 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 28 Sep 2021 20:43:06 +0200 Subject: [PATCH 023/338] const correctness --- Source/Flow/Private/FlowAsset.cpp | 8 ++++---- Source/Flow/Public/FlowAsset.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 3449b6ae5..f7d45d073 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -124,7 +124,7 @@ void UFlowAsset::HarvestNodeConnections() { if (ThisPin->Direction == EGPD_Output && ThisPin->LinkedTo.Num() > 0) { - if (UEdGraphPin* LinkedPin = ThisPin->LinkedTo[0]) + if (const UEdGraphPin* LinkedPin = ThisPin->LinkedTo[0]) { const UEdGraphNode* LinkedNode = LinkedPin->GetOwningNode(); Connections.Add(ThisPin->PinName, FConnectedPin(LinkedNode->NodeGuid, LinkedPin->PinName)); @@ -154,9 +154,9 @@ UFlowNode* UFlowAsset::GetNode(const FGuid& Guid) const return nullptr; } -void UFlowAsset::AddInstance(UFlowAsset* NewInstance) +void UFlowAsset::AddInstance(UFlowAsset* Instance) { - ActiveInstances.Add(NewInstance); + ActiveInstances.Add(Instance); } int32 UFlowAsset::RemoveInstance(UFlowAsset* Instance) @@ -195,7 +195,7 @@ void UFlowAsset::ClearInstances() #if WITH_EDITOR void UFlowAsset::GetInstanceDisplayNames(TArray>& OutDisplayNames) const { - for (UFlowAsset* Instance : ActiveInstances) + for (const UFlowAsset* Instance : ActiveInstances) { OutDisplayNames.Emplace(MakeShareable(new FName(Instance->GetDisplayName()))); } diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 4fe578d94..9545c4298 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -131,7 +131,7 @@ class FLOW_API UFlowAsset : public UObject #endif public: - void AddInstance(UFlowAsset* NewInstance); + void AddInstance(UFlowAsset* Instance); int32 RemoveInstance(UFlowAsset* Instance); void ClearInstances(); From 24ce1b031327e1cedd3358e52a007b9e1339842c Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 28 Sep 2021 20:43:50 +0200 Subject: [PATCH 024/338] replace method deprecated in UE5 --- Source/Flow/Private/Nodes/FlowNode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index eb5ee2f57..502a2e6d9 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -567,7 +567,7 @@ void UFlowNode::LogError(FString Message, const EFlowOnScreenMessageType OnScree { OutText = FText::FromString(Message); OutColor = FLinearColor::Red; - return !IsPendingKill() && ActivationState != EFlowNodeState::NeverActivated; + return IsValid(this) && ActivationState != EFlowNodeState::NeverActivated; }); } } From a73dfaed3e1a69509603cfae999a5c730ff5db12 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 28 Sep 2021 20:59:08 +0200 Subject: [PATCH 025/338] toolbar classes merged, a lot of Flow Asset methods made virtual --- .../Private/Asset/FlowAssetEditor.cpp | 153 +++++---------- .../Private/Asset/FlowAssetToolbar.cpp | 181 +++++++++++++++++- .../FlowEditor/Private/Asset/FlowDebugger.cpp | 2 +- .../Private/Asset/FlowDebuggerToolbar.cpp | 175 ----------------- .../FlowEditor/Public/Asset/FlowAssetEditor.h | 87 ++++----- .../Public/Asset/FlowAssetToolbar.h | 82 +++++++- .../Public/Asset/FlowDebuggerToolbar.h | 94 --------- 7 files changed, 340 insertions(+), 434 deletions(-) delete mode 100644 Source/FlowEditor/Private/Asset/FlowDebuggerToolbar.cpp delete mode 100644 Source/FlowEditor/Public/Asset/FlowDebuggerToolbar.h diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index 9883d38c2..37c07cb52 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -2,9 +2,7 @@ #include "Asset/FlowAssetToolbar.h" #include "Asset/FlowDebugger.h" -#include "Asset/FlowDebuggerToolbar.h" #include "FlowEditorCommands.h" -#include "FlowEditorModule.h" #include "Graph/FlowGraph.h" #include "Graph/FlowGraphSchema.h" #include "Graph/FlowGraphSchema_Actions.h" @@ -178,13 +176,13 @@ void FFlowAssetEditor::InitFlowAssetEditor(const EToolkitMode::Type Mode, const GEditor->RegisterForUndo(this); UFlowGraphSchema::SubscribeToAssetChanges(); + FlowDebugger = MakeShareable(new FFlowDebugger); - FGraphEditorCommands::Register(); - FFlowGraphCommands::Register(); - FFlowSpawnNodeCommands::Register(); + BindToolbarCommands(); + CreateToolbar(); - CreateWidgets(); BindGraphCommands(); + CreateWidgets(); const TSharedRef StandaloneDefaultLayout = FTabManager::NewLayout("FlowAssetEditor_Layout_v3") ->AddArea @@ -210,52 +208,16 @@ void FFlowAssetEditor::InitFlowAssetEditor(const EToolkitMode::Type Mode, const ) ); - const bool bCreateDefaultStandaloneMenu = true; - const bool bCreateDefaultToolbar = true; + constexpr bool bCreateDefaultStandaloneMenu = true; + constexpr bool bCreateDefaultToolbar = true; InitAssetEditor(Mode, InitToolkitHost, TEXT("FlowEditorApp"), StandaloneDefaultLayout, bCreateDefaultStandaloneMenu, bCreateDefaultToolbar, ObjectToEdit, false); - FFlowToolbarCommands::Register(); - - AddFlowAssetToolbar(); - AddPlayWorldToolbar(); - CreateFlowDebugger(); - - FFlowEditorModule* FlowEditorModule = &FModuleManager::LoadModuleChecked("FlowEditor"); - AddMenuExtender(FlowEditorModule->GetFlowAssetMenuExtensibilityManager()->GetAllExtenders(GetToolkitCommands(), GetEditingObjects())); - + RegenerateMenusAndToolbars(); FlowAsset->OnRegenerateToolbars().AddSP(this, &FFlowAssetEditor::RegenerateMenusAndToolbars); } -void FFlowAssetEditor::AddFlowAssetToolbar() -{ - AssetToolbar = MakeShareable(new FFlowAssetToolbar(SharedThis(this))); - - BindAssetCommands(); - - TSharedPtr ToolbarExtender = MakeShareable(new FExtender); - ToolbarExtender->AddToolBarExtension( - "Asset", - EExtensionHook::After, - GetToolkitCommands(), - FToolBarExtensionDelegate::CreateSP(AssetToolbar.Get(), &FFlowAssetToolbar::AddToolbar) - ); - AddToolbarExtender(ToolbarExtender); -} - -void FFlowAssetEditor::BindAssetCommands() -{ - const FFlowToolbarCommands& NodeCommands = FFlowToolbarCommands::Get(); - - ToolkitCommands->MapAction(NodeCommands.RefreshAsset, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::RefreshAsset), - FCanExecuteAction::CreateStatic(&FFlowAssetEditor::CanEdit)); -} - -void FFlowAssetEditor::AddPlayWorldToolbar() const +void FFlowAssetEditor::CreateToolbar() { - // Append play world commands - ToolkitCommands->Append(FPlayWorldCommands::GlobalPlayWorldActions.ToSharedRef()); - FName ParentToolbarName; const FName ToolBarName = GetToolMenuToolbarName(ParentToolbarName); @@ -268,40 +230,25 @@ void FFlowAssetEditor::AddPlayWorldToolbar() const if (FoundMenu) { - FToolMenuSection& Section = FoundMenu->AddSection("Debugging"); - Section.InsertPosition = FToolMenuInsert("Asset", EToolMenuInsertType::After); - - Section.AddDynamicEntry("DebuggingCommands", FNewToolMenuSectionDelegate::CreateLambda([](FToolMenuSection& InSection) - { - FPlayWorldCommands::BuildToolbar(InSection); - })); + AssetToolbar = MakeShareable(new FFlowAssetToolbar(SharedThis(this), FoundMenu)); } } -void FFlowAssetEditor::CreateFlowDebugger() +void FFlowAssetEditor::BindToolbarCommands() { - Debugger = MakeShareable(new FFlowDebugger); - DebuggerToolbar = MakeShareable(new FFlowDebuggerToolbar(SharedThis(this))); - - BindDebuggerCommands(); - - TSharedPtr ToolbarExtender = MakeShareable(new FExtender); - ToolbarExtender->AddToolBarExtension( - "Debugging", - EExtensionHook::After, - GetToolkitCommands(), - FToolBarExtensionDelegate::CreateSP(DebuggerToolbar.Get(), &FFlowDebuggerToolbar::AddToolbar) - ); - AddToolbarExtender(ToolbarExtender); + FFlowToolbarCommands::Register(); + const FFlowToolbarCommands& ToolbarCommands = FFlowToolbarCommands::Get(); - RegenerateMenusAndToolbars(); -} + // Editing + ToolkitCommands->MapAction(ToolbarCommands.RefreshAsset, + FExecuteAction::CreateSP(this, &FFlowAssetEditor::RefreshAsset), + FCanExecuteAction::CreateStatic(&FFlowAssetEditor::CanEdit)); -void FFlowAssetEditor::BindDebuggerCommands() -{ - const FFlowToolbarCommands& NodeCommands = FFlowToolbarCommands::Get(); + // Engine's Play commands + ToolkitCommands->Append(FPlayWorldCommands::GlobalPlayWorldActions.ToSharedRef()); - ToolkitCommands->MapAction(NodeCommands.GoToMasterInstance, + // Debugging + ToolkitCommands->MapAction(ToolbarCommands.GoToMasterInstance, FExecuteAction::CreateSP(this, &FFlowAssetEditor::GoToMasterInstance), FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanGoToMasterInstance), FIsActionChecked(), @@ -321,7 +268,7 @@ void FFlowAssetEditor::RefreshAsset() void FFlowAssetEditor::GoToMasterInstance() { - UFlowAsset* AssetThatInstancedThisAsset = FlowAsset->GetInspectedInstance()->GetMasterInstance(); + const UFlowAsset* AssetThatInstancedThisAsset = FlowAsset->GetInspectedInstance()->GetMasterInstance(); GEditor->GetEditorSubsystem()->OpenEditorForAsset(AssetThatInstancedThisAsset->GetTemplateAsset()); AssetThatInstancedThisAsset->GetTemplateAsset()->SetInspectedInstance(AssetThatInstancedThisAsset->GetDisplayName()); @@ -356,7 +303,7 @@ TSharedRef FFlowAssetEditor::CreateGraphWidget() InEvents.OnSelectionChanged = SGraphEditor::FOnSelectionChanged::CreateSP(this, &FFlowAssetEditor::OnSelectedNodesChanged); InEvents.OnNodeDoubleClicked = FSingleNodeEvent::CreateSP(this, &FFlowAssetEditor::OnNodeDoubleClicked); InEvents.OnTextCommitted = FOnNodeTextCommitted::CreateSP(this, &FFlowAssetEditor::OnNodeTitleCommitted); - InEvents.OnSpawnNodeByShortcut = SGraphEditor::FOnSpawnNodeByShortcut::CreateSP(this, &FFlowAssetEditor::OnSpawnGraphNodeByShortcut, static_cast(FlowAsset->GetGraph())); + InEvents.OnSpawnNodeByShortcut = SGraphEditor::FOnSpawnNodeByShortcut::CreateStatic(&FFlowAssetEditor::OnSpawnGraphNodeByShortcut, static_cast(FlowAsset->GetGraph())); return SNew(SGraphEditor) .AdditionalCommands(ToolkitCommands) @@ -373,7 +320,7 @@ FGraphAppearanceInfo FFlowAssetEditor::GetGraphAppearanceInfo() const FGraphAppearanceInfo AppearanceInfo; AppearanceInfo.CornerText = GetCornerText(); - if (Debugger.IsValid() && FFlowDebugger::IsPlaySessionPaused()) + if (FlowDebugger.IsValid() && FFlowDebugger::IsPlaySessionPaused()) { AppearanceInfo.PIENotifyText = LOCTEXT("PausedLabel", "PAUSED"); } @@ -388,6 +335,10 @@ FText FFlowAssetEditor::GetCornerText() const void FFlowAssetEditor::BindGraphCommands() { + FGraphEditorCommands::Register(); + FFlowGraphCommands::Register(); + FFlowSpawnNodeCommands::Register(); + const FGenericCommands& GenericCommands = FGenericCommands::Get(); const FGraphEditorCommandsImpl& GraphCommands = FGraphEditorCommands::Get(); const FFlowGraphCommands& FlowGraphCommands = FFlowGraphCommands::Get(); @@ -402,11 +353,11 @@ void FFlowAssetEditor::BindGraphCommands() // Generic Node commands ToolkitCommands->MapAction(GenericCommands.Undo, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::UndoGraphAction), + FExecuteAction::CreateStatic(&FFlowAssetEditor::UndoGraphAction), FCanExecuteAction::CreateStatic(&FFlowAssetEditor::CanEdit)); ToolkitCommands->MapAction(GenericCommands.Redo, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::RedoGraphAction), + FExecuteAction::CreateStatic(&FFlowAssetEditor::RedoGraphAction), FCanExecuteAction::CreateStatic(&FFlowAssetEditor::CanEdit)); ToolkitCommands->MapAction(GenericCommands.SelectAll, @@ -548,7 +499,7 @@ FReply FFlowAssetEditor::OnSpawnGraphNodeByShortcut(FInputChord InChord, const F if (FFlowSpawnNodeCommands::IsRegistered()) { - TSharedPtr Action = FFlowSpawnNodeCommands::Get().GetActionByChord(InChord); + const TSharedPtr Action = FFlowSpawnNodeCommands::Get().GetActionByChord(InChord); if (Action.IsValid()) { TArray DummyPins; @@ -646,7 +597,7 @@ void FFlowAssetEditor::OnSelectedNodesChanged(const TSet& Nodes) for (TSet::TConstIterator SetIt(Nodes); SetIt; ++SetIt) { - if (UFlowGraphNode* GraphNode = Cast(*SetIt)) + if (const UFlowGraphNode* GraphNode = Cast(*SetIt)) { SelectedObjects.Add(Cast(GraphNode->GetFlowNode())); } @@ -697,7 +648,7 @@ void FFlowAssetEditor::DeleteSelectedNodes() if (Node->CanUserDeleteNode()) { - if (UFlowGraphNode* FlowGraphNode = Cast(Node)) + if (const UFlowGraphNode* FlowGraphNode = Cast(Node)) { if (FlowGraphNode->GetFlowNode()) { @@ -713,7 +664,7 @@ void FFlowAssetEditor::DeleteSelectedNodes() } } -void FFlowAssetEditor::DeleteSelectedDuplicatableNodes() +void FFlowAssetEditor::DeleteSelectedDuplicableNodes() { // Cache off the old selection const FGraphPanelSelectionSet OldSelectedNodes = FocusedGraphEditor->GetSelectedNodes(); @@ -737,7 +688,7 @@ void FFlowAssetEditor::DeleteSelectedDuplicatableNodes() } } - // Delete the duplicatable nodes + // Delete the duplicable nodes DeleteSelectedNodes(); for (FGraphPanelSelectionSet::TConstIterator SelectedIt(RemainingNodes); SelectedIt; ++SelectedIt) @@ -776,7 +727,7 @@ void FFlowAssetEditor::CutSelectedNodes() CopySelectedNodes(); // Cut should only delete nodes that can be duplicated - DeleteSelectedDuplicatableNodes(); + DeleteSelectedDuplicableNodes(); } bool FFlowAssetEditor::CanCutNodes() const @@ -857,7 +808,7 @@ void FFlowAssetEditor::PasteNodesHere(const FVector2D& Location) for (TSet::TIterator It(PastedNodes); It; ++It) { - UEdGraphNode* Node = *It; + const UEdGraphNode* Node = *It; AvgNodePosition.X += Node->NodePosX; AvgNodePosition.Y += Node->NodePosY; } @@ -876,7 +827,7 @@ void FFlowAssetEditor::PasteNodesHere(const FVector2D& Location) // Give new node a different Guid from the old one Node->CreateNewGuid(); - if (UFlowGraphNode* FlowGraphNode = Cast(Node)) + if (const UFlowGraphNode* FlowGraphNode = Cast(Node)) { FlowAsset->RegisterNode(Node->NodeGuid, FlowGraphNode->GetFlowNode()); } @@ -976,7 +927,7 @@ bool FFlowAssetEditor::CanRefreshContextPins() const { if (CanEdit() && GetSelectedFlowNodes().Num() == 1) { - for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) { return SelectedNode->SupportsContextPins(); } @@ -997,7 +948,7 @@ bool FFlowAssetEditor::CanAddInput() const { if (CanEdit() && GetSelectedFlowNodes().Num() == 1) { - for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) { return SelectedNode->CanUserAddInput(); } @@ -1018,7 +969,7 @@ bool FFlowAssetEditor::CanAddOutput() const { if (CanEdit() && GetSelectedFlowNodes().Num() == 1) { - for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) { return SelectedNode->CanUserAddOutput(); } @@ -1042,9 +993,9 @@ bool FFlowAssetEditor::CanRemovePin() const { if (CanEdit() && GetSelectedFlowNodes().Num() == 1) { - if (UEdGraphPin* Pin = FocusedGraphEditor->GetGraphPinForMenu()) + if (const UEdGraphPin* Pin = FocusedGraphEditor->GetGraphPinForMenu()) { - if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) + if (const UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) { if (Pin->Direction == EGPD_Input) { @@ -1083,7 +1034,7 @@ void FFlowAssetEditor::OnAddPinBreakpoint() const bool FFlowAssetEditor::CanAddBreakpoint() const { - for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) { return !SelectedNode->NodeBreakpoint.HasBreakpoint(); } @@ -1125,7 +1076,7 @@ void FFlowAssetEditor::OnRemovePinBreakpoint() const bool FFlowAssetEditor::CanRemoveBreakpoint() const { - for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) { return SelectedNode->NodeBreakpoint.HasBreakpoint(); } @@ -1137,7 +1088,7 @@ bool FFlowAssetEditor::CanRemovePinBreakpoint() const { if (UEdGraphPin* Pin = FocusedGraphEditor->GetGraphPinForMenu()) { - if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) + if (const UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) { return GraphNode->PinBreakpoints.Contains(Pin); } @@ -1169,13 +1120,13 @@ bool FFlowAssetEditor::CanEnableBreakpoint() const { if (UEdGraphPin* Pin = FocusedGraphEditor->GetGraphPinForMenu()) { - if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) + if (const UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) { return GraphNode->PinBreakpoints.Contains(Pin); } } - for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) { return SelectedNode->NodeBreakpoint.CanEnableBreakpoint(); } @@ -1217,7 +1168,7 @@ void FFlowAssetEditor::OnDisablePinBreakpoint() const bool FFlowAssetEditor::CanDisableBreakpoint() const { - for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) { return SelectedNode->NodeBreakpoint.IsBreakpointEnabled(); } @@ -1273,7 +1224,7 @@ void FFlowAssetEditor::FocusViewport() const // Iterator used but should only contain one node for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) { - UFlowNode* FlowNode = Cast(SelectedNode)->GetFlowNode(); + const UFlowNode* FlowNode = Cast(SelectedNode)->GetFlowNode(); if (UFlowNode* NodeInstance = FlowNode->GetInspectedInstance()) { if (AActor* ActorToFocus = NodeInstance->GetActorToFocus()) @@ -1284,8 +1235,8 @@ void FFlowAssetEditor::FocusViewport() const GEditor->MoveViewportCamerasToActor(*ActorToFocus, false); - FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked("LevelEditor"); - TSharedPtr LevelEditorTab = LevelEditorModule.GetLevelEditorInstanceTab().Pin(); + const FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked("LevelEditor"); + const TSharedPtr LevelEditorTab = LevelEditorModule.GetLevelEditorInstanceTab().Pin(); if (LevelEditorTab.IsValid()) { LevelEditorTab->DrawAttention(); @@ -1305,7 +1256,7 @@ bool FFlowAssetEditor::CanFocusViewport() const void FFlowAssetEditor::JumpToNodeDefinition() const { // Iterator used but should only contain one node - for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) { SelectedNode->JumpToDefinition(); return; diff --git a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp index 8fd02b2e5..505a71434 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp @@ -2,22 +2,187 @@ #include "Asset/FlowAssetEditor.h" #include "FlowEditorCommands.h" -#include "Framework/MultiBox/MultiBoxBuilder.h" +#include "FlowAsset.h" -#define LOCTEXT_NAMESPACE "FlowAssetToolbar" +#include "EditorStyleSet.h" +#include "Kismet2/DebuggerCommands.h" +#include "Misc/Attribute.h" +#include "Subsystems/AssetEditorSubsystem.h" +#include "ToolMenu.h" +#include "ToolMenuSection.h" +#include "Widgets/Input/SComboBox.h" +#include "Widgets/SBoxPanel.h" +#include "Widgets/Text/STextBlock.h" -FFlowAssetToolbar::FFlowAssetToolbar(TSharedPtr InNodeEditor) - : FlowAssetEditor(InNodeEditor) +#define LOCTEXT_NAMESPACE "FlowDebuggerToolbar" + +////////////////////////////////////////////////////////////////////////// +// Flow Asset Instance List + +FText SFlowAssetInstanceList::NoInstanceSelectedText = LOCTEXT("NoInstanceSelected", "No instance selected"); + +void SFlowAssetInstanceList::Construct(const FArguments& InArgs, TWeakPtr InFlowAssetEditor) +{ + FlowAssetEditor = InFlowAssetEditor; + + // collect instance names of this Flow Asset + InstanceNames = {MakeShareable(new FName(*NoInstanceSelectedText.ToString()))}; + FlowAssetEditor.Pin()->GetFlowAsset()->GetInstanceDisplayNames(InstanceNames); + + // select instance + if (const UFlowAsset* InspectedInstance = FlowAssetEditor.Pin()->GetFlowAsset()->GetInspectedInstance()) + { + const FName& InspectedInstanceName = InspectedInstance->GetDisplayName(); + for (const TSharedPtr& Instance : InstanceNames) + { + if (*Instance == InspectedInstanceName) + { + SelectedInstance = Instance; + break; + } + } + } + else + { + // default object is always available + SelectedInstance = InstanceNames[0]; + } + + // create dropdown + SAssignNew(Dropdown, SComboBox>) + .OptionsSource(&InstanceNames) + .OnGenerateWidget(this, &SFlowAssetInstanceList::OnGenerateWidget) + .OnSelectionChanged(this, &SFlowAssetInstanceList::OnSelectionChanged) + .Visibility_Static(&FFlowAssetEditor::GetDebuggerVisibility) + [ + SNew(STextBlock) + .Text(this, &SFlowAssetInstanceList::GetSelectedInstanceName) + ]; + + ChildSlot + [ + Dropdown.ToSharedRef() + ]; +} + +TSharedRef SFlowAssetInstanceList::OnGenerateWidget(const TSharedPtr Item) const +{ + return SNew(STextBlock).Text(FText::FromName(*Item.Get())); +} + +void SFlowAssetInstanceList::OnSelectionChanged(const TSharedPtr SelectedItem, const ESelectInfo::Type SelectionType) +{ + SelectedInstance = SelectedItem; + + if (FlowAssetEditor.IsValid() && FlowAssetEditor.Pin()->GetFlowAsset()) + { + const FName NewSelectedInstanceName = (SelectedInstance.IsValid() && *SelectedInstance != *InstanceNames[0]) ? *SelectedInstance : NAME_None; + FlowAssetEditor.Pin()->GetFlowAsset()->SetInspectedInstance(NewSelectedInstanceName); + } +} + +FText SFlowAssetInstanceList::GetSelectedInstanceName() const +{ + return SelectedInstance.IsValid() ? FText::FromName(*SelectedInstance) : NoInstanceSelectedText; +} + +////////////////////////////////////////////////////////////////////////// +// Flow Asset Breadcrumb + +void SFlowAssetBreadcrumb::Construct(const FArguments& InArgs, TWeakPtr InFlowAssetEditor) { + FlowAssetEditor = InFlowAssetEditor; + + // create breadcrumb + SAssignNew(BreadcrumbTrail, SBreadcrumbTrail) + .OnCrumbClicked(this, &SFlowAssetBreadcrumb::OnCrumbClicked) + .Visibility_Static(&FFlowAssetEditor::GetDebuggerVisibility) + .ButtonStyle(FEditorStyle::Get(), "FlatButton") + .DelimiterImage(FEditorStyle::GetBrush("Sequencer.BreadcrumbIcon")) + .PersistentBreadcrumbs(true) + .TextStyle(FEditorStyle::Get(), "Sequencer.BreadcrumbText"); + + ChildSlot + [ + SNew(SVerticalBox) + + SVerticalBox::Slot() + .HAlign(HAlign_Right) + .VAlign(VAlign_Center) + .AutoHeight() + .Padding(25.0f, 10.0f) + [ + BreadcrumbTrail.ToSharedRef() + ] + ]; + + // fill breadcrumb + BreadcrumbTrail->ClearCrumbs(); + if (UFlowAsset* InspectedInstance = FlowAssetEditor.Pin()->GetFlowAsset()->GetInspectedInstance()) + { + TArray InstancesFromRoot = {InspectedInstance}; + + const UFlowAsset* CheckedInstance = InspectedInstance; + while (UFlowAsset* MasterInstance = CheckedInstance->GetMasterInstance()) + { + InstancesFromRoot.Insert(MasterInstance, 0); + CheckedInstance = MasterInstance; + } + + for (UFlowAsset* Instance : InstancesFromRoot) + { + TAttribute CrumbNameAttribute = MakeAttributeSP(this, &SFlowAssetBreadcrumb::GetBreadcrumbText, Instance); + BreadcrumbTrail->PushCrumb(CrumbNameAttribute, FFlowBreadcrumb(Instance)); + } + } } -void FFlowAssetToolbar::AddToolbar(FToolBarBuilder& ToolbarBuilder) +void SFlowAssetBreadcrumb::OnCrumbClicked(const FFlowBreadcrumb& Item) const { - ToolbarBuilder.BeginSection("FlowAsset"); + ensure(FlowAssetEditor.Pin()->GetFlowAsset()->GetInspectedInstance()); + + if (Item.InstanceName != FlowAssetEditor.Pin()->GetFlowAsset()->GetInspectedInstance()->GetDisplayName()) { - ToolbarBuilder.AddToolBarButton(FFlowToolbarCommands::Get().RefreshAsset); + GEditor->GetEditorSubsystem()->OpenEditorForAsset(Item.AssetPathName); } - ToolbarBuilder.EndSection(); +} + +FText SFlowAssetBreadcrumb::GetBreadcrumbText(const TWeakObjectPtr FlowInstance) const +{ + return FlowInstance.IsValid() ? FText::FromName(FlowInstance->GetDisplayName()) : FText(); +} + +////////////////////////////////////////////////////////////////////////// +// Flow Asset Toolbar + +FFlowAssetToolbar::FFlowAssetToolbar(const TSharedPtr InAssetEditor, UToolMenu* ToolbarMenu) + : FlowAssetEditor(InAssetEditor) +{ + BuildAssetToolbar(ToolbarMenu); + BuildDebuggerToolbar(ToolbarMenu); +} + +void FFlowAssetToolbar::BuildAssetToolbar(UToolMenu* ToolbarMenu) const +{ + FToolMenuSection& Section = ToolbarMenu->AddSection("Editing"); + Section.InsertPosition = FToolMenuInsert("Asset", EToolMenuInsertType::After); + + Section.AddEntry(FToolMenuEntry::InitToolBarButton(FFlowToolbarCommands::Get().RefreshAsset)); +} + +void FFlowAssetToolbar::BuildDebuggerToolbar(UToolMenu* ToolbarMenu) +{ + FToolMenuSection& Section = ToolbarMenu->AddSection("Debugging"); + Section.InsertPosition = FToolMenuInsert("Asset", EToolMenuInsertType::After); + + FPlayWorldCommands::BuildToolbar(Section); + + AssetInstanceList = SNew(SFlowAssetInstanceList, FlowAssetEditor); + Section.AddEntry(FToolMenuEntry::InitWidget("AssetInstances", AssetInstanceList.ToSharedRef(), FText(), true)); + + Section.AddEntry(FToolMenuEntry::InitToolBarButton(FFlowToolbarCommands::Get().GoToMasterInstance)); + + Breadcrumb = SNew(SFlowAssetBreadcrumb, FlowAssetEditor); + Section.AddEntry(FToolMenuEntry::InitWidget("AssetBreadcrumb", Breadcrumb.ToSharedRef(), FText(), true)); } #undef LOCTEXT_NAMESPACE diff --git a/Source/FlowEditor/Private/Asset/FlowDebugger.cpp b/Source/FlowEditor/Private/Asset/FlowDebugger.cpp index 7b918af01..796cad8a2 100644 --- a/Source/FlowEditor/Private/Asset/FlowDebugger.cpp +++ b/Source/FlowEditor/Private/Asset/FlowDebugger.cpp @@ -28,7 +28,7 @@ void ForEachGameWorld(const TFunction& Func) bool AreAllGameWorldPaused() { bool bPaused = true; - ForEachGameWorld([&](UWorld* World) + ForEachGameWorld([&](const UWorld* World) { bPaused = bPaused && World->bDebugPauseExecution; }); diff --git a/Source/FlowEditor/Private/Asset/FlowDebuggerToolbar.cpp b/Source/FlowEditor/Private/Asset/FlowDebuggerToolbar.cpp deleted file mode 100644 index ef0c9c6ae..000000000 --- a/Source/FlowEditor/Private/Asset/FlowDebuggerToolbar.cpp +++ /dev/null @@ -1,175 +0,0 @@ -#include "Asset/FlowDebuggerToolbar.h" -#include "Asset/FlowAssetEditor.h" -#include "FlowEditorCommands.h" - -#include "FlowAsset.h" - -#include "EditorStyleSet.h" -#include "Framework/MultiBox/MultiBoxBuilder.h" -#include "Misc/Attribute.h" -#include "Subsystems/AssetEditorSubsystem.h" -#include "Widgets/Input/SComboBox.h" -#include "Widgets/SBoxPanel.h" -#include "Widgets/Text/STextBlock.h" - -#define LOCTEXT_NAMESPACE "FlowDebuggerToolbar" - -////////////////////////////////////////////////////////////////////////// -// Flow Instance List - -FText SFlowInstanceList::NoInstanceSelectedText = LOCTEXT("NoInstanceSelected", "No instance selected"); - -void SFlowInstanceList::Construct(const FArguments& InArgs, TWeakPtr InFlowAssetEditor) -{ - FlowAssetEditor = InFlowAssetEditor; - - // collect instance names of this Flow Asset - InstanceNames = {MakeShareable(new FName(*NoInstanceSelectedText.ToString()))}; - FlowAssetEditor.Pin()->GetFlowAsset()->GetInstanceDisplayNames(InstanceNames); - - // select instance - if (const UFlowAsset* InspectedInstance = FlowAssetEditor.Pin()->GetFlowAsset()->GetInspectedInstance()) - { - const FName& InspectedInstanceName = InspectedInstance->GetDisplayName(); - for (const TSharedPtr& Instance : InstanceNames) - { - if (*Instance == InspectedInstanceName) - { - SelectedInstance = Instance; - break; - } - } - } - else - { - // default object is always available - SelectedInstance = InstanceNames[0]; - } - - // create dropdown - SAssignNew(Dropdown, SComboBox>) - .OptionsSource(&InstanceNames) - .OnGenerateWidget(this, &SFlowInstanceList::OnGenerateWidget) - .OnSelectionChanged(this, &SFlowInstanceList::OnSelectionChanged) - .Visibility_Static(&FFlowAssetEditor::GetDebuggerVisibility) - [ - SNew(STextBlock) - .Text(this, &SFlowInstanceList::GetSelectedInstanceName) - ]; - - ChildSlot - [ - Dropdown.ToSharedRef() - ]; -} - -TSharedRef SFlowInstanceList::OnGenerateWidget(const TSharedPtr Item) const -{ - return SNew(STextBlock).Text(FText::FromName(*Item.Get())); -} - -void SFlowInstanceList::OnSelectionChanged(const TSharedPtr SelectedItem, const ESelectInfo::Type SelectionType) -{ - SelectedInstance = SelectedItem; - - if (FlowAssetEditor.IsValid() && FlowAssetEditor.Pin()->GetFlowAsset()) - { - const FName NewSelectedInstanceName = (SelectedInstance.IsValid() && *SelectedInstance != *InstanceNames[0]) ? *SelectedInstance : NAME_None; - FlowAssetEditor.Pin()->GetFlowAsset()->SetInspectedInstance(NewSelectedInstanceName); - } -} - -FText SFlowInstanceList::GetSelectedInstanceName() const -{ - return SelectedInstance.IsValid() ? FText::FromName(*SelectedInstance) : NoInstanceSelectedText; -} - -////////////////////////////////////////////////////////////////////////// -// Flow Breadcrumb - -void SFlowBreadcrumb::Construct(const FArguments& InArgs, TWeakPtr InFlowAssetEditor) -{ - FlowAssetEditor = InFlowAssetEditor; - - // create breadcrumb - SAssignNew(BreadcrumbTrail, SBreadcrumbTrail) - .OnCrumbClicked(this, &SFlowBreadcrumb::OnCrumbClicked) - .Visibility_Static(&FFlowAssetEditor::GetDebuggerVisibility) - .ButtonStyle(FEditorStyle::Get(), "FlatButton") - .DelimiterImage(FEditorStyle::GetBrush("Sequencer.BreadcrumbIcon")) - .PersistentBreadcrumbs(true) - .TextStyle(FEditorStyle::Get(), "Sequencer.BreadcrumbText"); - - ChildSlot - [ - SNew(SVerticalBox) - + SVerticalBox::Slot() - .HAlign(HAlign_Right) - .VAlign(VAlign_Center) - .AutoHeight() - .Padding(25.0f, 10.0f) - [ - BreadcrumbTrail.ToSharedRef() - ] - ]; - - // fill breadcrumb - BreadcrumbTrail->ClearCrumbs(); - if (UFlowAsset* InspectedInstance = FlowAssetEditor.Pin()->GetFlowAsset()->GetInspectedInstance()) - { - TArray InstancesFromRoot = {InspectedInstance}; - - UFlowAsset* CheckedInstance = InspectedInstance; - while (UFlowAsset* MasterInstance = CheckedInstance->GetMasterInstance()) - { - InstancesFromRoot.Insert(MasterInstance, 0); - CheckedInstance = MasterInstance; - } - - for (UFlowAsset* Instance : InstancesFromRoot) - { - TAttribute CrumbNameAttribute = MakeAttributeSP(this, &SFlowBreadcrumb::GetBreadcrumbText, Instance); - BreadcrumbTrail->PushCrumb(CrumbNameAttribute, FFlowBreadcrumb(Instance)); - } - } -} - -void SFlowBreadcrumb::OnCrumbClicked(const FFlowBreadcrumb& Item) -{ - ensure(FlowAssetEditor.Pin()->GetFlowAsset()->GetInspectedInstance()); - - if (Item.InstanceName != FlowAssetEditor.Pin()->GetFlowAsset()->GetInspectedInstance()->GetDisplayName()) - { - GEditor->GetEditorSubsystem()->OpenEditorForAsset(Item.AssetPathName); - } -} - -FText SFlowBreadcrumb::GetBreadcrumbText(const TWeakObjectPtr FlowInstance) const -{ - return FlowInstance.IsValid() ? FText::FromName(FlowInstance->GetDisplayName()) : FText(); -} - -////////////////////////////////////////////////////////////////////////// -// Flow Debugger Toolbar - -FFlowDebuggerToolbar::FFlowDebuggerToolbar(TSharedPtr InNodeEditor) - : FlowAssetEditor(InNodeEditor) -{ -} - -void FFlowDebuggerToolbar::AddToolbar(FToolBarBuilder& ToolbarBuilder) -{ - ToolbarBuilder.BeginSection(""); - { - FlowInstanceList = SNew(SFlowInstanceList, FlowAssetEditor); - ToolbarBuilder.AddWidget(FlowInstanceList.ToSharedRef()); - - ToolbarBuilder.AddToolBarButton(FFlowToolbarCommands::Get().GoToMasterInstance); - - FlowBreadcrumb = SNew(SFlowBreadcrumb, FlowAssetEditor); - ToolbarBuilder.AddWidget(FlowBreadcrumb.ToSharedRef()); - } - ToolbarBuilder.EndSection(); -} - -#undef LOCTEXT_NAMESPACE diff --git a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h index 41d6bbdbd..df3657ea4 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h @@ -19,17 +19,13 @@ struct FSlateBrush; struct FPropertyChangedEvent; struct Rect; -class FFlowAssetEditor : public FAssetEditorToolkit, - public FEditorUndoClient, - public FGCObject, - public FNotifyHook +class FFlowAssetEditor : public FAssetEditorToolkit, public FEditorUndoClient, public FGCObject, public FNotifyHook { /** The FlowAsset asset being inspected */ UFlowAsset* FlowAsset; TSharedPtr AssetToolbar; - TSharedPtr Debugger; - TSharedPtr DebuggerToolbar; + TSharedPtr FlowDebugger; TSharedPtr FocusedGraphEditor; TSharedPtr DetailsView; @@ -47,7 +43,7 @@ class FFlowAssetEditor : public FAssetEditorToolkit, public: FFlowAssetEditor(); - virtual ~FFlowAssetEditor(); + virtual ~FFlowAssetEditor() override; UFlowAsset* GetFlowAsset() const { return FlowAsset; }; @@ -85,35 +81,27 @@ class FFlowAssetEditor : public FAssetEditorToolkit, /** Edits the specified FlowAsset object */ void InitFlowAssetEditor(const EToolkitMode::Type Mode, const TSharedPtr& InitToolkitHost, UObject* ObjectToEdit); -private: - void AddFlowAssetToolbar(); - void BindAssetCommands(); - - void AddPlayWorldToolbar() const; - - void CreateFlowDebugger(); - void BindDebuggerCommands(); - protected: - virtual void RefreshAsset(); + virtual void CreateToolbar(); + virtual void BindToolbarCommands(); + virtual void RefreshAsset(); virtual void GoToMasterInstance(); virtual bool CanGoToMasterInstance(); -private: - void CreateWidgets(); - TSharedRef CreateGraphWidget(); + virtual void CreateWidgets(); -protected: - FGraphAppearanceInfo GetGraphAppearanceInfo() const; + virtual TSharedRef CreateGraphWidget(); + virtual FGraphAppearanceInfo GetGraphAppearanceInfo() const; virtual FText GetCornerText() const; + virtual void BindGraphCommands(); + private: - void BindGraphCommands(); - void UndoGraphAction(); - void RedoGraphAction(); + static void UndoGraphAction(); + static void RedoGraphAction(); - FReply OnSpawnGraphNodeByShortcut(FInputChord InChord, const FVector2D& InPosition, UEdGraph* InGraph); + static FReply OnSpawnGraphNodeByShortcut(FInputChord InChord, const FVector2D& InPosition, UEdGraph* InGraph); public: /** Gets the UI selection state of this editor */ @@ -135,42 +123,43 @@ class FFlowAssetEditor : public FAssetEditorToolkit, int32 GetNumberOfSelectedNodes() const; bool GetBoundsForSelectedNodes(class FSlateRect& Rect, float Padding) const; -private: - void OnSelectedNodesChanged(const TSet& Nodes); +protected: + virtual void OnSelectedNodesChanged(const TSet& Nodes); public: - void SelectSingleNode(UEdGraphNode* Node) const; + virtual void SelectSingleNode(UEdGraphNode* Node) const; -private: - void SelectAllNodes() const; - bool CanSelectAllNodes() const; +protected: + virtual void SelectAllNodes() const; + virtual bool CanSelectAllNodes() const; - void DeleteSelectedNodes(); - void DeleteSelectedDuplicatableNodes(); - bool CanDeleteNodes() const; + virtual void DeleteSelectedNodes(); + virtual void DeleteSelectedDuplicableNodes(); + virtual bool CanDeleteNodes() const; - void CopySelectedNodes() const; - bool CanCopyNodes() const; + virtual void CopySelectedNodes() const; + virtual bool CanCopyNodes() const; - void CutSelectedNodes(); - bool CanCutNodes() const; + virtual void CutSelectedNodes(); + virtual bool CanCutNodes() const; - void PasteNodes(); + virtual void PasteNodes(); public: - void PasteNodesHere(const FVector2D& Location); - bool CanPasteNodes() const; + virtual void PasteNodesHere(const FVector2D& Location); + virtual bool CanPasteNodes() const; -private: - void DuplicateNodes(); - bool CanDuplicateNodes() const; +protected: + virtual void DuplicateNodes(); + virtual bool CanDuplicateNodes() const; - void OnNodeDoubleClicked(class UEdGraphNode* Node) const; - void OnNodeTitleCommitted(const FText& NewText, ETextCommit::Type CommitInfo, UEdGraphNode* NodeBeingChanged); + virtual void OnNodeDoubleClicked(class UEdGraphNode* Node) const; + virtual void OnNodeTitleCommitted(const FText& NewText, ETextCommit::Type CommitInfo, UEdGraphNode* NodeBeingChanged); - void RefreshContextPins() const; - bool CanRefreshContextPins() const; + virtual void RefreshContextPins() const; + virtual bool CanRefreshContextPins() const; +private: void AddInput() const; bool CanAddInput() const; diff --git a/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h b/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h index 2e611701a..63811a2b7 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h @@ -1,23 +1,93 @@ #pragma once -#include "CoreMinimal.h" +#include "Widgets/Input/SComboBox.h" +#include "Widgets/Navigation/SBreadcrumbTrail.h" -class FExtender; -class FToolBarBuilder; -class SWidget; +#include "FlowAsset.h" class FFlowAssetEditor; +////////////////////////////////////////////////////////////////////////// +// Flow Asset Instance List + +class SFlowAssetInstanceList final : public SCompoundWidget +{ +public: + SLATE_BEGIN_ARGS(SFlowAssetInstanceList) {} + SLATE_END_ARGS() + + void Construct(const FArguments& InArgs, TWeakPtr InFlowAssetEditor); + +private: + TSharedRef OnGenerateWidget(TSharedPtr Item) const; + void OnSelectionChanged(TSharedPtr SelectedItem, ESelectInfo::Type SelectionType); + FText GetSelectedInstanceName() const; + + TWeakPtr FlowAssetEditor; + TSharedPtr>> Dropdown; + + TArray> InstanceNames; + TSharedPtr SelectedInstance; + + static FText NoInstanceSelectedText; +}; + +////////////////////////////////////////////////////////////////////////// +// Flow Asset Breadcrumb + +/** + * The kind of breadcrumbs that Flow Debugger uses + */ +struct FFlowBreadcrumb +{ + FString AssetPathName; + FName InstanceName; + + FFlowBreadcrumb() + : AssetPathName(FString()) + , InstanceName(NAME_None) + {} + + FFlowBreadcrumb(const UFlowAsset* FlowAsset) + : AssetPathName(FlowAsset->GetTemplateAsset()->GetPathName()) + , InstanceName(FlowAsset->GetDisplayName()) + {} +}; + +class SFlowAssetBreadcrumb final : public SCompoundWidget +{ +public: + SLATE_BEGIN_ARGS(SFlowAssetInstanceList) {} + SLATE_END_ARGS() + + void Construct(const FArguments& InArgs, TWeakPtr InFlowAssetEditor); + +private: + void OnCrumbClicked(const FFlowBreadcrumb& Item) const; + FText GetBreadcrumbText(const TWeakObjectPtr FlowInstance) const; + + TWeakPtr FlowAssetEditor; + TSharedPtr> BreadcrumbTrail; +}; + ////////////////////////////////////////////////////////////////////////// // Flow Asset Toolbar class FFlowAssetToolbar final : public TSharedFromThis { public: - FFlowAssetToolbar(TSharedPtr InNodeEditor); + explicit FFlowAssetToolbar(const TSharedPtr InAssetEditor, UToolMenu* ToolbarMenu); + +private: + void BuildAssetToolbar(UToolMenu* ToolbarMenu) const; + void BuildDebuggerToolbar(UToolMenu* ToolbarMenu); - void AddToolbar(FToolBarBuilder& ToolbarBuilder); +public: + TSharedPtr GetAssetInstanceList() const { return AssetInstanceList; } private: TWeakPtr FlowAssetEditor; + + TSharedPtr AssetInstanceList; + TSharedPtr Breadcrumb; }; diff --git a/Source/FlowEditor/Public/Asset/FlowDebuggerToolbar.h b/Source/FlowEditor/Public/Asset/FlowDebuggerToolbar.h deleted file mode 100644 index 15037329c..000000000 --- a/Source/FlowEditor/Public/Asset/FlowDebuggerToolbar.h +++ /dev/null @@ -1,94 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" -#include "Widgets/Input/SComboBox.h" -#include "Widgets/Navigation/SBreadcrumbTrail.h" - -#include "FlowAsset.h" - -class FExtender; -class FToolBarBuilder; -class SWidget; - -class FFlowAssetEditor; - -////////////////////////////////////////////////////////////////////////// -// Flow Instance List - -class SFlowInstanceList final : public SCompoundWidget -{ -public: - SLATE_BEGIN_ARGS(SFlowInstanceList) {} - SLATE_END_ARGS() - - void Construct(const FArguments& InArgs, TWeakPtr InFlowAssetEditor); - -private: - TSharedRef OnGenerateWidget(TSharedPtr Item) const; - void OnSelectionChanged(TSharedPtr SelectedItem, ESelectInfo::Type SelectionType); - FText GetSelectedInstanceName() const; - - TWeakPtr FlowAssetEditor; - TSharedPtr>> Dropdown; - - TArray> InstanceNames; - TSharedPtr SelectedInstance; - - static FText NoInstanceSelectedText; -}; - -////////////////////////////////////////////////////////////////////////// -// Flow Breadcrumb - -/** - * The kind of breadcrumbs that Flow Debugger uses - */ -struct FFlowBreadcrumb -{ - FString AssetPathName; - FName InstanceName; - - FFlowBreadcrumb() - : AssetPathName(FString()) - , InstanceName(NAME_None) - {} - - FFlowBreadcrumb(const UFlowAsset* FlowAsset) - : AssetPathName(FlowAsset->GetTemplateAsset()->GetPathName()) - , InstanceName(FlowAsset->GetDisplayName()) - {} -}; - -class SFlowBreadcrumb final : public SCompoundWidget -{ -public: - SLATE_BEGIN_ARGS(SFlowInstanceList) {} - SLATE_END_ARGS() - - void Construct(const FArguments& InArgs, TWeakPtr InFlowAssetEditor); - -private: - void OnCrumbClicked(const FFlowBreadcrumb& Item); - FText GetBreadcrumbText(const TWeakObjectPtr FlowInstance) const; - - TWeakPtr FlowAssetEditor; - TSharedPtr> BreadcrumbTrail; -}; - -////////////////////////////////////////////////////////////////////////// -// Flow Debugger Toolbar - -class FFlowDebuggerToolbar final : public TSharedFromThis -{ -public: - FFlowDebuggerToolbar(TSharedPtr InNodeEditor); - - void AddToolbar(FToolBarBuilder& ToolbarBuilder); - TSharedPtr GetFlowInstanceList() const { return FlowInstanceList; } - -private: - TWeakPtr FlowAssetEditor; - - TSharedPtr FlowInstanceList; - TSharedPtr FlowBreadcrumb; -}; From 3b88e66ebc7bd440057c3eccdda195160f6480c0 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 28 Sep 2021 20:59:50 +0200 Subject: [PATCH 026/338] removed redundant Extensibility Managers --- .../FlowEditor/Private/FlowEditorModule.cpp | 16 ------------ Source/FlowEditor/Public/FlowEditorModule.h | 25 +------------------ 2 files changed, 1 insertion(+), 40 deletions(-) diff --git a/Source/FlowEditor/Private/FlowEditorModule.cpp b/Source/FlowEditor/Private/FlowEditorModule.cpp index 1251342fa..939f33f52 100644 --- a/Source/FlowEditor/Private/FlowEditorModule.cpp +++ b/Source/FlowEditor/Private/FlowEditorModule.cpp @@ -42,9 +42,6 @@ void FFlowEditorModule::StartupModule() // register visual utilities FEdGraphUtilities::RegisterVisualPinConnectionFactory(MakeShareable(new FFlowGraphConnectionDrawingPolicyFactory)); - // init menu extensibility - FlowAssetExtensibility.Init(); - // add Flow Toolbar if (UFlowGraphSettings::Get()->bShowAssetToolbarAboveLevelEditor) { @@ -86,9 +83,6 @@ void FFlowEditorModule::ShutdownModule() FEdGraphUtilities::UnregisterVisualPinConnectionFactory(FlowGraphConnectionFactory); } - // reset menu extensibility - FlowAssetExtensibility.Reset(); - // unregister track editors ISequencerModule& SequencerModule = FModuleManager::Get().LoadModuleChecked("Sequencer"); SequencerModule.UnRegisterTrackEditor(FlowTrackCreateEditorHandle); @@ -155,16 +149,6 @@ void FFlowEditorModule::RegisterCustomClassLayout(const TSubclassOf Cla } } -TSharedPtr FFlowEditorModule::GetFlowAssetMenuExtensibilityManager() const -{ - return FlowAssetExtensibility.MenuExtensibilityManager; -} - -TSharedPtr FFlowEditorModule::GetFlowAssetToolBarExtensibilityManager() const -{ - return FlowAssetExtensibility.ToolBarExtensibilityManager; -} - void FFlowEditorModule::CreateFlowToolbar(FToolBarBuilder& ToolbarBuilder) const { ToolbarBuilder.BeginSection("Flow"); diff --git a/Source/FlowEditor/Public/FlowEditorModule.h b/Source/FlowEditor/Public/FlowEditorModule.h index fe91883ef..93f679cf3 100644 --- a/Source/FlowEditor/Public/FlowEditorModule.h +++ b/Source/FlowEditor/Public/FlowEditorModule.h @@ -3,7 +3,6 @@ #include "AssetTypeCategories.h" #include "IAssetTypeActions.h" #include "Modules/ModuleInterface.h" -#include "Toolkits/AssetEditorToolkit.h" class FSlateStyleSet; struct FGraphPanelPinConnectionFactory; @@ -11,24 +10,6 @@ struct FGraphPanelPinConnectionFactory; class FFlowAssetEditor; class UFlowAsset; -struct FExtensibilityManagers -{ - TSharedPtr MenuExtensibilityManager; - TSharedPtr ToolBarExtensibilityManager; - - void Init() - { - MenuExtensibilityManager = MakeShareable(new FExtensibilityManager); - ToolBarExtensibilityManager = MakeShareable(new FExtensibilityManager); - } - - void Reset() - { - MenuExtensibilityManager.Reset(); - ToolBarExtensibilityManager.Reset(); - } -}; - DECLARE_LOG_CATEGORY_EXTERN(LogFlowEditor, Log, All) class FLOWEDITOR_API FFlowEditorModule : public IModuleInterface @@ -40,7 +21,6 @@ class FLOWEDITOR_API FFlowEditorModule : public IModuleInterface TArray> RegisteredAssetActions; TSet CustomClassLayouts; TSharedPtr FlowGraphConnectionFactory; - FExtensibilityManagers FlowAssetExtensibility; public: virtual void StartupModule() override; @@ -54,14 +34,11 @@ class FLOWEDITOR_API FFlowEditorModule : public IModuleInterface void RegisterCustomClassLayout(const TSubclassOf Class, const FOnGetDetailCustomizationInstance DetailLayout); public: - TSharedPtr GetFlowAssetMenuExtensibilityManager() const; - TSharedPtr GetFlowAssetToolBarExtensibilityManager() const; - FDelegateHandle FlowTrackCreateEditorHandle; private: void CreateFlowToolbar(FToolBarBuilder& ToolbarBuilder) const; public: - TSharedRef CreateFlowAssetEditor(const EToolkitMode::Type Mode, const TSharedPtr& InitToolkitHost, UFlowAsset* FlowAsset); + static TSharedRef CreateFlowAssetEditor(const EToolkitMode::Type Mode, const TSharedPtr& InitToolkitHost, UFlowAsset* FlowAsset); }; From c634c33560c58e4e74789d5d54bbd1700d7ff69d Mon Sep 17 00:00:00 2001 From: "Satheesh (ryanjon2040)" Date: Wed, 29 Sep 2021 01:28:59 +0530 Subject: [PATCH 027/338] Add circuit connection drawing. (#54) --- .../FlowGraphConnectionDrawingPolicy.cpp | 58 +++++++++++++++++++ .../Private/Graph/FlowGraphSettings.cpp | 3 + .../Graph/FlowGraphConnectionDrawingPolicy.h | 13 +++++ .../Public/Graph/FlowGraphSettings.h | 10 ++++ 4 files changed, 84 insertions(+) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp b/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp index 348596dac..8b4e42b86 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp @@ -100,6 +100,18 @@ void FFlowGraphConnectionDrawingPolicy::BuildPaths() } } +void FFlowGraphConnectionDrawingPolicy::DrawConnection(int32 LayerId, const FVector2D& Start, const FVector2D& End, + const FConnectionParams& Params) +{ + if (UFlowGraphSettings::Get()->ConnectionDrawType == EFlowConnectionDrawType::Default) + { + FConnectionDrawingPolicy::DrawConnection(LayerId, Start, End, Params); + return; + } + + Internal_DrawCircuitSpline(LayerId, Start, End, Params); +} + void FFlowGraphConnectionDrawingPolicy::Draw(TMap, FArrangedWidget>& InPinGeometries, FArrangedChildren& ArrangedNodes) { BuildPaths(); @@ -162,3 +174,49 @@ void FFlowGraphConnectionDrawingPolicy::DetermineWiringStyle(UEdGraphPin* Output } } } + +void FFlowGraphConnectionDrawingPolicy::Internal_DrawCircuitSpline(const int32& LayerId, const FVector2D& Start, const FVector2D& End, const FConnectionParams& Params) const +{ + const FVector2D StartingPoint = FVector2D(Start.X + UFlowGraphSettings::Get()->ConnectionSpacing.X, Start.Y); + const FVector2D EndPoint = FVector2D(End.X - UFlowGraphSettings::Get()->ConnectionSpacing.Y, End.Y); + const FVector2D ControlPoint = Internal_GetControlPoint(StartingPoint, EndPoint); + + const FVector2D StartDirection = (Params.StartDirection == EGPD_Output) ? FVector2D(1.0f, 0.0f) : FVector2D(-1.0f, 0.0f); + const FVector2D EndDirection = (Params.EndDirection == EGPD_Input) ? FVector2D(1.0f, 0.0f) : FVector2D(-1.0f, 0.0f); + + FSlateDrawElement::MakeDrawSpaceSpline(DrawElementsList, LayerId, Start, StartDirection, StartingPoint, EndDirection, Params.WireThickness, ESlateDrawEffect::None, Params.WireColor); + FSlateDrawElement::MakeDrawSpaceSpline(DrawElementsList, LayerId, StartingPoint, StartDirection, ControlPoint, EndDirection, Params.WireThickness, ESlateDrawEffect::None, Params.WireColor); + FSlateDrawElement::MakeDrawSpaceSpline(DrawElementsList, LayerId, ControlPoint, StartDirection, EndPoint, EndDirection, Params.WireThickness, ESlateDrawEffect::None, Params.WireColor); + FSlateDrawElement::MakeDrawSpaceSpline(DrawElementsList, LayerId, EndPoint, StartDirection, End, EndDirection, Params.WireThickness, ESlateDrawEffect::None, Params.WireColor); +} + +FVector2D FFlowGraphConnectionDrawingPolicy::Internal_GetControlPoint(const FVector2D& Source, const FVector2D& Target) const +{ + const FVector2D Delta = Target - Source; + const float Tangent = FMath::Tan(UFlowGraphSettings::Get()->ConnectionAngle * (PI / 180.f)); + + const float DX = FMath::Abs(Delta.X); + const float DY = FMath::Abs(Delta.Y); + + const float SlopeWidth = DY / Tangent; + if (DX > SlopeWidth) + { + return Delta.X > 0.f ? FVector2D(Target.X - SlopeWidth, Source.Y) : FVector2D(Source.X - SlopeWidth, Target.Y); + } + + const float SlopeHeight = DX * Tangent; + if (DY > SlopeHeight) + { + if (Delta.Y > 0.f) + { + return Delta.X < 0.f ? FVector2D(Source.X, Target.Y - SlopeHeight) : FVector2D(Target.X, Source.Y + SlopeHeight); + } + + if (Delta.X < 0.f) + { + return FVector2D(Source.X, Target.Y + SlopeHeight); + } + } + + return FVector2D(Target.X, Source.Y - SlopeHeight); +} diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp index b1bb137c8..acc4d3731 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp @@ -2,6 +2,9 @@ UFlowGraphSettings::UFlowGraphSettings(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) + , ConnectionDrawType(EFlowConnectionDrawType::Circuit) + , ConnectionAngle(45.f) + , ConnectionSpacing(FVector2D(30.f)) , bExposeFlowAssetCreation(true) , bExposeFlowNodeCreation(true) , bShowAssetToolbarAboveLevelEditor(true) diff --git a/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h b/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h index f8d2ad367..c84adb13b 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h @@ -3,6 +3,13 @@ #include "ConnectionDrawingPolicy.h" #include "EdGraphUtilities.h" +UENUM() +enum class EFlowConnectionDrawType : uint8 +{ + Default, + Circuit +}; + struct FFlowGraphConnectionDrawingPolicyFactory : public FGraphPanelPinConnectionFactory { virtual ~FFlowGraphConnectionDrawingPolicyFactory() @@ -42,7 +49,13 @@ class FFlowGraphConnectionDrawingPolicy : public FConnectionDrawingPolicy void BuildPaths(); // FConnectionDrawingPolicy interface + virtual void DrawConnection(int32 LayerId, const FVector2D& Start, const FVector2D& End, const FConnectionParams& Params) override; virtual void Draw(TMap, FArrangedWidget>& PinGeometries, FArrangedChildren& ArrangedNodes) override; virtual void DetermineWiringStyle(UEdGraphPin* OutputPin, UEdGraphPin* InputPin, FConnectionParams& Params) override; // End of FConnectionDrawingPolicy interface + +private: + + void Internal_DrawCircuitSpline(const int32& LayerId, const FVector2D& Start, const FVector2D& End, const FConnectionParams& Params) const; + FVector2D Internal_GetControlPoint(const FVector2D& Source, const FVector2D& Target) const; }; diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h index e33e7de87..f75e1d5da 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h @@ -1,5 +1,6 @@ #pragma once +#include "FlowGraphConnectionDrawingPolicy.h" #include "Engine/DeveloperSettings.h" #include "FlowTypes.h" @@ -14,6 +15,15 @@ class UFlowGraphSettings final : public UDeveloperSettings GENERATED_UCLASS_BODY() static UFlowGraphSettings* Get() { return CastChecked(UFlowGraphSettings::StaticClass()->GetDefaultObject()); } + UPROPERTY(config, EditAnywhere, Category = "Flow Graph") + EFlowConnectionDrawType ConnectionDrawType; + + UPROPERTY(config, EditAnywhere, Category = "Flow Graph", meta = (EditCondition = "ConnectionDrawType == EFlowConnectionDrawType::Circuit")) + float ConnectionAngle; + + UPROPERTY(config, EditAnywhere, Category = "Flow Graph", meta = (EditCondition = "ConnectionDrawType == EFlowConnectionDrawType::Circuit")) + FVector2D ConnectionSpacing; + /** Show Flow Asset in Flow category of "Create Asset" menu? * Requires restart after making a change. */ UPROPERTY(EditAnywhere, config, Category = "Default UI") From 00c33b5fe45d5e8d822443703af570fb6fb81d5d Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 28 Sep 2021 22:10:40 +0200 Subject: [PATCH 028/338] Update FlowNode_PlayLevelSequenceDetails.cpp --- .../Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.cpp b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.cpp index c95540ee3..9d4df4dad 100644 --- a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.cpp +++ b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.cpp @@ -8,4 +8,5 @@ void FFlowNode_PlayLevelSequenceDetails::CustomizeDetails(IDetailLayoutBuilder& { IDetailCategoryBuilder& SequenceCategory = DetailBuilder.EditCategory("Sequence"); SequenceCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UFlowNode_PlayLevelSequence, Sequence)); + SequenceCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UFlowNode_PlayLevelSequence, PlaybackSettings)); } From 06a614f8ca4ae4fafd4525dcbc63183f13ec0042 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 28 Sep 2021 22:18:35 +0200 Subject: [PATCH 029/338] use standard connection style by default --- Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp index acc4d3731..b7adbd573 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp @@ -2,7 +2,7 @@ UFlowGraphSettings::UFlowGraphSettings(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) - , ConnectionDrawType(EFlowConnectionDrawType::Circuit) + , ConnectionDrawType(EFlowConnectionDrawType::Default) , ConnectionAngle(45.f) , ConnectionSpacing(FVector2D(30.f)) , bExposeFlowAssetCreation(true) From 5ee34b85feaaa17c3ed78e11a3b144c4c6d00356 Mon Sep 17 00:00:00 2001 From: "Satheesh (ryanjon2040)" Date: Wed, 6 Oct 2021 02:00:47 +0530 Subject: [PATCH 030/338] Implement graph tooltip. (#55) * Implement graph tooltip. * Show path of graph in tooltip preview --- .../Private/Graph/FlowGraphSettings.cpp | 3 + .../Private/Graph/Widgets/SFlowGraphNode.cpp | 55 ++++++++++++++++--- .../Public/Graph/FlowGraphSettings.h | 9 +++ .../Public/Graph/Widgets/SFlowGraphNode.h | 1 + 4 files changed, 61 insertions(+), 7 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp index b7adbd573..b9523ff76 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp @@ -5,6 +5,9 @@ UFlowGraphSettings::UFlowGraphSettings(const FObjectInitializer& ObjectInitializ , ConnectionDrawType(EFlowConnectionDrawType::Default) , ConnectionAngle(45.f) , ConnectionSpacing(FVector2D(30.f)) + , bShowGraphPreview(true) + , bShowGraphPathInPreview(true) + , GraphPreviewSize(FVector2D(640.f, 360.f)) , bExposeFlowAssetCreation(true) , bExposeFlowNodeCreation(true) , bShowAssetToolbarAboveLevelEditor(true) diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp index 21ad855fe..b16f2a6d6 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp @@ -19,6 +19,9 @@ #include "SlateOptMacros.h" #include "Styling/SlateColor.h" #include "TutorialMetaData.h" +#include "FlowAsset.h" +#include "SGraphPreviewer.h" +#include "Nodes/Route/FlowNode_SubGraph.h" #include "Widgets/Images/SImage.h" #include "Widgets/Layout/SBorder.h" #include "Widgets/SBoxPanel.h" @@ -247,13 +250,6 @@ void SFlowGraphNode::UpdateGraphNode() DefaultTitleAreaWidget ]; - - if (!SWidget::GetToolTip().IsValid()) - { - const TSharedRef DefaultToolTip = IDocumentation::Get()->CreateToolTip(TAttribute(this, &SGraphNode::GetNodeTooltip), nullptr, GraphNode->GetDocumentationLink(), GraphNode->GetDocumentationExcerptName()); - SetToolTip(DefaultToolTip); - } - // Setup a meta tag for this node FGraphNodeMetaData TagMeta(TEXT("FlowGraphNode")); PopulateMetaTag(&TagMeta); @@ -470,4 +466,49 @@ FReply SFlowGraphNode::OnAddPin() return FReply::Handled(); } +TSharedPtr SFlowGraphNode::GetComplexTooltip() +{ + if (UFlowGraphSettings::Get()->bShowGraphPreview) + { + if (UFlowNode_SubGraph* MySubGraphNode = Cast(FlowGraphNode->GetFlowNode())) + { + const UFlowAsset* AssetToEdit = Cast(MySubGraphNode->GetAssetToEdit()); + if (AssetToEdit && AssetToEdit->GetGraph()) + { + TSharedPtr TitleBarWidget = SNullWidget::NullWidget; + if (UFlowGraphSettings::Get()->bShowGraphPathInPreview) + { + const FString AssetName = FString::Printf(TEXT(".%s"), *AssetToEdit->GetName()); + const FString AssetPath = AssetToEdit->GetPathName().Replace(*AssetName, TEXT("")); + TitleBarWidget = SNew(SBox) + .Padding(10.f) + [ + SNew(STextBlock) + .Text(FText::FromString(AssetPath)) + ]; + } + + return SNew(SToolTip) + [ + SNew(SBox) + .WidthOverride(UFlowGraphSettings::Get()->GraphPreviewSize.X) + .HeightOverride(UFlowGraphSettings::Get()->GraphPreviewSize.Y) + [ + SNew(SOverlay) + +SOverlay::Slot() + [ + SNew(SGraphPreviewer, AssetToEdit->GetGraph()) + .CornerOverlayText(LOCTEXT("FlowNodePreviewGraphOverlayText", "FLOW PREVIEW")) + .ShowGraphStateOverlay(false) + .TitleBar(TitleBarWidget) + ] + ] + ]; + } + } + } + + return IDocumentation::Get()->CreateToolTip(TAttribute(this, &SGraphNode::GetNodeTooltip), nullptr, GraphNode->GetDocumentationLink(), GraphNode->GetDocumentationExcerptName()); +} + #undef LOCTEXT_NAMESPACE diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h index f75e1d5da..9134c8459 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h @@ -24,6 +24,15 @@ class UFlowGraphSettings final : public UDeveloperSettings UPROPERTY(config, EditAnywhere, Category = "Flow Graph", meta = (EditCondition = "ConnectionDrawType == EFlowConnectionDrawType::Circuit")) FVector2D ConnectionSpacing; + UPROPERTY(config, EditAnywhere, Category = "Flow Graph") + bool bShowGraphPreview; + + UPROPERTY(config, EditAnywhere, Category = "Flow Graph", meta = (EditCondition = "bShowGraphPreview")) + bool bShowGraphPathInPreview; + + UPROPERTY(config, EditAnywhere, Category = "Flow Graph", meta = (EditCondition = "bShowGraphPreview")) + FVector2D GraphPreviewSize; + /** Show Flow Asset in Flow category of "Create Asset" menu? * Requires restart after making a change. */ UPROPERTY(EditAnywhere, config, Category = "Default UI") diff --git a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h index dd21aab64..b2814fa2d 100644 --- a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h +++ b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h @@ -42,6 +42,7 @@ class SFlowGraphNode : public SGraphNode virtual void CreateInputSideAddButton(TSharedPtr OutputBox) override; virtual void CreateOutputSideAddButton(TSharedPtr OutputBox) override; virtual FReply OnAddPin() override; + virtual TSharedPtr GetComplexTooltip() override; // -- private: From 9e6b57d266f4a61bb716b01ea601d4e588fd2e42 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 10 Oct 2021 00:49:43 +0200 Subject: [PATCH 031/338] #56 crash fix + optimizations --- .../Private/Graph/FlowGraphSchema.cpp | 48 ++++++++++--------- .../FlowEditor/Public/Graph/FlowGraphSchema.h | 3 +- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp index bf0cbfa88..f679567a8 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -39,7 +39,7 @@ void UFlowGraphSchema::SubscribeToAssetChanges() const FAssetRegistryModule& AssetRegistry = FModuleManager::LoadModuleChecked(AssetRegistryConstants::ModuleName); AssetRegistry.Get().OnFilesLoaded().AddStatic(&UFlowGraphSchema::GatherFlowNodes); AssetRegistry.Get().OnAssetAdded().AddStatic(&UFlowGraphSchema::OnAssetAdded); - AssetRegistry.Get().OnAssetRemoved().AddStatic(&UFlowGraphSchema::RemoveAsset); + AssetRegistry.Get().OnAssetRemoved().AddStatic(&UFlowGraphSchema::OnAssetRemoved); FCoreUObjectDelegates::ReloadCompleteDelegate.AddStatic(&UFlowGraphSchema::OnHotReload); @@ -203,14 +203,16 @@ void UFlowGraphSchema::GetFlowNodeActions(FGraphActionMenuBuilder& ActionMenuBui TArray FlowNodes; FlowNodes.Reserve(NativeFlowNodes.Num() + BlueprintFlowNodes.Num()); - for (UClass* FlowNodeClass : NativeFlowNodes) + for (const UClass* FlowNodeClass : NativeFlowNodes) { FlowNodes.Emplace(FlowNodeClass->GetDefaultObject()); } for (const TPair& AssetData : BlueprintFlowNodes) { - UBlueprint* Blueprint = GetNodeBlueprint(AssetData.Value); - FlowNodes.Emplace(Blueprint->GeneratedClass->GetDefaultObject()); + if (const UBlueprint* Blueprint = GetNodeBlueprint(AssetData.Value)) + { + FlowNodes.Emplace(Blueprint->GeneratedClass->GetDefaultObject()); + } } for (const UFlowNode* FlowNode : FlowNodes) @@ -252,34 +254,36 @@ void UFlowGraphSchema::GatherFlowNodes() // collect C++ nodes once per editor session if (NativeFlowNodes.Num() == 0) { - for (TObjectIterator It; It; ++It) + TArray FlowNodes; + GetDerivedClasses(UFlowNode::StaticClass(), FlowNodes); + for (UClass* Class : FlowNodes) { - if (It->IsChildOf(UFlowNode::StaticClass())) + if (Class->ClassGeneratedBy == nullptr && IsFlowNodePlaceable(Class)) { - if (It->ClassGeneratedBy == nullptr && IsFlowNodePlaceable(*It)) - { - NativeFlowNodes.Emplace(*It); + NativeFlowNodes.Emplace(Class); - const UFlowNode* DefaultObject = It->GetDefaultObject(); - UnsortedCategories.Emplace(DefaultObject->GetNodeCategory()); - } + const UFlowNode* DefaultObject = Class->GetDefaultObject(); + UnsortedCategories.Emplace(DefaultObject->GetNodeCategory()); } - else if (It->IsChildOf(UFlowGraphNode::StaticClass())) + } + + TArray GraphNodes; + GetDerivedClasses(UFlowGraphNode::StaticClass(), GraphNodes); + for (UClass* Class : GraphNodes) + { + const UFlowGraphNode* DefaultObject = Class->GetDefaultObject(); + for (UClass* AssignedClass : DefaultObject->AssignedNodeClasses) { - const UFlowGraphNode* DefaultObject = It->GetDefaultObject(); - for (UClass* AssignedClass : DefaultObject->AssignedNodeClasses) + if (AssignedClass->IsChildOf(UFlowNode::StaticClass())) { - if (AssignedClass->IsChildOf(UFlowNode::StaticClass())) - { - AssignedGraphNodeClasses.Emplace(AssignedClass, *It); - } + AssignedGraphNodeClasses.Emplace(AssignedClass, Class); } } } } // retrieve all blueprint nodes - FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(AssetRegistryConstants::ModuleName); + const FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(AssetRegistryConstants::ModuleName); FARFilter Filter; Filter.ClassNames.Add(UBlueprint::StaticClass()->GetFName()); @@ -310,7 +314,7 @@ void UFlowGraphSchema::AddAsset(const FAssetData& AssetData, const bool bBatch) { if (!BlueprintFlowNodes.Contains(AssetData.PackageName)) { - FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(AssetRegistryConstants::ModuleName); + const FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(AssetRegistryConstants::ModuleName); if (AssetRegistryModule.Get().IsLoadingAssets()) { return; @@ -350,7 +354,7 @@ void UFlowGraphSchema::AddAsset(const FAssetData& AssetData, const bool bBatch) } } -void UFlowGraphSchema::RemoveAsset(const FAssetData& AssetData) +void UFlowGraphSchema::OnAssetRemoved(const FAssetData& AssetData) { if (BlueprintFlowNodes.Contains(AssetData.PackageName)) { diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h index 2e394887a..c034395e5 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h @@ -49,7 +49,8 @@ class FLOWEDITOR_API UFlowGraphSchema : public UEdGraphSchema static void OnAssetAdded(const FAssetData& AssetData); static void AddAsset(const FAssetData& AssetData, const bool bBatch); - static void RemoveAsset(const FAssetData& AssetData); + static void OnAssetRemoved(const FAssetData& AssetData); + static void RefreshNodeList(); public: From c0bd98bb28f27edf2d83d19a0efab7a4c8f1bfe3 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 11 Oct 2021 20:43:09 +0200 Subject: [PATCH 032/338] exposed World Asset Class --- Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp | 3 +++ Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp | 2 +- Source/FlowEditor/Public/Graph/FlowGraphSettings.h | 4 ++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp index b9523ff76..8efa101ea 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp @@ -1,5 +1,7 @@ #include "Graph/FlowGraphSettings.h" +#include "FlowAsset.h" + UFlowGraphSettings::UFlowGraphSettings(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) , ConnectionDrawType(EFlowConnectionDrawType::Default) @@ -11,6 +13,7 @@ UFlowGraphSettings::UFlowGraphSettings(const FObjectInitializer& ObjectInitializ , bExposeFlowAssetCreation(true) , bExposeFlowNodeCreation(true) , bShowAssetToolbarAboveLevelEditor(true) + , WorldAssetClass(UFlowAsset::StaticClass()) , bShowDefaultPinNames(false) , ExecPinColorModifier(0.75f, 0.75f, 0.75f, 1.0f) , NodeDescriptionBackground(FLinearColor(0.0625f, 0.0625f, 0.0625f, 1.0f)) diff --git a/Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp b/Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp index 00bb77d10..14b8d7b6e 100644 --- a/Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp +++ b/Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp @@ -38,7 +38,7 @@ void SLevelEditorFlow::CreateFlowWidget() .AutoWidth() [ SNew(SObjectPropertyEntryBox) - .AllowedClass(UFlowAsset::StaticClass()) + .AllowedClass(UFlowGraphSettings::Get()->WorldAssetClass) .DisplayThumbnail(false) .OnObjectChanged(this, &SLevelEditorFlow::OnFlowChanged) .ObjectPath(this, &SLevelEditorFlow::GetFlowPath) diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h index 9134c8459..3486ae217 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h @@ -47,6 +47,10 @@ class UFlowGraphSettings final : public UDeveloperSettings * Requires restart after making a change. */ UPROPERTY(EditAnywhere, config, Category = "Default UI") bool bShowAssetToolbarAboveLevelEditor; + + /** Flow Asset class allowed to be assigned via Level Editor toolbar*/ + UPROPERTY(EditAnywhere, config, Category = "Default UI", meta = (EditCondition = "bShowAssetToolbarAboveLevelEditor")) + TSubclassOf WorldAssetClass; /** Hide specific nodes from the Flow Palette without changing the source code. * Requires restart after making a change. */ From 8df0f2b086a0ed3abaa8966295361d6d7db2c99e Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Wed, 13 Oct 2021 20:55:36 +0200 Subject: [PATCH 033/338] cosmetic tweaks --- Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp b/Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp index aa37b8293..37dbcb19f 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp @@ -11,12 +11,12 @@ void FFlowAssetDetails::CustomizeDetails(IDetailLayoutBuilder& DetailLayout) { - IDetailCategoryBuilder& FlowAssetCategory = DetailLayout.EditCategory("FlowAsset", LOCTEXT("FlowAssetCategory", "FlowAsset")); + IDetailCategoryBuilder& FlowAssetCategory = DetailLayout.EditCategory("FlowAsset", LOCTEXT("FlowAssetCategory", "Flow Asset")); const TSharedPtr InputsPropertyHandle = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(UFlowAsset, CustomInputs)); if (InputsPropertyHandle.IsValid() && InputsPropertyHandle->AsArray().IsValid()) { - TSharedRef InputsArrayBuilder = MakeShareable(new FDetailArrayBuilder(InputsPropertyHandle.ToSharedRef())); + const TSharedRef InputsArrayBuilder = MakeShareable(new FDetailArrayBuilder(InputsPropertyHandle.ToSharedRef())); InputsArrayBuilder->OnGenerateArrayElementWidget(FOnGenerateArrayElementWidget::CreateSP(this, &FFlowAssetDetails::GenerateCustomPinArray)); FlowAssetCategory.AddCustomBuilder(InputsArrayBuilder); @@ -25,7 +25,7 @@ void FFlowAssetDetails::CustomizeDetails(IDetailLayoutBuilder& DetailLayout) const TSharedPtr OutputsPropertyHandle = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(UFlowAsset, CustomOutputs)); if (OutputsPropertyHandle.IsValid() && OutputsPropertyHandle->AsArray().IsValid()) { - TSharedRef OutputsArrayBuilder = MakeShareable(new FDetailArrayBuilder(OutputsPropertyHandle.ToSharedRef())); + const TSharedRef OutputsArrayBuilder = MakeShareable(new FDetailArrayBuilder(OutputsPropertyHandle.ToSharedRef())); OutputsArrayBuilder->OnGenerateArrayElementWidget(FOnGenerateArrayElementWidget::CreateSP(this, &FFlowAssetDetails::GenerateCustomPinArray)); FlowAssetCategory.AddCustomBuilder(OutputsArrayBuilder); From 62c02fd4daab70acbb8c28c2238edfd5e35bb99d Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 24 Oct 2021 19:11:18 +0200 Subject: [PATCH 034/338] #57 don't cache node categories, loading blueprint too soon might cause compilation issues the additional benefit is that Flow Palette would refresh after changing properties of Flow Node class --- .../Private/Graph/FlowGraphSchema.cpp | 80 ++++++++++--------- .../FlowEditor/Public/Graph/FlowGraphSchema.h | 8 +- 2 files changed, 45 insertions(+), 43 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp index f679567a8..a6fad03dc 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -21,10 +21,6 @@ TArray UFlowGraphSchema::NativeFlowNodes; TMap UFlowGraphSchema::BlueprintFlowNodes; - -TSet UFlowGraphSchema::UnsortedCategories; -TArray> UFlowGraphSchema::FlowNodeCategories; - TMap UFlowGraphSchema::AssignedGraphNodeClasses; FFlowGraphSchemaRefresh UFlowGraphSchema::OnNodeListChanged; @@ -175,12 +171,42 @@ TSharedPtr UFlowGraphSchema::GetCreateCommentAction() cons TArray> UFlowGraphSchema::GetFlowNodeCategories() { - if (FlowNodeCategories.Num() == 0) + if (NativeFlowNodes.Num() == 0) { GatherFlowNodes(); } - return FlowNodeCategories; + TSet UnsortedCategories; + for (const UClass* FlowNodeClass : NativeFlowNodes) + { + if (const UFlowNode* DefaultObject = FlowNodeClass->GetDefaultObject()) + { + UnsortedCategories.Emplace(DefaultObject->GetNodeCategory()); + } + } + + for (const TPair& AssetData : BlueprintFlowNodes) + { + if (const UBlueprint* Blueprint = GetPlaceableNodeBlueprint(AssetData.Value)) + { + UnsortedCategories.Emplace(Blueprint->BlueprintCategory); + } + } + + TArray SortedCategories = UnsortedCategories.Array(); + SortedCategories.Sort(); + + // create list of categories + TArray> Result; + for (const FString& Category : SortedCategories) + { + if (!Category.IsEmpty()) + { + Result.Emplace(MakeShareable(new FString(Category))); + } + } + + return Result; } UClass* UFlowGraphSchema::GetAssignedGraphNodeClass(const UClass* FlowNodeClass) @@ -209,7 +235,7 @@ void UFlowGraphSchema::GetFlowNodeActions(FGraphActionMenuBuilder& ActionMenuBui } for (const TPair& AssetData : BlueprintFlowNodes) { - if (const UBlueprint* Blueprint = GetNodeBlueprint(AssetData.Value)) + if (const UBlueprint* Blueprint = GetPlaceableNodeBlueprint(AssetData.Value)) { FlowNodes.Emplace(Blueprint->GeneratedClass->GetDefaultObject()); } @@ -261,9 +287,6 @@ void UFlowGraphSchema::GatherFlowNodes() if (Class->ClassGeneratedBy == nullptr && IsFlowNodePlaceable(Class)) { NativeFlowNodes.Emplace(Class); - - const UFlowNode* DefaultObject = Class->GetDefaultObject(); - UnsortedCategories.Emplace(DefaultObject->GetNodeCategory()); } } @@ -297,7 +320,7 @@ void UFlowGraphSchema::GatherFlowNodes() AddAsset(AssetData, true); } - RefreshNodeList(); + OnNodeListChanged.Broadcast(); } void UFlowGraphSchema::OnHotReload(EReloadCompleteReason ReloadCompleteReason) @@ -338,16 +361,11 @@ void UFlowGraphSchema::AddAsset(const FAssetData& AssetData, const bool bBatch) // accept only Flow Node blueprints if (NativeParentClass && NativeParentClass->IsChildOf(UFlowNode::StaticClass())) { - UBlueprint* Blueprint = GetNodeBlueprint(AssetData); - if (Blueprint && IsFlowNodePlaceable(Blueprint->GeneratedClass)) - { - BlueprintFlowNodes.Emplace(AssetData.PackageName, AssetData); - UnsortedCategories.Emplace(Blueprint->BlueprintCategory); + BlueprintFlowNodes.Emplace(AssetData.PackageName, AssetData); - if (!bBatch) - { - RefreshNodeList(); - } + if (!bBatch) + { + OnNodeListChanged.Broadcast(); } } } @@ -361,29 +379,19 @@ void UFlowGraphSchema::OnAssetRemoved(const FAssetData& AssetData) BlueprintFlowNodes.Remove(AssetData.PackageName); BlueprintFlowNodes.Shrink(); - RefreshNodeList(); + OnNodeListChanged.Broadcast(); } } -void UFlowGraphSchema::RefreshNodeList() +UBlueprint* UFlowGraphSchema::GetPlaceableNodeBlueprint(const FAssetData& AssetData) { - // sort categories - TArray SortedCategories = UnsortedCategories.Array(); - SortedCategories.Sort(); - - // create list of categories - FlowNodeCategories.Empty(); - for (const FString& Category : SortedCategories) + UBlueprint* Blueprint = Cast(AssetData.GetAsset()); + if (Blueprint && IsFlowNodePlaceable(Blueprint->GeneratedClass)) { - FlowNodeCategories.Emplace(MakeShareable(new FString(Category))); + return Blueprint; } - OnNodeListChanged.Broadcast(); -} - -UBlueprint* UFlowGraphSchema::GetNodeBlueprint(const FAssetData& AssetData) -{ - return Cast(StaticLoadObject(AssetData.GetClass(), /*Outer =*/nullptr, *AssetData.ObjectPath.ToString(), nullptr, LOAD_NoWarn | LOAD_DisableCompileOnLoad)); + return nullptr; } #undef LOCTEXT_NAMESPACE diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h index c034395e5..3abd9f338 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h @@ -13,10 +13,6 @@ class FLOWEDITOR_API UFlowGraphSchema : public UEdGraphSchema private: static TArray NativeFlowNodes; static TMap BlueprintFlowNodes; - - static TSet UnsortedCategories; - static TArray> FlowNodeCategories; - static TMap AssignedGraphNodeClasses; public: @@ -50,10 +46,8 @@ class FLOWEDITOR_API UFlowGraphSchema : public UEdGraphSchema static void OnAssetAdded(const FAssetData& AssetData); static void AddAsset(const FAssetData& AssetData, const bool bBatch); static void OnAssetRemoved(const FAssetData& AssetData); - - static void RefreshNodeList(); public: static FFlowGraphSchemaRefresh OnNodeListChanged; - static UBlueprint* GetNodeBlueprint(const FAssetData& AssetData); + static UBlueprint* GetPlaceableNodeBlueprint(const FAssetData& AssetData); }; From abed98a3ce35d744f983ca46e09eb8bb38bfb3bb Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 24 Oct 2021 21:00:41 +0200 Subject: [PATCH 035/338] #63 prevent updating Flow objects while compiling any blueprint --- .../Private/Graph/FlowGraphSchema.cpp | 26 ++++++++++++++++--- .../Private/Graph/Nodes/FlowGraphNode.cpp | 23 ++++++++++++++-- .../FlowEditor/Public/Graph/FlowGraphSchema.h | 6 +++++ .../Public/Graph/Nodes/FlowGraphNode.h | 5 ++++ 4 files changed, 55 insertions(+), 5 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp index a6fad03dc..e2d49769a 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -23,6 +23,8 @@ TArray UFlowGraphSchema::NativeFlowNodes; TMap UFlowGraphSchema::BlueprintFlowNodes; TMap UFlowGraphSchema::AssignedGraphNodeClasses; +bool UFlowGraphSchema::bBlueprintCompilationPending; + FFlowGraphSchemaRefresh UFlowGraphSchema::OnNodeListChanged; UFlowGraphSchema::UFlowGraphSchema(const FObjectInitializer& ObjectInitializer) @@ -41,8 +43,8 @@ void UFlowGraphSchema::SubscribeToAssetChanges() if (GEditor) { - GEditor->OnBlueprintCompiled().AddStatic(&UFlowGraphSchema::GatherFlowNodes); - GEditor->OnClassPackageLoadedOrUnloaded().AddStatic(&UFlowGraphSchema::GatherFlowNodes); + GEditor->OnBlueprintPreCompile().AddStatic(&UFlowGraphSchema::OnBlueprintPreCompile); + GEditor->OnBlueprintCompiled().AddStatic(&UFlowGraphSchema::OnBlueprintCompiled); } } @@ -269,11 +271,29 @@ bool UFlowGraphSchema::IsFlowNodePlaceable(const UClass* Class) return !Class->HasAnyClassFlags(CLASS_Abstract) && !Class->HasAnyClassFlags(CLASS_NotPlaceable) && !Class->HasAnyClassFlags(CLASS_Deprecated); } +void UFlowGraphSchema::OnBlueprintPreCompile(UBlueprint* Blueprint) +{ + if (Blueprint && Blueprint->GeneratedClass && Blueprint->GeneratedClass->IsChildOf(UFlowNode::StaticClass())) + { + bBlueprintCompilationPending = true; + } +} + +void UFlowGraphSchema::OnBlueprintCompiled() +{ + if (bBlueprintCompilationPending) + { + GatherFlowNodes(); + } + + bBlueprintCompilationPending = false; +} + void UFlowGraphSchema::GatherFlowNodes() { + // prevent asset crunching during PIE if (GEditor && GEditor->PlayWorld) { - // prevent heavy asset crunching during PIE return; } diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 5d9ee7556..096b8dd83 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -102,6 +102,7 @@ bool UFlowGraphNode::bFlowAssetsLoaded = false; UFlowGraphNode::UFlowGraphNode(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) , FlowNode(nullptr) + , bBlueprintCompilationPending(false) , bNeedsFullReconstruction(false) { OrphanedPinSaveMode = ESaveOrphanPinMode::SaveAll; @@ -225,12 +226,30 @@ void UFlowGraphNode::SubscribeToExternalChanges() // blueprint nodes if (FlowNode->GetClass()->ClassGeneratedBy && GEditor) { - GEditor->OnBlueprintCompiled().AddUObject(this, &UFlowGraphNode::OnExternalChange); - GEditor->OnClassPackageLoadedOrUnloaded().AddUObject(this, &UFlowGraphNode::OnExternalChange); + GEditor->OnBlueprintPreCompile().AddUObject(this, &UFlowGraphNode::OnBlueprintPreCompile); + GEditor->OnBlueprintCompiled().AddUObject(this, &UFlowGraphNode::OnBlueprintCompiled); } } } +void UFlowGraphNode::OnBlueprintPreCompile(UBlueprint* Blueprint) +{ + if (Blueprint && Blueprint == FlowNode->GetClass()->ClassGeneratedBy) + { + bBlueprintCompilationPending = true; + } +} + +void UFlowGraphNode::OnBlueprintCompiled() +{ + if (bBlueprintCompilationPending) + { + OnExternalChange(); + } + + bBlueprintCompilationPending = false; +} + void UFlowGraphNode::OnExternalChange() { bNeedsFullReconstruction = true; diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h index 3abd9f338..5b1a43eb7 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h @@ -15,6 +15,8 @@ class FLOWEDITOR_API UFlowGraphSchema : public UEdGraphSchema static TMap BlueprintFlowNodes; static TMap AssignedGraphNodeClasses; + static bool bBlueprintCompilationPending; + public: static void SubscribeToAssetChanges(); static void GetPaletteActions(FGraphActionMenuBuilder& ActionMenuBuilder, const FString& CategoryName); @@ -40,6 +42,10 @@ class FLOWEDITOR_API UFlowGraphSchema : public UEdGraphSchema static void GetCommentAction(FGraphActionMenuBuilder& ActionMenuBuilder, const UEdGraph* CurrentGraph = nullptr); static bool IsFlowNodePlaceable(const UClass* Class); + + static void OnBlueprintPreCompile(UBlueprint* Blueprint); + static void OnBlueprintCompiled(); + static void GatherFlowNodes(); static void OnHotReload(EReloadCompleteReason ReloadCompleteReason); diff --git a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h index 6ce9e450c..12d5537aa 100644 --- a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h +++ b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h @@ -58,6 +58,7 @@ class FLOWEDITOR_API UFlowGraphNode : public UEdGraphNode UPROPERTY(Instanced) UFlowNode* FlowNode; + bool bBlueprintCompilationPending; bool bNeedsFullReconstruction; static bool bFlowAssetsLoaded; @@ -85,6 +86,10 @@ class FLOWEDITOR_API UFlowGraphNode : public UEdGraphNode private: void SubscribeToExternalChanges(); + + void OnBlueprintPreCompile(UBlueprint* Blueprint); + void OnBlueprintCompiled(); + void OnExternalChange(); ////////////////////////////////////////////////////////////////////////// From 42ff04bab0700c561a360f6a970dc5615838dd06 Mon Sep 17 00:00:00 2001 From: Markus Ahrweiler Date: Mon, 25 Oct 2021 21:48:38 +0200 Subject: [PATCH 036/338] set custom color for even "native" nodes (#59) --- Source/Flow/Public/FlowSettings.h | 4 ++++ Source/Flow/Public/Nodes/FlowNode.h | 12 +++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Source/Flow/Public/FlowSettings.h b/Source/Flow/Public/FlowSettings.h index 608bae1ce..8fd12b528 100644 --- a/Source/Flow/Public/FlowSettings.h +++ b/Source/Flow/Public/FlowSettings.h @@ -24,4 +24,8 @@ class UFlowSettings final : public UDeveloperSettings // How many nodes of given class should be preloaded with the Flow Asset instance? UPROPERTY(Config, EditAnywhere, Category = "Preload") TMap, int32> DefaultPreloadDepth; + + // Add custom color to a Node. + UPROPERTY(Config, EditAnywhere, Category = "Design", meta=(DisplayName="Color per Node")) + TMap, FColor> NodeColors; }; diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 300c48743..c2ba7dd8b 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -69,7 +69,17 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte virtual FText GetNodeToolTip() const; // This method allows to have different for every node instance, i.e. Red if node represents enemy, Green if node represents a friend - virtual bool GetNodeTitleColor(FLinearColor& OutColor) const { return false; } + virtual bool GetNodeTitleColor(FLinearColor& OutColor) const + { + const FColor* Color = UFlowSettings::Get()->NodeColors.Find(GetClass()); + + if (!Color) + return false; + + OutColor = *Color; + + return true; + } EFlowNodeStyle GetNodeStyle() const { return NodeStyle; } From 7893e25e02b4f3408d56376448a4d05ab451195d Mon Sep 17 00:00:00 2001 From: "Satheesh (ryanjon2040)" Date: Tue, 26 Oct 2021 01:17:44 +0530 Subject: [PATCH 037/338] Add bubbles to circuit connection (#61) --- .../FlowGraphConnectionDrawingPolicy.cpp | 56 +++++++++++++++++-- .../Graph/FlowGraphConnectionDrawingPolicy.h | 3 +- 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp b/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp index 8b4e42b86..e13c0c514 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp @@ -184,13 +184,59 @@ void FFlowGraphConnectionDrawingPolicy::Internal_DrawCircuitSpline(const int32& const FVector2D StartDirection = (Params.StartDirection == EGPD_Output) ? FVector2D(1.0f, 0.0f) : FVector2D(-1.0f, 0.0f); const FVector2D EndDirection = (Params.EndDirection == EGPD_Input) ? FVector2D(1.0f, 0.0f) : FVector2D(-1.0f, 0.0f); - FSlateDrawElement::MakeDrawSpaceSpline(DrawElementsList, LayerId, Start, StartDirection, StartingPoint, EndDirection, Params.WireThickness, ESlateDrawEffect::None, Params.WireColor); - FSlateDrawElement::MakeDrawSpaceSpline(DrawElementsList, LayerId, StartingPoint, StartDirection, ControlPoint, EndDirection, Params.WireThickness, ESlateDrawEffect::None, Params.WireColor); - FSlateDrawElement::MakeDrawSpaceSpline(DrawElementsList, LayerId, ControlPoint, StartDirection, EndPoint, EndDirection, Params.WireThickness, ESlateDrawEffect::None, Params.WireColor); - FSlateDrawElement::MakeDrawSpaceSpline(DrawElementsList, LayerId, EndPoint, StartDirection, End, EndDirection, Params.WireThickness, ESlateDrawEffect::None, Params.WireColor); + Internal_DrawCircuitConnection(LayerId, Start, StartDirection, StartingPoint, EndDirection, Params); + Internal_DrawCircuitConnection(LayerId, StartingPoint, StartDirection, ControlPoint, EndDirection, Params); + Internal_DrawCircuitConnection(LayerId, ControlPoint, StartDirection, EndPoint, EndDirection, Params); + Internal_DrawCircuitConnection(LayerId, EndPoint, StartDirection, End, EndDirection, Params); } -FVector2D FFlowGraphConnectionDrawingPolicy::Internal_GetControlPoint(const FVector2D& Source, const FVector2D& Target) const +void FFlowGraphConnectionDrawingPolicy::Internal_DrawCircuitConnection(const int32& LayerId, + const FVector2D& Start, const FVector2D& StartDirection, const FVector2D& End, const FVector2D& EndDirection, + const FConnectionParams& Params) const +{ + FSlateDrawElement::MakeDrawSpaceSpline(DrawElementsList, LayerId, Start, StartDirection, End, EndDirection, + Params.WireThickness, ESlateDrawEffect::None, Params.WireColor); + + if (Params.bDrawBubbles) + { + // This table maps distance along curve to alpha + FInterpCurve SplineReparamTable; + const float SplineLength = MakeSplineReparamTable(Start, StartDirection, End, EndDirection, SplineReparamTable); + + // Draw bubbles on the spline + if (Params.bDrawBubbles) + { + const float BubbleSpacing = 64.f * ZoomFactor; + const float BubbleSpeed = 192.f * ZoomFactor; + const FVector2D BubbleSize = BubbleImage->ImageSize * ZoomFactor * 0.2f * Params.WireThickness; + + const float Time = (FPlatformTime::Seconds() - GStartTime); + const float BubbleOffset = FMath::Fmod(Time * BubbleSpeed, BubbleSpacing); + const int32 NumBubbles = FMath::CeilToInt(SplineLength/BubbleSpacing); + for (int32 i = 0; i < NumBubbles; ++i) + { + const float Distance = (static_cast(i) * BubbleSpacing) + BubbleOffset; + if (Distance < SplineLength) + { + const float Alpha = SplineReparamTable.Eval(Distance, 0.f); + FVector2D BubblePos = FMath::CubicInterp(Start, StartDirection, End, EndDirection, Alpha); + BubblePos -= (BubbleSize * 0.5f); + + FSlateDrawElement::MakeBox( + DrawElementsList, + LayerId, + FPaintGeometry( BubblePos, BubbleSize, ZoomFactor ), + BubbleImage, + ESlateDrawEffect::None, + Params.WireColor + ); + } + } + } + } +} + +FVector2D FFlowGraphConnectionDrawingPolicy::Internal_GetControlPoint(const FVector2D& Source, const FVector2D& Target) { const FVector2D Delta = Target - Source; const float Tangent = FMath::Tan(UFlowGraphSettings::Get()->ConnectionAngle * (PI / 180.f)); diff --git a/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h b/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h index c84adb13b..a7ce7aefe 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h @@ -57,5 +57,6 @@ class FFlowGraphConnectionDrawingPolicy : public FConnectionDrawingPolicy private: void Internal_DrawCircuitSpline(const int32& LayerId, const FVector2D& Start, const FVector2D& End, const FConnectionParams& Params) const; - FVector2D Internal_GetControlPoint(const FVector2D& Source, const FVector2D& Target) const; + void Internal_DrawCircuitConnection(const int32& LayerId, const FVector2D& Start, const FVector2D& StartDirection, const FVector2D& End, const FVector2D& EndDirection, const FConnectionParams& Params) const; + static FVector2D Internal_GetControlPoint(const FVector2D& Source, const FVector2D& Target); }; From 0f579853c867af7826b067202fd63c19585423a4 Mon Sep 17 00:00:00 2001 From: "Satheesh (ryanjon2040)" Date: Tue, 26 Oct 2021 01:17:52 +0530 Subject: [PATCH 038/338] Add log verbosity (#58) --- .../Flow/Private/Nodes/Utils/FlowNode_Log.cpp | 27 ++++++++++++++++++- Source/Flow/Public/Nodes/Utils/FlowNode_Log.h | 20 ++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/Source/Flow/Private/Nodes/Utils/FlowNode_Log.cpp b/Source/Flow/Private/Nodes/Utils/FlowNode_Log.cpp index 01fb7fdbc..980997693 100644 --- a/Source/Flow/Private/Nodes/Utils/FlowNode_Log.cpp +++ b/Source/Flow/Private/Nodes/Utils/FlowNode_Log.cpp @@ -17,7 +17,27 @@ UFlowNode_Log::UFlowNode_Log(const FObjectInitializer& ObjectInitializer) void UFlowNode_Log::ExecuteInput(const FName& PinName) { - UE_LOG(LogFlow, Warning, TEXT("%s"), *Message); + switch (Verbosity) + { + case EFlowLogVerbosity::Log: + UE_LOG(LogFlow, Log, TEXT("%s"), *Message); + break; + case EFlowLogVerbosity::Warning: + UE_LOG(LogFlow, Warning, TEXT("%s"), *Message); + break; + case EFlowLogVerbosity::Error: + UE_LOG(LogFlow, Error, TEXT("%s"), *Message); + break; + case EFlowLogVerbosity::Verbose: + UE_LOG(LogFlow, Verbose, TEXT("%s"), *Message); + break; + case EFlowLogVerbosity::VeryVerbose: + UE_LOG(LogFlow, VeryVerbose, TEXT("%s"), *Message); + break; + case EFlowLogVerbosity::Fatal: + UE_LOG(LogFlow, Fatal, TEXT("%s"), *Message); + default:; + } if (bPrintToScreen) { @@ -30,6 +50,11 @@ void UFlowNode_Log::ExecuteInput(const FName& PinName) #if WITH_EDITOR FString UFlowNode_Log::GetNodeDescription() const { + if (Verbosity == EFlowLogVerbosity::Fatal) + { + return FString::Printf(TEXT("FATAL LOG: %s"), *Message); + } + return Message; } #endif diff --git a/Source/Flow/Public/Nodes/Utils/FlowNode_Log.h b/Source/Flow/Public/Nodes/Utils/FlowNode_Log.h index c20daa9f6..19d2a0b8b 100644 --- a/Source/Flow/Public/Nodes/Utils/FlowNode_Log.h +++ b/Source/Flow/Public/Nodes/Utils/FlowNode_Log.h @@ -3,6 +3,23 @@ #include "Nodes/FlowNode.h" #include "FlowNode_Log.generated.h" +UENUM(BlueprintType) +enum class EFlowLogVerbosity : uint8 +{ + Log, + Warning, + Error, + Verbose, + VeryVerbose, + + /** + * Here be dragons + * This is the fatal log which means it will literally completely crash your editor/game. + * You've been warned. Use with caution. + */ + Fatal UMETA(DisplaName = "Fatal (USE WITH CAUTION)") +}; + /** * Adds message to log * Optionally shows message on screen @@ -16,6 +33,9 @@ class FLOW_API UFlowNode_Log : public UFlowNode UPROPERTY(EditAnywhere, Category = "Flow") FString Message; + UPROPERTY(EditAnywhere, Category = "Flow") + EFlowLogVerbosity Verbosity; + UPROPERTY(EditAnywhere, Category = "Flow") bool bPrintToScreen; From d5d4a218cc56c04c5fe0dc7083cb33ff4e5cedfb Mon Sep 17 00:00:00 2001 From: "Satheesh (ryanjon2040)" Date: Tue, 26 Oct 2021 01:19:26 +0530 Subject: [PATCH 039/338] Add asset path on flow node (#60) --- .../Private/Graph/FlowGraphSettings.cpp | 1 + .../Private/Graph/Nodes/FlowGraphNode.cpp | 24 ++++++++++++++++++- .../Public/Graph/FlowGraphSettings.h | 3 +++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp index 8efa101ea..38f26063c 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp @@ -7,6 +7,7 @@ UFlowGraphSettings::UFlowGraphSettings(const FObjectInitializer& ObjectInitializ , ConnectionDrawType(EFlowConnectionDrawType::Default) , ConnectionAngle(45.f) , ConnectionSpacing(FVector2D(30.f)) + , bShowAssetPathInNode(false) , bShowGraphPreview(true) , bShowGraphPathInPreview(true) , GraphPreviewSize(FVector2D(640.f, 360.f)) diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 096b8dd83..1c27995b3 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -561,9 +561,31 @@ FText UFlowGraphNode::GetNodeTitle(ENodeTitleType::Type TitleType) const { if (FlowNode) { + if (UFlowGraphSettings::Get()->bShowAssetPathInNode) + { + FString FullName; + FlowNode->GetClass()->GetPathName(nullptr, FullName); + + FString CleanAssetName; + if (FlowNode->GetClass()->ClassGeneratedBy) + { + const int32 SubStringIdx = FullName.Find(".", ESearchCase::IgnoreCase, ESearchDir::FromEnd); + CleanAssetName = FullName.Left(SubStringIdx); + } + else + { + CleanAssetName = "C++ - " + FlowNode->GetClass()->GetName(); + } + + FFormatNamedArguments Args; + Args.Add(TEXT("NodeTitle"), FlowNode->GetNodeTitle()); + Args.Add(TEXT("AssetName"), FText::FromString(CleanAssetName)); + return FText::Format(INVTEXT("{NodeTitle}\n{AssetName}"), Args); + } + return FlowNode->GetNodeTitle(); } - + return Super::GetNodeTitle(TitleType); } diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h index 3486ae217..0dfc9b683 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h @@ -24,6 +24,9 @@ class UFlowGraphSettings final : public UDeveloperSettings UPROPERTY(config, EditAnywhere, Category = "Flow Graph", meta = (EditCondition = "ConnectionDrawType == EFlowConnectionDrawType::Circuit")) FVector2D ConnectionSpacing; + UPROPERTY(config, EditAnywhere, Category = "Flow Graph") + bool bShowAssetPathInNode; + UPROPERTY(config, EditAnywhere, Category = "Flow Graph") bool bShowGraphPreview; From 889624b22f8cd1f752a14f0893e5560d1b71582a Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 25 Oct 2021 22:19:17 +0200 Subject: [PATCH 040/338] fixed and improved PR --- Source/Flow/Public/FlowSettings.h | 4 ---- Source/Flow/Public/Nodes/FlowNode.h | 12 +----------- .../FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp | 9 +++++++-- Source/FlowEditor/Public/Graph/FlowGraphSettings.h | 3 +++ 4 files changed, 11 insertions(+), 17 deletions(-) diff --git a/Source/Flow/Public/FlowSettings.h b/Source/Flow/Public/FlowSettings.h index 8fd12b528..608bae1ce 100644 --- a/Source/Flow/Public/FlowSettings.h +++ b/Source/Flow/Public/FlowSettings.h @@ -24,8 +24,4 @@ class UFlowSettings final : public UDeveloperSettings // How many nodes of given class should be preloaded with the Flow Asset instance? UPROPERTY(Config, EditAnywhere, Category = "Preload") TMap, int32> DefaultPreloadDepth; - - // Add custom color to a Node. - UPROPERTY(Config, EditAnywhere, Category = "Design", meta=(DisplayName="Color per Node")) - TMap, FColor> NodeColors; }; diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index c2ba7dd8b..dc7ddabf9 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -69,17 +69,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte virtual FText GetNodeToolTip() const; // This method allows to have different for every node instance, i.e. Red if node represents enemy, Green if node represents a friend - virtual bool GetNodeTitleColor(FLinearColor& OutColor) const - { - const FColor* Color = UFlowSettings::Get()->NodeColors.Find(GetClass()); - - if (!Color) - return false; - - OutColor = *Color; - - return true; - } + virtual bool GetDynamicTitleColor(FLinearColor& OutColor) const { return false; } EFlowNodeStyle GetNodeStyle() const { return NodeStyle; } diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 1c27995b3..5177ccd76 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -594,12 +594,17 @@ FLinearColor UFlowGraphNode::GetNodeTitleColor() const if (FlowNode) { FLinearColor DynamicColor; - if (FlowNode->GetNodeTitleColor(DynamicColor)) + if (FlowNode->GetDynamicTitleColor(DynamicColor)) { return DynamicColor; } - if (const FLinearColor* StyleColor = UFlowGraphSettings::Get()->NodeTitleColors.Find(FlowNode->GetNodeStyle())) + UFlowGraphSettings* GraphSettings = UFlowGraphSettings::Get(); + if (const FLinearColor* NodeSpecificColor = GraphSettings->NodeSpecificColors.Find(FlowNode->GetClass())) + { + return *NodeSpecificColor; + } + if (const FLinearColor* StyleColor = GraphSettings->NodeTitleColors.Find(FlowNode->GetNodeStyle())) { return *StyleColor; } diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h index 0dfc9b683..2e7ed67ea 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h @@ -67,6 +67,9 @@ class UFlowGraphSettings final : public UDeveloperSettings UPROPERTY(EditAnywhere, config, Category = "Nodes") TMap NodeTitleColors; + UPROPERTY(Config, EditAnywhere, Category = "Nodes") + TMap, FLinearColor> NodeSpecificColors; + UPROPERTY(EditAnywhere, config, Category = "Nodes") FLinearColor ExecPinColorModifier; From aa68c4b4162fd6303998a081ebb310062066fa5f Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 25 Oct 2021 22:53:57 +0200 Subject: [PATCH 041/338] removed Fatal option, copy-pasted tooltips from ELogVerbosity --- .../Flow/Private/Nodes/Utils/FlowNode_Log.cpp | 21 ++++++++----------- Source/Flow/Public/Nodes/Utils/FlowNode_Log.h | 19 +++++++---------- 2 files changed, 16 insertions(+), 24 deletions(-) diff --git a/Source/Flow/Private/Nodes/Utils/FlowNode_Log.cpp b/Source/Flow/Private/Nodes/Utils/FlowNode_Log.cpp index 980997693..7bb1f628c 100644 --- a/Source/Flow/Private/Nodes/Utils/FlowNode_Log.cpp +++ b/Source/Flow/Private/Nodes/Utils/FlowNode_Log.cpp @@ -6,6 +6,7 @@ UFlowNode_Log::UFlowNode_Log(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) , Message(TEXT("Log!")) + , Verbosity(EFlowLogVerbosity::Warning) , bPrintToScreen(true) , Duration(5.0f) , TextColor(FColor::Yellow) @@ -19,14 +20,17 @@ void UFlowNode_Log::ExecuteInput(const FName& PinName) { switch (Verbosity) { - case EFlowLogVerbosity::Log: - UE_LOG(LogFlow, Log, TEXT("%s"), *Message); + case EFlowLogVerbosity::Error: + UE_LOG(LogFlow, Error, TEXT("%s"), *Message); break; case EFlowLogVerbosity::Warning: UE_LOG(LogFlow, Warning, TEXT("%s"), *Message); break; - case EFlowLogVerbosity::Error: - UE_LOG(LogFlow, Error, TEXT("%s"), *Message); + case EFlowLogVerbosity::Display: + UE_LOG(LogFlow, Display, TEXT("%s"), *Message); + break; + case EFlowLogVerbosity::Log: + UE_LOG(LogFlow, Log, TEXT("%s"), *Message); break; case EFlowLogVerbosity::Verbose: UE_LOG(LogFlow, Verbose, TEXT("%s"), *Message); @@ -34,9 +38,7 @@ void UFlowNode_Log::ExecuteInput(const FName& PinName) case EFlowLogVerbosity::VeryVerbose: UE_LOG(LogFlow, VeryVerbose, TEXT("%s"), *Message); break; - case EFlowLogVerbosity::Fatal: - UE_LOG(LogFlow, Fatal, TEXT("%s"), *Message); - default:; + default: ; } if (bPrintToScreen) @@ -50,11 +52,6 @@ void UFlowNode_Log::ExecuteInput(const FName& PinName) #if WITH_EDITOR FString UFlowNode_Log::GetNodeDescription() const { - if (Verbosity == EFlowLogVerbosity::Fatal) - { - return FString::Printf(TEXT("FATAL LOG: %s"), *Message); - } - return Message; } #endif diff --git a/Source/Flow/Public/Nodes/Utils/FlowNode_Log.h b/Source/Flow/Public/Nodes/Utils/FlowNode_Log.h index 19d2a0b8b..c429ad2a2 100644 --- a/Source/Flow/Public/Nodes/Utils/FlowNode_Log.h +++ b/Source/Flow/Public/Nodes/Utils/FlowNode_Log.h @@ -3,21 +3,16 @@ #include "Nodes/FlowNode.h" #include "FlowNode_Log.generated.h" +// Variant of ELogVerbosity UENUM(BlueprintType) enum class EFlowLogVerbosity : uint8 { - Log, - Warning, - Error, - Verbose, - VeryVerbose, - - /** - * Here be dragons - * This is the fatal log which means it will literally completely crash your editor/game. - * You've been warned. Use with caution. - */ - Fatal UMETA(DisplaName = "Fatal (USE WITH CAUTION)") + Error UMETA(ToolTip = "Prints a message to console (and log file)"), + Warning UMETA(ToolTip = "Prints a message to console (and log file)"), + Display UMETA(ToolTip = "Prints a message to console (and log file)"), + Log UMETA(ToolTip = "Prints a message to a log file (does not print to console)"), + Verbose UMETA(ToolTip = "Prints a verbose message to a log file (if Verbose logging is enabled for the given category, usually used for detailed logging)"), + VeryVerbose UMETA(ToolTip = "Prints a verbose message to a log file (if VeryVerbose logging is enabled, usually used for detailed logging that would otherwise spam output)"), }; /** From 5e551b1d0aeca3a6678ab2cc08fc2e139c19b91c Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 25 Oct 2021 23:09:00 +0200 Subject: [PATCH 042/338] minor tweaks to displayed node path --- .../FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 5177ccd76..77e605613 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -563,18 +563,16 @@ FText UFlowGraphNode::GetNodeTitle(ENodeTitleType::Type TitleType) const { if (UFlowGraphSettings::Get()->bShowAssetPathInNode) { - FString FullName; - FlowNode->GetClass()->GetPathName(nullptr, FullName); - FString CleanAssetName; if (FlowNode->GetClass()->ClassGeneratedBy) { - const int32 SubStringIdx = FullName.Find(".", ESearchCase::IgnoreCase, ESearchDir::FromEnd); - CleanAssetName = FullName.Left(SubStringIdx); + FlowNode->GetClass()->GetPathName(nullptr, CleanAssetName); + const int32 SubStringIdx = CleanAssetName.Find(".", ESearchCase::IgnoreCase, ESearchDir::FromEnd); + CleanAssetName.LeftInline(SubStringIdx); } else { - CleanAssetName = "C++ - " + FlowNode->GetClass()->GetName(); + CleanAssetName = FlowNode->GetClass()->GetName(); } FFormatNamedArguments Args; From aef5bed7f2b559daa6e7b309d5b87f5f157e65b1 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 26 Oct 2021 12:47:21 +0200 Subject: [PATCH 043/338] removed duplicated GetNodeInstance method + const correctness --- Source/Flow/Private/FlowAsset.cpp | 12 +----------- Source/Flow/Private/Nodes/FlowNode.cpp | 2 +- Source/Flow/Public/FlowAsset.h | 1 - .../Private/Graph/Nodes/FlowGraphNode.cpp | 16 ++++++++-------- 4 files changed, 10 insertions(+), 21 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index f7d45d073..96b04e27e 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -146,12 +146,7 @@ void UFlowAsset::HarvestNodeConnections() UFlowNode* UFlowAsset::GetNode(const FGuid& Guid) const { - if (UFlowNode* Node = Nodes.FindRef(Guid)) - { - return Node; - } - - return nullptr; + return Nodes.FindRef(Guid); } void UFlowAsset::AddInstance(UFlowAsset* Instance) @@ -418,11 +413,6 @@ UFlowAsset* UFlowAsset::GetMasterInstance() const return NodeOwningThisAssetInstance.IsValid() ? NodeOwningThisAssetInstance.Get()->GetFlowAsset() : nullptr; } -UFlowNode* UFlowAsset::GetNodeInstance(const FGuid Guid) const -{ - return Nodes.FindRef(Guid); -} - FFlowAssetSaveData UFlowAsset::SaveInstance(TArray& SavedFlowInstances) { FFlowAssetSaveData AssetRecord; diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 502a2e6d9..7b4bc38c0 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -446,7 +446,7 @@ UFlowNode* UFlowNode::GetInspectedInstance() const { if (const UFlowAsset* FlowInstance = GetFlowAsset()->GetInspectedInstance()) { - return FlowInstance->GetNodeInstance(GetGuid()); + return FlowInstance->GetNode(GetGuid()); } return nullptr; diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 9545c4298..bdb7a363f 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -230,7 +230,6 @@ class FLOW_API UFlowAsset : public UObject UFlowNode_SubGraph* GetNodeOwningThisAssetInstance() const; UFlowAsset* GetMasterInstance() const; - UFlowNode* GetNodeInstance(const FGuid Guid) const; // Are there any active nodes? UFUNCTION(BlueprintPure, Category = "Flow") diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 77e605613..0dbea0ea0 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -117,9 +117,9 @@ UFlowNode* UFlowGraphNode::GetFlowNode() const { if (FlowNode) { - if (UFlowAsset* InspectedInstance = FlowNode->GetFlowAsset()->GetInspectedInstance()) + if (const UFlowAsset* InspectedInstance = FlowNode->GetFlowAsset()->GetInspectedInstance()) { - return InspectedInstance->GetNodeInstance(FlowNode->GetGuid()); + return InspectedInstance->GetNode(FlowNode->GetGuid()); } return FlowNode; @@ -144,7 +144,7 @@ void UFlowGraphNode::PostLoad() { TArray FlowAssets; - FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(AssetRegistryConstants::ModuleName); + const FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(AssetRegistryConstants::ModuleName); AssetRegistryModule.Get().GetAssetsByClass(UFlowAsset::StaticClass()->GetFName(), FlowAssets, true); for (FAssetData const& Asset : FlowAssets) @@ -394,7 +394,7 @@ void UFlowGraphNode::RewireOldPinsToNewPins(TArray& InOldPins) // NOTE: we iterate backwards through the list because ReconstructSinglePin() // destroys pins as we go along (clearing out parent pointers, etc.); // we need the parent pin chain intact for DoPinsMatchForReconstruction(); - // we want to destroy old pins from the split children (leafs) up, so + // we want to destroy old pins from the split children (leaves) up, so // we do this since split child pins are ordered later in the list // (after their parents) for (int32 OldPinIndex = InOldPins.Num() - 1; OldPinIndex >= 0; --OldPinIndex) @@ -644,7 +644,7 @@ EFlowNodeState UFlowGraphNode::GetActivationState() const { if (FlowNode) { - if (UFlowNode* NodeInstance = FlowNode->GetInspectedInstance()) + if (const UFlowNode* NodeInstance = FlowNode->GetInspectedInstance()) { return NodeInstance->GetActivationState(); } @@ -657,7 +657,7 @@ FString UFlowGraphNode::GetStatusString() const { if (FlowNode) { - if (UFlowNode* NodeInstance = FlowNode->GetInspectedInstance()) + if (const UFlowNode* NodeInstance = FlowNode->GetInspectedInstance()) { return NodeInstance->GetStatusString(); } @@ -670,7 +670,7 @@ bool UFlowGraphNode::IsContentPreloaded() const { if (FlowNode) { - if (UFlowNode* NodeInstance = FlowNode->GetInspectedInstance()) + if (const UFlowNode* NodeInstance = FlowNode->GetInspectedInstance()) { return NodeInstance->bPreloaded; } @@ -885,7 +885,7 @@ void UFlowGraphNode::GetPinHoverText(const UEdGraphPin& Pin, FString& HoverTextO // add information on pin activations if (GEditor->PlayWorld) { - if (UFlowNode* InspectedNodeInstance = GetInspectedNodeInstance()) + if (const UFlowNode* InspectedNodeInstance = GetInspectedNodeInstance()) { if (!HoverTextOut.IsEmpty()) { From 91ee21de18d86af5a72b7e3e7d3626c6238e5a12 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 31 Oct 2021 16:07:22 +0100 Subject: [PATCH 044/338] actually pass ValidatedTags to notify event and replication Issue found by Mahoukyou --- Source/Flow/Private/FlowComponent.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/Flow/Private/FlowComponent.cpp b/Source/Flow/Private/FlowComponent.cpp index fabcfd9a7..f6bd5c881 100644 --- a/Source/Flow/Private/FlowComponent.cpp +++ b/Source/Flow/Private/FlowComponent.cpp @@ -235,7 +235,7 @@ void UFlowComponent::BulkNotifyGraph(const FGameplayTagContainer NotifyTags, con { // save recently notify, this allow for the retroactive check in nodes // if retroactive check wouldn't be performed, this is only used by the network replication - RecentlySentNotifyTags = NotifyTags; + RecentlySentNotifyTags = ValidatedTags; OnRep_SentNotifyTags(); } @@ -265,14 +265,14 @@ void UFlowComponent::NotifyFromGraph(const FGameplayTagContainer& NotifyTags, co if (ValidatedTags.Num() > 0) { - for (const FGameplayTag& NotifyTag : NotifyTags) + for (const FGameplayTag& ValidatedTag : ValidatedTags) { - ReceiveNotify.Broadcast(nullptr, NotifyTag); + ReceiveNotify.Broadcast(nullptr, ValidatedTag); } if (IsNetMode(NM_DedicatedServer) || IsNetMode(NM_ListenServer)) { - NotifyTagsFromGraph = NotifyTags; + NotifyTagsFromGraph = ValidatedTags; } } } From 524d0aba63dc5f505b5ef92d0af6a443cef5cd4f Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 1 Nov 2021 12:47:15 +0100 Subject: [PATCH 045/338] Created UFlowGraphEditorSettings, SFlowGraphNode_SubGraph followed by cosmetic tweaks of recent pull requests --- .../FlowGraphConnectionDrawingPolicy.cpp | 94 +++++++++---------- .../Private/Graph/FlowGraphEditorSettings.cpp | 14 +++ .../Private/Graph/FlowGraphSettings.cpp | 12 +-- .../Private/Graph/Nodes/FlowGraphNode.cpp | 3 +- .../Graph/Nodes/FlowGraphNode_SubGraph.cpp | 15 +++ .../Private/Graph/Widgets/SFlowGraphNode.cpp | 52 +--------- .../Graph/Widgets/SFlowGraphNode_SubGraph.cpp | 60 ++++++++++++ .../Graph/FlowGraphConnectionDrawingPolicy.h | 11 +-- .../Public/Graph/FlowGraphEditorSettings.h | 37 ++++++++ .../Public/Graph/FlowGraphSettings.h | 38 ++------ .../Graph/Nodes/FlowGraphNode_SubGraph.h | 14 +++ .../Public/Graph/Widgets/SFlowGraphNode.h | 3 +- .../Graph/Widgets/SFlowGraphNode_SubGraph.h | 11 +++ 13 files changed, 220 insertions(+), 144 deletions(-) create mode 100644 Source/FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp create mode 100644 Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_SubGraph.cpp create mode 100644 Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode_SubGraph.cpp create mode 100644 Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h create mode 100644 Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_SubGraph.h create mode 100644 Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode_SubGraph.h diff --git a/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp b/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp index e13c0c514..d0a765720 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp @@ -2,6 +2,7 @@ #include "Asset/FlowAssetEditor.h" #include "Graph/FlowGraph.h" +#include "Graph/FlowGraphEditorSettings.h" #include "Graph/FlowGraphSchema.h" #include "Graph/FlowGraphSettings.h" #include "Graph/FlowGraphUtils.h" @@ -24,8 +25,6 @@ FConnectionDrawingPolicy* FFlowGraphConnectionDrawingPolicyFactory::CreateConnec ///////////////////////////////////////////////////// // FFlowGraphConnectionDrawingPolicy -class UGraphEditorSettings; - FFlowGraphConnectionDrawingPolicy::FFlowGraphConnectionDrawingPolicy(int32 InBackLayerID, int32 InFrontLayerID, float ZoomFactor, const FSlateRect& InClippingRect, FSlateWindowElementList& InDrawElements, UEdGraph* InGraphObj) : FConnectionDrawingPolicy(InBackLayerID, InFrontLayerID, ZoomFactor, InClippingRect, InDrawElements) , GraphObj(InGraphObj) @@ -77,7 +76,7 @@ void FFlowGraphConnectionDrawingPolicy::BuildPaths() } } - if (GraphObj && (UFlowGraphSettings::Get()->bHighlightInputWiresOfSelectedNodes || UFlowGraphSettings::Get()->bHighlightOutputWiresOfSelectedNodes)) + if (GraphObj && (UFlowGraphEditorSettings::Get()->bHighlightInputWiresOfSelectedNodes || UFlowGraphEditorSettings::Get()->bHighlightOutputWiresOfSelectedNodes)) { const TSharedPtr FlowAssetEditor = FFlowGraphUtils::GetFlowAssetEditor(GraphObj); if (FlowAssetEditor.IsValid()) @@ -86,8 +85,8 @@ void FFlowGraphConnectionDrawingPolicy::BuildPaths() { for (UEdGraphPin* Pin : SelectedNode->Pins) { - if ((Pin->Direction == EGPD_Input && UFlowGraphSettings::Get()->bHighlightInputWiresOfSelectedNodes) - || (Pin->Direction == EGPD_Output && UFlowGraphSettings::Get()->bHighlightOutputWiresOfSelectedNodes)) + if ((Pin->Direction == EGPD_Input && UFlowGraphEditorSettings::Get()->bHighlightInputWiresOfSelectedNodes) + || (Pin->Direction == EGPD_Output && UFlowGraphEditorSettings::Get()->bHighlightOutputWiresOfSelectedNodes)) { for (UEdGraphPin* LinkedPin : Pin->LinkedTo) { @@ -100,24 +99,18 @@ void FFlowGraphConnectionDrawingPolicy::BuildPaths() } } -void FFlowGraphConnectionDrawingPolicy::DrawConnection(int32 LayerId, const FVector2D& Start, const FVector2D& End, - const FConnectionParams& Params) +void FFlowGraphConnectionDrawingPolicy::DrawConnection(int32 LayerId, const FVector2D& Start, const FVector2D& End, const FConnectionParams& Params) { - if (UFlowGraphSettings::Get()->ConnectionDrawType == EFlowConnectionDrawType::Default) + switch (UFlowGraphSettings::Get()->ConnectionDrawType) { - FConnectionDrawingPolicy::DrawConnection(LayerId, Start, End, Params); - return; + case EFlowConnectionDrawType::Default: + FConnectionDrawingPolicy::DrawConnection(LayerId, Start, End, Params); + break; + case EFlowConnectionDrawType::Circuit: + DrawCircuitSpline(LayerId, Start, End, Params); + break; + default: ; } - - Internal_DrawCircuitSpline(LayerId, Start, End, Params); -} - -void FFlowGraphConnectionDrawingPolicy::Draw(TMap, FArrangedWidget>& InPinGeometries, FArrangedChildren& ArrangedNodes) -{ - BuildPaths(); - - // Draw everything - FConnectionDrawingPolicy::Draw(InPinGeometries, ArrangedNodes); } // Give specific editor modes a chance to highlight this connection or darken non-interesting connections @@ -175,28 +168,32 @@ void FFlowGraphConnectionDrawingPolicy::DetermineWiringStyle(UEdGraphPin* Output } } -void FFlowGraphConnectionDrawingPolicy::Internal_DrawCircuitSpline(const int32& LayerId, const FVector2D& Start, const FVector2D& End, const FConnectionParams& Params) const +void FFlowGraphConnectionDrawingPolicy::Draw(TMap, FArrangedWidget>& InPinGeometries, FArrangedChildren& ArrangedNodes) { - const FVector2D StartingPoint = FVector2D(Start.X + UFlowGraphSettings::Get()->ConnectionSpacing.X, Start.Y); - const FVector2D EndPoint = FVector2D(End.X - UFlowGraphSettings::Get()->ConnectionSpacing.Y, End.Y); - const FVector2D ControlPoint = Internal_GetControlPoint(StartingPoint, EndPoint); - + BuildPaths(); + + FConnectionDrawingPolicy::Draw(InPinGeometries, ArrangedNodes); +} + +void FFlowGraphConnectionDrawingPolicy::DrawCircuitSpline(const int32& LayerId, const FVector2D& Start, const FVector2D& End, const FConnectionParams& Params) const +{ + const FVector2D StartingPoint = FVector2D(Start.X + UFlowGraphSettings::Get()->CircuitConnectionSpacing.X, Start.Y); + const FVector2D EndPoint = FVector2D(End.X - UFlowGraphSettings::Get()->CircuitConnectionSpacing.Y, End.Y); + const FVector2D ControlPoint = GetControlPoint(StartingPoint, EndPoint); + const FVector2D StartDirection = (Params.StartDirection == EGPD_Output) ? FVector2D(1.0f, 0.0f) : FVector2D(-1.0f, 0.0f); const FVector2D EndDirection = (Params.EndDirection == EGPD_Input) ? FVector2D(1.0f, 0.0f) : FVector2D(-1.0f, 0.0f); - Internal_DrawCircuitConnection(LayerId, Start, StartDirection, StartingPoint, EndDirection, Params); - Internal_DrawCircuitConnection(LayerId, StartingPoint, StartDirection, ControlPoint, EndDirection, Params); - Internal_DrawCircuitConnection(LayerId, ControlPoint, StartDirection, EndPoint, EndDirection, Params); - Internal_DrawCircuitConnection(LayerId, EndPoint, StartDirection, End, EndDirection, Params); + DrawCircuitConnection(LayerId, Start, StartDirection, StartingPoint, EndDirection, Params); + DrawCircuitConnection(LayerId, StartingPoint, StartDirection, ControlPoint, EndDirection, Params); + DrawCircuitConnection(LayerId, ControlPoint, StartDirection, EndPoint, EndDirection, Params); + DrawCircuitConnection(LayerId, EndPoint, StartDirection, End, EndDirection, Params); } -void FFlowGraphConnectionDrawingPolicy::Internal_DrawCircuitConnection(const int32& LayerId, - const FVector2D& Start, const FVector2D& StartDirection, const FVector2D& End, const FVector2D& EndDirection, - const FConnectionParams& Params) const +void FFlowGraphConnectionDrawingPolicy::DrawCircuitConnection(const int32& LayerId, const FVector2D& Start, const FVector2D& StartDirection, const FVector2D& End, const FVector2D& EndDirection, const FConnectionParams& Params) const { - FSlateDrawElement::MakeDrawSpaceSpline(DrawElementsList, LayerId, Start, StartDirection, End, EndDirection, - Params.WireThickness, ESlateDrawEffect::None, Params.WireColor); - + FSlateDrawElement::MakeDrawSpaceSpline(DrawElementsList, LayerId, Start, StartDirection, End, EndDirection, Params.WireThickness, ESlateDrawEffect::None, Params.WireColor); + if (Params.bDrawBubbles) { // This table maps distance along curve to alpha @@ -212,7 +209,7 @@ void FFlowGraphConnectionDrawingPolicy::Internal_DrawCircuitConnection(const int const float Time = (FPlatformTime::Seconds() - GStartTime); const float BubbleOffset = FMath::Fmod(Time * BubbleSpeed, BubbleSpacing); - const int32 NumBubbles = FMath::CeilToInt(SplineLength/BubbleSpacing); + const int32 NumBubbles = FMath::CeilToInt(SplineLength / BubbleSpacing); for (int32 i = 0; i < NumBubbles; ++i) { const float Distance = (static_cast(i) * BubbleSpacing) + BubbleOffset; @@ -222,36 +219,29 @@ void FFlowGraphConnectionDrawingPolicy::Internal_DrawCircuitConnection(const int FVector2D BubblePos = FMath::CubicInterp(Start, StartDirection, End, EndDirection, Alpha); BubblePos -= (BubbleSize * 0.5f); - FSlateDrawElement::MakeBox( - DrawElementsList, - LayerId, - FPaintGeometry( BubblePos, BubbleSize, ZoomFactor ), - BubbleImage, - ESlateDrawEffect::None, - Params.WireColor - ); + FSlateDrawElement::MakeBox(DrawElementsList, LayerId, FPaintGeometry(BubblePos, BubbleSize, ZoomFactor), BubbleImage, ESlateDrawEffect::None, Params.WireColor); } } } } } -FVector2D FFlowGraphConnectionDrawingPolicy::Internal_GetControlPoint(const FVector2D& Source, const FVector2D& Target) +FVector2D FFlowGraphConnectionDrawingPolicy::GetControlPoint(const FVector2D& Source, const FVector2D& Target) { const FVector2D Delta = Target - Source; - const float Tangent = FMath::Tan(UFlowGraphSettings::Get()->ConnectionAngle * (PI / 180.f)); + const float Tangent = FMath::Tan(UFlowGraphSettings::Get()->CircuitConnectionAngle * (PI / 180.f)); - const float DX = FMath::Abs(Delta.X); - const float DY = FMath::Abs(Delta.Y); + const float DeltaX = FMath::Abs(Delta.X); + const float DeltaY = FMath::Abs(Delta.Y); - const float SlopeWidth = DY / Tangent; - if (DX > SlopeWidth) + const float SlopeWidth = DeltaY / Tangent; + if (DeltaX > SlopeWidth) { return Delta.X > 0.f ? FVector2D(Target.X - SlopeWidth, Source.Y) : FVector2D(Source.X - SlopeWidth, Target.Y); } - const float SlopeHeight = DX * Tangent; - if (DY > SlopeHeight) + const float SlopeHeight = DeltaX * Tangent; + if (DeltaY > SlopeHeight) { if (Delta.Y > 0.f) { diff --git a/Source/FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp b/Source/FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp new file mode 100644 index 000000000..5778a6230 --- /dev/null +++ b/Source/FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp @@ -0,0 +1,14 @@ +#include "Graph/FlowGraphEditorSettings.h" + +#include "FlowAsset.h" + +UFlowGraphEditorSettings::UFlowGraphEditorSettings(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) + , bShowNodeClass(false) + , bShowSubGraphPreview(true) + , bShowSubGraphPath(true) + , SubGraphPreviewSize(FVector2D(640.f, 360.f)) + , bHighlightInputWiresOfSelectedNodes(true) + , bHighlightOutputWiresOfSelectedNodes(false) +{ +} diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp index 38f26063c..db9091aa7 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp @@ -4,13 +4,6 @@ UFlowGraphSettings::UFlowGraphSettings(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) - , ConnectionDrawType(EFlowConnectionDrawType::Default) - , ConnectionAngle(45.f) - , ConnectionSpacing(FVector2D(30.f)) - , bShowAssetPathInNode(false) - , bShowGraphPreview(true) - , bShowGraphPathInPreview(true) - , GraphPreviewSize(FVector2D(640.f, 360.f)) , bExposeFlowAssetCreation(true) , bExposeFlowNodeCreation(true) , bShowAssetToolbarAboveLevelEditor(true) @@ -20,6 +13,9 @@ UFlowGraphSettings::UFlowGraphSettings(const FObjectInitializer& ObjectInitializ , NodeDescriptionBackground(FLinearColor(0.0625f, 0.0625f, 0.0625f, 1.0f)) , NodeStatusBackground(FLinearColor(0.12f, 0.12f, 0.12f, 1.0f)) , NodePreloadedBackground(FLinearColor(0.12f, 0.12f, 0.12f, 1.0f)) + , ConnectionDrawType(EFlowConnectionDrawType::Default) + , CircuitConnectionAngle(45.f) + , CircuitConnectionSpacing(FVector2D(30.f)) , InactiveWireColor(FLinearColor(0.364f, 0.364f, 0.364f, 1.0f)) , InactiveWireThickness(1.5f) , RecentWireDuration(3.0f) @@ -27,8 +23,6 @@ UFlowGraphSettings::UFlowGraphSettings(const FObjectInitializer& ObjectInitializ , RecentWireThickness(6.0f) , RecordedWireColor(FLinearColor(0.432f, 0.258f, 0.096f, 1.0f)) , RecordedWireThickness(3.5f) - , bHighlightInputWiresOfSelectedNodes(true) - , bHighlightOutputWiresOfSelectedNodes(false) , SelectedWireColor(FLinearColor(0.984f, 0.482f, 0.010f, 1.0f)) , SelectedWireThickness(1.5f) { diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 0dbea0ea0..2879fbc51 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -3,6 +3,7 @@ #include "Asset/FlowDebugger.h" #include "FlowEditorCommands.h" #include "Graph/FlowGraph.h" +#include "Graph/FlowGraphEditorSettings.h" #include "Graph/FlowGraphSchema.h" #include "Graph/FlowGraphSettings.h" #include "Graph/Widgets/SFlowGraphNode.h" @@ -561,7 +562,7 @@ FText UFlowGraphNode::GetNodeTitle(ENodeTitleType::Type TitleType) const { if (FlowNode) { - if (UFlowGraphSettings::Get()->bShowAssetPathInNode) + if (UFlowGraphEditorSettings::Get()->bShowNodeClass) { FString CleanAssetName; if (FlowNode->GetClass()->ClassGeneratedBy) diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_SubGraph.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_SubGraph.cpp new file mode 100644 index 000000000..ed6dab19a --- /dev/null +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_SubGraph.cpp @@ -0,0 +1,15 @@ +#include "Graph/Nodes/FlowGraphNode_SubGraph.h" +#include "Graph/Widgets/SFlowGraphNode_SubGraph.h" + +#include "Nodes/Route/FlowNode_SubGraph.h" + +UFlowGraphNode_SubGraph::UFlowGraphNode_SubGraph(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + AssignedNodeClasses = {UFlowNode_SubGraph::StaticClass()}; +} + +TSharedPtr UFlowGraphNode_SubGraph::CreateVisualWidget() +{ + return SNew(SFlowGraphNode_SubGraph, this); +} diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp index b16f2a6d6..e93e0f034 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp @@ -1,7 +1,9 @@ #include "Graph/Widgets/SFlowGraphNode.h" #include "FlowEditorStyle.h" +#include "Graph/FlowGraphEditorSettings.h" #include "Graph/FlowGraphSettings.h" +#include "FlowAsset.h" #include "Nodes/FlowNode.h" #include "EdGraph/EdGraphPin.h" @@ -14,19 +16,15 @@ #include "SCommentBubble.h" #include "SGraphNode.h" #include "SGraphPin.h" +#include "SlateOptMacros.h" #include "SLevelOfDetailBranchNode.h" #include "SNodePanel.h" -#include "SlateOptMacros.h" #include "Styling/SlateColor.h" #include "TutorialMetaData.h" -#include "FlowAsset.h" -#include "SGraphPreviewer.h" -#include "Nodes/Route/FlowNode_SubGraph.h" #include "Widgets/Images/SImage.h" #include "Widgets/Layout/SBorder.h" #include "Widgets/SBoxPanel.h" #include "Widgets/SOverlay.h" -#include "Widgets/SToolTip.h" #define LOCTEXT_NAMESPACE "SFlowGraphNode" @@ -256,7 +254,7 @@ void SFlowGraphNode::UpdateGraphNode() this->ContentScale.Bind(this, &SGraphNode::GetContentScale); - TSharedPtr InnerVerticalBox = SNew(SVerticalBox) + const TSharedPtr InnerVerticalBox = SNew(SVerticalBox) + SVerticalBox::Slot() .AutoHeight() .HAlign(HAlign_Fill) @@ -383,7 +381,7 @@ const FSlateBrush* SFlowGraphNode::GetNodeBodyBrush() const void SFlowGraphNode::CreateStandardPinWidget(UEdGraphPin* Pin) { - TSharedPtr NewPin = SNew(SFlowGraphPinExec, Pin); + const TSharedPtr NewPin = SNew(SFlowGraphPinExec, Pin); if (!UFlowGraphSettings::Get()->bShowDefaultPinNames && FlowGraphNode->GetFlowNode()) { @@ -468,46 +466,6 @@ FReply SFlowGraphNode::OnAddPin() TSharedPtr SFlowGraphNode::GetComplexTooltip() { - if (UFlowGraphSettings::Get()->bShowGraphPreview) - { - if (UFlowNode_SubGraph* MySubGraphNode = Cast(FlowGraphNode->GetFlowNode())) - { - const UFlowAsset* AssetToEdit = Cast(MySubGraphNode->GetAssetToEdit()); - if (AssetToEdit && AssetToEdit->GetGraph()) - { - TSharedPtr TitleBarWidget = SNullWidget::NullWidget; - if (UFlowGraphSettings::Get()->bShowGraphPathInPreview) - { - const FString AssetName = FString::Printf(TEXT(".%s"), *AssetToEdit->GetName()); - const FString AssetPath = AssetToEdit->GetPathName().Replace(*AssetName, TEXT("")); - TitleBarWidget = SNew(SBox) - .Padding(10.f) - [ - SNew(STextBlock) - .Text(FText::FromString(AssetPath)) - ]; - } - - return SNew(SToolTip) - [ - SNew(SBox) - .WidthOverride(UFlowGraphSettings::Get()->GraphPreviewSize.X) - .HeightOverride(UFlowGraphSettings::Get()->GraphPreviewSize.Y) - [ - SNew(SOverlay) - +SOverlay::Slot() - [ - SNew(SGraphPreviewer, AssetToEdit->GetGraph()) - .CornerOverlayText(LOCTEXT("FlowNodePreviewGraphOverlayText", "FLOW PREVIEW")) - .ShowGraphStateOverlay(false) - .TitleBar(TitleBarWidget) - ] - ] - ]; - } - } - } - return IDocumentation::Get()->CreateToolTip(TAttribute(this, &SGraphNode::GetNodeTooltip), nullptr, GraphNode->GetDocumentationLink(), GraphNode->GetDocumentationExcerptName()); } diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode_SubGraph.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode_SubGraph.cpp new file mode 100644 index 000000000..4fcf83d5c --- /dev/null +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode_SubGraph.cpp @@ -0,0 +1,60 @@ +#include "Graph/Widgets/SFlowGraphNode_SubGraph.h" +#include "Graph/FlowGraphEditorSettings.h" + +#include "FlowAsset.h" +#include "Nodes/Route/FlowNode_SubGraph.h" + +#include "IDocumentation.h" +#include "SGraphPreviewer.h" +#include "Widgets/SToolTip.h" + +#define LOCTEXT_NAMESPACE "SFlowGraphNode_SubGraph" + +TSharedPtr SFlowGraphNode_SubGraph::GetComplexTooltip() +{ + if (UFlowGraphEditorSettings::Get()->bShowSubGraphPreview && FlowGraphNode) + { + if (UFlowNode* FlowNode = FlowGraphNode->GetFlowNode()) + { + const UFlowAsset* AssetToEdit = Cast(FlowNode->GetAssetToEdit()); + if (AssetToEdit && AssetToEdit->GetGraph()) + { + TSharedPtr TitleBarWidget = SNullWidget::NullWidget; + if (UFlowGraphEditorSettings::Get()->bShowSubGraphPath) + { + FString CleanAssetName = AssetToEdit->GetPathName(nullptr); + const int32 SubStringIdx = CleanAssetName.Find(".", ESearchCase::IgnoreCase, ESearchDir::FromEnd); + CleanAssetName.LeftInline(SubStringIdx); + + TitleBarWidget = SNew(SBox) + .Padding(10.f) + [ + SNew(STextBlock) + .Text(FText::FromString(CleanAssetName)) + ]; + } + + return SNew(SToolTip) + [ + SNew(SBox) + .WidthOverride(UFlowGraphEditorSettings::Get()->SubGraphPreviewSize.X) + .HeightOverride(UFlowGraphEditorSettings::Get()->SubGraphPreviewSize.Y) + [ + SNew(SOverlay) + +SOverlay::Slot() + [ + SNew(SGraphPreviewer, AssetToEdit->GetGraph()) + .CornerOverlayText(LOCTEXT("FlowNodePreviewGraphOverlayText", "GRAPH PREVIEW")) + .ShowGraphStateOverlay(false) + .TitleBar(TitleBarWidget) + ] + ] + ]; + } + } + } + + return SFlowGraphNode::GetComplexTooltip(); +} + +#undef LOCTEXT_NAMESPACE diff --git a/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h b/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h index a7ce7aefe..d4a954c74 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h @@ -50,13 +50,12 @@ class FFlowGraphConnectionDrawingPolicy : public FConnectionDrawingPolicy // FConnectionDrawingPolicy interface virtual void DrawConnection(int32 LayerId, const FVector2D& Start, const FVector2D& End, const FConnectionParams& Params) override; - virtual void Draw(TMap, FArrangedWidget>& PinGeometries, FArrangedChildren& ArrangedNodes) override; virtual void DetermineWiringStyle(UEdGraphPin* OutputPin, UEdGraphPin* InputPin, FConnectionParams& Params) override; + virtual void Draw(TMap, FArrangedWidget>& PinGeometries, FArrangedChildren& ArrangedNodes) override; // End of FConnectionDrawingPolicy interface -private: - - void Internal_DrawCircuitSpline(const int32& LayerId, const FVector2D& Start, const FVector2D& End, const FConnectionParams& Params) const; - void Internal_DrawCircuitConnection(const int32& LayerId, const FVector2D& Start, const FVector2D& StartDirection, const FVector2D& End, const FVector2D& EndDirection, const FConnectionParams& Params) const; - static FVector2D Internal_GetControlPoint(const FVector2D& Source, const FVector2D& Target); +protected: + void DrawCircuitSpline(const int32& LayerId, const FVector2D& Start, const FVector2D& End, const FConnectionParams& Params) const; + void DrawCircuitConnection(const int32& LayerId, const FVector2D& Start, const FVector2D& StartDirection, const FVector2D& End, const FVector2D& EndDirection, const FConnectionParams& Params) const; + static FVector2D GetControlPoint(const FVector2D& Source, const FVector2D& Target); }; diff --git a/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h b/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h new file mode 100644 index 000000000..be8230863 --- /dev/null +++ b/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h @@ -0,0 +1,37 @@ +#pragma once + +#include "FlowGraphConnectionDrawingPolicy.h" +#include "Engine/DeveloperSettings.h" + +#include "FlowTypes.h" +#include "FlowGraphEditorSettings.generated.h" + +/** + * + */ +UCLASS(Config = EditorPerProjectUserSettings, meta = (DisplayName = "Flow Graph")) +class UFlowGraphEditorSettings final : public UDeveloperSettings +{ + GENERATED_UCLASS_BODY() + static UFlowGraphEditorSettings* Get() { return StaticClass()->GetDefaultObject(); } + + // Displays information on the graph node, either C++ class name or path to blueprint asset + UPROPERTY(config, EditAnywhere, Category = "Nodes") + bool bShowNodeClass; + + // Renders preview of entire graph while hovering over + UPROPERTY(config, EditAnywhere, Category = "Nodes") + bool bShowSubGraphPreview; + + UPROPERTY(config, EditAnywhere, Category = "Nodes", meta = (EditCondition = "bShowSubGraphPreview")) + bool bShowSubGraphPath; + + UPROPERTY(config, EditAnywhere, Category = "Nodes", meta = (EditCondition = "bShowSubGraphPreview")) + FVector2D SubGraphPreviewSize; + + UPROPERTY(EditAnywhere, config, Category = "Wires") + bool bHighlightInputWiresOfSelectedNodes; + + UPROPERTY(EditAnywhere, config, Category = "Wires") + bool bHighlightOutputWiresOfSelectedNodes; +}; diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h index 2e7ed67ea..398736f4b 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h @@ -13,28 +13,7 @@ UCLASS(Config = Editor, defaultconfig, meta = (DisplayName = "Flow Graph")) class UFlowGraphSettings final : public UDeveloperSettings { GENERATED_UCLASS_BODY() - static UFlowGraphSettings* Get() { return CastChecked(UFlowGraphSettings::StaticClass()->GetDefaultObject()); } - - UPROPERTY(config, EditAnywhere, Category = "Flow Graph") - EFlowConnectionDrawType ConnectionDrawType; - - UPROPERTY(config, EditAnywhere, Category = "Flow Graph", meta = (EditCondition = "ConnectionDrawType == EFlowConnectionDrawType::Circuit")) - float ConnectionAngle; - - UPROPERTY(config, EditAnywhere, Category = "Flow Graph", meta = (EditCondition = "ConnectionDrawType == EFlowConnectionDrawType::Circuit")) - FVector2D ConnectionSpacing; - - UPROPERTY(config, EditAnywhere, Category = "Flow Graph") - bool bShowAssetPathInNode; - - UPROPERTY(config, EditAnywhere, Category = "Flow Graph") - bool bShowGraphPreview; - - UPROPERTY(config, EditAnywhere, Category = "Flow Graph", meta = (EditCondition = "bShowGraphPreview")) - bool bShowGraphPathInPreview; - - UPROPERTY(config, EditAnywhere, Category = "Flow Graph", meta = (EditCondition = "bShowGraphPreview")) - FVector2D GraphPreviewSize; + static UFlowGraphSettings* Get() { return StaticClass()->GetDefaultObject(); } /** Show Flow Asset in Flow category of "Create Asset" menu? * Requires restart after making a change. */ @@ -81,6 +60,15 @@ class UFlowGraphSettings final : public UDeveloperSettings UPROPERTY(EditAnywhere, config, Category = "NodePopups") FLinearColor NodePreloadedBackground; + + UPROPERTY(config, EditAnywhere, Category = "Wires") + EFlowConnectionDrawType ConnectionDrawType; + + UPROPERTY(config, EditAnywhere, Category = "Wires", meta = (EditCondition = "ConnectionDrawType == EFlowConnectionDrawType::Circuit")) + float CircuitConnectionAngle; + + UPROPERTY(config, EditAnywhere, Category = "Wires", meta = (EditCondition = "ConnectionDrawType == EFlowConnectionDrawType::Circuit")) + FVector2D CircuitConnectionSpacing; UPROPERTY(EditAnywhere, config, Category = "Wires") FLinearColor InactiveWireColor; @@ -104,12 +92,6 @@ class UFlowGraphSettings final : public UDeveloperSettings UPROPERTY(EditAnywhere, config, Category = "Wires", meta = (ClampMin = 0.0f)) float RecordedWireThickness; - UPROPERTY(EditAnywhere, config, Category = "Wires") - bool bHighlightInputWiresOfSelectedNodes; - - UPROPERTY(EditAnywhere, config, Category = "Wires") - bool bHighlightOutputWiresOfSelectedNodes; - UPROPERTY(EditAnywhere, config, Category = "Wires") FLinearColor SelectedWireColor; diff --git a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_SubGraph.h b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_SubGraph.h new file mode 100644 index 000000000..dea2d4d4b --- /dev/null +++ b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_SubGraph.h @@ -0,0 +1,14 @@ +#pragma once + +#include "Graph/Nodes/FlowGraphNode.h" +#include "FlowGraphNode_SubGraph.generated.h" + +UCLASS() +class FLOWEDITOR_API UFlowGraphNode_SubGraph : public UFlowGraphNode +{ + GENERATED_UCLASS_BODY() + + // UEdGraphNode + virtual TSharedPtr CreateVisualWidget() override; + // -- +}; diff --git a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h index b2814fa2d..acd271fe7 100644 --- a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h +++ b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h @@ -42,9 +42,10 @@ class SFlowGraphNode : public SGraphNode virtual void CreateInputSideAddButton(TSharedPtr OutputBox) override; virtual void CreateOutputSideAddButton(TSharedPtr OutputBox) override; virtual FReply OnAddPin() override; + virtual TSharedPtr GetComplexTooltip() override; // -- -private: +protected: UFlowGraphNode* FlowGraphNode = nullptr; }; diff --git a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode_SubGraph.h b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode_SubGraph.h new file mode 100644 index 000000000..95f7dde17 --- /dev/null +++ b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode_SubGraph.h @@ -0,0 +1,11 @@ +#pragma once + +#include "Graph/Widgets/SFlowGraphNode.h" + +class SFlowGraphNode_SubGraph : public SFlowGraphNode +{ +protected: + // SGraphNode + virtual TSharedPtr GetComplexTooltip() override; + // -- +}; From 167f5f35c7bb2811ee587ef58a70471ca4cb3b67 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 1 Nov 2021 16:26:17 +0100 Subject: [PATCH 046/338] exposed Camera Settings on Play Level Sequence node --- Source/Flow/Flow.Build.cs | 8 ++++++-- .../Private/LevelSequence/FlowLevelSequencePlayer.cpp | 7 ++++--- .../Private/Nodes/World/FlowNode_PlayLevelSequence.cpp | 2 +- .../Flow/Public/LevelSequence/FlowLevelSequencePlayer.h | 2 +- .../Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h | 8 ++++++-- 5 files changed, 18 insertions(+), 9 deletions(-) diff --git a/Source/Flow/Flow.Build.cs b/Source/Flow/Flow.Build.cs index a1c5597a9..b03f3b0d0 100644 --- a/Source/Flow/Flow.Build.cs +++ b/Source/Flow/Flow.Build.cs @@ -4,8 +4,13 @@ public class Flow : ModuleRules { public Flow(ReadOnlyTargetRules Target) : base(Target) { - PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; + PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; + PublicDependencyModuleNames.AddRange(new[] + { + "LevelSequence" + }); + PrivateDependencyModuleNames.AddRange(new[] { "Core", @@ -13,7 +18,6 @@ public Flow(ReadOnlyTargetRules Target) : base(Target) "DeveloperSettings", "Engine", "GameplayTags", - "LevelSequence", "MovieScene", "MovieSceneTracks", "Slate", diff --git a/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp b/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp index 484859fd9..43dc4cfa9 100644 --- a/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp +++ b/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp @@ -8,9 +8,9 @@ UFlowLevelSequencePlayer::UFlowLevelSequencePlayer(const FObjectInitializer& Obj { } -UFlowLevelSequencePlayer* UFlowLevelSequencePlayer::CreateFlowLevelSequencePlayer(UObject* WorldContextObject, ULevelSequence* InLevelSequence, FMovieSceneSequencePlaybackSettings Settings, ALevelSequenceActor*& OutActor) +UFlowLevelSequencePlayer* UFlowLevelSequencePlayer::CreateFlowLevelSequencePlayer(UObject* WorldContextObject, ULevelSequence* LevelSequence, FMovieSceneSequencePlaybackSettings Settings, FLevelSequenceCameraSettings CameraSettings, ALevelSequenceActor*& OutActor) { - if (InLevelSequence == nullptr) + if (LevelSequence == nullptr) { return nullptr; } @@ -32,7 +32,8 @@ UFlowLevelSequencePlayer* UFlowLevelSequencePlayer::CreateFlowLevelSequencePlaye ALevelSequenceActor* Actor = World->SpawnActor(SpawnParams); Actor->PlaybackSettings = Settings; - Actor->LevelSequence = InLevelSequence; + Actor->LevelSequence = LevelSequence; + Actor->CameraSettings = CameraSettings; Actor->InitializePlayer(); OutActor = Actor; diff --git a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp index 09e415b1a..cbf78117d 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp @@ -114,7 +114,7 @@ void UFlowNode_PlayLevelSequence::CreatePlayer() if (LoadedSequence) { ALevelSequenceActor* SequenceActor; - SequencePlayer = UFlowLevelSequencePlayer::CreateFlowLevelSequencePlayer(this, LoadedSequence, PlaybackSettings, SequenceActor); + SequencePlayer = UFlowLevelSequencePlayer::CreateFlowLevelSequencePlayer(this, LoadedSequence, PlaybackSettings, CameraSettings, SequenceActor); SequencePlayer->SetFlowEventReceiver(this); const FFrameRate FrameRate = LoadedSequence->GetMovieScene()->GetTickResolution(); diff --git a/Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h b/Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h index b6eb28eb6..d7cbceeaa 100644 --- a/Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h +++ b/Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h @@ -20,7 +20,7 @@ class FLOW_API UFlowLevelSequencePlayer : public ULevelSequencePlayer public: // variant of ULevelSequencePlayer::CreateLevelSequencePlayer - static UFlowLevelSequencePlayer* CreateFlowLevelSequencePlayer(UObject* WorldContextObject, ULevelSequence* LevelSequence, FMovieSceneSequencePlaybackSettings Settings, ALevelSequenceActor*& OutActor); + static UFlowLevelSequencePlayer* CreateFlowLevelSequencePlayer(UObject* WorldContextObject, ULevelSequence* LevelSequence, FMovieSceneSequencePlaybackSettings Settings, FLevelSequenceCameraSettings CameraSettings, ALevelSequenceActor*& OutActor); void SetFlowEventReceiver(UFlowNode* FlowNode) { FlowEventReceiver = FlowNode; } diff --git a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h index baa77747f..2db121ef0 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h @@ -1,12 +1,13 @@ #pragma once #include "EngineDefines.h" +#include "LevelSequencePlayer.h" #include "MovieSceneSequencePlayer.h" + #include "Nodes/FlowNode.h" #include "FlowNode_PlayLevelSequence.generated.h" class UFlowLevelSequencePlayer; -class ULevelSequence; DECLARE_MULTICAST_DELEGATE(FFlowNodeLevelSequenceEvent); @@ -31,7 +32,10 @@ class FLOW_API UFlowNode_PlayLevelSequence : public UFlowNode UPROPERTY(EditAnywhere, Category = "Sequence") FMovieSceneSequencePlaybackSettings PlaybackSettings; - + + UPROPERTY(EditAnywhere, Category = "Sequence") + FLevelSequenceCameraSettings CameraSettings; + protected: UPROPERTY() ULevelSequence* LoadedSequence; From 093207ff4bb4cde6508d8bce6acc48ace8d25b72 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Thu, 4 Nov 2021 15:11:54 +0100 Subject: [PATCH 047/338] Timer node is no longer final, it can be extended --- Source/Flow/Public/Nodes/Route/FlowNode_Timer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h b/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h index 35562d387..57d4ac057 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h @@ -8,7 +8,7 @@ * Triggers outputs after time elapsed */ UCLASS(NotBlueprintable, meta = (DisplayName = "Timer")) -class FLOW_API UFlowNode_Timer final : public UFlowNode +class FLOW_API UFlowNode_Timer : public UFlowNode { GENERATED_UCLASS_BODY() From 043de45683ff2f9c896460370300a788b8c4c0ae Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 7 Nov 2021 20:50:33 +0100 Subject: [PATCH 048/338] 5.0 compilation fix --- Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp b/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp index 43dc4cfa9..4ce1c28f4 100644 --- a/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp +++ b/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp @@ -32,7 +32,7 @@ UFlowLevelSequencePlayer* UFlowLevelSequencePlayer::CreateFlowLevelSequencePlaye ALevelSequenceActor* Actor = World->SpawnActor(SpawnParams); Actor->PlaybackSettings = Settings; - Actor->LevelSequence = LevelSequence; + Actor->LevelSequenceAsset = LevelSequence; Actor->CameraSettings = CameraSettings; Actor->InitializePlayer(); From 0c429d70a607879065d8f8caeff8262ccc458195 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 9 Nov 2021 11:18:28 +0100 Subject: [PATCH 049/338] Allowed Node Classes list filters out what nodes can be placed in given Flow Asset type --- Source/Flow/Private/FlowAsset.cpp | 1 + Source/Flow/Public/FlowAsset.h | 4 +++ .../Private/Graph/FlowGraphSchema.cpp | 34 +++++++++++++++---- .../Private/Graph/Widgets/SFlowPalette.cpp | 13 +++++-- .../FlowEditor/Public/Graph/FlowGraphSchema.h | 4 +-- 5 files changed, 46 insertions(+), 10 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 96b04e27e..5bbbbb146 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -16,6 +16,7 @@ UFlowAsset::UFlowAsset(const FObjectInitializer& ObjectInitializer) #if WITH_EDITOR , FlowGraph(nullptr) #endif + , AllowedNodeClasses({UFlowNode::StaticClass()}) , TemplateAsset(nullptr) , StartNode(nullptr) , FinishPolicy(EFlowFinishPolicy::Keep) diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index bdb7a363f..f95668ab5 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -45,6 +45,7 @@ class FLOW_API UFlowAsset : public UObject friend class UFlowSubsystem; friend class FFlowAssetDetails; + friend class UFlowGraphSchema; ////////////////////////////////////////////////////////////////////////// // Graph @@ -81,6 +82,9 @@ class FLOW_API UFlowAsset : public UObject ////////////////////////////////////////////////////////////////////////// // Nodes +protected: + TArray> AllowedNodeClasses; + private: UPROPERTY() TMap Nodes; diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp index e2d49769a..0bd6c9ca4 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -48,15 +48,21 @@ void UFlowGraphSchema::SubscribeToAssetChanges() } } -void UFlowGraphSchema::GetPaletteActions(FGraphActionMenuBuilder& ActionMenuBuilder, const FString& CategoryName) +void UFlowGraphSchema::GetPaletteActions(FGraphActionMenuBuilder& ActionMenuBuilder, UClass* AssetClass, const FString& CategoryName) { - GetFlowNodeActions(ActionMenuBuilder, CategoryName); + GetFlowNodeActions(ActionMenuBuilder, AssetClass, CategoryName); GetCommentAction(ActionMenuBuilder); } void UFlowGraphSchema::GetGraphContextActions(FGraphContextMenuBuilder& ContextMenuBuilder) const { - GetFlowNodeActions(ContextMenuBuilder, FString()); + UClass* AssetClass = UFlowAsset::StaticClass(); + if (const UFlowAsset* FlowAsset = ContextMenuBuilder.CurrentGraph->GetTypedOuter()) + { + AssetClass = FlowAsset->GetClass(); + } + + GetFlowNodeActions(ContextMenuBuilder, AssetClass, FString()); GetCommentAction(ContextMenuBuilder, ContextMenuBuilder.CurrentGraph); if (!ContextMenuBuilder.FromPin && FFlowGraphUtils::GetFlowAssetEditor(ContextMenuBuilder.CurrentGraph)->CanPasteNodes()) @@ -221,27 +227,43 @@ UClass* UFlowGraphSchema::GetAssignedGraphNodeClass(const UClass* FlowNodeClass) return UFlowGraphNode::StaticClass(); } -void UFlowGraphSchema::GetFlowNodeActions(FGraphActionMenuBuilder& ActionMenuBuilder, const FString& CategoryName) +void UFlowGraphSchema::GetFlowNodeActions(FGraphActionMenuBuilder& ActionMenuBuilder, UClass* AssetClass, const FString& CategoryName) { if (NativeFlowNodes.Num() == 0) { GatherFlowNodes(); } + // get actual asset type, as it might limit which nodes are placeable + const UFlowAsset* AssetClassDefaults = AssetClass->GetDefaultObject(); + TArray FlowNodes; FlowNodes.Reserve(NativeFlowNodes.Num() + BlueprintFlowNodes.Num()); for (const UClass* FlowNodeClass : NativeFlowNodes) { - FlowNodes.Emplace(FlowNodeClass->GetDefaultObject()); + for (const UClass* AllowedClass : AssetClassDefaults->AllowedNodeClasses) + { + if (FlowNodeClass->IsChildOf(AllowedClass)) + { + FlowNodes.Emplace(FlowNodeClass->GetDefaultObject()); + } + } } for (const TPair& AssetData : BlueprintFlowNodes) { if (const UBlueprint* Blueprint = GetPlaceableNodeBlueprint(AssetData.Value)) { - FlowNodes.Emplace(Blueprint->GeneratedClass->GetDefaultObject()); + for (const UClass* AllowedClass : AssetClassDefaults->AllowedNodeClasses) + { + if (Blueprint->GeneratedClass->IsChildOf(AllowedClass)) + { + FlowNodes.Emplace(Blueprint->GeneratedClass->GetDefaultObject()); + } + } } } + FlowNodes.Shrink(); for (const UFlowNode* FlowNode : FlowNodes) { diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp index caebf7cf8..73a8d4f6a 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp @@ -7,6 +7,7 @@ #include "Nodes/FlowNode.h" #include "EditorStyleSet.h" +#include "FlowAsset.h" #include "Fonts/SlateFontInfo.h" #include "Styling/CoreStyle.h" #include "Styling/SlateBrush.h" @@ -180,8 +181,16 @@ TSharedRef SFlowPalette::OnCreateWidgetForAction(FCreateWidgetForAction void SFlowPalette::CollectAllActions(FGraphActionListBuilderBase& OutAllActions) { + UClass* AssetClass = UFlowAsset::StaticClass(); + + const TSharedPtr FlowAssetEditor = FlowAssetEditorPtr.Pin(); + if (FlowAssetEditor && FlowAssetEditor->GetFlowAsset()) + { + AssetClass = FlowAssetEditor->GetFlowAsset()->GetClass(); + } + FGraphActionMenuBuilder ActionMenuBuilder; - UFlowGraphSchema::GetPaletteActions(ActionMenuBuilder, GetFilterCategoryName()); + UFlowGraphSchema::GetPaletteActions(ActionMenuBuilder, AssetClass, GetFilterCategoryName()); OutAllActions.Append(ActionMenuBuilder); } @@ -204,7 +213,7 @@ void SFlowPalette::OnActionSelected(const TArray FlowAssetEditor = FlowAssetEditorPtr.Pin(); + const TSharedPtr FlowAssetEditor = FlowAssetEditorPtr.Pin(); if (FlowAssetEditor) { FlowAssetEditor->SetUISelectionState(FFlowAssetEditor::PaletteTab); diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h index 5b1a43eb7..2e75d61cc 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h @@ -19,7 +19,7 @@ class FLOWEDITOR_API UFlowGraphSchema : public UEdGraphSchema public: static void SubscribeToAssetChanges(); - static void GetPaletteActions(FGraphActionMenuBuilder& ActionMenuBuilder, const FString& CategoryName); + static void GetPaletteActions(FGraphActionMenuBuilder& ActionMenuBuilder, UClass* AssetClass, const FString& CategoryName); // EdGraphSchema virtual void GetGraphContextActions(FGraphContextMenuBuilder& ContextMenuBuilder) const override; @@ -38,7 +38,7 @@ class FLOWEDITOR_API UFlowGraphSchema : public UEdGraphSchema static UClass* GetAssignedGraphNodeClass(const UClass* FlowNodeClass); private: - static void GetFlowNodeActions(FGraphActionMenuBuilder& ActionMenuBuilder, const FString& CategoryName); + static void GetFlowNodeActions(FGraphActionMenuBuilder& ActionMenuBuilder, UClass* AssetClass, const FString& CategoryName); static void GetCommentAction(FGraphActionMenuBuilder& ActionMenuBuilder, const UEdGraph* CurrentGraph = nullptr); static bool IsFlowNodePlaceable(const UClass* Class); From 63cd32e2611f8020900abe1d55836b984fcb665b Mon Sep 17 00:00:00 2001 From: "Satheesh (ryanjon2040)" Date: Thu, 11 Nov 2021 19:58:51 +0530 Subject: [PATCH 050/338] #14: Double clicking on wire creates reroute node (PR #70) --- .../FlowEditor/Private/Graph/FlowGraphSchema.cpp | 16 ++++++++++++++++ Source/FlowEditor/Public/Graph/FlowGraphSchema.h | 1 + 2 files changed, 17 insertions(+) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp index 0bd6c9ca4..78eae00bf 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -10,6 +10,7 @@ #include "FlowAsset.h" #include "Nodes/FlowNode.h" #include "Nodes/Route/FlowNode_Start.h" +#include "Nodes/Route/FlowNode_Reroute.h" #include "AssetRegistryModule.h" #include "Developer/ToolMenus/Public/ToolMenus.h" @@ -177,6 +178,21 @@ TSharedPtr UFlowGraphSchema::GetCreateCommentAction() cons return TSharedPtr(static_cast(new FFlowGraphSchemaAction_NewComment)); } +void UFlowGraphSchema::OnPinConnectionDoubleCicked(UEdGraphPin* PinA, UEdGraphPin* PinB, const FVector2D& GraphPosition) const +{ + const FScopedTransaction Transaction(LOCTEXT("CreateFlowRerouteNodeOnWire", "Create Flow Reroute Node")); + + const FVector2D NodeSpacerSize(42.0f, 24.0f); + const FVector2D KnotTopLeft = GraphPosition - (NodeSpacerSize * 0.5f); + + UEdGraph* ParentGraph = PinA->GetOwningNode()->GetGraph(); + UFlowGraphNode* NewReroute = FFlowGraphSchemaAction_NewNode::CreateNode(ParentGraph, nullptr, UFlowNode_Reroute::StaticClass(), KnotTopLeft, false); + + PinA->BreakLinkTo(PinB); + PinA->MakeLinkTo((PinA->Direction == EGPD_Output) ? NewReroute->InputPins[0] : NewReroute->OutputPins[0]); + PinB->MakeLinkTo((PinB->Direction == EGPD_Output) ? NewReroute->InputPins[0] : NewReroute->OutputPins[0]); +} + TArray> UFlowGraphSchema::GetFlowNodeCategories() { if (NativeFlowNodes.Num() == 0) diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h index 2e75d61cc..a8205f351 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h @@ -32,6 +32,7 @@ class FLOWEDITOR_API UFlowGraphSchema : public UEdGraphSchema virtual void BreakPinLinks(UEdGraphPin& TargetPin, bool bSendsNodeNotification) const override; virtual int32 GetNodeSelectionCount(const UEdGraph* Graph) const override; virtual TSharedPtr GetCreateCommentAction() const override; + virtual void OnPinConnectionDoubleCicked(UEdGraphPin* PinA, UEdGraphPin* PinB, const FVector2D& GraphPosition) const override; // -- static TArray> GetFlowNodeCategories(); From c808530f04330381ebefec14f152ce65236bc19e Mon Sep 17 00:00:00 2001 From: Proboszcz777 Date: Wed, 17 Nov 2021 20:55:52 +0100 Subject: [PATCH 051/338] Update FlowAsset.cpp (#73) Prevention of auto checkout when instancing flow asset --- Source/Flow/Private/FlowAsset.cpp | 33 ++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 5bbbbb146..cfb824122 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -105,6 +105,7 @@ void UFlowAsset::UnregisterNode(const FGuid& NodeGuid) void UFlowAsset::HarvestNodeConnections() { TMap Connections; + bool bModified = false; // last moment to remove invalid nodes for (auto NodeIt = Nodes.CreateIterator(); NodeIt; ++NodeIt) @@ -113,6 +114,7 @@ void UFlowAsset::HarvestNodeConnections() if (Pair.Value == nullptr) { NodeIt.RemoveCurrent(); + bModified = true; } } @@ -120,6 +122,7 @@ void UFlowAsset::HarvestNodeConnections() { UFlowNode* Node = Pair.Value; Connections.Empty(); + TMap CurrentConnections = Node->Connections; for (const UEdGraphPin* ThisPin : Node->GetGraphNode()->Pins) { @@ -129,19 +132,39 @@ void UFlowAsset::HarvestNodeConnections() { const UEdGraphNode* LinkedNode = LinkedPin->GetOwningNode(); Connections.Add(ThisPin->PinName, FConnectedPin(LinkedNode->NodeGuid, LinkedPin->PinName)); + + // check if connection already exists + bool bFoundConnection = false; + for (TPair& KeyVal : CurrentConnections) + { + if (KeyVal.Value.NodeGuid == LinkedNode->NodeGuid && KeyVal.Value.PinName == LinkedPin->PinName) + { + bFoundConnection = true; + break; + } + } + + // if not - we will have to override connections and modify the asset + if (!bFoundConnection) + { + bModified = true; + } } } } + if (bModified) + { #if WITH_EDITOR - Node->SetFlags(RF_Transactional); - Node->Modify(); + Node->SetFlags(RF_Transactional); + Node->Modify(); #endif - Node->SetConnections(Connections); + Node->SetConnections(Connections); #if WITH_EDITOR - Node->PostEditChange(); -#endif + Node->PostEditChange(); +#endif + } } } From dbcea32897c95b966b53a51bf793da5d07eeba54 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sat, 27 Nov 2021 22:04:40 +0100 Subject: [PATCH 052/338] compilaton fixed against recent engine's code --- Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 2879fbc51..e8112ba8c 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -758,7 +758,7 @@ void UFlowGraphNode::RemoveOrphanedPin(UEdGraphPin* Pin) PinBreakpoints.Remove(Pin); - Pin->MarkPendingKill(); + Pin->MarkAsGarbage(); Pins.Remove(Pin); ReconstructNode(); @@ -833,7 +833,7 @@ void UFlowGraphNode::RemoveInstancePin(UEdGraphPin* Pin) InputPins.Remove(Pin); FlowNode->RemoveUserInput(); - Pin->MarkPendingKill(); + Pin->MarkAsGarbage(); Pins.Remove(Pin); } } @@ -844,7 +844,7 @@ void UFlowGraphNode::RemoveInstancePin(UEdGraphPin* Pin) OutputPins.Remove(Pin); FlowNode->RemoveUserOutput(); - Pin->MarkPendingKill(); + Pin->MarkAsGarbage(); Pins.Remove(Pin); } } From 9865f653429ae685b50f58bb0c4f1ef6d1d71887 Mon Sep 17 00:00:00 2001 From: Sergey Vikhirev Date: Mon, 29 Nov 2021 23:26:42 +0400 Subject: [PATCH 053/338] Make UFlowSubsystem::CreateRootFlow public (#76) --- Source/Flow/Public/FlowSubsystem.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index 7f6ba58d2..2e4038085 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -61,10 +61,8 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem UFUNCTION(BlueprintCallable, Category = "FlowSubsystem") void StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances = true); -protected: UFlowAsset* CreateRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances = true); -public: // Finish the root Flow, typically when closing world that created this flow UFUNCTION(BlueprintCallable, Category = "FlowSubsystem") void FinishRootFlow(UObject* Owner, const EFlowFinishPolicy FinishPolicy); From fbc7208c7cb43971b799b13302545d3275b122af Mon Sep 17 00:00:00 2001 From: Sergey Vikhirev Date: Mon, 29 Nov 2021 23:27:01 +0400 Subject: [PATCH 054/338] Clear previously selected nodes before new node creation (#77) --- Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index 37c07cb52..406df94b0 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -621,6 +621,7 @@ void FFlowAssetEditor::OnSelectedNodesChanged(const TSet& Nodes) void FFlowAssetEditor::SelectSingleNode(UEdGraphNode* Node) const { + FocusedGraphEditor->ClearSelectionSet(); FocusedGraphEditor->SetNodeSelection(Node, true); } From 296a84dff49409328d755d9a0c26189a60b73b80 Mon Sep 17 00:00:00 2001 From: Sergey Vikhirev Date: Mon, 29 Nov 2021 23:45:09 +0400 Subject: [PATCH 055/338] FlowNode_Timer's RemainingStepTime should be used only for first timer tick (#75) --- Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp index 06423bb1a..453e6f649 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp @@ -118,7 +118,7 @@ void UFlowNode_Timer::OnLoad_Implementation() { if (RemainingStepTime > 0.0f) { - GetWorld()->GetTimerManager().SetTimer(StepTimerHandle, this, &UFlowNode_Timer::OnStep, RemainingStepTime, true); + GetWorld()->GetTimerManager().SetTimer(StepTimerHandle, this, &UFlowNode_Timer::OnStep, StepTime, true, RemainingStepTime); } GetWorld()->GetTimerManager().SetTimer(CompletionTimerHandle, this, &UFlowNode_Timer::OnCompletion, RemainingCompletionTime, false); From b283d5356f5cec5309a7f7adc862d0effc2d1e6a Mon Sep 17 00:00:00 2001 From: Mahoukyou Date: Mon, 29 Nov 2021 20:52:46 +0100 Subject: [PATCH 056/338] Fix node not being registered with the asset after undoing it's deletion (#74) --- Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index 406df94b0..1a0290580 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -639,6 +639,7 @@ void FFlowAssetEditor::DeleteSelectedNodes() { const FScopedTransaction Transaction(LOCTEXT("DeleteSelectedNode", "Delete Selected Node")); FocusedGraphEditor->GetCurrentGraph()->Modify(); + FlowAsset->Modify(); const FGraphPanelSelectionSet SelectedNodes = FocusedGraphEditor->GetSelectedNodes(); SetUISelectionState(NAME_None); From 7ad4dd7c409a940c1d98d414f2bd95525c6a83e2 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 29 Nov 2021 21:09:57 +0100 Subject: [PATCH 057/338] Mark entire HarvestNodeConnections method as editor-only --- Source/Flow/Private/FlowAsset.cpp | 8 ++------ Source/Flow/Public/FlowAsset.h | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index cfb824122..84f28e81e 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -100,7 +100,6 @@ void UFlowAsset::UnregisterNode(const FGuid& NodeGuid) HarvestNodeConnections(); MarkPackageDirty(); } -#endif void UFlowAsset::HarvestNodeConnections() { @@ -155,18 +154,15 @@ void UFlowAsset::HarvestNodeConnections() if (bModified) { -#if WITH_EDITOR Node->SetFlags(RF_Transactional); Node->Modify(); -#endif + Node->SetConnections(Connections); - -#if WITH_EDITOR Node->PostEditChange(); -#endif } } } +#endif UFlowNode* UFlowAsset::GetNode(const FGuid& Guid) const { diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index f95668ab5..c61c03272 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -111,10 +111,10 @@ class FLOW_API UFlowAsset : public UObject void RegisterNode(const FGuid& NewGuid, UFlowNode* NewNode); void UnregisterNode(const FGuid& NodeGuid); -#endif // Processes all nodes and creates map of all pin connections void HarvestNodeConnections(); +#endif UFlowNode* GetNode(const FGuid& Guid) const; TMap GetNodes() const { return Nodes; } From d8dab6cf9d995f4deed4626aa4d72fd0959e8136 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 29 Nov 2021 21:14:15 +0100 Subject: [PATCH 058/338] documentation on EFlowFinishPolicy --- Source/Flow/Public/FlowSubsystem.h | 4 +++- Source/Flow/Public/FlowTypes.h | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index 2e4038085..4069e4c8a 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -63,7 +63,9 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem UFlowAsset* CreateRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances = true); - // Finish the root Flow, typically when closing world that created this flow + // Finish Policy value is read by Flow Node + // Nodes have opportunity to terminate themselves differently if Flow Graph has been aborted + // Example: Spawn node might despawn all actors if Flow Graph is aborted, not completed UFUNCTION(BlueprintCallable, Category = "FlowSubsystem") void FinishRootFlow(UObject* Owner, const EFlowFinishPolicy FinishPolicy); diff --git a/Source/Flow/Public/FlowTypes.h b/Source/Flow/Public/FlowTypes.h index 026cc6596..badf9d24e 100644 --- a/Source/Flow/Public/FlowTypes.h +++ b/Source/Flow/Public/FlowTypes.h @@ -27,6 +27,9 @@ enum class EFlowNodeState : uint8 Aborted }; +// Finish Policy value is read by Flow Node +// Nodes have opportunity to terminate themselves differently if Flow Graph has been aborted +// Example: Spawn node might despawn all actors if Flow Graph is aborted, not completed UENUM(BlueprintType) enum class EFlowFinishPolicy : uint8 { From 91ad7f875169ddc1d47720be76bae60249ecee48 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 29 Nov 2021 21:59:47 +0100 Subject: [PATCH 059/338] tweaked include order --- Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp index 73a8d4f6a..a03a8990e 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp @@ -4,10 +4,10 @@ #include "Graph/FlowGraphSchema.h" #include "Graph/FlowGraphSchema_Actions.h" +#include "FlowAsset.h" #include "Nodes/FlowNode.h" #include "EditorStyleSet.h" -#include "FlowAsset.h" #include "Fonts/SlateFontInfo.h" #include "Styling/CoreStyle.h" #include "Styling/SlateBrush.h" From c998f72edc347c2edebaaf5630fc522b1d7c9296 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Thu, 16 Dec 2021 19:52:05 +0100 Subject: [PATCH 060/338] Fixed and optimized check preventing dirtying Flow Asset on harvesting node connections --- Source/Flow/Private/FlowAsset.cpp | 45 ++++++++++++++++++----------- Source/Flow/Public/Nodes/FlowNode.h | 2 +- Source/Flow/Public/Nodes/FlowPin.h | 20 +++++++++++++ 3 files changed, 49 insertions(+), 18 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 84f28e81e..6ecb0d746 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -104,7 +104,7 @@ void UFlowAsset::UnregisterNode(const FGuid& NodeGuid) void UFlowAsset::HarvestNodeConnections() { TMap Connections; - bool bModified = false; + bool bGraphDirty = false; // last moment to remove invalid nodes for (auto NodeIt = Nodes.CreateIterator(); NodeIt; ++NodeIt) @@ -113,15 +113,14 @@ void UFlowAsset::HarvestNodeConnections() if (Pair.Value == nullptr) { NodeIt.RemoveCurrent(); - bModified = true; + bGraphDirty = true; } } for (const TPair& Pair : Nodes) { UFlowNode* Node = Pair.Value; - Connections.Empty(); - TMap CurrentConnections = Node->Connections; + TMap FoundConnections; for (const UEdGraphPin* ThisPin : Node->GetGraphNode()->Pins) { @@ -130,34 +129,46 @@ void UFlowAsset::HarvestNodeConnections() if (const UEdGraphPin* LinkedPin = ThisPin->LinkedTo[0]) { const UEdGraphNode* LinkedNode = LinkedPin->GetOwningNode(); - Connections.Add(ThisPin->PinName, FConnectedPin(LinkedNode->NodeGuid, LinkedPin->PinName)); + FoundConnections.Add(ThisPin->PinName, FConnectedPin(LinkedNode->NodeGuid, LinkedPin->PinName)); + } + } + } - // check if connection already exists - bool bFoundConnection = false; - for (TPair& KeyVal : CurrentConnections) + // This check exists to ensure that we don't mark graph dirty, if none of connections changed + // Optimization: we need check it only until the first node would be marked dirty, as this already marks Flow Asset package dirty + if (bGraphDirty == false) + { + if (FoundConnections.Num() != Node->Connections.Num()) + { + bGraphDirty = true; + } + else + { + for (const TPair& FoundConnection : FoundConnections) + { + if (const FConnectedPin* OldConnection = Node->Connections.Find(FoundConnection.Key)) { - if (KeyVal.Value.NodeGuid == LinkedNode->NodeGuid && KeyVal.Value.PinName == LinkedPin->PinName) + if (FoundConnection.Value != *OldConnection) { - bFoundConnection = true; + bGraphDirty = true; break; } } - - // if not - we will have to override connections and modify the asset - if (!bFoundConnection) + else { - bModified = true; + bGraphDirty = true; + break; } } } } - - if (bModified) + + if (bGraphDirty) { Node->SetFlags(RF_Transactional); Node->Modify(); - Node->SetConnections(Connections); + Node->SetConnections(FoundConnections); Node->PostEditChange(); } } diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index dc7ddabf9..6d28ae083 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -158,7 +158,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte TMap Connections; public: - void SetConnections(TMap& InConnections) { Connections = InConnections; } + void SetConnections(const TMap& InConnections) { Connections = InConnections; } FConnectedPin GetConnection(const FName OutputName) const { return Connections.FindRef(OutputName); } TSet GetConnectedNodes() const; diff --git a/Source/Flow/Public/Nodes/FlowPin.h b/Source/Flow/Public/Nodes/FlowPin.h index 116677f8f..d800334aa 100644 --- a/Source/Flow/Public/Nodes/FlowPin.h +++ b/Source/Flow/Public/Nodes/FlowPin.h @@ -96,6 +96,11 @@ struct FLOW_API FFlowPin { return PinName != Other; } + + friend uint32 GetTypeHash(const FFlowPin& FlowPin) + { + return GetTypeHash(FlowPin.PinName); + } }; // Processing Flow Nodes creates map of connected pins @@ -121,6 +126,21 @@ struct FLOW_API FConnectedPin , PinName(InPinName) { } + + FORCEINLINE bool operator==(const FConnectedPin& Other) const + { + return NodeGuid == Other.NodeGuid && PinName == Other.PinName; + } + + FORCEINLINE bool operator!=(const FConnectedPin& Other) const + { + return NodeGuid != Other.NodeGuid || PinName != Other.PinName; + } + + friend uint32 GetTypeHash(const FConnectedPin& ConnectedPin) + { + return GetTypeHash(ConnectedPin.NodeGuid) + GetTypeHash(ConnectedPin.PinName); + } }; // Every time pin is activated, we record it and display this data while user hovers mouse over pin From 0c7bab9355018b71a686b9002739c3026b7e28ff Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sat, 18 Dec 2021 15:20:11 +0100 Subject: [PATCH 061/338] Data Validation now checks if node class does exist --- Source/Flow/Private/FlowAsset.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 6ecb0d746..46e4518c9 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -55,11 +55,16 @@ void UFlowAsset::PostDuplicate(bool bDuplicateForPIE) EDataValidationResult UFlowAsset::IsDataValid(TArray& ValidationErrors) { - for (const TPair& NodePair : Nodes) + for (const TPair& Node : Nodes) { - const EDataValidationResult Result = NodePair.Value->IsDataValid(ValidationErrors); - if (Result == EDataValidationResult::Invalid) + if (Node.Value == nullptr || Node.Value->IsDataValid(ValidationErrors) == EDataValidationResult::Invalid) { + // refresh data if Node is missing, i.e. its class has been deleted + if (Node.Value == nullptr) + { + HarvestNodeConnections(); + } + return EDataValidationResult::Invalid; } } From 9d7df1350192386b106ae2ab4eff252c3af0c193 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sat, 18 Dec 2021 19:08:35 +0100 Subject: [PATCH 062/338] removed hacky loading all Flow Assets, unused only caused issues with functional tests --- .../Private/Graph/Nodes/FlowGraphNode.cpp | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index e8112ba8c..95eb8b57a 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -11,7 +11,6 @@ #include "FlowAsset.h" #include "Nodes/FlowNode.h" -#include "AssetRegistryModule.h" #include "Developer/ToolMenus/Public/ToolMenus.h" #include "EdGraph/EdGraphSchema.h" #include "EdGraphSchema_K2.h" @@ -20,7 +19,6 @@ #include "Framework/Commands/GenericCommands.h" #include "GraphEditorActions.h" #include "Kismet2/KismetEditorUtilities.h" -#include "Modules/ModuleManager.h" #include "ScopedTransaction.h" #include "SourceCodeNavigation.h" #include "Textures/SlateIcon.h" @@ -95,8 +93,6 @@ void FFlowBreakpoint::ToggleBreakpoint() } } -bool UFlowGraphNode::bFlowAssetsLoaded = false; - ////////////////////////////////////////////////////////////////////////// // Flow Graph Node @@ -139,24 +135,6 @@ void UFlowGraphNode::PostLoad() SubscribeToExternalChanges(); } - // todo: verify if we still need this workaround - // without this reconstructing UFlowNode_SubGraph pins wouldn't work well - if (bFlowAssetsLoaded == false) - { - TArray FlowAssets; - - const FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(AssetRegistryConstants::ModuleName); - AssetRegistryModule.Get().GetAssetsByClass(UFlowAsset::StaticClass()->GetFName(), FlowAssets, true); - - for (FAssetData const& Asset : FlowAssets) - { - const FString AssetPath = Asset.ObjectPath.ToString(); - StaticLoadObject(Asset.GetClass(), nullptr, *AssetPath); - } - - bFlowAssetsLoaded = true; - } - ReconstructNode(); } From 7094fb5ea8b45976f236f9a26d4aa8a9f48cd0d5 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sat, 18 Dec 2021 19:08:55 +0100 Subject: [PATCH 063/338] unused property removed --- Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h b/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h index 4702fa367..e017b972a 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h @@ -21,8 +21,6 @@ class FLOW_API UFlowNode_SubGraph : public UFlowNode UPROPERTY(EditAnywhere, Category = "Graph") TSoftObjectPtr Asset; - TWeakObjectPtr AssetInstance; - UPROPERTY(SaveGame) FString SavedAssetInstanceName; From 8d043b6a8dbe8256e508bf72e2d1203101dd2b10 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sat, 18 Dec 2021 19:09:24 +0100 Subject: [PATCH 064/338] added include + cleanup --- .../Private/LevelEditor/SLevelEditorFlow.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp b/Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp index 14b8d7b6e..671278137 100644 --- a/Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp +++ b/Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp @@ -3,6 +3,8 @@ #include "FlowComponent.h" #include "FlowWorldSettings.h" +#include "Graph/FlowGraphSettings.h" + #include "Editor.h" #include "PropertyCustomizationHelpers.h" @@ -21,8 +23,7 @@ void SLevelEditorFlow::OnMapOpened(const FString& Filename, bool bAsTemplate) void SLevelEditorFlow::CreateFlowWidget() { - UFlowComponent* FlowComponent = FindFlowComponent(); - if (FlowComponent && FlowComponent->RootFlow) + if (UFlowComponent* FlowComponent = FindFlowComponent(); FlowComponent && FlowComponent->RootFlow) { FlowPath = FName(*FlowComponent->RootFlow->GetPathName()); } @@ -50,8 +51,7 @@ void SLevelEditorFlow::OnFlowChanged(const FAssetData& NewAsset) { FlowPath = NewAsset.ObjectPath; - UFlowComponent* FlowComponent = FindFlowComponent(); - if (FlowComponent) + if (UFlowComponent* FlowComponent = FindFlowComponent()) { if (UObject* NewObject = NewAsset.GetAsset()) { @@ -74,12 +74,11 @@ FString SLevelEditorFlow::GetFlowPath() const UFlowComponent* SLevelEditorFlow::FindFlowComponent() const { - if (UWorld* World = GEditor->GetEditorWorldContext().World()) + if (const UWorld* World = GEditor->GetEditorWorldContext().World()) { if (const AWorldSettings* WorldSettings = World->GetWorldSettings()) { - UActorComponent* FoundComponent = WorldSettings->GetComponentByClass(UFlowComponent::StaticClass()); - if (FoundComponent) + if (UActorComponent* FoundComponent = WorldSettings->GetComponentByClass(UFlowComponent::StaticClass())) { return Cast(FoundComponent); } From d37787a777e6725b67ccb23a558c43f859f4a9f5 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sat, 18 Dec 2021 19:09:56 +0100 Subject: [PATCH 065/338] added unique Referencer Name --- Source/FlowEditor/Public/Asset/FlowAssetEditor.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h index df3657ea4..a2e9df3c1 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h @@ -49,6 +49,10 @@ class FFlowAssetEditor : public FAssetEditorToolkit, public FEditorUndoClient, p // FGCObject virtual void AddReferencedObjects(FReferenceCollector& Collector) override; + virtual FString GetReferencerName() const override + { + return TEXT("FFlowAssetEditor"); + } // -- // FEditorUndoClient From eb6233d7ac3baae025c0c0ffa35bdee5f716ad27 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 19 Dec 2021 14:03:27 +0100 Subject: [PATCH 066/338] SaveGame fix: restoring state Recorded Nodes and Active Nodes on load Based on BorMor report and fix --- Source/Flow/Private/FlowAsset.cpp | 21 +++++++++++++++++---- Source/Flow/Private/Nodes/FlowNode.cpp | 5 +++++ Source/Flow/Public/FlowAsset.h | 3 +++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 46e4518c9..956d19bd7 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -62,9 +62,9 @@ EDataValidationResult UFlowAsset::IsDataValid(TArray& ValidationErrors) // refresh data if Node is missing, i.e. its class has been deleted if (Node.Value == nullptr) { - HarvestNodeConnections(); + HarvestNodeConnections(); } - + return EDataValidationResult::Invalid; } } @@ -167,12 +167,12 @@ void UFlowAsset::HarvestNodeConnections() } } } - + if (bGraphDirty) { Node->SetFlags(RF_Transactional); Node->Modify(); - + Node->SetConnections(FoundConnections); Node->PostEditChange(); } @@ -507,6 +507,19 @@ void UFlowAsset::LoadInstance(const FFlowAssetSaveData& AssetRecord) OnLoad(); } +void UFlowAsset::OnActivationStateLoaded(UFlowNode* Node) +{ + if (Node->ActivationState != EFlowNodeState::NeverActivated) + { + RecordedNodes.Emplace(Node); + } + + if (Node->ActivationState == EFlowNodeState::Active) + { + ActiveNodes.Emplace(Node); + } +} + void UFlowAsset::OnSave_Implementation() { } diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 7b4bc38c0..7c5c112c3 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -596,6 +596,11 @@ void UFlowNode::LoadInstance(const FFlowNodeSaveData& NodeRecord) FFlowArchive Ar(MemoryReader); Serialize(Ar); + if (UFlowAsset* FlowAsset = GetFlowAsset()) + { + FlowAsset->OnActivationStateLoaded(this); + } + OnLoad(); } diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index c61c03272..5e068596c 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -256,6 +256,9 @@ class FLOW_API UFlowAsset : public UObject UFUNCTION(BlueprintCallable, Category = "Flow") void LoadInstance(const FFlowAssetSaveData& AssetRecord); +private: + void OnActivationStateLoaded(UFlowNode* Node); + protected: UFUNCTION(BlueprintNativeEvent, Category = "SaveGame") void OnSave(); From eb398d301b6494dd4803865d34e9b702d3f26e24 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 19 Dec 2021 14:11:55 +0100 Subject: [PATCH 067/338] fixed case where Root Flow wouldn't be properly finished and cleaned up bug reported and fixed by BorMor --- Source/Flow/Private/FlowAsset.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 956d19bd7..ea5880bf2 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -412,9 +412,16 @@ void UFlowAsset::FinishNode(UFlowNode* Node) ActiveNodes.Remove(Node); // if graph reached Finish and this asset instance was created by SubGraph node - if (Node->GetClass()->IsChildOf(UFlowNode_Finish::StaticClass()) && NodeOwningThisAssetInstance.IsValid()) + if (Node->GetClass()->IsChildOf(UFlowNode_Finish::StaticClass())) { - NodeOwningThisAssetInstance.Get()->TriggerFirstOutput(true); + if (NodeOwningThisAssetInstance.IsValid()) + { + NodeOwningThisAssetInstance.Get()->TriggerFirstOutput(true); + } + else + { + FinishFlow(EFlowFinishPolicy::Keep); + } } } } From 8b7df0fed959a11d0dd612c3e3ea0574ca5a4d46 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 21 Dec 2021 20:23:28 +0100 Subject: [PATCH 068/338] clear old bindings before binding again, which might happen while loading a SaveGame --- .../World/FlowNode_ComponentObserver.cpp | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp index c2554dedf..21c72bf4d 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp @@ -55,24 +55,32 @@ void UFlowNode_ComponentObserver::OnLoad_Implementation() void UFlowNode_ComponentObserver::StartObserving() { - for (const TWeakObjectPtr& FoundComponent : GetFlowSubsystem()->GetComponents(IdentityTags, EGameplayContainerMatchType::Any)) + if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) { - ObserveActor(FoundComponent->GetOwner(), FoundComponent); - } + for (const TWeakObjectPtr& FoundComponent : FlowSubsystem->GetComponents(IdentityTags, EGameplayContainerMatchType::Any)) + { + ObserveActor(FoundComponent->GetOwner(), FoundComponent); + } + + // clear old bindings before binding again, which might happen while loading a SaveGame + StopObserving(); - GetFlowSubsystem()->OnComponentRegistered.AddDynamic(this, &UFlowNode_ComponentObserver::OnComponentRegistered); - GetFlowSubsystem()->OnComponentTagAdded.AddDynamic(this, &UFlowNode_ComponentObserver::OnComponentTagAdded); - GetFlowSubsystem()->OnComponentTagRemoved.AddDynamic(this, &UFlowNode_ComponentObserver::OnComponentTagRemoved); - GetFlowSubsystem()->OnComponentUnregistered.AddDynamic(this, &UFlowNode_ComponentObserver::OnComponentUnregistered); + FlowSubsystem->OnComponentRegistered.AddDynamic(this, &UFlowNode_ComponentObserver::OnComponentRegistered); + FlowSubsystem->OnComponentTagAdded.AddDynamic(this, &UFlowNode_ComponentObserver::OnComponentTagAdded); + FlowSubsystem->OnComponentTagRemoved.AddDynamic(this, &UFlowNode_ComponentObserver::OnComponentTagRemoved); + FlowSubsystem->OnComponentUnregistered.AddDynamic(this, &UFlowNode_ComponentObserver::OnComponentUnregistered); + } } void UFlowNode_ComponentObserver::StopObserving() { - GetFlowSubsystem()->OnComponentRegistered.RemoveAll(this); - GetFlowSubsystem()->OnComponentUnregistered.RemoveAll(this); - - GetFlowSubsystem()->OnComponentTagAdded.RemoveAll(this); - GetFlowSubsystem()->OnComponentTagRemoved.RemoveAll(this); + if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) + { + FlowSubsystem->OnComponentRegistered.RemoveAll(this); + FlowSubsystem->OnComponentUnregistered.RemoveAll(this); + FlowSubsystem->OnComponentTagAdded.RemoveAll(this); + FlowSubsystem->OnComponentTagRemoved.RemoveAll(this); + } } void UFlowNode_ComponentObserver::OnComponentRegistered(UFlowComponent* Component) From 4e07528609ee46ef92f4ae307595ef0bc4b9f27b Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Thu, 23 Dec 2021 21:22:14 +0100 Subject: [PATCH 069/338] added nullchecks on Sequence Player fixes a rare crash occurring blueprint caused infinite loop before calling CreatePlayer method --- .../World/FlowNode_PlayLevelSequence.cpp | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp index cbf78117d..ae4c03899 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp @@ -115,7 +115,10 @@ void UFlowNode_PlayLevelSequence::CreatePlayer() { ALevelSequenceActor* SequenceActor; SequencePlayer = UFlowLevelSequencePlayer::CreateFlowLevelSequencePlayer(this, LoadedSequence, PlaybackSettings, CameraSettings, SequenceActor); - SequencePlayer->SetFlowEventReceiver(this); + if (SequencePlayer) + { + SequencePlayer->SetFlowEventReceiver(this); + } const FFrameRate FrameRate = LoadedSequence->GetMovieScene()->GetTickResolution(); const FFrameNumber PlaybackStartFrame = LoadedSequence->GetMovieScene()->GetPlaybackRange().GetLowerBoundValue(); @@ -133,12 +136,15 @@ void UFlowNode_PlayLevelSequence::ExecuteInput(const FName& PinName) { CreatePlayer(); - TriggerOutput(TEXT("PreStart")); + if (SequencePlayer) + { + TriggerOutput(TEXT("PreStart")); - SequencePlayer->OnFinished.AddDynamic(this, &UFlowNode_PlayLevelSequence::OnPlaybackFinished); - SequencePlayer->Play(); + SequencePlayer->OnFinished.AddDynamic(this, &UFlowNode_PlayLevelSequence::OnPlaybackFinished); + SequencePlayer->Play(); - TriggerOutput(TEXT("Started")); + TriggerOutput(TEXT("Started")); + } } TriggerFirstOutput(false); @@ -166,11 +172,15 @@ void UFlowNode_PlayLevelSequence::OnLoad_Implementation() if (GetFlowSubsystem()->GetWorld() && LoadedSequence) { CreatePlayer(); - SequencePlayer->OnFinished.AddDynamic(this, &UFlowNode_PlayLevelSequence::OnPlaybackFinished); - SequencePlayer->SetPlayRate(TimeDilation); - SequencePlayer->SetPlaybackPosition(FMovieSceneSequencePlaybackParams(ElapsedTime, EUpdatePositionMethod::Jump)); - SequencePlayer->Play(); + if (SequencePlayer) + { + SequencePlayer->OnFinished.AddDynamic(this, &UFlowNode_PlayLevelSequence::OnPlaybackFinished); + + SequencePlayer->SetPlayRate(TimeDilation); + SequencePlayer->SetPlaybackPosition(FMovieSceneSequencePlaybackParams(ElapsedTime, EUpdatePositionMethod::Jump)); + SequencePlayer->Play(); + } } } } From e618dbec887294a73a21acd5b622689534524dfc Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 16 Jan 2022 20:31:12 +0100 Subject: [PATCH 070/338] allow to customize Flow Asset Category Name --- Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp | 2 +- Source/FlowEditor/Private/FlowEditorModule.cpp | 4 ++-- Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp | 5 +++++ Source/FlowEditor/Public/Graph/FlowGraphSettings.h | 3 +++ 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index 1a0290580..ff1c86e96 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -32,7 +32,7 @@ #include "ToolMenus.h" #include "Widgets/Docking/SDockTab.h" -#define LOCTEXT_NAMESPACE "FlowEditor" +#define LOCTEXT_NAMESPACE "FlowAssetEditor" const FName FFlowAssetEditor::DetailsTab(TEXT("Details")); const FName FFlowAssetEditor::GraphTab(TEXT("Graph")); diff --git a/Source/FlowEditor/Private/FlowEditorModule.cpp b/Source/FlowEditor/Private/FlowEditorModule.cpp index 939f33f52..8dbd4188f 100644 --- a/Source/FlowEditor/Private/FlowEditorModule.cpp +++ b/Source/FlowEditor/Private/FlowEditorModule.cpp @@ -29,7 +29,7 @@ #include "LevelEditor.h" #include "Modules/ModuleManager.h" -#define LOCTEXT_NAMESPACE "FlowEditor" +#define LOCTEXT_NAMESPACE "FlowEditorModule" EAssetTypeCategories::Type FFlowEditorModule::FlowAssetCategory = static_cast(0); @@ -105,7 +105,7 @@ void FFlowEditorModule::ShutdownModule() void FFlowEditorModule::RegisterAssets() { IAssetTools& AssetTools = FModuleManager::LoadModuleChecked("AssetTools").Get(); - FlowAssetCategory = AssetTools.RegisterAdvancedAssetCategory(FName(TEXT("Flow")), LOCTEXT("FlowAssetCategory", "Flow")); + FlowAssetCategory = AssetTools.RegisterAdvancedAssetCategory(FName(TEXT("Flow")), UFlowGraphSettings::Get()->FlowAssetCategoryName); const TSharedRef FlowAssetActions = MakeShareable(new FAssetTypeActions_FlowAsset()); RegisteredAssetActions.Add(FlowAssetActions); diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp index db9091aa7..1aa4879bc 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp @@ -2,11 +2,14 @@ #include "FlowAsset.h" +#define LOCTEXT_NAMESPACE "FlowGraphSettings" + UFlowGraphSettings::UFlowGraphSettings(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) , bExposeFlowAssetCreation(true) , bExposeFlowNodeCreation(true) , bShowAssetToolbarAboveLevelEditor(true) + , FlowAssetCategoryName(LOCTEXT("FlowAssetCategory", "Flow")) , WorldAssetClass(UFlowAsset::StaticClass()) , bShowDefaultPinNames(false) , ExecPinColorModifier(0.75f, 0.75f, 0.75f, 1.0f) @@ -33,3 +36,5 @@ UFlowGraphSettings::UFlowGraphSettings(const FObjectInitializer& ObjectInitializ NodeTitleColors.Emplace(EFlowNodeStyle::Logic, FLinearColor(1.0f, 1.0f, 1.0f, 1.0f)); NodeTitleColors.Emplace(EFlowNodeStyle::SubGraph, FLinearColor(1.0f, 0.128f, 0.0f, 1.0f)); } + +#undef LOCTEXT_NAMESPACE diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h index 398736f4b..abda02ed0 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h @@ -30,6 +30,9 @@ class UFlowGraphSettings final : public UDeveloperSettings UPROPERTY(EditAnywhere, config, Category = "Default UI") bool bShowAssetToolbarAboveLevelEditor; + UPROPERTY(EditAnywhere, config, Category = "Default UI") + FText FlowAssetCategoryName; + /** Flow Asset class allowed to be assigned via Level Editor toolbar*/ UPROPERTY(EditAnywhere, config, Category = "Default UI", meta = (EditCondition = "bShowAssetToolbarAboveLevelEditor")) TSubclassOf WorldAssetClass; From bffcaf4ca2b010f2119e291205696f915fb08991 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 24 Jan 2022 11:56:16 +0100 Subject: [PATCH 071/338] bump version to 1.2 --- Flow.uplugin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.uplugin b/Flow.uplugin index 7b536820b..395c537f6 100644 --- a/Flow.uplugin +++ b/Flow.uplugin @@ -1,6 +1,6 @@ { "FileVersion" : 3, - "Version" : 1.0, + "Version" : 1.2, "FriendlyName" : "Flow", "Description" : "Design-agnostic node editor for scripting game’s flow.", "Category" : "Gameplay", From ca6ab814113630dd4bcf10f7333f6f6f55cd506c Mon Sep 17 00:00:00 2001 From: Luna Ryuko Zaremba Date: Thu, 27 Jan 2022 17:02:55 +0100 Subject: [PATCH 072/338] Make UFlowNodeBlueprint not final, so it can be subclassed (#87) --- Source/Flow/Public/Nodes/FlowNodeBlueprint.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Flow/Public/Nodes/FlowNodeBlueprint.h b/Source/Flow/Public/Nodes/FlowNodeBlueprint.h index 3a02a2675..51b58df2a 100644 --- a/Source/Flow/Public/Nodes/FlowNodeBlueprint.h +++ b/Source/Flow/Public/Nodes/FlowNodeBlueprint.h @@ -9,7 +9,7 @@ */ UCLASS(BlueprintType) -class FLOW_API UFlowNodeBlueprint final : public UBlueprint +class FLOW_API UFlowNodeBlueprint : public UBlueprint { GENERATED_UCLASS_BODY() From 0cd28092cd1e0aae445ef9f1c6c059e6c00a62dd Mon Sep 17 00:00:00 2001 From: Luna Ryuko Zaremba Date: Thu, 27 Jan 2022 17:02:55 +0100 Subject: [PATCH 073/338] Make UFlowNodeBlueprint not final, so it can be subclassed (#87) From eaf2f9903139ef006b08e0f7654d10f07d55ea1e Mon Sep 17 00:00:00 2001 From: Guy Lundvall <47373221+Drakynfly@users.noreply.github.com> Date: Fri, 28 Jan 2022 02:57:30 -0800 Subject: [PATCH 074/338] Fix minor typo (#88) --- Source/FlowEditor/Private/FlowEditorCommands.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/FlowEditor/Private/FlowEditorCommands.cpp b/Source/FlowEditor/Private/FlowEditorCommands.cpp index 87b4c06ec..307951420 100644 --- a/Source/FlowEditor/Private/FlowEditorCommands.cpp +++ b/Source/FlowEditor/Private/FlowEditorCommands.cpp @@ -42,7 +42,7 @@ void FFlowGraphCommands::RegisterCommands() UI_COMMAND(TogglePinBreakpoint, "Toggle Pin Breakpoint", "Toggles a breakpoint on the pin", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(FocusViewport, "Focus Viewport", "Focus viewport on actor assigned to the node", EUserInterfaceActionType::Button, FInputChord()); - UI_COMMAND(JumpToNodeDefinition, "Jump to Node Definition", "Jump tp the node definition", EUserInterfaceActionType::Button, FInputChord()); + UI_COMMAND(JumpToNodeDefinition, "Jump to Node Definition", "Jump to the node definition", EUserInterfaceActionType::Button, FInputChord()); } FFlowSpawnNodeCommands::FFlowSpawnNodeCommands() From cb90eafc36313240a4e932a42874933c3e61ab1d Mon Sep 17 00:00:00 2001 From: "Satheesh (ryanjon2040)" Date: Fri, 28 Jan 2022 16:36:08 +0530 Subject: [PATCH 075/338] Fix start node deletable (#71) --- Source/Flow/Private/Nodes/FlowNode.cpp | 1 + Source/Flow/Private/Nodes/Route/FlowNode_Start.cpp | 1 + Source/Flow/Public/Nodes/FlowNode.h | 3 +++ .../FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp | 10 ++++++++++ Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h | 3 ++- .../Public/Graph/Nodes/FlowGraphNode_Start.h | 2 -- 6 files changed, 17 insertions(+), 3 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 7c5c112c3..21317084c 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -32,6 +32,7 @@ UFlowNode::UFlowNode(const FObjectInitializer& ObjectInitializer) #if WITH_EDITOR Category = TEXT("Uncategorized"); NodeStyle = EFlowNodeStyle::Default; + bCanDelete = bCanDuplicate = true; #endif InputPins = {DefaultInputPin}; diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_Start.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_Start.cpp index 4334f0451..82d7d3024 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_Start.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_Start.cpp @@ -6,6 +6,7 @@ UFlowNode_Start::UFlowNode_Start(const FObjectInitializer& ObjectInitializer) #if WITH_EDITOR Category = TEXT("Route"); NodeStyle = EFlowNodeStyle::InOut; + bCanDelete = bCanDuplicate = false; #endif InputPins = {}; diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 6d28ae083..9725df440 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -44,6 +44,9 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UPROPERTY(EditDefaultsOnly, Category = "FlowNode") EFlowNodeStyle NodeStyle; + uint8 bCanDelete : 1; + uint8 bCanDuplicate : 1; + public: FFlowNodeEvent OnReconstructionRequested; #endif diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 95eb8b57a..0d91ad1dc 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -531,6 +531,16 @@ void UFlowGraphNode::GetNodeContextMenuActions(class UToolMenu* Menu, class UGra } } +bool UFlowGraphNode::CanUserDeleteNode() const +{ + return FlowNode ? FlowNode->bCanDelete : Super::CanUserDeleteNode(); +} + +bool UFlowGraphNode::CanDuplicateNode() const +{ + return FlowNode ? FlowNode->bCanDuplicate : Super::CanDuplicateNode(); +} + TSharedPtr UFlowGraphNode::CreateVisualWidget() { return SNew(SFlowGraphNode, this); diff --git a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h index 12d5537aa..9fcbe64f8 100644 --- a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h +++ b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h @@ -125,7 +125,8 @@ class FLOWEDITOR_API UFlowGraphNode : public UEdGraphNode // UEdGraphNode virtual void GetNodeContextMenuActions(class UToolMenu* Menu, class UGraphNodeContextMenuContext* Context) const override; - + virtual bool CanUserDeleteNode() const override; + virtual bool CanDuplicateNode() const override; virtual TSharedPtr CreateVisualWidget() override; virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override; virtual FLinearColor GetNodeTitleColor() const override; diff --git a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_Start.h b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_Start.h index 095f06406..6e7b4540f 100644 --- a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_Start.h +++ b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_Start.h @@ -10,7 +10,5 @@ class FLOWEDITOR_API UFlowGraphNode_Start : public UFlowGraphNode // UEdGraphNode virtual TSharedPtr CreateVisualWidget() override; - virtual bool CanUserDeleteNode() const override { return false; } - virtual bool CanDuplicateNode() const override { return false; } // -- }; From 0a270245c0452583676ccad4ab0430eb90d40bf3 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 28 Jan 2022 15:57:09 +0100 Subject: [PATCH 076/338] fixed refreshing SFlowAssetInstanceList --- Source/Flow/Private/FlowAsset.cpp | 6 +- Source/Flow/Public/FlowAsset.h | 8 +- .../Private/Asset/FlowAssetEditor.cpp | 1 - .../Private/Asset/FlowAssetToolbar.cpp | 85 ++++++++++++------- .../Public/Asset/FlowAssetToolbar.h | 13 +-- 5 files changed, 69 insertions(+), 44 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index ea5880bf2..06941843a 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -253,7 +253,7 @@ void UFlowAsset::SetInspectedInstance(const FName& NewInspectedInstanceName) } } - BroadcastRegenerateToolbars(); + BroadcastDebuggerRefresh(); } #endif @@ -324,11 +324,13 @@ void UFlowAsset::PreStartFlow() #if WITH_EDITOR if (TemplateAsset->ActiveInstances.Num() == 1) { + // this instance is the only active one, set it directly as Inspected Instance TemplateAsset->SetInspectedInstance(GetDisplayName()); } else { - TemplateAsset->BroadcastRegenerateToolbars(); + // request to refresh list to show newly created instance + TemplateAsset->BroadcastDebuggerRefresh(); } #endif } diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 5e068596c..ec57e165b 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -147,12 +147,12 @@ class FLOW_API UFlowAsset : public UObject void SetInspectedInstance(const FName& NewInspectedInstanceName); UFlowAsset* GetInspectedInstance() const { return InspectedInstance.IsValid() ? InspectedInstance.Get() : nullptr; } - DECLARE_EVENT(UFlowAsset, FRegenerateToolbarsEvent); - FRegenerateToolbarsEvent& OnRegenerateToolbars() { return RegenerateToolbarsEvent; } - FRegenerateToolbarsEvent RegenerateToolbarsEvent; + DECLARE_EVENT(UFlowAsset, FRefreshDebuggerEvent); + FRefreshDebuggerEvent& OnDebuggerRefresh() { return RefreshDebuggerEvent; } + FRefreshDebuggerEvent RefreshDebuggerEvent; private: - void BroadcastRegenerateToolbars() const { RegenerateToolbarsEvent.Broadcast(); } + void BroadcastDebuggerRefresh() const { RefreshDebuggerEvent.Broadcast(); } #endif ////////////////////////////////////////////////////////////////////////// diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index ff1c86e96..3b9174d4a 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -213,7 +213,6 @@ void FFlowAssetEditor::InitFlowAssetEditor(const EToolkitMode::Type Mode, const InitAssetEditor(Mode, InitToolkitHost, TEXT("FlowEditorApp"), StandaloneDefaultLayout, bCreateDefaultStandaloneMenu, bCreateDefaultToolbar, ObjectToEdit, false); RegenerateMenusAndToolbars(); - FlowAsset->OnRegenerateToolbars().AddSP(this, &FFlowAssetEditor::RegenerateMenusAndToolbars); } void FFlowAssetEditor::CreateToolbar() diff --git a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp index 505a71434..d50065c6e 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp @@ -21,16 +21,48 @@ FText SFlowAssetInstanceList::NoInstanceSelectedText = LOCTEXT("NoInstanceSelected", "No instance selected"); -void SFlowAssetInstanceList::Construct(const FArguments& InArgs, TWeakPtr InFlowAssetEditor) +void SFlowAssetInstanceList::Construct(const FArguments& InArgs, const TWeakObjectPtr InTemplateAsset) { - FlowAssetEditor = InFlowAssetEditor; + TemplateAsset = InTemplateAsset; + if (TemplateAsset.IsValid()) + { + TemplateAsset->OnDebuggerRefresh().AddSP(this, &SFlowAssetInstanceList::RefreshInstances); + RefreshInstances(); + } + + // create dropdown + SAssignNew(Dropdown, SComboBox>) + .OptionsSource(&InstanceNames) + .OnGenerateWidget(this, &SFlowAssetInstanceList::OnGenerateWidget) + .OnSelectionChanged(this, &SFlowAssetInstanceList::OnSelectionChanged) + .Visibility_Static(&FFlowAssetEditor::GetDebuggerVisibility) + [ + SNew(STextBlock) + .Text(this, &SFlowAssetInstanceList::GetSelectedInstanceName) + ]; + + ChildSlot + [ + Dropdown.ToSharedRef() + ]; +} + +SFlowAssetInstanceList::~SFlowAssetInstanceList() +{ + if (TemplateAsset.IsValid()) + { + TemplateAsset->OnDebuggerRefresh().RemoveAll(this); + } +} +void SFlowAssetInstanceList::RefreshInstances() +{ // collect instance names of this Flow Asset InstanceNames = {MakeShareable(new FName(*NoInstanceSelectedText.ToString()))}; - FlowAssetEditor.Pin()->GetFlowAsset()->GetInstanceDisplayNames(InstanceNames); + TemplateAsset->GetInstanceDisplayNames(InstanceNames); // select instance - if (const UFlowAsset* InspectedInstance = FlowAssetEditor.Pin()->GetFlowAsset()->GetInspectedInstance()) + if (const UFlowAsset* InspectedInstance = TemplateAsset->GetInspectedInstance()) { const FName& InspectedInstanceName = InspectedInstance->GetDisplayName(); for (const TSharedPtr& Instance : InstanceNames) @@ -47,22 +79,6 @@ void SFlowAssetInstanceList::Construct(const FArguments& InArgs, TWeakPtr>) - .OptionsSource(&InstanceNames) - .OnGenerateWidget(this, &SFlowAssetInstanceList::OnGenerateWidget) - .OnSelectionChanged(this, &SFlowAssetInstanceList::OnSelectionChanged) - .Visibility_Static(&FFlowAssetEditor::GetDebuggerVisibility) - [ - SNew(STextBlock) - .Text(this, &SFlowAssetInstanceList::GetSelectedInstanceName) - ]; - - ChildSlot - [ - Dropdown.ToSharedRef() - ]; } TSharedRef SFlowAssetInstanceList::OnGenerateWidget(const TSharedPtr Item) const @@ -72,12 +88,15 @@ TSharedRef SFlowAssetInstanceList::OnGenerateWidget(const TSharedPtr SelectedItem, const ESelectInfo::Type SelectionType) { - SelectedInstance = SelectedItem; - - if (FlowAssetEditor.IsValid() && FlowAssetEditor.Pin()->GetFlowAsset()) + if (SelectionType != ESelectInfo::Direct) { - const FName NewSelectedInstanceName = (SelectedInstance.IsValid() && *SelectedInstance != *InstanceNames[0]) ? *SelectedInstance : NAME_None; - FlowAssetEditor.Pin()->GetFlowAsset()->SetInspectedInstance(NewSelectedInstanceName); + SelectedInstance = SelectedItem; + + if (TemplateAsset.IsValid()) + { + const FName NewSelectedInstanceName = (SelectedInstance.IsValid() && *SelectedInstance != *InstanceNames[0]) ? *SelectedInstance : NAME_None; + TemplateAsset->SetInspectedInstance(NewSelectedInstanceName); + } } } @@ -89,9 +108,9 @@ FText SFlowAssetInstanceList::GetSelectedInstanceName() const ////////////////////////////////////////////////////////////////////////// // Flow Asset Breadcrumb -void SFlowAssetBreadcrumb::Construct(const FArguments& InArgs, TWeakPtr InFlowAssetEditor) +void SFlowAssetBreadcrumb::Construct(const FArguments& InArgs, const TWeakObjectPtr InTemplateAsset) { - FlowAssetEditor = InFlowAssetEditor; + TemplateAsset = InTemplateAsset; // create breadcrumb SAssignNew(BreadcrumbTrail, SBreadcrumbTrail) @@ -117,7 +136,7 @@ void SFlowAssetBreadcrumb::Construct(const FArguments& InArgs, TWeakPtrClearCrumbs(); - if (UFlowAsset* InspectedInstance = FlowAssetEditor.Pin()->GetFlowAsset()->GetInspectedInstance()) + if (UFlowAsset* InspectedInstance = TemplateAsset->GetInspectedInstance()) { TArray InstancesFromRoot = {InspectedInstance}; @@ -138,9 +157,9 @@ void SFlowAssetBreadcrumb::Construct(const FArguments& InArgs, TWeakPtrGetFlowAsset()->GetInspectedInstance()); + ensure(TemplateAsset->GetInspectedInstance()); - if (Item.InstanceName != FlowAssetEditor.Pin()->GetFlowAsset()->GetInspectedInstance()->GetDisplayName()) + if (Item.InstanceName != TemplateAsset->GetInspectedInstance()->GetDisplayName()) { GEditor->GetEditorSubsystem()->OpenEditorForAsset(Item.AssetPathName); } @@ -175,13 +194,15 @@ void FFlowAssetToolbar::BuildDebuggerToolbar(UToolMenu* ToolbarMenu) Section.InsertPosition = FToolMenuInsert("Asset", EToolMenuInsertType::After); FPlayWorldCommands::BuildToolbar(Section); + + TWeakObjectPtr TemplateAsset = FlowAssetEditor.Pin()->GetFlowAsset(); - AssetInstanceList = SNew(SFlowAssetInstanceList, FlowAssetEditor); + AssetInstanceList = SNew(SFlowAssetInstanceList, TemplateAsset); Section.AddEntry(FToolMenuEntry::InitWidget("AssetInstances", AssetInstanceList.ToSharedRef(), FText(), true)); Section.AddEntry(FToolMenuEntry::InitToolBarButton(FFlowToolbarCommands::Get().GoToMasterInstance)); - Breadcrumb = SNew(SFlowAssetBreadcrumb, FlowAssetEditor); + Breadcrumb = SNew(SFlowAssetBreadcrumb, TemplateAsset); Section.AddEntry(FToolMenuEntry::InitWidget("AssetBreadcrumb", Breadcrumb.ToSharedRef(), FText(), true)); } diff --git a/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h b/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h index 63811a2b7..212e00c55 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h @@ -16,14 +16,17 @@ class SFlowAssetInstanceList final : public SCompoundWidget SLATE_BEGIN_ARGS(SFlowAssetInstanceList) {} SLATE_END_ARGS() - void Construct(const FArguments& InArgs, TWeakPtr InFlowAssetEditor); + void Construct(const FArguments& InArgs, const TWeakObjectPtr InTemplateAsset); + virtual ~SFlowAssetInstanceList() override; private: + void RefreshInstances(); + TSharedRef OnGenerateWidget(TSharedPtr Item) const; void OnSelectionChanged(TSharedPtr SelectedItem, ESelectInfo::Type SelectionType); FText GetSelectedInstanceName() const; - TWeakPtr FlowAssetEditor; + TWeakObjectPtr TemplateAsset; TSharedPtr>> Dropdown; TArray> InstanceNames; @@ -57,16 +60,16 @@ struct FFlowBreadcrumb class SFlowAssetBreadcrumb final : public SCompoundWidget { public: - SLATE_BEGIN_ARGS(SFlowAssetInstanceList) {} + SLATE_BEGIN_ARGS(SFlowAssetInstanceList) {} SLATE_END_ARGS() - void Construct(const FArguments& InArgs, TWeakPtr InFlowAssetEditor); + void Construct(const FArguments& InArgs, const TWeakObjectPtr InTemplateAsset); private: void OnCrumbClicked(const FFlowBreadcrumb& Item) const; FText GetBreadcrumbText(const TWeakObjectPtr FlowInstance) const; - TWeakPtr FlowAssetEditor; + TWeakObjectPtr TemplateAsset; TSharedPtr> BreadcrumbTrail; }; From ca6b5355c13b068384a61fff20fb6143fdcd2d5c Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 28 Jan 2022 15:57:09 +0100 Subject: [PATCH 077/338] fixed refreshing SFlowAssetInstanceList From b0b473668831ccf60e561ab9e4d5d922180ff156 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 28 Jan 2022 16:01:07 +0100 Subject: [PATCH 078/338] Only create Flow Subsystem instance if there is no override implementation defined --- Source/Flow/Private/FlowSubsystem.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index 9a18dc264..fddb57506 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -19,13 +19,21 @@ UFlowSubsystem::UFlowSubsystem() bool UFlowSubsystem::ShouldCreateSubsystem(UObject* Outer) const { + // Only create an instance if there is no override implementation defined elsewhere + TArray ChildClasses; + GetDerivedClasses(GetClass(), ChildClasses, false); + if (ChildClasses.Num() > 0) + { + return false; + } + // in this case, we simply create subsystem for every instance of the game if (UFlowSettings::Get()->bCreateFlowSubsystemOnClients) { return true; } - return Outer->GetWorld()->GetNetMode() < NM_Client && Outer->GetWorld()->IsServer(); + return Outer->GetWorld()->GetNetMode() < NM_Client; } void UFlowSubsystem::Initialize(FSubsystemCollectionBase& Collection) From 18b064e500973324354f43b09ca4b4a676528eb9 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 28 Jan 2022 16:18:23 +0100 Subject: [PATCH 079/338] added include --- Source/Flow/Private/FlowSubsystem.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index fddb57506..5d4fceff5 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -11,6 +11,7 @@ #include "Engine/World.h" #include "Misc/FileHelper.h" #include "Misc/Paths.h" +#include "UObject/UObjectHash.h" UFlowSubsystem::UFlowSubsystem() : UGameInstanceSubsystem() From d836e91d31d82b990326e603bdfe3cf9eb778ec4 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 13 Feb 2022 19:35:59 +0100 Subject: [PATCH 080/338] #91 Visualize in graph that Flow Node class is marked as "Deprecated" --- Source/Flow/Private/Nodes/FlowNode.cpp | 4 +++- Source/Flow/Public/Nodes/FlowNode.h | 8 ++++++++ .../FlowEditor/Private/Graph/FlowGraphSchema.cpp | 12 +++++++++++- .../Private/Graph/Widgets/SFlowGraphNode.cpp | 15 +++++++++++++++ .../Public/Graph/Widgets/SFlowGraphNode.h | 1 + 5 files changed, 38 insertions(+), 2 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 21317084c..0ba91f701 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -25,6 +25,9 @@ UFlowNode::UFlowNode(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) #if WITH_EDITOR , GraphNode(nullptr) + , bCanDelete(true) + , bCanDuplicate(true) + , bNodeDeprecated(false) #endif , bPreloaded(false) , ActivationState(EFlowNodeState::NeverActivated) @@ -32,7 +35,6 @@ UFlowNode::UFlowNode(const FObjectInitializer& ObjectInitializer) #if WITH_EDITOR Category = TEXT("Uncategorized"); NodeStyle = EFlowNodeStyle::Default; - bCanDelete = bCanDuplicate = true; #endif InputPins = {DefaultInputPin}; diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 9725df440..7045e0a65 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -28,6 +28,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte friend class SFlowGraphNode; friend class UFlowAsset; friend class UFlowGraphNode; + friend class UFlowGraphSchema; ////////////////////////////////////////////////////////////////////////// // Node @@ -47,6 +48,13 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte uint8 bCanDelete : 1; uint8 bCanDuplicate : 1; + UPROPERTY(EditDefaultsOnly, Category = "FlowNode") + bool bNodeDeprecated; + + // If this node is deprecated, it might be replaced by another node + UPROPERTY(EditDefaultsOnly, Category = "FlowNode") + TSubclassOf ReplacedBy; + public: FFlowNodeEvent OnReconstructionRequested; #endif diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp index 78eae00bf..a30415338 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -306,7 +306,17 @@ void UFlowGraphSchema::GetCommentAction(FGraphActionMenuBuilder& ActionMenuBuild bool UFlowGraphSchema::IsFlowNodePlaceable(const UClass* Class) { - return !Class->HasAnyClassFlags(CLASS_Abstract) && !Class->HasAnyClassFlags(CLASS_NotPlaceable) && !Class->HasAnyClassFlags(CLASS_Deprecated); + if (Class->HasAnyClassFlags(CLASS_Abstract) || Class->HasAnyClassFlags(CLASS_NotPlaceable) || Class->HasAnyClassFlags(CLASS_Deprecated)) + { + return false; + } + + if (const UFlowNode* DefaultObject = Class->GetDefaultObject()) + { + return !DefaultObject->bNodeDeprecated; + } + + return true; } void UFlowGraphSchema::OnBlueprintPreCompile(UBlueprint* Blueprint) diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp index e93e0f034..cb6fa12e5 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp @@ -351,6 +351,21 @@ void SFlowGraphNode::UpdateGraphNode() CreateAdvancedViewArrow(InnerVerticalBox); } +void SFlowGraphNode::UpdateErrorInfo() +{ + if (const UFlowNode* FlowNode = FlowGraphNode->GetFlowNode()) + { + if (FlowNode->GetClass()->HasAnyClassFlags(CLASS_Deprecated) || FlowNode->bNodeDeprecated) + { + ErrorMsg = FlowNode->ReplacedBy ? FString::Printf(TEXT(" REPLACED BY: %s "), *FlowNode->ReplacedBy->GetName()) : FString(TEXT(" DEPRECATED! ")); + ErrorColor = FEditorStyle::GetColor("ErrorReporting.WarningBackgroundColor"); + return; + } + } + + SGraphNode::UpdateErrorInfo(); +} + TSharedRef SFlowGraphNode::CreateNodeContentArea() { return SNew(SBorder) diff --git a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h index acd271fe7..9a7a6194d 100644 --- a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h +++ b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h @@ -35,6 +35,7 @@ class SFlowGraphNode : public SGraphNode // SGraphNode virtual void UpdateGraphNode() override; + virtual void UpdateErrorInfo() override; virtual TSharedRef CreateNodeContentArea() override; virtual const FSlateBrush* GetNodeBodyBrush() const override; From 4cb9ec293e013da628ed5d7c620a4eee727aad3e Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 22 Feb 2022 16:23:07 +0100 Subject: [PATCH 081/338] do not call Start node on Sub Graph loaded from save --- Source/Flow/Private/FlowSubsystem.cpp | 14 +++++++++----- Source/Flow/Public/FlowSubsystem.h | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index 5d4fceff5..ed849f15a 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -101,14 +101,14 @@ void UFlowSubsystem::FinishRootFlow(UObject* Owner, const EFlowFinishPolicy Fini } } -UFlowAsset* UFlowSubsystem::CreateSubFlow(UFlowNode_SubGraph* SubGraphNode, const FString NewInstanceName, const bool bPreloading /* = false */) +UFlowAsset* UFlowSubsystem::CreateSubFlow(UFlowNode_SubGraph* SubGraphNode, const FString SavedInstanceName, const bool bPreloading /* = false */) { UFlowAsset* NewInstance = nullptr; if (!InstancedSubFlows.Contains(SubGraphNode)) { const TWeakObjectPtr Owner = SubGraphNode->GetFlowAsset() ? SubGraphNode->GetFlowAsset()->GetOwner() : nullptr; - NewInstance = CreateFlowInstance(Owner, SubGraphNode->Asset, NewInstanceName); + NewInstance = CreateFlowInstance(Owner, SubGraphNode->Asset, SavedInstanceName); InstancedSubFlows.Add(SubGraphNode, NewInstance); if (bPreloading) @@ -124,8 +124,12 @@ UFlowAsset* UFlowSubsystem::CreateSubFlow(UFlowNode_SubGraph* SubGraphNode, cons AssetInstance->NodeOwningThisAssetInstance = SubGraphNode; SubGraphNode->GetFlowAsset()->ActiveSubGraphs.Add(SubGraphNode, AssetInstance); - - AssetInstance->StartFlow(); + + // don't activate Start Node if we're loading Sub Graph from SaveGame + if (SavedInstanceName.IsEmpty()) + { + AssetInstance->StartFlow(); + } } return NewInstance; @@ -221,7 +225,7 @@ void UFlowSubsystem::OnGameSaved(UFlowSaveGame* SaveGame) TArray> ComponentsArray; FlowComponentRegistry.GenerateValueArray(ComponentsArray); const TSet> FlowComponents = TSet>(ComponentsArray); - for (TWeakObjectPtr FlowComponent : FlowComponents) + for (const TWeakObjectPtr FlowComponent : FlowComponents) { SaveGame->FlowComponents.Emplace(FlowComponent->SaveInstance()); } diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index 4069e4c8a..3966d5d4b 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -70,7 +70,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem void FinishRootFlow(UObject* Owner, const EFlowFinishPolicy FinishPolicy); private: - UFlowAsset* CreateSubFlow(UFlowNode_SubGraph* SubGraphNode, const FString NewInstanceName = FString(), const bool bPreloading = false); + UFlowAsset* CreateSubFlow(UFlowNode_SubGraph* SubGraphNode, const FString SavedInstanceName = FString(), const bool bPreloading = false); void RemoveSubFlow(UFlowNode_SubGraph* SubGraphNode, const EFlowFinishPolicy FinishPolicy); UFlowAsset* CreateFlowInstance(const TWeakObjectPtr Owner, TSoftObjectPtr FlowAsset, FString NewInstanceName = FString()); From 21ec316ae21752353c9d7ad4505b9aac2e5c6506 Mon Sep 17 00:00:00 2001 From: Guy Lundvall <47373221+Drakynfly@users.noreply.github.com> Date: Tue, 8 Mar 2022 03:59:13 -0800 Subject: [PATCH 082/338] fix localization collision caused by identical keys (#95) --- Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp index cb6fa12e5..e2f71f4eb 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp @@ -427,7 +427,7 @@ void SFlowGraphNode::CreateInputSideAddButton(TSharedPtr OutputBox { const TSharedRef AddPinButton = AddPinButtonContent( LOCTEXT("FlowNodeAddPinButton", "Add pin"), - LOCTEXT("FlowNodeAddPinButton_Tooltip", "Adds an input pin") + LOCTEXT("FlowNodeAddPinButton_InputTooltip", "Adds an input pin") ); FMargin AddPinPadding = Settings->GetInputPinPadding(); @@ -449,7 +449,7 @@ void SFlowGraphNode::CreateOutputSideAddButton(TSharedPtr OutputBo { const TSharedRef AddPinButton = AddPinButtonContent( LOCTEXT("FlowNodeAddPinButton", "Add pin"), - LOCTEXT("FlowNodeAddPinButton_Tooltip", "Adds an output pin") + LOCTEXT("FlowNodeAddPinButton_OutputTooltip", "Adds an output pin") ); FMargin AddPinPadding = Settings->GetOutputPinPadding(); From 5bf8dd6974e564d3d51c4e34de2aeb80766ffc84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Tue, 8 Mar 2022 13:04:00 +0100 Subject: [PATCH 083/338] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9b45dab38..d6f18b4d0 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ## Concept -Flow plug-in for Unreal Engine provides a graph editor tailored for scripting flow of events in virtual worlds. It's based on a decade of experience with designing and implementing narrative in video games. All we need here is simplicity. +Flow plug-in for Unreal Engine is a design-agnostic event node editor. It provides a graph editor tailored for scripting flow of events in virtual worlds. It's based on a decade of experience with designing and implementing narrative in video games. All we need here is simplicity. -It's a design-agnostic event node editor. +The aim of publishing it as open-source project is to let people tell great stories and construct immersive worlds easier. That allows us to enrich video game storytelling so we can inspire people and make our world a better place. ![Flow101](https://user-images.githubusercontent.com/5065057/103543817-6d924080-4e9f-11eb-87d9-15ab092c3875.png) From 1baf450e961913fcdc71a94d598818f5f7786087 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Thu, 10 Mar 2022 14:20:32 +0100 Subject: [PATCH 084/338] clear data, in case we received here reused SaveGame object --- Source/Flow/Private/FlowSubsystem.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index ed849f15a..523ab1e3e 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -205,6 +205,10 @@ UWorld* UFlowSubsystem::GetWorld() const void UFlowSubsystem::OnGameSaved(UFlowSaveGame* SaveGame) { + // clear data, in case we received here reused SaveGame object + SaveGame->FlowComponents.Empty(); + SaveGame->FlowInstances.Empty(); + // save graphs with nodes for (const TPair, UFlowAsset*>& Pair : RootInstances) { From be4e496fc5de105fa0eef46d48ccacac07981e8a Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 25 Mar 2022 17:02:57 +0100 Subject: [PATCH 085/338] SaveGame fix: don't remove saved data from other worlds while saving --- Source/Flow/Private/FlowAsset.cpp | 14 +++++-- Source/Flow/Private/FlowComponent.cpp | 2 + Source/Flow/Private/FlowSubsystem.cpp | 58 +++++++++++++++++++++------ Source/Flow/Public/FlowAsset.h | 8 +++- Source/Flow/Public/FlowSave.h | 3 ++ 5 files changed, 67 insertions(+), 18 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 06941843a..36eb2674b 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -461,13 +461,13 @@ UFlowAsset* UFlowAsset::GetMasterInstance() const FFlowAssetSaveData UFlowAsset::SaveInstance(TArray& SavedFlowInstances) { FFlowAssetSaveData AssetRecord; - - //FSoftObjectPtr FlowAsset; - //FArchiveUObject::SerializeSoftObjectPtr(AssetRecord.AssetClass, FlowAsset); + AssetRecord.WorldName = IsBoundToWorld() ? GetWorld()->GetName() : FString(); AssetRecord.InstanceName = GetName(); + // opportunity to collect data before serializing asset OnSave(); + // iterate SubGraphs for (const TPair& Node : Nodes) { if (Node.Value && Node.Value->ActivationState == EFlowNodeState::Active) @@ -489,11 +489,14 @@ FFlowAssetSaveData UFlowAsset::SaveInstance(TArray& SavedFlo } } + // serialize asset FMemoryWriter MemoryWriter(AssetRecord.AssetData, true); FFlowArchive Ar(MemoryWriter); Serialize(Ar); + // write archive to SaveGame SavedFlowInstances.Emplace(AssetRecord); + return AssetRecord; } @@ -536,3 +539,8 @@ void UFlowAsset::OnSave_Implementation() void UFlowAsset::OnLoad_Implementation() { } + +bool UFlowAsset::IsBoundToWorld_Implementation() +{ + return true; +} diff --git a/Source/Flow/Private/FlowComponent.cpp b/Source/Flow/Private/FlowComponent.cpp index f6bd5c881..1987ca06c 100644 --- a/Source/Flow/Private/FlowComponent.cpp +++ b/Source/Flow/Private/FlowComponent.cpp @@ -376,8 +376,10 @@ FFlowComponentSaveData UFlowComponent::SaveInstance() ComponentRecord.WorldName = GetWorld()->GetName(); ComponentRecord.ActorInstanceName = GetOwner()->GetName(); + // opportunity to collect data before serializing component OnSave(); + // serialize component FMemoryWriter MemoryWriter(ComponentRecord.ComponentData, true); FFlowArchive Ar(MemoryWriter); Serialize(Ar); diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index 523ab1e3e..d228e1ac2 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -205,11 +205,31 @@ UWorld* UFlowSubsystem::GetWorld() const void UFlowSubsystem::OnGameSaved(UFlowSaveGame* SaveGame) { - // clear data, in case we received here reused SaveGame object - SaveGame->FlowComponents.Empty(); - SaveGame->FlowInstances.Empty(); + // clear existing data, in case we received reused SaveGame instance + // we only remove data for the current world + global Flow Graph instances (i.e. not bound to any world if created by UGameInstanceSubsystem) + // we keep data bound to other worlds + if (GetWorld()) + { + const FString& WorldName = GetWorld()->GetName(); + + for (int32 i = SaveGame->FlowInstances.Num() - 1; i >= 0; i--) + { + if (SaveGame->FlowInstances[i].WorldName.IsEmpty() || SaveGame->FlowInstances[i].WorldName == WorldName) + { + SaveGame->FlowInstances.RemoveAt(i); + } + } + + for (int32 i = SaveGame->FlowComponents.Num() - 1; i >= 0; i--) + { + if (SaveGame->FlowComponents[i].WorldName.IsEmpty() || SaveGame->FlowComponents[i].WorldName == WorldName) + { + SaveGame->FlowComponents.RemoveAt(i); + } + } + } - // save graphs with nodes + // save Flow Graphs for (const TPair, UFlowAsset*>& Pair : RootInstances) { if (Pair.Key.IsValid() && Pair.Value) @@ -225,13 +245,20 @@ void UFlowSubsystem::OnGameSaved(UFlowSaveGame* SaveGame) } } - // save components - TArray> ComponentsArray; - FlowComponentRegistry.GenerateValueArray(ComponentsArray); - const TSet> FlowComponents = TSet>(ComponentsArray); - for (const TWeakObjectPtr FlowComponent : FlowComponents) + // save Flow Components { - SaveGame->FlowComponents.Emplace(FlowComponent->SaveInstance()); + // retrieve all registered components + TArray> ComponentsArray; + FlowComponentRegistry.GenerateValueArray(ComponentsArray); + + // ensure uniqueness of entries + const TSet> RegisteredComponents = TSet>(ComponentsArray); + + // write archives to SaveGame + for (const TWeakObjectPtr RegisteredComponent : RegisteredComponents) + { + SaveGame->FlowComponents.Emplace(RegisteredComponent->SaveInstance()); + } } } @@ -242,14 +269,14 @@ void UFlowSubsystem::OnGameLoaded(UFlowSaveGame* SaveGame) void UFlowSubsystem::LoadRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const FString& SavedAssetInstanceName) { - if (SavedAssetInstanceName.IsEmpty()) + if (FlowAsset == nullptr || SavedAssetInstanceName.IsEmpty()) { return; } for (const FFlowAssetSaveData& AssetRecord : LoadedSaveGame->FlowInstances) { - if (AssetRecord.InstanceName == SavedAssetInstanceName) + if ((FlowAsset->IsBoundToWorld() == false || AssetRecord.WorldName == GetWorld()->GetName()) && AssetRecord.InstanceName == SavedAssetInstanceName) { UFlowAsset* LoadedInstance = CreateRootFlow(Owner, FlowAsset, false); if (LoadedInstance) @@ -263,9 +290,14 @@ void UFlowSubsystem::LoadRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const F void UFlowSubsystem::LoadSubFlow(UFlowNode_SubGraph* SubGraphNode, const FString& SavedAssetInstanceName) { + if (SubGraphNode->Asset.IsNull()) + { + return; + } + for (const FFlowAssetSaveData& AssetRecord : LoadedSaveGame->FlowInstances) { - if (AssetRecord.InstanceName == SavedAssetInstanceName) + if ((SubGraphNode->Asset->IsBoundToWorld() == false || AssetRecord.WorldName == GetWorld()->GetName()) && AssetRecord.InstanceName == SavedAssetInstanceName) { UFlowAsset* LoadedInstance = CreateSubFlow(SubGraphNode, SavedAssetInstanceName); if (LoadedInstance) diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index ec57e165b..896ab444c 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -250,10 +250,10 @@ class FLOW_API UFlowAsset : public UObject ////////////////////////////////////////////////////////////////////////// // SaveGame - UFUNCTION(BlueprintCallable, Category = "Flow") + UFUNCTION(BlueprintCallable, Category = "SaveGame") FFlowAssetSaveData SaveInstance(TArray& SavedFlowInstances); - UFUNCTION(BlueprintCallable, Category = "Flow") + UFUNCTION(BlueprintCallable, Category = "SaveGame") void LoadInstance(const FFlowAssetSaveData& AssetRecord); private: @@ -265,4 +265,8 @@ class FLOW_API UFlowAsset : public UObject UFUNCTION(BlueprintNativeEvent, Category = "SaveGame") void OnLoad(); + +public: + UFUNCTION(BlueprintNativeEvent, Category = "SaveGame") + bool IsBoundToWorld(); }; diff --git a/Source/Flow/Public/FlowSave.h b/Source/Flow/Public/FlowSave.h index 7c98ab50b..377d4e2cd 100644 --- a/Source/Flow/Public/FlowSave.h +++ b/Source/Flow/Public/FlowSave.h @@ -28,6 +28,9 @@ struct FLOW_API FFlowAssetSaveData { GENERATED_USTRUCT_BODY() + UPROPERTY(SaveGame, VisibleAnywhere, Category = "Flow") + FString WorldName; + UPROPERTY(SaveGame, VisibleAnywhere, Category = "Flow") FString InstanceName; From 68726c87238f425d0d52a4a2e252e1885e41492f Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 25 Mar 2022 17:28:58 +0100 Subject: [PATCH 086/338] CIS fix --- Source/Flow/Private/FlowAsset.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 36eb2674b..cd6e4413e 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -8,6 +8,7 @@ #include "Nodes/Route/FlowNode_Finish.h" #include "Nodes/Route/FlowNode_SubGraph.h" +#include "Engine/World.h" #include "Serialization/MemoryReader.h" #include "Serialization/MemoryWriter.h" From f915b7dc99c2bcc4931b16e4da65a35878c30c64 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 25 Mar 2022 19:10:01 +0100 Subject: [PATCH 087/338] crash fix --- Source/Flow/Private/FlowSubsystem.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index d228e1ac2..50a037963 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -276,7 +276,8 @@ void UFlowSubsystem::LoadRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const F for (const FFlowAssetSaveData& AssetRecord : LoadedSaveGame->FlowInstances) { - if ((FlowAsset->IsBoundToWorld() == false || AssetRecord.WorldName == GetWorld()->GetName()) && AssetRecord.InstanceName == SavedAssetInstanceName) + if (AssetRecord.InstanceName == SavedAssetInstanceName + && (FlowAsset->IsBoundToWorld() == false || AssetRecord.WorldName == GetWorld()->GetName())) { UFlowAsset* LoadedInstance = CreateRootFlow(Owner, FlowAsset, false); if (LoadedInstance) @@ -294,10 +295,17 @@ void UFlowSubsystem::LoadSubFlow(UFlowNode_SubGraph* SubGraphNode, const FString { return; } - + + if (SubGraphNode->Asset.IsPending()) + { + const FSoftObjectPath& AssetRef = SubGraphNode->Asset.ToSoftObjectPath(); + Streamable.LoadSynchronous(AssetRef, false); + } + for (const FFlowAssetSaveData& AssetRecord : LoadedSaveGame->FlowInstances) { - if ((SubGraphNode->Asset->IsBoundToWorld() == false || AssetRecord.WorldName == GetWorld()->GetName()) && AssetRecord.InstanceName == SavedAssetInstanceName) + if (AssetRecord.InstanceName == SavedAssetInstanceName + && ((SubGraphNode->Asset && SubGraphNode->Asset->IsBoundToWorld() == false) || AssetRecord.WorldName == GetWorld()->GetName())) { UFlowAsset* LoadedInstance = CreateSubFlow(SubGraphNode, SavedAssetInstanceName); if (LoadedInstance) From fc661a2835fbe538389b808d0d8c4ffdfc12b9f1 Mon Sep 17 00:00:00 2001 From: Markus Ahrweiler Date: Wed, 30 Mar 2022 18:58:44 +0200 Subject: [PATCH 088/338] Added DeniedClasses as option to blacklist FlowNodes (#92) --- Source/Flow/Public/FlowAsset.h | 1 + .../Private/Graph/FlowGraphSchema.cpp | 31 ++++++++++++++----- .../FlowEditor/Public/Graph/FlowGraphSchema.h | 2 ++ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 896ab444c..9d64020aa 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -84,6 +84,7 @@ class FLOW_API UFlowAsset : public UObject protected: TArray> AllowedNodeClasses; + TArray> DeniedNodeClasses; private: UPROPERTY() diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp index a30415338..cd68b5bc3 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -184,10 +184,10 @@ void UFlowGraphSchema::OnPinConnectionDoubleCicked(UEdGraphPin* PinA, UEdGraphPi const FVector2D NodeSpacerSize(42.0f, 24.0f); const FVector2D KnotTopLeft = GraphPosition - (NodeSpacerSize * 0.5f); - + UEdGraph* ParentGraph = PinA->GetOwningNode()->GetGraph(); UFlowGraphNode* NewReroute = FFlowGraphSchemaAction_NewNode::CreateNode(ParentGraph, nullptr, UFlowNode_Reroute::StaticClass(), KnotTopLeft, false); - + PinA->BreakLinkTo(PinB); PinA->MakeLinkTo((PinA->Direction == EGPD_Output) ? NewReroute->InputPins[0] : NewReroute->OutputPins[0]); PinB->MakeLinkTo((PinB->Direction == EGPD_Output) ? NewReroute->InputPins[0] : NewReroute->OutputPins[0]); @@ -243,6 +243,19 @@ UClass* UFlowGraphSchema::GetAssignedGraphNodeClass(const UClass* FlowNodeClass) return UFlowGraphNode::StaticClass(); } +bool UFlowGraphSchema::IsClassContained(const TArray> Classes, const UClass* Class) +{ + for (const UClass* CurrentClass : Classes) + { + if (Class->IsChildOf(CurrentClass)) + { + return true; + } + } + + return false; +} + void UFlowGraphSchema::GetFlowNodeActions(FGraphActionMenuBuilder& ActionMenuBuilder, UClass* AssetClass, const FString& CategoryName) { if (NativeFlowNodes.Num() == 0) @@ -258,12 +271,14 @@ void UFlowGraphSchema::GetFlowNodeActions(FGraphActionMenuBuilder& ActionMenuBui for (const UClass* FlowNodeClass : NativeFlowNodes) { - for (const UClass* AllowedClass : AssetClassDefaults->AllowedNodeClasses) + if (IsClassContained(AssetClassDefaults->DeniedNodeClasses, FlowNodeClass)) { - if (FlowNodeClass->IsChildOf(AllowedClass)) - { - FlowNodes.Emplace(FlowNodeClass->GetDefaultObject()); - } + continue; + } + + if (IsClassContained(AssetClassDefaults->AllowedNodeClasses, FlowNodeClass)) + { + FlowNodes.Emplace(FlowNodeClass->GetDefaultObject()); } } for (const TPair& AssetData : BlueprintFlowNodes) @@ -316,7 +331,7 @@ bool UFlowGraphSchema::IsFlowNodePlaceable(const UClass* Class) return !DefaultObject->bNodeDeprecated; } - return true; + return true; } void UFlowGraphSchema::OnBlueprintPreCompile(UBlueprint* Blueprint) diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h index a8205f351..4e11deca1 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h @@ -39,6 +39,8 @@ class FLOWEDITOR_API UFlowGraphSchema : public UEdGraphSchema static UClass* GetAssignedGraphNodeClass(const UClass* FlowNodeClass); private: + + static bool IsClassContained(const TArray> Classes, const UClass* Class); static void GetFlowNodeActions(FGraphActionMenuBuilder& ActionMenuBuilder, UClass* AssetClass, const FString& CategoryName); static void GetCommentAction(FGraphActionMenuBuilder& ActionMenuBuilder, const UEdGraph* CurrentGraph = nullptr); From 6398cf3ae91aaa2287ad5a7f9bf64966ee89b5ff Mon Sep 17 00:00:00 2001 From: Erdem Acar <50913011+kathelon@users.noreply.github.com> Date: Wed, 30 Mar 2022 20:04:46 +0300 Subject: [PATCH 089/338] Added timer restart pin. (#94) --- .../Private/Nodes/Route/FlowNode_Timer.cpp | 67 +++++++++++++------ .../Flow/Public/Nodes/Route/FlowNode_Timer.h | 4 +- 2 files changed, 48 insertions(+), 23 deletions(-) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp index 453e6f649..1081427c6 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp @@ -5,11 +5,11 @@ UFlowNode_Timer::UFlowNode_Timer(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) - , CompletionTime(1.0f) - , StepTime(0.0f) - , SumOfSteps(0.0f) - , RemainingCompletionTime(0.0f) - , RemainingStepTime(0.0f) + , CompletionTime(1.0f) + , StepTime(0.0f) + , SumOfSteps(0.0f) + , RemainingCompletionTime(0.0f) + , RemainingStepTime(0.0f) { #if WITH_EDITOR Category = TEXT("Route"); @@ -17,6 +17,7 @@ UFlowNode_Timer::UFlowNode_Timer(const FObjectInitializer& ObjectInitializer) #endif InputPins.Add(FFlowPin(TEXT("Skip"))); + InputPins.Add(FFlowPin(TEXT("Restart"))); OutputPins.Empty(); OutputPins.Add(FFlowPin(TEXT("Completed"))); @@ -41,27 +42,45 @@ void UFlowNode_Timer::ExecuteInput(const FName& PinName) return; } - if (GetWorld()) - { - if (StepTime > 0.0f) - { - GetWorld()->GetTimerManager().SetTimer(StepTimerHandle, this, &UFlowNode_Timer::OnStep, StepTime, true); - } + SetTimer(); + } + else if (PinName == TEXT("Skip")) + { + TriggerOutput(TEXT("Skipped"), true); + } + else if (PinName == TEXT("Restart")) + { + Restart(); + } +} - GetWorld()->GetTimerManager().SetTimer(CompletionTimerHandle, this, &UFlowNode_Timer::OnCompletion, CompletionTime, false); - } - else +void UFlowNode_Timer::SetTimer() +{ + if (GetWorld()) + { + if (StepTime > 0.0f) { - LogError("No valid world"); - TriggerOutput(TEXT("Completed"), true); + GetWorld()->GetTimerManager().SetTimer(StepTimerHandle, this, &UFlowNode_Timer::OnStep, StepTime, true); } + + GetWorld()->GetTimerManager().SetTimer(CompletionTimerHandle, this, &UFlowNode_Timer::OnCompletion, + CompletionTime, false); } - else if (PinName == TEXT("Skip")) + else { - TriggerOutput(TEXT("Skipped"), true); + LogError("No valid world"); + TriggerOutput(TEXT("Completed"), true); } } +void UFlowNode_Timer::Restart() +{ + SumOfSteps = 0.0f; + RemainingStepTime = 0.0f; + RemainingCompletionTime = 0.0f; + SetTimer(); +} + void UFlowNode_Timer::OnStep() { SumOfSteps += StepTime; @@ -118,10 +137,12 @@ void UFlowNode_Timer::OnLoad_Implementation() { if (RemainingStepTime > 0.0f) { - GetWorld()->GetTimerManager().SetTimer(StepTimerHandle, this, &UFlowNode_Timer::OnStep, StepTime, true, RemainingStepTime); + GetWorld()->GetTimerManager().SetTimer(StepTimerHandle, this, &UFlowNode_Timer::OnStep, StepTime, true, + RemainingStepTime); } - GetWorld()->GetTimerManager().SetTimer(CompletionTimerHandle, this, &UFlowNode_Timer::OnCompletion, RemainingCompletionTime, false); + GetWorld()->GetTimerManager().SetTimer(CompletionTimerHandle, this, &UFlowNode_Timer::OnCompletion, + RemainingCompletionTime, false); RemainingStepTime = 0.0f; RemainingCompletionTime = 0.0f; @@ -134,7 +155,8 @@ FString UFlowNode_Timer::GetNodeDescription() const { if (StepTime > 0.0f) { - return FString::SanitizeFloat(CompletionTime, 2).Append(TEXT(", step by ")).Append(FString::SanitizeFloat(StepTime, 2)); + return FString::SanitizeFloat(CompletionTime, 2).Append(TEXT(", step by ")).Append( + FString::SanitizeFloat(StepTime, 2)); } return FString::SanitizeFloat(CompletionTime, 2); @@ -152,7 +174,8 @@ FString UFlowNode_Timer::GetStatusString() const if (CompletionTimerHandle.IsValid() && GetWorld()) { - return TEXT("Progress: ") + GetProgressAsString(GetWorld()->GetTimerManager().GetTimerElapsed(CompletionTimerHandle)); + return TEXT("Progress: ") + GetProgressAsString( + GetWorld()->GetTimerManager().GetTimerElapsed(CompletionTimerHandle)); } return FString(); diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h b/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h index 57d4ac057..b76182fed 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h @@ -35,7 +35,9 @@ class FLOW_API UFlowNode_Timer : public UFlowNode protected: virtual void ExecuteInput(const FName& PinName) override; - + virtual void SetTimer(); + virtual void Restart(); + private: UFUNCTION() void OnStep(); From f2f5328f1be15a15cef164aa379f5d790d1aeb51 Mon Sep 17 00:00:00 2001 From: Joseph Date: Thu, 31 Mar 2022 02:13:17 +0900 Subject: [PATCH 090/338] Added a custom dilation from the parent actor (#90) while playing the level sequence. --- .../World/FlowNode_PlayLevelSequence.cpp | 29 +++++++++++++++++-- .../Nodes/World/FlowNode_PlayLevelSequence.h | 3 ++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp index ae4c03899..4c1f52b9c 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp @@ -1,5 +1,6 @@ #include "Nodes/World/FlowNode_PlayLevelSequence.h" +#include "FlowAsset.h" #include "FlowModule.h" #include "FlowSubsystem.h" #include "LevelSequence/FlowLevelSequencePlayer.h" @@ -34,6 +35,10 @@ UFlowNode_PlayLevelSequence::UFlowNode_PlayLevelSequence(const FObjectInitialize OutputPins.Add(FFlowPin(TEXT("Started"))); OutputPins.Add(FFlowPin(TEXT("Completed"))); OutputPins.Add(FFlowPin(TEXT("Stopped"))); + + // Initialize the original time dilation. + OriginalTimeDilation = PlaybackSettings.PlayRate; + } #if WITH_EDITOR @@ -114,6 +119,24 @@ void UFlowNode_PlayLevelSequence::CreatePlayer() if (LoadedSequence) { ALevelSequenceActor* SequenceActor; + + // This block is for setting the custom time dilation from the parent actor. + if(GetFlowAsset()) + { + if(GetFlowAsset()->GetOwner()) + { + const UFlowComponent* OwnerComp = Cast(GetFlowAsset()->GetOwner()); + if(OwnerComp) + { + if(IsValid(OwnerComp->GetOwner())) + { + PlaybackSettings.PlayRate = OriginalTimeDilation * OwnerComp->GetOwner()->CustomTimeDilation; + } + } + } + } + // End of custom time dilation block. + SequencePlayer = UFlowLevelSequencePlayer::CreateFlowLevelSequencePlayer(this, LoadedSequence, PlaybackSettings, CameraSettings, SequenceActor); if (SequencePlayer) { @@ -177,7 +200,8 @@ void UFlowNode_PlayLevelSequence::OnLoad_Implementation() { SequencePlayer->OnFinished.AddDynamic(this, &UFlowNode_PlayLevelSequence::OnPlaybackFinished); - SequencePlayer->SetPlayRate(TimeDilation); + // Added the multiplier if you set the playrate in playback settings. + SequencePlayer->SetPlayRate(TimeDilation * OriginalTimeDilation); SequencePlayer->SetPlaybackPosition(FMovieSceneSequencePlaybackParams(ElapsedTime, EUpdatePositionMethod::Jump)); SequencePlayer->Play(); } @@ -195,7 +219,8 @@ void UFlowNode_PlayLevelSequence::OnTimeDilationUpdate(const float NewTimeDilati if (SequencePlayer) { TimeDilation = NewTimeDilation; - SequencePlayer->SetPlayRate(NewTimeDilation); + // Added the multiplier if you set the playrate in playback settings. + SequencePlayer->SetPlayRate(NewTimeDilation * OriginalTimeDilation); } } diff --git a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h index 2db121ef0..64c3595a5 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h @@ -43,6 +43,9 @@ class FLOW_API UFlowNode_PlayLevelSequence : public UFlowNode UPROPERTY() UFlowLevelSequencePlayer* SequencePlayer; + UPROPERTY() + float OriginalTimeDilation; // It is for the default play rate getting from the playback settings. + UPROPERTY(SaveGame) float StartTime; From acd42603a4572902702c7bdfc28f28050cf2c435 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Wed, 30 Mar 2022 19:49:32 +0200 Subject: [PATCH 091/338] polishing up last PRs --- .../Private/Nodes/Route/FlowNode_Timer.cpp | 13 +++--- .../World/FlowNode_PlayLevelSequence.cpp | 45 ++++++++++++------- .../Flow/Public/Nodes/Route/FlowNode_Timer.h | 1 + .../Nodes/World/FlowNode_PlayLevelSequence.h | 10 ++++- .../FlowEditor/Public/Graph/FlowGraphSchema.h | 1 - 5 files changed, 45 insertions(+), 25 deletions(-) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp index 1081427c6..66607ec12 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp @@ -29,7 +29,7 @@ void UFlowNode_Timer::ExecuteInput(const FName& PinName) { if (CompletionTime == 0.0f) { - LogError("Invalid Timer settings"); + LogError(TEXT("Invalid Timer settings")); TriggerOutput(TEXT("Completed"), true); return; } @@ -38,7 +38,7 @@ void UFlowNode_Timer::ExecuteInput(const FName& PinName) { if (CompletionTimerHandle.IsValid() || StepTimerHandle.IsValid()) { - LogError("Timer already active"); + LogError(TEXT("Timer already active")); return; } @@ -63,21 +63,22 @@ void UFlowNode_Timer::SetTimer() GetWorld()->GetTimerManager().SetTimer(StepTimerHandle, this, &UFlowNode_Timer::OnStep, StepTime, true); } - GetWorld()->GetTimerManager().SetTimer(CompletionTimerHandle, this, &UFlowNode_Timer::OnCompletion, - CompletionTime, false); + GetWorld()->GetTimerManager().SetTimer(CompletionTimerHandle, this, &UFlowNode_Timer::OnCompletion, CompletionTime, false); } else { - LogError("No valid world"); + LogError(TEXT("No valid world")); TriggerOutput(TEXT("Completed"), true); } } void UFlowNode_Timer::Restart() { - SumOfSteps = 0.0f; + Cleanup(); + RemainingStepTime = 0.0f; RemainingCompletionTime = 0.0f; + SetTimer(); } diff --git a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp index 4c1f52b9c..e25eea3d2 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp @@ -16,8 +16,10 @@ FFlowNodeLevelSequenceEvent UFlowNode_PlayLevelSequence::OnPlaybackCompleted; UFlowNode_PlayLevelSequence::UFlowNode_PlayLevelSequence(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) + , bApplyOwnerTimeDilation(true) , LoadedSequence(nullptr) , SequencePlayer(nullptr) + , CachedPlayRate(0) , StartTime(0.0f) , ElapsedTime(0.0f) , TimeDilation(1.0f) @@ -35,10 +37,6 @@ UFlowNode_PlayLevelSequence::UFlowNode_PlayLevelSequence(const FObjectInitialize OutputPins.Add(FFlowPin(TEXT("Started"))); OutputPins.Add(FFlowPin(TEXT("Completed"))); OutputPins.Add(FFlowPin(TEXT("Stopped"))); - - // Initialize the original time dilation. - OriginalTimeDilation = PlaybackSettings.PlayRate; - } #if WITH_EDITOR @@ -113,6 +111,14 @@ void UFlowNode_PlayLevelSequence::FlushContent() } } +void UFlowNode_PlayLevelSequence::InitializeInstance() +{ + Super::InitializeInstance(); + + // Cache Play Rate set by user + CachedPlayRate = PlaybackSettings.PlayRate; +} + void UFlowNode_PlayLevelSequence::CreatePlayer() { LoadedSequence = LoadAsset(Sequence); @@ -120,22 +126,27 @@ void UFlowNode_PlayLevelSequence::CreatePlayer() { ALevelSequenceActor* SequenceActor; - // This block is for setting the custom time dilation from the parent actor. - if(GetFlowAsset()) + // Apply AActor::CustomTimeDilation from owner of the Root Flow + if (GetFlowAsset()) { - if(GetFlowAsset()->GetOwner()) + if (UObject* RootFlowOwner = GetFlowAsset()->GetOwner()) { - const UFlowComponent* OwnerComp = Cast(GetFlowAsset()->GetOwner()); - if(OwnerComp) + AActor* OwningActor = Cast(RootFlowOwner); // in case Root Flow was created directly from some actor + + if (OwningActor == nullptr) { - if(IsValid(OwnerComp->GetOwner())) + if (const USceneComponent* OwningComponent = Cast(RootFlowOwner)) { - PlaybackSettings.PlayRate = OriginalTimeDilation * OwnerComp->GetOwner()->CustomTimeDilation; + OwningActor = OwningComponent->GetOwner(); } } + + if (IsValid(OwningActor)) + { + PlaybackSettings.PlayRate = CachedPlayRate * OwningActor->CustomTimeDilation; + } } } - // End of custom time dilation block. SequencePlayer = UFlowLevelSequencePlayer::CreateFlowLevelSequencePlayer(this, LoadedSequence, PlaybackSettings, CameraSettings, SequenceActor); if (SequencePlayer) @@ -200,8 +211,9 @@ void UFlowNode_PlayLevelSequence::OnLoad_Implementation() { SequencePlayer->OnFinished.AddDynamic(this, &UFlowNode_PlayLevelSequence::OnPlaybackFinished); - // Added the multiplier if you set the playrate in playback settings. - SequencePlayer->SetPlayRate(TimeDilation * OriginalTimeDilation); + // Take into account Play Rate set in the Playback Settings + SequencePlayer->SetPlayRate(TimeDilation * CachedPlayRate); + SequencePlayer->SetPlaybackPosition(FMovieSceneSequencePlaybackParams(ElapsedTime, EUpdatePositionMethod::Jump)); SequencePlayer->Play(); } @@ -219,8 +231,9 @@ void UFlowNode_PlayLevelSequence::OnTimeDilationUpdate(const float NewTimeDilati if (SequencePlayer) { TimeDilation = NewTimeDilation; - // Added the multiplier if you set the playrate in playback settings. - SequencePlayer->SetPlayRate(NewTimeDilation * OriginalTimeDilation); + + // Take into account Play Rate set in the Playback Settings + SequencePlayer->SetPlayRate(NewTimeDilation * CachedPlayRate); } } diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h b/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h index b76182fed..6ac241602 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h @@ -35,6 +35,7 @@ class FLOW_API UFlowNode_Timer : public UFlowNode protected: virtual void ExecuteInput(const FName& PinName) override; + virtual void SetTimer(); virtual void Restart(); diff --git a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h index 64c3595a5..353188340 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h @@ -32,6 +32,11 @@ class FLOW_API UFlowNode_PlayLevelSequence : public UFlowNode UPROPERTY(EditAnywhere, Category = "Sequence") FMovieSceneSequencePlaybackSettings PlaybackSettings; + + // if True, Play Rate will by multiplied by Custom Time Dilation + // set in the actor that owns Root Flow + UPROPERTY(EditAnywhere, Category = "Sequence") + bool bApplyOwnerTimeDilation; UPROPERTY(EditAnywhere, Category = "Sequence") FLevelSequenceCameraSettings CameraSettings; @@ -43,8 +48,8 @@ class FLOW_API UFlowNode_PlayLevelSequence : public UFlowNode UPROPERTY() UFlowLevelSequencePlayer* SequencePlayer; - UPROPERTY() - float OriginalTimeDilation; // It is for the default play rate getting from the playback settings. + // Play Rate set by the user in PlaybackSettings + float CachedPlayRate; UPROPERTY(SaveGame) float StartTime; @@ -66,6 +71,7 @@ class FLOW_API UFlowNode_PlayLevelSequence : public UFlowNode virtual void PreloadContent() override; virtual void FlushContent() override; + virtual void InitializeInstance() override; void CreatePlayer(); protected: diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h index 4e11deca1..9f4d00189 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h @@ -39,7 +39,6 @@ class FLOWEDITOR_API UFlowGraphSchema : public UEdGraphSchema static UClass* GetAssignedGraphNodeClass(const UClass* FlowNodeClass); private: - static bool IsClassContained(const TArray> Classes, const UClass* Class); static void GetFlowNodeActions(FGraphActionMenuBuilder& ActionMenuBuilder, UClass* AssetClass, const FString& CategoryName); static void GetCommentAction(FGraphActionMenuBuilder& ActionMenuBuilder, const UEdGraph* CurrentGraph = nullptr); From ea7e0d41171df23a77310af14cd201d501093151 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Wed, 30 Mar 2022 20:25:27 +0200 Subject: [PATCH 092/338] added Is Input Connected method #96 --- Source/Flow/Private/Nodes/FlowNode.cpp | 22 ++++++++++++++++++++++ Source/Flow/Public/Nodes/FlowNode.h | 3 +++ 2 files changed, 25 insertions(+) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 0ba91f701..77efcabec 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -240,6 +240,28 @@ TSet UFlowNode::GetConnectedNodes() const return Result; } +bool UFlowNode::IsInputConnected(const FName& PinName) const +{ + if (GetFlowAsset()) + { + for (const TPair& Pair : GetFlowAsset()->Nodes) + { + if (Pair.Value) + { + for (const TPair& Connection : Pair.Value->Connections) + { + if (Connection.Value.NodeGuid == NodeGuid && Connection.Value.PinName == PinName) + { + return true; + } + } + } + } + } + + return false; +} + bool UFlowNode::IsOutputConnected(const FName& PinName) const { return OutputPins.Contains(PinName) && Connections.Contains(PinName); diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 7045e0a65..3457f10cf 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -173,6 +173,9 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte FConnectedPin GetConnection(const FName OutputName) const { return Connections.FindRef(OutputName); } TSet GetConnectedNodes() const; + UFUNCTION(BlueprintPure, Category= "FlowNode") + bool IsInputConnected(const FName& PinName) const; + UFUNCTION(BlueprintPure, Category= "FlowNode") bool IsOutputConnected(const FName& PinName) const; From 09713a29ff0f98aa483ac71d1846a5b394910514 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 5 Apr 2022 18:03:07 +0200 Subject: [PATCH 093/338] contributors link --- Flow.uplugin | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Flow.uplugin b/Flow.uplugin index 395c537f6..fbe3b12ca 100644 --- a/Flow.uplugin +++ b/Flow.uplugin @@ -4,8 +4,7 @@ "FriendlyName" : "Flow", "Description" : "Design-agnostic node editor for scripting game’s flow.", "Category" : "Gameplay", - "CreatedBy" : "Krzysztof Justyński", - "CreatedByURL" : "https://twitter.com/MothDoctor", + "CreatedByURL" : "https://github.com/MothCocoon/FlowGraph/graphs/contributors", "DocsURL" : "https://github.com/MothCocoon/FlowGraph/wiki", "MarketplaceURL" : "", "SupportURL": "https://discord.gg/zMtMQ2vUUa", From f9f644114dec6f64d1ea367cf645ff8f49ab43d2 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 10 Apr 2022 12:55:16 +0200 Subject: [PATCH 094/338] bump to 1.3 --- Flow.uplugin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.uplugin b/Flow.uplugin index fbe3b12ca..c92bfa1a8 100644 --- a/Flow.uplugin +++ b/Flow.uplugin @@ -1,6 +1,6 @@ { "FileVersion" : 3, - "Version" : 1.2, + "Version" : 1.3, "FriendlyName" : "Flow", "Description" : "Design-agnostic node editor for scripting game’s flow.", "Category" : "Gameplay", From 9e03b5b47936abbcfa2ea837ba12310d441c0376 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 11 Apr 2022 00:40:12 +0200 Subject: [PATCH 095/338] #15 Implemented Asset Search Sadly, the feature must remain commented out as it requires engine modification. https://github.com/MothCocoon/FlowGraph/wiki/Asset-Search --- Flow.uplugin | 6 + Source/FlowEditor/FlowEditor.Build.cs | 1 + .../Private/Asset/FlowAssetIndexer.cpp | 136 ++++++++++++++++++ .../FlowEditor/Private/FlowEditorModule.cpp | 30 ++++ .../Public/Asset/FlowAssetIndexer.h | 23 +++ Source/FlowEditor/Public/FlowEditorModule.h | 4 + 6 files changed, 200 insertions(+) create mode 100644 Source/FlowEditor/Private/Asset/FlowAssetIndexer.cpp create mode 100644 Source/FlowEditor/Public/Asset/FlowAssetIndexer.h diff --git a/Flow.uplugin b/Flow.uplugin index c92bfa1a8..fdba8368f 100644 --- a/Flow.uplugin +++ b/Flow.uplugin @@ -25,5 +25,11 @@ "Type" : "Editor", "LoadingPhase" : "Default" } + ], + "Plugins": [ + { + "Name": "AssetSearch", + "Enabled": true + } ] } \ No newline at end of file diff --git a/Source/FlowEditor/FlowEditor.Build.cs b/Source/FlowEditor/FlowEditor.Build.cs index 61dc7b14c..2d95ddb06 100644 --- a/Source/FlowEditor/FlowEditor.Build.cs +++ b/Source/FlowEditor/FlowEditor.Build.cs @@ -14,6 +14,7 @@ public FlowEditor(ReadOnlyTargetRules Target) : base(Target) PrivateDependencyModuleNames.AddRange(new[] { "ApplicationCore", + "AssetSearch", "AssetTools", "BlueprintGraph", "ClassViewer", diff --git a/Source/FlowEditor/Private/Asset/FlowAssetIndexer.cpp b/Source/FlowEditor/Private/Asset/FlowAssetIndexer.cpp new file mode 100644 index 000000000..9d0031ab8 --- /dev/null +++ b/Source/FlowEditor/Private/Asset/FlowAssetIndexer.cpp @@ -0,0 +1,136 @@ +#include "Asset/FlowAssetIndexer.h" + +#include "FlowAsset.h" +#include "Nodes/FlowNode.h" + +#include "Graph/Nodes/FlowGraphNode_Reroute.h" + +#include "EdGraph/EdGraphPin.h" +#include "EdGraphNode_Comment.h" +#include "Engine/SimpleConstructionScript.h" +#include "Internationalization/Text.h" +#include "SearchSerializer.h" +#include "Utility/IndexerUtilities.h" + +#define LOCTEXT_NAMESPACE "FFlowAssetIndexer" + +/*enum class EFlowAssetIndexerVersion +{ + Empty, + Initial, + + // ------------------------------------------------------ + VersionPlusOne, + LatestVersion = VersionPlusOne - 1 +}; + +int32 FFlowAssetIndexer::GetVersion() const +{ + return static_cast(EFlowAssetIndexerVersion::LatestVersion); +} + +void FFlowAssetIndexer::IndexAsset(const UObject* InAssetObject, FSearchSerializer& Serializer) const +{ + const UFlowAsset* FlowAsset = CastChecked(InAssetObject); + + { + Serializer.BeginIndexingObject(FlowAsset, TEXT("$self")); + + // for (const FName& CustomInput : FlowAsset->GetCustomInputs()) + // { + // Serializer.IndexProperty(CustomInput.ToString(), CustomInput); + // } + // for (const FName& CustomOutput : FlowAsset->GetCustomOutputs()) + // { + // Serializer.IndexProperty(CustomOutput.ToString(), CustomOutput); + // } + + FIndexerUtilities::IterateIndexableProperties(FlowAsset, [&Serializer](const FProperty* Property, const FString& Value) + { + Serializer.IndexProperty(Property, Value); + }); + + Serializer.EndIndexingObject(); + } + + IndexGraph(FlowAsset, Serializer); +} + +void FFlowAssetIndexer::IndexGraph(const UFlowAsset* InFlowAsset, FSearchSerializer& Serializer) const +{ + for (UEdGraphNode* Node : InFlowAsset->GetGraph()->Nodes) + { + // Ignore Reroutes + if (Cast(Node)) + { + continue; + } + + // Special rules for comment nodes + if (Cast(Node)) + { + Serializer.BeginIndexingObject(Node, Node->NodeComment); + Serializer.IndexProperty(TEXT("Comment"), Node->NodeComment); + Serializer.EndIndexingObject(); + continue; + } + + // Indexing UEdGraphNode + { + const FText NodeText = Node->GetNodeTitle(ENodeTitleType::MenuTitle); + Serializer.BeginIndexingObject(Node, NodeText); + Serializer.IndexProperty(TEXT("Title"), NodeText); + + if (!Node->NodeComment.IsEmpty()) + { + Serializer.IndexProperty(TEXT("Comment"), Node->NodeComment); + } + + for (const UEdGraphPin* Pin : Node->GetAllPins()) + { + if (Pin->Direction == EGPD_Input && Pin->LinkedTo.Num() == 0) + { + const FText PinText = Pin->GetDisplayName(); + if (PinText.IsEmpty()) + { + continue; + } + + const FText PinValue = Pin->GetDefaultAsText(); + if (PinValue.IsEmpty()) + { + continue; + } + + const FString PinLabel = TEXT("[Pin] ") + *FTextInspector::GetSourceString(PinText); + Serializer.IndexProperty(PinLabel, PinValue); + } + } + + // This will serialize any user exposed options for the node that are editable in the Details + FIndexerUtilities::IterateIndexableProperties(Node, [&Serializer](const FProperty* Property, const FString& Value) + { + Serializer.IndexProperty(Property, Value); + }); + + Serializer.EndIndexingObject(); + } + + // Indexing Flow Node + if (const UFlowGraphNode* FlowGraphNode = Cast(Node)) + { + if (const UFlowNode* FlowNode = FlowGraphNode->GetFlowNode()) + { + const FString NodeFriendlyName = FString::Printf(TEXT("%s: %s"), *FlowNode->GetClass()->GetName(), *FlowNode->GetNodeDescription()); + Serializer.BeginIndexingObject(FlowNode, NodeFriendlyName); + FIndexerUtilities::IterateIndexableProperties(FlowNode, [&Serializer](const FProperty* Property, const FString& Value) + { + Serializer.IndexProperty(Property, Value); + }); + Serializer.EndIndexingObject(); + } + } + } +}*/ + +#undef LOCTEXT_NAMESPACE diff --git a/Source/FlowEditor/Private/FlowEditorModule.cpp b/Source/FlowEditor/Private/FlowEditorModule.cpp index 8dbd4188f..1b849e4c2 100644 --- a/Source/FlowEditor/Private/FlowEditorModule.cpp +++ b/Source/FlowEditor/Private/FlowEditorModule.cpp @@ -4,6 +4,7 @@ #include "Asset/AssetTypeActions_FlowAsset.h" #include "Asset/FlowAssetDetails.h" #include "Asset/FlowAssetEditor.h" +#include "Asset/FlowAssetIndexer.h" #include "Graph/FlowGraphConnectionDrawingPolicy.h" #include "Graph/FlowGraphSettings.h" #include "LevelEditor/SLevelEditorFlow.h" @@ -23,12 +24,15 @@ #include "AssetToolsModule.h" #include "EdGraphUtilities.h" +#include "IAssetSearchModule.h" #include "Framework/MultiBox/MultiBoxBuilder.h" #include "ISequencerChannelInterface.h" #include "ISequencerModule.h" #include "LevelEditor.h" #include "Modules/ModuleManager.h" +static FName AssetSearchModuleName = TEXT("AssetSearch"); + #define LOCTEXT_NAMESPACE "FlowEditorModule" EAssetTypeCategories::Type FFlowEditorModule::FlowAssetCategory = static_cast(0); @@ -69,6 +73,13 @@ void FFlowEditorModule::StartupModule() FPropertyEditorModule& PropertyModule = FModuleManager::GetModuleChecked("PropertyEditor"); PropertyModule.NotifyCustomizationModuleChanged(); + + // register asset indexers + if (FModuleManager::Get().IsModuleLoaded(AssetSearchModuleName)) + { + RegisterAssetIndexers(); + } + ModulesChangedHandle = FModuleManager::Get().OnModulesChanged().AddRaw(this, &FFlowEditorModule::ModulesChangesCallback); } void FFlowEditorModule::ShutdownModule() @@ -100,6 +111,8 @@ void FFlowEditorModule::ShutdownModule() } } } + + FModuleManager::Get().OnModulesChanged().Remove(ModulesChangedHandle); } void FFlowEditorModule::RegisterAssets() @@ -149,6 +162,23 @@ void FFlowEditorModule::RegisterCustomClassLayout(const TSubclassOf Cla } } +void FFlowEditorModule::ModulesChangesCallback(FName ModuleName, EModuleChangeReason ReasonForChange) +{ + if (ReasonForChange == EModuleChangeReason::ModuleLoaded && ModuleName == AssetSearchModuleName) + { + RegisterAssetIndexers(); + } +} + +void FFlowEditorModule::RegisterAssetIndexers() const +{ + /** + * Documentation: https://github.com/MothCocoon/FlowGraph/wiki/Asset-Search + * Uncomment line below, if you made these changes to the engine: https://github.com/EpicGames/UnrealEngine/pull/9070 + */ + //IAssetSearchModule::Get().RegisterAssetIndexer(UFlowAsset::StaticClass(), MakeUnique()); +} + void FFlowEditorModule::CreateFlowToolbar(FToolBarBuilder& ToolbarBuilder) const { ToolbarBuilder.BeginSection("Flow"); diff --git a/Source/FlowEditor/Public/Asset/FlowAssetIndexer.h b/Source/FlowEditor/Public/Asset/FlowAssetIndexer.h new file mode 100644 index 000000000..736f4e7cf --- /dev/null +++ b/Source/FlowEditor/Public/Asset/FlowAssetIndexer.h @@ -0,0 +1,23 @@ +#pragma once + +#include "CoreMinimal.h" +#include "IAssetIndexer.h" + +class UFlowAsset; +class FSearchSerializer; + +/** + * Documentation: https://github.com/MothCocoon/FlowGraph/wiki/Asset-Search + * Uncomment entire class, if you made these changes to the engine: https://github.com/EpicGames/UnrealEngine/pull/9070 + */ +/*class FFlowAssetIndexer : public IAssetIndexer +{ +public: + virtual FString GetName() const override { return TEXT("FlowAsset"); } + virtual int32 GetVersion() const override; + virtual void IndexAsset(const UObject* InAssetObject, FSearchSerializer& Serializer) const override; + +private: + // Variant of FBlueprintIndexer::IndexGraphs + void IndexGraph(const UFlowAsset* InFlowAsset, FSearchSerializer& Serializer) const; +};*/ diff --git a/Source/FlowEditor/Public/FlowEditorModule.h b/Source/FlowEditor/Public/FlowEditorModule.h index 93f679cf3..9bb0a37c4 100644 --- a/Source/FlowEditor/Public/FlowEditorModule.h +++ b/Source/FlowEditor/Public/FlowEditorModule.h @@ -35,8 +35,12 @@ class FLOWEDITOR_API FFlowEditorModule : public IModuleInterface public: FDelegateHandle FlowTrackCreateEditorHandle; + FDelegateHandle ModulesChangedHandle; private: + void ModulesChangesCallback(FName ModuleName, EModuleChangeReason ReasonForChange); + void RegisterAssetIndexers() const; + void CreateFlowToolbar(FToolBarBuilder& ToolbarBuilder) const; public: From 237ef9ecc4f0c574d39318dcae9c2a31d702cf86 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 11 Apr 2022 01:03:56 +0200 Subject: [PATCH 096/338] added Json modules --- Source/FlowEditor/FlowEditor.Build.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/FlowEditor/FlowEditor.Build.cs b/Source/FlowEditor/FlowEditor.Build.cs index 2d95ddb06..53d252d5c 100644 --- a/Source/FlowEditor/FlowEditor.Build.cs +++ b/Source/FlowEditor/FlowEditor.Build.cs @@ -28,6 +28,8 @@ public FlowEditor(ReadOnlyTargetRules Target) : base(Target) "Engine", "GraphEditor", "InputCore", + "Json", + "JsonUtilities", "KismetWidgets", "LevelEditor", "MovieScene", From 21b5f462136dea9edf9637a3d6866af53d42c898 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Wed, 13 Apr 2022 21:30:42 +0200 Subject: [PATCH 097/338] added Play Reverse option, based on --- .../World/FlowNode_PlayLevelSequence.cpp | 26 +++++++++++++++---- .../Nodes/World/FlowNode_PlayLevelSequence.h | 3 +++ .../FlowNode_PlayLevelSequenceDetails.cpp | 3 +++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp index e25eea3d2..02370e60a 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp @@ -16,6 +16,7 @@ FFlowNodeLevelSequenceEvent UFlowNode_PlayLevelSequence::OnPlaybackCompleted; UFlowNode_PlayLevelSequence::UFlowNode_PlayLevelSequence(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) + , bPlayReverse(false) , bApplyOwnerTimeDilation(true) , LoadedSequence(nullptr) , SequencePlayer(nullptr) @@ -131,8 +132,7 @@ void UFlowNode_PlayLevelSequence::CreatePlayer() { if (UObject* RootFlowOwner = GetFlowAsset()->GetOwner()) { - AActor* OwningActor = Cast(RootFlowOwner); // in case Root Flow was created directly from some actor - + const AActor* OwningActor = Cast(RootFlowOwner); // in case Root Flow was created directly from some actor if (OwningActor == nullptr) { if (const USceneComponent* OwningComponent = Cast(RootFlowOwner)) @@ -175,7 +175,15 @@ void UFlowNode_PlayLevelSequence::ExecuteInput(const FName& PinName) TriggerOutput(TEXT("PreStart")); SequencePlayer->OnFinished.AddDynamic(this, &UFlowNode_PlayLevelSequence::OnPlaybackFinished); - SequencePlayer->Play(); + + if (bPlayReverse) + { + SequencePlayer->PlayReverse(); + } + else + { + SequencePlayer->Play(); + } TriggerOutput(TEXT("Started")); } @@ -211,11 +219,19 @@ void UFlowNode_PlayLevelSequence::OnLoad_Implementation() { SequencePlayer->OnFinished.AddDynamic(this, &UFlowNode_PlayLevelSequence::OnPlaybackFinished); + SequencePlayer->SetPlaybackPosition(FMovieSceneSequencePlaybackParams(ElapsedTime, EUpdatePositionMethod::Jump)); + // Take into account Play Rate set in the Playback Settings SequencePlayer->SetPlayRate(TimeDilation * CachedPlayRate); - SequencePlayer->SetPlaybackPosition(FMovieSceneSequencePlaybackParams(ElapsedTime, EUpdatePositionMethod::Jump)); - SequencePlayer->Play(); + if (bPlayReverse) + { + SequencePlayer->PlayReverse(); + } + else + { + SequencePlayer->Play(); + } } } } diff --git a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h index 353188340..5feb95658 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h @@ -33,6 +33,9 @@ class FLOW_API UFlowNode_PlayLevelSequence : public UFlowNode UPROPERTY(EditAnywhere, Category = "Sequence") FMovieSceneSequencePlaybackSettings PlaybackSettings; + UPROPERTY(EditAnywhere, Category = "Sequence") + bool bPlayReverse; + // if True, Play Rate will by multiplied by Custom Time Dilation // set in the actor that owns Root Flow UPROPERTY(EditAnywhere, Category = "Sequence") diff --git a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.cpp b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.cpp index 9d4df4dad..d1807690c 100644 --- a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.cpp +++ b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.cpp @@ -9,4 +9,7 @@ void FFlowNode_PlayLevelSequenceDetails::CustomizeDetails(IDetailLayoutBuilder& IDetailCategoryBuilder& SequenceCategory = DetailBuilder.EditCategory("Sequence"); SequenceCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UFlowNode_PlayLevelSequence, Sequence)); SequenceCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UFlowNode_PlayLevelSequence, PlaybackSettings)); + SequenceCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UFlowNode_PlayLevelSequence, bPlayReverse)); + SequenceCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UFlowNode_PlayLevelSequence, bApplyOwnerTimeDilation)); + SequenceCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UFlowNode_PlayLevelSequence, CameraSettings)); } From d085203cc5373ef1fac23068b786f2f7eb0c7fe0 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Wed, 27 Apr 2022 15:35:17 +0200 Subject: [PATCH 098/338] exposed remaining methods to subclasses --- Source/Flow/Public/FlowSubsystem.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index 3966d5d4b..7d543bfed 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -59,17 +59,17 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem // Start the root Flow, graph that will eventually instantiate next Flow Graphs through the SubGraph node UFUNCTION(BlueprintCallable, Category = "FlowSubsystem") - void StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances = true); + virtual void StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances = true); - UFlowAsset* CreateRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances = true); + virtual UFlowAsset* CreateRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances = true); // Finish Policy value is read by Flow Node // Nodes have opportunity to terminate themselves differently if Flow Graph has been aborted // Example: Spawn node might despawn all actors if Flow Graph is aborted, not completed UFUNCTION(BlueprintCallable, Category = "FlowSubsystem") - void FinishRootFlow(UObject* Owner, const EFlowFinishPolicy FinishPolicy); + virtual void FinishRootFlow(UObject* Owner, const EFlowFinishPolicy FinishPolicy); -private: +protected: UFlowAsset* CreateSubFlow(UFlowNode_SubGraph* SubGraphNode, const FString SavedInstanceName = FString(), const bool bPreloading = false); void RemoveSubFlow(UFlowNode_SubGraph* SubGraphNode, const EFlowFinishPolicy FinishPolicy); From 326ad869e682f7f1764528b2b6d0eb99d56e4778 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 8 May 2022 16:35:49 +0200 Subject: [PATCH 099/338] Prevented crash if `SubGraph` node would try to instantiate the same Flow Asset as the asset containing this `SubGraph` node. Such an option is still disabled by default, so we could avoid triggering an accidental infinite loop. Users can remove this limitation by checking the `bCanInstanceIdenticalAsset` flag on the specific `SubGraph` nodes. --- Source/Flow/Private/FlowSubsystem.cpp | 5 +-- Source/Flow/Private/Nodes/FlowNode.cpp | 2 +- .../Private/Nodes/Route/FlowNode_SubGraph.cpp | 43 ++++++++++++------- .../Public/Nodes/Route/FlowNode_SubGraph.h | 9 ++++ 4 files changed, 40 insertions(+), 19 deletions(-) diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index 50a037963..2507e7ecc 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -153,10 +153,9 @@ UFlowAsset* UFlowSubsystem::CreateFlowInstance(const TWeakObjectPtr Own { check(!FlowAsset.IsNull()); - if (FlowAsset.IsPending()) + if (FlowAsset.IsPending() || !FlowAsset.IsValid()) { - const FSoftObjectPath& AssetRef = FlowAsset.ToSoftObjectPath(); - FlowAsset = Cast(Streamable.LoadSynchronous(AssetRef, false)); + FlowAsset = Cast(Streamable.LoadSynchronous(FlowAsset.ToSoftObjectPath(), false)); } InstancedTemplates.Add(FlowAsset.Get()); diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 77efcabec..fa1eda07d 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -580,7 +580,7 @@ FString UFlowNode::GetProgressAsString(float Value) void UFlowNode::LogError(FString Message, const EFlowOnScreenMessageType OnScreenMessageType) const { const FString TemplatePath = GetFlowAsset()->TemplateAsset->GetPathName(); - Message += TEXT(" in node ") + GetName() + TEXT(", asset ") + FPaths::GetPath(TemplatePath) + TEXT("/") + FPaths::GetBaseFilename(TemplatePath); + Message += TEXT(" --- node ") + GetName() + TEXT(", asset ") + FPaths::GetPath(TemplatePath) / FPaths::GetBaseFilename(TemplatePath); if (OnScreenMessageType == EFlowOnScreenMessageType::Permanent) { diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp index 149e41615..9a4838848 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp @@ -8,6 +8,7 @@ FFlowPin UFlowNode_SubGraph::FinishPin(TEXT("Finish")); UFlowNode_SubGraph::UFlowNode_SubGraph(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) + , bCanInstanceIdenticalAsset(false) { #if WITH_EDITOR Category = TEXT("Route"); @@ -18,9 +19,14 @@ UFlowNode_SubGraph::UFlowNode_SubGraph(const FObjectInitializer& ObjectInitializ OutputPins = {FinishPin}; } +bool UFlowNode_SubGraph::CanBeAssetInstanced() const +{ + return !Asset.IsNull() && (bCanInstanceIdenticalAsset || Asset->GetPathName() != GetFlowAsset()->GetTemplateAsset()->GetPathName()); +} + void UFlowNode_SubGraph::PreloadContent() { - if (!Asset.IsNull() && GetFlowSubsystem()) + if (CanBeAssetInstanced() && GetFlowSubsystem()) { GetFlowSubsystem()->CreateSubFlow(this, FString(), true); } @@ -28,7 +34,7 @@ void UFlowNode_SubGraph::PreloadContent() void UFlowNode_SubGraph::FlushContent() { - if (!Asset.IsNull() && GetFlowSubsystem()) + if (CanBeAssetInstanced() && GetFlowSubsystem()) { GetFlowSubsystem()->RemoveSubFlow(this, EFlowFinishPolicy::Abort); } @@ -36,30 +42,37 @@ void UFlowNode_SubGraph::FlushContent() void UFlowNode_SubGraph::ExecuteInput(const FName& PinName) { - if (Asset.IsNull()) + if (CanBeAssetInstanced() == false) { - LogError(TEXT("Missing Flow Asset")); - Finish(); - } - else - { - if (PinName == TEXT("Start")) + if (Asset.IsNull()) { - if (GetFlowSubsystem()) - { - GetFlowSubsystem()->CreateSubFlow(this); - } + LogError(TEXT("Missing Flow Asset")); } else { - GetFlowAsset()->TriggerCustomEvent(this, PinName); + LogError(FString::Printf(TEXT("Asset %s cannot be instance, probably is the same as the asset owning this SubGraph node."), *Asset->GetPathName())); } + + Finish(); + return; + } + + if (PinName == TEXT("Start")) + { + if (GetFlowSubsystem()) + { + GetFlowSubsystem()->CreateSubFlow(this); + } + } + else + { + GetFlowAsset()->TriggerCustomEvent(this, PinName); } } void UFlowNode_SubGraph::Cleanup() { - if (!Asset.IsNull() && GetFlowSubsystem()) + if (CanBeAssetInstanced() && GetFlowSubsystem()) { GetFlowSubsystem()->RemoveSubFlow(this, EFlowFinishPolicy::Keep); } diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h b/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h index e017b972a..2a4c0fe35 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h @@ -21,10 +21,19 @@ class FLOW_API UFlowNode_SubGraph : public UFlowNode UPROPERTY(EditAnywhere, Category = "Graph") TSoftObjectPtr Asset; + /* + * Allow to create instance of the same Flow Asset as the asset containing this node + * Enabling it may cause an infinite loop, if graph would keep creating copies of itself + */ + UPROPERTY(EditAnywhere, Category = "Graph") + bool bCanInstanceIdenticalAsset; + UPROPERTY(SaveGame) FString SavedAssetInstanceName; protected: + virtual bool CanBeAssetInstanced() const; + virtual void PreloadContent() override; virtual void FlushContent() override; From c15610bef22a32e03a770aeb36dae3eaf963556c Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 8 May 2022 17:42:16 +0200 Subject: [PATCH 100/338] #99 customized AddPin button code, so users can add Input and Output pins on the same node --- .../Private/Graph/Widgets/SFlowGraphNode.cpp | 234 +++++++++++------- .../Public/Graph/Widgets/SFlowGraphNode.h | 11 +- 2 files changed, 151 insertions(+), 94 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp index e2f71f4eb..efd3e5bf6 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp @@ -190,46 +190,46 @@ void SFlowGraphNode::UpdateGraphNode() const TSharedRef DefaultTitleAreaWidget = SNew(SOverlay) + SOverlay::Slot() + .HAlign(HAlign_Fill) + .VAlign(VAlign_Center) + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() .HAlign(HAlign_Fill) - .VAlign(VAlign_Center) [ - SNew(SHorizontalBox) - + SHorizontalBox::Slot() - .HAlign(HAlign_Fill) - [ - SNew(SBorder) - .BorderImage(FFlowEditorStyle::GetBrush("Flow.Node.Title")) - // The extra margin on the right is for making the color spill stretch well past the node title - .Padding(FMargin(10, 5, 30, 3)) - .BorderBackgroundColor(this, &SGraphNode::GetNodeTitleColor) - [ - SNew(SHorizontalBox) - + SHorizontalBox::Slot() - .VAlign(VAlign_Top) - .Padding(FMargin(0.f, 0.f, 4.f, 0.f)) - .AutoWidth() - [ - SNew(SImage) - .Image(IconBrush) - .ColorAndOpacity(this, &SGraphNode::GetNodeTitleIconColor) - ] - + SHorizontalBox::Slot() - [ - SNew(SVerticalBox) - + SVerticalBox::Slot() - .AutoHeight() - [ - CreateTitleWidget(NodeTitle) - ] - + SVerticalBox::Slot() - .AutoHeight() - [ - NodeTitle.ToSharedRef() - ] - ] - ] - ] - ]; + SNew(SBorder) + .BorderImage(FFlowEditorStyle::GetBrush("Flow.Node.Title")) + // The extra margin on the right is for making the color spill stretch well past the node title + .Padding(FMargin(10, 5, 30, 3)) + .BorderBackgroundColor(this, &SGraphNode::GetNodeTitleColor) + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .VAlign(VAlign_Top) + .Padding(FMargin(0.f, 0.f, 4.f, 0.f)) + .AutoWidth() + [ + SNew(SImage) + .Image(IconBrush) + .ColorAndOpacity(this, &SGraphNode::GetNodeTitleIconColor) + ] + + SHorizontalBox::Slot() + [ + SNew(SVerticalBox) + + SVerticalBox::Slot() + .AutoHeight() + [ + CreateTitleWidget(NodeTitle) + ] + + SVerticalBox::Slot() + .AutoHeight() + [ + NodeTitle.ToSharedRef() + ] + ] + ] + ] + ]; SetDefaultTitleAreaWidget(DefaultTitleAreaWidget); @@ -297,22 +297,22 @@ void SFlowGraphNode::UpdateGraphNode() [ SAssignNew(MainVerticalBox, SVerticalBox) + SVerticalBox::Slot() - .AutoHeight() - [ - SNew(SOverlay) - .AddMetaData(TagMeta) - + SOverlay::Slot() - .Padding(Settings->GetNonPinNodeBodyPadding()) - [ - SNew(SImage) - .Image(GetNodeBodyBrush()) - .ColorAndOpacity(this, &SGraphNode::GetNodeBodyColor) - ] - + SOverlay::Slot() - [ - InnerVerticalBox.ToSharedRef() - ] - ] + .AutoHeight() + [ + SNew(SOverlay) + .AddMetaData(TagMeta) + + SOverlay::Slot() + .Padding(Settings->GetNonPinNodeBodyPadding()) + [ + SNew(SImage) + .Image(GetNodeBodyBrush()) + .ColorAndOpacity(this, &SGraphNode::GetNodeBodyColor) + ] + + SOverlay::Slot() + [ + InnerVerticalBox.ToSharedRef() + ] + ] ]; if (GraphNode && GraphNode->SupportsCommentBubble()) @@ -421,25 +421,35 @@ void SFlowGraphNode::CreateStandardPinWidget(UEdGraphPin* Pin) END_SLATE_FUNCTION_BUILD_OPTIMIZATION +TSharedPtr SFlowGraphNode::GetComplexTooltip() +{ + return IDocumentation::Get()->CreateToolTip(TAttribute(this, &SGraphNode::GetNodeTooltip), nullptr, GraphNode->GetDocumentationLink(), GraphNode->GetDocumentationExcerptName()); +} + void SFlowGraphNode::CreateInputSideAddButton(TSharedPtr OutputBox) { if (FlowGraphNode->CanUserAddInput()) { - const TSharedRef AddPinButton = AddPinButtonContent( - LOCTEXT("FlowNodeAddPinButton", "Add pin"), - LOCTEXT("FlowNodeAddPinButton_InputTooltip", "Adds an input pin") - ); - - FMargin AddPinPadding = Settings->GetInputPinPadding(); - AddPinPadding.Top += 6.0f; + TSharedPtr AddPinWidget; + SAssignNew(AddPinWidget, SHorizontalBox) + +SHorizontalBox::Slot() + .AutoWidth() + . VAlign(VAlign_Center) + . Padding( 0,0,7,0 ) + [ + SNew(SImage) + .Image(FEditorStyle::GetBrush(TEXT("PropertyWindow.Button_AddToArray"))) + ] + +SHorizontalBox::Slot() + .AutoWidth() + .HAlign(HAlign_Left) + [ + SNew(STextBlock) + .Text(LOCTEXT("FlowNodeAddPinButton", "Add pin")) + .ColorAndOpacity(FLinearColor::White) + ]; - OutputBox->AddSlot() - .AutoHeight() - .VAlign(VAlign_Center) - .Padding(AddPinPadding) - [ - AddPinButton - ]; + AddPinButton(OutputBox, AddPinWidget.ToSharedRef(), EGPD_Input); } } @@ -447,41 +457,83 @@ void SFlowGraphNode::CreateOutputSideAddButton(TSharedPtr OutputBo { if (FlowGraphNode->CanUserAddOutput()) { - const TSharedRef AddPinButton = AddPinButtonContent( - LOCTEXT("FlowNodeAddPinButton", "Add pin"), - LOCTEXT("FlowNodeAddPinButton_OutputTooltip", "Adds an output pin") - ); - - FMargin AddPinPadding = Settings->GetOutputPinPadding(); - AddPinPadding.Top += 6.0f; + TSharedPtr AddPinWidget; + SAssignNew(AddPinWidget, SHorizontalBox) + +SHorizontalBox::Slot() + .AutoWidth() + .HAlign(HAlign_Left) + [ + SNew(STextBlock) + .Text(LOCTEXT("FlowNodeAddPinButton", "Add pin")) + .ColorAndOpacity(FLinearColor::White) + ] + +SHorizontalBox::Slot() + .AutoWidth() + .VAlign(VAlign_Center) + .Padding(7,0,0,0) + [ + SNew(SImage) + .Image(FEditorStyle::GetBrush(TEXT("PropertyWindow.Button_AddToArray"))) + ]; - OutputBox->AddSlot() - .AutoHeight() - .VAlign(VAlign_Center) - .Padding(AddPinPadding) - [ - AddPinButton - ]; - } + AddPinButton(OutputBox, AddPinWidget.ToSharedRef(), EGPD_Output); + } } -FReply SFlowGraphNode::OnAddPin() +void SFlowGraphNode::AddPinButton(TSharedPtr OutputBox, const TSharedRef ButtonContent, const EEdGraphPinDirection Direction, const FString DocumentationExcerpt, const TSharedPtr CustomTooltip) { - if (FlowGraphNode->CanUserAddInput()) + const FText PinTooltipText = (Direction == EEdGraphPinDirection::EGPD_Input) ? LOCTEXT("FlowNodeAddPinButton_InputTooltip", "Adds an input pin") : LOCTEXT("FlowNodeAddPinButton_OutputTooltip", "Adds an output pin"); + TSharedPtr Tooltip; + + if (CustomTooltip.IsValid()) { - FlowGraphNode->AddUserInput(); + Tooltip = CustomTooltip; } - else if (FlowGraphNode->CanUserAddOutput()) + else if (!DocumentationExcerpt.IsEmpty()) { - FlowGraphNode->AddUserOutput(); + Tooltip = IDocumentation::Get()->CreateToolTip(PinTooltipText, nullptr, GraphNode->GetDocumentationLink(), DocumentationExcerpt); } - return FReply::Handled(); + const TSharedRef AddPinButton = SNew(SButton) + .ContentPadding(0.0f) + .ButtonStyle(FEditorStyle::Get(), "NoBorder") + .OnClicked(this, &SFlowGraphNode::OnAddFlowPin, Direction) + .IsEnabled(this, &SFlowGraphNode::IsNodeEditable) + .ToolTipText(PinTooltipText) + .ToolTip(Tooltip) + .Visibility(this, &SFlowGraphNode::IsAddPinButtonVisible) + [ + ButtonContent + ]; + + AddPinButton->SetCursor(EMouseCursor::Hand); + + FMargin AddPinPadding = (Direction == EEdGraphPinDirection::EGPD_Input) ? Settings->GetInputPinPadding() : Settings->GetOutputPinPadding(); + AddPinPadding.Top += 6.0f; + + OutputBox->AddSlot() + .AutoHeight() + .VAlign(VAlign_Center) + .Padding(AddPinPadding) + [ + AddPinButton + ]; } -TSharedPtr SFlowGraphNode::GetComplexTooltip() +FReply SFlowGraphNode::OnAddFlowPin(const EEdGraphPinDirection Direction) { - return IDocumentation::Get()->CreateToolTip(TAttribute(this, &SGraphNode::GetNodeTooltip), nullptr, GraphNode->GetDocumentationLink(), GraphNode->GetDocumentationExcerptName()); + switch (Direction) + { + case EGPD_Input: + FlowGraphNode->AddUserInput(); + break; + case EGPD_Output: + FlowGraphNode->AddUserOutput(); + break; + default: ; + } + + return FReply::Handled(); } #undef LOCTEXT_NAMESPACE diff --git a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h index 9a7a6194d..e69f46e49 100644 --- a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h +++ b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h @@ -40,12 +40,17 @@ class SFlowGraphNode : public SGraphNode virtual const FSlateBrush* GetNodeBodyBrush() const override; virtual void CreateStandardPinWidget(UEdGraphPin* Pin) override; + virtual TSharedPtr GetComplexTooltip() override; + virtual void CreateInputSideAddButton(TSharedPtr OutputBox) override; virtual void CreateOutputSideAddButton(TSharedPtr OutputBox) override; - virtual FReply OnAddPin() override; - - virtual TSharedPtr GetComplexTooltip() override; // -- + + // Variant of SGraphNode::AddPinButtonContent + virtual void AddPinButton(TSharedPtr OutputBox, TSharedRef ButtonContent, const EEdGraphPinDirection Direction, FString DocumentationExcerpt = FString(), TSharedPtr CustomTooltip = nullptr); + + // Variant of SGraphNode::OnAddPin + virtual FReply OnAddFlowPin(const EEdGraphPinDirection Direction); protected: UFlowGraphNode* FlowGraphNode = nullptr; From fe40a401e2aa3ba1c3e07b29922781d11de486e9 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 8 May 2022 22:52:02 +0200 Subject: [PATCH 101/338] added clearing Root Instance while resetting game prior to loading SaveGame --- Source/Flow/Private/FlowSubsystem.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index 2507e7ecc..d38dea211 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -61,6 +61,8 @@ void UFlowSubsystem::AbortActiveFlows() InstancedTemplates.Empty(); InstancedSubFlows.Empty(); + + RootInstances.Empty(); } void UFlowSubsystem::StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances /* = true */) From 785cd9a9bb19ae403e8273b871705d245193513a Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 8 May 2022 22:52:54 +0200 Subject: [PATCH 102/338] minor polishing --- Source/Flow/Private/FlowWorldSettings.cpp | 19 +++++++++++++++---- Source/Flow/Public/FlowSubsystem.h | 3 +++ Source/Flow/Public/FlowWorldSettings.h | 2 ++ .../Public/Nodes/Utils/FlowNode_Checkpoint.h | 2 +- 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/Source/Flow/Private/FlowWorldSettings.cpp b/Source/Flow/Private/FlowWorldSettings.cpp index 441a894bd..6b3d0af82 100644 --- a/Source/Flow/Private/FlowWorldSettings.cpp +++ b/Source/Flow/Private/FlowWorldSettings.cpp @@ -1,5 +1,6 @@ #include "FlowWorldSettings.h" #include "FlowComponent.h" +#include "FlowSubsystem.h" AFlowWorldSettings::AFlowWorldSettings(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) @@ -25,13 +26,23 @@ void AFlowWorldSettings::PostInitializeComponents() { Super::PostInitializeComponents(); + if (!IsValidInstance()) + { + GetFlowComponent()->bAutoStartRootFlow = false; + } +} + +bool AFlowWorldSettings::IsValidInstance() const +{ if (const UWorld* World = GetWorld()) { - // prevent starting Flow from the obsolete AWorldSettings actor that still exists in the world - // i.e. instance of class that is parent to the class set in Project Settings - if (World->GetWorldSettings() != this) + // workaround to prevent starting Flow from stray AWorldSettings actor that still exists in the world + // cause of this issue fixed in UE 5.0: https://github.com/EpicGames/UnrealEngine/commit/001f50b8b55507940f9c2cb1349592c692aae2c1?diff=unified + if (World->GetWorldSettings() == this) { - GetFlowComponent()->bAutoStartRootFlow = false; + return true; } } + + return false; } diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index 7d543bfed..bcd400b8c 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -26,8 +26,10 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem { GENERATED_BODY() +public: UFlowSubsystem(); +private: friend class UFlowAsset; friend class UFlowComponent; friend class UFlowNode_SubGraph; @@ -46,6 +48,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem FStreamableManager Streamable; +protected: UPROPERTY() UFlowSaveGame* LoadedSaveGame; diff --git a/Source/Flow/Public/FlowWorldSettings.h b/Source/Flow/Public/FlowWorldSettings.h index d07e32eaf..0098b73aa 100644 --- a/Source/Flow/Public/FlowWorldSettings.h +++ b/Source/Flow/Public/FlowWorldSettings.h @@ -24,6 +24,8 @@ class FLOW_API AFlowWorldSettings : public AWorldSettings virtual void PostInitializeComponents() override; private: + bool IsValidInstance() const; + UPROPERTY() class UFlowAsset* FlowAsset_DEPRECATED; }; diff --git a/Source/Flow/Public/Nodes/Utils/FlowNode_Checkpoint.h b/Source/Flow/Public/Nodes/Utils/FlowNode_Checkpoint.h index b5ca71382..640f4d394 100644 --- a/Source/Flow/Public/Nodes/Utils/FlowNode_Checkpoint.h +++ b/Source/Flow/Public/Nodes/Utils/FlowNode_Checkpoint.h @@ -5,7 +5,7 @@ /** * Save the state of the game to the save file -* It's recommended to replace this with game-specific variant and this node to UFlowGraphSettings::HiddenNodes + * It's recommended to replace this with game-specific variant and this node to UFlowGraphSettings::HiddenNodes */ UCLASS(NotBlueprintable, meta = (DisplayName = "Checkpoint")) class FLOW_API UFlowNode_Checkpoint final : public UFlowNode From 08ef890186c0544898cec21cbc4daf14390350e4 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 9 May 2022 15:09:59 +0200 Subject: [PATCH 103/338] notify users on missing Identity Tags in component starting Root Flow --- Source/Flow/Private/FlowComponent.cpp | 41 +++++++++++++++++++++++++++ Source/Flow/Public/FlowComponent.h | 6 ++++ 2 files changed, 47 insertions(+) diff --git a/Source/Flow/Private/FlowComponent.cpp b/Source/Flow/Private/FlowComponent.cpp index 1987ca06c..6c7cd669d 100644 --- a/Source/Flow/Private/FlowComponent.cpp +++ b/Source/Flow/Private/FlowComponent.cpp @@ -1,10 +1,12 @@ #include "FlowComponent.h" #include "FlowAsset.h" +#include "FlowModule.h" #include "FlowSettings.h" #include "FlowSubsystem.h" #include "Engine/GameInstance.h" +#include "Engine/ViewportStatsSubsystem.h" #include "Engine/World.h" #include "Net/UnrealNetwork.h" #include "Serialization/MemoryReader.h" @@ -206,6 +208,41 @@ void UFlowComponent::OnRep_RemovedIdentityTags() } } +void UFlowComponent::VerifyIdentityTags() const +{ + if (IdentityTags.IsEmpty()) + { + LogError(TEXT("Missing Identity Tags on the Flow Component creating Flow Asset instance! This gonna break loading SaveGame for this component!")); + } +} + +void UFlowComponent::LogError(FString Message, const EFlowOnScreenMessageType OnScreenMessageType) const +{ + Message += TEXT(" --- Flow Component in actor ") + GetOwner()->GetName(); + + if (OnScreenMessageType == EFlowOnScreenMessageType::Permanent) + { + if (GetWorld()) + { + if (UViewportStatsSubsystem* StatsSubsystem = GetWorld()->GetSubsystem()) + { + StatsSubsystem->AddDisplayDelegate([this, Message](FText& OutText, FLinearColor& OutColor) + { + OutText = FText::FromString(Message); + OutColor = FLinearColor::Red; + return IsValid(this); + }); + } + } + } + else + { + GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, Message); + } + + UE_LOG(LogFlow, Error, TEXT("%s"), *Message); +} + void UFlowComponent::NotifyGraph(const FGameplayTag NotifyTag, const EFlowNetMode NetMode /* = EFlowNetMode::Authority*/) { if (IsFlowNetMode(NetMode) && NotifyTag.IsValid() && HasBegunPlay()) @@ -326,6 +363,8 @@ void UFlowComponent::StartRootFlow() { if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) { + VerifyIdentityTags(); + FlowSubsystem->StartRootFlow(this, RootFlow, bAllowMultipleInstances); } } @@ -365,6 +404,8 @@ void UFlowComponent::LoadRootFlow() { if (RootFlow && !SavedAssetInstanceName.IsEmpty() && GetFlowSubsystem()) { + VerifyIdentityTags(); + GetFlowSubsystem()->LoadRootFlow(this, RootFlow, SavedAssetInstanceName); SavedAssetInstanceName = FString(); } diff --git a/Source/Flow/Public/FlowComponent.h b/Source/Flow/Public/FlowComponent.h index a282ae3e0..103898698 100644 --- a/Source/Flow/Public/FlowComponent.h +++ b/Source/Flow/Public/FlowComponent.h @@ -92,6 +92,12 @@ class FLOW_API UFlowComponent : public UActorComponent UPROPERTY(BlueprintAssignable, Category = "Flow") FFlowComponentTagsReplicated OnIdentityTagsRemoved; +public: + void VerifyIdentityTags() const; + + UFUNCTION(BlueprintCallable, Category = "Flow") + void LogError(FString Message, const EFlowOnScreenMessageType OnScreenMessageType = EFlowOnScreenMessageType::Permanent) const; + ////////////////////////////////////////////////////////////////////////// // Component sending Notify Tags to Flow Graph, or any other listener From 934113353642d1192f3047fa46ab5e6670a4dc2c Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sat, 14 May 2022 00:31:42 +0200 Subject: [PATCH 104/338] added dummy copyrights in hope of satisfying Unreal Marketplace guidelines 2.6.2.b https://www.unrealengine.com/en-US/marketplace-guidelines --- Source/Flow/Flow.Build.cs | 2 ++ Source/Flow/Private/FlowAsset.cpp | 2 ++ Source/Flow/Private/FlowComponent.cpp | 2 ++ Source/Flow/Private/FlowModule.cpp | 2 ++ Source/Flow/Private/FlowSettings.cpp | 2 ++ Source/Flow/Private/FlowSubsystem.cpp | 2 ++ Source/Flow/Private/FlowWorldSettings.cpp | 2 ++ Source/Flow/Private/LevelSequence/FlowLevelSequenceActor.cpp | 2 ++ Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp | 2 ++ .../Flow/Private/MovieScene/MovieSceneFlowRepeaterSection.cpp | 2 ++ Source/Flow/Private/MovieScene/MovieSceneFlowSectionBase.cpp | 2 ++ Source/Flow/Private/MovieScene/MovieSceneFlowTemplate.cpp | 2 ++ Source/Flow/Private/MovieScene/MovieSceneFlowTrack.cpp | 2 ++ .../Flow/Private/MovieScene/MovieSceneFlowTriggerSection.cpp | 2 ++ Source/Flow/Private/Nodes/FlowNode.cpp | 2 ++ Source/Flow/Private/Nodes/FlowNodeBlueprint.cpp | 2 ++ Source/Flow/Private/Nodes/FlowPin.cpp | 2 ++ Source/Flow/Private/Nodes/Operators/FlowNode_LogicalAND.cpp | 2 ++ Source/Flow/Private/Nodes/Operators/FlowNode_LogicalOR.cpp | 2 ++ Source/Flow/Private/Nodes/Route/FlowNode_Counter.cpp | 2 ++ Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp | 2 ++ Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp | 2 ++ .../Flow/Private/Nodes/Route/FlowNode_ExecutionMultiGate.cpp | 2 ++ .../Flow/Private/Nodes/Route/FlowNode_ExecutionSequence.cpp | 2 ++ Source/Flow/Private/Nodes/Route/FlowNode_Finish.cpp | 2 ++ Source/Flow/Private/Nodes/Route/FlowNode_Reroute.cpp | 2 ++ Source/Flow/Private/Nodes/Route/FlowNode_Start.cpp | 2 ++ Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp | 2 ++ Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp | 2 ++ Source/Flow/Private/Nodes/Utils/FlowNode_Checkpoint.cpp | 4 +++- Source/Flow/Private/Nodes/Utils/FlowNode_Log.cpp | 2 ++ .../Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp | 2 ++ Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp | 2 ++ .../Flow/Private/Nodes/World/FlowNode_OnActorRegistered.cpp | 2 ++ .../Flow/Private/Nodes/World/FlowNode_OnActorUnregistered.cpp | 2 ++ .../Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp | 2 ++ .../Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp | 2 ++ Source/Flow/Public/FlowAsset.h | 2 ++ Source/Flow/Public/FlowComponent.h | 2 ++ Source/Flow/Public/FlowModule.h | 2 ++ Source/Flow/Public/FlowSave.h | 2 ++ Source/Flow/Public/FlowSettings.h | 2 ++ Source/Flow/Public/FlowSubsystem.h | 2 ++ Source/Flow/Public/FlowTypes.h | 2 ++ Source/Flow/Public/FlowWorldSettings.h | 2 ++ Source/Flow/Public/LevelSequence/FlowLevelSequenceActor.h | 2 ++ Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h | 2 ++ Source/Flow/Public/MovieScene/MovieSceneFlowRepeaterSection.h | 2 ++ Source/Flow/Public/MovieScene/MovieSceneFlowSectionBase.h | 2 ++ Source/Flow/Public/MovieScene/MovieSceneFlowTemplate.h | 2 ++ Source/Flow/Public/MovieScene/MovieSceneFlowTrack.h | 2 ++ Source/Flow/Public/MovieScene/MovieSceneFlowTriggerSection.h | 2 ++ Source/Flow/Public/Nodes/FlowNode.h | 2 ++ Source/Flow/Public/Nodes/FlowNodeBlueprint.h | 2 ++ Source/Flow/Public/Nodes/FlowPin.h | 2 ++ Source/Flow/Public/Nodes/Operators/FlowNode_LogicalAND.h | 2 ++ Source/Flow/Public/Nodes/Operators/FlowNode_LogicalOR.h | 2 ++ Source/Flow/Public/Nodes/Route/FlowNode_Counter.h | 2 ++ Source/Flow/Public/Nodes/Route/FlowNode_CustomInput.h | 2 ++ Source/Flow/Public/Nodes/Route/FlowNode_CustomOutput.h | 2 ++ Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h | 2 ++ Source/Flow/Public/Nodes/Route/FlowNode_ExecutionSequence.h | 2 ++ Source/Flow/Public/Nodes/Route/FlowNode_Finish.h | 2 ++ Source/Flow/Public/Nodes/Route/FlowNode_Reroute.h | 2 ++ Source/Flow/Public/Nodes/Route/FlowNode_Start.h | 2 ++ Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h | 2 ++ Source/Flow/Public/Nodes/Route/FlowNode_Timer.h | 2 ++ Source/Flow/Public/Nodes/Utils/FlowNode_Checkpoint.h | 4 +++- Source/Flow/Public/Nodes/Utils/FlowNode_Log.h | 2 ++ Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h | 2 ++ Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h | 2 ++ Source/Flow/Public/Nodes/World/FlowNode_OnActorRegistered.h | 2 ++ Source/Flow/Public/Nodes/World/FlowNode_OnActorUnregistered.h | 2 ++ Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h | 2 ++ Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h | 2 ++ Source/FlowEditor/FlowEditor.Build.cs | 2 ++ Source/FlowEditor/Public/Asset/AssetTypeActions_FlowAsset.h | 2 ++ Source/FlowEditor/Public/Asset/FlowAssetEditor.h | 2 ++ Source/FlowEditor/Public/Asset/FlowAssetFactory.h | 2 ++ Source/FlowEditor/Public/Asset/FlowAssetIndexer.h | 2 ++ Source/FlowEditor/Public/Asset/FlowAssetToolbar.h | 2 ++ Source/FlowEditor/Public/Asset/FlowDebugger.h | 2 ++ Source/FlowEditor/Public/FlowEditorCommands.h | 2 ++ Source/FlowEditor/Public/FlowEditorModule.h | 2 ++ Source/FlowEditor/Public/FlowEditorStyle.h | 2 ++ Source/FlowEditor/Public/Graph/FlowGraph.h | 2 ++ .../Public/Graph/FlowGraphConnectionDrawingPolicy.h | 2 ++ Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h | 2 ++ Source/FlowEditor/Public/Graph/FlowGraphSchema.h | 2 ++ Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h | 2 ++ Source/FlowEditor/Public/Graph/FlowGraphSettings.h | 2 ++ Source/FlowEditor/Public/Graph/FlowGraphUtils.h | 2 ++ Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h | 2 ++ .../Public/Graph/Nodes/FlowGraphNode_ExecutionSequence.h | 2 ++ Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_Finish.h | 2 ++ Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_Reroute.h | 2 ++ Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_Start.h | 2 ++ Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_SubGraph.h | 2 ++ Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h | 2 ++ .../FlowEditor/Public/Graph/Widgets/SFlowGraphNode_Finish.h | 2 ++ Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode_Start.h | 2 ++ .../FlowEditor/Public/Graph/Widgets/SFlowGraphNode_SubGraph.h | 2 ++ Source/FlowEditor/Public/Graph/Widgets/SFlowPalette.h | 2 ++ Source/FlowEditor/Public/LevelEditor/SLevelEditorFlow.h | 2 ++ .../Public/Nodes/AssetTypeActions_FlowNodeBlueprint.h | 2 ++ Source/FlowEditor/Public/Nodes/FlowNodeBlueprintFactory.h | 2 ++ 106 files changed, 214 insertions(+), 2 deletions(-) diff --git a/Source/Flow/Flow.Build.cs b/Source/Flow/Flow.Build.cs index b03f3b0d0..b69475b87 100644 --- a/Source/Flow/Flow.Build.cs +++ b/Source/Flow/Flow.Build.cs @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + using UnrealBuildTool; public class Flow : ModuleRules diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index cd6e4413e..5ce7a25db 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "FlowAsset.h" #include "FlowSettings.h" #include "FlowSubsystem.h" diff --git a/Source/Flow/Private/FlowComponent.cpp b/Source/Flow/Private/FlowComponent.cpp index 6c7cd669d..15ab6dee4 100644 --- a/Source/Flow/Private/FlowComponent.cpp +++ b/Source/Flow/Private/FlowComponent.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "FlowComponent.h" #include "FlowAsset.h" diff --git a/Source/Flow/Private/FlowModule.cpp b/Source/Flow/Private/FlowModule.cpp index 0b8a9a35d..4c202ca89 100644 --- a/Source/Flow/Private/FlowModule.cpp +++ b/Source/Flow/Private/FlowModule.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "FlowModule.h" #include "Modules/ModuleManager.h" diff --git a/Source/Flow/Private/FlowSettings.cpp b/Source/Flow/Private/FlowSettings.cpp index f31c414ed..c68e3da90 100644 --- a/Source/Flow/Private/FlowSettings.cpp +++ b/Source/Flow/Private/FlowSettings.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "FlowSettings.h" UFlowSettings::UFlowSettings(const FObjectInitializer& ObjectInitializer) diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index d38dea211..8407ef47b 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "FlowSubsystem.h" #include "FlowAsset.h" diff --git a/Source/Flow/Private/FlowWorldSettings.cpp b/Source/Flow/Private/FlowWorldSettings.cpp index 6b3d0af82..82526f4b7 100644 --- a/Source/Flow/Private/FlowWorldSettings.cpp +++ b/Source/Flow/Private/FlowWorldSettings.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "FlowWorldSettings.h" #include "FlowComponent.h" #include "FlowSubsystem.h" diff --git a/Source/Flow/Private/LevelSequence/FlowLevelSequenceActor.cpp b/Source/Flow/Private/LevelSequence/FlowLevelSequenceActor.cpp index 96a3b51ec..4910d7509 100644 --- a/Source/Flow/Private/LevelSequence/FlowLevelSequenceActor.cpp +++ b/Source/Flow/Private/LevelSequence/FlowLevelSequenceActor.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "LevelSequence/FlowLevelSequenceActor.h" #include "LevelSequence/FlowLevelSequencePlayer.h" diff --git a/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp b/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp index 4ce1c28f4..630ab9c14 100644 --- a/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp +++ b/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "LevelSequence/FlowLevelSequencePlayer.h" #include "LevelSequence/FlowLevelSequenceActor.h" #include "Nodes/FlowNode.h" diff --git a/Source/Flow/Private/MovieScene/MovieSceneFlowRepeaterSection.cpp b/Source/Flow/Private/MovieScene/MovieSceneFlowRepeaterSection.cpp index 211a6b578..6aaaa8afc 100644 --- a/Source/Flow/Private/MovieScene/MovieSceneFlowRepeaterSection.cpp +++ b/Source/Flow/Private/MovieScene/MovieSceneFlowRepeaterSection.cpp @@ -1 +1,3 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "MovieScene/MovieSceneFlowRepeaterSection.h" diff --git a/Source/Flow/Private/MovieScene/MovieSceneFlowSectionBase.cpp b/Source/Flow/Private/MovieScene/MovieSceneFlowSectionBase.cpp index 9acb1e42f..0016b8255 100644 --- a/Source/Flow/Private/MovieScene/MovieSceneFlowSectionBase.cpp +++ b/Source/Flow/Private/MovieScene/MovieSceneFlowSectionBase.cpp @@ -1 +1,3 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "MovieScene/MovieSceneFlowSectionBase.h" diff --git a/Source/Flow/Private/MovieScene/MovieSceneFlowTemplate.cpp b/Source/Flow/Private/MovieScene/MovieSceneFlowTemplate.cpp index 5fd6dc681..6e953a52c 100644 --- a/Source/Flow/Private/MovieScene/MovieSceneFlowTemplate.cpp +++ b/Source/Flow/Private/MovieScene/MovieSceneFlowTemplate.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "MovieScene/MovieSceneFlowTemplate.h" #include "MovieScene/MovieSceneFlowTrack.h" #include "Nodes/World/FlowNode_PlayLevelSequence.h" diff --git a/Source/Flow/Private/MovieScene/MovieSceneFlowTrack.cpp b/Source/Flow/Private/MovieScene/MovieSceneFlowTrack.cpp index e67cb9ac5..cb47fe513 100644 --- a/Source/Flow/Private/MovieScene/MovieSceneFlowTrack.cpp +++ b/Source/Flow/Private/MovieScene/MovieSceneFlowTrack.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "MovieScene/MovieSceneFlowTrack.h" #include "MovieScene/MovieSceneFlowRepeaterSection.h" #include "MovieScene/MovieSceneFlowTemplate.h" diff --git a/Source/Flow/Private/MovieScene/MovieSceneFlowTriggerSection.cpp b/Source/Flow/Private/MovieScene/MovieSceneFlowTriggerSection.cpp index a81d575b5..d1cc40a7e 100644 --- a/Source/Flow/Private/MovieScene/MovieSceneFlowTriggerSection.cpp +++ b/Source/Flow/Private/MovieScene/MovieSceneFlowTriggerSection.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "MovieScene/MovieSceneFlowTriggerSection.h" #include "Channels/MovieSceneChannelProxy.h" diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index fa1eda07d..dc749707c 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Nodes/FlowNode.h" #include "FlowAsset.h" diff --git a/Source/Flow/Private/Nodes/FlowNodeBlueprint.cpp b/Source/Flow/Private/Nodes/FlowNodeBlueprint.cpp index 8b06d0bfc..8d9b7969b 100644 --- a/Source/Flow/Private/Nodes/FlowNodeBlueprint.cpp +++ b/Source/Flow/Private/Nodes/FlowNodeBlueprint.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Nodes/FlowNodeBlueprint.h" UFlowNodeBlueprint::UFlowNodeBlueprint(const FObjectInitializer& ObjectInitializer) diff --git a/Source/Flow/Private/Nodes/FlowPin.cpp b/Source/Flow/Private/Nodes/FlowPin.cpp index 8faca4ae1..7401df83d 100644 --- a/Source/Flow/Private/Nodes/FlowPin.cpp +++ b/Source/Flow/Private/Nodes/FlowPin.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Nodes/FlowPin.h" #if !UE_BUILD_SHIPPING diff --git a/Source/Flow/Private/Nodes/Operators/FlowNode_LogicalAND.cpp b/Source/Flow/Private/Nodes/Operators/FlowNode_LogicalAND.cpp index 4d57bc96a..753bed54a 100644 --- a/Source/Flow/Private/Nodes/Operators/FlowNode_LogicalAND.cpp +++ b/Source/Flow/Private/Nodes/Operators/FlowNode_LogicalAND.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Nodes/Operators/FlowNode_LogicalAND.h" UFlowNode_LogicalAND::UFlowNode_LogicalAND(const FObjectInitializer& ObjectInitializer) diff --git a/Source/Flow/Private/Nodes/Operators/FlowNode_LogicalOR.cpp b/Source/Flow/Private/Nodes/Operators/FlowNode_LogicalOR.cpp index 5b1dcc0ad..f814ee709 100644 --- a/Source/Flow/Private/Nodes/Operators/FlowNode_LogicalOR.cpp +++ b/Source/Flow/Private/Nodes/Operators/FlowNode_LogicalOR.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Nodes/Operators/FlowNode_LogicalOR.h" UFlowNode_LogicalOR::UFlowNode_LogicalOR(const FObjectInitializer& ObjectInitializer) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_Counter.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_Counter.cpp index 8ab4dd443..5a4eaf50c 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_Counter.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_Counter.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Nodes/Route/FlowNode_Counter.h" UFlowNode_Counter::UFlowNode_Counter(const FObjectInitializer& ObjectInitializer) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp index 06a61ae40..a4f2f6aca 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Nodes/Route/FlowNode_CustomInput.h" UFlowNode_CustomInput::UFlowNode_CustomInput(const FObjectInitializer& ObjectInitializer) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp index 64d907f3e..fe32ed2ae 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Nodes/Route/FlowNode_CustomOutput.h" #include "FlowAsset.h" diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionMultiGate.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionMultiGate.cpp index 0b8858177..c8ca5016b 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionMultiGate.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionMultiGate.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Nodes/Route/FlowNode_ExecutionMultiGate.h" UFlowNode_ExecutionMultiGate::UFlowNode_ExecutionMultiGate(const FObjectInitializer& ObjectInitializer) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionSequence.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionSequence.cpp index 4aacc2667..93afd9dd9 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionSequence.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionSequence.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Nodes/Route/FlowNode_ExecutionSequence.h" UFlowNode_ExecutionSequence::UFlowNode_ExecutionSequence(const FObjectInitializer& ObjectInitializer) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_Finish.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_Finish.cpp index 9012dec8b..ba6a5e635 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_Finish.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_Finish.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Nodes/Route/FlowNode_Finish.h" UFlowNode_Finish::UFlowNode_Finish(const FObjectInitializer& ObjectInitializer) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_Reroute.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_Reroute.cpp index 181172ea7..3f002b6bd 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_Reroute.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_Reroute.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Nodes/Route/FlowNode_Reroute.h" UFlowNode_Reroute::UFlowNode_Reroute(const FObjectInitializer& ObjectInitializer) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_Start.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_Start.cpp index 82d7d3024..746c01adf 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_Start.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_Start.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Nodes/Route/FlowNode_Start.h" UFlowNode_Start::UFlowNode_Start(const FObjectInitializer& ObjectInitializer) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp index 9a4838848..c1949bd28 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Nodes/Route/FlowNode_SubGraph.h" #include "FlowAsset.h" diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp index 66607ec12..d55703707 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Nodes/Route/FlowNode_Timer.h" #include "Engine/World.h" diff --git a/Source/Flow/Private/Nodes/Utils/FlowNode_Checkpoint.cpp b/Source/Flow/Private/Nodes/Utils/FlowNode_Checkpoint.cpp index a8e44589c..1cdd9e280 100644 --- a/Source/Flow/Private/Nodes/Utils/FlowNode_Checkpoint.cpp +++ b/Source/Flow/Private/Nodes/Utils/FlowNode_Checkpoint.cpp @@ -1,4 +1,6 @@ -#include "Nodes/Utils/FlowNode_Checkpoint.h" +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#include "Nodes/Utils/FlowNode_Checkpoint.h" #include "FlowSubsystem.h" #include "Kismet/GameplayStatics.h" diff --git a/Source/Flow/Private/Nodes/Utils/FlowNode_Log.cpp b/Source/Flow/Private/Nodes/Utils/FlowNode_Log.cpp index 7bb1f628c..5da89a4e4 100644 --- a/Source/Flow/Private/Nodes/Utils/FlowNode_Log.cpp +++ b/Source/Flow/Private/Nodes/Utils/FlowNode_Log.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Nodes/Utils/FlowNode_Log.h" #include "FlowModule.h" diff --git a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp index 21c72bf4d..beefe0e87 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Nodes/World/FlowNode_ComponentObserver.h" #include "FlowSubsystem.h" diff --git a/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp b/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp index a2f5d71bb..f9f9c4819 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Nodes/World/FlowNode_NotifyActor.h" #include "FlowComponent.h" #include "FlowSubsystem.h" diff --git a/Source/Flow/Private/Nodes/World/FlowNode_OnActorRegistered.cpp b/Source/Flow/Private/Nodes/World/FlowNode_OnActorRegistered.cpp index d8440a0e7..6ad8ca537 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_OnActorRegistered.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_OnActorRegistered.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Nodes/World/FlowNode_OnActorRegistered.h" UFlowNode_OnActorRegistered::UFlowNode_OnActorRegistered(const FObjectInitializer& ObjectInitializer) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_OnActorUnregistered.cpp b/Source/Flow/Private/Nodes/World/FlowNode_OnActorUnregistered.cpp index db89089e8..a802ff41e 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_OnActorUnregistered.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_OnActorUnregistered.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Nodes/World/FlowNode_OnActorUnregistered.h" UFlowNode_OnActorUnregistered::UFlowNode_OnActorUnregistered(const FObjectInitializer& ObjectInitializer) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp b/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp index 131128097..4e64bbec1 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Nodes/World/FlowNode_OnNotifyFromActor.h" #include "FlowComponent.h" diff --git a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp index 02370e60a..ec4a3a74e 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Nodes/World/FlowNode_PlayLevelSequence.h" #include "FlowAsset.h" diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 9d64020aa..62b3d5a64 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "CoreMinimal.h" diff --git a/Source/Flow/Public/FlowComponent.h b/Source/Flow/Public/FlowComponent.h index 103898698..f94fe995e 100644 --- a/Source/Flow/Public/FlowComponent.h +++ b/Source/Flow/Public/FlowComponent.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Components/ActorComponent.h" diff --git a/Source/Flow/Public/FlowModule.h b/Source/Flow/Public/FlowModule.h index ef7b470ed..9244e2be4 100644 --- a/Source/Flow/Public/FlowModule.h +++ b/Source/Flow/Public/FlowModule.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Logging/LogMacros.h" diff --git a/Source/Flow/Public/FlowSave.h b/Source/Flow/Public/FlowSave.h index 377d4e2cd..fc9e939ef 100644 --- a/Source/Flow/Public/FlowSave.h +++ b/Source/Flow/Public/FlowSave.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "CoreMinimal.h" diff --git a/Source/Flow/Public/FlowSettings.h b/Source/Flow/Public/FlowSettings.h index 608bae1ce..225cbf647 100644 --- a/Source/Flow/Public/FlowSettings.h +++ b/Source/Flow/Public/FlowSettings.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Engine/DeveloperSettings.h" diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index bcd400b8c..cae9da307 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Engine/StreamableManager.h" diff --git a/Source/Flow/Public/FlowTypes.h b/Source/Flow/Public/FlowTypes.h index badf9d24e..11dec7977 100644 --- a/Source/Flow/Public/FlowTypes.h +++ b/Source/Flow/Public/FlowTypes.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "GameplayTagContainer.h" diff --git a/Source/Flow/Public/FlowWorldSettings.h b/Source/Flow/Public/FlowWorldSettings.h index 0098b73aa..b6fb3dffd 100644 --- a/Source/Flow/Public/FlowWorldSettings.h +++ b/Source/Flow/Public/FlowWorldSettings.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "GameFramework/WorldSettings.h" diff --git a/Source/Flow/Public/LevelSequence/FlowLevelSequenceActor.h b/Source/Flow/Public/LevelSequence/FlowLevelSequenceActor.h index 18b0ca75d..966d7e9c5 100644 --- a/Source/Flow/Public/LevelSequence/FlowLevelSequenceActor.h +++ b/Source/Flow/Public/LevelSequence/FlowLevelSequenceActor.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "LevelSequenceActor.h" diff --git a/Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h b/Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h index d7cbceeaa..08d1771ac 100644 --- a/Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h +++ b/Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "LevelSequencePlayer.h" diff --git a/Source/Flow/Public/MovieScene/MovieSceneFlowRepeaterSection.h b/Source/Flow/Public/MovieScene/MovieSceneFlowRepeaterSection.h index 118c3138d..3642103f6 100644 --- a/Source/Flow/Public/MovieScene/MovieSceneFlowRepeaterSection.h +++ b/Source/Flow/Public/MovieScene/MovieSceneFlowRepeaterSection.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "MovieSceneFlowSectionBase.h" diff --git a/Source/Flow/Public/MovieScene/MovieSceneFlowSectionBase.h b/Source/Flow/Public/MovieScene/MovieSceneFlowSectionBase.h index d41f972d7..6ea290bc2 100644 --- a/Source/Flow/Public/MovieScene/MovieSceneFlowSectionBase.h +++ b/Source/Flow/Public/MovieScene/MovieSceneFlowSectionBase.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "MovieSceneSection.h" diff --git a/Source/Flow/Public/MovieScene/MovieSceneFlowTemplate.h b/Source/Flow/Public/MovieScene/MovieSceneFlowTemplate.h index 4d8f08ff5..47ff27af4 100644 --- a/Source/Flow/Public/MovieScene/MovieSceneFlowTemplate.h +++ b/Source/Flow/Public/MovieScene/MovieSceneFlowTemplate.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Evaluation/MovieSceneEvalTemplate.h" diff --git a/Source/Flow/Public/MovieScene/MovieSceneFlowTrack.h b/Source/Flow/Public/MovieScene/MovieSceneFlowTrack.h index af7f07f4d..3b7f921ef 100644 --- a/Source/Flow/Public/MovieScene/MovieSceneFlowTrack.h +++ b/Source/Flow/Public/MovieScene/MovieSceneFlowTrack.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Tracks/MovieSceneEventTrack.h" diff --git a/Source/Flow/Public/MovieScene/MovieSceneFlowTriggerSection.h b/Source/Flow/Public/MovieScene/MovieSceneFlowTriggerSection.h index 880beb995..1650cd373 100644 --- a/Source/Flow/Public/MovieScene/MovieSceneFlowTriggerSection.h +++ b/Source/Flow/Public/MovieScene/MovieSceneFlowTriggerSection.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Channels/MovieSceneStringChannel.h" diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 3457f10cf..55bed68ab 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "CoreMinimal.h" diff --git a/Source/Flow/Public/Nodes/FlowNodeBlueprint.h b/Source/Flow/Public/Nodes/FlowNodeBlueprint.h index 51b58df2a..32f82c4ba 100644 --- a/Source/Flow/Public/Nodes/FlowNodeBlueprint.h +++ b/Source/Flow/Public/Nodes/FlowNodeBlueprint.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "CoreMinimal.h" diff --git a/Source/Flow/Public/Nodes/FlowPin.h b/Source/Flow/Public/Nodes/FlowPin.h index d800334aa..ad09e6e99 100644 --- a/Source/Flow/Public/Nodes/FlowPin.h +++ b/Source/Flow/Public/Nodes/FlowPin.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "FlowPin.generated.h" diff --git a/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalAND.h b/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalAND.h index 1b27942fd..b646bf773 100644 --- a/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalAND.h +++ b/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalAND.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Nodes/FlowNode.h" diff --git a/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalOR.h b/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalOR.h index 6abdd48af..75828dab9 100644 --- a/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalOR.h +++ b/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalOR.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Nodes/FlowNode.h" diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_Counter.h b/Source/Flow/Public/Nodes/Route/FlowNode_Counter.h index 0bce7ea28..8346814d5 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_Counter.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_Counter.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Nodes/FlowNode.h" diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_CustomInput.h b/Source/Flow/Public/Nodes/Route/FlowNode_CustomInput.h index 9a0e244c9..be86208af 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_CustomInput.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_CustomInput.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Nodes/FlowNode.h" diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_CustomOutput.h b/Source/Flow/Public/Nodes/Route/FlowNode_CustomOutput.h index d1ec007c6..9e430b267 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_CustomOutput.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_CustomOutput.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Nodes/FlowNode.h" diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h index 29c03f6f8..da039c221 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Nodes/FlowNode.h" diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionSequence.h b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionSequence.h index 69b99cfe3..bda6e8e57 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionSequence.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionSequence.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Nodes/FlowNode.h" diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_Finish.h b/Source/Flow/Public/Nodes/Route/FlowNode_Finish.h index 832bf9e39..d5d4c59af 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_Finish.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_Finish.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Nodes/FlowNode.h" diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_Reroute.h b/Source/Flow/Public/Nodes/Route/FlowNode_Reroute.h index f4e17eea9..3556dbe91 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_Reroute.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_Reroute.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Nodes/FlowNode.h" diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_Start.h b/Source/Flow/Public/Nodes/Route/FlowNode_Start.h index 50af14bde..9a0a09525 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_Start.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_Start.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Nodes/FlowNode.h" diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h b/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h index 2a4c0fe35..522540f25 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Nodes/FlowNode.h" diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h b/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h index 6ac241602..0d9154ad2 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Engine/EngineTypes.h" diff --git a/Source/Flow/Public/Nodes/Utils/FlowNode_Checkpoint.h b/Source/Flow/Public/Nodes/Utils/FlowNode_Checkpoint.h index 640f4d394..cc2b4dac8 100644 --- a/Source/Flow/Public/Nodes/Utils/FlowNode_Checkpoint.h +++ b/Source/Flow/Public/Nodes/Utils/FlowNode_Checkpoint.h @@ -1,4 +1,6 @@ -#pragma once +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#pragma once #include "Nodes/FlowNode.h" #include "FlowNode_Checkpoint.generated.h" diff --git a/Source/Flow/Public/Nodes/Utils/FlowNode_Log.h b/Source/Flow/Public/Nodes/Utils/FlowNode_Log.h index c429ad2a2..5c74fcc5b 100644 --- a/Source/Flow/Public/Nodes/Utils/FlowNode_Log.h +++ b/Source/Flow/Public/Nodes/Utils/FlowNode_Log.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Nodes/FlowNode.h" diff --git a/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h b/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h index 351ea5276..f8b2c95a1 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "GameplayTagContainer.h" diff --git a/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h b/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h index 6d0f1a428..26a072f95 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "GameplayTagContainer.h" diff --git a/Source/Flow/Public/Nodes/World/FlowNode_OnActorRegistered.h b/Source/Flow/Public/Nodes/World/FlowNode_OnActorRegistered.h index ae1da3b69..59882d377 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_OnActorRegistered.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_OnActorRegistered.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Nodes/World/FlowNode_ComponentObserver.h" diff --git a/Source/Flow/Public/Nodes/World/FlowNode_OnActorUnregistered.h b/Source/Flow/Public/Nodes/World/FlowNode_OnActorUnregistered.h index ffd4a246a..fccad314e 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_OnActorUnregistered.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_OnActorUnregistered.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Nodes/World/FlowNode_ComponentObserver.h" diff --git a/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h b/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h index 251c2c0b3..7c863fde9 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Nodes/World/FlowNode_ComponentObserver.h" diff --git a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h index 5feb95658..c44f3295c 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "EngineDefines.h" diff --git a/Source/FlowEditor/FlowEditor.Build.cs b/Source/FlowEditor/FlowEditor.Build.cs index 53d252d5c..9623bb4ab 100644 --- a/Source/FlowEditor/FlowEditor.Build.cs +++ b/Source/FlowEditor/FlowEditor.Build.cs @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + using UnrealBuildTool; public class FlowEditor : ModuleRules diff --git a/Source/FlowEditor/Public/Asset/AssetTypeActions_FlowAsset.h b/Source/FlowEditor/Public/Asset/AssetTypeActions_FlowAsset.h index 6ae3b99cf..b6f28e659 100644 --- a/Source/FlowEditor/Public/Asset/AssetTypeActions_FlowAsset.h +++ b/Source/FlowEditor/Public/Asset/AssetTypeActions_FlowAsset.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "AssetTypeActions_Base.h" diff --git a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h index a2e9df3c1..682f8aab0 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "EditorUndoClient.h" diff --git a/Source/FlowEditor/Public/Asset/FlowAssetFactory.h b/Source/FlowEditor/Public/Asset/FlowAssetFactory.h index 5dc8e3c3b..b8a3f93a3 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetFactory.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetFactory.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Factories/Factory.h" diff --git a/Source/FlowEditor/Public/Asset/FlowAssetIndexer.h b/Source/FlowEditor/Public/Asset/FlowAssetIndexer.h index 736f4e7cf..859b6c177 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetIndexer.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetIndexer.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "CoreMinimal.h" diff --git a/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h b/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h index 212e00c55..1b0269ad7 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Widgets/Input/SComboBox.h" diff --git a/Source/FlowEditor/Public/Asset/FlowDebugger.h b/Source/FlowEditor/Public/Asset/FlowDebugger.h index 01a8336c1..1487e20c9 100644 --- a/Source/FlowEditor/Public/Asset/FlowDebugger.h +++ b/Source/FlowEditor/Public/Asset/FlowDebugger.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "CoreMinimal.h" diff --git a/Source/FlowEditor/Public/FlowEditorCommands.h b/Source/FlowEditor/Public/FlowEditorCommands.h index 9f3045992..c608d364f 100644 --- a/Source/FlowEditor/Public/FlowEditorCommands.h +++ b/Source/FlowEditor/Public/FlowEditorCommands.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "EdGraph/EdGraphSchema.h" diff --git a/Source/FlowEditor/Public/FlowEditorModule.h b/Source/FlowEditor/Public/FlowEditorModule.h index 9bb0a37c4..36673d8a0 100644 --- a/Source/FlowEditor/Public/FlowEditorModule.h +++ b/Source/FlowEditor/Public/FlowEditorModule.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "AssetTypeCategories.h" diff --git a/Source/FlowEditor/Public/FlowEditorStyle.h b/Source/FlowEditor/Public/FlowEditorStyle.h index b25dbbb0b..0aa06b843 100644 --- a/Source/FlowEditor/Public/FlowEditorStyle.h +++ b/Source/FlowEditor/Public/FlowEditorStyle.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Styling/SlateStyle.h" diff --git a/Source/FlowEditor/Public/Graph/FlowGraph.h b/Source/FlowEditor/Public/Graph/FlowGraph.h index e41e22f8a..9ca219976 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraph.h +++ b/Source/FlowEditor/Public/Graph/FlowGraph.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "EdGraph/EdGraph.h" diff --git a/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h b/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h index d4a954c74..1cf9ea48c 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "ConnectionDrawingPolicy.h" diff --git a/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h b/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h index be8230863..06122b1da 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "FlowGraphConnectionDrawingPolicy.h" diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h index 9f4d00189..6e8bbc397 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "EdGraph/EdGraphSchema.h" diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h b/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h index 1d7eb3ea1..5cbd54c69 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "EdGraph/EdGraphSchema.h" diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h index abda02ed0..c114be373 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "FlowGraphConnectionDrawingPolicy.h" diff --git a/Source/FlowEditor/Public/Graph/FlowGraphUtils.h b/Source/FlowEditor/Public/Graph/FlowGraphUtils.h index 29441e89b..c9d8f7f8d 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphUtils.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphUtils.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "CoreMinimal.h" diff --git a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h index 9fcbe64f8..93d9fd202 100644 --- a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h +++ b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "EdGraph/EdGraphNode.h" diff --git a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_ExecutionSequence.h b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_ExecutionSequence.h index ec3c5dd1f..d7a4e1b9f 100644 --- a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_ExecutionSequence.h +++ b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_ExecutionSequence.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Graph/Nodes/FlowGraphNode.h" diff --git a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_Finish.h b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_Finish.h index 2124d0b02..c8e2ac632 100644 --- a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_Finish.h +++ b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_Finish.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Graph/Nodes/FlowGraphNode.h" diff --git a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_Reroute.h b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_Reroute.h index e69b1d158..41364c825 100644 --- a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_Reroute.h +++ b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_Reroute.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Graph/Nodes/FlowGraphNode.h" diff --git a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_Start.h b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_Start.h index 6e7b4540f..c69e23433 100644 --- a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_Start.h +++ b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_Start.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Graph/Nodes/FlowGraphNode.h" diff --git a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_SubGraph.h b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_SubGraph.h index dea2d4d4b..ae9f1c682 100644 --- a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_SubGraph.h +++ b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_SubGraph.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Graph/Nodes/FlowGraphNode.h" diff --git a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h index e69f46e49..a4fceb3ed 100644 --- a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h +++ b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "SGraphNode.h" diff --git a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode_Finish.h b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode_Finish.h index 7ce3ce865..f68137550 100644 --- a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode_Finish.h +++ b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode_Finish.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Graph/Widgets/SFlowGraphNode.h" diff --git a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode_Start.h b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode_Start.h index f5baa839f..80c7946e5 100644 --- a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode_Start.h +++ b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode_Start.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Graph/Widgets/SFlowGraphNode.h" diff --git a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode_SubGraph.h b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode_SubGraph.h index 95f7dde17..a88348351 100644 --- a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode_SubGraph.h +++ b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode_SubGraph.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Graph/Widgets/SFlowGraphNode.h" diff --git a/Source/FlowEditor/Public/Graph/Widgets/SFlowPalette.h b/Source/FlowEditor/Public/Graph/Widgets/SFlowPalette.h index 55066f3e4..c30f9d28a 100644 --- a/Source/FlowEditor/Public/Graph/Widgets/SFlowPalette.h +++ b/Source/FlowEditor/Public/Graph/Widgets/SFlowPalette.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "SGraphPalette.h" diff --git a/Source/FlowEditor/Public/LevelEditor/SLevelEditorFlow.h b/Source/FlowEditor/Public/LevelEditor/SLevelEditorFlow.h index f9dd30881..5d4be19b0 100644 --- a/Source/FlowEditor/Public/LevelEditor/SLevelEditorFlow.h +++ b/Source/FlowEditor/Public/LevelEditor/SLevelEditorFlow.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "CoreMinimal.h" diff --git a/Source/FlowEditor/Public/Nodes/AssetTypeActions_FlowNodeBlueprint.h b/Source/FlowEditor/Public/Nodes/AssetTypeActions_FlowNodeBlueprint.h index 1d2a2a447..201124de5 100644 --- a/Source/FlowEditor/Public/Nodes/AssetTypeActions_FlowNodeBlueprint.h +++ b/Source/FlowEditor/Public/Nodes/AssetTypeActions_FlowNodeBlueprint.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "AssetTypeActions/AssetTypeActions_Blueprint.h" diff --git a/Source/FlowEditor/Public/Nodes/FlowNodeBlueprintFactory.h b/Source/FlowEditor/Public/Nodes/FlowNodeBlueprintFactory.h index 1a966bc1f..cec3d3a25 100644 --- a/Source/FlowEditor/Public/Nodes/FlowNodeBlueprintFactory.h +++ b/Source/FlowEditor/Public/Nodes/FlowNodeBlueprintFactory.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "Factories/Factory.h" From 514d4d8b76e0ad76d67f5792f75f5c746a37f933 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 22 May 2022 15:34:02 +0200 Subject: [PATCH 105/338] CIS fix --- Source/Flow/Private/FlowComponent.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Flow/Private/FlowComponent.cpp b/Source/Flow/Private/FlowComponent.cpp index 15ab6dee4..62dcf3964 100644 --- a/Source/Flow/Private/FlowComponent.cpp +++ b/Source/Flow/Private/FlowComponent.cpp @@ -7,6 +7,7 @@ #include "FlowSettings.h" #include "FlowSubsystem.h" +#include "Engine/Engine.h" #include "Engine/GameInstance.h" #include "Engine/ViewportStatsSubsystem.h" #include "Engine/World.h" From b0ac0ee63cb6b95a9b1dd38292f65079b8a97336 Mon Sep 17 00:00:00 2001 From: "Satheesh (ryanjon2040)" Date: Sun, 29 May 2022 01:19:49 +0530 Subject: [PATCH 106/338] Double clicking on blueprint node opens it. (#78) --- Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index 3b9174d4a..63e16d8e3 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -903,6 +903,10 @@ void FFlowAssetEditor::OnNodeDoubleClicked(class UEdGraphNode* Node) const } } } + else if (UObject* BlueprintAsset = FlowNode->GetClass()->ClassGeneratedBy) + { + GEditor->GetEditorSubsystem()->OpenEditorForAsset(BlueprintAsset); + } } } From 1b0da2d2953c375708eb3dc84bc1a6f079e4cfc6 Mon Sep 17 00:00:00 2001 From: "Satheesh (ryanjon2040)" Date: Sun, 29 May 2022 01:21:14 +0530 Subject: [PATCH 107/338] Make automatically placed Start node as ghost node. (#65) --- Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp index cd68b5bc3..9f6180f9e 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -77,6 +77,7 @@ void UFlowGraphSchema::CreateDefaultNodesForGraph(UEdGraph& Graph) const { // Start node UFlowGraphNode* NewGraphNode = FFlowGraphSchemaAction_NewNode::CreateNode(&Graph, nullptr, UFlowNode_Start::StaticClass(), FVector2D::ZeroVector); + NewGraphNode->MakeAutomaticallyPlacedGhostNode(); SetNodeMetaData(NewGraphNode, FNodeMetadata::DefaultGraphNode); CastChecked(&Graph)->GetFlowAsset()->HarvestNodeConnections(); From a4a14624df04f32d83a52089150ed49c35410524 Mon Sep 17 00:00:00 2001 From: Joseph Date: Sun, 29 May 2022 04:51:26 +0900 Subject: [PATCH 108/338] Implemented the feature that can set the flow graph (#102) asset owner actor as the original start point for the level sequence. --- .../LevelSequence/FlowLevelSequencePlayer.cpp | 14 ++++++++++++-- .../Nodes/World/FlowNode_PlayLevelSequence.cpp | 11 ++++++++++- .../Public/LevelSequence/FlowLevelSequencePlayer.h | 2 +- .../Nodes/World/FlowNode_PlayLevelSequence.h | 6 ++++++ 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp b/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp index 630ab9c14..61d6f374a 100644 --- a/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp +++ b/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp @@ -2,6 +2,7 @@ #include "LevelSequence/FlowLevelSequencePlayer.h" #include "LevelSequence/FlowLevelSequenceActor.h" +#include "DefaultLevelSequenceInstanceData.h" #include "Nodes/FlowNode.h" UFlowLevelSequencePlayer::UFlowLevelSequencePlayer(const FObjectInitializer& ObjectInitializer) @@ -10,7 +11,7 @@ UFlowLevelSequencePlayer::UFlowLevelSequencePlayer(const FObjectInitializer& Obj { } -UFlowLevelSequencePlayer* UFlowLevelSequencePlayer::CreateFlowLevelSequencePlayer(UObject* WorldContextObject, ULevelSequence* LevelSequence, FMovieSceneSequencePlaybackSettings Settings, FLevelSequenceCameraSettings CameraSettings, ALevelSequenceActor*& OutActor) +UFlowLevelSequencePlayer* UFlowLevelSequencePlayer::CreateFlowLevelSequencePlayer(UObject* WorldContextObject, ULevelSequence* LevelSequence, FMovieSceneSequencePlaybackSettings Settings, FLevelSequenceCameraSettings CameraSettings, AActor* OriginalPointActor, ALevelSequenceActor*& OutActor) { if (LevelSequence == nullptr) { @@ -38,9 +39,18 @@ UFlowLevelSequencePlayer* UFlowLevelSequencePlayer::CreateFlowLevelSequencePlaye Actor->CameraSettings = CameraSettings; Actor->InitializePlayer(); + Actor->bOverrideInstanceData = true; OutActor = Actor; - const FTransform DefaultTransform; + UDefaultLevelSequenceInstanceData* LevelSequenceData = static_cast(Actor->DefaultInstanceData); + if (IsValid(LevelSequenceData) && IsValid(OriginalPointActor)) + { + LevelSequenceData->TransformOrigin = OriginalPointActor->GetTransform(); + } + + // It seems doesn't really matter where the level sequence actor is. + const FTransform DefaultTransform = FTransform(OriginalPointActor->GetActorRotation(), + OriginalPointActor->GetActorLocation(), FVector::OneVector); Actor->FinishSpawning(DefaultTransform); return Cast(Actor->SequencePlayer); diff --git a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp index ec4a3a74e..3c1fa6a60 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp @@ -26,6 +26,7 @@ UFlowNode_PlayLevelSequence::UFlowNode_PlayLevelSequence(const FObjectInitialize , StartTime(0.0f) , ElapsedTime(0.0f) , TimeDilation(1.0f) + , bUseGraphOwnerAsOriginalPointActor(false) { #if WITH_EDITOR Category = TEXT("World"); @@ -150,7 +151,15 @@ void UFlowNode_PlayLevelSequence::CreatePlayer() } } - SequencePlayer = UFlowLevelSequencePlayer::CreateFlowLevelSequencePlayer(this, LoadedSequence, PlaybackSettings, CameraSettings, SequenceActor); + if(bUseGraphOwnerAsOriginalPointActor) + { + SequencePlayer = UFlowLevelSequencePlayer::CreateFlowLevelSequencePlayer(this, LoadedSequence, PlaybackSettings, CameraSettings, OwningActor, SequenceActor); + } + else + { + SequencePlayer = UFlowLevelSequencePlayer::CreateFlowLevelSequencePlayer(this, LoadedSequence, PlaybackSettings, CameraSettings, nullptr, SequenceActor); + } + if (SequencePlayer) { SequencePlayer->SetFlowEventReceiver(this); diff --git a/Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h b/Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h index 08d1771ac..d06db6738 100644 --- a/Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h +++ b/Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h @@ -22,7 +22,7 @@ class FLOW_API UFlowLevelSequencePlayer : public ULevelSequencePlayer public: // variant of ULevelSequencePlayer::CreateLevelSequencePlayer - static UFlowLevelSequencePlayer* CreateFlowLevelSequencePlayer(UObject* WorldContextObject, ULevelSequence* LevelSequence, FMovieSceneSequencePlaybackSettings Settings, FLevelSequenceCameraSettings CameraSettings, ALevelSequenceActor*& OutActor); + static UFlowLevelSequencePlayer* CreateFlowLevelSequencePlayer(UObject* WorldContextObject, ULevelSequence* LevelSequence, FMovieSceneSequencePlaybackSettings Settings, FLevelSequenceCameraSettings CameraSettings, AActor* OriginalPointActor, ALevelSequenceActor*& OutActor); void SetFlowEventReceiver(UFlowNode* FlowNode) { FlowEventReceiver = FlowNode; } diff --git a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h index c44f3295c..83ee042e7 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h @@ -45,6 +45,9 @@ class FLOW_API UFlowNode_PlayLevelSequence : public UFlowNode UPROPERTY(EditAnywhere, Category = "Sequence") FLevelSequenceCameraSettings CameraSettings; + + UPROPERTY(EditAnywhere, Category = "Sequence") + bool bUseGraphOwnerAsOriginalPointActor; protected: UPROPERTY() @@ -53,6 +56,9 @@ class FLOW_API UFlowNode_PlayLevelSequence : public UFlowNode UPROPERTY() UFlowLevelSequencePlayer* SequencePlayer; + UPROPERTY() + AActor* GraphOwner; + // Play Rate set by the user in PlaybackSettings float CachedPlayRate; From c90313627aac14b0602aaef3a65dbbb0868746c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sat, 28 May 2022 22:29:55 +0200 Subject: [PATCH 109/338] PR #65 follow-up: added flag enabling new behavior bStartNodePlacedAsGhostNode is false by default, matching existing behavior --- Source/Flow/Private/FlowAsset.cpp | 1 + Source/Flow/Public/FlowAsset.h | 4 +- .../Private/Graph/FlowGraphSchema.cpp | 42 ++++++++++++------- .../FlowEditor/Public/Graph/FlowGraphSchema.h | 8 +++- 4 files changed, 37 insertions(+), 18 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 5ce7a25db..c7612a560 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -20,6 +20,7 @@ UFlowAsset::UFlowAsset(const FObjectInitializer& ObjectInitializer) , FlowGraph(nullptr) #endif , AllowedNodeClasses({UFlowNode::StaticClass()}) + , bStartNodePlacedAsGhostNode(false) , TemplateAsset(nullptr) , StartNode(nullptr) , FinishPolicy(EFlowFinishPolicy::Keep) diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 62b3d5a64..ca87c6d35 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -86,7 +86,9 @@ class FLOW_API UFlowAsset : public UObject protected: TArray> AllowedNodeClasses; - TArray> DeniedNodeClasses; + TArray> DeniedNodeClasses; + + bool bStartNodePlacedAsGhostNode; private: UPROPERTY() diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp index 9f6180f9e..516118a19 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -49,21 +49,15 @@ void UFlowGraphSchema::SubscribeToAssetChanges() } } -void UFlowGraphSchema::GetPaletteActions(FGraphActionMenuBuilder& ActionMenuBuilder, UClass* AssetClass, const FString& CategoryName) +void UFlowGraphSchema::GetPaletteActions(FGraphActionMenuBuilder& ActionMenuBuilder, const UClass* AssetClass, const FString& CategoryName) { - GetFlowNodeActions(ActionMenuBuilder, AssetClass, CategoryName); + GetFlowNodeActions(ActionMenuBuilder, AssetClass->GetDefaultObject(), CategoryName); GetCommentAction(ActionMenuBuilder); } void UFlowGraphSchema::GetGraphContextActions(FGraphContextMenuBuilder& ContextMenuBuilder) const { - UClass* AssetClass = UFlowAsset::StaticClass(); - if (const UFlowAsset* FlowAsset = ContextMenuBuilder.CurrentGraph->GetTypedOuter()) - { - AssetClass = FlowAsset->GetClass(); - } - - GetFlowNodeActions(ContextMenuBuilder, AssetClass, FString()); + GetFlowNodeActions(ContextMenuBuilder, GetAssetClassDefaults(ContextMenuBuilder.CurrentGraph), FString()); GetCommentAction(ContextMenuBuilder, ContextMenuBuilder.CurrentGraph); if (!ContextMenuBuilder.FromPin && FFlowGraphUtils::GetFlowAssetEditor(ContextMenuBuilder.CurrentGraph)->CanPasteNodes()) @@ -77,9 +71,14 @@ void UFlowGraphSchema::CreateDefaultNodesForGraph(UEdGraph& Graph) const { // Start node UFlowGraphNode* NewGraphNode = FFlowGraphSchemaAction_NewNode::CreateNode(&Graph, nullptr, UFlowNode_Start::StaticClass(), FVector2D::ZeroVector); - NewGraphNode->MakeAutomaticallyPlacedGhostNode(); SetNodeMetaData(NewGraphNode, FNodeMetadata::DefaultGraphNode); + const UFlowAsset* AssetClassDefaults = GetAssetClassDefaults(&Graph); + if (AssetClassDefaults && AssetClassDefaults->bStartNodePlacedAsGhostNode) + { + NewGraphNode->MakeAutomaticallyPlacedGhostNode(); + } + CastChecked(&Graph)->GetFlowAsset()->HarvestNodeConnections(); } @@ -257,21 +256,19 @@ bool UFlowGraphSchema::IsClassContained(const TArray> Cla return false; } -void UFlowGraphSchema::GetFlowNodeActions(FGraphActionMenuBuilder& ActionMenuBuilder, UClass* AssetClass, const FString& CategoryName) +void UFlowGraphSchema::GetFlowNodeActions(FGraphActionMenuBuilder& ActionMenuBuilder, const UFlowAsset* AssetClassDefaults, const FString& CategoryName) { if (NativeFlowNodes.Num() == 0) { GatherFlowNodes(); } - // get actual asset type, as it might limit which nodes are placeable - const UFlowAsset* AssetClassDefaults = AssetClass->GetDefaultObject(); - TArray FlowNodes; FlowNodes.Reserve(NativeFlowNodes.Num() + BlueprintFlowNodes.Num()); for (const UClass* FlowNodeClass : NativeFlowNodes) { + // Flow Asset type might limit which nodes are placeable if (IsClassContained(AssetClassDefaults->DeniedNodeClasses, FlowNodeClass)) { continue; @@ -440,7 +437,7 @@ void UFlowGraphSchema::AddAsset(const FAssetData& AssetData, const bool bBatch) { UObject* Outer = nullptr; ResolveName(Outer, NativeParentClassPath, false, false); - UClass* NativeParentClass = FindObject(ANY_PACKAGE, *NativeParentClassPath); + const UClass* NativeParentClass = FindObject(ANY_PACKAGE, *NativeParentClassPath); // accept only Flow Node blueprints if (NativeParentClass && NativeParentClass->IsChildOf(UFlowNode::StaticClass())) @@ -478,4 +475,19 @@ UBlueprint* UFlowGraphSchema::GetPlaceableNodeBlueprint(const FAssetData& AssetD return nullptr; } +const UFlowAsset* UFlowGraphSchema::GetAssetClassDefaults(const UEdGraph* Graph) +{ + const UClass* AssetClass = UFlowAsset::StaticClass(); + + if (Graph) + { + if (const UFlowAsset* FlowAsset = Graph->GetTypedOuter()) + { + AssetClass = FlowAsset->GetClass(); + } + } + + return AssetClass->GetDefaultObject(); +} + #undef LOCTEXT_NAMESPACE diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h index 6e8bbc397..ed4110b81 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h @@ -5,6 +5,8 @@ #include "EdGraph/EdGraphSchema.h" #include "FlowGraphSchema.generated.h" +class UFlowAsset; + DECLARE_MULTICAST_DELEGATE(FFlowGraphSchemaRefresh); UCLASS() @@ -21,7 +23,7 @@ class FLOWEDITOR_API UFlowGraphSchema : public UEdGraphSchema public: static void SubscribeToAssetChanges(); - static void GetPaletteActions(FGraphActionMenuBuilder& ActionMenuBuilder, UClass* AssetClass, const FString& CategoryName); + static void GetPaletteActions(FGraphActionMenuBuilder& ActionMenuBuilder, const UClass* AssetClass, const FString& CategoryName); // EdGraphSchema virtual void GetGraphContextActions(FGraphContextMenuBuilder& ContextMenuBuilder) const override; @@ -42,7 +44,7 @@ class FLOWEDITOR_API UFlowGraphSchema : public UEdGraphSchema private: static bool IsClassContained(const TArray> Classes, const UClass* Class); - static void GetFlowNodeActions(FGraphActionMenuBuilder& ActionMenuBuilder, UClass* AssetClass, const FString& CategoryName); + static void GetFlowNodeActions(FGraphActionMenuBuilder& ActionMenuBuilder, const UFlowAsset* AssetClassDefaults, const FString& CategoryName); static void GetCommentAction(FGraphActionMenuBuilder& ActionMenuBuilder, const UEdGraph* CurrentGraph = nullptr); static bool IsFlowNodePlaceable(const UClass* Class); @@ -60,4 +62,6 @@ class FLOWEDITOR_API UFlowGraphSchema : public UEdGraphSchema public: static FFlowGraphSchemaRefresh OnNodeListChanged; static UBlueprint* GetPlaceableNodeBlueprint(const FAssetData& AssetData); + + static const UFlowAsset* GetAssetClassDefaults(const UEdGraph* Graph); }; From d6ff851d1bbddb5e7838f99eeded3840f96e0bfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sat, 28 May 2022 22:30:09 +0200 Subject: [PATCH 110/338] const correctness --- Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp | 6 +++--- Source/FlowEditor/Public/Graph/Widgets/SFlowPalette.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp index a03a8990e..a92f47a8b 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp @@ -48,7 +48,7 @@ void SFlowPaletteItem::Construct(const FArguments& InArgs, FCreateWidgetForActio const FSlateBrush* IconBrush = FEditorStyle::GetBrush(TEXT("NoBrush")); const FSlateColor IconColor = FSlateColor::UseForeground(); const FText IconToolTip = GraphAction->GetTooltipDescription(); - const bool bIsReadOnly = false; + constexpr bool bIsReadOnly = false; const TSharedRef IconWidget = CreateIconWidget(IconToolTip, IconBrush, IconColor); const TSharedRef NameSlotWidget = CreateTextSlotWidget(InCreateData, bIsReadOnly); @@ -181,7 +181,7 @@ TSharedRef SFlowPalette::OnCreateWidgetForAction(FCreateWidgetForAction void SFlowPalette::CollectAllActions(FGraphActionListBuilderBase& OutAllActions) { - UClass* AssetClass = UFlowAsset::StaticClass(); + const UClass* AssetClass = UFlowAsset::StaticClass(); const TSharedPtr FlowAssetEditor = FlowAssetEditorPtr.Pin(); if (FlowAssetEditor && FlowAssetEditor->GetFlowAsset()) @@ -209,7 +209,7 @@ void SFlowPalette::CategorySelectionChanged(TSharedPtr NewSelection, ES RefreshActionsList(true); } -void SFlowPalette::OnActionSelected(const TArray>& InActions, ESelectInfo::Type InSelectionType) +void SFlowPalette::OnActionSelected(const TArray>& InActions, ESelectInfo::Type InSelectionType) const { if (InSelectionType == ESelectInfo::OnMouseClick || InSelectionType == ESelectInfo::OnKeyPress || InSelectionType == ESelectInfo::OnNavigation || InActions.Num() == 0) { diff --git a/Source/FlowEditor/Public/Graph/Widgets/SFlowPalette.h b/Source/FlowEditor/Public/Graph/Widgets/SFlowPalette.h index c30f9d28a..d11873ef3 100644 --- a/Source/FlowEditor/Public/Graph/Widgets/SFlowPalette.h +++ b/Source/FlowEditor/Public/Graph/Widgets/SFlowPalette.h @@ -28,7 +28,7 @@ class SFlowPalette : public SGraphPalette SLATE_END_ARGS() void Construct(const FArguments& InArgs, TWeakPtr InFlowAssetEditor); - virtual ~SFlowPalette(); + virtual ~SFlowPalette() override; protected: void Refresh(); @@ -42,7 +42,7 @@ class SFlowPalette : public SGraphPalette FString GetFilterCategoryName() const; void CategorySelectionChanged(TSharedPtr NewSelection, ESelectInfo::Type SelectInfo); - void OnActionSelected(const TArray>& InActions, ESelectInfo::Type InSelectionType); + void OnActionSelected(const TArray>& InActions, ESelectInfo::Type InSelectionType) const; public: void ClearGraphActionMenuSelection() const; From 540fc7ba3cf7d67cc9638fee35b6e7df4ab9def2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sat, 28 May 2022 22:30:40 +0200 Subject: [PATCH 111/338] #102 compilation fix --- .../Nodes/World/FlowNode_PlayLevelSequence.cpp | 11 ++++++----- .../Public/Nodes/World/FlowNode_PlayLevelSequence.h | 6 +++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp index 3c1fa6a60..01bd6d07a 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp @@ -20,13 +20,14 @@ UFlowNode_PlayLevelSequence::UFlowNode_PlayLevelSequence(const FObjectInitialize : Super(ObjectInitializer) , bPlayReverse(false) , bApplyOwnerTimeDilation(true) + , bUseGraphOwnerAsOriginalPointActor(false) , LoadedSequence(nullptr) , SequencePlayer(nullptr) , CachedPlayRate(0) , StartTime(0.0f) , ElapsedTime(0.0f) , TimeDilation(1.0f) - , bUseGraphOwnerAsOriginalPointActor(false) + , GraphOwner(nullptr) { #if WITH_EDITOR Category = TEXT("World"); @@ -151,15 +152,15 @@ void UFlowNode_PlayLevelSequence::CreatePlayer() } } - if(bUseGraphOwnerAsOriginalPointActor) + if (bUseGraphOwnerAsOriginalPointActor) { - SequencePlayer = UFlowLevelSequencePlayer::CreateFlowLevelSequencePlayer(this, LoadedSequence, PlaybackSettings, CameraSettings, OwningActor, SequenceActor); + SequencePlayer = UFlowLevelSequencePlayer::CreateFlowLevelSequencePlayer(this, LoadedSequence, PlaybackSettings, CameraSettings, GraphOwner, SequenceActor); } else { SequencePlayer = UFlowLevelSequencePlayer::CreateFlowLevelSequencePlayer(this, LoadedSequence, PlaybackSettings, CameraSettings, nullptr, SequenceActor); } - + if (SequencePlayer) { SequencePlayer->SetFlowEventReceiver(this); @@ -231,7 +232,7 @@ void UFlowNode_PlayLevelSequence::OnLoad_Implementation() SequencePlayer->OnFinished.AddDynamic(this, &UFlowNode_PlayLevelSequence::OnPlaybackFinished); SequencePlayer->SetPlaybackPosition(FMovieSceneSequencePlaybackParams(ElapsedTime, EUpdatePositionMethod::Jump)); - + // Take into account Play Rate set in the Playback Settings SequencePlayer->SetPlayRate(TimeDilation * CachedPlayRate); diff --git a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h index 83ee042e7..ac2c9e37e 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h @@ -56,9 +56,6 @@ class FLOW_API UFlowNode_PlayLevelSequence : public UFlowNode UPROPERTY() UFlowLevelSequencePlayer* SequencePlayer; - UPROPERTY() - AActor* GraphOwner; - // Play Rate set by the user in PlaybackSettings float CachedPlayRate; @@ -71,6 +68,9 @@ class FLOW_API UFlowNode_PlayLevelSequence : public UFlowNode UPROPERTY(SaveGame) float TimeDilation; + UPROPERTY() + AActor* GraphOwner; + public: #if WITH_EDITOR virtual bool SupportsContextPins() const override { return true; } From 156f3576a122fae56bd8674940676d7443ec75b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sat, 28 May 2022 23:01:06 +0200 Subject: [PATCH 112/338] improving #78 pull request - added `NodeDoubleClickTarget` enum to editor settings, defaulting to old behavior - calling the already existing `UFlowGraphNode::JumpToDefinition` method, which is able to open IDE if a given node is defined in C++ --- .../Private/Asset/FlowAssetEditor.cpp | 36 ++++++++++--------- .../Private/Graph/FlowGraphEditorSettings.cpp | 1 + .../Public/Graph/FlowGraphEditorSettings.h | 15 ++++++-- 3 files changed, 33 insertions(+), 19 deletions(-) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index 63e16d8e3..41b386ec0 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -4,6 +4,7 @@ #include "Asset/FlowDebugger.h" #include "FlowEditorCommands.h" #include "Graph/FlowGraph.h" +#include "Graph/FlowGraphEditorSettings.h" #include "Graph/FlowGraphSchema.h" #include "Graph/FlowGraphSchema_Actions.h" #include "Graph/Nodes/FlowGraphNode.h" @@ -768,7 +769,7 @@ bool FFlowAssetEditor::CanCopyNodes() const const FGraphPanelSelectionSet SelectedNodes = FocusedGraphEditor->GetSelectedNodes(); for (FGraphPanelSelectionSet::TConstIterator SelectedIt(SelectedNodes); SelectedIt; ++SelectedIt) { - UEdGraphNode* Node = Cast(*SelectedIt); + const UEdGraphNode* Node = Cast(*SelectedIt); if (Node && Node->CanDuplicateNode()) { return true; @@ -882,31 +883,34 @@ void FFlowAssetEditor::OnNodeDoubleClicked(class UEdGraphNode* Node) const if (FlowNode) { - const FString AssetPath = FlowNode->GetAssetPath(); - if (!AssetPath.IsEmpty()) + if (UFlowGraphEditorSettings::Get()->NodeDoubleClickTarget == EFlowNodeDoubleClickTarget::NodeDefinition) { - GEditor->GetEditorSubsystem()->OpenEditorForAsset(AssetPath); + Node->JumpToDefinition(); } - else if (UObject* AssetToEdit = FlowNode->GetAssetToEdit()) + else { - GEditor->GetEditorSubsystem()->OpenEditorForAsset(AssetToEdit); - - if (IsPIE()) + const FString AssetPath = FlowNode->GetAssetPath(); + if (!AssetPath.IsEmpty()) { - if (UFlowNode_SubGraph* SubGraphNode = Cast(FlowNode)) + GEditor->GetEditorSubsystem()->OpenEditorForAsset(AssetPath); + } + else if (UObject* AssetToEdit = FlowNode->GetAssetToEdit()) + { + GEditor->GetEditorSubsystem()->OpenEditorForAsset(AssetToEdit); + + if (IsPIE()) { - const TWeakObjectPtr SubFlowInstance = SubGraphNode->GetFlowAsset()->GetFlowInstance(SubGraphNode); - if (SubFlowInstance.IsValid()) + if (UFlowNode_SubGraph* SubGraphNode = Cast(FlowNode)) { - SubGraphNode->GetFlowAsset()->GetTemplateAsset()->SetInspectedInstance(SubFlowInstance->GetDisplayName()); + const TWeakObjectPtr SubFlowInstance = SubGraphNode->GetFlowAsset()->GetFlowInstance(SubGraphNode); + if (SubFlowInstance.IsValid()) + { + SubGraphNode->GetFlowAsset()->GetTemplateAsset()->SetInspectedInstance(SubFlowInstance->GetDisplayName()); + } } } } } - else if (UObject* BlueprintAsset = FlowNode->GetClass()->ClassGeneratedBy) - { - GEditor->GetEditorSubsystem()->OpenEditorForAsset(BlueprintAsset); - } } } diff --git a/Source/FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp b/Source/FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp index 5778a6230..062cde715 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp @@ -4,6 +4,7 @@ UFlowGraphEditorSettings::UFlowGraphEditorSettings(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) + , NodeDoubleClickTarget(EFlowNodeDoubleClickTarget::PrimaryAsset) , bShowNodeClass(false) , bShowSubGraphPreview(true) , bShowSubGraphPath(true) diff --git a/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h b/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h index 06122b1da..11ceb0619 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h @@ -2,12 +2,16 @@ #pragma once -#include "FlowGraphConnectionDrawingPolicy.h" #include "Engine/DeveloperSettings.h" - -#include "FlowTypes.h" #include "FlowGraphEditorSettings.generated.h" +UENUM() +enum class EFlowNodeDoubleClickTarget : uint8 +{ + NodeDefinition UMETA(Tooltip = "Open node class: either blueprint or C++ class"), + PrimaryAsset UMETA(Tooltip = "Open asset defined as primary asset, i.e. Dialogue asset for PlayDialogue node") +}; + /** * */ @@ -15,8 +19,13 @@ UCLASS(Config = EditorPerProjectUserSettings, meta = (DisplayName = "Flow Graph" class UFlowGraphEditorSettings final : public UDeveloperSettings { GENERATED_UCLASS_BODY() + static UFlowGraphEditorSettings* Get() { return StaticClass()->GetDefaultObject(); } + // Double-clicking a Flow Node might open relevant asset/code editor + UPROPERTY(config, EditAnywhere, Category = "Nodes") + EFlowNodeDoubleClickTarget NodeDoubleClickTarget; + // Displays information on the graph node, either C++ class name or path to blueprint asset UPROPERTY(config, EditAnywhere, Category = "Nodes") bool bShowNodeClass; From 3a0a876585848f3856625699ece65ce149c05ce7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 29 May 2022 00:53:13 +0200 Subject: [PATCH 113/338] polishing up Transform Origin implementation, based on #102 --- .../LevelSequence/FlowLevelSequencePlayer.cpp | 46 +++++++++++-------- .../World/FlowNode_PlayLevelSequence.cpp | 29 ++++++------ .../LevelSequence/FlowLevelSequencePlayer.h | 2 +- .../Nodes/World/FlowNode_PlayLevelSequence.h | 20 ++++---- .../FlowNode_PlayLevelSequenceDetails.cpp | 3 +- 5 files changed, 54 insertions(+), 46 deletions(-) diff --git a/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp b/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp index 61d6f374a..4ba5f6c9a 100644 --- a/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp +++ b/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp @@ -2,16 +2,17 @@ #include "LevelSequence/FlowLevelSequencePlayer.h" #include "LevelSequence/FlowLevelSequenceActor.h" -#include "DefaultLevelSequenceInstanceData.h" #include "Nodes/FlowNode.h" +#include "DefaultLevelSequenceInstanceData.h" + UFlowLevelSequencePlayer::UFlowLevelSequencePlayer(const FObjectInitializer& ObjectInitializer) - : Super(ObjectInitializer) - , FlowEventReceiver(nullptr) + : Super(ObjectInitializer) + , FlowEventReceiver(nullptr) { } -UFlowLevelSequencePlayer* UFlowLevelSequencePlayer::CreateFlowLevelSequencePlayer(UObject* WorldContextObject, ULevelSequence* LevelSequence, FMovieSceneSequencePlaybackSettings Settings, FLevelSequenceCameraSettings CameraSettings, AActor* OriginalPointActor, ALevelSequenceActor*& OutActor) +UFlowLevelSequencePlayer* UFlowLevelSequencePlayer::CreateFlowLevelSequencePlayer(UObject* WorldContextObject, const ULevelSequence* LevelSequence, FMovieSceneSequencePlaybackSettings Settings, FLevelSequenceCameraSettings CameraSettings, AActor* TransformOriginActor, ALevelSequenceActor*& OutActor) { if (LevelSequence == nullptr) { @@ -39,31 +40,40 @@ UFlowLevelSequencePlayer* UFlowLevelSequencePlayer::CreateFlowLevelSequencePlaye Actor->CameraSettings = CameraSettings; Actor->InitializePlayer(); - Actor->bOverrideInstanceData = true; OutActor = Actor; - UDefaultLevelSequenceInstanceData* LevelSequenceData = static_cast(Actor->DefaultInstanceData); - if (IsValid(LevelSequenceData) && IsValid(OriginalPointActor)) { - LevelSequenceData->TransformOrigin = OriginalPointActor->GetTransform(); - } + FTransform DefaultTransform; + + // apply Transform Origin + // https://docs.unrealengine.com/5.0/en-US/creating-level-sequences-with-dynamic-transforms-in-unreal-engine/ + if (IsValid(TransformOriginActor)) + { + if (UDefaultLevelSequenceInstanceData* InstanceData = Cast(Actor->DefaultInstanceData)) + { + Actor->bOverrideInstanceData = true; + InstanceData->TransformOriginActor = TransformOriginActor; - // It seems doesn't really matter where the level sequence actor is. - const FTransform DefaultTransform = FTransform(OriginalPointActor->GetActorRotation(), - OriginalPointActor->GetActorLocation(), FVector::OneVector); - Actor->FinishSpawning(DefaultTransform); + // moving Level Sequence Actor might allow proper distance-based actor replication in networked games + const FTransform OriginTransform = TransformOriginActor->GetTransform(); + DefaultTransform = FTransform(OriginTransform.GetRotation(), OriginTransform.GetLocation(), FVector::OneVector); + } + } + Actor->FinishSpawning(DefaultTransform); + } + return Cast(Actor->SequencePlayer); } TArray UFlowLevelSequencePlayer::GetEventContexts() const { TArray EventContexts; - - if (FlowEventReceiver) - { - EventContexts.Add(FlowEventReceiver); - } + + if (FlowEventReceiver) + { + EventContexts.Add(FlowEventReceiver); + } return EventContexts; } diff --git a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp index 01bd6d07a..f8aee6e8b 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp @@ -19,15 +19,14 @@ FFlowNodeLevelSequenceEvent UFlowNode_PlayLevelSequence::OnPlaybackCompleted; UFlowNode_PlayLevelSequence::UFlowNode_PlayLevelSequence(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) , bPlayReverse(false) + , bUseGraphOwnerAsTransformOrigin(false) , bApplyOwnerTimeDilation(true) - , bUseGraphOwnerAsOriginalPointActor(false) , LoadedSequence(nullptr) , SequencePlayer(nullptr) , CachedPlayRate(0) , StartTime(0.0f) , ElapsedTime(0.0f) , TimeDilation(1.0f) - , GraphOwner(nullptr) { #if WITH_EDITOR Category = TEXT("World"); @@ -131,36 +130,34 @@ void UFlowNode_PlayLevelSequence::CreatePlayer() { ALevelSequenceActor* SequenceActor; - // Apply AActor::CustomTimeDilation from owner of the Root Flow + AActor* OwningActor = nullptr; if (GetFlowAsset()) { if (UObject* RootFlowOwner = GetFlowAsset()->GetOwner()) { - const AActor* OwningActor = Cast(RootFlowOwner); // in case Root Flow was created directly from some actor + OwningActor = Cast(RootFlowOwner); // in case Root Flow was created directly from some actor if (OwningActor == nullptr) { - if (const USceneComponent* OwningComponent = Cast(RootFlowOwner)) + if (const UActorComponent* OwningComponent = Cast(RootFlowOwner)) { OwningActor = OwningComponent->GetOwner(); } } - - if (IsValid(OwningActor)) - { - PlaybackSettings.PlayRate = CachedPlayRate * OwningActor->CustomTimeDilation; - } } } - if (bUseGraphOwnerAsOriginalPointActor) - { - SequencePlayer = UFlowLevelSequencePlayer::CreateFlowLevelSequencePlayer(this, LoadedSequence, PlaybackSettings, CameraSettings, GraphOwner, SequenceActor); - } - else + // Apply AActor::CustomTimeDilation from owner of the Root Flow + if (IsValid(OwningActor)) { - SequencePlayer = UFlowLevelSequencePlayer::CreateFlowLevelSequencePlayer(this, LoadedSequence, PlaybackSettings, CameraSettings, nullptr, SequenceActor); + PlaybackSettings.PlayRate = CachedPlayRate * OwningActor->CustomTimeDilation; } + // Apply Transform Origin + AActor* TransformOriginActor = bUseGraphOwnerAsTransformOrigin ? OwningActor : nullptr; + + // Finally create the player + SequencePlayer = UFlowLevelSequencePlayer::CreateFlowLevelSequencePlayer(this, LoadedSequence, PlaybackSettings, CameraSettings, TransformOriginActor, SequenceActor); + if (SequencePlayer) { SequencePlayer->SetFlowEventReceiver(this); diff --git a/Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h b/Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h index d06db6738..75110ff63 100644 --- a/Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h +++ b/Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h @@ -22,7 +22,7 @@ class FLOW_API UFlowLevelSequencePlayer : public ULevelSequencePlayer public: // variant of ULevelSequencePlayer::CreateLevelSequencePlayer - static UFlowLevelSequencePlayer* CreateFlowLevelSequencePlayer(UObject* WorldContextObject, ULevelSequence* LevelSequence, FMovieSceneSequencePlaybackSettings Settings, FLevelSequenceCameraSettings CameraSettings, AActor* OriginalPointActor, ALevelSequenceActor*& OutActor); + static UFlowLevelSequencePlayer* CreateFlowLevelSequencePlayer(UObject* WorldContextObject, const ULevelSequence* LevelSequence, FMovieSceneSequencePlaybackSettings Settings, FLevelSequenceCameraSettings CameraSettings, AActor* TransformOriginActor, ALevelSequenceActor*& OutActor); void SetFlowEventReceiver(UFlowNode* FlowNode) { FlowEventReceiver = FlowNode; } diff --git a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h index ac2c9e37e..c9a5d62c2 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h @@ -37,17 +37,20 @@ class FLOW_API UFlowNode_PlayLevelSequence : public UFlowNode UPROPERTY(EditAnywhere, Category = "Sequence") bool bPlayReverse; - - // if True, Play Rate will by multiplied by Custom Time Dilation - // set in the actor that owns Root Flow + UPROPERTY(EditAnywhere, Category = "Sequence") - bool bApplyOwnerTimeDilation; + FLevelSequenceCameraSettings CameraSettings; + // Level Sequence playback can be moved to any place in the world by applying Transform Origin + // Enabling this option will use actor that created Root Flow instance, i.e. World Settings or Player Controller + // https://docs.unrealengine.com/5.0/en-US/creating-level-sequences-with-dynamic-transforms-in-unreal-engine/ UPROPERTY(EditAnywhere, Category = "Sequence") - FLevelSequenceCameraSettings CameraSettings; - + bool bUseGraphOwnerAsTransformOrigin; + + // if True, Play Rate will by multiplied by Custom Time Dilation + // Enabling this option will use Custom Time Dilation from actor that created Root Flow instance, i.e. World Settings or Player Controller UPROPERTY(EditAnywhere, Category = "Sequence") - bool bUseGraphOwnerAsOriginalPointActor; + bool bApplyOwnerTimeDilation; protected: UPROPERTY() @@ -68,9 +71,6 @@ class FLOW_API UFlowNode_PlayLevelSequence : public UFlowNode UPROPERTY(SaveGame) float TimeDilation; - UPROPERTY() - AActor* GraphOwner; - public: #if WITH_EDITOR virtual bool SupportsContextPins() const override { return true; } diff --git a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.cpp b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.cpp index d1807690c..79ef368e0 100644 --- a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.cpp +++ b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.cpp @@ -10,6 +10,7 @@ void FFlowNode_PlayLevelSequenceDetails::CustomizeDetails(IDetailLayoutBuilder& SequenceCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UFlowNode_PlayLevelSequence, Sequence)); SequenceCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UFlowNode_PlayLevelSequence, PlaybackSettings)); SequenceCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UFlowNode_PlayLevelSequence, bPlayReverse)); - SequenceCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UFlowNode_PlayLevelSequence, bApplyOwnerTimeDilation)); SequenceCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UFlowNode_PlayLevelSequence, CameraSettings)); + SequenceCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UFlowNode_PlayLevelSequence, bUseGraphOwnerAsTransformOrigin)); + SequenceCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UFlowNode_PlayLevelSequence, bApplyOwnerTimeDilation)); } From 5e42823ba96d8f968dad4bbabe0126eee0ed5014 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 29 May 2022 01:08:41 +0200 Subject: [PATCH 114/338] merge fix --- Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp | 2 +- Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp b/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp index 4ba5f6c9a..e07a39764 100644 --- a/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp +++ b/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp @@ -12,7 +12,7 @@ UFlowLevelSequencePlayer::UFlowLevelSequencePlayer(const FObjectInitializer& Obj { } -UFlowLevelSequencePlayer* UFlowLevelSequencePlayer::CreateFlowLevelSequencePlayer(UObject* WorldContextObject, const ULevelSequence* LevelSequence, FMovieSceneSequencePlaybackSettings Settings, FLevelSequenceCameraSettings CameraSettings, AActor* TransformOriginActor, ALevelSequenceActor*& OutActor) +UFlowLevelSequencePlayer* UFlowLevelSequencePlayer::CreateFlowLevelSequencePlayer(UObject* WorldContextObject, ULevelSequence* LevelSequence, FMovieSceneSequencePlaybackSettings Settings, FLevelSequenceCameraSettings CameraSettings, AActor* TransformOriginActor, ALevelSequenceActor*& OutActor) { if (LevelSequence == nullptr) { diff --git a/Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h b/Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h index 75110ff63..b7c4ac347 100644 --- a/Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h +++ b/Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h @@ -22,7 +22,7 @@ class FLOW_API UFlowLevelSequencePlayer : public ULevelSequencePlayer public: // variant of ULevelSequencePlayer::CreateLevelSequencePlayer - static UFlowLevelSequencePlayer* CreateFlowLevelSequencePlayer(UObject* WorldContextObject, const ULevelSequence* LevelSequence, FMovieSceneSequencePlaybackSettings Settings, FLevelSequenceCameraSettings CameraSettings, AActor* TransformOriginActor, ALevelSequenceActor*& OutActor); + static UFlowLevelSequencePlayer* CreateFlowLevelSequencePlayer(UObject* WorldContextObject, ULevelSequence* LevelSequence, FMovieSceneSequencePlaybackSettings Settings, FLevelSequenceCameraSettings CameraSettings, AActor* TransformOriginActor, ALevelSequenceActor*& OutActor); void SetFlowEventReceiver(UFlowNode* FlowNode) { FlowEventReceiver = FlowNode; } From 01a64b7487bc94045113d931216b87c2d407cfe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 29 May 2022 15:53:31 +0200 Subject: [PATCH 115/338] #97 implemented Force Pin Activation * It's a new debugging feature available from Pin's context menu during PIE. * Allows pushing the graph execution in case of blockers, i.e. specific node doesn't work for whatever reason and we wanted to continue playtesting. * It works both on Input pins and Output pins. You can even trigger unconnected Input pins this way. --- Source/Flow/Private/Nodes/FlowNode.cpp | 8 ++-- Source/Flow/Private/Nodes/FlowPin.cpp | 13 +++--- Source/Flow/Public/Nodes/FlowNode.h | 6 +-- Source/Flow/Public/Nodes/FlowPin.h | 4 +- .../Private/Asset/FlowAssetEditor.cpp | 19 ++++++++ .../FlowEditor/Private/FlowEditorCommands.cpp | 2 + .../Private/Graph/Nodes/FlowGraphNode.cpp | 43 ++++++++++++++++--- .../FlowEditor/Public/Asset/FlowAssetEditor.h | 2 + Source/FlowEditor/Public/FlowEditorCommands.h | 3 ++ .../Public/Graph/Nodes/FlowGraphNode.h | 25 +++++++---- 10 files changed, 98 insertions(+), 27 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index dc749707c..47226e935 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -334,7 +334,7 @@ void UFlowNode::FlushContent() K2_FlushContent(); } -void UFlowNode::TriggerInput(const FName& PinName) +void UFlowNode::TriggerInput(const FName& PinName, const bool bForcedActivation /*= false*/) { if (InputPins.Contains(PinName)) { @@ -343,7 +343,7 @@ void UFlowNode::TriggerInput(const FName& PinName) #if !UE_BUILD_SHIPPING // record for debugging TArray& Records = InputRecords.FindOrAdd(PinName); - Records.Add(FPinRecord(FApp::GetCurrentTime())); + Records.Add(FPinRecord(FApp::GetCurrentTime(), bForcedActivation)); #endif // UE_BUILD_SHIPPING #if WITH_EDITOR @@ -377,7 +377,7 @@ void UFlowNode::TriggerFirstOutput(const bool bFinish) } } -void UFlowNode::TriggerOutput(const FName& PinName, const bool bFinish /*= false*/) +void UFlowNode::TriggerOutput(const FName& PinName, const bool bFinish /*= false*/, const bool bForcedActivation /*= false*/) { // clean up node, if needed if (bFinish) @@ -390,7 +390,7 @@ void UFlowNode::TriggerOutput(const FName& PinName, const bool bFinish /*= false { // record for debugging, even if nothing is connected to this pin TArray& Records = OutputRecords.FindOrAdd(PinName); - Records.Add(FPinRecord(FApp::GetCurrentTime())); + Records.Add(FPinRecord(FApp::GetCurrentTime(), bForcedActivation)); #if WITH_EDITOR if (GetWorld()->WorldType == EWorldType::PIE && UFlowAsset::GetFlowGraphInterface().IsValid()) diff --git a/Source/Flow/Private/Nodes/FlowPin.cpp b/Source/Flow/Private/Nodes/FlowPin.cpp index 7401df83d..3ae2a42d5 100644 --- a/Source/Flow/Private/Nodes/FlowPin.cpp +++ b/Source/Flow/Private/Nodes/FlowPin.cpp @@ -6,17 +6,19 @@ FString FPinRecord::NoActivations = TEXT("No activations"); FString FPinRecord::PinActivations = TEXT("Pin activations"); +FString FPinRecord::ForcedActivation = TEXT(" (forced activation)"); FPinRecord::FPinRecord() + : Time(0.0f) + , HumanReadableTime(FString()) + , bForcedActivation(false) { - Time = 0.0f; - HumanReadableTime = FString(); } -FPinRecord::FPinRecord(const double InTime) +FPinRecord::FPinRecord(const double InTime, const bool bInForcedActivation) + : Time(InTime) + , bForcedActivation(bInForcedActivation) { - Time = InTime; - const FDateTime SystemTime(FDateTime::Now()); HumanReadableTime = DoubleDigit(SystemTime.GetHour()) + TEXT(".") + DoubleDigit(SystemTime.GetMinute()) + TEXT(".") @@ -28,4 +30,5 @@ FORCEINLINE FString FPinRecord::DoubleDigit(const int32 Number) { return Number > 9 ? FString::FromInt(Number) : TEXT("0") + FString::FromInt(Number); } + #endif diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 55bed68ab..112118deb 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -240,7 +240,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte void K2_FlushContent(); // Trigger execution of input pin - void TriggerInput(const FName& PinName); + void TriggerInput(const FName& PinName, const bool bForcedActivation = false); // Method reacting on triggering Input pin virtual void ExecuteInput(const FName& PinName); @@ -254,8 +254,8 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte void TriggerFirstOutput(const bool bFinish); // Trigger Output Pin - UFUNCTION(BlueprintCallable, Category = "FlowNode") - void TriggerOutput(const FName& PinName, const bool bFinish = false); + UFUNCTION(BlueprintCallable, Category = "FlowNode", meta = (HidePin = "bForcedActivation")) + void TriggerOutput(const FName& PinName, const bool bFinish = false, const bool bForcedActivation = false); void TriggerOutput(const FString& PinName, const bool bFinish = false); void TriggerOutput(const FText& PinName, const bool bFinish = false); diff --git a/Source/Flow/Public/Nodes/FlowPin.h b/Source/Flow/Public/Nodes/FlowPin.h index ad09e6e99..4ca7c16b9 100644 --- a/Source/Flow/Public/Nodes/FlowPin.h +++ b/Source/Flow/Public/Nodes/FlowPin.h @@ -151,12 +151,14 @@ struct FLOW_API FPinRecord { double Time; FString HumanReadableTime; + bool bForcedActivation; static FString NoActivations; static FString PinActivations; + static FString ForcedActivation; FPinRecord(); - FPinRecord(const double InTime); + FPinRecord(const double InTime, const bool bInForcedActivation); private: FORCEINLINE static FString DoubleDigit(const int32 Number); diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index 41b386ec0..d7aa17c50 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -473,6 +473,14 @@ void FFlowAssetEditor::BindGraphCommands() FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanTogglePinBreakpoint) ); + // Execution Override commands + ToolkitCommands->MapAction(FlowGraphCommands.ForcePinActivation, + FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnForcePinActivation), + FCanExecuteAction::CreateStatic(&FFlowAssetEditor::IsPIE), + FIsActionChecked(), + FIsActionButtonVisible::CreateStatic(&FFlowAssetEditor::IsPIE) + ); + // Jump commands ToolkitCommands->MapAction(FlowGraphCommands.FocusViewport, FExecuteAction::CreateSP(this, &FFlowAssetEditor::FocusViewport), @@ -1228,6 +1236,17 @@ bool FFlowAssetEditor::CanTogglePinBreakpoint() const return FocusedGraphEditor->GetGraphPinForMenu() != nullptr; } +void FFlowAssetEditor::OnForcePinActivation() const +{ + if (UEdGraphPin* Pin = FocusedGraphEditor->GetGraphPinForMenu()) + { + if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) + { + GraphNode->ForcePinActivation(Pin); + } + } +} + void FFlowAssetEditor::FocusViewport() const { // Iterator used but should only contain one node diff --git a/Source/FlowEditor/Private/FlowEditorCommands.cpp b/Source/FlowEditor/Private/FlowEditorCommands.cpp index 307951420..9462deb8a 100644 --- a/Source/FlowEditor/Private/FlowEditorCommands.cpp +++ b/Source/FlowEditor/Private/FlowEditorCommands.cpp @@ -41,6 +41,8 @@ void FFlowGraphCommands::RegisterCommands() UI_COMMAND(DisablePinBreakpoint, "Disable Pin Breakpoint", "Disables a breakpoint on the pin", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(TogglePinBreakpoint, "Toggle Pin Breakpoint", "Toggles a breakpoint on the pin", EUserInterfaceActionType::Button, FInputChord()); + UI_COMMAND(ForcePinActivation, "Force Pin Activation", "Forces execution of the pin in a graph, used to bypass blockers", EUserInterfaceActionType::Button, FInputChord()); + UI_COMMAND(FocusViewport, "Focus Viewport", "Focus viewport on actor assigned to the node", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(JumpToNodeDefinition, "Jump to Node Definition", "Jump to the node definition", EUserInterfaceActionType::Button, FInputChord()); } diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 0d91ad1dc..78f3c85a4 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -457,7 +457,7 @@ void UFlowGraphNode::GetNodeContextMenuActions(class UToolMenu* Menu, class UGra if (Context->Pin) { { - FToolMenuSection& Section = Menu->AddSection("FlowGraphSchemaPinActions", LOCTEXT("PinActionsMenuHeader", "Pin Actions")); + FToolMenuSection& Section = Menu->AddSection("FlowGraphPinActions", LOCTEXT("PinActionsMenuHeader", "Pin Actions")); if (Context->Pin->LinkedTo.Num() > 0) { Section.AddMenuEntry(GraphCommands.BreakPinLinks); @@ -474,18 +474,23 @@ void UFlowGraphNode::GetNodeContextMenuActions(class UToolMenu* Menu, class UGra } { - FToolMenuSection& Section = Menu->AddSection("FlowGraphNodePinBreakpoints", LOCTEXT("PinBreakpointsMenuHeader", "Pin Breakpoints")); + FToolMenuSection& Section = Menu->AddSection("FlowGraphPinBreakpoints", LOCTEXT("PinBreakpointsMenuHeader", "Pin Breakpoints")); Section.AddMenuEntry(FlowGraphCommands.AddPinBreakpoint); Section.AddMenuEntry(FlowGraphCommands.RemovePinBreakpoint); Section.AddMenuEntry(FlowGraphCommands.EnablePinBreakpoint); Section.AddMenuEntry(FlowGraphCommands.DisablePinBreakpoint); Section.AddMenuEntry(FlowGraphCommands.TogglePinBreakpoint); } + + { + FToolMenuSection& Section = Menu->AddSection("FlowGraphPinExecutionOverride", LOCTEXT("PinExecutionOverrideMenuHeader", "Execution Override")); + Section.AddMenuEntry(FlowGraphCommands.ForcePinActivation); + } } else if (Context->Node) { { - FToolMenuSection& Section = Menu->AddSection("FlowGraphSchemaNodeActions", LOCTEXT("NodeActionsMenuHeader", "Node Actions")); + FToolMenuSection& Section = Menu->AddSection("FlowGraphNodeActions", LOCTEXT("NodeActionsMenuHeader", "Node Actions")); Section.AddMenuEntry(GenericCommands.Delete); Section.AddMenuEntry(GenericCommands.Cut); Section.AddMenuEntry(GenericCommands.Copy); @@ -572,7 +577,7 @@ FText UFlowGraphNode::GetNodeTitle(ENodeTitleType::Type TitleType) const return FlowNode->GetNodeTitle(); } - + return Super::GetNodeTitle(TitleType); } @@ -880,7 +885,7 @@ void UFlowGraphNode::GetPinHoverText(const UEdGraphPin& Pin, FString& HoverTextO { HoverTextOut.Append(LINE_TERMINATOR).Append(LINE_TERMINATOR); } - + const TArray& PinRecords = InspectedNodeInstance->GetPinRecords(Pin.PinName, Pin.Direction); if (PinRecords.Num() == 0) { @@ -893,6 +898,11 @@ void UFlowGraphNode::GetPinHoverText(const UEdGraphPin& Pin, FString& HoverTextO { HoverTextOut.Append(LINE_TERMINATOR); HoverTextOut.Appendf(TEXT("%d) %s"), i + 1, *PinRecords[i].HumanReadableTime); + + if (PinRecords[i].bForcedActivation) + { + HoverTextOut.Append(FPinRecord::ForcedActivation); + } } } } @@ -961,4 +971,27 @@ void UFlowGraphNode::ResetBreakpoints() } } +void UFlowGraphNode::ForcePinActivation(const FEdGraphPinReference PinReference) const +{ + UFlowNode* InspectedNodeInstance = GetInspectedNodeInstance(); + if (InspectedNodeInstance == nullptr) + { + return; + } + + if (const UEdGraphPin* FoundPin = PinReference.Get()) + { + switch (FoundPin->Direction) + { + case EGPD_Input: + InspectedNodeInstance->TriggerInput(FoundPin->PinName, true); + break; + case EGPD_Output: + InspectedNodeInstance->TriggerOutput(FoundPin->PinName, false, true); + break; + default: ; + } + } +} + #undef LOCTEXT_NAMESPACE diff --git a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h index 682f8aab0..cd3bca47e 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h @@ -205,6 +205,8 @@ class FFlowAssetEditor : public FAssetEditorToolkit, public FEditorUndoClient, p bool CanToggleBreakpoint() const; bool CanTogglePinBreakpoint() const; + void OnForcePinActivation() const; + void FocusViewport() const; bool CanFocusViewport() const; diff --git a/Source/FlowEditor/Public/FlowEditorCommands.h b/Source/FlowEditor/Public/FlowEditorCommands.h index c608d364f..6f9defc3e 100644 --- a/Source/FlowEditor/Public/FlowEditorCommands.h +++ b/Source/FlowEditor/Public/FlowEditorCommands.h @@ -39,6 +39,9 @@ class FFlowGraphCommands final : public TCommands TSharedPtr DisablePinBreakpoint; TSharedPtr TogglePinBreakpoint; + /** Execution Override */ + TSharedPtr ForcePinActivation; + /** Jumps */ TSharedPtr FocusViewport; TSharedPtr JumpToNodeDefinition; diff --git a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h index 93d9fd202..d3446ce51 100644 --- a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h +++ b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h @@ -65,8 +65,8 @@ class FLOWEDITOR_API UFlowGraphNode : public UEdGraphNode static bool bFlowAssetsLoaded; public: - // actually, it would be intuitive to assign a custom Graph Node class in Flow Node class - // although we shouldn't assign class from editor module to runtime module class + // It would be intuitive to assign a custom Graph Node class in Flow Node class + // However, we shouldn't assign class from editor module to runtime module class UPROPERTY() TArray> AssignedNodeClasses; @@ -141,19 +141,19 @@ class FLOWEDITOR_API UFlowGraphNode : public UEdGraphNode // Utils public: - // short summary of node's content + // Short summary of node's content FString GetNodeDescription() const; - // get flow node for the inspected asset instance + // Get flow node for the inspected asset instance UFlowNode* GetInspectedNodeInstance() const; - // used for highlighting active nodes of the inspected asset instance + // Used for highlighting active nodes of the inspected asset instance EFlowNodeState GetActivationState() const; - // information displayed while node is active + // Information displayed while node is active FString GetStatusString() const; - // check this to display information while node is preloaded + // Check this to display information while node is preloaded bool IsContentPreloaded() const; bool CanFocusViewport() const; @@ -189,10 +189,10 @@ class FLOWEDITOR_API UFlowGraphNode : public UEdGraphNode void AddUserInput(); void AddUserOutput(); - // add pin only on this instance of node, under default pins + // Add pin only on this instance of node, under default pins void AddInstancePin(const EEdGraphPinDirection Direction, const FName& PinName); - // call node and graph updates manually, if using bBatchRemoval + // Call node and graph updates manually, if using bBatchRemoval void RemoveInstancePin(UEdGraphPin* Pin); // Create pins from the context asset, i.e. Sequencer events @@ -215,4 +215,11 @@ class FLOWEDITOR_API UFlowGraphNode : public UEdGraphNode void OnResumePIE(const bool bIsSimulating); void OnEndPIE(const bool bIsSimulating); void ResetBreakpoints(); + +////////////////////////////////////////////////////////////////////////// +// Execution Override + +public: + // Pin activation forced by user during PIE + void ForcePinActivation(const FEdGraphPinReference PinReference) const; }; From 18c66344cba9299ede2cb4fc348501e3487fb1ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Mon, 30 May 2022 11:41:27 +0200 Subject: [PATCH 116/338] copyright added --- Source/FlowEditor/Private/Asset/AssetTypeActions_FlowAsset.cpp | 2 ++ Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp | 2 ++ Source/FlowEditor/Private/Asset/FlowAssetDetails.h | 2 ++ Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp | 2 ++ Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp | 2 ++ Source/FlowEditor/Private/Asset/FlowAssetIndexer.cpp | 2 ++ Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp | 2 ++ Source/FlowEditor/Private/Asset/FlowDebugger.cpp | 2 ++ Source/FlowEditor/Private/FlowEditorCommands.cpp | 2 ++ Source/FlowEditor/Private/FlowEditorModule.cpp | 2 ++ Source/FlowEditor/Private/FlowEditorStyle.cpp | 2 ++ Source/FlowEditor/Private/Graph/FlowGraph.cpp | 2 ++ .../Private/Graph/FlowGraphConnectionDrawingPolicy.cpp | 2 ++ Source/FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp | 2 ++ Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp | 2 ++ Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp | 2 ++ Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp | 2 ++ Source/FlowEditor/Private/Graph/FlowGraphUtils.cpp | 2 ++ Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp | 2 ++ .../Private/Graph/Nodes/FlowGraphNode_ExecutionSequence.cpp | 2 ++ Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_Finish.cpp | 2 ++ Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_Reroute.cpp | 2 ++ Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_Start.cpp | 2 ++ .../FlowEditor/Private/Graph/Nodes/FlowGraphNode_SubGraph.cpp | 2 ++ Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp | 2 ++ .../FlowEditor/Private/Graph/Widgets/SFlowGraphNode_Finish.cpp | 2 ++ .../FlowEditor/Private/Graph/Widgets/SFlowGraphNode_Start.cpp | 2 ++ .../Private/Graph/Widgets/SFlowGraphNode_SubGraph.cpp | 2 ++ Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp | 2 ++ Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp | 2 ++ Source/FlowEditor/Private/MovieScene/FlowSection.cpp | 2 ++ Source/FlowEditor/Private/MovieScene/FlowSection.h | 2 ++ Source/FlowEditor/Private/MovieScene/FlowTrackEditor.cpp | 2 ++ Source/FlowEditor/Private/MovieScene/FlowTrackEditor.h | 2 ++ .../Private/Nodes/AssetTypeActions_FlowNodeBlueprint.cpp | 2 ++ .../Nodes/Customizations/FlowNode_ComponentObserverDetails.cpp | 2 ++ .../Nodes/Customizations/FlowNode_ComponentObserverDetails.h | 2 ++ .../Nodes/Customizations/FlowNode_CustomInputDetails.cpp | 2 ++ .../Private/Nodes/Customizations/FlowNode_CustomInputDetails.h | 2 ++ .../Nodes/Customizations/FlowNode_CustomOutputDetails.cpp | 2 ++ .../Private/Nodes/Customizations/FlowNode_CustomOutputDetails.h | 2 ++ .../Private/Nodes/Customizations/FlowNode_Details.cpp | 2 ++ .../FlowEditor/Private/Nodes/Customizations/FlowNode_Details.h | 2 ++ .../Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.cpp | 2 ++ .../Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.h | 2 ++ Source/FlowEditor/Private/Nodes/FlowNodeBlueprintFactory.cpp | 2 ++ 46 files changed, 92 insertions(+) diff --git a/Source/FlowEditor/Private/Asset/AssetTypeActions_FlowAsset.cpp b/Source/FlowEditor/Private/Asset/AssetTypeActions_FlowAsset.cpp index 060b57260..576cfabef 100644 --- a/Source/FlowEditor/Private/Asset/AssetTypeActions_FlowAsset.cpp +++ b/Source/FlowEditor/Private/Asset/AssetTypeActions_FlowAsset.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Asset/AssetTypeActions_FlowAsset.h" #include "FlowEditorModule.h" #include "Graph/FlowGraphSettings.h" diff --git a/Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp b/Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp index 37dbcb19f..9c78abef4 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "FlowAssetDetails.h" #include "FlowAsset.h" #include "Nodes/Route/FlowNode_SubGraph.h" diff --git a/Source/FlowEditor/Private/Asset/FlowAssetDetails.h b/Source/FlowEditor/Private/Asset/FlowAssetDetails.h index ccc2d33d8..7fd420780 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetDetails.h +++ b/Source/FlowEditor/Private/Asset/FlowAssetDetails.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "IDetailCustomization.h" diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index d7aa17c50..82ab50115 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Asset/FlowAssetEditor.h" #include "Asset/FlowAssetToolbar.h" diff --git a/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp b/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp index 128576097..13e6a31a6 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Asset/FlowAssetFactory.h" #include "FlowAsset.h" #include "Graph/FlowGraph.h" diff --git a/Source/FlowEditor/Private/Asset/FlowAssetIndexer.cpp b/Source/FlowEditor/Private/Asset/FlowAssetIndexer.cpp index 9d0031ab8..55e1e5bdc 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetIndexer.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetIndexer.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Asset/FlowAssetIndexer.h" #include "FlowAsset.h" diff --git a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp index d50065c6e..99259929d 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Asset/FlowAssetToolbar.h" #include "Asset/FlowAssetEditor.h" #include "FlowEditorCommands.h" diff --git a/Source/FlowEditor/Private/Asset/FlowDebugger.cpp b/Source/FlowEditor/Private/Asset/FlowDebugger.cpp index 796cad8a2..f7e2aea37 100644 --- a/Source/FlowEditor/Private/Asset/FlowDebugger.cpp +++ b/Source/FlowEditor/Private/Asset/FlowDebugger.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Asset/FlowDebugger.h" #include "Engine/Engine.h" diff --git a/Source/FlowEditor/Private/FlowEditorCommands.cpp b/Source/FlowEditor/Private/FlowEditorCommands.cpp index 9462deb8a..863c9c75a 100644 --- a/Source/FlowEditor/Private/FlowEditorCommands.cpp +++ b/Source/FlowEditor/Private/FlowEditorCommands.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "FlowEditorCommands.h" #include "FlowEditorStyle.h" diff --git a/Source/FlowEditor/Private/FlowEditorModule.cpp b/Source/FlowEditor/Private/FlowEditorModule.cpp index 1b849e4c2..4cc08b607 100644 --- a/Source/FlowEditor/Private/FlowEditorModule.cpp +++ b/Source/FlowEditor/Private/FlowEditorModule.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "FlowEditorModule.h" #include "FlowEditorStyle.h" diff --git a/Source/FlowEditor/Private/FlowEditorStyle.cpp b/Source/FlowEditor/Private/FlowEditorStyle.cpp index c5d7a2a7e..ab4046e05 100644 --- a/Source/FlowEditor/Private/FlowEditorStyle.cpp +++ b/Source/FlowEditor/Private/FlowEditorStyle.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "FlowEditorStyle.h" #include "Interfaces/IPluginManager.h" diff --git a/Source/FlowEditor/Private/Graph/FlowGraph.cpp b/Source/FlowEditor/Private/Graph/FlowGraph.cpp index 10157e1eb..b776077e9 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraph.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraph.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Graph/FlowGraph.h" #include "Graph/FlowGraphSchema.h" #include "Graph/Nodes/FlowGraphNode.h" diff --git a/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp b/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp index d0a765720..4aa0c4eb0 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Graph/FlowGraphConnectionDrawingPolicy.h" #include "Asset/FlowAssetEditor.h" diff --git a/Source/FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp b/Source/FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp index 062cde715..a09ae135b 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Graph/FlowGraphEditorSettings.h" #include "FlowAsset.h" diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp index 516118a19..0a7db0cf4 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Graph/FlowGraphSchema.h" #include "Asset/FlowAssetEditor.h" diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp index ce8152c6c..386baa6ac 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Graph/FlowGraphSchema_Actions.h" #include "Asset/FlowAssetEditor.h" diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp index 1aa4879bc..ea44964da 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Graph/FlowGraphSettings.h" #include "FlowAsset.h" diff --git a/Source/FlowEditor/Private/Graph/FlowGraphUtils.cpp b/Source/FlowEditor/Private/Graph/FlowGraphUtils.cpp index c84930f31..81cecdd66 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphUtils.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphUtils.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Graph/FlowGraphUtils.h" #include "Asset/FlowAssetEditor.h" #include "Graph/FlowGraph.h" diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 78f3c85a4..ee9e43f96 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Graph/Nodes/FlowGraphNode.h" #include "Asset/FlowDebugger.h" diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_ExecutionSequence.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_ExecutionSequence.cpp index 6b093c1c8..5ba3e06f2 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_ExecutionSequence.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_ExecutionSequence.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Graph/Nodes/FlowGraphNode_ExecutionSequence.h" #include "Nodes/Route/FlowNode_ExecutionMultiGate.h" #include "Nodes/Route/FlowNode_ExecutionSequence.h" diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_Finish.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_Finish.cpp index f18d02e06..1092260e4 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_Finish.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_Finish.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Graph/Nodes/FlowGraphNode_Finish.h" #include "Graph/Widgets/SFlowGraphNode_Finish.h" diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_Reroute.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_Reroute.cpp index 3bb0d6918..cac81f6d4 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_Reroute.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_Reroute.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Graph/Nodes/FlowGraphNode_Reroute.h" #include "SGraphNodeKnot.h" diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_Start.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_Start.cpp index a8b1d2b56..19fde8ba8 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_Start.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_Start.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Graph/Nodes/FlowGraphNode_Start.h" #include "Graph/Widgets/SFlowGraphNode_Start.h" diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_SubGraph.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_SubGraph.cpp index ed6dab19a..2e22bc80b 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_SubGraph.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_SubGraph.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Graph/Nodes/FlowGraphNode_SubGraph.h" #include "Graph/Widgets/SFlowGraphNode_SubGraph.h" diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp index efd3e5bf6..b4bd8845f 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Graph/Widgets/SFlowGraphNode.h" #include "FlowEditorStyle.h" #include "Graph/FlowGraphEditorSettings.h" diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode_Finish.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode_Finish.cpp index ad77c560a..b5df50053 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode_Finish.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode_Finish.cpp @@ -1 +1,3 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Graph/Widgets/SFlowGraphNode_Finish.h" diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode_Start.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode_Start.cpp index ac9e25785..7fe9b3062 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode_Start.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode_Start.cpp @@ -1 +1,3 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Graph/Widgets/SFlowGraphNode_Start.h" diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode_SubGraph.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode_SubGraph.cpp index 4fcf83d5c..7e626f880 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode_SubGraph.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode_SubGraph.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Graph/Widgets/SFlowGraphNode_SubGraph.h" #include "Graph/FlowGraphEditorSettings.h" diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp index a92f47a8b..b73374648 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Graph/Widgets/SFlowPalette.h" #include "Asset/FlowAssetEditor.h" #include "FlowEditorCommands.h" diff --git a/Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp b/Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp index 671278137..11c18509e 100644 --- a/Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp +++ b/Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "LevelEditor/SLevelEditorFlow.h" #include "FlowAsset.h" #include "FlowComponent.h" diff --git a/Source/FlowEditor/Private/MovieScene/FlowSection.cpp b/Source/FlowEditor/Private/MovieScene/FlowSection.cpp index 7204d51ec..5a67120b4 100644 --- a/Source/FlowEditor/Private/MovieScene/FlowSection.cpp +++ b/Source/FlowEditor/Private/MovieScene/FlowSection.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "FlowSection.h" #include "MovieScene/MovieSceneFlowRepeaterSection.h" #include "MovieScene/MovieSceneFlowTriggerSection.h" diff --git a/Source/FlowEditor/Private/MovieScene/FlowSection.h b/Source/FlowEditor/Private/MovieScene/FlowSection.h index e32c5078b..e1202d61e 100644 --- a/Source/FlowEditor/Private/MovieScene/FlowSection.h +++ b/Source/FlowEditor/Private/MovieScene/FlowSection.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "ISequencerSection.h" diff --git a/Source/FlowEditor/Private/MovieScene/FlowTrackEditor.cpp b/Source/FlowEditor/Private/MovieScene/FlowTrackEditor.cpp index 60d10678b..51dd0d55d 100644 --- a/Source/FlowEditor/Private/MovieScene/FlowTrackEditor.cpp +++ b/Source/FlowEditor/Private/MovieScene/FlowTrackEditor.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "FlowTrackEditor.h" #include "FlowSection.h" diff --git a/Source/FlowEditor/Private/MovieScene/FlowTrackEditor.h b/Source/FlowEditor/Private/MovieScene/FlowTrackEditor.h index 84abd9c23..6e7fa7ed0 100644 --- a/Source/FlowEditor/Private/MovieScene/FlowTrackEditor.h +++ b/Source/FlowEditor/Private/MovieScene/FlowTrackEditor.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "CoreMinimal.h" diff --git a/Source/FlowEditor/Private/Nodes/AssetTypeActions_FlowNodeBlueprint.cpp b/Source/FlowEditor/Private/Nodes/AssetTypeActions_FlowNodeBlueprint.cpp index f6086b3ab..a7b1b6afe 100644 --- a/Source/FlowEditor/Private/Nodes/AssetTypeActions_FlowNodeBlueprint.cpp +++ b/Source/FlowEditor/Private/Nodes/AssetTypeActions_FlowNodeBlueprint.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Nodes/AssetTypeActions_FlowNodeBlueprint.h" #include "Nodes/FlowNodeBlueprintFactory.h" #include "FlowEditorModule.h" diff --git a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_ComponentObserverDetails.cpp b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_ComponentObserverDetails.cpp index 5ddf96576..bf346e6e5 100644 --- a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_ComponentObserverDetails.cpp +++ b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_ComponentObserverDetails.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "FlowNode_ComponentObserverDetails.h" #include "Nodes/World/FlowNode_ComponentObserver.h" diff --git a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_ComponentObserverDetails.h b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_ComponentObserverDetails.h index ca84f4745..c3450294f 100644 --- a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_ComponentObserverDetails.h +++ b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_ComponentObserverDetails.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "IDetailCustomization.h" diff --git a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomInputDetails.cpp b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomInputDetails.cpp index 5919e37aa..4892202b3 100644 --- a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomInputDetails.cpp +++ b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomInputDetails.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "FlowNode_CustomInputDetails.h" #include "FlowAsset.h" #include "Nodes/Route/FlowNode_CustomInput.h" diff --git a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomInputDetails.h b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomInputDetails.h index 3f3cbd352..2fe9b995a 100644 --- a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomInputDetails.h +++ b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomInputDetails.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "IDetailCustomization.h" diff --git a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomOutputDetails.cpp b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomOutputDetails.cpp index d3795dc14..bc7923bb2 100644 --- a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomOutputDetails.cpp +++ b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomOutputDetails.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "FlowNode_CustomOutputDetails.h" #include "FlowAsset.h" #include "Nodes/Route/FlowNode_CustomOutput.h" diff --git a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomOutputDetails.h b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomOutputDetails.h index 982f795b6..dba0de2c2 100644 --- a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomOutputDetails.h +++ b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomOutputDetails.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "IDetailCustomization.h" diff --git a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_Details.cpp b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_Details.cpp index 5c5c66f62..ae9ddd072 100644 --- a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_Details.cpp +++ b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_Details.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "FlowNode_Details.h" #include "PropertyEditing.h" diff --git a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_Details.h b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_Details.h index 6d55c2971..ce85a66d6 100644 --- a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_Details.h +++ b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_Details.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "IDetailCustomization.h" diff --git a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.cpp b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.cpp index 79ef368e0..f57695a0c 100644 --- a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.cpp +++ b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "FlowNode_PlayLevelSequenceDetails.h" #include "Nodes/World/FlowNode_PlayLevelSequence.h" diff --git a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.h b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.h index c76781877..efb935389 100644 --- a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.h +++ b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.h @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #pragma once #include "IDetailCustomization.h" diff --git a/Source/FlowEditor/Private/Nodes/FlowNodeBlueprintFactory.cpp b/Source/FlowEditor/Private/Nodes/FlowNodeBlueprintFactory.cpp index 8dfd6cbd6..06209c356 100644 --- a/Source/FlowEditor/Private/Nodes/FlowNodeBlueprintFactory.cpp +++ b/Source/FlowEditor/Private/Nodes/FlowNodeBlueprintFactory.cpp @@ -1,3 +1,5 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + #include "Nodes/FlowNodeBlueprintFactory.h" #include "Nodes/FlowNode.h" From 1a4cf9bf256fc1e497f020403ff9ce2cc3f2fa6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Wed, 8 Jun 2022 18:29:31 +0200 Subject: [PATCH 117/338] added flag to disable SaveSystem-related message if project doesn't use SaveSystem --- Source/Flow/Private/FlowComponent.cpp | 6 ++++-- Source/Flow/Private/FlowSettings.cpp | 1 + Source/Flow/Public/FlowSettings.h | 3 +++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Source/Flow/Private/FlowComponent.cpp b/Source/Flow/Private/FlowComponent.cpp index 62dcf3964..9c2b7b4c6 100644 --- a/Source/Flow/Private/FlowComponent.cpp +++ b/Source/Flow/Private/FlowComponent.cpp @@ -213,9 +213,11 @@ void UFlowComponent::OnRep_RemovedIdentityTags() void UFlowComponent::VerifyIdentityTags() const { - if (IdentityTags.IsEmpty()) + if (IdentityTags.IsEmpty() && UFlowSettings::Get()->bWarnAboutMissingIdentityTags) { - LogError(TEXT("Missing Identity Tags on the Flow Component creating Flow Asset instance! This gonna break loading SaveGame for this component!")); + FString Message = TEXT("Missing Identity Tags on the Flow Component creating Flow Asset instance! This gonna break loading SaveGame for this component!"); + Message.Append(LINE_TERMINATOR).Append(TEXT("If you're not using SaveSystem, you can silence this warning by unchecking bWarnAboutMissingIdentityTags flag in Flow Settings.")); + LogError(Message); } } diff --git a/Source/Flow/Private/FlowSettings.cpp b/Source/Flow/Private/FlowSettings.cpp index c68e3da90..c287a3aef 100644 --- a/Source/Flow/Private/FlowSettings.cpp +++ b/Source/Flow/Private/FlowSettings.cpp @@ -5,5 +5,6 @@ UFlowSettings::UFlowSettings(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) , bCreateFlowSubsystemOnClients(true) + , bWarnAboutMissingIdentityTags(true) { } diff --git a/Source/Flow/Public/FlowSettings.h b/Source/Flow/Public/FlowSettings.h index 225cbf647..475c11c09 100644 --- a/Source/Flow/Public/FlowSettings.h +++ b/Source/Flow/Public/FlowSettings.h @@ -26,4 +26,7 @@ class UFlowSettings final : public UDeveloperSettings // How many nodes of given class should be preloaded with the Flow Asset instance? UPROPERTY(Config, EditAnywhere, Category = "Preload") TMap, int32> DefaultPreloadDepth; + + UPROPERTY(Config, EditAnywhere, Category = "SaveSystem") + bool bWarnAboutMissingIdentityTags; }; From ef1750b73f7dc14c712729ca0469641bc5f66a29 Mon Sep 17 00:00:00 2001 From: dnault1 <98410411+dnault1@users.noreply.github.com> Date: Wed, 15 Jun 2022 15:32:45 -0400 Subject: [PATCH 118/338] Fix add output pin + icon (#108) Changes the FeditorStyle brush to the one used in the input pin for the + icon --- Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp index b4bd8845f..e7da24177 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp @@ -475,7 +475,7 @@ void SFlowGraphNode::CreateOutputSideAddButton(TSharedPtr OutputBo .Padding(7,0,0,0) [ SNew(SImage) - .Image(FEditorStyle::GetBrush(TEXT("PropertyWindow.Button_AddToArray"))) + .Image(FEditorStyle::GetBrush(TEXT("Icons.PlusCircle"))) ]; AddPinButton(OutputBox, AddPinWidget.ToSharedRef(), EGPD_Output); From eb61f037e2b1b4aab957915738a9953b222653d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Wed, 15 Jun 2022 21:37:28 +0200 Subject: [PATCH 119/338] also fixed input pin icon --- Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp index e7da24177..00a1fd51e 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp @@ -440,7 +440,7 @@ void SFlowGraphNode::CreateInputSideAddButton(TSharedPtr OutputBox . Padding( 0,0,7,0 ) [ SNew(SImage) - .Image(FEditorStyle::GetBrush(TEXT("PropertyWindow.Button_AddToArray"))) + .Image(FEditorStyle::GetBrush(TEXT("Icons.PlusCircle"))) ] +SHorizontalBox::Slot() .AutoWidth() From d4cc94b22d5f44b9a1212ad7e58f503c658dbdfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sat, 25 Jun 2022 21:21:10 +0200 Subject: [PATCH 120/338] Breaking change: GetActors method now only returns actor - Moved original implementation to GetActorsAndComponents methods - Added searching component by non-exactly matched tag (expensive linear complexity!), based on #53 by iknowDavenMC - documented method params --- Source/Flow/Private/FlowSubsystem.cpp | 54 +++-- Source/Flow/Public/FlowSubsystem.h | 297 +++++++++++++++++++------- 2 files changed, 258 insertions(+), 93 deletions(-) diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index 8407ef47b..ba88505ff 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -29,7 +29,7 @@ bool UFlowSubsystem::ShouldCreateSubsystem(UObject* Outer) const { return false; } - + // in this case, we simply create subsystem for every instance of the game if (UFlowSettings::Get()->bCreateFlowSubsystemOnClients) { @@ -125,7 +125,7 @@ UFlowAsset* UFlowSubsystem::CreateSubFlow(UFlowNode_SubGraph* SubGraphNode, cons { // get instanced asset from map - in case it was already instanced by calling CreateSubFlow() with bPreloading == true UFlowAsset* AssetInstance = InstancedSubFlows[SubGraphNode]; - + AssetInstance->NodeOwningThisAssetInstance = SubGraphNode; SubGraphNode->GetFlowAsset()->ActiveSubGraphs.Add(SubGraphNode, AssetInstance); @@ -231,7 +231,7 @@ void UFlowSubsystem::OnGameSaved(UFlowSaveGame* SaveGame) } } } - + // save Flow Graphs for (const TPair, UFlowAsset*>& Pair : RootInstances) { @@ -412,10 +412,10 @@ void UFlowSubsystem::OnIdentityTagsRemoved(UFlowComponent* Component, const FGam } } -TSet UFlowSubsystem::GetFlowComponentsByTag(const FGameplayTag Tag, const TSubclassOf ComponentClass) const +TSet UFlowSubsystem::GetFlowComponentsByTag(const FGameplayTag Tag, const TSubclassOf ComponentClass, const bool bExactMatch) const { TArray> FoundComponents; - FlowComponentRegistry.MultiFind(Tag, FoundComponents); + FindComponents(Tag, bExactMatch, FoundComponents); TSet Result; for (const TWeakObjectPtr& Component : FoundComponents) @@ -429,10 +429,10 @@ TSet UFlowSubsystem::GetFlowComponentsByTag(const FGameplayTag return Result; } -TSet UFlowSubsystem::GetFlowComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType, const TSubclassOf ComponentClass) const +TSet UFlowSubsystem::GetFlowComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType, const TSubclassOf ComponentClass, const bool bExactMatch) const { TSet> FoundComponents; - FindComponents(Tags, FoundComponents, MatchType); + FindComponents(Tags, MatchType, bExactMatch, FoundComponents); TSet Result; for (const TWeakObjectPtr& Component : FoundComponents) @@ -446,10 +446,10 @@ TSet UFlowSubsystem::GetFlowComponentsByTags(const FGameplayTag return Result; } -TSet UFlowSubsystem::GetFlowActorsByTag(const FGameplayTag Tag, const TSubclassOf ActorClass) const +TSet UFlowSubsystem::GetFlowActorsByTag(const FGameplayTag Tag, const TSubclassOf ActorClass, const bool bExactMatch) const { TArray> FoundComponents; - FlowComponentRegistry.MultiFind(Tag, FoundComponents); + FindComponents(Tag, bExactMatch, FoundComponents); TSet Result; for (const TWeakObjectPtr& Component : FoundComponents) @@ -463,10 +463,10 @@ TSet UFlowSubsystem::GetFlowActorsByTag(const FGameplayTag Tag, const T return Result; } -TSet UFlowSubsystem::GetFlowActorsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType, const TSubclassOf ActorClass) const +TSet UFlowSubsystem::GetFlowActorsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType, const TSubclassOf ActorClass, const bool bExactMatch) const { TSet> FoundComponents; - FindComponents(Tags, FoundComponents, MatchType); + FindComponents(Tags, MatchType, bExactMatch, FoundComponents); TSet Result; for (const TWeakObjectPtr& Component : FoundComponents) @@ -480,10 +480,10 @@ TSet UFlowSubsystem::GetFlowActorsByTags(const FGameplayTagContainer Ta return Result; } -TMap UFlowSubsystem::GetFlowActorsAndComponentsByTag(const FGameplayTag Tag, const TSubclassOf ActorClass) const +TMap UFlowSubsystem::GetFlowActorsAndComponentsByTag(const FGameplayTag Tag, const TSubclassOf ActorClass, const bool bExactMatch) const { TArray> FoundComponents; - FlowComponentRegistry.MultiFind(Tag, FoundComponents); + FindComponents(Tag, bExactMatch, FoundComponents); TMap Result; for (const TWeakObjectPtr& Component : FoundComponents) @@ -497,10 +497,10 @@ TMap UFlowSubsystem::GetFlowActorsAndComponentsByTag(c return Result; } -TMap UFlowSubsystem::GetFlowActorsAndComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType, const TSubclassOf ActorClass) const +TMap UFlowSubsystem::GetFlowActorsAndComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType, const TSubclassOf ActorClass, const bool bExactMatch) const { TSet> FoundComponents; - FindComponents(Tags, FoundComponents, MatchType); + FindComponents(Tags, MatchType, bExactMatch, FoundComponents); TMap Result; for (const TWeakObjectPtr& Component : FoundComponents) @@ -514,14 +514,32 @@ TMap UFlowSubsystem::GetFlowActorsAndComponentsByTags( return Result; } -void UFlowSubsystem::FindComponents(const FGameplayTagContainer& Tags, TSet>& OutComponents, const EGameplayContainerMatchType MatchType) const +void UFlowSubsystem::FindComponents(const FGameplayTag& Tag, const bool bExactMatch, TArray>& OutComponents) const +{ + if (bExactMatch) + { + FlowComponentRegistry.MultiFind(Tag, OutComponents); + } + else + { + for (TMultiMap>::TConstIterator It(FlowComponentRegistry); It; ++It) + { + if (It.Key().MatchesTag(Tag)) + { + OutComponents.Emplace(It.Value()); + } + } + } +} + +void UFlowSubsystem::FindComponents(const FGameplayTagContainer& Tags, const EGameplayContainerMatchType MatchType, const bool bExactMatch, TSet>& OutComponents) const { if (MatchType == EGameplayContainerMatchType::Any) { for (const FGameplayTag& Tag : Tags) { TArray> ComponentsPerTag; - FlowComponentRegistry.MultiFind(Tag, ComponentsPerTag); + FindComponents(Tag, bExactMatch, ComponentsPerTag); OutComponents.Append(ComponentsPerTag); } } @@ -531,7 +549,7 @@ void UFlowSubsystem::FindComponents(const FGameplayTagContainer& Tags, TSet> ComponentsPerTag; - FlowComponentRegistry.MultiFind(Tag, ComponentsPerTag); + FindComponents(Tag, bExactMatch, ComponentsPerTag); ComponentsWithAnyTag.Append(ComponentsPerTag); } diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index cae9da307..9ad462acf 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -28,23 +28,23 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem { GENERATED_BODY() -public: +public: UFlowSubsystem(); -private: +private: friend class UFlowAsset; friend class UFlowComponent; friend class UFlowNode_SubGraph; - // All asset templates with active instances + /* All asset templates with active instances */ UPROPERTY() TArray InstancedTemplates; - // Assets instanced by object from another system, i.e. World Settings or Player Controller + /* Assets instanced by object from another system, i.e. World Settings or Player Controller */ UPROPERTY() TMap, UFlowAsset*> RootInstances; - // Assets instanced by Sub Graph nodes + /* Assets instanced by Sub Graph nodes */ UPROPERTY() TMap InstancedSubFlows; @@ -62,15 +62,15 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem virtual void AbortActiveFlows(); - // Start the root Flow, graph that will eventually instantiate next Flow Graphs through the SubGraph node + /* Start the root Flow, graph that will eventually instantiate next Flow Graphs through the SubGraph node */ UFUNCTION(BlueprintCallable, Category = "FlowSubsystem") virtual void StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances = true); virtual UFlowAsset* CreateRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances = true); - // Finish Policy value is read by Flow Node - // Nodes have opportunity to terminate themselves differently if Flow Graph has been aborted - // Example: Spawn node might despawn all actors if Flow Graph is aborted, not completed + /* Finish Policy value is read by Flow Node + * Nodes have opportunity to terminate themselves differently if Flow Graph has been aborted + * Example: Spawn node might despawn all actors if Flow Graph is aborted, not completed */ UFUNCTION(BlueprintCallable, Category = "FlowSubsystem") virtual void FinishRootFlow(UObject* Owner, const EFlowFinishPolicy FinishPolicy); @@ -82,20 +82,20 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem void RemoveInstancedTemplate(UFlowAsset* Template); public: - // Returns asset instanced by object from another system like World Settings + /* Returns asset instanced by object from another system like World Settings */ UFUNCTION(BlueprintPure, Category = "FlowSubsystem") - UFlowAsset* GetRootFlow(UObject* Owner) const { return RootInstances.FindRef(Owner); } - - // Returns assets instanced by object from another system like World Settings + UFlowAsset* GetRootFlow(UObject* Owner) const { return RootInstances.FindRef(Owner); } + + /* Returns assets instanced by object from another system like World Settings */ UFUNCTION(BlueprintPure, Category = "FlowSubsystem") - TMap GetRootInstances() const; + TMap GetRootInstances() const; - // Returns assets instanced by Sub Graph nodes + /* Returns assets instanced by Sub Graph nodes */ UFUNCTION(BlueprintPure, Category = "FlowSubsystem") - TMap GetInstancedSubFlows() const { return InstancedSubFlows; } - + TMap GetInstancedSubFlows() const { return InstancedSubFlows; } + virtual UWorld* GetWorld() const override; - + ////////////////////////////////////////////////////////////////////////// // SaveGame @@ -110,7 +110,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem virtual void LoadRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const FString& SavedAssetInstanceName); virtual void LoadSubFlow(UFlowNode_SubGraph* SubGraphNode, const FString& SavedAssetInstanceName); - + UFUNCTION(BlueprintPure, Category = "FlowSubsystem") UFlowSaveGame* GetLoadedSaveGame() const { return LoadedSaveGame; } @@ -118,139 +118,285 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem // Component Registry private: - // All the Flow Components currently existing in the world + /* All the Flow Components currently existing in the world */ TMultiMap> FlowComponentRegistry; protected: virtual void RegisterComponent(UFlowComponent* Component); virtual void OnIdentityTagAdded(UFlowComponent* Component, const FGameplayTag& AddedTag); virtual void OnIdentityTagsAdded(UFlowComponent* Component, const FGameplayTagContainer& AddedTags); - + virtual void UnregisterComponent(UFlowComponent* Component); virtual void OnIdentityTagRemoved(UFlowComponent* Component, const FGameplayTag& RemovedTag); virtual void OnIdentityTagsRemoved(UFlowComponent* Component, const FGameplayTagContainer& RemovedTags); public: - // Called when actor with Flow Component appears in the world + /* Called when actor with Flow Component appears in the world */ UPROPERTY(BlueprintAssignable, Category = "FlowSubsystem") FSimpleFlowComponentEvent OnComponentRegistered; - // Called after adding Identity Tags to already registered Flow Component - // This can happen only after Begin Play occured in the component + /* Called after adding Identity Tags to already registered Flow Component + * This can happen only after Begin Play occured in the component */ UPROPERTY(BlueprintAssignable, Category = "FlowSubsystem") FTaggedFlowComponentEvent OnComponentTagAdded; - // Called when actor with Flow Component disappears from the world + /* Called when actor with Flow Component disappears from the world */ UPROPERTY(BlueprintAssignable, Category = "FlowSubsystem") FSimpleFlowComponentEvent OnComponentUnregistered; - // Called after removing Identity Tags from the Flow Component, if component still has some Identity Tags - // This can happen only after Begin Play occured in the component + /* Called after removing Identity Tags from the Flow Component, if component still has some Identity Tags + * This can happen only after Begin Play occured in the component */ UPROPERTY(BlueprintAssignable, Category = "FlowSubsystem") FTaggedFlowComponentEvent OnComponentTagRemoved; - // Returns all registered Flow Components identified by given tag - UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "ComponentClass")) - TSet GetFlowComponentsByTag(const FGameplayTag Tag, const TSubclassOf ComponentClass) const; + /** + * Returns all registered Flow Components identified by given tag + * + * @param Tag Tag to check if it matches Identity Tags of registered Flow Components + * @param ComponentClass Only components matching this class we'll be returned + * @param bExactMatch If true, the tag has to be exactly present, if false then TagContainer will include it's parent tags while matching. Be careful, using latter option may be very expensive, as the search cost is proportional to the number of registered Gameplay Tags! + */ + UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "T")) + TSet GetFlowComponentsByTag(const FGameplayTag Tag, const TSubclassOf ComponentClass, const bool bExactMatch = true) const; + + /** + * Returns all registered Flow Components identified by Any or All provided tags + * + * @param Tags Container to check if it matches Identity Tags of registered Flow Components + * @param MatchType If Any, returned component needs to have only one of given tags. If All, component needs to have all given Identity Tags + * @param ComponentClass Only components matching this class we'll be returned + * @param bExactMatch If true, the tag has to be exactly present, if false then TagContainer will include it's parent tags while matching. Be careful, using latter option may be very expensive, as the search cost is proportional to the number of registered Gameplay Tags! + */ + UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "T")) + TSet GetFlowComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType, const TSubclassOf ComponentClass, const bool bExactMatch = true) const; + + /** + * Returns all registered actors with Flow Component identified by given tag + * + * @param Tag Tag to check if it matches Identity Tags of registered Flow Components + * @param ActorClass Only actors matching this class we'll be returned + * @param bExactMatch If true, the tag has to be exactly present, if false then TagContainer will include it's parent tags while matching. Be careful, using latter option may be very expensive, as the search cost is proportional to the number of registered Gameplay Tags! + */ + UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "T")) + TSet GetFlowActorsByTag(const FGameplayTag Tag, const TSubclassOf ActorClass, const bool bExactMatch = true) const; + + /** + * Returns all registered actors with Flow Component identified by Any or All provided tags + * + * @param Tags Container to check if it matches Identity Tags of registered Flow Components + * @param MatchType If Any, returned component needs to have only one of given tags. If All, component needs to have all given Identity Tags + * @param ActorClass Only actors matching this class we'll be returned + * @param bExactMatch If true, the tag has to be exactly present, if false then TagContainer will include it's parent tags while matching. Be careful, using latter option may be very expensive, as the search cost is proportional to the number of registered Gameplay Tags! + */ + UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "T")) + TSet GetFlowActorsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType, const TSubclassOf ActorClass, const bool bExactMatch = true) const; + + /** + * Returns all registered actors as pairs: Actor as key, its Flow Component as value + * + * @param Tag Tag to check if it matches Identity Tags of registered Flow Components + * @param ActorClass Only actors matching this class we'll be returned + * @param bExactMatch If true, the tag has to be exactly present, if false then TagContainer will include it's parent tags while matching. Be careful, using latter option may be very expensive, as the search cost is proportional to the number of registered Gameplay Tags! + */ + UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "T")) + TMap GetFlowActorsAndComponentsByTag(const FGameplayTag Tag, const TSubclassOf ActorClass, const bool bExactMatch = true) const; + + /** + * Returns all registered actors as pairs: Actor as key, its Flow Component as value + * + * @param Tags Container to check if it matches Identity Tags of registered Flow Components + * @param MatchType If Any, returned component needs to have only one of given tags. If All, component needs to have all given Identity Tags + * @param ActorClass Only actors matching this class we'll be returned + * @param bExactMatch If true, the tag has to be exactly present, if false then TagContainer will include it's parent tags while matching. Be careful, using latter option may be very expensive, as the search cost is proportional to the number of registered Gameplay Tags! + */ + UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "T")) + TMap GetFlowActorsAndComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType, const TSubclassOf ActorClass, const bool bExactMatch = true) const; + + /** + * Returns all registered Flow Components identified by given tag + * + * @tparam T Only components matching this class we'll be returned + * @param Tag Tag to check if it matches Identity Tags of registered Flow Components + * @param bExactMatch If true, the tag has to be exactly present, if false then TagContainer will include it's parent tags while matching. Be careful, using latter option may be very expensive, as the search cost is proportional to the number of registered Gameplay Tags! + */ + template + TSet> GetComponents(const FGameplayTag& Tag, const bool bExactMatch = true) const + { + static_assert(TPointerIsConvertibleFromTo::Value, "'T' template parameter to GetComponents must be derived from UActorComponent"); - // Returns all registered Flow Components identified by Any or All provided tags - UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "ComponentClass")) - TSet GetFlowComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType, const TSubclassOf ComponentClass) const; + TArray> FoundComponents; + FindComponents(Tag, bExactMatch, FoundComponents); - // Returns all registered actors with Flow Component identified by given tag - UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "ActorClass")) - TSet GetFlowActorsByTag(const FGameplayTag Tag, const TSubclassOf ActorClass) const; + TSet> Result; + for (const TWeakObjectPtr& Component : FoundComponents) + { + if (Component.IsValid()) + { + if (T* ComponentOfClass = Cast(Component)) + { + Result.Emplace(ComponentOfClass); + } + } + } - // Returns all registered actors with Flow Component identified by Any or All provided tags - UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "ActorClass")) - TSet GetFlowActorsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType, const TSubclassOf ActorClass) const; + return Result; + } - // Returns all registered actors as pairs: Actor as key, its Flow Component as value - UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "ActorClass")) - TMap GetFlowActorsAndComponentsByTag(const FGameplayTag Tag, const TSubclassOf ActorClass) const; + /** + * Returns all registered Flow Components identified by Any or All provided tags + * + * @tparam T Only components matching this class we'll be returned + * @param Tags Container to check if it matches Identity Tags of registered Flow Components + * @param MatchType If Any, returned component needs to have only one of given tags. If All, component needs to have all given Identity Tags + * @param bExactMatch If true, the tag has to be exactly present, if false then TagContainer will include it's parent tags while matching. Be careful, using latter option may be very expensive, as the search cost is proportional to the number of registered Gameplay Tags! + */ + template + TSet> GetComponents(const FGameplayTagContainer& Tags, const EGameplayContainerMatchType MatchType, const bool bExactMatch = true) const + { + static_assert(TPointerIsConvertibleFromTo::Value, "'T' template parameter to GetComponents must be derived from UActorComponent"); + + TSet> FoundComponents; + FindComponents(Tags, MatchType, bExactMatch, FoundComponents); + + TSet> Result; + for (const TWeakObjectPtr& Component : FoundComponents) + { + if (Component.IsValid()) + { + if (T* ComponentOfClass = Cast(Component)) + { + Result.Emplace(ComponentOfClass); + } + } + } - // Returns all registered actors as pairs: Actor as key, its Flow Component as value - UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "ActorClass")) - TMap GetFlowActorsAndComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType, const TSubclassOf ActorClass) const; + return Result; + } - // Returns all registered Flow Components identified by given tag + /** + * Returns all registered Flow Components identified by given tag + * + * @tparam T Only components matching this class we'll be returned + * @param Tag Tag to check if it matches Identity Tags of registered Flow Components + * @param bExactMatch If true, the tag has to be exactly present, if false then TagContainer will include it's parent tags while matching. Be careful, using latter option may be very expensive, as the search cost is proportional to the number of registered Gameplay Tags! + */ template - TSet> GetComponents(const FGameplayTag& Tag) const + TSet> GetActors(const FGameplayTag& Tag, const bool bExactMatch = true) const { - static_assert(TPointerIsConvertibleFromTo::Value, "'T' template parameter to GetComponents must be derived from UActorComponent"); + static_assert(TPointerIsConvertibleFromTo::Value, "'T' template parameter to GetActors must be derived from AActor"); TArray> FoundComponents; - FlowComponentRegistry.MultiFind(Tag, FoundComponents); + FindComponents(Tag, bExactMatch, FoundComponents); TSet> Result; for (const TWeakObjectPtr& Component : FoundComponents) { - if (Component.IsValid() && Component->GetClass()->IsChildOf(T::StaticClass())) + if (Component.IsValid()) { - Result.Emplace(Cast(Component)); + if (T* ActorOfClass = Cast(Component->GetOwner())) + { + Result.Emplace(ActorOfClass); + } } } return Result; } - // Returns all registered Flow Components identified by Any or All provided tags + /** + * Returns all registered Flow Components identified by Any or All provided tags + * + * @tparam T Only actors matching this class we'll be returned + * @param Tags Container to check if it matches Identity Tags of registered Flow Components + * @param MatchType If Any, returned component needs to have only one of given tags. If All, component needs to have all given Identity Tags + * @param bExactMatch If true, the tag has to be exactly present, if false then TagContainer will include it's parent tags while matching. Be careful, using latter option may be very expensive, as the search cost is proportional to the number of registered Gameplay Tags! + */ template - TSet> GetComponents(const FGameplayTagContainer& Tags, const EGameplayContainerMatchType MatchType) const + TSet> GetActors(const FGameplayTagContainer& Tags, const EGameplayContainerMatchType MatchType, const bool bExactMatch = true) const { - static_assert(TPointerIsConvertibleFromTo::Value, "'T' template parameter to GetComponents must be derived from UActorComponent"); + static_assert(TPointerIsConvertibleFromTo::Value, "'T' template parameter to GetActors must be derived from AActor"); TSet> FoundComponents; - FindComponents(Tags, FoundComponents, MatchType); + FindComponents(Tags, MatchType, bExactMatch, FoundComponents); TSet> Result; for (const TWeakObjectPtr& Component : FoundComponents) { - if (Component.IsValid() && Component->GetClass()->IsChildOf(T::StaticClass())) + if (Component.IsValid()) { - Result.Emplace(Cast(Component)); + if (T* ActorOfClass = Cast(Component->GetOwner())) + { + Result.Emplace(ActorOfClass); + } } } return Result; } - // Returns all registered actors with Flow Component identified by given tag - template - TMap, TWeakObjectPtr> GetActors(const FGameplayTag& Tag) const + /** + * Returns all registered actors with Flow Component identified by given tag + * + * @tparam ActorT Only actors matching this class we'll be returned + * @tparam ComponentT Only components matching this class we'll be returned + * @param Tag Tag to check if it matches Identity Tags of registered Flow Components + * @param bExactMatch If true, the tag has to be exactly present, if false then TagContainer will include it's parent tags while matching. Be careful, using latter option may be very expensive, as the search cost is proportional to the number of registered Gameplay Tags! + */ + template + TMap, TWeakObjectPtr> GetActorsAndComponents(const FGameplayTag& Tag, const bool bExactMatch = true) const { - static_assert(TPointerIsConvertibleFromTo::Value, "'T' template parameter to GetComponents must be derived from AActor"); + static_assert(TPointerIsConvertibleFromTo::Value, "'ActorT' template parameter to GetActorsAndComponents must be derived from AActor"); + static_assert(TPointerIsConvertibleFromTo::Value, "'ComponentT' template parameter to GetActorsAndComponents must be derived from UActorComponent"); TArray> FoundComponents; - FlowComponentRegistry.MultiFind(Tag, FoundComponents); + FindComponents(Tag, bExactMatch, FoundComponents); - TMap, TWeakObjectPtr> Result; + TMap, TWeakObjectPtr> Result; for (const TWeakObjectPtr& Component : FoundComponents) { - if (Component.IsValid() && Component->GetOwner()->GetClass()->IsChildOf(T::StaticClass())) + if (Component.IsValid()) { - Result.Emplace(Cast(Component->GetOwner()), Component); + ComponentT* ComponentOfClass = Cast(Component); + ActorT* ActorOfClass = Cast(Component->GetOwner()); + if (ComponentOfClass && ActorOfClass) + { + Result.Emplace(ActorOfClass, ComponentOfClass); + } } } return Result; } - // Returns all registered actors with Flow Component identified by at least one of given tags - template - TMap, TWeakObjectPtr> GetActors(const FGameplayTagContainer& Tags, const EGameplayContainerMatchType MatchType) const + /** + * Returns all registered actors with Flow Component identified by Any or All provided tags + * + * @tparam ActorT Only actors matching this class we'll be returned + * @tparam ComponentT Only components matching this class we'll be returned + * @param Tags Container to check if it matches Identity Tags of registered Flow Components + * @param MatchType If Any, returned component needs to have only one of given tags. If All, component needs to have all given Identity Tags + * @param bExactMatch If true, the tag has to be exactly present, if false then TagContainer will include it's parent tags while matching. Be careful, using latter option may be very expensive, as the search cost is proportional to the number of registered Gameplay Tags! + */ + template + TMap, TWeakObjectPtr> GetActorsAndComponents(const FGameplayTagContainer& Tags, const EGameplayContainerMatchType MatchType, const bool bExactMatch = true) const { - static_assert(TPointerIsConvertibleFromTo::Value, "'T' template parameter to GetComponents must be derived from AActor"); + static_assert(TPointerIsConvertibleFromTo::Value, "'ActorT' template parameter to GetActorsAndComponents must be derived from AActor"); + static_assert(TPointerIsConvertibleFromTo::Value, "'ComponentT' template parameter to GetActorsAndComponents must be derived from UActorComponent"); TSet> FoundComponents; - FindComponents(Tags, FoundComponents, MatchType); + FindComponents(Tags, MatchType, bExactMatch, FoundComponents); - TMap, TWeakObjectPtr> Result; + TMap, TWeakObjectPtr> Result; for (const TWeakObjectPtr& Component : FoundComponents) { - if (Component.IsValid() && Component->GetOwner()->GetClass()->IsChildOf(T::StaticClass())) + if (Component.IsValid()) { - Result.Emplace(Cast(Component->GetOwner()), Component); + ComponentT* ComponentOfClass = Cast(Component); + ActorT* ActorOfClass = Cast(Component->GetOwner()); + if (ComponentOfClass && ActorOfClass) + { + Result.Emplace(ActorOfClass, ComponentOfClass); + } } } @@ -258,5 +404,6 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem } private: - void FindComponents(const FGameplayTagContainer& Tags, TSet>& OutComponents, const EGameplayContainerMatchType MatchType) const; -}; \ No newline at end of file + void FindComponents(const FGameplayTag& Tag, const bool bExactMatch, TArray>& OutComponents) const; + void FindComponents(const FGameplayTagContainer& Tags, const EGameplayContainerMatchType MatchType, const bool bExactMatch, TSet>& OutComponents) const; +}; From 048621e98e1542317020accf82a308ed3241d2a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 1 Jul 2022 17:25:45 +0200 Subject: [PATCH 121/338] improved Notify categories --- Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h | 6 +++--- Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h | 4 ++-- .../Customizations/FlowNode_ComponentObserverDetails.cpp | 1 + 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h b/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h index 26a072f95..f637cd27e 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h @@ -16,13 +16,13 @@ class FLOW_API UFlowNode_NotifyActor : public UFlowNode GENERATED_UCLASS_BODY() protected: - UPROPERTY(EditAnywhere, Category = "ObservedComponent") + UPROPERTY(EditAnywhere, Category = "Notify") FGameplayTagContainer IdentityTags; - UPROPERTY(EditAnywhere, Category = "ObservedComponent") + UPROPERTY(EditAnywhere, Category = "Notify") FGameplayTagContainer NotifyTags; - UPROPERTY(EditAnywhere, Category = "ObservedComponent") + UPROPERTY(EditAnywhere, Category = "Notify") EFlowNetMode NetMode; virtual void PostLoad() override; diff --git a/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h b/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h index 7c863fde9..3cab19a33 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h @@ -14,12 +14,12 @@ class FLOW_API UFlowNode_OnNotifyFromActor : public UFlowNode_ComponentObserver GENERATED_UCLASS_BODY() protected: - UPROPERTY(EditAnywhere, Category = "ObservedComponent") + UPROPERTY(EditAnywhere, Category = "Notify") FGameplayTagContainer NotifyTags; // If true, node will check given Notify Tag is present in the Recently Sent Notify Tags // This might be helpful in multiplayer, if client-side Flow Node started work after server sent the notify - UPROPERTY(EditAnywhere, Category = "ObservedComponent") + UPROPERTY(EditAnywhere, Category = "Notify") bool bRetroactive; virtual void PostLoad() override; diff --git a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_ComponentObserverDetails.cpp b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_ComponentObserverDetails.cpp index bf346e6e5..dec2f9222 100644 --- a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_ComponentObserverDetails.cpp +++ b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_ComponentObserverDetails.cpp @@ -10,4 +10,5 @@ void FFlowNode_ComponentObserverDetails::CustomizeDetails(IDetailLayoutBuilder& { IDetailCategoryBuilder& SequenceCategory = DetailBuilder.EditCategory("ObservedComponent"); SequenceCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UFlowNode_ComponentObserver, IdentityTags)); + SequenceCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UFlowNode_ComponentObserver, IdentityMatchType)); } From 6bea7ff1fc68037855117adc98e30dcc11e4bfc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 24 Jul 2022 16:33:44 +0200 Subject: [PATCH 122/338] removed limitation of executing only the first found CustomInput with given EventName --- Source/Flow/Private/FlowAsset.cpp | 18 ++++++++++-------- .../Private/Nodes/Route/FlowNode_SubGraph.cpp | 2 +- Source/Flow/Public/FlowAsset.h | 2 +- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index c7612a560..59047626c 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -279,10 +279,9 @@ void UFlowAsset::InitializeInstance(const TWeakObjectPtr InOwner, UFlow if (UFlowNode_CustomInput* CustomInput = Cast(NewNodeInstance)) { - const FName& EventName = CustomInput->EventName; - if (!EventName.IsNone() && !CustomInputNodes.Contains(CustomInput->EventName)) + if (!CustomInput->EventName.IsNone()) { - CustomInputNodes.Emplace(CustomInput->EventName, CustomInput); + CustomInputNodes.Emplace(CustomInput); } } @@ -293,9 +292,9 @@ void UFlowAsset::InitializeInstance(const TWeakObjectPtr InOwner, UFlow void UFlowAsset::PreloadNodes() { TArray GraphEntryNodes = {StartNode}; - for (const TPair& CustomEvent : CustomInputNodes) + for (UFlowNode_CustomInput* CustomInput : CustomInputNodes) { - GraphEntryNodes.Emplace(CustomEvent.Value); + GraphEntryNodes.Emplace(CustomInput); } // NOTE: this is just the example algorithm of gathering nodes for pre-load @@ -384,10 +383,13 @@ void UFlowAsset::TriggerCustomEvent(UFlowNode_SubGraph* Node, const FName& Event const TWeakObjectPtr FlowInstance = ActiveSubGraphs.FindRef(Node); if (FlowInstance.IsValid()) { - if (UFlowNode_CustomInput* CustomEvent = FlowInstance->CustomInputNodes.FindRef(EventName)) + for (UFlowNode_CustomInput* CustomInput : FlowInstance->CustomInputNodes) { - RecordedNodes.Add(CustomEvent); - CustomEvent->TriggerFirstOutput(true); + if (CustomInput->EventName == EventName) + { + RecordedNodes.Add(CustomInput); + CustomInput->TriggerFirstOutput(true); + } } } } diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp index c1949bd28..dede5195c 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp @@ -66,7 +66,7 @@ void UFlowNode_SubGraph::ExecuteInput(const FName& PinName) GetFlowSubsystem()->CreateSubFlow(this); } } - else + else if (!PinName.IsNone()) { GetFlowAsset()->TriggerCustomEvent(this, PinName); } diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index ca87c6d35..44d1f7a3a 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -183,7 +183,7 @@ class FLOW_API UFlowAsset : public UObject // Optional entry points to the graph, similar to blueprint Custom Events UPROPERTY() - TMap CustomInputNodes; + TSet CustomInputNodes; UPROPERTY() TSet PreloadedNodes; From 443fe1578f2c1a59615b3d82acd0d33125451b98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 24 Jul 2022 16:58:59 +0200 Subject: [PATCH 123/338] Fixed highlighting of activate wire coming out of Custom Input node --- Source/Flow/Private/FlowAsset.cpp | 4 ++-- Source/Flow/Public/FlowAsset.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 59047626c..58635dce3 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -378,7 +378,7 @@ TWeakObjectPtr UFlowAsset::GetFlowInstance(UFlowNode_SubGraph* SubGr return ActiveSubGraphs.FindRef(SubGraphNode); } -void UFlowAsset::TriggerCustomEvent(UFlowNode_SubGraph* Node, const FName& EventName) +void UFlowAsset::TriggerCustomEvent(UFlowNode_SubGraph* Node, const FName& EventName) const { const TWeakObjectPtr FlowInstance = ActiveSubGraphs.FindRef(Node); if (FlowInstance.IsValid()) @@ -387,7 +387,7 @@ void UFlowAsset::TriggerCustomEvent(UFlowNode_SubGraph* Node, const FName& Event { if (CustomInput->EventName == EventName) { - RecordedNodes.Add(CustomInput); + FlowInstance->RecordedNodes.Add(CustomInput); CustomInput->TriggerFirstOutput(true); } } diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 44d1f7a3a..eacbdf7f4 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -225,7 +225,7 @@ class FLOW_API UFlowAsset : public UObject TWeakObjectPtr GetFlowInstance(UFlowNode_SubGraph* SubGraphNode) const; private: - void TriggerCustomEvent(UFlowNode_SubGraph* Node, const FName& EventName); + void TriggerCustomEvent(UFlowNode_SubGraph* Node, const FName& EventName) const; void TriggerCustomOutput(const FName& EventName) const; void TriggerInput(const FGuid& NodeGuid, const FName& PinName); From dc00bcd8c16eb63d17e84c8b416006754ee9ae0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Wed, 17 Aug 2022 18:34:59 +0200 Subject: [PATCH 124/338] fixed reading IdentityMatchType --- .../Private/Nodes/World/FlowNode_ComponentObserver.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp index beefe0e87..e4522cf99 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp @@ -59,7 +59,12 @@ void UFlowNode_ComponentObserver::StartObserving() { if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) { - for (const TWeakObjectPtr& FoundComponent : FlowSubsystem->GetComponents(IdentityTags, EGameplayContainerMatchType::Any)) + // translate Flow name into engine types + const EGameplayContainerMatchType ContainerMatchType = (IdentityMatchType == EFlowTagContainerMatchType::HasAny || IdentityMatchType == EFlowTagContainerMatchType::HasAnyExact) ? EGameplayContainerMatchType::Any : EGameplayContainerMatchType::All; + const bool bExactMatch = (IdentityMatchType == EFlowTagContainerMatchType::HasAnyExact || IdentityMatchType == EFlowTagContainerMatchType::HasAllExact); + + // collect already registered components + for (const TWeakObjectPtr& FoundComponent : FlowSubsystem->GetComponents(IdentityTags, ContainerMatchType, bExactMatch)) { ObserveActor(FoundComponent->GetOwner(), FoundComponent); } From aca80af4abf9f441be3ec0c8610697cc4b1fcf42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sat, 20 Aug 2022 09:48:03 +0200 Subject: [PATCH 125/338] shorted notation --- Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp index 0a7db0cf4..43aebb508 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -321,7 +321,7 @@ void UFlowGraphSchema::GetCommentAction(FGraphActionMenuBuilder& ActionMenuBuild bool UFlowGraphSchema::IsFlowNodePlaceable(const UClass* Class) { - if (Class->HasAnyClassFlags(CLASS_Abstract) || Class->HasAnyClassFlags(CLASS_NotPlaceable) || Class->HasAnyClassFlags(CLASS_Deprecated)) + if (Class->HasAnyClassFlags(CLASS_Abstract | CLASS_NotPlaceable | CLASS_Deprecated)) { return false; } From f063e634424cf232a5ebe4e0aa7169040780e17d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sat, 20 Aug 2022 09:49:14 +0200 Subject: [PATCH 126/338] fixed accidental parameter rename --- Source/Flow/Public/FlowSubsystem.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index 9ad462acf..e634f6092 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -156,7 +156,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem * @param ComponentClass Only components matching this class we'll be returned * @param bExactMatch If true, the tag has to be exactly present, if false then TagContainer will include it's parent tags while matching. Be careful, using latter option may be very expensive, as the search cost is proportional to the number of registered Gameplay Tags! */ - UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "T")) + UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "ComponentClass")) TSet GetFlowComponentsByTag(const FGameplayTag Tag, const TSubclassOf ComponentClass, const bool bExactMatch = true) const; /** @@ -167,7 +167,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem * @param ComponentClass Only components matching this class we'll be returned * @param bExactMatch If true, the tag has to be exactly present, if false then TagContainer will include it's parent tags while matching. Be careful, using latter option may be very expensive, as the search cost is proportional to the number of registered Gameplay Tags! */ - UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "T")) + UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "ComponentClass")) TSet GetFlowComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType, const TSubclassOf ComponentClass, const bool bExactMatch = true) const; /** @@ -177,7 +177,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem * @param ActorClass Only actors matching this class we'll be returned * @param bExactMatch If true, the tag has to be exactly present, if false then TagContainer will include it's parent tags while matching. Be careful, using latter option may be very expensive, as the search cost is proportional to the number of registered Gameplay Tags! */ - UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "T")) + UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "ActorClass")) TSet GetFlowActorsByTag(const FGameplayTag Tag, const TSubclassOf ActorClass, const bool bExactMatch = true) const; /** @@ -188,7 +188,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem * @param ActorClass Only actors matching this class we'll be returned * @param bExactMatch If true, the tag has to be exactly present, if false then TagContainer will include it's parent tags while matching. Be careful, using latter option may be very expensive, as the search cost is proportional to the number of registered Gameplay Tags! */ - UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "T")) + UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "ActorClass")) TSet GetFlowActorsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType, const TSubclassOf ActorClass, const bool bExactMatch = true) const; /** @@ -198,7 +198,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem * @param ActorClass Only actors matching this class we'll be returned * @param bExactMatch If true, the tag has to be exactly present, if false then TagContainer will include it's parent tags while matching. Be careful, using latter option may be very expensive, as the search cost is proportional to the number of registered Gameplay Tags! */ - UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "T")) + UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "ActorClass")) TMap GetFlowActorsAndComponentsByTag(const FGameplayTag Tag, const TSubclassOf ActorClass, const bool bExactMatch = true) const; /** @@ -209,7 +209,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem * @param ActorClass Only actors matching this class we'll be returned * @param bExactMatch If true, the tag has to be exactly present, if false then TagContainer will include it's parent tags while matching. Be careful, using latter option may be very expensive, as the search cost is proportional to the number of registered Gameplay Tags! */ - UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "T")) + UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "ActorClass")) TMap GetFlowActorsAndComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType, const TSubclassOf ActorClass, const bool bExactMatch = true) const; /** From f138c4e350c9e461974aa1efb4deb6ad90a4c80a Mon Sep 17 00:00:00 2001 From: Markus Ahrweiler Date: Sat, 20 Aug 2022 09:52:22 +0200 Subject: [PATCH 127/338] The OR-Operator can now be executed once and can be reset if, it's only executed once (#109) --- .../Nodes/Operators/FlowNode_LogicalOR.cpp | 37 +++++++++++++++++++ .../Nodes/Operators/FlowNode_LogicalOR.h | 12 +++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/Source/Flow/Private/Nodes/Operators/FlowNode_LogicalOR.cpp b/Source/Flow/Private/Nodes/Operators/FlowNode_LogicalOR.cpp index f814ee709..14adc663c 100644 --- a/Source/Flow/Private/Nodes/Operators/FlowNode_LogicalOR.cpp +++ b/Source/Flow/Private/Nodes/Operators/FlowNode_LogicalOR.cpp @@ -2,6 +2,8 @@ #include "Nodes/Operators/FlowNode_LogicalOR.h" +static FName ResetName = TEXT("Reset"); + UFlowNode_LogicalOR::UFlowNode_LogicalOR(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { @@ -13,7 +15,42 @@ UFlowNode_LogicalOR::UFlowNode_LogicalOR(const FObjectInitializer& ObjectInitial SetNumberedInputPins(0, 1); } +void UFlowNode_LogicalOR::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) +{ + Super::PostEditChangeProperty(PropertyChangedEvent); + + if (PropertyChangedEvent.GetPropertyName() == GET_MEMBER_NAME_CHECKED(UFlowNode_LogicalOR, bOnce)) + { + if (bOnce) + { + InputPins.EmplaceAt(0, ResetName); + OutputPins.Emplace(ResetName); + } + else + { + InputPins.Remove(ResetName); + OutputPins.Remove(ResetName); + } + + OnReconstructionRequested.ExecuteIfBound(); + } +} + void UFlowNode_LogicalOR::ExecuteInput(const FName& PinName) { + if (PinName == ResetName) + { + bCompleted = false; + TriggerOutput(ResetName, false); + return; + } + + if (bOnce && bCompleted) + { + return; + } + + bCompleted = true; + TriggerFirstOutput(true); } diff --git a/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalOR.h b/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalOR.h index 75828dab9..e293e9fd7 100644 --- a/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalOR.h +++ b/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalOR.h @@ -13,11 +13,21 @@ UCLASS(NotBlueprintable, meta = (DisplayName = "OR")) class FLOW_API UFlowNode_LogicalOR final : public UFlowNode { GENERATED_UCLASS_BODY() - #if WITH_EDITOR virtual bool CanUserAddInput() const override { return true; } + + virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; #endif + + protected: + /** If set to true, this node will only execute once until reset */ + UPROPERTY(EditAnywhere) + bool bOnce = false; + + UPROPERTY(SaveGame) + bool bCompleted = false; + virtual void ExecuteInput(const FName& PinName) override; }; From af0bbe14f3b5166d2511d9a034c55c027c603ca2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sat, 20 Aug 2022 10:35:51 +0200 Subject: [PATCH 128/338] added SaveGame specifier --- Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h b/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h index f8b2c95a1..32a7254a8 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h @@ -35,7 +35,7 @@ class FLOW_API UFlowNode_ComponentObserver : public UFlowNode int32 SuccessLimit; // This node will become Completed, if Success Limit > 0 and Success Count reaches this limit - UPROPERTY(VisibleAnywhere, Category = "Lifetime") + UPROPERTY(VisibleAnywhere, Category = "Lifetime", SaveGame) int32 SuccessCount; TMap, TWeakObjectPtr> RegisteredActors; From c9a49b2531e72a5b34aead1b7f484566e72a14b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sat, 20 Aug 2022 11:18:22 +0200 Subject: [PATCH 129/338] Revert "The OR-Operator can now be executed once and can be reset if, it's only executed once (#109)" This reverts commit f138c4e350c9e461974aa1efb4deb6ad90a4c80a. --- .../Nodes/Operators/FlowNode_LogicalOR.cpp | 37 ------------------- .../Nodes/Operators/FlowNode_LogicalOR.h | 12 +----- 2 files changed, 1 insertion(+), 48 deletions(-) diff --git a/Source/Flow/Private/Nodes/Operators/FlowNode_LogicalOR.cpp b/Source/Flow/Private/Nodes/Operators/FlowNode_LogicalOR.cpp index 14adc663c..f814ee709 100644 --- a/Source/Flow/Private/Nodes/Operators/FlowNode_LogicalOR.cpp +++ b/Source/Flow/Private/Nodes/Operators/FlowNode_LogicalOR.cpp @@ -2,8 +2,6 @@ #include "Nodes/Operators/FlowNode_LogicalOR.h" -static FName ResetName = TEXT("Reset"); - UFlowNode_LogicalOR::UFlowNode_LogicalOR(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { @@ -15,42 +13,7 @@ UFlowNode_LogicalOR::UFlowNode_LogicalOR(const FObjectInitializer& ObjectInitial SetNumberedInputPins(0, 1); } -void UFlowNode_LogicalOR::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) -{ - Super::PostEditChangeProperty(PropertyChangedEvent); - - if (PropertyChangedEvent.GetPropertyName() == GET_MEMBER_NAME_CHECKED(UFlowNode_LogicalOR, bOnce)) - { - if (bOnce) - { - InputPins.EmplaceAt(0, ResetName); - OutputPins.Emplace(ResetName); - } - else - { - InputPins.Remove(ResetName); - OutputPins.Remove(ResetName); - } - - OnReconstructionRequested.ExecuteIfBound(); - } -} - void UFlowNode_LogicalOR::ExecuteInput(const FName& PinName) { - if (PinName == ResetName) - { - bCompleted = false; - TriggerOutput(ResetName, false); - return; - } - - if (bOnce && bCompleted) - { - return; - } - - bCompleted = true; - TriggerFirstOutput(true); } diff --git a/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalOR.h b/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalOR.h index e293e9fd7..75828dab9 100644 --- a/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalOR.h +++ b/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalOR.h @@ -13,21 +13,11 @@ UCLASS(NotBlueprintable, meta = (DisplayName = "OR")) class FLOW_API UFlowNode_LogicalOR final : public UFlowNode { GENERATED_UCLASS_BODY() + #if WITH_EDITOR virtual bool CanUserAddInput() const override { return true; } - - virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; #endif - - protected: - /** If set to true, this node will only execute once until reset */ - UPROPERTY(EditAnywhere) - bool bOnce = false; - - UPROPERTY(SaveGame) - bool bCompleted = false; - virtual void ExecuteInput(const FName& PinName) override; }; From 8891eda69b0a13e28c8a042df58e9dbf0923962c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sat, 20 Aug 2022 12:10:47 +0200 Subject: [PATCH 130/338] #107 added Asset Guid --- Source/Flow/Private/FlowAsset.cpp | 5 ++++ Source/Flow/Public/FlowAsset.h | 7 +++-- .../Private/Asset/FlowAssetDetails.cpp | 28 ++++++++----------- .../Private/Asset/FlowAssetDetails.h | 2 +- 4 files changed, 23 insertions(+), 19 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 58635dce3..9a1cbb635 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -25,6 +25,10 @@ UFlowAsset::UFlowAsset(const FObjectInitializer& ObjectInitializer) , StartNode(nullptr) , FinishPolicy(EFlowFinishPolicy::Keep) { + if (!AssetGuid.IsValid()) + { + AssetGuid = FGuid::NewGuid(); + } } #if WITH_EDITOR @@ -53,6 +57,7 @@ void UFlowAsset::PostDuplicate(bool bDuplicateForPIE) if (!bDuplicateForPIE) { + AssetGuid = FGuid::NewGuid(); Nodes.Empty(); } } diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index eacbdf7f4..01b7e6c2c 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -49,6 +49,9 @@ class FLOW_API UFlowAsset : public UObject friend class FFlowAssetDetails; friend class UFlowGraphSchema; + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Flow Asset") + FGuid AssetGuid; + ////////////////////////////////////////////////////////////////////////// // Graph @@ -98,14 +101,14 @@ class FLOW_API UFlowAsset : public UObject * Custom Inputs define custom entry points in graph, it's similar to blueprint Custom Events * Sub Graph node using this Flow Asset will generate context Input Pin for every valid Event name on this list */ - UPROPERTY(EditAnywhere, Category = "Flow") + UPROPERTY(EditAnywhere, Category = "Sub Graph") TArray CustomInputs; /** * Custom Outputs define custom graph outputs, this allow to send signals to the parent graph while executing this graph * Sub Graph node using this Flow Asset will generate context Output Pin for every valid Event name on this list */ - UPROPERTY(EditAnywhere, Category = "Flow") + UPROPERTY(EditAnywhere, Category = "Sub Graph") TArray CustomOutputs; public: diff --git a/Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp b/Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp index 9c78abef4..ef202ebaa 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp @@ -11,26 +11,22 @@ #define LOCTEXT_NAMESPACE "FlowAssetDetails" -void FFlowAssetDetails::CustomizeDetails(IDetailLayoutBuilder& DetailLayout) +void FFlowAssetDetails::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) { - IDetailCategoryBuilder& FlowAssetCategory = DetailLayout.EditCategory("FlowAsset", LOCTEXT("FlowAssetCategory", "Flow Asset")); - - const TSharedPtr InputsPropertyHandle = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(UFlowAsset, CustomInputs)); - if (InputsPropertyHandle.IsValid() && InputsPropertyHandle->AsArray().IsValid()) - { - const TSharedRef InputsArrayBuilder = MakeShareable(new FDetailArrayBuilder(InputsPropertyHandle.ToSharedRef())); - InputsArrayBuilder->OnGenerateArrayElementWidget(FOnGenerateArrayElementWidget::CreateSP(this, &FFlowAssetDetails::GenerateCustomPinArray)); - - FlowAssetCategory.AddCustomBuilder(InputsArrayBuilder); - } + IDetailCategoryBuilder& FlowAssetCategory = DetailBuilder.EditCategory("SubGraph", LOCTEXT("SubGraphCategory", "Sub Graph")); - const TSharedPtr OutputsPropertyHandle = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(UFlowAsset, CustomOutputs)); - if (OutputsPropertyHandle.IsValid() && OutputsPropertyHandle->AsArray().IsValid()) + TArray> ArrayPropertyHandles; + ArrayPropertyHandles.Add(DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UFlowAsset, CustomInputs))); + ArrayPropertyHandles.Add(DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UFlowAsset, CustomOutputs))); + for (const TSharedPtr& PropertyHandle : ArrayPropertyHandles) { - const TSharedRef OutputsArrayBuilder = MakeShareable(new FDetailArrayBuilder(OutputsPropertyHandle.ToSharedRef())); - OutputsArrayBuilder->OnGenerateArrayElementWidget(FOnGenerateArrayElementWidget::CreateSP(this, &FFlowAssetDetails::GenerateCustomPinArray)); + if (PropertyHandle.IsValid() && PropertyHandle->AsArray().IsValid()) + { + const TSharedRef ArrayBuilder = MakeShareable(new FDetailArrayBuilder(PropertyHandle.ToSharedRef())); + ArrayBuilder->OnGenerateArrayElementWidget(FOnGenerateArrayElementWidget::CreateSP(this, &FFlowAssetDetails::GenerateCustomPinArray)); - FlowAssetCategory.AddCustomBuilder(OutputsArrayBuilder); + FlowAssetCategory.AddCustomBuilder(ArrayBuilder); + } } } diff --git a/Source/FlowEditor/Private/Asset/FlowAssetDetails.h b/Source/FlowEditor/Private/Asset/FlowAssetDetails.h index 7fd420780..016151dd1 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetDetails.h +++ b/Source/FlowEditor/Private/Asset/FlowAssetDetails.h @@ -19,7 +19,7 @@ class FFlowAssetDetails final : public IDetailCustomization } // IDetailCustomization - virtual void CustomizeDetails(IDetailLayoutBuilder& DetailLayout) override; + virtual void CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) override; // -- private: From 36dd165318daf5af6edf14a1f017588e89a1b5bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sat, 20 Aug 2022 12:41:11 +0200 Subject: [PATCH 131/338] #89 added PinFriendlyName to Flow Pin --- Source/Flow/Public/Nodes/FlowPin.h | 42 +++++++++---------- .../Private/Graph/Nodes/FlowGraphNode.cpp | 14 +++++++ 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/Source/Flow/Public/Nodes/FlowPin.h b/Source/Flow/Public/Nodes/FlowPin.h index 4ca7c16b9..726f96bff 100644 --- a/Source/Flow/Public/Nodes/FlowPin.h +++ b/Source/Flow/Public/Nodes/FlowPin.h @@ -9,9 +9,14 @@ struct FLOW_API FFlowPin { GENERATED_BODY() + // A logical name, used during execution of pin UPROPERTY(EditDefaultsOnly, Category = "FlowPin") FName PinName; + // An optional Display Name, you can use it override PinName without need to update graph connections + UPROPERTY(EditDefaultsOnly, Category = "FlowPin") + FText PinFriendlyName; + UPROPERTY(EditDefaultsOnly, Category = "FlowPin") FString PinToolTip; @@ -31,7 +36,7 @@ struct FLOW_API FFlowPin } FFlowPin(const FText& InPinName) - : PinName(*InPinName.ToString()) + : PinName(*InPinName.ToString()) { } @@ -50,30 +55,25 @@ struct FLOW_API FFlowPin { } - FFlowPin(const FName& InPinName, const FString& InPinTooltip) + FFlowPin(const FStringView InPinName, const FText& InPinFriendlyName) : PinName(InPinName) - , PinToolTip(InPinTooltip) + , PinFriendlyName(InPinFriendlyName) { } - FFlowPin(const FString& InPinName, const FString& InPinTooltip) - : PinName(*InPinName) + FFlowPin(const FStringView InPinName, const FString& InPinTooltip) + : PinName(InPinName) , PinToolTip(InPinTooltip) { } - FFlowPin(const FText& InPinName, const FString& InPinTooltip) - : PinName(*InPinName.ToString()) - , PinToolTip(InPinTooltip) - { - } - - FFlowPin(const TCHAR* InPinName, const FString& InPinTooltip) - : PinName(FName(InPinName)) + FFlowPin(const FStringView InPinName, const FText& InPinFriendlyName, const FString& InPinTooltip) + : PinName(InPinName) + , PinFriendlyName(InPinFriendlyName) , PinToolTip(InPinTooltip) { } - + FORCEINLINE bool IsValid() const { return !PinName.IsNone(); @@ -111,21 +111,21 @@ struct FLOW_API FConnectedPin { GENERATED_USTRUCT_BODY() - UPROPERTY() + UPROPERTY() FGuid NodeGuid; UPROPERTY() FName PinName; FConnectedPin() - : NodeGuid(FGuid()) - , PinName(NAME_None) + : NodeGuid(FGuid()) + , PinName(NAME_None) { } FConnectedPin(const FGuid InNodeId, const FName& InPinName) - : NodeGuid(InNodeId) - , PinName(InPinName) + : NodeGuid(InNodeId) + , PinName(InPinName) { } @@ -148,7 +148,7 @@ struct FLOW_API FConnectedPin // Every time pin is activated, we record it and display this data while user hovers mouse over pin #if !UE_BUILD_SHIPPING struct FLOW_API FPinRecord -{ +{ double Time; FString HumanReadableTime; bool bForcedActivation; @@ -160,7 +160,7 @@ struct FLOW_API FPinRecord FPinRecord(); FPinRecord(const double InTime, const bool bInForcedActivation); - private: +private: FORCEINLINE static FString DoubleDigit(const int32 Number); }; #endif diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index ee9e43f96..813438dfd 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -726,6 +726,13 @@ void UFlowGraphNode::CreateInputPin(const FFlowPin& FlowPin, const int32 Index / const FEdGraphPinType PinType = FEdGraphPinType(UEdGraphSchema_K2::PC_Exec, FName(NAME_None), nullptr, EPinContainerType::None, false, FEdGraphTerminalType()); UEdGraphPin* NewPin = CreatePin(EGPD_Input, PinType, FlowPin.PinName, Index); check(NewPin); + + if (!FlowPin.PinFriendlyName.IsEmpty()) + { + NewPin->bAllowFriendlyName = true; + NewPin->PinFriendlyName = FlowPin.PinFriendlyName; + } + NewPin->PinToolTip = FlowPin.PinToolTip; InputPins.Emplace(NewPin); @@ -741,6 +748,13 @@ void UFlowGraphNode::CreateOutputPin(const FFlowPin& FlowPin, const int32 Index const FEdGraphPinType PinType = FEdGraphPinType(UEdGraphSchema_K2::PC_Exec, FName(NAME_None), nullptr, EPinContainerType::None, false, FEdGraphTerminalType()); UEdGraphPin* NewPin = CreatePin(EGPD_Output, PinType, FlowPin.PinName, Index); check(NewPin); + + if (!FlowPin.PinFriendlyName.IsEmpty()) + { + NewPin->bAllowFriendlyName = true; + NewPin->PinFriendlyName = FlowPin.PinFriendlyName; + } + NewPin->PinToolTip = FlowPin.PinToolTip; OutputPins.Emplace(NewPin); From 27778292bb1cb4922eaa2803feae3be25ba3a754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sat, 20 Aug 2022 12:45:45 +0200 Subject: [PATCH 132/338] typo fix --- Source/Flow/Public/Nodes/FlowPin.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Flow/Public/Nodes/FlowPin.h b/Source/Flow/Public/Nodes/FlowPin.h index 726f96bff..cdd8f4881 100644 --- a/Source/Flow/Public/Nodes/FlowPin.h +++ b/Source/Flow/Public/Nodes/FlowPin.h @@ -13,7 +13,7 @@ struct FLOW_API FFlowPin UPROPERTY(EditDefaultsOnly, Category = "FlowPin") FName PinName; - // An optional Display Name, you can use it override PinName without need to update graph connections + // An optional Display Name, you can use it to override PinName without the need to update graph connections UPROPERTY(EditDefaultsOnly, Category = "FlowPin") FText PinFriendlyName; From 22a6aab478cd334e9300e11d18bfd0c2f519cbab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sat, 20 Aug 2022 17:27:49 +0200 Subject: [PATCH 133/338] #98 added GetStatusBackgroundColor method --- Source/Flow/Private/Nodes/FlowNode.cpp | 5 +++++ Source/Flow/Public/Nodes/FlowNode.h | 4 ++++ .../Private/Graph/Nodes/FlowGraphNode.cpp | 17 +++++++++++++++++ .../Private/Graph/Widgets/SFlowGraphNode.cpp | 2 +- .../FlowEditor/Public/Graph/FlowGraphSettings.h | 1 + .../Public/Graph/Nodes/FlowGraphNode.h | 1 + 6 files changed, 29 insertions(+), 1 deletion(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 47226e935..f3bbb0a37 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -507,6 +507,11 @@ FString UFlowNode::GetStatusString() const return K2_GetStatusString(); } +bool UFlowNode::GetStatusBackgroundColor(FLinearColor& OutColor) const +{ + return K2_GetStatusBackgroundColor(OutColor); +} + FString UFlowNode::GetAssetPath() { return K2_GetAssetPath(); diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 112118deb..29e84ef91 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -296,6 +296,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte // Information displayed while node is working - displayed over node as NodeInfoPopup virtual FString GetStatusString() const; + bool GetStatusBackgroundColor(FLinearColor& OutColor) const; virtual FString GetAssetPath(); virtual UObject* GetAssetToEdit(); @@ -307,6 +308,9 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "GetStatusString")) FString K2_GetStatusString() const; + UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "GetStatusBackgroundColor")) + bool K2_GetStatusBackgroundColor(FLinearColor& OutColor) const; + UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "GetAssetPath")) FString K2_GetAssetPath(); diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 813438dfd..b1b5b14d6 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -662,6 +662,23 @@ FString UFlowGraphNode::GetStatusString() const return FString(); } +FLinearColor UFlowGraphNode::GetStatusBackgroundColor() const +{ + if (FlowNode) + { + if (const UFlowNode* NodeInstance = FlowNode->GetInspectedInstance()) + { + FLinearColor ObtainedColor; + if (NodeInstance->GetStatusBackgroundColor(ObtainedColor)) + { + return ObtainedColor; + } + } + } + + return UFlowGraphSettings::Get()->NodeStatusBackground; +} + bool UFlowGraphNode::IsContentPreloaded() const { if (FlowNode) diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp index 00a1fd51e..f906f6781 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp @@ -64,7 +64,7 @@ void SFlowGraphNode::GetNodeInfoPopups(FNodeInfoContext* Context, TArrayGetStatusString(); if (!Status.IsEmpty()) { - const FGraphInformationPopupInfo DescriptionPopup = FGraphInformationPopupInfo(nullptr, UFlowGraphSettings::Get()->NodeStatusBackground, Status); + const FGraphInformationPopupInfo DescriptionPopup = FGraphInformationPopupInfo(nullptr, FlowGraphNode->GetStatusBackgroundColor(), Status); Popups.Add(DescriptionPopup); } else if (FlowGraphNode->IsContentPreloaded()) diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h index c114be373..b82092d3c 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h @@ -15,6 +15,7 @@ UCLASS(Config = Editor, defaultconfig, meta = (DisplayName = "Flow Graph")) class UFlowGraphSettings final : public UDeveloperSettings { GENERATED_UCLASS_BODY() + static UFlowGraphSettings* Get() { return StaticClass()->GetDefaultObject(); } /** Show Flow Asset in Flow category of "Create Asset" menu? diff --git a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h index d3446ce51..45a37adbb 100644 --- a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h +++ b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h @@ -152,6 +152,7 @@ class FLOWEDITOR_API UFlowGraphNode : public UEdGraphNode // Information displayed while node is active FString GetStatusString() const; + FLinearColor GetStatusBackgroundColor() const; // Check this to display information while node is preloaded bool IsContentPreloaded() const; From d3523b988c6299a67d3ff77c6f738ff79ea3bf17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Tue, 23 Aug 2022 18:13:33 +0200 Subject: [PATCH 134/338] added virtual keyword --- Source/Flow/Public/Nodes/FlowNode.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 29e84ef91..d518d481e 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -296,7 +296,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte // Information displayed while node is working - displayed over node as NodeInfoPopup virtual FString GetStatusString() const; - bool GetStatusBackgroundColor(FLinearColor& OutColor) const; + virtual bool GetStatusBackgroundColor(FLinearColor& OutColor) const; virtual FString GetAssetPath(); virtual UObject* GetAssetToEdit(); From 3652dbead2049ad5f93fce7d627688effd1aaa4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Tue, 23 Aug 2022 19:17:57 +0200 Subject: [PATCH 135/338] Implement support for launching multiple DIFFERENT flows for single owner. #100 --- Source/Flow/Private/FlowComponent.cpp | 24 ++++++-- Source/Flow/Private/FlowSubsystem.cpp | 85 ++++++++++++++++++++++----- Source/Flow/Public/FlowComponent.h | 9 ++- Source/Flow/Public/FlowSubsystem.h | 27 ++++++--- 4 files changed, 114 insertions(+), 31 deletions(-) diff --git a/Source/Flow/Private/FlowComponent.cpp b/Source/Flow/Private/FlowComponent.cpp index 9c2b7b4c6..8635991ab 100644 --- a/Source/Flow/Private/FlowComponent.cpp +++ b/Source/Flow/Private/FlowComponent.cpp @@ -72,7 +72,7 @@ void UFlowComponent::EndPlay(const EEndPlayReason::Type EndPlayReason) { if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) { - FlowSubsystem->FinishRootFlow(this, EFlowFinishPolicy::Keep); + FlowSubsystem->FinishAllRootFlows(this, EFlowFinishPolicy::Keep); FlowSubsystem->UnregisterComponent(this); } @@ -375,19 +375,33 @@ void UFlowComponent::StartRootFlow() } } -void UFlowComponent::FinishRootFlow(const EFlowFinishPolicy FinishPolicy) +void UFlowComponent::FinishRootFlow(UFlowAsset* TemplateAsset, const EFlowFinishPolicy FinishPolicy) { if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) { - FlowSubsystem->FinishRootFlow(this, FinishPolicy); + FlowSubsystem->FinishRootFlow(this, TemplateAsset, FinishPolicy); } } -UFlowAsset* UFlowComponent::GetRootFlowInstance() +TSet UFlowComponent::GetRootInstances(const UObject* Owner) const { if (const UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) { - return FlowSubsystem->GetRootFlow(this); + return FlowSubsystem->GetRootInstancesByOwner(this); + } + + return TSet(); +} + +UFlowAsset* UFlowComponent::GetRootFlowInstance() const +{ + if (const UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) + { + const TSet Result = FlowSubsystem->GetRootInstancesByOwner(this); + if (Result.Num() > 0) + { + return Result.Array()[0]; + } } return nullptr; diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index ba88505ff..bcbdde0e9 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -78,10 +78,13 @@ void UFlowSubsystem::StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const UFlowAsset* UFlowSubsystem::CreateRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances) { - if (RootInstances.Contains(Owner)) + for (const TPair>& RootInstance : RootInstances) { - UE_LOG(LogFlow, Warning, TEXT("Attempted to start Root Flow for the same Owner again. Owner: %s. Flow Asset: %s."), *Owner->GetName(), *FlowAsset->GetName()); - return nullptr; + if (Owner == RootInstance.Value.Get() && FlowAsset == RootInstance.Key->GetTemplateAsset()) + { + UE_LOG(LogFlow, Warning, TEXT("Attempted to start Root Flow for the same Owner again. Owner: %s. Flow Asset: %s."), *Owner->GetName(), *FlowAsset->GetName()); + return nullptr; + } } if (!bAllowMultipleInstances && InstancedTemplates.Contains(FlowAsset)) @@ -91,17 +94,47 @@ UFlowAsset* UFlowSubsystem::CreateRootFlow(UObject* Owner, UFlowAsset* FlowAsset } UFlowAsset* NewFlow = CreateFlowInstance(Owner, FlowAsset); - RootInstances.Add(Owner, NewFlow); + RootInstances.Add(NewFlow, Owner); return NewFlow; } -void UFlowSubsystem::FinishRootFlow(UObject* Owner, const EFlowFinishPolicy FinishPolicy) +void UFlowSubsystem::FinishRootFlow(UObject* Owner, UFlowAsset* TemplateAsset, const EFlowFinishPolicy FinishPolicy) +{ + UFlowAsset* InstanceToFinish = nullptr; + + for (TPair>& RootInstance : RootInstances) + { + if (Owner && Owner == RootInstance.Value.Get() && RootInstance.Key && RootInstance.Key->GetTemplateAsset() == TemplateAsset) + { + InstanceToFinish = RootInstance.Key; + break; + } + } + + if (InstanceToFinish) + { + RootInstances.Remove(InstanceToFinish); + InstanceToFinish->FinishFlow(FinishPolicy); + } +} + +void UFlowSubsystem::FinishAllRootFlows(UObject* Owner, const EFlowFinishPolicy FinishPolicy) { - if (UFlowAsset* Instance = RootInstances.FindRef(Owner)) + TArray InstancesToFinish; + + for (TPair>& RootInstance : RootInstances) + { + if (Owner && Owner == RootInstance.Value.Get() && RootInstance.Key) + { + InstancesToFinish.Emplace(RootInstance.Key); + } + } + + for (UFlowAsset* InstanceToFinish : InstancesToFinish) { - RootInstances.Remove(Owner); - Instance->FinishFlow(FinishPolicy); + RootInstances.Remove(InstanceToFinish); + InstanceToFinish->FinishFlow(FinishPolicy); } } @@ -194,13 +227,37 @@ void UFlowSubsystem::RemoveInstancedTemplate(UFlowAsset* Template) TMap UFlowSubsystem::GetRootInstances() const { TMap Result; - for (const TPair, UFlowAsset*>& Pair : RootInstances) + for (const TPair>& RootInstance : RootInstances) + { + Result.Emplace(RootInstance.Value.Get(), RootInstance.Key); + } + return Result; +} + +TSet UFlowSubsystem::GetRootInstancesByOwner(const UObject* Owner) const +{ + TSet Result; + for (const TPair>& RootInstance : RootInstances) { - Result.Emplace(Pair.Key.Get(), Pair.Value); + if (Owner && RootInstance.Value == Owner) + { + Result.Emplace(RootInstance.Key); + } } return Result; } +UFlowAsset* UFlowSubsystem::GetRootFlow(const UObject* Owner) const +{ + const TSet Result = GetRootInstancesByOwner(Owner); + if (Result.Num() > 0) + { + return Result.Array()[0]; + } + + return nullptr; +} + UWorld* UFlowSubsystem::GetWorld() const { return GetGameInstance()->GetWorld(); @@ -233,17 +290,17 @@ void UFlowSubsystem::OnGameSaved(UFlowSaveGame* SaveGame) } // save Flow Graphs - for (const TPair, UFlowAsset*>& Pair : RootInstances) + for (const TPair>& RootInstance : RootInstances) { - if (Pair.Key.IsValid() && Pair.Value) + if (RootInstance.Key && RootInstance.Value.IsValid()) { - if (UFlowComponent* FlowComponent = Cast(Pair.Key)) + if (UFlowComponent* FlowComponent = Cast(RootInstance.Value)) { FlowComponent->SaveRootFlow(SaveGame->FlowInstances); } else { - Pair.Value->SaveInstance(SaveGame->FlowInstances); + RootInstance.Key->SaveInstance(SaveGame->FlowInstances); } } } diff --git a/Source/Flow/Public/FlowComponent.h b/Source/Flow/Public/FlowComponent.h index f94fe995e..abc83704a 100644 --- a/Source/Flow/Public/FlowComponent.h +++ b/Source/Flow/Public/FlowComponent.h @@ -195,10 +195,13 @@ class FLOW_API UFlowComponent : public UActorComponent // This will destroy instantiated Flow Asset - created from asset assigned on this component. UFUNCTION(BlueprintCallable, Category = "RootFlow") - void FinishRootFlow(const EFlowFinishPolicy FinishPolicy); + void FinishRootFlow(UFlowAsset* TemplateAsset, const EFlowFinishPolicy FinishPolicy); - UFUNCTION(BlueprintPure, Category = "RootFlow") - UFlowAsset* GetRootFlowInstance(); + UFUNCTION(BlueprintPure, Category = "FlowSubsystem") + TSet GetRootInstances(const UObject* Owner) const; + + UFUNCTION(BlueprintPure, Category = "RootFlow", meta = (DeprecatedFunction, DeprecationMessage="Use GetRootInstances() instead.")) + UFlowAsset* GetRootFlowInstance() const; ////////////////////////////////////////////////////////////////////////// // SaveGame diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index e634f6092..3315609dd 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -42,7 +42,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem /* Assets instanced by object from another system, i.e. World Settings or Player Controller */ UPROPERTY() - TMap, UFlowAsset*> RootInstances; + TMap> RootInstances; /* Assets instanced by Sub Graph nodes */ UPROPERTY() @@ -63,7 +63,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem virtual void AbortActiveFlows(); /* Start the root Flow, graph that will eventually instantiate next Flow Graphs through the SubGraph node */ - UFUNCTION(BlueprintCallable, Category = "FlowSubsystem") + UFUNCTION(BlueprintCallable, Category = "FlowSubsystem", meta = (DefaultToSelf = "Owner")) virtual void StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances = true); virtual UFlowAsset* CreateRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances = true); @@ -71,8 +71,14 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem /* Finish Policy value is read by Flow Node * Nodes have opportunity to terminate themselves differently if Flow Graph has been aborted * Example: Spawn node might despawn all actors if Flow Graph is aborted, not completed */ - UFUNCTION(BlueprintCallable, Category = "FlowSubsystem") - virtual void FinishRootFlow(UObject* Owner, const EFlowFinishPolicy FinishPolicy); + UFUNCTION(BlueprintCallable, Category = "FlowSubsystem", meta = (DefaultToSelf = "Owner")) + virtual void FinishRootFlow(UObject* Owner, UFlowAsset* TemplateAsset, const EFlowFinishPolicy FinishPolicy); + + /* Finish Policy value is read by Flow Node + * Nodes have opportunity to terminate themselves differently if Flow Graph has been aborted + * Example: Spawn node might despawn all actors if Flow Graph is aborted, not completed */ + UFUNCTION(BlueprintCallable, Category = "FlowSubsystem", meta = (DefaultToSelf = "Owner")) + virtual void FinishAllRootFlows(UObject* Owner, const EFlowFinishPolicy FinishPolicy); protected: UFlowAsset* CreateSubFlow(UFlowNode_SubGraph* SubGraphNode, const FString SavedInstanceName = FString(), const bool bPreloading = false); @@ -82,13 +88,16 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem void RemoveInstancedTemplate(UFlowAsset* Template); public: - /* Returns asset instanced by object from another system like World Settings */ - UFUNCTION(BlueprintPure, Category = "FlowSubsystem") - UFlowAsset* GetRootFlow(UObject* Owner) const { return RootInstances.FindRef(Owner); } - - /* Returns assets instanced by object from another system like World Settings */ + /* Returns all assets instanced by object from another system like World Settings */ UFUNCTION(BlueprintPure, Category = "FlowSubsystem") TMap GetRootInstances() const; + + /* Returns asset instanced by specific object */ + UFUNCTION(BlueprintPure, Category = "FlowSubsystem") + TSet GetRootInstancesByOwner(const UObject* Owner) const; + + UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeprecatedFunction, DeprecationMessage="Use GetRootInstancesByOwner() instead.")) + UFlowAsset* GetRootFlow(const UObject* Owner) const; /* Returns assets instanced by Sub Graph nodes */ UFUNCTION(BlueprintPure, Category = "FlowSubsystem") From fffdb3a5d128be57613314842e6e4a21e3aa2688 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 26 Aug 2022 16:57:39 +0200 Subject: [PATCH 136/338] const correctness --- Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index 82ab50115..7b4e90d91 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -1242,7 +1242,7 @@ void FFlowAssetEditor::OnForcePinActivation() const { if (UEdGraphPin* Pin = FocusedGraphEditor->GetGraphPinForMenu()) { - if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) + if (const UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) { GraphNode->ForcePinActivation(Pin); } From e74cbf0391b7c5946648d5dca94c76656e6a8286 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 26 Aug 2022 17:18:02 +0200 Subject: [PATCH 137/338] ensure that we don't iterate loop after Component Observer already finished its work --- .../Nodes/World/FlowNode_ComponentObserver.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp index e4522cf99..0ebde212d 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp @@ -66,7 +66,16 @@ void UFlowNode_ComponentObserver::StartObserving() // collect already registered components for (const TWeakObjectPtr& FoundComponent : FlowSubsystem->GetComponents(IdentityTags, ContainerMatchType, bExactMatch)) { - ObserveActor(FoundComponent->GetOwner(), FoundComponent); + if (GetActivationState() == EFlowNodeState::Active) + { + ObserveActor(FoundComponent->GetOwner(), FoundComponent); + } + else + { + // node might finish work as the effect of triggering event on the found actor + // we should terminate iteration in this case + return; + } } // clear old bindings before binding again, which might happen while loading a SaveGame From dc6d85305dbb5146db7f0b739ea3c602813360a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 26 Aug 2022 19:39:54 +0200 Subject: [PATCH 138/338] GetActivationState() should be available in non-editor builds --- Source/Flow/Public/Nodes/FlowNode.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index d518d481e..fde88852f 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -202,6 +202,9 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UPROPERTY(SaveGame) EFlowNodeState ActivationState; + +public: + EFlowNodeState GetActivationState() const { return ActivationState; } #if !UE_BUILD_SHIPPING private: @@ -289,7 +292,6 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte #if WITH_EDITOR public: UFlowNode* GetInspectedInstance() const; - EFlowNodeState GetActivationState() const { return ActivationState; } TMap GetWireRecords() const; TArray GetPinRecords(const FName& PinName, const EEdGraphPinDirection PinDirection) const; From 20bfb1fde732ae8376b5b93ffff6e42b5af8831d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sat, 27 Aug 2022 11:48:46 +0200 Subject: [PATCH 139/338] exposed bWorldBound bool to eliminate need to subclass UFlowAsset for simple world-independent Root Flows --- Source/Flow/Private/FlowAsset.cpp | 3 ++- Source/Flow/Public/FlowAsset.h | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 9a1cbb635..d0fb82fef 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -17,6 +17,7 @@ UFlowAsset::UFlowAsset(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) #if WITH_EDITOR + , bWorldBound(true) , FlowGraph(nullptr) #endif , AllowedNodeClasses({UFlowNode::StaticClass()}) @@ -553,5 +554,5 @@ void UFlowAsset::OnLoad_Implementation() bool UFlowAsset::IsBoundToWorld_Implementation() { - return true; + return bWorldBound; } diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 01b7e6c2c..f0e3c0363 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -51,6 +51,11 @@ class FLOW_API UFlowAsset : public UObject UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Flow Asset") FGuid AssetGuid; + + // Set it to False, if this asset is instantiated as Root Flow for owner that doesn't live in the world + // This allow to SaveGame support works properly, if owner of Root Flow would be Game Instance or its subsystem + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Flow Asset") + bool bWorldBound; ////////////////////////////////////////////////////////////////////////// // Graph From d33f8dcce0e5d97b63f12e87141302430af6763d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sat, 27 Aug 2022 11:53:36 +0200 Subject: [PATCH 140/338] fixed initialization list --- Source/Flow/Private/FlowAsset.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index d0fb82fef..7744705f8 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -16,8 +16,8 @@ UFlowAsset::UFlowAsset(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) -#if WITH_EDITOR , bWorldBound(true) +#if WITH_EDITOR , FlowGraph(nullptr) #endif , AllowedNodeClasses({UFlowNode::StaticClass()}) From b3a4760cf7d17b0cb5e472630723ce6d850c3a73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sat, 27 Aug 2022 15:54:48 +0200 Subject: [PATCH 141/338] #9 Added blueprint TriggerOutputPin method with dropdown for Output Pin Name selection --- Source/Flow/Private/Nodes/FlowNode.cpp | 5 ++ Source/Flow/Public/Nodes/FlowNode.h | 6 +- Source/Flow/Public/Nodes/FlowPin.h | 35 +++++++++ .../FlowEditor/Private/FlowEditorModule.cpp | 10 +-- .../Private/Pins/SFlowInputPinHandle.cpp | 36 +++++++++ .../Private/Pins/SFlowOutputPinHandle.cpp | 36 +++++++++ .../Private/Pins/SFlowPinHandle.cpp | 77 +++++++++++++++++++ Source/FlowEditor/Public/FlowEditorModule.h | 1 - .../Public/Pins/SFlowInputPinHandle.h | 18 +++++ .../Public/Pins/SFlowOutputPinHandle.h | 18 +++++ .../FlowEditor/Public/Pins/SFlowPinHandle.h | 30 ++++++++ 11 files changed, 264 insertions(+), 8 deletions(-) create mode 100644 Source/FlowEditor/Private/Pins/SFlowInputPinHandle.cpp create mode 100644 Source/FlowEditor/Private/Pins/SFlowOutputPinHandle.cpp create mode 100644 Source/FlowEditor/Private/Pins/SFlowPinHandle.cpp create mode 100644 Source/FlowEditor/Public/Pins/SFlowInputPinHandle.h create mode 100644 Source/FlowEditor/Public/Pins/SFlowOutputPinHandle.h create mode 100644 Source/FlowEditor/Public/Pins/SFlowPinHandle.h diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index f3bbb0a37..438b2a9d5 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -413,6 +413,11 @@ void UFlowNode::TriggerOutput(const FName& PinName, const bool bFinish /*= false } } +void UFlowNode::TriggerOutputPin(const FFlowOutputPinHandle Pin, const bool bFinish, const bool bForcedActivation) +{ + TriggerOutput(Pin.PinName, bFinish, bForcedActivation); +} + void UFlowNode::TriggerOutput(const FString& PinName, const bool bFinish) { TriggerOutput(*PinName, bFinish); diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index fde88852f..f0d20c63b 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -31,6 +31,8 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte friend class UFlowAsset; friend class UFlowGraphNode; friend class UFlowGraphSchema; + friend class SFlowInputPinHandle; + friend class SFlowOutputPinHandle; ////////////////////////////////////////////////////////////////////////// // Node @@ -256,7 +258,6 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UFUNCTION(BlueprintCallable, Category = "FlowNode") void TriggerFirstOutput(const bool bFinish); - // Trigger Output Pin UFUNCTION(BlueprintCallable, Category = "FlowNode", meta = (HidePin = "bForcedActivation")) void TriggerOutput(const FName& PinName, const bool bFinish = false, const bool bForcedActivation = false); @@ -264,6 +265,9 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte void TriggerOutput(const FText& PinName, const bool bFinish = false); void TriggerOutput(const TCHAR* PinName, const bool bFinish = false); + UFUNCTION(BlueprintCallable, Category = "FlowNode", meta = (HidePin = "bForcedActivation")) + void TriggerOutputPin(const FFlowOutputPinHandle Pin, const bool bFinish = false, const bool bForcedActivation = false); + // Finish execution of node, it will call Cleanup UFUNCTION(BlueprintCallable, Category = "FlowNode") void Finish(); diff --git a/Source/Flow/Public/Nodes/FlowPin.h b/Source/Flow/Public/Nodes/FlowPin.h index cdd8f4881..42186bfc9 100644 --- a/Source/Flow/Public/Nodes/FlowPin.h +++ b/Source/Flow/Public/Nodes/FlowPin.h @@ -105,6 +105,41 @@ struct FLOW_API FFlowPin } }; +USTRUCT() +struct FLOW_API FFlowPinHandle +{ + GENERATED_BODY() + + // Update SFlowPinHandleBase code if this property name would be ever changed + UPROPERTY() + FName PinName; + + FFlowPinHandle() + : PinName(NAME_None) + { + } +}; + +USTRUCT(BlueprintType) +struct FLOW_API FFlowInputPinHandle : public FFlowPinHandle +{ + GENERATED_BODY() + + FFlowInputPinHandle() + { + } +}; + +USTRUCT(BlueprintType) +struct FLOW_API FFlowOutputPinHandle : public FFlowPinHandle +{ + GENERATED_BODY() + + FFlowOutputPinHandle() + { + } +}; + // Processing Flow Nodes creates map of connected pins USTRUCT() struct FLOW_API FConnectedPin diff --git a/Source/FlowEditor/Private/FlowEditorModule.cpp b/Source/FlowEditor/Private/FlowEditorModule.cpp index 4cc08b607..8d83d0340 100644 --- a/Source/FlowEditor/Private/FlowEditorModule.cpp +++ b/Source/FlowEditor/Private/FlowEditorModule.cpp @@ -17,6 +17,8 @@ #include "Nodes/Customizations/FlowNode_CustomInputDetails.h" #include "Nodes/Customizations/FlowNode_CustomOutputDetails.h" #include "Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.h" +#include "Pins/SFlowInputPinHandle.h" +#include "Pins/SFlowOutputPinHandle.h" #include "FlowAsset.h" #include "Nodes/Route/FlowNode_CustomInput.h" @@ -47,6 +49,8 @@ void FFlowEditorModule::StartupModule() // register visual utilities FEdGraphUtilities::RegisterVisualPinConnectionFactory(MakeShareable(new FFlowGraphConnectionDrawingPolicyFactory)); + FEdGraphUtilities::RegisterVisualPinFactory(MakeShareable(new FFlowInputPinHandleFactory())); + FEdGraphUtilities::RegisterVisualPinFactory(MakeShareable(new FFlowOutputPinHandleFactory())); // add Flow Toolbar if (UFlowGraphSettings::Get()->bShowAssetToolbarAboveLevelEditor) @@ -90,12 +94,6 @@ void FFlowEditorModule::ShutdownModule() UnregisterAssets(); - // unregister visual utilities - if (FlowGraphConnectionFactory.IsValid()) - { - FEdGraphUtilities::UnregisterVisualPinConnectionFactory(FlowGraphConnectionFactory); - } - // unregister track editors ISequencerModule& SequencerModule = FModuleManager::Get().LoadModuleChecked("Sequencer"); SequencerModule.UnRegisterTrackEditor(FlowTrackCreateEditorHandle); diff --git a/Source/FlowEditor/Private/Pins/SFlowInputPinHandle.cpp b/Source/FlowEditor/Private/Pins/SFlowInputPinHandle.cpp new file mode 100644 index 000000000..c8e41ae44 --- /dev/null +++ b/Source/FlowEditor/Private/Pins/SFlowInputPinHandle.cpp @@ -0,0 +1,36 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#include "Pins/SFlowInputPinHandle.h" +#include "Nodes/FlowNode.h" + +void SFlowInputPinHandle::RefreshNameList() +{ + PinNames.Empty(); + + if (Blueprint && Blueprint->GeneratedClass) + { + if (UFlowNode* FlowNode = Blueprint->GeneratedClass->GetDefaultObject()) + { + for (const FFlowPin& InputPin : FlowNode->InputPins) + { + PinNames.Add(MakeShareable(new FName(InputPin.PinName))); + } + } + } +} + +TSharedPtr FFlowInputPinHandleFactory::CreatePin(UEdGraphPin* InPin) const +{ + if (InPin->PinType.PinCategory == GetDefault()->PC_Struct && InPin->PinType.PinSubCategoryObject == FFlowInputPinHandle::StaticStruct() && InPin->LinkedTo.Num() == 0) + { + if (const UEdGraphNode* GraphNode = InPin->GetOuter()) + { + if (const UBlueprint* Blueprint = GraphNode->GetGraph()->GetTypedOuter()) + { + return SNew(SFlowInputPinHandle, InPin, Blueprint); + } + } + } + + return nullptr; +} diff --git a/Source/FlowEditor/Private/Pins/SFlowOutputPinHandle.cpp b/Source/FlowEditor/Private/Pins/SFlowOutputPinHandle.cpp new file mode 100644 index 000000000..5fca65021 --- /dev/null +++ b/Source/FlowEditor/Private/Pins/SFlowOutputPinHandle.cpp @@ -0,0 +1,36 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#include "Pins/SFlowOutputPinHandle.h" +#include "Nodes/FlowNode.h" + +void SFlowOutputPinHandle::RefreshNameList() +{ + PinNames.Empty(); + + if (Blueprint && Blueprint->GeneratedClass) + { + if (UFlowNode* FlowNode = Blueprint->GeneratedClass->GetDefaultObject()) + { + for (const FFlowPin& OutputPin : FlowNode->OutputPins) + { + PinNames.Add(MakeShareable(new FName(OutputPin.PinName))); + } + } + } +} + +TSharedPtr FFlowOutputPinHandleFactory::CreatePin(UEdGraphPin* InPin) const +{ + if (InPin->PinType.PinCategory == GetDefault()->PC_Struct && InPin->PinType.PinSubCategoryObject == FFlowOutputPinHandle::StaticStruct() && InPin->LinkedTo.Num() == 0) + { + if (const UEdGraphNode* GraphNode = InPin->GetOuter()) + { + if (const UBlueprint* Blueprint = GraphNode->GetGraph()->GetTypedOuter()) + { + return SNew(SFlowOutputPinHandle, InPin, Blueprint); + } + } + } + + return nullptr; +} diff --git a/Source/FlowEditor/Private/Pins/SFlowPinHandle.cpp b/Source/FlowEditor/Private/Pins/SFlowPinHandle.cpp new file mode 100644 index 000000000..1a85544c9 --- /dev/null +++ b/Source/FlowEditor/Private/Pins/SFlowPinHandle.cpp @@ -0,0 +1,77 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#include "Pins/SFlowPinHandle.h" + +#define LOCTEXT_NAMESPACE "SFlowPinHandle" + +SFlowPinHandle::SFlowPinHandle() + : Blueprint(nullptr) +{ +} + +SFlowPinHandle::~SFlowPinHandle() +{ + Blueprint = nullptr; +} + +void SFlowPinHandle::Construct(const FArguments& InArgs, UEdGraphPin* InGraphPinObj, const UBlueprint* InBlueprint) +{ + Blueprint = InBlueprint; + RefreshNameList(); + SGraphPin::Construct(SGraphPin::FArguments(), InGraphPinObj); +} + +TSharedRef SFlowPinHandle::GetDefaultValueWidget() +{ + ParseDefaultValueData(); + + // Create widget + return SAssignNew(ComboBox, SNameComboBox) + .ContentPadding(FMargin(6.0f, 2.0f)) + .OptionsSource(&PinNames) + .InitiallySelectedItem(CurrentlySelectedName) + .OnSelectionChanged(this, &SFlowPinHandle::ComboBoxSelectionChanged) + .Visibility(this, &SGraphPin::GetDefaultValueVisibility); +} + +void SFlowPinHandle::ParseDefaultValueData() +{ + FString DefaultValue = GraphPinObj->GetDefaultAsString(); + if (DefaultValue.StartsWith(TEXT("(PinName=")) && DefaultValue.EndsWith(TEXT(")"))) + { + DefaultValue.Split(TEXT("PinName=\""), nullptr, &DefaultValue); + DefaultValue.Split(TEXT("\""), &DefaultValue, nullptr); + } + + // Preserve previous selection + if (PinNames.Num() > 0) + { + for (TSharedPtr PinName : PinNames) + { + if (*PinName.Get() == *DefaultValue) + { + CurrentlySelectedName = PinName; + break; + } + } + } +} + +void SFlowPinHandle::ComboBoxSelectionChanged(const TSharedPtr NameItem, ESelectInfo::Type SelectInfo) const +{ + const FName Name = NameItem.IsValid() ? *NameItem : NAME_None; + if (const UEdGraphSchema* Schema = (GraphPinObj ? GraphPinObj->GetSchema() : nullptr)) + { + const FString ValueString = TEXT("(PinName=\"") + Name.ToString() + TEXT("\")"); + + if (GraphPinObj->GetDefaultAsString() != ValueString) + { + const FScopedTransaction Transaction(LOCTEXT("ChangePinValue", "Change Pin Value")); + GraphPinObj->Modify(); + + Schema->TrySetDefaultValue(*GraphPinObj, ValueString); + } + } +} + +#undef LOCTEXT_NAMESPACE diff --git a/Source/FlowEditor/Public/FlowEditorModule.h b/Source/FlowEditor/Public/FlowEditorModule.h index 36673d8a0..0672e916d 100644 --- a/Source/FlowEditor/Public/FlowEditorModule.h +++ b/Source/FlowEditor/Public/FlowEditorModule.h @@ -22,7 +22,6 @@ class FLOWEDITOR_API FFlowEditorModule : public IModuleInterface private: TArray> RegisteredAssetActions; TSet CustomClassLayouts; - TSharedPtr FlowGraphConnectionFactory; public: virtual void StartupModule() override; diff --git a/Source/FlowEditor/Public/Pins/SFlowInputPinHandle.h b/Source/FlowEditor/Public/Pins/SFlowInputPinHandle.h new file mode 100644 index 000000000..5355265bb --- /dev/null +++ b/Source/FlowEditor/Public/Pins/SFlowInputPinHandle.h @@ -0,0 +1,18 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#pragma once + +#include "EdGraphUtilities.h" +#include "SFlowPinHandle.h" + +class FLOWEDITOR_API SFlowInputPinHandle : public SFlowPinHandle +{ +protected: + virtual void RefreshNameList() override; +}; + +class FFlowInputPinHandleFactory final : public FGraphPanelPinFactory +{ +public: + virtual TSharedPtr CreatePin(class UEdGraphPin* InPin) const override; +}; diff --git a/Source/FlowEditor/Public/Pins/SFlowOutputPinHandle.h b/Source/FlowEditor/Public/Pins/SFlowOutputPinHandle.h new file mode 100644 index 000000000..a291ac83c --- /dev/null +++ b/Source/FlowEditor/Public/Pins/SFlowOutputPinHandle.h @@ -0,0 +1,18 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#pragma once + +#include "EdGraphUtilities.h" +#include "SFlowPinHandle.h" + +class FLOWEDITOR_API SFlowOutputPinHandle : public SFlowPinHandle +{ +protected: + virtual void RefreshNameList() override; +}; + +class FFlowOutputPinHandleFactory final : public FGraphPanelPinFactory +{ +public: + virtual TSharedPtr CreatePin(class UEdGraphPin* InPin) const override; +}; diff --git a/Source/FlowEditor/Public/Pins/SFlowPinHandle.h b/Source/FlowEditor/Public/Pins/SFlowPinHandle.h new file mode 100644 index 000000000..141ba3c1a --- /dev/null +++ b/Source/FlowEditor/Public/Pins/SFlowPinHandle.h @@ -0,0 +1,30 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#pragma once + +#include "SGraphPin.h" +#include "SNameComboBox.h" + +class FLOWEDITOR_API SFlowPinHandle : public SGraphPin +{ +public: + SFlowPinHandle(); + virtual ~SFlowPinHandle() override; + + SLATE_BEGIN_ARGS(SFlowPinHandle) {} + SLATE_END_ARGS() + + void Construct(const FArguments& InArgs, UEdGraphPin* InGraphPinObj, const UBlueprint* InBlueprint); + virtual TSharedRef GetDefaultValueWidget() override; + +protected: + virtual void RefreshNameList() {} + void ParseDefaultValueData(); + void ComboBoxSelectionChanged(const TSharedPtr NameItem, ESelectInfo::Type SelectInfo) const; + + const UBlueprint* Blueprint; + TArray> PinNames; + + TSharedPtr ComboBox; + TSharedPtr CurrentlySelectedName; +}; From 19eb80a7883e513a03fe6d8cf3ed3b7deb99baca Mon Sep 17 00:00:00 2001 From: Arseniy Zvezda <39789643+ArseniyZvezda@users.noreply.github.com> Date: Tue, 30 Aug 2022 20:16:30 +0300 Subject: [PATCH 142/338] Sequence replication option (#115) --- .../LevelSequence/FlowLevelSequenceActor.cpp | 27 +++++++++++++++++++ .../LevelSequence/FlowLevelSequencePlayer.cpp | 19 +++++++++---- .../World/FlowNode_PlayLevelSequence.cpp | 3 ++- .../LevelSequence/FlowLevelSequenceActor.h | 16 +++++++++++ .../LevelSequence/FlowLevelSequencePlayer.h | 2 +- .../Nodes/World/FlowNode_PlayLevelSequence.h | 3 +++ 6 files changed, 63 insertions(+), 7 deletions(-) diff --git a/Source/Flow/Private/LevelSequence/FlowLevelSequenceActor.cpp b/Source/Flow/Private/LevelSequence/FlowLevelSequenceActor.cpp index 4910d7509..bcb0cdedb 100644 --- a/Source/Flow/Private/LevelSequence/FlowLevelSequenceActor.cpp +++ b/Source/Flow/Private/LevelSequence/FlowLevelSequenceActor.cpp @@ -2,9 +2,36 @@ #include "LevelSequence/FlowLevelSequenceActor.h" #include "LevelSequence/FlowLevelSequencePlayer.h" +#include "Net/UnrealNetwork.h" AFlowLevelSequenceActor::AFlowLevelSequenceActor(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer .SetDefaultSubobjectClass("AnimationPlayer")) { } + +void AFlowLevelSequenceActor::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const +{ + Super::GetLifetimeReplicatedProps(OutLifetimeProps); + + DOREPLIFETIME(AFlowLevelSequenceActor, ReplicatedLevelSequenceAsset); +} + +void AFlowLevelSequenceActor::SetReplicatedLevelSequenceAsset(ULevelSequence* Asset) +{ + if (HasAuthority()) + { + LevelSequenceAsset = Asset; + ReplicatedLevelSequenceAsset = LevelSequenceAsset; + } +} + +void AFlowLevelSequenceActor::OnRep_ReplicatedLevelSequenceAsset() +{ + LevelSequenceAsset = ReplicatedLevelSequenceAsset; +} + +void AFlowLevelSequenceActor::RPC_InitializePlayer_Implementation() +{ + InitializePlayer(); +}; diff --git a/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp b/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp index e07a39764..011760d90 100644 --- a/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp +++ b/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp @@ -12,7 +12,7 @@ UFlowLevelSequencePlayer::UFlowLevelSequencePlayer(const FObjectInitializer& Obj { } -UFlowLevelSequencePlayer* UFlowLevelSequencePlayer::CreateFlowLevelSequencePlayer(UObject* WorldContextObject, ULevelSequence* LevelSequence, FMovieSceneSequencePlaybackSettings Settings, FLevelSequenceCameraSettings CameraSettings, AActor* TransformOriginActor, ALevelSequenceActor*& OutActor) +UFlowLevelSequencePlayer* UFlowLevelSequencePlayer::CreateFlowLevelSequencePlayer(UObject* WorldContextObject, ULevelSequence* LevelSequence, FMovieSceneSequencePlaybackSettings Settings, FLevelSequenceCameraSettings CameraSettings, AActor* TransformOriginActor, bool bReplicates, ALevelSequenceActor*& OutActor) { if (LevelSequence == nullptr) { @@ -33,13 +33,22 @@ UFlowLevelSequencePlayer* UFlowLevelSequencePlayer::CreateFlowLevelSequencePlaye // Defer construction for autoplay so that BeginPlay() is called SpawnParams.bDeferConstruction = true; - ALevelSequenceActor* Actor = World->SpawnActor(SpawnParams); + AFlowLevelSequenceActor* Actor = World->SpawnActor(SpawnParams); Actor->PlaybackSettings = Settings; - Actor->LevelSequenceAsset = LevelSequence; Actor->CameraSettings = CameraSettings; - - Actor->InitializePlayer(); + if (bReplicates) + { + Actor->SetReplicatedLevelSequenceAsset(LevelSequence); + Actor->SetReplicatePlayback(true); + Actor->bAlwaysRelevant = true; + Actor->RPC_InitializePlayer(); + } + else + { + Actor->LevelSequenceAsset = LevelSequence; + Actor->InitializePlayer(); + } OutActor = Actor; { diff --git a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp index f8aee6e8b..9a7063abe 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp @@ -19,6 +19,7 @@ FFlowNodeLevelSequenceEvent UFlowNode_PlayLevelSequence::OnPlaybackCompleted; UFlowNode_PlayLevelSequence::UFlowNode_PlayLevelSequence(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) , bPlayReverse(false) + , bReplicates(false) , bUseGraphOwnerAsTransformOrigin(false) , bApplyOwnerTimeDilation(true) , LoadedSequence(nullptr) @@ -156,7 +157,7 @@ void UFlowNode_PlayLevelSequence::CreatePlayer() AActor* TransformOriginActor = bUseGraphOwnerAsTransformOrigin ? OwningActor : nullptr; // Finally create the player - SequencePlayer = UFlowLevelSequencePlayer::CreateFlowLevelSequencePlayer(this, LoadedSequence, PlaybackSettings, CameraSettings, TransformOriginActor, SequenceActor); + SequencePlayer = UFlowLevelSequencePlayer::CreateFlowLevelSequencePlayer(this, LoadedSequence, PlaybackSettings, CameraSettings, TransformOriginActor, bReplicates, SequenceActor); if (SequencePlayer) { diff --git a/Source/Flow/Public/LevelSequence/FlowLevelSequenceActor.h b/Source/Flow/Public/LevelSequence/FlowLevelSequenceActor.h index 966d7e9c5..c84cc538e 100644 --- a/Source/Flow/Public/LevelSequence/FlowLevelSequenceActor.h +++ b/Source/Flow/Public/LevelSequence/FlowLevelSequenceActor.h @@ -12,4 +12,20 @@ UCLASS(hideCategories=(Rendering, Physics, LOD, Activation, Input)) class FLOW_API AFlowLevelSequenceActor : public ALevelSequenceActor { GENERATED_UCLASS_BODY() + +protected: + virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; + +public: + void SetReplicatedLevelSequenceAsset(ULevelSequence* Asset); + + UFUNCTION(NetMulticast, Reliable) + void RPC_InitializePlayer(); + +protected: + UPROPERTY(ReplicatedUsing = OnRep_ReplicatedLevelSequenceAsset) + TObjectPtr ReplicatedLevelSequenceAsset; + + UFUNCTION() + void OnRep_ReplicatedLevelSequenceAsset(); }; diff --git a/Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h b/Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h index b7c4ac347..8818a9786 100644 --- a/Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h +++ b/Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h @@ -22,7 +22,7 @@ class FLOW_API UFlowLevelSequencePlayer : public ULevelSequencePlayer public: // variant of ULevelSequencePlayer::CreateLevelSequencePlayer - static UFlowLevelSequencePlayer* CreateFlowLevelSequencePlayer(UObject* WorldContextObject, ULevelSequence* LevelSequence, FMovieSceneSequencePlaybackSettings Settings, FLevelSequenceCameraSettings CameraSettings, AActor* TransformOriginActor, ALevelSequenceActor*& OutActor); + static UFlowLevelSequencePlayer* CreateFlowLevelSequencePlayer(UObject* WorldContextObject, ULevelSequence* LevelSequence, FMovieSceneSequencePlaybackSettings Settings, FLevelSequenceCameraSettings CameraSettings, AActor* TransformOriginActor, bool bReplicates, ALevelSequenceActor*& OutActor); void SetFlowEventReceiver(UFlowNode* FlowNode) { FlowEventReceiver = FlowNode; } diff --git a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h index c9a5d62c2..ac526fe1c 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h @@ -38,6 +38,9 @@ class FLOW_API UFlowNode_PlayLevelSequence : public UFlowNode UPROPERTY(EditAnywhere, Category = "Sequence") bool bPlayReverse; + UPROPERTY(EditAnywhere, Category = "Sequence") + bool bReplicates; + UPROPERTY(EditAnywhere, Category = "Sequence") FLevelSequenceCameraSettings CameraSettings; From b1b4a6f96ef6afccd4c9a80584a487824d3ca658 Mon Sep 17 00:00:00 2001 From: "Satheesh (ryanjon2040)" Date: Thu, 1 Sep 2022 15:41:39 +0530 Subject: [PATCH 143/338] Support keyword search for node search in graph. (#116) --- Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h b/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h index 5cbd54c69..d882bd41d 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h @@ -38,7 +38,7 @@ struct FLOWEDITOR_API FFlowGraphSchemaAction_NewNode : public FEdGraphSchemaActi } FFlowGraphSchemaAction_NewNode(const UFlowNode* Node) - : FEdGraphSchemaAction(FText::FromString(Node->GetNodeCategory()), Node->GetNodeTitle(), Node->GetNodeToolTip(), 0) + : FEdGraphSchemaAction(FText::FromString(Node->GetNodeCategory()), Node->GetNodeTitle(), Node->GetNodeToolTip(), 0, FText::FromString(Node->GetClass()->GetMetaData("Keywords"))) , NodeClass(Node->GetClass()) { } From a0ceadf9c8eed1e76b9f131048b9f3723d68bec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 2 Sep 2022 13:54:13 +0200 Subject: [PATCH 144/338] missing access specifier --- Source/FlowEditor/Public/Asset/FlowAssetEditor.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h index cd3bca47e..7b4d280f0 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h @@ -23,6 +23,7 @@ struct Rect; class FFlowAssetEditor : public FAssetEditorToolkit, public FEditorUndoClient, public FGCObject, public FNotifyHook { +protected: /** The FlowAsset asset being inspected */ UFlowAsset* FlowAsset; From 4767cb01c975d7e55ee9a4c056dab076472baafb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 2 Sep 2022 13:59:33 +0200 Subject: [PATCH 145/338] exposed Initialize/Deinitialize Instance as virtual methods --- Source/Flow/Private/FlowAsset.cpp | 21 ++++++++++++++++----- Source/Flow/Public/FlowAsset.h | 5 +++-- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 7744705f8..62233e8b4 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -295,6 +295,18 @@ void UFlowAsset::InitializeInstance(const TWeakObjectPtr InOwner, UFlow } } +void UFlowAsset::DeinitializeInstance() +{ + if (TemplateAsset) + { + const int32 ActiveInstancesLeft = TemplateAsset->RemoveInstance(this); + if (ActiveInstancesLeft == 0 && GetFlowSubsystem()) + { + GetFlowSubsystem()->RemoveInstancedTemplate(TemplateAsset); + } + } +} + void UFlowAsset::PreloadNodes() { TArray GraphEntryNodes = {StartNode}; @@ -353,7 +365,7 @@ void UFlowAsset::StartFlow() StartNode->TriggerFirstOutput(true); } -void UFlowAsset::FinishFlow(const EFlowFinishPolicy InFinishPolicy) +void UFlowAsset::FinishFlow(const EFlowFinishPolicy InFinishPolicy, const bool bRemoveInstance /*= true*/) { FinishPolicy = InFinishPolicy; @@ -371,11 +383,10 @@ void UFlowAsset::FinishFlow(const EFlowFinishPolicy InFinishPolicy) } PreloadedNodes.Empty(); - // clear instance entries - const int32 ActiveInstancesLeft = TemplateAsset->RemoveInstance(this); - if (ActiveInstancesLeft == 0 && GetFlowSubsystem()) + // provides option to finish game-specific logic prior to removing asset instance + if (bRemoveInstance) { - GetFlowSubsystem()->RemoveInstancedTemplate(TemplateAsset); + DeinitializeInstance(); } } diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index f0e3c0363..b067d533a 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -207,7 +207,8 @@ class FLOW_API UFlowAsset : public UObject EFlowFinishPolicy FinishPolicy; public: - void InitializeInstance(const TWeakObjectPtr InOwner, UFlowAsset* InTemplateAsset); + virtual void InitializeInstance(const TWeakObjectPtr InOwner, UFlowAsset* InTemplateAsset); + virtual void DeinitializeInstance(); UFlowAsset* GetTemplateAsset() const { return TemplateAsset; } @@ -227,7 +228,7 @@ class FLOW_API UFlowAsset : public UObject virtual void PreStartFlow(); virtual void StartFlow(); - virtual void FinishFlow(const EFlowFinishPolicy InFinishPolicy); + virtual void FinishFlow(const EFlowFinishPolicy InFinishPolicy, const bool bRemoveInstance = true); // Get Flow Asset instance created by the given SubGraph node TWeakObjectPtr GetFlowInstance(UFlowNode_SubGraph* SubGraphNode) const; From 2046cc4444e16e81fcdd686d9c013c002d9eceb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 2 Sep 2022 19:44:03 +0200 Subject: [PATCH 146/338] added export macro to every editor class that might be theoretically extended or called --- .../FlowEditor/Public/Asset/AssetTypeActions_FlowAsset.h | 2 +- Source/FlowEditor/Public/Asset/FlowAssetEditor.h | 2 +- Source/FlowEditor/Public/Asset/FlowAssetIndexer.h | 2 +- Source/FlowEditor/Public/Asset/FlowAssetToolbar.h | 8 ++++---- Source/FlowEditor/Public/Asset/FlowDebugger.h | 2 +- Source/FlowEditor/Public/FlowEditorCommands.h | 2 +- Source/FlowEditor/Public/FlowEditorStyle.h | 2 +- Source/FlowEditor/Public/Graph/FlowGraph.h | 2 +- .../Public/Graph/FlowGraphConnectionDrawingPolicy.h | 4 ++-- Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h | 2 +- .../Public/Graph/Nodes/FlowGraphNode_ExecutionSequence.h | 2 +- Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h | 4 ++-- .../Public/Graph/Widgets/SFlowGraphNode_Finish.h | 2 +- .../Public/Graph/Widgets/SFlowGraphNode_Start.h | 2 +- .../Public/Graph/Widgets/SFlowGraphNode_SubGraph.h | 2 +- Source/FlowEditor/Public/Graph/Widgets/SFlowPalette.h | 4 ++-- Source/FlowEditor/Public/LevelEditor/SLevelEditorFlow.h | 2 +- .../Public/Nodes/AssetTypeActions_FlowNodeBlueprint.h | 2 +- 18 files changed, 24 insertions(+), 24 deletions(-) diff --git a/Source/FlowEditor/Public/Asset/AssetTypeActions_FlowAsset.h b/Source/FlowEditor/Public/Asset/AssetTypeActions_FlowAsset.h index b6f28e659..bee8c6b8f 100644 --- a/Source/FlowEditor/Public/Asset/AssetTypeActions_FlowAsset.h +++ b/Source/FlowEditor/Public/Asset/AssetTypeActions_FlowAsset.h @@ -5,7 +5,7 @@ #include "AssetTypeActions_Base.h" #include "Toolkits/IToolkitHost.h" -class FAssetTypeActions_FlowAsset : public FAssetTypeActions_Base +class FLOWEDITOR_API FAssetTypeActions_FlowAsset : public FAssetTypeActions_Base { public: virtual FText GetName() const override; diff --git a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h index 7b4d280f0..63dd36cf7 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h @@ -21,7 +21,7 @@ struct FSlateBrush; struct FPropertyChangedEvent; struct Rect; -class FFlowAssetEditor : public FAssetEditorToolkit, public FEditorUndoClient, public FGCObject, public FNotifyHook +class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEditorUndoClient, public FGCObject, public FNotifyHook { protected: /** The FlowAsset asset being inspected */ diff --git a/Source/FlowEditor/Public/Asset/FlowAssetIndexer.h b/Source/FlowEditor/Public/Asset/FlowAssetIndexer.h index 859b6c177..afdb90c89 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetIndexer.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetIndexer.h @@ -12,7 +12,7 @@ class FSearchSerializer; * Documentation: https://github.com/MothCocoon/FlowGraph/wiki/Asset-Search * Uncomment entire class, if you made these changes to the engine: https://github.com/EpicGames/UnrealEngine/pull/9070 */ -/*class FFlowAssetIndexer : public IAssetIndexer +/*class FLOWEDITOR_API FFlowAssetIndexer : public IAssetIndexer { public: virtual FString GetName() const override { return TEXT("FlowAsset"); } diff --git a/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h b/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h index 1b0269ad7..1676dcbba 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h @@ -12,7 +12,7 @@ class FFlowAssetEditor; ////////////////////////////////////////////////////////////////////////// // Flow Asset Instance List -class SFlowAssetInstanceList final : public SCompoundWidget +class FLOWEDITOR_API SFlowAssetInstanceList final : public SCompoundWidget { public: SLATE_BEGIN_ARGS(SFlowAssetInstanceList) {} @@ -43,7 +43,7 @@ class SFlowAssetInstanceList final : public SCompoundWidget /** * The kind of breadcrumbs that Flow Debugger uses */ -struct FFlowBreadcrumb +struct FLOWEDITOR_API FFlowBreadcrumb { FString AssetPathName; FName InstanceName; @@ -59,7 +59,7 @@ struct FFlowBreadcrumb {} }; -class SFlowAssetBreadcrumb final : public SCompoundWidget +class FLOWEDITOR_API SFlowAssetBreadcrumb final : public SCompoundWidget { public: SLATE_BEGIN_ARGS(SFlowAssetInstanceList) {} @@ -78,7 +78,7 @@ class SFlowAssetBreadcrumb final : public SCompoundWidget ////////////////////////////////////////////////////////////////////////// // Flow Asset Toolbar -class FFlowAssetToolbar final : public TSharedFromThis +class FLOWEDITOR_API FFlowAssetToolbar final : public TSharedFromThis { public: explicit FFlowAssetToolbar(const TSharedPtr InAssetEditor, UToolMenu* ToolbarMenu); diff --git a/Source/FlowEditor/Public/Asset/FlowDebugger.h b/Source/FlowEditor/Public/Asset/FlowDebugger.h index 1487e20c9..75a5ef47b 100644 --- a/Source/FlowEditor/Public/Asset/FlowDebugger.h +++ b/Source/FlowEditor/Public/Asset/FlowDebugger.h @@ -8,7 +8,7 @@ ** Minimalistic form of breakpoint debugger ** See BehaviorTreeDebugger for a more complex example */ -class FFlowDebugger +class FLOWEDITOR_API FFlowDebugger { public: FFlowDebugger(); diff --git a/Source/FlowEditor/Public/FlowEditorCommands.h b/Source/FlowEditor/Public/FlowEditorCommands.h index 6f9defc3e..f3f9caf2c 100644 --- a/Source/FlowEditor/Public/FlowEditorCommands.h +++ b/Source/FlowEditor/Public/FlowEditorCommands.h @@ -7,7 +7,7 @@ #include "Framework/Commands/UICommandInfo.h" #include "Templates/SharedPointer.h" -class FFlowToolbarCommands final : public TCommands +class FLOWEDITOR_API FFlowToolbarCommands final : public TCommands { public: FFlowToolbarCommands(); diff --git a/Source/FlowEditor/Public/FlowEditorStyle.h b/Source/FlowEditor/Public/FlowEditorStyle.h index 0aa06b843..93b45ec05 100644 --- a/Source/FlowEditor/Public/FlowEditorStyle.h +++ b/Source/FlowEditor/Public/FlowEditorStyle.h @@ -4,7 +4,7 @@ #include "Styling/SlateStyle.h" -class FFlowEditorStyle +class FLOWEDITOR_API FFlowEditorStyle { public: static TSharedPtr Get() { return StyleSet; } diff --git a/Source/FlowEditor/Public/Graph/FlowGraph.h b/Source/FlowEditor/Public/Graph/FlowGraph.h index 9ca219976..134562e19 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraph.h +++ b/Source/FlowEditor/Public/Graph/FlowGraph.h @@ -10,7 +10,7 @@ class FLOWEDITOR_API FFlowGraphInterface final : public IFlowGraphInterface { public: - virtual ~FFlowGraphInterface() {} + virtual ~FFlowGraphInterface() override {} virtual void OnInputTriggered(UEdGraphNode* GraphNode, const int32 Index) const override; virtual void OnOutputTriggered(UEdGraphNode* GraphNode, const int32 Index) const override; diff --git a/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h b/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h index 1cf9ea48c..0893d30e8 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h @@ -14,7 +14,7 @@ enum class EFlowConnectionDrawType : uint8 struct FFlowGraphConnectionDrawingPolicyFactory : public FGraphPanelPinConnectionFactory { - virtual ~FFlowGraphConnectionDrawingPolicyFactory() + virtual ~FFlowGraphConnectionDrawingPolicyFactory() override { } @@ -25,7 +25,7 @@ class FSlateWindowElementList; class UEdGraph; // This class draws the connections between nodes -class FFlowGraphConnectionDrawingPolicy : public FConnectionDrawingPolicy +class FLOWEDITOR_API FFlowGraphConnectionDrawingPolicy : public FConnectionDrawingPolicy { float RecentWireDuration; diff --git a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h index 45a37adbb..4a7da0975 100644 --- a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h +++ b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h @@ -15,7 +15,7 @@ class UEdGraphSchema; class UFlowNode; USTRUCT() -struct FFlowBreakpoint +struct FLOWEDITOR_API FFlowBreakpoint { GENERATED_USTRUCT_BODY() diff --git a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_ExecutionSequence.h b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_ExecutionSequence.h index d7a4e1b9f..82105197f 100644 --- a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_ExecutionSequence.h +++ b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode_ExecutionSequence.h @@ -6,7 +6,7 @@ #include "FlowGraphNode_ExecutionSequence.generated.h" UCLASS() -class UFlowGraphNode_ExecutionSequence final : public UFlowGraphNode +class FLOWEDITOR_API UFlowGraphNode_ExecutionSequence : public UFlowGraphNode { GENERATED_UCLASS_BODY() diff --git a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h index a4fceb3ed..d54e948df 100644 --- a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h +++ b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h @@ -7,7 +7,7 @@ #include "Graph/Nodes/FlowGraphNode.h" -class SFlowGraphPinExec final : public SGraphPinExec +class FLOWEDITOR_API SFlowGraphPinExec : public SGraphPinExec { public: SFlowGraphPinExec(); @@ -18,7 +18,7 @@ class SFlowGraphPinExec final : public SGraphPinExec void Construct(const FArguments& InArgs, UEdGraphPin* InPin); }; -class SFlowGraphNode : public SGraphNode +class FLOWEDITOR_API SFlowGraphNode : public SGraphNode { public: SLATE_BEGIN_ARGS(SFlowGraphNode) {} diff --git a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode_Finish.h b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode_Finish.h index f68137550..d054d4a37 100644 --- a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode_Finish.h +++ b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode_Finish.h @@ -4,6 +4,6 @@ #include "Graph/Widgets/SFlowGraphNode.h" -class SFlowGraphNode_Finish : public SFlowGraphNode +class FLOWEDITOR_API SFlowGraphNode_Finish : public SFlowGraphNode { }; diff --git a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode_Start.h b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode_Start.h index 80c7946e5..52a959239 100644 --- a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode_Start.h +++ b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode_Start.h @@ -4,6 +4,6 @@ #include "Graph/Widgets/SFlowGraphNode.h" -class SFlowGraphNode_Start : public SFlowGraphNode +class FLOWEDITOR_API SFlowGraphNode_Start : public SFlowGraphNode { }; diff --git a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode_SubGraph.h b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode_SubGraph.h index a88348351..9a97dd3de 100644 --- a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode_SubGraph.h +++ b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode_SubGraph.h @@ -4,7 +4,7 @@ #include "Graph/Widgets/SFlowGraphNode.h" -class SFlowGraphNode_SubGraph : public SFlowGraphNode +class FLOWEDITOR_API SFlowGraphNode_SubGraph : public SFlowGraphNode { protected: // SGraphNode diff --git a/Source/FlowEditor/Public/Graph/Widgets/SFlowPalette.h b/Source/FlowEditor/Public/Graph/Widgets/SFlowPalette.h index d11873ef3..257bb200c 100644 --- a/Source/FlowEditor/Public/Graph/Widgets/SFlowPalette.h +++ b/Source/FlowEditor/Public/Graph/Widgets/SFlowPalette.h @@ -7,7 +7,7 @@ class FFlowAssetEditor; /** Widget displaying a single item */ -class SFlowPaletteItem : public SGraphPaletteItem +class FLOWEDITOR_API SFlowPaletteItem : public SGraphPaletteItem { public: SLATE_BEGIN_ARGS(SFlowPaletteItem) {} @@ -21,7 +21,7 @@ class SFlowPaletteItem : public SGraphPaletteItem }; /** Flow Palette */ -class SFlowPalette : public SGraphPalette +class FLOWEDITOR_API SFlowPalette : public SGraphPalette { public: SLATE_BEGIN_ARGS(SFlowPalette) {} diff --git a/Source/FlowEditor/Public/LevelEditor/SLevelEditorFlow.h b/Source/FlowEditor/Public/LevelEditor/SLevelEditorFlow.h index 5d4be19b0..d004bce48 100644 --- a/Source/FlowEditor/Public/LevelEditor/SLevelEditorFlow.h +++ b/Source/FlowEditor/Public/LevelEditor/SLevelEditorFlow.h @@ -8,7 +8,7 @@ struct FAssetData; -class SLevelEditorFlow : public SCompoundWidget +class FLOWEDITOR_API SLevelEditorFlow : public SCompoundWidget { public: SLATE_BEGIN_ARGS(SLevelEditorFlow) {} diff --git a/Source/FlowEditor/Public/Nodes/AssetTypeActions_FlowNodeBlueprint.h b/Source/FlowEditor/Public/Nodes/AssetTypeActions_FlowNodeBlueprint.h index 201124de5..cb7552fa3 100644 --- a/Source/FlowEditor/Public/Nodes/AssetTypeActions_FlowNodeBlueprint.h +++ b/Source/FlowEditor/Public/Nodes/AssetTypeActions_FlowNodeBlueprint.h @@ -4,7 +4,7 @@ #include "AssetTypeActions/AssetTypeActions_Blueprint.h" -class FAssetTypeActions_FlowNodeBlueprint final : public FAssetTypeActions_Blueprint +class FLOWEDITOR_API FAssetTypeActions_FlowNodeBlueprint final : public FAssetTypeActions_Blueprint { public: virtual FText GetName() const override; From 7601328161cb13d3ada4dc1228946413ccd0c136 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 2 Sep 2022 19:45:47 +0200 Subject: [PATCH 147/338] removed redundant include --- Source/Flow/Public/FlowAsset.h | 1 - Source/Flow/Public/FlowSave.h | 1 - Source/Flow/Public/Nodes/FlowNode.h | 1 - 3 files changed, 3 deletions(-) diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index b067d533a..93a8ef340 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -2,7 +2,6 @@ #pragma once -#include "CoreMinimal.h" #include "FlowSave.h" #include "FlowTypes.h" #include "FlowAsset.generated.h" diff --git a/Source/Flow/Public/FlowSave.h b/Source/Flow/Public/FlowSave.h index fc9e939ef..1c2a07735 100644 --- a/Source/Flow/Public/FlowSave.h +++ b/Source/Flow/Public/FlowSave.h @@ -2,7 +2,6 @@ #pragma once -#include "CoreMinimal.h" #include "GameFramework/SaveGame.h" #include "Serialization/BufferArchive.h" #include "Serialization/ObjectAndNameAsStringProxyArchive.h" diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index f0d20c63b..673ca0470 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -2,7 +2,6 @@ #pragma once -#include "CoreMinimal.h" #include "EdGraph/EdGraphNode.h" #include "Engine/StreamableManager.h" #include "GameplayTagContainer.h" From 36a1ab638d30face3332abfd2b83149b1b9fc0c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sat, 3 Sep 2022 15:42:05 +0200 Subject: [PATCH 148/338] added templated GetNode, as it was always tempting --- Source/Flow/Private/FlowAsset.cpp | 5 ----- Source/Flow/Public/FlowAsset.h | 15 ++++++++++++++- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 62233e8b4..80776e0f5 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -190,11 +190,6 @@ void UFlowAsset::HarvestNodeConnections() } #endif -UFlowNode* UFlowAsset::GetNode(const FGuid& Guid) const -{ - return Nodes.FindRef(Guid); -} - void UFlowAsset::AddInstance(UFlowAsset* Instance) { ActiveInstances.Add(Instance); diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 93a8ef340..6df8357ab 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -128,8 +128,21 @@ class FLOW_API UFlowAsset : public UObject void HarvestNodeConnections(); #endif - UFlowNode* GetNode(const FGuid& Guid) const; TMap GetNodes() const { return Nodes; } + UFlowNode* GetNode(const FGuid& Guid) const { return Nodes.FindRef(Guid); } + + template + T* GetNode(const FGuid& Guid) const + { + static_assert(TPointerIsConvertibleFromTo::Value, "'T' template parameter to GetNode must be derived from UFlowNode"); + + if (UFlowNode* Node = Nodes.FindRef(Guid)) + { + return Cast(Node); + } + + return nullptr; + } TArray GetCustomInputs() const { return CustomInputs; } TArray GetCustomOutputs() const { return CustomOutputs; } From 8d9f7d09d0420cbaea03d24d63c1074b2b31bdbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sat, 3 Sep 2022 15:42:05 +0200 Subject: [PATCH 149/338] added templated GetNode, as it was always tempting From dcc6d405c624730112e25e204bd63acecdc77e89 Mon Sep 17 00:00:00 2001 From: Bargestt Date: Thu, 8 Sep 2022 22:48:30 +0700 Subject: [PATCH 150/338] Asset category merge (#117) --- .../FlowEditor/Private/FlowEditorModule.cpp | 24 ++++++++++++++++++- .../Public/Graph/FlowGraphSettings.h | 8 +++---- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/Source/FlowEditor/Private/FlowEditorModule.cpp b/Source/FlowEditor/Private/FlowEditorModule.cpp index 8d83d0340..33b922f4a 100644 --- a/Source/FlowEditor/Private/FlowEditorModule.cpp +++ b/Source/FlowEditor/Private/FlowEditorModule.cpp @@ -118,7 +118,29 @@ void FFlowEditorModule::ShutdownModule() void FFlowEditorModule::RegisterAssets() { IAssetTools& AssetTools = FModuleManager::LoadModuleChecked("AssetTools").Get(); - FlowAssetCategory = AssetTools.RegisterAdvancedAssetCategory(FName(TEXT("Flow")), UFlowGraphSettings::Get()->FlowAssetCategoryName); + + FText AssetCategoryText = UFlowGraphSettings::Get()->FlowAssetCategoryName; + + // Find matching BuildIn category + if (!AssetCategoryText.IsEmpty()) + { + TArray AllCategories; + AssetTools.GetAllAdvancedAssetCategories(AllCategories); + for (const FAdvancedAssetCategory& ExistingCategory : AllCategories) + { + if (ExistingCategory.CategoryName.EqualTo(AssetCategoryText)) + { + FlowAssetCategory = ExistingCategory.CategoryType; + break; + } + } + } + + if (FlowAssetCategory == EAssetTypeCategories::None) + { + FlowAssetCategory = AssetTools.RegisterAdvancedAssetCategory(FName(TEXT("Flow")), AssetCategoryText); + } + const TSharedRef FlowAssetActions = MakeShareable(new FAssetTypeActions_FlowAsset()); RegisteredAssetActions.Add(FlowAssetActions); diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h index b82092d3c..fb155608b 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h @@ -20,20 +20,20 @@ class UFlowGraphSettings final : public UDeveloperSettings /** Show Flow Asset in Flow category of "Create Asset" menu? * Requires restart after making a change. */ - UPROPERTY(EditAnywhere, config, Category = "Default UI") + UPROPERTY(EditAnywhere, config, Category = "Default UI", meta = (ConfigRestartRequired = true)) bool bExposeFlowAssetCreation; /** Show Flow Node blueprint in Flow category of "Create Asset" menu? * Requires restart after making a change. */ - UPROPERTY(EditAnywhere, config, Category = "Default UI") + UPROPERTY(EditAnywhere, config, Category = "Default UI", meta = (ConfigRestartRequired = true)) bool bExposeFlowNodeCreation; /** Show Flow Asset toolbar? * Requires restart after making a change. */ - UPROPERTY(EditAnywhere, config, Category = "Default UI") + UPROPERTY(EditAnywhere, config, Category = "Default UI", meta = (ConfigRestartRequired = true)) bool bShowAssetToolbarAboveLevelEditor; - UPROPERTY(EditAnywhere, config, Category = "Default UI") + UPROPERTY(EditAnywhere, config, Category = "Default UI", meta = (ConfigRestartRequired = true)) FText FlowAssetCategoryName; /** Flow Asset class allowed to be assigned via Level Editor toolbar*/ From b058efbd10e5cb5ab289c75d46bb4f25138fa714 Mon Sep 17 00:00:00 2001 From: Bargestt Date: Thu, 8 Sep 2022 22:48:45 +0700 Subject: [PATCH 151/338] Class picker for new assets (#118) --- .../Private/Asset/FlowAssetFactory.cpp | 97 ++++++++++++++++++- .../Private/Graph/FlowGraphSettings.cpp | 1 + .../Public/Asset/FlowAssetFactory.h | 4 + .../Public/Graph/FlowGraphSettings.h | 4 + 4 files changed, 105 insertions(+), 1 deletion(-) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp b/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp index 13e6a31a6..1abe5bd9d 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp @@ -4,6 +4,56 @@ #include "FlowAsset.h" #include "Graph/FlowGraph.h" +#include +#include +#include +#include + + +class FAssetClassParentFilter : public IClassViewerFilter +{ +public: + FAssetClassParentFilter() + : DisallowedClassFlags(CLASS_None), bDisallowBlueprintBase(false) + {} + + /** All children of these classes will be included unless filtered out by another setting. */ + TSet< const UClass* > AllowedChildrenOfClasses; + + /** Disallowed class flags. */ + EClassFlags DisallowedClassFlags; + + /** Disallow blueprint base classes. */ + bool bDisallowBlueprintBase; + + virtual bool IsClassAllowed(const FClassViewerInitializationOptions& InInitOptions, const UClass* InClass, TSharedRef< FClassViewerFilterFuncs > InFilterFuncs) override + { + bool bAllowed = !InClass->HasAnyClassFlags(DisallowedClassFlags) + && InFilterFuncs->IfInChildOfClassesSet(AllowedChildrenOfClasses, InClass) != EFilterReturn::Failed; + + if (bAllowed && bDisallowBlueprintBase) + { + if (FKismetEditorUtilities::CanCreateBlueprintOfClass(InClass)) + { + return false; + } + } + + return bAllowed; + } + + virtual bool IsUnloadedClassAllowed(const FClassViewerInitializationOptions& InInitOptions, const TSharedRef< const IUnloadedBlueprintData > InUnloadedClassData, TSharedRef< FClassViewerFilterFuncs > InFilterFuncs) override + { + if (bDisallowBlueprintBase) + { + return false; + } + + return !InUnloadedClassData->HasAnyClassFlags(DisallowedClassFlags) + && InFilterFuncs->IfInChildOfClassesSet(AllowedChildrenOfClasses, InUnloadedClassData) != EFilterReturn::Failed; + } +}; + UFlowAssetFactory::UFlowAssetFactory(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { @@ -14,9 +64,54 @@ UFlowAssetFactory::UFlowAssetFactory(const FObjectInitializer& ObjectInitializer bEditAfterNew = true; } +bool UFlowAssetFactory::ConfigureProperties() +{ + AssetClass = UFlowGraphSettings::Get()->DefaultFlowAssetClass;; + + if (AssetClass != nullptr) + { + // Class was selected in settings + return true; + } + + // Load the classviewer module to display a class picker + FClassViewerModule& ClassViewerModule = FModuleManager::LoadModuleChecked("ClassViewer"); + + // Fill in options + FClassViewerInitializationOptions Options; + Options.Mode = EClassViewerMode::ClassPicker; + + TSharedPtr Filter = MakeShareable(new FAssetClassParentFilter); + Options.ClassFilter = Filter; + + Filter->DisallowedClassFlags = CLASS_Abstract | CLASS_Deprecated | CLASS_NewerVersionExists | CLASS_HideDropDown; + Filter->AllowedChildrenOfClasses.Add(UFlowAsset::StaticClass()); + + const FText TitleText = NSLOCTEXT("FlowAssetFactory", "CreateFlowAssetOptions", "Pick Flow Asset Class"); + UClass* ChosenClass = nullptr; + const bool bPressedOk = SClassPickerDialog::PickClass(TitleText, Options, ChosenClass, UFlowAsset::StaticClass()); + + if (bPressedOk) + { + AssetClass = ChosenClass; + } + + return bPressedOk; +} + UObject* UFlowAssetFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) { - UFlowAsset* NewFlow = NewObject(InParent, Class, Name, Flags | RF_Transactional, Context); + UFlowAsset* NewFlow = nullptr; + if (AssetClass != nullptr) + { + NewFlow = NewObject(InParent, AssetClass, Name, Flags | RF_Transactional, Context); + } + else + { + // if we have no asset class, use the passed-in class instead + NewFlow = NewObject(InParent, Class, Name, Flags | RF_Transactional, Context); + } + UFlowGraph::CreateGraph(NewFlow); return NewFlow; } diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp index ea44964da..7c54658fb 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp @@ -12,6 +12,7 @@ UFlowGraphSettings::UFlowGraphSettings(const FObjectInitializer& ObjectInitializ , bExposeFlowNodeCreation(true) , bShowAssetToolbarAboveLevelEditor(true) , FlowAssetCategoryName(LOCTEXT("FlowAssetCategory", "Flow")) + , DefaultFlowAssetClass(UFlowAsset::StaticClass()) , WorldAssetClass(UFlowAsset::StaticClass()) , bShowDefaultPinNames(false) , ExecPinColorModifier(0.75f, 0.75f, 0.75f, 1.0f) diff --git a/Source/FlowEditor/Public/Asset/FlowAssetFactory.h b/Source/FlowEditor/Public/Asset/FlowAssetFactory.h index b8a3f93a3..1a085fa7c 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetFactory.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetFactory.h @@ -10,5 +10,9 @@ class UFlowAssetFactory : public UFactory { GENERATED_UCLASS_BODY() + UPROPERTY(EditAnywhere, Category = Asset) + TSubclassOf AssetClass; + + virtual bool ConfigureProperties() override; virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override; }; diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h index fb155608b..cbd5be68a 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h @@ -36,6 +36,10 @@ class UFlowGraphSettings final : public UDeveloperSettings UPROPERTY(EditAnywhere, config, Category = "Default UI", meta = (ConfigRestartRequired = true)) FText FlowAssetCategoryName; + /** Use this class to create new assets. Class picker will show up if None */ + UPROPERTY(EditAnywhere, config, Category = "Default UI") + TSubclassOf DefaultFlowAssetClass; + /** Flow Asset class allowed to be assigned via Level Editor toolbar*/ UPROPERTY(EditAnywhere, config, Category = "Default UI", meta = (EditCondition = "bShowAssetToolbarAboveLevelEditor")) TSubclassOf WorldAssetClass; From dfdc2fd4c3bf771d222568314be3836c13e587c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Thu, 8 Sep 2022 19:36:34 +0200 Subject: [PATCH 152/338] minor readability tweak to #117 --- .../Private/Asset/FlowAssetFactory.cpp | 41 ++++++++++--------- .../FlowEditor/Private/FlowEditorModule.cpp | 34 +++++++-------- 2 files changed, 40 insertions(+), 35 deletions(-) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp b/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp index 1abe5bd9d..47f0de8cd 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp @@ -3,22 +3,26 @@ #include "Asset/FlowAssetFactory.h" #include "FlowAsset.h" #include "Graph/FlowGraph.h" +#include "Graph/FlowGraphSettings.h" -#include -#include -#include -#include +#include "ClassViewerFilter.h" +#include "ClassViewerModule.h" +#include "Kismet2/KismetEditorUtilities.h" +#include "Kismet2/SClassPickerDialog.h" +#define LOCTEXT_NAMESPACE "FlowAssetFactory" class FAssetClassParentFilter : public IClassViewerFilter { public: FAssetClassParentFilter() - : DisallowedClassFlags(CLASS_None), bDisallowBlueprintBase(false) - {} + : DisallowedClassFlags(CLASS_None) + , bDisallowBlueprintBase(false) + { + } /** All children of these classes will be included unless filtered out by another setting. */ - TSet< const UClass* > AllowedChildrenOfClasses; + TSet AllowedChildrenOfClasses; /** Disallowed class flags. */ EClassFlags DisallowedClassFlags; @@ -26,10 +30,9 @@ class FAssetClassParentFilter : public IClassViewerFilter /** Disallow blueprint base classes. */ bool bDisallowBlueprintBase; - virtual bool IsClassAllowed(const FClassViewerInitializationOptions& InInitOptions, const UClass* InClass, TSharedRef< FClassViewerFilterFuncs > InFilterFuncs) override + virtual bool IsClassAllowed(const FClassViewerInitializationOptions& InInitOptions, const UClass* InClass, TSharedRef InFilterFuncs) override { - bool bAllowed = !InClass->HasAnyClassFlags(DisallowedClassFlags) - && InFilterFuncs->IfInChildOfClassesSet(AllowedChildrenOfClasses, InClass) != EFilterReturn::Failed; + const bool bAllowed = !InClass->HasAnyClassFlags(DisallowedClassFlags) && InFilterFuncs->IfInChildOfClassesSet(AllowedChildrenOfClasses, InClass) != EFilterReturn::Failed; if (bAllowed && bDisallowBlueprintBase) { @@ -42,15 +45,14 @@ class FAssetClassParentFilter : public IClassViewerFilter return bAllowed; } - virtual bool IsUnloadedClassAllowed(const FClassViewerInitializationOptions& InInitOptions, const TSharedRef< const IUnloadedBlueprintData > InUnloadedClassData, TSharedRef< FClassViewerFilterFuncs > InFilterFuncs) override + virtual bool IsUnloadedClassAllowed(const FClassViewerInitializationOptions& InInitOptions, const TSharedRef InUnloadedClassData, TSharedRef InFilterFuncs) override { if (bDisallowBlueprintBase) { return false; } - return !InUnloadedClassData->HasAnyClassFlags(DisallowedClassFlags) - && InFilterFuncs->IfInChildOfClassesSet(AllowedChildrenOfClasses, InUnloadedClassData) != EFilterReturn::Failed; + return !InUnloadedClassData->HasAnyClassFlags(DisallowedClassFlags) && InFilterFuncs->IfInChildOfClassesSet(AllowedChildrenOfClasses, InUnloadedClassData) != EFilterReturn::Failed; } }; @@ -67,27 +69,26 @@ UFlowAssetFactory::UFlowAssetFactory(const FObjectInitializer& ObjectInitializer bool UFlowAssetFactory::ConfigureProperties() { AssetClass = UFlowGraphSettings::Get()->DefaultFlowAssetClass;; - if (AssetClass != nullptr) - { + { // Class was selected in settings return true; } - // Load the classviewer module to display a class picker - FClassViewerModule& ClassViewerModule = FModuleManager::LoadModuleChecked("ClassViewer"); + // Load the Class Viewer module to display a class picker + FModuleManager::LoadModuleChecked("ClassViewer"); // Fill in options FClassViewerInitializationOptions Options; Options.Mode = EClassViewerMode::ClassPicker; - TSharedPtr Filter = MakeShareable(new FAssetClassParentFilter); + const TSharedPtr Filter = MakeShareable(new FAssetClassParentFilter); Options.ClassFilter = Filter; Filter->DisallowedClassFlags = CLASS_Abstract | CLASS_Deprecated | CLASS_NewerVersionExists | CLASS_HideDropDown; Filter->AllowedChildrenOfClasses.Add(UFlowAsset::StaticClass()); - const FText TitleText = NSLOCTEXT("FlowAssetFactory", "CreateFlowAssetOptions", "Pick Flow Asset Class"); + const FText TitleText = LOCTEXT("CreateFlowAssetOptions", "Pick Flow Asset Class"); UClass* ChosenClass = nullptr; const bool bPressedOk = SClassPickerDialog::PickClass(TitleText, Options, ChosenClass, UFlowAsset::StaticClass()); @@ -115,3 +116,5 @@ UObject* UFlowAssetFactory::FactoryCreateNew(UClass* Class, UObject* InParent, F UFlowGraph::CreateGraph(NewFlow); return NewFlow; } + +#undef LOCTEXT_NAMESPACE \ No newline at end of file diff --git a/Source/FlowEditor/Private/FlowEditorModule.cpp b/Source/FlowEditor/Private/FlowEditorModule.cpp index 33b922f4a..faf8797ff 100644 --- a/Source/FlowEditor/Private/FlowEditorModule.cpp +++ b/Source/FlowEditor/Private/FlowEditorModule.cpp @@ -111,7 +111,7 @@ void FFlowEditorModule::ShutdownModule() } } } - + FModuleManager::Get().OnModulesChanged().Remove(ModulesChangedHandle); } @@ -119,29 +119,31 @@ void FFlowEditorModule::RegisterAssets() { IAssetTools& AssetTools = FModuleManager::LoadModuleChecked("AssetTools").Get(); - FText AssetCategoryText = UFlowGraphSettings::Get()->FlowAssetCategoryName; + // try to merge asset category with a built-in one + { + FText AssetCategoryText = UFlowGraphSettings::Get()->FlowAssetCategoryName; - // Find matching BuildIn category - if (!AssetCategoryText.IsEmpty()) - { - TArray AllCategories; - AssetTools.GetAllAdvancedAssetCategories(AllCategories); - for (const FAdvancedAssetCategory& ExistingCategory : AllCategories) + // Find matching built-in category + if (!AssetCategoryText.IsEmpty()) { - if (ExistingCategory.CategoryName.EqualTo(AssetCategoryText)) + TArray AllCategories; + AssetTools.GetAllAdvancedAssetCategories(AllCategories); + for (const FAdvancedAssetCategory& ExistingCategory : AllCategories) { - FlowAssetCategory = ExistingCategory.CategoryType; - break; + if (ExistingCategory.CategoryName.EqualTo(AssetCategoryText)) + { + FlowAssetCategory = ExistingCategory.CategoryType; + break; + } } } - } - if (FlowAssetCategory == EAssetTypeCategories::None) - { - FlowAssetCategory = AssetTools.RegisterAdvancedAssetCategory(FName(TEXT("Flow")), AssetCategoryText); + if (FlowAssetCategory == EAssetTypeCategories::None) + { + FlowAssetCategory = AssetTools.RegisterAdvancedAssetCategory(FName(TEXT("Flow")), AssetCategoryText); + } } - const TSharedRef FlowAssetActions = MakeShareable(new FAssetTypeActions_FlowAsset()); RegisteredAssetActions.Add(FlowAssetActions); AssetTools.RegisterAssetTypeActions(FlowAssetActions); From 3b237a75b2ccdf8085cdb9156f78736636afafcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Wed, 21 Sep 2022 15:59:07 +0200 Subject: [PATCH 153/338] compilation fixes --- Source/Flow/Public/FlowSave.h | 1 + Source/FlowEditor/Public/Asset/FlowAssetFactory.h | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Source/Flow/Public/FlowSave.h b/Source/Flow/Public/FlowSave.h index 1c2a07735..fc9e939ef 100644 --- a/Source/Flow/Public/FlowSave.h +++ b/Source/Flow/Public/FlowSave.h @@ -2,6 +2,7 @@ #pragma once +#include "CoreMinimal.h" #include "GameFramework/SaveGame.h" #include "Serialization/BufferArchive.h" #include "Serialization/ObjectAndNameAsStringProxyArchive.h" diff --git a/Source/FlowEditor/Public/Asset/FlowAssetFactory.h b/Source/FlowEditor/Public/Asset/FlowAssetFactory.h index 1a085fa7c..e1c3f5274 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetFactory.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetFactory.h @@ -5,8 +5,8 @@ #include "Factories/Factory.h" #include "FlowAssetFactory.generated.h" -UCLASS(HideCategories = Object, MinimalAPI) -class UFlowAssetFactory : public UFactory +UCLASS(HideCategories = Object) +class FLOWEDITOR_API UFlowAssetFactory : public UFactory { GENERATED_UCLASS_BODY() From c13f8316fc8347dc04f4b56e0061bd57eb150d66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Wed, 21 Sep 2022 18:01:33 +0200 Subject: [PATCH 154/338] 5.0 deprecation warning fixed --- Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp b/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp index 47f0de8cd..03f29d11d 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp @@ -83,11 +83,11 @@ bool UFlowAssetFactory::ConfigureProperties() Options.Mode = EClassViewerMode::ClassPicker; const TSharedPtr Filter = MakeShareable(new FAssetClassParentFilter); - Options.ClassFilter = Filter; - Filter->DisallowedClassFlags = CLASS_Abstract | CLASS_Deprecated | CLASS_NewerVersionExists | CLASS_HideDropDown; Filter->AllowedChildrenOfClasses.Add(UFlowAsset::StaticClass()); + Options.ClassFilters = {Filter.ToSharedRef()}; + const FText TitleText = LOCTEXT("CreateFlowAssetOptions", "Pick Flow Asset Class"); UClass* ChosenClass = nullptr; const bool bPressedOk = SClassPickerDialog::PickClass(TitleText, Options, ChosenClass, UFlowAsset::StaticClass()); From 8a31b29799364f88f75d0a3e013c7be3067b721b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Wed, 21 Sep 2022 18:04:34 +0200 Subject: [PATCH 155/338] added AllowedAssetClasses & DeniedAssetClasses to Flow Node class Flow Node class now can defined in which Flow Asset class can be placed --- Source/Flow/Public/Nodes/FlowNode.h | 3 + .../Private/Graph/FlowGraphSchema.cpp | 100 +++++++++++++----- .../FlowEditor/Public/Graph/FlowGraphSchema.h | 3 +- 3 files changed, 77 insertions(+), 29 deletions(-) diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 673ca0470..b3b969e24 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -42,6 +42,9 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte #if WITH_EDITORONLY_DATA protected: + TArray> AllowedAssetClasses; + TArray> DeniedAssetClasses; + UPROPERTY() FString Category; diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp index 43aebb508..cbe7b267b 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -18,7 +18,6 @@ #include "Developer/ToolMenus/Public/ToolMenus.h" #include "EdGraph/EdGraph.h" #include "ScopedTransaction.h" -#include "UObject/UObjectIterator.h" #define LOCTEXT_NAMESPACE "FlowGraphSchema" @@ -245,17 +244,72 @@ UClass* UFlowGraphSchema::GetAssignedGraphNodeClass(const UClass* FlowNodeClass) return UFlowGraphNode::StaticClass(); } -bool UFlowGraphSchema::IsClassContained(const TArray> Classes, const UClass* Class) +void UFlowGraphSchema::ApplyNodeFilter(const UFlowAsset* AssetClassDefaults, const UClass* FlowNodeClass, TArray& FilteredNodes) { - for (const UClass* CurrentClass : Classes) + if (FlowNodeClass == nullptr) { - if (Class->IsChildOf(CurrentClass)) + return; + } + + UFlowNode* NodeDefaults = FlowNodeClass->GetDefaultObject(); + + // UFlowNode class limits which UFlowAsset class can use it + { + for (const UClass* DeniedAssetClass : NodeDefaults->DeniedAssetClasses) + { + if (DeniedAssetClass && AssetClassDefaults->GetClass()->IsChildOf(DeniedAssetClass)) + { + return; + } + } + + if (NodeDefaults->AllowedAssetClasses.Num() > 0) + { + bool bAllowedInAsset = false; + for (const UClass* AllowedAssetClass : NodeDefaults->AllowedAssetClasses) + { + if (AllowedAssetClass && AssetClassDefaults->GetClass()->IsChildOf(AllowedAssetClass)) + { + bAllowedInAsset = true; + break; + } + } + if (!bAllowedInAsset) + { + return; + } + } + } + + // UFlowAsset class can limit which UFlowNode classes can be used + { + for (const UClass* DeniedNodeClass : AssetClassDefaults->DeniedNodeClasses) + { + if (DeniedNodeClass && FlowNodeClass->IsChildOf(DeniedNodeClass)) + { + return; + } + } + + if (AssetClassDefaults->AllowedNodeClasses.Num() > 0) { - return true; + bool bAllowedInAsset = false; + for (const UClass* AllowedNodeClass : AssetClassDefaults->AllowedNodeClasses) + { + if (AllowedNodeClass && FlowNodeClass->IsChildOf(AllowedNodeClass)) + { + bAllowedInAsset = true; + break; + } + } + if (!bAllowedInAsset) + { + return; + } } } - return false; + FilteredNodes.Emplace(NodeDefaults); } void UFlowGraphSchema::GetFlowNodeActions(FGraphActionMenuBuilder& ActionMenuBuilder, const UFlowAsset* AssetClassDefaults, const FString& CategoryName) @@ -265,38 +319,28 @@ void UFlowGraphSchema::GetFlowNodeActions(FGraphActionMenuBuilder& ActionMenuBui GatherFlowNodes(); } - TArray FlowNodes; - FlowNodes.Reserve(NativeFlowNodes.Num() + BlueprintFlowNodes.Num()); - - for (const UClass* FlowNodeClass : NativeFlowNodes) + // Flow Asset type might limit which nodes are placeable + TArray FilteredNodes; { - // Flow Asset type might limit which nodes are placeable - if (IsClassContained(AssetClassDefaults->DeniedNodeClasses, FlowNodeClass)) - { - continue; - } + FilteredNodes.Reserve(NativeFlowNodes.Num() + BlueprintFlowNodes.Num()); - if (IsClassContained(AssetClassDefaults->AllowedNodeClasses, FlowNodeClass)) + for (const UClass* FlowNodeClass : NativeFlowNodes) { - FlowNodes.Emplace(FlowNodeClass->GetDefaultObject()); + ApplyNodeFilter(AssetClassDefaults, FlowNodeClass, FilteredNodes); } - } - for (const TPair& AssetData : BlueprintFlowNodes) - { - if (const UBlueprint* Blueprint = GetPlaceableNodeBlueprint(AssetData.Value)) + + for (const TPair& AssetData : BlueprintFlowNodes) { - for (const UClass* AllowedClass : AssetClassDefaults->AllowedNodeClasses) + if (const UBlueprint* Blueprint = GetPlaceableNodeBlueprint(AssetData.Value)) { - if (Blueprint->GeneratedClass->IsChildOf(AllowedClass)) - { - FlowNodes.Emplace(Blueprint->GeneratedClass->GetDefaultObject()); - } + ApplyNodeFilter(AssetClassDefaults, Blueprint->GeneratedClass, FilteredNodes); } } + + FilteredNodes.Shrink(); } - FlowNodes.Shrink(); - for (const UFlowNode* FlowNode : FlowNodes) + for (const UFlowNode* FlowNode : FilteredNodes) { if ((CategoryName.IsEmpty() || CategoryName.Equals(FlowNode->GetNodeCategory())) && !UFlowGraphSettings::Get()->NodesHiddenFromPalette.Contains(FlowNode->GetClass())) { diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h index ed4110b81..592309bc1 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h @@ -5,6 +5,7 @@ #include "EdGraph/EdGraphSchema.h" #include "FlowGraphSchema.generated.h" +class UFlowNode; class UFlowAsset; DECLARE_MULTICAST_DELEGATE(FFlowGraphSchemaRefresh); @@ -43,7 +44,7 @@ class FLOWEDITOR_API UFlowGraphSchema : public UEdGraphSchema static UClass* GetAssignedGraphNodeClass(const UClass* FlowNodeClass); private: - static bool IsClassContained(const TArray> Classes, const UClass* Class); + static void ApplyNodeFilter(const UFlowAsset* AssetClassDefaults, const UClass* FlowNodeClass, TArray& FilteredNodes); static void GetFlowNodeActions(FGraphActionMenuBuilder& ActionMenuBuilder, const UFlowAsset* AssetClassDefaults, const FString& CategoryName); static void GetCommentAction(FGraphActionMenuBuilder& ActionMenuBuilder, const UEdGraph* CurrentGraph = nullptr); From 97bb4e87bdff5a0b5910e026f5469f28bec15184 Mon Sep 17 00:00:00 2001 From: Jani Hartikainen Date: Sun, 25 Sep 2022 13:25:08 +0300 Subject: [PATCH 156/338] Improve drawing for reroute nodes that go backwards (#121) --- .../FlowGraphConnectionDrawingPolicy.cpp | 109 ++++++++++++++++++ .../Graph/FlowGraphConnectionDrawingPolicy.h | 7 ++ 2 files changed, 116 insertions(+) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp b/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp index 4aa0c4eb0..4d462c1d7 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp @@ -11,6 +11,7 @@ #include "Graph/Nodes/FlowGraphNode.h" #include "FlowAsset.h" +#include "Graph/Nodes/FlowGraphNode_Reroute.h" #include "Nodes/FlowNode.h" #include "Misc/App.h" @@ -126,6 +127,28 @@ void FFlowGraphConnectionDrawingPolicy::DetermineWiringStyle(UEdGraphPin* Output check(GraphObj); const UEdGraphSchema* Schema = GraphObj->GetSchema(); + { + //If reroute node path goes backwards, we need to flip the direction to make it look nice + //(all of the logic for this is basically same as in FKismetConnectionDrawingPolicy) + UEdGraphNode* OutputNode = OutputPin->GetOwningNode(); + UEdGraphNode* InputNode = (InputPin != nullptr) ? InputPin->GetOwningNode() : nullptr; + if (auto* OutputRerouteNode = Cast(OutputNode)) + { + if (ShouldChangeTangentForReroute(OutputRerouteNode)) + { + Params.StartDirection = EGPD_Input; + } + } + + if (auto* InputRerouteNode = Cast(InputNode)) + { + if (ShouldChangeTangentForReroute(InputRerouteNode)) + { + Params.EndDirection = EGPD_Output; + } + } + } + if (OutputPin->bOrphanedPin || (InputPin && InputPin->bOrphanedPin)) { Params.WireColor = FLinearColor::Red; @@ -258,3 +281,89 @@ FVector2D FFlowGraphConnectionDrawingPolicy::GetControlPoint(const FVector2D& So return FVector2D(Target.X, Source.Y - SlopeHeight); } + +bool FFlowGraphConnectionDrawingPolicy::ShouldChangeTangentForReroute(UFlowGraphNode_Reroute* Reroute) +{ + if (bool* pResult = RerouteToReversedDirectionMap.Find(Reroute)) + { + return *pResult; + } + else + { + bool bPinReversed = false; + + FVector2D AverageLeftPin; + FVector2D AverageRightPin; + FVector2D CenterPin; + bool bCenterValid = Reroute->OutputPins.Num() == 0 ? false : FindPinCenter(Reroute->OutputPins[0], /*out*/ CenterPin); + bool bLeftValid = GetAverageConnectedPosition(Reroute, EGPD_Input, /*out*/ AverageLeftPin); + bool bRightValid = GetAverageConnectedPosition(Reroute, EGPD_Output, /*out*/ AverageRightPin); + + if (bLeftValid && bRightValid) + { + bPinReversed = AverageRightPin.X < AverageLeftPin.X; + } + else if (bCenterValid) + { + if (bLeftValid) + { + bPinReversed = CenterPin.X < AverageLeftPin.X; + } + else if (bRightValid) + { + bPinReversed = AverageRightPin.X < CenterPin.X; + } + } + + RerouteToReversedDirectionMap.Add(Reroute, bPinReversed); + + return bPinReversed; + } +} + +bool FFlowGraphConnectionDrawingPolicy::FindPinCenter(UEdGraphPin* Pin, FVector2D& OutCenter) const +{ + if (const TSharedPtr* pPinWidget = PinToPinWidgetMap.Find(Pin)) + { + if (FArrangedWidget* pPinEntry = PinGeometries->Find((*pPinWidget).ToSharedRef())) + { + OutCenter = FGeometryHelper::CenterOf(pPinEntry->Geometry); + return true; + } + } + + return false; +} + +bool FFlowGraphConnectionDrawingPolicy::GetAverageConnectedPosition(UFlowGraphNode_Reroute* Reroute, EEdGraphPinDirection Direction, FVector2D& OutPos) const +{ + FVector2D Result = FVector2D::ZeroVector; + int32 ResultCount = 0; + + if(Reroute->InputPins.Num() == 0 || Reroute->OutputPins.Num() == 0) + { + return false; + } + + UEdGraphPin* Pin = (Direction == EGPD_Input) ? Reroute->InputPins[0] : Reroute->OutputPins[0]; + for (UEdGraphPin* LinkedPin : Pin->LinkedTo) + { + FVector2D CenterPoint; + if (FindPinCenter(LinkedPin, /*out*/ CenterPoint)) + { + Result += CenterPoint; + ResultCount++; + } + } + + if (ResultCount > 0) + { + OutPos = Result * (1.0f / ResultCount); + return true; + } + else + { + return false; + } +} + diff --git a/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h b/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h index 0893d30e8..c940adfc4 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h @@ -45,6 +45,9 @@ class FLOWEDITOR_API FFlowGraphConnectionDrawingPolicy : public FConnectionDrawi TMap RecordedPaths; TMap SelectedPaths; + //Used to help reversing pins on nodes that go backwards + TMap RerouteToReversedDirectionMap; + public: FFlowGraphConnectionDrawingPolicy(int32 InBackLayerID, int32 InFrontLayerID, float ZoomFactor, const FSlateRect& InClippingRect, FSlateWindowElementList& InDrawElements, UEdGraph* InGraphObj); @@ -60,4 +63,8 @@ class FLOWEDITOR_API FFlowGraphConnectionDrawingPolicy : public FConnectionDrawi void DrawCircuitSpline(const int32& LayerId, const FVector2D& Start, const FVector2D& End, const FConnectionParams& Params) const; void DrawCircuitConnection(const int32& LayerId, const FVector2D& Start, const FVector2D& StartDirection, const FVector2D& End, const FVector2D& EndDirection, const FConnectionParams& Params) const; static FVector2D GetControlPoint(const FVector2D& Source, const FVector2D& Target); + + bool ShouldChangeTangentForReroute(class UFlowGraphNode_Reroute* Reroute); + bool FindPinCenter(UEdGraphPin* Pin, FVector2D& OutCenter) const; + bool GetAverageConnectedPosition(class UFlowGraphNode_Reroute* Reroute, EEdGraphPinDirection Direction, FVector2D& OutPos) const; }; From ca06b5be9f59673fe0584d0df72271d61861ccc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 9 Oct 2022 16:19:21 +0200 Subject: [PATCH 157/338] redundant include removed --- Source/FlowEditor/Private/FlowEditorCommands.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Source/FlowEditor/Private/FlowEditorCommands.cpp b/Source/FlowEditor/Private/FlowEditorCommands.cpp index 863c9c75a..8b2a42aa7 100644 --- a/Source/FlowEditor/Private/FlowEditorCommands.cpp +++ b/Source/FlowEditor/Private/FlowEditorCommands.cpp @@ -3,7 +3,6 @@ #include "FlowEditorCommands.h" #include "FlowEditorStyle.h" -#include "Graph/FlowGraphSchema.h" #include "Graph/FlowGraphSchema_Actions.h" #include "Nodes/FlowNode.h" From 7559cbf837d2fe39f3ee321120f8f23f1df64833 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 9 Oct 2022 16:19:48 +0200 Subject: [PATCH 158/338] moved icon from 5.1 to plugin resources --- Resources/Icons/Refresh.png | Bin 0 -> 5742 bytes Source/FlowEditor/Private/FlowEditorStyle.cpp | 7 +++---- 2 files changed, 3 insertions(+), 4 deletions(-) create mode 100644 Resources/Icons/Refresh.png diff --git a/Resources/Icons/Refresh.png b/Resources/Icons/Refresh.png new file mode 100644 index 0000000000000000000000000000000000000000..4bf3091f3ec3eaae54b613fa17358b1b4f8a0e0f GIT binary patch literal 5742 zcmV-!7LnKLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z000Y_Nkl>oyMo zQZz`L1O;56D2f7cfg){Cw{99g6ire$X=A``8pp1ST9)ldc4$Si7E82DEtVx~BPkB| z8Im(|mvc@ZW=K&MRoFluf*=RDz`ek|=l;&O{Ll9tVT|Dyc}RZ2$FBf?=>hHe4-Jc! z01$-%&F#zCw)1zfq$XXLrmilHj(no1DAMWL?yjz`UD<5ru2{@n>UmzBW82dAi&HA{ z`=5R3tsnI4+w;Qmwr0}FINh5z6DdV;riksh1VMn-29QKi1W1ImP)bwCPx8u3&ti<> z-05RC0^Vw9rBTY%w6?W>adCU|mm0E}jh<%rIM+eU&ki?RS z`c$g6J&ZI_WU6roS{oe4O*J+&?XItH+}+W+@~@|-r;p_elZQ{e*ZaIN`sW~S223O~ z7-I+=pPjou|5xkRuKco!3|fGc1}ViHnAV2;REhENNy_C?!Ex-!cH*g_;i1!Ed3wUw z32fV59*cRIFw`hzFb0ePZ7Q&{&#q%Tj+@vzIMnZ)JbCsNr4+X9ERe;`T?BrK+tzJ) z^fM1V_UB=sD={VwQVU#Hpp@a{xr@AW{KUog&-VTJ>Xq|*E!6u!f-y2L7R#dg@7E zNGUL~;?k>wqwIbC&FJ*IJzqr!&v>p!NQ7nCl@$w7(XyE$3X51GC9>JZ4N)`;c-^JO z7_S_3>^wN;4CbXC|;Mi$!g#X>46}vjtP>?ABB&-5EyLt!F|*@2L+M8SOt%7`yyrJeej8 zX0YA(oE(LrPco4NqYy%(R7AWc(H`@>I;ARZ9UL0h$wWeWo`cqvm{dy8(b2iNxo!Ez z{P@suX;l{OdNm8XINQ*&86+`C@9h9j^32NQ!ADX!f{GL^-$Y_!oBt;MOnW8W=Ij-Pft zFS0BP75U@_FZK)$4h^@pwlvLpNo%N0rj|L5*BFK6+f zDV4u^`TWI}mgXi^jYEOJcHCsFrZ!tHnmIrr7T8ImFw|PlT2Nvz#A?HJ0cly- zj?0xZeH`ES;teYegEFJJOH7UpQkQMPc4JKCN14tK1A^%X*&w0io|NSY$*|z-aC= zqq)oTBuG-p4nz)p0 zShQAYjT8b)3M?atC6a4G-|q^_r4I)$oMoi{(kH5ljnP~_e~dL7?{BP4WtS>#h_uES zgAjrs48p-HXQs==Df%zI%ljwaM5*v*3yut5J>1@L+k;wb3<9Gd9)Oj! z?CA@=M;2nJsa^>n4tVqCRzMK=r4P%+sk^cbEp=fKqLjj5kkTRug8aAQ2z&e{S9~jr6r}nXcSO0qcDzS$;vw)?>n&n-zJ6!Cjkp+1loXBpsosKEzsu( zAOiI2JMQ_DL?THL2F&*3(sH?S>FkA`SH2g8LCFEaTQ*IF$&nLdBLk-q0&O(fXi9}L zu|VQDiOywf?*2Bg1b7JeEU*RW0MbAVaH?|}Kv&@maA?iO`*(NWwd>O=s#s5JjnW!z z;KbW|u7*MB0pPcQ2Y{|wHhE(vmZD4Nd%s)JCymjDnR0+#itvnNm^FWsNcv}Aw!!ngi) zDnI-h&@Y6Xk(PyJIk;Y&nq)o6R09o*I%wt)IcRsbGy(v*D`6yMD7YwddL+{bo zPEHp_azH&ZvLjU}>Qtn_85#*F`wFGB4*i+)MymlKW$2en8OMz+tEq|AH)K3KM=&u_A_$|o-2nuS8{Hsyid#5YT%|z<44xr|!~noLvup?T4FpJofp(FV1VI3=Q>hGMNO9<4`PX z%D$meqCw2Fh!o%g-Es?Zu~mSPe5-b?ZUk#4Q2EM@k7H zME!3(^7v1--TQ@mq9{PCXbut}QR9$Gdc-^%DJ9w%!bmYSw(arO z>(9RP>I>igcVl!^l_skigKq#s9~-cmsoOT){pb_-Jn#p*Qgsbh;1??;xe$Orsp~sJ z<%4R^EN`r~U9W~xaf&zh{L9Y{?tAv-stnoHe+&aZ2hPoJj6V+G>@KmTp}F(X?f3oO zXI5?4(dl|Ms3<^dRfYTLsssp-(#E!3lnOb2=J2_mz2EQYzx3X@s%Bb15jYPV1+Ff1 zc<^xmsS5B4U~|jj)w{a4es){O^6vJ!`WD-9V=QF&C<>U)j|TmhPF?Fg{6BjyoH_J7 zFg8!bT_9ftE8psL4&7%Gfh z`|w(B;Dd|BnaOKa2`K=Vfs+ea>;DUI{;+@)kgZ;I)j|Ov07_NSEdZ0%`|?ePFP{YP gS0}8$jDY_;0Aw{4pa(fKg8%>k07*qoM6N<$g6|Lo761SM literal 0 HcmV?d00001 diff --git a/Source/FlowEditor/Private/FlowEditorStyle.cpp b/Source/FlowEditor/Private/FlowEditorStyle.cpp index ab4046e05..e5954617e 100644 --- a/Source/FlowEditor/Private/FlowEditorStyle.cpp +++ b/Source/FlowEditor/Private/FlowEditorStyle.cpp @@ -30,9 +30,6 @@ void FFlowEditorStyle::Initialize() // engine assets StyleSet->SetContentRoot(FPaths::EngineContentDir() / TEXT("Editor/Slate/")); - StyleSet->Set("FlowToolbar.RefreshAsset", new IMAGE_BRUSH("Automation/RefreshTests", Icon40)); - StyleSet->Set("FlowToolbar.RefreshAsset.Small", new IMAGE_BRUSH("Automation/RefreshTests", Icon20)); - StyleSet->Set("FlowToolbar.GoToMasterInstance", new IMAGE_BRUSH("Icons/icon_DebugStepOut_40x", Icon40)); StyleSet->Set("FlowToolbar.GoToMasterInstance.Small", new IMAGE_BRUSH("Icons/icon_DebugStepOut_40x", Icon20)); @@ -41,7 +38,7 @@ void FFlowEditorStyle::Initialize() StyleSet->Set("FlowGraph.BreakpointHit", new IMAGE_BRUSH("Old/Kismet2/IP_Breakpoint", Icon40)); StyleSet->Set("FlowGraph.PinBreakpointHit", new IMAGE_BRUSH("Old/Kismet2/IP_Breakpoint", Icon30)); - StyleSet->Set( "GraphEditor.Sequence_16x", new IMAGE_BRUSH("Icons/icon_Blueprint_Sequence_16x", Icon16)); + StyleSet->Set("GraphEditor.Sequence_16x", new IMAGE_BRUSH("Icons/icon_Blueprint_Sequence_16x", Icon16)); // Flow assets StyleSet->SetContentRoot(IPluginManager::Get().FindPlugin(TEXT("Flow"))->GetBaseDir() / TEXT("Resources")); @@ -49,6 +46,8 @@ void FFlowEditorStyle::Initialize() StyleSet->Set("ClassIcon.FlowAsset", new IMAGE_BRUSH(TEXT("Icons/FlowAsset_16x"), Icon16)); StyleSet->Set("ClassThumbnail.FlowAsset", new IMAGE_BRUSH(TEXT("Icons/FlowAsset_64x"), Icon64)); + StyleSet->Set("FlowToolbar.RefreshAsset", new IMAGE_BRUSH("Icons/Refresh", Icon40)); + StyleSet->Set("Flow.Node.Title", new BOX_BRUSH("Icons/FlowNode_Title", FMargin(8.0f/64.0f, 0, 0, 0))); StyleSet->Set("Flow.Node.Body", new BOX_BRUSH("Icons/FlowNode_Body", FMargin(16.f/64.f))); StyleSet->Set("Flow.Node.ActiveShadow", new BOX_BRUSH("Icons/FlowNode_Shadow_Active", FMargin(18.0f/64.0f))); From ac8ab262ad891cd0d58f316c99ab8c9c87596f16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 14 Oct 2022 21:40:55 +0200 Subject: [PATCH 159/338] #105 implemented visual Diff: properties, graph it requires engine modification to work https://github.com/MothCocoon/FlowGraph/wiki/Visual-Diff --- Source/FlowEditor/FlowEditor.Build.cs | 2 + .../Asset/AssetTypeActions_FlowAsset.cpp | 24 +- .../Private/Asset/FlowAssetToolbar.cpp | 120 ++- .../Private/Asset/FlowDiffControl.cpp | 193 ++++ .../Private/Asset/SAssetRevisionMenu.cpp | 236 +++++ Source/FlowEditor/Private/Asset/SFlowDiff.cpp | 862 ++++++++++++++++++ .../Public/Asset/AssetTypeActions_FlowAsset.h | 10 + .../Public/Asset/FlowAssetToolbar.h | 4 +- .../FlowEditor/Public/Asset/FlowDiffControl.h | 73 ++ .../Public/Asset/SAssetRevisionMenu.h | 53 ++ Source/FlowEditor/Public/Asset/SFlowDiff.h | 224 +++++ Source/FlowEditor/Public/FlowEditorDefines.h | 9 + 12 files changed, 1801 insertions(+), 9 deletions(-) create mode 100644 Source/FlowEditor/Private/Asset/FlowDiffControl.cpp create mode 100644 Source/FlowEditor/Private/Asset/SAssetRevisionMenu.cpp create mode 100644 Source/FlowEditor/Private/Asset/SFlowDiff.cpp create mode 100644 Source/FlowEditor/Public/Asset/FlowDiffControl.h create mode 100644 Source/FlowEditor/Public/Asset/SAssetRevisionMenu.h create mode 100644 Source/FlowEditor/Public/Asset/SFlowDiff.h create mode 100644 Source/FlowEditor/Public/FlowEditorDefines.h diff --git a/Source/FlowEditor/FlowEditor.Build.cs b/Source/FlowEditor/FlowEditor.Build.cs index 9623bb4ab..3f1c9ae2f 100644 --- a/Source/FlowEditor/FlowEditor.Build.cs +++ b/Source/FlowEditor/FlowEditor.Build.cs @@ -32,6 +32,7 @@ public FlowEditor(ReadOnlyTargetRules Target) : base(Target) "InputCore", "Json", "JsonUtilities", + "Kismet", "KismetWidgets", "LevelEditor", "MovieScene", @@ -43,6 +44,7 @@ public FlowEditor(ReadOnlyTargetRules Target) : base(Target) "Sequencer", "Slate", "SlateCore", + "SourceControl", "ToolMenus", "UnrealEd" }); diff --git a/Source/FlowEditor/Private/Asset/AssetTypeActions_FlowAsset.cpp b/Source/FlowEditor/Private/Asset/AssetTypeActions_FlowAsset.cpp index 576cfabef..a9edee225 100644 --- a/Source/FlowEditor/Private/Asset/AssetTypeActions_FlowAsset.cpp +++ b/Source/FlowEditor/Private/Asset/AssetTypeActions_FlowAsset.cpp @@ -1,6 +1,7 @@ // Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors #include "Asset/AssetTypeActions_FlowAsset.h" +#include "Asset/SFlowDiff.h" #include "FlowEditorModule.h" #include "Graph/FlowGraphSettings.h" @@ -33,10 +34,31 @@ void FAssetTypeActions_FlowAsset::OpenAssetEditor(const TArray& InObje { if (UFlowAsset* FlowAsset = Cast(*ObjIt)) { - FFlowEditorModule* FlowModule = &FModuleManager::LoadModuleChecked("FlowEditor"); + const FFlowEditorModule* FlowModule = &FModuleManager::LoadModuleChecked("FlowEditor"); FlowModule->CreateFlowAssetEditor(Mode, EditWithinLevelEditor, FlowAsset); } } } +/** + * Documentation: https://github.com/MothCocoon/FlowGraph/wiki/Visual-Diff + * Set macro value to 1, if you made these changes to the engine: https://github.com/EpicGames/UnrealEngine/pull/9659 + */ +#if ENABLE_FLOW_DIFF +void FAssetTypeActions_FlowAsset::PerformAssetDiff(UObject* OldAsset, UObject* NewAsset, const FRevisionInfo& OldRevision, const FRevisionInfo& NewRevision) const +{ + const UFlowAsset* OldFlow = CastChecked(OldAsset); + const UFlowAsset* NewFlow = CastChecked(NewAsset); + + // sometimes we're comparing different revisions of one single asset (other + // times we're comparing two completely separate assets altogether) + const bool bIsSingleAsset = (OldFlow->GetName() == NewFlow->GetName()); + + static const FText BasicWindowTitle = LOCTEXT("FlowAssetDiff", "FlowAsset Diff"); + const FText WindowTitle = !bIsSingleAsset ? BasicWindowTitle : FText::Format(LOCTEXT("FlowAsset Diff", "{0} - FlowAsset Diff"), FText::FromString(NewFlow->GetName())); + + SFlowDiff::CreateDiffWindow(WindowTitle, OldFlow, NewFlow, OldRevision, NewRevision); +} +#endif + #undef LOCTEXT_NAMESPACE diff --git a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp index 99259929d..75a0c78b2 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp @@ -1,8 +1,11 @@ // Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors #include "Asset/FlowAssetToolbar.h" + #include "Asset/FlowAssetEditor.h" +#include "Asset/SAssetRevisionMenu.h" #include "FlowEditorCommands.h" +#include "FlowEditorDefines.h" #include "FlowAsset.h" @@ -16,6 +19,12 @@ #include "Widgets/SBoxPanel.h" #include "Widgets/Text/STextBlock.h" +#include "AssetToolsModule.h" +#include "IAssetTypeActions.h" +#include "ISourceControlModule.h" +#include "ISourceControlProvider.h" +#include "SourceControlHelpers.h" + #define LOCTEXT_NAMESPACE "FlowDebuggerToolbar" ////////////////////////////////////////////////////////////////////////// @@ -38,10 +47,10 @@ void SFlowAssetInstanceList::Construct(const FArguments& InArgs, const TWeakObje .OnGenerateWidget(this, &SFlowAssetInstanceList::OnGenerateWidget) .OnSelectionChanged(this, &SFlowAssetInstanceList::OnSelectionChanged) .Visibility_Static(&FFlowAssetEditor::GetDebuggerVisibility) - [ - SNew(STextBlock) - .Text(this, &SFlowAssetInstanceList::GetSelectedInstanceName) - ]; + [ + SNew(STextBlock) + .Text(this, &SFlowAssetInstanceList::GetSelectedInstanceName) + ]; ChildSlot [ @@ -186,19 +195,116 @@ void FFlowAssetToolbar::BuildAssetToolbar(UToolMenu* ToolbarMenu) const { FToolMenuSection& Section = ToolbarMenu->AddSection("Editing"); Section.InsertPosition = FToolMenuInsert("Asset", EToolMenuInsertType::After); - + Section.AddEntry(FToolMenuEntry::InitToolBarButton(FFlowToolbarCommands::Get().RefreshAsset)); + + /** + * Documentation: https://github.com/MothCocoon/FlowGraph/wiki/Visual-Diff + * Set macro value to 1, if you made these changes to the engine: https://github.com/EpicGames/UnrealEngine/pull/9659 + */ +#if ENABLE_FLOW_DIFF + FToolMenuSection& DiffSection = ToolbarMenu->AddSection("SourceControl"); + DiffSection.InsertPosition = FToolMenuInsert("Asset", EToolMenuInsertType::After); + DiffSection.AddDynamicEntry("SourceControlCommands", FNewToolMenuSectionDelegate::CreateLambda([this](FToolMenuSection& InSection) + { + InSection.InsertPosition = FToolMenuInsert(); + FToolMenuEntry DiffEntry = FToolMenuEntry::InitComboButton( + "Diff", + FUIAction(), + FOnGetContent::CreateRaw(this, &FFlowAssetToolbar::MakeDiffMenu), + LOCTEXT("Diff", "Diff"), + LOCTEXT("FlowAssetEditorDiffToolTip", "Diff against previous revisions"), + FSlateIcon(FAppStyle::Get().GetStyleSetName(), "BlueprintDiff.ToolbarIcon") + ); + DiffEntry.StyleNameOverride = "CalloutToolbar"; + InSection.AddEntry(DiffEntry); + })); +#endif +} + +/** Delegate called to diff a specific revision with the current */ +// Copy from FBlueprintEditorToolbar::OnDiffRevisionPicked +static void OnDiffRevisionPicked(FRevisionInfo const& RevisionInfo, const FString& Filename, TWeakObjectPtr CurrentAsset) +{ + ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider(); + + // Get the SCC state + const FSourceControlStatePtr SourceControlState = SourceControlProvider.GetState(Filename, EStateCacheUsage::Use); + if (SourceControlState.IsValid()) + { + for (int32 HistoryIndex = 0; HistoryIndex < SourceControlState->GetHistorySize(); HistoryIndex++) + { + TSharedPtr Revision = SourceControlState->GetHistoryItem(HistoryIndex); + check(Revision.IsValid()); + if (Revision->GetRevision() == RevisionInfo.Revision) + { + // Get the revision of this package from source control + FString PreviousTempPkgName; + if (Revision->Get(PreviousTempPkgName)) + { + // Try and load that package + UPackage* PreviousTempPkg = LoadPackage(nullptr, *PreviousTempPkgName, LOAD_ForDiff | LOAD_DisableCompileOnLoad); + if (PreviousTempPkg) + { + const FString PreviousAssetName = FPaths::GetBaseFilename(Filename, true); + UObject* PreviousAsset = FindObject(PreviousTempPkg, *PreviousAssetName); + if (PreviousAsset) + { + const FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked(TEXT("AssetTools")); + const FRevisionInfo OldRevision = {Revision->GetRevision(), Revision->GetCheckInIdentifier(), Revision->GetDate()}; + const FRevisionInfo CurrentRevision = {TEXT(""), Revision->GetCheckInIdentifier(), Revision->GetDate()}; + AssetToolsModule.Get().DiffAssets(PreviousAsset, CurrentAsset.Get(), OldRevision, CurrentRevision); + } + } + else + { + FMessageDialog::Open(EAppMsgType::Ok, NSLOCTEXT("SourceControl.HistoryWindow", "UnableToLoadAssets", "Unable to load assets to diff. Content may no longer be supported?")); + } + } + break; + } + } + } +} + +// Variant of FBlueprintEditorToolbar::MakeDiffMenu +TSharedRef FFlowAssetToolbar::MakeDiffMenu() const +{ + if (ISourceControlModule::Get().IsEnabled() && ISourceControlModule::Get().GetProvider().IsAvailable()) + { + UFlowAsset* FlowAsset = FlowAssetEditor.Pin()->GetFlowAsset(); + if (FlowAsset) + { + FString Filename = SourceControlHelpers::PackageFilename(FlowAsset->GetPathName()); + TWeakObjectPtr AssetPtr = FlowAsset; + + // Add our async SCC task widget + return SNew(SAssetRevisionMenu, Filename) + .OnRevisionSelected_Static(&OnDiffRevisionPicked, AssetPtr); + } + else + { + // if asset is null then this means that multiple assets are selected + FMenuBuilder MenuBuilder(true, nullptr); + MenuBuilder.AddMenuEntry(LOCTEXT("NoRevisionsForMultipleFlowAssets", "Multiple Flow Assets selected"), FText(), FSlateIcon(), FUIAction()); + return MenuBuilder.MakeWidget(); + } + } + + FMenuBuilder MenuBuilder(true, nullptr); + MenuBuilder.AddMenuEntry(LOCTEXT("SourceControlDisabled", "Source control is disabled"), FText(), FSlateIcon(), FUIAction()); + return MenuBuilder.MakeWidget(); } void FFlowAssetToolbar::BuildDebuggerToolbar(UToolMenu* ToolbarMenu) { FToolMenuSection& Section = ToolbarMenu->AddSection("Debugging"); Section.InsertPosition = FToolMenuInsert("Asset", EToolMenuInsertType::After); - + FPlayWorldCommands::BuildToolbar(Section); TWeakObjectPtr TemplateAsset = FlowAssetEditor.Pin()->GetFlowAsset(); - + AssetInstanceList = SNew(SFlowAssetInstanceList, TemplateAsset); Section.AddEntry(FToolMenuEntry::InitWidget("AssetInstances", AssetInstanceList.ToSharedRef(), FText(), true)); diff --git a/Source/FlowEditor/Private/Asset/FlowDiffControl.cpp b/Source/FlowEditor/Private/Asset/FlowDiffControl.cpp new file mode 100644 index 000000000..cd68d6502 --- /dev/null +++ b/Source/FlowEditor/Private/Asset/FlowDiffControl.cpp @@ -0,0 +1,193 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#include "Asset/FlowDiffControl.h" + +/** + * Documentation: https://github.com/MothCocoon/FlowGraph/wiki/Visual-Diff + * Set macro value to 1, if you made these changes to the engine: https://github.com/EpicGames/UnrealEngine/pull/9659 + */ + +#if ENABLE_FLOW_DIFF +#include "Asset/SFlowDiff.h" + +#include "FlowAsset.h" + +#include "GraphDiffControl.h" +#include "SBlueprintDiff.h" + +#define LOCTEXT_NAMESPACE "SFlowDiffControl" + +///////////////////////////////////////////////////////////////////////////// +/// FFlowAssetDiffControl + +FFlowAssetDiffControl::FFlowAssetDiffControl(const UFlowAsset* InOldFlowAsset, const UFlowAsset* InNewFlowAsset, FOnDiffEntryFocused InSelectionCallback) + : TDetailsDiffControl(InOldFlowAsset, InNewFlowAsset, InSelectionCallback) +{ +} + +// TDetailsDiffControl::GenerateTreeEntries + "NoDifferences" entry + category label +void FFlowAssetDiffControl::GenerateTreeEntries(TArray>& OutTreeEntries, TArray>& OutRealDifferences) +{ + TDetailsDiffControl::GenerateTreeEntries(OutTreeEntries, OutRealDifferences); + + const bool bHasDifferences = Children.Num() != 0; + if (!bHasDifferences) + { + // make one child informing the user that there are no differences: + Children.Push(FBlueprintDifferenceTreeEntry::NoDifferencesEntry()); + } + + static const FText AssetPropertiesLabel = LOCTEXT("AssetPropertiesLabel", "Properties"); + static const FText AssetPropertiesTooltip = LOCTEXT("AssetPropertiesTooltip", "The list of changes made to Flow Asset properties."); + OutTreeEntries.Push(FBlueprintDifferenceTreeEntry::CreateCategoryEntry( + AssetPropertiesLabel, + AssetPropertiesTooltip, + SelectionCallback, + Children, + bHasDifferences + )); +} + +///////////////////////////////////////////////////////////////////////////// +/// FFlowGraphToDiff + +FFlowGraphToDiff::FFlowGraphToDiff(SFlowDiff* InDiffWidget, UEdGraph* InGraphOld, UEdGraph* InGraphNew, const FRevisionInfo& InRevisionOld, const FRevisionInfo& InRevisionNew) + : FoundDiffs(MakeShared>()) + , DiffWidget(InDiffWidget) + , GraphOld(InGraphOld) + , GraphNew(InGraphNew) + , RevisionOld(InRevisionOld) + , RevisionNew(InRevisionNew) +{ + check(InGraphOld || InGraphNew); + + if (InGraphNew) + { + OnGraphChangedDelegateHandle = InGraphNew->AddOnGraphChangedHandler(FOnGraphChanged::FDelegate::CreateRaw(this, &FFlowGraphToDiff::OnGraphChanged)); + } + + BuildDiffSourceArray(); +} + +FFlowGraphToDiff::~FFlowGraphToDiff() +{ + if (GraphNew) + { + GraphNew->RemoveOnGraphChangedHandler(OnGraphChangedDelegateHandle); + } +} + +void FFlowGraphToDiff::GenerateTreeEntries(TArray>& OutTreeEntries, TArray>& OutRealDifferences) +{ + if (!DiffListSource.IsEmpty()) + { + RealDifferencesStartIndex = OutRealDifferences.Num(); + } + + TArray> Children; + for (const TSharedPtr& Difference : DiffListSource) + { + TSharedPtr ChildEntry = MakeShared( + FOnDiffEntryFocused::CreateRaw(DiffWidget, &SFlowDiff::OnDiffListSelectionChanged, Difference), + FGenerateDiffEntryWidget::CreateSP(Difference.ToSharedRef(), &FDiffResultItem::GenerateWidget)); + Children.Push(ChildEntry); + OutRealDifferences.Push(ChildEntry); + } + + if (Children.Num() == 0) + { + // make one child informing the user that there are no differences: + Children.Push(FBlueprintDifferenceTreeEntry::NoDifferencesEntry()); + } + + const TSharedPtr Entry = MakeShared( + FOnDiffEntryFocused::CreateRaw(DiffWidget, &SFlowDiff::OnGraphSelectionChanged, TSharedPtr(AsShared()), ESelectInfo::Direct), + FGenerateDiffEntryWidget::CreateSP(AsShared(), &FFlowGraphToDiff::GenerateCategoryWidget), + Children); + OutTreeEntries.Push(Entry); +} + +FText FFlowGraphToDiff::GetToolTip() const +{ + if (GraphOld && GraphNew) + { + if (DiffListSource.Num() > 0) + { + return LOCTEXT("ContainsDifferences", "Revisions are different"); + } + else + { + return LOCTEXT("GraphsIdentical", "Revisions appear to be identical"); + } + } + else + { + const UEdGraph* GoodGraph = GraphOld ? GraphOld : GraphNew; + check(GoodGraph); + const FRevisionInfo& Revision = GraphNew ? RevisionOld : RevisionNew; + FText RevisionText = LOCTEXT("CurrentRevision", "Current Revision"); + + if (!Revision.Revision.IsEmpty()) + { + RevisionText = FText::Format(LOCTEXT("Revision Number", "Revision {0}"), FText::FromString(Revision.Revision)); + } + + return FText::Format(LOCTEXT("MissingGraph", "Graph '{0}' missing from {1}"), FText::FromString(GoodGraph->GetName()), RevisionText); + } +} + +TSharedRef FFlowGraphToDiff::GenerateCategoryWidget() const +{ + const UEdGraph* Graph = GraphOld ? GraphOld : GraphNew; + check(Graph); + + FLinearColor Color = (GraphOld && GraphNew) ? DiffViewUtils::Identical() : FLinearColor(0.3f, 0.3f, 1.f); + + const bool bHasDiffs = DiffListSource.Num() > 0; + + if (bHasDiffs) + { + Color = DiffViewUtils::Differs(); + } + + return SNew(SHorizontalBox) + + SHorizontalBox::Slot() + [ + SNew(STextBlock) + .ColorAndOpacity(Color) + .Text(FText::FromString(TEXT("Graph"))) + .ToolTipText(GetToolTip()) + ] + + DiffViewUtils::Box(GraphOld != nullptr, Color) + + DiffViewUtils::Box(GraphNew != nullptr, Color); +} + +void FFlowGraphToDiff::BuildDiffSourceArray() +{ + FoundDiffs->Empty(); + FGraphDiffControl::DiffGraphs(GraphOld, GraphNew, *FoundDiffs); + + struct SortDiff + { + bool operator ()(const FDiffSingleResult& A, const FDiffSingleResult& B) const + { + return A.Diff < B.Diff; + } + }; + + Sort(FoundDiffs->GetData(), FoundDiffs->Num(), SortDiff()); + + DiffListSource.Empty(); + for (const FDiffSingleResult& Diff : *FoundDiffs) + { + DiffListSource.Add(MakeShared(Diff)); + } +} + +void FFlowGraphToDiff::OnGraphChanged(const FEdGraphEditAction& Action) const +{ + DiffWidget->OnGraphChanged(this); +} + +#undef LOCTEXT_NAMESPACE +#endif diff --git a/Source/FlowEditor/Private/Asset/SAssetRevisionMenu.cpp b/Source/FlowEditor/Private/Asset/SAssetRevisionMenu.cpp new file mode 100644 index 000000000..e6b17761f --- /dev/null +++ b/Source/FlowEditor/Private/Asset/SAssetRevisionMenu.cpp @@ -0,0 +1,236 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#include "Asset/SAssetRevisionMenu.h" + +#include "IAssetTypeActions.h" +#include "ISourceControlModule.h" +#include "ISourceControlRevision.h" +#include "SourceControlOperations.h" +#include "Widgets/Images/SThrobber.h" + +#define LOCTEXT_NAMESPACE "SFlowRevisionMenu" + +/** */ +namespace ESourceControlQueryState +{ + enum Type + { + NotQueried, + QueryInProgress, + Queried, + }; +} + +//------------------------------------------------------------------------------ +SAssetRevisionMenu::~SAssetRevisionMenu() +{ + // cancel any operation if this widget is destroyed while in progress + if (SourceControlQueryState == ESourceControlQueryState::QueryInProgress) + { + ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider(); + if (SourceControlQueryOp.IsValid() && SourceControlProvider.CanCancelOperation(SourceControlQueryOp.ToSharedRef())) + { + SourceControlProvider.CancelOperation(SourceControlQueryOp.ToSharedRef()); + } + } +} + +//------------------------------------------------------------------------------ +void SAssetRevisionMenu::Construct(const FArguments& InArgs, const FString& InFilename) +{ + bIncludeLocalRevision = InArgs._bIncludeLocalRevision; + OnRevisionSelected = InArgs._OnRevisionSelected; + + SourceControlQueryState = ESourceControlQueryState::NotQueried; + + ChildSlot + [ + SAssignNew(MenuBox, SVerticalBox) + + SVerticalBox::Slot() + [ + SNew(SBorder) + .Visibility(this, &SAssetRevisionMenu::GetInProgressVisibility) + .BorderImage(FAppStyle::GetBrush("Menu.Background")) + .Content() + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + .VAlign(VAlign_Center) + [ + SNew(SThrobber) + ] + + SHorizontalBox::Slot() + .AutoWidth() + .VAlign(VAlign_Center) + .Padding(2.0f, 0.0f, 4.0f, 0.0f) + [ + SNew(STextBlock) + .Text(LOCTEXT("DiffMenuOperationInProgress", "Updating history...")) + ] + + SHorizontalBox::Slot() + .FillWidth(1.0f) + .HAlign(HAlign_Right) + .VAlign(VAlign_Center) + [ + SNew(SButton) + .Visibility(this, &SAssetRevisionMenu::GetCancelButtonVisibility) + .OnClicked(this, &SAssetRevisionMenu::OnCancelButtonClicked) + .VAlign(VAlign_Center) + .HAlign(HAlign_Center) + .Content() + [ + SNew(STextBlock) + .Text(LOCTEXT("DiffMenuCancelButton", "Cancel")) + ] + ] + ] + ] + ]; + + Filename = InFilename; + if (!Filename.IsEmpty()) + { + // make sure the history info is up to date + SourceControlQueryOp = ISourceControlOperation::Create(); + SourceControlQueryOp->SetUpdateHistory(true); + ISourceControlModule::Get().GetProvider().Execute(SourceControlQueryOp.ToSharedRef(), Filename, EConcurrency::Asynchronous, FSourceControlOperationComplete::CreateSP(this, &SAssetRevisionMenu::OnSourceControlQueryComplete)); + + SourceControlQueryState = ESourceControlQueryState::QueryInProgress; + } +} + +//------------------------------------------------------------------------------ +EVisibility SAssetRevisionMenu::GetInProgressVisibility() const +{ + return (SourceControlQueryState == ESourceControlQueryState::QueryInProgress) ? EVisibility::Visible : EVisibility::Collapsed; +} + +//------------------------------------------------------------------------------ +EVisibility SAssetRevisionMenu::GetCancelButtonVisibility() const +{ + const ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider(); + return SourceControlQueryOp.IsValid() && SourceControlProvider.CanCancelOperation(SourceControlQueryOp.ToSharedRef()) ? EVisibility::Visible : EVisibility::Collapsed; +} + +//------------------------------------------------------------------------------ +FReply SAssetRevisionMenu::OnCancelButtonClicked() const +{ + if (SourceControlQueryOp.IsValid()) + { + ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider(); + SourceControlProvider.CancelOperation(SourceControlQueryOp.ToSharedRef()); + } + + return FReply::Handled(); +} + +//------------------------------------------------------------------------------ +void SAssetRevisionMenu::OnSourceControlQueryComplete(const FSourceControlOperationRef& InOperation, ECommandResult::Type InResult) +{ + check(SourceControlQueryOp == InOperation); + + + // Add pop-out menu for each revision + FMenuBuilder MenuBuilder(/*bInShouldCloseWindowAfterMenuSelection =*/true, /*InCommandList =*/nullptr); + + MenuBuilder.BeginSection("AddDiffRevision", LOCTEXT("Revisions", "Revisions")); + if (bIncludeLocalRevision) + { + FText const ToolTipText = LOCTEXT("LocalRevisionToolTip", "The current copy you have saved to disk (locally)"); + + FOnRevisionSelected OnRevisionSelectedDelegate = OnRevisionSelected; + auto OnMenuItemSelected = [OnRevisionSelectedDelegate, this]() + { + OnRevisionSelectedDelegate.ExecuteIfBound(FRevisionInfo::InvalidRevision(), Filename); + }; + + MenuBuilder.AddMenuEntry(LOCTEXT("LocalRevision", "Local"), ToolTipText, FSlateIcon(), FUIAction(FExecuteAction::CreateLambda(OnMenuItemSelected))); + } + + if (InResult == ECommandResult::Succeeded) + { + // get the cached state + ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider(); + FSourceControlStatePtr SourceControlState = SourceControlProvider.GetState(Filename, EStateCacheUsage::Use); + + if (SourceControlState.IsValid() && SourceControlState->GetHistorySize() > 0) + { + // Figure out the highest revision # (so we can label it "Depot") + int32 LatestRevision = 0; + for (int32 HistoryIndex = 0; HistoryIndex < SourceControlState->GetHistorySize(); HistoryIndex++) + { + TSharedPtr Revision = SourceControlState->GetHistoryItem(HistoryIndex); + if (Revision.IsValid() && Revision->GetRevisionNumber() > LatestRevision) + { + LatestRevision = Revision->GetRevisionNumber(); + } + } + + for (int32 HistoryIndex = 0; HistoryIndex < SourceControlState->GetHistorySize(); HistoryIndex++) + { + TSharedPtr Revision = SourceControlState->GetHistoryItem(HistoryIndex); + if (Revision.IsValid()) + { + FInternationalization& I18N = FInternationalization::Get(); + + FText Label = FText::Format(LOCTEXT("RevisionNumber", "Revision {0}"), FText::AsNumber(Revision->GetRevisionNumber(), nullptr, I18N.GetInvariantCulture())); + + FFormatNamedArguments Args; + Args.Add(TEXT("CheckInNumber"), FText::AsNumber(Revision->GetCheckInIdentifier(), nullptr, I18N.GetInvariantCulture())); + Args.Add(TEXT("Revision"), FText::FromString(Revision->GetRevision())); + Args.Add(TEXT("UserName"), FText::FromString(Revision->GetUserName())); + Args.Add(TEXT("DateTime"), FText::AsDate(Revision->GetDate())); + Args.Add(TEXT("ChanglistDescription"), FText::FromString(Revision->GetDescription())); + FText ToolTipText; + if (ISourceControlModule::Get().GetProvider().UsesChangelists()) + { + ToolTipText = FText::Format(LOCTEXT("ChangelistToolTip", "CL #{CheckInNumber} {UserName} \n{DateTime} \n{ChanglistDescription}"), Args); + } + else + { + ToolTipText = FText::Format(LOCTEXT("RevisionToolTip", "{Revision} {UserName} \n{DateTime} \n{ChanglistDescription}"), Args); + } + + if (LatestRevision == Revision->GetRevisionNumber()) + { + Label = LOCTEXT("Depo", "Depot"); + } + + FRevisionInfo RevisionInfo = { + Revision->GetRevision(), + Revision->GetCheckInIdentifier(), + Revision->GetDate() + }; + FOnRevisionSelected OnRevisionSelectedDelegate = OnRevisionSelected; + auto OnMenuItemSelected = [RevisionInfo, OnRevisionSelectedDelegate, this]() + { + OnRevisionSelectedDelegate.ExecuteIfBound(RevisionInfo, Filename); + }; + MenuBuilder.AddMenuEntry(TAttribute(Label), ToolTipText, FSlateIcon(), FUIAction(FExecuteAction::CreateLambda(OnMenuItemSelected))); + } + } + } + else if (!bIncludeLocalRevision) + { + // Show 'empty' item in toolbar + MenuBuilder.AddMenuEntry(LOCTEXT("NoRevisonHistory", "No revisions found"), FText(), FSlateIcon(), FUIAction()); + } + } + else if (!bIncludeLocalRevision) + { + // Show 'empty' item in toolbar + MenuBuilder.AddMenuEntry(LOCTEXT("NoRevisonHistory", "No revisions found"), FText(), FSlateIcon(), FUIAction()); + } + + MenuBuilder.EndSection(); + MenuBox->AddSlot() + [ + MenuBuilder.MakeWidget(nullptr, 500) + ]; + + SourceControlQueryOp.Reset(); + SourceControlQueryState = ESourceControlQueryState::Queried; +} + +#undef LOCTEXT_NAMESPACE diff --git a/Source/FlowEditor/Private/Asset/SFlowDiff.cpp b/Source/FlowEditor/Private/Asset/SFlowDiff.cpp new file mode 100644 index 000000000..ec58621f1 --- /dev/null +++ b/Source/FlowEditor/Private/Asset/SFlowDiff.cpp @@ -0,0 +1,862 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +/** + * Documentation: https://github.com/MothCocoon/FlowGraph/wiki/Visual-Diff + * Set macro value to 1, if you made these changes to the engine: https://github.com/EpicGames/UnrealEngine/pull/9659 + */ + +#include "Asset/SFlowDiff.h" + +#if ENABLE_FLOW_DIFF +#include "Asset/FlowDiffControl.h" + +#include "FlowAsset.h" + +#include "EdGraphUtilities.h" +#include "Framework/Commands/GenericCommands.h" +#include "GraphDiffControl.h" +#include "HAL/PlatformApplicationMisc.h" +#include "Internationalization/Text.h" +#include "SBlueprintDiff.h" +#include "SlateOptMacros.h" + +#define LOCTEXT_NAMESPACE "SFlowDiff" + +static const FName DetailsMode = FName(TEXT("DetailsMode")); +static const FName GraphMode = FName(TEXT("GraphMode")); + +FFlowDiffPanel::FFlowDiffPanel() + : FlowAsset(nullptr) + , bShowAssetName(false) +{ +} + +static int32 GetCurrentIndex(SListView> const& ListView, const TArray>& ListViewSource) +{ + const TArray>& Selected = ListView.GetSelectedItems(); + if (Selected.Num() == 1) + { + for (const TSharedPtr& Diff : ListViewSource) + { + if (Diff == Selected[0]) + { + return 0; + } + } + } + return -1; +} + +void FlowDiffUtils::SelectNextRow(SListView>& ListView, const TArray>& ListViewSource) +{ + const int32 CurrentIndex = GetCurrentIndex(ListView, ListViewSource); + if (CurrentIndex == ListViewSource.Num() - 1) + { + return; + } + + ListView.SetSelection(ListViewSource[CurrentIndex + 1]); +} + +void FlowDiffUtils::SelectPrevRow(SListView>& ListView, const TArray>& ListViewSource) +{ + const int32 CurrentIndex = GetCurrentIndex(ListView, ListViewSource); + if (CurrentIndex == 0) + { + return; + } + + ListView.SetSelection(ListViewSource[CurrentIndex - 1]); +} + +bool FlowDiffUtils::HasNextDifference(const SListView>& ListView, const TArray>& ListViewSource) +{ + const int32 CurrentIndex = GetCurrentIndex(ListView, ListViewSource); + return ListViewSource.IsValidIndex(CurrentIndex + 1); +} + +bool FlowDiffUtils::HasPrevDifference(const SListView>& ListView, const TArray>& ListViewSource) +{ + const int32 CurrentIndex = GetCurrentIndex(ListView, ListViewSource); + return ListViewSource.IsValidIndex(CurrentIndex - 1); +} + +BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION + +void SFlowDiff::Construct(const FArguments& InArgs) +{ + check(InArgs._OldFlow && InArgs._NewFlow); + PanelOld.FlowAsset = InArgs._OldFlow; + PanelNew.FlowAsset = InArgs._NewFlow; + PanelOld.RevisionInfo = InArgs._OldRevision; + PanelNew.RevisionInfo = InArgs._NewRevision; + + // sometimes we want to clearly identify the assets being diffed (when it's + // not the same asset in each panel) + PanelOld.bShowAssetName = InArgs._ShowAssetNames; + PanelNew.bShowAssetName = InArgs._ShowAssetNames; + + bLockViews = true; + + if (InArgs._ParentWindow.IsValid()) + { + WeakParentWindow = InArgs._ParentWindow; + + AssetEditorCloseDelegate = GEditor->GetEditorSubsystem()->OnAssetEditorRequestClose().AddSP(this, &SFlowDiff::OnCloseAssetEditor); + } + + FToolBarBuilder NavToolBarBuilder(TSharedPtr(), FMultiBoxCustomization::None); + NavToolBarBuilder.AddToolBarButton( + FUIAction( + FExecuteAction::CreateSP(this, &SFlowDiff::PrevDiff), + FCanExecuteAction::CreateSP(this, &SFlowDiff::HasPrevDiff) + ) + , NAME_None + , LOCTEXT("PrevDiffLabel", "Prev") + , LOCTEXT("PrevDiffTooltip", "Go to previous difference") + , FSlateIcon(FAppStyle::GetAppStyleSetName(), "BlueprintDif.PrevDiff") + ); + NavToolBarBuilder.AddToolBarButton( + FUIAction( + FExecuteAction::CreateSP(this, &SFlowDiff::NextDiff), + FCanExecuteAction::CreateSP(this, &SFlowDiff::HasNextDiff) + ) + , NAME_None + , LOCTEXT("NextDiffLabel", "Next") + , LOCTEXT("NextDiffTooltip", "Go to next difference") + , FSlateIcon(FAppStyle::GetAppStyleSetName(), "BlueprintDif.NextDiff") + ); + + FToolBarBuilder GraphToolbarBuilder(TSharedPtr(), FMultiBoxCustomization::None); + GraphToolbarBuilder.AddToolBarButton( + FUIAction(FExecuteAction::CreateSP(this, &SFlowDiff::OnToggleLockView)) + , NAME_None + , LOCTEXT("LockGraphsLabel", "Lock/Unlock") + , LOCTEXT("LockGraphsTooltip", "Force all graph views to change together, or allow independent scrolling/zooming") + , TAttribute(this, &SFlowDiff::GetLockViewImage) + ); + GraphToolbarBuilder.AddToolBarButton( + FUIAction(FExecuteAction::CreateSP(this, &SFlowDiff::OnToggleSplitViewMode)) + , NAME_None + , LOCTEXT("SplitGraphsModeLabel", "Vertical/Horizontal") + , LOCTEXT("SplitGraphsModeLabelTooltip", "Toggles the split view of graphs between vertical and horizontal") + , TAttribute(this, &SFlowDiff::GetSplitViewModeImage) + ); + + DifferencesTreeView = DiffTreeView::CreateTreeView(&PrimaryDifferencesList); + + GenerateDifferencesList(); + + const auto TextBlock = [](FText Text) -> TSharedRef + { + return SNew(SBox) + .Padding(FMargin(4.0f, 10.0f)) + .VAlign(VAlign_Center) + .HAlign(HAlign_Left) + [ + SNew(STextBlock) + .Visibility(EVisibility::HitTestInvisible) + .TextStyle(FAppStyle::Get(), "DetailsView.CategoryTextStyle") + .Text(Text) + ]; + }; + + TopRevisionInfoWidget = + SNew(SSplitter) + .Visibility(EVisibility::HitTestInvisible) + + SSplitter::Slot() + .Value(.2f) + [ + SNew(SBox) + ] + + SSplitter::Slot() + .Value(.8f) + [ + SNew(SSplitter) + .PhysicalSplitterHandleSize(10.0f) + + SSplitter::Slot() + .Value(.5f) + [ + TextBlock(DiffViewUtils::GetPanelLabel(PanelOld.FlowAsset, PanelOld.RevisionInfo, FText())) + ] + + SSplitter::Slot() + .Value(.5f) + [ + TextBlock(DiffViewUtils::GetPanelLabel(PanelNew.FlowAsset, PanelNew.RevisionInfo, FText())) + ] + ]; + + GraphToolBarWidget = + SNew(SSplitter) + .Visibility(EVisibility::HitTestInvisible) + + SSplitter::Slot() + .Value(.2f) + [ + SNew(SBox) + ] + + SSplitter::Slot() + .Value(.8f) + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + [ + GraphToolbarBuilder.MakeWidget() + ] + ]; + + this->ChildSlot + [ + SNew(SBorder) + .BorderImage(FAppStyle::GetBrush("Docking.Tab", ".ContentAreaBrush")) + [ + SNew(SOverlay) + + SOverlay::Slot() + .VAlign(VAlign_Top) + [ + TopRevisionInfoWidget.ToSharedRef() + ] + + SOverlay::Slot() + .VAlign(VAlign_Top) + .Padding(0.0f, 6.0f, 0.0f, 4.0f) + [ + GraphToolBarWidget.ToSharedRef() + ] + + SOverlay::Slot() + [ + SNew(SVerticalBox) + + SVerticalBox::Slot() + .AutoHeight() + .Padding(0.0f, 2.0f, 0.0f, 2.0f) + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .Padding(4.f) + .AutoWidth() + [ + NavToolBarBuilder.MakeWidget() + ] + + SHorizontalBox::Slot() + [ + SNew(SSpacer) + ] + ] + + SVerticalBox::Slot() + [ + SNew(SSplitter) + + SSplitter::Slot() + .Value(.2f) + [ + SNew(SBorder) + .BorderImage(FAppStyle::GetBrush("ToolPanel.GroupBorder")) + [ + DifferencesTreeView.ToSharedRef() + ] + ] + + SSplitter::Slot() + .Value(.8f) + [ + SAssignNew(ModeContents, SBox) + ] + ] + ] + ] + ]; + + SetCurrentMode(DetailsMode); +} + +END_SLATE_FUNCTION_BUILD_OPTIMIZATION + +SFlowDiff::~SFlowDiff() +{ + if (AssetEditorCloseDelegate.IsValid()) + { + GEditor->GetEditorSubsystem()->OnAssetEditorRequestClose().Remove(AssetEditorCloseDelegate); + } +} + +void SFlowDiff::OnCloseAssetEditor(UObject* Asset, const EAssetEditorCloseReason CloseReason) +{ + if (PanelOld.FlowAsset == Asset || PanelNew.FlowAsset == Asset || CloseReason == EAssetEditorCloseReason::CloseAllAssetEditors) + { + // Tell our window to close and set our selves to collapsed to try and stop it from ticking + SetVisibility(EVisibility::Collapsed); + + if (AssetEditorCloseDelegate.IsValid()) + { + GEditor->GetEditorSubsystem()->OnAssetEditorRequestClose().Remove(AssetEditorCloseDelegate); + } + + if (WeakParentWindow.IsValid()) + { + WeakParentWindow.Pin()->RequestDestroyWindow(); + } + } +} + +void SFlowDiff::OnGraphSelectionChanged(const TSharedPtr Item, ESelectInfo::Type SelectionType) +{ + if (!Item.IsValid()) + { + return; + } + + FocusOnGraphRevisions(Item.Get()); +} + +void SFlowDiff::OnGraphChanged(const FFlowGraphToDiff* Diff) +{ + if (PanelNew.GraphEditor.IsValid() && PanelNew.GraphEditor.Pin()->GetCurrentGraph() == Diff->GetGraphNew()) + { + FocusOnGraphRevisions(Diff); + } +} + +TSharedRef SFlowDiff::DefaultEmptyPanel() +{ + return SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .HAlign(HAlign_Center) + .VAlign(VAlign_Center) + [ + SNew(STextBlock) + .Text(LOCTEXT("BlueprintDifGraphsToolTip", "Select Graph to Diff")) + ]; +} + +TSharedPtr SFlowDiff::CreateDiffWindow(const FText WindowTitle, const UFlowAsset* OldFlow, const UFlowAsset* NewFlow, const FRevisionInfo& OldRevision, const FRevisionInfo& NewRevision) +{ + // sometimes we're comparing different revisions of one single asset (other + // times we're comparing two completely separate assets altogether) + const bool bIsSingleAsset = (NewFlow->GetName() == OldFlow->GetName()); + + TSharedPtr Window = SNew(SWindow) + .Title(WindowTitle) + .ClientSize(FVector2D(1000, 800)); + + Window->SetContent(SNew(SFlowDiff) + .OldFlow(OldFlow) + .NewFlow(NewFlow) + .OldRevision(OldRevision) + .NewRevision(NewRevision) + .ShowAssetNames(!bIsSingleAsset) + .ParentWindow(Window)); + + // Make this window a child of the modal window if we've been spawned while one is active. + const TSharedPtr ActiveModal = FSlateApplication::Get().GetActiveModalWindow(); + if (ActiveModal.IsValid()) + { + FSlateApplication::Get().AddWindowAsNativeChild(Window.ToSharedRef(), ActiveModal.ToSharedRef()); + } + else + { + FSlateApplication::Get().AddWindow(Window.ToSharedRef()); + } + + return Window; +} + +void SFlowDiff::NextDiff() const +{ + DiffTreeView::HighlightNextDifference(DifferencesTreeView.ToSharedRef(), RealDifferences, PrimaryDifferencesList); +} + +void SFlowDiff::PrevDiff() const +{ + DiffTreeView::HighlightPrevDifference(DifferencesTreeView.ToSharedRef(), RealDifferences, PrimaryDifferencesList); +} + +bool SFlowDiff::HasNextDiff() const +{ + return DiffTreeView::HasNextDifference(DifferencesTreeView.ToSharedRef(), RealDifferences); +} + +bool SFlowDiff::HasPrevDiff() const +{ + return DiffTreeView::HasPrevDifference(DifferencesTreeView.ToSharedRef(), RealDifferences); +} + +FFlowGraphToDiff* SFlowDiff::FindGraphToDiffEntry(const FString& GraphPath) const +{ + const FString SearchGraphPath = GraphToDiff->GetGraphOld() ? FGraphDiffControl::GetGraphPath(GraphToDiff->GetGraphOld()) : FGraphDiffControl::GetGraphPath(GraphToDiff->GetGraphNew()); + if (SearchGraphPath.Equals(GraphPath, ESearchCase::CaseSensitive)) + { + return GraphToDiff.Get(); + } + + return nullptr; +} + +void SFlowDiff::FocusOnGraphRevisions(const FFlowGraphToDiff* Diff) +{ + UEdGraph* Graph = Diff->GetGraphOld() ? Diff->GetGraphOld() : Diff->GetGraphNew(); + + const FString GraphPath = FGraphDiffControl::GetGraphPath(Graph); + HandleGraphChanged(GraphPath); + + ResetGraphEditors(); +} + +void SFlowDiff::OnDiffListSelectionChanged(TSharedPtr TheDiff) +{ + check(!TheDiff->Result.OwningObjectPath.IsEmpty()); + FocusOnGraphRevisions(FindGraphToDiffEntry(TheDiff->Result.OwningObjectPath)); + const FDiffSingleResult Result = TheDiff->Result; + + const auto SafeClearSelection = [](TWeakPtr GraphEditor) + { + const TSharedPtr GraphEditorPtr = GraphEditor.Pin(); + if (GraphEditorPtr.IsValid()) + { + GraphEditorPtr->ClearSelectionSet(); + } + }; + + SafeClearSelection(PanelNew.GraphEditor); + SafeClearSelection(PanelOld.GraphEditor); + + if (Result.Pin1) + { + GetDiffPanelForNode(*Result.Pin1->GetOwningNode()).FocusDiff(*Result.Pin1); + if (Result.Pin2) + { + GetDiffPanelForNode(*Result.Pin2->GetOwningNode()).FocusDiff(*Result.Pin2); + } + } + else if (Result.Node1) + { + GetDiffPanelForNode(*Result.Node1).FocusDiff(*Result.Node1); + if (Result.Node2) + { + GetDiffPanelForNode(*Result.Node2).FocusDiff(*Result.Node2); + } + } +} + +void SFlowDiff::OnToggleLockView() +{ + bLockViews = !bLockViews; + ResetGraphEditors(); +} + +void SFlowDiff::OnToggleSplitViewMode() +{ + bVerticalSplitGraphMode = !bVerticalSplitGraphMode; + + if (SSplitter* DiffGraphSplitterPtr = DiffGraphSplitter.Get()) + { + DiffGraphSplitterPtr->SetOrientation(bVerticalSplitGraphMode ? Orient_Horizontal : Orient_Vertical); + } +} + +FSlateIcon SFlowDiff::GetLockViewImage() const +{ + return FSlateIcon(FAppStyle::GetAppStyleSetName(), bLockViews ? "Icons.Lock" : "Icons.Unlock"); +} + +FSlateIcon SFlowDiff::GetSplitViewModeImage() const +{ + return FSlateIcon(FAppStyle::GetAppStyleSetName(), bVerticalSplitGraphMode ? "BlueprintDif.VerticalDiff.Small" : "BlueprintDif.HorizontalDiff.Small"); +} + +void SFlowDiff::ResetGraphEditors() const +{ + if (PanelOld.GraphEditor.IsValid() && PanelNew.GraphEditor.IsValid()) + { + if (bLockViews) + { + PanelOld.GraphEditor.Pin()->LockToGraphEditor(PanelNew.GraphEditor); + PanelNew.GraphEditor.Pin()->LockToGraphEditor(PanelOld.GraphEditor); + } + else + { + PanelOld.GraphEditor.Pin()->UnlockFromGraphEditor(PanelNew.GraphEditor); + PanelNew.GraphEditor.Pin()->UnlockFromGraphEditor(PanelOld.GraphEditor); + } + } +} + +void FFlowDiffPanel::GeneratePanel(UEdGraph* NewGraph, UEdGraph* OldGraph) +{ + const TSharedPtr> Diff = MakeShared>(); + FGraphDiffControl::DiffGraphs(OldGraph, NewGraph, *Diff); + GeneratePanel(NewGraph, Diff, {}); +} + +void FFlowDiffPanel::GeneratePanel(UEdGraph* Graph, TSharedPtr> DiffResults, TAttribute FocusedDiffResult) +{ + if (GraphEditor.IsValid() && GraphEditor.Pin()->GetCurrentGraph() == Graph) + { + return; + } + + TSharedPtr Widget = SNew(SBorder) + .HAlign(HAlign_Center) + .VAlign(VAlign_Center) + [ + SNew(STextBlock).Text(LOCTEXT("FlowDiffPanelNoGraphTip", "Graph does not exist in this revision")) + ]; + + if (Graph) + { + SGraphEditor::FGraphEditorEvents InEvents; + { + const auto SelectionChangedHandler = [](const FGraphPanelSelectionSet& SelectionSet, TSharedPtr Container) + { + Container->SetObjects(SelectionSet.Array()); + }; + + const auto ContextMenuHandler = [](UEdGraph* CurrentGraph, const UEdGraphNode* InGraphNode, const UEdGraphPin* InGraphPin, FMenuBuilder* MenuBuilder, bool bIsDebugging) + { + MenuBuilder->AddMenuEntry(FGenericCommands::Get().Copy); + return FActionMenuContent(MenuBuilder->MakeWidget()); + }; + + InEvents.OnSelectionChanged = SGraphEditor::FOnSelectionChanged::CreateStatic(SelectionChangedHandler, DetailsView); + InEvents.OnCreateNodeOrPinMenu = SGraphEditor::FOnCreateNodeOrPinMenu::CreateStatic(ContextMenuHandler); + } + + if (!GraphEditorCommands.IsValid()) + { + GraphEditorCommands = MakeShared(); + + GraphEditorCommands->MapAction(FGenericCommands::Get().Copy, + FExecuteAction::CreateRaw(this, &FFlowDiffPanel::CopySelectedNodes), + FCanExecuteAction::CreateRaw(this, &FFlowDiffPanel::CanCopyNodes) + ); + } + + const TSharedRef Editor = SNew(SGraphEditor) + .AdditionalCommands(GraphEditorCommands) + .GraphToEdit(Graph) + .GraphToDiff(nullptr) + .DiffResults(DiffResults) + .FocusedDiffResult(FocusedDiffResult) + .IsEditable(false) + .GraphEvents(InEvents); + + GraphEditor = Editor; + Widget = Editor; + } + + GraphEditorBox->SetContent(Widget.ToSharedRef()); +} + +FGraphPanelSelectionSet FFlowDiffPanel::GetSelectedNodes() const +{ + FGraphPanelSelectionSet CurrentSelection; + const TSharedPtr FocusedGraphEd = GraphEditor.Pin(); + if (FocusedGraphEd.IsValid()) + { + CurrentSelection = FocusedGraphEd->GetSelectedNodes(); + } + return CurrentSelection; +} + +void FFlowDiffPanel::CopySelectedNodes() const +{ + // Export the selected nodes and place the text on the clipboard + const FGraphPanelSelectionSet SelectedNodes = GetSelectedNodes(); + + FString ExportedText; + FEdGraphUtilities::ExportNodesToText(SelectedNodes, /*out*/ ExportedText); + FPlatformApplicationMisc::ClipboardCopy(*ExportedText); +} + +bool FFlowDiffPanel::CanCopyNodes() const +{ + // If any of the nodes can be duplicated then we should allow copying + const FGraphPanelSelectionSet SelectedNodes = GetSelectedNodes(); + for (FGraphPanelSelectionSet::TConstIterator SelectedIter(SelectedNodes); SelectedIter; ++SelectedIter) + { + const UEdGraphNode* Node = Cast(*SelectedIter); + if ((Node != nullptr) && Node->CanDuplicateNode()) + { + return true; + } + } + return false; +} + +void FFlowDiffPanel::FocusDiff(const UEdGraphPin& Pin) const +{ + GraphEditor.Pin()->JumpToPin(&Pin); +} + +void FFlowDiffPanel::FocusDiff(const UEdGraphNode& Node) const +{ + if (GraphEditor.IsValid()) + { + GraphEditor.Pin()->JumpToNode(&Node, false); + } +} + +FFlowDiffPanel& SFlowDiff::GetDiffPanelForNode(const UEdGraphNode& Node) +{ + const TSharedPtr OldGraphEditorPtr = PanelOld.GraphEditor.Pin(); + if (OldGraphEditorPtr.IsValid() && Node.GetGraph() == OldGraphEditorPtr->GetCurrentGraph()) + { + return PanelOld; + } + + const TSharedPtr NewGraphEditorPtr = PanelNew.GraphEditor.Pin(); + if (NewGraphEditorPtr.IsValid() && Node.GetGraph() == NewGraphEditorPtr->GetCurrentGraph()) + { + return PanelNew; + } + + ensureMsgf(false, TEXT("Looking for node %s but it cannot be found in provided panels"), *Node.GetName()); + static FFlowDiffPanel Default; + return Default; +} + +void SFlowDiff::HandleGraphChanged(const FString& GraphPath) +{ + SetCurrentMode(GraphMode); + + UEdGraph* GraphOld = nullptr; + UEdGraph* GraphNew = nullptr; + TSharedPtr> DiffResults; + int32 RealDifferencesStartIndex = INDEX_NONE; + { + UEdGraph* NewGraph = GraphToDiff->GetGraphNew(); + UEdGraph* OldGraph = GraphToDiff->GetGraphOld(); + const FString OtherGraphPath = NewGraph ? FGraphDiffControl::GetGraphPath(NewGraph) : FGraphDiffControl::GetGraphPath(OldGraph); + if (GraphPath.Equals(OtherGraphPath)) + { + GraphNew = NewGraph; + GraphOld = OldGraph; + DiffResults = GraphToDiff->FoundDiffs; + RealDifferencesStartIndex = GraphToDiff->RealDifferencesStartIndex; + } + } + + const TAttribute FocusedDiffResult = TAttribute::CreateLambda( + [this, RealDifferencesStartIndex]() + { + int32 FocusedDiffResult = INDEX_NONE; + if (RealDifferencesStartIndex != INDEX_NONE) + { + FocusedDiffResult = DiffTreeView::CurrentDifference(DifferencesTreeView.ToSharedRef(), RealDifferences) - RealDifferencesStartIndex; + } + + // find selected index in all the graphs, and subtract the index of the first entry in this graph + return FocusedDiffResult; + }); + + // only regenerate PanelOld if the old graph has changed + if (!PanelOld.GraphEditor.IsValid() || GraphOld != PanelOld.GraphEditor.Pin()->GetCurrentGraph()) + { + PanelOld.GeneratePanel(GraphOld, DiffResults, FocusedDiffResult); + } + + // only regenerate PanelNew if the old graph has changed + if (!PanelNew.GraphEditor.IsValid() || GraphNew != PanelNew.GraphEditor.Pin()->GetCurrentGraph()) + { + PanelNew.GeneratePanel(GraphNew, DiffResults, FocusedDiffResult); + } +} + +void SFlowDiff::GenerateDifferencesList() +{ + PrimaryDifferencesList.Empty(); + RealDifferences.Empty(); + ModePanels.Empty(); + + const auto CreateInspector = [](const UObject* Object) + { + FPropertyEditorModule& EditModule = FModuleManager::Get().GetModuleChecked("PropertyEditor"); + + FNotifyHook* NotifyHook = nullptr; + + FDetailsViewArgs DetailsViewArgs; + DetailsViewArgs.NameAreaSettings = FDetailsViewArgs::HideNameArea; + DetailsViewArgs.bHideSelectionTip = true; + DetailsViewArgs.NotifyHook = NotifyHook; + DetailsViewArgs.ViewIdentifier = FName("ObjectInspector"); + TSharedRef DetailsView = EditModule.CreateDetailView(DetailsViewArgs); + DetailsView->SetObject(const_cast(Object)); + + return DetailsView; + }; + + // TODO: construct DetailsView of PanelOld and PanelNew + PanelOld.DetailsView = CreateInspector(PanelOld.FlowAsset); + PanelNew.DetailsView = CreateInspector(PanelOld.FlowAsset); + + // Now that we have done the diffs, create the panel widgets + ModePanels.Add(DetailsMode, GenerateDetailsPanel()); + ModePanels.Add(GraphMode, GenerateGraphPanel()); + + DifferencesTreeView->RebuildList(); +} + +SFlowDiff::FDiffControl SFlowDiff::GenerateDetailsPanel() +{ + const TSharedPtr NewDiffControl = MakeShared(PanelOld.FlowAsset, PanelNew.FlowAsset, FOnDiffEntryFocused::CreateRaw(this, &SFlowDiff::SetCurrentMode, DetailsMode)); + NewDiffControl->GenerateTreeEntries(PrimaryDifferencesList, RealDifferences); + + SFlowDiff::FDiffControl Ret; + Ret.DiffControl = NewDiffControl; + Ret.Widget = SNew(SSplitter) + .PhysicalSplitterHandleSize(10.0f) + + SSplitter::Slot() + .Value(0.5f) + [ + NewDiffControl->OldDetailsWidget() + ] + + SSplitter::Slot() + .Value(0.5f) + [ + NewDiffControl->NewDetailsWidget() + ]; + + return Ret; +} + +SFlowDiff::FDiffControl SFlowDiff::GenerateGraphPanel() +{ + // We only have a single permanent graph in Flow Asset + GraphToDiff = MakeShared(this, PanelOld.FlowAsset->GetGraph(), PanelNew.FlowAsset->GetGraph(), PanelOld.RevisionInfo, PanelNew.RevisionInfo); + GraphToDiff->GenerateTreeEntries(PrimaryDifferencesList, RealDifferences); + + FDiffControl Ret; + + Ret.Widget = SNew(SVerticalBox) + + SVerticalBox::Slot() + .FillHeight(1.f) + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .FillWidth(1.f) + [ + //diff window + SNew(SSplitter) + .Orientation(Orient_Vertical) + + SSplitter::Slot() + .Value(.8f) + [ + SAssignNew(DiffGraphSplitter, SSplitter) + .PhysicalSplitterHandleSize(10.0f) + .Orientation(bVerticalSplitGraphMode ? Orient_Horizontal : Orient_Vertical) + + SSplitter::Slot() // Old revision graph slot + [ + GenerateGraphWidgetForPanel(PanelOld) + ] + + SSplitter::Slot() // New revision graph slot + [ + GenerateGraphWidgetForPanel(PanelNew) + ] + ] + + SSplitter::Slot() + .Value(.2f) + [ + SNew(SSplitter) + .PhysicalSplitterHandleSize(10.0f) + + SSplitter::Slot() + [ + PanelOld.DetailsView.ToSharedRef() + ] + + SSplitter::Slot() + [ + PanelNew.DetailsView.ToSharedRef() + ] + ] + ] + ]; + + return Ret; +} + +TSharedRef SFlowDiff::GenerateGraphWidgetForPanel(FFlowDiffPanel& OutDiffPanel) const +{ + return SNew(SOverlay) + + SOverlay::Slot() // Graph slot + [ + SAssignNew(OutDiffPanel.GraphEditorBox, SBox) + .HAlign(HAlign_Fill) + [ + DefaultEmptyPanel() + ] + ] + + SOverlay::Slot() // Revision info slot + .VAlign(VAlign_Bottom) + .HAlign(HAlign_Right) + .Padding(FMargin(20.0f, 10.0f)) + [ + GenerateRevisionInfoWidgetForPanel(OutDiffPanel.OverlayGraphRevisionInfo, DiffViewUtils::GetPanelLabel(OutDiffPanel.FlowAsset, OutDiffPanel.RevisionInfo, FText())) + ]; +} + +TSharedRef SFlowDiff::GenerateRevisionInfoWidgetForPanel(TSharedPtr& OutGeneratedWidget, const FText& InRevisionText) const +{ + return SAssignNew(OutGeneratedWidget, SBox) + .Padding(FMargin(4.0f, 10.0f)) + .VAlign(VAlign_Center) + .HAlign(HAlign_Left) + [ + SNew(STextBlock) + .TextStyle(FAppStyle::Get(), "DetailsView.CategoryTextStyle") + .Text(InRevisionText) + .ShadowColorAndOpacity(FColor::Black) + .ShadowOffset(FVector2D(1.4, 1.4)) + ]; +} + +void SFlowDiff::SetCurrentMode(FName NewMode) +{ + if (CurrentMode == NewMode) + { + return; + } + + CurrentMode = NewMode; + + const FDiffControl* FoundControl = ModePanels.Find(NewMode); + + if (FoundControl) + { + // Reset inspector view + PanelOld.DetailsView->SetObjects(TArray()); + PanelNew.DetailsView->SetObjects(TArray()); + + ModeContents->SetContent(FoundControl->Widget.ToSharedRef()); + } + else + { + ensureMsgf(false, TEXT("Diff panel does not support mode %s"), *NewMode.ToString()); + } + + OnModeChanged(NewMode); +} + +void SFlowDiff::UpdateTopSectionVisibility(const FName& InNewViewMode) const +{ + SSplitter* GraphToolBarPtr = GraphToolBarWidget.Get(); + SSplitter* TopRevisionInfoWidgetPtr = TopRevisionInfoWidget.Get(); + + if (!GraphToolBarPtr || !TopRevisionInfoWidgetPtr) + { + return; + } + + if (InNewViewMode == GraphMode) + { + GraphToolBarPtr->SetVisibility(EVisibility::Visible); + TopRevisionInfoWidgetPtr->SetVisibility(EVisibility::Collapsed); + } + else + { + GraphToolBarPtr->SetVisibility(EVisibility::Collapsed); + TopRevisionInfoWidgetPtr->SetVisibility(EVisibility::HitTestInvisible); + } +} + +void SFlowDiff::OnModeChanged(const FName& InNewViewMode) const +{ + UpdateTopSectionVisibility(InNewViewMode); +} + +#undef LOCTEXT_NAMESPACE +#endif diff --git a/Source/FlowEditor/Public/Asset/AssetTypeActions_FlowAsset.h b/Source/FlowEditor/Public/Asset/AssetTypeActions_FlowAsset.h index bee8c6b8f..dfab704c8 100644 --- a/Source/FlowEditor/Public/Asset/AssetTypeActions_FlowAsset.h +++ b/Source/FlowEditor/Public/Asset/AssetTypeActions_FlowAsset.h @@ -5,6 +5,8 @@ #include "AssetTypeActions_Base.h" #include "Toolkits/IToolkitHost.h" +#include "FlowEditorDefines.h" + class FLOWEDITOR_API FAssetTypeActions_FlowAsset : public FAssetTypeActions_Base { public: @@ -14,4 +16,12 @@ class FLOWEDITOR_API FAssetTypeActions_FlowAsset : public FAssetTypeActions_Base virtual UClass* GetSupportedClass() const override; virtual void OpenAssetEditor(const TArray& InObjects, TSharedPtr EditWithinLevelEditor = TSharedPtr()) override; + + /** + * Documentation: https://github.com/MothCocoon/FlowGraph/wiki/Visual-Diff + * Set macro value to 1, if you made these changes to the engine: https://github.com/EpicGames/UnrealEngine/pull/9659 + */ +#if ENABLE_FLOW_DIFF + virtual void PerformAssetDiff(UObject* OldAsset, UObject* NewAsset, const FRevisionInfo& OldRevision, const FRevisionInfo& NewRevision) const override; +#endif }; diff --git a/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h b/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h index 1676dcbba..9450f127b 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h @@ -85,9 +85,11 @@ class FLOWEDITOR_API FFlowAssetToolbar final : public TSharedFromThis MakeDiffMenu() const; + void BuildDebuggerToolbar(UToolMenu* ToolbarMenu); -public: +public: TSharedPtr GetAssetInstanceList() const { return AssetInstanceList; } private: diff --git a/Source/FlowEditor/Public/Asset/FlowDiffControl.h b/Source/FlowEditor/Public/Asset/FlowDiffControl.h new file mode 100644 index 000000000..efb6aaf11 --- /dev/null +++ b/Source/FlowEditor/Public/Asset/FlowDiffControl.h @@ -0,0 +1,73 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#pragma once + +/** + * Documentation: https://github.com/MothCocoon/FlowGraph/wiki/Visual-Diff + * Set macro value to 1, if you made these changes to the engine: https://github.com/EpicGames/UnrealEngine/pull/9659 + */ + +#include "FlowEditorDefines.h" +#if ENABLE_FLOW_DIFF +#include "DetailsDiff.h" +#include "DiffResults.h" +#include "IAssetTypeActions.h" +#include "Kismet/Private/DiffControl.h" + +struct FDiffResultItem; +class UEdGraph; +struct FEdGraphEditAction; + +class UFlowAsset; +class SFlowDiff; + +///////////////////////////////////////////////////////////////////////////// +/// FFlowAssetDiffControl +class FLOWEDITOR_API FFlowAssetDiffControl : public TDetailsDiffControl +{ +public: + FFlowAssetDiffControl(const UFlowAsset* InOldFlowAsset, const UFlowAsset* InNewFlowAsset, FOnDiffEntryFocused InSelectionCallback); + + virtual void GenerateTreeEntries(TArray>& OutTreeEntries, TArray>& OutRealDifferences) override; +}; + +///////////////////////////////////////////////////////////////////////////// +/// FFlowGraphToDiff: engine's FGraphToDiff customized to Flow Graph +struct FLOWEDITOR_API FFlowGraphToDiff : public TSharedFromThis, IDiffControl +{ + FFlowGraphToDiff(class SFlowDiff* DiffWidget, UEdGraph* GraphOld, UEdGraph* GraphNew, const FRevisionInfo& RevisionOld, const FRevisionInfo& RevisionNew); + virtual ~FFlowGraphToDiff() override; + + /** Add widgets to the differences tree */ + virtual void GenerateTreeEntries(TArray>& OutTreeEntries, TArray>& OutRealDifferences) override; + + UEdGraph* GetGraphOld() const { return GraphOld; }; + UEdGraph* GetGraphNew() const { return GraphNew; }; + + /** Source for list view */ + TArray> DiffListSource; + TSharedPtr> FoundDiffs; + + /** Index of the first item in RealDifferences that was generated by this graph */ + int32 RealDifferencesStartIndex = INDEX_NONE; + +private: + FText GetToolTip() const; + TSharedRef GenerateCategoryWidget() const; + + /** Called when the Newer Graph is modified*/ + void OnGraphChanged(const FEdGraphEditAction& Action) const; + + void BuildDiffSourceArray(); + + class SFlowDiff* DiffWidget; + UEdGraph* GraphOld; + UEdGraph* GraphNew; + + /** Description of Old and new graph */ + FRevisionInfo RevisionOld; + FRevisionInfo RevisionNew; + + FDelegateHandle OnGraphChangedDelegateHandle; +}; +#endif \ No newline at end of file diff --git a/Source/FlowEditor/Public/Asset/SAssetRevisionMenu.h b/Source/FlowEditor/Public/Asset/SAssetRevisionMenu.h new file mode 100644 index 000000000..4bd540150 --- /dev/null +++ b/Source/FlowEditor/Public/Asset/SAssetRevisionMenu.h @@ -0,0 +1,53 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#pragma once + +#include "ISourceControlProvider.h" +#include "Widgets/SCompoundWidget.h" + +class FUpdateStatus; +struct FRevisionInfo; + +// Forced to make a variant of SBlueprintRevisionMenu, only to replace to UBlueprint* parameter +class FLOWEDITOR_API SAssetRevisionMenu : public SCompoundWidget +{ + DECLARE_DELEGATE_TwoParams(FOnRevisionSelected, FRevisionInfo const& RevisionInfo, const FString& InFilename) + +public: + SLATE_BEGIN_ARGS(SAssetRevisionMenu) + : _bIncludeLocalRevision(false) + { + } + + SLATE_ARGUMENT(bool, bIncludeLocalRevision) + SLATE_EVENT(FOnRevisionSelected, OnRevisionSelected) + SLATE_END_ARGS() + + virtual ~SAssetRevisionMenu() override; + + void Construct(const FArguments& InArgs, const FString& InFilename); + +private: + /** Delegate used to determine the visibility 'in progress' widgets */ + EVisibility GetInProgressVisibility() const; + /** Delegate used to determine the visibility of the cancel button */ + EVisibility GetCancelButtonVisibility() const; + + /** Delegate used to cancel a source control operation in progress */ + FReply OnCancelButtonClicked() const; + /** Callback for when the source control operation is complete */ + void OnSourceControlQueryComplete(const FSourceControlOperationRef& InOperation, ECommandResult::Type InResult); + + /** */ + bool bIncludeLocalRevision = false; + /** */ + FOnRevisionSelected OnRevisionSelected; + /** The name of the file we want revision info for */ + FString Filename; + /** The box we are using to display our menu */ + TSharedPtr MenuBox; + /** The source control operation in progress */ + TSharedPtr SourceControlQueryOp; + /** The state of the SCC query */ + uint32 SourceControlQueryState = 0; +}; diff --git a/Source/FlowEditor/Public/Asset/SFlowDiff.h b/Source/FlowEditor/Public/Asset/SFlowDiff.h new file mode 100644 index 000000000..c054204ba --- /dev/null +++ b/Source/FlowEditor/Public/Asset/SFlowDiff.h @@ -0,0 +1,224 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#pragma once + +/** + * Documentation: https://github.com/MothCocoon/FlowGraph/wiki/Visual-Diff + * Set macro value to 1, if you made these changes to the engine: https://github.com/EpicGames/UnrealEngine/pull/9659 + */ + +#include "FlowEditorDefines.h" +#if ENABLE_FLOW_DIFF +#include "SDetailsDiff.h" + +struct FFlowGraphToDiff; +class UFlowAsset; + +enum class EAssetEditorCloseReason : uint8; + +namespace FlowDiffUtils +{ + FLOWEDITOR_API void SelectNextRow(SListView>& ListView, const TArray>& ListViewSource); + FLOWEDITOR_API void SelectPrevRow(SListView>& ListView, const TArray>& ListViewSource); + FLOWEDITOR_API bool HasNextDifference(const SListView>& ListView, const TArray>& ListViewSource); + FLOWEDITOR_API bool HasPrevDifference(const SListView>& ListView, const TArray>& ListViewSource); +} + +/** Panel used to display the asset */ +struct FLOWEDITOR_API FFlowDiffPanel +{ + FFlowDiffPanel(); + + /** Generate a panel for NewGraph diffed against OldGraph */ + void GeneratePanel(UEdGraph* NewGraph, UEdGraph* OldGraph); + + /** Generate a panel that displays the Graph and reflects the items in the DiffResults */ + void GeneratePanel(UEdGraph* Graph, TSharedPtr> DiffResults, TAttribute FocusedDiffResult); + + /** Called when user hits keyboard shortcut to copy nodes */ + void CopySelectedNodes() const; + + /** Gets whatever nodes are selected in the Graph Editor */ + FGraphPanelSelectionSet GetSelectedNodes() const; + + /** Can user copy any of the selected nodes? */ + bool CanCopyNodes() const; + + /** Functions used to focus/find a particular change in a diff result */ + void FocusDiff(const UEdGraphPin& Pin) const; + void FocusDiff(const UEdGraphNode& Node) const; + + /** The Flow Asset that owns the graph we are showing */ + const UFlowAsset* FlowAsset; + + /** The box around the graph editor, used to change the content when new graphs are set */ + TSharedPtr GraphEditorBox; + + /** The details view associated with the graph editor */ + TSharedPtr DetailsView; + + /** The graph editor which does the work of displaying the graph */ + TWeakPtr GraphEditor; + + /** Revision information for this asset */ + FRevisionInfo RevisionInfo; + + /** True if we should show a name identifying which asset this panel is displaying */ + bool bShowAssetName; + + /** The widget that contains the revision info in graph mode */ + TSharedPtr OverlayGraphRevisionInfo; +private: + /** Command list for this diff panel */ + TSharedPtr GraphEditorCommands; +}; + +/* Visual Diff between two Flow Assets */ +class FLOWEDITOR_API SFlowDiff : public SCompoundWidget +{ +public: + DECLARE_DELEGATE_TwoParams(FOpenInDefaults, const class UFlowAsset*, const class UFlowAsset*); + + SLATE_BEGIN_ARGS(SFlowDiff) + { + } + + SLATE_ARGUMENT(const class UFlowAsset*, OldFlow) + SLATE_ARGUMENT(const class UFlowAsset*, NewFlow) + SLATE_ARGUMENT(struct FRevisionInfo, OldRevision) + SLATE_ARGUMENT(struct FRevisionInfo, NewRevision) + SLATE_ARGUMENT(bool, ShowAssetNames) + SLATE_ARGUMENT(TSharedPtr, ParentWindow) + SLATE_END_ARGS() + + void Construct(const FArguments& InArgs); + virtual ~SFlowDiff() override; + + /** Called when a new Graph is clicked on by user */ + void OnGraphChanged(const FFlowGraphToDiff* Diff); + + /** Called when user clicks on a new graph list item */ + void OnGraphSelectionChanged(const TSharedPtr Item, ESelectInfo::Type SelectionType); + + /** Called when user clicks on an entry in the listview of differences */ + void OnDiffListSelectionChanged(TSharedPtr TheDiff); + + /** Helper function for generating an empty widget */ + static TSharedRef DefaultEmptyPanel(); + + /** Helper function to create a window that holds a diff widget */ + static TSharedPtr CreateDiffWindow(const FText WindowTitle, const UFlowAsset* OldFlow, const UFlowAsset* NewFlow, const struct FRevisionInfo& OldRevision, const struct FRevisionInfo& NewRevision); + +protected: + /** Called when user clicks button to go to next difference */ + void NextDiff() const; + + /** Called when user clicks button to go to prev difference */ + void PrevDiff() const; + + /** Called to determine whether we have a list of differences to cycle through */ + bool HasNextDiff() const; + bool HasPrevDiff() const; + + /** Find the FGraphToDiff that displays the graph with GraphPath relative path */ + FFlowGraphToDiff* FindGraphToDiffEntry(const FString& GraphPath) const; + + /** Bring these revisions of graph into focus on main display*/ + void FocusOnGraphRevisions(const FFlowGraphToDiff* Diff); + + /** User toggles the option to lock the views between the two assets */ + void OnToggleLockView(); + + /** User toggles the option to change the split view mode between vertical and horizontal */ + void OnToggleSplitViewMode(); + + /** Reset the graph editor, called when user switches graphs to display*/ + void ResetGraphEditors() const; + + /** Get the image to show for the toggle lock option*/ + FSlateIcon GetLockViewImage() const; + + /** Get the image to show for the toggle split view mode option*/ + FSlateIcon GetSplitViewModeImage() const; + + /** List of graphs to diff, are added to panel last */ + TSharedPtr GraphToDiff; + + /** Get Graph editor associated with this Graph */ + FFlowDiffPanel& GetDiffPanelForNode(const UEdGraphNode& Node); + + /** Event handler that updates the graph view when user selects a new graph */ + void HandleGraphChanged(const FString& GraphPath); + + /** Function used to generate the list of differences and the widgets needed to calculate that list */ + void GenerateDifferencesList(); + + /** Called when editor may need to be closed */ + void OnCloseAssetEditor(UObject* Asset, const EAssetEditorCloseReason CloseReason); + + struct FDiffControl + { + FDiffControl() + : Widget() + , DiffControl(nullptr) + { + } + + TSharedPtr Widget; + TSharedPtr DiffControl; + }; + + FDiffControl GenerateDetailsPanel(); + FDiffControl GenerateGraphPanel(); + + TSharedRef GenerateGraphWidgetForPanel(FFlowDiffPanel& OutDiffPanel) const; + TSharedRef GenerateRevisionInfoWidgetForPanel(TSharedPtr& OutGeneratedWidget, const FText& InRevisionText) const; + + /** Accessor and event handler for toggling between diff view modes (defaults, components, graph view, interface, macro): */ + void SetCurrentMode(FName NewMode); + FName GetCurrentMode() const { return CurrentMode; } + void OnModeChanged(const FName& InNewViewMode) const; + + void UpdateTopSectionVisibility(const FName& InNewViewMode) const; + + FName CurrentMode; + + /*The two panels used to show the old & new revision*/ + FFlowDiffPanel PanelOld, PanelNew; + + /** If the two views should be locked */ + bool bLockViews; + + /** If the view on Graph Mode should be divided vertically */ + bool bVerticalSplitGraphMode = true; + + /** Contents widget that we swap when mode changes (defaults, components, etc) */ + TSharedPtr ModeContents; + + TSharedPtr TopRevisionInfoWidget; + TSharedPtr DiffGraphSplitter; + TSharedPtr GraphToolBarWidget; + + friend struct FListItemGraphToDiff; + + /** We can't use the global tab manager because we need to instance the diff control, so we have our own tab manager: */ + TSharedPtr TabManager; + + /** Tree of differences collected across all panels: */ + TArray> PrimaryDifferencesList; + + /** List of all differences, cached so that we can iterate only the differences and not labels, etc: */ + TArray> RealDifferences; + + /** Tree view that displays the differences, cached for the buttons that iterate the differences: */ + TSharedPtr>> DifferencesTreeView; + + /** Stored references to widgets used to display various parts of a asset, from the mode name */ + TMap ModePanels; + + /** A pointer to the window holding this */ + TWeakPtr WeakParentWindow; + + FDelegateHandle AssetEditorCloseDelegate; +}; +#endif diff --git a/Source/FlowEditor/Public/FlowEditorDefines.h b/Source/FlowEditor/Public/FlowEditorDefines.h new file mode 100644 index 000000000..736d9ce32 --- /dev/null +++ b/Source/FlowEditor/Public/FlowEditorDefines.h @@ -0,0 +1,9 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#pragma once + +/** + * Documentation: https://github.com/MothCocoon/FlowGraph/wiki/Visual-Diff + * Set macro value to 1, if you made these changes to the engine: https://github.com/EpicGames/UnrealEngine/pull/9659 + */ +#define ENABLE_FLOW_DIFF 0 From d5668f23c5c9453d730c6e543fefe296aec263da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 14 Oct 2022 21:41:12 +0200 Subject: [PATCH 160/338] seems to be a redundant include From 86a63e3a90a1812a2331e6186201f459a99eda44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 14 Oct 2022 21:54:23 +0200 Subject: [PATCH 161/338] 5.0 compilation fix --- Source/FlowEditor/Private/Asset/SAssetRevisionMenu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/FlowEditor/Private/Asset/SAssetRevisionMenu.cpp b/Source/FlowEditor/Private/Asset/SAssetRevisionMenu.cpp index e6b17761f..60c912488 100644 --- a/Source/FlowEditor/Private/Asset/SAssetRevisionMenu.cpp +++ b/Source/FlowEditor/Private/Asset/SAssetRevisionMenu.cpp @@ -50,7 +50,7 @@ void SAssetRevisionMenu::Construct(const FArguments& InArgs, const FString& InFi [ SNew(SBorder) .Visibility(this, &SAssetRevisionMenu::GetInProgressVisibility) - .BorderImage(FAppStyle::GetBrush("Menu.Background")) + .BorderImage(FEditorStyle::GetBrush("Menu.Background")) .Content() [ SNew(SHorizontalBox) From 5b3c965da852ac2a9ab059c755ca12470d7d77fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 14 Oct 2022 22:01:33 +0200 Subject: [PATCH 162/338] added ENABLE_FLOW_SEARCH define --- .../FlowEditor/Private/Asset/FlowAssetIndexer.cpp | 9 ++++++++- Source/FlowEditor/Private/FlowEditorModule.cpp | 14 ++++++++++---- Source/FlowEditor/Public/Asset/FlowAssetIndexer.h | 15 +++++++++------ Source/FlowEditor/Public/FlowEditorDefines.h | 6 ++++++ 4 files changed, 33 insertions(+), 11 deletions(-) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetIndexer.cpp b/Source/FlowEditor/Private/Asset/FlowAssetIndexer.cpp index 55e1e5bdc..036eaeb78 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetIndexer.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetIndexer.cpp @@ -2,6 +2,12 @@ #include "Asset/FlowAssetIndexer.h" +/** + * Documentation: https://github.com/MothCocoon/FlowGraph/wiki/Asset-Search + * Set macro value to 1, if you made these changes to the engine: https://github.com/EpicGames/UnrealEngine/pull/9070 + */ +#include "FlowEditorDefines.h" +#if ENABLE_FLOW_SEARCH #include "FlowAsset.h" #include "Nodes/FlowNode.h" @@ -16,7 +22,7 @@ #define LOCTEXT_NAMESPACE "FFlowAssetIndexer" -/*enum class EFlowAssetIndexerVersion +enum class EFlowAssetIndexerVersion { Empty, Initial, @@ -136,3 +142,4 @@ void FFlowAssetIndexer::IndexGraph(const UFlowAsset* InFlowAsset, FSearchSeriali }*/ #undef LOCTEXT_NAMESPACE +#endif diff --git a/Source/FlowEditor/Private/FlowEditorModule.cpp b/Source/FlowEditor/Private/FlowEditorModule.cpp index faf8797ff..c2102b3f6 100644 --- a/Source/FlowEditor/Private/FlowEditorModule.cpp +++ b/Source/FlowEditor/Private/FlowEditorModule.cpp @@ -6,7 +6,6 @@ #include "Asset/AssetTypeActions_FlowAsset.h" #include "Asset/FlowAssetDetails.h" #include "Asset/FlowAssetEditor.h" -#include "Asset/FlowAssetIndexer.h" #include "Graph/FlowGraphConnectionDrawingPolicy.h" #include "Graph/FlowGraphSettings.h" #include "LevelEditor/SLevelEditorFlow.h" @@ -20,6 +19,11 @@ #include "Pins/SFlowInputPinHandle.h" #include "Pins/SFlowOutputPinHandle.h" +#include "FlowEditorDefines.h" +#if ENABLE_FLOW_SEARCH +#include "Asset/FlowAssetIndexer.h" +#endif + #include "FlowAsset.h" #include "Nodes/Route/FlowNode_CustomInput.h" #include "Nodes/Route/FlowNode_CustomOutput.h" @@ -121,7 +125,7 @@ void FFlowEditorModule::RegisterAssets() // try to merge asset category with a built-in one { - FText AssetCategoryText = UFlowGraphSettings::Get()->FlowAssetCategoryName; + const FText AssetCategoryText = UFlowGraphSettings::Get()->FlowAssetCategoryName; // Find matching built-in category if (!AssetCategoryText.IsEmpty()) @@ -198,9 +202,11 @@ void FFlowEditorModule::RegisterAssetIndexers() const { /** * Documentation: https://github.com/MothCocoon/FlowGraph/wiki/Asset-Search - * Uncomment line below, if you made these changes to the engine: https://github.com/EpicGames/UnrealEngine/pull/9070 + * Set macro value to 1, if you made these changes to the engine: https://github.com/EpicGames/UnrealEngine/pull/9070 */ - //IAssetSearchModule::Get().RegisterAssetIndexer(UFlowAsset::StaticClass(), MakeUnique()); +#if ENABLE_FLOW_SEARCH + IAssetSearchModule::Get().RegisterAssetIndexer(UFlowAsset::StaticClass(), MakeUnique()); +#endif } void FFlowEditorModule::CreateFlowToolbar(FToolBarBuilder& ToolbarBuilder) const diff --git a/Source/FlowEditor/Public/Asset/FlowAssetIndexer.h b/Source/FlowEditor/Public/Asset/FlowAssetIndexer.h index afdb90c89..4b97b0fb4 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetIndexer.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetIndexer.h @@ -2,17 +2,19 @@ #pragma once +/** + * Documentation: https://github.com/MothCocoon/FlowGraph/wiki/Asset-Search + * Set macro value to 1, if you made these changes to the engine: https://github.com/EpicGames/UnrealEngine/pull/9070 + */ +#include "FlowEditorDefines.h" +#if ENABLE_FLOW_SEARCH #include "CoreMinimal.h" #include "IAssetIndexer.h" class UFlowAsset; class FSearchSerializer; -/** - * Documentation: https://github.com/MothCocoon/FlowGraph/wiki/Asset-Search - * Uncomment entire class, if you made these changes to the engine: https://github.com/EpicGames/UnrealEngine/pull/9070 - */ -/*class FLOWEDITOR_API FFlowAssetIndexer : public IAssetIndexer +class FLOWEDITOR_API FFlowAssetIndexer : public IAssetIndexer { public: virtual FString GetName() const override { return TEXT("FlowAsset"); } @@ -22,4 +24,5 @@ class FSearchSerializer; private: // Variant of FBlueprintIndexer::IndexGraphs void IndexGraph(const UFlowAsset* InFlowAsset, FSearchSerializer& Serializer) const; -};*/ +}; +#endif diff --git a/Source/FlowEditor/Public/FlowEditorDefines.h b/Source/FlowEditor/Public/FlowEditorDefines.h index 736d9ce32..0cc1160e2 100644 --- a/Source/FlowEditor/Public/FlowEditorDefines.h +++ b/Source/FlowEditor/Public/FlowEditorDefines.h @@ -7,3 +7,9 @@ * Set macro value to 1, if you made these changes to the engine: https://github.com/EpicGames/UnrealEngine/pull/9659 */ #define ENABLE_FLOW_DIFF 0 + +/** +* Documentation: https://github.com/MothCocoon/FlowGraph/wiki/Asset-Search +* Set macro value to 1, if you made these changes to the engine: https://github.com/EpicGames/UnrealEngine/pull/9070 + */ +#define ENABLE_FLOW_SEARCH 0 From eb31d87fccb51e44aa30a7a272e7899bd2b59825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 16 Oct 2022 22:21:36 +0200 Subject: [PATCH 163/338] 5.0 fixes --- Source/FlowEditor/Private/Asset/SFlowDiff.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/FlowEditor/Private/Asset/SFlowDiff.cpp b/Source/FlowEditor/Private/Asset/SFlowDiff.cpp index ec58621f1..037e767c3 100644 --- a/Source/FlowEditor/Private/Asset/SFlowDiff.cpp +++ b/Source/FlowEditor/Private/Asset/SFlowDiff.cpp @@ -208,7 +208,7 @@ void SFlowDiff::Construct(const FArguments& InArgs) this->ChildSlot [ SNew(SBorder) - .BorderImage(FAppStyle::GetBrush("Docking.Tab", ".ContentAreaBrush")) + .BorderImage(FEditorStyle::GetBrush("Docking.Tab", ".ContentAreaBrush")) [ SNew(SOverlay) + SOverlay::Slot() @@ -248,7 +248,7 @@ void SFlowDiff::Construct(const FArguments& InArgs) .Value(.2f) [ SNew(SBorder) - .BorderImage(FAppStyle::GetBrush("ToolPanel.GroupBorder")) + .BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder")) [ DifferencesTreeView.ToSharedRef() ] @@ -531,8 +531,8 @@ void FFlowDiffPanel::GeneratePanel(UEdGraph* Graph, TSharedPtr Date: Mon, 17 Oct 2022 10:40:38 +0200 Subject: [PATCH 164/338] compilation fix --- Source/FlowEditor/Private/Asset/FlowAssetIndexer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetIndexer.cpp b/Source/FlowEditor/Private/Asset/FlowAssetIndexer.cpp index 036eaeb78..4492e1f95 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetIndexer.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetIndexer.cpp @@ -139,7 +139,7 @@ void FFlowAssetIndexer::IndexGraph(const UFlowAsset* InFlowAsset, FSearchSeriali } } } -}*/ +} #undef LOCTEXT_NAMESPACE #endif From c57bb454e056eb8ebbd8d371cba8583d852ac598 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Tue, 18 Oct 2022 19:33:26 +0200 Subject: [PATCH 165/338] renamed "master instance" to "parent instance" + button hidden if can't be used --- Source/Flow/Private/FlowAsset.cpp | 2 +- Source/Flow/Public/FlowAsset.h | 2 +- .../FlowEditor/Private/Asset/FlowAssetEditor.cpp | 14 +++++++------- .../FlowEditor/Private/Asset/FlowAssetToolbar.cpp | 8 ++++---- Source/FlowEditor/Private/FlowEditorCommands.cpp | 2 +- Source/FlowEditor/Private/FlowEditorStyle.cpp | 4 ++-- Source/FlowEditor/Public/Asset/FlowAssetEditor.h | 4 ++-- Source/FlowEditor/Public/FlowEditorCommands.h | 2 +- 8 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 80776e0f5..87f193826 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -471,7 +471,7 @@ UFlowNode_SubGraph* UFlowAsset::GetNodeOwningThisAssetInstance() const return NodeOwningThisAssetInstance.Get(); } -UFlowAsset* UFlowAsset::GetMasterInstance() const +UFlowAsset* UFlowAsset::GetParentInstance() const { return NodeOwningThisAssetInstance.IsValid() ? NodeOwningThisAssetInstance.Get()->GetFlowAsset() : nullptr; } diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 6df8357ab..281875987 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -259,7 +259,7 @@ class FLOW_API UFlowAsset : public UObject FName GetDisplayName() const; UFlowNode_SubGraph* GetNodeOwningThisAssetInstance() const; - UFlowAsset* GetMasterInstance() const; + UFlowAsset* GetParentInstance() const; // Are there any active nodes? UFUNCTION(BlueprintPure, Category = "Flow") diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index 7b4e90d91..5a7d22a0b 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -250,11 +250,11 @@ void FFlowAssetEditor::BindToolbarCommands() ToolkitCommands->Append(FPlayWorldCommands::GlobalPlayWorldActions.ToSharedRef()); // Debugging - ToolkitCommands->MapAction(ToolbarCommands.GoToMasterInstance, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::GoToMasterInstance), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanGoToMasterInstance), + ToolkitCommands->MapAction(ToolbarCommands.GoToParentInstance, + FExecuteAction::CreateSP(this, &FFlowAssetEditor::GoToParentInstance), + FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanGoToParentInstance), FIsActionChecked(), - FIsActionButtonVisible::CreateStatic(&FFlowAssetEditor::IsPIE)); + FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanGoToParentInstance)); } void FFlowAssetEditor::RefreshAsset() @@ -268,15 +268,15 @@ void FFlowAssetEditor::RefreshAsset() } } -void FFlowAssetEditor::GoToMasterInstance() +void FFlowAssetEditor::GoToParentInstance() { - const UFlowAsset* AssetThatInstancedThisAsset = FlowAsset->GetInspectedInstance()->GetMasterInstance(); + const UFlowAsset* AssetThatInstancedThisAsset = FlowAsset->GetInspectedInstance()->GetParentInstance(); GEditor->GetEditorSubsystem()->OpenEditorForAsset(AssetThatInstancedThisAsset->GetTemplateAsset()); AssetThatInstancedThisAsset->GetTemplateAsset()->SetInspectedInstance(AssetThatInstancedThisAsset->GetDisplayName()); } -bool FFlowAssetEditor::CanGoToMasterInstance() +bool FFlowAssetEditor::CanGoToParentInstance() { return FlowAsset->GetInspectedInstance() && FlowAsset->GetInspectedInstance()->GetNodeOwningThisAssetInstance() != nullptr; } diff --git a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp index 75a0c78b2..4867c58bd 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp @@ -152,10 +152,10 @@ void SFlowAssetBreadcrumb::Construct(const FArguments& InArgs, const TWeakObject TArray InstancesFromRoot = {InspectedInstance}; const UFlowAsset* CheckedInstance = InspectedInstance; - while (UFlowAsset* MasterInstance = CheckedInstance->GetMasterInstance()) + while (UFlowAsset* ParentInstance = CheckedInstance->GetParentInstance()) { - InstancesFromRoot.Insert(MasterInstance, 0); - CheckedInstance = MasterInstance; + InstancesFromRoot.Insert(ParentInstance, 0); + CheckedInstance = ParentInstance; } for (UFlowAsset* Instance : InstancesFromRoot) @@ -308,7 +308,7 @@ void FFlowAssetToolbar::BuildDebuggerToolbar(UToolMenu* ToolbarMenu) AssetInstanceList = SNew(SFlowAssetInstanceList, TemplateAsset); Section.AddEntry(FToolMenuEntry::InitWidget("AssetInstances", AssetInstanceList.ToSharedRef(), FText(), true)); - Section.AddEntry(FToolMenuEntry::InitToolBarButton(FFlowToolbarCommands::Get().GoToMasterInstance)); + Section.AddEntry(FToolMenuEntry::InitToolBarButton(FFlowToolbarCommands::Get().GoToParentInstance)); Breadcrumb = SNew(SFlowAssetBreadcrumb, TemplateAsset); Section.AddEntry(FToolMenuEntry::InitWidget("AssetBreadcrumb", Breadcrumb.ToSharedRef(), FText(), true)); diff --git a/Source/FlowEditor/Private/FlowEditorCommands.cpp b/Source/FlowEditor/Private/FlowEditorCommands.cpp index 8b2a42aa7..4cee7ffe4 100644 --- a/Source/FlowEditor/Private/FlowEditorCommands.cpp +++ b/Source/FlowEditor/Private/FlowEditorCommands.cpp @@ -20,7 +20,7 @@ FFlowToolbarCommands::FFlowToolbarCommands() void FFlowToolbarCommands::RegisterCommands() { UI_COMMAND(RefreshAsset, "Refresh Asset", "Refresh asset and all nodes", EUserInterfaceActionType::Button, FInputChord()); - UI_COMMAND(GoToMasterInstance, "Go To Master", "Open editor for the Flow Asset that created this Flow instance", EUserInterfaceActionType::Button, FInputChord()); + UI_COMMAND(GoToParentInstance, "Go To Parent", "Open editor for the Flow Asset that created this Flow instance", EUserInterfaceActionType::Button, FInputChord()); } FFlowGraphCommands::FFlowGraphCommands() diff --git a/Source/FlowEditor/Private/FlowEditorStyle.cpp b/Source/FlowEditor/Private/FlowEditorStyle.cpp index e5954617e..6faa3b813 100644 --- a/Source/FlowEditor/Private/FlowEditorStyle.cpp +++ b/Source/FlowEditor/Private/FlowEditorStyle.cpp @@ -30,8 +30,8 @@ void FFlowEditorStyle::Initialize() // engine assets StyleSet->SetContentRoot(FPaths::EngineContentDir() / TEXT("Editor/Slate/")); - StyleSet->Set("FlowToolbar.GoToMasterInstance", new IMAGE_BRUSH("Icons/icon_DebugStepOut_40x", Icon40)); - StyleSet->Set("FlowToolbar.GoToMasterInstance.Small", new IMAGE_BRUSH("Icons/icon_DebugStepOut_40x", Icon20)); + StyleSet->Set("FlowToolbar.GoToParentInstance", new IMAGE_BRUSH("Icons/icon_DebugStepOut_40x", Icon40)); + StyleSet->Set("FlowToolbar.GoToParentInstance.Small", new IMAGE_BRUSH("Icons/icon_DebugStepOut_40x", Icon20)); StyleSet->Set("FlowGraph.BreakpointEnabled", new IMAGE_BRUSH("Old/Kismet2/Breakpoint_Valid", FVector2D(24.0f, 24.0f))); StyleSet->Set("FlowGraph.BreakpointDisabled", new IMAGE_BRUSH("Old/Kismet2/Breakpoint_Disabled", FVector2D(24.0f, 24.0f))); diff --git a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h index 63dd36cf7..96264559c 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h @@ -93,8 +93,8 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit virtual void BindToolbarCommands(); virtual void RefreshAsset(); - virtual void GoToMasterInstance(); - virtual bool CanGoToMasterInstance(); + virtual void GoToParentInstance(); + virtual bool CanGoToParentInstance(); virtual void CreateWidgets(); diff --git a/Source/FlowEditor/Public/FlowEditorCommands.h b/Source/FlowEditor/Public/FlowEditorCommands.h index f3f9caf2c..bd6fc6480 100644 --- a/Source/FlowEditor/Public/FlowEditorCommands.h +++ b/Source/FlowEditor/Public/FlowEditorCommands.h @@ -13,7 +13,7 @@ class FLOWEDITOR_API FFlowToolbarCommands final : public TCommands RefreshAsset; - TSharedPtr GoToMasterInstance; + TSharedPtr GoToParentInstance; virtual void RegisterCommands() override; }; From 4134d3d6cfe92206c36034bd519c46a5160ab3e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Tue, 18 Oct 2022 19:37:54 +0200 Subject: [PATCH 166/338] removed small icon style, as Small variants are removed in UE5 --- Source/FlowEditor/Private/FlowEditorStyle.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Source/FlowEditor/Private/FlowEditorStyle.cpp b/Source/FlowEditor/Private/FlowEditorStyle.cpp index 6faa3b813..875cfc585 100644 --- a/Source/FlowEditor/Private/FlowEditorStyle.cpp +++ b/Source/FlowEditor/Private/FlowEditorStyle.cpp @@ -22,7 +22,6 @@ void FFlowEditorStyle::Initialize() StyleSet = MakeShareable(new FSlateStyleSet(TEXT("FlowEditorStyle"))); const FVector2D Icon16(16.0f, 16.0f); - const FVector2D Icon20(20.0f, 20.0f); const FVector2D Icon30(30.0f, 30.0f); const FVector2D Icon40(40.0f, 40.0f); const FVector2D Icon64(64.0f, 64.0f); @@ -31,7 +30,6 @@ void FFlowEditorStyle::Initialize() StyleSet->SetContentRoot(FPaths::EngineContentDir() / TEXT("Editor/Slate/")); StyleSet->Set("FlowToolbar.GoToParentInstance", new IMAGE_BRUSH("Icons/icon_DebugStepOut_40x", Icon40)); - StyleSet->Set("FlowToolbar.GoToParentInstance.Small", new IMAGE_BRUSH("Icons/icon_DebugStepOut_40x", Icon20)); StyleSet->Set("FlowGraph.BreakpointEnabled", new IMAGE_BRUSH("Old/Kismet2/Breakpoint_Valid", FVector2D(24.0f, 24.0f))); StyleSet->Set("FlowGraph.BreakpointDisabled", new IMAGE_BRUSH("Old/Kismet2/Breakpoint_Disabled", FVector2D(24.0f, 24.0f))); From c1a355fa7f07202b072ac805ab48b06988126a66 Mon Sep 17 00:00:00 2001 From: Cchnn <12191713+Cchnn@users.noreply.github.com> Date: Tue, 18 Oct 2022 13:39:32 -0400 Subject: [PATCH 167/338] On node input triggered/output triggered (#120) * Activate-function * OnNodeInputTriggered and OnNodeOutputTriggered Co-authored-by: Chun --- Source/Flow/Private/FlowSubsystem.cpp | 8 ++++++++ Source/Flow/Private/Nodes/FlowNode.cpp | 15 +++++++++++++++ Source/Flow/Public/FlowSubsystem.h | 4 ++++ Source/Flow/Public/Nodes/FlowNode.h | 5 +++++ 4 files changed, 32 insertions(+) diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index bcbdde0e9..0e14d3d0b 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -48,6 +48,14 @@ void UFlowSubsystem::Deinitialize() AbortActiveFlows(); } +void UFlowSubsystem::OnNodeInputTriggered(const UFlowNode* node, const bool bWasActive) +{ +} + +void UFlowSubsystem::OnNodeOutputTriggered(const UFlowNode* node, const bool bFinish) +{ +} + void UFlowSubsystem::AbortActiveFlows() { if (InstancedTemplates.Num() > 0) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 438b2a9d5..a7851b082 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -338,8 +338,16 @@ void UFlowNode::TriggerInput(const FName& PinName, const bool bForcedActivation { if (InputPins.Contains(PinName)) { + EFlowNodeState PreviousActivationState = ActivationState; + if (PreviousActivationState != EFlowNodeState::Active) + { + Activate(); + } + ActivationState = EFlowNodeState::Active; + GetFlowSubsystem()->OnNodeInputTriggered(this, PreviousActivationState == EFlowNodeState::Active); + #if !UE_BUILD_SHIPPING // record for debugging TArray& Records = InputRecords.FindOrAdd(PinName); @@ -379,6 +387,8 @@ void UFlowNode::TriggerFirstOutput(const bool bFinish) void UFlowNode::TriggerOutput(const FName& PinName, const bool bFinish /*= false*/, const bool bForcedActivation /*= false*/) { + GetFlowSubsystem()->OnNodeOutputTriggered(this, bFinish); + // clean up node, if needed if (bFinish) { @@ -458,6 +468,11 @@ void UFlowNode::Cleanup() K2_Cleanup(); } +void UFlowNode::Activate() +{ + K2_Activate(); +} + void UFlowNode::ForceFinishNode() { K2_ForceFinishNode(); diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index 3315609dd..d2706f28d 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -12,6 +12,7 @@ class UFlowAsset; class UFlowNode_SubGraph; +class UFlowNode; DECLARE_DYNAMIC_MULTICAST_DELEGATE(FSimpleFlowEvent); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FSimpleFlowComponentEvent, UFlowComponent*, Component); @@ -60,6 +61,9 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem virtual void Initialize(FSubsystemCollectionBase& Collection) override; virtual void Deinitialize() override; + virtual void OnNodeInputTriggered(const UFlowNode* node, const bool bWasActive); + virtual void OnNodeOutputTriggered(const UFlowNode* node, const bool bFinish); + virtual void AbortActiveFlows(); /* Start the root Flow, graph that will eventually instantiate next Flow Graphs through the SubGraph node */ diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index b3b969e24..96c8967af 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -283,6 +283,11 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "Cleanup")) void K2_Cleanup(); + virtual void Activate(); + + UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "Activate")) + void K2_Activate(); + public: // Define what happens when node is terminated from the outside virtual void ForceFinishNode(); From 8b2d3b4e4d3bb4614c7b6f6cd55bb9c751e43c4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Tue, 18 Oct 2022 20:01:26 +0200 Subject: [PATCH 168/338] PR #120 cleanup: removal of subsystem part, renamed event to Activate --- Source/Flow/Private/FlowSubsystem.cpp | 8 -------- Source/Flow/Private/Nodes/FlowNode.cpp | 18 +++++++----------- Source/Flow/Public/FlowSubsystem.h | 4 ---- Source/Flow/Public/Nodes/FlowNode.h | 10 +++++----- 4 files changed, 12 insertions(+), 28 deletions(-) diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index 0e14d3d0b..bcbdde0e9 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -48,14 +48,6 @@ void UFlowSubsystem::Deinitialize() AbortActiveFlows(); } -void UFlowSubsystem::OnNodeInputTriggered(const UFlowNode* node, const bool bWasActive) -{ -} - -void UFlowSubsystem::OnNodeOutputTriggered(const UFlowNode* node, const bool bFinish) -{ -} - void UFlowSubsystem::AbortActiveFlows() { if (InstancedTemplates.Num() > 0) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index a7851b082..d04834017 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -334,20 +334,23 @@ void UFlowNode::FlushContent() K2_FlushContent(); } +void UFlowNode::OnActivate() +{ + K2_OnActivate(); +} + void UFlowNode::TriggerInput(const FName& PinName, const bool bForcedActivation /*= false*/) { if (InputPins.Contains(PinName)) { - EFlowNodeState PreviousActivationState = ActivationState; + const EFlowNodeState PreviousActivationState = ActivationState; if (PreviousActivationState != EFlowNodeState::Active) { - Activate(); + OnActivate(); } ActivationState = EFlowNodeState::Active; - GetFlowSubsystem()->OnNodeInputTriggered(this, PreviousActivationState == EFlowNodeState::Active); - #if !UE_BUILD_SHIPPING // record for debugging TArray& Records = InputRecords.FindOrAdd(PinName); @@ -387,8 +390,6 @@ void UFlowNode::TriggerFirstOutput(const bool bFinish) void UFlowNode::TriggerOutput(const FName& PinName, const bool bFinish /*= false*/, const bool bForcedActivation /*= false*/) { - GetFlowSubsystem()->OnNodeOutputTriggered(this, bFinish); - // clean up node, if needed if (bFinish) { @@ -468,11 +469,6 @@ void UFlowNode::Cleanup() K2_Cleanup(); } -void UFlowNode::Activate() -{ - K2_Activate(); -} - void UFlowNode::ForceFinishNode() { K2_ForceFinishNode(); diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index d2706f28d..3315609dd 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -12,7 +12,6 @@ class UFlowAsset; class UFlowNode_SubGraph; -class UFlowNode; DECLARE_DYNAMIC_MULTICAST_DELEGATE(FSimpleFlowEvent); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FSimpleFlowComponentEvent, UFlowComponent*, Component); @@ -61,9 +60,6 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem virtual void Initialize(FSubsystemCollectionBase& Collection) override; virtual void Deinitialize() override; - virtual void OnNodeInputTriggered(const UFlowNode* node, const bool bWasActive); - virtual void OnNodeOutputTriggered(const UFlowNode* node, const bool bFinish); - virtual void AbortActiveFlows(); /* Start the root Flow, graph that will eventually instantiate next Flow Graphs through the SubGraph node */ diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 96c8967af..774ae746b 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -246,6 +246,11 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "FlushContent")) void K2_FlushContent(); + virtual void OnActivate(); + + UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "On Activate")) + void K2_OnActivate(); + // Trigger execution of input pin void TriggerInput(const FName& PinName, const bool bForcedActivation = false); @@ -283,11 +288,6 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "Cleanup")) void K2_Cleanup(); - virtual void Activate(); - - UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "Activate")) - void K2_Activate(); - public: // Define what happens when node is terminated from the outside virtual void ForceFinishNode(); From 73437b4e2a478c42e4742ea03dc5eada41d2c9ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Tue, 18 Oct 2022 20:41:41 +0200 Subject: [PATCH 169/338] added Can Finish Graph method, this logic isn't hardcoded to Finish node anymore --- Source/Flow/Private/FlowAsset.cpp | 3 +-- Source/Flow/Public/Nodes/FlowNode.h | 3 +++ Source/Flow/Public/Nodes/Route/FlowNode_Finish.h | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 87f193826..054474096 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -7,7 +7,6 @@ #include "Nodes/FlowNode.h" #include "Nodes/Route/FlowNode_CustomInput.h" #include "Nodes/Route/FlowNode_Start.h" -#include "Nodes/Route/FlowNode_Finish.h" #include "Nodes/Route/FlowNode_SubGraph.h" #include "Engine/World.h" @@ -432,7 +431,7 @@ void UFlowAsset::FinishNode(UFlowNode* Node) ActiveNodes.Remove(Node); // if graph reached Finish and this asset instance was created by SubGraph node - if (Node->GetClass()->IsChildOf(UFlowNode_Finish::StaticClass())) + if (Node->CanFinishGraph()) { if (NodeOwningThisAssetInstance.IsValid()) { diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 774ae746b..b0d5e2531 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -110,6 +110,9 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UFUNCTION(BlueprintPure, Category = "FlowNode") UFlowAsset* GetFlowAsset() const; +protected: + virtual bool CanFinishGraph() const { return false; } + ////////////////////////////////////////////////////////////////////////// // All created pins (default, class-specific and added by user) diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_Finish.h b/Source/Flow/Public/Nodes/Route/FlowNode_Finish.h index d5d4c59af..a9f9299b6 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_Finish.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_Finish.h @@ -15,5 +15,6 @@ class FLOW_API UFlowNode_Finish : public UFlowNode GENERATED_UCLASS_BODY() protected: + virtual bool CanFinishGraph() const override { return true; } virtual void ExecuteInput(const FName& PinName) override; }; From 4529e4b73d076d9480d17d8811f7dfb4fddd8734 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Tue, 18 Oct 2022 20:49:03 +0200 Subject: [PATCH 170/338] added spaces to blueprint event Display Names --- Source/Flow/Public/Nodes/FlowNode.h | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index b0d5e2531..522a610a5 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -96,7 +96,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte protected: // Short summary of node's content - displayed over node as NodeInfoPopup - UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "GetNodeDescription")) + UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "Get Node Description")) FString K2_GetNodeDescription() const; // Inherits Guid after graph node @@ -163,10 +163,10 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte #endif protected: - UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "CanUserAddInput")) + UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "Can User Add Input")) bool K2_CanUserAddInput() const; - UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "CanUserAddOutput")) + UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "Can User Add Output")) bool K2_CanUserAddOutput() const; ////////////////////////////////////////////////////////////////////////// @@ -232,7 +232,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte // Event called just after creating the node instance, while initializing the Flow Asset instance // This happens before executing graph, only called during gameplay - UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "InitInstance")) + UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "Init Instance")) void K2_InitializeInstance(); public: @@ -243,10 +243,10 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte virtual void PreloadContent(); virtual void FlushContent(); - UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "PreloadContent")) + UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "Preload Content")) void K2_PreloadContent(); - UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "FlushContent")) + UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "Flush Content")) void K2_FlushContent(); virtual void OnActivate(); @@ -261,7 +261,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte virtual void ExecuteInput(const FName& PinName); // Event reacting on triggering Input pin - UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "ExecuteInput")) + UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "Execute Input")) void K2_ExecuteInput(const FName& PinName); // Simply trigger the first Output Pin, convenient to use if node has only one output @@ -297,7 +297,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte protected: // Define what happens when node is terminated from the outside - UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "ForceFinishNode")) + UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "Force Finish Node")) void K2_ForceFinishNode(); private: @@ -321,19 +321,19 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte protected: // Information displayed while node is working - displayed over node as NodeInfoPopup - UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "GetStatusString")) + UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "Get Status String")) FString K2_GetStatusString() const; - UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "GetStatusBackgroundColor")) + UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "Get Status Background Color")) bool K2_GetStatusBackgroundColor(FLinearColor& OutColor) const; - UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "GetAssetPath")) + UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "Get Asset Path")) FString K2_GetAssetPath(); - UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "GetAssetToEdit")) + UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "Get Asset To Edit")) UObject* K2_GetAssetToEdit(); - UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "GetActorToFocus")) + UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "Get Actor To Focus")) AActor* K2_GetActorToFocus(); template From 6d3b4d3df5380c9b7765ca059a454a20b1c49e35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Tue, 18 Oct 2022 21:17:11 +0200 Subject: [PATCH 171/338] static analysis fixes --- Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp | 3 +-- Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp index 386baa6ac..e19a6b199 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp @@ -11,7 +11,6 @@ #include "FlowAsset.h" #include "Nodes/FlowNode.h" -#include "Developer/ToolMenus/Public/ToolMenus.h" #include "EdGraph/EdGraph.h" #include "EdGraphNode_Comment.h" #include "Editor.h" @@ -39,7 +38,7 @@ UEdGraphNode* FFlowGraphSchemaAction_NewNode::PerformAction(class UEdGraph* Pare return nullptr; } -UFlowGraphNode* FFlowGraphSchemaAction_NewNode::CreateNode(UEdGraph* ParentGraph, UEdGraphPin* FromPin, UClass* NodeClass, const FVector2D Location, const bool bSelectNewNode /*= true*/) +UFlowGraphNode* FFlowGraphSchemaAction_NewNode::CreateNode(UEdGraph* ParentGraph, UEdGraphPin* FromPin, const UClass* NodeClass, const FVector2D Location, const bool bSelectNewNode /*= true*/) { check(NodeClass); diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h b/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h index d882bd41d..520f6176a 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h @@ -47,7 +47,7 @@ struct FLOWEDITOR_API FFlowGraphSchemaAction_NewNode : public FEdGraphSchemaActi virtual UEdGraphNode* PerformAction(class UEdGraph* ParentGraph, UEdGraphPin* FromPin, const FVector2D Location, bool bSelectNewNode = true) override; // -- - static UFlowGraphNode* CreateNode(class UEdGraph* ParentGraph, UEdGraphPin* FromPin, UClass* NodeClass, const FVector2D Location, const bool bSelectNewNode = true); + static UFlowGraphNode* CreateNode(class UEdGraph* ParentGraph, UEdGraphPin* FromPin, const UClass* NodeClass, const FVector2D Location, const bool bSelectNewNode = true); }; /** Action to paste clipboard contents into the graph */ From 17b6aecac37d2fa27b6deddbe9873353bf9708ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Tue, 18 Oct 2022 21:46:18 +0200 Subject: [PATCH 172/338] ANY_PACKAGE fix: removed redundant search for static class --- Source/FlowEditor/FlowEditor.Build.cs | 1 + Source/FlowEditor/Private/MovieScene/FlowTrackEditor.cpp | 9 +++------ 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Source/FlowEditor/FlowEditor.Build.cs b/Source/FlowEditor/FlowEditor.Build.cs index 3f1c9ae2f..90b593114 100644 --- a/Source/FlowEditor/FlowEditor.Build.cs +++ b/Source/FlowEditor/FlowEditor.Build.cs @@ -35,6 +35,7 @@ public FlowEditor(ReadOnlyTargetRules Target) : base(Target) "Kismet", "KismetWidgets", "LevelEditor", + "LevelSequence", "MovieScene", "MovieSceneTracks", "MovieSceneTools", diff --git a/Source/FlowEditor/Private/MovieScene/FlowTrackEditor.cpp b/Source/FlowEditor/Private/MovieScene/FlowTrackEditor.cpp index 51dd0d55d..71472faab 100644 --- a/Source/FlowEditor/Private/MovieScene/FlowTrackEditor.cpp +++ b/Source/FlowEditor/Private/MovieScene/FlowTrackEditor.cpp @@ -8,13 +8,11 @@ #include "MovieScene/MovieSceneFlowTriggerSection.h" #include "Framework/MultiBox/MultiBoxBuilder.h" -#include "UObject/Package.h" #include "ISequencerSection.h" -#include "DetailLayoutBuilder.h" -#include "DetailCategoryBuilder.h" +#include "LevelSequence.h" +#include "MovieSceneSequenceEditor.h" #include "Sections/MovieSceneEventSection.h" #include "SequencerUtilities.h" -#include "MovieSceneSequenceEditor.h" #define LOCTEXT_NAMESPACE "FFlowTrackEditor" @@ -138,8 +136,7 @@ bool FFlowTrackEditor::SupportsType(TSubclassOf Type) const bool FFlowTrackEditor::SupportsSequence(UMovieSceneSequence* InSequence) const { - static UClass* LevelSequenceClass = FindObject(ANY_PACKAGE, TEXT("LevelSequence"), true); - return InSequence && LevelSequenceClass && InSequence->GetClass()->IsChildOf(LevelSequenceClass); + return InSequence && InSequence->GetClass()->IsChildOf(ULevelSequence::StaticClass()); } const FSlateBrush* FFlowTrackEditor::GetIconBrush() const From 4b5dad34c59218b2f9cd704a11b7c81e38d11c4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Wed, 19 Oct 2022 00:25:34 +0200 Subject: [PATCH 173/338] #113 Refactored numbered pins support, so it would fully safe to add regular pins --- Source/Flow/Private/Nodes/FlowNode.cpp | 50 +++++++++++++++++-- Source/Flow/Public/Nodes/FlowNode.h | 7 ++- .../Private/Graph/Nodes/FlowGraphNode.cpp | 40 +++++++++++---- .../Public/Graph/Nodes/FlowGraphNode.h | 2 +- 4 files changed, 81 insertions(+), 18 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index d04834017..7230d2771 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -182,6 +182,32 @@ void UFlowNode::SetNumberedOutputPins(const uint8 FirstNumber /*= 0*/, const uin } } +uint8 UFlowNode::CountNumberedInputs() const +{ + uint8 Result = 0; + for (const FFlowPin& Pin : InputPins) + { + if (Pin.PinName.ToString().IsNumeric()) + { + Result++; + } + } + return Result; +} + +uint8 UFlowNode::CountNumberedOutputs() const +{ + uint8 Result = 0; + for (const FFlowPin& Pin : OutputPins) + { + if (Pin.PinName.ToString().IsNumeric()) + { + Result++; + } + } + return Result; +} + TArray UFlowNode::GetInputNames() const { TArray Result; @@ -219,16 +245,32 @@ bool UFlowNode::CanUserAddOutput() const return K2_CanUserAddOutput(); } -void UFlowNode::RemoveUserInput() +void UFlowNode::RemoveUserInput(const FName& PinName) { Modify(); - InputPins.RemoveAt(InputPins.Num() - 1); + + for (int32 i = 0; i < InputPins.Num(); i++) + { + if (InputPins[i].PinName == PinName) + { + InputPins.RemoveAt(i); + break; + } + } } -void UFlowNode::RemoveUserOutput() +void UFlowNode::RemoveUserOutput(const FName& PinName) { Modify(); - OutputPins.RemoveAt(OutputPins.Num() - 1); + + for (int32 i = 0; i < OutputPins.Num(); i++) + { + if (OutputPins[i].PinName == PinName) + { + OutputPins.RemoveAt(i); + break; + } + } } #endif diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 522a610a5..086c3a236 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -136,6 +136,9 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte void SetNumberedInputPins(const uint8 FirstNumber = 0, const uint8 LastNumber = 1); void SetNumberedOutputPins(const uint8 FirstNumber = 0, const uint8 LastNumber = 1); + uint8 CountNumberedInputs() const; + uint8 CountNumberedOutputs() const; + TArray GetInputPins() const { return InputPins; } TArray GetOutputPins() const { return OutputPins; } @@ -158,8 +161,8 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte virtual bool CanUserAddInput() const; virtual bool CanUserAddOutput() const; - void RemoveUserInput(); - void RemoveUserOutput(); + void RemoveUserInput(const FName& PinName); + void RemoveUserOutput(const FName& PinName); #endif protected: diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index b1b5b14d6..28f302105 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -808,38 +808,56 @@ bool UFlowGraphNode::CanUserAddOutput() const bool UFlowGraphNode::CanUserRemoveInput(const UEdGraphPin* Pin) const { - return FlowNode && FlowNode->InputPins.Num() > FlowNode->GetClass()->GetDefaultObject()->InputPins.Num(); + return FlowNode && !FlowNode->GetClass()->GetDefaultObject()->InputPins.Contains(Pin->PinName); } bool UFlowGraphNode::CanUserRemoveOutput(const UEdGraphPin* Pin) const { - return FlowNode && FlowNode->OutputPins.Num() > FlowNode->GetClass()->GetDefaultObject()->OutputPins.Num(); + return FlowNode && !FlowNode->GetClass()->GetDefaultObject()->OutputPins.Contains(Pin->PinName); } void UFlowGraphNode::AddUserInput() { - AddInstancePin(EGPD_Input, *FString::FromInt(InputPins.Num())); + AddInstancePin(EGPD_Input, FlowNode->CountNumberedInputs()); } void UFlowGraphNode::AddUserOutput() { - AddInstancePin(EGPD_Output, *FString::FromInt(OutputPins.Num())); + AddInstancePin(EGPD_Output, FlowNode->CountNumberedOutputs()); } -void UFlowGraphNode::AddInstancePin(const EEdGraphPinDirection Direction, const FName& PinName) +void UFlowGraphNode::AddInstancePin(const EEdGraphPinDirection Direction, const uint8 NumberedPinsAmount) { const FScopedTransaction Transaction(LOCTEXT("AddInstancePin", "Add Instance Pin")); Modify(); + const FFlowPin PinName = FFlowPin(FString::FromInt(NumberedPinsAmount)); + if (Direction == EGPD_Input) { - FlowNode->InputPins.Emplace(PinName); - CreateInputPin(FlowNode->InputPins.Last()); + if (FlowNode->InputPins.IsValidIndex(NumberedPinsAmount)) + { + FlowNode->InputPins.Insert(PinName, NumberedPinsAmount); + } + else + { + FlowNode->InputPins.Add(PinName); + } + + CreateInputPin(PinName, NumberedPinsAmount); } else { - FlowNode->OutputPins.Emplace(PinName); - CreateOutputPin(FlowNode->OutputPins.Last()); + if (FlowNode->OutputPins.IsValidIndex(NumberedPinsAmount)) + { + FlowNode->OutputPins.Insert(PinName, NumberedPinsAmount); + } + else + { + FlowNode->InputPins.Add(PinName); + } + + CreateOutputPin(PinName, NumberedPinsAmount); } GetGraph()->NotifyGraphChanged(); @@ -857,7 +875,7 @@ void UFlowGraphNode::RemoveInstancePin(UEdGraphPin* Pin) if (InputPins.Contains(Pin)) { InputPins.Remove(Pin); - FlowNode->RemoveUserInput(); + FlowNode->RemoveUserInput(Pin->PinName); Pin->MarkAsGarbage(); Pins.Remove(Pin); @@ -868,7 +886,7 @@ void UFlowGraphNode::RemoveInstancePin(UEdGraphPin* Pin) if (OutputPins.Contains(Pin)) { OutputPins.Remove(Pin); - FlowNode->RemoveUserOutput(); + FlowNode->RemoveUserOutput(Pin->PinName); Pin->MarkAsGarbage(); Pins.Remove(Pin); diff --git a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h index 4a7da0975..a47e80e68 100644 --- a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h +++ b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h @@ -191,7 +191,7 @@ class FLOWEDITOR_API UFlowGraphNode : public UEdGraphNode void AddUserOutput(); // Add pin only on this instance of node, under default pins - void AddInstancePin(const EEdGraphPinDirection Direction, const FName& PinName); + void AddInstancePin(const EEdGraphPinDirection Direction, const uint8 NumberedPinsAmount); // Call node and graph updates manually, if using bBatchRemoval void RemoveInstancePin(UEdGraphPin* Pin); From f017f9904efd4e98576f34c38214644d17707a12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Wed, 19 Oct 2022 00:30:14 +0200 Subject: [PATCH 174/338] Reworked version of #109 - possible to disable infinite execution of the OR node Now OR node executes output only once, by default. Added logic to enable/disable the `Logical OR` node. This can be a breaking change if you somewhere relied on an infinitely working OR node. You can fix this by changing the `Execution Limit` value to 0. --- .../Nodes/Operators/FlowNode_LogicalOR.cpp | 46 ++++++++++++++++++- .../Nodes/Operators/FlowNode_LogicalOR.h | 17 +++++++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/Source/Flow/Private/Nodes/Operators/FlowNode_LogicalOR.cpp b/Source/Flow/Private/Nodes/Operators/FlowNode_LogicalOR.cpp index f814ee709..402758b77 100644 --- a/Source/Flow/Private/Nodes/Operators/FlowNode_LogicalOR.cpp +++ b/Source/Flow/Private/Nodes/Operators/FlowNode_LogicalOR.cpp @@ -4,6 +4,9 @@ UFlowNode_LogicalOR::UFlowNode_LogicalOR(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) + , bEnabled(true) + , ExecutionLimit(1) + , ExecutionCount(0) { #if WITH_EDITOR Category = TEXT("Operators"); @@ -11,9 +14,50 @@ UFlowNode_LogicalOR::UFlowNode_LogicalOR(const FObjectInitializer& ObjectInitial #endif SetNumberedInputPins(0, 1); + InputPins.Add(FFlowPin(TEXT("Enable"), TEXT("Enabling resets Execution Count"))); + InputPins.Add(FFlowPin(TEXT("Disable"), TEXT("Disabling resets Execution Count"))); } void UFlowNode_LogicalOR::ExecuteInput(const FName& PinName) { - TriggerFirstOutput(true); + if (PinName == TEXT("Enable")) + { + if (!bEnabled) + { + ResetCounter(); + bEnabled = true; + } + return; + } + + if (PinName == TEXT("Disable")) + { + if (bEnabled) + { + bEnabled = false; + Finish(); + } + return; + } + + if (bEnabled && PinName.ToString().IsNumeric()) + { + ExecutionCount++; + if (ExecutionLimit > 0 && ExecutionCount == ExecutionLimit) + { + bEnabled = false; + } + + TriggerFirstOutput(true); + } +} + +void UFlowNode_LogicalOR::Cleanup() +{ + ResetCounter(); +} + +void UFlowNode_LogicalOR::ResetCounter() +{ + ExecutionCount = 0; } diff --git a/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalOR.h b/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalOR.h index 75828dab9..3265478a3 100644 --- a/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalOR.h +++ b/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalOR.h @@ -14,10 +14,27 @@ class FLOW_API UFlowNode_LogicalOR final : public UFlowNode { GENERATED_UCLASS_BODY() +protected: + UPROPERTY(EditAnywhere, Category = "Lifetime", SaveGame) + bool bEnabled; + + // This node will become Blocked (not executed any more), if Execution Limit > 0 and Execution Count reaches this limit + // Set this to zero, if you'd like fire output indefinitely + UPROPERTY(EditAnywhere, Category = "Lifetime", meta = (ClampMin = 0)) + int32 ExecutionLimit; + + // This node will become Blocked (not executed any more), if Execution Limit > 0 and Execution Count reaches this limit + UPROPERTY(VisibleAnywhere, Category = "Lifetime", SaveGame) + int32 ExecutionCount; + #if WITH_EDITOR +public: virtual bool CanUserAddInput() const override { return true; } #endif protected: virtual void ExecuteInput(const FName& PinName) override; + virtual void Cleanup() override; + + void ResetCounter(); }; From 2e2ba2c143c2ae845e83e9382630450f57ec18e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Wed, 19 Oct 2022 19:06:41 +0200 Subject: [PATCH 175/338] simple way to check if Asset Data represents Flow Node blueprint --- .../Private/Graph/FlowGraphSchema.cpp | 27 ++++--------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp index cbe7b267b..12c44493e 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -11,11 +11,11 @@ #include "FlowAsset.h" #include "Nodes/FlowNode.h" +#include "Nodes/FlowNodeBlueprint.h" #include "Nodes/Route/FlowNode_Start.h" #include "Nodes/Route/FlowNode_Reroute.h" #include "AssetRegistryModule.h" -#include "Developer/ToolMenus/Public/ToolMenus.h" #include "EdGraph/EdGraph.h" #include "ScopedTransaction.h" @@ -470,30 +470,13 @@ void UFlowGraphSchema::AddAsset(const FAssetData& AssetData, const bool bBatch) return; } - TArray AncestorClassNames; - AssetRegistryModule.Get().GetAncestorClassNames(AssetData.AssetClass, AncestorClassNames); - if (!AncestorClassNames.Contains(UBlueprintCore::StaticClass()->GetFName())) + if (AssetData.GetClass()->IsChildOf(UFlowNodeBlueprint::StaticClass())) { - return; - } - - FString NativeParentClassPath; - AssetData.GetTagValue(FBlueprintTags::NativeParentClassPath, NativeParentClassPath); - if (!NativeParentClassPath.IsEmpty()) - { - UObject* Outer = nullptr; - ResolveName(Outer, NativeParentClassPath, false, false); - const UClass* NativeParentClass = FindObject(ANY_PACKAGE, *NativeParentClassPath); + BlueprintFlowNodes.Emplace(AssetData.PackageName, AssetData); - // accept only Flow Node blueprints - if (NativeParentClass && NativeParentClass->IsChildOf(UFlowNode::StaticClass())) + if (!bBatch) { - BlueprintFlowNodes.Emplace(AssetData.PackageName, AssetData); - - if (!bBatch) - { - OnNodeListChanged.Broadcast(); - } + OnNodeListChanged.Broadcast(); } } } From ed056bc2d74e292bc75a23b33d1617105d42c544 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Thu, 20 Oct 2022 00:36:40 +0200 Subject: [PATCH 176/338] fixed adding user output pins --- Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 28f302105..91eb93198 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -854,10 +854,10 @@ void UFlowGraphNode::AddInstancePin(const EEdGraphPinDirection Direction, const } else { - FlowNode->InputPins.Add(PinName); + FlowNode->OutputPins.Add(PinName); } - CreateOutputPin(PinName, NumberedPinsAmount); + CreateOutputPin(PinName, FlowNode->InputPins.Num() + NumberedPinsAmount); } GetGraph()->NotifyGraphChanged(); From 833e1a58a80545caa4d09ffc286afac82104bd0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 23 Oct 2022 22:02:33 +0200 Subject: [PATCH 177/338] Play Level Sequence improvements #102, #105: Transform Origin and playback replication --- .../LevelSequence/FlowLevelSequenceActor.cpp | 10 +-- .../LevelSequence/FlowLevelSequencePlayer.cpp | 79 +++++++++++-------- .../World/FlowNode_PlayLevelSequence.cpp | 5 +- .../LevelSequence/FlowLevelSequenceActor.h | 13 ++- .../LevelSequence/FlowLevelSequencePlayer.h | 22 ++++-- .../Nodes/World/FlowNode_PlayLevelSequence.h | 15 ++-- .../FlowNode_PlayLevelSequenceDetails.cpp | 2 + 7 files changed, 83 insertions(+), 63 deletions(-) diff --git a/Source/Flow/Private/LevelSequence/FlowLevelSequenceActor.cpp b/Source/Flow/Private/LevelSequence/FlowLevelSequenceActor.cpp index bcb0cdedb..ae97484e4 100644 --- a/Source/Flow/Private/LevelSequence/FlowLevelSequenceActor.cpp +++ b/Source/Flow/Private/LevelSequence/FlowLevelSequenceActor.cpp @@ -5,8 +5,8 @@ #include "Net/UnrealNetwork.h" AFlowLevelSequenceActor::AFlowLevelSequenceActor(const FObjectInitializer& ObjectInitializer) - : Super(ObjectInitializer - .SetDefaultSubobjectClass("AnimationPlayer")) + : Super(ObjectInitializer.SetDefaultSubobjectClass("AnimationPlayer")) + , ReplicatedLevelSequenceAsset(nullptr) { } @@ -29,9 +29,7 @@ void AFlowLevelSequenceActor::SetReplicatedLevelSequenceAsset(ULevelSequence* As void AFlowLevelSequenceActor::OnRep_ReplicatedLevelSequenceAsset() { LevelSequenceAsset = ReplicatedLevelSequenceAsset; -} + ReplicatedLevelSequenceAsset = nullptr; -void AFlowLevelSequenceActor::RPC_InitializePlayer_Implementation() -{ InitializePlayer(); -}; +} diff --git a/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp b/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp index 011760d90..29f51f385 100644 --- a/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp +++ b/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp @@ -12,7 +12,16 @@ UFlowLevelSequencePlayer::UFlowLevelSequencePlayer(const FObjectInitializer& Obj { } -UFlowLevelSequencePlayer* UFlowLevelSequencePlayer::CreateFlowLevelSequencePlayer(UObject* WorldContextObject, ULevelSequence* LevelSequence, FMovieSceneSequencePlaybackSettings Settings, FLevelSequenceCameraSettings CameraSettings, AActor* TransformOriginActor, bool bReplicates, ALevelSequenceActor*& OutActor) +UFlowLevelSequencePlayer* UFlowLevelSequencePlayer::CreateFlowLevelSequencePlayer( + const UObject* WorldContextObject, + ULevelSequence* LevelSequence, + FMovieSceneSequencePlaybackSettings Settings, + FLevelSequenceCameraSettings CameraSettings, + AActor* TransformOriginActor, + const bool bReplicates, + const bool bAlwaysRelevant, + ALevelSequenceActor*& OutActor +) { if (LevelSequence == nullptr) { @@ -25,53 +34,53 @@ UFlowLevelSequencePlayer* UFlowLevelSequencePlayer::CreateFlowLevelSequencePlaye return nullptr; } - FActorSpawnParameters SpawnParams; - SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; - SpawnParams.ObjectFlags |= RF_Transient; - SpawnParams.bAllowDuringConstructionScript = true; - - // Defer construction for autoplay so that BeginPlay() is called - SpawnParams.bDeferConstruction = true; - - AFlowLevelSequenceActor* Actor = World->SpawnActor(SpawnParams); + // Sequence Actor might be spawned exactly where playback happens + FTransform SpawnTransform = FTransform::Identity; + { + // apply Transform Origin + // https://docs.unrealengine.com/5.0/en-US/creating-level-sequences-with-dynamic-transforms-in-unreal-engine/ + if (IsValid(TransformOriginActor)) + { + // moving Level Sequence Actor might allow proper distance-based actor replication in networked games + SpawnTransform = TransformOriginActor->GetTransform(); + SpawnTransform = FTransform(SpawnTransform.GetRotation(), SpawnTransform.GetLocation(), FVector::OneVector); + } + } + // Create Sequence Actor + // We use deferred spawn, so we can set all actor properties prior to its initialization. + // This also helpful in case of multiplayer, since all actor settings are replicated with the spawned actor. No need to call replication just after spawn. + AFlowLevelSequenceActor* Actor = World->SpawnActorDeferred(AFlowLevelSequenceActor::StaticClass(), SpawnTransform, nullptr, nullptr, ESpawnActorCollisionHandlingMethod::AlwaysSpawn); Actor->PlaybackSettings = Settings; Actor->CameraSettings = CameraSettings; + + // apply Transform Origin to spawned actor + if (IsValid(TransformOriginActor)) + { + if (UDefaultLevelSequenceInstanceData* InstanceData = Cast(Actor->DefaultInstanceData)) + { + Actor->bOverrideInstanceData = true; + InstanceData->TransformOriginActor = TransformOriginActor; + } + } + + // support networking if (bReplicates) { + Actor->bReplicatePlayback = true; + Actor->bAlwaysRelevant = bAlwaysRelevant; Actor->SetReplicatedLevelSequenceAsset(LevelSequence); - Actor->SetReplicatePlayback(true); - Actor->bAlwaysRelevant = true; - Actor->RPC_InitializePlayer(); } else { Actor->LevelSequenceAsset = LevelSequence; - Actor->InitializePlayer(); } - OutActor = Actor; - - { - FTransform DefaultTransform; - - // apply Transform Origin - // https://docs.unrealengine.com/5.0/en-US/creating-level-sequences-with-dynamic-transforms-in-unreal-engine/ - if (IsValid(TransformOriginActor)) - { - if (UDefaultLevelSequenceInstanceData* InstanceData = Cast(Actor->DefaultInstanceData)) - { - Actor->bOverrideInstanceData = true; - InstanceData->TransformOriginActor = TransformOriginActor; - // moving Level Sequence Actor might allow proper distance-based actor replication in networked games - const FTransform OriginTransform = TransformOriginActor->GetTransform(); - DefaultTransform = FTransform(OriginTransform.GetRotation(), OriginTransform.GetLocation(), FVector::OneVector); - } - } + // finish deferred spawn + Actor->FinishSpawning(SpawnTransform); + OutActor = Actor; - Actor->FinishSpawning(DefaultTransform); - } - + // Sequence Player is created by Level Sequence Actor return Cast(Actor->SequencePlayer); } diff --git a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp index 9a7063abe..b0dfa8a70 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp @@ -19,8 +19,9 @@ FFlowNodeLevelSequenceEvent UFlowNode_PlayLevelSequence::OnPlaybackCompleted; UFlowNode_PlayLevelSequence::UFlowNode_PlayLevelSequence(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) , bPlayReverse(false) - , bReplicates(false) , bUseGraphOwnerAsTransformOrigin(false) + , bReplicates(false) + , bAlwaysRelevant(false) , bApplyOwnerTimeDilation(true) , LoadedSequence(nullptr) , SequencePlayer(nullptr) @@ -157,7 +158,7 @@ void UFlowNode_PlayLevelSequence::CreatePlayer() AActor* TransformOriginActor = bUseGraphOwnerAsTransformOrigin ? OwningActor : nullptr; // Finally create the player - SequencePlayer = UFlowLevelSequencePlayer::CreateFlowLevelSequencePlayer(this, LoadedSequence, PlaybackSettings, CameraSettings, TransformOriginActor, bReplicates, SequenceActor); + SequencePlayer = UFlowLevelSequencePlayer::CreateFlowLevelSequencePlayer(this, LoadedSequence, PlaybackSettings, CameraSettings, TransformOriginActor, bReplicates, bAlwaysRelevant, SequenceActor); if (SequencePlayer) { diff --git a/Source/Flow/Public/LevelSequence/FlowLevelSequenceActor.h b/Source/Flow/Public/LevelSequence/FlowLevelSequenceActor.h index c84cc538e..8242cae05 100644 --- a/Source/Flow/Public/LevelSequence/FlowLevelSequenceActor.h +++ b/Source/Flow/Public/LevelSequence/FlowLevelSequenceActor.h @@ -13,19 +13,16 @@ class FLOW_API AFlowLevelSequenceActor : public ALevelSequenceActor { GENERATED_UCLASS_BODY() -protected: +protected: + UPROPERTY(ReplicatedUsing = OnRep_ReplicatedLevelSequenceAsset) + TObjectPtr ReplicatedLevelSequenceAsset; + virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; - + public: void SetReplicatedLevelSequenceAsset(ULevelSequence* Asset); - UFUNCTION(NetMulticast, Reliable) - void RPC_InitializePlayer(); - protected: - UPROPERTY(ReplicatedUsing = OnRep_ReplicatedLevelSequenceAsset) - TObjectPtr ReplicatedLevelSequenceAsset; - UFUNCTION() void OnRep_ReplicatedLevelSequenceAsset(); }; diff --git a/Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h b/Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h index 8818a9786..3e98e11c4 100644 --- a/Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h +++ b/Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h @@ -13,20 +13,28 @@ class UFlowNode; UCLASS() class FLOW_API UFlowLevelSequencePlayer : public ULevelSequencePlayer { - GENERATED_UCLASS_BODY() + GENERATED_UCLASS_BODY() private: - // most likely this is a UFlowNode_PlayLevelSequence or its child - UPROPERTY() - UFlowNode* FlowEventReceiver; + // most likely this is a UFlowNode_PlayLevelSequence or its child + UPROPERTY() + UFlowNode* FlowEventReceiver; public: - // variant of ULevelSequencePlayer::CreateLevelSequencePlayer - static UFlowLevelSequencePlayer* CreateFlowLevelSequencePlayer(UObject* WorldContextObject, ULevelSequence* LevelSequence, FMovieSceneSequencePlaybackSettings Settings, FLevelSequenceCameraSettings CameraSettings, AActor* TransformOriginActor, bool bReplicates, ALevelSequenceActor*& OutActor); + // variant of ULevelSequencePlayer::CreateLevelSequencePlayer + static UFlowLevelSequencePlayer* CreateFlowLevelSequencePlayer( + const UObject* WorldContextObject, + ULevelSequence* LevelSequence, + FMovieSceneSequencePlaybackSettings Settings, + FLevelSequenceCameraSettings CameraSettings, + AActor* TransformOriginActor, + const bool bReplicates, + const bool bAlwaysRelevant, + ALevelSequenceActor*& OutActor); void SetFlowEventReceiver(UFlowNode* FlowNode) { FlowEventReceiver = FlowNode; } // IMovieScenePlayer virtual TArray GetEventContexts() const override; - // -- + // -- }; diff --git a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h index ac526fe1c..b46cad5df 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h @@ -38,9 +38,6 @@ class FLOW_API UFlowNode_PlayLevelSequence : public UFlowNode UPROPERTY(EditAnywhere, Category = "Sequence") bool bPlayReverse; - UPROPERTY(EditAnywhere, Category = "Sequence") - bool bReplicates; - UPROPERTY(EditAnywhere, Category = "Sequence") FLevelSequenceCameraSettings CameraSettings; @@ -49,8 +46,16 @@ class FLOW_API UFlowNode_PlayLevelSequence : public UFlowNode // https://docs.unrealengine.com/5.0/en-US/creating-level-sequences-with-dynamic-transforms-in-unreal-engine/ UPROPERTY(EditAnywhere, Category = "Sequence") bool bUseGraphOwnerAsTransformOrigin; - - // if True, Play Rate will by multiplied by Custom Time Dilation + + // If true, playback of this level sequence on the server will be synchronized across other clients + UPROPERTY(EditAnywhere, Category = "Sequence") + bool bReplicates; + + // Always relevant for network (overrides bOnlyRelevantToOwner) + UPROPERTY(EditAnywhere, Category = "Sequence") + bool bAlwaysRelevant; + + // If True, Play Rate will by multiplied by Custom Time Dilation // Enabling this option will use Custom Time Dilation from actor that created Root Flow instance, i.e. World Settings or Player Controller UPROPERTY(EditAnywhere, Category = "Sequence") bool bApplyOwnerTimeDilation; diff --git a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.cpp b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.cpp index f57695a0c..3f1374fed 100644 --- a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.cpp +++ b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.cpp @@ -14,5 +14,7 @@ void FFlowNode_PlayLevelSequenceDetails::CustomizeDetails(IDetailLayoutBuilder& SequenceCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UFlowNode_PlayLevelSequence, bPlayReverse)); SequenceCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UFlowNode_PlayLevelSequence, CameraSettings)); SequenceCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UFlowNode_PlayLevelSequence, bUseGraphOwnerAsTransformOrigin)); + SequenceCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UFlowNode_PlayLevelSequence, bReplicates)); + SequenceCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UFlowNode_PlayLevelSequence, bAlwaysRelevant)); SequenceCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UFlowNode_PlayLevelSequence, bApplyOwnerTimeDilation)); } From da47bd5ff22e907f319867dc72af8739c184de13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 30 Oct 2022 14:31:51 +0100 Subject: [PATCH 178/338] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d6f18b4d0..97056f896 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ The aim of publishing it as open-source project is to let people tell great stor ## In-depth video presentation This 24-minute presentation breaks down the concept of the Flow Graph. It goes through everything written in this ReadMe but in greater detail. -[![Introducing Flow Graph for Unreal Engine](https://img.youtube.com/vi/Rj76JP1f-I4/0.jpg)](https://www.youtube.com/watch?v=BAqhccgKx_k) +[![Introducing Flow Graph for Unreal Engine](https://img.youtube.com/vi/BAqhccgKx_k/0.jpg)](https://www.youtube.com/watch?v=BAqhccgKx_k) ## Acknowledgements I got an opportunity to work on something like the Flow Graph at Reikon Games. They shared my enthusiasm for providing the plugin as open source and as such allowed me to publish this work and keep expanding it as a personal project. Kudos, guys! From 5c273a986c790580c79e554bb0966df680fac654 Mon Sep 17 00:00:00 2001 From: sturcotte06 Date: Tue, 8 Nov 2022 11:15:00 -0500 Subject: [PATCH 179/338] Fix instance names to be truly unique (#123) Co-authored-by: Simon Turcotte-Langevin --- Source/Flow/Private/FlowSubsystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index bcbdde0e9..122b46f70 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -208,7 +208,7 @@ UFlowAsset* UFlowSubsystem::CreateFlowInstance(const TWeakObjectPtr Own // it won't be empty, if we're restoring Flow Asset instance from the SaveGame if (NewInstanceName.IsEmpty()) { - NewInstanceName = FPaths::GetBaseFilename(FlowAsset.Get()->GetPathName()) + TEXT("_") + FString::FromInt(FlowAsset.Get()->GetInstancesNum()); + NewInstanceName = MakeUniqueObjectName(this, UFlowAsset::StaticClass(), *FPaths::GetBaseFilename(FlowAsset.Get()->GetPathName())).ToString(); } UFlowAsset* NewInstance = NewObject(this, FlowAsset->GetClass(), *NewInstanceName, RF_Transient, FlowAsset.Get(), false, nullptr); From 22f79185f490102f6c7a212221bd5cf1db458e23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Tue, 8 Nov 2022 23:08:58 +0100 Subject: [PATCH 180/338] cosmetic cleanup --- .../Private/Nodes/Route/FlowNode_Timer.cpp | 30 +++++++++---------- .../World/FlowNode_PlayLevelSequence.cpp | 1 - 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp index d55703707..6583fd6c7 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp @@ -7,11 +7,11 @@ UFlowNode_Timer::UFlowNode_Timer(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) - , CompletionTime(1.0f) - , StepTime(0.0f) - , SumOfSteps(0.0f) - , RemainingCompletionTime(0.0f) - , RemainingStepTime(0.0f) + , CompletionTime(1.0f) + , StepTime(0.0f) + , SumOfSteps(0.0f) + , RemainingCompletionTime(0.0f) + , RemainingStepTime(0.0f) { #if WITH_EDITOR Category = TEXT("Route"); @@ -138,17 +138,18 @@ void UFlowNode_Timer::OnSave_Implementation() void UFlowNode_Timer::OnLoad_Implementation() { - if (RemainingStepTime > 0.0f) + if (RemainingStepTime > 0.0f || RemainingCompletionTime > 0.0f) { - GetWorld()->GetTimerManager().SetTimer(StepTimerHandle, this, &UFlowNode_Timer::OnStep, StepTime, true, - RemainingStepTime); - } + if (RemainingStepTime > 0.0f) + { + GetWorld()->GetTimerManager().SetTimer(StepTimerHandle, this, &UFlowNode_Timer::OnStep, StepTime, true, RemainingStepTime); + } - GetWorld()->GetTimerManager().SetTimer(CompletionTimerHandle, this, &UFlowNode_Timer::OnCompletion, - RemainingCompletionTime, false); + GetWorld()->GetTimerManager().SetTimer(CompletionTimerHandle, this, &UFlowNode_Timer::OnCompletion, RemainingCompletionTime, false); - RemainingStepTime = 0.0f; - RemainingCompletionTime = 0.0f; + RemainingStepTime = 0.0f; + RemainingCompletionTime = 0.0f; + } } #if WITH_EDITOR @@ -177,8 +178,7 @@ FString UFlowNode_Timer::GetStatusString() const if (CompletionTimerHandle.IsValid() && GetWorld()) { - return TEXT("Progress: ") + GetProgressAsString( - GetWorld()->GetTimerManager().GetTimerElapsed(CompletionTimerHandle)); + return TEXT("Progress: ") + GetProgressAsString(GetWorld()->GetTimerManager().GetTimerElapsed(CompletionTimerHandle)); } return FString(); diff --git a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp index b0dfa8a70..428951044 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp @@ -221,7 +221,6 @@ void UFlowNode_PlayLevelSequence::OnLoad_Implementation() if (ElapsedTime != 0.0f) { LoadedSequence = LoadAsset(Sequence); - if (GetFlowSubsystem()->GetWorld() && LoadedSequence) { CreatePlayer(); From 4b2be4fd35be89de701a5bfa630b4b5ee0fbc6ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Tue, 8 Nov 2022 23:10:43 +0100 Subject: [PATCH 181/338] last rogue new line fixed --- Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp index 6583fd6c7..3e14f88cb 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp @@ -159,8 +159,7 @@ FString UFlowNode_Timer::GetNodeDescription() const { if (StepTime > 0.0f) { - return FString::SanitizeFloat(CompletionTime, 2).Append(TEXT(", step by ")).Append( - FString::SanitizeFloat(StepTime, 2)); + return FString::SanitizeFloat(CompletionTime, 2).Append(TEXT(", step by ")).Append(FString::SanitizeFloat(StepTime, 2)); } return FString::SanitizeFloat(CompletionTime, 2); From d45d5ba47b07590b91ac5230ffce3a06c7631a8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 11 Nov 2022 12:48:34 +0100 Subject: [PATCH 182/338] implemented Signal Modes: Enabled (default), Disabled, Pass Through https://github.com/MothCocoon/FlowGraph/wiki/Signal-Modes --- Source/Flow/Private/Nodes/FlowNode.cpp | 71 +++++++++++--- Source/Flow/Private/Nodes/FlowPin.cpp | 7 +- .../Nodes/Route/FlowNode_CustomInput.cpp | 1 + .../Nodes/Route/FlowNode_CustomOutput.cpp | 1 + .../Route/FlowNode_ExecutionMultiGate.cpp | 1 + .../Route/FlowNode_ExecutionSequence.cpp | 1 + .../Private/Nodes/Route/FlowNode_Finish.cpp | 1 + .../Private/Nodes/Route/FlowNode_Reroute.cpp | 2 + .../Private/Nodes/Route/FlowNode_Start.cpp | 1 + Source/Flow/Public/FlowTypes.h | 8 ++ Source/Flow/Public/Nodes/FlowNode.h | 20 +++- Source/Flow/Public/Nodes/FlowPin.h | 15 ++- .../Private/Asset/FlowAssetEditor.cpp | 46 ++++++++- .../FlowEditor/Private/FlowEditorCommands.cpp | 3 + .../FlowGraphConnectionDrawingPolicy.cpp | 49 +++++----- .../Private/Graph/Nodes/FlowGraphNode.cpp | 59 ++++++++++-- .../Private/Graph/Widgets/SFlowGraphNode.cpp | 96 ++++++++++++++++++- .../FlowEditor/Public/Asset/FlowAssetEditor.h | 5 + Source/FlowEditor/Public/FlowEditorCommands.h | 3 + .../Public/Graph/Nodes/FlowGraphNode.h | 12 ++- .../Public/Graph/Widgets/SFlowGraphNode.h | 9 ++ 21 files changed, 355 insertions(+), 56 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 7230d2771..549bb11a4 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -31,6 +31,8 @@ UFlowNode::UFlowNode(const FObjectInitializer& ObjectInitializer) , bCanDuplicate(true) , bNodeDeprecated(false) #endif + , AllowedSignalModes({EFlowSignalMode::Enabled, EFlowSignalMode::Disabled, EFlowSignalMode::PassThrough}) + , SignalMode(EFlowSignalMode::Enabled) , bPreloaded(false) , ActivationState(EFlowNodeState::NeverActivated) { @@ -381,22 +383,30 @@ void UFlowNode::OnActivate() K2_OnActivate(); } -void UFlowNode::TriggerInput(const FName& PinName, const bool bForcedActivation /*= false*/) +void UFlowNode::TriggerInput(const FName& PinName, const EFlowPinActivationType ActivationType /*= Default*/) { + if (SignalMode == EFlowSignalMode::Disabled) + { + // entirely ignore any Input activation + } + if (InputPins.Contains(PinName)) { - const EFlowNodeState PreviousActivationState = ActivationState; - if (PreviousActivationState != EFlowNodeState::Active) + if (SignalMode == EFlowSignalMode::Enabled) { - OnActivate(); - } + const EFlowNodeState PreviousActivationState = ActivationState; + if (PreviousActivationState != EFlowNodeState::Active) + { + OnActivate(); + } - ActivationState = EFlowNodeState::Active; + ActivationState = EFlowNodeState::Active; + } #if !UE_BUILD_SHIPPING // record for debugging TArray& Records = InputRecords.FindOrAdd(PinName); - Records.Add(FPinRecord(FApp::GetCurrentTime(), bForcedActivation)); + Records.Add(FPinRecord(FApp::GetCurrentTime(), ActivationType)); #endif // UE_BUILD_SHIPPING #if WITH_EDITOR @@ -414,7 +424,14 @@ void UFlowNode::TriggerInput(const FName& PinName, const bool bForcedActivation return; } - ExecuteInput(PinName); + if (SignalMode == EFlowSignalMode::Enabled) + { + ExecuteInput(PinName); + } + else if (SignalMode == EFlowSignalMode::PassThrough) + { + OnPassThrough(); + } } void UFlowNode::ExecuteInput(const FName& PinName) @@ -430,7 +447,7 @@ void UFlowNode::TriggerFirstOutput(const bool bFinish) } } -void UFlowNode::TriggerOutput(const FName& PinName, const bool bFinish /*= false*/, const bool bForcedActivation /*= false*/) +void UFlowNode::TriggerOutput(const FName& PinName, const bool bFinish /*= false*/, const EFlowPinActivationType ActivationType /*= Default*/) { // clean up node, if needed if (bFinish) @@ -443,7 +460,7 @@ void UFlowNode::TriggerOutput(const FName& PinName, const bool bFinish /*= false { // record for debugging, even if nothing is connected to this pin TArray& Records = OutputRecords.FindOrAdd(PinName); - Records.Add(FPinRecord(FApp::GetCurrentTime(), bForcedActivation)); + Records.Add(FPinRecord(FApp::GetCurrentTime(), ActivationType)); #if WITH_EDITOR if (GetWorld()->WorldType == EWorldType::PIE && UFlowAsset::GetFlowGraphInterface().IsValid()) @@ -466,9 +483,9 @@ void UFlowNode::TriggerOutput(const FName& PinName, const bool bFinish /*= false } } -void UFlowNode::TriggerOutputPin(const FFlowOutputPinHandle Pin, const bool bFinish, const bool bForcedActivation) +void UFlowNode::TriggerOutputPin(const FFlowOutputPinHandle Pin, const bool bFinish, const EFlowPinActivationType ActivationType /*= Default*/) { - TriggerOutput(Pin.PinName, bFinish, bForcedActivation); + TriggerOutput(Pin.PinName, bFinish, ActivationType); } void UFlowNode::TriggerOutput(const FString& PinName, const bool bFinish) @@ -691,7 +708,20 @@ void UFlowNode::LoadInstance(const FFlowNodeSaveData& NodeRecord) FlowAsset->OnActivationStateLoaded(this); } - OnLoad(); + switch (SignalMode) + { + case EFlowSignalMode::Enabled: + OnLoad(); + break; + case EFlowSignalMode::Disabled: + // designer doesn't want to execute this node's logic at all, so we kill it + Finish(); + break; + case EFlowSignalMode::PassThrough: + OnPassThrough(); + break; + default: ; + } } void UFlowNode::OnSave_Implementation() @@ -701,3 +731,18 @@ void UFlowNode::OnSave_Implementation() void UFlowNode::OnLoad_Implementation() { } + +void UFlowNode::OnPassThrough_Implementation() +{ + // trigger all connected outputs + // pin connections aren't serialized to the SaveGame, so users can safely change connections post game release + for (const FFlowPin& OutputPin : OutputPins) + { + if (Connections.Contains(OutputPin.PinName)) + { + TriggerOutput(OutputPin.PinName, false, EFlowPinActivationType::PassThrough); + } + } + + Finish(); +} diff --git a/Source/Flow/Private/Nodes/FlowPin.cpp b/Source/Flow/Private/Nodes/FlowPin.cpp index 3ae2a42d5..d072bd140 100644 --- a/Source/Flow/Private/Nodes/FlowPin.cpp +++ b/Source/Flow/Private/Nodes/FlowPin.cpp @@ -7,17 +7,18 @@ FString FPinRecord::NoActivations = TEXT("No activations"); FString FPinRecord::PinActivations = TEXT("Pin activations"); FString FPinRecord::ForcedActivation = TEXT(" (forced activation)"); +FString FPinRecord::PassThroughActivation = TEXT(" (pass-through activation)"); FPinRecord::FPinRecord() : Time(0.0f) , HumanReadableTime(FString()) - , bForcedActivation(false) + , ActivationType(EFlowPinActivationType::Default) { } -FPinRecord::FPinRecord(const double InTime, const bool bInForcedActivation) +FPinRecord::FPinRecord(const double InTime, const EFlowPinActivationType InActivationType) : Time(InTime) - , bForcedActivation(bInForcedActivation) + , ActivationType(InActivationType) { const FDateTime SystemTime(FDateTime::Now()); HumanReadableTime = DoubleDigit(SystemTime.GetHour()) + TEXT(".") diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp index a4f2f6aca..bfa30140d 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp @@ -11,6 +11,7 @@ UFlowNode_CustomInput::UFlowNode_CustomInput(const FObjectInitializer& ObjectIni #endif InputPins.Empty(); + AllowedSignalModes = {EFlowSignalMode::Enabled, EFlowSignalMode::Disabled}; } void UFlowNode_CustomInput::ExecuteInput(const FName& PinName) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp index fe32ed2ae..48acfe972 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp @@ -14,6 +14,7 @@ UFlowNode_CustomOutput::UFlowNode_CustomOutput(const FObjectInitializer& ObjectI #endif OutputPins.Empty(); + AllowedSignalModes = {EFlowSignalMode::Enabled, EFlowSignalMode::Disabled}; } void UFlowNode_CustomOutput::ExecuteInput(const FName& PinName) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionMultiGate.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionMultiGate.cpp index c8ca5016b..455989751 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionMultiGate.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionMultiGate.cpp @@ -17,6 +17,7 @@ UFlowNode_ExecutionMultiGate::UFlowNode_ExecutionMultiGate(const FObjectInitiali InputPins.Add(FFlowPin(TEXT("Reset"), ResetPinTooltip)); SetNumberedOutputPins(0, 1); + AllowedSignalModes = {EFlowSignalMode::Enabled, EFlowSignalMode::Disabled}; } void UFlowNode_ExecutionMultiGate::ExecuteInput(const FName& PinName) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionSequence.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionSequence.cpp index 93afd9dd9..e7d8d1631 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionSequence.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionSequence.cpp @@ -11,6 +11,7 @@ UFlowNode_ExecutionSequence::UFlowNode_ExecutionSequence(const FObjectInitialize #endif SetNumberedOutputPins(0, 1); + AllowedSignalModes = {EFlowSignalMode::Enabled, EFlowSignalMode::Disabled}; } void UFlowNode_ExecutionSequence::ExecuteInput(const FName& PinName) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_Finish.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_Finish.cpp index ba6a5e635..7001d8617 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_Finish.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_Finish.cpp @@ -11,6 +11,7 @@ UFlowNode_Finish::UFlowNode_Finish(const FObjectInitializer& ObjectInitializer) #endif OutputPins = {}; + AllowedSignalModes = {EFlowSignalMode::Enabled, EFlowSignalMode::Disabled}; } void UFlowNode_Finish::ExecuteInput(const FName& PinName) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_Reroute.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_Reroute.cpp index 3f002b6bd..cf9d012d3 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_Reroute.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_Reroute.cpp @@ -8,6 +8,8 @@ UFlowNode_Reroute::UFlowNode_Reroute(const FObjectInitializer& ObjectInitializer #if WITH_EDITOR Category = TEXT("Route"); #endif + + AllowedSignalModes = {EFlowSignalMode::Enabled, EFlowSignalMode::Disabled}; } void UFlowNode_Reroute::ExecuteInput(const FName& PinName) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_Start.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_Start.cpp index 746c01adf..01fcae6fb 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_Start.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_Start.cpp @@ -12,6 +12,7 @@ UFlowNode_Start::UFlowNode_Start(const FObjectInitializer& ObjectInitializer) #endif InputPins = {}; + AllowedSignalModes = {EFlowSignalMode::Enabled, EFlowSignalMode::Disabled}; } void UFlowNode_Start::ExecuteInput(const FName& PinName) diff --git a/Source/Flow/Public/FlowTypes.h b/Source/Flow/Public/FlowTypes.h index 11dec7977..334a6d254 100644 --- a/Source/Flow/Public/FlowTypes.h +++ b/Source/Flow/Public/FlowTypes.h @@ -39,6 +39,14 @@ enum class EFlowFinishPolicy : uint8 Abort }; +UENUM(BlueprintType) +enum class EFlowSignalMode : uint8 +{ + Enabled UMETA(ToolTip = "Node executes its logic."), + Disabled UMETA(ToolTip = "No logic executed, any Input Pin activation is ignored"), + PassThrough UMETA(ToolTip = "No logic executed, but signal pass through from Input Pin to assigned Output Pin") +}; + UENUM(BlueprintType) enum class EFlowNetMode : uint8 { diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 086c3a236..2e51e99d4 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -113,6 +113,15 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte protected: virtual bool CanFinishGraph() const { return false; } +protected: + UPROPERTY(EditDefaultsOnly, Category = "FlowNode") + TArray AllowedSignalModes; + + // If enabled, signal will pass through node without calling ExecuteInput() + // Designed to handle patching + UPROPERTY() + EFlowSignalMode SignalMode; + ////////////////////////////////////////////////////////////////////////// // All created pins (default, class-specific and added by user) @@ -258,7 +267,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte void K2_OnActivate(); // Trigger execution of input pin - void TriggerInput(const FName& PinName, const bool bForcedActivation = false); + void TriggerInput(const FName& PinName, const EFlowPinActivationType ActivationType = EFlowPinActivationType::Default); // Method reacting on triggering Input pin virtual void ExecuteInput(const FName& PinName); @@ -272,14 +281,14 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte void TriggerFirstOutput(const bool bFinish); UFUNCTION(BlueprintCallable, Category = "FlowNode", meta = (HidePin = "bForcedActivation")) - void TriggerOutput(const FName& PinName, const bool bFinish = false, const bool bForcedActivation = false); + void TriggerOutput(const FName& PinName, const bool bFinish = false, const EFlowPinActivationType ActivationType = EFlowPinActivationType::Default); void TriggerOutput(const FString& PinName, const bool bFinish = false); void TriggerOutput(const FText& PinName, const bool bFinish = false); void TriggerOutput(const TCHAR* PinName, const bool bFinish = false); - UFUNCTION(BlueprintCallable, Category = "FlowNode", meta = (HidePin = "bForcedActivation")) - void TriggerOutputPin(const FFlowOutputPinHandle Pin, const bool bFinish = false, const bool bForcedActivation = false); + UFUNCTION(BlueprintCallable, Category = "FlowNode", meta = (HidePin = "ActivationType")) + void TriggerOutputPin(const FFlowOutputPinHandle Pin, const bool bFinish = false, const EFlowPinActivationType ActivationType = EFlowPinActivationType::Default); // Finish execution of node, it will call Cleanup UFUNCTION(BlueprintCallable, Category = "FlowNode") @@ -385,6 +394,9 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UFUNCTION(BlueprintNativeEvent, Category = "FlowNode") void OnLoad(); + UFUNCTION(BlueprintNativeEvent, Category = "FlowNode") + void OnPassThrough(); + private: UPROPERTY() TArray InputNames_DEPRECATED; diff --git a/Source/Flow/Public/Nodes/FlowPin.h b/Source/Flow/Public/Nodes/FlowPin.h index 42186bfc9..78ef72c41 100644 --- a/Source/Flow/Public/Nodes/FlowPin.h +++ b/Source/Flow/Public/Nodes/FlowPin.h @@ -20,6 +20,8 @@ struct FLOW_API FFlowPin UPROPERTY(EditDefaultsOnly, Category = "FlowPin") FString PinToolTip; + static inline FName AnyPinName = TEXT("AnyPinName"); + FFlowPin() : PinName(NAME_None) { @@ -180,20 +182,29 @@ struct FLOW_API FConnectedPin } }; +UENUM(BlueprintType) +enum class EFlowPinActivationType : uint8 +{ + Default, + Forced, + PassThrough +}; + // Every time pin is activated, we record it and display this data while user hovers mouse over pin #if !UE_BUILD_SHIPPING struct FLOW_API FPinRecord { double Time; FString HumanReadableTime; - bool bForcedActivation; + EFlowPinActivationType ActivationType; static FString NoActivations; static FString PinActivations; static FString ForcedActivation; + static FString PassThroughActivation; FPinRecord(); - FPinRecord(const double InTime, const bool bInForcedActivation); + FPinRecord(const double InTime, const EFlowPinActivationType InActivationType); private: FORCEINLINE static FString DoubleDigit(const int32 Number); diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index 5a7d22a0b..858f8e440 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -476,13 +476,34 @@ void FFlowAssetEditor::BindGraphCommands() ); // Execution Override commands + ToolkitCommands->MapAction(FlowGraphCommands.EnableNode, + FExecuteAction::CreateSP(this, &FFlowAssetEditor::SetSignalMode, EFlowSignalMode::Enabled), + FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanSetSignalMode, EFlowSignalMode::Enabled), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanSetSignalMode, EFlowSignalMode::Enabled) + ); + + ToolkitCommands->MapAction(FlowGraphCommands.DisableNode, + FExecuteAction::CreateSP(this, &FFlowAssetEditor::SetSignalMode, EFlowSignalMode::Disabled), + FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanSetSignalMode, EFlowSignalMode::Disabled), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanSetSignalMode, EFlowSignalMode::Disabled) + ); + + ToolkitCommands->MapAction(FlowGraphCommands.SetPassThrough, + FExecuteAction::CreateSP(this, &FFlowAssetEditor::SetSignalMode, EFlowSignalMode::PassThrough), + FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanSetSignalMode, EFlowSignalMode::PassThrough), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanSetSignalMode, EFlowSignalMode::PassThrough) + ); + ToolkitCommands->MapAction(FlowGraphCommands.ForcePinActivation, FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnForcePinActivation), FCanExecuteAction::CreateStatic(&FFlowAssetEditor::IsPIE), FIsActionChecked(), FIsActionButtonVisible::CreateStatic(&FFlowAssetEditor::IsPIE) ); - + // Jump commands ToolkitCommands->MapAction(FlowGraphCommands.FocusViewport, FExecuteAction::CreateSP(this, &FFlowAssetEditor::FocusViewport), @@ -1238,6 +1259,29 @@ bool FFlowAssetEditor::CanTogglePinBreakpoint() const return FocusedGraphEditor->GetGraphPinForMenu() != nullptr; } +void FFlowAssetEditor::SetSignalMode(const EFlowSignalMode Mode) const +{ + for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + { + SelectedNode->SetSignalMode(Mode); + } +} + +bool FFlowAssetEditor::CanSetSignalMode(const EFlowSignalMode Mode) const +{ + if (IsPIE()) + { + return false; + } + + for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + { + return SelectedNode->CanSetSignalMode(Mode); + } + + return false; +} + void FFlowAssetEditor::OnForcePinActivation() const { if (UEdGraphPin* Pin = FocusedGraphEditor->GetGraphPinForMenu()) diff --git a/Source/FlowEditor/Private/FlowEditorCommands.cpp b/Source/FlowEditor/Private/FlowEditorCommands.cpp index 4cee7ffe4..d9b5f37bb 100644 --- a/Source/FlowEditor/Private/FlowEditorCommands.cpp +++ b/Source/FlowEditor/Private/FlowEditorCommands.cpp @@ -42,6 +42,9 @@ void FFlowGraphCommands::RegisterCommands() UI_COMMAND(DisablePinBreakpoint, "Disable Pin Breakpoint", "Disables a breakpoint on the pin", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(TogglePinBreakpoint, "Toggle Pin Breakpoint", "Toggles a breakpoint on the pin", EUserInterfaceActionType::Button, FInputChord()); + UI_COMMAND(EnableNode, "Enable Node", "Enable node execution", EUserInterfaceActionType::Button, FInputChord()); + UI_COMMAND(DisableNode, "Disable Node", "Any Input Pin activation would be ignored", EUserInterfaceActionType::Button, FInputChord()); + UI_COMMAND(SetPassThrough, "Set Pass Through", "Signal will pass through node without executing its logic", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(ForcePinActivation, "Force Pin Activation", "Forces execution of the pin in a graph, used to bypass blockers", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(FocusViewport, "Focus Viewport", "Focus viewport on actor assigned to the node", EUserInterfaceActionType::Button, FInputChord()); diff --git a/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp b/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp index 4d462c1d7..78397fd7f 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp @@ -127,32 +127,15 @@ void FFlowGraphConnectionDrawingPolicy::DetermineWiringStyle(UEdGraphPin* Output check(GraphObj); const UEdGraphSchema* Schema = GraphObj->GetSchema(); - { - //If reroute node path goes backwards, we need to flip the direction to make it look nice - //(all of the logic for this is basically same as in FKismetConnectionDrawingPolicy) - UEdGraphNode* OutputNode = OutputPin->GetOwningNode(); - UEdGraphNode* InputNode = (InputPin != nullptr) ? InputPin->GetOwningNode() : nullptr; - if (auto* OutputRerouteNode = Cast(OutputNode)) - { - if (ShouldChangeTangentForReroute(OutputRerouteNode)) - { - Params.StartDirection = EGPD_Input; - } - } - - if (auto* InputRerouteNode = Cast(InputNode)) - { - if (ShouldChangeTangentForReroute(InputRerouteNode)) - { - Params.EndDirection = EGPD_Output; - } - } - } - if (OutputPin->bOrphanedPin || (InputPin && InputPin->bOrphanedPin)) { Params.WireColor = FLinearColor::Red; } + else if (Cast(OutputPin->GetOwningNode())->GetSignalMode() == EFlowSignalMode::Disabled) + { + Params.WireColor *= 0.5f; + Params.WireThickness = 0.5f; + } else { Params.WireColor = Schema->GetPinTypeColor(OutputPin->PinType); @@ -191,6 +174,28 @@ void FFlowGraphConnectionDrawingPolicy::DetermineWiringStyle(UEdGraphPin* Output Params.WireThickness = InactiveWireThickness; } } + + // If reroute node path goes backwards, we need to flip the direction to make it look nice + // (all of the logic for this is basically same as in FKismetConnectionDrawingPolicy) + { + UEdGraphNode* OutputNode = OutputPin->GetOwningNode(); + UEdGraphNode* InputNode = (InputPin != nullptr) ? InputPin->GetOwningNode() : nullptr; + if (auto* OutputRerouteNode = Cast(OutputNode)) + { + if (ShouldChangeTangentForReroute(OutputRerouteNode)) + { + Params.StartDirection = EGPD_Input; + } + } + + if (auto* InputRerouteNode = Cast(InputNode)) + { + if (ShouldChangeTangentForReroute(InputRerouteNode)) + { + Params.EndDirection = EGPD_Output; + } + } + } } void FFlowGraphConnectionDrawingPolicy::Draw(TMap, FArrangedWidget>& InPinGeometries, FArrangedChildren& ArrangedNodes) diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 91eb93198..4eb48e408 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -524,6 +524,22 @@ void UFlowGraphNode::GetNodeContextMenuActions(class UToolMenu* Menu, class UGra Section.AddMenuEntry(GraphCommands.ToggleBreakpoint); } + { + FToolMenuSection& Section = Menu->AddSection("FlowGraphNodeExecutionOverride", LOCTEXT("NodeExecutionOverrideMenuHeader", "Execution Override")); + if (CanSetSignalMode(EFlowSignalMode::Enabled)) + { + Section.AddMenuEntry(FlowGraphCommands.EnableNode); + } + if (CanSetSignalMode(EFlowSignalMode::Disabled)) + { + Section.AddMenuEntry(FlowGraphCommands.DisableNode); + } + if (CanSetSignalMode(EFlowSignalMode::PassThrough)) + { + Section.AddMenuEntry(FlowGraphCommands.SetPassThrough); + } + } + { FToolMenuSection& Section = Menu->AddSection("FlowGraphNodeJumps", LOCTEXT("NodeJumpsMenuHeader", "Jumps")); if (CanFocusViewport()) @@ -749,7 +765,7 @@ void UFlowGraphNode::CreateInputPin(const FFlowPin& FlowPin, const int32 Index / NewPin->bAllowFriendlyName = true; NewPin->PinFriendlyName = FlowPin.PinFriendlyName; } - + NewPin->PinToolTip = FlowPin.PinToolTip; InputPins.Emplace(NewPin); @@ -832,7 +848,7 @@ void UFlowGraphNode::AddInstancePin(const EEdGraphPinDirection Direction, const Modify(); const FFlowPin PinName = FFlowPin(FString::FromInt(NumberedPinsAmount)); - + if (Direction == EGPD_Input) { if (FlowNode->InputPins.IsValidIndex(NumberedPinsAmount)) @@ -843,7 +859,7 @@ void UFlowGraphNode::AddInstancePin(const EEdGraphPinDirection Direction, const { FlowNode->InputPins.Add(PinName); } - + CreateInputPin(PinName, NumberedPinsAmount); } else @@ -856,7 +872,7 @@ void UFlowGraphNode::AddInstancePin(const EEdGraphPinDirection Direction, const { FlowNode->OutputPins.Add(PinName); } - + CreateOutputPin(PinName, FlowNode->InputPins.Num() + NumberedPinsAmount); } @@ -950,9 +966,17 @@ void UFlowGraphNode::GetPinHoverText(const UEdGraphPin& Pin, FString& HoverTextO HoverTextOut.Append(LINE_TERMINATOR); HoverTextOut.Appendf(TEXT("%d) %s"), i + 1, *PinRecords[i].HumanReadableTime); - if (PinRecords[i].bForcedActivation) + switch (PinRecords[i].ActivationType) { - HoverTextOut.Append(FPinRecord::ForcedActivation); + case EFlowPinActivationType::Default: + break; + case EFlowPinActivationType::Forced: + HoverTextOut.Append(FPinRecord::ForcedActivation); + break; + case EFlowPinActivationType::PassThrough: + HoverTextOut.Append(FPinRecord::PassThroughActivation); + break; + default: ; } } } @@ -1035,14 +1059,33 @@ void UFlowGraphNode::ForcePinActivation(const FEdGraphPinReference PinReference) switch (FoundPin->Direction) { case EGPD_Input: - InspectedNodeInstance->TriggerInput(FoundPin->PinName, true); + InspectedNodeInstance->TriggerInput(FoundPin->PinName, EFlowPinActivationType::Forced); break; case EGPD_Output: - InspectedNodeInstance->TriggerOutput(FoundPin->PinName, false, true); + InspectedNodeInstance->TriggerOutput(FoundPin->PinName, false, EFlowPinActivationType::Forced); break; default: ; } } } +void UFlowGraphNode::SetSignalMode(const EFlowSignalMode Mode) +{ + if (FlowNode) + { + FlowNode->SignalMode = Mode; + OnSignalModeChanged.ExecuteIfBound(); + } +} + +EFlowSignalMode UFlowGraphNode::GetSignalMode() const +{ + return FlowNode ? FlowNode->SignalMode : EFlowSignalMode::Disabled; +} + +bool UFlowGraphNode::CanSetSignalMode(const EFlowSignalMode Mode) const +{ + return FlowNode ? (FlowNode->AllowedSignalModes.Contains(Mode) && FlowNode->SignalMode != Mode) : false; +} + #undef LOCTEXT_NAMESPACE diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp index f906f6781..c6e72260f 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp @@ -27,6 +27,8 @@ #include "Widgets/Layout/SBorder.h" #include "Widgets/SBoxPanel.h" #include "Widgets/SOverlay.h" +#include "Widgets/SToolTip.h" +#include "Widgets/Text/SInlineEditableTextBlock.h" #define LOCTEXT_NAMESPACE "SFlowGraphNode" @@ -44,7 +46,9 @@ void SFlowGraphPinExec::Construct(const FArguments& InArgs, UEdGraphPin* InPin) void SFlowGraphNode::Construct(const FArguments& InArgs, UFlowGraphNode* InNode) { GraphNode = InNode; + FlowGraphNode = InNode; + FlowGraphNode->OnSignalModeChanged.BindRaw(this, &SFlowGraphNode::UpdateGraphNode); SetCursor(EMouseCursor::CardinalCross); UpdateGraphNode(); @@ -213,7 +217,7 @@ void SFlowGraphNode::UpdateGraphNode() [ SNew(SImage) .Image(IconBrush) - .ColorAndOpacity(this, &SGraphNode::GetNodeTitleIconColor) + .ColorAndOpacity(this, &SFlowGraphNode::GetNodeTitleIconColor) ] + SHorizontalBox::Slot() [ @@ -308,7 +312,7 @@ void SFlowGraphNode::UpdateGraphNode() [ SNew(SImage) .Image(GetNodeBodyBrush()) - .ColorAndOpacity(this, &SGraphNode::GetNodeBodyColor) + .ColorAndOpacity(this, &SFlowGraphNode::GetNodeBodyColor) ] + SOverlay::Slot() [ @@ -368,6 +372,20 @@ void SFlowGraphNode::UpdateErrorInfo() SGraphNode::UpdateErrorInfo(); } +TSharedRef SFlowGraphNode::CreateTitleWidget(TSharedPtr NodeTitle) +{ + SAssignNew(InlineEditableText, SInlineEditableTextBlock) + .Style(FAppStyle::Get(), "Graph.Node.NodeTitleInlineEditableText") + .Text(NodeTitle.Get(), &SNodeTitle::GetHeadTitle) + .OnVerifyTextChanged(this, &SFlowGraphNode::OnVerifyNameTextChanged) + .OnTextCommitted(this, &SFlowGraphNode::OnNameTextCommited) + .IsReadOnly(this, &SFlowGraphNode::IsNameReadOnly) + .IsSelected(this, &SFlowGraphNode::IsSelectedExclusively); + InlineEditableText->SetColorAndOpacity(TAttribute::Create(TAttribute::FGetter::CreateSP(this, &SFlowGraphNode::GetNodeTitleTextColor))); + + return InlineEditableText.ToSharedRef(); +} + TSharedRef SFlowGraphNode::CreateNodeContentArea() { return SNew(SBorder) @@ -396,6 +414,80 @@ const FSlateBrush* SFlowGraphNode::GetNodeBodyBrush() const return FFlowEditorStyle::GetBrush("Flow.Node.Body"); } +FSlateColor SFlowGraphNode::GetNodeTitleColor() const +{ + FLinearColor ReturnTitleColor = GraphNode->IsDeprecated() ? FLinearColor::Red : GetNodeObj()->GetNodeTitleColor(); + + if (FlowGraphNode->GetSignalMode() == EFlowSignalMode::Enabled) + { + ReturnTitleColor.A = FadeCurve.GetLerp(); + } + else + { + ReturnTitleColor *= FLinearColor(0.5f, 0.5f, 0.5f, 0.4f); + } + + return ReturnTitleColor; +} + +FSlateColor SFlowGraphNode::GetNodeBodyColor() const +{ + FLinearColor ReturnBodyColor = GraphNode->GetNodeBodyTintColor(); + if (FlowGraphNode->GetSignalMode() != EFlowSignalMode::Enabled) + { + ReturnBodyColor *= FLinearColor(1.0f, 1.0f, 1.0f, 0.5f); + } + return ReturnBodyColor; +} + +FSlateColor SFlowGraphNode::GetNodeTitleIconColor() const +{ + FLinearColor ReturnIconColor = IconColor; + if (FlowGraphNode->GetSignalMode() != EFlowSignalMode::Enabled) + { + ReturnIconColor *= FLinearColor(1.0f, 1.0f, 1.0f, 0.3f); + } + return ReturnIconColor; +} + +FLinearColor SFlowGraphNode::GetNodeTitleTextColor() const +{ + FLinearColor ReturnTextColor = FLinearColor::White; + if (FlowGraphNode->GetSignalMode() != EFlowSignalMode::Enabled) + { + ReturnTextColor *= FLinearColor(1.0f, 1.0f, 1.0f, 0.3f); + } + return ReturnTextColor; +} + +TSharedPtr SFlowGraphNode::GetEnabledStateWidget() const +{ + if (FlowGraphNode->GetSignalMode() != EFlowSignalMode::Enabled && !GraphNode->IsAutomaticallyPlacedGhostNode()) + { + const bool bPassThrough = FlowGraphNode->GetSignalMode() == EFlowSignalMode::PassThrough; + const FText StatusMessage = bPassThrough ? LOCTEXT("PassThrough", "Pass Through") : LOCTEXT("DisabledNode", "Disabled"); + const FText StatusMessageTooltip = bPassThrough ? + LOCTEXT("PassThroughTooltip", "This node won't execute internal logic, but it will trigger all connected outputs") : + LOCTEXT("DisabledNodeTooltip", "This node is disabled and will not be executed"); + + return SNew(SBorder) + .BorderImage(FEditorStyle::GetBrush(bPassThrough ? "Graph.Node.DevelopmentBanner" : "Graph.Node.DisabledBanner")) + .HAlign(HAlign_Fill) + .VAlign(VAlign_Fill) + [ + SNew(STextBlock) + .Text(StatusMessage) + .ToolTipText(StatusMessageTooltip) + .Justification(ETextJustify::Center) + .ColorAndOpacity(FLinearColor::White) + .ShadowOffset(FVector2D::UnitVector) + .Visibility(EVisibility::Visible) + ]; + } + + return TSharedPtr(); +} + void SFlowGraphNode::CreateStandardPinWidget(UEdGraphPin* Pin) { const TSharedPtr NewPin = SNew(SFlowGraphPinExec, Pin); diff --git a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h index 96264559c..a72f0f59e 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h @@ -9,6 +9,8 @@ #include "Toolkits/IToolkitHost.h" #include "UObject/GCObject.h" +#include "FlowTypes.h" + class SFlowPalette; class UFlowAsset; class UFlowGraphNode; @@ -206,6 +208,9 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit bool CanToggleBreakpoint() const; bool CanTogglePinBreakpoint() const; + void SetSignalMode(const EFlowSignalMode Mode) const; + bool CanSetSignalMode(const EFlowSignalMode Mode) const; + void OnForcePinActivation() const; void FocusViewport() const; diff --git a/Source/FlowEditor/Public/FlowEditorCommands.h b/Source/FlowEditor/Public/FlowEditorCommands.h index bd6fc6480..16613c857 100644 --- a/Source/FlowEditor/Public/FlowEditorCommands.h +++ b/Source/FlowEditor/Public/FlowEditorCommands.h @@ -40,6 +40,9 @@ class FFlowGraphCommands final : public TCommands TSharedPtr TogglePinBreakpoint; /** Execution Override */ + TSharedPtr EnableNode; + TSharedPtr DisableNode; + TSharedPtr SetPassThrough; TSharedPtr ForcePinActivation; /** Jumps */ diff --git a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h index a47e80e68..7cbc1092f 100644 --- a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h +++ b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h @@ -45,6 +45,8 @@ struct FLOWEDITOR_API FFlowBreakpoint void ToggleBreakpoint(); }; +DECLARE_DELEGATE(FFlowGraphNodeEvent); + /** * Graph representation of the Flow Node */ @@ -221,6 +223,14 @@ class FLOWEDITOR_API UFlowGraphNode : public UEdGraphNode // Execution Override public: + FFlowGraphNodeEvent OnSignalModeChanged; + // Pin activation forced by user during PIE - void ForcePinActivation(const FEdGraphPinReference PinReference) const; + virtual void ForcePinActivation(const FEdGraphPinReference PinReference) const; + + // Pass-through forced by designer, set per node instance + virtual void SetSignalMode(const EFlowSignalMode Mode); + + virtual EFlowSignalMode GetSignalMode() const; + virtual bool CanSetSignalMode(const EFlowSignalMode Mode) const; }; diff --git a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h index d54e948df..3d50e872e 100644 --- a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h +++ b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h @@ -38,9 +38,18 @@ class FLOWEDITOR_API SFlowGraphNode : public SGraphNode // SGraphNode virtual void UpdateGraphNode() override; virtual void UpdateErrorInfo() override; + + virtual TSharedRef CreateTitleWidget(TSharedPtr NodeTitle) override; virtual TSharedRef CreateNodeContentArea() override; virtual const FSlateBrush* GetNodeBodyBrush() const override; + // purposely overriden non-virtual methods, avoiding engine modification + FSlateColor GetNodeTitleColor() const; + FSlateColor GetNodeBodyColor() const; + FSlateColor GetNodeTitleIconColor() const; + FLinearColor GetNodeTitleTextColor() const; + TSharedPtr GetEnabledStateWidget() const; + virtual void CreateStandardPinWidget(UEdGraphPin* Pin) override; virtual TSharedPtr GetComplexTooltip() override; From 04f102ade99354eaa82ea4f91670a7a6d0090ad7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 11 Nov 2022 13:14:52 +0100 Subject: [PATCH 183/338] documentation updates --- Source/Flow/Private/Nodes/FlowNode.cpp | 1 + Source/Flow/Public/FlowTypes.h | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 549bb11a4..995ec1c0c 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -744,5 +744,6 @@ void UFlowNode::OnPassThrough_Implementation() } } + // deactivate node, so it doesn't get saved to a new SaveGame Finish(); } diff --git a/Source/Flow/Public/FlowTypes.h b/Source/Flow/Public/FlowTypes.h index 334a6d254..b45dedba7 100644 --- a/Source/Flow/Public/FlowTypes.h +++ b/Source/Flow/Public/FlowTypes.h @@ -43,8 +43,8 @@ UENUM(BlueprintType) enum class EFlowSignalMode : uint8 { Enabled UMETA(ToolTip = "Node executes its logic."), - Disabled UMETA(ToolTip = "No logic executed, any Input Pin activation is ignored"), - PassThrough UMETA(ToolTip = "No logic executed, but signal pass through from Input Pin to assigned Output Pin") + Disabled UMETA(ToolTip = "No logic executed, any Input Pin activation is ignored. Node instantly enters a deactivated state."), + PassThrough UMETA(ToolTip = "Internal node logic not executed. All connected outputs are triggered, node finishes its work.") }; UENUM(BlueprintType) From bb3b672aa3965437767b5b332e919c0c10372829 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 11 Nov 2022 13:52:57 +0100 Subject: [PATCH 184/338] documentation updates --- Source/Flow/Public/FlowTypes.h | 2 +- Source/FlowEditor/Private/FlowEditorCommands.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/Flow/Public/FlowTypes.h b/Source/Flow/Public/FlowTypes.h index b45dedba7..235cc366a 100644 --- a/Source/Flow/Public/FlowTypes.h +++ b/Source/Flow/Public/FlowTypes.h @@ -42,7 +42,7 @@ enum class EFlowFinishPolicy : uint8 UENUM(BlueprintType) enum class EFlowSignalMode : uint8 { - Enabled UMETA(ToolTip = "Node executes its logic."), + Enabled UMETA(ToolTip = "Default state, node is fully executed."), Disabled UMETA(ToolTip = "No logic executed, any Input Pin activation is ignored. Node instantly enters a deactivated state."), PassThrough UMETA(ToolTip = "Internal node logic not executed. All connected outputs are triggered, node finishes its work.") }; diff --git a/Source/FlowEditor/Private/FlowEditorCommands.cpp b/Source/FlowEditor/Private/FlowEditorCommands.cpp index d9b5f37bb..2b9e7daae 100644 --- a/Source/FlowEditor/Private/FlowEditorCommands.cpp +++ b/Source/FlowEditor/Private/FlowEditorCommands.cpp @@ -42,9 +42,9 @@ void FFlowGraphCommands::RegisterCommands() UI_COMMAND(DisablePinBreakpoint, "Disable Pin Breakpoint", "Disables a breakpoint on the pin", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(TogglePinBreakpoint, "Toggle Pin Breakpoint", "Toggles a breakpoint on the pin", EUserInterfaceActionType::Button, FInputChord()); - UI_COMMAND(EnableNode, "Enable Node", "Enable node execution", EUserInterfaceActionType::Button, FInputChord()); - UI_COMMAND(DisableNode, "Disable Node", "Any Input Pin activation would be ignored", EUserInterfaceActionType::Button, FInputChord()); - UI_COMMAND(SetPassThrough, "Set Pass Through", "Signal will pass through node without executing its logic", EUserInterfaceActionType::Button, FInputChord()); + UI_COMMAND(EnableNode, "Enable Node", "Default state, node is fully executed.", EUserInterfaceActionType::Button, FInputChord()); + UI_COMMAND(DisableNode, "Disable Node", "No logic executed, any Input Pin activation is ignored. Node instantly enters a deactivated state.", EUserInterfaceActionType::Button, FInputChord()); + UI_COMMAND(SetPassThrough, "Set Pass Through", "Internal node logic not executed. All connected outputs are triggered, node finishes its work.", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(ForcePinActivation, "Force Pin Activation", "Forces execution of the pin in a graph, used to bypass blockers", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(FocusViewport, "Focus Viewport", "Focus viewport on actor assigned to the node", EUserInterfaceActionType::Button, FInputChord()); From 8a63ac8c51dbfbd7c9eef6e99d17c1de6621e717 Mon Sep 17 00:00:00 2001 From: "arseniy.zvezda" Date: Mon, 5 Sep 2022 16:13:30 +0300 Subject: [PATCH 185/338] refresh node graph class --- .../Private/Asset/FlowAssetEditor.cpp | 95 ++++++++++++++++++- 1 file changed, 91 insertions(+), 4 deletions(-) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index 858f8e440..880943587 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -33,6 +33,7 @@ #include "ScopedTransaction.h" #include "SNodePanel.h" #include "ToolMenus.h" +#include "Nodes/Route/FlowNode_Start.h" #include "Widgets/Docking/SDockTab.h" #define LOCTEXT_NAMESPACE "FlowAssetEditor" @@ -259,13 +260,99 @@ void FFlowAssetEditor::BindToolbarCommands() void FFlowAssetEditor::RefreshAsset() { - TArray FlowGraphNodes; - FlowAsset->GetGraph()->GetNodesOfClass(FlowGraphNodes); + UEdGraph* Graph = FlowAsset->GetGraph(); + + TMap AssetNodes = FlowAsset->GetNodes(); + + TArray GraphNodes; + Graph->GetNodesOfClass(GraphNodes); + + for (UFlowGraphNode* GraphNode : GraphNodes) + { + UFlowNode* FlowNode = GraphNode->GetFlowNode(); + if (FlowNode) + { + if (!FlowNode->GetGraphNode()) + { + FlowNode->FixNode(GraphNode); + GraphNode->ReconstructNode(); + UE_LOG(LogTemp, Display, TEXT("Node %s fix - Missing GraphNode %s"), *GetNameSafe(FlowNode), *GetNameSafe(GraphNode)); + } + } + } - for (UFlowGraphNode* GraphNode : FlowGraphNodes) + TArray GraphNodesToRemove; + for (auto&& Node : AssetNodes) + { + if (IsValid(Node.Value)) + { + UEdGraphNode* CurrentGraphNode = Node.Value->GetGraphNode(); + + const UClass* CorrectClass = UFlowGraphSchema::GetAssignedGraphNodeClass(Node.Value->GetClass()); + if ((!CurrentGraphNode || CurrentGraphNode->GetClass() != CorrectClass) && + Node.Value->GetClass() != UFlowNode_Start::StaticClass()) + { + UE_LOG(LogTemp, Display, TEXT("Fixing node %s ..."), *GetNameSafe(Node.Value)); + // Create a new node with the correct graph type. + UFlowGraphNode* NewGraphNode = NewObject(Graph, CorrectClass); + + NewGraphNode->NodeGuid = Node.Value->GetGuid(); + if (CurrentGraphNode) + { + NewGraphNode->NodePosX = CurrentGraphNode->NodePosX; + NewGraphNode->NodePosY = CurrentGraphNode->NodePosY; + } + else + { + NewGraphNode->NodePosX = 0; + NewGraphNode->NodePosY = 0; + } + + Graph->AddNode(NewGraphNode, false, false); + + NewGraphNode->SetFlowNode(Node.Value); + + Node.Value->FixNode(NewGraphNode); + + NewGraphNode->PostPlacedNewNode(); + NewGraphNode->AllocateDefaultPins(); + + if (CurrentGraphNode) + { + // Move links from the old node to the new node. + for (UEdGraphPin* OldNodePin : CurrentGraphNode->Pins) + { + if (UEdGraphPin** NewNodePin = NewGraphNode->Pins.FindByPredicate( + [OldNodePin](const UEdGraphPin* GraphPin) + { + return GraphPin->PinName == OldNodePin->PinName; + })) + { + TArray Connections = OldNodePin->LinkedTo; + OldNodePin->BreakAllPinLinks(true); + for (UEdGraphPin* const Connection : Connections) + { + (*(NewNodePin))->MakeLinkTo(Connection); + } + } + } + + // Remove the old node. + GraphNodesToRemove.Add(CurrentGraphNode); + } + + } + } + } + + for (UEdGraphNode* RemovedGraphNode : GraphNodesToRemove) { - GraphNode->RefreshContextPins(true); + UE_LOG(LogTemp, Display, TEXT("Deleting node %s"), *GetNameSafe(RemovedGraphNode)); + const FGuid NodeGuid = RemovedGraphNode->NodeGuid; + FBlueprintEditorUtils::RemoveNode(nullptr, RemovedGraphNode, true); + // GetFlowAsset()->UnregisterNode(NodeGuid); } + Graph->NotifyGraphChanged(); } void FFlowAssetEditor::GoToParentInstance() From 43dbae644d201d6a41735f9d3fcc0753529fcf3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Tue, 15 Nov 2022 22:27:20 +0100 Subject: [PATCH 186/338] reverting last pull request --- .../Private/Asset/FlowAssetEditor.cpp | 95 +------------------ 1 file changed, 4 insertions(+), 91 deletions(-) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index 880943587..858f8e440 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -33,7 +33,6 @@ #include "ScopedTransaction.h" #include "SNodePanel.h" #include "ToolMenus.h" -#include "Nodes/Route/FlowNode_Start.h" #include "Widgets/Docking/SDockTab.h" #define LOCTEXT_NAMESPACE "FlowAssetEditor" @@ -260,99 +259,13 @@ void FFlowAssetEditor::BindToolbarCommands() void FFlowAssetEditor::RefreshAsset() { - UEdGraph* Graph = FlowAsset->GetGraph(); - - TMap AssetNodes = FlowAsset->GetNodes(); - - TArray GraphNodes; - Graph->GetNodesOfClass(GraphNodes); - - for (UFlowGraphNode* GraphNode : GraphNodes) - { - UFlowNode* FlowNode = GraphNode->GetFlowNode(); - if (FlowNode) - { - if (!FlowNode->GetGraphNode()) - { - FlowNode->FixNode(GraphNode); - GraphNode->ReconstructNode(); - UE_LOG(LogTemp, Display, TEXT("Node %s fix - Missing GraphNode %s"), *GetNameSafe(FlowNode), *GetNameSafe(GraphNode)); - } - } - } + TArray FlowGraphNodes; + FlowAsset->GetGraph()->GetNodesOfClass(FlowGraphNodes); - TArray GraphNodesToRemove; - for (auto&& Node : AssetNodes) - { - if (IsValid(Node.Value)) - { - UEdGraphNode* CurrentGraphNode = Node.Value->GetGraphNode(); - - const UClass* CorrectClass = UFlowGraphSchema::GetAssignedGraphNodeClass(Node.Value->GetClass()); - if ((!CurrentGraphNode || CurrentGraphNode->GetClass() != CorrectClass) && - Node.Value->GetClass() != UFlowNode_Start::StaticClass()) - { - UE_LOG(LogTemp, Display, TEXT("Fixing node %s ..."), *GetNameSafe(Node.Value)); - // Create a new node with the correct graph type. - UFlowGraphNode* NewGraphNode = NewObject(Graph, CorrectClass); - - NewGraphNode->NodeGuid = Node.Value->GetGuid(); - if (CurrentGraphNode) - { - NewGraphNode->NodePosX = CurrentGraphNode->NodePosX; - NewGraphNode->NodePosY = CurrentGraphNode->NodePosY; - } - else - { - NewGraphNode->NodePosX = 0; - NewGraphNode->NodePosY = 0; - } - - Graph->AddNode(NewGraphNode, false, false); - - NewGraphNode->SetFlowNode(Node.Value); - - Node.Value->FixNode(NewGraphNode); - - NewGraphNode->PostPlacedNewNode(); - NewGraphNode->AllocateDefaultPins(); - - if (CurrentGraphNode) - { - // Move links from the old node to the new node. - for (UEdGraphPin* OldNodePin : CurrentGraphNode->Pins) - { - if (UEdGraphPin** NewNodePin = NewGraphNode->Pins.FindByPredicate( - [OldNodePin](const UEdGraphPin* GraphPin) - { - return GraphPin->PinName == OldNodePin->PinName; - })) - { - TArray Connections = OldNodePin->LinkedTo; - OldNodePin->BreakAllPinLinks(true); - for (UEdGraphPin* const Connection : Connections) - { - (*(NewNodePin))->MakeLinkTo(Connection); - } - } - } - - // Remove the old node. - GraphNodesToRemove.Add(CurrentGraphNode); - } - - } - } - } - - for (UEdGraphNode* RemovedGraphNode : GraphNodesToRemove) + for (UFlowGraphNode* GraphNode : FlowGraphNodes) { - UE_LOG(LogTemp, Display, TEXT("Deleting node %s"), *GetNameSafe(RemovedGraphNode)); - const FGuid NodeGuid = RemovedGraphNode->NodeGuid; - FBlueprintEditorUtils::RemoveNode(nullptr, RemovedGraphNode, true); - // GetFlowAsset()->UnregisterNode(NodeGuid); + GraphNode->RefreshContextPins(true); } - Graph->NotifyGraphChanged(); } void FFlowAssetEditor::GoToParentInstance() From ba67531b0d3bb9156d42dc93a0f2cdb2a711028c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Tue, 15 Nov 2022 22:28:38 +0100 Subject: [PATCH 187/338] cleanup --- Source/Flow/Private/Nodes/FlowNode.cpp | 6 +++--- Source/Flow/Public/Nodes/FlowNode.h | 2 +- Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 995ec1c0c..650a2ab17 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -65,12 +65,12 @@ void UFlowNode::PostLoad() FixNode(nullptr); } -void UFlowNode::FixNode(UEdGraphNode* NewGraph) +void UFlowNode::FixNode(UEdGraphNode* NewGraphNode) { // Fix any node pointers that may be out of date - if (NewGraph) + if (NewGraphNode) { - GraphNode = NewGraph; + GraphNode = NewGraphNode; } // v1.1 upgraded pins to be defined as structs diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 2e51e99d4..d76d97a69 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -73,7 +73,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte // -- // Opportunity to update node's data before UFlowGraphNode would call ReconstructNode() - virtual void FixNode(UEdGraphNode* NewGraph); + virtual void FixNode(UEdGraphNode* NewGraphNode); #endif UEdGraphNode* GetGraphNode() const { return GraphNode; } diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 4eb48e408..3c5d81619 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -1085,7 +1085,7 @@ EFlowSignalMode UFlowGraphNode::GetSignalMode() const bool UFlowGraphNode::CanSetSignalMode(const EFlowSignalMode Mode) const { - return FlowNode ? (FlowNode->AllowedSignalModes.Contains(Mode) && FlowNode->SignalMode != Mode) : false; + return FlowNode ? (FlowNode->AllowedSignalModes.Contains(Mode) && FlowNode->SignalMode != Mode) : false; } #undef LOCTEXT_NAMESPACE From d2ef639bb2e8bf72e131e4386f6ef27fbf0bba16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Wed, 16 Nov 2022 01:01:51 +0100 Subject: [PATCH 188/338] removed properties deprecated in version 1.1 --- Source/Flow/Private/FlowWorldSettings.cpp | 10 ---------- Source/Flow/Private/Nodes/FlowNode.cpp | 16 ---------------- .../Nodes/World/FlowNode_ComponentObserver.cpp | 10 ---------- .../Private/Nodes/World/FlowNode_NotifyActor.cpp | 16 ---------------- .../Nodes/World/FlowNode_OnNotifyFromActor.cpp | 10 ---------- Source/Flow/Public/FlowWorldSettings.h | 4 ---- Source/Flow/Public/Nodes/FlowNode.h | 7 ------- .../Nodes/World/FlowNode_ComponentObserver.h | 6 ------ .../Public/Nodes/World/FlowNode_NotifyActor.h | 10 ---------- .../Nodes/World/FlowNode_OnNotifyFromActor.h | 6 ------ 10 files changed, 95 deletions(-) diff --git a/Source/Flow/Private/FlowWorldSettings.cpp b/Source/Flow/Private/FlowWorldSettings.cpp index 82526f4b7..447fafdbf 100644 --- a/Source/Flow/Private/FlowWorldSettings.cpp +++ b/Source/Flow/Private/FlowWorldSettings.cpp @@ -14,16 +14,6 @@ AFlowWorldSettings::AFlowWorldSettings(const FObjectInitializer& ObjectInitializ FlowComponent->bAllowMultipleInstances = false; } -void AFlowWorldSettings::PostLoad() -{ - Super::PostLoad(); - - if (FlowAsset_DEPRECATED) - { - FlowComponent->RootFlow = FlowAsset_DEPRECATED; - } -} - void AFlowWorldSettings::PostInitializeComponents() { Super::PostInitializeComponents(); diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 650a2ab17..3bde1928f 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -72,22 +72,6 @@ void UFlowNode::FixNode(UEdGraphNode* NewGraphNode) { GraphNode = NewGraphNode; } - - // v1.1 upgraded pins to be defined as structs - if (InputNames_DEPRECATED.Num() > InputPins.Num()) - { - for (int32 i = InputPins.Num(); i < InputNames_DEPRECATED.Num(); i++) - { - InputPins.Emplace(InputNames_DEPRECATED[i]); - } - } - if (OutputNames_DEPRECATED.Num() > OutputPins.Num()) - { - for (int32 i = OutputPins.Num(); i < OutputNames_DEPRECATED.Num(); i++) - { - OutputPins.Emplace(OutputNames_DEPRECATED[i]); - } - } } void UFlowNode::SetGraphNode(UEdGraphNode* NewGraph) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp index 0ebde212d..bbe89feb1 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp @@ -18,16 +18,6 @@ UFlowNode_ComponentObserver::UFlowNode_ComponentObserver(const FObjectInitialize OutputPins = {FFlowPin(TEXT("Success")), FFlowPin(TEXT("Completed")), FFlowPin(TEXT("Stopped"))}; } -void UFlowNode_ComponentObserver::PostLoad() -{ - Super::PostLoad(); - - if (IdentityTag_DEPRECATED.IsValid()) - { - IdentityTags = FGameplayTagContainer(IdentityTag_DEPRECATED); - } -} - void UFlowNode_ComponentObserver::ExecuteInput(const FName& PinName) { if (IdentityTags.IsValid()) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp b/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp index f9f9c4819..d67df77e5 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp @@ -15,22 +15,6 @@ UFlowNode_NotifyActor::UFlowNode_NotifyActor(const FObjectInitializer& ObjectIni #endif } -void UFlowNode_NotifyActor::PostLoad() -{ - Super::PostLoad(); - - if (IdentityTag_DEPRECATED.IsValid()) - { - IdentityTags = FGameplayTagContainer(IdentityTag_DEPRECATED); - } - - if (NotifyTag_DEPRECATED.IsValid()) - { - NotifyTags = FGameplayTagContainer(NotifyTag_DEPRECATED); - NotifyTag_DEPRECATED = FGameplayTag(); - } -} - void UFlowNode_NotifyActor::ExecuteInput(const FName& PinName) { if (const UFlowSubsystem* FlowSubsystem = GetWorld()->GetGameInstance()->GetSubsystem()) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp b/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp index 4e64bbec1..ae59ecf3a 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp @@ -13,16 +13,6 @@ UFlowNode_OnNotifyFromActor::UFlowNode_OnNotifyFromActor(const FObjectInitialize #endif } -void UFlowNode_OnNotifyFromActor::PostLoad() -{ - Super::PostLoad(); - - if (NotifyTag_DEPRECATED.IsValid()) - { - NotifyTags = FGameplayTagContainer(NotifyTag_DEPRECATED); - } -} - void UFlowNode_OnNotifyFromActor::ExecuteInput(const FName& PinName) { Super::ExecuteInput(PinName); diff --git a/Source/Flow/Public/FlowWorldSettings.h b/Source/Flow/Public/FlowWorldSettings.h index b6fb3dffd..ba1b1dacc 100644 --- a/Source/Flow/Public/FlowWorldSettings.h +++ b/Source/Flow/Public/FlowWorldSettings.h @@ -22,12 +22,8 @@ class FLOW_API AFlowWorldSettings : public AWorldSettings public: UFlowComponent* GetFlowComponent() const { return FlowComponent; } - virtual void PostLoad() override; virtual void PostInitializeComponents() override; private: bool IsValidInstance() const; - - UPROPERTY() - class UFlowAsset* FlowAsset_DEPRECATED; }; diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index d76d97a69..09c7a5eb2 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -396,11 +396,4 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UFUNCTION(BlueprintNativeEvent, Category = "FlowNode") void OnPassThrough(); - -private: - UPROPERTY() - TArray InputNames_DEPRECATED; - - UPROPERTY() - TArray OutputNames_DEPRECATED; }; diff --git a/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h b/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h index 32a7254a8..724768836 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h @@ -41,8 +41,6 @@ class FLOW_API UFlowNode_ComponentObserver : public UFlowNode TMap, TWeakObjectPtr> RegisteredActors; protected: - virtual void PostLoad() override; - virtual void ExecuteInput(const FName& PinName) override; virtual void OnLoad_Implementation() override; @@ -74,8 +72,4 @@ class FLOW_API UFlowNode_ComponentObserver : public UFlowNode virtual FString GetNodeDescription() const override; virtual FString GetStatusString() const override; #endif - -private: - UPROPERTY() - FGameplayTag IdentityTag_DEPRECATED; }; diff --git a/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h b/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h index f637cd27e..228cc47d1 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h @@ -25,20 +25,10 @@ class FLOW_API UFlowNode_NotifyActor : public UFlowNode UPROPERTY(EditAnywhere, Category = "Notify") EFlowNetMode NetMode; - virtual void PostLoad() override; - virtual void ExecuteInput(const FName& PinName) override; #if WITH_EDITOR public: virtual FString GetNodeDescription() const override; #endif - -private: - UPROPERTY() - FGameplayTag IdentityTag_DEPRECATED; - - UPROPERTY() - FGameplayTag NotifyTag_DEPRECATED; - }; diff --git a/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h b/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h index 3cab19a33..9c5f77a7d 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h @@ -22,8 +22,6 @@ class FLOW_API UFlowNode_OnNotifyFromActor : public UFlowNode_ComponentObserver UPROPERTY(EditAnywhere, Category = "Notify") bool bRetroactive; - virtual void PostLoad() override; - virtual void ExecuteInput(const FName& PinName) override; virtual void ObserveActor(TWeakObjectPtr Actor, TWeakObjectPtr Component) override; @@ -35,8 +33,4 @@ class FLOW_API UFlowNode_OnNotifyFromActor : public UFlowNode_ComponentObserver public: virtual FString GetNodeDescription() const override; #endif - -private: - UPROPERTY() - FGameplayTag NotifyTag_DEPRECATED; }; From 76bf7e8080b5f18a793b59c1a248f13db8d0a844 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Wed, 16 Nov 2022 01:01:51 +0100 Subject: [PATCH 189/338] removed properties deprecated in version 1.1 From 730e88c0a8e0dc1642d080e15d1ef86e462faeff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 20 Nov 2022 16:05:30 +0100 Subject: [PATCH 190/338] Revert "removed properties deprecated in version 1.1" This reverts commit d2ef639bb2e8bf72e131e4386f6ef27fbf0bba16. --- Source/Flow/Private/FlowWorldSettings.cpp | 10 ++++++++++ Source/Flow/Private/Nodes/FlowNode.cpp | 16 ++++++++++++++++ .../Nodes/World/FlowNode_ComponentObserver.cpp | 10 ++++++++++ .../Private/Nodes/World/FlowNode_NotifyActor.cpp | 16 ++++++++++++++++ .../Nodes/World/FlowNode_OnNotifyFromActor.cpp | 10 ++++++++++ Source/Flow/Public/FlowWorldSettings.h | 4 ++++ Source/Flow/Public/Nodes/FlowNode.h | 7 +++++++ .../Nodes/World/FlowNode_ComponentObserver.h | 6 ++++++ .../Public/Nodes/World/FlowNode_NotifyActor.h | 10 ++++++++++ .../Nodes/World/FlowNode_OnNotifyFromActor.h | 6 ++++++ 10 files changed, 95 insertions(+) diff --git a/Source/Flow/Private/FlowWorldSettings.cpp b/Source/Flow/Private/FlowWorldSettings.cpp index 447fafdbf..82526f4b7 100644 --- a/Source/Flow/Private/FlowWorldSettings.cpp +++ b/Source/Flow/Private/FlowWorldSettings.cpp @@ -14,6 +14,16 @@ AFlowWorldSettings::AFlowWorldSettings(const FObjectInitializer& ObjectInitializ FlowComponent->bAllowMultipleInstances = false; } +void AFlowWorldSettings::PostLoad() +{ + Super::PostLoad(); + + if (FlowAsset_DEPRECATED) + { + FlowComponent->RootFlow = FlowAsset_DEPRECATED; + } +} + void AFlowWorldSettings::PostInitializeComponents() { Super::PostInitializeComponents(); diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 3bde1928f..650a2ab17 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -72,6 +72,22 @@ void UFlowNode::FixNode(UEdGraphNode* NewGraphNode) { GraphNode = NewGraphNode; } + + // v1.1 upgraded pins to be defined as structs + if (InputNames_DEPRECATED.Num() > InputPins.Num()) + { + for (int32 i = InputPins.Num(); i < InputNames_DEPRECATED.Num(); i++) + { + InputPins.Emplace(InputNames_DEPRECATED[i]); + } + } + if (OutputNames_DEPRECATED.Num() > OutputPins.Num()) + { + for (int32 i = OutputPins.Num(); i < OutputNames_DEPRECATED.Num(); i++) + { + OutputPins.Emplace(OutputNames_DEPRECATED[i]); + } + } } void UFlowNode::SetGraphNode(UEdGraphNode* NewGraph) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp index bbe89feb1..0ebde212d 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp @@ -18,6 +18,16 @@ UFlowNode_ComponentObserver::UFlowNode_ComponentObserver(const FObjectInitialize OutputPins = {FFlowPin(TEXT("Success")), FFlowPin(TEXT("Completed")), FFlowPin(TEXT("Stopped"))}; } +void UFlowNode_ComponentObserver::PostLoad() +{ + Super::PostLoad(); + + if (IdentityTag_DEPRECATED.IsValid()) + { + IdentityTags = FGameplayTagContainer(IdentityTag_DEPRECATED); + } +} + void UFlowNode_ComponentObserver::ExecuteInput(const FName& PinName) { if (IdentityTags.IsValid()) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp b/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp index d67df77e5..f9f9c4819 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp @@ -15,6 +15,22 @@ UFlowNode_NotifyActor::UFlowNode_NotifyActor(const FObjectInitializer& ObjectIni #endif } +void UFlowNode_NotifyActor::PostLoad() +{ + Super::PostLoad(); + + if (IdentityTag_DEPRECATED.IsValid()) + { + IdentityTags = FGameplayTagContainer(IdentityTag_DEPRECATED); + } + + if (NotifyTag_DEPRECATED.IsValid()) + { + NotifyTags = FGameplayTagContainer(NotifyTag_DEPRECATED); + NotifyTag_DEPRECATED = FGameplayTag(); + } +} + void UFlowNode_NotifyActor::ExecuteInput(const FName& PinName) { if (const UFlowSubsystem* FlowSubsystem = GetWorld()->GetGameInstance()->GetSubsystem()) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp b/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp index ae59ecf3a..4e64bbec1 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp @@ -13,6 +13,16 @@ UFlowNode_OnNotifyFromActor::UFlowNode_OnNotifyFromActor(const FObjectInitialize #endif } +void UFlowNode_OnNotifyFromActor::PostLoad() +{ + Super::PostLoad(); + + if (NotifyTag_DEPRECATED.IsValid()) + { + NotifyTags = FGameplayTagContainer(NotifyTag_DEPRECATED); + } +} + void UFlowNode_OnNotifyFromActor::ExecuteInput(const FName& PinName) { Super::ExecuteInput(PinName); diff --git a/Source/Flow/Public/FlowWorldSettings.h b/Source/Flow/Public/FlowWorldSettings.h index ba1b1dacc..b6fb3dffd 100644 --- a/Source/Flow/Public/FlowWorldSettings.h +++ b/Source/Flow/Public/FlowWorldSettings.h @@ -22,8 +22,12 @@ class FLOW_API AFlowWorldSettings : public AWorldSettings public: UFlowComponent* GetFlowComponent() const { return FlowComponent; } + virtual void PostLoad() override; virtual void PostInitializeComponents() override; private: bool IsValidInstance() const; + + UPROPERTY() + class UFlowAsset* FlowAsset_DEPRECATED; }; diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 09c7a5eb2..d76d97a69 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -396,4 +396,11 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UFUNCTION(BlueprintNativeEvent, Category = "FlowNode") void OnPassThrough(); + +private: + UPROPERTY() + TArray InputNames_DEPRECATED; + + UPROPERTY() + TArray OutputNames_DEPRECATED; }; diff --git a/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h b/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h index 724768836..32a7254a8 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h @@ -41,6 +41,8 @@ class FLOW_API UFlowNode_ComponentObserver : public UFlowNode TMap, TWeakObjectPtr> RegisteredActors; protected: + virtual void PostLoad() override; + virtual void ExecuteInput(const FName& PinName) override; virtual void OnLoad_Implementation() override; @@ -72,4 +74,8 @@ class FLOW_API UFlowNode_ComponentObserver : public UFlowNode virtual FString GetNodeDescription() const override; virtual FString GetStatusString() const override; #endif + +private: + UPROPERTY() + FGameplayTag IdentityTag_DEPRECATED; }; diff --git a/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h b/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h index 228cc47d1..f637cd27e 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h @@ -25,10 +25,20 @@ class FLOW_API UFlowNode_NotifyActor : public UFlowNode UPROPERTY(EditAnywhere, Category = "Notify") EFlowNetMode NetMode; + virtual void PostLoad() override; + virtual void ExecuteInput(const FName& PinName) override; #if WITH_EDITOR public: virtual FString GetNodeDescription() const override; #endif + +private: + UPROPERTY() + FGameplayTag IdentityTag_DEPRECATED; + + UPROPERTY() + FGameplayTag NotifyTag_DEPRECATED; + }; diff --git a/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h b/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h index 9c5f77a7d..3cab19a33 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h @@ -22,6 +22,8 @@ class FLOW_API UFlowNode_OnNotifyFromActor : public UFlowNode_ComponentObserver UPROPERTY(EditAnywhere, Category = "Notify") bool bRetroactive; + virtual void PostLoad() override; + virtual void ExecuteInput(const FName& PinName) override; virtual void ObserveActor(TWeakObjectPtr Actor, TWeakObjectPtr Component) override; @@ -33,4 +35,8 @@ class FLOW_API UFlowNode_OnNotifyFromActor : public UFlowNode_ComponentObserver public: virtual FString GetNodeDescription() const override; #endif + +private: + UPROPERTY() + FGameplayTag NotifyTag_DEPRECATED; }; From c71400dabce29c49d9b4214da6d2acd605993a56 Mon Sep 17 00:00:00 2001 From: ryanjon2040 Date: Fri, 18 Nov 2022 18:57:00 +0530 Subject: [PATCH 191/338] Mark asset as dirty after changing signal mode --- Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index 858f8e440..46dd2daa2 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -1265,6 +1265,8 @@ void FFlowAssetEditor::SetSignalMode(const EFlowSignalMode Mode) const { SelectedNode->SetSignalMode(Mode); } + + FlowAsset->Modify(); } bool FFlowAssetEditor::CanSetSignalMode(const EFlowSignalMode Mode) const From 596c79e4f0db3c840990221c7a3976e4d60cff49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Mon, 21 Nov 2022 21:30:47 +0100 Subject: [PATCH 192/338] Revert "Revert "removed properties deprecated in version 1.1"" This reverts commit 730e88c0a8e0dc1642d080e15d1ef86e462faeff. --- Source/Flow/Private/FlowWorldSettings.cpp | 10 ---------- Source/Flow/Private/Nodes/FlowNode.cpp | 16 ---------------- .../Nodes/World/FlowNode_ComponentObserver.cpp | 10 ---------- .../Private/Nodes/World/FlowNode_NotifyActor.cpp | 16 ---------------- .../Nodes/World/FlowNode_OnNotifyFromActor.cpp | 10 ---------- Source/Flow/Public/FlowWorldSettings.h | 4 ---- Source/Flow/Public/Nodes/FlowNode.h | 7 ------- .../Nodes/World/FlowNode_ComponentObserver.h | 6 ------ .../Public/Nodes/World/FlowNode_NotifyActor.h | 10 ---------- .../Nodes/World/FlowNode_OnNotifyFromActor.h | 6 ------ 10 files changed, 95 deletions(-) diff --git a/Source/Flow/Private/FlowWorldSettings.cpp b/Source/Flow/Private/FlowWorldSettings.cpp index 82526f4b7..447fafdbf 100644 --- a/Source/Flow/Private/FlowWorldSettings.cpp +++ b/Source/Flow/Private/FlowWorldSettings.cpp @@ -14,16 +14,6 @@ AFlowWorldSettings::AFlowWorldSettings(const FObjectInitializer& ObjectInitializ FlowComponent->bAllowMultipleInstances = false; } -void AFlowWorldSettings::PostLoad() -{ - Super::PostLoad(); - - if (FlowAsset_DEPRECATED) - { - FlowComponent->RootFlow = FlowAsset_DEPRECATED; - } -} - void AFlowWorldSettings::PostInitializeComponents() { Super::PostInitializeComponents(); diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 650a2ab17..3bde1928f 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -72,22 +72,6 @@ void UFlowNode::FixNode(UEdGraphNode* NewGraphNode) { GraphNode = NewGraphNode; } - - // v1.1 upgraded pins to be defined as structs - if (InputNames_DEPRECATED.Num() > InputPins.Num()) - { - for (int32 i = InputPins.Num(); i < InputNames_DEPRECATED.Num(); i++) - { - InputPins.Emplace(InputNames_DEPRECATED[i]); - } - } - if (OutputNames_DEPRECATED.Num() > OutputPins.Num()) - { - for (int32 i = OutputPins.Num(); i < OutputNames_DEPRECATED.Num(); i++) - { - OutputPins.Emplace(OutputNames_DEPRECATED[i]); - } - } } void UFlowNode::SetGraphNode(UEdGraphNode* NewGraph) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp index 0ebde212d..bbe89feb1 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp @@ -18,16 +18,6 @@ UFlowNode_ComponentObserver::UFlowNode_ComponentObserver(const FObjectInitialize OutputPins = {FFlowPin(TEXT("Success")), FFlowPin(TEXT("Completed")), FFlowPin(TEXT("Stopped"))}; } -void UFlowNode_ComponentObserver::PostLoad() -{ - Super::PostLoad(); - - if (IdentityTag_DEPRECATED.IsValid()) - { - IdentityTags = FGameplayTagContainer(IdentityTag_DEPRECATED); - } -} - void UFlowNode_ComponentObserver::ExecuteInput(const FName& PinName) { if (IdentityTags.IsValid()) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp b/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp index f9f9c4819..d67df77e5 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp @@ -15,22 +15,6 @@ UFlowNode_NotifyActor::UFlowNode_NotifyActor(const FObjectInitializer& ObjectIni #endif } -void UFlowNode_NotifyActor::PostLoad() -{ - Super::PostLoad(); - - if (IdentityTag_DEPRECATED.IsValid()) - { - IdentityTags = FGameplayTagContainer(IdentityTag_DEPRECATED); - } - - if (NotifyTag_DEPRECATED.IsValid()) - { - NotifyTags = FGameplayTagContainer(NotifyTag_DEPRECATED); - NotifyTag_DEPRECATED = FGameplayTag(); - } -} - void UFlowNode_NotifyActor::ExecuteInput(const FName& PinName) { if (const UFlowSubsystem* FlowSubsystem = GetWorld()->GetGameInstance()->GetSubsystem()) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp b/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp index 4e64bbec1..ae59ecf3a 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp @@ -13,16 +13,6 @@ UFlowNode_OnNotifyFromActor::UFlowNode_OnNotifyFromActor(const FObjectInitialize #endif } -void UFlowNode_OnNotifyFromActor::PostLoad() -{ - Super::PostLoad(); - - if (NotifyTag_DEPRECATED.IsValid()) - { - NotifyTags = FGameplayTagContainer(NotifyTag_DEPRECATED); - } -} - void UFlowNode_OnNotifyFromActor::ExecuteInput(const FName& PinName) { Super::ExecuteInput(PinName); diff --git a/Source/Flow/Public/FlowWorldSettings.h b/Source/Flow/Public/FlowWorldSettings.h index b6fb3dffd..ba1b1dacc 100644 --- a/Source/Flow/Public/FlowWorldSettings.h +++ b/Source/Flow/Public/FlowWorldSettings.h @@ -22,12 +22,8 @@ class FLOW_API AFlowWorldSettings : public AWorldSettings public: UFlowComponent* GetFlowComponent() const { return FlowComponent; } - virtual void PostLoad() override; virtual void PostInitializeComponents() override; private: bool IsValidInstance() const; - - UPROPERTY() - class UFlowAsset* FlowAsset_DEPRECATED; }; diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index d76d97a69..09c7a5eb2 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -396,11 +396,4 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UFUNCTION(BlueprintNativeEvent, Category = "FlowNode") void OnPassThrough(); - -private: - UPROPERTY() - TArray InputNames_DEPRECATED; - - UPROPERTY() - TArray OutputNames_DEPRECATED; }; diff --git a/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h b/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h index 32a7254a8..724768836 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h @@ -41,8 +41,6 @@ class FLOW_API UFlowNode_ComponentObserver : public UFlowNode TMap, TWeakObjectPtr> RegisteredActors; protected: - virtual void PostLoad() override; - virtual void ExecuteInput(const FName& PinName) override; virtual void OnLoad_Implementation() override; @@ -74,8 +72,4 @@ class FLOW_API UFlowNode_ComponentObserver : public UFlowNode virtual FString GetNodeDescription() const override; virtual FString GetStatusString() const override; #endif - -private: - UPROPERTY() - FGameplayTag IdentityTag_DEPRECATED; }; diff --git a/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h b/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h index f637cd27e..228cc47d1 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h @@ -25,20 +25,10 @@ class FLOW_API UFlowNode_NotifyActor : public UFlowNode UPROPERTY(EditAnywhere, Category = "Notify") EFlowNetMode NetMode; - virtual void PostLoad() override; - virtual void ExecuteInput(const FName& PinName) override; #if WITH_EDITOR public: virtual FString GetNodeDescription() const override; #endif - -private: - UPROPERTY() - FGameplayTag IdentityTag_DEPRECATED; - - UPROPERTY() - FGameplayTag NotifyTag_DEPRECATED; - }; diff --git a/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h b/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h index 3cab19a33..9c5f77a7d 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h @@ -22,8 +22,6 @@ class FLOW_API UFlowNode_OnNotifyFromActor : public UFlowNode_ComponentObserver UPROPERTY(EditAnywhere, Category = "Notify") bool bRetroactive; - virtual void PostLoad() override; - virtual void ExecuteInput(const FName& PinName) override; virtual void ObserveActor(TWeakObjectPtr Actor, TWeakObjectPtr Component) override; @@ -35,8 +33,4 @@ class FLOW_API UFlowNode_OnNotifyFromActor : public UFlowNode_ComponentObserver public: virtual FString GetNodeDescription() const override; #endif - -private: - UPROPERTY() - FGameplayTag NotifyTag_DEPRECATED; }; From 3a127e4171afffe788e7f828918ee48100bd2368 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Mon, 21 Nov 2022 22:38:57 +0100 Subject: [PATCH 193/338] bump to 1.4 --- Flow.uplugin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.uplugin b/Flow.uplugin index fdba8368f..1f165bb4a 100644 --- a/Flow.uplugin +++ b/Flow.uplugin @@ -1,6 +1,6 @@ { "FileVersion" : 3, - "Version" : 1.3, + "Version" : 1.4, "FriendlyName" : "Flow", "Description" : "Design-agnostic node editor for scripting game’s flow.", "Category" : "Gameplay", From 39e1db488b281c0231934f75354819fedce92f16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 27 Nov 2022 19:56:25 +0100 Subject: [PATCH 194/338] #124 reworked pull request - recreating UFlowGraphNode with a new class on graph load --- Source/FlowEditor/Private/Graph/FlowGraph.cpp | 38 ++++++- .../Private/Graph/FlowGraphSchema.cpp | 67 +++++++------ .../Private/Graph/FlowGraphSchema_Actions.cpp | 99 ++++++++++++++++--- Source/FlowEditor/Public/Graph/FlowGraph.h | 1 + .../FlowEditor/Public/Graph/FlowGraphSchema.h | 7 +- .../Public/Graph/FlowGraphSchema_Actions.h | 1 + 6 files changed, 164 insertions(+), 49 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/FlowGraph.cpp b/Source/FlowEditor/Private/Graph/FlowGraph.cpp index b776077e9..57fc743d0 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraph.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraph.cpp @@ -2,8 +2,11 @@ #include "Graph/FlowGraph.h" #include "Graph/FlowGraphSchema.h" +#include "Graph/FlowGraphSchema_Actions.h" #include "Graph/Nodes/FlowGraphNode.h" +#include "Nodes/FlowNode.h" + #include "Kismet2/BlueprintEditorUtils.h" void FFlowGraphInterface::OnInputTriggered(UEdGraphNode* GraphNode, const int32 Index) const @@ -27,7 +30,7 @@ UFlowGraph::UFlowGraph(const FObjectInitializer& ObjectInitializer) UEdGraph* UFlowGraph::CreateGraph(UFlowAsset* InFlowAsset) { - UFlowGraph* NewGraph = CastChecked(FBlueprintEditorUtils::CreateNewGraph(InFlowAsset, NAME_None, StaticClass(), UFlowGraphSchema::StaticClass())); + UEdGraph* NewGraph = CastChecked(FBlueprintEditorUtils::CreateNewGraph(InFlowAsset, NAME_None, StaticClass(), UFlowGraphSchema::StaticClass())); NewGraph->bAllowDeletion = false; InFlowAsset->FlowGraph = NewGraph; @@ -36,6 +39,37 @@ UEdGraph* UFlowGraph::CreateGraph(UFlowAsset* InFlowAsset) return NewGraph; } +void UFlowGraph::PostLoad() +{ + Super::PostLoad(); + + // gather AssignedGraphNodeClasses before we'd checking nodes below + const UFlowGraphSchema* FlowGraphSchema = CastChecked(GetSchema()); + FlowGraphSchema->GatherNativeNodes(); + + // Check if all Graph Nodes have expected, up-to-date type + bool bAnyUpdate = false; + for (const TPair& Node : GetFlowAsset()->GetNodes()) + { + if (UFlowNode* FlowNode = Node.Value) + { + const UClass* ExpectGraphNodeClass = UFlowGraphSchema::GetAssignedGraphNodeClass(FlowNode->GetClass()); + if (FlowNode->GetGraphNode() && FlowNode->GetGraphNode()->GetClass() != ExpectGraphNodeClass) + { + // Create a new Flow Graph Node of proper type + FFlowGraphSchemaAction_NewNode::RecreateNode(this, FlowNode->GetGraphNode(), FlowNode); + bAnyUpdate = true; + } + } + } + + if (bAnyUpdate) + { + GetFlowAsset()->HarvestNodeConnections(); + GetOutermost()->SetDirtyFlag(true); // force dirty while loading asset + } +} + void UFlowGraph::NotifyGraphChanged() { GetFlowAsset()->HarvestNodeConnections(); @@ -46,5 +80,5 @@ void UFlowGraph::NotifyGraphChanged() UFlowAsset* UFlowGraph::GetFlowAsset() const { - return CastChecked(GetOuter()); + return GetTypedOuter(); } diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp index 12c44493e..4b2668b6c 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -37,7 +37,7 @@ UFlowGraphSchema::UFlowGraphSchema(const FObjectInitializer& ObjectInitializer) void UFlowGraphSchema::SubscribeToAssetChanges() { const FAssetRegistryModule& AssetRegistry = FModuleManager::LoadModuleChecked(AssetRegistryConstants::ModuleName); - AssetRegistry.Get().OnFilesLoaded().AddStatic(&UFlowGraphSchema::GatherFlowNodes); + AssetRegistry.Get().OnFilesLoaded().AddStatic(&UFlowGraphSchema::GatherNodes); AssetRegistry.Get().OnAssetAdded().AddStatic(&UFlowGraphSchema::OnAssetAdded); AssetRegistry.Get().OnAssetRemoved().AddStatic(&UFlowGraphSchema::OnAssetRemoved); @@ -198,7 +198,7 @@ TArray> UFlowGraphSchema::GetFlowNodeCategories() { if (NativeFlowNodes.Num() == 0) { - GatherFlowNodes(); + GatherNodes(); } TSet UnsortedCategories; @@ -316,7 +316,7 @@ void UFlowGraphSchema::GetFlowNodeActions(FGraphActionMenuBuilder& ActionMenuBui { if (NativeFlowNodes.Num() == 0) { - GatherFlowNodes(); + GatherNodes(); } // Flow Asset type might limit which nodes are placeable @@ -390,47 +390,59 @@ void UFlowGraphSchema::OnBlueprintCompiled() { if (bBlueprintCompilationPending) { - GatherFlowNodes(); + GatherNodes(); } bBlueprintCompilationPending = false; } -void UFlowGraphSchema::GatherFlowNodes() +void UFlowGraphSchema::OnHotReload(EReloadCompleteReason ReloadCompleteReason) { - // prevent asset crunching during PIE - if (GEditor && GEditor->PlayWorld) + GatherNodes(); +} + +void UFlowGraphSchema::GatherNativeNodes() +{ + // collect C++ nodes once per editor session + if (NativeFlowNodes.Num() > 0) { return; } - // collect C++ nodes once per editor session - if (NativeFlowNodes.Num() == 0) + TArray FlowNodes; + GetDerivedClasses(UFlowNode::StaticClass(), FlowNodes); + for (UClass* Class : FlowNodes) { - TArray FlowNodes; - GetDerivedClasses(UFlowNode::StaticClass(), FlowNodes); - for (UClass* Class : FlowNodes) + if (Class->ClassGeneratedBy == nullptr && IsFlowNodePlaceable(Class)) { - if (Class->ClassGeneratedBy == nullptr && IsFlowNodePlaceable(Class)) - { - NativeFlowNodes.Emplace(Class); - } + NativeFlowNodes.Emplace(Class); } + } - TArray GraphNodes; - GetDerivedClasses(UFlowGraphNode::StaticClass(), GraphNodes); - for (UClass* Class : GraphNodes) + TArray GraphNodes; + GetDerivedClasses(UFlowGraphNode::StaticClass(), GraphNodes); + for (UClass* Class : GraphNodes) + { + const UFlowGraphNode* DefaultObject = Class->GetDefaultObject(); + for (UClass* AssignedClass : DefaultObject->AssignedNodeClasses) { - const UFlowGraphNode* DefaultObject = Class->GetDefaultObject(); - for (UClass* AssignedClass : DefaultObject->AssignedNodeClasses) + if (AssignedClass->IsChildOf(UFlowNode::StaticClass())) { - if (AssignedClass->IsChildOf(UFlowNode::StaticClass())) - { - AssignedGraphNodeClasses.Emplace(AssignedClass, Class); - } + AssignedGraphNodeClasses.Emplace(AssignedClass, Class); } } } +} + +void UFlowGraphSchema::GatherNodes() +{ + // prevent asset crunching during PIE + if (GEditor && GEditor->PlayWorld) + { + return; + } + + GatherNativeNodes(); // retrieve all blueprint nodes const FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(AssetRegistryConstants::ModuleName); @@ -450,11 +462,6 @@ void UFlowGraphSchema::GatherFlowNodes() OnNodeListChanged.Broadcast(); } -void UFlowGraphSchema::OnHotReload(EReloadCompleteReason ReloadCompleteReason) -{ - GatherFlowNodes(); -} - void UFlowGraphSchema::OnAssetAdded(const FAssetData& AssetData) { AddAsset(AssetData, false); diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp index e19a6b199..f6fbc8e59 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp @@ -14,7 +14,6 @@ #include "EdGraph/EdGraph.h" #include "EdGraphNode_Comment.h" #include "Editor.h" -#include "Layout/SlateRect.h" #include "ScopedTransaction.h" #define LOCTEXT_NAMESPACE "FlowGraphSchema_Actions" @@ -53,37 +52,107 @@ UFlowGraphNode* FFlowGraphSchemaAction_NewNode::CreateNode(UEdGraph* ParentGraph UFlowAsset* FlowAsset = CastChecked(ParentGraph)->GetFlowAsset(); FlowAsset->Modify(); + // create new Flow Graph node const UClass* GraphNodeClass = UFlowGraphSchema::GetAssignedGraphNodeClass(NodeClass); UFlowGraphNode* NewGraphNode = NewObject(ParentGraph, GraphNodeClass, NAME_None, RF_Transactional); - NewGraphNode->CreateNewGuid(); - NewGraphNode->NodePosX = Location.X; - NewGraphNode->NodePosY = Location.Y; + // register to the graph + NewGraphNode->CreateNewGuid(); ParentGraph->AddNode(NewGraphNode, false, bSelectNewNode); - UFlowNode* NewNode = FlowAsset->CreateNode(NodeClass, NewGraphNode); - NewGraphNode->SetFlowNode(NewNode); + // link editor and runtime nodes together + UFlowNode* FlowNode = FlowAsset->CreateNode(NodeClass, NewGraphNode); + NewGraphNode->SetFlowNode(FlowNode); - NewGraphNode->PostPlacedNewNode(); + // create pins and connections NewGraphNode->AllocateDefaultPins(); - NewGraphNode->AutowireNewNode(FromPin); - + + // set position + NewGraphNode->NodePosX = Location.X; + NewGraphNode->NodePosY = Location.Y; + + // call notifies + NewGraphNode->PostPlacedNewNode(); ParentGraph->NotifyGraphChanged(); - const TSharedPtr FlowEditor = FFlowGraphUtils::GetFlowAssetEditor(ParentGraph); - if (FlowEditor.IsValid()) + // select in editor UI + if (bSelectNewNode) { - FlowEditor->SelectSingleNode(NewGraphNode); + const TSharedPtr FlowEditor = FFlowGraphUtils::GetFlowAssetEditor(ParentGraph); + if (FlowEditor.IsValid()) + { + FlowEditor->SelectSingleNode(NewGraphNode); + } } FlowAsset->PostEditChange(); - FlowAsset->MarkPackageDirty(); return NewGraphNode; } -UEdGraphNode* FFlowGraphSchemaAction_Paste::PerformAction(class UEdGraph* ParentGraph, UEdGraphPin* FromPin, const FVector2D Location, bool bSelectNewNode/* = true*/) +UFlowGraphNode* FFlowGraphSchemaAction_NewNode::RecreateNode(UEdGraph* ParentGraph, UEdGraphNode* OldInstance, UFlowNode* FlowNode) +{ + check(FlowNode); + + ParentGraph->Modify(); + + UFlowAsset* FlowAsset = CastChecked(ParentGraph)->GetFlowAsset(); + FlowAsset->Modify(); + + // create new Flow Graph node + const UClass* GraphNodeClass = UFlowGraphSchema::GetAssignedGraphNodeClass(FlowNode->GetClass()); + UFlowGraphNode* NewGraphNode = NewObject(ParentGraph, GraphNodeClass, NAME_None, RF_Transactional); + + // register to the graph + NewGraphNode->NodeGuid = FlowNode->GetGuid(); + ParentGraph->AddNode(NewGraphNode, false, false); + + // link editor and runtime nodes together + FlowNode->SetGraphNode(NewGraphNode); + NewGraphNode->SetFlowNode(FlowNode); + + // move links from the old node + NewGraphNode->AllocateDefaultPins(); + if (OldInstance) + { + for (UEdGraphPin* OldPin : OldInstance->Pins) + { + if (OldPin->LinkedTo.Num() == 0) + { + continue; + } + + for (UEdGraphPin* NewPin : NewGraphNode->Pins) + { + if (NewPin->Direction == OldPin->Direction && NewPin->PinName == OldPin->PinName) + { + TArray Connections = OldPin->LinkedTo; + for (UEdGraphPin* ConnectedPin : Connections) + { + ConnectedPin->BreakLinkTo(OldPin); + ConnectedPin->MakeLinkTo(NewPin); + } + } + } + } + } + + // keep old position + NewGraphNode->NodePosX = OldInstance ? OldInstance->NodePosX : 0; + NewGraphNode->NodePosY = OldInstance ? OldInstance->NodePosY : 0; + + // remove leftover + if (OldInstance) + { + OldInstance->DestroyNode(); + } + + NewGraphNode->PostPlacedNewNode(); + return NewGraphNode; +} + +UEdGraphNode* FFlowGraphSchemaAction_Paste::PerformAction(class UEdGraph* ParentGraph, UEdGraphPin* FromPin, const FVector2D Location, const bool bSelectNewNode/* = true*/) { // prevent adding new nodes while playing if (GEditor->PlayWorld == nullptr) @@ -97,7 +166,7 @@ UEdGraphNode* FFlowGraphSchemaAction_Paste::PerformAction(class UEdGraph* Parent ///////////////////////////////////////////////////// // Comment Node -UEdGraphNode* FFlowGraphSchemaAction_NewComment::PerformAction(class UEdGraph* ParentGraph, UEdGraphPin* FromPin, const FVector2D Location, bool bSelectNewNode/* = true*/) +UEdGraphNode* FFlowGraphSchemaAction_NewComment::PerformAction(class UEdGraph* ParentGraph, UEdGraphPin* FromPin, const FVector2D Location, const bool bSelectNewNode/* = true*/) { // prevent adding new nodes while playing if (GEditor->PlayWorld != nullptr) diff --git a/Source/FlowEditor/Public/Graph/FlowGraph.h b/Source/FlowEditor/Public/Graph/FlowGraph.h index 134562e19..1e92342ad 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraph.h +++ b/Source/FlowEditor/Public/Graph/FlowGraph.h @@ -24,6 +24,7 @@ class FLOWEDITOR_API UFlowGraph : public UEdGraph static UEdGraph* CreateGraph(UFlowAsset* InFlowAsset); // UEdGraph + virtual void PostLoad() override; virtual void NotifyGraphChanged() override; // -- diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h index 592309bc1..842c27788 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h @@ -15,6 +15,8 @@ class FLOWEDITOR_API UFlowGraphSchema : public UEdGraphSchema { GENERATED_UCLASS_BODY() + friend class UFlowGraph; + private: static TArray NativeFlowNodes; static TMap BlueprintFlowNodes; @@ -52,10 +54,11 @@ class FLOWEDITOR_API UFlowGraphSchema : public UEdGraphSchema static void OnBlueprintPreCompile(UBlueprint* Blueprint); static void OnBlueprintCompiled(); - - static void GatherFlowNodes(); static void OnHotReload(EReloadCompleteReason ReloadCompleteReason); + static void GatherNativeNodes(); + static void GatherNodes(); + static void OnAssetAdded(const FAssetData& AssetData); static void AddAsset(const FAssetData& AssetData, const bool bBatch); static void OnAssetRemoved(const FAssetData& AssetData); diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h b/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h index 520f6176a..528934593 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h @@ -48,6 +48,7 @@ struct FLOWEDITOR_API FFlowGraphSchemaAction_NewNode : public FEdGraphSchemaActi // -- static UFlowGraphNode* CreateNode(class UEdGraph* ParentGraph, UEdGraphPin* FromPin, const UClass* NodeClass, const FVector2D Location, const bool bSelectNewNode = true); + static UFlowGraphNode* RecreateNode(UEdGraph* ParentGraph, UEdGraphNode* OldInstance, UFlowNode* FlowNode); }; /** Action to paste clipboard contents into the graph */ From 5e333fea835298c286cff22aef1fa122df196b3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 27 Nov 2022 19:58:35 +0100 Subject: [PATCH 195/338] replaced redundant call to blueprint editor utils --- Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index 46dd2daa2..640515d6b 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -5,7 +5,6 @@ #include "Asset/FlowAssetToolbar.h" #include "Asset/FlowDebugger.h" #include "FlowEditorCommands.h" -#include "Graph/FlowGraph.h" #include "Graph/FlowGraphEditorSettings.h" #include "Graph/FlowGraphSchema.h" #include "Graph/FlowGraphSchema_Actions.h" @@ -19,13 +18,11 @@ #include "EdGraphUtilities.h" #include "EdGraph/EdGraphNode.h" #include "Editor.h" -#include "EditorStyleSet.h" #include "Framework/Commands/GenericCommands.h" #include "GraphEditor.h" #include "GraphEditorActions.h" #include "HAL/PlatformApplicationMisc.h" #include "IDetailsView.h" -#include "Kismet2/BlueprintEditorUtils.h" #include "Kismet2/DebuggerCommands.h" #include "LevelEditor.h" #include "Modules/ModuleManager.h" @@ -678,7 +675,6 @@ void FFlowAssetEditor::DeleteSelectedNodes() for (FGraphPanelSelectionSet::TConstIterator NodeIt(SelectedNodes); NodeIt; ++NodeIt) { UEdGraphNode* Node = CastChecked(*NodeIt); - if (Node->CanUserDeleteNode()) { if (const UFlowGraphNode* FlowGraphNode = Cast(Node)) @@ -686,13 +682,17 @@ void FFlowAssetEditor::DeleteSelectedNodes() if (FlowGraphNode->GetFlowNode()) { const FGuid NodeGuid = FlowGraphNode->GetFlowNode()->GetGuid(); - FBlueprintEditorUtils::RemoveNode(nullptr, Node, true); + + FocusedGraphEditor->GetCurrentGraph()->GetSchema()->BreakNodeLinks(*Node); + Node->DestroyNode(); + FlowAsset->UnregisterNode(NodeGuid); continue; } } - FBlueprintEditorUtils::RemoveNode(nullptr, Node, true); + FocusedGraphEditor->GetCurrentGraph()->GetSchema()->BreakNodeLinks(*Node); + Node->DestroyNode(); } } } From a437987c59dc7767d17ed8e6962e2f8f3989563f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 27 Nov 2022 20:34:10 +0100 Subject: [PATCH 196/338] replaced naive counter check with bespoke flag --- Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp | 10 ++++++---- Source/FlowEditor/Public/Graph/FlowGraphSchema.h | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp index 4b2668b6c..09ff6bef6 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -21,6 +21,7 @@ #define LOCTEXT_NAMESPACE "FlowGraphSchema" +bool UFlowGraphSchema::bInitialGatherPerformed = false; TArray UFlowGraphSchema::NativeFlowNodes; TMap UFlowGraphSchema::BlueprintFlowNodes; TMap UFlowGraphSchema::AssignedGraphNodeClasses; @@ -196,7 +197,7 @@ void UFlowGraphSchema::OnPinConnectionDoubleCicked(UEdGraphPin* PinA, UEdGraphPi TArray> UFlowGraphSchema::GetFlowNodeCategories() { - if (NativeFlowNodes.Num() == 0) + if (!bInitialGatherPerformed) { GatherNodes(); } @@ -314,7 +315,7 @@ void UFlowGraphSchema::ApplyNodeFilter(const UFlowAsset* AssetClassDefaults, con void UFlowGraphSchema::GetFlowNodeActions(FGraphActionMenuBuilder& ActionMenuBuilder, const UFlowAsset* AssetClassDefaults, const FString& CategoryName) { - if (NativeFlowNodes.Num() == 0) + if (!bInitialGatherPerformed) { GatherNodes(); } @@ -442,17 +443,18 @@ void UFlowGraphSchema::GatherNodes() return; } + bInitialGatherPerformed = true; + GatherNativeNodes(); // retrieve all blueprint nodes - const FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(AssetRegistryConstants::ModuleName); - FARFilter Filter; Filter.ClassNames.Add(UBlueprint::StaticClass()->GetFName()); Filter.ClassNames.Add(UBlueprintGeneratedClass::StaticClass()->GetFName()); Filter.bRecursiveClasses = true; TArray FoundAssets; + const FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(AssetRegistryConstants::ModuleName); AssetRegistryModule.Get().GetAssets(Filter, FoundAssets); for (const FAssetData& AssetData : FoundAssets) { diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h index 842c27788..6c97a6c64 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h @@ -18,6 +18,7 @@ class FLOWEDITOR_API UFlowGraphSchema : public UEdGraphSchema friend class UFlowGraph; private: + static bool bInitialGatherPerformed; static TArray NativeFlowNodes; static TMap BlueprintFlowNodes; static TMap AssignedGraphNodeClasses; From 68cb0ccc7905d2e87f9cd5e25b42efa2c8a5683f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 27 Nov 2022 20:49:19 +0100 Subject: [PATCH 197/338] narrowed down Flow Node blueprint search filter --- Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp index 09ff6bef6..022327050 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -449,8 +449,7 @@ void UFlowGraphSchema::GatherNodes() // retrieve all blueprint nodes FARFilter Filter; - Filter.ClassNames.Add(UBlueprint::StaticClass()->GetFName()); - Filter.ClassNames.Add(UBlueprintGeneratedClass::StaticClass()->GetFName()); + Filter.ClassNames.Add(UFlowNodeBlueprint::StaticClass()->GetFName()); Filter.bRecursiveClasses = true; TArray FoundAssets; From 09b40c10e3895db3b39e192801e91078ac1c27ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 27 Nov 2022 22:05:28 +0100 Subject: [PATCH 198/338] rollback to recreating Graph Nodes manually as PostLoad has some issues --- .../Private/Asset/FlowAssetEditor.cpp | 8 ++- Source/FlowEditor/Private/Graph/FlowGraph.cpp | 41 +++++++------- .../Private/Graph/FlowGraphSchema_Actions.cpp | 53 ++++++++++--------- Source/FlowEditor/Public/Graph/FlowGraph.h | 2 +- 4 files changed, 52 insertions(+), 52 deletions(-) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index 640515d6b..f75a52084 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -5,6 +5,7 @@ #include "Asset/FlowAssetToolbar.h" #include "Asset/FlowDebugger.h" #include "FlowEditorCommands.h" +#include "Graph/FlowGraph.h" #include "Graph/FlowGraphEditorSettings.h" #include "Graph/FlowGraphSchema.h" #include "Graph/FlowGraphSchema_Actions.h" @@ -256,12 +257,9 @@ void FFlowAssetEditor::BindToolbarCommands() void FFlowAssetEditor::RefreshAsset() { - TArray FlowGraphNodes; - FlowAsset->GetGraph()->GetNodesOfClass(FlowGraphNodes); - - for (UFlowGraphNode* GraphNode : FlowGraphNodes) + if (UFlowGraph* FlowGraph = Cast(FlowAsset->GetGraph())) { - GraphNode->RefreshContextPins(true); + FlowGraph->RefreshGraph(); } } diff --git a/Source/FlowEditor/Private/Graph/FlowGraph.cpp b/Source/FlowEditor/Private/Graph/FlowGraph.cpp index 57fc743d0..096d48bf6 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraph.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraph.cpp @@ -39,34 +39,33 @@ UEdGraph* UFlowGraph::CreateGraph(UFlowAsset* InFlowAsset) return NewGraph; } -void UFlowGraph::PostLoad() +void UFlowGraph::RefreshGraph() { - Super::PostLoad(); - - // gather AssignedGraphNodeClasses before we'd checking nodes below - const UFlowGraphSchema* FlowGraphSchema = CastChecked(GetSchema()); - FlowGraphSchema->GatherNativeNodes(); - - // Check if all Graph Nodes have expected, up-to-date type - bool bAnyUpdate = false; - for (const TPair& Node : GetFlowAsset()->GetNodes()) + // don't run fixup in commandlets or PIE + if (!IsRunningCommandlet() && GEditor && !GEditor->PlayWorld) { - if (UFlowNode* FlowNode = Node.Value) + // check if all Graph Nodes have expected, up-to-date type + CastChecked(GetSchema())->GatherNativeNodes(); + for (const TPair& Node : GetFlowAsset()->GetNodes()) { - const UClass* ExpectGraphNodeClass = UFlowGraphSchema::GetAssignedGraphNodeClass(FlowNode->GetClass()); - if (FlowNode->GetGraphNode() && FlowNode->GetGraphNode()->GetClass() != ExpectGraphNodeClass) + if (UFlowNode* FlowNode = Node.Value) { - // Create a new Flow Graph Node of proper type - FFlowGraphSchemaAction_NewNode::RecreateNode(this, FlowNode->GetGraphNode(), FlowNode); - bAnyUpdate = true; + const UClass* ExpectGraphNodeClass = UFlowGraphSchema::GetAssignedGraphNodeClass(FlowNode->GetClass()); + if (FlowNode->GetGraphNode() && FlowNode->GetGraphNode()->GetClass() != ExpectGraphNodeClass) + { + // Create a new Flow Graph Node of proper type + FFlowGraphSchemaAction_NewNode::RecreateNode(this, FlowNode->GetGraphNode(), FlowNode); + } } } - } - if (bAnyUpdate) - { - GetFlowAsset()->HarvestNodeConnections(); - GetOutermost()->SetDirtyFlag(true); // force dirty while loading asset + // update context pins + TArray FlowGraphNodes; + GetNodesOfClass(FlowGraphNodes); + for (UFlowGraphNode* GraphNode : FlowGraphNodes) + { + GraphNode->RefreshContextPins(true); + } } } diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp index f6fbc8e59..06dfad3b7 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp @@ -76,7 +76,9 @@ UFlowGraphNode* FFlowGraphSchemaAction_NewNode::CreateNode(UEdGraph* ParentGraph NewGraphNode->PostPlacedNewNode(); ParentGraph->NotifyGraphChanged(); - // select in editor UI + FlowAsset->PostEditChange(); + + // select in editor UI if (bSelectNewNode) { const TSharedPtr FlowEditor = FFlowGraphUtils::GetFlowAssetEditor(ParentGraph); @@ -86,8 +88,6 @@ UFlowGraphNode* FFlowGraphSchemaAction_NewNode::CreateNode(UEdGraph* ParentGraph } } - FlowAsset->PostEditChange(); - return NewGraphNode; } @@ -103,7 +103,7 @@ UFlowGraphNode* FFlowGraphSchemaAction_NewNode::RecreateNode(UEdGraph* ParentGra // create new Flow Graph node const UClass* GraphNodeClass = UFlowGraphSchema::GetAssignedGraphNodeClass(FlowNode->GetClass()); UFlowGraphNode* NewGraphNode = NewObject(ParentGraph, GraphNodeClass, NAME_None, RF_Transactional); - + // register to the graph NewGraphNode->NodeGuid = FlowNode->GetGuid(); ParentGraph->AddNode(NewGraphNode, false, false); @@ -116,26 +116,26 @@ UFlowGraphNode* FFlowGraphSchemaAction_NewNode::RecreateNode(UEdGraph* ParentGra NewGraphNode->AllocateDefaultPins(); if (OldInstance) { - for (UEdGraphPin* OldPin : OldInstance->Pins) - { - if (OldPin->LinkedTo.Num() == 0) - { - continue; - } - - for (UEdGraphPin* NewPin : NewGraphNode->Pins) - { - if (NewPin->Direction == OldPin->Direction && NewPin->PinName == OldPin->PinName) - { - TArray Connections = OldPin->LinkedTo; - for (UEdGraphPin* ConnectedPin : Connections) - { - ConnectedPin->BreakLinkTo(OldPin); - ConnectedPin->MakeLinkTo(NewPin); - } - } - } - } + for (UEdGraphPin* OldPin : OldInstance->Pins) + { + if (OldPin->LinkedTo.Num() == 0) + { + continue; + } + + for (UEdGraphPin* NewPin : NewGraphNode->Pins) + { + if (NewPin->Direction == OldPin->Direction && NewPin->PinName == OldPin->PinName) + { + TArray Connections = OldPin->LinkedTo; + for (UEdGraphPin* ConnectedPin : Connections) + { + ConnectedPin->BreakLinkTo(OldPin); + ConnectedPin->MakeLinkTo(NewPin); + } + } + } + } } // keep old position @@ -147,8 +147,11 @@ UFlowGraphNode* FFlowGraphSchemaAction_NewNode::RecreateNode(UEdGraph* ParentGra { OldInstance->DestroyNode(); } - + + // call notifies NewGraphNode->PostPlacedNewNode(); + ParentGraph->NotifyGraphChanged(); + return NewGraphNode; } diff --git a/Source/FlowEditor/Public/Graph/FlowGraph.h b/Source/FlowEditor/Public/Graph/FlowGraph.h index 1e92342ad..9759dc676 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraph.h +++ b/Source/FlowEditor/Public/Graph/FlowGraph.h @@ -22,9 +22,9 @@ class FLOWEDITOR_API UFlowGraph : public UEdGraph GENERATED_UCLASS_BODY() static UEdGraph* CreateGraph(UFlowAsset* InFlowAsset); + void RefreshGraph(); // UEdGraph - virtual void PostLoad() override; virtual void NotifyGraphChanged() override; // -- From 3dd3d1522c7a5523a3b043bd0322f63d0fb7b759 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Wed, 30 Nov 2022 21:27:15 +0100 Subject: [PATCH 199/338] compile out body of LogError in Shipping --- Source/Flow/Private/Nodes/FlowNode.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 3bde1928f..13c4fcf6f 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -645,6 +645,7 @@ FString UFlowNode::GetProgressAsString(float Value) void UFlowNode::LogError(FString Message, const EFlowOnScreenMessageType OnScreenMessageType) const { +#if !UE_BUILD_SHIPPING const FString TemplatePath = GetFlowAsset()->TemplateAsset->GetPathName(); Message += TEXT(" --- node ") + GetName() + TEXT(", asset ") + FPaths::GetPath(TemplatePath) / FPaths::GetBaseFilename(TemplatePath); @@ -669,6 +670,7 @@ void UFlowNode::LogError(FString Message, const EFlowOnScreenMessageType OnScree } UE_LOG(LogFlow, Error, TEXT("%s"), *Message); +#endif } void UFlowNode::SaveInstance(FFlowNodeSaveData& NodeRecord) From ffd33f32de17513bad17ee51961acf67b50608a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Thu, 1 Dec 2022 18:53:47 +0100 Subject: [PATCH 200/338] added LogMessage + added messages on executing Disabled and PassThrough nodes --- Source/Flow/Private/Nodes/FlowNode.cpp | 32 ++++++++++++++++++++------ Source/Flow/Public/Nodes/FlowNode.h | 5 +++- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 13c4fcf6f..d2aefbaa6 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -408,13 +408,19 @@ void UFlowNode::TriggerInput(const FName& PinName, const EFlowPinActivationType return; } - if (SignalMode == EFlowSignalMode::Enabled) - { - ExecuteInput(PinName); - } - else if (SignalMode == EFlowSignalMode::PassThrough) + switch (SignalMode) { - OnPassThrough(); + case EFlowSignalMode::Enabled: + ExecuteInput(PinName); + break; + case EFlowSignalMode::Disabled: + LogMessage(FString::Printf(TEXT("Node disabled while triggering input %s"), *PinName.ToString())); + break; + case EFlowSignalMode::PassThrough: + LogMessage(FString::Printf(TEXT("Signal pass-through on triggering input %s"), *PinName.ToString())); + OnPassThrough(); + break; + default: ; } } @@ -670,7 +676,17 @@ void UFlowNode::LogError(FString Message, const EFlowOnScreenMessageType OnScree } UE_LOG(LogFlow, Error, TEXT("%s"), *Message); -#endif +#endif +} + +void UFlowNode::LogMessage(FString Message) const +{ +#if !UE_BUILD_SHIPPING + const FString TemplatePath = GetFlowAsset()->TemplateAsset->GetPathName(); + Message += TEXT(" --- node ") + GetName() + TEXT(", asset ") + FPaths::GetPath(TemplatePath) / FPaths::GetBaseFilename(TemplatePath); + + UE_LOG(LogFlow, Log, TEXT("%s"), *Message); +#endif } void UFlowNode::SaveInstance(FFlowNodeSaveData& NodeRecord) @@ -701,9 +717,11 @@ void UFlowNode::LoadInstance(const FFlowNodeSaveData& NodeRecord) break; case EFlowSignalMode::Disabled: // designer doesn't want to execute this node's logic at all, so we kill it + LogMessage(TEXT("Signal disabled while loading Flow Node from SaveGame")); Finish(); break; case EFlowSignalMode::PassThrough: + LogMessage(TEXT("Signal pass-through on loading Flow Node from SaveGame")); OnPassThrough(); break; default: ; diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 09c7a5eb2..cbc2a8576 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -378,9 +378,12 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UFUNCTION(BlueprintPure, Category = "FlowNode") static FString GetProgressAsString(float Value); - UFUNCTION(BlueprintCallable, Category = "FlowNode") + UFUNCTION(BlueprintCallable, Category = "FlowNode", meta = (DevelopmentOnly)) void LogError(FString Message, const EFlowOnScreenMessageType OnScreenMessageType = EFlowOnScreenMessageType::Permanent) const; + UFUNCTION(BlueprintCallable, Category = "FlowNode", meta = (DevelopmentOnly)) + void LogMessage(FString Message) const; + UFUNCTION(BlueprintCallable, Category = "FlowNode") void SaveInstance(FFlowNodeSaveData& NodeRecord); From 13f7d0467a5a69981e1b38b87c89784e750812ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 4 Dec 2022 16:15:15 +0100 Subject: [PATCH 201/338] Jump from Asset Search result to the Flow Node, if found property belongs to the node requires integrating engine change: EpicGames/UnrealEngine#9882 --- Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp | 10 ++++++++++ Source/FlowEditor/Public/Asset/FlowAssetEditor.h | 7 +++++++ Source/FlowEditor/Public/FlowEditorDefines.h | 8 +++++++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index f75a52084..4a4c6e266 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -651,6 +651,16 @@ void FFlowAssetEditor::SelectSingleNode(UEdGraphNode* Node) const FocusedGraphEditor->SetNodeSelection(Node, true); } +#if ENABLE_JUMP_TO_INNER_OBJECT +void FFlowAssetEditor::JumpToInnerObject(UObject* InnerObject) +{ + if (const UFlowNode* FlowNode = Cast(InnerObject)) + { + FocusedGraphEditor->JumpToNode(FlowNode->GetGraphNode(), false); + } +} +#endif + void FFlowAssetEditor::SelectAllNodes() const { FocusedGraphEditor->SelectAllNodes(); diff --git a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h index a72f0f59e..2e811e975 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h @@ -9,6 +9,7 @@ #include "Toolkits/IToolkitHost.h" #include "UObject/GCObject.h" +#include "FlowEditorDefines.h" #include "FlowTypes.h" class SFlowPalette; @@ -138,6 +139,12 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit public: virtual void SelectSingleNode(UEdGraphNode* Node) const; +#if ENABLE_JUMP_TO_INNER_OBJECT + // FAssetEditorToolkit + virtual void JumpToInnerObject(UObject* InnerObject) override; + // -- +#endif + protected: virtual void SelectAllNodes() const; virtual bool CanSelectAllNodes() const; diff --git a/Source/FlowEditor/Public/FlowEditorDefines.h b/Source/FlowEditor/Public/FlowEditorDefines.h index 0cc1160e2..d9cbd0757 100644 --- a/Source/FlowEditor/Public/FlowEditorDefines.h +++ b/Source/FlowEditor/Public/FlowEditorDefines.h @@ -1,4 +1,4 @@ -// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors #pragma once @@ -13,3 +13,9 @@ * Set macro value to 1, if you made these changes to the engine: https://github.com/EpicGames/UnrealEngine/pull/9070 */ #define ENABLE_FLOW_SEARCH 0 + +/** + * Documentation: https://github.com/MothCocoon/FlowGraph/wiki/Asset-Search + * Set macro value to 1, if you made these changes to the engine: https://github.com/EpicGames/UnrealEngine/pull/9882 + */ +#define ENABLE_JUMP_TO_INNER_OBJECT 0 From 316c4d6e04201ba9d75271298c907a0b6d42ff90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 4 Dec 2022 23:12:14 +0100 Subject: [PATCH 202/338] don't bind to delegates if node got deactivated during first loop on actors --- .../Nodes/World/FlowNode_ComponentObserver.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp index bbe89feb1..3a875af3d 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp @@ -68,13 +68,13 @@ void UFlowNode_ComponentObserver::StartObserving() } } - // clear old bindings before binding again, which might happen while loading a SaveGame - StopObserving(); - - FlowSubsystem->OnComponentRegistered.AddDynamic(this, &UFlowNode_ComponentObserver::OnComponentRegistered); - FlowSubsystem->OnComponentTagAdded.AddDynamic(this, &UFlowNode_ComponentObserver::OnComponentTagAdded); - FlowSubsystem->OnComponentTagRemoved.AddDynamic(this, &UFlowNode_ComponentObserver::OnComponentTagRemoved); - FlowSubsystem->OnComponentUnregistered.AddDynamic(this, &UFlowNode_ComponentObserver::OnComponentUnregistered); + if (GetActivationState() == EFlowNodeState::Active) + { + FlowSubsystem->OnComponentRegistered.AddUniqueDynamic(this, &UFlowNode_ComponentObserver::OnComponentRegistered); + FlowSubsystem->OnComponentTagAdded.AddUniqueDynamic(this, &UFlowNode_ComponentObserver::OnComponentTagAdded); + FlowSubsystem->OnComponentTagRemoved.AddUniqueDynamic(this, &UFlowNode_ComponentObserver::OnComponentTagRemoved); + FlowSubsystem->OnComponentUnregistered.AddUniqueDynamic(this, &UFlowNode_ComponentObserver::OnComponentUnregistered); + } } } From d2ffe391678ff062d6d9f7e0e473c662a08f7b3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Tue, 6 Dec 2022 21:42:59 +0100 Subject: [PATCH 203/338] fix by @lfowles Component Observer may continue triggering outputs if the last component triggered a finish during UFlowNode_ComponentObserver::StartObserving --- .../World/FlowNode_ComponentObserver.cpp | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp index 3a875af3d..896c9530d 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp @@ -56,25 +56,20 @@ void UFlowNode_ComponentObserver::StartObserving() // collect already registered components for (const TWeakObjectPtr& FoundComponent : FlowSubsystem->GetComponents(IdentityTags, ContainerMatchType, bExactMatch)) { - if (GetActivationState() == EFlowNodeState::Active) + ObserveActor(FoundComponent->GetOwner(), FoundComponent); + + // node might finish work immediately as the effect of ObserveActor() + // we should terminate iteration in this case + if (GetActivationState() != EFlowNodeState::Active) { - ObserveActor(FoundComponent->GetOwner(), FoundComponent); - } - else - { - // node might finish work as the effect of triggering event on the found actor - // we should terminate iteration in this case return; } } - - if (GetActivationState() == EFlowNodeState::Active) - { - FlowSubsystem->OnComponentRegistered.AddUniqueDynamic(this, &UFlowNode_ComponentObserver::OnComponentRegistered); - FlowSubsystem->OnComponentTagAdded.AddUniqueDynamic(this, &UFlowNode_ComponentObserver::OnComponentTagAdded); - FlowSubsystem->OnComponentTagRemoved.AddUniqueDynamic(this, &UFlowNode_ComponentObserver::OnComponentTagRemoved); - FlowSubsystem->OnComponentUnregistered.AddUniqueDynamic(this, &UFlowNode_ComponentObserver::OnComponentUnregistered); - } + + FlowSubsystem->OnComponentRegistered.AddUniqueDynamic(this, &UFlowNode_ComponentObserver::OnComponentRegistered); + FlowSubsystem->OnComponentTagAdded.AddUniqueDynamic(this, &UFlowNode_ComponentObserver::OnComponentTagAdded); + FlowSubsystem->OnComponentTagRemoved.AddUniqueDynamic(this, &UFlowNode_ComponentObserver::OnComponentTagRemoved); + FlowSubsystem->OnComponentUnregistered.AddUniqueDynamic(this, &UFlowNode_ComponentObserver::OnComponentUnregistered); } } From 23a80dec9ac2751ccaad8dba3c6435df1502c82e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Thu, 8 Dec 2022 21:52:45 +0100 Subject: [PATCH 204/338] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 97056f896..2f4856bdf 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ The aim of publishing it as open-source project is to let people tell great stor * It's easy to include plugin in your own project, follow this short [Getting Started](https://github.com/MothCocoon/FlowGraph/wiki/Getting-Started) guide. ## In-depth video presentation -This 24-minute presentation breaks down the concept of the Flow Graph. It goes through everything written in this ReadMe but in greater detail. +This 24-minute presentation breaks down the concept of the Flow Graph. Trust me, you want to understand concept properly before diving into implementation. [![Introducing Flow Graph for Unreal Engine](https://img.youtube.com/vi/BAqhccgKx_k/0.jpg)](https://www.youtube.com/watch?v=BAqhccgKx_k) From 73e436e5ea540b73b9850bec2815ae1e8800aa27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 25 Dec 2022 19:34:08 +0100 Subject: [PATCH 205/338] promoted FlowComponentRegistry to protected --- Source/Flow/Public/FlowSubsystem.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index 3315609dd..c98d8c4a0 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -126,7 +126,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem ////////////////////////////////////////////////////////////////////////// // Component Registry -private: +protected: /* All the Flow Components currently existing in the world */ TMultiMap> FlowComponentRegistry; From 8808f22b71ffb87e7cba101d4e68caf90ecbae2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 25 Dec 2022 19:34:17 +0100 Subject: [PATCH 206/338] added commentary --- Source/Flow/Private/FlowSubsystem.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index 122b46f70..397394184 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -325,6 +325,9 @@ void UFlowSubsystem::OnGameSaved(UFlowSaveGame* SaveGame) void UFlowSubsystem::OnGameLoaded(UFlowSaveGame* SaveGame) { LoadedSaveGame = SaveGame; + + // here's opportunity to apply loaded data to custom systems + // it's recommended to do this by overriding method in the subclass } void UFlowSubsystem::LoadRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const FString& SavedAssetInstanceName) From 7ca21198df48e261b53d2a9cb1705d1f3295aaa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 30 Dec 2022 17:13:49 +0100 Subject: [PATCH 207/338] Asset Search: added option to run search on single asset, with Search Browser opened as asset editor tab Requires engine modification: EpicGames/UnrealEngine#9943 docs: https://github.com/MothCocoon/FlowGraph/wiki/Asset-Search --- Resources/Icons/Refresh.png | Bin 5742 -> 0 bytes .../Private/Asset/FlowAssetEditor.cpp | 79 +++++++++++++++--- .../Private/Asset/FlowAssetToolbar.cpp | 14 ++-- .../FlowEditor/Private/FlowEditorCommands.cpp | 3 +- Source/FlowEditor/Private/FlowEditorStyle.cpp | 6 +- .../FlowEditor/Public/Asset/FlowAssetEditor.h | 13 ++- Source/FlowEditor/Public/FlowEditorCommands.h | 1 + Source/FlowEditor/Public/FlowEditorDefines.h | 6 ++ 8 files changed, 99 insertions(+), 23 deletions(-) delete mode 100644 Resources/Icons/Refresh.png diff --git a/Resources/Icons/Refresh.png b/Resources/Icons/Refresh.png deleted file mode 100644 index 4bf3091f3ec3eaae54b613fa17358b1b4f8a0e0f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5742 zcmV-!7LnKLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z000Y_Nkl>oyMo zQZz`L1O;56D2f7cfg){Cw{99g6ire$X=A``8pp1ST9)ldc4$Si7E82DEtVx~BPkB| z8Im(|mvc@ZW=K&MRoFluf*=RDz`ek|=l;&O{Ll9tVT|Dyc}RZ2$FBf?=>hHe4-Jc! z01$-%&F#zCw)1zfq$XXLrmilHj(no1DAMWL?yjz`UD<5ru2{@n>UmzBW82dAi&HA{ z`=5R3tsnI4+w;Qmwr0}FINh5z6DdV;riksh1VMn-29QKi1W1ImP)bwCPx8u3&ti<> z-05RC0^Vw9rBTY%w6?W>adCU|mm0E}jh<%rIM+eU&ki?RS z`c$g6J&ZI_WU6roS{oe4O*J+&?XItH+}+W+@~@|-r;p_elZQ{e*ZaIN`sW~S223O~ z7-I+=pPjou|5xkRuKco!3|fGc1}ViHnAV2;REhENNy_C?!Ex-!cH*g_;i1!Ed3wUw z32fV59*cRIFw`hzFb0ePZ7Q&{&#q%Tj+@vzIMnZ)JbCsNr4+X9ERe;`T?BrK+tzJ) z^fM1V_UB=sD={VwQVU#Hpp@a{xr@AW{KUog&-VTJ>Xq|*E!6u!f-y2L7R#dg@7E zNGUL~;?k>wqwIbC&FJ*IJzqr!&v>p!NQ7nCl@$w7(XyE$3X51GC9>JZ4N)`;c-^JO z7_S_3>^wN;4CbXC|;Mi$!g#X>46}vjtP>?ABB&-5EyLt!F|*@2L+M8SOt%7`yyrJeej8 zX0YA(oE(LrPco4NqYy%(R7AWc(H`@>I;ARZ9UL0h$wWeWo`cqvm{dy8(b2iNxo!Ez z{P@suX;l{OdNm8XINQ*&86+`C@9h9j^32NQ!ADX!f{GL^-$Y_!oBt;MOnW8W=Ij-Pft zFS0BP75U@_FZK)$4h^@pwlvLpNo%N0rj|L5*BFK6+f zDV4u^`TWI}mgXi^jYEOJcHCsFrZ!tHnmIrr7T8ImFw|PlT2Nvz#A?HJ0cly- zj?0xZeH`ES;teYegEFJJOH7UpQkQMPc4JKCN14tK1A^%X*&w0io|NSY$*|z-aC= zqq)oTBuG-p4nz)p0 zShQAYjT8b)3M?atC6a4G-|q^_r4I)$oMoi{(kH5ljnP~_e~dL7?{BP4WtS>#h_uES zgAjrs48p-HXQs==Df%zI%ljwaM5*v*3yut5J>1@L+k;wb3<9Gd9)Oj! z?CA@=M;2nJsa^>n4tVqCRzMK=r4P%+sk^cbEp=fKqLjj5kkTRug8aAQ2z&e{S9~jr6r}nXcSO0qcDzS$;vw)?>n&n-zJ6!Cjkp+1loXBpsosKEzsu( zAOiI2JMQ_DL?THL2F&*3(sH?S>FkA`SH2g8LCFEaTQ*IF$&nLdBLk-q0&O(fXi9}L zu|VQDiOywf?*2Bg1b7JeEU*RW0MbAVaH?|}Kv&@maA?iO`*(NWwd>O=s#s5JjnW!z z;KbW|u7*MB0pPcQ2Y{|wHhE(vmZD4Nd%s)JCymjDnR0+#itvnNm^FWsNcv}Aw!!ngi) zDnI-h&@Y6Xk(PyJIk;Y&nq)o6R09o*I%wt)IcRsbGy(v*D`6yMD7YwddL+{bo zPEHp_azH&ZvLjU}>Qtn_85#*F`wFGB4*i+)MymlKW$2en8OMz+tEq|AH)K3KM=&u_A_$|o-2nuS8{Hsyid#5YT%|z<44xr|!~noLvup?T4FpJofp(FV1VI3=Q>hGMNO9<4`PX z%D$meqCw2Fh!o%g-Es?Zu~mSPe5-b?ZUk#4Q2EM@k7H zME!3(^7v1--TQ@mq9{PCXbut}QR9$Gdc-^%DJ9w%!bmYSw(arO z>(9RP>I>igcVl!^l_skigKq#s9~-cmsoOT){pb_-Jn#p*Qgsbh;1??;xe$Orsp~sJ z<%4R^EN`r~U9W~xaf&zh{L9Y{?tAv-stnoHe+&aZ2hPoJj6V+G>@KmTp}F(X?f3oO zXI5?4(dl|Ms3<^dRfYTLsssp-(#E!3lnOb2=J2_mz2EQYzx3X@s%Bb15jYPV1+Ff1 zc<^xmsS5B4U~|jj)w{a4es){O^6vJ!`WD-9V=QF&C<>U)j|TmhPF?Fg{6BjyoH_J7 zFg8!bT_9ftE8psL4&7%Gfh z`|w(B;Dd|BnaOKa2`K=Vfs+ea>;DUI{;+@)kgZ;I)j|Ov07_NSEdZ0%`|?ePFP{YP gS0}8$jDY_;0Aw{4pa(fKg8%>k07*qoM6N<$g6|Lo761SM diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index 4a4c6e266..c9bd6a7c7 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -30,6 +30,7 @@ #include "PropertyEditorModule.h" #include "ScopedTransaction.h" #include "SNodePanel.h" +#include "Source/Private/Widgets/SSearchBrowser.h" #include "ToolMenus.h" #include "Widgets/Docking/SDockTab.h" @@ -38,6 +39,7 @@ const FName FFlowAssetEditor::DetailsTab(TEXT("Details")); const FName FFlowAssetEditor::GraphTab(TEXT("Graph")); const FName FFlowAssetEditor::PaletteTab(TEXT("Palette")); +const FName FFlowAssetEditor::SearchTab(TEXT("Search")); FFlowAssetEditor::FFlowAssetEditor() : FlowAsset(nullptr) @@ -106,29 +108,39 @@ void FFlowAssetEditor::RegisterTabSpawners(const TSharedRef& FAssetEditorToolkit::RegisterTabSpawners(InTabManager); - InTabManager->RegisterTabSpawner(GraphTab, FOnSpawnTab::CreateSP(this, &FFlowAssetEditor::SpawnTab_GraphCanvas)) - .SetDisplayName(LOCTEXT("GraphTab", "Viewport")) - .SetGroup(WorkspaceMenuCategoryRef) - .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "GraphEditor.EventGraph_16x")); - InTabManager->RegisterTabSpawner(DetailsTab, FOnSpawnTab::CreateSP(this, &FFlowAssetEditor::SpawnTab_Details)) .SetDisplayName(LOCTEXT("DetailsTab", "Details")) .SetGroup(WorkspaceMenuCategoryRef) .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.Tabs.Details")); + InTabManager->RegisterTabSpawner(GraphTab, FOnSpawnTab::CreateSP(this, &FFlowAssetEditor::SpawnTab_Graph)) + .SetDisplayName(LOCTEXT("GraphTab", "Viewport")) + .SetGroup(WorkspaceMenuCategoryRef) + .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "GraphEditor.EventGraph_16x")); + InTabManager->RegisterTabSpawner(PaletteTab, FOnSpawnTab::CreateSP(this, &FFlowAssetEditor::SpawnTab_Palette)) .SetDisplayName(LOCTEXT("PaletteTab", "Palette")) .SetGroup(WorkspaceMenuCategoryRef) .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "Kismet.Tabs.Palette")); + +#if ENABLE_SEARCH_IN_ASSET_EDITOR + InTabManager->RegisterTabSpawner(SearchTab, FOnSpawnTab::CreateSP(this, &FFlowAssetEditor::SpawnTab_Search)) + .SetDisplayName(LOCTEXT("SearchTab", "Search")) + .SetGroup(WorkspaceMenuCategoryRef) + .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "Kismet.Tabs.FindResults")); +#endif } void FFlowAssetEditor::UnregisterTabSpawners(const TSharedRef& InTabManager) { FAssetEditorToolkit::UnregisterTabSpawners(InTabManager); - InTabManager->UnregisterTabSpawner(GraphTab); InTabManager->UnregisterTabSpawner(DetailsTab); + InTabManager->UnregisterTabSpawner(GraphTab); InTabManager->UnregisterTabSpawner(PaletteTab); +#if ENABLE_SEARCH_IN_ASSET_EDITOR + InTabManager->UnregisterTabSpawner(SearchTab); +#endif } TSharedRef FFlowAssetEditor::SpawnTab_Details(const FSpawnTabArgs& Args) const @@ -142,7 +154,24 @@ TSharedRef FFlowAssetEditor::SpawnTab_Details(const FSpawnTabArgs& Arg ]; } -TSharedRef FFlowAssetEditor::SpawnTab_GraphCanvas(const FSpawnTabArgs& Args) const +#if ENABLE_SEARCH_IN_ASSET_EDITOR +TSharedRef FFlowAssetEditor::SpawnTab_Search(const FSpawnTabArgs& Args) const +{ + check(Args.GetTabId() == SearchTab); + + return SNew(SDockTab) + .Label(LOCTEXT("FlowSearchTitle", "Search")) + [ + SNew(SBox) + .AddMetaData(FTagMetaData(TEXT("FlowSearch"))) + [ + SearchBrowser.ToSharedRef() + ] + ]; +} +#endif + +TSharedRef FFlowAssetEditor::SpawnTab_Graph(const FSpawnTabArgs& Args) const { check(Args.GetTabId() == GraphTab); @@ -185,7 +214,7 @@ void FFlowAssetEditor::InitFlowAssetEditor(const EToolkitMode::Type Mode, const BindGraphCommands(); CreateWidgets(); - const TSharedRef StandaloneDefaultLayout = FTabManager::NewLayout("FlowAssetEditor_Layout_v3") + const TSharedRef StandaloneDefaultLayout = FTabManager::NewLayout("FlowAssetEditor_Layout_v4") ->AddArea ( FTabManager::NewPrimaryArea()->SetOrientation(Orient_Horizontal) @@ -197,9 +226,22 @@ void FFlowAssetEditor::InitFlowAssetEditor(const EToolkitMode::Type Mode, const ) ->Split ( - FTabManager::NewStack() + FTabManager::NewSplitter() ->SetSizeCoefficient(0.65f) - ->AddTab(GraphTab, ETabState::OpenedTab)->SetHideTabWell(true) + ->SetOrientation(Orient_Vertical) + ->Split + ( + FTabManager::NewStack() + ->SetSizeCoefficient(0.8f) + ->SetHideTabWell(true) + ->AddTab(GraphTab, ETabState::OpenedTab) + ) + ->Split + ( + FTabManager::NewStack() + ->SetSizeCoefficient(0.2f) + ->AddTab(SearchTab, ETabState::ClosedTab) + ) ) ->Split ( @@ -244,6 +286,12 @@ void FFlowAssetEditor::BindToolbarCommands() FExecuteAction::CreateSP(this, &FFlowAssetEditor::RefreshAsset), FCanExecuteAction::CreateStatic(&FFlowAssetEditor::CanEdit)); +#if ENABLE_SEARCH_IN_ASSET_EDITOR + ToolkitCommands->MapAction(ToolbarCommands.SearchInAsset, + FExecuteAction::CreateSP(this, &FFlowAssetEditor::SearchInAsset), + FCanExecuteAction()); +#endif + // Engine's Play commands ToolkitCommands->Append(FPlayWorldCommands::GlobalPlayWorldActions.ToSharedRef()); @@ -263,6 +311,14 @@ void FFlowAssetEditor::RefreshAsset() } } +#if ENABLE_SEARCH_IN_ASSET_EDITOR +void FFlowAssetEditor::SearchInAsset() +{ + TabManager->TryInvokeTab(SearchTab); + SearchBrowser->FocusForUse(); +} +#endif + void FFlowAssetEditor::GoToParentInstance() { const UFlowAsset* AssetThatInstancedThisAsset = FlowAsset->GetInspectedInstance()->GetParentInstance(); @@ -291,6 +347,9 @@ void FFlowAssetEditor::CreateWidgets() DetailsView->SetIsPropertyEditingEnabledDelegate(FIsPropertyEditingEnabled::CreateStatic(&FFlowAssetEditor::CanEdit)); DetailsView->SetObject(FlowAsset); +#if ENABLE_SEARCH_IN_ASSET_EDITOR + SearchBrowser = SNew(SSearchBrowser, GetFlowAsset()); +#endif Palette = SNew(SFlowPalette, SharedThis(this)); } diff --git a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp index 4867c58bd..95e95f77c 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp @@ -196,16 +196,14 @@ void FFlowAssetToolbar::BuildAssetToolbar(UToolMenu* ToolbarMenu) const FToolMenuSection& Section = ToolbarMenu->AddSection("Editing"); Section.InsertPosition = FToolMenuInsert("Asset", EToolMenuInsertType::After); + // add buttons Section.AddEntry(FToolMenuEntry::InitToolBarButton(FFlowToolbarCommands::Get().RefreshAsset)); +#if ENABLE_SEARCH_IN_ASSET_EDITOR + Section.AddEntry(FToolMenuEntry::InitToolBarButton(FFlowToolbarCommands::Get().SearchInAsset)); +#endif - /** - * Documentation: https://github.com/MothCocoon/FlowGraph/wiki/Visual-Diff - * Set macro value to 1, if you made these changes to the engine: https://github.com/EpicGames/UnrealEngine/pull/9659 - */ -#if ENABLE_FLOW_DIFF - FToolMenuSection& DiffSection = ToolbarMenu->AddSection("SourceControl"); - DiffSection.InsertPosition = FToolMenuInsert("Asset", EToolMenuInsertType::After); - DiffSection.AddDynamicEntry("SourceControlCommands", FNewToolMenuSectionDelegate::CreateLambda([this](FToolMenuSection& InSection) + // Visual Diff: menu to choose asset revision compared with the current one + Section.AddDynamicEntry("SourceControlCommands", FNewToolMenuSectionDelegate::CreateLambda([this](FToolMenuSection& InSection) { InSection.InsertPosition = FToolMenuInsert(); FToolMenuEntry DiffEntry = FToolMenuEntry::InitComboButton( diff --git a/Source/FlowEditor/Private/FlowEditorCommands.cpp b/Source/FlowEditor/Private/FlowEditorCommands.cpp index 2b9e7daae..b2eca30fb 100644 --- a/Source/FlowEditor/Private/FlowEditorCommands.cpp +++ b/Source/FlowEditor/Private/FlowEditorCommands.cpp @@ -19,7 +19,8 @@ FFlowToolbarCommands::FFlowToolbarCommands() void FFlowToolbarCommands::RegisterCommands() { - UI_COMMAND(RefreshAsset, "Refresh Asset", "Refresh asset and all nodes", EUserInterfaceActionType::Button, FInputChord()); + UI_COMMAND(RefreshAsset, "Refresh", "Refresh asset and all nodes", EUserInterfaceActionType::Button, FInputChord()); + UI_COMMAND(SearchInAsset, "Search", "Search in the current Flow Graph", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Control | EModifierKey::Shift, EKeys::F) ); UI_COMMAND(GoToParentInstance, "Go To Parent", "Open editor for the Flow Asset that created this Flow instance", EUserInterfaceActionType::Button, FInputChord()); } diff --git a/Source/FlowEditor/Private/FlowEditorStyle.cpp b/Source/FlowEditor/Private/FlowEditorStyle.cpp index 875cfc585..98bd0cd70 100644 --- a/Source/FlowEditor/Private/FlowEditorStyle.cpp +++ b/Source/FlowEditor/Private/FlowEditorStyle.cpp @@ -8,6 +8,7 @@ #define IMAGE_BRUSH( RelativePath, ... ) FSlateImageBrush( StyleSet->RootToContentDir( RelativePath, TEXT(".png") ), __VA_ARGS__ ) #define BOX_BRUSH( RelativePath, ... ) FSlateBoxBrush( StyleSet->RootToContentDir( RelativePath, TEXT(".png") ), __VA_ARGS__ ) #define BORDER_BRUSH( RelativePath, ... ) FSlateBorderBrush( StyleSet->RootToContentDir( RelativePath, TEXT(".png") ), __VA_ARGS__ ) +#define IMAGE_BRUSH_SVG( RelativePath, ... ) FSlateVectorImageBrush(StyleSet->RootToContentDir(RelativePath, TEXT(".svg")), __VA_ARGS__) TSharedPtr FFlowEditorStyle::StyleSet = nullptr; @@ -22,6 +23,7 @@ void FFlowEditorStyle::Initialize() StyleSet = MakeShareable(new FSlateStyleSet(TEXT("FlowEditorStyle"))); const FVector2D Icon16(16.0f, 16.0f); + const FVector2D Icon20(20.0f, 20.0f); const FVector2D Icon30(30.0f, 30.0f); const FVector2D Icon40(40.0f, 40.0f); const FVector2D Icon64(64.0f, 64.0f); @@ -29,6 +31,8 @@ void FFlowEditorStyle::Initialize() // engine assets StyleSet->SetContentRoot(FPaths::EngineContentDir() / TEXT("Editor/Slate/")); + StyleSet->Set("FlowToolbar.RefreshAsset", new IMAGE_BRUSH_SVG( "Starship/Common/Apply", Icon20)); + StyleSet->Set("FlowToolbar.SearchInAsset", new IMAGE_BRUSH_SVG( "Starship/Common/Search", Icon20)); StyleSet->Set("FlowToolbar.GoToParentInstance", new IMAGE_BRUSH("Icons/icon_DebugStepOut_40x", Icon40)); StyleSet->Set("FlowGraph.BreakpointEnabled", new IMAGE_BRUSH("Old/Kismet2/Breakpoint_Valid", FVector2D(24.0f, 24.0f))); @@ -44,8 +48,6 @@ void FFlowEditorStyle::Initialize() StyleSet->Set("ClassIcon.FlowAsset", new IMAGE_BRUSH(TEXT("Icons/FlowAsset_16x"), Icon16)); StyleSet->Set("ClassThumbnail.FlowAsset", new IMAGE_BRUSH(TEXT("Icons/FlowAsset_64x"), Icon64)); - StyleSet->Set("FlowToolbar.RefreshAsset", new IMAGE_BRUSH("Icons/Refresh", Icon40)); - StyleSet->Set("Flow.Node.Title", new BOX_BRUSH("Icons/FlowNode_Title", FMargin(8.0f/64.0f, 0, 0, 0))); StyleSet->Set("Flow.Node.Body", new BOX_BRUSH("Icons/FlowNode_Body", FMargin(16.f/64.f))); StyleSet->Set("Flow.Node.ActiveShadow", new BOX_BRUSH("Icons/FlowNode_Shadow_Active", FMargin(18.0f/64.0f))); diff --git a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h index 2e811e975..063419f87 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h @@ -36,12 +36,16 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit TSharedPtr FocusedGraphEditor; TSharedPtr DetailsView; TSharedPtr Palette; +#if ENABLE_SEARCH_IN_ASSET_EDITOR + TSharedPtr SearchBrowser; +#endif public: /** The tab ids for all the tabs used */ static const FName DetailsTab; static const FName GraphTab; static const FName PaletteTab; + static const FName SearchTab; private: /** The current UI selection state of this editor */ @@ -84,8 +88,9 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit private: TSharedRef SpawnTab_Details(const FSpawnTabArgs& Args) const; - TSharedRef SpawnTab_GraphCanvas(const FSpawnTabArgs& Args) const; + TSharedRef SpawnTab_Graph(const FSpawnTabArgs& Args) const; TSharedRef SpawnTab_Palette(const FSpawnTabArgs& Args) const; + TSharedRef SpawnTab_Search(const FSpawnTabArgs& Args) const; public: /** Edits the specified FlowAsset object */ @@ -96,6 +101,10 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit virtual void BindToolbarCommands(); virtual void RefreshAsset(); +#if ENABLE_SEARCH_IN_ASSET_EDITOR + virtual void SearchInAsset(); +#endif + virtual void GoToParentInstance(); virtual bool CanGoToParentInstance(); @@ -143,7 +152,7 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit // FAssetEditorToolkit virtual void JumpToInnerObject(UObject* InnerObject) override; // -- -#endif +#endif protected: virtual void SelectAllNodes() const; diff --git a/Source/FlowEditor/Public/FlowEditorCommands.h b/Source/FlowEditor/Public/FlowEditorCommands.h index 16613c857..341419db5 100644 --- a/Source/FlowEditor/Public/FlowEditorCommands.h +++ b/Source/FlowEditor/Public/FlowEditorCommands.h @@ -13,6 +13,7 @@ class FLOWEDITOR_API FFlowToolbarCommands final : public TCommands RefreshAsset; + TSharedPtr SearchInAsset; TSharedPtr GoToParentInstance; virtual void RegisterCommands() override; diff --git a/Source/FlowEditor/Public/FlowEditorDefines.h b/Source/FlowEditor/Public/FlowEditorDefines.h index d9cbd0757..bd4834e33 100644 --- a/Source/FlowEditor/Public/FlowEditorDefines.h +++ b/Source/FlowEditor/Public/FlowEditorDefines.h @@ -19,3 +19,9 @@ * Set macro value to 1, if you made these changes to the engine: https://github.com/EpicGames/UnrealEngine/pull/9882 */ #define ENABLE_JUMP_TO_INNER_OBJECT 0 + +/** + * Documentation: https://github.com/MothCocoon/FlowGraph/wiki/Asset-Search + * Set macro value to 1, if you made these changes to the engine: https://github.com/EpicGames/UnrealEngine/pull/9943 + */ +#define ENABLE_SEARCH_IN_ASSET_EDITOR 0 From 2da16845026033aab8be0c051a33df3739558efd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 30 Dec 2022 17:15:33 +0100 Subject: [PATCH 208/338] removed dead code --- Source/FlowEditor/Private/Asset/FlowAssetIndexer.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetIndexer.cpp b/Source/FlowEditor/Private/Asset/FlowAssetIndexer.cpp index 4492e1f95..ccb58de6e 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetIndexer.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetIndexer.cpp @@ -15,7 +15,6 @@ #include "EdGraph/EdGraphPin.h" #include "EdGraphNode_Comment.h" -#include "Engine/SimpleConstructionScript.h" #include "Internationalization/Text.h" #include "SearchSerializer.h" #include "Utility/IndexerUtilities.h" @@ -44,15 +43,6 @@ void FFlowAssetIndexer::IndexAsset(const UObject* InAssetObject, FSearchSerializ { Serializer.BeginIndexingObject(FlowAsset, TEXT("$self")); - // for (const FName& CustomInput : FlowAsset->GetCustomInputs()) - // { - // Serializer.IndexProperty(CustomInput.ToString(), CustomInput); - // } - // for (const FName& CustomOutput : FlowAsset->GetCustomOutputs()) - // { - // Serializer.IndexProperty(CustomOutput.ToString(), CustomOutput); - // } - FIndexerUtilities::IterateIndexableProperties(FlowAsset, [&Serializer](const FProperty* Property, const FString& Value) { Serializer.IndexProperty(Property, Value); From dcf6d10c03f3de56f8ef133d5a926cdbdfbae37a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 30 Dec 2022 17:27:23 +0100 Subject: [PATCH 209/338] merge fix --- Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp index 95e95f77c..d96210084 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp @@ -202,6 +202,7 @@ void FFlowAssetToolbar::BuildAssetToolbar(UToolMenu* ToolbarMenu) const Section.AddEntry(FToolMenuEntry::InitToolBarButton(FFlowToolbarCommands::Get().SearchInAsset)); #endif +#if ENABLE_FLOW_DIFF // Visual Diff: menu to choose asset revision compared with the current one Section.AddDynamicEntry("SourceControlCommands", FNewToolMenuSectionDelegate::CreateLambda([this](FToolMenuSection& InSection) { From e8c2fed19dded4daa2ab92d2df4254580ddee82c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sat, 31 Dec 2022 12:46:21 +0100 Subject: [PATCH 210/338] ifdef include to silence static analysis --- Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index c9bd6a7c7..f2dd8ffef 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -30,10 +30,13 @@ #include "PropertyEditorModule.h" #include "ScopedTransaction.h" #include "SNodePanel.h" -#include "Source/Private/Widgets/SSearchBrowser.h" #include "ToolMenus.h" #include "Widgets/Docking/SDockTab.h" +#if ENABLE_SEARCH_IN_ASSET_EDITOR +#include "Source/Private/Widgets/SSearchBrowser.h" +#endif + #define LOCTEXT_NAMESPACE "FlowAssetEditor" const FName FFlowAssetEditor::DetailsTab(TEXT("Details")); From a37238679ec814aaf908ded725e8b2cf213c325e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sat, 31 Dec 2022 12:50:00 +0100 Subject: [PATCH 211/338] cosmetic cleanup --- Source/FlowEditor/Public/Asset/FlowAssetEditor.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h index 063419f87..7de2d5d6c 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h @@ -59,10 +59,12 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit // FGCObject virtual void AddReferencedObjects(FReferenceCollector& Collector) override; + virtual FString GetReferencerName() const override { return TEXT("FFlowAssetEditor"); } + // -- // FEditorUndoClient @@ -90,7 +92,9 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit TSharedRef SpawnTab_Details(const FSpawnTabArgs& Args) const; TSharedRef SpawnTab_Graph(const FSpawnTabArgs& Args) const; TSharedRef SpawnTab_Palette(const FSpawnTabArgs& Args) const; +#if ENABLE_SEARCH_IN_ASSET_EDITOR TSharedRef SpawnTab_Search(const FSpawnTabArgs& Args) const; +#endif public: /** Edits the specified FlowAsset object */ @@ -103,8 +107,8 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit virtual void RefreshAsset(); #if ENABLE_SEARCH_IN_ASSET_EDITOR virtual void SearchInAsset(); -#endif - +#endif + virtual void GoToParentInstance(); virtual bool CanGoToParentInstance(); @@ -228,7 +232,7 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit bool CanSetSignalMode(const EFlowSignalMode Mode) const; void OnForcePinActivation() const; - + void FocusViewport() const; bool CanFocusViewport() const; From f6a4faff288ed1f3e050e7cdd3937fe6f3255c5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 1 Jan 2023 19:33:34 +0100 Subject: [PATCH 212/338] node validation added --- .../Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp | 12 ++++++++++++ Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h | 3 ++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp index dede5195c..ab6dfa5bb 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp @@ -3,6 +3,7 @@ #include "Nodes/Route/FlowNode_SubGraph.h" #include "FlowAsset.h" +#include "FlowMessageLog.h" #include "FlowSubsystem.h" FFlowPin UFlowNode_SubGraph::StartPin(TEXT("Start")); @@ -105,6 +106,17 @@ UObject* UFlowNode_SubGraph::GetAssetToEdit() return Asset.IsNull() ? nullptr : LoadAsset(Asset); } +EDataValidationResult UFlowNode_SubGraph::ValidateNode() +{ + if (Asset.IsNull()) + { + Log.Error(TEXT("Flow Asset not assigned or invalid!"), this); + return EDataValidationResult::Invalid; + } + + return EDataValidationResult::Valid; +} + TArray UFlowNode_SubGraph::GetContextInputs() { TArray EventNames; diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h b/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h index 522540f25..d6356e1a0 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h @@ -52,7 +52,8 @@ class FLOW_API UFlowNode_SubGraph : public UFlowNode #if WITH_EDITOR virtual FString GetNodeDescription() const override; virtual UObject* GetAssetToEdit() override; - + virtual EDataValidationResult ValidateNode() override; + virtual bool SupportsContextPins() const override { return true; } virtual TArray GetContextInputs() override; From 828ab03a7dcfc06facc5bc609c359f3882de3f2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 1 Jan 2023 19:32:53 +0100 Subject: [PATCH 213/338] added Message Log support! Node validation uses new UFlowNode::ValidateNode method which is available in C++ only --- Source/Flow/Flow.Build.cs | 8 +- Source/Flow/Private/FlowAsset.cpp | 23 ++-- Source/Flow/Private/FlowMessageLog.cpp | 84 +++++++++++++ Source/Flow/Private/Nodes/FlowNode.cpp | 24 +++- Source/Flow/Public/FlowAsset.h | 6 +- Source/Flow/Public/FlowMessageLog.h | 94 ++++++++++++++ Source/Flow/Public/Nodes/FlowNode.h | 11 +- Source/FlowEditor/FlowEditor.Build.cs | 1 + .../Private/Asset/FlowAssetEditor.cpp | 116 +++++++++++++++--- .../Private/Asset/FlowMessageLogListing.cpp | 70 +++++++++++ Source/FlowEditor/Private/Graph/FlowGraph.cpp | 13 +- .../Private/Graph/FlowGraphSchema_Actions.cpp | 4 +- .../Private/Graph/Nodes/FlowGraphNode.cpp | 13 +- .../Private/Graph/Widgets/SFlowGraphNode.cpp | 34 ++++- .../Graph/Widgets/SFlowGraphNode_SubGraph.cpp | 1 - .../FlowEditor/Public/Asset/FlowAssetEditor.h | 9 +- .../Public/Asset/FlowMessageLogListing.h | 29 +++++ Source/FlowEditor/Public/Graph/FlowGraph.h | 2 + .../Public/Graph/Nodes/FlowGraphNode.h | 7 +- 19 files changed, 505 insertions(+), 44 deletions(-) create mode 100644 Source/Flow/Private/FlowMessageLog.cpp create mode 100644 Source/Flow/Public/FlowMessageLog.h create mode 100644 Source/FlowEditor/Private/Asset/FlowMessageLogListing.cpp create mode 100644 Source/FlowEditor/Public/Asset/FlowMessageLogListing.h diff --git a/Source/Flow/Flow.Build.cs b/Source/Flow/Flow.Build.cs index b69475b87..62f81ef48 100644 --- a/Source/Flow/Flow.Build.cs +++ b/Source/Flow/Flow.Build.cs @@ -24,11 +24,15 @@ public Flow(ReadOnlyTargetRules Target) : base(Target) "MovieSceneTracks", "Slate", "SlateCore" - }); + }); if (Target.Type == TargetType.Editor) { - PublicDependencyModuleNames.Add("UnrealEd"); + PublicDependencyModuleNames.AddRange(new[] + { + "MessageLog", + "UnrealEd" + }); } } } diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 054474096..45c330ac6 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -1,6 +1,8 @@ // Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors #include "FlowAsset.h" + +#include "FlowMessageLog.h" #include "FlowSettings.h" #include "FlowSubsystem.h" @@ -62,23 +64,28 @@ void UFlowAsset::PostDuplicate(bool bDuplicateForPIE) } } -EDataValidationResult UFlowAsset::IsDataValid(TArray& ValidationErrors) +EDataValidationResult UFlowAsset::ValidateAsset(FFlowMessageLog& MessageLog) { + // first attempt to refresh graph, fix common issues automatically + if (GetFlowGraphInterface().IsValid()) + { + GetFlowGraphInterface()->RefreshGraph(this); + } + + // validate nodes for (const TPair& Node : Nodes) { - if (Node.Value == nullptr || Node.Value->IsDataValid(ValidationErrors) == EDataValidationResult::Invalid) + if (Node.Value) { - // refresh data if Node is missing, i.e. its class has been deleted - if (Node.Value == nullptr) + Node.Value->Log.Messages.Empty(); + if (Node.Value->ValidateNode() == EDataValidationResult::Invalid) { - HarvestNodeConnections(); + MessageLog.Messages.Append(Node.Value->Log.Messages); } - - return EDataValidationResult::Invalid; } } - return EDataValidationResult::Valid; + return MessageLog.Messages.Num() > 0 ? EDataValidationResult::Invalid : EDataValidationResult::Valid; } TSharedPtr UFlowAsset::FlowGraphInterface = nullptr; diff --git a/Source/Flow/Private/FlowMessageLog.cpp b/Source/Flow/Private/FlowMessageLog.cpp new file mode 100644 index 000000000..ec5afe928 --- /dev/null +++ b/Source/Flow/Private/FlowMessageLog.cpp @@ -0,0 +1,84 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#include "FlowMessageLog.h" +#include "Nodes/FlowNode.h" +#include "FlowAsset.h" + +#define LOCTEXT_NAMESPACE "FlowMessageLog" + +const FName FFlowMessageLog::LogName(TEXT("FlowGraph")); + +FFlowGraphToken::FFlowGraphToken(const UFlowAsset* InFlowAsset) +{ + CachedText = FText::FromString(InFlowAsset->GetClass()->GetPathName()); +} + +FFlowGraphToken::FFlowGraphToken(const UFlowNode* InFlowNode) + : GraphNode(InFlowNode->GetGraphNode()) +{ + CachedText = InFlowNode->GetNodeTitle(); +} + +FFlowGraphToken::FFlowGraphToken(UEdGraphNode* InGraphNode, const UEdGraphPin* InPin) + : GraphNode(InGraphNode) + , GraphPin(InPin) +{ + if (InPin) + { + CachedText = InPin->GetDisplayName(); + if (CachedText.IsEmpty()) + { + CachedText = LOCTEXT("UnnamedPin", ""); + } + } + else + { + CachedText = GraphNode->GetNodeTitle(ENodeTitleType::ListView); + } +} + +TSharedPtr FFlowGraphToken::Create(const UFlowAsset* InFlowAsset, FTokenizedMessage& Message) +{ + if (InFlowAsset) + { + Message.AddToken(MakeShareable(new FFlowGraphToken(InFlowAsset))); + return Message.GetMessageTokens().Last(); + } + + return nullptr; +} + +TSharedPtr FFlowGraphToken::Create(const UFlowNode* InFlowNode, FTokenizedMessage& Message) +{ + if (InFlowNode) + { + Message.AddToken(MakeShareable(new FFlowGraphToken(InFlowNode))); + return Message.GetMessageTokens().Last(); + } + + return nullptr; +} + +TSharedPtr FFlowGraphToken::Create(UEdGraphNode* InGraphNode, FTokenizedMessage& Message) +{ + if (InGraphNode) + { + Message.AddToken(MakeShareable(new FFlowGraphToken(InGraphNode, nullptr))); + return Message.GetMessageTokens().Last(); + } + + return nullptr; +} + +TSharedPtr FFlowGraphToken::Create(const UEdGraphPin* InPin, FTokenizedMessage& Message) +{ + if (InPin && InPin->GetOwningNode()) + { + Message.AddToken(MakeShareable(new FFlowGraphToken(InPin->GetOwningNode(), InPin))); + return Message.GetMessageTokens().Last(); + } + + return nullptr; +} + +#undef LOCTEXT_NAMESPACE diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index d2aefbaa6..db83ace65 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -3,6 +3,7 @@ #include "Nodes/FlowNode.h" #include "FlowAsset.h" +#include "FlowMessageLog.h" #include "FlowModule.h" #include "FlowSubsystem.h" #include "FlowTypes.h" @@ -649,12 +650,13 @@ FString UFlowNode::GetProgressAsString(float Value) return TempString; } -void UFlowNode::LogError(FString Message, const EFlowOnScreenMessageType OnScreenMessageType) const +void UFlowNode::LogError(FString Message, const EFlowOnScreenMessageType OnScreenMessageType) { #if !UE_BUILD_SHIPPING const FString TemplatePath = GetFlowAsset()->TemplateAsset->GetPathName(); Message += TEXT(" --- node ") + GetName() + TEXT(", asset ") + FPaths::GetPath(TemplatePath) / FPaths::GetBaseFilename(TemplatePath); + // OnScreen Message if (OnScreenMessageType == EFlowOnScreenMessageType::Permanent) { if (GetWorld()) @@ -675,16 +677,34 @@ void UFlowNode::LogError(FString Message, const EFlowOnScreenMessageType OnScree GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, Message); } + // Message Log - not yet functional + { + Log.Error(*Message, GetGraphNode()); + + FMessageLog MessageLog("FlowGraph"); + MessageLog.AddMessages(Log.Messages); + } + + // Output Log UE_LOG(LogFlow, Error, TEXT("%s"), *Message); #endif } -void UFlowNode::LogMessage(FString Message) const +void UFlowNode::LogMessage(FString Message) { #if !UE_BUILD_SHIPPING const FString TemplatePath = GetFlowAsset()->TemplateAsset->GetPathName(); Message += TEXT(" --- node ") + GetName() + TEXT(", asset ") + FPaths::GetPath(TemplatePath) / FPaths::GetBaseFilename(TemplatePath); + // Message Log - not yet functional + { + Log.Note(*Message, GetGraphNode()); + + FMessageLog MessageLog("FlowGraph"); + MessageLog.AddMessages(Log.Messages); + } + + // Output Log UE_LOG(LogFlow, Log, TEXT("%s"), *Message); #endif } diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 281875987..efb57a00e 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -2,6 +2,7 @@ #pragma once +#include "FlowMessageLog.h" #include "FlowSave.h" #include "FlowTypes.h" #include "FlowAsset.generated.h" @@ -25,6 +26,8 @@ class FLOW_API IFlowGraphInterface IFlowGraphInterface() {} virtual ~IFlowGraphInterface() {} + virtual void RefreshGraph(UFlowAsset* FlowAsset) {} + virtual void OnInputTriggered(UEdGraphNode* GraphNode, const int32 Index) const {} virtual void OnOutputTriggered(UEdGraphNode* GraphNode, const int32 Index) const {} }; @@ -66,8 +69,9 @@ class FLOW_API UFlowAsset : public UObject static void AddReferencedObjects(UObject* InThis, FReferenceCollector& Collector); virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; virtual void PostDuplicate(bool bDuplicateForPIE) override; - virtual EDataValidationResult IsDataValid(TArray& ValidationErrors) override; // -- + + virtual EDataValidationResult ValidateAsset(FFlowMessageLog& MessageLog); #endif // IFlowGraphInterface diff --git a/Source/Flow/Public/FlowMessageLog.h b/Source/Flow/Public/FlowMessageLog.h new file mode 100644 index 000000000..3ac6cc84c --- /dev/null +++ b/Source/Flow/Public/FlowMessageLog.h @@ -0,0 +1,94 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#pragma once + +#include "EdGraph/EdGraphNode.h" +#include "Logging/TokenizedMessage.h" +#include "Misc/UObjectToken.h" + +class UFlowAsset; +class UFlowNode; + +/** + * Message Log token that links to an element in Flow Graph + */ +class FLOW_API FFlowGraphToken : public IMessageToken +{ +private: + const TWeakObjectPtr GraphNode; + const FEdGraphPinReference GraphPin; + + explicit FFlowGraphToken(const UFlowAsset* InFlowAsset); + explicit FFlowGraphToken(const UFlowNode* InFlowNode); + explicit FFlowGraphToken(UEdGraphNode* InGraphNode, const UEdGraphPin* InPin); + +public: + /** Factory method, tokens can only be constructed as shared refs */ + static TSharedPtr Create(const UFlowAsset* InFlowAsset, FTokenizedMessage& Message); + static TSharedPtr Create(const UFlowNode* InFlowNode, FTokenizedMessage& Message); + static TSharedPtr Create(UEdGraphNode* InGraphNode, FTokenizedMessage& Message); + static TSharedPtr Create(const UEdGraphPin* InPin, FTokenizedMessage& Message); + + const UEdGraphNode* GetGraphNode() const { return GraphNode.Get(); } + const UEdGraphPin* GetPin() const { return GraphPin.Get(); } + + // IMessageToken + virtual EMessageToken::Type GetType() const override + { + return EMessageToken::EdGraph; + } +}; + +/** + * List of Message Log lines + */ +class FLOW_API FFlowMessageLog +{ +public: + static const FName LogName; + TArray> Messages; + +public: + FFlowMessageLog() + { + } + + template + void Error(const TCHAR* Format, T* Object) + { + TSharedRef Message = FTokenizedMessage::Create(EMessageSeverity::Error); + AddMessage(NAME_None, Format, Message, Object); + } + + template + void Warning(const TCHAR* Format, T* Object) + { + TSharedRef Message = FTokenizedMessage::Create(EMessageSeverity::Warning); + AddMessage(NAME_None, Format, Message, Object); + } + + template + void Note(const TCHAR* Format, T* Object) + { + TSharedRef Message = FTokenizedMessage::Create(EMessageSeverity::Info); + AddMessage(NAME_None, Format, Message, Object); + } + +protected: + template + void AddMessage(FName MessageID, const TCHAR* Format, TSharedRef& Message, T* Object) + { + Message->SetIdentifier(MessageID); + + if (Object) + { + if (const TSharedPtr Token = FFlowGraphToken::Create(Object, Message.Get())) + { + Message->SetMessageLink(FUObjectToken::Create(Object)); + } + } + + Message.Get().AddToken(FTextToken::Create(FText::FromString(Format))); + Messages.Add(Message); + } +}; diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index cbc2a8576..e36d4c6b5 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -7,6 +7,7 @@ #include "GameplayTagContainer.h" #include "VisualLogger/VisualLoggerDebugSnapshotInterface.h" +#include "FlowMessageLog.h" #include "FlowTypes.h" #include "Nodes/FlowPin.h" #include "FlowNode.generated.h" @@ -74,6 +75,8 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte // Opportunity to update node's data before UFlowGraphNode would call ReconstructNode() virtual void FixNode(UEdGraphNode* NewGraphNode); + + virtual EDataValidationResult ValidateNode() { return EDataValidationResult::NotValidated; } #endif UEdGraphNode* GetGraphNode() const { return GraphNode; } @@ -121,6 +124,10 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte // Designed to handle patching UPROPERTY() EFlowSignalMode SignalMode; + +#if !UE_BUILD_SHIPPING + FFlowMessageLog Log; +#endif ////////////////////////////////////////////////////////////////////////// // All created pins (default, class-specific and added by user) @@ -379,10 +386,10 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte static FString GetProgressAsString(float Value); UFUNCTION(BlueprintCallable, Category = "FlowNode", meta = (DevelopmentOnly)) - void LogError(FString Message, const EFlowOnScreenMessageType OnScreenMessageType = EFlowOnScreenMessageType::Permanent) const; + void LogError(FString Message, const EFlowOnScreenMessageType OnScreenMessageType = EFlowOnScreenMessageType::Permanent); UFUNCTION(BlueprintCallable, Category = "FlowNode", meta = (DevelopmentOnly)) - void LogMessage(FString Message) const; + void LogMessage(FString Message); UFUNCTION(BlueprintCallable, Category = "FlowNode") void SaveInstance(FFlowNodeSaveData& NodeRecord); diff --git a/Source/FlowEditor/FlowEditor.Build.cs b/Source/FlowEditor/FlowEditor.Build.cs index 90b593114..3de6ce699 100644 --- a/Source/FlowEditor/FlowEditor.Build.cs +++ b/Source/FlowEditor/FlowEditor.Build.cs @@ -36,6 +36,7 @@ public FlowEditor(ReadOnlyTargetRules Target) : base(Target) "KismetWidgets", "LevelEditor", "LevelSequence", + "MessageLog", "MovieScene", "MovieSceneTracks", "MovieSceneTools", diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index f2dd8ffef..ed1c607f7 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -2,10 +2,13 @@ #include "Asset/FlowAssetEditor.h" +#include "FlowEditorCommands.h" +#include "FlowEditorModule.h" +#include "FlowMessageLog.h" + #include "Asset/FlowAssetToolbar.h" #include "Asset/FlowDebugger.h" -#include "FlowEditorCommands.h" -#include "Graph/FlowGraph.h" +#include "Asset/FlowMessageLogListing.h" #include "Graph/FlowGraphEditorSettings.h" #include "Graph/FlowGraphSchema.h" #include "Graph/FlowGraphSchema_Actions.h" @@ -24,8 +27,11 @@ #include "GraphEditorActions.h" #include "HAL/PlatformApplicationMisc.h" #include "IDetailsView.h" +#include "IMessageLogListing.h" #include "Kismet2/DebuggerCommands.h" #include "LevelEditor.h" +#include "MessageLogModule.h" +#include "Misc/UObjectToken.h" #include "Modules/ModuleManager.h" #include "PropertyEditorModule.h" #include "ScopedTransaction.h" @@ -41,6 +47,7 @@ const FName FFlowAssetEditor::DetailsTab(TEXT("Details")); const FName FFlowAssetEditor::GraphTab(TEXT("Graph")); +const FName FFlowAssetEditor::MessagesTab(TEXT("Messages")); const FName FFlowAssetEditor::PaletteTab(TEXT("Palette")); const FName FFlowAssetEditor::SearchTab(TEXT("Search")); @@ -120,6 +127,11 @@ void FFlowAssetEditor::RegisterTabSpawners(const TSharedRef& .SetDisplayName(LOCTEXT("GraphTab", "Viewport")) .SetGroup(WorkspaceMenuCategoryRef) .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "GraphEditor.EventGraph_16x")); + + InTabManager->RegisterTabSpawner(MessagesTab, FOnSpawnTab::CreateSP(this, &FFlowAssetEditor::SpawnTab_MessageLog)) + .SetDisplayName(LOCTEXT("MessagesTab", "Messages")) + .SetGroup(WorkspaceMenuCategoryRef) + .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "Kismet.Tabs.CompilerResults")); InTabManager->RegisterTabSpawner(PaletteTab, FOnSpawnTab::CreateSP(this, &FFlowAssetEditor::SpawnTab_Palette)) .SetDisplayName(LOCTEXT("PaletteTab", "Palette")) @@ -140,6 +152,7 @@ void FFlowAssetEditor::UnregisterTabSpawners(const TSharedRef InTabManager->UnregisterTabSpawner(DetailsTab); InTabManager->UnregisterTabSpawner(GraphTab); + InTabManager->UnregisterTabSpawner(MessagesTab); InTabManager->UnregisterTabSpawner(PaletteTab); #if ENABLE_SEARCH_IN_ASSET_EDITOR InTabManager->UnregisterTabSpawner(SearchTab); @@ -189,6 +202,17 @@ TSharedRef FFlowAssetEditor::SpawnTab_Graph(const FSpawnTabArgs& Args) return SpawnedTab; } +TSharedRef FFlowAssetEditor::SpawnTab_MessageLog(const FSpawnTabArgs& Args) const +{ + check(Args.GetTabId() == MessagesTab); + + return SNew(SDockTab) + .Label(LOCTEXT("FlowMessagesTitle", "Messages")) + [ + MessageLog.ToSharedRef() + ]; +} + TSharedRef FFlowAssetEditor::SpawnTab_Palette(const FSpawnTabArgs& Args) const { check(Args.GetTabId() == PaletteTab); @@ -217,7 +241,7 @@ void FFlowAssetEditor::InitFlowAssetEditor(const EToolkitMode::Type Mode, const BindGraphCommands(); CreateWidgets(); - const TSharedRef StandaloneDefaultLayout = FTabManager::NewLayout("FlowAssetEditor_Layout_v4") + const TSharedRef StandaloneDefaultLayout = FTabManager::NewLayout("FlowAssetEditor_Layout_v5") ->AddArea ( FTabManager::NewPrimaryArea()->SetOrientation(Orient_Horizontal) @@ -240,6 +264,12 @@ void FFlowAssetEditor::InitFlowAssetEditor(const EToolkitMode::Type Mode, const ->AddTab(GraphTab, ETabState::OpenedTab) ) ->Split + ( + FTabManager::NewStack() + ->SetSizeCoefficient(0.2f) + ->AddTab(MessagesTab, ETabState::ClosedTab) + ) + ->Split ( FTabManager::NewStack() ->SetSizeCoefficient(0.2f) @@ -308,10 +338,18 @@ void FFlowAssetEditor::BindToolbarCommands() void FFlowAssetEditor::RefreshAsset() { - if (UFlowGraph* FlowGraph = Cast(FlowAsset->GetGraph())) + // Refresh and validate asset, including graph + FFlowMessageLog LogResults; + FlowAsset->ValidateAsset(LogResults); + + // push messages to its window + MessageLogListing->ClearMessages(); + if (LogResults.Messages.Num() > 0) { - FlowGraph->RefreshGraph(); + TabManager->TryInvokeTab(MessagesTab); + MessageLogListing->AddMessages(LogResults.Messages); } + MessageLogListing->OnDataChanged().Broadcast(); } #if ENABLE_SEARCH_IN_ASSET_EDITOR @@ -339,21 +377,32 @@ void FFlowAssetEditor::CreateWidgets() { FocusedGraphEditor = CreateGraphWidget(); - FDetailsViewArgs Args; - Args.bHideSelectionTip = true; - Args.bShowPropertyMatrixButton = false; - Args.DefaultsOnlyVisibility = EEditDefaultsOnlyNodeVisibility::Hide; - Args.NotifyHook = this; + { + FDetailsViewArgs Args; + Args.bHideSelectionTip = true; + Args.bShowPropertyMatrixButton = false; + Args.DefaultsOnlyVisibility = EEditDefaultsOnlyNodeVisibility::Hide; + Args.NotifyHook = this; + + FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked("PropertyEditor"); + DetailsView = PropertyModule.CreateDetailView(Args); + DetailsView->SetIsPropertyEditingEnabledDelegate(FIsPropertyEditingEnabled::CreateStatic(&FFlowAssetEditor::CanEdit)); + DetailsView->SetObject(FlowAsset); + } - FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked("PropertyEditor"); - DetailsView = PropertyModule.CreateDetailView(Args); - DetailsView->SetIsPropertyEditingEnabledDelegate(FIsPropertyEditingEnabled::CreateStatic(&FFlowAssetEditor::CanEdit)); - DetailsView->SetObject(FlowAsset); + Palette = SNew(SFlowPalette, SharedThis(this)); #if ENABLE_SEARCH_IN_ASSET_EDITOR SearchBrowser = SNew(SSearchBrowser, GetFlowAsset()); #endif - Palette = SNew(SFlowPalette, SharedThis(this)); + + { + MessageLogListing = FFlowMessageLogListing::GetLogListing(FlowAsset); + MessageLogListing->OnMessageTokenClicked().AddSP(this, &FFlowAssetEditor::OnLogTokenClicked); + + FMessageLogModule& MessageLogModule = FModuleManager::LoadModuleChecked("MessageLog"); + MessageLog = MessageLogModule.CreateLogListingWidget(MessageLogListing.ToSharedRef()); + } } TSharedRef FFlowAssetEditor::CreateGraphWidget() @@ -718,11 +767,46 @@ void FFlowAssetEditor::JumpToInnerObject(UObject* InnerObject) { if (const UFlowNode* FlowNode = Cast(InnerObject)) { - FocusedGraphEditor->JumpToNode(FlowNode->GetGraphNode(), false); + FocusedGraphEditor->JumpToNode(FlowNode->GetGraphNode(), true); } } #endif +void FFlowAssetEditor::OnLogTokenClicked(const TSharedRef& Token) const +{ + if (Token->GetType() == EMessageToken::Object) + { + const TSharedRef ObjectToken = StaticCastSharedRef(Token); + if (const UObject* Object = ObjectToken->GetObject().Get()) + { + if (Object->IsAsset()) + { + GEditor->GetEditorSubsystem()->OpenEditorForAsset(const_cast(Object)); + } + else + { + UE_LOG(LogFlowEditor, Warning, TEXT("Unknown type of hyperlinked object (%s), cannot focus it"), *GetNameSafe(Object)); + } + } + } + else if (Token->GetType() == EMessageToken::EdGraph && FocusedGraphEditor.IsValid()) + { + const TSharedRef EdGraphToken = StaticCastSharedRef(Token); + + if (const UEdGraphPin* GraphPin = EdGraphToken->GetPin()) + { + if (!GraphPin->IsPendingKill()) + { + FocusedGraphEditor->JumpToPin(GraphPin); + } + } + else if (const UEdGraphNode* GraphNode = EdGraphToken->GetGraphNode()) + { + FocusedGraphEditor->JumpToNode(GraphNode, true); + } + } +} + void FFlowAssetEditor::SelectAllNodes() const { FocusedGraphEditor->SelectAllNodes(); diff --git a/Source/FlowEditor/Private/Asset/FlowMessageLogListing.cpp b/Source/FlowEditor/Private/Asset/FlowMessageLogListing.cpp new file mode 100644 index 000000000..516630d1d --- /dev/null +++ b/Source/FlowEditor/Private/Asset/FlowMessageLogListing.cpp @@ -0,0 +1,70 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#include "Asset/FlowMessageLogListing.h" + +#include "MessageLogModule.h" + +#define LOCTEXT_NAMESPACE "FlowMessageLogListing" + +FFlowMessageLogListing::FFlowMessageLogListing(const UFlowAsset* InFlowAsset) + : Log(RegisterLogListing(InFlowAsset)) +{ +} + +FFlowMessageLogListing::~FFlowMessageLogListing() +{ + // Unregister the log so it will be ref-counted to zero if it has no messages + if(Log->NumMessages(EMessageSeverity::Info) == 0) + { + FMessageLogModule& MessageLogModule = FModuleManager::LoadModuleChecked("MessageLog"); + MessageLogModule.UnregisterLogListing(Log->GetName()); + } +} + +TSharedRef FFlowMessageLogListing::RegisterLogListing(const UFlowAsset* InFlowAsset) +{ + FMessageLogModule& MessageLogModule = FModuleManager::LoadModuleChecked("MessageLog"); + + const FName LogName = GetListingName(InFlowAsset); + + // Register the log (this will return an existing log if it has been used before) + FMessageLogInitializationOptions LogInitOptions; + LogInitOptions.bShowInLogWindow = false; + MessageLogModule.RegisterLogListing(LogName, LOCTEXT("FlowGraphLogLabel", "FlowGraph"), LogInitOptions); + return MessageLogModule.GetLogListing(LogName); +} + +TSharedRef FFlowMessageLogListing::GetLogListing(const UFlowAsset* InFlowAsset) +{ + FMessageLogModule& MessageLogModule = FModuleManager::LoadModuleChecked("MessageLog"); + + const FName LogName = GetListingName(InFlowAsset); + + // Reuse any existing log, or create a new one (that is not held onto bey the message log system) + if(MessageLogModule.IsRegisteredLogListing(LogName)) + { + return MessageLogModule.GetLogListing(LogName); + } + else + { + FMessageLogInitializationOptions LogInitOptions; + LogInitOptions.bShowInLogWindow = false; + return MessageLogModule.CreateLogListing(LogName, LogInitOptions); + } +} + +FName FFlowMessageLogListing::GetListingName(const UFlowAsset* InFlowAsset) +{ + FName LogListingName; + if (InFlowAsset) + { + LogListingName = *FString::Printf(TEXT("%s_%s_FlowMessageLog"), *InFlowAsset->AssetGuid.ToString(), *InFlowAsset->GetName()); + } + else + { + LogListingName = "FlowGraph"; + } + return LogListingName; +} + +#undef LOCTEXT_NAMESPACE diff --git a/Source/FlowEditor/Private/Graph/FlowGraph.cpp b/Source/FlowEditor/Private/Graph/FlowGraph.cpp index 096d48bf6..93626cedb 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraph.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraph.cpp @@ -9,6 +9,11 @@ #include "Kismet2/BlueprintEditorUtils.h" +void FFlowGraphInterface::RefreshGraph(UFlowAsset* FlowAsset) +{ + CastChecked(FlowAsset->GetGraph())->RefreshGraph(); +} + void FFlowGraphInterface::OnInputTriggered(UEdGraphNode* GraphNode, const int32 Index) const { CastChecked(GraphNode)->OnInputTriggered(Index); @@ -41,8 +46,8 @@ UEdGraph* UFlowGraph::CreateGraph(UFlowAsset* InFlowAsset) void UFlowGraph::RefreshGraph() { - // don't run fixup in commandlets or PIE - if (!IsRunningCommandlet() && GEditor && !GEditor->PlayWorld) + // don't run fixup in PIE + if (GEditor && !GEditor->PlayWorld) { // check if all Graph Nodes have expected, up-to-date type CastChecked(GetSchema())->GatherNativeNodes(); @@ -59,12 +64,12 @@ void UFlowGraph::RefreshGraph() } } - // update context pins + // refresh nodes TArray FlowGraphNodes; GetNodesOfClass(FlowGraphNodes); for (UFlowGraphNode* GraphNode : FlowGraphNodes) { - GraphNode->RefreshContextPins(true); + GraphNode->OnGraphRefresh(); } } } diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp index 06dfad3b7..6baba1027 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp @@ -62,7 +62,7 @@ UFlowGraphNode* FFlowGraphSchemaAction_NewNode::CreateNode(UEdGraph* ParentGraph // link editor and runtime nodes together UFlowNode* FlowNode = FlowAsset->CreateNode(NodeClass, NewGraphNode); - NewGraphNode->SetFlowNode(FlowNode); + NewGraphNode->SetNodeTemplate(FlowNode); // create pins and connections NewGraphNode->AllocateDefaultPins(); @@ -110,7 +110,7 @@ UFlowGraphNode* FFlowGraphSchemaAction_NewNode::RecreateNode(UEdGraph* ParentGra // link editor and runtime nodes together FlowNode->SetGraphNode(NewGraphNode); - NewGraphNode->SetFlowNode(FlowNode); + NewGraphNode->SetNodeTemplate(FlowNode); // move links from the old node NewGraphNode->AllocateDefaultPins(); diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 3c5d81619..d72ae9260 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -25,7 +25,6 @@ #include "SourceCodeNavigation.h" #include "Textures/SlateIcon.h" #include "ToolMenuSection.h" -#include "UnrealEd.h" #define LOCTEXT_NAMESPACE "FlowGraphNode" @@ -107,11 +106,16 @@ UFlowGraphNode::UFlowGraphNode(const FObjectInitializer& ObjectInitializer) OrphanedPinSaveMode = ESaveOrphanPinMode::SaveAll; } -void UFlowGraphNode::SetFlowNode(UFlowNode* InFlowNode) +void UFlowGraphNode::SetNodeTemplate(UFlowNode* InFlowNode) { FlowNode = InFlowNode; } +const UFlowNode* UFlowGraphNode::GetNodeTemplate() const +{ + return FlowNode; +} + UFlowNode* UFlowGraphNode::GetFlowNode() const { if (FlowNode) @@ -239,6 +243,11 @@ void UFlowGraphNode::OnExternalChange() GetGraph()->NotifyGraphChanged(); } +void UFlowGraphNode::OnGraphRefresh() +{ + RefreshContextPins(true); +} + bool UFlowGraphNode::CanCreateUnderSpecifiedSchema(const UEdGraphSchema* Schema) const { return Schema->IsA(UFlowGraphSchema::StaticClass()); diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp index c6e72260f..a6f371ea5 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp @@ -2,10 +2,8 @@ #include "Graph/Widgets/SFlowGraphNode.h" #include "FlowEditorStyle.h" -#include "Graph/FlowGraphEditorSettings.h" #include "Graph/FlowGraphSettings.h" -#include "FlowAsset.h" #include "Nodes/FlowNode.h" #include "EdGraph/EdGraphPin.h" @@ -361,6 +359,38 @@ void SFlowGraphNode::UpdateErrorInfo() { if (const UFlowNode* FlowNode = FlowGraphNode->GetFlowNode()) { + if (FlowNode->Log.Messages.Num() > 0) + { + EMessageSeverity::Type MaxSeverity = EMessageSeverity::Info; + for (const TSharedRef& Message : FlowNode->Log.Messages) + { + if (Message->GetSeverity() < MaxSeverity) + { + MaxSeverity = Message->GetSeverity(); + } + } + + switch(MaxSeverity) + { + case EMessageSeverity::Error: + ErrorMsg = FString(TEXT("ERROR!")); + ErrorColor = FAppStyle::GetColor("ErrorReporting.BackgroundColor"); + break; + case EMessageSeverity::PerformanceWarning: + case EMessageSeverity::Warning: + ErrorMsg = FString(TEXT("WARNING!")); + ErrorColor = FAppStyle::GetColor("ErrorReporting.WarningBackgroundColor"); + break; + case EMessageSeverity::Info: + ErrorMsg = FString(TEXT("NOTE")); + ErrorColor = FAppStyle::GetColor("InfoReporting.BackgroundColor"); + break; + default: ; + } + + return; + } + if (FlowNode->GetClass()->HasAnyClassFlags(CLASS_Deprecated) || FlowNode->bNodeDeprecated) { ErrorMsg = FlowNode->ReplacedBy ? FString::Printf(TEXT(" REPLACED BY: %s "), *FlowNode->ReplacedBy->GetName()) : FString(TEXT(" DEPRECATED! ")); diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode_SubGraph.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode_SubGraph.cpp index 7e626f880..18216afc7 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode_SubGraph.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode_SubGraph.cpp @@ -6,7 +6,6 @@ #include "FlowAsset.h" #include "Nodes/Route/FlowNode_SubGraph.h" -#include "IDocumentation.h" #include "SGraphPreviewer.h" #include "Widgets/SToolTip.h" diff --git a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h index 7de2d5d6c..04e056a9a 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h @@ -40,10 +40,15 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit TSharedPtr SearchBrowser; #endif + /** Message log, with the log listing that it reflects */ + TSharedPtr MessageLog; + TSharedPtr MessageLogListing; + public: /** The tab ids for all the tabs used */ static const FName DetailsTab; static const FName GraphTab; + static const FName MessagesTab; static const FName PaletteTab; static const FName SearchTab; @@ -64,7 +69,6 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit { return TEXT("FFlowAssetEditor"); } - // -- // FEditorUndoClient @@ -91,6 +95,7 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit private: TSharedRef SpawnTab_Details(const FSpawnTabArgs& Args) const; TSharedRef SpawnTab_Graph(const FSpawnTabArgs& Args) const; + TSharedRef SpawnTab_MessageLog(const FSpawnTabArgs& Args) const; TSharedRef SpawnTab_Palette(const FSpawnTabArgs& Args) const; #if ENABLE_SEARCH_IN_ASSET_EDITOR TSharedRef SpawnTab_Search(const FSpawnTabArgs& Args) const; @@ -159,6 +164,8 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit #endif protected: + void OnLogTokenClicked(const TSharedRef& Token) const; + virtual void SelectAllNodes() const; virtual bool CanSelectAllNodes() const; diff --git a/Source/FlowEditor/Public/Asset/FlowMessageLogListing.h b/Source/FlowEditor/Public/Asset/FlowMessageLogListing.h new file mode 100644 index 000000000..b9935e8b1 --- /dev/null +++ b/Source/FlowEditor/Public/Asset/FlowMessageLogListing.h @@ -0,0 +1,29 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#pragma once + +#include "IMessageLogListing.h" + +#include "FlowAsset.h" + +/** + * Scope wrapper for the message log. Ensures we don't leak logs that we dont need (i.e. those that have no messages) + * Replicated after FScopedBlueprintMessageLog + */ +class FLOWEDITOR_API FFlowMessageLogListing +{ +public: + FFlowMessageLogListing(const UFlowAsset* InFlowAsset); + ~FFlowMessageLogListing(); + +public: + TSharedRef Log; + FName LogName; + +private: + static TSharedRef RegisterLogListing(const UFlowAsset* InFlowAsset); + static FName GetListingName(const UFlowAsset* InFlowAsset); + +public: + static TSharedRef GetLogListing(const UFlowAsset* InFlowAsset); +}; diff --git a/Source/FlowEditor/Public/Graph/FlowGraph.h b/Source/FlowEditor/Public/Graph/FlowGraph.h index 9759dc676..d46cea58f 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraph.h +++ b/Source/FlowEditor/Public/Graph/FlowGraph.h @@ -12,6 +12,8 @@ class FLOWEDITOR_API FFlowGraphInterface final : public IFlowGraphInterface public: virtual ~FFlowGraphInterface() override {} + virtual void RefreshGraph(UFlowAsset* FlowAsset) override; + virtual void OnInputTriggered(UEdGraphNode* GraphNode, const int32 Index) const override; virtual void OnOutputTriggered(UEdGraphNode* GraphNode, const int32 Index) const override; }; diff --git a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h index 7cbc1092f..35733f77d 100644 --- a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h +++ b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h @@ -72,7 +72,9 @@ class FLOWEDITOR_API UFlowGraphNode : public UEdGraphNode UPROPERTY() TArray> AssignedNodeClasses; - void SetFlowNode(UFlowNode* InFlowNode); + void SetNodeTemplate(UFlowNode* InFlowNode); + const UFlowNode* GetNodeTemplate() const; + UFlowNode* GetFlowNode() const; // UObject @@ -96,6 +98,9 @@ class FLOWEDITOR_API UFlowGraphNode : public UEdGraphNode void OnExternalChange(); +public: + virtual void OnGraphRefresh(); + ////////////////////////////////////////////////////////////////////////// // Graph node From 2df6cf3395b6f2ebd2eecd075f6cc8b853c1a93c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 1 Jan 2023 19:37:47 +0100 Subject: [PATCH 214/338] renamed reference to Graph Editor --- .../Private/Asset/FlowAssetEditor.cpp | 92 +++++++++---------- .../FlowEditor/Public/Asset/FlowAssetEditor.h | 2 +- 2 files changed, 47 insertions(+), 47 deletions(-) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index ed1c607f7..cb10badae 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -79,7 +79,7 @@ void FFlowAssetEditor::PostRedo(bool bSuccess) void FFlowAssetEditor::HandleUndoTransaction() { SetUISelectionState(NAME_None); - FocusedGraphEditor->NotifyGraphChanged(); + GraphEditor->NotifyGraphChanged(); FSlateApplication::Get().DismissAllMenus(); } @@ -87,7 +87,7 @@ void FFlowAssetEditor::NotifyPostChange(const FPropertyChangedEvent& PropertyCha { if (PropertyChangedEvent.ChangeType != EPropertyChangeType::Interactive) { - FocusedGraphEditor->NotifyGraphChanged(); + GraphEditor->NotifyGraphChanged(); } } @@ -194,9 +194,9 @@ TSharedRef FFlowAssetEditor::SpawnTab_Graph(const FSpawnTabArgs& Args) TSharedRef SpawnedTab = SNew(SDockTab) .Label(LOCTEXT("FlowGraphTitle", "Graph")); - if (FocusedGraphEditor.IsValid()) + if (GraphEditor.IsValid()) { - SpawnedTab->SetContent(FocusedGraphEditor.ToSharedRef()); + SpawnedTab->SetContent(GraphEditor.ToSharedRef()); } return SpawnedTab; @@ -375,7 +375,7 @@ bool FFlowAssetEditor::CanGoToParentInstance() void FFlowAssetEditor::CreateWidgets() { - FocusedGraphEditor = CreateGraphWidget(); + GraphEditor = CreateGraphWidget(); { FDetailsViewArgs Args; @@ -661,7 +661,7 @@ void FFlowAssetEditor::ClearSelectionStateFor(const FName SelectionOwner) { if (SelectionOwner == GraphTab) { - FocusedGraphEditor->ClearSelectionSet(); + GraphEditor->ClearSelectionSet(); } else if (SelectionOwner == PaletteTab) { @@ -675,12 +675,12 @@ void FFlowAssetEditor::ClearSelectionStateFor(const FName SelectionOwner) void FFlowAssetEditor::OnCreateComment() const { FFlowGraphSchemaAction_NewComment CommentAction; - CommentAction.PerformAction(FlowAsset->GetGraph(), nullptr, FocusedGraphEditor->GetPasteLocation()); + CommentAction.PerformAction(FlowAsset->GetGraph(), nullptr, GraphEditor->GetPasteLocation()); } void FFlowAssetEditor::OnStraightenConnections() const { - FocusedGraphEditor->OnStraightenConnections(); + GraphEditor->OnStraightenConnections(); } bool FFlowAssetEditor::CanEdit() @@ -702,7 +702,7 @@ TSet FFlowAssetEditor::GetSelectedFlowNodes() const { TSet Result; - const FGraphPanelSelectionSet SelectedNodes = FocusedGraphEditor->GetSelectedNodes(); + const FGraphPanelSelectionSet SelectedNodes = GraphEditor->GetSelectedNodes(); for (FGraphPanelSelectionSet::TConstIterator NodeIt(SelectedNodes); NodeIt; ++NodeIt) { if (UFlowGraphNode* SelectedNode = Cast(*NodeIt)) @@ -716,12 +716,12 @@ TSet FFlowAssetEditor::GetSelectedFlowNodes() const int32 FFlowAssetEditor::GetNumberOfSelectedNodes() const { - return FocusedGraphEditor->GetSelectedNodes().Num(); + return GraphEditor->GetSelectedNodes().Num(); } bool FFlowAssetEditor::GetBoundsForSelectedNodes(class FSlateRect& Rect, float Padding) const { - return FocusedGraphEditor->GetBoundsForSelectedNodes(Rect, Padding); + return GraphEditor->GetBoundsForSelectedNodes(Rect, Padding); } void FFlowAssetEditor::OnSelectedNodesChanged(const TSet& Nodes) @@ -758,8 +758,8 @@ void FFlowAssetEditor::OnSelectedNodesChanged(const TSet& Nodes) void FFlowAssetEditor::SelectSingleNode(UEdGraphNode* Node) const { - FocusedGraphEditor->ClearSelectionSet(); - FocusedGraphEditor->SetNodeSelection(Node, true); + GraphEditor->ClearSelectionSet(); + GraphEditor->SetNodeSelection(Node, true); } #if ENABLE_JUMP_TO_INNER_OBJECT @@ -789,7 +789,7 @@ void FFlowAssetEditor::OnLogTokenClicked(const TSharedRef& Token) } } } - else if (Token->GetType() == EMessageToken::EdGraph && FocusedGraphEditor.IsValid()) + else if (Token->GetType() == EMessageToken::EdGraph && GraphEditor.IsValid()) { const TSharedRef EdGraphToken = StaticCastSharedRef(Token); @@ -797,19 +797,19 @@ void FFlowAssetEditor::OnLogTokenClicked(const TSharedRef& Token) { if (!GraphPin->IsPendingKill()) { - FocusedGraphEditor->JumpToPin(GraphPin); + GraphEditor->JumpToPin(GraphPin); } } else if (const UEdGraphNode* GraphNode = EdGraphToken->GetGraphNode()) { - FocusedGraphEditor->JumpToNode(GraphNode, true); + GraphEditor->JumpToNode(GraphNode, true); } } } void FFlowAssetEditor::SelectAllNodes() const { - FocusedGraphEditor->SelectAllNodes(); + GraphEditor->SelectAllNodes(); } bool FFlowAssetEditor::CanSelectAllNodes() const @@ -820,10 +820,10 @@ bool FFlowAssetEditor::CanSelectAllNodes() const void FFlowAssetEditor::DeleteSelectedNodes() { const FScopedTransaction Transaction(LOCTEXT("DeleteSelectedNode", "Delete Selected Node")); - FocusedGraphEditor->GetCurrentGraph()->Modify(); + GraphEditor->GetCurrentGraph()->Modify(); FlowAsset->Modify(); - const FGraphPanelSelectionSet SelectedNodes = FocusedGraphEditor->GetSelectedNodes(); + const FGraphPanelSelectionSet SelectedNodes = GraphEditor->GetSelectedNodes(); SetUISelectionState(NAME_None); for (FGraphPanelSelectionSet::TConstIterator NodeIt(SelectedNodes); NodeIt; ++NodeIt) @@ -837,7 +837,7 @@ void FFlowAssetEditor::DeleteSelectedNodes() { const FGuid NodeGuid = FlowGraphNode->GetFlowNode()->GetGuid(); - FocusedGraphEditor->GetCurrentGraph()->GetSchema()->BreakNodeLinks(*Node); + GraphEditor->GetCurrentGraph()->GetSchema()->BreakNodeLinks(*Node); Node->DestroyNode(); FlowAsset->UnregisterNode(NodeGuid); @@ -845,7 +845,7 @@ void FFlowAssetEditor::DeleteSelectedNodes() } } - FocusedGraphEditor->GetCurrentGraph()->GetSchema()->BreakNodeLinks(*Node); + GraphEditor->GetCurrentGraph()->GetSchema()->BreakNodeLinks(*Node); Node->DestroyNode(); } } @@ -854,11 +854,11 @@ void FFlowAssetEditor::DeleteSelectedNodes() void FFlowAssetEditor::DeleteSelectedDuplicableNodes() { // Cache off the old selection - const FGraphPanelSelectionSet OldSelectedNodes = FocusedGraphEditor->GetSelectedNodes(); + const FGraphPanelSelectionSet OldSelectedNodes = GraphEditor->GetSelectedNodes(); // Clear the selection and only select the nodes that can be duplicated FGraphPanelSelectionSet RemainingNodes; - FocusedGraphEditor->ClearSelectionSet(); + GraphEditor->ClearSelectionSet(); for (FGraphPanelSelectionSet::TConstIterator SelectedIt(OldSelectedNodes); SelectedIt; ++SelectedIt) { @@ -866,7 +866,7 @@ void FFlowAssetEditor::DeleteSelectedDuplicableNodes() { if (Node->CanDuplicateNode()) { - FocusedGraphEditor->SetNodeSelection(Node, true); + GraphEditor->SetNodeSelection(Node, true); } else { @@ -882,7 +882,7 @@ void FFlowAssetEditor::DeleteSelectedDuplicableNodes() { if (UEdGraphNode* Node = Cast(*SelectedIt)) { - FocusedGraphEditor->SetNodeSelection(Node, true); + GraphEditor->SetNodeSelection(Node, true); } } } @@ -891,7 +891,7 @@ bool FFlowAssetEditor::CanDeleteNodes() const { if (CanEdit()) { - const FGraphPanelSelectionSet SelectedNodes = FocusedGraphEditor->GetSelectedNodes(); + const FGraphPanelSelectionSet SelectedNodes = GraphEditor->GetSelectedNodes(); for (FGraphPanelSelectionSet::TConstIterator NodeIt(SelectedNodes); NodeIt; ++NodeIt) { if (const UEdGraphNode* Node = Cast(*NodeIt)) @@ -924,7 +924,7 @@ bool FFlowAssetEditor::CanCutNodes() const void FFlowAssetEditor::CopySelectedNodes() const { - const FGraphPanelSelectionSet SelectedNodes = FocusedGraphEditor->GetSelectedNodes(); + const FGraphPanelSelectionSet SelectedNodes = GraphEditor->GetSelectedNodes(); for (FGraphPanelSelectionSet::TConstIterator SelectedIt(SelectedNodes); SelectedIt; ++SelectedIt) { if (UFlowGraphNode* Node = Cast(*SelectedIt)) @@ -951,7 +951,7 @@ bool FFlowAssetEditor::CanCopyNodes() const { if (CanEdit()) { - const FGraphPanelSelectionSet SelectedNodes = FocusedGraphEditor->GetSelectedNodes(); + const FGraphPanelSelectionSet SelectedNodes = GraphEditor->GetSelectedNodes(); for (FGraphPanelSelectionSet::TConstIterator SelectedIt(SelectedNodes); SelectedIt; ++SelectedIt) { const UEdGraphNode* Node = Cast(*SelectedIt); @@ -967,7 +967,7 @@ bool FFlowAssetEditor::CanCopyNodes() const void FFlowAssetEditor::PasteNodes() { - PasteNodesHere(FocusedGraphEditor->GetPasteLocation()); + PasteNodesHere(GraphEditor->GetPasteLocation()); } void FFlowAssetEditor::PasteNodesHere(const FVector2D& Location) @@ -980,7 +980,7 @@ void FFlowAssetEditor::PasteNodesHere(const FVector2D& Location) FlowAsset->Modify(); // Clear the selection set (newly pasted stuff will be selected) - FocusedGraphEditor->ClearSelectionSet(); + GraphEditor->ClearSelectionSet(); // Grab the text to paste from the clipboard. FString TextToImport; @@ -1020,7 +1020,7 @@ void FFlowAssetEditor::PasteNodesHere(const FVector2D& Location) } // Select the newly pasted stuff - FocusedGraphEditor->SetNodeSelection(Node, true); + GraphEditor->SetNodeSelection(Node, true); Node->NodePosX = (Node->NodePosX - AvgNodePosition.X) + Location.X; Node->NodePosY = (Node->NodePosY - AvgNodePosition.Y) + Location.Y; @@ -1032,7 +1032,7 @@ void FFlowAssetEditor::PasteNodesHere(const FVector2D& Location) FlowAsset->HarvestNodeConnections(); // Update UI - FocusedGraphEditor->NotifyGraphChanged(); + GraphEditor->NotifyGraphChanged(); FlowAsset->PostEditChange(); FlowAsset->MarkPackageDirty(); @@ -1174,7 +1174,7 @@ bool FFlowAssetEditor::CanAddOutput() const void FFlowAssetEditor::RemovePin() const { - if (UEdGraphPin* SelectedPin = FocusedGraphEditor->GetGraphPinForMenu()) + if (UEdGraphPin* SelectedPin = GraphEditor->GetGraphPinForMenu()) { if (UFlowGraphNode* SelectedNode = Cast(SelectedPin->GetOwningNode())) { @@ -1187,7 +1187,7 @@ bool FFlowAssetEditor::CanRemovePin() const { if (CanEdit() && GetSelectedFlowNodes().Num() == 1) { - if (const UEdGraphPin* Pin = FocusedGraphEditor->GetGraphPinForMenu()) + if (const UEdGraphPin* Pin = GraphEditor->GetGraphPinForMenu()) { if (const UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) { @@ -1216,7 +1216,7 @@ void FFlowAssetEditor::OnAddBreakpoint() const void FFlowAssetEditor::OnAddPinBreakpoint() const { - if (UEdGraphPin* Pin = FocusedGraphEditor->GetGraphPinForMenu()) + if (UEdGraphPin* Pin = GraphEditor->GetGraphPinForMenu()) { if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) { @@ -1238,7 +1238,7 @@ bool FFlowAssetEditor::CanAddBreakpoint() const bool FFlowAssetEditor::CanAddPinBreakpoint() const { - if (UEdGraphPin* Pin = FocusedGraphEditor->GetGraphPinForMenu()) + if (UEdGraphPin* Pin = GraphEditor->GetGraphPinForMenu()) { if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) { @@ -1259,7 +1259,7 @@ void FFlowAssetEditor::OnRemoveBreakpoint() const void FFlowAssetEditor::OnRemovePinBreakpoint() const { - if (UEdGraphPin* Pin = FocusedGraphEditor->GetGraphPinForMenu()) + if (UEdGraphPin* Pin = GraphEditor->GetGraphPinForMenu()) { if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) { @@ -1280,7 +1280,7 @@ bool FFlowAssetEditor::CanRemoveBreakpoint() const bool FFlowAssetEditor::CanRemovePinBreakpoint() const { - if (UEdGraphPin* Pin = FocusedGraphEditor->GetGraphPinForMenu()) + if (UEdGraphPin* Pin = GraphEditor->GetGraphPinForMenu()) { if (const UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) { @@ -1301,7 +1301,7 @@ void FFlowAssetEditor::OnEnableBreakpoint() const void FFlowAssetEditor::OnEnablePinBreakpoint() const { - if (UEdGraphPin* Pin = FocusedGraphEditor->GetGraphPinForMenu()) + if (UEdGraphPin* Pin = GraphEditor->GetGraphPinForMenu()) { if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) { @@ -1312,7 +1312,7 @@ void FFlowAssetEditor::OnEnablePinBreakpoint() const bool FFlowAssetEditor::CanEnableBreakpoint() const { - if (UEdGraphPin* Pin = FocusedGraphEditor->GetGraphPinForMenu()) + if (UEdGraphPin* Pin = GraphEditor->GetGraphPinForMenu()) { if (const UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) { @@ -1330,7 +1330,7 @@ bool FFlowAssetEditor::CanEnableBreakpoint() const bool FFlowAssetEditor::CanEnablePinBreakpoint() const { - if (UEdGraphPin* Pin = FocusedGraphEditor->GetGraphPinForMenu()) + if (UEdGraphPin* Pin = GraphEditor->GetGraphPinForMenu()) { if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) { @@ -1351,7 +1351,7 @@ void FFlowAssetEditor::OnDisableBreakpoint() const void FFlowAssetEditor::OnDisablePinBreakpoint() const { - if (UEdGraphPin* Pin = FocusedGraphEditor->GetGraphPinForMenu()) + if (UEdGraphPin* Pin = GraphEditor->GetGraphPinForMenu()) { if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) { @@ -1372,7 +1372,7 @@ bool FFlowAssetEditor::CanDisableBreakpoint() const bool FFlowAssetEditor::CanDisablePinBreakpoint() const { - if (UEdGraphPin* Pin = FocusedGraphEditor->GetGraphPinForMenu()) + if (UEdGraphPin* Pin = GraphEditor->GetGraphPinForMenu()) { if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) { @@ -1393,7 +1393,7 @@ void FFlowAssetEditor::OnToggleBreakpoint() const void FFlowAssetEditor::OnTogglePinBreakpoint() const { - if (UEdGraphPin* Pin = FocusedGraphEditor->GetGraphPinForMenu()) + if (UEdGraphPin* Pin = GraphEditor->GetGraphPinForMenu()) { if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) { @@ -1410,7 +1410,7 @@ bool FFlowAssetEditor::CanToggleBreakpoint() const bool FFlowAssetEditor::CanTogglePinBreakpoint() const { - return FocusedGraphEditor->GetGraphPinForMenu() != nullptr; + return GraphEditor->GetGraphPinForMenu() != nullptr; } void FFlowAssetEditor::SetSignalMode(const EFlowSignalMode Mode) const @@ -1440,7 +1440,7 @@ bool FFlowAssetEditor::CanSetSignalMode(const EFlowSignalMode Mode) const void FFlowAssetEditor::OnForcePinActivation() const { - if (UEdGraphPin* Pin = FocusedGraphEditor->GetGraphPinForMenu()) + if (UEdGraphPin* Pin = GraphEditor->GetGraphPinForMenu()) { if (const UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) { diff --git a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h index 04e056a9a..c08b218e1 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h @@ -33,7 +33,7 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit TSharedPtr AssetToolbar; TSharedPtr FlowDebugger; - TSharedPtr FocusedGraphEditor; + TSharedPtr GraphEditor; TSharedPtr DetailsView; TSharedPtr Palette; #if ENABLE_SEARCH_IN_ASSET_EDITOR From 1c37d704ec226778e337df7797c86707a8c6f953 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 1 Jan 2023 19:48:40 +0100 Subject: [PATCH 215/338] CIS fix --- Source/Flow/Public/FlowMessageLog.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Flow/Public/FlowMessageLog.h b/Source/Flow/Public/FlowMessageLog.h index 3ac6cc84c..75fd57009 100644 --- a/Source/Flow/Public/FlowMessageLog.h +++ b/Source/Flow/Public/FlowMessageLog.h @@ -3,6 +3,7 @@ #pragma once #include "EdGraph/EdGraphNode.h" +#include "EdGraph/EdGraphPin.h" #include "Logging/TokenizedMessage.h" #include "Misc/UObjectToken.h" From 99d762409a077dc1acccf2c9a683768377ba55b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 1 Jan 2023 20:22:51 +0100 Subject: [PATCH 216/338] non-editor build fix --- Source/Flow/Private/FlowMessageLog.cpp | 3 +++ Source/Flow/Public/FlowMessageLog.h | 4 ++++ Source/Flow/Public/Nodes/FlowNode.h | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Source/Flow/Private/FlowMessageLog.cpp b/Source/Flow/Private/FlowMessageLog.cpp index ec5afe928..f4e1ef621 100644 --- a/Source/Flow/Private/FlowMessageLog.cpp +++ b/Source/Flow/Private/FlowMessageLog.cpp @@ -4,6 +4,8 @@ #include "Nodes/FlowNode.h" #include "FlowAsset.h" +#if WITH_EDITOR + #define LOCTEXT_NAMESPACE "FlowMessageLog" const FName FFlowMessageLog::LogName(TEXT("FlowGraph")); @@ -82,3 +84,4 @@ TSharedPtr FFlowGraphToken::Create(const UEdGraphPin* InPin, FTok } #undef LOCTEXT_NAMESPACE +#endif // WITH_EDITOR diff --git a/Source/Flow/Public/FlowMessageLog.h b/Source/Flow/Public/FlowMessageLog.h index 75fd57009..ee6308636 100644 --- a/Source/Flow/Public/FlowMessageLog.h +++ b/Source/Flow/Public/FlowMessageLog.h @@ -10,6 +10,8 @@ class UFlowAsset; class UFlowNode; +#if WITH_EDITOR + /** * Message Log token that links to an element in Flow Graph */ @@ -93,3 +95,5 @@ class FLOW_API FFlowMessageLog Messages.Add(Message); } }; + +#endif // WITH_EDITOR diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index e36d4c6b5..539b2f59f 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -125,7 +125,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UPROPERTY() EFlowSignalMode SignalMode; -#if !UE_BUILD_SHIPPING +#if WITH_EDITOR FFlowMessageLog Log; #endif From 9c92b26bd195cdbdfd07dca40cb95ff15be2702e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 1 Jan 2023 20:28:49 +0100 Subject: [PATCH 217/338] added node validation --- .../Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp | 11 +++++++++++ .../Private/Nodes/Route/FlowNode_CustomOutput.cpp | 11 +++++++++++ .../Nodes/World/FlowNode_ComponentObserver.cpp | 11 +++++++++++ .../Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp | 11 +++++++++++ .../Nodes/World/FlowNode_PlayLevelSequence.cpp | 11 +++++++++++ Source/Flow/Public/Nodes/Route/FlowNode_CustomInput.h | 1 + .../Flow/Public/Nodes/Route/FlowNode_CustomOutput.h | 1 + .../Public/Nodes/World/FlowNode_ComponentObserver.h | 2 ++ Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h | 1 + .../Public/Nodes/World/FlowNode_PlayLevelSequence.h | 2 ++ 10 files changed, 62 insertions(+) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp index bfa30140d..ae3946235 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp @@ -24,4 +24,15 @@ FString UFlowNode_CustomInput::GetNodeDescription() const { return EventName.ToString(); } + +EDataValidationResult UFlowNode_CustomInput::ValidateNode() +{ + if (EventName.IsNone()) + { + Log.Error(TEXT("Event Name is empty!"), this); + return EDataValidationResult::Invalid; + } + + return EDataValidationResult::Valid; +} #endif diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp index 48acfe972..df59bc1d3 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp @@ -30,4 +30,15 @@ FString UFlowNode_CustomOutput::GetNodeDescription() const { return EventName.ToString(); } + +EDataValidationResult UFlowNode_CustomOutput::ValidateNode() +{ + if (EventName.IsNone()) + { + Log.Error(TEXT("Event Name is empty!"), this); + return EDataValidationResult::Invalid; + } + + return EDataValidationResult::Valid; +} #endif diff --git a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp index 896c9530d..0ad362e00 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp @@ -151,6 +151,17 @@ FString UFlowNode_ComponentObserver::GetNodeDescription() const return GetIdentityTagsDescription(IdentityTags); } +EDataValidationResult UFlowNode_ComponentObserver::ValidateNode() +{ + if (IdentityTags.IsEmpty()) + { + Log.Error(*UFlowNode::MissingIdentityTag, this); + return EDataValidationResult::Invalid; + } + + return EDataValidationResult::Valid; +} + FString UFlowNode_ComponentObserver::GetStatusString() const { if (ActivationState == EFlowNodeState::Active && RegisteredActors.Num() == 0) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp b/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp index d67df77e5..12f303690 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp @@ -33,4 +33,15 @@ FString UFlowNode_NotifyActor::GetNodeDescription() const { return GetIdentityTagsDescription(IdentityTags) + LINE_TERMINATOR + GetNotifyTagsDescription(NotifyTags); } + +EDataValidationResult UFlowNode_NotifyActor::ValidateNode() +{ + if (IdentityTags.IsEmpty()) + { + Log.Error(*UFlowNode::MissingIdentityTag, this); + return EDataValidationResult::Invalid; + } + + return EDataValidationResult::Valid; +} #endif diff --git a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp index 428951044..727d7e0f4 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp @@ -314,6 +314,17 @@ FString UFlowNode_PlayLevelSequence::GetNodeDescription() const return Sequence.IsNull() ? TEXT("[No sequence]") : Sequence.GetAssetName(); } +EDataValidationResult UFlowNode_PlayLevelSequence::ValidateNode() +{ + if (Sequence.IsNull()) + { + Log.Error(TEXT("Level Sequence asset not assigned or invalid!"), this); + return EDataValidationResult::Invalid; + } + + return EDataValidationResult::Valid; +} + FString UFlowNode_PlayLevelSequence::GetStatusString() const { return GetPlaybackProgress(); diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_CustomInput.h b/Source/Flow/Public/Nodes/Route/FlowNode_CustomInput.h index be86208af..e1919866e 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_CustomInput.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_CustomInput.h @@ -22,5 +22,6 @@ class FLOW_API UFlowNode_CustomInput : public UFlowNode #if WITH_EDITOR public: virtual FString GetNodeDescription() const override; + virtual EDataValidationResult ValidateNode() override; #endif }; diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_CustomOutput.h b/Source/Flow/Public/Nodes/Route/FlowNode_CustomOutput.h index 9e430b267..c2624cb2f 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_CustomOutput.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_CustomOutput.h @@ -22,5 +22,6 @@ class FLOW_API UFlowNode_CustomOutput final : public UFlowNode #if WITH_EDITOR virtual FString GetNodeDescription() const override; + virtual EDataValidationResult ValidateNode() override; #endif }; diff --git a/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h b/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h index 724768836..ecc5bbf35 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h @@ -70,6 +70,8 @@ class FLOW_API UFlowNode_ComponentObserver : public UFlowNode #if WITH_EDITOR public: virtual FString GetNodeDescription() const override; + virtual EDataValidationResult ValidateNode() override; + virtual FString GetStatusString() const override; #endif }; diff --git a/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h b/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h index 228cc47d1..74219765b 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h @@ -30,5 +30,6 @@ class FLOW_API UFlowNode_NotifyActor : public UFlowNode #if WITH_EDITOR public: virtual FString GetNodeDescription() const override; + virtual EDataValidationResult ValidateNode() override; #endif }; diff --git a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h index b46cad5df..eb24d35ac 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h @@ -120,6 +120,8 @@ class FLOW_API UFlowNode_PlayLevelSequence : public UFlowNode #if WITH_EDITOR virtual FString GetNodeDescription() const override; + virtual EDataValidationResult ValidateNode() override; + virtual FString GetStatusString() const override; virtual UObject* GetAssetToEdit() override; #endif From f3e679d9d9ce54f8369898ad5545b7ec0c485f03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 1 Jan 2023 20:42:24 +0100 Subject: [PATCH 218/338] more WITH_EDITOR --- Source/Flow/Private/Nodes/FlowNode.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index db83ace65..32f7e46ef 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -677,6 +677,7 @@ void UFlowNode::LogError(FString Message, const EFlowOnScreenMessageType OnScree GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, Message); } +#if WITH_EDITOR // Message Log - not yet functional { Log.Error(*Message, GetGraphNode()); @@ -684,6 +685,7 @@ void UFlowNode::LogError(FString Message, const EFlowOnScreenMessageType OnScree FMessageLog MessageLog("FlowGraph"); MessageLog.AddMessages(Log.Messages); } +#endif // Output Log UE_LOG(LogFlow, Error, TEXT("%s"), *Message); @@ -696,6 +698,7 @@ void UFlowNode::LogMessage(FString Message) const FString TemplatePath = GetFlowAsset()->TemplateAsset->GetPathName(); Message += TEXT(" --- node ") + GetName() + TEXT(", asset ") + FPaths::GetPath(TemplatePath) / FPaths::GetBaseFilename(TemplatePath); +#if WITH_EDITOR // Message Log - not yet functional { Log.Note(*Message, GetGraphNode()); @@ -703,7 +706,8 @@ void UFlowNode::LogMessage(FString Message) FMessageLog MessageLog("FlowGraph"); MessageLog.AddMessages(Log.Messages); } - +#endif + // Output Log UE_LOG(LogFlow, Log, TEXT("%s"), *Message); #endif From 3f8ccb6838bec91f7ce5a39d54d701976ed09d5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 1 Jan 2023 21:05:05 +0100 Subject: [PATCH 219/338] 5.0 fix --- Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp index a6f371ea5..45be63c0f 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp @@ -374,16 +374,16 @@ void SFlowGraphNode::UpdateErrorInfo() { case EMessageSeverity::Error: ErrorMsg = FString(TEXT("ERROR!")); - ErrorColor = FAppStyle::GetColor("ErrorReporting.BackgroundColor"); + ErrorColor = FEditorStyle::GetColor("ErrorReporting.BackgroundColor"); break; case EMessageSeverity::PerformanceWarning: case EMessageSeverity::Warning: ErrorMsg = FString(TEXT("WARNING!")); - ErrorColor = FAppStyle::GetColor("ErrorReporting.WarningBackgroundColor"); + ErrorColor = FEditorStyle::GetColor("ErrorReporting.WarningBackgroundColor"); break; case EMessageSeverity::Info: ErrorMsg = FString(TEXT("NOTE")); - ErrorColor = FAppStyle::GetColor("InfoReporting.BackgroundColor"); + ErrorColor = FEditorStyle::GetColor("InfoReporting.BackgroundColor"); break; default: ; } From 7bedf85c131ec5165529688d58b1d7d759babb5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Mon, 2 Jan 2023 14:35:46 +0100 Subject: [PATCH 220/338] compilation fix --- Source/FlowEditor/FlowEditor.Build.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/FlowEditor/FlowEditor.Build.cs b/Source/FlowEditor/FlowEditor.Build.cs index 3de6ce699..07c98553a 100644 --- a/Source/FlowEditor/FlowEditor.Build.cs +++ b/Source/FlowEditor/FlowEditor.Build.cs @@ -10,7 +10,8 @@ public FlowEditor(ReadOnlyTargetRules Target) : base(Target) PublicDependencyModuleNames.AddRange(new[] { - "Flow" + "Flow", + "MessageLog" }); PrivateDependencyModuleNames.AddRange(new[] @@ -36,7 +37,6 @@ public FlowEditor(ReadOnlyTargetRules Target) : base(Target) "KismetWidgets", "LevelEditor", "LevelSequence", - "MessageLog", "MovieScene", "MovieSceneTracks", "MovieSceneTools", From f5c7d60db18864195aa1a60f3dea9b5feac0612d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Mon, 2 Jan 2023 14:39:20 +0100 Subject: [PATCH 221/338] compilation fix --- Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index cb10badae..623b2f728 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -767,7 +767,7 @@ void FFlowAssetEditor::JumpToInnerObject(UObject* InnerObject) { if (const UFlowNode* FlowNode = Cast(InnerObject)) { - FocusedGraphEditor->JumpToNode(FlowNode->GetGraphNode(), true); + GraphEditor->JumpToNode(FlowNode->GetGraphNode(), true); } } #endif From 2c321820635dbcbdb7eb9a090e7663ec16df2a69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 6 Jan 2023 15:14:44 +0100 Subject: [PATCH 222/338] moved SLevelEditorFlow to the Utils folder --- Source/FlowEditor/Private/FlowEditorModule.cpp | 2 +- .../Private/{LevelEditor => Utils}/SLevelEditorFlow.cpp | 2 +- .../FlowEditor/Public/{LevelEditor => Utils}/SLevelEditorFlow.h | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename Source/FlowEditor/Private/{LevelEditor => Utils}/SLevelEditorFlow.cpp (98%) rename Source/FlowEditor/Public/{LevelEditor => Utils}/SLevelEditorFlow.h (100%) diff --git a/Source/FlowEditor/Private/FlowEditorModule.cpp b/Source/FlowEditor/Private/FlowEditorModule.cpp index c2102b3f6..432fef49d 100644 --- a/Source/FlowEditor/Private/FlowEditorModule.cpp +++ b/Source/FlowEditor/Private/FlowEditorModule.cpp @@ -8,7 +8,7 @@ #include "Asset/FlowAssetEditor.h" #include "Graph/FlowGraphConnectionDrawingPolicy.h" #include "Graph/FlowGraphSettings.h" -#include "LevelEditor/SLevelEditorFlow.h" +#include "Utils/SLevelEditorFlow.h" #include "MovieScene/FlowTrackEditor.h" #include "Nodes/AssetTypeActions_FlowNodeBlueprint.h" #include "Nodes/Customizations/FlowNode_Details.h" diff --git a/Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp b/Source/FlowEditor/Private/Utils/SLevelEditorFlow.cpp similarity index 98% rename from Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp rename to Source/FlowEditor/Private/Utils/SLevelEditorFlow.cpp index 11c18509e..b31eb942a 100644 --- a/Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp +++ b/Source/FlowEditor/Private/Utils/SLevelEditorFlow.cpp @@ -1,6 +1,6 @@ // Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors -#include "LevelEditor/SLevelEditorFlow.h" +#include "Utils/SLevelEditorFlow.h" #include "FlowAsset.h" #include "FlowComponent.h" #include "FlowWorldSettings.h" diff --git a/Source/FlowEditor/Public/LevelEditor/SLevelEditorFlow.h b/Source/FlowEditor/Public/Utils/SLevelEditorFlow.h similarity index 100% rename from Source/FlowEditor/Public/LevelEditor/SLevelEditorFlow.h rename to Source/FlowEditor/Public/Utils/SLevelEditorFlow.h From 3563bc46f595b6cf2d5ab394a2b48aaade8162d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 6 Jan 2023 15:31:12 +0100 Subject: [PATCH 223/338] Exposed all remaining closed out of the module, allowing to extend any class --- .../Private/MovieScene/FlowSection.cpp | 13 ++++++------- .../Private/MovieScene/FlowTrackEditor.cpp | 16 ++++++++-------- .../FlowEditor/Public/Asset/FlowAssetToolbar.h | 6 +++--- Source/FlowEditor/Public/FlowEditorCommands.h | 6 +++--- Source/FlowEditor/Public/Graph/FlowGraph.h | 2 +- .../Graph/FlowGraphConnectionDrawingPolicy.h | 2 +- .../Public/Graph/FlowGraphEditorSettings.h | 2 +- .../FlowEditor/Public/Graph/FlowGraphSettings.h | 2 +- .../{Private => Public}/MovieScene/FlowSection.h | 8 ++++---- .../MovieScene/FlowTrackEditor.h | 4 ++-- .../Nodes/AssetTypeActions_FlowNodeBlueprint.h | 2 +- .../Public/Nodes/FlowNodeBlueprintFactory.h | 4 ++-- 12 files changed, 33 insertions(+), 34 deletions(-) rename Source/FlowEditor/{Private => Public}/MovieScene/FlowSection.h (83%) rename Source/FlowEditor/{Private => Public}/MovieScene/FlowTrackEditor.h (92%) diff --git a/Source/FlowEditor/Private/MovieScene/FlowSection.cpp b/Source/FlowEditor/Private/MovieScene/FlowSection.cpp index 5a67120b4..d88c773be 100644 --- a/Source/FlowEditor/Private/MovieScene/FlowSection.cpp +++ b/Source/FlowEditor/Private/MovieScene/FlowSection.cpp @@ -1,13 +1,12 @@ // Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors -#include "FlowSection.h" +#include "MovieScene/FlowSection.h" #include "MovieScene/MovieSceneFlowRepeaterSection.h" #include "MovieScene/MovieSceneFlowTriggerSection.h" #include "CommonMovieSceneTools.h" #include "Fonts/FontMeasure.h" #include "Framework/Application/SlateApplication.h" -#include "MovieSceneEventUtils.h" #include "MovieSceneTrack.h" #include "Rendering/DrawElements.h" #include "Sections/MovieSceneEventSection.h" @@ -18,19 +17,19 @@ bool FFlowSectionBase::IsSectionSelected() const { - TSharedPtr SequencerPtr = Sequencer.Pin(); + const TSharedPtr SequencerPtr = Sequencer.Pin(); TArray SelectedTracks; SequencerPtr->GetSelectedTracks(SelectedTracks); - UMovieSceneSection* Section = WeakSection.Get(); + const UMovieSceneSection* Section = WeakSection.Get(); UMovieSceneTrack* Track = Section ? CastChecked(Section->GetOuter()) : nullptr; return Track && SelectedTracks.Contains(Track); } void FFlowSectionBase::PaintEventName(FSequencerSectionPainter& Painter, int32 LayerId, const FString& InEventString, float PixelPos, bool bIsEventValid) const { - static const float BoxOffsetPx = 10.f; + static constexpr float BoxOffsetPx = 10.f; static const TCHAR* WarningString = TEXT("\xf071"); const FSlateFontInfo FontAwesomeFont = FEditorStyle::Get().GetFontStyle("FontAwesome.10"); @@ -99,7 +98,7 @@ void FFlowSectionBase::PaintEventName(FSequencerSectionPainter& Painter, int32 L int32 FFlowSection::OnPaintSection(FSequencerSectionPainter& Painter) const { const int32 LayerId = Painter.PaintSectionBackground(); - UMovieSceneEventSection* EventSection = Cast(WeakSection.Get()); + const UMovieSceneEventSection* EventSection = Cast(WeakSection.Get()); if (!EventSection || !IsSectionSelected()) { return LayerId; @@ -160,7 +159,7 @@ int32 FFlowRepeaterSection::OnPaintSection(FSequencerSectionPainter& Painter) co { const int32 LayerId = Painter.PaintSectionBackground(); - UMovieSceneFlowRepeaterSection* EventRepeaterSection = Cast(WeakSection.Get()); + const UMovieSceneFlowRepeaterSection* EventRepeaterSection = Cast(WeakSection.Get()); if (!EventRepeaterSection) { return LayerId; diff --git a/Source/FlowEditor/Private/MovieScene/FlowTrackEditor.cpp b/Source/FlowEditor/Private/MovieScene/FlowTrackEditor.cpp index 71472faab..f0e908683 100644 --- a/Source/FlowEditor/Private/MovieScene/FlowTrackEditor.cpp +++ b/Source/FlowEditor/Private/MovieScene/FlowTrackEditor.cpp @@ -1,7 +1,7 @@ // Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors -#include "FlowTrackEditor.h" -#include "FlowSection.h" +#include "MovieScene/FlowTrackEditor.h" +#include "MovieScene/FlowSection.h" #include "MovieScene/MovieSceneFlowRepeaterSection.h" #include "MovieScene/MovieSceneFlowTrack.h" @@ -65,7 +65,7 @@ void FFlowTrackEditor::AddFlowSubMenu(FMenuBuilder& MenuBuilder) void FFlowTrackEditor::BuildAddTrackMenu(FMenuBuilder& MenuBuilder) { UMovieSceneSequence* RootMovieSceneSequence = GetSequencer()->GetRootMovieSceneSequence(); - FMovieSceneSequenceEditor* SequenceEditor = FMovieSceneSequenceEditor::Find(RootMovieSceneSequence); + const FMovieSceneSequenceEditor* SequenceEditor = FMovieSceneSequenceEditor::Find(RootMovieSceneSequence); if (SequenceEditor && SequenceEditor->SupportsEvents(RootMovieSceneSequence)) { @@ -144,7 +144,7 @@ const FSlateBrush* FFlowTrackEditor::GetIconBrush() const return FEditorStyle::GetBrush("Sequencer.Tracks.Event"); } -void FFlowTrackEditor::HandleAddFlowTrackMenuEntryExecute(UClass* SectionType) +void FFlowTrackEditor::HandleAddFlowTrackMenuEntryExecute(UClass* SectionType) const { UMovieScene* FocusedMovieScene = GetFocusedMovieScene(); @@ -179,12 +179,12 @@ void FFlowTrackEditor::HandleAddFlowTrackMenuEntryExecute(UClass* SectionType) } } -void FFlowTrackEditor::CreateNewSection(UMovieSceneTrack* Track, int32 RowIndex, UClass* SectionType, bool bSelect) const +void FFlowTrackEditor::CreateNewSection(UMovieSceneTrack* Track, const int32 RowIndex, UClass* SectionType, const bool bSelect) const { - TSharedPtr SequencerPtr = GetSequencer(); + const TSharedPtr SequencerPtr = GetSequencer(); if (SequencerPtr.IsValid()) { - UMovieScene* FocusedMovieScene = GetFocusedMovieScene(); + const UMovieScene* FocusedMovieScene = GetFocusedMovieScene(); const FQualifiedFrameTime CurrentTime = SequencerPtr->GetLocalTime(); FScopedTransaction Transaction(LOCTEXT("CreateNewFlowSectionTransactionText", "Add Flow Section")); @@ -218,7 +218,7 @@ void FFlowTrackEditor::CreateNewSection(UMovieSceneTrack* Track, int32 RowIndex, } else { - const float DefaultLengthInSeconds = 5.f; + constexpr float DefaultLengthInSeconds = 5.f; NewSectionRange = TRange(CurrentTime.Time.FrameNumber, CurrentTime.Time.FrameNumber + (DefaultLengthInSeconds * SequencerPtr->GetFocusedTickResolution()).FloorToFrame()); } diff --git a/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h b/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h index 9450f127b..b93d67751 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h @@ -12,7 +12,7 @@ class FFlowAssetEditor; ////////////////////////////////////////////////////////////////////////// // Flow Asset Instance List -class FLOWEDITOR_API SFlowAssetInstanceList final : public SCompoundWidget +class FLOWEDITOR_API SFlowAssetInstanceList : public SCompoundWidget { public: SLATE_BEGIN_ARGS(SFlowAssetInstanceList) {} @@ -59,7 +59,7 @@ struct FLOWEDITOR_API FFlowBreadcrumb {} }; -class FLOWEDITOR_API SFlowAssetBreadcrumb final : public SCompoundWidget +class FLOWEDITOR_API SFlowAssetBreadcrumb : public SCompoundWidget { public: SLATE_BEGIN_ARGS(SFlowAssetInstanceList) {} @@ -78,7 +78,7 @@ class FLOWEDITOR_API SFlowAssetBreadcrumb final : public SCompoundWidget ////////////////////////////////////////////////////////////////////////// // Flow Asset Toolbar -class FLOWEDITOR_API FFlowAssetToolbar final : public TSharedFromThis +class FLOWEDITOR_API FFlowAssetToolbar : public TSharedFromThis { public: explicit FFlowAssetToolbar(const TSharedPtr InAssetEditor, UToolMenu* ToolbarMenu); diff --git a/Source/FlowEditor/Public/FlowEditorCommands.h b/Source/FlowEditor/Public/FlowEditorCommands.h index 341419db5..7441d02bc 100644 --- a/Source/FlowEditor/Public/FlowEditorCommands.h +++ b/Source/FlowEditor/Public/FlowEditorCommands.h @@ -7,7 +7,7 @@ #include "Framework/Commands/UICommandInfo.h" #include "Templates/SharedPointer.h" -class FLOWEDITOR_API FFlowToolbarCommands final : public TCommands +class FLOWEDITOR_API FFlowToolbarCommands : public TCommands { public: FFlowToolbarCommands(); @@ -20,7 +20,7 @@ class FLOWEDITOR_API FFlowToolbarCommands final : public TCommands +class FLOWEDITOR_API FFlowGraphCommands : public TCommands { public: FFlowGraphCommands(); @@ -54,7 +54,7 @@ class FFlowGraphCommands final : public TCommands }; /** Handles spawning nodes by keyboard shortcut */ -class FFlowSpawnNodeCommands : public TCommands +class FLOWEDITOR_API FFlowSpawnNodeCommands : public TCommands { public: FFlowSpawnNodeCommands(); diff --git a/Source/FlowEditor/Public/Graph/FlowGraph.h b/Source/FlowEditor/Public/Graph/FlowGraph.h index d46cea58f..de76d7949 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraph.h +++ b/Source/FlowEditor/Public/Graph/FlowGraph.h @@ -7,7 +7,7 @@ #include "FlowAsset.h" #include "FlowGraph.generated.h" -class FLOWEDITOR_API FFlowGraphInterface final : public IFlowGraphInterface +class FLOWEDITOR_API FFlowGraphInterface : public IFlowGraphInterface { public: virtual ~FFlowGraphInterface() override {} diff --git a/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h b/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h index c940adfc4..f62db79ab 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h @@ -12,7 +12,7 @@ enum class EFlowConnectionDrawType : uint8 Circuit }; -struct FFlowGraphConnectionDrawingPolicyFactory : public FGraphPanelPinConnectionFactory +struct FLOWEDITOR_API FFlowGraphConnectionDrawingPolicyFactory : public FGraphPanelPinConnectionFactory { virtual ~FFlowGraphConnectionDrawingPolicyFactory() override { diff --git a/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h b/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h index 11ceb0619..6f3cb06b1 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h @@ -16,7 +16,7 @@ enum class EFlowNodeDoubleClickTarget : uint8 * */ UCLASS(Config = EditorPerProjectUserSettings, meta = (DisplayName = "Flow Graph")) -class UFlowGraphEditorSettings final : public UDeveloperSettings +class FLOWEDITOR_API UFlowGraphEditorSettings : public UDeveloperSettings { GENERATED_UCLASS_BODY() diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h index cbd5be68a..8f5b3fa49 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h @@ -12,7 +12,7 @@ * */ UCLASS(Config = Editor, defaultconfig, meta = (DisplayName = "Flow Graph")) -class UFlowGraphSettings final : public UDeveloperSettings +class FLOWEDITOR_API UFlowGraphSettings : public UDeveloperSettings { GENERATED_UCLASS_BODY() diff --git a/Source/FlowEditor/Private/MovieScene/FlowSection.h b/Source/FlowEditor/Public/MovieScene/FlowSection.h similarity index 83% rename from Source/FlowEditor/Private/MovieScene/FlowSection.h rename to Source/FlowEditor/Public/MovieScene/FlowSection.h index e1202d61e..b630ca77c 100644 --- a/Source/FlowEditor/Private/MovieScene/FlowSection.h +++ b/Source/FlowEditor/Public/MovieScene/FlowSection.h @@ -7,7 +7,7 @@ class FSequencerSectionPainter; -class FFlowSectionBase : public FSequencerSection +class FLOWEDITOR_API FFlowSectionBase : public FSequencerSection { public: FFlowSectionBase(UMovieSceneSection& InSectionObject, TWeakPtr InSequencer) @@ -26,7 +26,7 @@ class FFlowSectionBase : public FSequencerSection /** * An implementation of flow sections. */ -class FFlowSection final : public FFlowSectionBase +class FLOWEDITOR_API FFlowSection : public FFlowSectionBase { public: FFlowSection(UMovieSceneSection& InSectionObject, TWeakPtr InSequencer) @@ -37,7 +37,7 @@ class FFlowSection final : public FFlowSectionBase virtual int32 OnPaintSection(FSequencerSectionPainter& Painter) const override; }; -class FFlowTriggerSection : public FFlowSectionBase +class FLOWEDITOR_API FFlowTriggerSection : public FFlowSectionBase { public: FFlowTriggerSection(UMovieSceneSection& InSectionObject, TWeakPtr InSequencer) @@ -48,7 +48,7 @@ class FFlowTriggerSection : public FFlowSectionBase virtual int32 OnPaintSection(FSequencerSectionPainter& Painter) const override; }; -class FFlowRepeaterSection : public FFlowSectionBase +class FLOWEDITOR_API FFlowRepeaterSection : public FFlowSectionBase { public: FFlowRepeaterSection(UMovieSceneSection& InSectionObject, TWeakPtr InSequencer) diff --git a/Source/FlowEditor/Private/MovieScene/FlowTrackEditor.h b/Source/FlowEditor/Public/MovieScene/FlowTrackEditor.h similarity index 92% rename from Source/FlowEditor/Private/MovieScene/FlowTrackEditor.h rename to Source/FlowEditor/Public/MovieScene/FlowTrackEditor.h index 6e7fa7ed0..c6e32d5a0 100644 --- a/Source/FlowEditor/Private/MovieScene/FlowTrackEditor.h +++ b/Source/FlowEditor/Public/MovieScene/FlowTrackEditor.h @@ -14,7 +14,7 @@ class FMenuBuilder; /** * A property track editor for named events. */ -class FFlowTrackEditor final : public FMovieSceneTrackEditor +class FLOWEDITOR_API FFlowTrackEditor : public FMovieSceneTrackEditor { public: /** @@ -47,7 +47,7 @@ class FFlowTrackEditor final : public FMovieSceneTrackEditor void AddFlowSubMenu(FMenuBuilder& MenuBuilder); /** Callback for executing the "Add Event Track" menu entry. */ - void HandleAddFlowTrackMenuEntryExecute(UClass* SectionType); + void HandleAddFlowTrackMenuEntryExecute(UClass* SectionType) const; void CreateNewSection(UMovieSceneTrack* Track, int32 RowIndex, UClass* SectionType, bool bSelect) const; }; diff --git a/Source/FlowEditor/Public/Nodes/AssetTypeActions_FlowNodeBlueprint.h b/Source/FlowEditor/Public/Nodes/AssetTypeActions_FlowNodeBlueprint.h index cb7552fa3..e8243cf42 100644 --- a/Source/FlowEditor/Public/Nodes/AssetTypeActions_FlowNodeBlueprint.h +++ b/Source/FlowEditor/Public/Nodes/AssetTypeActions_FlowNodeBlueprint.h @@ -4,7 +4,7 @@ #include "AssetTypeActions/AssetTypeActions_Blueprint.h" -class FLOWEDITOR_API FAssetTypeActions_FlowNodeBlueprint final : public FAssetTypeActions_Blueprint +class FLOWEDITOR_API FAssetTypeActions_FlowNodeBlueprint : public FAssetTypeActions_Blueprint { public: virtual FText GetName() const override; diff --git a/Source/FlowEditor/Public/Nodes/FlowNodeBlueprintFactory.h b/Source/FlowEditor/Public/Nodes/FlowNodeBlueprintFactory.h index cec3d3a25..d3b8a129e 100644 --- a/Source/FlowEditor/Public/Nodes/FlowNodeBlueprintFactory.h +++ b/Source/FlowEditor/Public/Nodes/FlowNodeBlueprintFactory.h @@ -5,8 +5,8 @@ #include "Factories/Factory.h" #include "FlowNodeBlueprintFactory.generated.h" -UCLASS(hidecategories=Object, MinimalAPI) -class UFlowNodeBlueprintFactory : public UFactory +UCLASS(hidecategories=Object) +class FLOWEDITOR_API UFlowNodeBlueprintFactory : public UFactory { GENERATED_UCLASS_BODY() From f9c6237ad562af62a3e0d319d153b2af7733fc25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 6 Jan 2023 15:45:23 +0100 Subject: [PATCH 224/338] Moved all Details Customizations classes to a single folder --- .../FlowAssetDetails.cpp | 2 +- .../FlowNode_ComponentObserverDetails.cpp | 2 +- .../FlowNode_CustomInputDetails.cpp | 3 +-- .../FlowNode_CustomOutputDetails.cpp | 3 +-- .../FlowNode_Details.cpp | 2 +- .../FlowNode_PlayLevelSequenceDetails.cpp | 2 +- Source/FlowEditor/Private/FlowEditorModule.cpp | 17 +++++++++-------- .../DetailCustomizations}/FlowAssetDetails.h | 0 .../FlowNode_ComponentObserverDetails.h | 0 .../FlowNode_CustomInputDetails.h | 0 .../FlowNode_CustomOutputDetails.h | 0 .../DetailCustomizations}/FlowNode_Details.h | 0 .../FlowNode_PlayLevelSequenceDetails.h | 0 Source/FlowEditor/Public/FlowEditorModule.h | 2 +- 14 files changed, 16 insertions(+), 17 deletions(-) rename Source/FlowEditor/Private/{Asset => DetailCustomizations}/FlowAssetDetails.cpp (98%) rename Source/FlowEditor/Private/{Nodes/Customizations => DetailCustomizations}/FlowNode_ComponentObserverDetails.cpp (89%) rename Source/FlowEditor/Private/{Nodes/Customizations => DetailCustomizations}/FlowNode_CustomInputDetails.cpp (97%) rename Source/FlowEditor/Private/{Nodes/Customizations => DetailCustomizations}/FlowNode_CustomOutputDetails.cpp (97%) rename Source/FlowEditor/Private/{Nodes/Customizations => DetailCustomizations}/FlowNode_Details.cpp (87%) rename Source/FlowEditor/Private/{Nodes/Customizations => DetailCustomizations}/FlowNode_PlayLevelSequenceDetails.cpp (94%) rename Source/FlowEditor/{Private/Asset => Public/DetailCustomizations}/FlowAssetDetails.h (100%) rename Source/FlowEditor/{Private/Nodes/Customizations => Public/DetailCustomizations}/FlowNode_ComponentObserverDetails.h (100%) rename Source/FlowEditor/{Private/Nodes/Customizations => Public/DetailCustomizations}/FlowNode_CustomInputDetails.h (100%) rename Source/FlowEditor/{Private/Nodes/Customizations => Public/DetailCustomizations}/FlowNode_CustomOutputDetails.h (100%) rename Source/FlowEditor/{Private/Nodes/Customizations => Public/DetailCustomizations}/FlowNode_Details.h (100%) rename Source/FlowEditor/{Private/Nodes/Customizations => Public/DetailCustomizations}/FlowNode_PlayLevelSequenceDetails.h (100%) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp b/Source/FlowEditor/Private/DetailCustomizations/FlowAssetDetails.cpp similarity index 98% rename from Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp rename to Source/FlowEditor/Private/DetailCustomizations/FlowAssetDetails.cpp index ef202ebaa..41e6b8861 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp +++ b/Source/FlowEditor/Private/DetailCustomizations/FlowAssetDetails.cpp @@ -1,6 +1,6 @@ // Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors -#include "FlowAssetDetails.h" +#include "DetailCustomizations/FlowAssetDetails.h" #include "FlowAsset.h" #include "Nodes/Route/FlowNode_SubGraph.h" diff --git a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_ComponentObserverDetails.cpp b/Source/FlowEditor/Private/DetailCustomizations/FlowNode_ComponentObserverDetails.cpp similarity index 89% rename from Source/FlowEditor/Private/Nodes/Customizations/FlowNode_ComponentObserverDetails.cpp rename to Source/FlowEditor/Private/DetailCustomizations/FlowNode_ComponentObserverDetails.cpp index dec2f9222..297fb3afa 100644 --- a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_ComponentObserverDetails.cpp +++ b/Source/FlowEditor/Private/DetailCustomizations/FlowNode_ComponentObserverDetails.cpp @@ -1,6 +1,6 @@ // Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors -#include "FlowNode_ComponentObserverDetails.h" +#include "DetailCustomizations/FlowNode_ComponentObserverDetails.h" #include "Nodes/World/FlowNode_ComponentObserver.h" #include "DetailCategoryBuilder.h" diff --git a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomInputDetails.cpp b/Source/FlowEditor/Private/DetailCustomizations/FlowNode_CustomInputDetails.cpp similarity index 97% rename from Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomInputDetails.cpp rename to Source/FlowEditor/Private/DetailCustomizations/FlowNode_CustomInputDetails.cpp index 4892202b3..ca37aa4fb 100644 --- a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomInputDetails.cpp +++ b/Source/FlowEditor/Private/DetailCustomizations/FlowNode_CustomInputDetails.cpp @@ -1,13 +1,12 @@ // Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors -#include "FlowNode_CustomInputDetails.h" +#include "DetailCustomizations/FlowNode_CustomInputDetails.h" #include "FlowAsset.h" #include "Nodes/Route/FlowNode_CustomInput.h" #include "DetailCategoryBuilder.h" #include "DetailWidgetRow.h" #include "PropertyEditing.h" -#include "UnrealEd.h" #include "Widgets/Input/SComboBox.h" #include "Widgets/Text/STextBlock.h" diff --git a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomOutputDetails.cpp b/Source/FlowEditor/Private/DetailCustomizations/FlowNode_CustomOutputDetails.cpp similarity index 97% rename from Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomOutputDetails.cpp rename to Source/FlowEditor/Private/DetailCustomizations/FlowNode_CustomOutputDetails.cpp index bc7923bb2..d2ab37aee 100644 --- a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomOutputDetails.cpp +++ b/Source/FlowEditor/Private/DetailCustomizations/FlowNode_CustomOutputDetails.cpp @@ -1,13 +1,12 @@ // Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors -#include "FlowNode_CustomOutputDetails.h" +#include "DetailCustomizations/FlowNode_CustomOutputDetails.h" #include "FlowAsset.h" #include "Nodes/Route/FlowNode_CustomOutput.h" #include "DetailCategoryBuilder.h" #include "DetailWidgetRow.h" #include "PropertyEditing.h" -#include "UnrealEd.h" #include "Widgets/Input/SComboBox.h" #include "Widgets/Text/STextBlock.h" diff --git a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_Details.cpp b/Source/FlowEditor/Private/DetailCustomizations/FlowNode_Details.cpp similarity index 87% rename from Source/FlowEditor/Private/Nodes/Customizations/FlowNode_Details.cpp rename to Source/FlowEditor/Private/DetailCustomizations/FlowNode_Details.cpp index ae9ddd072..98074032c 100644 --- a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_Details.cpp +++ b/Source/FlowEditor/Private/DetailCustomizations/FlowNode_Details.cpp @@ -1,6 +1,6 @@ // Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors -#include "FlowNode_Details.h" +#include "DetailCustomizations/FlowNode_Details.h" #include "PropertyEditing.h" void FFlowNode_Details::CustomizeDetails(IDetailLayoutBuilder& DetailLayout) diff --git a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.cpp b/Source/FlowEditor/Private/DetailCustomizations/FlowNode_PlayLevelSequenceDetails.cpp similarity index 94% rename from Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.cpp rename to Source/FlowEditor/Private/DetailCustomizations/FlowNode_PlayLevelSequenceDetails.cpp index 3f1374fed..76d5b1f4b 100644 --- a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.cpp +++ b/Source/FlowEditor/Private/DetailCustomizations/FlowNode_PlayLevelSequenceDetails.cpp @@ -1,6 +1,6 @@ // Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors -#include "FlowNode_PlayLevelSequenceDetails.h" +#include "DetailCustomizations/FlowNode_PlayLevelSequenceDetails.h" #include "Nodes/World/FlowNode_PlayLevelSequence.h" #include "DetailCategoryBuilder.h" diff --git a/Source/FlowEditor/Private/FlowEditorModule.cpp b/Source/FlowEditor/Private/FlowEditorModule.cpp index 432fef49d..65a81745c 100644 --- a/Source/FlowEditor/Private/FlowEditorModule.cpp +++ b/Source/FlowEditor/Private/FlowEditorModule.cpp @@ -4,18 +4,12 @@ #include "FlowEditorStyle.h" #include "Asset/AssetTypeActions_FlowAsset.h" -#include "Asset/FlowAssetDetails.h" #include "Asset/FlowAssetEditor.h" #include "Graph/FlowGraphConnectionDrawingPolicy.h" #include "Graph/FlowGraphSettings.h" #include "Utils/SLevelEditorFlow.h" #include "MovieScene/FlowTrackEditor.h" #include "Nodes/AssetTypeActions_FlowNodeBlueprint.h" -#include "Nodes/Customizations/FlowNode_Details.h" -#include "Nodes/Customizations/FlowNode_ComponentObserverDetails.h" -#include "Nodes/Customizations/FlowNode_CustomInputDetails.h" -#include "Nodes/Customizations/FlowNode_CustomOutputDetails.h" -#include "Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.h" #include "Pins/SFlowInputPinHandle.h" #include "Pins/SFlowOutputPinHandle.h" @@ -24,6 +18,13 @@ #include "Asset/FlowAssetIndexer.h" #endif +#include "DetailCustomizations/FlowAssetDetails.h" +#include "DetailCustomizations/FlowNode_Details.h" +#include "DetailCustomizations/FlowNode_ComponentObserverDetails.h" +#include "DetailCustomizations/FlowNode_CustomInputDetails.h" +#include "DetailCustomizations/FlowNode_CustomOutputDetails.h" +#include "DetailCustomizations/FlowNode_PlayLevelSequenceDetails.h" + #include "FlowAsset.h" #include "Nodes/Route/FlowNode_CustomInput.h" #include "Nodes/Route/FlowNode_CustomOutput.h" @@ -34,7 +35,7 @@ #include "EdGraphUtilities.h" #include "IAssetSearchModule.h" #include "Framework/MultiBox/MultiBoxBuilder.h" -#include "ISequencerChannelInterface.h" +#include "ISequencerChannelInterface.h" // ignore Rider's false "unused include" warning #include "ISequencerModule.h" #include "LevelEditor.h" #include "Modules/ModuleManager.h" @@ -190,7 +191,7 @@ void FFlowEditorModule::RegisterCustomClassLayout(const TSubclassOf Cla } } -void FFlowEditorModule::ModulesChangesCallback(FName ModuleName, EModuleChangeReason ReasonForChange) +void FFlowEditorModule::ModulesChangesCallback(const FName ModuleName, const EModuleChangeReason ReasonForChange) const { if (ReasonForChange == EModuleChangeReason::ModuleLoaded && ModuleName == AssetSearchModuleName) { diff --git a/Source/FlowEditor/Private/Asset/FlowAssetDetails.h b/Source/FlowEditor/Public/DetailCustomizations/FlowAssetDetails.h similarity index 100% rename from Source/FlowEditor/Private/Asset/FlowAssetDetails.h rename to Source/FlowEditor/Public/DetailCustomizations/FlowAssetDetails.h diff --git a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_ComponentObserverDetails.h b/Source/FlowEditor/Public/DetailCustomizations/FlowNode_ComponentObserverDetails.h similarity index 100% rename from Source/FlowEditor/Private/Nodes/Customizations/FlowNode_ComponentObserverDetails.h rename to Source/FlowEditor/Public/DetailCustomizations/FlowNode_ComponentObserverDetails.h diff --git a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomInputDetails.h b/Source/FlowEditor/Public/DetailCustomizations/FlowNode_CustomInputDetails.h similarity index 100% rename from Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomInputDetails.h rename to Source/FlowEditor/Public/DetailCustomizations/FlowNode_CustomInputDetails.h diff --git a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomOutputDetails.h b/Source/FlowEditor/Public/DetailCustomizations/FlowNode_CustomOutputDetails.h similarity index 100% rename from Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomOutputDetails.h rename to Source/FlowEditor/Public/DetailCustomizations/FlowNode_CustomOutputDetails.h diff --git a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_Details.h b/Source/FlowEditor/Public/DetailCustomizations/FlowNode_Details.h similarity index 100% rename from Source/FlowEditor/Private/Nodes/Customizations/FlowNode_Details.h rename to Source/FlowEditor/Public/DetailCustomizations/FlowNode_Details.h diff --git a/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.h b/Source/FlowEditor/Public/DetailCustomizations/FlowNode_PlayLevelSequenceDetails.h similarity index 100% rename from Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.h rename to Source/FlowEditor/Public/DetailCustomizations/FlowNode_PlayLevelSequenceDetails.h diff --git a/Source/FlowEditor/Public/FlowEditorModule.h b/Source/FlowEditor/Public/FlowEditorModule.h index 0672e916d..74fb82b8e 100644 --- a/Source/FlowEditor/Public/FlowEditorModule.h +++ b/Source/FlowEditor/Public/FlowEditorModule.h @@ -39,7 +39,7 @@ class FLOWEDITOR_API FFlowEditorModule : public IModuleInterface FDelegateHandle ModulesChangedHandle; private: - void ModulesChangesCallback(FName ModuleName, EModuleChangeReason ReasonForChange); + void ModulesChangesCallback(FName ModuleName, EModuleChangeReason ReasonForChange) const; void RegisterAssetIndexers() const; void CreateFlowToolbar(FToolBarBuilder& ToolbarBuilder) const; From 28929a4f330ded265c0a934eb1004faae80c3843 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 6 Jan 2023 15:54:43 +0100 Subject: [PATCH 225/338] added LogWarning method, renamed LogMessage to LogNote --- Source/Flow/Private/Nodes/FlowNode.cpp | 44 ++++++++++++++++++++------ Source/Flow/Public/Nodes/FlowNode.h | 11 ++++++- 2 files changed, 45 insertions(+), 10 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 32f7e46ef..7c6272285 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -415,10 +415,10 @@ void UFlowNode::TriggerInput(const FName& PinName, const EFlowPinActivationType ExecuteInput(PinName); break; case EFlowSignalMode::Disabled: - LogMessage(FString::Printf(TEXT("Node disabled while triggering input %s"), *PinName.ToString())); + LogNote(FString::Printf(TEXT("Node disabled while triggering input %s"), *PinName.ToString())); break; case EFlowSignalMode::PassThrough: - LogMessage(FString::Printf(TEXT("Signal pass-through on triggering input %s"), *PinName.ToString())); + LogNote(FString::Printf(TEXT("Signal pass-through on triggering input %s"), *PinName.ToString())); OnPassThrough(); break; default: ; @@ -653,8 +653,7 @@ FString UFlowNode::GetProgressAsString(float Value) void UFlowNode::LogError(FString Message, const EFlowOnScreenMessageType OnScreenMessageType) { #if !UE_BUILD_SHIPPING - const FString TemplatePath = GetFlowAsset()->TemplateAsset->GetPathName(); - Message += TEXT(" --- node ") + GetName() + TEXT(", asset ") + FPaths::GetPath(TemplatePath) / FPaths::GetBaseFilename(TemplatePath); + BuildMessage(Message); // OnScreen Message if (OnScreenMessageType == EFlowOnScreenMessageType::Permanent) @@ -692,11 +691,30 @@ void UFlowNode::LogError(FString Message, const EFlowOnScreenMessageType OnScree #endif } -void UFlowNode::LogMessage(FString Message) +void UFlowNode::LogWarning(FString Message) { #if !UE_BUILD_SHIPPING - const FString TemplatePath = GetFlowAsset()->TemplateAsset->GetPathName(); - Message += TEXT(" --- node ") + GetName() + TEXT(", asset ") + FPaths::GetPath(TemplatePath) / FPaths::GetBaseFilename(TemplatePath); + BuildMessage(Message); + +#if WITH_EDITOR + // Message Log - not yet functional + { + Log.Warning(*Message, GetGraphNode()); + + FMessageLog MessageLog("FlowGraph"); + MessageLog.AddMessages(Log.Messages); + } +#endif + + // Output Log + UE_LOG(LogFlow, Warning, TEXT("%s"), *Message); +#endif +} + +void UFlowNode::LogNote(FString Message) +{ +#if !UE_BUILD_SHIPPING + BuildMessage(Message); #if WITH_EDITOR // Message Log - not yet functional @@ -713,6 +731,14 @@ void UFlowNode::LogMessage(FString Message) #endif } +#if !UE_BUILD_SHIPPING +void UFlowNode::BuildMessage(FString& Message) const +{ + const FString TemplatePath = GetFlowAsset()->TemplateAsset->GetPathName(); + Message.Append(TEXT(" --- node ")).Append(GetName()).Append(TEXT(", asset ")).Append(FPaths::GetPath(TemplatePath) / FPaths::GetBaseFilename(TemplatePath)); +} +#endif + void UFlowNode::SaveInstance(FFlowNodeSaveData& NodeRecord) { NodeRecord.NodeGuid = NodeGuid; @@ -741,11 +767,11 @@ void UFlowNode::LoadInstance(const FFlowNodeSaveData& NodeRecord) break; case EFlowSignalMode::Disabled: // designer doesn't want to execute this node's logic at all, so we kill it - LogMessage(TEXT("Signal disabled while loading Flow Node from SaveGame")); + LogNote(TEXT("Signal disabled while loading Flow Node from SaveGame")); Finish(); break; case EFlowSignalMode::PassThrough: - LogMessage(TEXT("Signal pass-through on loading Flow Node from SaveGame")); + LogNote(TEXT("Signal pass-through on loading Flow Node from SaveGame")); OnPassThrough(); break; default: ; diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 539b2f59f..c734babe4 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -389,8 +389,17 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte void LogError(FString Message, const EFlowOnScreenMessageType OnScreenMessageType = EFlowOnScreenMessageType::Permanent); UFUNCTION(BlueprintCallable, Category = "FlowNode", meta = (DevelopmentOnly)) - void LogMessage(FString Message); + void LogWarning(FString Message); + UFUNCTION(BlueprintCallable, Category = "FlowNode", meta = (DevelopmentOnly)) + void LogNote(FString Message); + +#if !UE_BUILD_SHIPPING +private: + void BuildMessage(FString& Message) const; +#endif + +public: UFUNCTION(BlueprintCallable, Category = "FlowNode") void SaveInstance(FFlowNodeSaveData& NodeRecord); From 8a4c0913631e39fc5d7bd3dd7ae7523f902ea8d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 6 Jan 2023 16:11:44 +0100 Subject: [PATCH 226/338] addressed static analysis warning and fixes - Editor module --- Source/FlowEditor/FlowEditor.Build.cs | 2 +- .../Private/Asset/FlowAssetFactory.cpp | 4 ++-- .../Private/Asset/FlowAssetToolbar.cpp | 13 ++++++------- .../Graph/FlowGraphConnectionDrawingPolicy.cpp | 18 +++++++++--------- .../Private/Graph/FlowGraphUtils.cpp | 2 +- .../Private/Nodes/FlowNodeBlueprintFactory.cpp | 2 +- .../FlowEditor/Public/Asset/FlowAssetToolbar.h | 1 - .../FlowEditor/Public/Asset/FlowDiffControl.h | 1 - .../Graph/FlowGraphConnectionDrawingPolicy.h | 2 +- .../Public/Graph/Widgets/SFlowGraphNode.h | 2 +- 10 files changed, 22 insertions(+), 25 deletions(-) diff --git a/Source/FlowEditor/FlowEditor.Build.cs b/Source/FlowEditor/FlowEditor.Build.cs index 07c98553a..4da586c31 100644 --- a/Source/FlowEditor/FlowEditor.Build.cs +++ b/Source/FlowEditor/FlowEditor.Build.cs @@ -4,7 +4,7 @@ public class FlowEditor : ModuleRules { - public FlowEditor(ReadOnlyTargetRules Target) : base(Target) + public FlowEditor(ReadOnlyTargetRules target) : base(target) { PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; diff --git a/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp b/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp index 03f29d11d..f9b25fc65 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp @@ -30,7 +30,7 @@ class FAssetClassParentFilter : public IClassViewerFilter /** Disallow blueprint base classes. */ bool bDisallowBlueprintBase; - virtual bool IsClassAllowed(const FClassViewerInitializationOptions& InInitOptions, const UClass* InClass, TSharedRef InFilterFuncs) override + virtual bool IsClassAllowed(const FClassViewerInitializationOptions& InInitOptions, const UClass* InClass, const TSharedRef InFilterFuncs) override { const bool bAllowed = !InClass->HasAnyClassFlags(DisallowedClassFlags) && InFilterFuncs->IfInChildOfClassesSet(AllowedChildrenOfClasses, InClass) != EFilterReturn::Failed; @@ -102,7 +102,7 @@ bool UFlowAssetFactory::ConfigureProperties() UObject* UFlowAssetFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) { - UFlowAsset* NewFlow = nullptr; + UFlowAsset* NewFlow; if (AssetClass != nullptr) { NewFlow = NewObject(InParent, AssetClass, Name, Flags | RF_Transactional, Context); diff --git a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp index d96210084..32c1d8e93 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp @@ -160,8 +160,12 @@ void SFlowAssetBreadcrumb::Construct(const FArguments& InArgs, const TWeakObject for (UFlowAsset* Instance : InstancesFromRoot) { - TAttribute CrumbNameAttribute = MakeAttributeSP(this, &SFlowAssetBreadcrumb::GetBreadcrumbText, Instance); - BreadcrumbTrail->PushCrumb(CrumbNameAttribute, FFlowBreadcrumb(Instance)); + TAttribute CrumbText = MakeAttributeLambda([Instance]() + { + return Instance ? FText::FromName(Instance->GetDisplayName()) : FText(); + }); + + BreadcrumbTrail->PushCrumb(CrumbText, FFlowBreadcrumb(Instance)); } } } @@ -176,11 +180,6 @@ void SFlowAssetBreadcrumb::OnCrumbClicked(const FFlowBreadcrumb& Item) const } } -FText SFlowAssetBreadcrumb::GetBreadcrumbText(const TWeakObjectPtr FlowInstance) const -{ - return FlowInstance.IsValid() ? FText::FromName(FlowInstance->GetDisplayName()) : FText(); -} - ////////////////////////////////////////////////////////////////////////// // Flow Asset Toolbar diff --git a/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp b/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp index 78397fd7f..78ee5c179 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp @@ -289,7 +289,7 @@ FVector2D FFlowGraphConnectionDrawingPolicy::GetControlPoint(const FVector2D& So bool FFlowGraphConnectionDrawingPolicy::ShouldChangeTangentForReroute(UFlowGraphNode_Reroute* Reroute) { - if (bool* pResult = RerouteToReversedDirectionMap.Find(Reroute)) + if (const bool* pResult = RerouteToReversedDirectionMap.Find(Reroute)) { return *pResult; } @@ -300,9 +300,9 @@ bool FFlowGraphConnectionDrawingPolicy::ShouldChangeTangentForReroute(UFlowGraph FVector2D AverageLeftPin; FVector2D AverageRightPin; FVector2D CenterPin; - bool bCenterValid = Reroute->OutputPins.Num() == 0 ? false : FindPinCenter(Reroute->OutputPins[0], /*out*/ CenterPin); - bool bLeftValid = GetAverageConnectedPosition(Reroute, EGPD_Input, /*out*/ AverageLeftPin); - bool bRightValid = GetAverageConnectedPosition(Reroute, EGPD_Output, /*out*/ AverageRightPin); + const bool bCenterValid = Reroute->OutputPins.Num() == 0 ? false : FindPinCenter(Reroute->OutputPins[0], /*out*/ CenterPin); + const bool bLeftValid = GetAverageConnectedPosition(Reroute, EGPD_Input, /*out*/ AverageLeftPin); + const bool bRightValid = GetAverageConnectedPosition(Reroute, EGPD_Output, /*out*/ AverageRightPin); if (bLeftValid && bRightValid) { @@ -326,13 +326,13 @@ bool FFlowGraphConnectionDrawingPolicy::ShouldChangeTangentForReroute(UFlowGraph } } -bool FFlowGraphConnectionDrawingPolicy::FindPinCenter(UEdGraphPin* Pin, FVector2D& OutCenter) const +bool FFlowGraphConnectionDrawingPolicy::FindPinCenter(const UEdGraphPin* Pin, FVector2D& OutCenter) const { - if (const TSharedPtr* pPinWidget = PinToPinWidgetMap.Find(Pin)) + if (const TSharedPtr* PinWidget = PinToPinWidgetMap.Find(Pin)) { - if (FArrangedWidget* pPinEntry = PinGeometries->Find((*pPinWidget).ToSharedRef())) + if (const FArrangedWidget* PinEntry = PinGeometries->Find((*PinWidget).ToSharedRef())) { - OutCenter = FGeometryHelper::CenterOf(pPinEntry->Geometry); + OutCenter = FGeometryHelper::CenterOf(PinEntry->Geometry); return true; } } @@ -351,7 +351,7 @@ bool FFlowGraphConnectionDrawingPolicy::GetAverageConnectedPosition(UFlowGraphNo } UEdGraphPin* Pin = (Direction == EGPD_Input) ? Reroute->InputPins[0] : Reroute->OutputPins[0]; - for (UEdGraphPin* LinkedPin : Pin->LinkedTo) + for (const UEdGraphPin* LinkedPin : Pin->LinkedTo) { FVector2D CenterPoint; if (FindPinCenter(LinkedPin, /*out*/ CenterPoint)) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphUtils.cpp b/Source/FlowEditor/Private/Graph/FlowGraphUtils.cpp index 81cecdd66..b00e6a898 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphUtils.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphUtils.cpp @@ -13,7 +13,7 @@ TSharedPtr FFlowGraphUtils::GetFlowAssetEditor(const UObject* check(ObjectToFocusOn); TSharedPtr FlowAssetEditor; - if (UFlowAsset* FlowAsset = Cast(ObjectToFocusOn)->GetFlowAsset()) + if (const UFlowAsset* FlowAsset = Cast(ObjectToFocusOn)->GetFlowAsset()) { const TSharedPtr FoundAssetEditor = FToolkitManager::Get().FindEditorForAsset(FlowAsset); if (FoundAssetEditor.IsValid()) diff --git a/Source/FlowEditor/Private/Nodes/FlowNodeBlueprintFactory.cpp b/Source/FlowEditor/Private/Nodes/FlowNodeBlueprintFactory.cpp index 06209c356..40dd60d08 100644 --- a/Source/FlowEditor/Private/Nodes/FlowNodeBlueprintFactory.cpp +++ b/Source/FlowEditor/Private/Nodes/FlowNodeBlueprintFactory.cpp @@ -262,7 +262,7 @@ UObject* UFlowNodeBlueprintFactory::FactoryCreateNew(UClass* Class, UObject* InP if (NewBP && NewBP->UbergraphPages.Num() > 0) { - UBlueprintEditorSettings* Settings = GetMutableDefault(); + const UBlueprintEditorSettings* Settings = GetMutableDefault(); if(Settings && Settings->bSpawnDefaultBlueprintNodes) { int32 NodePositionY = 0; diff --git a/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h b/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h index b93d67751..1e646f2d4 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h @@ -69,7 +69,6 @@ class FLOWEDITOR_API SFlowAssetBreadcrumb : public SCompoundWidget private: void OnCrumbClicked(const FFlowBreadcrumb& Item) const; - FText GetBreadcrumbText(const TWeakObjectPtr FlowInstance) const; TWeakObjectPtr TemplateAsset; TSharedPtr> BreadcrumbTrail; diff --git a/Source/FlowEditor/Public/Asset/FlowDiffControl.h b/Source/FlowEditor/Public/Asset/FlowDiffControl.h index efb6aaf11..f8fa7b6b7 100644 --- a/Source/FlowEditor/Public/Asset/FlowDiffControl.h +++ b/Source/FlowEditor/Public/Asset/FlowDiffControl.h @@ -9,7 +9,6 @@ #include "FlowEditorDefines.h" #if ENABLE_FLOW_DIFF -#include "DetailsDiff.h" #include "DiffResults.h" #include "IAssetTypeActions.h" #include "Kismet/Private/DiffControl.h" diff --git a/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h b/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h index f62db79ab..410a78ae7 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphConnectionDrawingPolicy.h @@ -65,6 +65,6 @@ class FLOWEDITOR_API FFlowGraphConnectionDrawingPolicy : public FConnectionDrawi static FVector2D GetControlPoint(const FVector2D& Source, const FVector2D& Target); bool ShouldChangeTangentForReroute(class UFlowGraphNode_Reroute* Reroute); - bool FindPinCenter(UEdGraphPin* Pin, FVector2D& OutCenter) const; + bool FindPinCenter(const UEdGraphPin* Pin, FVector2D& OutCenter) const; bool GetAverageConnectedPosition(class UFlowGraphNode_Reroute* Reroute, EEdGraphPinDirection Direction, FVector2D& OutPos) const; }; diff --git a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h index 3d50e872e..cc33a3e78 100644 --- a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h +++ b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h @@ -43,7 +43,7 @@ class FLOWEDITOR_API SFlowGraphNode : public SGraphNode virtual TSharedRef CreateNodeContentArea() override; virtual const FSlateBrush* GetNodeBodyBrush() const override; - // purposely overriden non-virtual methods, avoiding engine modification + // purposely overriden non-virtual methods, added PR #9791 to made these methods virtual: https://github.com/EpicGames/UnrealEngine/pull/9791 FSlateColor GetNodeTitleColor() const; FSlateColor GetNodeBodyColor() const; FSlateColor GetNodeTitleIconColor() const; From 326d531702e09371fa6e4cd5c4665498e520c359 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 6 Jan 2023 16:12:46 +0100 Subject: [PATCH 227/338] autoformat --- Source/Flow/Flow.Build.cs | 38 +++++------ Source/FlowEditor/FlowEditor.Build.cs | 92 +++++++++++++-------------- 2 files changed, 65 insertions(+), 65 deletions(-) diff --git a/Source/Flow/Flow.Build.cs b/Source/Flow/Flow.Build.cs index 62f81ef48..5896761f9 100644 --- a/Source/Flow/Flow.Build.cs +++ b/Source/Flow/Flow.Build.cs @@ -4,35 +4,35 @@ public class Flow : ModuleRules { - public Flow(ReadOnlyTargetRules Target) : base(Target) + public Flow(ReadOnlyTargetRules target) : base(target) { PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; - PublicDependencyModuleNames.AddRange(new[] + PublicDependencyModuleNames.AddRange(new[] { "LevelSequence" }); - - PrivateDependencyModuleNames.AddRange(new[] + + PrivateDependencyModuleNames.AddRange(new[] { - "Core", + "Core", "CoreUObject", - "DeveloperSettings", + "DeveloperSettings", "Engine", - "GameplayTags", + "GameplayTags", "MovieScene", "MovieSceneTracks", - "Slate", - "SlateCore" + "Slate", + "SlateCore" }); - if (Target.Type == TargetType.Editor) - { - PublicDependencyModuleNames.AddRange(new[] - { - "MessageLog", - "UnrealEd" - }); - } - } -} + if (target.Type == TargetType.Editor) + { + PublicDependencyModuleNames.AddRange(new[] + { + "MessageLog", + "UnrealEd" + }); + } + } +} \ No newline at end of file diff --git a/Source/FlowEditor/FlowEditor.Build.cs b/Source/FlowEditor/FlowEditor.Build.cs index 4da586c31..4fdf98210 100644 --- a/Source/FlowEditor/FlowEditor.Build.cs +++ b/Source/FlowEditor/FlowEditor.Build.cs @@ -4,51 +4,51 @@ public class FlowEditor : ModuleRules { - public FlowEditor(ReadOnlyTargetRules target) : base(target) - { - PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; + public FlowEditor(ReadOnlyTargetRules target) : base(target) + { + PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; - PublicDependencyModuleNames.AddRange(new[] - { - "Flow", - "MessageLog" - }); + PublicDependencyModuleNames.AddRange(new[] + { + "Flow", + "MessageLog" + }); - PrivateDependencyModuleNames.AddRange(new[] - { - "ApplicationCore", - "AssetSearch", - "AssetTools", - "BlueprintGraph", - "ClassViewer", - "ContentBrowser", - "Core", - "CoreUObject", - "DetailCustomizations", - "DeveloperSettings", - "EditorFramework", - "EditorStyle", - "Engine", - "GraphEditor", - "InputCore", - "Json", - "JsonUtilities", - "Kismet", - "KismetWidgets", - "LevelEditor", - "LevelSequence", - "MovieScene", - "MovieSceneTracks", - "MovieSceneTools", - "Projects", - "PropertyEditor", - "RenderCore", - "Sequencer", - "Slate", - "SlateCore", - "SourceControl", - "ToolMenus", - "UnrealEd" - }); - } -} + PrivateDependencyModuleNames.AddRange(new[] + { + "ApplicationCore", + "AssetSearch", + "AssetTools", + "BlueprintGraph", + "ClassViewer", + "ContentBrowser", + "Core", + "CoreUObject", + "DetailCustomizations", + "DeveloperSettings", + "EditorFramework", + "EditorStyle", + "Engine", + "GraphEditor", + "InputCore", + "Json", + "JsonUtilities", + "Kismet", + "KismetWidgets", + "LevelEditor", + "LevelSequence", + "MovieScene", + "MovieSceneTracks", + "MovieSceneTools", + "Projects", + "PropertyEditor", + "RenderCore", + "Sequencer", + "Slate", + "SlateCore", + "SourceControl", + "ToolMenus", + "UnrealEd" + }); + } +} \ No newline at end of file From ac8725767d9174dde2ca6e3bc948fb9da6f71977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 6 Jan 2023 16:19:21 +0100 Subject: [PATCH 228/338] addressed static analysis warning and fixes - Runtime module --- Source/Flow/Private/FlowSubsystem.cpp | 1 - Source/Flow/Private/FlowWorldSettings.cpp | 1 - Source/Flow/Private/MovieScene/MovieSceneFlowTriggerSection.cpp | 2 +- Source/Flow/Public/FlowSave.h | 1 - Source/Flow/Public/FlowTypes.h | 2 -- 5 files changed, 1 insertion(+), 6 deletions(-) diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index 397394184..405673b25 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -11,7 +11,6 @@ #include "Engine/GameInstance.h" #include "Engine/World.h" -#include "Misc/FileHelper.h" #include "Misc/Paths.h" #include "UObject/UObjectHash.h" diff --git a/Source/Flow/Private/FlowWorldSettings.cpp b/Source/Flow/Private/FlowWorldSettings.cpp index 447fafdbf..b0f03d6ec 100644 --- a/Source/Flow/Private/FlowWorldSettings.cpp +++ b/Source/Flow/Private/FlowWorldSettings.cpp @@ -2,7 +2,6 @@ #include "FlowWorldSettings.h" #include "FlowComponent.h" -#include "FlowSubsystem.h" AFlowWorldSettings::AFlowWorldSettings(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) diff --git a/Source/Flow/Private/MovieScene/MovieSceneFlowTriggerSection.cpp b/Source/Flow/Private/MovieScene/MovieSceneFlowTriggerSection.cpp index d1cc40a7e..bc86dd921 100644 --- a/Source/Flow/Private/MovieScene/MovieSceneFlowTriggerSection.cpp +++ b/Source/Flow/Private/MovieScene/MovieSceneFlowTriggerSection.cpp @@ -8,7 +8,7 @@ UMovieSceneFlowTriggerSection::UMovieSceneFlowTriggerSection(const FObjectInitia : Super(ObjInit) { bSupportsInfiniteRange = true; - SetRange(TRange::All()); + UMovieSceneSection::SetRange(TRange::All()); #if WITH_EDITOR ChannelProxy = MakeShared(StringChannel, FMovieSceneChannelMetaData(), TMovieSceneExternalValue::Make()); diff --git a/Source/Flow/Public/FlowSave.h b/Source/Flow/Public/FlowSave.h index fc9e939ef..d3330eeaa 100644 --- a/Source/Flow/Public/FlowSave.h +++ b/Source/Flow/Public/FlowSave.h @@ -4,7 +4,6 @@ #include "CoreMinimal.h" #include "GameFramework/SaveGame.h" -#include "Serialization/BufferArchive.h" #include "Serialization/ObjectAndNameAsStringProxyArchive.h" #include "FlowSave.generated.h" diff --git a/Source/Flow/Public/FlowTypes.h b/Source/Flow/Public/FlowTypes.h index 235cc366a..a1be09b7b 100644 --- a/Source/Flow/Public/FlowTypes.h +++ b/Source/Flow/Public/FlowTypes.h @@ -3,8 +3,6 @@ #pragma once #include "GameplayTagContainer.h" - -#include "FlowSave.h" #include "FlowTypes.generated.h" #if WITH_EDITORONLY_DATA From 2873c4d9a0e0aff6db3ec37332ce85c885afb842 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 8 Jan 2023 18:48:36 +0100 Subject: [PATCH 229/338] importing blueprint graph into Flow Graph - basic functionality - Creating Flow Graph asset in the same folder as selected blueprint. - Simple graph iteration attempting to recreate Flow Graph with nodes matching UFunctions. - Transferring blueprint input pin values to Flow Node properties, names need to match. --- Flow.uplugin | 4 + Source/Flow/Public/FlowSettings.h | 6 +- Source/Flow/Public/Nodes/FlowPin.h | 19 +- Source/FlowEditor/FlowEditor.Build.cs | 2 + .../Private/Asset/FlowAssetFactory.cpp | 17 +- .../Private/Asset/FlowImportUtils.cpp | 243 ++++++++++++++++++ .../Private/Graph/FlowGraphSchema_Actions.cpp | 42 ++- .../FlowEditor/Public/Asset/FlowImportUtils.h | 22 ++ .../FlowEditor/Public/Graph/FlowGraphSchema.h | 4 +- .../Public/Graph/FlowGraphSchema_Actions.h | 1 + 10 files changed, 346 insertions(+), 14 deletions(-) create mode 100644 Source/FlowEditor/Private/Asset/FlowImportUtils.cpp create mode 100644 Source/FlowEditor/Public/Asset/FlowImportUtils.h diff --git a/Flow.uplugin b/Flow.uplugin index 1f165bb4a..d650ea904 100644 --- a/Flow.uplugin +++ b/Flow.uplugin @@ -30,6 +30,10 @@ { "Name": "AssetSearch", "Enabled": true + }, + { + "Name": "EditorScriptingUtilities", + "Enabled": true } ] } \ No newline at end of file diff --git a/Source/Flow/Public/FlowSettings.h b/Source/Flow/Public/FlowSettings.h index 475c11c09..c4c21dcc8 100644 --- a/Source/Flow/Public/FlowSettings.h +++ b/Source/Flow/Public/FlowSettings.h @@ -12,7 +12,7 @@ class UFlowNode; * */ UCLASS(Config = Game, defaultconfig, meta = (DisplayName = "Flow")) -class UFlowSettings final : public UDeveloperSettings +class FLOW_API UFlowSettings : public UDeveloperSettings { GENERATED_UCLASS_BODY() @@ -29,4 +29,8 @@ class UFlowSettings final : public UDeveloperSettings UPROPERTY(Config, EditAnywhere, Category = "SaveSystem") bool bWarnAboutMissingIdentityTags; + + // How many nodes of given class should be preloaded with the Flow Asset instance? + UPROPERTY(Config, EditAnywhere, Category = "Importer") + TMap> BlueprintFunctionsToFlowNodes; }; diff --git a/Source/Flow/Public/Nodes/FlowPin.h b/Source/Flow/Public/Nodes/FlowPin.h index 78ef72c41..55be81cfb 100644 --- a/Source/Flow/Public/Nodes/FlowPin.h +++ b/Source/Flow/Public/Nodes/FlowPin.h @@ -21,7 +21,7 @@ struct FLOW_API FFlowPin FString PinToolTip; static inline FName AnyPinName = TEXT("AnyPinName"); - + FFlowPin() : PinName(NAME_None) { @@ -182,6 +182,23 @@ struct FLOW_API FConnectedPin } }; +USTRUCT() +struct FLOW_API FGraphNodeImport +{ + GENERATED_USTRUCT_BODY() + + UPROPERTY() + UEdGraphNode* SourceGraphNode; + + TArray Inputs; + TArray Outputs; + + FGraphNodeImport() + : SourceGraphNode(nullptr) + { + } +}; + UENUM(BlueprintType) enum class EFlowPinActivationType : uint8 { diff --git a/Source/FlowEditor/FlowEditor.Build.cs b/Source/FlowEditor/FlowEditor.Build.cs index 4fdf98210..6a7901f69 100644 --- a/Source/FlowEditor/FlowEditor.Build.cs +++ b/Source/FlowEditor/FlowEditor.Build.cs @@ -26,6 +26,7 @@ public FlowEditor(ReadOnlyTargetRules target) : base(target) "CoreUObject", "DetailCustomizations", "DeveloperSettings", + "EditorScriptingUtilities", "EditorFramework", "EditorStyle", "Engine", @@ -42,6 +43,7 @@ public FlowEditor(ReadOnlyTargetRules target) : base(target) "MovieSceneTools", "Projects", "PropertyEditor", + "PropertyPath", "RenderCore", "Sequencer", "Slate", diff --git a/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp b/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp index f9b25fc65..65ab06e68 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp @@ -68,10 +68,9 @@ UFlowAssetFactory::UFlowAssetFactory(const FObjectInitializer& ObjectInitializer bool UFlowAssetFactory::ConfigureProperties() { - AssetClass = UFlowGraphSettings::Get()->DefaultFlowAssetClass;; - if (AssetClass != nullptr) + AssetClass = UFlowGraphSettings::Get()->DefaultFlowAssetClass; + if (AssetClass) // Class was set in settings { - // Class was selected in settings return true; } @@ -102,19 +101,19 @@ bool UFlowAssetFactory::ConfigureProperties() UObject* UFlowAssetFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) { - UFlowAsset* NewFlow; - if (AssetClass != nullptr) + UFlowAsset* NewFlowAsset; + if (AssetClass) { - NewFlow = NewObject(InParent, AssetClass, Name, Flags | RF_Transactional, Context); + NewFlowAsset = NewObject(InParent, AssetClass, Name, Flags | RF_Transactional, Context); } else { // if we have no asset class, use the passed-in class instead - NewFlow = NewObject(InParent, Class, Name, Flags | RF_Transactional, Context); + NewFlowAsset = NewObject(InParent, Class, Name, Flags | RF_Transactional, Context); } - UFlowGraph::CreateGraph(NewFlow); - return NewFlow; + UFlowGraph::CreateGraph(NewFlowAsset); + return NewFlowAsset; } #undef LOCTEXT_NAMESPACE \ No newline at end of file diff --git a/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp b/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp new file mode 100644 index 000000000..3807d186d --- /dev/null +++ b/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp @@ -0,0 +1,243 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#include "Asset/FlowImportUtils.h" +#include "Asset/FlowAssetFactory.h" +#include "Graph/FlowGraphSchema_Actions.h" + +#include "FlowAsset.h" +#include "FlowSettings.h" +#include "Nodes/FlowPin.h" +#include "Nodes/Route/FlowNode_Start.h" + +#include "AssetRegistry/AssetRegistryModule.h" +#include "AssetToolsModule.h" +#include "EditorAssetLibrary.h" +#include "K2Node_CallFunction.h" +#include "K2Node_Event.h" +#include "Misc/ScopedSlowTask.h" +#include "PropertyPathHelpers.h" + +#define LOCTEXT_NAMESPACE "FlowImportUtils" + +UFlowAsset* UFlowImportUtils::ImportBlueprintGraph(UObject* BlueprintAsset, TSubclassOf FlowAssetClass, FString FlowAssetName, const FName StartEventName) +{ + if (BlueprintAsset == nullptr || FlowAssetClass == nullptr || FlowAssetName.IsEmpty() || StartEventName.IsNone()) + { + return nullptr; + } + + UBlueprint* Blueprint = Cast(BlueprintAsset); + UFlowAsset* FlowAsset = nullptr; + + // we assume that users want to have a converted asset in the same folder as the legacy blueprint + const FString PackageFolder = FPaths::GetPath(Blueprint->GetOuter()->GetPathName()); + + if (!FPackageName::DoesPackageExist(PackageFolder / FlowAssetName, nullptr)) // create a new asset + { + IAssetTools& AssetTools = FModuleManager::GetModuleChecked("AssetTools").Get(); + UFactory* Factory = Cast(UFlowAssetFactory::StaticClass()->GetDefaultObject()); + + if (UObject* NewAsset = AssetTools.CreateAsset(FlowAssetName, PackageFolder, FlowAssetClass, Factory)) + { + UEditorAssetLibrary::SaveLoadedAsset(NewAsset->GetPackage()); + FlowAsset = Cast(NewAsset); + } + } + else // load existing asset + { + const FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(AssetRegistryConstants::ModuleName); + + const FString PackageName = PackageFolder / (FlowAssetName + TEXT(".") + FlowAssetName); + const FAssetData& FoundAssetData = AssetRegistryModule.GetRegistry().GetAssetByObjectPath(*PackageName); + + FlowAsset = Cast(FoundAssetData.GetAsset()); + } + + // import graph + if (FlowAsset) + { + ImportBlueprintGraph(Blueprint, FlowAsset, StartEventName); + } + + return FlowAsset; +} + +void UFlowImportUtils::ImportBlueprintGraph(UBlueprint* Blueprint, const UFlowAsset* FlowAsset, const FName StartEventName) +{ + ensureAlways(Blueprint && FlowAsset); + + UEdGraph* BlueprintGraph = Blueprint->UbergraphPages.IsValidIndex(0) ? Blueprint->UbergraphPages[0] : nullptr; + if (BlueprintGraph == nullptr) + { + return; + } + + FScopedSlowTask ExecuteAssetTask(BlueprintGraph->Nodes.Num(), FText::Format(LOCTEXT("FFlowGraphUtils::ImportBlueprintGraph", "Reading {0}"), FText::FromString(Blueprint->GetFriendlyName()))); + ExecuteAssetTask.MakeDialog(); + + TMap ImportedNodes; + UEdGraphNode* StartNode = nullptr; + + for (UEdGraphNode* ThisNode : BlueprintGraph->Nodes) + { + ExecuteAssetTask.EnterProgressFrame(1, FText::Format(LOCTEXT("FFlowGraphUtils::ImportBlueprintGraph", "Processing blueprint node: {0}"), ThisNode->GetNodeTitle(ENodeTitleType::ListView))); + + const UK2Node* K2Node = Cast(ThisNode); + if (K2Node == nullptr || K2Node->IsNodePure()) + { + continue; + } + + // create map of all non-pure blueprint nodes with theirs pin connections + for (const UEdGraphPin* ThisPin : ThisNode->Pins) + { + if (ThisPin->Direction == EGPD_Output && ThisPin->LinkedTo.Num() > 0) + { + if (const UEdGraphPin* LinkedPin = ThisPin->LinkedTo[0]) + { + UEdGraphNode* LinkedNode = LinkedPin->GetOwningNode(); + + // we assume all imported nodes except the entry point node represent functions + // only the first node from the left in the blueprint uber-graph has to be the Event node (UK2Node_Event) + const UK2Node_CallFunction* LinkedFunctionNode = Cast(LinkedNode); + if (LinkedFunctionNode && !LinkedFunctionNode->IsNodePure()) + { + FGraphNodeImport& ThisNodeImport = ImportedNodes.FindOrAdd(ThisNode->NodeGuid); + ThisNodeImport.Outputs.Add(FConnectedPin(LinkedNode->NodeGuid, LinkedPin->PinName)); + + FGraphNodeImport& LinkedNodeImport = ImportedNodes.FindOrAdd(LinkedNode->NodeGuid); + LinkedNodeImport.SourceGraphNode = LinkedNode; + LinkedNodeImport.Inputs.Add(FConnectedPin(ThisNode->NodeGuid, ThisPin->PinName)); + } + } + } + } + + // we need to know the default entry point of blueprint graph + const UK2Node_Event* EventNode = Cast(ThisNode); + if (EventNode && (EventNode->EventReference.GetMemberName() == StartEventName || EventNode->CustomFunctionName == StartEventName)) + { + StartNode = ThisNode; + } + } + + // can't start import if provided graph doesn't have required start node + // todo: do we really needs this? + if (StartNode == nullptr) + { + return; + } + + // clear existing graph + UEdGraph* FlowGraph = FlowAsset->GetGraph(); + FlowGraph->Nodes.Empty(); + + // recreated UFlowNode_Start, assign it a blueprint node FGuid + UFlowGraphNode* NewGraphNode = FFlowGraphSchemaAction_NewNode::CreateNode(FlowGraph, nullptr, UFlowNode_Start::StaticClass(), FVector2D::ZeroVector); + FlowGraph->GetSchema()->SetNodeMetaData(NewGraphNode, FNodeMetadata::DefaultGraphNode); + NewGraphNode->NodeGuid = StartNode->NodeGuid; + NewGraphNode->GetFlowNode()->SetGuid(StartNode->NodeGuid); + + // execute graph import + ImportBlueprintFunction_Recursive(FlowGraph->Nodes[0], ImportedNodes); +} + +void UFlowImportUtils::ImportBlueprintFunction_Recursive(UEdGraphNode* PrecedingGraphNode, const TMap SourceNodes) +{ + UEdGraph* Graph = PrecedingGraphNode->GetGraph(); + const FGraphNodeImport& PrecedingNode = SourceNodes.FindRef(PrecedingGraphNode->NodeGuid); + + for (const FConnectedPin& Output : PrecedingNode.Outputs) + { + // todo: support multiple output pins + //UFlowNode* LinkedNodeDefaults = MatchingFlowNodeClass.GetDefaultObject(); + //const FName PinName = LinkedNodeDefaults->OutputPins[0].PinName; + UEdGraphPin* OutputPin = Cast(PrecedingGraphNode)->OutputPins[0]; + + const FGuid& LinkedNodeGuid = Output.NodeGuid; + const FGraphNodeImport& LinkedNodeImport = SourceNodes.FindRef(LinkedNodeGuid); + + // we only accept here blueprint nodes representing functions + const UK2Node_CallFunction* FunctionNode = Cast(LinkedNodeImport.SourceGraphNode); + if (FunctionNode == nullptr) + { + continue; + } + + // find FlowNode class matching provided UFunction name + const TSubclassOf MatchingFlowNodeClass = UFlowSettings::Get()->BlueprintFunctionsToFlowNodes.FindRef(FunctionNode->GetFunctionName()); + if (MatchingFlowNodeClass == nullptr) + { + continue; + } + + // check if already imported connected node + // todo: optimize? + UFlowGraphNode* LinkedGraphNode = nullptr; + for (const TObjectPtr ExistingGraphNode : Graph->Nodes) + { + if (ExistingGraphNode->NodeGuid == LinkedNodeGuid) + { + LinkedGraphNode = Cast(ExistingGraphNode); + break; + } + } + + if (LinkedGraphNode == nullptr) + { + // create a new Flow Graph node + const FVector2d Location = FVector2D(LinkedNodeImport.SourceGraphNode->NodePosX, LinkedNodeImport.SourceGraphNode->NodePosY); + LinkedGraphNode = FFlowGraphSchemaAction_NewNode::ImportNode(PrecedingGraphNode->GetGraph(), OutputPin, MatchingFlowNodeClass, LinkedNodeGuid, Location); + } + else + { + UEdGraphPin* LinkedPin = nullptr; + for (UEdGraphPin* InputPin : LinkedGraphNode->InputPins) + { + if (InputPin->PinName == Output.PinName) + { + LinkedPin = InputPin; + break; + } + } + + // just link the pin to existing node + Graph->GetSchema()->TryCreateConnection(OutputPin, LinkedPin); + } + + if (LinkedGraphNode) + { + // transfer properties from UFunction input parameters to Flow Node properties + { + TMap InputPins; + for (UEdGraphPin* Pin : FunctionNode->Pins) + { + if (Pin->Direction == EGPD_Input && !Pin->bHidden && !Pin->bOrphanedPin) + { + InputPins.Add(Pin->PinName, Pin); + } + } + + for (TFieldIterator PropIt(LinkedGraphNode->GetFlowNode()->GetClass(), EFieldIteratorFlags::IncludeSuper); PropIt; ++PropIt) + { + const FProperty* Param = *PropIt; + const bool bIsEditable = !Param->HasAnyPropertyFlags(CPF_Edit | CPF_Deprecated); + if (bIsEditable) + { + if (const UEdGraphPin* InputPin = InputPins.FindRef(*Param->GetAuthoredName())) + { + FString const PinValue = InputPin->GetDefaultAsString(); + uint8* Offset = Param->ContainerPtrToValuePtr(LinkedGraphNode->GetFlowNode()); + Param->ImportText(*PinValue, Offset, PPF_Copy, nullptr, GLog); + } + } + } + } + + // iterate next nodes + ImportBlueprintFunction_Recursive(LinkedGraphNode, SourceNodes); + } + } +} + +#undef LOCTEXT_NAMESPACE diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp index 6baba1027..4d8464b26 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp @@ -77,7 +77,7 @@ UFlowGraphNode* FFlowGraphSchemaAction_NewNode::CreateNode(UEdGraph* ParentGraph ParentGraph->NotifyGraphChanged(); FlowAsset->PostEditChange(); - + // select in editor UI if (bSelectNewNode) { @@ -155,6 +155,46 @@ UFlowGraphNode* FFlowGraphSchemaAction_NewNode::RecreateNode(UEdGraph* ParentGra return NewGraphNode; } +UFlowGraphNode* FFlowGraphSchemaAction_NewNode::ImportNode(UEdGraph* ParentGraph, UEdGraphPin* FromPin, const UClass* NodeClass, const FGuid& NodeGuid, const FVector2D Location) +{ + check(NodeClass); + + ParentGraph->Modify(); + if (FromPin) + { + FromPin->Modify(); + } + + UFlowAsset* FlowAsset = CastChecked(ParentGraph)->GetFlowAsset(); + FlowAsset->Modify(); + + // create new Flow Graph node + const UClass* GraphNodeClass = UFlowGraphSchema::GetAssignedGraphNodeClass(NodeClass); + UFlowGraphNode* NewGraphNode = NewObject(ParentGraph, GraphNodeClass, NAME_None, RF_Transactional); + + // register to the graph + NewGraphNode->NodeGuid = NodeGuid; + ParentGraph->AddNode(NewGraphNode, false, false); + + // link editor and runtime nodes together + UFlowNode* FlowNode = FlowAsset->CreateNode(NodeClass, NewGraphNode); + NewGraphNode->SetNodeTemplate(FlowNode); + + // create pins and connections + NewGraphNode->AllocateDefaultPins(); + NewGraphNode->AutowireNewNode(FromPin); + + // set position + NewGraphNode->NodePosX = Location.X; + NewGraphNode->NodePosY = Location.Y; + + // call notifies + NewGraphNode->PostPlacedNewNode(); + ParentGraph->NotifyGraphChanged(); + + return NewGraphNode; +} + UEdGraphNode* FFlowGraphSchemaAction_Paste::PerformAction(class UEdGraph* ParentGraph, UEdGraphPin* FromPin, const FVector2D Location, const bool bSelectNewNode/* = true*/) { // prevent adding new nodes while playing diff --git a/Source/FlowEditor/Public/Asset/FlowImportUtils.h b/Source/FlowEditor/Public/Asset/FlowImportUtils.h new file mode 100644 index 000000000..a040802d2 --- /dev/null +++ b/Source/FlowEditor/Public/Asset/FlowImportUtils.h @@ -0,0 +1,22 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#pragma once + +#include "FlowAsset.h" +#include "FlowImportUtils.generated.h" + +/** + * + */ +UCLASS(meta = (ScriptName = "FlowImportUtils")) +class FLOWEDITOR_API UFlowImportUtils final : public UBlueprintFunctionLibrary +{ + GENERATED_BODY() + +public: + UFUNCTION(BlueprintCallable, Category = "FlowImportUtils") + static UFlowAsset* ImportBlueprintGraph(UObject* BlueprintAsset, TSubclassOf FlowAssetClass, FString FlowAssetName, const FName StartEventName = TEXT("BeginPlay")); + + static void ImportBlueprintGraph(UBlueprint* Blueprint, const UFlowAsset* FlowAsset, const FName StartEventName = TEXT("BeginPlay")); + static void ImportBlueprintFunction_Recursive(UEdGraphNode* PrecedingGraphNode, const TMap SourceNodes); +}; diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h index 6c97a6c64..3a5b4ef58 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h @@ -5,8 +5,8 @@ #include "EdGraph/EdGraphSchema.h" #include "FlowGraphSchema.generated.h" -class UFlowNode; class UFlowAsset; +class UFlowNode; DECLARE_MULTICAST_DELEGATE(FFlowGraphSchemaRefresh); @@ -16,7 +16,7 @@ class FLOWEDITOR_API UFlowGraphSchema : public UEdGraphSchema GENERATED_UCLASS_BODY() friend class UFlowGraph; - + private: static bool bInitialGatherPerformed; static TArray NativeFlowNodes; diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h b/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h index 528934593..3bb8d230d 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h @@ -49,6 +49,7 @@ struct FLOWEDITOR_API FFlowGraphSchemaAction_NewNode : public FEdGraphSchemaActi static UFlowGraphNode* CreateNode(class UEdGraph* ParentGraph, UEdGraphPin* FromPin, const UClass* NodeClass, const FVector2D Location, const bool bSelectNewNode = true); static UFlowGraphNode* RecreateNode(UEdGraph* ParentGraph, UEdGraphNode* OldInstance, UFlowNode* FlowNode); + static UFlowGraphNode* ImportNode(class UEdGraph* ParentGraph, UEdGraphPin* FromPin, const UClass* NodeClass, const FGuid& NodeGuid, const FVector2D Location); }; /** Action to paste clipboard contents into the graph */ From 6cfa90c5646d8cfc9a501cc3435e6a79aa169b23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 8 Jan 2023 20:44:54 +0100 Subject: [PATCH 230/338] bad Undo fixed --- Source/FlowEditor/Private/Asset/FlowImportUtils.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp b/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp index 3807d186d..d7f0df159 100644 --- a/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp +++ b/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp @@ -15,7 +15,6 @@ #include "K2Node_CallFunction.h" #include "K2Node_Event.h" #include "Misc/ScopedSlowTask.h" -#include "PropertyPathHelpers.h" #define LOCTEXT_NAMESPACE "FlowImportUtils" @@ -218,10 +217,10 @@ void UFlowImportUtils::ImportBlueprintFunction_Recursive(UEdGraphNode* Preceding } } - for (TFieldIterator PropIt(LinkedGraphNode->GetFlowNode()->GetClass(), EFieldIteratorFlags::IncludeSuper); PropIt; ++PropIt) + for (TFieldIterator PropIt(LinkedGraphNode->GetFlowNode()->GetClass(), EFieldIteratorFlags::IncludeSuper); PropIt && (PropIt->PropertyFlags & CPF_Edit); ++PropIt) { const FProperty* Param = *PropIt; - const bool bIsEditable = !Param->HasAnyPropertyFlags(CPF_Edit | CPF_Deprecated); + const bool bIsEditable = !Param->HasAnyPropertyFlags(CPF_Deprecated); if (bIsEditable) { if (const UEdGraphPin* InputPin = InputPins.FindRef(*Param->GetAuthoredName())) From 0538f2f342e67c8c2813bbf8ca4e8770ee03ce7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Mon, 9 Jan 2023 00:56:15 +0100 Subject: [PATCH 231/338] import utils improvements - importing Comment nodes - importing BaseAsyncTask nodes (i.e. gameplay tasks) - added UFlowNode::PostImport() - supporting nodes with multiple outputs --- Source/Flow/Private/Nodes/FlowNode.cpp | 12 +- Source/Flow/Public/Nodes/FlowNode.h | 3 + Source/Flow/Public/Nodes/FlowPin.h | 17 --- .../Private/Asset/FlowImportUtils.cpp | 135 ++++++++++++------ .../FlowEditor/Public/Asset/FlowImportUtils.h | 16 +++ 5 files changed, 116 insertions(+), 67 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 7c6272285..dbd275761 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -133,19 +133,19 @@ UFlowAsset* UFlowNode::GetFlowAsset() const return GetOuter() ? Cast(GetOuter()) : nullptr; } -void UFlowNode::AddInputPins(TArray PinNames) +void UFlowNode::AddInputPins(TArray Pins) { - for (const FName& PinName : PinNames) + for (const FFlowPin& Pin : Pins) { - InputPins.Emplace(PinName); + InputPins.Emplace(Pin); } } -void UFlowNode::AddOutputPins(TArray PinNames) +void UFlowNode::AddOutputPins(TArray Pins) { - for (const FName& PinName : PinNames) + for (const FFlowPin& Pin : Pins) { - OutputPins.Emplace(PinName); + OutputPins.Emplace(Pin); } } diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index c734babe4..7595ca4ec 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -77,6 +77,9 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte virtual void FixNode(UEdGraphNode* NewGraphNode); virtual EDataValidationResult ValidateNode() { return EDataValidationResult::NotValidated; } + + // used when import graph from another asset + virtual void PostImport() {} #endif UEdGraphNode* GetGraphNode() const { return GraphNode; } diff --git a/Source/Flow/Public/Nodes/FlowPin.h b/Source/Flow/Public/Nodes/FlowPin.h index 55be81cfb..1f5c2d82b 100644 --- a/Source/Flow/Public/Nodes/FlowPin.h +++ b/Source/Flow/Public/Nodes/FlowPin.h @@ -182,23 +182,6 @@ struct FLOW_API FConnectedPin } }; -USTRUCT() -struct FLOW_API FGraphNodeImport -{ - GENERATED_USTRUCT_BODY() - - UPROPERTY() - UEdGraphNode* SourceGraphNode; - - TArray Inputs; - TArray Outputs; - - FGraphNodeImport() - : SourceGraphNode(nullptr) - { - } -}; - UENUM(BlueprintType) enum class EFlowPinActivationType : uint8 { diff --git a/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp b/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp index d7f0df159..2b62a1607 100644 --- a/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp +++ b/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp @@ -1,8 +1,10 @@ // Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors #include "Asset/FlowImportUtils.h" + #include "Asset/FlowAssetFactory.h" #include "Graph/FlowGraphSchema_Actions.h" +#include "Graph/FlowGraph.h" #include "FlowAsset.h" #include "FlowSettings.h" @@ -11,7 +13,9 @@ #include "AssetRegistry/AssetRegistryModule.h" #include "AssetToolsModule.h" +#include "EdGraphNode_Comment.h" #include "EditorAssetLibrary.h" +#include "K2Node_BaseAsyncTask.h" #include "K2Node_CallFunction.h" #include "K2Node_Event.h" #include "Misc/ScopedSlowTask.h" @@ -38,7 +42,6 @@ UFlowAsset* UFlowImportUtils::ImportBlueprintGraph(UObject* BlueprintAsset, TSub if (UObject* NewAsset = AssetTools.CreateAsset(FlowAssetName, PackageFolder, FlowAssetClass, Factory)) { - UEditorAssetLibrary::SaveLoadedAsset(NewAsset->GetPackage()); FlowAsset = Cast(NewAsset); } } @@ -56,6 +59,9 @@ UFlowAsset* UFlowImportUtils::ImportBlueprintGraph(UObject* BlueprintAsset, TSub if (FlowAsset) { ImportBlueprintGraph(Blueprint, FlowAsset, StartEventName); + + Cast(FlowAsset->GetGraph())->RefreshGraph(); + UEditorAssetLibrary::SaveLoadedAsset(FlowAsset->GetPackage()); } return FlowAsset; @@ -81,47 +87,63 @@ void UFlowImportUtils::ImportBlueprintGraph(UBlueprint* Blueprint, const UFlowAs { ExecuteAssetTask.EnterProgressFrame(1, FText::Format(LOCTEXT("FFlowGraphUtils::ImportBlueprintGraph", "Processing blueprint node: {0}"), ThisNode->GetNodeTitle(ENodeTitleType::ListView))); - const UK2Node* K2Node = Cast(ThisNode); - if (K2Node == nullptr || K2Node->IsNodePure()) + if (UEdGraphNode_Comment* CommentNode = Cast(ThisNode)) { - continue; - } + // special case: recreate Comment node + FFlowGraphSchemaAction_NewComment CommentAction; + UEdGraphNode* NewNode = CommentAction.PerformAction(FlowAsset->GetGraph(), nullptr, FVector2D(CommentNode->NodePosX, CommentNode->NodePosY), false); + if (UEdGraphNode_Comment* CommentCopy = Cast(NewNode)) + { + CommentCopy->NodeComment = CommentNode->NodeComment; - // create map of all non-pure blueprint nodes with theirs pin connections - for (const UEdGraphPin* ThisPin : ThisNode->Pins) + CommentCopy->CommentColor = CommentNode->CommentColor; + CommentCopy->FontSize = CommentNode->FontSize; + CommentCopy->bCommentBubbleVisible_InDetailsPanel = CommentNode->bCommentBubbleVisible_InDetailsPanel; + CommentCopy->bColorCommentBubble = CommentNode->bColorCommentBubble; + CommentCopy->MoveMode = CommentNode->MoveMode; + } + } + else // non-pure K2Nodes { - if (ThisPin->Direction == EGPD_Output && ThisPin->LinkedTo.Num() > 0) + const UK2Node* K2Node = Cast(ThisNode); + if (K2Node && !K2Node->IsNodePure()) { - if (const UEdGraphPin* LinkedPin = ThisPin->LinkedTo[0]) + // create map of all non-pure blueprint nodes with theirs pin connections + for (const UEdGraphPin* ThisPin : ThisNode->Pins) { - UEdGraphNode* LinkedNode = LinkedPin->GetOwningNode(); - - // we assume all imported nodes except the entry point node represent functions - // only the first node from the left in the blueprint uber-graph has to be the Event node (UK2Node_Event) - const UK2Node_CallFunction* LinkedFunctionNode = Cast(LinkedNode); - if (LinkedFunctionNode && !LinkedFunctionNode->IsNodePure()) + if (ThisPin->Direction == EGPD_Output && ThisPin->LinkedTo.Num() > 0) { - FGraphNodeImport& ThisNodeImport = ImportedNodes.FindOrAdd(ThisNode->NodeGuid); - ThisNodeImport.Outputs.Add(FConnectedPin(LinkedNode->NodeGuid, LinkedPin->PinName)); - - FGraphNodeImport& LinkedNodeImport = ImportedNodes.FindOrAdd(LinkedNode->NodeGuid); - LinkedNodeImport.SourceGraphNode = LinkedNode; - LinkedNodeImport.Inputs.Add(FConnectedPin(ThisNode->NodeGuid, ThisPin->PinName)); + if (const UEdGraphPin* LinkedPin = ThisPin->LinkedTo[0]) + { + UEdGraphNode* LinkedNode = LinkedPin->GetOwningNode(); + + // we assume all imported nodes except the entry point node represent functions + // only the first node from the left in the blueprint uber-graph has to be the Event node (UK2Node_Event) + const UK2Node_CallFunction* LinkedFunctionNode = Cast(LinkedNode); + const UK2Node_BaseAsyncTask* LinkedAsyncTaskNode = Cast(LinkedNode); + if ((LinkedFunctionNode && !LinkedFunctionNode->IsNodePure()) || LinkedAsyncTaskNode) + { + FGraphNodeImport& ThisNodeImport = ImportedNodes.FindOrAdd(ThisNode->NodeGuid); + ThisNodeImport.Connections.Add(ThisPin->PinName, FConnectedPin(LinkedNode->NodeGuid, LinkedPin->PinName)); + + FGraphNodeImport& LinkedNodeImport = ImportedNodes.FindOrAdd(LinkedNode->NodeGuid); + LinkedNodeImport.SourceGraphNode = LinkedNode; + } + } } } - } - } - // we need to know the default entry point of blueprint graph - const UK2Node_Event* EventNode = Cast(ThisNode); - if (EventNode && (EventNode->EventReference.GetMemberName() == StartEventName || EventNode->CustomFunctionName == StartEventName)) - { - StartNode = ThisNode; + // we need to know the default entry point of blueprint graph + const UK2Node_Event* EventNode = Cast(ThisNode); + if (EventNode && (EventNode->EventReference.GetMemberName() == StartEventName || EventNode->CustomFunctionName == StartEventName)) + { + StartNode = ThisNode; + } + } } } // can't start import if provided graph doesn't have required start node - // todo: do we really needs this? if (StartNode == nullptr) { return; @@ -146,30 +168,50 @@ void UFlowImportUtils::ImportBlueprintFunction_Recursive(UEdGraphNode* Preceding UEdGraph* Graph = PrecedingGraphNode->GetGraph(); const FGraphNodeImport& PrecedingNode = SourceNodes.FindRef(PrecedingGraphNode->NodeGuid); - for (const FConnectedPin& Output : PrecedingNode.Outputs) + const UFlowGraphNode* PrecedingFlowGraphNode = Cast(PrecedingGraphNode); + if (PrecedingFlowGraphNode == nullptr || PrecedingFlowGraphNode->OutputPins.IsEmpty()) { - // todo: support multiple output pins - //UFlowNode* LinkedNodeDefaults = MatchingFlowNodeClass.GetDefaultObject(); - //const FName PinName = LinkedNodeDefaults->OutputPins[0].PinName; - UEdGraphPin* OutputPin = Cast(PrecedingGraphNode)->OutputPins[0]; + return; + } - const FGuid& LinkedNodeGuid = Output.NodeGuid; + for (const TPair& Connection : PrecedingNode.Connections) + { + const FGuid& LinkedNodeGuid = Connection.Value.NodeGuid; const FGraphNodeImport& LinkedNodeImport = SourceNodes.FindRef(LinkedNodeGuid); - // we only accept here blueprint nodes representing functions - const UK2Node_CallFunction* FunctionNode = Cast(LinkedNodeImport.SourceGraphNode); - if (FunctionNode == nullptr) + // find FlowNode class matching provided UFunction name + TSubclassOf MatchingFlowNodeClass = nullptr; + if (const UK2Node_CallFunction* FunctionNode = Cast(LinkedNodeImport.SourceGraphNode)) { - continue; + // find FlowNode class matching provided UFunction name + MatchingFlowNodeClass = UFlowSettings::Get()->BlueprintFunctionsToFlowNodes.FindRef(FunctionNode->GetFunctionName()); + } + else if (const UK2Node_BaseAsyncTask* AsyncTaskNode = Cast(LinkedNodeImport.SourceGraphNode)) + { + // find FlowNode class matching provided AsyncTask name + MatchingFlowNodeClass = UFlowSettings::Get()->BlueprintFunctionsToFlowNodes.FindRef(AsyncTaskNode->GetProxyFactoryFunctionName()); } - // find FlowNode class matching provided UFunction name - const TSubclassOf MatchingFlowNodeClass = UFlowSettings::Get()->BlueprintFunctionsToFlowNodes.FindRef(FunctionNode->GetFunctionName()); if (MatchingFlowNodeClass == nullptr) { continue; } + // find output pin of preceding node + UEdGraphPin* OutputPin = nullptr; + for (UEdGraphPin* Pin : PrecedingFlowGraphNode->OutputPins) + { + if (Pin->PinName == Connection.Key || PrecedingFlowGraphNode->OutputPins.Num() == 1) + { + OutputPin = Pin; + break; + } + } + if (OutputPin == nullptr) + { + continue; + } + // check if already imported connected node // todo: optimize? UFlowGraphNode* LinkedGraphNode = nullptr; @@ -193,7 +235,7 @@ void UFlowImportUtils::ImportBlueprintFunction_Recursive(UEdGraphNode* Preceding UEdGraphPin* LinkedPin = nullptr; for (UEdGraphPin* InputPin : LinkedGraphNode->InputPins) { - if (InputPin->PinName == Output.PinName) + if (InputPin->PinName == Connection.Value.PinName || LinkedGraphNode->InputPins.Num() == 1) { LinkedPin = InputPin; break; @@ -201,7 +243,10 @@ void UFlowImportUtils::ImportBlueprintFunction_Recursive(UEdGraphNode* Preceding } // just link the pin to existing node - Graph->GetSchema()->TryCreateConnection(OutputPin, LinkedPin); + if (LinkedPin) + { + Graph->GetSchema()->TryCreateConnection(OutputPin, LinkedPin); + } } if (LinkedGraphNode) @@ -209,7 +254,7 @@ void UFlowImportUtils::ImportBlueprintFunction_Recursive(UEdGraphNode* Preceding // transfer properties from UFunction input parameters to Flow Node properties { TMap InputPins; - for (UEdGraphPin* Pin : FunctionNode->Pins) + for (UEdGraphPin* Pin : LinkedNodeImport.SourceGraphNode->Pins) { if (Pin->Direction == EGPD_Input && !Pin->bHidden && !Pin->bOrphanedPin) { @@ -233,6 +278,8 @@ void UFlowImportUtils::ImportBlueprintFunction_Recursive(UEdGraphNode* Preceding } } + LinkedGraphNode->GetFlowNode()->PostImport(); + // iterate next nodes ImportBlueprintFunction_Recursive(LinkedGraphNode, SourceNodes); } diff --git a/Source/FlowEditor/Public/Asset/FlowImportUtils.h b/Source/FlowEditor/Public/Asset/FlowImportUtils.h index a040802d2..e3d20e0e8 100644 --- a/Source/FlowEditor/Public/Asset/FlowImportUtils.h +++ b/Source/FlowEditor/Public/Asset/FlowImportUtils.h @@ -5,6 +5,22 @@ #include "FlowAsset.h" #include "FlowImportUtils.generated.h" +USTRUCT() +struct FLOWEDITOR_API FGraphNodeImport +{ + GENERATED_USTRUCT_BODY() + + UPROPERTY() + UEdGraphNode* SourceGraphNode; + + TMap Connections + + FGraphNodeImport() + : SourceGraphNode(nullptr) + { + } +}; + /** * */ From 28520a3583df7719d30213781ac0d4ecb2cee787 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Mon, 9 Jan 2023 00:56:49 +0100 Subject: [PATCH 232/338] Context Pins now can are constructed directly as FFlowPin --- .../Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp | 12 ++++++------ .../Nodes/World/FlowNode_PlayLevelSequence.cpp | 10 +++++----- Source/Flow/Public/Nodes/FlowNode.h | 8 ++++---- Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h | 4 ++-- .../Public/Nodes/World/FlowNode_PlayLevelSequence.h | 2 +- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp index ab6dfa5bb..006c15dda 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp @@ -117,9 +117,9 @@ EDataValidationResult UFlowNode_SubGraph::ValidateNode() return EDataValidationResult::Valid; } -TArray UFlowNode_SubGraph::GetContextInputs() +TArray UFlowNode_SubGraph::GetContextInputs() { - TArray EventNames; + TArray EventNames; if (!Asset.IsNull()) { @@ -136,9 +136,9 @@ TArray UFlowNode_SubGraph::GetContextInputs() return EventNames; } -TArray UFlowNode_SubGraph::GetContextOutputs() +TArray UFlowNode_SubGraph::GetContextOutputs() { - TArray EventNames; + TArray Pins; if (!Asset.IsNull()) { @@ -147,12 +147,12 @@ TArray UFlowNode_SubGraph::GetContextOutputs() { if (!PinName.IsNone()) { - EventNames.Emplace(PinName); + Pins.Emplace(PinName); } } } - return EventNames; + return Pins; } void UFlowNode_SubGraph::PostLoad() diff --git a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp index 727d7e0f4..1927105d2 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp @@ -46,14 +46,14 @@ UFlowNode_PlayLevelSequence::UFlowNode_PlayLevelSequence(const FObjectInitialize } #if WITH_EDITOR -TArray UFlowNode_PlayLevelSequence::GetContextOutputs() +TArray UFlowNode_PlayLevelSequence::GetContextOutputs() { if (Sequence.IsNull()) { - return TArray(); + return TArray(); } - TArray PinNames = {}; + TArray Pins = {}; Sequence = Sequence.LoadSynchronous(); if (Sequence && Sequence->GetMovieScene()) @@ -70,7 +70,7 @@ TArray UFlowNode_PlayLevelSequence::GetContextOutputs() { if (!EventName.IsEmpty()) { - PinNames.Emplace(EventName); + Pins.Emplace(EventName); } } } @@ -79,7 +79,7 @@ TArray UFlowNode_PlayLevelSequence::GetContextOutputs() } } - return PinNames; + return Pins; } void UFlowNode_PlayLevelSequence::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 7595ca4ec..7fbea8205 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -148,8 +148,8 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UPROPERTY(EditDefaultsOnly, Category = "FlowNode") TArray OutputPins; - void AddInputPins(TArray PinNames); - void AddOutputPins(TArray PinNames); + void AddInputPins(TArray Pins); + void AddOutputPins(TArray Pins); // always use default range for nodes with user-created outputs i.e. Execution Sequence void SetNumberedInputPins(const uint8 FirstNumber = 0, const uint8 LastNumber = 1); @@ -174,8 +174,8 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte // Be careful, enabling it might cause loading gigabytes of data as nodes would load all related data (i.e. Level Sequences) virtual bool CanRefreshContextPinsOnLoad() const { return false; } - virtual TArray GetContextInputs() { return TArray(); } - virtual TArray GetContextOutputs() { return TArray(); } + virtual TArray GetContextInputs() { return TArray(); } + virtual TArray GetContextOutputs() { return TArray(); } virtual bool CanUserAddInput() const; virtual bool CanUserAddOutput() const; diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h b/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h index d6356e1a0..394e631f9 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h @@ -56,8 +56,8 @@ class FLOW_API UFlowNode_SubGraph : public UFlowNode virtual bool SupportsContextPins() const override { return true; } - virtual TArray GetContextInputs() override; - virtual TArray GetContextOutputs() override; + virtual TArray GetContextInputs() override; + virtual TArray GetContextOutputs() override; // UObject virtual void PostLoad() override; diff --git a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h index eb24d35ac..ad118d008 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h @@ -82,7 +82,7 @@ class FLOW_API UFlowNode_PlayLevelSequence : public UFlowNode public: #if WITH_EDITOR virtual bool SupportsContextPins() const override { return true; } - virtual TArray GetContextOutputs() override; + virtual TArray GetContextOutputs() override; virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; #endif From 725c39e0698931177a6275e9ff02032f6031b22c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Tue, 10 Jan 2023 00:01:08 +0100 Subject: [PATCH 233/338] Flow Import improvements -Iterating all nodes in simple for-loop instead of recursive loop that would abort graph import if single node class wouldn't recreated. - Moved map functions-nodes to blutility param as Flow Settings could not serialize classes from other modules. Plus, that potentially allow to have a few different import scripts. - Added logging if matching Flow Node class can't be found. --- Source/Flow/Public/FlowSettings.h | 4 - .../Private/Asset/FlowImportUtils.cpp | 236 ++++++++++-------- .../FlowEditor/Public/Asset/FlowImportUtils.h | 17 +- 3 files changed, 143 insertions(+), 114 deletions(-) diff --git a/Source/Flow/Public/FlowSettings.h b/Source/Flow/Public/FlowSettings.h index c4c21dcc8..6b9e66f18 100644 --- a/Source/Flow/Public/FlowSettings.h +++ b/Source/Flow/Public/FlowSettings.h @@ -29,8 +29,4 @@ class FLOW_API UFlowSettings : public UDeveloperSettings UPROPERTY(Config, EditAnywhere, Category = "SaveSystem") bool bWarnAboutMissingIdentityTags; - - // How many nodes of given class should be preloaded with the Flow Asset instance? - UPROPERTY(Config, EditAnywhere, Category = "Importer") - TMap> BlueprintFunctionsToFlowNodes; }; diff --git a/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp b/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp index 2b62a1607..977e92260 100644 --- a/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp +++ b/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp @@ -3,11 +3,11 @@ #include "Asset/FlowImportUtils.h" #include "Asset/FlowAssetFactory.h" +#include "FlowEditorModule.h" #include "Graph/FlowGraphSchema_Actions.h" #include "Graph/FlowGraph.h" #include "FlowAsset.h" -#include "FlowSettings.h" #include "Nodes/FlowPin.h" #include "Nodes/Route/FlowNode_Start.h" @@ -22,7 +22,9 @@ #define LOCTEXT_NAMESPACE "FlowImportUtils" -UFlowAsset* UFlowImportUtils::ImportBlueprintGraph(UObject* BlueprintAsset, TSubclassOf FlowAssetClass, FString FlowAssetName, const FName StartEventName) +TMap> UFlowImportUtils::FunctionsToFlowNodes = TMap>(); + +UFlowAsset* UFlowImportUtils::ImportBlueprintGraph(UObject* BlueprintAsset, TSubclassOf FlowAssetClass, FString FlowAssetName, TMap> BlueprintFunctionsToFlowNodes, const FName StartEventName) { if (BlueprintAsset == nullptr || FlowAssetClass == nullptr || FlowAssetName.IsEmpty() || StartEventName.IsNone()) { @@ -58,7 +60,9 @@ UFlowAsset* UFlowImportUtils::ImportBlueprintGraph(UObject* BlueprintAsset, TSub // import graph if (FlowAsset) { + FunctionsToFlowNodes = BlueprintFunctionsToFlowNodes; ImportBlueprintGraph(Blueprint, FlowAsset, StartEventName); + FunctionsToFlowNodes.Empty(); Cast(FlowAsset->GetGraph())->RefreshGraph(); UEditorAssetLibrary::SaveLoadedAsset(FlowAsset->GetPackage()); @@ -67,7 +71,7 @@ UFlowAsset* UFlowImportUtils::ImportBlueprintGraph(UObject* BlueprintAsset, TSub return FlowAsset; } -void UFlowImportUtils::ImportBlueprintGraph(UBlueprint* Blueprint, const UFlowAsset* FlowAsset, const FName StartEventName) +void UFlowImportUtils::ImportBlueprintGraph(UBlueprint* Blueprint, UFlowAsset* FlowAsset, const FName StartEventName) { ensureAlways(Blueprint && FlowAsset); @@ -80,7 +84,7 @@ void UFlowImportUtils::ImportBlueprintGraph(UBlueprint* Blueprint, const UFlowAs FScopedSlowTask ExecuteAssetTask(BlueprintGraph->Nodes.Num(), FText::Format(LOCTEXT("FFlowGraphUtils::ImportBlueprintGraph", "Reading {0}"), FText::FromString(Blueprint->GetFriendlyName()))); ExecuteAssetTask.MakeDialog(); - TMap ImportedNodes; + TMap SourceNodes; UEdGraphNode* StartNode = nullptr; for (UEdGraphNode* ThisNode : BlueprintGraph->Nodes) @@ -108,26 +112,25 @@ void UFlowImportUtils::ImportBlueprintGraph(UBlueprint* Blueprint, const UFlowAs const UK2Node* K2Node = Cast(ThisNode); if (K2Node && !K2Node->IsNodePure()) { + FImportedGraphNode& NodeImport = SourceNodes.FindOrAdd(ThisNode->NodeGuid); + NodeImport.SourceGraphNode = ThisNode; + // create map of all non-pure blueprint nodes with theirs pin connections for (const UEdGraphPin* ThisPin : ThisNode->Pins) { - if (ThisPin->Direction == EGPD_Output && ThisPin->LinkedTo.Num() > 0) + for (const UEdGraphPin* LinkedPin : ThisPin->LinkedTo) { - if (const UEdGraphPin* LinkedPin = ThisPin->LinkedTo[0]) + if (LinkedPin && LinkedPin->GetOwningNode()) { - UEdGraphNode* LinkedNode = LinkedPin->GetOwningNode(); + const FConnectedPin ConnectedPin(LinkedPin->GetOwningNode()->NodeGuid, LinkedPin->PinName); - // we assume all imported nodes except the entry point node represent functions - // only the first node from the left in the blueprint uber-graph has to be the Event node (UK2Node_Event) - const UK2Node_CallFunction* LinkedFunctionNode = Cast(LinkedNode); - const UK2Node_BaseAsyncTask* LinkedAsyncTaskNode = Cast(LinkedNode); - if ((LinkedFunctionNode && !LinkedFunctionNode->IsNodePure()) || LinkedAsyncTaskNode) + if (ThisPin->Direction == EGPD_Input) { - FGraphNodeImport& ThisNodeImport = ImportedNodes.FindOrAdd(ThisNode->NodeGuid); - ThisNodeImport.Connections.Add(ThisPin->PinName, FConnectedPin(LinkedNode->NodeGuid, LinkedPin->PinName)); - - FGraphNodeImport& LinkedNodeImport = ImportedNodes.FindOrAdd(LinkedNode->NodeGuid); - LinkedNodeImport.SourceGraphNode = LinkedNode; + NodeImport.Incoming.Add(ThisPin->PinName, ConnectedPin); + } + else + { + NodeImport.Outgoing.Add(ThisPin->PinName, ConnectedPin); } } } @@ -150,138 +153,165 @@ void UFlowImportUtils::ImportBlueprintGraph(UBlueprint* Blueprint, const UFlowAs } // clear existing graph - UEdGraph* FlowGraph = FlowAsset->GetGraph(); + UFlowGraph* FlowGraph = Cast(FlowAsset->GetGraph()); FlowGraph->Nodes.Empty(); + TMap TargetNodes; + // recreated UFlowNode_Start, assign it a blueprint node FGuid - UFlowGraphNode* NewGraphNode = FFlowGraphSchemaAction_NewNode::CreateNode(FlowGraph, nullptr, UFlowNode_Start::StaticClass(), FVector2D::ZeroVector); - FlowGraph->GetSchema()->SetNodeMetaData(NewGraphNode, FNodeMetadata::DefaultGraphNode); - NewGraphNode->NodeGuid = StartNode->NodeGuid; - NewGraphNode->GetFlowNode()->SetGuid(StartNode->NodeGuid); + UFlowGraphNode* StartGraphNode = FFlowGraphSchemaAction_NewNode::CreateNode(FlowGraph, nullptr, UFlowNode_Start::StaticClass(), FVector2D::ZeroVector); + FlowGraph->GetSchema()->SetNodeMetaData(StartGraphNode, FNodeMetadata::DefaultGraphNode); + StartGraphNode->NodeGuid = StartNode->NodeGuid; + StartGraphNode->GetFlowNode()->SetGuid(StartNode->NodeGuid); + TargetNodes.Add(StartGraphNode->NodeGuid, StartGraphNode); // execute graph import - ImportBlueprintFunction_Recursive(FlowGraph->Nodes[0], ImportedNodes); + // iterate all nodes separately, ensures we import all possible nodes and connect them together + for (const TPair& SourceNode : SourceNodes) + { + ImportBlueprintFunction(FlowAsset, SourceNode.Value, SourceNodes, TargetNodes); + } } -void UFlowImportUtils::ImportBlueprintFunction_Recursive(UEdGraphNode* PrecedingGraphNode, const TMap SourceNodes) +void UFlowImportUtils::ImportBlueprintFunction(UFlowAsset* FlowAsset, const FImportedGraphNode& NodeImport, const TMap& SourceNodes, TMap& TargetNodes) { - UEdGraph* Graph = PrecedingGraphNode->GetGraph(); - const FGraphNodeImport& PrecedingNode = SourceNodes.FindRef(PrecedingGraphNode->NodeGuid); + ensureAlways(NodeImport.SourceGraphNode); + TSubclassOf MatchingFlowNodeClass = nullptr; - const UFlowGraphNode* PrecedingFlowGraphNode = Cast(PrecedingGraphNode); - if (PrecedingFlowGraphNode == nullptr || PrecedingFlowGraphNode->OutputPins.IsEmpty()) + // find FlowNode class matching provided UFunction name + FName FunctionName = NAME_None; + if (const UK2Node_CallFunction* FunctionNode = Cast(NodeImport.SourceGraphNode)) { - return; + FunctionName = FunctionNode->GetFunctionName(); } - - for (const TPair& Connection : PrecedingNode.Connections) + else if (const UK2Node_BaseAsyncTask* AsyncTaskNode = Cast(NodeImport.SourceGraphNode)) { - const FGuid& LinkedNodeGuid = Connection.Value.NodeGuid; - const FGraphNodeImport& LinkedNodeImport = SourceNodes.FindRef(LinkedNodeGuid); + FunctionName = AsyncTaskNode->GetProxyFactoryFunctionName(); + } + if (!FunctionName.IsNone()) + { // find FlowNode class matching provided UFunction name - TSubclassOf MatchingFlowNodeClass = nullptr; - if (const UK2Node_CallFunction* FunctionNode = Cast(LinkedNodeImport.SourceGraphNode)) - { - // find FlowNode class matching provided UFunction name - MatchingFlowNodeClass = UFlowSettings::Get()->BlueprintFunctionsToFlowNodes.FindRef(FunctionNode->GetFunctionName()); - } - else if (const UK2Node_BaseAsyncTask* AsyncTaskNode = Cast(LinkedNodeImport.SourceGraphNode)) - { - // find FlowNode class matching provided AsyncTask name - MatchingFlowNodeClass = UFlowSettings::Get()->BlueprintFunctionsToFlowNodes.FindRef(AsyncTaskNode->GetProxyFactoryFunctionName()); - } + MatchingFlowNodeClass = FunctionsToFlowNodes.FindRef(FunctionName); + } + + if (MatchingFlowNodeClass == nullptr) + { + UE_LOG(LogFlowEditor, Error, TEXT("Can't find Flow Node class for K2Node, function name %s"), *FunctionName.ToString()); + return; + } - if (MatchingFlowNodeClass == nullptr) - { - continue; - } + const FGuid& NodeGuid = NodeImport.SourceGraphNode->NodeGuid; + + // create a new Flow Graph node + const FVector2d Location = FVector2D(NodeImport.SourceGraphNode->NodePosX, NodeImport.SourceGraphNode->NodePosY); + UFlowGraphNode* FlowGraphNode = FFlowGraphSchemaAction_NewNode::ImportNode(FlowAsset->GetGraph(), nullptr, MatchingFlowNodeClass, NodeGuid, Location); + + if (FlowGraphNode == nullptr) + { + return; + } + TargetNodes.Add(NodeGuid, FlowGraphNode); - // find output pin of preceding node - UEdGraphPin* OutputPin = nullptr; - for (UEdGraphPin* Pin : PrecedingFlowGraphNode->OutputPins) + // transfer properties from UFunction input parameters to Flow Node properties + { + TMap InputPins; + for (UEdGraphPin* Pin : NodeImport.SourceGraphNode->Pins) { - if (Pin->PinName == Connection.Key || PrecedingFlowGraphNode->OutputPins.Num() == 1) + if (Pin->Direction == EGPD_Input && !Pin->bHidden && !Pin->bOrphanedPin) { - OutputPin = Pin; - break; + InputPins.Add(Pin->PinName, Pin); } } - if (OutputPin == nullptr) + + for (TFieldIterator PropIt(FlowGraphNode->GetFlowNode()->GetClass(), EFieldIteratorFlags::IncludeSuper); PropIt && (PropIt->PropertyFlags & CPF_Edit); ++PropIt) { - continue; + const FProperty* Param = *PropIt; + const bool bIsEditable = !Param->HasAnyPropertyFlags(CPF_Deprecated); + if (bIsEditable) + { + if (const UEdGraphPin* InputPin = InputPins.FindRef(*Param->GetAuthoredName())) + { + FString const PinValue = InputPin->GetDefaultAsString(); + uint8* Offset = Param->ContainerPtrToValuePtr(FlowGraphNode->GetFlowNode()); + Param->ImportText_Direct(*PinValue, Offset, FlowGraphNode->GetFlowNode(), PPF_Copy, GLog); + } + } } + } - // check if already imported connected node - // todo: optimize? - UFlowGraphNode* LinkedGraphNode = nullptr; - for (const TObjectPtr ExistingGraphNode : Graph->Nodes) + // Flow Nodes with Context Pins needs to update related data and call OnReconstructionRequested.ExecuteIfBound() in order to fully construct a graph node + FlowGraphNode->GetFlowNode()->PostImport(); + + // connect new node to all already recreated nodes + for (const TPair& Connection : NodeImport.Incoming) + { + UEdGraphPin* ThisPin = nullptr; + for (UEdGraphPin* Pin : FlowGraphNode->InputPins) { - if (ExistingGraphNode->NodeGuid == LinkedNodeGuid) + if (Pin->PinName == Connection.Key || FlowGraphNode->InputPins.Num() == 1) { - LinkedGraphNode = Cast(ExistingGraphNode); + ThisPin = Pin; break; } } - - if (LinkedGraphNode == nullptr) + if (ThisPin == nullptr) { - // create a new Flow Graph node - const FVector2d Location = FVector2D(LinkedNodeImport.SourceGraphNode->NodePosX, LinkedNodeImport.SourceGraphNode->NodePosY); - LinkedGraphNode = FFlowGraphSchemaAction_NewNode::ImportNode(PrecedingGraphNode->GetGraph(), OutputPin, MatchingFlowNodeClass, LinkedNodeGuid, Location); + continue; } - else + + UEdGraphPin* ConnectedPin = nullptr; + if (UFlowGraphNode* ConnectedNode = TargetNodes.FindRef(Connection.Value.NodeGuid)) { - UEdGraphPin* LinkedPin = nullptr; - for (UEdGraphPin* InputPin : LinkedGraphNode->InputPins) + for (UEdGraphPin* Pin : ConnectedNode->OutputPins) { - if (InputPin->PinName == Connection.Value.PinName || LinkedGraphNode->InputPins.Num() == 1) + if (ConnectedNode->OutputPins.Num() == 1 || Pin->PinName == Connection.Value.PinName) { - LinkedPin = InputPin; + ConnectedPin = Pin; break; } } + } - // just link the pin to existing node - if (LinkedPin) + // link the pin to existing node + if (ConnectedPin) + { + FlowAsset->GetGraph()->GetSchema()->TryCreateConnection(ThisPin, ConnectedPin); + } + } + for (const TPair& Connection : NodeImport.Outgoing) + { + UEdGraphPin* ThisPin = nullptr; + for (UEdGraphPin* Pin : FlowGraphNode->OutputPins) + { + if (Pin->PinName == Connection.Key || FlowGraphNode->OutputPins.Num() == 1) { - Graph->GetSchema()->TryCreateConnection(OutputPin, LinkedPin); + ThisPin = Pin; + break; } } - - if (LinkedGraphNode) + if (ThisPin == nullptr) { - // transfer properties from UFunction input parameters to Flow Node properties + continue; + } + + UEdGraphPin* ConnectedPin = nullptr; + if (UFlowGraphNode* ConnectedNode = TargetNodes.FindRef(Connection.Value.NodeGuid)) + { + for (UEdGraphPin* Pin : ConnectedNode->InputPins) { - TMap InputPins; - for (UEdGraphPin* Pin : LinkedNodeImport.SourceGraphNode->Pins) - { - if (Pin->Direction == EGPD_Input && !Pin->bHidden && !Pin->bOrphanedPin) - { - InputPins.Add(Pin->PinName, Pin); - } - } - - for (TFieldIterator PropIt(LinkedGraphNode->GetFlowNode()->GetClass(), EFieldIteratorFlags::IncludeSuper); PropIt && (PropIt->PropertyFlags & CPF_Edit); ++PropIt) + if (ConnectedNode->InputPins.Num() == 1 || Pin->PinName == Connection.Value.PinName) { - const FProperty* Param = *PropIt; - const bool bIsEditable = !Param->HasAnyPropertyFlags(CPF_Deprecated); - if (bIsEditable) - { - if (const UEdGraphPin* InputPin = InputPins.FindRef(*Param->GetAuthoredName())) - { - FString const PinValue = InputPin->GetDefaultAsString(); - uint8* Offset = Param->ContainerPtrToValuePtr(LinkedGraphNode->GetFlowNode()); - Param->ImportText(*PinValue, Offset, PPF_Copy, nullptr, GLog); - } - } + ConnectedPin = Pin; + break; } } + } - LinkedGraphNode->GetFlowNode()->PostImport(); - - // iterate next nodes - ImportBlueprintFunction_Recursive(LinkedGraphNode, SourceNodes); + // link the pin to existing node + if (ConnectedPin) + { + FlowAsset->GetGraph()->GetSchema()->TryCreateConnection(ThisPin, ConnectedPin); } } } diff --git a/Source/FlowEditor/Public/Asset/FlowImportUtils.h b/Source/FlowEditor/Public/Asset/FlowImportUtils.h index e3d20e0e8..540c06990 100644 --- a/Source/FlowEditor/Public/Asset/FlowImportUtils.h +++ b/Source/FlowEditor/Public/Asset/FlowImportUtils.h @@ -6,16 +6,17 @@ #include "FlowImportUtils.generated.h" USTRUCT() -struct FLOWEDITOR_API FGraphNodeImport +struct FLOWEDITOR_API FImportedGraphNode { GENERATED_USTRUCT_BODY() UPROPERTY() UEdGraphNode* SourceGraphNode; - TMap Connections + TMultiMap Incoming; + TMultiMap Outgoing; - FGraphNodeImport() + FImportedGraphNode() : SourceGraphNode(nullptr) { } @@ -25,14 +26,16 @@ struct FLOWEDITOR_API FGraphNodeImport * */ UCLASS(meta = (ScriptName = "FlowImportUtils")) -class FLOWEDITOR_API UFlowImportUtils final : public UBlueprintFunctionLibrary +class FLOWEDITOR_API UFlowImportUtils : public UBlueprintFunctionLibrary { GENERATED_BODY() public: + static TMap> FunctionsToFlowNodes; + UFUNCTION(BlueprintCallable, Category = "FlowImportUtils") - static UFlowAsset* ImportBlueprintGraph(UObject* BlueprintAsset, TSubclassOf FlowAssetClass, FString FlowAssetName, const FName StartEventName = TEXT("BeginPlay")); + static UFlowAsset* ImportBlueprintGraph(UObject* BlueprintAsset, TSubclassOf FlowAssetClass, FString FlowAssetName, TMap> BlueprintFunctionsToFlowNodes, const FName StartEventName = TEXT("BeginPlay")); - static void ImportBlueprintGraph(UBlueprint* Blueprint, const UFlowAsset* FlowAsset, const FName StartEventName = TEXT("BeginPlay")); - static void ImportBlueprintFunction_Recursive(UEdGraphNode* PrecedingGraphNode, const TMap SourceNodes); + static void ImportBlueprintGraph(UBlueprint* Blueprint, UFlowAsset* FlowAsset, const FName StartEventName = TEXT("BeginPlay")); + static void ImportBlueprintFunction(UFlowAsset* FlowAsset, const FImportedGraphNode& NodeImport, const TMap& SourceNodes, TMap& TargetNodes); }; From 7a43bb42bb76b428ca7700ff6ecfb18c926fd07e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Tue, 10 Jan 2023 00:20:52 +0100 Subject: [PATCH 234/338] merge fix --- Source/FlowEditor/Private/Asset/FlowImportUtils.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp b/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp index 977e92260..696bef43a 100644 --- a/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp +++ b/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp @@ -15,7 +15,6 @@ #include "AssetToolsModule.h" #include "EdGraphNode_Comment.h" #include "EditorAssetLibrary.h" -#include "K2Node_BaseAsyncTask.h" #include "K2Node_CallFunction.h" #include "K2Node_Event.h" #include "Misc/ScopedSlowTask.h" @@ -184,10 +183,6 @@ void UFlowImportUtils::ImportBlueprintFunction(UFlowAsset* FlowAsset, const FImp { FunctionName = FunctionNode->GetFunctionName(); } - else if (const UK2Node_BaseAsyncTask* AsyncTaskNode = Cast(NodeImport.SourceGraphNode)) - { - FunctionName = AsyncTaskNode->GetProxyFactoryFunctionName(); - } if (!FunctionName.IsNone()) { From 428e1c462e088ee6fdebbc3819c1aa8435078476 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Tue, 10 Jan 2023 01:48:35 +0100 Subject: [PATCH 235/338] 5.0 fix --- Source/FlowEditor/Private/Asset/FlowImportUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp b/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp index 696bef43a..e8400f6f1 100644 --- a/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp +++ b/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp @@ -229,7 +229,7 @@ void UFlowImportUtils::ImportBlueprintFunction(UFlowAsset* FlowAsset, const FImp { FString const PinValue = InputPin->GetDefaultAsString(); uint8* Offset = Param->ContainerPtrToValuePtr(FlowGraphNode->GetFlowNode()); - Param->ImportText_Direct(*PinValue, Offset, FlowGraphNode->GetFlowNode(), PPF_Copy, GLog); + Param->ImportText(*PinValue, Offset, PPF_Copy, nullptr, GLog); } } } From 488afae316a9c111ad90041c913bbaf428d346d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Thu, 12 Jan 2023 19:39:50 +0100 Subject: [PATCH 236/338] Flow Import utils improvements - Matching blueprint Pins with Flow Node properties named differently. Name mappings need to provided by user, would messy to hardcode such information in Flow Nodes. - Iterating to get pin values from the first pure K2Node connected to the input pins. Supports simple situations like literal value nodes. - Special case to recognize blueprint Branch node. Added special pin mapping since actual Branch pin names are "then" and "else", not "True" and "False". --- .../Private/Asset/FlowImportUtils.cpp | 161 ++++++++++++++---- .../FlowEditor/Public/Asset/FlowImportUtils.h | 28 ++- 2 files changed, 153 insertions(+), 36 deletions(-) diff --git a/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp b/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp index e8400f6f1..7e9b076e8 100644 --- a/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp +++ b/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp @@ -15,15 +15,19 @@ #include "AssetToolsModule.h" #include "EdGraphNode_Comment.h" #include "EditorAssetLibrary.h" +#include "K2Node_BaseAsyncTask.h" #include "K2Node_CallFunction.h" #include "K2Node_Event.h" +#include "K2Node_IfThenElse.h" #include "Misc/ScopedSlowTask.h" #define LOCTEXT_NAMESPACE "FlowImportUtils" TMap> UFlowImportUtils::FunctionsToFlowNodes = TMap>(); +TMap, FBlueprintToFlowPinName> UFlowImportUtils::PinMappings = TMap, FBlueprintToFlowPinName>(); -UFlowAsset* UFlowImportUtils::ImportBlueprintGraph(UObject* BlueprintAsset, TSubclassOf FlowAssetClass, FString FlowAssetName, TMap> BlueprintFunctionsToFlowNodes, const FName StartEventName) +UFlowAsset* UFlowImportUtils::ImportBlueprintGraph(UObject* BlueprintAsset, const TSubclassOf FlowAssetClass, const FString FlowAssetName, + const TMap> InFunctionsToFlowNodes, const TMap, FBlueprintToFlowPinName> InPinMappings, const FName StartEventName) { if (BlueprintAsset == nullptr || FlowAssetClass == nullptr || FlowAssetName.IsEmpty() || StartEventName.IsNone()) { @@ -33,7 +37,7 @@ UFlowAsset* UFlowImportUtils::ImportBlueprintGraph(UObject* BlueprintAsset, TSub UBlueprint* Blueprint = Cast(BlueprintAsset); UFlowAsset* FlowAsset = nullptr; - // we assume that users want to have a converted asset in the same folder as the legacy blueprint + // we assume that users want to have a converted asset in the same folder as the legacy blueprint const FString PackageFolder = FPaths::GetPath(Blueprint->GetOuter()->GetPathName()); if (!FPackageName::DoesPackageExist(PackageFolder / FlowAssetName, nullptr)) // create a new asset @@ -59,7 +63,9 @@ UFlowAsset* UFlowImportUtils::ImportBlueprintGraph(UObject* BlueprintAsset, TSub // import graph if (FlowAsset) { - FunctionsToFlowNodes = BlueprintFunctionsToFlowNodes; + FunctionsToFlowNodes = InFunctionsToFlowNodes; + PinMappings = InPinMappings; + ImportBlueprintGraph(Blueprint, FlowAsset, StartEventName); FunctionsToFlowNodes.Empty(); @@ -156,7 +162,7 @@ void UFlowImportUtils::ImportBlueprintGraph(UBlueprint* Blueprint, UFlowAsset* F FlowGraph->Nodes.Empty(); TMap TargetNodes; - + // recreated UFlowNode_Start, assign it a blueprint node FGuid UFlowGraphNode* StartGraphNode = FFlowGraphSchemaAction_NewNode::CreateNode(FlowGraph, nullptr, UFlowNode_Start::StaticClass(), FVector2D::ZeroVector); FlowGraph->GetSchema()->SetNodeMetaData(StartGraphNode, FNodeMetadata::DefaultGraphNode); @@ -172,7 +178,7 @@ void UFlowImportUtils::ImportBlueprintGraph(UBlueprint* Blueprint, UFlowAsset* F } } -void UFlowImportUtils::ImportBlueprintFunction(UFlowAsset* FlowAsset, const FImportedGraphNode& NodeImport, const TMap& SourceNodes, TMap& TargetNodes) +void UFlowImportUtils::ImportBlueprintFunction(const UFlowAsset* FlowAsset, const FImportedGraphNode& NodeImport, const TMap& SourceNodes, TMap& TargetNodes) { ensureAlways(NodeImport.SourceGraphNode); TSubclassOf MatchingFlowNodeClass = nullptr; @@ -183,13 +189,21 @@ void UFlowImportUtils::ImportBlueprintFunction(UFlowAsset* FlowAsset, const FImp { FunctionName = FunctionNode->GetFunctionName(); } + else if (const UK2Node_BaseAsyncTask* AsyncTaskNode = Cast(NodeImport.SourceGraphNode)) + { + FunctionName = AsyncTaskNode->GetProxyFactoryFunctionName(); + } + else if (Cast(NodeImport.SourceGraphNode)) + { + FunctionName = TEXT("Branch"); + } if (!FunctionName.IsNone()) { // find FlowNode class matching provided UFunction name MatchingFlowNodeClass = FunctionsToFlowNodes.FindRef(FunctionName); } - + if (MatchingFlowNodeClass == nullptr) { UE_LOG(LogFlowEditor, Error, TEXT("Can't find Flow Node class for K2Node, function name %s"), *FunctionName.ToString()); @@ -210,26 +224,67 @@ void UFlowImportUtils::ImportBlueprintFunction(UFlowAsset* FlowAsset, const FImp // transfer properties from UFunction input parameters to Flow Node properties { - TMap InputPins; - for (UEdGraphPin* Pin : NodeImport.SourceGraphNode->Pins) - { - if (Pin->Direction == EGPD_Input && !Pin->bHidden && !Pin->bOrphanedPin) - { - InputPins.Add(Pin->PinName, Pin); - } - } + TMap InputPins; + GetValidInputPins(NodeImport.SourceGraphNode, InputPins); - for (TFieldIterator PropIt(FlowGraphNode->GetFlowNode()->GetClass(), EFieldIteratorFlags::IncludeSuper); PropIt && (PropIt->PropertyFlags & CPF_Edit); ++PropIt) + UClass* FlowNodeClass = FlowGraphNode->GetFlowNode()->GetClass(); + for (TFieldIterator PropIt(FlowNodeClass, EFieldIteratorFlags::IncludeSuper); PropIt && (PropIt->PropertyFlags & CPF_Edit); ++PropIt) { const FProperty* Param = *PropIt; const bool bIsEditable = !Param->HasAnyPropertyFlags(CPF_Deprecated); if (bIsEditable) { - if (const UEdGraphPin* InputPin = InputPins.FindRef(*Param->GetAuthoredName())) + if (const UEdGraphPin* MatchingInputPin = FindPinMatchingToProperty(FlowNodeClass, Param, InputPins)) + { + if (MatchingInputPin->LinkedTo.Num() == 0) // nothing connected to pin, so user can set value directly on this pin + { + FString const PinValue = MatchingInputPin->GetDefaultAsString(); + uint8* Offset = Param->ContainerPtrToValuePtr(FlowGraphNode->GetFlowNode()); + Param->ImportText(*PinValue, Offset, PPF_Copy, nullptr, GLog); + } + } + else // try to find matching Pin in connected pure nodes { - FString const PinValue = InputPin->GetDefaultAsString(); - uint8* Offset = Param->ContainerPtrToValuePtr(FlowGraphNode->GetFlowNode()); - Param->ImportText(*PinValue, Offset, PPF_Copy, nullptr, GLog); + bool bPinFound = false; + for (const TPair InputPin : InputPins) + { + for (const UEdGraphPin* LinkedPin : InputPin.Value->LinkedTo) + { + if (LinkedPin && LinkedPin->GetOwningNode()) // try to read value from the first pure node connected to the pin + { + // in theory, we could put this part in recursive loop, iterating pure nodes until we find one with matching Pin Name + // in practice, iterating blueprint graph isn't that easy as might encounter Make/Break nodes, array builders + // if someone is willing put work to it, you're welcome to make a pull request + + UK2Node* LinkedK2Node = Cast(LinkedPin->GetOwningNode()); + if (LinkedK2Node && LinkedK2Node->IsNodePure()) + { + TMap PureNodePins; + GetValidInputPins(LinkedK2Node, PureNodePins); + + if (const UEdGraphPin* PureInputPin = FindPinMatchingToProperty(FlowNodeClass, Param, PureNodePins)) + { + if (PureInputPin->LinkedTo.Num() == 0) // nothing connected to pin, so user can set value directly on this pin + { + FString const PinValue = PureInputPin->GetDefaultAsString(); + uint8* Offset = Param->ContainerPtrToValuePtr(FlowGraphNode->GetFlowNode()); + Param->ImportText(*PinValue, Offset, PPF_Copy, nullptr, GLog); + + bPinFound = true; + } + } + } + + // there can be only single valid connection on input parameter pin + break; + } + } + + if (bPinFound) + { + break; + } + } } } } @@ -242,11 +297,11 @@ void UFlowImportUtils::ImportBlueprintFunction(UFlowAsset* FlowAsset, const FImp for (const TPair& Connection : NodeImport.Incoming) { UEdGraphPin* ThisPin = nullptr; - for (UEdGraphPin* Pin : FlowGraphNode->InputPins) + for (UEdGraphPin* FlowInputPin : FlowGraphNode->InputPins) { - if (Pin->PinName == Connection.Key || FlowGraphNode->InputPins.Num() == 1) + if (FlowGraphNode->InputPins.Num() == 1 || Connection.Key == FlowInputPin->PinName) { - ThisPin = Pin; + ThisPin = FlowInputPin; break; } } @@ -254,15 +309,17 @@ void UFlowImportUtils::ImportBlueprintFunction(UFlowAsset* FlowAsset, const FImp { continue; } - + UEdGraphPin* ConnectedPin = nullptr; if (UFlowGraphNode* ConnectedNode = TargetNodes.FindRef(Connection.Value.NodeGuid)) { - for (UEdGraphPin* Pin : ConnectedNode->OutputPins) + for (UEdGraphPin* FlowOutputPin : ConnectedNode->OutputPins) { - if (ConnectedNode->OutputPins.Num() == 1 || Pin->PinName == Connection.Value.PinName) + if (ConnectedNode->OutputPins.Num() == 1 || Connection.Value.PinName == FlowOutputPin->PinName + || (Connection.Value.PinName == UEdGraphSchema_K2::PN_Then && FlowOutputPin->PinName == FName("TRUE")) + || (Connection.Value.PinName == UEdGraphSchema_K2::PN_Else && FlowOutputPin->PinName == FName("FALSE"))) { - ConnectedPin = Pin; + ConnectedPin = FlowOutputPin; break; } } @@ -277,11 +334,13 @@ void UFlowImportUtils::ImportBlueprintFunction(UFlowAsset* FlowAsset, const FImp for (const TPair& Connection : NodeImport.Outgoing) { UEdGraphPin* ThisPin = nullptr; - for (UEdGraphPin* Pin : FlowGraphNode->OutputPins) + for (UEdGraphPin* FlowOutputPin : FlowGraphNode->OutputPins) { - if (Pin->PinName == Connection.Key || FlowGraphNode->OutputPins.Num() == 1) + if (FlowGraphNode->OutputPins.Num() == 1 || Connection.Key == FlowOutputPin->PinName + || (Connection.Key == UEdGraphSchema_K2::PN_Then && FlowOutputPin->PinName == FName("TRUE")) + || (Connection.Key == UEdGraphSchema_K2::PN_Else && FlowOutputPin->PinName == FName("FALSE"))) { - ThisPin = Pin; + ThisPin = FlowOutputPin; break; } } @@ -289,15 +348,15 @@ void UFlowImportUtils::ImportBlueprintFunction(UFlowAsset* FlowAsset, const FImp { continue; } - + UEdGraphPin* ConnectedPin = nullptr; if (UFlowGraphNode* ConnectedNode = TargetNodes.FindRef(Connection.Value.NodeGuid)) { - for (UEdGraphPin* Pin : ConnectedNode->InputPins) + for (UEdGraphPin* FlowInputPin : ConnectedNode->InputPins) { - if (ConnectedNode->InputPins.Num() == 1 || Pin->PinName == Connection.Value.PinName) + if (ConnectedNode->InputPins.Num() == 1 || Connection.Value.PinName == FlowInputPin->PinName) { - ConnectedPin = Pin; + ConnectedPin = FlowInputPin; break; } } @@ -311,4 +370,40 @@ void UFlowImportUtils::ImportBlueprintFunction(UFlowAsset* FlowAsset, const FImp } } +void UFlowImportUtils::GetValidInputPins(const UEdGraphNode* GraphNode, TMap& Result) +{ + for (const UEdGraphPin* Pin : GraphNode->Pins) + { + if (Pin->Direction == EGPD_Input && !Pin->bHidden && !Pin->bOrphanedPin) + { + Result.Add(Pin->PinName, Pin); + } + } +} + +const UEdGraphPin* UFlowImportUtils::FindPinMatchingToProperty(UClass* FlowNodeClass, const FProperty* Property, const TMap Pins) +{ + const FName& PropertyAuthoredName = *Property->GetAuthoredName(); + + // if Pin Name is exactly the same as Flow Node property name + if (const UEdGraphPin* Pin = Pins.FindRef(PropertyAuthoredName)) + { + return Pin; + } + + // if not, check if appropriate Pin Mapping has been provided + if (const FBlueprintToFlowPinName* PinMapping = PinMappings.Find(FlowNodeClass)) + { + if (const FName* MappedPinName = PinMapping->NodePropertiesToFunctionPins.Find(PropertyAuthoredName)) + { + if (const UEdGraphPin* Pin = Pins.FindRef(*MappedPinName)) + { + return Pin; + } + } + } + + return nullptr; +} + #undef LOCTEXT_NAMESPACE diff --git a/Source/FlowEditor/Public/Asset/FlowImportUtils.h b/Source/FlowEditor/Public/Asset/FlowImportUtils.h index 540c06990..a18917b5c 100644 --- a/Source/FlowEditor/Public/Asset/FlowImportUtils.h +++ b/Source/FlowEditor/Public/Asset/FlowImportUtils.h @@ -5,6 +5,7 @@ #include "FlowAsset.h" #include "FlowImportUtils.generated.h" +// Helper structure allowing to recreate blueprint graph as Flow Graph USTRUCT() struct FLOWEDITOR_API FImportedGraphNode { @@ -22,6 +23,22 @@ struct FLOWEDITOR_API FImportedGraphNode } }; +// Helper structure allowing to copy properties from blueprint function pin to the Flow Node property of different name +USTRUCT(BlueprintType) +struct FLOWEDITOR_API FBlueprintToFlowPinName +{ + GENERATED_USTRUCT_BODY() + + // Key represents Flow Node property name + // Value represents Input Pin name of blueprint function + UPROPERTY(EditAnywhere, BlueprintReadWrite) + TMap NodePropertiesToFunctionPins; + + FBlueprintToFlowPinName() + { + } +}; + /** * */ @@ -32,10 +49,15 @@ class FLOWEDITOR_API UFlowImportUtils : public UBlueprintFunctionLibrary public: static TMap> FunctionsToFlowNodes; - + static TMap, FBlueprintToFlowPinName> PinMappings; + UFUNCTION(BlueprintCallable, Category = "FlowImportUtils") - static UFlowAsset* ImportBlueprintGraph(UObject* BlueprintAsset, TSubclassOf FlowAssetClass, FString FlowAssetName, TMap> BlueprintFunctionsToFlowNodes, const FName StartEventName = TEXT("BeginPlay")); + static UFlowAsset* ImportBlueprintGraph(UObject* BlueprintAsset, const TSubclassOf FlowAssetClass, const FString FlowAssetName, + const TMap> InFunctionsToFlowNodes, const TMap, FBlueprintToFlowPinName> InPinMappings, const FName StartEventName = TEXT("BeginPlay")); static void ImportBlueprintGraph(UBlueprint* Blueprint, UFlowAsset* FlowAsset, const FName StartEventName = TEXT("BeginPlay")); - static void ImportBlueprintFunction(UFlowAsset* FlowAsset, const FImportedGraphNode& NodeImport, const TMap& SourceNodes, TMap& TargetNodes); + static void ImportBlueprintFunction(const UFlowAsset* FlowAsset, const FImportedGraphNode& NodeImport, const TMap& SourceNodes, TMap& TargetNodes); + + static void GetValidInputPins(const UEdGraphNode* GraphNode, TMap& Result); + static const UEdGraphPin* FindPinMatchingToProperty(UClass* FlowNodeClass, const FProperty* Property, const TMapPins); }; From c803f6e1e82e306d121f73039ed818ed3ae08c5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Thu, 12 Jan 2023 21:34:43 +0100 Subject: [PATCH 237/338] added define and docs on optional check --- Source/FlowEditor/Private/Asset/FlowImportUtils.cpp | 9 +++++++-- Source/FlowEditor/Public/FlowEditorDefines.h | 6 ++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp b/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp index 7e9b076e8..7b5fccb37 100644 --- a/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp +++ b/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp @@ -15,11 +15,14 @@ #include "AssetToolsModule.h" #include "EdGraphNode_Comment.h" #include "EditorAssetLibrary.h" +#include "Misc/ScopedSlowTask.h" + +#if ENABLE_ASYNC_NODES_IMPORT #include "K2Node_BaseAsyncTask.h" +#endif #include "K2Node_CallFunction.h" #include "K2Node_Event.h" #include "K2Node_IfThenElse.h" -#include "Misc/ScopedSlowTask.h" #define LOCTEXT_NAMESPACE "FlowImportUtils" @@ -37,7 +40,7 @@ UFlowAsset* UFlowImportUtils::ImportBlueprintGraph(UObject* BlueprintAsset, cons UBlueprint* Blueprint = Cast(BlueprintAsset); UFlowAsset* FlowAsset = nullptr; - // we assume that users want to have a converted asset in the same folder as the legacy blueprint + // we assume that users want to have a converted asset in the same folder as the legacy blueprint const FString PackageFolder = FPaths::GetPath(Blueprint->GetOuter()->GetPathName()); if (!FPackageName::DoesPackageExist(PackageFolder / FlowAssetName, nullptr)) // create a new asset @@ -189,10 +192,12 @@ void UFlowImportUtils::ImportBlueprintFunction(const UFlowAsset* FlowAsset, cons { FunctionName = FunctionNode->GetFunctionName(); } +#if ENABLE_ASYNC_NODES_IMPORT else if (const UK2Node_BaseAsyncTask* AsyncTaskNode = Cast(NodeImport.SourceGraphNode)) { FunctionName = AsyncTaskNode->GetProxyFactoryFunctionName(); } +#endif else if (Cast(NodeImport.SourceGraphNode)) { FunctionName = TEXT("Branch"); diff --git a/Source/FlowEditor/Public/FlowEditorDefines.h b/Source/FlowEditor/Public/FlowEditorDefines.h index bd4834e33..e991dd4f2 100644 --- a/Source/FlowEditor/Public/FlowEditorDefines.h +++ b/Source/FlowEditor/Public/FlowEditorDefines.h @@ -25,3 +25,9 @@ * Set macro value to 1, if you made these changes to the engine: https://github.com/EpicGames/UnrealEngine/pull/9943 */ #define ENABLE_SEARCH_IN_ASSET_EDITOR 0 + +/** + * Documentation: https://github.com/MothCocoon/FlowGraph/wiki/Import-Utils + * Set macro value to 1, if you made these changes to the engine: https://github.com/EpicGames/UnrealEngine/pull/10004 + */ +#define ENABLE_ASYNC_NODES_IMPORT 0 From 398287d703ca93f42fbc1013a08e07e3b26ea085 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Thu, 12 Jan 2023 21:55:41 +0100 Subject: [PATCH 238/338] plugin-only compilation fix --- Source/FlowEditor/Public/Asset/FlowImportUtils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/FlowEditor/Public/Asset/FlowImportUtils.h b/Source/FlowEditor/Public/Asset/FlowImportUtils.h index a18917b5c..211bb0671 100644 --- a/Source/FlowEditor/Public/Asset/FlowImportUtils.h +++ b/Source/FlowEditor/Public/Asset/FlowImportUtils.h @@ -31,7 +31,7 @@ struct FLOWEDITOR_API FBlueprintToFlowPinName // Key represents Flow Node property name // Value represents Input Pin name of blueprint function - UPROPERTY(EditAnywhere, BlueprintReadWrite) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Pins") TMap NodePropertiesToFunctionPins; FBlueprintToFlowPinName() From 3f06e6957ee1626f1dd45c3ff04c2a19e6d2c9a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 13 Jan 2023 14:34:51 +0100 Subject: [PATCH 239/338] fix crash on importing comment node --- .../FlowEditor/Private/Asset/FlowImportUtils.cpp | 3 +++ .../Private/Graph/FlowGraphSchema_Actions.cpp | 14 +++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp b/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp index 7b5fccb37..7c25fd90a 100644 --- a/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp +++ b/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp @@ -71,6 +71,7 @@ UFlowAsset* UFlowImportUtils::ImportBlueprintGraph(UObject* BlueprintAsset, cons ImportBlueprintGraph(Blueprint, FlowAsset, StartEventName); FunctionsToFlowNodes.Empty(); + PinMappings.Empty(); Cast(FlowAsset->GetGraph())->RefreshGraph(); UEditorAssetLibrary::SaveLoadedAsset(FlowAsset->GetPackage()); @@ -107,6 +108,8 @@ void UFlowImportUtils::ImportBlueprintGraph(UBlueprint* Blueprint, UFlowAsset* F if (UEdGraphNode_Comment* CommentCopy = Cast(NewNode)) { CommentCopy->NodeComment = CommentNode->NodeComment; + CommentCopy->NodeWidth = CommentNode->NodeWidth; + CommentCopy->NodeHeight = CommentNode->NodeHeight; CommentCopy->CommentColor = CommentNode->CommentColor; CommentCopy->FontSize = CommentNode->FontSize; diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp index 4d8464b26..7aea403a3 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp @@ -220,12 +220,16 @@ UEdGraphNode* FFlowGraphSchemaAction_NewComment::PerformAction(class UEdGraph* P UEdGraphNode_Comment* CommentTemplate = NewObject(); FVector2D SpawnLocation = Location; - FSlateRect Bounds; - if (FFlowGraphUtils::GetFlowAssetEditor(ParentGraph)->GetBoundsForSelectedNodes(Bounds, 50.0f)) + const TSharedPtr FlowAssetEditor = FFlowGraphUtils::GetFlowAssetEditor(ParentGraph); + if (FlowAssetEditor.IsValid()) { - CommentTemplate->SetBounds(Bounds); - SpawnLocation.X = CommentTemplate->NodePosX; - SpawnLocation.Y = CommentTemplate->NodePosY; + FSlateRect Bounds; + if (FlowAssetEditor->GetBoundsForSelectedNodes(Bounds, 50.0f)) + { + CommentTemplate->SetBounds(Bounds); + SpawnLocation.X = CommentTemplate->NodePosX; + SpawnLocation.Y = CommentTemplate->NodePosY; + } } return FEdGraphSchemaAction_NewNode::SpawnNodeFromTemplate(ParentGraph, CommentTemplate, SpawnLocation); From 2932622959cb5d2f37d990d0897b2b700eb559c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sat, 14 Jan 2023 22:40:31 +0100 Subject: [PATCH 240/338] exposed GetStartedNode, per community request --- Source/Flow/Private/FlowAsset.cpp | 15 +++++++++++++++ Source/Flow/Public/FlowAsset.h | 2 ++ 2 files changed, 17 insertions(+) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 45c330ac6..1d0c25b10 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -196,6 +196,21 @@ void UFlowAsset::HarvestNodeConnections() } #endif +UFlowNode_Start* UFlowAsset::GetStartNode() const +{ + for (const TPair& Node : Nodes) + { + // there can be only one, automatically added while creating graph + if (UFlowNode_Start* TestedNode = Cast(Node.Value)) + { + return TestedNode; + } + } + + // shouldn't ever get here, Start Node is a default node that can't be deleted by user + return nullptr; +} + void UFlowAsset::AddInstance(UFlowAsset* Instance) { ActiveInstances.Add(Instance); diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index efb57a00e..d5d529fe5 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -151,6 +151,8 @@ class FLOW_API UFlowAsset : public UObject TArray GetCustomInputs() const { return CustomInputs; } TArray GetCustomOutputs() const { return CustomOutputs; } + UFlowNode_Start* GetStartNode() const; + ////////////////////////////////////////////////////////////////////////// // Instances of the template asset From 7aabd59b898b5b5b2f472b36f75ab97d22536d78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sat, 14 Jan 2023 22:41:02 +0100 Subject: [PATCH 241/338] exposed access to connections --- Source/Flow/Private/Nodes/FlowNode.cpp | 25 +++++++++++++++++++------ Source/Flow/Public/Nodes/FlowNode.h | 4 +++- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index dbd275761..36a5b481b 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -271,6 +271,19 @@ TSet UFlowNode::GetConnectedNodes() const return Result; } +FName UFlowNode::GetPinConnectedToNode(const FGuid& OtherNodeGuid) +{ + for (const TPair& Connection : Connections) + { + if (Connection.Value.NodeGuid == OtherNodeGuid) + { + return Connection.Key; + } + } + + return NAME_None; +} + bool UFlowNode::IsInputConnected(const FName& PinName) const { if (GetFlowAsset()) @@ -676,11 +689,11 @@ void UFlowNode::LogError(FString Message, const EFlowOnScreenMessageType OnScree GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, Message); } -#if WITH_EDITOR +#if WITH_EDITOR // Message Log - not yet functional { Log.Error(*Message, GetGraphNode()); - + FMessageLog MessageLog("FlowGraph"); MessageLog.AddMessages(Log.Messages); } @@ -696,11 +709,11 @@ void UFlowNode::LogWarning(FString Message) #if !UE_BUILD_SHIPPING BuildMessage(Message); -#if WITH_EDITOR +#if WITH_EDITOR // Message Log - not yet functional { Log.Warning(*Message, GetGraphNode()); - + FMessageLog MessageLog("FlowGraph"); MessageLog.AddMessages(Log.Messages); } @@ -716,11 +729,11 @@ void UFlowNode::LogNote(FString Message) #if !UE_BUILD_SHIPPING BuildMessage(Message); -#if WITH_EDITOR +#if WITH_EDITOR // Message Log - not yet functional { Log.Note(*Message, GetGraphNode()); - + FMessageLog MessageLog("FlowGraph"); MessageLog.AddMessages(Log.Messages); } diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 7fbea8205..f5a3f3ab6 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -194,7 +194,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte ////////////////////////////////////////////////////////////////////////// // Connections to other nodes -private: +protected: // Map outputs to the connected node and input pin UPROPERTY() TMap Connections; @@ -202,7 +202,9 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte public: void SetConnections(const TMap& InConnections) { Connections = InConnections; } FConnectedPin GetConnection(const FName OutputName) const { return Connections.FindRef(OutputName); } + TSet GetConnectedNodes() const; + FName GetPinConnectedToNode(const FGuid& OtherNodeGuid); UFUNCTION(BlueprintPure, Category= "FlowNode") bool IsInputConnected(const FName& PinName) const; From a4c7a97fc300c1ffe8841c2e8fdfe3e5c1eb6d9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sat, 14 Jan 2023 22:56:48 +0100 Subject: [PATCH 242/338] Flow Import improvements - Added Reroute node conversion. - Removed Comment node conversion as it doesn't work fully. Added lengthy description explaining intention behind this utility. --- .../Private/Asset/FlowImportUtils.cpp | 76 ++++++++----------- .../FlowEditor/Public/Asset/FlowImportUtils.h | 8 +- 2 files changed, 36 insertions(+), 48 deletions(-) diff --git a/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp b/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp index 7c25fd90a..314f15f7a 100644 --- a/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp +++ b/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp @@ -13,7 +13,6 @@ #include "AssetRegistry/AssetRegistryModule.h" #include "AssetToolsModule.h" -#include "EdGraphNode_Comment.h" #include "EditorAssetLibrary.h" #include "Misc/ScopedSlowTask.h" @@ -23,6 +22,7 @@ #include "K2Node_CallFunction.h" #include "K2Node_Event.h" #include "K2Node_IfThenElse.h" +#include "K2Node_Knot.h" #define LOCTEXT_NAMESPACE "FlowImportUtils" @@ -100,59 +100,39 @@ void UFlowImportUtils::ImportBlueprintGraph(UBlueprint* Blueprint, UFlowAsset* F { ExecuteAssetTask.EnterProgressFrame(1, FText::Format(LOCTEXT("FFlowGraphUtils::ImportBlueprintGraph", "Processing blueprint node: {0}"), ThisNode->GetNodeTitle(ENodeTitleType::ListView))); - if (UEdGraphNode_Comment* CommentNode = Cast(ThisNode)) + // non-pure K2Nodes or UK2Node_Knot + const UK2Node* K2Node = Cast(ThisNode); + if (K2Node && (!K2Node->IsNodePure() || Cast(K2Node))) { - // special case: recreate Comment node - FFlowGraphSchemaAction_NewComment CommentAction; - UEdGraphNode* NewNode = CommentAction.PerformAction(FlowAsset->GetGraph(), nullptr, FVector2D(CommentNode->NodePosX, CommentNode->NodePosY), false); - if (UEdGraphNode_Comment* CommentCopy = Cast(NewNode)) - { - CommentCopy->NodeComment = CommentNode->NodeComment; - CommentCopy->NodeWidth = CommentNode->NodeWidth; - CommentCopy->NodeHeight = CommentNode->NodeHeight; - - CommentCopy->CommentColor = CommentNode->CommentColor; - CommentCopy->FontSize = CommentNode->FontSize; - CommentCopy->bCommentBubbleVisible_InDetailsPanel = CommentNode->bCommentBubbleVisible_InDetailsPanel; - CommentCopy->bColorCommentBubble = CommentNode->bColorCommentBubble; - CommentCopy->MoveMode = CommentNode->MoveMode; - } - } - else // non-pure K2Nodes - { - const UK2Node* K2Node = Cast(ThisNode); - if (K2Node && !K2Node->IsNodePure()) - { - FImportedGraphNode& NodeImport = SourceNodes.FindOrAdd(ThisNode->NodeGuid); - NodeImport.SourceGraphNode = ThisNode; + FImportedGraphNode& NodeImport = SourceNodes.FindOrAdd(ThisNode->NodeGuid); + NodeImport.SourceGraphNode = ThisNode; - // create map of all non-pure blueprint nodes with theirs pin connections - for (const UEdGraphPin* ThisPin : ThisNode->Pins) + // create map of all non-pure blueprint nodes with theirs pin connections + for (const UEdGraphPin* ThisPin : ThisNode->Pins) + { + for (const UEdGraphPin* LinkedPin : ThisPin->LinkedTo) { - for (const UEdGraphPin* LinkedPin : ThisPin->LinkedTo) + if (LinkedPin && LinkedPin->GetOwningNode()) { - if (LinkedPin && LinkedPin->GetOwningNode()) - { - const FConnectedPin ConnectedPin(LinkedPin->GetOwningNode()->NodeGuid, LinkedPin->PinName); + const FConnectedPin ConnectedPin(LinkedPin->GetOwningNode()->NodeGuid, LinkedPin->PinName); - if (ThisPin->Direction == EGPD_Input) - { - NodeImport.Incoming.Add(ThisPin->PinName, ConnectedPin); - } - else - { - NodeImport.Outgoing.Add(ThisPin->PinName, ConnectedPin); - } + if (ThisPin->Direction == EGPD_Input) + { + NodeImport.Incoming.Add(ThisPin->PinName, ConnectedPin); + } + else + { + NodeImport.Outgoing.Add(ThisPin->PinName, ConnectedPin); } } } + } - // we need to know the default entry point of blueprint graph - const UK2Node_Event* EventNode = Cast(ThisNode); - if (EventNode && (EventNode->EventReference.GetMemberName() == StartEventName || EventNode->CustomFunctionName == StartEventName)) - { - StartNode = ThisNode; - } + // we need to know the default entry point of blueprint graph + const UK2Node_Event* EventNode = Cast(ThisNode); + if (EventNode && (EventNode->EventReference.GetMemberName() == StartEventName || EventNode->CustomFunctionName == StartEventName)) + { + StartNode = ThisNode; } } } @@ -184,7 +164,7 @@ void UFlowImportUtils::ImportBlueprintGraph(UBlueprint* Blueprint, UFlowAsset* F } } -void UFlowImportUtils::ImportBlueprintFunction(const UFlowAsset* FlowAsset, const FImportedGraphNode& NodeImport, const TMap& SourceNodes, TMap& TargetNodes) +void UFlowImportUtils::ImportBlueprintFunction(const UFlowAsset* FlowAsset, const FImportedGraphNode& NodeImport, const TMap& SourceNodes, TMap& TargetNodes) { ensureAlways(NodeImport.SourceGraphNode); TSubclassOf MatchingFlowNodeClass = nullptr; @@ -201,6 +181,10 @@ void UFlowImportUtils::ImportBlueprintFunction(const UFlowAsset* FlowAsset, cons FunctionName = AsyncTaskNode->GetProxyFactoryFunctionName(); } #endif + else if (Cast(NodeImport.SourceGraphNode)) + { + FunctionName = TEXT("Reroute"); + } else if (Cast(NodeImport.SourceGraphNode)) { FunctionName = TEXT("Branch"); diff --git a/Source/FlowEditor/Public/Asset/FlowImportUtils.h b/Source/FlowEditor/Public/Asset/FlowImportUtils.h index 211bb0671..63e4c08e1 100644 --- a/Source/FlowEditor/Public/Asset/FlowImportUtils.h +++ b/Source/FlowEditor/Public/Asset/FlowImportUtils.h @@ -3,6 +3,7 @@ #pragma once #include "FlowAsset.h" +#include "Nodes/FlowPin.h" #include "FlowImportUtils.generated.h" // Helper structure allowing to recreate blueprint graph as Flow Graph @@ -40,7 +41,10 @@ struct FLOWEDITOR_API FBlueprintToFlowPinName }; /** - * + * Groundwork for converting blueprint graphs to Flow Graph. + * It's NOT meant to be universal, out-of-box solution as complexity of blueprint graphs conflicts with simplicity of Flow Graph. + * However, it might useful to provide this basic utility to anyone who would like to batch-convert their custom blueprint-based event system to Flow Graph. + * Pull requests are welcome if you able to improve this utility w/o with minimal amount of code. */ UCLASS(meta = (ScriptName = "FlowImportUtils")) class FLOWEDITOR_API UFlowImportUtils : public UBlueprintFunctionLibrary @@ -56,7 +60,7 @@ class FLOWEDITOR_API UFlowImportUtils : public UBlueprintFunctionLibrary const TMap> InFunctionsToFlowNodes, const TMap, FBlueprintToFlowPinName> InPinMappings, const FName StartEventName = TEXT("BeginPlay")); static void ImportBlueprintGraph(UBlueprint* Blueprint, UFlowAsset* FlowAsset, const FName StartEventName = TEXT("BeginPlay")); - static void ImportBlueprintFunction(const UFlowAsset* FlowAsset, const FImportedGraphNode& NodeImport, const TMap& SourceNodes, TMap& TargetNodes); + static void ImportBlueprintFunction(const UFlowAsset* FlowAsset, const FImportedGraphNode& NodeImport, const TMap& SourceNodes, TMap& TargetNodes); static void GetValidInputPins(const UEdGraphNode* GraphNode, TMap& Result); static const UEdGraphPin* FindPinMatchingToProperty(UClass* FlowNodeClass, const FProperty* Property, const TMapPins); From 3694aed0f86008927d8c5b284d3bdeabd2f42a30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 15 Jan 2023 01:38:36 +0100 Subject: [PATCH 243/338] exposed blueprintable functions also to C++ --- Source/Flow/Public/Nodes/FlowNode.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index f5a3f3ab6..aa588ea81 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -161,13 +161,13 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte TArray GetInputPins() const { return InputPins; } TArray GetOutputPins() const { return OutputPins; } +public: UFUNCTION(BlueprintPure, Category = "FlowNode") TArray GetInputNames() const; UFUNCTION(BlueprintPure, Category = "FlowNode") TArray GetOutputNames() const; -public: #if WITH_EDITOR virtual bool SupportsContextPins() const { return false; } From 637de9cc3f6aec656bea6a5fd9d5f683feb24d42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Mon, 16 Jan 2023 01:39:42 +0100 Subject: [PATCH 244/338] correct graph cleanup while importing blueprint graph --- Source/FlowEditor/Private/Asset/FlowImportUtils.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp b/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp index 314f15f7a..698def15c 100644 --- a/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp +++ b/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp @@ -145,7 +145,16 @@ void UFlowImportUtils::ImportBlueprintGraph(UBlueprint* Blueprint, UFlowAsset* F // clear existing graph UFlowGraph* FlowGraph = Cast(FlowAsset->GetGraph()); - FlowGraph->Nodes.Empty(); + for (const TPair& Node : FlowAsset->GetNodes()) + { + if (UFlowGraphNode* FlowGraphNode = Cast(Node.Value->GetGraphNode())) + { + FlowGraph->GetSchema()->BreakNodeLinks(*FlowGraphNode); + FlowGraphNode->DestroyNode(); + } + + FlowAsset->UnregisterNode(Node.Key); + } TMap TargetNodes; From 120da22202119862a184acaa2238657eba31cb65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Tue, 17 Jan 2023 21:15:12 +0100 Subject: [PATCH 245/338] removed LoadAsset template method as it was redundant --- .../Private/Nodes/Route/FlowNode_SubGraph.cpp | 2 +- .../Nodes/World/FlowNode_PlayLevelSequence.cpp | 8 ++++---- Source/Flow/Public/Nodes/FlowNode.h | 15 +-------------- 3 files changed, 6 insertions(+), 19 deletions(-) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp index 006c15dda..c55d13b21 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp @@ -103,7 +103,7 @@ FString UFlowNode_SubGraph::GetNodeDescription() const UObject* UFlowNode_SubGraph::GetAssetToEdit() { - return Asset.IsNull() ? nullptr : LoadAsset(Asset); + return Asset.IsNull() ? nullptr : Asset.LoadSynchronous(); } EDataValidationResult UFlowNode_SubGraph::ValidateNode() diff --git a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp index 1927105d2..93b3112ae 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp @@ -127,7 +127,7 @@ void UFlowNode_PlayLevelSequence::InitializeInstance() void UFlowNode_PlayLevelSequence::CreatePlayer() { - LoadedSequence = LoadAsset(Sequence); + LoadedSequence = Sequence.LoadSynchronous(); if (LoadedSequence) { ALevelSequenceActor* SequenceActor; @@ -175,7 +175,7 @@ void UFlowNode_PlayLevelSequence::ExecuteInput(const FName& PinName) { if (PinName == TEXT("Start")) { - LoadedSequence = LoadAsset(Sequence); + LoadedSequence = Sequence.LoadSynchronous(); if (GetFlowSubsystem()->GetWorld() && LoadedSequence) { @@ -220,7 +220,7 @@ void UFlowNode_PlayLevelSequence::OnLoad_Implementation() { if (ElapsedTime != 0.0f) { - LoadedSequence = LoadAsset(Sequence); + LoadedSequence = Sequence.LoadSynchronous(); if (GetFlowSubsystem()->GetWorld() && LoadedSequence) { CreatePlayer(); @@ -332,7 +332,7 @@ FString UFlowNode_PlayLevelSequence::GetStatusString() const UObject* UFlowNode_PlayLevelSequence::GetAssetToEdit() { - return Sequence.IsNull() ? nullptr : LoadAsset(Sequence); + return Sequence.IsNull() ? nullptr : Sequence.LoadSynchronous(); } #endif diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index aa588ea81..4e2826f17 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -5,6 +5,7 @@ #include "EdGraph/EdGraphNode.h" #include "Engine/StreamableManager.h" #include "GameplayTagContainer.h" +#include "Templates/SubclassOf.h" #include "VisualLogger/VisualLoggerDebugSnapshotInterface.h" #include "FlowMessageLog.h" @@ -360,20 +361,6 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "Get Actor To Focus")) AActor* K2_GetActorToFocus(); - template - T* LoadAsset(TSoftObjectPtr AssetPtr) - { - ensure(!AssetPtr.IsNull()); - - if (AssetPtr.IsPending()) - { - const FSoftObjectPath& AssetRef = AssetPtr.ToSoftObjectPath(); - AssetPtr = Cast(StreamableManager.LoadSynchronous(AssetRef, false)); - } - - return Cast(AssetPtr.Get()); - } - public: UFUNCTION(BlueprintPure, Category = "FlowNode") static FString GetIdentityTagDescription(const FGameplayTag& Tag); From f8330bb0fd499aa8f3fb4ec5c7293b1e4126b5ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Wed, 18 Jan 2023 00:13:47 +0100 Subject: [PATCH 246/338] initial version of runtime message log! --- Source/Flow/Private/FlowAsset.cpp | 43 +++++- Source/Flow/Private/FlowSubsystem.cpp | 16 +- Source/Flow/Private/Nodes/FlowNode.cpp | 46 +++--- .../Nodes/Route/FlowNode_CustomInput.cpp | 2 +- .../Nodes/Route/FlowNode_CustomOutput.cpp | 2 +- .../Private/Nodes/Route/FlowNode_SubGraph.cpp | 2 +- .../World/FlowNode_ComponentObserver.cpp | 2 +- .../Nodes/World/FlowNode_NotifyActor.cpp | 2 +- .../World/FlowNode_PlayLevelSequence.cpp | 2 +- Source/Flow/Public/FlowAsset.h | 16 +- Source/Flow/Public/FlowMessageLog.h | 9 +- Source/Flow/Public/FlowSubsystem.h | 4 +- Source/Flow/Public/Nodes/FlowNode.h | 2 +- .../Private/Asset/FlowAssetEditor.cpp | 139 ++++++++++++------ .../Private/Asset/FlowMessageLogListing.cpp | 17 ++- .../Private/Graph/Widgets/SFlowGraphNode.cpp | 4 +- .../FlowEditor/Public/Asset/FlowAssetEditor.h | 23 ++- .../Public/Asset/FlowMessageLogListing.h | 15 +- 18 files changed, 233 insertions(+), 113 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 1d0c25b10..7f3be67f2 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -77,10 +77,10 @@ EDataValidationResult UFlowAsset::ValidateAsset(FFlowMessageLog& MessageLog) { if (Node.Value) { - Node.Value->Log.Messages.Empty(); + Node.Value->ValidationLog.Messages.Empty(); if (Node.Value->ValidateNode() == EDataValidationResult::Invalid) { - MessageLog.Messages.Append(Node.Value->Log.Messages); + MessageLog.Messages.Append(Node.Value->ValidationLog.Messages); } } } @@ -281,6 +281,16 @@ void UFlowAsset::SetInspectedInstance(const FName& NewInspectedInstanceName) BroadcastDebuggerRefresh(); } + +void UFlowAsset::BroadcastDebuggerRefresh() const +{ + RefreshDebuggerEvent.Broadcast(); +} + +void UFlowAsset::BroadcastRuntimeMessageAdded(const UFlowAsset* AssetInstance, const TSharedRef& Message) const +{ + RuntimeMessageEvent.Broadcast(AssetInstance, Message); +} #endif void UFlowAsset::InitializeInstance(const TWeakObjectPtr InOwner, UFlowAsset* InTemplateAsset) @@ -497,6 +507,35 @@ UFlowAsset* UFlowAsset::GetParentInstance() const return NodeOwningThisAssetInstance.IsValid() ? NodeOwningThisAssetInstance.Get()->GetFlowAsset() : nullptr; } +#if WITH_EDITOR +void UFlowAsset::LogError(const FString& MessageToLog, UFlowNode* Node) const +{ + if (RuntimeLog.IsValid()) + { + const TSharedRef TokenizedMessage = RuntimeLog.Get()->Error(*MessageToLog, Node); + BroadcastRuntimeMessageAdded(this, TokenizedMessage); + } +} + +void UFlowAsset::LogWarning(const FString& MessageToLog, UFlowNode* Node) const +{ + if (RuntimeLog.IsValid()) + { + const TSharedRef TokenizedMessage = RuntimeLog.Get()->Warning(*MessageToLog, Node); + BroadcastRuntimeMessageAdded(this, TokenizedMessage); + } +} + +void UFlowAsset::LogNote(const FString& MessageToLog, UFlowNode* Node) const +{ + if (RuntimeLog.IsValid()) + { + const TSharedRef TokenizedMessage = RuntimeLog.Get()->Note(*MessageToLog, Node); + BroadcastRuntimeMessageAdded(this, TokenizedMessage); + } +} +#endif + FFlowAssetSaveData UFlowAsset::SaveInstance(TArray& SavedFlowInstances) { FFlowAssetSaveData AssetRecord; diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index 405673b25..a40defd61 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -101,7 +101,7 @@ UFlowAsset* UFlowSubsystem::CreateRootFlow(UObject* Owner, UFlowAsset* FlowAsset void UFlowSubsystem::FinishRootFlow(UObject* Owner, UFlowAsset* TemplateAsset, const EFlowFinishPolicy FinishPolicy) { UFlowAsset* InstanceToFinish = nullptr; - + for (TPair>& RootInstance : RootInstances) { if (Owner && Owner == RootInstance.Value.Get() && RootInstance.Key && RootInstance.Key->GetTemplateAsset() == TemplateAsset) @@ -121,7 +121,7 @@ void UFlowSubsystem::FinishRootFlow(UObject* Owner, UFlowAsset* TemplateAsset, c void UFlowSubsystem::FinishAllRootFlows(UObject* Owner, const EFlowFinishPolicy FinishPolicy) { TArray InstancesToFinish; - + for (TPair>& RootInstance : RootInstances) { if (Owner && Owner == RootInstance.Value.Get() && RootInstance.Key) @@ -194,7 +194,7 @@ UFlowAsset* UFlowSubsystem::CreateFlowInstance(const TWeakObjectPtr Own FlowAsset = Cast(Streamable.LoadSynchronous(FlowAsset.ToSoftObjectPath(), false)); } - InstancedTemplates.Add(FlowAsset.Get()); + AddInstancedTemplate(FlowAsset.Get()); #if WITH_EDITOR if (GetWorld()->WorldType != EWorldType::Game) @@ -218,8 +218,18 @@ UFlowAsset* UFlowSubsystem::CreateFlowInstance(const TWeakObjectPtr Own return NewInstance; } +void UFlowSubsystem::AddInstancedTemplate(UFlowAsset* Template) +{ + if (!InstancedTemplates.Contains(Template)) + { + InstancedTemplates.Add(Template); + Template->RuntimeLog = MakeShareable(new FFlowMessageLog()); + } +} + void UFlowSubsystem::RemoveInstancedTemplate(UFlowAsset* Template) { + Template->RuntimeLog.Reset(); InstancedTemplates.Remove(Template); } diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 36a5b481b..86b50f59d 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -3,7 +3,6 @@ #include "Nodes/FlowNode.h" #include "FlowAsset.h" -#include "FlowMessageLog.h" #include "FlowModule.h" #include "FlowSubsystem.h" #include "FlowTypes.h" @@ -666,6 +665,7 @@ FString UFlowNode::GetProgressAsString(float Value) void UFlowNode::LogError(FString Message, const EFlowOnScreenMessageType OnScreenMessageType) { #if !UE_BUILD_SHIPPING + BuildMessage(Message); // OnScreen Message @@ -689,58 +689,48 @@ void UFlowNode::LogError(FString Message, const EFlowOnScreenMessageType OnScree GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, Message); } -#if WITH_EDITOR - // Message Log - not yet functional - { - Log.Error(*Message, GetGraphNode()); + // Output Log + UE_LOG(LogFlow, Error, TEXT("%s"), *Message); - FMessageLog MessageLog("FlowGraph"); - MessageLog.AddMessages(Log.Messages); - } + // Message Log +#if WITH_EDITOR + GetFlowAsset()->GetTemplateAsset()->LogError(Message, this); #endif - // Output Log - UE_LOG(LogFlow, Error, TEXT("%s"), *Message); #endif } void UFlowNode::LogWarning(FString Message) { #if !UE_BUILD_SHIPPING + BuildMessage(Message); -#if WITH_EDITOR - // Message Log - not yet functional - { - Log.Warning(*Message, GetGraphNode()); + // Output Log + UE_LOG(LogFlow, Warning, TEXT("%s"), *Message); - FMessageLog MessageLog("FlowGraph"); - MessageLog.AddMessages(Log.Messages); - } + // Message Log +#if WITH_EDITOR + GetFlowAsset()->GetTemplateAsset()->LogWarning(Message, this); #endif - // Output Log - UE_LOG(LogFlow, Warning, TEXT("%s"), *Message); #endif } void UFlowNode::LogNote(FString Message) { #if !UE_BUILD_SHIPPING + BuildMessage(Message); -#if WITH_EDITOR - // Message Log - not yet functional - { - Log.Note(*Message, GetGraphNode()); + // Output Log + UE_LOG(LogFlow, Log, TEXT("%s"), *Message); - FMessageLog MessageLog("FlowGraph"); - MessageLog.AddMessages(Log.Messages); - } + // Message Log +#if WITH_EDITOR + GetFlowAsset()->GetTemplateAsset()->LogNote(Message, this); #endif - // Output Log - UE_LOG(LogFlow, Log, TEXT("%s"), *Message); #endif } diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp index ae3946235..e7fa8c5ec 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp @@ -29,7 +29,7 @@ EDataValidationResult UFlowNode_CustomInput::ValidateNode() { if (EventName.IsNone()) { - Log.Error(TEXT("Event Name is empty!"), this); + ValidationLog.Error(TEXT("Event Name is empty!"), this); return EDataValidationResult::Invalid; } diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp index df59bc1d3..b53cbfc31 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp @@ -35,7 +35,7 @@ EDataValidationResult UFlowNode_CustomOutput::ValidateNode() { if (EventName.IsNone()) { - Log.Error(TEXT("Event Name is empty!"), this); + ValidationLog.Error(TEXT("Event Name is empty!"), this); return EDataValidationResult::Invalid; } diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp index c55d13b21..04bbe1e68 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp @@ -110,7 +110,7 @@ EDataValidationResult UFlowNode_SubGraph::ValidateNode() { if (Asset.IsNull()) { - Log.Error(TEXT("Flow Asset not assigned or invalid!"), this); + ValidationLog.Error(TEXT("Flow Asset not assigned or invalid!"), this); return EDataValidationResult::Invalid; } diff --git a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp index 0ad362e00..73151f305 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp @@ -155,7 +155,7 @@ EDataValidationResult UFlowNode_ComponentObserver::ValidateNode() { if (IdentityTags.IsEmpty()) { - Log.Error(*UFlowNode::MissingIdentityTag, this); + ValidationLog.Error(*UFlowNode::MissingIdentityTag, this); return EDataValidationResult::Invalid; } diff --git a/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp b/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp index 12f303690..7340e5896 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp @@ -38,7 +38,7 @@ EDataValidationResult UFlowNode_NotifyActor::ValidateNode() { if (IdentityTags.IsEmpty()) { - Log.Error(*UFlowNode::MissingIdentityTag, this); + ValidationLog.Error(*UFlowNode::MissingIdentityTag, this); return EDataValidationResult::Invalid; } diff --git a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp index 93b3112ae..8a8b28740 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp @@ -318,7 +318,7 @@ EDataValidationResult UFlowNode_PlayLevelSequence::ValidateNode() { if (Sequence.IsNull()) { - Log.Error(TEXT("Level Sequence asset not assigned or invalid!"), this); + ValidationLog.Error(TEXT("Level Sequence asset not assigned or invalid!"), this); return EDataValidationResult::Invalid; } diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index d5d529fe5..21e4008ab 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -163,6 +163,9 @@ class FLOW_API UFlowAsset : public UObject #if WITH_EDITORONLY_DATA TWeakObjectPtr InspectedInstance; + + // Message log for storing runtime errors/notes/warnings that will only last until the next game run + TSharedPtr RuntimeLog; #endif public: @@ -182,8 +185,13 @@ class FLOW_API UFlowAsset : public UObject FRefreshDebuggerEvent& OnDebuggerRefresh() { return RefreshDebuggerEvent; } FRefreshDebuggerEvent RefreshDebuggerEvent; + DECLARE_EVENT_TwoParams(UFlowAsset, FRuntimeMessageEvent, const UFlowAsset*, const TSharedRef&); + FRuntimeMessageEvent& OnRuntimeMessageAdded() { return RuntimeMessageEvent; } + FRuntimeMessageEvent RuntimeMessageEvent; + private: - void BroadcastDebuggerRefresh() const { RefreshDebuggerEvent.Broadcast(); } + void BroadcastDebuggerRefresh() const; + void BroadcastRuntimeMessageAdded(const UFlowAsset* AssetInstance, const TSharedRef& Message) const;; #endif ////////////////////////////////////////////////////////////////////////// @@ -279,6 +287,12 @@ class FLOW_API UFlowAsset : public UObject UFUNCTION(BlueprintPure, Category = "Flow") TArray GetRecordedNodes() const { return RecordedNodes; } +#if WITH_EDITOR + void LogError(const FString& MessageToLog, UFlowNode* Node) const; + void LogWarning(const FString& MessageToLog, UFlowNode* Node) const; + void LogNote(const FString& MessageToLog, UFlowNode* Node) const; +#endif + ////////////////////////////////////////////////////////////////////////// // SaveGame diff --git a/Source/Flow/Public/FlowMessageLog.h b/Source/Flow/Public/FlowMessageLog.h index ee6308636..58ad0495b 100644 --- a/Source/Flow/Public/FlowMessageLog.h +++ b/Source/Flow/Public/FlowMessageLog.h @@ -57,24 +57,27 @@ class FLOW_API FFlowMessageLog } template - void Error(const TCHAR* Format, T* Object) + TSharedRef Error(const TCHAR* Format, T* Object) { TSharedRef Message = FTokenizedMessage::Create(EMessageSeverity::Error); AddMessage(NAME_None, Format, Message, Object); + return Message; } template - void Warning(const TCHAR* Format, T* Object) + TSharedRef Warning(const TCHAR* Format, T* Object) { TSharedRef Message = FTokenizedMessage::Create(EMessageSeverity::Warning); AddMessage(NAME_None, Format, Message, Object); + return Message; } template - void Note(const TCHAR* Format, T* Object) + TSharedRef Note(const TCHAR* Format, T* Object) { TSharedRef Message = FTokenizedMessage::Create(EMessageSeverity::Info); AddMessage(NAME_None, Format, Message, Object); + return Message; } protected: diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index c98d8c4a0..62d468384 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -85,7 +85,9 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem void RemoveSubFlow(UFlowNode_SubGraph* SubGraphNode, const EFlowFinishPolicy FinishPolicy); UFlowAsset* CreateFlowInstance(const TWeakObjectPtr Owner, TSoftObjectPtr FlowAsset, FString NewInstanceName = FString()); - void RemoveInstancedTemplate(UFlowAsset* Template); + + virtual void AddInstancedTemplate(UFlowAsset* Template); + virtual void RemoveInstancedTemplate(UFlowAsset* Template); public: /* Returns all assets instanced by object from another system like World Settings */ diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 4e2826f17..5b5feb3fa 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -130,7 +130,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte EFlowSignalMode SignalMode; #if WITH_EDITOR - FFlowMessageLog Log; + FFlowMessageLog ValidationLog; #endif ////////////////////////////////////////////////////////////////////////// diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index 623b2f728..9c7b1e3a3 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -47,9 +47,10 @@ const FName FFlowAssetEditor::DetailsTab(TEXT("Details")); const FName FFlowAssetEditor::GraphTab(TEXT("Graph")); -const FName FFlowAssetEditor::MessagesTab(TEXT("Messages")); const FName FFlowAssetEditor::PaletteTab(TEXT("Palette")); +const FName FFlowAssetEditor::RuntimeLogTab(TEXT("RuntimeLog")); const FName FFlowAssetEditor::SearchTab(TEXT("Search")); +const FName FFlowAssetEditor::ValidationLogTab(TEXT("ValidationLog")); FFlowAssetEditor::FFlowAssetEditor() : FlowAsset(nullptr) @@ -124,26 +125,31 @@ void FFlowAssetEditor::RegisterTabSpawners(const TSharedRef& .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.Tabs.Details")); InTabManager->RegisterTabSpawner(GraphTab, FOnSpawnTab::CreateSP(this, &FFlowAssetEditor::SpawnTab_Graph)) - .SetDisplayName(LOCTEXT("GraphTab", "Viewport")) + .SetDisplayName(LOCTEXT("GraphTab", "Graph")) .SetGroup(WorkspaceMenuCategoryRef) .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "GraphEditor.EventGraph_16x")); - - InTabManager->RegisterTabSpawner(MessagesTab, FOnSpawnTab::CreateSP(this, &FFlowAssetEditor::SpawnTab_MessageLog)) - .SetDisplayName(LOCTEXT("MessagesTab", "Messages")) - .SetGroup(WorkspaceMenuCategoryRef) - .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "Kismet.Tabs.CompilerResults")); InTabManager->RegisterTabSpawner(PaletteTab, FOnSpawnTab::CreateSP(this, &FFlowAssetEditor::SpawnTab_Palette)) .SetDisplayName(LOCTEXT("PaletteTab", "Palette")) .SetGroup(WorkspaceMenuCategoryRef) .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "Kismet.Tabs.Palette")); + InTabManager->RegisterTabSpawner(RuntimeLogTab, FOnSpawnTab::CreateSP(this, &FFlowAssetEditor::SpawnTab_RuntimeLog)) + .SetDisplayName(LOCTEXT("RuntimeLog", "RuntimeLog")) + .SetGroup(WorkspaceMenuCategoryRef) + .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "Kismet.Tabs.CompilerResults")); + #if ENABLE_SEARCH_IN_ASSET_EDITOR InTabManager->RegisterTabSpawner(SearchTab, FOnSpawnTab::CreateSP(this, &FFlowAssetEditor::SpawnTab_Search)) .SetDisplayName(LOCTEXT("SearchTab", "Search")) .SetGroup(WorkspaceMenuCategoryRef) .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "Kismet.Tabs.FindResults")); -#endif +#endif + + InTabManager->RegisterTabSpawner(ValidationLogTab, FOnSpawnTab::CreateSP(this, &FFlowAssetEditor::SpawnTab_ValidationLog)) + .SetDisplayName(LOCTEXT("ValidationLog", "Validation Log")) + .SetGroup(WorkspaceMenuCategoryRef) + .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "Kismet.Tabs.CompilerResults")); } void FFlowAssetEditor::UnregisterTabSpawners(const TSharedRef& InTabManager) @@ -152,7 +158,7 @@ void FFlowAssetEditor::UnregisterTabSpawners(const TSharedRef InTabManager->UnregisterTabSpawner(DetailsTab); InTabManager->UnregisterTabSpawner(GraphTab); - InTabManager->UnregisterTabSpawner(MessagesTab); + InTabManager->UnregisterTabSpawner(ValidationLogTab); InTabManager->UnregisterTabSpawner(PaletteTab); #if ENABLE_SEARCH_IN_ASSET_EDITOR InTabManager->UnregisterTabSpawner(SearchTab); @@ -170,23 +176,6 @@ TSharedRef FFlowAssetEditor::SpawnTab_Details(const FSpawnTabArgs& Arg ]; } -#if ENABLE_SEARCH_IN_ASSET_EDITOR -TSharedRef FFlowAssetEditor::SpawnTab_Search(const FSpawnTabArgs& Args) const -{ - check(Args.GetTabId() == SearchTab); - - return SNew(SDockTab) - .Label(LOCTEXT("FlowSearchTitle", "Search")) - [ - SNew(SBox) - .AddMetaData(FTagMetaData(TEXT("FlowSearch"))) - [ - SearchBrowser.ToSharedRef() - ] - ]; -} -#endif - TSharedRef FFlowAssetEditor::SpawnTab_Graph(const FSpawnTabArgs& Args) const { check(Args.GetTabId() == GraphTab); @@ -202,25 +191,53 @@ TSharedRef FFlowAssetEditor::SpawnTab_Graph(const FSpawnTabArgs& Args) return SpawnedTab; } -TSharedRef FFlowAssetEditor::SpawnTab_MessageLog(const FSpawnTabArgs& Args) const +TSharedRef FFlowAssetEditor::SpawnTab_Palette(const FSpawnTabArgs& Args) const { - check(Args.GetTabId() == MessagesTab); + check(Args.GetTabId() == PaletteTab); return SNew(SDockTab) - .Label(LOCTEXT("FlowMessagesTitle", "Messages")) + .Label(LOCTEXT("FlowPaletteTitle", "Palette")) [ - MessageLog.ToSharedRef() + Palette.ToSharedRef() ]; } -TSharedRef FFlowAssetEditor::SpawnTab_Palette(const FSpawnTabArgs& Args) const +TSharedRef FFlowAssetEditor::SpawnTab_RuntimeLog(const FSpawnTabArgs& Args) const { - check(Args.GetTabId() == PaletteTab); + check(Args.GetTabId() == RuntimeLogTab); return SNew(SDockTab) - .Label(LOCTEXT("FlowPaletteTitle", "Palette")) + .Label(LOCTEXT("FlowRuntimeLogTitle", "Runtime Log")) [ - Palette.ToSharedRef() + RuntimeLog.ToSharedRef() + ]; +} + +#if ENABLE_SEARCH_IN_ASSET_EDITOR +TSharedRef FFlowAssetEditor::SpawnTab_Search(const FSpawnTabArgs& Args) const +{ + check(Args.GetTabId() == SearchTab); + + return SNew(SDockTab) + .Label(LOCTEXT("FlowSearchTitle", "Search")) + [ + SNew(SBox) + .AddMetaData(FTagMetaData(TEXT("FlowSearch"))) + [ + SearchBrowser.ToSharedRef() + ] + ]; +} +#endif + +TSharedRef FFlowAssetEditor::SpawnTab_ValidationLog(const FSpawnTabArgs& Args) const +{ + check(Args.GetTabId() == ValidationLogTab); + + return SNew(SDockTab) + .Label(LOCTEXT("FlowValidationLogTitle", "Validation Log")) + [ + ValidationLog.ToSharedRef() ]; } @@ -241,7 +258,10 @@ void FFlowAssetEditor::InitFlowAssetEditor(const EToolkitMode::Type Mode, const BindGraphCommands(); CreateWidgets(); - const TSharedRef StandaloneDefaultLayout = FTabManager::NewLayout("FlowAssetEditor_Layout_v5") + FlowAsset->OnRuntimeMessageAdded().AddSP(this, &FFlowAssetEditor::OnRuntimeMessageAdded); + FEditorDelegates::BeginPIE.AddSP(this, &FFlowAssetEditor::OnBeginPIE); + + const TSharedRef StandaloneDefaultLayout = FTabManager::NewLayout("FlowAssetEditor_Layout_v5.1") ->AddArea ( FTabManager::NewPrimaryArea()->SetOrientation(Orient_Horizontal) @@ -266,15 +286,21 @@ void FFlowAssetEditor::InitFlowAssetEditor(const EToolkitMode::Type Mode, const ->Split ( FTabManager::NewStack() - ->SetSizeCoefficient(0.2f) - ->AddTab(MessagesTab, ETabState::ClosedTab) + ->SetSizeCoefficient(0.15f) + ->AddTab(RuntimeLogTab, ETabState::ClosedTab) ) ->Split ( FTabManager::NewStack() - ->SetSizeCoefficient(0.2f) + ->SetSizeCoefficient(0.15f) ->AddTab(SearchTab, ETabState::ClosedTab) ) + ->Split + ( + FTabManager::NewStack() + ->SetSizeCoefficient(0.15f) + ->AddTab(ValidationLogTab, ETabState::ClosedTab) + ) ) ->Split ( @@ -343,13 +369,13 @@ void FFlowAssetEditor::RefreshAsset() FlowAsset->ValidateAsset(LogResults); // push messages to its window - MessageLogListing->ClearMessages(); + ValidationLogListing->ClearMessages(); if (LogResults.Messages.Num() > 0) { - TabManager->TryInvokeTab(MessagesTab); - MessageLogListing->AddMessages(LogResults.Messages); + TabManager->TryInvokeTab(ValidationLogTab); + ValidationLogListing->AddMessages(LogResults.Messages); } - MessageLogListing->OnDataChanged().Broadcast(); + ValidationLogListing->OnDataChanged().Broadcast(); } #if ENABLE_SEARCH_IN_ASSET_EDITOR @@ -394,14 +420,18 @@ void FFlowAssetEditor::CreateWidgets() #if ENABLE_SEARCH_IN_ASSET_EDITOR SearchBrowser = SNew(SSearchBrowser, GetFlowAsset()); -#endif +#endif + FMessageLogModule& MessageLogModule = FModuleManager::LoadModuleChecked("MessageLog"); { - MessageLogListing = FFlowMessageLogListing::GetLogListing(FlowAsset); - MessageLogListing->OnMessageTokenClicked().AddSP(this, &FFlowAssetEditor::OnLogTokenClicked); - - FMessageLogModule& MessageLogModule = FModuleManager::LoadModuleChecked("MessageLog"); - MessageLog = MessageLogModule.CreateLogListingWidget(MessageLogListing.ToSharedRef()); + RuntimeLogListing = FFlowMessageLogListing::GetLogListing(FlowAsset, EFlowLogType::Runtime); + RuntimeLogListing->OnMessageTokenClicked().AddSP(this, &FFlowAssetEditor::OnLogTokenClicked); + RuntimeLog = MessageLogModule.CreateLogListingWidget(RuntimeLogListing.ToSharedRef()); + } + { + ValidationLogListing = FFlowMessageLogListing::GetLogListing(FlowAsset, EFlowLogType::Validation); + ValidationLogListing->OnMessageTokenClicked().AddSP(this, &FFlowAssetEditor::OnLogTokenClicked); + ValidationLog = MessageLogModule.CreateLogListingWidget(ValidationLogListing.ToSharedRef()); } } @@ -698,6 +728,11 @@ EVisibility FFlowAssetEditor::GetDebuggerVisibility() return GEditor->PlayWorld ? EVisibility::Visible : EVisibility::Collapsed; } +void FFlowAssetEditor::OnBeginPIE(const bool bInSimulateInEditor) const +{ + RuntimeLogListing->ClearMessages(); +} + TSet FFlowAssetEditor::GetSelectedFlowNodes() const { TSet Result; @@ -772,6 +807,14 @@ void FFlowAssetEditor::JumpToInnerObject(UObject* InnerObject) } #endif +void FFlowAssetEditor::OnRuntimeMessageAdded(const UFlowAsset* AssetInstance, const TSharedRef& Message) const +{ + // push messages to its window + TabManager->TryInvokeTab(RuntimeLogTab); + RuntimeLogListing->AddMessage(Message); + RuntimeLogListing->OnDataChanged().Broadcast(); +} + void FFlowAssetEditor::OnLogTokenClicked(const TSharedRef& Token) const { if (Token->GetType() == EMessageToken::Object) diff --git a/Source/FlowEditor/Private/Asset/FlowMessageLogListing.cpp b/Source/FlowEditor/Private/Asset/FlowMessageLogListing.cpp index 516630d1d..ce4d264f7 100644 --- a/Source/FlowEditor/Private/Asset/FlowMessageLogListing.cpp +++ b/Source/FlowEditor/Private/Asset/FlowMessageLogListing.cpp @@ -6,8 +6,8 @@ #define LOCTEXT_NAMESPACE "FlowMessageLogListing" -FFlowMessageLogListing::FFlowMessageLogListing(const UFlowAsset* InFlowAsset) - : Log(RegisterLogListing(InFlowAsset)) +FFlowMessageLogListing::FFlowMessageLogListing(const UFlowAsset* InFlowAsset, const EFlowLogType Type) + : Log(RegisterLogListing(InFlowAsset, Type)) { } @@ -21,11 +21,11 @@ FFlowMessageLogListing::~FFlowMessageLogListing() } } -TSharedRef FFlowMessageLogListing::RegisterLogListing(const UFlowAsset* InFlowAsset) +TSharedRef FFlowMessageLogListing::RegisterLogListing(const UFlowAsset* InFlowAsset, const EFlowLogType Type) { FMessageLogModule& MessageLogModule = FModuleManager::LoadModuleChecked("MessageLog"); - const FName LogName = GetListingName(InFlowAsset); + const FName LogName = GetListingName(InFlowAsset, Type); // Register the log (this will return an existing log if it has been used before) FMessageLogInitializationOptions LogInitOptions; @@ -34,11 +34,11 @@ TSharedRef FFlowMessageLogListing::RegisterLogListing(const return MessageLogModule.GetLogListing(LogName); } -TSharedRef FFlowMessageLogListing::GetLogListing(const UFlowAsset* InFlowAsset) +TSharedRef FFlowMessageLogListing::GetLogListing(const UFlowAsset* InFlowAsset, const EFlowLogType Type) { FMessageLogModule& MessageLogModule = FModuleManager::LoadModuleChecked("MessageLog"); - const FName LogName = GetListingName(InFlowAsset); + const FName LogName = GetListingName(InFlowAsset, Type); // Reuse any existing log, or create a new one (that is not held onto bey the message log system) if(MessageLogModule.IsRegisteredLogListing(LogName)) @@ -53,12 +53,13 @@ TSharedRef FFlowMessageLogListing::GetLogListing(const UFlow } } -FName FFlowMessageLogListing::GetListingName(const UFlowAsset* InFlowAsset) +FName FFlowMessageLogListing::GetListingName(const UFlowAsset* InFlowAsset, const EFlowLogType Type) { FName LogListingName; if (InFlowAsset) { - LogListingName = *FString::Printf(TEXT("%s_%s_FlowMessageLog"), *InFlowAsset->AssetGuid.ToString(), *InFlowAsset->GetName()); + const FString TypeAsString = StaticEnum()->GetNameStringByIndex(static_cast(Type)); + LogListingName = *FString::Printf(TEXT("FlowLog_%s_%s_%s_"), *TypeAsString, *InFlowAsset->AssetGuid.ToString(), *InFlowAsset->GetName()); } else { diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp index 45be63c0f..cc1ce6da5 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp @@ -359,10 +359,10 @@ void SFlowGraphNode::UpdateErrorInfo() { if (const UFlowNode* FlowNode = FlowGraphNode->GetFlowNode()) { - if (FlowNode->Log.Messages.Num() > 0) + if (FlowNode->ValidationLog.Messages.Num() > 0) { EMessageSeverity::Type MaxSeverity = EMessageSeverity::Info; - for (const TSharedRef& Message : FlowNode->Log.Messages) + for (const TSharedRef& Message : FlowNode->ValidationLog.Messages) { if (Message->GetSeverity() < MaxSeverity) { diff --git a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h index c08b218e1..58ea65282 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h @@ -36,21 +36,27 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit TSharedPtr GraphEditor; TSharedPtr DetailsView; TSharedPtr Palette; + #if ENABLE_SEARCH_IN_ASSET_EDITOR TSharedPtr SearchBrowser; #endif - /** Message log, with the log listing that it reflects */ - TSharedPtr MessageLog; - TSharedPtr MessageLogListing; + /** Runtime message log, with the log listing that it reflects */ + TSharedPtr RuntimeLog; + TSharedPtr RuntimeLogListing; + + /** Asset Validation message log, with the log listing that it reflects */ + TSharedPtr ValidationLog; + TSharedPtr ValidationLogListing; public: /** The tab ids for all the tabs used */ static const FName DetailsTab; static const FName GraphTab; - static const FName MessagesTab; static const FName PaletteTab; + static const FName RuntimeLogTab; static const FName SearchTab; + static const FName ValidationLogTab; private: /** The current UI selection state of this editor */ @@ -95,11 +101,12 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit private: TSharedRef SpawnTab_Details(const FSpawnTabArgs& Args) const; TSharedRef SpawnTab_Graph(const FSpawnTabArgs& Args) const; - TSharedRef SpawnTab_MessageLog(const FSpawnTabArgs& Args) const; TSharedRef SpawnTab_Palette(const FSpawnTabArgs& Args) const; + TSharedRef SpawnTab_RuntimeLog(const FSpawnTabArgs& Args) const; #if ENABLE_SEARCH_IN_ASSET_EDITOR TSharedRef SpawnTab_Search(const FSpawnTabArgs& Args) const; #endif + TSharedRef SpawnTab_ValidationLog(const FSpawnTabArgs& Args) const; public: /** Edits the specified FlowAsset object */ @@ -107,9 +114,10 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit protected: virtual void CreateToolbar(); - virtual void BindToolbarCommands(); + virtual void RefreshAsset(); + #if ENABLE_SEARCH_IN_ASSET_EDITOR virtual void SearchInAsset(); #endif @@ -147,6 +155,8 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit static bool IsPIE(); static EVisibility GetDebuggerVisibility(); + void OnBeginPIE(const bool bInSimulateInEditor) const; + TSet GetSelectedFlowNodes() const; int32 GetNumberOfSelectedNodes() const; bool GetBoundsForSelectedNodes(class FSlateRect& Rect, float Padding) const; @@ -164,6 +174,7 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit #endif protected: + void OnRuntimeMessageAdded(const UFlowAsset* AssetInstance, const TSharedRef& Message) const; void OnLogTokenClicked(const TSharedRef& Token) const; virtual void SelectAllNodes() const; diff --git a/Source/FlowEditor/Public/Asset/FlowMessageLogListing.h b/Source/FlowEditor/Public/Asset/FlowMessageLogListing.h index b9935e8b1..5651f25c3 100644 --- a/Source/FlowEditor/Public/Asset/FlowMessageLogListing.h +++ b/Source/FlowEditor/Public/Asset/FlowMessageLogListing.h @@ -6,6 +6,13 @@ #include "FlowAsset.h" +UENUM() +enum class EFlowLogType : uint8 +{ + Runtime, + Validation +}; + /** * Scope wrapper for the message log. Ensures we don't leak logs that we dont need (i.e. those that have no messages) * Replicated after FScopedBlueprintMessageLog @@ -13,7 +20,7 @@ class FLOWEDITOR_API FFlowMessageLogListing { public: - FFlowMessageLogListing(const UFlowAsset* InFlowAsset); + FFlowMessageLogListing(const UFlowAsset* InFlowAsset, const EFlowLogType Type); ~FFlowMessageLogListing(); public: @@ -21,9 +28,9 @@ class FLOWEDITOR_API FFlowMessageLogListing FName LogName; private: - static TSharedRef RegisterLogListing(const UFlowAsset* InFlowAsset); - static FName GetListingName(const UFlowAsset* InFlowAsset); + static TSharedRef RegisterLogListing(const UFlowAsset* InFlowAsset, const EFlowLogType Type); + static FName GetListingName(const UFlowAsset* InFlowAsset, const EFlowLogType Type); public: - static TSharedRef GetLogListing(const UFlowAsset* InFlowAsset); + static TSharedRef GetLogListing(const UFlowAsset* InFlowAsset, const EFlowLogType Type); }; From a5cb74c3ac8baab8f7cf9b1e009a89387776d555 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Wed, 18 Jan 2023 00:37:05 +0100 Subject: [PATCH 247/338] non-editor build fix --- Source/Flow/Private/FlowSubsystem.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index a40defd61..4913040c8 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -223,13 +223,19 @@ void UFlowSubsystem::AddInstancedTemplate(UFlowAsset* Template) if (!InstancedTemplates.Contains(Template)) { InstancedTemplates.Add(Template); + +#if WITH_EDITOR Template->RuntimeLog = MakeShareable(new FFlowMessageLog()); +#endif } } void UFlowSubsystem::RemoveInstancedTemplate(UFlowAsset* Template) { +#if WITH_EDITOR Template->RuntimeLog.Reset(); +#endif + InstancedTemplates.Remove(Template); } From 3f7f1f162f55dda59b1d11af1f6c61eb7d5aeb6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 5 Feb 2023 17:41:47 +0100 Subject: [PATCH 248/338] fixed debugging toolbar not working in per-asset context --- .../Private/Asset/FlowAssetEditor.cpp | 10 ++++ .../Private/Asset/FlowAssetEditorContext.cpp | 9 +++ .../Private/Asset/FlowAssetToolbar.cpp | 59 ++++++++++--------- .../FlowEditor/Public/Asset/FlowAssetEditor.h | 6 +- .../Public/Asset/FlowAssetEditorContext.h | 21 +++++++ .../Public/Asset/FlowAssetToolbar.h | 14 ++--- 6 files changed, 79 insertions(+), 40 deletions(-) create mode 100644 Source/FlowEditor/Private/Asset/FlowAssetEditorContext.cpp create mode 100644 Source/FlowEditor/Public/Asset/FlowAssetEditorContext.h diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index 9c7b1e3a3..5fee880e9 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -6,6 +6,7 @@ #include "FlowEditorModule.h" #include "FlowMessageLog.h" +#include "Asset/FlowAssetEditorContext.h" #include "Asset/FlowAssetToolbar.h" #include "Asset/FlowDebugger.h" #include "Asset/FlowMessageLogListing.h" @@ -165,6 +166,15 @@ void FFlowAssetEditor::UnregisterTabSpawners(const TSharedRef #endif } +void FFlowAssetEditor::InitToolMenuContext(FToolMenuContext& MenuContext) +{ + FAssetEditorToolkit::InitToolMenuContext(MenuContext); + + UFlowAssetEditorContext* Context = NewObject(); + Context->FlowAssetEditor = SharedThis(this); + MenuContext.AddObject(Context); +} + TSharedRef FFlowAssetEditor::SpawnTab_Details(const FSpawnTabArgs& Args) const { check(Args.GetTabId() == DetailsTab); diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditorContext.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditorContext.cpp new file mode 100644 index 000000000..0d5501ddf --- /dev/null +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditorContext.cpp @@ -0,0 +1,9 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#include "Asset/FlowAssetEditorContext.h" +#include "Asset/FlowAssetEditor.h" + +UFlowAsset* UFlowAssetEditorContext::GetFlowAsset() const +{ + return FlowAssetEditor.IsValid() ? FlowAssetEditor.Pin()->GetFlowAsset() : nullptr; +} diff --git a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp index 32c1d8e93..88a03a5cd 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp @@ -3,6 +3,7 @@ #include "Asset/FlowAssetToolbar.h" #include "Asset/FlowAssetEditor.h" +#include "Asset/FlowAssetEditorContext.h" #include "Asset/SAssetRevisionMenu.h" #include "FlowEditorCommands.h" #include "FlowEditorDefines.h" @@ -47,10 +48,10 @@ void SFlowAssetInstanceList::Construct(const FArguments& InArgs, const TWeakObje .OnGenerateWidget(this, &SFlowAssetInstanceList::OnGenerateWidget) .OnSelectionChanged(this, &SFlowAssetInstanceList::OnSelectionChanged) .Visibility_Static(&FFlowAssetEditor::GetDebuggerVisibility) - [ - SNew(STextBlock) - .Text(this, &SFlowAssetInstanceList::GetSelectedInstanceName) - ]; + [ + SNew(STextBlock) + .Text(this, &SFlowAssetInstanceList::GetSelectedInstanceName) + ]; ChildSlot [ @@ -136,10 +137,10 @@ void SFlowAssetBreadcrumb::Construct(const FArguments& InArgs, const TWeakObject [ SNew(SVerticalBox) + SVerticalBox::Slot() - .HAlign(HAlign_Right) - .VAlign(VAlign_Center) - .AutoHeight() - .Padding(25.0f, 10.0f) + .HAlign(HAlign_Right) + .VAlign(VAlign_Center) + .AutoHeight() + .Padding(25.0f, 10.0f) [ BreadcrumbTrail.ToSharedRef() ] @@ -149,7 +150,7 @@ void SFlowAssetBreadcrumb::Construct(const FArguments& InArgs, const TWeakObject BreadcrumbTrail->ClearCrumbs(); if (UFlowAsset* InspectedInstance = TemplateAsset->GetInspectedInstance()) { - TArray InstancesFromRoot = {InspectedInstance}; + TArray> InstancesFromRoot = {InspectedInstance}; const UFlowAsset* CheckedInstance = InspectedInstance; while (UFlowAsset* ParentInstance = CheckedInstance->GetParentInstance()) @@ -158,23 +159,21 @@ void SFlowAssetBreadcrumb::Construct(const FArguments& InArgs, const TWeakObject CheckedInstance = ParentInstance; } - for (UFlowAsset* Instance : InstancesFromRoot) + for (TWeakObjectPtr Instance : InstancesFromRoot) { - TAttribute CrumbText = MakeAttributeLambda([Instance]() + if (Instance.IsValid()) { - return Instance ? FText::FromName(Instance->GetDisplayName()) : FText(); - }); - - BreadcrumbTrail->PushCrumb(CrumbText, FFlowBreadcrumb(Instance)); + const FFlowBreadcrumb NewBreadcrumb = FFlowBreadcrumb(Instance); + BreadcrumbTrail->PushCrumb(FText::FromName(NewBreadcrumb.InstanceName), FFlowBreadcrumb(Instance)); + } } } } void SFlowAssetBreadcrumb::OnCrumbClicked(const FFlowBreadcrumb& Item) const { - ensure(TemplateAsset->GetInspectedInstance()); - - if (Item.InstanceName != TemplateAsset->GetInspectedInstance()->GetDisplayName()) + const UFlowAsset* InspectedInstance = TemplateAsset->GetInspectedInstance(); + if (InspectedInstance == nullptr || Item.InstanceName != InspectedInstance->GetDisplayName()) { GEditor->GetEditorSubsystem()->OpenEditorForAsset(Item.AssetPathName); } @@ -199,7 +198,7 @@ void FFlowAssetToolbar::BuildAssetToolbar(UToolMenu* ToolbarMenu) const Section.AddEntry(FToolMenuEntry::InitToolBarButton(FFlowToolbarCommands::Get().RefreshAsset)); #if ENABLE_SEARCH_IN_ASSET_EDITOR Section.AddEntry(FToolMenuEntry::InitToolBarButton(FFlowToolbarCommands::Get().SearchInAsset)); -#endif +#endif #if ENABLE_FLOW_DIFF // Visual Diff: menu to choose asset revision compared with the current one @@ -294,22 +293,24 @@ TSharedRef FFlowAssetToolbar::MakeDiffMenu() const return MenuBuilder.MakeWidget(); } -void FFlowAssetToolbar::BuildDebuggerToolbar(UToolMenu* ToolbarMenu) +void FFlowAssetToolbar::BuildDebuggerToolbar(UToolMenu* ToolbarMenu) const { FToolMenuSection& Section = ToolbarMenu->AddSection("Debugging"); Section.InsertPosition = FToolMenuInsert("Asset", EToolMenuInsertType::After); - FPlayWorldCommands::BuildToolbar(Section); - - TWeakObjectPtr TemplateAsset = FlowAssetEditor.Pin()->GetFlowAsset(); - - AssetInstanceList = SNew(SFlowAssetInstanceList, TemplateAsset); - Section.AddEntry(FToolMenuEntry::InitWidget("AssetInstances", AssetInstanceList.ToSharedRef(), FText(), true)); + Section.AddDynamicEntry("DebuggingCommands", FNewToolMenuSectionDelegate::CreateLambda([](FToolMenuSection& InSection) + { + const UFlowAssetEditorContext* Context = InSection.FindContext(); + if (Context && Context->GetFlowAsset()) + { + FPlayWorldCommands::BuildToolbar(InSection); - Section.AddEntry(FToolMenuEntry::InitToolBarButton(FFlowToolbarCommands::Get().GoToParentInstance)); + InSection.AddEntry(FToolMenuEntry::InitWidget("AssetInstances", SNew(SFlowAssetInstanceList, Context->GetFlowAsset()), FText(), true)); - Breadcrumb = SNew(SFlowAssetBreadcrumb, TemplateAsset); - Section.AddEntry(FToolMenuEntry::InitWidget("AssetBreadcrumb", Breadcrumb.ToSharedRef(), FText(), true)); + InSection.AddEntry(FToolMenuEntry::InitToolBarButton(FFlowToolbarCommands::Get().GoToParentInstance)); + InSection.AddEntry(FToolMenuEntry::InitWidget("AssetBreadcrumb", SNew(SFlowAssetBreadcrumb, Context->GetFlowAsset()), FText(), true)); + } + })); } #undef LOCTEXT_NAMESPACE diff --git a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h index 58ea65282..04d3b3cdf 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h @@ -66,7 +66,7 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit FFlowAssetEditor(); virtual ~FFlowAssetEditor() override; - UFlowAsset* GetFlowAsset() const { return FlowAsset; }; + UFlowAsset* GetFlowAsset() const { return FlowAsset; } // FGCObject virtual void AddReferencedObjects(FReferenceCollector& Collector) override; @@ -98,6 +98,10 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit virtual void UnregisterTabSpawners(const TSharedRef& TabManager) override; // -- + // FAssetEditorToolkit + virtual void InitToolMenuContext(FToolMenuContext& MenuContext) override; + // -- + private: TSharedRef SpawnTab_Details(const FSpawnTabArgs& Args) const; TSharedRef SpawnTab_Graph(const FSpawnTabArgs& Args) const; diff --git a/Source/FlowEditor/Public/Asset/FlowAssetEditorContext.h b/Source/FlowEditor/Public/Asset/FlowAssetEditorContext.h new file mode 100644 index 000000000..f26d03ca4 --- /dev/null +++ b/Source/FlowEditor/Public/Asset/FlowAssetEditorContext.h @@ -0,0 +1,21 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#pragma once + +#include "CoreMinimal.h" +#include "FlowAssetEditorContext.generated.h" + +class UFlowAsset; +class FFlowAssetEditor; + +UCLASS() +class FLOWEDITOR_API UFlowAssetEditorContext : public UObject +{ + GENERATED_BODY() + +public: + UFUNCTION(BlueprintCallable, Category="Tool Menus") + UFlowAsset* GetFlowAsset() const; + + TWeakPtr FlowAssetEditor; +}; diff --git a/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h b/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h index 1e646f2d4..82dd7844a 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h @@ -45,15 +45,15 @@ class FLOWEDITOR_API SFlowAssetInstanceList : public SCompoundWidget */ struct FLOWEDITOR_API FFlowBreadcrumb { - FString AssetPathName; - FName InstanceName; + const FString AssetPathName; + const FName InstanceName; FFlowBreadcrumb() : AssetPathName(FString()) , InstanceName(NAME_None) {} - FFlowBreadcrumb(const UFlowAsset* FlowAsset) + explicit FFlowBreadcrumb(const TWeakObjectPtr FlowAsset) : AssetPathName(FlowAsset->GetTemplateAsset()->GetPathName()) , InstanceName(FlowAsset->GetDisplayName()) {} @@ -86,14 +86,8 @@ class FLOWEDITOR_API FFlowAssetToolbar : public TSharedFromThis MakeDiffMenu() const; - void BuildDebuggerToolbar(UToolMenu* ToolbarMenu); - -public: - TSharedPtr GetAssetInstanceList() const { return AssetInstanceList; } + void BuildDebuggerToolbar(UToolMenu* ToolbarMenu) const; private: TWeakPtr FlowAssetEditor; - - TSharedPtr AssetInstanceList; - TSharedPtr Breadcrumb; }; From 1501beb44ac80e0bca40139a5f36e21b11c44875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 12 Feb 2023 15:29:29 +0100 Subject: [PATCH 249/338] fixed crash on exiting game, reported by community --- Source/Flow/Private/Nodes/FlowNode.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 86b50f59d..64b92810f 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -407,7 +407,7 @@ void UFlowNode::TriggerInput(const FName& PinName, const EFlowPinActivationType #endif // UE_BUILD_SHIPPING #if WITH_EDITOR - if (GetWorld()->WorldType == EWorldType::PIE && UFlowAsset::GetFlowGraphInterface().IsValid()) + if (GEditor && UFlowAsset::GetFlowGraphInterface().IsValid()) { UFlowAsset::GetFlowGraphInterface()->OnInputTriggered(GraphNode, InputPins.IndexOfByKey(PinName)); } @@ -466,7 +466,7 @@ void UFlowNode::TriggerOutput(const FName& PinName, const bool bFinish /*= false Records.Add(FPinRecord(FApp::GetCurrentTime(), ActivationType)); #if WITH_EDITOR - if (GetWorld()->WorldType == EWorldType::PIE && UFlowAsset::GetFlowGraphInterface().IsValid()) + if (GEditor && UFlowAsset::GetFlowGraphInterface().IsValid()) { UFlowAsset::GetFlowGraphInterface()->OnOutputTriggered(GraphNode, OutputPins.IndexOfByKey(PinName)); } From a3b3168a501b2c99d5aaff32757da578aaf98bc9 Mon Sep 17 00:00:00 2001 From: Bohdon Sayre Date: Sun, 12 Feb 2023 12:45:49 -0500 Subject: [PATCH 250/338] add bExactMatch option to Notify Actor flow node --- Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp | 3 ++- Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp b/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp index 7340e5896..dd3303c7b 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp @@ -8,6 +8,7 @@ UFlowNode_NotifyActor::UFlowNode_NotifyActor(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) + , bExactMatch(true) , NetMode(EFlowNetMode::Authority) { #if WITH_EDITOR @@ -19,7 +20,7 @@ void UFlowNode_NotifyActor::ExecuteInput(const FName& PinName) { if (const UFlowSubsystem* FlowSubsystem = GetWorld()->GetGameInstance()->GetSubsystem()) { - for (const TWeakObjectPtr& Component : FlowSubsystem->GetComponents(IdentityTags, EGameplayContainerMatchType::Any)) + for (const TWeakObjectPtr& Component : FlowSubsystem->GetComponents(IdentityTags, EGameplayContainerMatchType::Any, bExactMatch)) { Component->NotifyFromGraph(NotifyTags, NetMode); } diff --git a/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h b/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h index 74219765b..63f3e8c37 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h @@ -18,6 +18,14 @@ class FLOW_API UFlowNode_NotifyActor : public UFlowNode protected: UPROPERTY(EditAnywhere, Category = "Notify") FGameplayTagContainer IdentityTags; + + /** + * If true, identity tags must be an exact match. + * Be careful, setting this to false may be very expensive, as the + * search cost is proportional to the number of registered Gameplay Tags! + */ + UPROPERTY(EditAnywhere, Category = "Notify") + bool bExactMatch; UPROPERTY(EditAnywhere, Category = "Notify") FGameplayTagContainer NotifyTags; From e1f210a3108fa5b304d4b83e77a108fa0d2f1c8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 12 Feb 2023 23:11:24 +0100 Subject: [PATCH 251/338] Merge pull request #133 from bohdon/feature-notify-actor-inexact add bExactMatch option to Notify Actor flow node From 4bf4573704773b799144b803a84df87702d753ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Mon, 13 Feb 2023 22:13:21 +0100 Subject: [PATCH 252/338] added separate Validate toolbar action calling it together with Refresh action was always dirtying asset, and we don't want that for a validation --- Source/Flow/Private/FlowAsset.cpp | 6 -- Source/Flow/Public/FlowAsset.h | 2 - .../Private/Asset/FlowAssetEditor.cpp | 16 +++++- .../Private/Asset/FlowAssetToolbar.cpp | 55 +++++++++++-------- .../FlowEditor/Private/FlowEditorCommands.cpp | 4 +- Source/FlowEditor/Private/FlowEditorStyle.cpp | 2 + Source/FlowEditor/Private/Graph/FlowGraph.cpp | 5 -- .../FlowEditor/Public/Asset/FlowAssetEditor.h | 1 + Source/FlowEditor/Public/FlowEditorCommands.h | 2 + Source/FlowEditor/Public/Graph/FlowGraph.h | 2 - 10 files changed, 53 insertions(+), 42 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 7f3be67f2..0eaaa3e58 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -66,12 +66,6 @@ void UFlowAsset::PostDuplicate(bool bDuplicateForPIE) EDataValidationResult UFlowAsset::ValidateAsset(FFlowMessageLog& MessageLog) { - // first attempt to refresh graph, fix common issues automatically - if (GetFlowGraphInterface().IsValid()) - { - GetFlowGraphInterface()->RefreshGraph(this); - } - // validate nodes for (const TPair& Node : Nodes) { diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 21e4008ab..ab8e78e0b 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -26,8 +26,6 @@ class FLOW_API IFlowGraphInterface IFlowGraphInterface() {} virtual ~IFlowGraphInterface() {} - virtual void RefreshGraph(UFlowAsset* FlowAsset) {} - virtual void OnInputTriggered(UEdGraphNode* GraphNode, const int32 Index) const {} virtual void OnOutputTriggered(UEdGraphNode* GraphNode, const int32 Index) const {} }; diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index 5fee880e9..b8100d921 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -10,6 +10,7 @@ #include "Asset/FlowAssetToolbar.h" #include "Asset/FlowDebugger.h" #include "Asset/FlowMessageLogListing.h" +#include "Graph/FlowGraph.h" #include "Graph/FlowGraphEditorSettings.h" #include "Graph/FlowGraphSchema.h" #include "Graph/FlowGraphSchema_Actions.h" @@ -136,7 +137,7 @@ void FFlowAssetEditor::RegisterTabSpawners(const TSharedRef& .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "Kismet.Tabs.Palette")); InTabManager->RegisterTabSpawner(RuntimeLogTab, FOnSpawnTab::CreateSP(this, &FFlowAssetEditor::SpawnTab_RuntimeLog)) - .SetDisplayName(LOCTEXT("RuntimeLog", "RuntimeLog")) + .SetDisplayName(LOCTEXT("RuntimeLog", "Runtime Log")) .SetGroup(WorkspaceMenuCategoryRef) .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "Kismet.Tabs.CompilerResults")); @@ -150,7 +151,7 @@ void FFlowAssetEditor::RegisterTabSpawners(const TSharedRef& InTabManager->RegisterTabSpawner(ValidationLogTab, FOnSpawnTab::CreateSP(this, &FFlowAssetEditor::SpawnTab_ValidationLog)) .SetDisplayName(LOCTEXT("ValidationLog", "Validation Log")) .SetGroup(WorkspaceMenuCategoryRef) - .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "Kismet.Tabs.CompilerResults")); + .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "Debug")); } void FFlowAssetEditor::UnregisterTabSpawners(const TSharedRef& InTabManager) @@ -355,6 +356,10 @@ void FFlowAssetEditor::BindToolbarCommands() FExecuteAction::CreateSP(this, &FFlowAssetEditor::RefreshAsset), FCanExecuteAction::CreateStatic(&FFlowAssetEditor::CanEdit)); + ToolkitCommands->MapAction(ToolbarCommands.ValidateAsset, + FExecuteAction::CreateSP(this, &FFlowAssetEditor::ValidateAsset), + FCanExecuteAction()); + #if ENABLE_SEARCH_IN_ASSET_EDITOR ToolkitCommands->MapAction(ToolbarCommands.SearchInAsset, FExecuteAction::CreateSP(this, &FFlowAssetEditor::SearchInAsset), @@ -374,7 +379,12 @@ void FFlowAssetEditor::BindToolbarCommands() void FFlowAssetEditor::RefreshAsset() { - // Refresh and validate asset, including graph + // attempt to refresh graph, fix common issues automatically + CastChecked(FlowAsset->GetGraph())->RefreshGraph(); +} + +void FFlowAssetEditor::ValidateAsset() +{ FFlowMessageLog LogResults; FlowAsset->ValidateAsset(LogResults); diff --git a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp index 88a03a5cd..1ac8d58fe 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp @@ -191,32 +191,41 @@ FFlowAssetToolbar::FFlowAssetToolbar(const TSharedPtr InAssetE void FFlowAssetToolbar::BuildAssetToolbar(UToolMenu* ToolbarMenu) const { - FToolMenuSection& Section = ToolbarMenu->AddSection("Editing"); - Section.InsertPosition = FToolMenuInsert("Asset", EToolMenuInsertType::After); + { + FToolMenuSection& Section = ToolbarMenu->AddSection("FlowAsset"); + Section.InsertPosition = FToolMenuInsert("Asset", EToolMenuInsertType::After); + + // add buttons + Section.AddEntry(FToolMenuEntry::InitToolBarButton(FFlowToolbarCommands::Get().RefreshAsset)); + Section.AddEntry(FToolMenuEntry::InitToolBarButton(FFlowToolbarCommands::Get().ValidateAsset)); + } + + { + FToolMenuSection& Section = ToolbarMenu->AddSection("View"); + Section.InsertPosition = FToolMenuInsert("FlowAsset", EToolMenuInsertType::After); - // add buttons - Section.AddEntry(FToolMenuEntry::InitToolBarButton(FFlowToolbarCommands::Get().RefreshAsset)); #if ENABLE_SEARCH_IN_ASSET_EDITOR - Section.AddEntry(FToolMenuEntry::InitToolBarButton(FFlowToolbarCommands::Get().SearchInAsset)); + Section.AddEntry(FToolMenuEntry::InitToolBarButton(FFlowToolbarCommands::Get().SearchInAsset)); #endif #if ENABLE_FLOW_DIFF - // Visual Diff: menu to choose asset revision compared with the current one - Section.AddDynamicEntry("SourceControlCommands", FNewToolMenuSectionDelegate::CreateLambda([this](FToolMenuSection& InSection) - { - InSection.InsertPosition = FToolMenuInsert(); - FToolMenuEntry DiffEntry = FToolMenuEntry::InitComboButton( - "Diff", - FUIAction(), - FOnGetContent::CreateRaw(this, &FFlowAssetToolbar::MakeDiffMenu), - LOCTEXT("Diff", "Diff"), - LOCTEXT("FlowAssetEditorDiffToolTip", "Diff against previous revisions"), - FSlateIcon(FAppStyle::Get().GetStyleSetName(), "BlueprintDiff.ToolbarIcon") - ); - DiffEntry.StyleNameOverride = "CalloutToolbar"; - InSection.AddEntry(DiffEntry); - })); -#endif + // Visual Diff: menu to choose asset revision compared with the current one + Section.AddDynamicEntry("SourceControlCommands", FNewToolMenuSectionDelegate::CreateLambda([this](FToolMenuSection& InSection) + { + InSection.InsertPosition = FToolMenuInsert(); + FToolMenuEntry DiffEntry = FToolMenuEntry::InitComboButton( + "Diff", + FUIAction(), + FOnGetContent::CreateRaw(this, &FFlowAssetToolbar::MakeDiffMenu), + LOCTEXT("Diff", "Diff"), + LOCTEXT("FlowAssetEditorDiffToolTip", "Diff against previous revisions"), + FSlateIcon(FAppStyle::Get().GetStyleSetName(), "BlueprintDiff.ToolbarIcon") + ); + DiffEntry.StyleNameOverride = "CalloutToolbar"; + InSection.AddEntry(DiffEntry); + })); + } +#endif } /** Delegate called to diff a specific revision with the current */ @@ -295,8 +304,8 @@ TSharedRef FFlowAssetToolbar::MakeDiffMenu() const void FFlowAssetToolbar::BuildDebuggerToolbar(UToolMenu* ToolbarMenu) const { - FToolMenuSection& Section = ToolbarMenu->AddSection("Debugging"); - Section.InsertPosition = FToolMenuInsert("Asset", EToolMenuInsertType::After); + FToolMenuSection& Section = ToolbarMenu->AddSection("Debug"); + Section.InsertPosition = FToolMenuInsert("View", EToolMenuInsertType::After); Section.AddDynamicEntry("DebuggingCommands", FNewToolMenuSectionDelegate::CreateLambda([](FToolMenuSection& InSection) { diff --git a/Source/FlowEditor/Private/FlowEditorCommands.cpp b/Source/FlowEditor/Private/FlowEditorCommands.cpp index b2eca30fb..033bc3767 100644 --- a/Source/FlowEditor/Private/FlowEditorCommands.cpp +++ b/Source/FlowEditor/Private/FlowEditorCommands.cpp @@ -20,7 +20,9 @@ FFlowToolbarCommands::FFlowToolbarCommands() void FFlowToolbarCommands::RegisterCommands() { UI_COMMAND(RefreshAsset, "Refresh", "Refresh asset and all nodes", EUserInterfaceActionType::Button, FInputChord()); - UI_COMMAND(SearchInAsset, "Search", "Search in the current Flow Graph", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Control | EModifierKey::Shift, EKeys::F) ); + UI_COMMAND(ValidateAsset, "Validate", "Validate asset and all nodes", EUserInterfaceActionType::Button, FInputChord()); + + UI_COMMAND(SearchInAsset, "Search", "Search in the current Flow Graph", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Control | EModifierKey::Shift, EKeys::F)); UI_COMMAND(GoToParentInstance, "Go To Parent", "Open editor for the Flow Asset that created this Flow instance", EUserInterfaceActionType::Button, FInputChord()); } diff --git a/Source/FlowEditor/Private/FlowEditorStyle.cpp b/Source/FlowEditor/Private/FlowEditorStyle.cpp index 98bd0cd70..19d331783 100644 --- a/Source/FlowEditor/Private/FlowEditorStyle.cpp +++ b/Source/FlowEditor/Private/FlowEditorStyle.cpp @@ -32,6 +32,8 @@ void FFlowEditorStyle::Initialize() StyleSet->SetContentRoot(FPaths::EngineContentDir() / TEXT("Editor/Slate/")); StyleSet->Set("FlowToolbar.RefreshAsset", new IMAGE_BRUSH_SVG( "Starship/Common/Apply", Icon20)); + StyleSet->Set("FlowToolbar.ValidateAsset", new IMAGE_BRUSH_SVG( "Starship/Common/Debug", Icon20)); + StyleSet->Set("FlowToolbar.SearchInAsset", new IMAGE_BRUSH_SVG( "Starship/Common/Search", Icon20)); StyleSet->Set("FlowToolbar.GoToParentInstance", new IMAGE_BRUSH("Icons/icon_DebugStepOut_40x", Icon40)); diff --git a/Source/FlowEditor/Private/Graph/FlowGraph.cpp b/Source/FlowEditor/Private/Graph/FlowGraph.cpp index 93626cedb..b83c18312 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraph.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraph.cpp @@ -9,11 +9,6 @@ #include "Kismet2/BlueprintEditorUtils.h" -void FFlowGraphInterface::RefreshGraph(UFlowAsset* FlowAsset) -{ - CastChecked(FlowAsset->GetGraph())->RefreshGraph(); -} - void FFlowGraphInterface::OnInputTriggered(UEdGraphNode* GraphNode, const int32 Index) const { CastChecked(GraphNode)->OnInputTriggered(Index); diff --git a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h index 04d3b3cdf..6fd99566d 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h @@ -121,6 +121,7 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit virtual void BindToolbarCommands(); virtual void RefreshAsset(); + virtual void ValidateAsset(); #if ENABLE_SEARCH_IN_ASSET_EDITOR virtual void SearchInAsset(); diff --git a/Source/FlowEditor/Public/FlowEditorCommands.h b/Source/FlowEditor/Public/FlowEditorCommands.h index 7441d02bc..f2c31b847 100644 --- a/Source/FlowEditor/Public/FlowEditorCommands.h +++ b/Source/FlowEditor/Public/FlowEditorCommands.h @@ -13,6 +13,8 @@ class FLOWEDITOR_API FFlowToolbarCommands : public TCommands RefreshAsset; + TSharedPtr ValidateAsset; + TSharedPtr SearchInAsset; TSharedPtr GoToParentInstance; diff --git a/Source/FlowEditor/Public/Graph/FlowGraph.h b/Source/FlowEditor/Public/Graph/FlowGraph.h index de76d7949..7c1803481 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraph.h +++ b/Source/FlowEditor/Public/Graph/FlowGraph.h @@ -12,8 +12,6 @@ class FLOWEDITOR_API FFlowGraphInterface : public IFlowGraphInterface public: virtual ~FFlowGraphInterface() override {} - virtual void RefreshGraph(UFlowAsset* FlowAsset) override; - virtual void OnInputTriggered(UEdGraphNode* GraphNode, const int32 Index) const override; virtual void OnOutputTriggered(UEdGraphNode* GraphNode, const int32 Index) const override; }; From 99e1e7da1d612d59d3482557f8c752fa1250cf3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Tue, 14 Feb 2023 10:19:47 +0100 Subject: [PATCH 253/338] merge fix --- Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp index 1ac8d58fe..8315d7ac6 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp @@ -200,6 +200,7 @@ void FFlowAssetToolbar::BuildAssetToolbar(UToolMenu* ToolbarMenu) const Section.AddEntry(FToolMenuEntry::InitToolBarButton(FFlowToolbarCommands::Get().ValidateAsset)); } +#if defined ENABLE_SEARCH_IN_ASSET_EDITOR || defined ENABLE_FLOW_DIFF { FToolMenuSection& Section = ToolbarMenu->AddSection("View"); Section.InsertPosition = FToolMenuInsert("FlowAsset", EToolMenuInsertType::After); @@ -224,6 +225,7 @@ void FFlowAssetToolbar::BuildAssetToolbar(UToolMenu* ToolbarMenu) const DiffEntry.StyleNameOverride = "CalloutToolbar"; InSection.AddEntry(DiffEntry); })); +#endif } #endif } From db70e7523278fef4cfe3536332d47cfafc75e3d5 Mon Sep 17 00:00:00 2001 From: "Satheesh (ryanjon2040)" Date: Sat, 18 Feb 2023 15:48:46 +0530 Subject: [PATCH 254/338] Fix templated version of GetOwner (#139) --- Source/Flow/Public/FlowAsset.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index ab8e78e0b..0e319101d 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -242,7 +242,7 @@ class FLOW_API UFlowAsset : public UObject UObject* GetOwner() const { return Owner.Get(); } template - TWeakObjectPtr GetOwner() const + TWeakObjectPtr GetOwner() const { return Owner.IsValid() ? Cast(Owner) : nullptr; } From 50c10d4eade4df5da3a96960b2bbd50ef8a62e49 Mon Sep 17 00:00:00 2001 From: "Satheesh (ryanjon2040)" Date: Sat, 18 Feb 2023 15:50:11 +0530 Subject: [PATCH 255/338] Add keywords for timer to make search easier (#137) --- Source/Flow/Public/Nodes/Route/FlowNode_Timer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h b/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h index 0d9154ad2..70424bd63 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h @@ -9,7 +9,7 @@ /** * Triggers outputs after time elapsed */ -UCLASS(NotBlueprintable, meta = (DisplayName = "Timer")) +UCLASS(NotBlueprintable, meta = (DisplayName = "Timer", Keywords = "delay, wait, step, tick")) class FLOW_API UFlowNode_Timer : public UFlowNode { GENERATED_UCLASS_BODY() From 4f3db4718c676aa4b02de7f4cc9e9f6b51897053 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 19 Feb 2023 14:15:22 +0100 Subject: [PATCH 256/338] Simplified overriding "Validate Asset" directly in the editor code + finally applying auto-format --- .../Private/Asset/FlowAssetEditor.cpp | 327 +++++++++--------- .../FlowEditor/Public/Asset/FlowAssetEditor.h | 10 +- 2 files changed, 174 insertions(+), 163 deletions(-) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index b8100d921..96268a130 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -130,7 +130,7 @@ void FFlowAssetEditor::RegisterTabSpawners(const TSharedRef& .SetDisplayName(LOCTEXT("GraphTab", "Graph")) .SetGroup(WorkspaceMenuCategoryRef) .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "GraphEditor.EventGraph_16x")); - + InTabManager->RegisterTabSpawner(PaletteTab, FOnSpawnTab::CreateSP(this, &FFlowAssetEditor::SpawnTab_Palette)) .SetDisplayName(LOCTEXT("PaletteTab", "Palette")) .SetGroup(WorkspaceMenuCategoryRef) @@ -149,9 +149,9 @@ void FFlowAssetEditor::RegisterTabSpawners(const TSharedRef& #endif InTabManager->RegisterTabSpawner(ValidationLogTab, FOnSpawnTab::CreateSP(this, &FFlowAssetEditor::SpawnTab_ValidationLog)) - .SetDisplayName(LOCTEXT("ValidationLog", "Validation Log")) - .SetGroup(WorkspaceMenuCategoryRef) - .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "Debug")); + .SetDisplayName(LOCTEXT("ValidationLog", "Validation Log")) + .SetGroup(WorkspaceMenuCategoryRef) + .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "Debug")); } void FFlowAssetEditor::UnregisterTabSpawners(const TSharedRef& InTabManager) @@ -164,7 +164,7 @@ void FFlowAssetEditor::UnregisterTabSpawners(const TSharedRef InTabManager->UnregisterTabSpawner(PaletteTab); #if ENABLE_SEARCH_IN_ASSET_EDITOR InTabManager->UnregisterTabSpawner(SearchTab); -#endif +#endif } void FFlowAssetEditor::InitToolMenuContext(FToolMenuContext& MenuContext) @@ -276,49 +276,49 @@ void FFlowAssetEditor::InitFlowAssetEditor(const EToolkitMode::Type Mode, const ->AddArea ( FTabManager::NewPrimaryArea()->SetOrientation(Orient_Horizontal) - ->Split - ( - FTabManager::NewStack() - ->SetSizeCoefficient(0.225f) - ->AddTab(DetailsTab, ETabState::OpenedTab) - ) - ->Split - ( - FTabManager::NewSplitter() - ->SetSizeCoefficient(0.65f) - ->SetOrientation(Orient_Vertical) - ->Split - ( - FTabManager::NewStack() - ->SetSizeCoefficient(0.8f) - ->SetHideTabWell(true) - ->AddTab(GraphTab, ETabState::OpenedTab) - ) - ->Split - ( - FTabManager::NewStack() - ->SetSizeCoefficient(0.15f) - ->AddTab(RuntimeLogTab, ETabState::ClosedTab) - ) - ->Split - ( - FTabManager::NewStack() - ->SetSizeCoefficient(0.15f) - ->AddTab(SearchTab, ETabState::ClosedTab) - ) - ->Split - ( - FTabManager::NewStack() - ->SetSizeCoefficient(0.15f) - ->AddTab(ValidationLogTab, ETabState::ClosedTab) - ) - ) - ->Split - ( - FTabManager::NewStack() - ->SetSizeCoefficient(0.125f) - ->AddTab(PaletteTab, ETabState::OpenedTab) - ) + ->Split + ( + FTabManager::NewStack() + ->SetSizeCoefficient(0.225f) + ->AddTab(DetailsTab, ETabState::OpenedTab) + ) + ->Split + ( + FTabManager::NewSplitter() + ->SetSizeCoefficient(0.65f) + ->SetOrientation(Orient_Vertical) + ->Split + ( + FTabManager::NewStack() + ->SetSizeCoefficient(0.8f) + ->SetHideTabWell(true) + ->AddTab(GraphTab, ETabState::OpenedTab) + ) + ->Split + ( + FTabManager::NewStack() + ->SetSizeCoefficient(0.15f) + ->AddTab(RuntimeLogTab, ETabState::ClosedTab) + ) + ->Split + ( + FTabManager::NewStack() + ->SetSizeCoefficient(0.15f) + ->AddTab(SearchTab, ETabState::ClosedTab) + ) + ->Split + ( + FTabManager::NewStack() + ->SetSizeCoefficient(0.15f) + ->AddTab(ValidationLogTab, ETabState::ClosedTab) + ) + ) + ->Split + ( + FTabManager::NewStack() + ->SetSizeCoefficient(0.125f) + ->AddTab(PaletteTab, ETabState::OpenedTab) + ) ); constexpr bool bCreateDefaultStandaloneMenu = true; @@ -353,28 +353,28 @@ void FFlowAssetEditor::BindToolbarCommands() // Editing ToolkitCommands->MapAction(ToolbarCommands.RefreshAsset, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::RefreshAsset), - FCanExecuteAction::CreateStatic(&FFlowAssetEditor::CanEdit)); + FExecuteAction::CreateSP(this, &FFlowAssetEditor::RefreshAsset), + FCanExecuteAction::CreateStatic(&FFlowAssetEditor::CanEdit)); ToolkitCommands->MapAction(ToolbarCommands.ValidateAsset, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::ValidateAsset), - FCanExecuteAction()); + FExecuteAction::CreateSP(this, &FFlowAssetEditor::ValidateAsset_Internal), + FCanExecuteAction()); #if ENABLE_SEARCH_IN_ASSET_EDITOR ToolkitCommands->MapAction(ToolbarCommands.SearchInAsset, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::SearchInAsset), - FCanExecuteAction()); -#endif + FExecuteAction::CreateSP(this, &FFlowAssetEditor::SearchInAsset), + FCanExecuteAction()); +#endif // Engine's Play commands ToolkitCommands->Append(FPlayWorldCommands::GlobalPlayWorldActions.ToSharedRef()); // Debugging ToolkitCommands->MapAction(ToolbarCommands.GoToParentInstance, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::GoToParentInstance), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanGoToParentInstance), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanGoToParentInstance)); + FExecuteAction::CreateSP(this, &FFlowAssetEditor::GoToParentInstance), + FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanGoToParentInstance), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanGoToParentInstance)); } void FFlowAssetEditor::RefreshAsset() @@ -383,10 +383,10 @@ void FFlowAssetEditor::RefreshAsset() CastChecked(FlowAsset->GetGraph())->RefreshGraph(); } -void FFlowAssetEditor::ValidateAsset() +void FFlowAssetEditor::ValidateAsset_Internal() { FFlowMessageLog LogResults; - FlowAsset->ValidateAsset(LogResults); + ValidateAsset(LogResults); // push messages to its window ValidationLogListing->ClearMessages(); @@ -398,6 +398,11 @@ void FFlowAssetEditor::ValidateAsset() ValidationLogListing->OnDataChanged().Broadcast(); } +void FFlowAssetEditor::ValidateAsset(FFlowMessageLog& MessageLog) +{ + FlowAsset->ValidateAsset(MessageLog); +} + #if ENABLE_SEARCH_IN_ASSET_EDITOR void FFlowAssetEditor::SearchInAsset() { @@ -496,178 +501,178 @@ void FFlowAssetEditor::BindGraphCommands() FGraphEditorCommands::Register(); FFlowGraphCommands::Register(); FFlowSpawnNodeCommands::Register(); - + const FGenericCommands& GenericCommands = FGenericCommands::Get(); const FGraphEditorCommandsImpl& GraphCommands = FGraphEditorCommands::Get(); const FFlowGraphCommands& FlowGraphCommands = FFlowGraphCommands::Get(); // Graph commands ToolkitCommands->MapAction(GraphCommands.CreateComment, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnCreateComment), - FCanExecuteAction::CreateStatic(&FFlowAssetEditor::CanEdit)); + FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnCreateComment), + FCanExecuteAction::CreateStatic(&FFlowAssetEditor::CanEdit)); ToolkitCommands->MapAction(GraphCommands.StraightenConnections, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnStraightenConnections)); + FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnStraightenConnections)); // Generic Node commands ToolkitCommands->MapAction(GenericCommands.Undo, - FExecuteAction::CreateStatic(&FFlowAssetEditor::UndoGraphAction), - FCanExecuteAction::CreateStatic(&FFlowAssetEditor::CanEdit)); + FExecuteAction::CreateStatic(&FFlowAssetEditor::UndoGraphAction), + FCanExecuteAction::CreateStatic(&FFlowAssetEditor::CanEdit)); ToolkitCommands->MapAction(GenericCommands.Redo, - FExecuteAction::CreateStatic(&FFlowAssetEditor::RedoGraphAction), - FCanExecuteAction::CreateStatic(&FFlowAssetEditor::CanEdit)); + FExecuteAction::CreateStatic(&FFlowAssetEditor::RedoGraphAction), + FCanExecuteAction::CreateStatic(&FFlowAssetEditor::CanEdit)); ToolkitCommands->MapAction(GenericCommands.SelectAll, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::SelectAllNodes), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanSelectAllNodes)); + FExecuteAction::CreateSP(this, &FFlowAssetEditor::SelectAllNodes), + FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanSelectAllNodes)); ToolkitCommands->MapAction(GenericCommands.Delete, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::DeleteSelectedNodes), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanDeleteNodes)); + FExecuteAction::CreateSP(this, &FFlowAssetEditor::DeleteSelectedNodes), + FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanDeleteNodes)); ToolkitCommands->MapAction(GenericCommands.Copy, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::CopySelectedNodes), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanCopyNodes)); + FExecuteAction::CreateSP(this, &FFlowAssetEditor::CopySelectedNodes), + FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanCopyNodes)); ToolkitCommands->MapAction(GenericCommands.Cut, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::CutSelectedNodes), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanCutNodes)); + FExecuteAction::CreateSP(this, &FFlowAssetEditor::CutSelectedNodes), + FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanCutNodes)); ToolkitCommands->MapAction(GenericCommands.Paste, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::PasteNodes), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanPasteNodes)); + FExecuteAction::CreateSP(this, &FFlowAssetEditor::PasteNodes), + FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanPasteNodes)); ToolkitCommands->MapAction(GenericCommands.Duplicate, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::DuplicateNodes), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanDuplicateNodes)); + FExecuteAction::CreateSP(this, &FFlowAssetEditor::DuplicateNodes), + FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanDuplicateNodes)); // Pin commands ToolkitCommands->MapAction(FlowGraphCommands.RefreshContextPins, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::RefreshContextPins), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanRefreshContextPins)); + FExecuteAction::CreateSP(this, &FFlowAssetEditor::RefreshContextPins), + FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanRefreshContextPins)); ToolkitCommands->MapAction(FlowGraphCommands.AddInput, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::AddInput), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanAddInput)); + FExecuteAction::CreateSP(this, &FFlowAssetEditor::AddInput), + FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanAddInput)); ToolkitCommands->MapAction(FlowGraphCommands.AddOutput, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::AddOutput), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanAddOutput)); + FExecuteAction::CreateSP(this, &FFlowAssetEditor::AddOutput), + FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanAddOutput)); ToolkitCommands->MapAction(FlowGraphCommands.RemovePin, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::RemovePin), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanRemovePin)); + FExecuteAction::CreateSP(this, &FFlowAssetEditor::RemovePin), + FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanRemovePin)); // Breakpoint commands ToolkitCommands->MapAction(GraphCommands.AddBreakpoint, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnAddBreakpoint), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanAddBreakpoint), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanAddBreakpoint) + FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnAddBreakpoint), + FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanAddBreakpoint), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanAddBreakpoint) ); ToolkitCommands->MapAction(GraphCommands.RemoveBreakpoint, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnRemoveBreakpoint), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanRemoveBreakpoint), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanRemoveBreakpoint) + FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnRemoveBreakpoint), + FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanRemoveBreakpoint), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanRemoveBreakpoint) ); ToolkitCommands->MapAction(GraphCommands.EnableBreakpoint, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnEnableBreakpoint), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanEnableBreakpoint), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanEnableBreakpoint) + FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnEnableBreakpoint), + FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanEnableBreakpoint), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanEnableBreakpoint) ); ToolkitCommands->MapAction(GraphCommands.DisableBreakpoint, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnDisableBreakpoint), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanDisableBreakpoint), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanDisableBreakpoint) + FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnDisableBreakpoint), + FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanDisableBreakpoint), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanDisableBreakpoint) ); ToolkitCommands->MapAction(GraphCommands.ToggleBreakpoint, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnToggleBreakpoint), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanToggleBreakpoint), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanToggleBreakpoint) + FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnToggleBreakpoint), + FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanToggleBreakpoint), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanToggleBreakpoint) ); // Pin Breakpoint commands ToolkitCommands->MapAction(FlowGraphCommands.AddPinBreakpoint, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnAddPinBreakpoint), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanAddPinBreakpoint), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanAddPinBreakpoint) + FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnAddPinBreakpoint), + FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanAddPinBreakpoint), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanAddPinBreakpoint) ); ToolkitCommands->MapAction(FlowGraphCommands.RemovePinBreakpoint, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnRemovePinBreakpoint), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanRemovePinBreakpoint), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanRemovePinBreakpoint) + FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnRemovePinBreakpoint), + FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanRemovePinBreakpoint), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanRemovePinBreakpoint) ); ToolkitCommands->MapAction(FlowGraphCommands.EnablePinBreakpoint, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnEnablePinBreakpoint), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanEnablePinBreakpoint), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanEnablePinBreakpoint) + FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnEnablePinBreakpoint), + FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanEnablePinBreakpoint), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanEnablePinBreakpoint) ); ToolkitCommands->MapAction(FlowGraphCommands.DisablePinBreakpoint, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnDisablePinBreakpoint), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanDisablePinBreakpoint), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanDisablePinBreakpoint) + FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnDisablePinBreakpoint), + FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanDisablePinBreakpoint), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanDisablePinBreakpoint) ); ToolkitCommands->MapAction(FlowGraphCommands.TogglePinBreakpoint, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnTogglePinBreakpoint), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanTogglePinBreakpoint), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanTogglePinBreakpoint) + FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnTogglePinBreakpoint), + FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanTogglePinBreakpoint), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanTogglePinBreakpoint) ); // Execution Override commands ToolkitCommands->MapAction(FlowGraphCommands.EnableNode, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::SetSignalMode, EFlowSignalMode::Enabled), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanSetSignalMode, EFlowSignalMode::Enabled), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanSetSignalMode, EFlowSignalMode::Enabled) + FExecuteAction::CreateSP(this, &FFlowAssetEditor::SetSignalMode, EFlowSignalMode::Enabled), + FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanSetSignalMode, EFlowSignalMode::Enabled), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanSetSignalMode, EFlowSignalMode::Enabled) ); ToolkitCommands->MapAction(FlowGraphCommands.DisableNode, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::SetSignalMode, EFlowSignalMode::Disabled), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanSetSignalMode, EFlowSignalMode::Disabled), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanSetSignalMode, EFlowSignalMode::Disabled) + FExecuteAction::CreateSP(this, &FFlowAssetEditor::SetSignalMode, EFlowSignalMode::Disabled), + FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanSetSignalMode, EFlowSignalMode::Disabled), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanSetSignalMode, EFlowSignalMode::Disabled) ); - + ToolkitCommands->MapAction(FlowGraphCommands.SetPassThrough, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::SetSignalMode, EFlowSignalMode::PassThrough), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanSetSignalMode, EFlowSignalMode::PassThrough), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanSetSignalMode, EFlowSignalMode::PassThrough) + FExecuteAction::CreateSP(this, &FFlowAssetEditor::SetSignalMode, EFlowSignalMode::PassThrough), + FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanSetSignalMode, EFlowSignalMode::PassThrough), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanSetSignalMode, EFlowSignalMode::PassThrough) ); ToolkitCommands->MapAction(FlowGraphCommands.ForcePinActivation, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnForcePinActivation), - FCanExecuteAction::CreateStatic(&FFlowAssetEditor::IsPIE), - FIsActionChecked(), - FIsActionButtonVisible::CreateStatic(&FFlowAssetEditor::IsPIE) + FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnForcePinActivation), + FCanExecuteAction::CreateStatic(&FFlowAssetEditor::IsPIE), + FIsActionChecked(), + FIsActionButtonVisible::CreateStatic(&FFlowAssetEditor::IsPIE) ); - + // Jump commands ToolkitCommands->MapAction(FlowGraphCommands.FocusViewport, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::FocusViewport), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanFocusViewport)); + FExecuteAction::CreateSP(this, &FFlowAssetEditor::FocusViewport), + FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanFocusViewport)); ToolkitCommands->MapAction(FlowGraphCommands.JumpToNodeDefinition, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::JumpToNodeDefinition), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanJumpToNodeDefinition)); + FExecuteAction::CreateSP(this, &FFlowAssetEditor::JumpToNodeDefinition), + FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanJumpToNodeDefinition)); } void FFlowAssetEditor::UndoGraphAction() @@ -687,12 +692,12 @@ FReply FFlowAssetEditor::OnSpawnGraphNodeByShortcut(FInputChord InChord, const F if (FFlowSpawnNodeCommands::IsRegistered()) { const TSharedPtr Action = FFlowSpawnNodeCommands::Get().GetActionByChord(InChord); - if (Action.IsValid()) - { - TArray DummyPins; - Action->PerformAction(Graph, DummyPins, InPosition); - return FReply::Handled(); - } + if (Action.IsValid()) + { + TArray DummyPins; + Action->PerformAction(Graph, DummyPins, InPosition); + return FReply::Handled(); + } } return FReply::Unhandled(); @@ -756,7 +761,7 @@ void FFlowAssetEditor::OnBeginPIE(const bool bInSimulateInEditor) const TSet FFlowAssetEditor::GetSelectedFlowNodes() const { TSet Result; - + const FGraphPanelSelectionSet SelectedNodes = GraphEditor->GetSelectedNodes(); for (FGraphPanelSelectionSet::TConstIterator NodeIt(SelectedNodes); NodeIt; ++NodeIt) { @@ -765,7 +770,7 @@ TSet FFlowAssetEditor::GetSelectedFlowNodes() const Result.Emplace(SelectedNode); } } - + return Result; } @@ -1145,7 +1150,7 @@ void FFlowAssetEditor::OnNodeDoubleClicked(class UEdGraphNode* Node) const else if (UObject* AssetToEdit = FlowNode->GetAssetToEdit()) { GEditor->GetEditorSubsystem()->OpenEditorForAsset(AssetToEdit); - + if (IsPIE()) { if (UFlowNode_SubGraph* SubGraphNode = Cast(FlowNode)) @@ -1492,7 +1497,7 @@ bool FFlowAssetEditor::CanSetSignalMode(const EFlowSignalMode Mode) const { return false; } - + for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) { return SelectedNode->CanSetSignalMode(Mode); diff --git a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h index 6fd99566d..b1d053829 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h @@ -12,6 +12,7 @@ #include "FlowEditorDefines.h" #include "FlowTypes.h" +class FFlowMessageLog; class SFlowPalette; class UFlowAsset; class UFlowGraphNode; @@ -27,7 +28,7 @@ struct Rect; class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEditorUndoClient, public FGCObject, public FNotifyHook { protected: - /** The FlowAsset asset being inspected */ + /** The Flow Asset being edited */ UFlowAsset* FlowAsset; TSharedPtr AssetToolbar; @@ -121,7 +122,12 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit virtual void BindToolbarCommands(); virtual void RefreshAsset(); - virtual void ValidateAsset(); + +private: + void ValidateAsset_Internal(); + +protected: + virtual void ValidateAsset(FFlowMessageLog& MessageLog); #if ENABLE_SEARCH_IN_ASSET_EDITOR virtual void SearchInAsset(); From 377cdd9c8e03dbf803d6be3aacc15cb08e823d09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 19 Feb 2023 14:28:41 +0100 Subject: [PATCH 257/338] auto-format applied --- Source/Flow/Public/FlowAsset.h | 42 ++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 0e319101d..e6aa39e1d 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -40,7 +40,6 @@ UCLASS(BlueprintType, hideCategories = Object) class FLOW_API UFlowAsset : public UObject { GENERATED_UCLASS_BODY() - friend class UFlowNode; friend class UFlowNode_CustomOutput; friend class UFlowNode_SubGraph; @@ -56,7 +55,7 @@ class FLOW_API UFlowAsset : public UObject // This allow to SaveGame support works properly, if owner of Root Flow would be Game Instance or its subsystem UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Flow Asset") bool bWorldBound; - + ////////////////////////////////////////////////////////////////////////// // Graph @@ -74,6 +73,7 @@ class FLOW_API UFlowAsset : public UObject // IFlowGraphInterface #if WITH_EDITORONLY_DATA + private: UPROPERTY() UEdGraph* FlowGraph; @@ -94,7 +94,7 @@ class FLOW_API UFlowAsset : public UObject // Nodes protected: - TArray> AllowedNodeClasses; + TArray> AllowedNodeClasses; TArray> DeniedNodeClasses; bool bStartNodePlacedAsGhostNode; @@ -131,20 +131,20 @@ class FLOW_API UFlowAsset : public UObject #endif TMap GetNodes() const { return Nodes; } - UFlowNode* GetNode(const FGuid& Guid) const { return Nodes.FindRef(Guid); } + UFlowNode* GetNode(const FGuid& Guid) const { return Nodes.FindRef(Guid); } - template - T* GetNode(const FGuid& Guid) const - { - static_assert(TPointerIsConvertibleFromTo::Value, "'T' template parameter to GetNode must be derived from UFlowNode"); - - if (UFlowNode* Node = Nodes.FindRef(Guid)) - { - return Cast(Node); - } + template + T* GetNode(const FGuid& Guid) const + { + static_assert(TPointerIsConvertibleFromTo::Value, "'T' template parameter to GetNode must be derived from UFlowNode"); + + if (UFlowNode* Node = Nodes.FindRef(Guid)) + { + return Cast(Node); + } - return nullptr; - } + return nullptr; + } TArray GetCustomInputs() const { return CustomInputs; } TArray GetCustomOutputs() const { return CustomOutputs; } @@ -180,10 +180,12 @@ class FLOW_API UFlowAsset : public UObject UFlowAsset* GetInspectedInstance() const { return InspectedInstance.IsValid() ? InspectedInstance.Get() : nullptr; } DECLARE_EVENT(UFlowAsset, FRefreshDebuggerEvent); + FRefreshDebuggerEvent& OnDebuggerRefresh() { return RefreshDebuggerEvent; } FRefreshDebuggerEvent RefreshDebuggerEvent; DECLARE_EVENT_TwoParams(UFlowAsset, FRuntimeMessageEvent, const UFlowAsset*, const TSharedRef&); + FRuntimeMessageEvent& OnRuntimeMessageAdded() { return RuntimeMessageEvent; } FRuntimeMessageEvent RuntimeMessageEvent; @@ -235,7 +237,7 @@ class FLOW_API UFlowAsset : public UObject virtual void DeinitializeInstance(); UFlowAsset* GetTemplateAsset() const { return TemplateAsset; } - + // Object that spawned Root Flow instance, i.e. World Settings or Player Controller // This pointer is passed to child instances: Flow Asset instances created by the SubGraph nodes UFUNCTION(BlueprintPure, Category = "Flow") @@ -251,7 +253,7 @@ class FLOW_API UFlowAsset : public UObject virtual void PreStartFlow(); virtual void StartFlow(); - + virtual void FinishFlow(const EFlowFinishPolicy InFinishPolicy, const bool bRemoveInstance = true); // Get Flow Asset instance created by the given SubGraph node @@ -293,7 +295,7 @@ class FLOW_API UFlowAsset : public UObject ////////////////////////////////////////////////////////////////////////// // SaveGame - + UFUNCTION(BlueprintCallable, Category = "SaveGame") FFlowAssetSaveData SaveInstance(TArray& SavedFlowInstances); @@ -306,11 +308,11 @@ class FLOW_API UFlowAsset : public UObject protected: UFUNCTION(BlueprintNativeEvent, Category = "SaveGame") void OnSave(); - + UFUNCTION(BlueprintNativeEvent, Category = "SaveGame") void OnLoad(); -public: +public: UFUNCTION(BlueprintNativeEvent, Category = "SaveGame") bool IsBoundToWorld(); }; From 3cfa75fdcd36d270d7849840752f0234a2b36dd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 19 Feb 2023 15:03:57 +0100 Subject: [PATCH 258/338] added "Runtime" word to runtime log methods added nullcheck on GetTemplateAsset() if someone would runtime logging on template instance --- Source/Flow/Private/Nodes/FlowNode.cpp | 33 +++++++++++++++++--------- Source/Flow/Public/Nodes/FlowNode.h | 9 ++++--- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 64b92810f..22949957b 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -416,7 +416,7 @@ void UFlowNode::TriggerInput(const FName& PinName, const EFlowPinActivationType else { #if !UE_BUILD_SHIPPING - LogError(FString::Printf(TEXT("Input Pin name %s invalid"), *PinName.ToString())); + LogRuntimeError(FString::Printf(TEXT("Input Pin name %s invalid"), *PinName.ToString())); #endif // UE_BUILD_SHIPPING return; } @@ -427,10 +427,10 @@ void UFlowNode::TriggerInput(const FName& PinName, const EFlowPinActivationType ExecuteInput(PinName); break; case EFlowSignalMode::Disabled: - LogNote(FString::Printf(TEXT("Node disabled while triggering input %s"), *PinName.ToString())); + LogRuntimeNote(FString::Printf(TEXT("Node disabled while triggering input %s"), *PinName.ToString())); break; case EFlowSignalMode::PassThrough: - LogNote(FString::Printf(TEXT("Signal pass-through on triggering input %s"), *PinName.ToString())); + LogRuntimeNote(FString::Printf(TEXT("Signal pass-through on triggering input %s"), *PinName.ToString())); OnPassThrough(); break; default: ; @@ -474,7 +474,7 @@ void UFlowNode::TriggerOutput(const FName& PinName, const bool bFinish /*= false } else { - LogError(FString::Printf(TEXT("Output Pin name %s invalid"), *PinName.ToString())); + LogRuntimeError(FString::Printf(TEXT("Output Pin name %s invalid"), *PinName.ToString())); } #endif // UE_BUILD_SHIPPING @@ -662,7 +662,12 @@ FString UFlowNode::GetProgressAsString(float Value) return TempString; } -void UFlowNode::LogError(FString Message, const EFlowOnScreenMessageType OnScreenMessageType) +void UFlowNode::LogError(const FString Message, const EFlowOnScreenMessageType OnScreenMessageType) +{ + LogRuntimeError(Message, OnScreenMessageType); +} + +void UFlowNode::LogRuntimeError(FString Message, const EFlowOnScreenMessageType OnScreenMessageType) { #if !UE_BUILD_SHIPPING @@ -694,13 +699,16 @@ void UFlowNode::LogError(FString Message, const EFlowOnScreenMessageType OnScree // Message Log #if WITH_EDITOR - GetFlowAsset()->GetTemplateAsset()->LogError(Message, this); + if (GetFlowAsset()->GetTemplateAsset()) + { + GetFlowAsset()->GetTemplateAsset()->LogError(Message, this); + } #endif #endif } -void UFlowNode::LogWarning(FString Message) +void UFlowNode::LogRuntimeWarning(FString Message) { #if !UE_BUILD_SHIPPING @@ -711,13 +719,16 @@ void UFlowNode::LogWarning(FString Message) // Message Log #if WITH_EDITOR - GetFlowAsset()->GetTemplateAsset()->LogWarning(Message, this); + if (GetFlowAsset()->GetTemplateAsset()) + { + GetFlowAsset()->GetTemplateAsset()->LogWarning(Message, this); + } #endif #endif } -void UFlowNode::LogNote(FString Message) +void UFlowNode::LogRuntimeNote(FString Message) { #if !UE_BUILD_SHIPPING @@ -770,11 +781,11 @@ void UFlowNode::LoadInstance(const FFlowNodeSaveData& NodeRecord) break; case EFlowSignalMode::Disabled: // designer doesn't want to execute this node's logic at all, so we kill it - LogNote(TEXT("Signal disabled while loading Flow Node from SaveGame")); + LogRuntimeNote(TEXT("Signal disabled while loading Flow Node from SaveGame")); Finish(); break; case EFlowSignalMode::PassThrough: - LogNote(TEXT("Signal pass-through on loading Flow Node from SaveGame")); + LogRuntimeNote(TEXT("Signal pass-through on loading Flow Node from SaveGame")); OnPassThrough(); break; default: ; diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 5b5feb3fa..bd45e1dad 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -377,14 +377,17 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UFUNCTION(BlueprintPure, Category = "FlowNode") static FString GetProgressAsString(float Value); - UFUNCTION(BlueprintCallable, Category = "FlowNode", meta = (DevelopmentOnly)) + UFUNCTION(BlueprintCallable, Category = "FlowNode", meta = (DevelopmentOnly), meta=(DeprecatedFunction, DeprecationMessage="Use LogRuntimeError instead.")) void LogError(FString Message, const EFlowOnScreenMessageType OnScreenMessageType = EFlowOnScreenMessageType::Permanent); UFUNCTION(BlueprintCallable, Category = "FlowNode", meta = (DevelopmentOnly)) - void LogWarning(FString Message); + void LogRuntimeError(FString Message, const EFlowOnScreenMessageType OnScreenMessageType = EFlowOnScreenMessageType::Permanent); + + UFUNCTION(BlueprintCallable, Category = "FlowNode", meta = (DevelopmentOnly)) + void LogRuntimeWarning(FString Message); UFUNCTION(BlueprintCallable, Category = "FlowNode", meta = (DevelopmentOnly)) - void LogNote(FString Message); + void LogRuntimeNote(FString Message); #if !UE_BUILD_SHIPPING private: From 0c34329157f6dd3767896bfe7937006ee1be2fe9 Mon Sep 17 00:00:00 2001 From: "Satheesh (ryanjon2040)" Date: Mon, 20 Feb 2023 15:22:18 +0530 Subject: [PATCH 259/338] Properly deprecate LogError (#141) --- Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp | 4 ++-- Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp | 6 +++--- .../Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp | 2 +- Source/Flow/Public/Nodes/FlowNode.h | 1 + 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp index 04bbe1e68..9182f0140 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp @@ -49,11 +49,11 @@ void UFlowNode_SubGraph::ExecuteInput(const FName& PinName) { if (Asset.IsNull()) { - LogError(TEXT("Missing Flow Asset")); + LogRuntimeError(TEXT("Missing Flow Asset")); } else { - LogError(FString::Printf(TEXT("Asset %s cannot be instance, probably is the same as the asset owning this SubGraph node."), *Asset->GetPathName())); + LogRuntimeError(FString::Printf(TEXT("Asset %s cannot be instance, probably is the same as the asset owning this SubGraph node."), *Asset->GetPathName())); } Finish(); diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp index 3e14f88cb..663e47240 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp @@ -31,7 +31,7 @@ void UFlowNode_Timer::ExecuteInput(const FName& PinName) { if (CompletionTime == 0.0f) { - LogError(TEXT("Invalid Timer settings")); + LogRuntimeError(TEXT("Invalid Timer settings")); TriggerOutput(TEXT("Completed"), true); return; } @@ -40,7 +40,7 @@ void UFlowNode_Timer::ExecuteInput(const FName& PinName) { if (CompletionTimerHandle.IsValid() || StepTimerHandle.IsValid()) { - LogError(TEXT("Timer already active")); + LogRuntimeError(TEXT("Timer already active")); return; } @@ -69,7 +69,7 @@ void UFlowNode_Timer::SetTimer() } else { - LogError(TEXT("No valid world")); + LogRuntimeError(TEXT("No valid world")); TriggerOutput(TEXT("Completed"), true); } } diff --git a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp index 73151f305..f0676f895 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp @@ -33,7 +33,7 @@ void UFlowNode_ComponentObserver::ExecuteInput(const FName& PinName) } else { - LogError(MissingIdentityTag); + LogRuntimeError(MissingIdentityTag); } } diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index bd45e1dad..9eb4ce264 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -377,6 +377,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UFUNCTION(BlueprintPure, Category = "FlowNode") static FString GetProgressAsString(float Value); + UE_DEPRECATED(5.0, "LogError has been deprecated. Use LogRuntimeError instead.") UFUNCTION(BlueprintCallable, Category = "FlowNode", meta = (DevelopmentOnly), meta=(DeprecatedFunction, DeprecationMessage="Use LogRuntimeError instead.")) void LogError(FString Message, const EFlowOnScreenMessageType OnScreenMessageType = EFlowOnScreenMessageType::Permanent); From be44063efff2d6932507c916fa811476b560f3b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Mon, 20 Feb 2023 18:44:51 +0100 Subject: [PATCH 260/338] reverted naming changing that caused collision engine's defines --- Source/Flow/Private/Nodes/FlowNode.cpp | 189 +++++++++--------- .../Private/Nodes/Route/FlowNode_SubGraph.cpp | 4 +- .../Private/Nodes/Route/FlowNode_Timer.cpp | 6 +- .../World/FlowNode_ComponentObserver.cpp | 2 +- Source/Flow/Public/Nodes/FlowNode.h | 33 ++- 5 files changed, 113 insertions(+), 121 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 22949957b..8b1b2aca6 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -416,7 +416,7 @@ void UFlowNode::TriggerInput(const FName& PinName, const EFlowPinActivationType else { #if !UE_BUILD_SHIPPING - LogRuntimeError(FString::Printf(TEXT("Input Pin name %s invalid"), *PinName.ToString())); + LogError(FString::Printf(TEXT("Input Pin name %s invalid"), *PinName.ToString())); #endif // UE_BUILD_SHIPPING return; } @@ -427,10 +427,10 @@ void UFlowNode::TriggerInput(const FName& PinName, const EFlowPinActivationType ExecuteInput(PinName); break; case EFlowSignalMode::Disabled: - LogRuntimeNote(FString::Printf(TEXT("Node disabled while triggering input %s"), *PinName.ToString())); + LogNote(FString::Printf(TEXT("Node disabled while triggering input %s"), *PinName.ToString())); break; case EFlowSignalMode::PassThrough: - LogRuntimeNote(FString::Printf(TEXT("Signal pass-through on triggering input %s"), *PinName.ToString())); + LogNote(FString::Printf(TEXT("Signal pass-through on triggering input %s"), *PinName.ToString())); OnPassThrough(); break; default: ; @@ -474,7 +474,7 @@ void UFlowNode::TriggerOutput(const FName& PinName, const bool bFinish /*= false } else { - LogRuntimeError(FString::Printf(TEXT("Output Pin name %s invalid"), *PinName.ToString())); + LogError(FString::Printf(TEXT("Output Pin name %s invalid"), *PinName.ToString())); } #endif // UE_BUILD_SHIPPING @@ -662,97 +662,6 @@ FString UFlowNode::GetProgressAsString(float Value) return TempString; } -void UFlowNode::LogError(const FString Message, const EFlowOnScreenMessageType OnScreenMessageType) -{ - LogRuntimeError(Message, OnScreenMessageType); -} - -void UFlowNode::LogRuntimeError(FString Message, const EFlowOnScreenMessageType OnScreenMessageType) -{ -#if !UE_BUILD_SHIPPING - - BuildMessage(Message); - - // OnScreen Message - if (OnScreenMessageType == EFlowOnScreenMessageType::Permanent) - { - if (GetWorld()) - { - if (UViewportStatsSubsystem* StatsSubsystem = GetWorld()->GetSubsystem()) - { - StatsSubsystem->AddDisplayDelegate([this, Message](FText& OutText, FLinearColor& OutColor) - { - OutText = FText::FromString(Message); - OutColor = FLinearColor::Red; - return IsValid(this) && ActivationState != EFlowNodeState::NeverActivated; - }); - } - } - } - else - { - GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, Message); - } - - // Output Log - UE_LOG(LogFlow, Error, TEXT("%s"), *Message); - - // Message Log -#if WITH_EDITOR - if (GetFlowAsset()->GetTemplateAsset()) - { - GetFlowAsset()->GetTemplateAsset()->LogError(Message, this); - } -#endif - -#endif -} - -void UFlowNode::LogRuntimeWarning(FString Message) -{ -#if !UE_BUILD_SHIPPING - - BuildMessage(Message); - - // Output Log - UE_LOG(LogFlow, Warning, TEXT("%s"), *Message); - - // Message Log -#if WITH_EDITOR - if (GetFlowAsset()->GetTemplateAsset()) - { - GetFlowAsset()->GetTemplateAsset()->LogWarning(Message, this); - } -#endif - -#endif -} - -void UFlowNode::LogRuntimeNote(FString Message) -{ -#if !UE_BUILD_SHIPPING - - BuildMessage(Message); - - // Output Log - UE_LOG(LogFlow, Log, TEXT("%s"), *Message); - - // Message Log -#if WITH_EDITOR - GetFlowAsset()->GetTemplateAsset()->LogNote(Message, this); -#endif - -#endif -} - -#if !UE_BUILD_SHIPPING -void UFlowNode::BuildMessage(FString& Message) const -{ - const FString TemplatePath = GetFlowAsset()->TemplateAsset->GetPathName(); - Message.Append(TEXT(" --- node ")).Append(GetName()).Append(TEXT(", asset ")).Append(FPaths::GetPath(TemplatePath) / FPaths::GetBaseFilename(TemplatePath)); -} -#endif - void UFlowNode::SaveInstance(FFlowNodeSaveData& NodeRecord) { NodeRecord.NodeGuid = NodeGuid; @@ -781,11 +690,11 @@ void UFlowNode::LoadInstance(const FFlowNodeSaveData& NodeRecord) break; case EFlowSignalMode::Disabled: // designer doesn't want to execute this node's logic at all, so we kill it - LogRuntimeNote(TEXT("Signal disabled while loading Flow Node from SaveGame")); + LogNote(TEXT("Signal disabled while loading Flow Node from SaveGame")); Finish(); break; case EFlowSignalMode::PassThrough: - LogRuntimeNote(TEXT("Signal pass-through on loading Flow Node from SaveGame")); + LogNote(TEXT("Signal pass-through on loading Flow Node from SaveGame")); OnPassThrough(); break; default: ; @@ -815,3 +724,89 @@ void UFlowNode::OnPassThrough_Implementation() // deactivate node, so it doesn't get saved to a new SaveGame Finish(); } + +void UFlowNode::LogError(FString Message, const EFlowOnScreenMessageType OnScreenMessageType) +{ +#if !UE_BUILD_SHIPPING + if (BuildMessage(Message)) + { + // OnScreen Message + if (OnScreenMessageType == EFlowOnScreenMessageType::Permanent) + { + if (GetWorld()) + { + if (UViewportStatsSubsystem* StatsSubsystem = GetWorld()->GetSubsystem()) + { + StatsSubsystem->AddDisplayDelegate([this, Message](FText& OutText, FLinearColor& OutColor) + { + OutText = FText::FromString(Message); + OutColor = FLinearColor::Red; + return IsValid(this) && ActivationState != EFlowNodeState::NeverActivated; + }); + } + } + } + else + { + GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, Message); + } + + // Output Log + UE_LOG(LogFlow, Error, TEXT("%s"), *Message); + + // Message Log +#if WITH_EDITOR + GetFlowAsset()->GetTemplateAsset()->LogError(Message, this); +#endif + } +#endif +} + +void UFlowNode::LogWarning(FString Message) +{ +#if !UE_BUILD_SHIPPING + if (BuildMessage(Message)) + { + // Output Log + UE_LOG(LogFlow, Warning, TEXT("%s"), *Message); + + // Message Log +#if WITH_EDITOR + if (GetFlowAsset()->GetTemplateAsset()) + { + GetFlowAsset()->GetTemplateAsset()->LogWarning(Message, this); + } +#endif + } +#endif +} + +void UFlowNode::LogNote(FString Message) +{ +#if !UE_BUILD_SHIPPING + if (BuildMessage(Message)) + { + // Output Log + UE_LOG(LogFlow, Log, TEXT("%s"), *Message); + + // Message Log +#if WITH_EDITOR + GetFlowAsset()->GetTemplateAsset()->LogNote(Message, this); +#endif + } +#endif +} + +#if !UE_BUILD_SHIPPING +bool UFlowNode::BuildMessage(FString& Message) const +{ + if (GetFlowAsset()->TemplateAsset) // this is runtime log which is should be only called on runtime instances of asset + { + const FString TemplatePath = GetFlowAsset()->TemplateAsset->GetPathName(); + Message.Append(TEXT(" --- node ")).Append(GetName()).Append(TEXT(", asset ")).Append(FPaths::GetPath(TemplatePath) / FPaths::GetBaseFilename(TemplatePath)); + return true; + } + + return false; +} +#endif diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp index 9182f0140..04bbe1e68 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp @@ -49,11 +49,11 @@ void UFlowNode_SubGraph::ExecuteInput(const FName& PinName) { if (Asset.IsNull()) { - LogRuntimeError(TEXT("Missing Flow Asset")); + LogError(TEXT("Missing Flow Asset")); } else { - LogRuntimeError(FString::Printf(TEXT("Asset %s cannot be instance, probably is the same as the asset owning this SubGraph node."), *Asset->GetPathName())); + LogError(FString::Printf(TEXT("Asset %s cannot be instance, probably is the same as the asset owning this SubGraph node."), *Asset->GetPathName())); } Finish(); diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp index 663e47240..3e14f88cb 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp @@ -31,7 +31,7 @@ void UFlowNode_Timer::ExecuteInput(const FName& PinName) { if (CompletionTime == 0.0f) { - LogRuntimeError(TEXT("Invalid Timer settings")); + LogError(TEXT("Invalid Timer settings")); TriggerOutput(TEXT("Completed"), true); return; } @@ -40,7 +40,7 @@ void UFlowNode_Timer::ExecuteInput(const FName& PinName) { if (CompletionTimerHandle.IsValid() || StepTimerHandle.IsValid()) { - LogRuntimeError(TEXT("Timer already active")); + LogError(TEXT("Timer already active")); return; } @@ -69,7 +69,7 @@ void UFlowNode_Timer::SetTimer() } else { - LogRuntimeError(TEXT("No valid world")); + LogError(TEXT("No valid world")); TriggerOutput(TEXT("Completed"), true); } } diff --git a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp index f0676f895..73151f305 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp @@ -33,7 +33,7 @@ void UFlowNode_ComponentObserver::ExecuteInput(const FName& PinName) } else { - LogRuntimeError(MissingIdentityTag); + LogError(MissingIdentityTag); } } diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 9eb4ce264..adeb3b63e 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -377,24 +377,6 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UFUNCTION(BlueprintPure, Category = "FlowNode") static FString GetProgressAsString(float Value); - UE_DEPRECATED(5.0, "LogError has been deprecated. Use LogRuntimeError instead.") - UFUNCTION(BlueprintCallable, Category = "FlowNode", meta = (DevelopmentOnly), meta=(DeprecatedFunction, DeprecationMessage="Use LogRuntimeError instead.")) - void LogError(FString Message, const EFlowOnScreenMessageType OnScreenMessageType = EFlowOnScreenMessageType::Permanent); - - UFUNCTION(BlueprintCallable, Category = "FlowNode", meta = (DevelopmentOnly)) - void LogRuntimeError(FString Message, const EFlowOnScreenMessageType OnScreenMessageType = EFlowOnScreenMessageType::Permanent); - - UFUNCTION(BlueprintCallable, Category = "FlowNode", meta = (DevelopmentOnly)) - void LogRuntimeWarning(FString Message); - - UFUNCTION(BlueprintCallable, Category = "FlowNode", meta = (DevelopmentOnly)) - void LogRuntimeNote(FString Message); - -#if !UE_BUILD_SHIPPING -private: - void BuildMessage(FString& Message) const; -#endif - public: UFUNCTION(BlueprintCallable, Category = "FlowNode") void SaveInstance(FFlowNodeSaveData& NodeRecord); @@ -411,4 +393,19 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UFUNCTION(BlueprintNativeEvent, Category = "FlowNode") void OnPassThrough(); + +public: + UFUNCTION(BlueprintCallable, Category = "FlowNode", meta = (DevelopmentOnly)) + void LogError(FString Message, const EFlowOnScreenMessageType OnScreenMessageType = EFlowOnScreenMessageType::Permanent); + + UFUNCTION(BlueprintCallable, Category = "FlowNode", meta = (DevelopmentOnly)) + void LogWarning(FString Message); + + UFUNCTION(BlueprintCallable, Category = "FlowNode", meta = (DevelopmentOnly)) + void LogNote(FString Message); + +#if !UE_BUILD_SHIPPING +private: + bool BuildMessage(FString& Message) const; +#endif }; From 6b884bf3cb47aaf44831741f799c40a797a878c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Mon, 20 Feb 2023 19:08:53 +0100 Subject: [PATCH 261/338] optimized building debug-only status strings --- Source/Flow/Private/Nodes/FlowNode.cpp | 35 ++----------------- .../Private/Nodes/Route/FlowNode_Timer.cpp | 8 ++--- .../World/FlowNode_PlayLevelSequence.cpp | 2 +- Source/Flow/Public/Nodes/FlowNode.h | 30 ++++++++-------- 4 files changed, 23 insertions(+), 52 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 8b1b2aca6..17325db06 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -626,40 +626,9 @@ FString UFlowNode::GetClassDescription(const TSubclassOf Class) return Class ? Class->GetName() : MissingClass; } -FString UFlowNode::GetProgressAsString(float Value) +FString UFlowNode::GetProgressAsString(const float Value) { - // Avoids negative zero - if (Value == 0) - { - Value = 0; - } - - // First create the string - FString TempString = FString::Printf(TEXT("%f"), Value); - if (!TempString.IsNumeric()) - { - // String did not format as a valid decimal number so avoid messing with it - return TempString; - } - - // Get position of the first digit after decimal separator - int32 TrimIndex = INDEX_NONE; - for (int32 CharIndex = 0; CharIndex < TempString.Len(); CharIndex++) - { - const TCHAR Char = TempString[CharIndex]; - if (Char == TEXT('.')) - { - TrimIndex = CharIndex + 2; - break; - } - if (TrimIndex == INDEX_NONE && Char != TEXT('0')) - { - TrimIndex = CharIndex + 1; - } - } - - TempString.RemoveAt(TrimIndex, TempString.Len() - TrimIndex, /*bAllowShrinking*/false); - return TempString; + return FString::Printf(TEXT("%.*f"), 2, Value); } void UFlowNode::SaveInstance(FFlowNodeSaveData& NodeRecord) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp index 3e14f88cb..bd32bf146 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp @@ -159,10 +159,10 @@ FString UFlowNode_Timer::GetNodeDescription() const { if (StepTime > 0.0f) { - return FString::SanitizeFloat(CompletionTime, 2).Append(TEXT(", step by ")).Append(FString::SanitizeFloat(StepTime, 2)); + return FString::Printf(TEXT("%.*f, step by %.*f"), 2, CompletionTime, 2, StepTime); } - return FString::SanitizeFloat(CompletionTime, 2); + return FString::Printf(TEXT("%.*f"), 2, CompletionTime); } return TEXT("Invalid settings"); @@ -172,12 +172,12 @@ FString UFlowNode_Timer::GetStatusString() const { if (StepTime > 0.0f) { - return TEXT("Progress: ") + GetProgressAsString(SumOfSteps); + return FString::Printf(TEXT("Progress: %.*f"), 2, SumOfSteps); } if (CompletionTimerHandle.IsValid() && GetWorld()) { - return TEXT("Progress: ") + GetProgressAsString(GetWorld()->GetTimerManager().GetTimerElapsed(CompletionTimerHandle)); + return FString::Printf(TEXT("Progress: %.*f"), 2, GetWorld()->GetTimerManager().GetTimerElapsed(CompletionTimerHandle)); } return FString(); diff --git a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp index 8a8b28740..00c3cce6b 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp @@ -302,7 +302,7 @@ FString UFlowNode_PlayLevelSequence::GetPlaybackProgress() const { if (SequencePlayer && SequencePlayer->IsPlaying()) { - return GetProgressAsString(SequencePlayer->GetCurrentTime().AsSeconds() - StartTime).Append(TEXT(" / ")).Append(GetProgressAsString(SequencePlayer->GetDuration().AsSeconds())); + return FString::Printf(TEXT("%.*f / %.*f"), 2, SequencePlayer->GetCurrentTime().AsSeconds() - StartTime, 2, SequencePlayer->GetDuration().AsSeconds()); } return FString(); diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index adeb3b63e..f4e83d7e2 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -27,7 +27,6 @@ UCLASS(Abstract, Blueprintable, HideCategories = Object) class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInterface { GENERATED_UCLASS_BODY() - friend class SFlowGraphNode; friend class UFlowAsset; friend class UFlowGraphNode; @@ -43,10 +42,11 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UEdGraphNode* GraphNode; #if WITH_EDITORONLY_DATA + protected: TArray> AllowedAssetClasses; TArray> DeniedAssetClasses; - + UPROPERTY() FString Category; @@ -58,7 +58,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UPROPERTY(EditDefaultsOnly, Category = "FlowNode") bool bNodeDeprecated; - + // If this node is deprecated, it might be replaced by another node UPROPERTY(EditDefaultsOnly, Category = "FlowNode") TSubclassOf ReplacedBy; @@ -91,7 +91,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte virtual FString GetNodeCategory() const; virtual FText GetNodeTitle() const; virtual FText GetNodeToolTip() const; - + // This method allows to have different for every node instance, i.e. Red if node represents enemy, Green if node represents a friend virtual bool GetDynamicTitleColor(FLinearColor& OutColor) const { return false; } @@ -123,7 +123,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte protected: UPROPERTY(EditDefaultsOnly, Category = "FlowNode") TArray AllowedSignalModes; - + // If enabled, signal will pass through node without calling ExecuteInput() // Designed to handle patching UPROPERTY() @@ -131,8 +131,8 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte #if WITH_EDITOR FFlowMessageLog ValidationLog; -#endif - +#endif + ////////////////////////////////////////////////////////////////////////// // All created pins (default, class-specific and added by user) @@ -158,7 +158,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte uint8 CountNumberedInputs() const; uint8 CountNumberedOutputs() const; - + TArray GetInputPins() const { return InputPins; } TArray GetOutputPins() const { return OutputPins; } @@ -235,10 +235,11 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UPROPERTY(SaveGame) EFlowNodeState ActivationState; -public: +public: EFlowNodeState GetActivationState() const { return ActivationState; } - + #if !UE_BUILD_SHIPPING + private: TMap> InputRecords; TMap> OutputRecords; @@ -278,7 +279,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "On Activate")) void K2_OnActivate(); - + // Trigger execution of input pin void TriggerInput(const FName& PinName, const EFlowPinActivationType ActivationType = EFlowPinActivationType::Default); @@ -329,6 +330,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte void ResetRecords(); #if WITH_EDITOR + public: UFlowNode* GetInspectedInstance() const; @@ -377,7 +379,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UFUNCTION(BlueprintPure, Category = "FlowNode") static FString GetProgressAsString(float Value); -public: +public: UFUNCTION(BlueprintCallable, Category = "FlowNode") void SaveInstance(FFlowNodeSaveData& NodeRecord); @@ -387,7 +389,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte protected: UFUNCTION(BlueprintNativeEvent, Category = "FlowNode") void OnSave(); - + UFUNCTION(BlueprintNativeEvent, Category = "FlowNode") void OnLoad(); @@ -400,7 +402,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UFUNCTION(BlueprintCallable, Category = "FlowNode", meta = (DevelopmentOnly)) void LogWarning(FString Message); - + UFUNCTION(BlueprintCallable, Category = "FlowNode", meta = (DevelopmentOnly)) void LogNote(FString Message); From a7fda43b1dfd24c4410e0cfab4889aca1479d7e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Mon, 20 Feb 2023 21:35:28 +0100 Subject: [PATCH 262/338] improved filtering of given Flow Node subclasses --- .../Private/Graph/FlowGraphSchema.cpp | 17 ++++++++++------- .../FlowEditor/Public/Graph/FlowGraphSchema.h | 2 +- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp index 022327050..e60a6a5fb 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -24,7 +24,7 @@ bool UFlowGraphSchema::bInitialGatherPerformed = false; TArray UFlowGraphSchema::NativeFlowNodes; TMap UFlowGraphSchema::BlueprintFlowNodes; -TMap UFlowGraphSchema::AssignedGraphNodeClasses; +TMap UFlowGraphSchema::GraphNodesByFlowNodes; bool UFlowGraphSchema::bBlueprintCompilationPending; @@ -237,9 +237,12 @@ TArray> UFlowGraphSchema::GetFlowNodeCategories() UClass* UFlowGraphSchema::GetAssignedGraphNodeClass(const UClass* FlowNodeClass) { - if (UClass* AssignedGraphNode = AssignedGraphNodeClasses.FindRef(FlowNodeClass)) + for (const TPair& GraphNodeByFlowNode : GraphNodesByFlowNodes) { - return AssignedGraphNode; + if (FlowNodeClass->IsChildOf(GraphNodeByFlowNode.Key)) + { + return GraphNodeByFlowNode.Value; + } } return UFlowGraphNode::StaticClass(); @@ -422,14 +425,14 @@ void UFlowGraphSchema::GatherNativeNodes() TArray GraphNodes; GetDerivedClasses(UFlowGraphNode::StaticClass(), GraphNodes); - for (UClass* Class : GraphNodes) + for (UClass* GraphNodeClass : GraphNodes) { - const UFlowGraphNode* DefaultObject = Class->GetDefaultObject(); - for (UClass* AssignedClass : DefaultObject->AssignedNodeClasses) + const UFlowGraphNode* GraphNodeCDO = GraphNodeClass->GetDefaultObject(); + for (UClass* AssignedClass : GraphNodeCDO->AssignedNodeClasses) { if (AssignedClass->IsChildOf(UFlowNode::StaticClass())) { - AssignedGraphNodeClasses.Emplace(AssignedClass, Class); + GraphNodesByFlowNodes.Emplace(AssignedClass, GraphNodeClass); } } } diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h index 3a5b4ef58..8ceb89ff6 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h @@ -21,7 +21,7 @@ class FLOWEDITOR_API UFlowGraphSchema : public UEdGraphSchema static bool bInitialGatherPerformed; static TArray NativeFlowNodes; static TMap BlueprintFlowNodes; - static TMap AssignedGraphNodeClasses; + static TMap GraphNodesByFlowNodes; static bool bBlueprintCompilationPending; From e0c170833ea8c1a030126d6bc828c5bd2c382ca5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Mon, 20 Feb 2023 19:25:22 +0100 Subject: [PATCH 263/338] auto-format --- Source/FlowEditor/Public/Graph/FlowGraphSettings.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h index 8f5b3fa49..13eab763b 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h @@ -15,7 +15,6 @@ UCLASS(Config = Editor, defaultconfig, meta = (DisplayName = "Flow Graph")) class FLOWEDITOR_API UFlowGraphSettings : public UDeveloperSettings { GENERATED_UCLASS_BODY() - static UFlowGraphSettings* Get() { return StaticClass()->GetDefaultObject(); } /** Show Flow Asset in Flow category of "Create Asset" menu? @@ -27,7 +26,7 @@ class FLOWEDITOR_API UFlowGraphSettings : public UDeveloperSettings * Requires restart after making a change. */ UPROPERTY(EditAnywhere, config, Category = "Default UI", meta = (ConfigRestartRequired = true)) bool bExposeFlowNodeCreation; - + /** Show Flow Asset toolbar? * Requires restart after making a change. */ UPROPERTY(EditAnywhere, config, Category = "Default UI", meta = (ConfigRestartRequired = true)) @@ -43,7 +42,7 @@ class FLOWEDITOR_API UFlowGraphSettings : public UDeveloperSettings /** Flow Asset class allowed to be assigned via Level Editor toolbar*/ UPROPERTY(EditAnywhere, config, Category = "Default UI", meta = (EditCondition = "bShowAssetToolbarAboveLevelEditor")) TSubclassOf WorldAssetClass; - + /** Hide specific nodes from the Flow Palette without changing the source code. * Requires restart after making a change. */ UPROPERTY(EditAnywhere, config, Category = "Nodes") @@ -79,7 +78,7 @@ class FLOWEDITOR_API UFlowGraphSettings : public UDeveloperSettings UPROPERTY(config, EditAnywhere, Category = "Wires", meta = (EditCondition = "ConnectionDrawType == EFlowConnectionDrawType::Circuit")) FVector2D CircuitConnectionSpacing; - + UPROPERTY(EditAnywhere, config, Category = "Wires") FLinearColor InactiveWireColor; From ec57343ac7e2b3e531731c3b4dd17fcd145e07f4 Mon Sep 17 00:00:00 2001 From: Markus Ahrweiler Date: Sat, 11 Mar 2023 16:37:37 +0100 Subject: [PATCH 264/338] Makes LoadRootFlow & LoadSubFlow accessible to Blueprints (#149) --- Source/Flow/Public/FlowSubsystem.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index 62d468384..aab9b3769 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -119,7 +119,9 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem UFUNCTION(BlueprintCallable, Category = "FlowSubsystem") virtual void OnGameLoaded(UFlowSaveGame* SaveGame); + UFUNCTION(BlueprintCallable, Category = "FlowSubsystem") virtual void LoadRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const FString& SavedAssetInstanceName); + UFUNCTION(BlueprintCallable, Category = "FlowSubsystem") virtual void LoadSubFlow(UFlowNode_SubGraph* SubGraphNode, const FString& SavedAssetInstanceName); UFUNCTION(BlueprintPure, Category = "FlowSubsystem") From c38643466c1e2faf7e1a32fe479209d9570f247e Mon Sep 17 00:00:00 2001 From: "Satheesh (ryanjon2040)" Date: Sat, 11 Mar 2023 21:16:21 +0530 Subject: [PATCH 265/338] Add an option to hide node description when PIE is active (#147) --- Source/FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp | 1 + Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp | 3 ++- Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h | 4 ++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp b/Source/FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp index a09ae135b..9692ff114 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp @@ -8,6 +8,7 @@ UFlowGraphEditorSettings::UFlowGraphEditorSettings(const FObjectInitializer& Obj : Super(ObjectInitializer) , NodeDoubleClickTarget(EFlowNodeDoubleClickTarget::PrimaryAsset) , bShowNodeClass(false) + , bHideNodeDescriptionOnPIE(false) , bShowSubGraphPreview(true) , bShowSubGraphPath(true) , SubGraphPreviewSize(FVector2D(640.f, 360.f)) diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp index cc1ce6da5..a9d53bb11 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp @@ -21,6 +21,7 @@ #include "SNodePanel.h" #include "Styling/SlateColor.h" #include "TutorialMetaData.h" +#include "Graph/FlowGraphEditorSettings.h" #include "Widgets/Images/SImage.h" #include "Widgets/Layout/SBorder.h" #include "Widgets/SBoxPanel.h" @@ -54,7 +55,7 @@ void SFlowGraphNode::Construct(const FArguments& InArgs, UFlowGraphNode* InNode) void SFlowGraphNode::GetNodeInfoPopups(FNodeInfoContext* Context, TArray& Popups) const { - const FString Description = FlowGraphNode->GetNodeDescription(); + const FString Description = GEditor->PlayWorld && UFlowGraphEditorSettings::Get()->bHideNodeDescriptionOnPIE ? "" : FlowGraphNode->GetNodeDescription(); if (!Description.IsEmpty()) { const FGraphInformationPopupInfo DescriptionPopup = FGraphInformationPopupInfo(nullptr, UFlowGraphSettings::Get()->NodeDescriptionBackground, Description); diff --git a/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h b/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h index 6f3cb06b1..0a07f8ae8 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h @@ -30,6 +30,10 @@ class FLOWEDITOR_API UFlowGraphEditorSettings : public UDeveloperSettings UPROPERTY(config, EditAnywhere, Category = "Nodes") bool bShowNodeClass; + // Hides the node description when you play in editor and only shows node status string. + UPROPERTY(config, EditAnywhere, Category = "Nodes") + bool bHideNodeDescriptionOnPIE; + // Renders preview of entire graph while hovering over UPROPERTY(config, EditAnywhere, Category = "Nodes") bool bShowSubGraphPreview; From f6c0c0e9a67cfbd445a71e6f3c89fdf62f1f2d56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sat, 11 Mar 2023 17:00:05 +0100 Subject: [PATCH 266/338] cosmetic improvements to accepted PRs --- Source/Flow/Public/FlowSubsystem.h | 1 + Source/FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp | 2 +- Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp | 2 +- Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index aab9b3769..a171a245e 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -121,6 +121,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem UFUNCTION(BlueprintCallable, Category = "FlowSubsystem") virtual void LoadRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const FString& SavedAssetInstanceName); + UFUNCTION(BlueprintCallable, Category = "FlowSubsystem") virtual void LoadSubFlow(UFlowNode_SubGraph* SubGraphNode, const FString& SavedAssetInstanceName); diff --git a/Source/FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp b/Source/FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp index 9692ff114..ed81e3d11 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp @@ -8,7 +8,7 @@ UFlowGraphEditorSettings::UFlowGraphEditorSettings(const FObjectInitializer& Obj : Super(ObjectInitializer) , NodeDoubleClickTarget(EFlowNodeDoubleClickTarget::PrimaryAsset) , bShowNodeClass(false) - , bHideNodeDescriptionOnPIE(false) + , bShowNodeDescriptionInPIE(true) , bShowSubGraphPreview(true) , bShowSubGraphPath(true) , SubGraphPreviewSize(FVector2D(640.f, 360.f)) diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp index a9d53bb11..3c440612d 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp @@ -55,7 +55,7 @@ void SFlowGraphNode::Construct(const FArguments& InArgs, UFlowGraphNode* InNode) void SFlowGraphNode::GetNodeInfoPopups(FNodeInfoContext* Context, TArray& Popups) const { - const FString Description = GEditor->PlayWorld && UFlowGraphEditorSettings::Get()->bHideNodeDescriptionOnPIE ? "" : FlowGraphNode->GetNodeDescription(); + const FString Description = GEditor->PlayWorld && UFlowGraphEditorSettings::Get()->bShowNodeDescriptionInPIE ? FString() : FlowGraphNode->GetNodeDescription(); if (!Description.IsEmpty()) { const FGraphInformationPopupInfo DescriptionPopup = FGraphInformationPopupInfo(nullptr, UFlowGraphSettings::Get()->NodeDescriptionBackground, Description); diff --git a/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h b/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h index 0a07f8ae8..8f2a14961 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h @@ -32,7 +32,7 @@ class FLOWEDITOR_API UFlowGraphEditorSettings : public UDeveloperSettings // Hides the node description when you play in editor and only shows node status string. UPROPERTY(config, EditAnywhere, Category = "Nodes") - bool bHideNodeDescriptionOnPIE; + bool bShowNodeDescriptionInPIE; // Renders preview of entire graph while hovering over UPROPERTY(config, EditAnywhere, Category = "Nodes") From 460d318758055fba2220f4c0e581f45720d8c899 Mon Sep 17 00:00:00 2001 From: "Satheesh (ryanjon2040)" Date: Sat, 11 Mar 2023 23:55:32 +0530 Subject: [PATCH 267/338] More keywords to make search easier for multiple nodes (#144) * More keywords to make search easier for multiple nodes * Add print keyword to log node * Mooarrrr keywords --- Source/Flow/Public/Nodes/Operators/FlowNode_LogicalAND.h | 2 +- Source/Flow/Public/Nodes/Operators/FlowNode_LogicalOR.h | 2 +- Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h | 2 +- Source/Flow/Public/Nodes/Route/FlowNode_Finish.h | 2 +- Source/Flow/Public/Nodes/Utils/FlowNode_Checkpoint.h | 2 +- Source/Flow/Public/Nodes/Utils/FlowNode_Log.h | 2 +- Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h | 2 +- Source/Flow/Public/Nodes/World/FlowNode_OnActorRegistered.h | 2 +- Source/Flow/Public/Nodes/World/FlowNode_OnActorUnregistered.h | 2 +- Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalAND.h b/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalAND.h index b646bf773..6296d07e1 100644 --- a/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalAND.h +++ b/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalAND.h @@ -9,7 +9,7 @@ * Logical AND * Output will be triggered only once */ -UCLASS(NotBlueprintable, meta = (DisplayName = "AND")) +UCLASS(NotBlueprintable, meta = (DisplayName = "AND", Keywords = "&")) class FLOW_API UFlowNode_LogicalAND final : public UFlowNode { GENERATED_UCLASS_BODY() diff --git a/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalOR.h b/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalOR.h index 3265478a3..70ea21e82 100644 --- a/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalOR.h +++ b/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalOR.h @@ -9,7 +9,7 @@ * Logical OR * Output will be triggered only once */ -UCLASS(NotBlueprintable, meta = (DisplayName = "OR")) +UCLASS(NotBlueprintable, meta = (DisplayName = "OR", Keywords = "|")) class FLOW_API UFlowNode_LogicalOR final : public UFlowNode { GENERATED_UCLASS_BODY() diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h index da039c221..8c440aabe 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h @@ -8,7 +8,7 @@ /** * Executes a series of pins in order */ -UCLASS(NotBlueprintable, meta = (DisplayName = "Multi Gate")) +UCLASS(NotBlueprintable, meta = (DisplayName = "Multi Gate", Keywords = "series, order, loop, random")) class FLOW_API UFlowNode_ExecutionMultiGate final : public UFlowNode { GENERATED_UCLASS_BODY() diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_Finish.h b/Source/Flow/Public/Nodes/Route/FlowNode_Finish.h index a9f9299b6..2f44851fe 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_Finish.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_Finish.h @@ -9,7 +9,7 @@ * Finish execution of this Flow Asset * All active nodes and sub graphs will be deactivated */ -UCLASS(NotBlueprintable, meta = (DisplayName = "Finish")) +UCLASS(NotBlueprintable, meta = (DisplayName = "Finish", Keywords = "stop, disable, deactivate")) class FLOW_API UFlowNode_Finish : public UFlowNode { GENERATED_UCLASS_BODY() diff --git a/Source/Flow/Public/Nodes/Utils/FlowNode_Checkpoint.h b/Source/Flow/Public/Nodes/Utils/FlowNode_Checkpoint.h index cc2b4dac8..814df107c 100644 --- a/Source/Flow/Public/Nodes/Utils/FlowNode_Checkpoint.h +++ b/Source/Flow/Public/Nodes/Utils/FlowNode_Checkpoint.h @@ -9,7 +9,7 @@ * Save the state of the game to the save file * It's recommended to replace this with game-specific variant and this node to UFlowGraphSettings::HiddenNodes */ -UCLASS(NotBlueprintable, meta = (DisplayName = "Checkpoint")) +UCLASS(NotBlueprintable, meta = (DisplayName = "Checkpoint", Keywords = "save, state")) class FLOW_API UFlowNode_Checkpoint final : public UFlowNode { GENERATED_UCLASS_BODY() diff --git a/Source/Flow/Public/Nodes/Utils/FlowNode_Log.h b/Source/Flow/Public/Nodes/Utils/FlowNode_Log.h index 5c74fcc5b..89c1fef8f 100644 --- a/Source/Flow/Public/Nodes/Utils/FlowNode_Log.h +++ b/Source/Flow/Public/Nodes/Utils/FlowNode_Log.h @@ -21,7 +21,7 @@ enum class EFlowLogVerbosity : uint8 * Adds message to log * Optionally shows message on screen */ -UCLASS(NotBlueprintable, meta = (DisplayName = "Log")) +UCLASS(NotBlueprintable, meta = (DisplayName = "Log", Keywords = "print")) class FLOW_API UFlowNode_Log : public UFlowNode { GENERATED_UCLASS_BODY() diff --git a/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h b/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h index 63f3e8c37..fa7b712b1 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h @@ -10,7 +10,7 @@ /** * Finds all Flow Components with matching Identity Tag and calls ReceiveNotify event on these components */ -UCLASS(NotBlueprintable, meta = (DisplayName = "Notify Actor")) +UCLASS(NotBlueprintable, meta = (DisplayName = "Notify Actor", Keywords = "event")) class FLOW_API UFlowNode_NotifyActor : public UFlowNode { GENERATED_UCLASS_BODY() diff --git a/Source/Flow/Public/Nodes/World/FlowNode_OnActorRegistered.h b/Source/Flow/Public/Nodes/World/FlowNode_OnActorRegistered.h index 59882d377..ecf4b9e56 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_OnActorRegistered.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_OnActorRegistered.h @@ -8,7 +8,7 @@ /** * Triggers output when Flow Component with matching Identity Tag appears in the world */ -UCLASS(NotBlueprintable, meta = (DisplayName = "On Actor Registered")) +UCLASS(NotBlueprintable, meta = (DisplayName = "On Actor Registered", Keywords = "bind")) class FLOW_API UFlowNode_OnActorRegistered : public UFlowNode_ComponentObserver { GENERATED_UCLASS_BODY() diff --git a/Source/Flow/Public/Nodes/World/FlowNode_OnActorUnregistered.h b/Source/Flow/Public/Nodes/World/FlowNode_OnActorUnregistered.h index fccad314e..4d44d740f 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_OnActorUnregistered.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_OnActorUnregistered.h @@ -8,7 +8,7 @@ /** * Triggers output when Flow Component with matching Identity Tag disappears from the world */ -UCLASS(NotBlueprintable, meta = (DisplayName = "On Actor Unregistered")) +UCLASS(NotBlueprintable, meta = (DisplayName = "On Actor Unregistered", Keywords = "unbind")) class FLOW_API UFlowNode_OnActorUnregistered : public UFlowNode_ComponentObserver { GENERATED_UCLASS_BODY() diff --git a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h index ad118d008..6825337ba 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h @@ -20,7 +20,7 @@ DECLARE_MULTICAST_DELEGATE(FFlowNodeLevelSequenceEvent); * - Out (always, even if Sequence is invalid) * - Completed */ -UCLASS(NotBlueprintable, meta = (DisplayName = "Play Level Sequence")) +UCLASS(NotBlueprintable, meta = (DisplayName = "Play Level Sequence", Keywords = "camera, cinematic, cutscene, movie")) class FLOW_API UFlowNode_PlayLevelSequence : public UFlowNode { GENERATED_UCLASS_BODY() From 65f77928b323e7b14a96d65388d3eb3e4f60577a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sat, 11 Mar 2023 19:28:52 +0100 Subject: [PATCH 268/338] created SaveGame section in class layout --- Source/Flow/Private/Nodes/FlowNode.cpp | 126 ++++++++++++------------- Source/Flow/Public/Nodes/FlowNode.h | 41 ++++---- 2 files changed, 86 insertions(+), 81 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 17325db06..4a01ce343 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -546,6 +546,69 @@ void UFlowNode::ResetRecords() #endif } +void UFlowNode::SaveInstance(FFlowNodeSaveData& NodeRecord) +{ + NodeRecord.NodeGuid = NodeGuid; + OnSave(); + + FMemoryWriter MemoryWriter(NodeRecord.NodeData, true); + FFlowArchive Ar(MemoryWriter); + Serialize(Ar); +} + +void UFlowNode::LoadInstance(const FFlowNodeSaveData& NodeRecord) +{ + FMemoryReader MemoryReader(NodeRecord.NodeData, true); + FFlowArchive Ar(MemoryReader); + Serialize(Ar); + + if (UFlowAsset* FlowAsset = GetFlowAsset()) + { + FlowAsset->OnActivationStateLoaded(this); + } + + switch (SignalMode) + { + case EFlowSignalMode::Enabled: + OnLoad(); + break; + case EFlowSignalMode::Disabled: + // designer doesn't want to execute this node's logic at all, so we kill it + LogNote(TEXT("Signal disabled while loading Flow Node from SaveGame")); + Finish(); + break; + case EFlowSignalMode::PassThrough: + LogNote(TEXT("Signal pass-through on loading Flow Node from SaveGame")); + OnPassThrough(); + break; + default: ; + } +} + +void UFlowNode::OnSave_Implementation() +{ +} + +void UFlowNode::OnLoad_Implementation() +{ +} + +void UFlowNode::OnPassThrough_Implementation() +{ + // trigger all connected outputs + // pin connections aren't serialized to the SaveGame, so users can safely change connections post game release + for (const FFlowPin& OutputPin : OutputPins) + { + if (Connections.Contains(OutputPin.PinName)) + { + TriggerOutput(OutputPin.PinName, false, EFlowPinActivationType::PassThrough); + } + } + + // deactivate node, so it doesn't get saved to a new SaveGame + Finish(); +} + #if WITH_EDITOR UFlowNode* UFlowNode::GetInspectedInstance() const { @@ -631,69 +694,6 @@ FString UFlowNode::GetProgressAsString(const float Value) return FString::Printf(TEXT("%.*f"), 2, Value); } -void UFlowNode::SaveInstance(FFlowNodeSaveData& NodeRecord) -{ - NodeRecord.NodeGuid = NodeGuid; - OnSave(); - - FMemoryWriter MemoryWriter(NodeRecord.NodeData, true); - FFlowArchive Ar(MemoryWriter); - Serialize(Ar); -} - -void UFlowNode::LoadInstance(const FFlowNodeSaveData& NodeRecord) -{ - FMemoryReader MemoryReader(NodeRecord.NodeData, true); - FFlowArchive Ar(MemoryReader); - Serialize(Ar); - - if (UFlowAsset* FlowAsset = GetFlowAsset()) - { - FlowAsset->OnActivationStateLoaded(this); - } - - switch (SignalMode) - { - case EFlowSignalMode::Enabled: - OnLoad(); - break; - case EFlowSignalMode::Disabled: - // designer doesn't want to execute this node's logic at all, so we kill it - LogNote(TEXT("Signal disabled while loading Flow Node from SaveGame")); - Finish(); - break; - case EFlowSignalMode::PassThrough: - LogNote(TEXT("Signal pass-through on loading Flow Node from SaveGame")); - OnPassThrough(); - break; - default: ; - } -} - -void UFlowNode::OnSave_Implementation() -{ -} - -void UFlowNode::OnLoad_Implementation() -{ -} - -void UFlowNode::OnPassThrough_Implementation() -{ - // trigger all connected outputs - // pin connections aren't serialized to the SaveGame, so users can safely change connections post game release - for (const FFlowPin& OutputPin : OutputPins) - { - if (Connections.Contains(OutputPin.PinName)) - { - TriggerOutput(OutputPin.PinName, false, EFlowPinActivationType::PassThrough); - } - } - - // deactivate node, so it doesn't get saved to a new SaveGame - Finish(); -} - void UFlowNode::LogError(FString Message, const EFlowOnScreenMessageType OnScreenMessageType) { #if !UE_BUILD_SHIPPING diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index f4e83d7e2..e7543d435 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -329,8 +329,30 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte private: void ResetRecords(); -#if WITH_EDITOR +////////////////////////////////////////////////////////////////////////// +// SaveGame support + +public: + UFUNCTION(BlueprintCallable, Category = "FlowNode") + void SaveInstance(FFlowNodeSaveData& NodeRecord); + + UFUNCTION(BlueprintCallable, Category = "FlowNode") + void LoadInstance(const FFlowNodeSaveData& NodeRecord); + +protected: + UFUNCTION(BlueprintNativeEvent, Category = "FlowNode") + void OnSave(); + + UFUNCTION(BlueprintNativeEvent, Category = "FlowNode") + void OnLoad(); + + UFUNCTION(BlueprintNativeEvent, Category = "FlowNode") + void OnPassThrough(); + +////////////////////////////////////////////////////////////////////////// +// Utils +#if WITH_EDITOR public: UFlowNode* GetInspectedInstance() const; @@ -379,23 +401,6 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UFUNCTION(BlueprintPure, Category = "FlowNode") static FString GetProgressAsString(float Value); -public: - UFUNCTION(BlueprintCallable, Category = "FlowNode") - void SaveInstance(FFlowNodeSaveData& NodeRecord); - - UFUNCTION(BlueprintCallable, Category = "FlowNode") - void LoadInstance(const FFlowNodeSaveData& NodeRecord); - -protected: - UFUNCTION(BlueprintNativeEvent, Category = "FlowNode") - void OnSave(); - - UFUNCTION(BlueprintNativeEvent, Category = "FlowNode") - void OnLoad(); - - UFUNCTION(BlueprintNativeEvent, Category = "FlowNode") - void OnPassThrough(); - public: UFUNCTION(BlueprintCallable, Category = "FlowNode", meta = (DevelopmentOnly)) void LogError(FString Message, const EFlowOnScreenMessageType OnScreenMessageType = EFlowOnScreenMessageType::Permanent); From 7cbdfad93b4796122296e853aea3535f2fd640f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sat, 11 Mar 2023 19:36:09 +0100 Subject: [PATCH 269/338] minor changes to search keywords, avoiding confusion in project with custom nodes --- Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h | 2 +- Source/Flow/Public/Nodes/Route/FlowNode_Finish.h | 2 +- Source/Flow/Public/Nodes/Utils/FlowNode_Checkpoint.h | 2 +- Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h index 8c440aabe..262529cbc 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h @@ -8,7 +8,7 @@ /** * Executes a series of pins in order */ -UCLASS(NotBlueprintable, meta = (DisplayName = "Multi Gate", Keywords = "series, order, loop, random")) +UCLASS(NotBlueprintable, meta = (DisplayName = "Multi Gate", Keywords = "series, loop, random")) class FLOW_API UFlowNode_ExecutionMultiGate final : public UFlowNode { GENERATED_UCLASS_BODY() diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_Finish.h b/Source/Flow/Public/Nodes/Route/FlowNode_Finish.h index 2f44851fe..a9f9299b6 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_Finish.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_Finish.h @@ -9,7 +9,7 @@ * Finish execution of this Flow Asset * All active nodes and sub graphs will be deactivated */ -UCLASS(NotBlueprintable, meta = (DisplayName = "Finish", Keywords = "stop, disable, deactivate")) +UCLASS(NotBlueprintable, meta = (DisplayName = "Finish")) class FLOW_API UFlowNode_Finish : public UFlowNode { GENERATED_UCLASS_BODY() diff --git a/Source/Flow/Public/Nodes/Utils/FlowNode_Checkpoint.h b/Source/Flow/Public/Nodes/Utils/FlowNode_Checkpoint.h index 814df107c..a4ce5605e 100644 --- a/Source/Flow/Public/Nodes/Utils/FlowNode_Checkpoint.h +++ b/Source/Flow/Public/Nodes/Utils/FlowNode_Checkpoint.h @@ -9,7 +9,7 @@ * Save the state of the game to the save file * It's recommended to replace this with game-specific variant and this node to UFlowGraphSettings::HiddenNodes */ -UCLASS(NotBlueprintable, meta = (DisplayName = "Checkpoint", Keywords = "save, state")) +UCLASS(NotBlueprintable, meta = (DisplayName = "Checkpoint", Keywords = "autosave, save")) class FLOW_API UFlowNode_Checkpoint final : public UFlowNode { GENERATED_UCLASS_BODY() diff --git a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h index 6825337ba..ad118d008 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h @@ -20,7 +20,7 @@ DECLARE_MULTICAST_DELEGATE(FFlowNodeLevelSequenceEvent); * - Out (always, even if Sequence is invalid) * - Completed */ -UCLASS(NotBlueprintable, meta = (DisplayName = "Play Level Sequence", Keywords = "camera, cinematic, cutscene, movie")) +UCLASS(NotBlueprintable, meta = (DisplayName = "Play Level Sequence")) class FLOW_API UFlowNode_PlayLevelSequence : public UFlowNode { GENERATED_UCLASS_BODY() From c4d446266a5a43fe403e235d1502b49f94150f76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 19 Mar 2023 14:01:40 +0100 Subject: [PATCH 270/338] Refactored plain debugger struct into Flow Debugged Subsystem - This is editor subsystem gathering Runtime Logs is independent from Flow Asset editor instances. - Editor throws a notification on PIE end if there are any warnings or errors reported. --- Source/Flow/Private/FlowAsset.cpp | 81 ++++++----- Source/Flow/Private/FlowSubsystem.cpp | 5 + Source/Flow/Private/Nodes/FlowNode.cpp | 5 +- Source/Flow/Public/FlowAsset.h | 28 ++-- Source/Flow/Public/FlowSubsystem.h | 15 +- Source/FlowEditor/FlowEditor.Build.cs | 5 +- .../Private/Asset/FlowAssetEditor.cpp | 21 +-- .../FlowEditor/Private/Asset/FlowDebugger.cpp | 60 -------- .../Private/Asset/FlowDebuggerSubsystem.cpp | 129 ++++++++++++++++++ .../Private/Asset/FlowMessageLogListing.cpp | 26 ++-- .../Private/Graph/Nodes/FlowGraphNode.cpp | 4 +- .../FlowEditor/Public/Asset/FlowAssetEditor.h | 4 - Source/FlowEditor/Public/Asset/FlowDebugger.h | 19 --- .../Public/Asset/FlowDebuggerSubsystem.h | 36 +++++ .../Public/Asset/FlowMessageLogListing.h | 1 + 15 files changed, 272 insertions(+), 167 deletions(-) delete mode 100644 Source/FlowEditor/Private/Asset/FlowDebugger.cpp create mode 100644 Source/FlowEditor/Private/Asset/FlowDebuggerSubsystem.cpp delete mode 100644 Source/FlowEditor/Public/Asset/FlowDebugger.h create mode 100644 Source/FlowEditor/Public/Asset/FlowDebuggerSubsystem.h diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 0eaaa3e58..13574003e 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -3,6 +3,7 @@ #include "FlowAsset.h" #include "FlowMessageLog.h" +#include "FlowModule.h" #include "FlowSettings.h" #include "FlowSubsystem.h" @@ -281,9 +282,9 @@ void UFlowAsset::BroadcastDebuggerRefresh() const RefreshDebuggerEvent.Broadcast(); } -void UFlowAsset::BroadcastRuntimeMessageAdded(const UFlowAsset* AssetInstance, const TSharedRef& Message) const +void UFlowAsset::BroadcastRuntimeMessageAdded(const TSharedRef& Message) { - RuntimeMessageEvent.Broadcast(AssetInstance, Message); + RuntimeMessageEvent.Broadcast(this, Message); } #endif @@ -501,35 +502,6 @@ UFlowAsset* UFlowAsset::GetParentInstance() const return NodeOwningThisAssetInstance.IsValid() ? NodeOwningThisAssetInstance.Get()->GetFlowAsset() : nullptr; } -#if WITH_EDITOR -void UFlowAsset::LogError(const FString& MessageToLog, UFlowNode* Node) const -{ - if (RuntimeLog.IsValid()) - { - const TSharedRef TokenizedMessage = RuntimeLog.Get()->Error(*MessageToLog, Node); - BroadcastRuntimeMessageAdded(this, TokenizedMessage); - } -} - -void UFlowAsset::LogWarning(const FString& MessageToLog, UFlowNode* Node) const -{ - if (RuntimeLog.IsValid()) - { - const TSharedRef TokenizedMessage = RuntimeLog.Get()->Warning(*MessageToLog, Node); - BroadcastRuntimeMessageAdded(this, TokenizedMessage); - } -} - -void UFlowAsset::LogNote(const FString& MessageToLog, UFlowNode* Node) const -{ - if (RuntimeLog.IsValid()) - { - const TSharedRef TokenizedMessage = RuntimeLog.Get()->Note(*MessageToLog, Node); - BroadcastRuntimeMessageAdded(this, TokenizedMessage); - } -} -#endif - FFlowAssetSaveData UFlowAsset::SaveInstance(TArray& SavedFlowInstances) { FFlowAssetSaveData AssetRecord; @@ -616,3 +588,50 @@ bool UFlowAsset::IsBoundToWorld_Implementation() { return bWorldBound; } + +#if WITH_EDITOR +void UFlowAsset::LogError(const FString& MessageToLog, UFlowNode* Node) +{ + // this is runtime log which is should be only called on runtime instances of asset + if (TemplateAsset == nullptr) + { + UE_LOG(LogFlow, Log, TEXT("Attempted to use Runtime Log on template asset %s"), *MessageToLog); + } + + if (RuntimeLog.Get()) + { + const TSharedRef TokenizedMessage = RuntimeLog.Get()->Error(*MessageToLog, Node); + BroadcastRuntimeMessageAdded(TokenizedMessage); + } +} + +void UFlowAsset::LogWarning(const FString& MessageToLog, UFlowNode* Node) +{ + // this is runtime log which is should be only called on runtime instances of asset + if (TemplateAsset == nullptr) + { + UE_LOG(LogFlow, Log, TEXT("Attempted to use Runtime Log on template asset %s"), *MessageToLog); + } + + if (RuntimeLog.Get()) + { + const TSharedRef TokenizedMessage = RuntimeLog.Get()->Warning(*MessageToLog, Node); + BroadcastRuntimeMessageAdded(TokenizedMessage); + } +} + +void UFlowAsset::LogNote(const FString& MessageToLog, UFlowNode* Node) +{ + // this is runtime log which is should be only called on runtime instances of asset + if (TemplateAsset == nullptr) + { + UE_LOG(LogFlow, Log, TEXT("Attempted to use Runtime Log on template asset %s"), *MessageToLog); + } + + if (RuntimeLog.Get()) + { + const TSharedRef TokenizedMessage = RuntimeLog.Get()->Note(*MessageToLog, Node); + BroadcastRuntimeMessageAdded(TokenizedMessage); + } +} +#endif diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index 4913040c8..4cd30e5b3 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -14,6 +14,9 @@ #include "Misc/Paths.h" #include "UObject/UObjectHash.h" +FNativeFlowAssetEvent UFlowSubsystem::OnInstancedTemplateAdded; +FNativeFlowAssetEvent UFlowSubsystem::OnInstancedTemplateRemoved; + UFlowSubsystem::UFlowSubsystem() : UGameInstanceSubsystem() { @@ -226,6 +229,7 @@ void UFlowSubsystem::AddInstancedTemplate(UFlowAsset* Template) #if WITH_EDITOR Template->RuntimeLog = MakeShareable(new FFlowMessageLog()); + OnInstancedTemplateAdded.ExecuteIfBound(Template); #endif } } @@ -233,6 +237,7 @@ void UFlowSubsystem::AddInstancedTemplate(UFlowAsset* Template) void UFlowSubsystem::RemoveInstancedTemplate(UFlowAsset* Template) { #if WITH_EDITOR + OnInstancedTemplateRemoved.ExecuteIfBound(Template); Template->RuntimeLog.Reset(); #endif diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 4a01ce343..4c2feb965 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -741,10 +741,7 @@ void UFlowNode::LogWarning(FString Message) // Message Log #if WITH_EDITOR - if (GetFlowAsset()->GetTemplateAsset()) - { - GetFlowAsset()->GetTemplateAsset()->LogWarning(Message, this); - } + GetFlowAsset()->GetTemplateAsset()->LogWarning(Message, this); #endif } #endif diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index e6aa39e1d..7e4f87bd0 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -30,7 +30,8 @@ class FLOW_API IFlowGraphInterface virtual void OnOutputTriggered(UEdGraphNode* GraphNode, const int32 Index) const {} }; -DECLARE_DELEGATE(FFlowAssetEvent); +DECLARE_DELEGATE(FFlowGraphEvent); + #endif /** @@ -119,7 +120,7 @@ class FLOW_API UFlowAsset : public UObject public: #if WITH_EDITOR - FFlowAssetEvent OnSubGraphReconstructionRequested; + FFlowGraphEvent OnSubGraphReconstructionRequested; UFlowNode* CreateNode(const UClass* NodeClass, UEdGraphNode* GraphNode); @@ -163,6 +164,7 @@ class FLOW_API UFlowAsset : public UObject TWeakObjectPtr InspectedInstance; // Message log for storing runtime errors/notes/warnings that will only last until the next game run + // Log lives in the asset template, so it can be inspected after ending the PIE TSharedPtr RuntimeLog; #endif @@ -184,14 +186,14 @@ class FLOW_API UFlowAsset : public UObject FRefreshDebuggerEvent& OnDebuggerRefresh() { return RefreshDebuggerEvent; } FRefreshDebuggerEvent RefreshDebuggerEvent; - DECLARE_EVENT_TwoParams(UFlowAsset, FRuntimeMessageEvent, const UFlowAsset*, const TSharedRef&); + DECLARE_EVENT_TwoParams(UFlowAsset, FRuntimeMessageEvent, UFlowAsset*, const TSharedRef&); FRuntimeMessageEvent& OnRuntimeMessageAdded() { return RuntimeMessageEvent; } FRuntimeMessageEvent RuntimeMessageEvent; private: void BroadcastDebuggerRefresh() const; - void BroadcastRuntimeMessageAdded(const UFlowAsset* AssetInstance, const TSharedRef& Message) const;; + void BroadcastRuntimeMessageAdded(const TSharedRef& Message); #endif ////////////////////////////////////////////////////////////////////////// @@ -287,14 +289,8 @@ class FLOW_API UFlowAsset : public UObject UFUNCTION(BlueprintPure, Category = "Flow") TArray GetRecordedNodes() const { return RecordedNodes; } -#if WITH_EDITOR - void LogError(const FString& MessageToLog, UFlowNode* Node) const; - void LogWarning(const FString& MessageToLog, UFlowNode* Node) const; - void LogNote(const FString& MessageToLog, UFlowNode* Node) const; -#endif - ////////////////////////////////////////////////////////////////////////// -// SaveGame +// SaveGame support UFUNCTION(BlueprintCallable, Category = "SaveGame") FFlowAssetSaveData SaveInstance(TArray& SavedFlowInstances); @@ -315,4 +311,14 @@ class FLOW_API UFlowAsset : public UObject public: UFUNCTION(BlueprintNativeEvent, Category = "SaveGame") bool IsBoundToWorld(); + +////////////////////////////////////////////////////////////////////////// +// Utils + +#if WITH_EDITOR +public: + void LogError(const FString& MessageToLog, UFlowNode* Node); + void LogWarning(const FString& MessageToLog, UFlowNode* Node); + void LogNote(const FString& MessageToLog, UFlowNode* Node); +#endif }; diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index a171a245e..2255519de 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -17,6 +17,8 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE(FSimpleFlowEvent); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FSimpleFlowComponentEvent, UFlowComponent*, Component); DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FTaggedFlowComponentEvent, UFlowComponent*, Component, const FGameplayTagContainer&, Tags); +DECLARE_DELEGATE_OneParam(FNativeFlowAssetEvent, class UFlowAsset*); + /** * Flow Subsystem * - manages lifetime of Flow Graphs @@ -31,11 +33,11 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem public: UFlowSubsystem(); -private: friend class UFlowAsset; friend class UFlowComponent; friend class UFlowNode_SubGraph; +private: /* All asset templates with active instances */ UPROPERTY() TArray InstancedTemplates; @@ -50,6 +52,15 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem FStreamableManager Streamable; +#if WITH_EDITOR +public: + /* Called after creating the first instance of given Flow Asset */ + static FNativeFlowAssetEvent OnInstancedTemplateAdded; + + /* Called just before removing the last instance of given Flow Asset */ + static FNativeFlowAssetEvent OnInstancedTemplateRemoved; +#endif + protected: UPROPERTY() UFlowSaveGame* LoadedSaveGame; @@ -108,7 +119,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem virtual UWorld* GetWorld() const override; ////////////////////////////////////////////////////////////////////////// -// SaveGame +// SaveGame support UPROPERTY(BlueprintAssignable, Category = "FlowSubsystem") FSimpleFlowEvent OnSaveGame; diff --git a/Source/FlowEditor/FlowEditor.Build.cs b/Source/FlowEditor/FlowEditor.Build.cs index 6a7901f69..cf1e47c04 100644 --- a/Source/FlowEditor/FlowEditor.Build.cs +++ b/Source/FlowEditor/FlowEditor.Build.cs @@ -26,9 +26,10 @@ public FlowEditor(ReadOnlyTargetRules target) : base(target) "CoreUObject", "DetailCustomizations", "DeveloperSettings", - "EditorScriptingUtilities", "EditorFramework", + "EditorScriptingUtilities", "EditorStyle", + "EditorSubsystem", "Engine", "GraphEditor", "InputCore", @@ -39,8 +40,8 @@ public FlowEditor(ReadOnlyTargetRules target) : base(target) "LevelEditor", "LevelSequence", "MovieScene", - "MovieSceneTracks", "MovieSceneTools", + "MovieSceneTracks", "Projects", "PropertyEditor", "PropertyPath", diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index 96268a130..25bd024e3 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -8,7 +8,7 @@ #include "Asset/FlowAssetEditorContext.h" #include "Asset/FlowAssetToolbar.h" -#include "Asset/FlowDebugger.h" +#include "Asset/FlowDebuggerSubsystem.h" #include "Asset/FlowMessageLogListing.h" #include "Graph/FlowGraph.h" #include "Graph/FlowGraphEditorSettings.h" @@ -261,7 +261,6 @@ void FFlowAssetEditor::InitFlowAssetEditor(const EToolkitMode::Type Mode, const GEditor->RegisterForUndo(this); UFlowGraphSchema::SubscribeToAssetChanges(); - FlowDebugger = MakeShareable(new FFlowDebugger); BindToolbarCommands(); CreateToolbar(); @@ -269,9 +268,6 @@ void FFlowAssetEditor::InitFlowAssetEditor(const EToolkitMode::Type Mode, const BindGraphCommands(); CreateWidgets(); - FlowAsset->OnRuntimeMessageAdded().AddSP(this, &FFlowAssetEditor::OnRuntimeMessageAdded); - FEditorDelegates::BeginPIE.AddSP(this, &FFlowAssetEditor::OnBeginPIE); - const TSharedRef StandaloneDefaultLayout = FTabManager::NewLayout("FlowAssetEditor_Layout_v5.1") ->AddArea ( @@ -483,7 +479,7 @@ FGraphAppearanceInfo FFlowAssetEditor::GetGraphAppearanceInfo() const FGraphAppearanceInfo AppearanceInfo; AppearanceInfo.CornerText = GetCornerText(); - if (FlowDebugger.IsValid() && FFlowDebugger::IsPlaySessionPaused()) + if (UFlowDebuggerSubsystem::IsPlaySessionPaused()) { AppearanceInfo.PIENotifyText = LOCTEXT("PausedLabel", "PAUSED"); } @@ -753,11 +749,6 @@ EVisibility FFlowAssetEditor::GetDebuggerVisibility() return GEditor->PlayWorld ? EVisibility::Visible : EVisibility::Collapsed; } -void FFlowAssetEditor::OnBeginPIE(const bool bInSimulateInEditor) const -{ - RuntimeLogListing->ClearMessages(); -} - TSet FFlowAssetEditor::GetSelectedFlowNodes() const { TSet Result; @@ -832,14 +823,6 @@ void FFlowAssetEditor::JumpToInnerObject(UObject* InnerObject) } #endif -void FFlowAssetEditor::OnRuntimeMessageAdded(const UFlowAsset* AssetInstance, const TSharedRef& Message) const -{ - // push messages to its window - TabManager->TryInvokeTab(RuntimeLogTab); - RuntimeLogListing->AddMessage(Message); - RuntimeLogListing->OnDataChanged().Broadcast(); -} - void FFlowAssetEditor::OnLogTokenClicked(const TSharedRef& Token) const { if (Token->GetType() == EMessageToken::Object) diff --git a/Source/FlowEditor/Private/Asset/FlowDebugger.cpp b/Source/FlowEditor/Private/Asset/FlowDebugger.cpp deleted file mode 100644 index f7e2aea37..000000000 --- a/Source/FlowEditor/Private/Asset/FlowDebugger.cpp +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors - -#include "Asset/FlowDebugger.h" - -#include "Engine/Engine.h" -#include "Engine/World.h" -#include "Templates/Function.h" -#include "UnrealEd.h" - -FFlowDebugger::FFlowDebugger() -{ -} - -FFlowDebugger::~FFlowDebugger() -{ -} - -void ForEachGameWorld(const TFunction& Func) -{ - for (const FWorldContext& PieContext : GUnrealEd->GetWorldContexts()) - { - UWorld* PlayWorld = PieContext.World(); - if (PlayWorld && PlayWorld->IsGameWorld()) - { - Func(PlayWorld); - } - } -} - -bool AreAllGameWorldPaused() -{ - bool bPaused = true; - ForEachGameWorld([&](const UWorld* World) - { - bPaused = bPaused && World->bDebugPauseExecution; - }); - return bPaused; -} - -void FFlowDebugger::PausePlaySession() -{ - bool bPaused = false; - ForEachGameWorld([&](UWorld* World) - { - if (!World->bDebugPauseExecution) - { - World->bDebugPauseExecution = true; - bPaused = true; - } - }); - if (bPaused) - { - GUnrealEd->PlaySessionPaused(); - } -} - -bool FFlowDebugger::IsPlaySessionPaused() -{ - return AreAllGameWorldPaused(); -} diff --git a/Source/FlowEditor/Private/Asset/FlowDebuggerSubsystem.cpp b/Source/FlowEditor/Private/Asset/FlowDebuggerSubsystem.cpp new file mode 100644 index 000000000..635882999 --- /dev/null +++ b/Source/FlowEditor/Private/Asset/FlowDebuggerSubsystem.cpp @@ -0,0 +1,129 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#include "Asset/FlowDebuggerSubsystem.h" +#include "Asset/FlowAssetEditor.h" +#include "Asset/FlowMessageLogListing.h" + +#include "FlowSubsystem.h" + +#include "Engine/Engine.h" +#include "Engine/World.h" +#include "Framework/Notifications/NotificationManager.h" +#include "Templates/Function.h" +#include "UnrealEd.h" +#include "Widgets/Notifications/SNotificationList.h" + +#define LOCTEXT_NAMESPACE "FlowDebuggerSubsystem" + +UFlowDebuggerSubsystem::UFlowDebuggerSubsystem() +{ + FEditorDelegates::BeginPIE.AddUObject(this, &UFlowDebuggerSubsystem::OnBeginPIE); + FEditorDelegates::EndPIE.AddUObject(this, &UFlowDebuggerSubsystem::OnEndPIE); + + UFlowSubsystem::OnInstancedTemplateAdded.BindUObject(this, &UFlowDebuggerSubsystem::OnInstancedTemplateAdded); + UFlowSubsystem::OnInstancedTemplateRemoved.BindUObject(this, &UFlowDebuggerSubsystem::OnInstancedTemplateRemoved); +} + +void UFlowDebuggerSubsystem::OnInstancedTemplateAdded(UFlowAsset* FlowAsset) +{ + if (!RuntimeLogs.Contains(FlowAsset)) + { + RuntimeLogs.Add(FlowAsset, FFlowMessageLogListing::GetLogListing(FlowAsset, EFlowLogType::Runtime)); + FlowAsset->OnRuntimeMessageAdded().AddUObject(this, &UFlowDebuggerSubsystem::OnRuntimeMessageAdded); + } +} + +void UFlowDebuggerSubsystem::OnInstancedTemplateRemoved(UFlowAsset* FlowAsset) +{ + FlowAsset->OnRuntimeMessageAdded().RemoveAll(this); +} + +void UFlowDebuggerSubsystem::OnRuntimeMessageAdded(UFlowAsset* FlowAsset, const TSharedRef& Message) const +{ + const TSharedPtr Log = RuntimeLogs.FindRef(FlowAsset); + if (Log.IsValid()) + { + Log->AddMessage(Message); + Log->OnDataChanged().Broadcast(); + } +} + +void UFlowDebuggerSubsystem::OnBeginPIE(const bool bIsSimulating) +{ + // clear all logs from a previous session + RuntimeLogs.Empty(); +} + +void UFlowDebuggerSubsystem::OnEndPIE(const bool bIsSimulating) +{ + for (const TPair, TSharedPtr>& Log : RuntimeLogs) + { + if (Log.Key.IsValid() && Log.Value->NumMessages(EMessageSeverity::Warning) > 0) + { + FNotificationInfo Info{FText::FromString(TEXT("Flow Graph reported in-game issues"))}; + Info.ExpireDuration = 15.0; + + Info.HyperlinkText = FText::Format(LOCTEXT("OpenFlowAssetHyperlink", "Open {0}"), FText::FromString(Log.Key->GetName())); + Info.Hyperlink = FSimpleDelegate::CreateLambda([this, Log]() + { + UAssetEditorSubsystem* AssetEditorSubsystem = GEditor->GetEditorSubsystem(); + if (AssetEditorSubsystem->OpenEditorForAsset(Log.Key.Get())) + { + AssetEditorSubsystem->FindEditorForAsset(Log.Key.Get(), true)->InvokeTab(FFlowAssetEditor::RuntimeLogTab); + } + }); + + const TSharedPtr Notification = FSlateNotificationManager::Get().AddNotification(Info); + if (Notification.IsValid()) + { + Notification->SetCompletionState(SNotificationItem::CS_Fail); + } + } + } +} + +void ForEachGameWorld(const TFunction& Func) +{ + for (const FWorldContext& PieContext : GUnrealEd->GetWorldContexts()) + { + UWorld* PlayWorld = PieContext.World(); + if (PlayWorld && PlayWorld->IsGameWorld()) + { + Func(PlayWorld); + } + } +} + +bool AreAllGameWorldPaused() +{ + bool bPaused = true; + ForEachGameWorld([&](const UWorld* World) + { + bPaused = bPaused && World->bDebugPauseExecution; + }); + return bPaused; +} + +void UFlowDebuggerSubsystem::PausePlaySession() +{ + bool bPaused = false; + ForEachGameWorld([&](UWorld* World) + { + if (!World->bDebugPauseExecution) + { + World->bDebugPauseExecution = true; + bPaused = true; + } + }); + if (bPaused) + { + GUnrealEd->PlaySessionPaused(); + } +} + +bool UFlowDebuggerSubsystem::IsPlaySessionPaused() +{ + return AreAllGameWorldPaused(); +} + +#undef LOCTEXT_NAMESPACE diff --git a/Source/FlowEditor/Private/Asset/FlowMessageLogListing.cpp b/Source/FlowEditor/Private/Asset/FlowMessageLogListing.cpp index ce4d264f7..9bd7a6f73 100644 --- a/Source/FlowEditor/Private/Asset/FlowMessageLogListing.cpp +++ b/Source/FlowEditor/Private/Asset/FlowMessageLogListing.cpp @@ -14,7 +14,7 @@ FFlowMessageLogListing::FFlowMessageLogListing(const UFlowAsset* InFlowAsset, co FFlowMessageLogListing::~FFlowMessageLogListing() { // Unregister the log so it will be ref-counted to zero if it has no messages - if(Log->NumMessages(EMessageSeverity::Info) == 0) + if (Log->NumMessages(EMessageSeverity::Info) == 0) { FMessageLogModule& MessageLogModule = FModuleManager::LoadModuleChecked("MessageLog"); MessageLogModule.UnregisterLogListing(Log->GetName()); @@ -37,20 +37,21 @@ TSharedRef FFlowMessageLogListing::RegisterLogListing(const TSharedRef FFlowMessageLogListing::GetLogListing(const UFlowAsset* InFlowAsset, const EFlowLogType Type) { FMessageLogModule& MessageLogModule = FModuleManager::LoadModuleChecked("MessageLog"); - const FName LogName = GetListingName(InFlowAsset, Type); - // Reuse any existing log, or create a new one (that is not held onto bey the message log system) - if(MessageLogModule.IsRegisteredLogListing(LogName)) + // Create a new message log + if (!MessageLogModule.IsRegisteredLogListing(LogName)) { - return MessageLogModule.GetLogListing(LogName); - } - else - { - FMessageLogInitializationOptions LogInitOptions; - LogInitOptions.bShowInLogWindow = false; - return MessageLogModule.CreateLogListing(LogName, LogInitOptions); + MessageLogModule.RegisterLogListing(LogName, FText::FromString(GetLogLabel(Type))); } + + return MessageLogModule.GetLogListing(LogName); +} + +FString FFlowMessageLogListing::GetLogLabel(const EFlowLogType Type) +{ + const FString TypeAsString = StaticEnum()->GetNameStringByIndex(static_cast(Type)); + return FString::Printf(TEXT("Flow%sLog"), *TypeAsString); } FName FFlowMessageLogListing::GetListingName(const UFlowAsset* InFlowAsset, const EFlowLogType Type) @@ -58,8 +59,7 @@ FName FFlowMessageLogListing::GetListingName(const UFlowAsset* InFlowAsset, cons FName LogListingName; if (InFlowAsset) { - const FString TypeAsString = StaticEnum()->GetNameStringByIndex(static_cast(Type)); - LogListingName = *FString::Printf(TEXT("FlowLog_%s_%s_%s_"), *TypeAsString, *InFlowAsset->AssetGuid.ToString(), *InFlowAsset->GetName()); + LogListingName = *FString::Printf(TEXT("%s::%s::%s"), *GetLogLabel(Type), *InFlowAsset->GetName(), *InFlowAsset->AssetGuid.ToString()); } else { diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index d72ae9260..1fc3797c8 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -2,7 +2,7 @@ #include "Graph/Nodes/FlowGraphNode.h" -#include "Asset/FlowDebugger.h" +#include "Asset/FlowDebuggerSubsystem.h" #include "FlowEditorCommands.h" #include "Graph/FlowGraph.h" #include "Graph/FlowGraphEditorSettings.h" @@ -1029,7 +1029,7 @@ void UFlowGraphNode::TryPausingSession(bool bPauseSession) FEditorDelegates::ResumePIE.AddUObject(this, &UFlowGraphNode::OnResumePIE); FEditorDelegates::EndPIE.AddUObject(this, &UFlowGraphNode::OnEndPIE); - FFlowDebugger::PausePlaySession(); + UFlowDebuggerSubsystem::PausePlaySession(); } } diff --git a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h index b1d053829..fb8814331 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h @@ -32,7 +32,6 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit UFlowAsset* FlowAsset; TSharedPtr AssetToolbar; - TSharedPtr FlowDebugger; TSharedPtr GraphEditor; TSharedPtr DetailsView; @@ -166,8 +165,6 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit static bool IsPIE(); static EVisibility GetDebuggerVisibility(); - void OnBeginPIE(const bool bInSimulateInEditor) const; - TSet GetSelectedFlowNodes() const; int32 GetNumberOfSelectedNodes() const; bool GetBoundsForSelectedNodes(class FSlateRect& Rect, float Padding) const; @@ -185,7 +182,6 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit #endif protected: - void OnRuntimeMessageAdded(const UFlowAsset* AssetInstance, const TSharedRef& Message) const; void OnLogTokenClicked(const TSharedRef& Token) const; virtual void SelectAllNodes() const; diff --git a/Source/FlowEditor/Public/Asset/FlowDebugger.h b/Source/FlowEditor/Public/Asset/FlowDebugger.h deleted file mode 100644 index 75a5ef47b..000000000 --- a/Source/FlowEditor/Public/Asset/FlowDebugger.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors - -#pragma once - -#include "CoreMinimal.h" - -/** -** Minimalistic form of breakpoint debugger -** See BehaviorTreeDebugger for a more complex example - */ -class FLOWEDITOR_API FFlowDebugger -{ -public: - FFlowDebugger(); - ~FFlowDebugger(); - - static void PausePlaySession(); - static bool IsPlaySessionPaused(); -}; diff --git a/Source/FlowEditor/Public/Asset/FlowDebuggerSubsystem.h b/Source/FlowEditor/Public/Asset/FlowDebuggerSubsystem.h new file mode 100644 index 000000000..da10e3032 --- /dev/null +++ b/Source/FlowEditor/Public/Asset/FlowDebuggerSubsystem.h @@ -0,0 +1,36 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#pragma once + +#include "EditorSubsystem.h" +#include "FlowDebuggerSubsystem.generated.h" + +class UFlowAsset; +class FFlowMessageLog; + +/** +** Persistent subsystem supporting Flow Graph debugging + */ +UCLASS() +class FLOWEDITOR_API UFlowDebuggerSubsystem : public UEditorSubsystem +{ + GENERATED_BODY() + +public: + UFlowDebuggerSubsystem(); + +protected: + TMap, TSharedPtr> RuntimeLogs; + + void OnInstancedTemplateAdded(UFlowAsset* FlowAsset); + void OnInstancedTemplateRemoved(UFlowAsset* FlowAsset); + + void OnRuntimeMessageAdded(UFlowAsset* FlowAsset, const TSharedRef& Message) const; + + void OnBeginPIE(const bool bIsSimulating); + void OnEndPIE(const bool bIsSimulating); + +public: + static void PausePlaySession(); + static bool IsPlaySessionPaused(); +}; diff --git a/Source/FlowEditor/Public/Asset/FlowMessageLogListing.h b/Source/FlowEditor/Public/Asset/FlowMessageLogListing.h index 5651f25c3..b7e7aafaf 100644 --- a/Source/FlowEditor/Public/Asset/FlowMessageLogListing.h +++ b/Source/FlowEditor/Public/Asset/FlowMessageLogListing.h @@ -33,4 +33,5 @@ class FLOWEDITOR_API FFlowMessageLogListing public: static TSharedRef GetLogListing(const UFlowAsset* InFlowAsset, const EFlowLogType Type); + static FString GetLogLabel(const EFlowLogType Type); }; From 856d6c40c02382a5bfeb5144e31ea028d7dfcea0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 19 Mar 2023 17:41:26 +0100 Subject: [PATCH 271/338] non-editor compilation fix --- Source/Flow/Private/FlowSubsystem.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index 4cd30e5b3..205f87f0f 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -14,8 +14,10 @@ #include "Misc/Paths.h" #include "UObject/UObjectHash.h" +#if WITH_EDITOR FNativeFlowAssetEvent UFlowSubsystem::OnInstancedTemplateAdded; FNativeFlowAssetEvent UFlowSubsystem::OnInstancedTemplateRemoved; +#endif UFlowSubsystem::UFlowSubsystem() : UGameInstanceSubsystem() From 674414df7c99726e2c7bddb4d0a3e9b30bc03a98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Wed, 22 Mar 2023 19:52:34 +0100 Subject: [PATCH 272/338] fixed compilation in some projects --- Source/FlowEditor/FlowEditor.Build.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/FlowEditor/FlowEditor.Build.cs b/Source/FlowEditor/FlowEditor.Build.cs index cf1e47c04..00d4faf7d 100644 --- a/Source/FlowEditor/FlowEditor.Build.cs +++ b/Source/FlowEditor/FlowEditor.Build.cs @@ -10,6 +10,7 @@ public FlowEditor(ReadOnlyTargetRules target) : base(target) PublicDependencyModuleNames.AddRange(new[] { + "EditorSubsystem", "Flow", "MessageLog" }); @@ -29,7 +30,6 @@ public FlowEditor(ReadOnlyTargetRules target) : base(target) "EditorFramework", "EditorScriptingUtilities", "EditorStyle", - "EditorSubsystem", "Engine", "GraphEditor", "InputCore", From 8150d939f35da0a5b646f9c9076380e886043de1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 26 Mar 2023 12:32:47 +0200 Subject: [PATCH 273/338] formatting fix --- Source/Flow/Private/Nodes/FlowNode.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 4c2feb965..2b06be73a 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -571,16 +571,16 @@ void UFlowNode::LoadInstance(const FFlowNodeSaveData& NodeRecord) { case EFlowSignalMode::Enabled: OnLoad(); - break; + break; case EFlowSignalMode::Disabled: // designer doesn't want to execute this node's logic at all, so we kill it LogNote(TEXT("Signal disabled while loading Flow Node from SaveGame")); - Finish(); - break; + Finish(); + break; case EFlowSignalMode::PassThrough: LogNote(TEXT("Signal pass-through on loading Flow Node from SaveGame")); - OnPassThrough(); - break; + OnPassThrough(); + break; default: ; } } From 34d2cdb894d0e8dcf5807d93debb1a945aab0923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 26 Mar 2023 12:37:47 +0200 Subject: [PATCH 274/338] Fixed rare issue with loading saves - prevent triggering input on not-yet-loaded node --- Source/Flow/Private/FlowAsset.cpp | 21 ++++++++++------- Source/Flow/Public/FlowAsset.h | 39 ++++++++++++++++++++++++++++--- 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 13574003e..e10a30108 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -511,12 +511,15 @@ FFlowAssetSaveData UFlowAsset::SaveInstance(TArray& SavedFlo // opportunity to collect data before serializing asset OnSave(); - // iterate SubGraphs - for (const TPair& Node : Nodes) + // iterate nodes + TArray NodesInExecutionOrder; + GetNodesInExecutionOrder(NodesInExecutionOrder); + for (UFlowNode* Node : NodesInExecutionOrder) { - if (Node.Value && Node.Value->ActivationState == EFlowNodeState::Active) + if (Node && Node->ActivationState == EFlowNodeState::Active) { - if (UFlowNode_SubGraph* SubGraphNode = Cast(Node.Value)) + // iterate SubGraphs + if (UFlowNode_SubGraph* SubGraphNode = Cast(Node)) { const TWeakObjectPtr SubFlowInstance = GetFlowInstance(SubGraphNode); if (SubFlowInstance.IsValid()) @@ -527,7 +530,7 @@ FFlowAssetSaveData UFlowAsset::SaveInstance(TArray& SavedFlo } FFlowNodeSaveData NodeRecord; - Node.Value->SaveInstance(NodeRecord); + Node->SaveInstance(NodeRecord); AssetRecord.NodeRecords.Emplace(NodeRecord); } @@ -552,11 +555,13 @@ void UFlowAsset::LoadInstance(const FFlowAssetSaveData& AssetRecord) PreStartFlow(); - for (const FFlowNodeSaveData& NodeRecord : AssetRecord.NodeRecords) + // iterate nodes from "the end" of graph, backwards to execution order + // prevents issue when preceding node would instantly fire output to not-yet-loaded node + for (int32 i = AssetRecord.NodeRecords.Num() - 1; i >= 0; i--) { - if (UFlowNode* Node = Nodes.FindRef(NodeRecord.NodeGuid)) + if (UFlowNode* Node = Nodes.FindRef(AssetRecord.NodeRecords[i].NodeGuid)) { - Node->LoadInstance(NodeRecord); + Node->LoadInstance(AssetRecord.NodeRecords[i]); } } diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 7e4f87bd0..8c4af61a9 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -5,9 +5,9 @@ #include "FlowMessageLog.h" #include "FlowSave.h" #include "FlowTypes.h" +#include "Nodes/FlowNode.h" #include "FlowAsset.generated.h" -class UFlowNode; class UFlowNode_CustomInput; class UFlowNode_Start; class UFlowNode_SubGraph; @@ -147,11 +147,44 @@ class FLOW_API UFlowAsset : public UObject return nullptr; } + UFlowNode_Start* GetStartNode() const; + + template + void GetNodesInExecutionOrder(TArray& OutNodes) + { + static_assert(TPointerIsConvertibleFromTo::Value, "'T' template parameter to GetNodesInExecutionOrder must be derived from UFlowNode"); + + if (UFlowNode_Start* FoundStartNode = GetStartNode()) + { + TSet> IteratedNodes; + GetNodesInExecutionOrder_Recursive(FoundStartNode, IteratedNodes, OutNodes); + } + } + +protected: + template + void GetNodesInExecutionOrder_Recursive(UFlowNode* Node, TSet>& IteratedNodes, TArray& OutNodes) + { + IteratedNodes.Add(Node); + + if (T* NodeOfRequiredType = Cast(Node)) + { + OutNodes.Emplace(NodeOfRequiredType); + } + + for (UFlowNode* ConnectedNode : Node->GetConnectedNodes()) + { + if (ConnectedNode && !IteratedNodes.Contains(ConnectedNode)) + { + GetNodesInExecutionOrder_Recursive(ConnectedNode, IteratedNodes, OutNodes); + } + } + } + +public: TArray GetCustomInputs() const { return CustomInputs; } TArray GetCustomOutputs() const { return CustomOutputs; } - UFlowNode_Start* GetStartNode() const; - ////////////////////////////////////////////////////////////////////////// // Instances of the template asset From e88897c4f05d7252c7ca8a6c98f83db4970aaa04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 26 Mar 2023 12:42:10 +0200 Subject: [PATCH 275/338] wording corrected --- Source/Flow/Private/FlowAsset.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index e10a30108..2dea57c62 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -555,8 +555,8 @@ void UFlowAsset::LoadInstance(const FFlowAssetSaveData& AssetRecord) PreStartFlow(); - // iterate nodes from "the end" of graph, backwards to execution order - // prevents issue when preceding node would instantly fire output to not-yet-loaded node + // iterate graph "from the end", backward to execution order + // prevents issue when the preceding node would instantly fire output to a not-yet-loaded node for (int32 i = AssetRecord.NodeRecords.Num() - 1; i >= 0; i--) { if (UFlowNode* Node = Nodes.FindRef(AssetRecord.NodeRecords[i].NodeGuid)) From f826647f564ab420d06df29a94c69591c947e697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 26 Mar 2023 17:23:04 +0200 Subject: [PATCH 276/338] extracted graph-related code from the FFlowAssetEditor to new SFlowGraphEditor class added FFlowAssetEditor::IsTabFocused() to prevent delete/paste/copy nodes if graph tab isn't focused --- .../Private/Asset/FlowAssetEditor.cpp | 1052 +---------------- .../Private/Asset/FlowAssetToolbar.cpp | 9 +- .../FlowGraphConnectionDrawingPolicy.cpp | 8 +- .../Private/Graph/FlowGraphEditor.cpp | 1029 ++++++++++++++++ .../Private/Graph/FlowGraphSchema.cpp | 7 +- .../Private/Graph/FlowGraphSchema_Actions.cpp | 16 +- .../Private/Graph/FlowGraphUtils.cpp | 19 +- .../Private/Graph/Widgets/SFlowPalette.cpp | 17 +- .../FlowEditor/Public/Asset/FlowAssetEditor.h | 141 +-- .../Public/Asset/FlowAssetToolbar.h | 4 +- .../FlowEditor/Public/Graph/FlowGraphEditor.h | 144 +++ .../FlowEditor/Public/Graph/FlowGraphUtils.h | 4 +- .../Public/Graph/Widgets/SFlowPalette.h | 2 +- 13 files changed, 1267 insertions(+), 1185 deletions(-) create mode 100644 Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp create mode 100644 Source/FlowEditor/Public/Graph/FlowGraphEditor.h diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index 25bd024e3..3900e2cdf 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -8,23 +8,17 @@ #include "Asset/FlowAssetEditorContext.h" #include "Asset/FlowAssetToolbar.h" -#include "Asset/FlowDebuggerSubsystem.h" #include "Asset/FlowMessageLogListing.h" -#include "Graph/FlowGraph.h" -#include "Graph/FlowGraphEditorSettings.h" +#include "Graph/FlowGraphEditor.h" #include "Graph/FlowGraphSchema.h" -#include "Graph/FlowGraphSchema_Actions.h" -#include "Graph/Nodes/FlowGraphNode.h" #include "Graph/Widgets/SFlowPalette.h" #include "FlowAsset.h" #include "Nodes/FlowNode.h" -#include "Nodes/Route/FlowNode_SubGraph.h" #include "EdGraphUtilities.h" #include "EdGraph/EdGraphNode.h" #include "Editor.h" -#include "Framework/Commands/GenericCommands.h" #include "GraphEditor.h" #include "GraphEditorActions.h" #include "HAL/PlatformApplicationMisc.h" @@ -36,7 +30,6 @@ #include "Misc/UObjectToken.h" #include "Modules/ModuleManager.h" #include "PropertyEditorModule.h" -#include "ScopedTransaction.h" #include "SNodePanel.h" #include "ToolMenus.h" #include "Widgets/Docking/SDockTab.h" @@ -176,6 +169,16 @@ void FFlowAssetEditor::InitToolMenuContext(FToolMenuContext& MenuContext) MenuContext.AddObject(Context); } +bool FFlowAssetEditor::IsTabFocused(const FTabId& TabId) const +{ + if (const TSharedPtr CurrentGraphTab = GetToolkitHost()->GetTabManager()->FindExistingLiveTab(TabId)) + { + return CurrentGraphTab->IsActive(); + } + + return false; +} + TSharedRef FFlowAssetEditor::SpawnTab_Details(const FSpawnTabArgs& Args) const { check(Args.GetTabId() == DetailsTab); @@ -265,7 +268,6 @@ void FFlowAssetEditor::InitFlowAssetEditor(const EToolkitMode::Type Mode, const BindToolbarCommands(); CreateToolbar(); - BindGraphCommands(); CreateWidgets(); const TSharedRef StandaloneDefaultLayout = FTabManager::NewLayout("FlowAssetEditor_Layout_v5.1") @@ -422,8 +424,7 @@ bool FFlowAssetEditor::CanGoToParentInstance() void FFlowAssetEditor::CreateWidgets() { - GraphEditor = CreateGraphWidget(); - + // Details View { FDetailsViewArgs Args; Args.bHideSelectionTip = true; @@ -437,12 +438,19 @@ void FFlowAssetEditor::CreateWidgets() DetailsView->SetObject(FlowAsset); } + // Graph + CreateGraphWidget(); + GraphEditor->OnSelectionChangedEvent.BindRaw(this, &FFlowAssetEditor::OnSelectedNodesChanged); + + // Palette Palette = SNew(SFlowPalette, SharedThis(this)); + // Search #if ENABLE_SEARCH_IN_ASSET_EDITOR SearchBrowser = SNew(SSearchBrowser, GetFlowAsset()); #endif + // Logs FMessageLogModule& MessageLogModule = FModuleManager::LoadModuleChecked("MessageLog"); { RuntimeLogListing = FFlowMessageLogListing::GetLogListing(FlowAsset, EFlowLogType::Runtime); @@ -456,247 +464,15 @@ void FFlowAssetEditor::CreateWidgets() } } -TSharedRef FFlowAssetEditor::CreateGraphWidget() -{ - SGraphEditor::FGraphEditorEvents InEvents; - InEvents.OnSelectionChanged = SGraphEditor::FOnSelectionChanged::CreateSP(this, &FFlowAssetEditor::OnSelectedNodesChanged); - InEvents.OnNodeDoubleClicked = FSingleNodeEvent::CreateSP(this, &FFlowAssetEditor::OnNodeDoubleClicked); - InEvents.OnTextCommitted = FOnNodeTextCommitted::CreateSP(this, &FFlowAssetEditor::OnNodeTitleCommitted); - InEvents.OnSpawnNodeByShortcut = SGraphEditor::FOnSpawnNodeByShortcut::CreateStatic(&FFlowAssetEditor::OnSpawnGraphNodeByShortcut, static_cast(FlowAsset->GetGraph())); - - return SNew(SGraphEditor) - .AdditionalCommands(ToolkitCommands) - .IsEditable(true) - .Appearance(GetGraphAppearanceInfo()) - .GraphToEdit(FlowAsset->GetGraph()) - .GraphEvents(InEvents) - .AutoExpandActionMenu(true) - .ShowGraphStateOverlay(false); -} - -FGraphAppearanceInfo FFlowAssetEditor::GetGraphAppearanceInfo() const -{ - FGraphAppearanceInfo AppearanceInfo; - AppearanceInfo.CornerText = GetCornerText(); - - if (UFlowDebuggerSubsystem::IsPlaySessionPaused()) - { - AppearanceInfo.PIENotifyText = LOCTEXT("PausedLabel", "PAUSED"); - } - - return AppearanceInfo; -} - -FText FFlowAssetEditor::GetCornerText() const -{ - return LOCTEXT("AppearanceCornerText_FlowAsset", "FLOW"); -} - -void FFlowAssetEditor::BindGraphCommands() -{ - FGraphEditorCommands::Register(); - FFlowGraphCommands::Register(); - FFlowSpawnNodeCommands::Register(); - - const FGenericCommands& GenericCommands = FGenericCommands::Get(); - const FGraphEditorCommandsImpl& GraphCommands = FGraphEditorCommands::Get(); - const FFlowGraphCommands& FlowGraphCommands = FFlowGraphCommands::Get(); - - // Graph commands - ToolkitCommands->MapAction(GraphCommands.CreateComment, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnCreateComment), - FCanExecuteAction::CreateStatic(&FFlowAssetEditor::CanEdit)); - - ToolkitCommands->MapAction(GraphCommands.StraightenConnections, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnStraightenConnections)); - - // Generic Node commands - ToolkitCommands->MapAction(GenericCommands.Undo, - FExecuteAction::CreateStatic(&FFlowAssetEditor::UndoGraphAction), - FCanExecuteAction::CreateStatic(&FFlowAssetEditor::CanEdit)); - - ToolkitCommands->MapAction(GenericCommands.Redo, - FExecuteAction::CreateStatic(&FFlowAssetEditor::RedoGraphAction), - FCanExecuteAction::CreateStatic(&FFlowAssetEditor::CanEdit)); - - ToolkitCommands->MapAction(GenericCommands.SelectAll, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::SelectAllNodes), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanSelectAllNodes)); - - ToolkitCommands->MapAction(GenericCommands.Delete, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::DeleteSelectedNodes), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanDeleteNodes)); - - ToolkitCommands->MapAction(GenericCommands.Copy, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::CopySelectedNodes), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanCopyNodes)); - - ToolkitCommands->MapAction(GenericCommands.Cut, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::CutSelectedNodes), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanCutNodes)); - - ToolkitCommands->MapAction(GenericCommands.Paste, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::PasteNodes), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanPasteNodes)); - - ToolkitCommands->MapAction(GenericCommands.Duplicate, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::DuplicateNodes), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanDuplicateNodes)); - - // Pin commands - ToolkitCommands->MapAction(FlowGraphCommands.RefreshContextPins, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::RefreshContextPins), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanRefreshContextPins)); - - ToolkitCommands->MapAction(FlowGraphCommands.AddInput, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::AddInput), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanAddInput)); - - ToolkitCommands->MapAction(FlowGraphCommands.AddOutput, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::AddOutput), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanAddOutput)); - - ToolkitCommands->MapAction(FlowGraphCommands.RemovePin, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::RemovePin), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanRemovePin)); - - // Breakpoint commands - ToolkitCommands->MapAction(GraphCommands.AddBreakpoint, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnAddBreakpoint), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanAddBreakpoint), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanAddBreakpoint) - ); - - ToolkitCommands->MapAction(GraphCommands.RemoveBreakpoint, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnRemoveBreakpoint), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanRemoveBreakpoint), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanRemoveBreakpoint) - ); - - ToolkitCommands->MapAction(GraphCommands.EnableBreakpoint, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnEnableBreakpoint), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanEnableBreakpoint), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanEnableBreakpoint) - ); - - ToolkitCommands->MapAction(GraphCommands.DisableBreakpoint, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnDisableBreakpoint), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanDisableBreakpoint), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanDisableBreakpoint) - ); - - ToolkitCommands->MapAction(GraphCommands.ToggleBreakpoint, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnToggleBreakpoint), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanToggleBreakpoint), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanToggleBreakpoint) - ); - - // Pin Breakpoint commands - ToolkitCommands->MapAction(FlowGraphCommands.AddPinBreakpoint, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnAddPinBreakpoint), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanAddPinBreakpoint), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanAddPinBreakpoint) - ); - - ToolkitCommands->MapAction(FlowGraphCommands.RemovePinBreakpoint, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnRemovePinBreakpoint), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanRemovePinBreakpoint), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanRemovePinBreakpoint) - ); - - ToolkitCommands->MapAction(FlowGraphCommands.EnablePinBreakpoint, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnEnablePinBreakpoint), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanEnablePinBreakpoint), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanEnablePinBreakpoint) - ); - - ToolkitCommands->MapAction(FlowGraphCommands.DisablePinBreakpoint, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnDisablePinBreakpoint), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanDisablePinBreakpoint), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanDisablePinBreakpoint) - ); - - ToolkitCommands->MapAction(FlowGraphCommands.TogglePinBreakpoint, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnTogglePinBreakpoint), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanTogglePinBreakpoint), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanTogglePinBreakpoint) - ); - - // Execution Override commands - ToolkitCommands->MapAction(FlowGraphCommands.EnableNode, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::SetSignalMode, EFlowSignalMode::Enabled), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanSetSignalMode, EFlowSignalMode::Enabled), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanSetSignalMode, EFlowSignalMode::Enabled) - ); - - ToolkitCommands->MapAction(FlowGraphCommands.DisableNode, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::SetSignalMode, EFlowSignalMode::Disabled), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanSetSignalMode, EFlowSignalMode::Disabled), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanSetSignalMode, EFlowSignalMode::Disabled) - ); - - ToolkitCommands->MapAction(FlowGraphCommands.SetPassThrough, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::SetSignalMode, EFlowSignalMode::PassThrough), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanSetSignalMode, EFlowSignalMode::PassThrough), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanSetSignalMode, EFlowSignalMode::PassThrough) - ); - - ToolkitCommands->MapAction(FlowGraphCommands.ForcePinActivation, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::OnForcePinActivation), - FCanExecuteAction::CreateStatic(&FFlowAssetEditor::IsPIE), - FIsActionChecked(), - FIsActionButtonVisible::CreateStatic(&FFlowAssetEditor::IsPIE) - ); - - // Jump commands - ToolkitCommands->MapAction(FlowGraphCommands.FocusViewport, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::FocusViewport), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanFocusViewport)); - - ToolkitCommands->MapAction(FlowGraphCommands.JumpToNodeDefinition, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::JumpToNodeDefinition), - FCanExecuteAction::CreateSP(this, &FFlowAssetEditor::CanJumpToNodeDefinition)); -} - -void FFlowAssetEditor::UndoGraphAction() -{ - GEditor->UndoTransaction(); -} - -void FFlowAssetEditor::RedoGraphAction() +void FFlowAssetEditor::CreateGraphWidget() { - GEditor->RedoTransaction(); + SAssignNew(GraphEditor, SFlowGraphEditor, SharedThis(this)) + .DetailsView(DetailsView); } -FReply FFlowAssetEditor::OnSpawnGraphNodeByShortcut(FInputChord InChord, const FVector2D& InPosition, UEdGraph* InGraph) +bool FFlowAssetEditor::CanEdit() { - UEdGraph* Graph = InGraph; - - if (FFlowSpawnNodeCommands::IsRegistered()) - { - const TSharedPtr Action = FFlowSpawnNodeCommands::Get().GetActionByChord(InChord); - if (Action.IsValid()) - { - TArray DummyPins; - Action->PerformAction(Graph, DummyPins, InPosition); - return FReply::Handled(); - } - } - - return FReply::Unhandled(); + return GEditor->PlayWorld == nullptr; } void FFlowAssetEditor::SetUISelectionState(const FName SelectionOwner) @@ -723,94 +499,9 @@ void FFlowAssetEditor::ClearSelectionStateFor(const FName SelectionOwner) } } -void FFlowAssetEditor::OnCreateComment() const -{ - FFlowGraphSchemaAction_NewComment CommentAction; - CommentAction.PerformAction(FlowAsset->GetGraph(), nullptr, GraphEditor->GetPasteLocation()); -} - -void FFlowAssetEditor::OnStraightenConnections() const -{ - GraphEditor->OnStraightenConnections(); -} - -bool FFlowAssetEditor::CanEdit() -{ - return GEditor->PlayWorld == nullptr; -} - -bool FFlowAssetEditor::IsPIE() -{ - return GEditor->PlayWorld != nullptr; -} - -EVisibility FFlowAssetEditor::GetDebuggerVisibility() -{ - return GEditor->PlayWorld ? EVisibility::Visible : EVisibility::Collapsed; -} - -TSet FFlowAssetEditor::GetSelectedFlowNodes() const -{ - TSet Result; - - const FGraphPanelSelectionSet SelectedNodes = GraphEditor->GetSelectedNodes(); - for (FGraphPanelSelectionSet::TConstIterator NodeIt(SelectedNodes); NodeIt; ++NodeIt) - { - if (UFlowGraphNode* SelectedNode = Cast(*NodeIt)) - { - Result.Emplace(SelectedNode); - } - } - - return Result; -} - -int32 FFlowAssetEditor::GetNumberOfSelectedNodes() const -{ - return GraphEditor->GetSelectedNodes().Num(); -} - -bool FFlowAssetEditor::GetBoundsForSelectedNodes(class FSlateRect& Rect, float Padding) const -{ - return GraphEditor->GetBoundsForSelectedNodes(Rect, Padding); -} - -void FFlowAssetEditor::OnSelectedNodesChanged(const TSet& Nodes) -{ - TArray SelectedObjects; - - if (Nodes.Num() > 0) - { - SetUISelectionState(GraphTab); - - for (TSet::TConstIterator SetIt(Nodes); SetIt; ++SetIt) - { - if (const UFlowGraphNode* GraphNode = Cast(*SetIt)) - { - SelectedObjects.Add(Cast(GraphNode->GetFlowNode())); - } - else - { - SelectedObjects.Add(*SetIt); - } - } - } - else - { - SetUISelectionState(NAME_None); - SelectedObjects.Add(GetFlowAsset()); - } - - if (DetailsView.IsValid()) - { - DetailsView->SetObjects(SelectedObjects); - } -} - -void FFlowAssetEditor::SelectSingleNode(UEdGraphNode* Node) const +FName FFlowAssetEditor::GetUISelectionState() const { - GraphEditor->ClearSelectionSet(); - GraphEditor->SetNodeSelection(Node, true); + return CurrentUISelection; } #if ENABLE_JUMP_TO_INNER_OBJECT @@ -858,695 +549,4 @@ void FFlowAssetEditor::OnLogTokenClicked(const TSharedRef& Token) } } -void FFlowAssetEditor::SelectAllNodes() const -{ - GraphEditor->SelectAllNodes(); -} - -bool FFlowAssetEditor::CanSelectAllNodes() const -{ - return true; -} - -void FFlowAssetEditor::DeleteSelectedNodes() -{ - const FScopedTransaction Transaction(LOCTEXT("DeleteSelectedNode", "Delete Selected Node")); - GraphEditor->GetCurrentGraph()->Modify(); - FlowAsset->Modify(); - - const FGraphPanelSelectionSet SelectedNodes = GraphEditor->GetSelectedNodes(); - SetUISelectionState(NAME_None); - - for (FGraphPanelSelectionSet::TConstIterator NodeIt(SelectedNodes); NodeIt; ++NodeIt) - { - UEdGraphNode* Node = CastChecked(*NodeIt); - if (Node->CanUserDeleteNode()) - { - if (const UFlowGraphNode* FlowGraphNode = Cast(Node)) - { - if (FlowGraphNode->GetFlowNode()) - { - const FGuid NodeGuid = FlowGraphNode->GetFlowNode()->GetGuid(); - - GraphEditor->GetCurrentGraph()->GetSchema()->BreakNodeLinks(*Node); - Node->DestroyNode(); - - FlowAsset->UnregisterNode(NodeGuid); - continue; - } - } - - GraphEditor->GetCurrentGraph()->GetSchema()->BreakNodeLinks(*Node); - Node->DestroyNode(); - } - } -} - -void FFlowAssetEditor::DeleteSelectedDuplicableNodes() -{ - // Cache off the old selection - const FGraphPanelSelectionSet OldSelectedNodes = GraphEditor->GetSelectedNodes(); - - // Clear the selection and only select the nodes that can be duplicated - FGraphPanelSelectionSet RemainingNodes; - GraphEditor->ClearSelectionSet(); - - for (FGraphPanelSelectionSet::TConstIterator SelectedIt(OldSelectedNodes); SelectedIt; ++SelectedIt) - { - if (UEdGraphNode* Node = Cast(*SelectedIt)) - { - if (Node->CanDuplicateNode()) - { - GraphEditor->SetNodeSelection(Node, true); - } - else - { - RemainingNodes.Add(Node); - } - } - } - - // Delete the duplicable nodes - DeleteSelectedNodes(); - - for (FGraphPanelSelectionSet::TConstIterator SelectedIt(RemainingNodes); SelectedIt; ++SelectedIt) - { - if (UEdGraphNode* Node = Cast(*SelectedIt)) - { - GraphEditor->SetNodeSelection(Node, true); - } - } -} - -bool FFlowAssetEditor::CanDeleteNodes() const -{ - if (CanEdit()) - { - const FGraphPanelSelectionSet SelectedNodes = GraphEditor->GetSelectedNodes(); - for (FGraphPanelSelectionSet::TConstIterator NodeIt(SelectedNodes); NodeIt; ++NodeIt) - { - if (const UEdGraphNode* Node = Cast(*NodeIt)) - { - if (!Node->CanUserDeleteNode()) - { - return false; - } - } - } - - return SelectedNodes.Num() > 0; - } - - return false; -} - -void FFlowAssetEditor::CutSelectedNodes() -{ - CopySelectedNodes(); - - // Cut should only delete nodes that can be duplicated - DeleteSelectedDuplicableNodes(); -} - -bool FFlowAssetEditor::CanCutNodes() const -{ - return CanCopyNodes() && CanDeleteNodes(); -} - -void FFlowAssetEditor::CopySelectedNodes() const -{ - const FGraphPanelSelectionSet SelectedNodes = GraphEditor->GetSelectedNodes(); - for (FGraphPanelSelectionSet::TConstIterator SelectedIt(SelectedNodes); SelectedIt; ++SelectedIt) - { - if (UFlowGraphNode* Node = Cast(*SelectedIt)) - { - Node->PrepareForCopying(); - } - } - - // Export the selected nodes and place the text on the clipboard - FString ExportedText; - FEdGraphUtilities::ExportNodesToText(SelectedNodes, /*out*/ ExportedText); - FPlatformApplicationMisc::ClipboardCopy(*ExportedText); - - for (FGraphPanelSelectionSet::TConstIterator SelectedIt(SelectedNodes); SelectedIt; ++SelectedIt) - { - if (UFlowGraphNode* Node = Cast(*SelectedIt)) - { - Node->PostCopyNode(); - } - } -} - -bool FFlowAssetEditor::CanCopyNodes() const -{ - if (CanEdit()) - { - const FGraphPanelSelectionSet SelectedNodes = GraphEditor->GetSelectedNodes(); - for (FGraphPanelSelectionSet::TConstIterator SelectedIt(SelectedNodes); SelectedIt; ++SelectedIt) - { - const UEdGraphNode* Node = Cast(*SelectedIt); - if (Node && Node->CanDuplicateNode()) - { - return true; - } - } - } - - return false; -} - -void FFlowAssetEditor::PasteNodes() -{ - PasteNodesHere(GraphEditor->GetPasteLocation()); -} - -void FFlowAssetEditor::PasteNodesHere(const FVector2D& Location) -{ - SetUISelectionState(NAME_None); - - // Undo/Redo support - const FScopedTransaction Transaction(LOCTEXT("PasteNode", "Paste Node")); - FlowAsset->GetGraph()->Modify(); - FlowAsset->Modify(); - - // Clear the selection set (newly pasted stuff will be selected) - GraphEditor->ClearSelectionSet(); - - // Grab the text to paste from the clipboard. - FString TextToImport; - FPlatformApplicationMisc::ClipboardPaste(TextToImport); - - // Import the nodes - TSet PastedNodes; - FEdGraphUtilities::ImportNodesFromText(FlowAsset->GetGraph(), TextToImport, /*out*/ PastedNodes); - - //Average position of nodes so we can move them while still maintaining relative distances to each other - FVector2D AvgNodePosition(0.0f, 0.0f); - - for (TSet::TIterator It(PastedNodes); It; ++It) - { - const UEdGraphNode* Node = *It; - AvgNodePosition.X += Node->NodePosX; - AvgNodePosition.Y += Node->NodePosY; - } - - if (PastedNodes.Num() > 0) - { - const float InvNumNodes = 1.0f / static_cast(PastedNodes.Num()); - AvgNodePosition.X *= InvNumNodes; - AvgNodePosition.Y *= InvNumNodes; - } - - for (TSet::TIterator It(PastedNodes); It; ++It) - { - UEdGraphNode* Node = *It; - - // Give new node a different Guid from the old one - Node->CreateNewGuid(); - - if (const UFlowGraphNode* FlowGraphNode = Cast(Node)) - { - FlowAsset->RegisterNode(Node->NodeGuid, FlowGraphNode->GetFlowNode()); - } - - // Select the newly pasted stuff - GraphEditor->SetNodeSelection(Node, true); - - Node->NodePosX = (Node->NodePosX - AvgNodePosition.X) + Location.X; - Node->NodePosY = (Node->NodePosY - AvgNodePosition.Y) + Location.Y; - - Node->SnapToGrid(SNodePanel::GetSnapGridSize()); - } - - // Force new pasted FlowNodes to have same connections as graph nodes - FlowAsset->HarvestNodeConnections(); - - // Update UI - GraphEditor->NotifyGraphChanged(); - - FlowAsset->PostEditChange(); - FlowAsset->MarkPackageDirty(); -} - -bool FFlowAssetEditor::CanPasteNodes() const -{ - if (CanEdit()) - { - FString ClipboardContent; - FPlatformApplicationMisc::ClipboardPaste(ClipboardContent); - - return FEdGraphUtilities::CanImportNodesFromText(FlowAsset->GetGraph(), ClipboardContent); - } - - return false; -} - -void FFlowAssetEditor::DuplicateNodes() -{ - CopySelectedNodes(); - PasteNodes(); -} - -bool FFlowAssetEditor::CanDuplicateNodes() const -{ - return CanCopyNodes(); -} - -void FFlowAssetEditor::OnNodeDoubleClicked(class UEdGraphNode* Node) const -{ - UFlowNode* FlowNode = Cast(Node)->GetFlowNode(); - - if (FlowNode) - { - if (UFlowGraphEditorSettings::Get()->NodeDoubleClickTarget == EFlowNodeDoubleClickTarget::NodeDefinition) - { - Node->JumpToDefinition(); - } - else - { - const FString AssetPath = FlowNode->GetAssetPath(); - if (!AssetPath.IsEmpty()) - { - GEditor->GetEditorSubsystem()->OpenEditorForAsset(AssetPath); - } - else if (UObject* AssetToEdit = FlowNode->GetAssetToEdit()) - { - GEditor->GetEditorSubsystem()->OpenEditorForAsset(AssetToEdit); - - if (IsPIE()) - { - if (UFlowNode_SubGraph* SubGraphNode = Cast(FlowNode)) - { - const TWeakObjectPtr SubFlowInstance = SubGraphNode->GetFlowAsset()->GetFlowInstance(SubGraphNode); - if (SubFlowInstance.IsValid()) - { - SubGraphNode->GetFlowAsset()->GetTemplateAsset()->SetInspectedInstance(SubFlowInstance->GetDisplayName()); - } - } - } - } - } - } -} - -void FFlowAssetEditor::OnNodeTitleCommitted(const FText& NewText, ETextCommit::Type CommitInfo, UEdGraphNode* NodeBeingChanged) -{ - if (NodeBeingChanged) - { - const FScopedTransaction Transaction(LOCTEXT("RenameNode", "Rename Node")); - NodeBeingChanged->Modify(); - NodeBeingChanged->OnRenameNode(NewText.ToString()); - } -} - -void FFlowAssetEditor::RefreshContextPins() const -{ - for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) - { - SelectedNode->RefreshContextPins(true); - } -} - -bool FFlowAssetEditor::CanRefreshContextPins() const -{ - if (CanEdit() && GetSelectedFlowNodes().Num() == 1) - { - for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) - { - return SelectedNode->SupportsContextPins(); - } - } - - return false; -} - -void FFlowAssetEditor::AddInput() const -{ - for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) - { - SelectedNode->AddUserInput(); - } -} - -bool FFlowAssetEditor::CanAddInput() const -{ - if (CanEdit() && GetSelectedFlowNodes().Num() == 1) - { - for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) - { - return SelectedNode->CanUserAddInput(); - } - } - - return false; -} - -void FFlowAssetEditor::AddOutput() const -{ - for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) - { - SelectedNode->AddUserOutput(); - } -} - -bool FFlowAssetEditor::CanAddOutput() const -{ - if (CanEdit() && GetSelectedFlowNodes().Num() == 1) - { - for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) - { - return SelectedNode->CanUserAddOutput(); - } - } - - return false; -} - -void FFlowAssetEditor::RemovePin() const -{ - if (UEdGraphPin* SelectedPin = GraphEditor->GetGraphPinForMenu()) - { - if (UFlowGraphNode* SelectedNode = Cast(SelectedPin->GetOwningNode())) - { - SelectedNode->RemoveInstancePin(SelectedPin); - } - } -} - -bool FFlowAssetEditor::CanRemovePin() const -{ - if (CanEdit() && GetSelectedFlowNodes().Num() == 1) - { - if (const UEdGraphPin* Pin = GraphEditor->GetGraphPinForMenu()) - { - if (const UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) - { - if (Pin->Direction == EGPD_Input) - { - return GraphNode->CanUserRemoveInput(Pin); - } - else - { - return GraphNode->CanUserRemoveOutput(Pin); - } - } - } - } - - return false; -} - -void FFlowAssetEditor::OnAddBreakpoint() const -{ - for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) - { - SelectedNode->NodeBreakpoint.AddBreakpoint(); - } -} - -void FFlowAssetEditor::OnAddPinBreakpoint() const -{ - if (UEdGraphPin* Pin = GraphEditor->GetGraphPinForMenu()) - { - if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) - { - GraphNode->PinBreakpoints.Add(Pin, FFlowBreakpoint()); - GraphNode->PinBreakpoints[Pin].AddBreakpoint(); - } - } -} - -bool FFlowAssetEditor::CanAddBreakpoint() const -{ - for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) - { - return !SelectedNode->NodeBreakpoint.HasBreakpoint(); - } - - return false; -} - -bool FFlowAssetEditor::CanAddPinBreakpoint() const -{ - if (UEdGraphPin* Pin = GraphEditor->GetGraphPinForMenu()) - { - if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) - { - return !GraphNode->PinBreakpoints.Contains(Pin) || !GraphNode->PinBreakpoints[Pin].HasBreakpoint(); - } - } - - return false; -} - -void FFlowAssetEditor::OnRemoveBreakpoint() const -{ - for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) - { - SelectedNode->NodeBreakpoint.RemoveBreakpoint(); - } -} - -void FFlowAssetEditor::OnRemovePinBreakpoint() const -{ - if (UEdGraphPin* Pin = GraphEditor->GetGraphPinForMenu()) - { - if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) - { - GraphNode->PinBreakpoints.Remove(Pin); - } - } -} - -bool FFlowAssetEditor::CanRemoveBreakpoint() const -{ - for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) - { - return SelectedNode->NodeBreakpoint.HasBreakpoint(); - } - - return false; -} - -bool FFlowAssetEditor::CanRemovePinBreakpoint() const -{ - if (UEdGraphPin* Pin = GraphEditor->GetGraphPinForMenu()) - { - if (const UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) - { - return GraphNode->PinBreakpoints.Contains(Pin); - } - } - - return false; -} - -void FFlowAssetEditor::OnEnableBreakpoint() const -{ - for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) - { - SelectedNode->NodeBreakpoint.EnableBreakpoint(); - } -} - -void FFlowAssetEditor::OnEnablePinBreakpoint() const -{ - if (UEdGraphPin* Pin = GraphEditor->GetGraphPinForMenu()) - { - if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) - { - GraphNode->PinBreakpoints[Pin].EnableBreakpoint(); - } - } -} - -bool FFlowAssetEditor::CanEnableBreakpoint() const -{ - if (UEdGraphPin* Pin = GraphEditor->GetGraphPinForMenu()) - { - if (const UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) - { - return GraphNode->PinBreakpoints.Contains(Pin); - } - } - - for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) - { - return SelectedNode->NodeBreakpoint.CanEnableBreakpoint(); - } - - return false; -} - -bool FFlowAssetEditor::CanEnablePinBreakpoint() const -{ - if (UEdGraphPin* Pin = GraphEditor->GetGraphPinForMenu()) - { - if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) - { - return GraphNode->PinBreakpoints.Contains(Pin) && GraphNode->PinBreakpoints[Pin].CanEnableBreakpoint(); - } - } - - return false; -} - -void FFlowAssetEditor::OnDisableBreakpoint() const -{ - for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) - { - SelectedNode->NodeBreakpoint.DisableBreakpoint(); - } -} - -void FFlowAssetEditor::OnDisablePinBreakpoint() const -{ - if (UEdGraphPin* Pin = GraphEditor->GetGraphPinForMenu()) - { - if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) - { - GraphNode->PinBreakpoints[Pin].DisableBreakpoint(); - } - } -} - -bool FFlowAssetEditor::CanDisableBreakpoint() const -{ - for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) - { - return SelectedNode->NodeBreakpoint.IsBreakpointEnabled(); - } - - return false; -} - -bool FFlowAssetEditor::CanDisablePinBreakpoint() const -{ - if (UEdGraphPin* Pin = GraphEditor->GetGraphPinForMenu()) - { - if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) - { - return GraphNode->PinBreakpoints.Contains(Pin) && GraphNode->PinBreakpoints[Pin].IsBreakpointEnabled(); - } - } - - return false; -} - -void FFlowAssetEditor::OnToggleBreakpoint() const -{ - for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) - { - SelectedNode->NodeBreakpoint.ToggleBreakpoint(); - } -} - -void FFlowAssetEditor::OnTogglePinBreakpoint() const -{ - if (UEdGraphPin* Pin = GraphEditor->GetGraphPinForMenu()) - { - if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) - { - GraphNode->PinBreakpoints.Add(Pin, FFlowBreakpoint()); - GraphNode->PinBreakpoints[Pin].ToggleBreakpoint(); - } - } -} - -bool FFlowAssetEditor::CanToggleBreakpoint() const -{ - return GetSelectedFlowNodes().Num() > 0; -} - -bool FFlowAssetEditor::CanTogglePinBreakpoint() const -{ - return GraphEditor->GetGraphPinForMenu() != nullptr; -} - -void FFlowAssetEditor::SetSignalMode(const EFlowSignalMode Mode) const -{ - for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) - { - SelectedNode->SetSignalMode(Mode); - } - - FlowAsset->Modify(); -} - -bool FFlowAssetEditor::CanSetSignalMode(const EFlowSignalMode Mode) const -{ - if (IsPIE()) - { - return false; - } - - for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) - { - return SelectedNode->CanSetSignalMode(Mode); - } - - return false; -} - -void FFlowAssetEditor::OnForcePinActivation() const -{ - if (UEdGraphPin* Pin = GraphEditor->GetGraphPinForMenu()) - { - if (const UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) - { - GraphNode->ForcePinActivation(Pin); - } - } -} - -void FFlowAssetEditor::FocusViewport() const -{ - // Iterator used but should only contain one node - for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) - { - const UFlowNode* FlowNode = Cast(SelectedNode)->GetFlowNode(); - if (UFlowNode* NodeInstance = FlowNode->GetInspectedInstance()) - { - if (AActor* ActorToFocus = NodeInstance->GetActorToFocus()) - { - GEditor->SelectNone(false, false, false); - GEditor->SelectActor(ActorToFocus, true, true, true); - GEditor->NoteSelectionChange(); - - GEditor->MoveViewportCamerasToActor(*ActorToFocus, false); - - const FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked("LevelEditor"); - const TSharedPtr LevelEditorTab = LevelEditorModule.GetLevelEditorInstanceTab().Pin(); - if (LevelEditorTab.IsValid()) - { - LevelEditorTab->DrawAttention(); - } - } - } - - return; - } -} - -bool FFlowAssetEditor::CanFocusViewport() const -{ - return GetSelectedFlowNodes().Num() == 1; -} - -void FFlowAssetEditor::JumpToNodeDefinition() const -{ - // Iterator used but should only contain one node - for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) - { - SelectedNode->JumpToDefinition(); - return; - } -} - -bool FFlowAssetEditor::CanJumpToNodeDefinition() const -{ - return GetSelectedFlowNodes().Num() == 1; -} - #undef LOCTEXT_NAMESPACE diff --git a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp index 8315d7ac6..712b24543 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp @@ -45,9 +45,9 @@ void SFlowAssetInstanceList::Construct(const FArguments& InArgs, const TWeakObje // create dropdown SAssignNew(Dropdown, SComboBox>) .OptionsSource(&InstanceNames) + .Visibility_Static(&SFlowAssetInstanceList::GetDebuggerVisibility) .OnGenerateWidget(this, &SFlowAssetInstanceList::OnGenerateWidget) .OnSelectionChanged(this, &SFlowAssetInstanceList::OnSelectionChanged) - .Visibility_Static(&FFlowAssetEditor::GetDebuggerVisibility) [ SNew(STextBlock) .Text(this, &SFlowAssetInstanceList::GetSelectedInstanceName) @@ -93,6 +93,11 @@ void SFlowAssetInstanceList::RefreshInstances() } } +EVisibility SFlowAssetInstanceList::GetDebuggerVisibility() +{ + return GEditor->PlayWorld ? EVisibility::Visible : EVisibility::Collapsed; +} + TSharedRef SFlowAssetInstanceList::OnGenerateWidget(const TSharedPtr Item) const { return SNew(STextBlock).Text(FText::FromName(*Item.Get())); @@ -127,7 +132,7 @@ void SFlowAssetBreadcrumb::Construct(const FArguments& InArgs, const TWeakObject // create breadcrumb SAssignNew(BreadcrumbTrail, SBreadcrumbTrail) .OnCrumbClicked(this, &SFlowAssetBreadcrumb::OnCrumbClicked) - .Visibility_Static(&FFlowAssetEditor::GetDebuggerVisibility) + .Visibility_Static(&SFlowAssetInstanceList::GetDebuggerVisibility) .ButtonStyle(FEditorStyle::Get(), "FlatButton") .DelimiterImage(FEditorStyle::GetBrush("Sequencer.BreadcrumbIcon")) .PersistentBreadcrumbs(true) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp b/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp index 78ee5c179..42510dddd 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp @@ -2,8 +2,8 @@ #include "Graph/FlowGraphConnectionDrawingPolicy.h" -#include "Asset/FlowAssetEditor.h" #include "Graph/FlowGraph.h" +#include "Graph/FlowGraphEditor.h" #include "Graph/FlowGraphEditorSettings.h" #include "Graph/FlowGraphSchema.h" #include "Graph/FlowGraphSettings.h" @@ -81,10 +81,10 @@ void FFlowGraphConnectionDrawingPolicy::BuildPaths() if (GraphObj && (UFlowGraphEditorSettings::Get()->bHighlightInputWiresOfSelectedNodes || UFlowGraphEditorSettings::Get()->bHighlightOutputWiresOfSelectedNodes)) { - const TSharedPtr FlowAssetEditor = FFlowGraphUtils::GetFlowAssetEditor(GraphObj); - if (FlowAssetEditor.IsValid()) + const TSharedPtr FlowGraphEditor = FFlowGraphUtils::GetFlowGraphEditor(GraphObj); + if (FlowGraphEditor.IsValid()) { - for (UFlowGraphNode* SelectedNode : FlowAssetEditor->GetSelectedFlowNodes()) + for (UFlowGraphNode* SelectedNode : FlowGraphEditor->GetSelectedFlowNodes()) { for (UEdGraphPin* Pin : SelectedNode->Pins) { diff --git a/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp b/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp new file mode 100644 index 000000000..b7f1a63f8 --- /dev/null +++ b/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp @@ -0,0 +1,1029 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#include "Graph/FlowGraphEditor.h" + +#include "FlowEditorCommands.h" + +#include "Asset/FlowAssetEditor.h" +#include "Asset/FlowDebuggerSubsystem.h" +#include "Graph/FlowGraphEditorSettings.h" +#include "Graph/FlowGraphSchema_Actions.h" +#include "Graph/Nodes/FlowGraphNode.h" + +#include "Nodes/Route/FlowNode_SubGraph.h" + +#include "Framework/Commands/GenericCommands.h" +#include "HAL/PlatformApplicationMisc.h" +#include "LevelEditor.h" + +#define LOCTEXT_NAMESPACE "FlowGraphEditor" + +void SFlowGraphEditor::Construct(const FArguments& InArgs, const TSharedPtr InAssetEditor) +{ + FlowAssetEditor = InAssetEditor; + FlowAsset = FlowAssetEditor.Pin()->GetFlowAsset(); + + DetailsView = InArgs._DetailsView; + + BindGraphCommands(); + + SGraphEditor::FArguments Arguments; + Arguments._Appearance = GetGraphAppearanceInfo(); + Arguments._GraphToEdit = FlowAsset->GetGraph(); + Arguments._GraphEvents = InArgs._GraphEvents; + Arguments._AutoExpandActionMenu = true; + //Arguments._ShowGraphStateOverlay = false; + + Arguments._GraphEvents.OnSelectionChanged = FOnSelectionChanged::CreateSP(this, &SFlowGraphEditor::OnSelectedNodesChanged); + Arguments._GraphEvents.OnNodeDoubleClicked = FSingleNodeEvent::CreateSP(this, &SFlowGraphEditor::OnNodeDoubleClicked); + Arguments._GraphEvents.OnTextCommitted = FOnNodeTextCommitted::CreateSP(this, &SFlowGraphEditor::OnNodeTitleCommitted); + Arguments._GraphEvents.OnSpawnNodeByShortcut = FOnSpawnNodeByShortcut::CreateStatic(&SFlowGraphEditor::OnSpawnGraphNodeByShortcut, static_cast(FlowAsset->GetGraph())); + + SGraphEditor::Construct(Arguments); +} + +void SFlowGraphEditor::BindGraphCommands() +{ + FGraphEditorCommands::Register(); + FFlowGraphCommands::Register(); + FFlowSpawnNodeCommands::Register(); + + const TSharedRef& ToolkitCommands = FlowAssetEditor.Pin()->GetToolkitCommands(); + const FGenericCommands& GenericCommands = FGenericCommands::Get(); + const FGraphEditorCommandsImpl& GraphCommands = FGraphEditorCommands::Get(); + const FFlowGraphCommands& FlowGraphCommands = FFlowGraphCommands::Get(); + + // Graph commands + ToolkitCommands->MapAction(GraphCommands.CreateComment, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnCreateComment), + FCanExecuteAction::CreateStatic(&SFlowGraphEditor::CanEdit)); + + ToolkitCommands->MapAction(GraphCommands.StraightenConnections, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnStraightenConnections)); + + // Generic Node commands + ToolkitCommands->MapAction(GenericCommands.Undo, + FExecuteAction::CreateStatic(&SFlowGraphEditor::UndoGraphAction), + FCanExecuteAction::CreateStatic(&SFlowGraphEditor::CanEdit)); + + ToolkitCommands->MapAction(GenericCommands.Redo, + FExecuteAction::CreateStatic(&SFlowGraphEditor::RedoGraphAction), + FCanExecuteAction::CreateStatic(&SFlowGraphEditor::CanEdit)); + + ToolkitCommands->MapAction(GenericCommands.SelectAll, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::SelectAllNodes), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanSelectAllNodes)); + + ToolkitCommands->MapAction(GenericCommands.Delete, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::DeleteSelectedNodes), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanDeleteNodes)); + + ToolkitCommands->MapAction(GenericCommands.Copy, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::CopySelectedNodes), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanCopyNodes)); + + ToolkitCommands->MapAction(GenericCommands.Cut, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::CutSelectedNodes), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanCutNodes)); + + ToolkitCommands->MapAction(GenericCommands.Paste, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::PasteNodes), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanPasteNodes)); + + ToolkitCommands->MapAction(GenericCommands.Duplicate, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::DuplicateNodes), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanDuplicateNodes)); + + // Pin commands + ToolkitCommands->MapAction(FlowGraphCommands.RefreshContextPins, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::RefreshContextPins), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanRefreshContextPins)); + + ToolkitCommands->MapAction(FlowGraphCommands.AddInput, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::AddInput), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanAddInput)); + + ToolkitCommands->MapAction(FlowGraphCommands.AddOutput, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::AddOutput), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanAddOutput)); + + ToolkitCommands->MapAction(FlowGraphCommands.RemovePin, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::RemovePin), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanRemovePin)); + + // Breakpoint commands + ToolkitCommands->MapAction(GraphCommands.AddBreakpoint, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnAddBreakpoint), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanAddBreakpoint), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanAddBreakpoint) + ); + + ToolkitCommands->MapAction(GraphCommands.RemoveBreakpoint, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnRemoveBreakpoint), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanRemoveBreakpoint), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanRemoveBreakpoint) + ); + + ToolkitCommands->MapAction(GraphCommands.EnableBreakpoint, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnEnableBreakpoint), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanEnableBreakpoint), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanEnableBreakpoint) + ); + + ToolkitCommands->MapAction(GraphCommands.DisableBreakpoint, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnDisableBreakpoint), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanDisableBreakpoint), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanDisableBreakpoint) + ); + + ToolkitCommands->MapAction(GraphCommands.ToggleBreakpoint, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnToggleBreakpoint), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanToggleBreakpoint), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanToggleBreakpoint) + ); + + // Pin Breakpoint commands + ToolkitCommands->MapAction(FlowGraphCommands.AddPinBreakpoint, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnAddPinBreakpoint), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanAddPinBreakpoint), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanAddPinBreakpoint) + ); + + ToolkitCommands->MapAction(FlowGraphCommands.RemovePinBreakpoint, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnRemovePinBreakpoint), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanRemovePinBreakpoint), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanRemovePinBreakpoint) + ); + + ToolkitCommands->MapAction(FlowGraphCommands.EnablePinBreakpoint, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnEnablePinBreakpoint), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanEnablePinBreakpoint), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanEnablePinBreakpoint) + ); + + ToolkitCommands->MapAction(FlowGraphCommands.DisablePinBreakpoint, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnDisablePinBreakpoint), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanDisablePinBreakpoint), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanDisablePinBreakpoint) + ); + + ToolkitCommands->MapAction(FlowGraphCommands.TogglePinBreakpoint, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnTogglePinBreakpoint), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanTogglePinBreakpoint), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanTogglePinBreakpoint) + ); + + // Execution Override commands + ToolkitCommands->MapAction(FlowGraphCommands.EnableNode, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::SetSignalMode, EFlowSignalMode::Enabled), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanSetSignalMode, EFlowSignalMode::Enabled), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanSetSignalMode, EFlowSignalMode::Enabled) + ); + + ToolkitCommands->MapAction(FlowGraphCommands.DisableNode, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::SetSignalMode, EFlowSignalMode::Disabled), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanSetSignalMode, EFlowSignalMode::Disabled), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanSetSignalMode, EFlowSignalMode::Disabled) + ); + + ToolkitCommands->MapAction(FlowGraphCommands.SetPassThrough, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::SetSignalMode, EFlowSignalMode::PassThrough), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanSetSignalMode, EFlowSignalMode::PassThrough), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanSetSignalMode, EFlowSignalMode::PassThrough) + ); + + ToolkitCommands->MapAction(FlowGraphCommands.ForcePinActivation, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnForcePinActivation), + FCanExecuteAction::CreateStatic(&SFlowGraphEditor::IsPIE), + FIsActionChecked(), + FIsActionButtonVisible::CreateStatic(&SFlowGraphEditor::IsPIE) + ); + + // Jump commands + ToolkitCommands->MapAction(FlowGraphCommands.FocusViewport, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::FocusViewport), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanFocusViewport)); + + ToolkitCommands->MapAction(FlowGraphCommands.JumpToNodeDefinition, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::JumpToNodeDefinition), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanJumpToNodeDefinition)); +} + +FGraphAppearanceInfo SFlowGraphEditor::GetGraphAppearanceInfo() const +{ + FGraphAppearanceInfo AppearanceInfo; + AppearanceInfo.CornerText = GetCornerText(); + + if (UFlowDebuggerSubsystem::IsPlaySessionPaused()) + { + AppearanceInfo.PIENotifyText = LOCTEXT("PausedLabel", "PAUSED"); + } + + return AppearanceInfo; +} + +FText SFlowGraphEditor::GetCornerText() const +{ + return LOCTEXT("AppearanceCornerText_FlowAsset", "FLOW"); +} + +void SFlowGraphEditor::UndoGraphAction() +{ + GEditor->UndoTransaction(); +} + +void SFlowGraphEditor::RedoGraphAction() +{ + GEditor->RedoTransaction(); +} + +FReply SFlowGraphEditor::OnSpawnGraphNodeByShortcut(FInputChord InChord, const FVector2D& InPosition, UEdGraph* InGraph) +{ + UEdGraph* Graph = InGraph; + + if (FFlowSpawnNodeCommands::IsRegistered()) + { + const TSharedPtr Action = FFlowSpawnNodeCommands::Get().GetActionByChord(InChord); + if (Action.IsValid()) + { + TArray DummyPins; + Action->PerformAction(Graph, DummyPins, InPosition); + return FReply::Handled(); + } + } + + return FReply::Unhandled(); +} + +void SFlowGraphEditor::OnCreateComment() const +{ + FFlowGraphSchemaAction_NewComment CommentAction; + CommentAction.PerformAction(FlowAsset->GetGraph(), nullptr, GetPasteLocation()); +} + +bool SFlowGraphEditor::CanEdit() +{ + return GEditor->PlayWorld == nullptr; +} + +bool SFlowGraphEditor::IsPIE() +{ + return GEditor->PlayWorld != nullptr; +} + +bool SFlowGraphEditor::IsTabFocused() const +{ + return FlowAssetEditor.Pin()->IsTabFocused(FFlowAssetEditor::GraphTab); +} + +void SFlowGraphEditor::SelectSingleNode(UEdGraphNode* Node) +{ + ClearSelectionSet(); + SetNodeSelection(Node, true); +} + +void SFlowGraphEditor::OnSelectedNodesChanged(const TSet& Nodes) +{ + TArray SelectedObjects; + + if (Nodes.Num() > 0) + { + FlowAssetEditor.Pin()->SetUISelectionState(FFlowAssetEditor::GraphTab); + + for (TSet::TConstIterator SetIt(Nodes); SetIt; ++SetIt) + { + if (const UFlowGraphNode* GraphNode = Cast(*SetIt)) + { + SelectedObjects.Add(Cast(GraphNode->GetFlowNode())); + } + else + { + SelectedObjects.Add(*SetIt); + } + } + } + else + { + FlowAssetEditor.Pin()->SetUISelectionState(NAME_None); + SelectedObjects.Add(FlowAsset.Get()); + } + + if (DetailsView.IsValid()) + { + DetailsView->SetObjects(SelectedObjects); + } + + OnSelectionChangedEvent.ExecuteIfBound(Nodes); +} + +TSet SFlowGraphEditor::GetSelectedFlowNodes() const +{ + TSet Result; + + const FGraphPanelSelectionSet SelectedNodes = GetSelectedNodes(); + for (FGraphPanelSelectionSet::TConstIterator NodeIt(SelectedNodes); NodeIt; ++NodeIt) + { + if (UFlowGraphNode* SelectedNode = Cast(*NodeIt)) + { + Result.Emplace(SelectedNode); + } + } + + return Result; +} + +void SFlowGraphEditor::DeleteSelectedNodes() +{ + const FScopedTransaction Transaction(LOCTEXT("DeleteSelectedNode", "Delete Selected Node")); + GetCurrentGraph()->Modify(); + FlowAsset->Modify(); + + const FGraphPanelSelectionSet SelectedNodes = GetSelectedNodes(); + FlowAssetEditor.Pin()->SetUISelectionState(NAME_None); + + for (FGraphPanelSelectionSet::TConstIterator NodeIt(SelectedNodes); NodeIt; ++NodeIt) + { + UEdGraphNode* Node = CastChecked(*NodeIt); + if (Node->CanUserDeleteNode()) + { + if (const UFlowGraphNode* FlowGraphNode = Cast(Node)) + { + if (FlowGraphNode->GetFlowNode()) + { + const FGuid NodeGuid = FlowGraphNode->GetFlowNode()->GetGuid(); + + GetCurrentGraph()->GetSchema()->BreakNodeLinks(*Node); + Node->DestroyNode(); + + FlowAsset->UnregisterNode(NodeGuid); + continue; + } + } + + GetCurrentGraph()->GetSchema()->BreakNodeLinks(*Node); + Node->DestroyNode(); + } + } +} + +void SFlowGraphEditor::DeleteSelectedDuplicableNodes() +{ + // Cache off the old selection + const FGraphPanelSelectionSet OldSelectedNodes = GetSelectedNodes(); + + // Clear the selection and only select the nodes that can be duplicated + FGraphPanelSelectionSet RemainingNodes; + ClearSelectionSet(); + + for (FGraphPanelSelectionSet::TConstIterator SelectedIt(OldSelectedNodes); SelectedIt; ++SelectedIt) + { + if (UEdGraphNode* Node = Cast(*SelectedIt)) + { + if (Node->CanDuplicateNode()) + { + SetNodeSelection(Node, true); + } + else + { + RemainingNodes.Add(Node); + } + } + } + + // Delete the duplicable nodes + DeleteSelectedNodes(); + + for (FGraphPanelSelectionSet::TConstIterator SelectedIt(RemainingNodes); SelectedIt; ++SelectedIt) + { + if (UEdGraphNode* Node = Cast(*SelectedIt)) + { + SetNodeSelection(Node, true); + } + } +} + +bool SFlowGraphEditor::CanDeleteNodes() const +{ + if (CanEdit() && IsTabFocused()) + { + const FGraphPanelSelectionSet SelectedNodes = GetSelectedNodes(); + for (FGraphPanelSelectionSet::TConstIterator NodeIt(SelectedNodes); NodeIt; ++NodeIt) + { + if (const UEdGraphNode* Node = Cast(*NodeIt)) + { + if (!Node->CanUserDeleteNode()) + { + return false; + } + } + } + + return SelectedNodes.Num() > 0; + } + + return false; +} + +void SFlowGraphEditor::CutSelectedNodes() +{ + CopySelectedNodes(); + + // Cut should only delete nodes that can be duplicated + DeleteSelectedDuplicableNodes(); +} + +bool SFlowGraphEditor::CanCutNodes() const +{ + return CanCopyNodes() && CanDeleteNodes(); +} + +void SFlowGraphEditor::CopySelectedNodes() const +{ + const FGraphPanelSelectionSet SelectedNodes = GetSelectedNodes(); + for (FGraphPanelSelectionSet::TConstIterator SelectedIt(SelectedNodes); SelectedIt; ++SelectedIt) + { + if (UFlowGraphNode* Node = Cast(*SelectedIt)) + { + Node->PrepareForCopying(); + } + } + + // Export the selected nodes and place the text on the clipboard + FString ExportedText; + FEdGraphUtilities::ExportNodesToText(SelectedNodes, /*out*/ ExportedText); + FPlatformApplicationMisc::ClipboardCopy(*ExportedText); + + for (FGraphPanelSelectionSet::TConstIterator SelectedIt(SelectedNodes); SelectedIt; ++SelectedIt) + { + if (UFlowGraphNode* Node = Cast(*SelectedIt)) + { + Node->PostCopyNode(); + } + } +} + +bool SFlowGraphEditor::CanCopyNodes() const +{ + if (CanEdit() && IsTabFocused()) + { + const FGraphPanelSelectionSet SelectedNodes = GetSelectedNodes(); + for (FGraphPanelSelectionSet::TConstIterator SelectedIt(SelectedNodes); SelectedIt; ++SelectedIt) + { + const UEdGraphNode* Node = Cast(*SelectedIt); + if (Node && Node->CanDuplicateNode()) + { + return true; + } + } + } + + return false; +} + +void SFlowGraphEditor::PasteNodes() +{ + PasteNodesHere(GetPasteLocation()); +} + +void SFlowGraphEditor::PasteNodesHere(const FVector2D& Location) +{ + FlowAssetEditor.Pin()->SetUISelectionState(NAME_None); + + // Undo/Redo support + const FScopedTransaction Transaction(LOCTEXT("PasteNode", "Paste Node")); + FlowAsset->GetGraph()->Modify(); + FlowAsset->Modify(); + + // Clear the selection set (newly pasted stuff will be selected) + ClearSelectionSet(); + + // Grab the text to paste from the clipboard. + FString TextToImport; + FPlatformApplicationMisc::ClipboardPaste(TextToImport); + + // Import the nodes + TSet PastedNodes; + FEdGraphUtilities::ImportNodesFromText(FlowAsset->GetGraph(), TextToImport, /*out*/ PastedNodes); + + //Average position of nodes so we can move them while still maintaining relative distances to each other + FVector2D AvgNodePosition(0.0f, 0.0f); + + for (TSet::TIterator It(PastedNodes); It; ++It) + { + const UEdGraphNode* Node = *It; + AvgNodePosition.X += Node->NodePosX; + AvgNodePosition.Y += Node->NodePosY; + } + + if (PastedNodes.Num() > 0) + { + const float InvNumNodes = 1.0f / static_cast(PastedNodes.Num()); + AvgNodePosition.X *= InvNumNodes; + AvgNodePosition.Y *= InvNumNodes; + } + + for (TSet::TIterator It(PastedNodes); It; ++It) + { + UEdGraphNode* Node = *It; + + // Give new node a different Guid from the old one + Node->CreateNewGuid(); + + if (const UFlowGraphNode* FlowGraphNode = Cast(Node)) + { + FlowAsset->RegisterNode(Node->NodeGuid, FlowGraphNode->GetFlowNode()); + } + + // Select the newly pasted stuff + SetNodeSelection(Node, true); + + Node->NodePosX = (Node->NodePosX - AvgNodePosition.X) + Location.X; + Node->NodePosY = (Node->NodePosY - AvgNodePosition.Y) + Location.Y; + + Node->SnapToGrid(SNodePanel::GetSnapGridSize()); + } + + // Force new pasted FlowNodes to have same connections as graph nodes + FlowAsset->HarvestNodeConnections(); + + // Update UI + NotifyGraphChanged(); + + FlowAsset->PostEditChange(); + FlowAsset->MarkPackageDirty(); +} + +bool SFlowGraphEditor::CanPasteNodes() const +{ + if (CanEdit() && IsTabFocused()) + { + FString ClipboardContent; + FPlatformApplicationMisc::ClipboardPaste(ClipboardContent); + + return FEdGraphUtilities::CanImportNodesFromText(FlowAsset->GetGraph(), ClipboardContent); + } + + return false; +} + +void SFlowGraphEditor::DuplicateNodes() +{ + CopySelectedNodes(); + PasteNodes(); +} + +bool SFlowGraphEditor::CanDuplicateNodes() const +{ + return CanCopyNodes(); +} + +void SFlowGraphEditor::OnNodeDoubleClicked(class UEdGraphNode* Node) const +{ + UFlowNode* FlowNode = Cast(Node)->GetFlowNode(); + + if (FlowNode) + { + if (UFlowGraphEditorSettings::Get()->NodeDoubleClickTarget == EFlowNodeDoubleClickTarget::NodeDefinition) + { + Node->JumpToDefinition(); + } + else + { + const FString AssetPath = FlowNode->GetAssetPath(); + if (!AssetPath.IsEmpty()) + { + GEditor->GetEditorSubsystem()->OpenEditorForAsset(AssetPath); + } + else if (UObject* AssetToEdit = FlowNode->GetAssetToEdit()) + { + GEditor->GetEditorSubsystem()->OpenEditorForAsset(AssetToEdit); + + if (IsPIE()) + { + if (UFlowNode_SubGraph* SubGraphNode = Cast(FlowNode)) + { + const TWeakObjectPtr SubFlowInstance = SubGraphNode->GetFlowAsset()->GetFlowInstance(SubGraphNode); + if (SubFlowInstance.IsValid()) + { + SubGraphNode->GetFlowAsset()->GetTemplateAsset()->SetInspectedInstance(SubFlowInstance->GetDisplayName()); + } + } + } + } + } + } +} + +void SFlowGraphEditor::OnNodeTitleCommitted(const FText& NewText, ETextCommit::Type CommitInfo, UEdGraphNode* NodeBeingChanged) +{ + if (NodeBeingChanged) + { + const FScopedTransaction Transaction(LOCTEXT("RenameNode", "Rename Node")); + NodeBeingChanged->Modify(); + NodeBeingChanged->OnRenameNode(NewText.ToString()); + } +} + +void SFlowGraphEditor::RefreshContextPins() const +{ + for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + { + SelectedNode->RefreshContextPins(true); + } +} + +bool SFlowGraphEditor::CanRefreshContextPins() const +{ + if (CanEdit() && GetSelectedFlowNodes().Num() == 1) + { + for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + { + return SelectedNode->SupportsContextPins(); + } + } + + return false; +} + +void SFlowGraphEditor::AddInput() const +{ + for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + { + SelectedNode->AddUserInput(); + } +} + +bool SFlowGraphEditor::CanAddInput() const +{ + if (CanEdit() && GetSelectedFlowNodes().Num() == 1) + { + for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + { + return SelectedNode->CanUserAddInput(); + } + } + + return false; +} + +void SFlowGraphEditor::AddOutput() const +{ + for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + { + SelectedNode->AddUserOutput(); + } +} + +bool SFlowGraphEditor::CanAddOutput() const +{ + if (CanEdit() && GetSelectedFlowNodes().Num() == 1) + { + for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + { + return SelectedNode->CanUserAddOutput(); + } + } + + return false; +} + +void SFlowGraphEditor::RemovePin() +{ + if (UEdGraphPin* SelectedPin = GetGraphPinForMenu()) + { + if (UFlowGraphNode* SelectedNode = Cast(SelectedPin->GetOwningNode())) + { + SelectedNode->RemoveInstancePin(SelectedPin); + } + } +} + +bool SFlowGraphEditor::CanRemovePin() +{ + if (CanEdit() && GetSelectedFlowNodes().Num() == 1) + { + if (const UEdGraphPin* Pin = GetGraphPinForMenu()) + { + if (const UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) + { + if (Pin->Direction == EGPD_Input) + { + return GraphNode->CanUserRemoveInput(Pin); + } + else + { + return GraphNode->CanUserRemoveOutput(Pin); + } + } + } + } + + return false; +} + +void SFlowGraphEditor::OnAddBreakpoint() const +{ + for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + { + SelectedNode->NodeBreakpoint.AddBreakpoint(); + } +} + +void SFlowGraphEditor::OnAddPinBreakpoint() +{ + if (UEdGraphPin* Pin = GetGraphPinForMenu()) + { + if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) + { + GraphNode->PinBreakpoints.Add(Pin, FFlowBreakpoint()); + GraphNode->PinBreakpoints[Pin].AddBreakpoint(); + } + } +} + +bool SFlowGraphEditor::CanAddBreakpoint() const +{ + for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + { + return !SelectedNode->NodeBreakpoint.HasBreakpoint(); + } + + return false; +} + +bool SFlowGraphEditor::CanAddPinBreakpoint() +{ + if (UEdGraphPin* Pin = GetGraphPinForMenu()) + { + if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) + { + return !GraphNode->PinBreakpoints.Contains(Pin) || !GraphNode->PinBreakpoints[Pin].HasBreakpoint(); + } + } + + return false; +} + +void SFlowGraphEditor::OnRemoveBreakpoint() const +{ + for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + { + SelectedNode->NodeBreakpoint.RemoveBreakpoint(); + } +} + +void SFlowGraphEditor::OnRemovePinBreakpoint() +{ + if (UEdGraphPin* Pin = GetGraphPinForMenu()) + { + if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) + { + GraphNode->PinBreakpoints.Remove(Pin); + } + } +} + +bool SFlowGraphEditor::CanRemoveBreakpoint() const +{ + for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + { + return SelectedNode->NodeBreakpoint.HasBreakpoint(); + } + + return false; +} + +bool SFlowGraphEditor::CanRemovePinBreakpoint() +{ + if (UEdGraphPin* Pin = GetGraphPinForMenu()) + { + if (const UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) + { + return GraphNode->PinBreakpoints.Contains(Pin); + } + } + + return false; +} + +void SFlowGraphEditor::OnEnableBreakpoint() const +{ + for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + { + SelectedNode->NodeBreakpoint.EnableBreakpoint(); + } +} + +void SFlowGraphEditor::OnEnablePinBreakpoint() +{ + if (UEdGraphPin* Pin = GetGraphPinForMenu()) + { + if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) + { + GraphNode->PinBreakpoints[Pin].EnableBreakpoint(); + } + } +} + +bool SFlowGraphEditor::CanEnableBreakpoint() +{ + if (UEdGraphPin* Pin = GetGraphPinForMenu()) + { + if (const UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) + { + return GraphNode->PinBreakpoints.Contains(Pin); + } + } + + for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + { + return SelectedNode->NodeBreakpoint.CanEnableBreakpoint(); + } + + return false; +} + +bool SFlowGraphEditor::CanEnablePinBreakpoint() +{ + if (UEdGraphPin* Pin = GetGraphPinForMenu()) + { + if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) + { + return GraphNode->PinBreakpoints.Contains(Pin) && GraphNode->PinBreakpoints[Pin].CanEnableBreakpoint(); + } + } + + return false; +} + +void SFlowGraphEditor::OnDisableBreakpoint() const +{ + for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + { + SelectedNode->NodeBreakpoint.DisableBreakpoint(); + } +} + +void SFlowGraphEditor::OnDisablePinBreakpoint() +{ + if (UEdGraphPin* Pin = GetGraphPinForMenu()) + { + if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) + { + GraphNode->PinBreakpoints[Pin].DisableBreakpoint(); + } + } +} + +bool SFlowGraphEditor::CanDisableBreakpoint() const +{ + for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + { + return SelectedNode->NodeBreakpoint.IsBreakpointEnabled(); + } + + return false; +} + +bool SFlowGraphEditor::CanDisablePinBreakpoint() +{ + if (UEdGraphPin* Pin = GetGraphPinForMenu()) + { + if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) + { + return GraphNode->PinBreakpoints.Contains(Pin) && GraphNode->PinBreakpoints[Pin].IsBreakpointEnabled(); + } + } + + return false; +} + +void SFlowGraphEditor::OnToggleBreakpoint() const +{ + for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + { + SelectedNode->NodeBreakpoint.ToggleBreakpoint(); + } +} + +void SFlowGraphEditor::OnTogglePinBreakpoint() +{ + if (UEdGraphPin* Pin = GetGraphPinForMenu()) + { + if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) + { + GraphNode->PinBreakpoints.Add(Pin, FFlowBreakpoint()); + GraphNode->PinBreakpoints[Pin].ToggleBreakpoint(); + } + } +} + +bool SFlowGraphEditor::CanToggleBreakpoint() const +{ + return GetSelectedFlowNodes().Num() > 0; +} + +bool SFlowGraphEditor::CanTogglePinBreakpoint() +{ + return GetGraphPinForMenu() != nullptr; +} + +void SFlowGraphEditor::SetSignalMode(const EFlowSignalMode Mode) const +{ + for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + { + SelectedNode->SetSignalMode(Mode); + } + + FlowAsset->Modify(); +} + +bool SFlowGraphEditor::CanSetSignalMode(const EFlowSignalMode Mode) const +{ + if (IsPIE()) + { + return false; + } + + for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + { + return SelectedNode->CanSetSignalMode(Mode); + } + + return false; +} + +void SFlowGraphEditor::OnForcePinActivation() +{ + if (UEdGraphPin* Pin = GetGraphPinForMenu()) + { + if (const UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) + { + GraphNode->ForcePinActivation(Pin); + } + } +} + +void SFlowGraphEditor::FocusViewport() const +{ + // Iterator used but should only contain one node + for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + { + const UFlowNode* FlowNode = Cast(SelectedNode)->GetFlowNode(); + if (UFlowNode* NodeInstance = FlowNode->GetInspectedInstance()) + { + if (AActor* ActorToFocus = NodeInstance->GetActorToFocus()) + { + GEditor->SelectNone(false, false, false); + GEditor->SelectActor(ActorToFocus, true, true, true); + GEditor->NoteSelectionChange(); + + GEditor->MoveViewportCamerasToActor(*ActorToFocus, false); + + const FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked("LevelEditor"); + const TSharedPtr LevelEditorTab = LevelEditorModule.GetLevelEditorInstanceTab().Pin(); + if (LevelEditorTab.IsValid()) + { + LevelEditorTab->DrawAttention(); + } + } + } + + return; + } +} + +bool SFlowGraphEditor::CanFocusViewport() const +{ + return GetSelectedFlowNodes().Num() == 1; +} + +void SFlowGraphEditor::JumpToNodeDefinition() const +{ + // Iterator used but should only contain one node + for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + { + SelectedNode->JumpToDefinition(); + return; + } +} + +bool SFlowGraphEditor::CanJumpToNodeDefinition() const +{ + return GetSelectedFlowNodes().Num() == 1; +} + +#undef LOCTEXT_NAMESPACE diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp index e60a6a5fb..83ff22706 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -4,6 +4,7 @@ #include "Asset/FlowAssetEditor.h" #include "Graph/FlowGraph.h" +#include "Graph/FlowGraphEditor.h" #include "Graph/FlowGraphSchema_Actions.h" #include "Graph/FlowGraphSettings.h" #include "Graph/FlowGraphUtils.h" @@ -62,7 +63,7 @@ void UFlowGraphSchema::GetGraphContextActions(FGraphContextMenuBuilder& ContextM GetFlowNodeActions(ContextMenuBuilder, GetAssetClassDefaults(ContextMenuBuilder.CurrentGraph), FString()); GetCommentAction(ContextMenuBuilder, ContextMenuBuilder.CurrentGraph); - if (!ContextMenuBuilder.FromPin && FFlowGraphUtils::GetFlowAssetEditor(ContextMenuBuilder.CurrentGraph)->CanPasteNodes()) + if (!ContextMenuBuilder.FromPin && FFlowGraphUtils::GetFlowGraphEditor(ContextMenuBuilder.CurrentGraph)->CanPasteNodes()) { const TSharedPtr NewAction(new FFlowGraphSchemaAction_Paste(FText::GetEmpty(), LOCTEXT("PasteHereAction", "Paste here"), FText::GetEmpty(), 0)); ContextMenuBuilder.AddAction(NewAction); @@ -172,7 +173,7 @@ void UFlowGraphSchema::BreakPinLinks(UEdGraphPin& TargetPin, bool bSendsNodeNoti int32 UFlowGraphSchema::GetNodeSelectionCount(const UEdGraph* Graph) const { - return FFlowGraphUtils::GetFlowAssetEditor(Graph)->GetNumberOfSelectedNodes(); + return FFlowGraphUtils::GetFlowGraphEditor(Graph)->GetNumberOfSelectedNodes(); } TSharedPtr UFlowGraphSchema::GetCreateCommentAction() const @@ -358,7 +359,7 @@ void UFlowGraphSchema::GetCommentAction(FGraphActionMenuBuilder& ActionMenuBuild { if (!ActionMenuBuilder.FromPin) { - const bool bIsManyNodesSelected = CurrentGraph ? (FFlowGraphUtils::GetFlowAssetEditor(CurrentGraph)->GetNumberOfSelectedNodes() > 0) : false; + const bool bIsManyNodesSelected = CurrentGraph ? (FFlowGraphUtils::GetFlowGraphEditor(CurrentGraph)->GetNumberOfSelectedNodes() > 0) : false; const FText MenuDescription = bIsManyNodesSelected ? LOCTEXT("CreateCommentAction", "Create Comment from Selection") : LOCTEXT("AddCommentAction", "Add Comment..."); const FText ToolTip = LOCTEXT("CreateCommentToolTip", "Creates a comment."); diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp index 7aea403a3..fcc34b9b9 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp @@ -2,8 +2,8 @@ #include "Graph/FlowGraphSchema_Actions.h" -#include "Asset/FlowAssetEditor.h" #include "Graph/FlowGraph.h" +#include "Graph/FlowGraphEditor.h" #include "Graph/FlowGraphSchema.h" #include "Graph/FlowGraphUtils.h" #include "Graph/Nodes/FlowGraphNode.h" @@ -81,10 +81,10 @@ UFlowGraphNode* FFlowGraphSchemaAction_NewNode::CreateNode(UEdGraph* ParentGraph // select in editor UI if (bSelectNewNode) { - const TSharedPtr FlowEditor = FFlowGraphUtils::GetFlowAssetEditor(ParentGraph); - if (FlowEditor.IsValid()) + const TSharedPtr FlowGraphEditor = FFlowGraphUtils::GetFlowGraphEditor(ParentGraph); + if (FlowGraphEditor.IsValid()) { - FlowEditor->SelectSingleNode(NewGraphNode); + FlowGraphEditor->SelectSingleNode(NewGraphNode); } } @@ -200,7 +200,7 @@ UEdGraphNode* FFlowGraphSchemaAction_Paste::PerformAction(class UEdGraph* Parent // prevent adding new nodes while playing if (GEditor->PlayWorld == nullptr) { - FFlowGraphUtils::GetFlowAssetEditor(ParentGraph)->PasteNodesHere(Location); + FFlowGraphUtils::GetFlowGraphEditor(ParentGraph)->PasteNodesHere(Location); } return nullptr; @@ -220,11 +220,11 @@ UEdGraphNode* FFlowGraphSchemaAction_NewComment::PerformAction(class UEdGraph* P UEdGraphNode_Comment* CommentTemplate = NewObject(); FVector2D SpawnLocation = Location; - const TSharedPtr FlowAssetEditor = FFlowGraphUtils::GetFlowAssetEditor(ParentGraph); - if (FlowAssetEditor.IsValid()) + const TSharedPtr FlowGraphEditor = FFlowGraphUtils::GetFlowGraphEditor(ParentGraph); + if (FlowGraphEditor.IsValid()) { FSlateRect Bounds; - if (FlowAssetEditor->GetBoundsForSelectedNodes(Bounds, 50.0f)) + if (FlowGraphEditor->GetBoundsForSelectedNodes(Bounds, 50.0f)) { CommentTemplate->SetBounds(Bounds); SpawnLocation.X = CommentTemplate->NodePosX; diff --git a/Source/FlowEditor/Private/Graph/FlowGraphUtils.cpp b/Source/FlowEditor/Private/Graph/FlowGraphUtils.cpp index b00e6a898..468ba353f 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphUtils.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphUtils.cpp @@ -8,12 +8,12 @@ #include "Toolkits/ToolkitManager.h" -TSharedPtr FFlowGraphUtils::GetFlowAssetEditor(const UObject* ObjectToFocusOn) +TSharedPtr FFlowGraphUtils::GetFlowAssetEditor(const UEdGraph* Graph) { - check(ObjectToFocusOn); + check(Graph); TSharedPtr FlowAssetEditor; - if (const UFlowAsset* FlowAsset = Cast(ObjectToFocusOn)->GetFlowAsset()) + if (const UFlowAsset* FlowAsset = Cast(Graph)->GetFlowAsset()) { const TSharedPtr FoundAssetEditor = FToolkitManager::Get().FindEditorForAsset(FlowAsset); if (FoundAssetEditor.IsValid()) @@ -23,3 +23,16 @@ TSharedPtr FFlowGraphUtils::GetFlowAssetEditor(const UObject* } return FlowAssetEditor; } + +TSharedPtr FFlowGraphUtils::GetFlowGraphEditor(const UEdGraph* Graph) +{ + TSharedPtr FlowGraphEditor; + + const TSharedPtr FlowEditor = GetFlowAssetEditor(Graph); + if (FlowEditor.IsValid()) + { + FlowGraphEditor = FlowEditor->GetFlowGraph(); + } + + return FlowGraphEditor; +} diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp index b73374648..3332500d2 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp @@ -101,7 +101,7 @@ FText SFlowPaletteItem::GetItemTooltip() const void SFlowPalette::Construct(const FArguments& InArgs, TWeakPtr InFlowAssetEditor) { - FlowAssetEditorPtr = InFlowAssetEditor; + FlowAssetEditor = InFlowAssetEditor; UpdateCategoryNames(); UFlowGraphSchema::OnNodeListChanged.AddSP(this, &SFlowPalette::Refresh); @@ -183,13 +183,8 @@ TSharedRef SFlowPalette::OnCreateWidgetForAction(FCreateWidgetForAction void SFlowPalette::CollectAllActions(FGraphActionListBuilderBase& OutAllActions) { - const UClass* AssetClass = UFlowAsset::StaticClass(); - - const TSharedPtr FlowAssetEditor = FlowAssetEditorPtr.Pin(); - if (FlowAssetEditor && FlowAssetEditor->GetFlowAsset()) - { - AssetClass = FlowAssetEditor->GetFlowAsset()->GetClass(); - } + ensureAlways(FlowAssetEditor.Pin() && FlowAssetEditor.Pin()->GetFlowAsset()); + const UClass* AssetClass = FlowAssetEditor.Pin()->GetFlowAsset()->GetClass(); FGraphActionMenuBuilder ActionMenuBuilder; UFlowGraphSchema::GetPaletteActions(ActionMenuBuilder, AssetClass, GetFilterCategoryName()); @@ -215,11 +210,7 @@ void SFlowPalette::OnActionSelected(const TArray FlowAssetEditor = FlowAssetEditorPtr.Pin(); - if (FlowAssetEditor) - { - FlowAssetEditor->SetUISelectionState(FFlowAssetEditor::PaletteTab); - } + FlowAssetEditor.Pin()->SetUISelectionState(FFlowAssetEditor::PaletteTab); } } diff --git a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h index fb8814331..0591c9cfd 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h @@ -3,7 +3,6 @@ #pragma once #include "EditorUndoClient.h" -#include "GraphEditor.h" #include "Misc/NotifyHook.h" #include "Toolkits/AssetEditorToolkit.h" #include "Toolkits/IToolkitHost.h" @@ -13,6 +12,7 @@ #include "FlowTypes.h" class FFlowMessageLog; +class SFlowGraphEditor; class SFlowPalette; class UFlowAsset; class UFlowGraphNode; @@ -27,13 +27,22 @@ struct Rect; class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEditorUndoClient, public FGCObject, public FNotifyHook { +public: + /** The tab ids for all the tabs used */ + static const FName DetailsTab; + static const FName GraphTab; + static const FName PaletteTab; + static const FName RuntimeLogTab; + static const FName SearchTab; + static const FName ValidationLogTab; + protected: /** The Flow Asset being edited */ UFlowAsset* FlowAsset; TSharedPtr AssetToolbar; - TSharedPtr GraphEditor; + TSharedPtr GraphEditor; TSharedPtr DetailsView; TSharedPtr Palette; @@ -49,15 +58,6 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit TSharedPtr ValidationLog; TSharedPtr ValidationLogListing; -public: - /** The tab ids for all the tabs used */ - static const FName DetailsTab; - static const FName GraphTab; - static const FName PaletteTab; - static const FName RuntimeLogTab; - static const FName SearchTab; - static const FName ValidationLogTab; - private: /** The current UI selection state of this editor */ FName CurrentUISelection; @@ -67,6 +67,7 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit virtual ~FFlowAssetEditor() override; UFlowAsset* GetFlowAsset() const { return FlowAsset; } + TSharedPtr GetFlowGraph() const { return GraphEditor; } // FGCObject virtual void AddReferencedObjects(FReferenceCollector& Collector) override; @@ -102,6 +103,8 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit virtual void InitToolMenuContext(FToolMenuContext& MenuContext) override; // -- + bool IsTabFocused(const FTabId& TabId) const; + private: TSharedRef SpawnTab_Details(const FSpawnTabArgs& Args) const; TSharedRef SpawnTab_Graph(const FSpawnTabArgs& Args) const; @@ -136,44 +139,16 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit virtual bool CanGoToParentInstance(); virtual void CreateWidgets(); + virtual void CreateGraphWidget(); - virtual TSharedRef CreateGraphWidget(); - virtual FGraphAppearanceInfo GetGraphAppearanceInfo() const; - virtual FText GetCornerText() const; - - virtual void BindGraphCommands(); - -private: - static void UndoGraphAction(); - static void RedoGraphAction(); - - static FReply OnSpawnGraphNodeByShortcut(FInputChord InChord, const FVector2D& InPosition, UEdGraph* InGraph); + static bool CanEdit(); public: - /** Gets the UI selection state of this editor */ - FName GetUISelectionState() const { return CurrentUISelection; } void SetUISelectionState(const FName SelectionOwner); - virtual void ClearSelectionStateFor(const FName SelectionOwner); + FName GetUISelectionState() const; -private: - void OnCreateComment() const; - void OnStraightenConnections() const; - -public: - static bool CanEdit(); - static bool IsPIE(); - static EVisibility GetDebuggerVisibility(); - - TSet GetSelectedFlowNodes() const; - int32 GetNumberOfSelectedNodes() const; - bool GetBoundsForSelectedNodes(class FSlateRect& Rect, float Padding) const; - -protected: - virtual void OnSelectedNodesChanged(const TSet& Nodes); - -public: - virtual void SelectSingleNode(UEdGraphNode* Node) const; + virtual void OnSelectedNodesChanged(const TSet& Nodes) {} #if ENABLE_JUMP_TO_INNER_OBJECT // FAssetEditorToolkit @@ -183,84 +158,4 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit protected: void OnLogTokenClicked(const TSharedRef& Token) const; - - virtual void SelectAllNodes() const; - virtual bool CanSelectAllNodes() const; - - virtual void DeleteSelectedNodes(); - virtual void DeleteSelectedDuplicableNodes(); - virtual bool CanDeleteNodes() const; - - virtual void CopySelectedNodes() const; - virtual bool CanCopyNodes() const; - - virtual void CutSelectedNodes(); - virtual bool CanCutNodes() const; - - virtual void PasteNodes(); - -public: - virtual void PasteNodesHere(const FVector2D& Location); - virtual bool CanPasteNodes() const; - -protected: - virtual void DuplicateNodes(); - virtual bool CanDuplicateNodes() const; - - virtual void OnNodeDoubleClicked(class UEdGraphNode* Node) const; - virtual void OnNodeTitleCommitted(const FText& NewText, ETextCommit::Type CommitInfo, UEdGraphNode* NodeBeingChanged); - - virtual void RefreshContextPins() const; - virtual bool CanRefreshContextPins() const; - -private: - void AddInput() const; - bool CanAddInput() const; - - void AddOutput() const; - bool CanAddOutput() const; - - void RemovePin() const; - bool CanRemovePin() const; - - void OnAddBreakpoint() const; - void OnAddPinBreakpoint() const; - - bool CanAddBreakpoint() const; - bool CanAddPinBreakpoint() const; - - void OnRemoveBreakpoint() const; - void OnRemovePinBreakpoint() const; - - bool CanRemoveBreakpoint() const; - bool CanRemovePinBreakpoint() const; - - void OnEnableBreakpoint() const; - void OnEnablePinBreakpoint() const; - - bool CanEnableBreakpoint() const; - bool CanEnablePinBreakpoint() const; - - void OnDisableBreakpoint() const; - void OnDisablePinBreakpoint() const; - - bool CanDisableBreakpoint() const; - bool CanDisablePinBreakpoint() const; - - void OnToggleBreakpoint() const; - void OnTogglePinBreakpoint() const; - - bool CanToggleBreakpoint() const; - bool CanTogglePinBreakpoint() const; - - void SetSignalMode(const EFlowSignalMode Mode) const; - bool CanSetSignalMode(const EFlowSignalMode Mode) const; - - void OnForcePinActivation() const; - - void FocusViewport() const; - bool CanFocusViewport() const; - - void JumpToNodeDefinition() const; - bool CanJumpToNodeDefinition() const; }; diff --git a/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h b/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h index 82dd7844a..d9bda86d9 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetToolbar.h @@ -21,9 +21,11 @@ class FLOWEDITOR_API SFlowAssetInstanceList : public SCompoundWidget void Construct(const FArguments& InArgs, const TWeakObjectPtr InTemplateAsset); virtual ~SFlowAssetInstanceList() override; + static EVisibility GetDebuggerVisibility(); + private: void RefreshInstances(); - + TSharedRef OnGenerateWidget(TSharedPtr Item) const; void OnSelectionChanged(TSharedPtr SelectedItem, ESelectInfo::Type SelectionType); FText GetSelectedInstanceName() const; diff --git a/Source/FlowEditor/Public/Graph/FlowGraphEditor.h b/Source/FlowEditor/Public/Graph/FlowGraphEditor.h new file mode 100644 index 000000000..eabbc8b82 --- /dev/null +++ b/Source/FlowEditor/Public/Graph/FlowGraphEditor.h @@ -0,0 +1,144 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#pragma once + +#include "EdGraphUtilities.h" +#include "GraphEditor.h" +#include "GraphEditorActions.h" +#include "SGraphNode.h" +#include "Widgets/DeclarativeSyntaxSupport.h" + +#include "FlowGraph.h" + +class FFlowAssetEditor; + +/** + * + */ +class FLOWEDITOR_API SFlowGraphEditor : public SGraphEditor +{ +public: + SLATE_BEGIN_ARGS(SFlowGraphEditor) + { + } + + SLATE_ARGUMENT(FGraphEditorEvents, GraphEvents) + SLATE_ARGUMENT(TSharedPtr, DetailsView) + SLATE_END_ARGS() + +protected: + TWeakObjectPtr FlowAsset; + + TWeakPtr FlowAssetEditor; + TSharedPtr DetailsView; + +public: + void Construct(const FArguments& InArgs, const TSharedPtr InAssetEditor); + + virtual void BindGraphCommands(); + + virtual FGraphAppearanceInfo GetGraphAppearanceInfo() const; + virtual FText GetCornerText() const; + +private: + static void UndoGraphAction(); + static void RedoGraphAction(); + + static FReply OnSpawnGraphNodeByShortcut(FInputChord InChord, const FVector2D& InPosition, UEdGraph* InGraph); + void OnCreateComment() const; + +public: + static bool CanEdit(); + static bool IsPIE(); + virtual bool IsTabFocused() const; + + virtual void SelectSingleNode(UEdGraphNode* Node); + +protected: + virtual void OnSelectedNodesChanged(const TSet& Nodes); + +public: + FOnSelectionChanged OnSelectionChangedEvent; + + TSet GetSelectedFlowNodes() const; + +protected: + virtual bool CanSelectAllNodes() const { return true; } + + virtual void DeleteSelectedNodes(); + virtual void DeleteSelectedDuplicableNodes(); + virtual bool CanDeleteNodes() const; + + virtual void CopySelectedNodes() const; + virtual bool CanCopyNodes() const; + + virtual void CutSelectedNodes(); + virtual bool CanCutNodes() const; + + virtual void PasteNodes(); + +public: + virtual void PasteNodesHere(const FVector2D& Location); + virtual bool CanPasteNodes() const; + +protected: + virtual void DuplicateNodes(); + virtual bool CanDuplicateNodes() const; + + virtual void OnNodeDoubleClicked(class UEdGraphNode* Node) const; + virtual void OnNodeTitleCommitted(const FText& NewText, ETextCommit::Type CommitInfo, UEdGraphNode* NodeBeingChanged); + + virtual void RefreshContextPins() const; + virtual bool CanRefreshContextPins() const; + +private: + void AddInput() const; + bool CanAddInput() const; + + void AddOutput() const; + bool CanAddOutput() const; + + void RemovePin(); + bool CanRemovePin(); + + void OnAddBreakpoint() const; + void OnAddPinBreakpoint(); + + bool CanAddBreakpoint() const; + bool CanAddPinBreakpoint(); + + void OnRemoveBreakpoint() const; + void OnRemovePinBreakpoint(); + + bool CanRemoveBreakpoint() const; + bool CanRemovePinBreakpoint(); + + void OnEnableBreakpoint() const; + void OnEnablePinBreakpoint(); + + bool CanEnableBreakpoint(); + bool CanEnablePinBreakpoint(); + + void OnDisableBreakpoint() const; + void OnDisablePinBreakpoint(); + + bool CanDisableBreakpoint() const; + bool CanDisablePinBreakpoint(); + + void OnToggleBreakpoint() const; + void OnTogglePinBreakpoint(); + + bool CanToggleBreakpoint() const; + bool CanTogglePinBreakpoint(); + + void SetSignalMode(const EFlowSignalMode Mode) const; + bool CanSetSignalMode(const EFlowSignalMode Mode) const; + + void OnForcePinActivation(); + + void FocusViewport() const; + bool CanFocusViewport() const; + + void JumpToNodeDefinition() const; + bool CanJumpToNodeDefinition() const; +}; diff --git a/Source/FlowEditor/Public/Graph/FlowGraphUtils.h b/Source/FlowEditor/Public/Graph/FlowGraphUtils.h index c9d8f7f8d..5747c7dc2 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphUtils.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphUtils.h @@ -5,11 +5,13 @@ #include "CoreMinimal.h" class FFlowAssetEditor; +class SFlowGraphEditor; class FLOWEDITOR_API FFlowGraphUtils { public: FFlowGraphUtils() {} - static TSharedPtr GetFlowAssetEditor(const UObject* ObjectToFocusOn); + static TSharedPtr GetFlowAssetEditor(const UEdGraph* Graph); + static TSharedPtr GetFlowGraphEditor(const UEdGraph* Graph); }; diff --git a/Source/FlowEditor/Public/Graph/Widgets/SFlowPalette.h b/Source/FlowEditor/Public/Graph/Widgets/SFlowPalette.h index 257bb200c..dff23d85f 100644 --- a/Source/FlowEditor/Public/Graph/Widgets/SFlowPalette.h +++ b/Source/FlowEditor/Public/Graph/Widgets/SFlowPalette.h @@ -48,7 +48,7 @@ class FLOWEDITOR_API SFlowPalette : public SGraphPalette void ClearGraphActionMenuSelection() const; protected: - TWeakPtr FlowAssetEditorPtr; + TWeakPtr FlowAssetEditor; TArray> CategoryNames; TSharedPtr CategoryComboBox; }; From b7d97069d9fefb4d8298b4d6e618d2123e48cb5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 26 Mar 2023 20:21:44 +0200 Subject: [PATCH 277/338] fixed graph commands --- .../Private/Graph/FlowGraphEditor.cpp | 244 +++++++++--------- .../FlowEditor/Public/Graph/FlowGraphEditor.h | 2 + 2 files changed, 125 insertions(+), 121 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp b/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp index b7f1a63f8..ba61997d0 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp @@ -22,12 +22,13 @@ void SFlowGraphEditor::Construct(const FArguments& InArgs, const TSharedPtrGetFlowAsset(); - + DetailsView = InArgs._DetailsView; BindGraphCommands(); SGraphEditor::FArguments Arguments; + Arguments._AdditionalCommands = CommandList; Arguments._Appearance = GetGraphAppearanceInfo(); Arguments._GraphToEdit = FlowAsset->GetGraph(); Arguments._GraphEvents = InArgs._GraphEvents; @@ -48,178 +49,179 @@ void SFlowGraphEditor::BindGraphCommands() FFlowGraphCommands::Register(); FFlowSpawnNodeCommands::Register(); - const TSharedRef& ToolkitCommands = FlowAssetEditor.Pin()->GetToolkitCommands(); const FGenericCommands& GenericCommands = FGenericCommands::Get(); - const FGraphEditorCommandsImpl& GraphCommands = FGraphEditorCommands::Get(); + const FGraphEditorCommandsImpl& GraphEditorCommands = FGraphEditorCommands::Get(); const FFlowGraphCommands& FlowGraphCommands = FFlowGraphCommands::Get(); - + + CommandList = MakeShareable(new FUICommandList); + // Graph commands - ToolkitCommands->MapAction(GraphCommands.CreateComment, - FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnCreateComment), - FCanExecuteAction::CreateStatic(&SFlowGraphEditor::CanEdit)); + CommandList->MapAction(GraphEditorCommands.CreateComment, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnCreateComment), + FCanExecuteAction::CreateStatic(&SFlowGraphEditor::CanEdit)); - ToolkitCommands->MapAction(GraphCommands.StraightenConnections, - FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnStraightenConnections)); + CommandList->MapAction(GraphEditorCommands.StraightenConnections, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnStraightenConnections)); // Generic Node commands - ToolkitCommands->MapAction(GenericCommands.Undo, - FExecuteAction::CreateStatic(&SFlowGraphEditor::UndoGraphAction), - FCanExecuteAction::CreateStatic(&SFlowGraphEditor::CanEdit)); + CommandList->MapAction(GenericCommands.Undo, + FExecuteAction::CreateStatic(&SFlowGraphEditor::UndoGraphAction), + FCanExecuteAction::CreateStatic(&SFlowGraphEditor::CanEdit)); - ToolkitCommands->MapAction(GenericCommands.Redo, - FExecuteAction::CreateStatic(&SFlowGraphEditor::RedoGraphAction), - FCanExecuteAction::CreateStatic(&SFlowGraphEditor::CanEdit)); + CommandList->MapAction(GenericCommands.Redo, + FExecuteAction::CreateStatic(&SFlowGraphEditor::RedoGraphAction), + FCanExecuteAction::CreateStatic(&SFlowGraphEditor::CanEdit)); - ToolkitCommands->MapAction(GenericCommands.SelectAll, - FExecuteAction::CreateSP(this, &SFlowGraphEditor::SelectAllNodes), - FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanSelectAllNodes)); + CommandList->MapAction(GenericCommands.SelectAll, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::SelectAllNodes), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanSelectAllNodes)); - ToolkitCommands->MapAction(GenericCommands.Delete, - FExecuteAction::CreateSP(this, &SFlowGraphEditor::DeleteSelectedNodes), - FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanDeleteNodes)); + CommandList->MapAction(GenericCommands.Delete, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::DeleteSelectedNodes), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanDeleteNodes)); - ToolkitCommands->MapAction(GenericCommands.Copy, - FExecuteAction::CreateSP(this, &SFlowGraphEditor::CopySelectedNodes), - FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanCopyNodes)); + CommandList->MapAction(GenericCommands.Copy, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::CopySelectedNodes), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanCopyNodes)); - ToolkitCommands->MapAction(GenericCommands.Cut, - FExecuteAction::CreateSP(this, &SFlowGraphEditor::CutSelectedNodes), - FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanCutNodes)); + CommandList->MapAction(GenericCommands.Cut, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::CutSelectedNodes), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanCutNodes)); - ToolkitCommands->MapAction(GenericCommands.Paste, - FExecuteAction::CreateSP(this, &SFlowGraphEditor::PasteNodes), - FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanPasteNodes)); + CommandList->MapAction(GenericCommands.Paste, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::PasteNodes), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanPasteNodes)); - ToolkitCommands->MapAction(GenericCommands.Duplicate, - FExecuteAction::CreateSP(this, &SFlowGraphEditor::DuplicateNodes), - FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanDuplicateNodes)); + CommandList->MapAction(GenericCommands.Duplicate, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::DuplicateNodes), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanDuplicateNodes)); // Pin commands - ToolkitCommands->MapAction(FlowGraphCommands.RefreshContextPins, - FExecuteAction::CreateSP(this, &SFlowGraphEditor::RefreshContextPins), - FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanRefreshContextPins)); + CommandList->MapAction(FlowGraphCommands.RefreshContextPins, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::RefreshContextPins), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanRefreshContextPins)); - ToolkitCommands->MapAction(FlowGraphCommands.AddInput, - FExecuteAction::CreateSP(this, &SFlowGraphEditor::AddInput), - FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanAddInput)); + CommandList->MapAction(FlowGraphCommands.AddInput, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::AddInput), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanAddInput)); - ToolkitCommands->MapAction(FlowGraphCommands.AddOutput, - FExecuteAction::CreateSP(this, &SFlowGraphEditor::AddOutput), - FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanAddOutput)); + CommandList->MapAction(FlowGraphCommands.AddOutput, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::AddOutput), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanAddOutput)); - ToolkitCommands->MapAction(FlowGraphCommands.RemovePin, - FExecuteAction::CreateSP(this, &SFlowGraphEditor::RemovePin), - FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanRemovePin)); + CommandList->MapAction(FlowGraphCommands.RemovePin, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::RemovePin), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanRemovePin)); // Breakpoint commands - ToolkitCommands->MapAction(GraphCommands.AddBreakpoint, - FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnAddBreakpoint), - FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanAddBreakpoint), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanAddBreakpoint) + CommandList->MapAction(GraphEditorCommands.AddBreakpoint, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnAddBreakpoint), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanAddBreakpoint), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanAddBreakpoint) ); - ToolkitCommands->MapAction(GraphCommands.RemoveBreakpoint, - FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnRemoveBreakpoint), - FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanRemoveBreakpoint), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanRemoveBreakpoint) + CommandList->MapAction(GraphEditorCommands.RemoveBreakpoint, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnRemoveBreakpoint), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanRemoveBreakpoint), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanRemoveBreakpoint) ); - ToolkitCommands->MapAction(GraphCommands.EnableBreakpoint, - FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnEnableBreakpoint), - FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanEnableBreakpoint), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanEnableBreakpoint) + CommandList->MapAction(GraphEditorCommands.EnableBreakpoint, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnEnableBreakpoint), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanEnableBreakpoint), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanEnableBreakpoint) ); - ToolkitCommands->MapAction(GraphCommands.DisableBreakpoint, - FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnDisableBreakpoint), - FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanDisableBreakpoint), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanDisableBreakpoint) + CommandList->MapAction(GraphEditorCommands.DisableBreakpoint, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnDisableBreakpoint), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanDisableBreakpoint), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanDisableBreakpoint) ); - ToolkitCommands->MapAction(GraphCommands.ToggleBreakpoint, - FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnToggleBreakpoint), - FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanToggleBreakpoint), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanToggleBreakpoint) + CommandList->MapAction(GraphEditorCommands.ToggleBreakpoint, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnToggleBreakpoint), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanToggleBreakpoint), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanToggleBreakpoint) ); // Pin Breakpoint commands - ToolkitCommands->MapAction(FlowGraphCommands.AddPinBreakpoint, - FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnAddPinBreakpoint), - FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanAddPinBreakpoint), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanAddPinBreakpoint) + CommandList->MapAction(FlowGraphCommands.AddPinBreakpoint, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnAddPinBreakpoint), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanAddPinBreakpoint), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanAddPinBreakpoint) ); - ToolkitCommands->MapAction(FlowGraphCommands.RemovePinBreakpoint, - FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnRemovePinBreakpoint), - FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanRemovePinBreakpoint), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanRemovePinBreakpoint) + CommandList->MapAction(FlowGraphCommands.RemovePinBreakpoint, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnRemovePinBreakpoint), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanRemovePinBreakpoint), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanRemovePinBreakpoint) ); - ToolkitCommands->MapAction(FlowGraphCommands.EnablePinBreakpoint, - FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnEnablePinBreakpoint), - FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanEnablePinBreakpoint), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanEnablePinBreakpoint) + CommandList->MapAction(FlowGraphCommands.EnablePinBreakpoint, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnEnablePinBreakpoint), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanEnablePinBreakpoint), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanEnablePinBreakpoint) ); - ToolkitCommands->MapAction(FlowGraphCommands.DisablePinBreakpoint, - FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnDisablePinBreakpoint), - FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanDisablePinBreakpoint), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanDisablePinBreakpoint) + CommandList->MapAction(FlowGraphCommands.DisablePinBreakpoint, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnDisablePinBreakpoint), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanDisablePinBreakpoint), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanDisablePinBreakpoint) ); - ToolkitCommands->MapAction(FlowGraphCommands.TogglePinBreakpoint, - FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnTogglePinBreakpoint), - FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanTogglePinBreakpoint), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanTogglePinBreakpoint) + CommandList->MapAction(FlowGraphCommands.TogglePinBreakpoint, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnTogglePinBreakpoint), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanTogglePinBreakpoint), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanTogglePinBreakpoint) ); // Execution Override commands - ToolkitCommands->MapAction(FlowGraphCommands.EnableNode, - FExecuteAction::CreateSP(this, &SFlowGraphEditor::SetSignalMode, EFlowSignalMode::Enabled), - FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanSetSignalMode, EFlowSignalMode::Enabled), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanSetSignalMode, EFlowSignalMode::Enabled) + CommandList->MapAction(FlowGraphCommands.EnableNode, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::SetSignalMode, EFlowSignalMode::Enabled), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanSetSignalMode, EFlowSignalMode::Enabled), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanSetSignalMode, EFlowSignalMode::Enabled) ); - ToolkitCommands->MapAction(FlowGraphCommands.DisableNode, - FExecuteAction::CreateSP(this, &SFlowGraphEditor::SetSignalMode, EFlowSignalMode::Disabled), - FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanSetSignalMode, EFlowSignalMode::Disabled), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanSetSignalMode, EFlowSignalMode::Disabled) + CommandList->MapAction(FlowGraphCommands.DisableNode, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::SetSignalMode, EFlowSignalMode::Disabled), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanSetSignalMode, EFlowSignalMode::Disabled), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanSetSignalMode, EFlowSignalMode::Disabled) ); - ToolkitCommands->MapAction(FlowGraphCommands.SetPassThrough, - FExecuteAction::CreateSP(this, &SFlowGraphEditor::SetSignalMode, EFlowSignalMode::PassThrough), - FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanSetSignalMode, EFlowSignalMode::PassThrough), - FIsActionChecked(), - FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanSetSignalMode, EFlowSignalMode::PassThrough) + CommandList->MapAction(FlowGraphCommands.SetPassThrough, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::SetSignalMode, EFlowSignalMode::PassThrough), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanSetSignalMode, EFlowSignalMode::PassThrough), + FIsActionChecked(), + FIsActionButtonVisible::CreateSP(this, &SFlowGraphEditor::CanSetSignalMode, EFlowSignalMode::PassThrough) ); - ToolkitCommands->MapAction(FlowGraphCommands.ForcePinActivation, - FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnForcePinActivation), - FCanExecuteAction::CreateStatic(&SFlowGraphEditor::IsPIE), - FIsActionChecked(), - FIsActionButtonVisible::CreateStatic(&SFlowGraphEditor::IsPIE) + CommandList->MapAction(FlowGraphCommands.ForcePinActivation, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnForcePinActivation), + FCanExecuteAction::CreateStatic(&SFlowGraphEditor::IsPIE), + FIsActionChecked(), + FIsActionButtonVisible::CreateStatic(&SFlowGraphEditor::IsPIE) ); // Jump commands - ToolkitCommands->MapAction(FlowGraphCommands.FocusViewport, - FExecuteAction::CreateSP(this, &SFlowGraphEditor::FocusViewport), - FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanFocusViewport)); + CommandList->MapAction(FlowGraphCommands.FocusViewport, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::FocusViewport), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanFocusViewport)); - ToolkitCommands->MapAction(FlowGraphCommands.JumpToNodeDefinition, - FExecuteAction::CreateSP(this, &SFlowGraphEditor::JumpToNodeDefinition), - FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanJumpToNodeDefinition)); + CommandList->MapAction(FlowGraphCommands.JumpToNodeDefinition, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::JumpToNodeDefinition), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanJumpToNodeDefinition)); } FGraphAppearanceInfo SFlowGraphEditor::GetGraphAppearanceInfo() const diff --git a/Source/FlowEditor/Public/Graph/FlowGraphEditor.h b/Source/FlowEditor/Public/Graph/FlowGraphEditor.h index eabbc8b82..5debee64c 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphEditor.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphEditor.h @@ -32,6 +32,8 @@ class FLOWEDITOR_API SFlowGraphEditor : public SGraphEditor TWeakPtr FlowAssetEditor; TSharedPtr DetailsView; + TSharedPtr CommandList; + public: void Construct(const FArguments& InArgs, const TSharedPtr InAssetEditor); From cc397e7725c88408682f05f278cd538e1e01c239 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 26 Mar 2023 20:43:19 +0200 Subject: [PATCH 278/338] #131 fixed updating pin names below removed pin --- Source/Flow/Private/Nodes/FlowNode.cpp | 28 ++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 2b06be73a..e6a48bb3a 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -235,28 +235,56 @@ void UFlowNode::RemoveUserInput(const FName& PinName) { Modify(); + int32 RemovedPinIndex = INDEX_NONE; for (int32 i = 0; i < InputPins.Num(); i++) { if (InputPins[i].PinName == PinName) { InputPins.RemoveAt(i); + RemovedPinIndex = i; break; } } + + // update remaining pins + if (RemovedPinIndex > INDEX_NONE) + { + for (int32 i = RemovedPinIndex; i < InputPins.Num(); ++i) + { + if (InputPins[i].PinName.ToString().IsNumeric()) + { + InputPins[i].PinName = *FString::FromInt(i); + } + } + } } void UFlowNode::RemoveUserOutput(const FName& PinName) { Modify(); + int32 RemovedPinIndex = INDEX_NONE; for (int32 i = 0; i < OutputPins.Num(); i++) { if (OutputPins[i].PinName == PinName) { OutputPins.RemoveAt(i); + RemovedPinIndex = i; break; } } + + // update remaining pins + if (RemovedPinIndex > INDEX_NONE) + { + for (int32 i = RemovedPinIndex; i < OutputPins.Num(); ++i) + { + if (OutputPins[i].PinName.ToString().IsNumeric()) + { + OutputPins[i].PinName = *FString::FromInt(i); + } + } + } } #endif From 2e909fca9b2929b2377c0e4cafacb12eb5eba5a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Mon, 27 Mar 2023 00:33:39 +0200 Subject: [PATCH 279/338] quick CIS compilation fix --- Source/Flow/Public/FlowAsset.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 8c4af61a9..1a6acb976 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -5,11 +5,10 @@ #include "FlowMessageLog.h" #include "FlowSave.h" #include "FlowTypes.h" -#include "Nodes/FlowNode.h" +#include "Nodes/Route/FlowNode_Start.h" #include "FlowAsset.generated.h" class UFlowNode_CustomInput; -class UFlowNode_Start; class UFlowNode_SubGraph; class UFlowSubsystem; From 6f5bb003d49c7575b5fe4be0e0a0829aa6e3f63b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Mon, 27 Mar 2023 00:42:58 +0200 Subject: [PATCH 280/338] another CIS fix attempt --- Source/Flow/Public/FlowAsset.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 1a6acb976..27aa62fe1 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -5,10 +5,13 @@ #include "FlowMessageLog.h" #include "FlowSave.h" #include "FlowTypes.h" -#include "Nodes/Route/FlowNode_Start.h" +#include "Nodes/FlowNode.h" + +#include "UObject/ObjectKey.h" #include "FlowAsset.generated.h" class UFlowNode_CustomInput; +class UFlowNode_Start; class UFlowNode_SubGraph; class UFlowSubsystem; From 74ae8fe03d25f122d41f66557662ecc42dbf5a4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Thu, 30 Mar 2023 14:02:55 +0200 Subject: [PATCH 281/338] redundant include removed --- Source/FlowEditor/Public/Asset/FlowAssetEditor.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h index 0591c9cfd..44645c432 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h @@ -9,7 +9,6 @@ #include "UObject/GCObject.h" #include "FlowEditorDefines.h" -#include "FlowTypes.h" class FFlowMessageLog; class SFlowGraphEditor; From 2829593cecd02f99324f45d080d51182543e1e9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Thu, 30 Mar 2023 14:03:49 +0200 Subject: [PATCH 282/338] fixed showing static descriptions in PIE/SIE renamed flag to better reflect its role --- .../FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp | 2 +- Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp | 7 ++++++- Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp | 2 +- Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h | 2 +- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp b/Source/FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp index ed81e3d11..c555e64ab 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp @@ -8,7 +8,7 @@ UFlowGraphEditorSettings::UFlowGraphEditorSettings(const FObjectInitializer& Obj : Super(ObjectInitializer) , NodeDoubleClickTarget(EFlowNodeDoubleClickTarget::PrimaryAsset) , bShowNodeClass(false) - , bShowNodeDescriptionInPIE(true) + , bShowNodeDescriptionWhilePlaying(true) , bShowSubGraphPreview(true) , bShowSubGraphPath(true) , SubGraphPreviewSize(FVector2D(640.f, 360.f)) diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 1fc3797c8..83f26e9d9 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -653,7 +653,12 @@ FText UFlowGraphNode::GetTooltipText() const FString UFlowGraphNode::GetNodeDescription() const { - return FlowNode ? FlowNode->GetNodeDescription() : FString(); + if (FlowNode && (GEditor->PlayWorld == nullptr || UFlowGraphEditorSettings::Get()->bShowNodeDescriptionWhilePlaying)) + { + return FlowNode->GetNodeDescription(); + } + + return FString(); } UFlowNode* UFlowGraphNode::GetInspectedNodeInstance() const diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp index 3c440612d..a72eecf0f 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp @@ -55,7 +55,7 @@ void SFlowGraphNode::Construct(const FArguments& InArgs, UFlowGraphNode* InNode) void SFlowGraphNode::GetNodeInfoPopups(FNodeInfoContext* Context, TArray& Popups) const { - const FString Description = GEditor->PlayWorld && UFlowGraphEditorSettings::Get()->bShowNodeDescriptionInPIE ? FString() : FlowGraphNode->GetNodeDescription(); + const FString& Description = FlowGraphNode->GetNodeDescription(); if (!Description.IsEmpty()) { const FGraphInformationPopupInfo DescriptionPopup = FGraphInformationPopupInfo(nullptr, UFlowGraphSettings::Get()->NodeDescriptionBackground, Description); diff --git a/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h b/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h index 8f2a14961..8a8d10b73 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h @@ -32,7 +32,7 @@ class FLOWEDITOR_API UFlowGraphEditorSettings : public UDeveloperSettings // Hides the node description when you play in editor and only shows node status string. UPROPERTY(config, EditAnywhere, Category = "Nodes") - bool bShowNodeDescriptionInPIE; + bool bShowNodeDescriptionWhilePlaying; // Renders preview of entire graph while hovering over UPROPERTY(config, EditAnywhere, Category = "Nodes") From de305684c07b12873bd2e16448447f6a5ee2086d Mon Sep 17 00:00:00 2001 From: Bohdon Sayre Date: Fri, 31 Mar 2023 11:22:44 -0400 Subject: [PATCH 283/338] add null flow asset check when calling StartRootFlow (#132) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Krzysiek Justyński --- Source/Flow/Private/FlowSubsystem.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index 205f87f0f..db5b5562a 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -19,6 +19,8 @@ FNativeFlowAssetEvent UFlowSubsystem::OnInstancedTemplateAdded; FNativeFlowAssetEvent UFlowSubsystem::OnInstancedTemplateRemoved; #endif +#define LOCTEXT_NAMESPACE "FlowSubsystem" + UFlowSubsystem::UFlowSubsystem() : UGameInstanceSubsystem() { @@ -73,6 +75,12 @@ void UFlowSubsystem::AbortActiveFlows() void UFlowSubsystem::StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances /* = true */) { + if (!FlowAsset) + { + FMessageLog("PIE").Error(LOCTEXT("StartRootFlowNullAsset", "Attempted to start Root Flow with null asset.")) + ->AddToken(FUObjectToken::Create(Owner)); + return; + } UFlowAsset* NewFlow = CreateRootFlow(Owner, FlowAsset, bAllowMultipleInstances); if (NewFlow) { @@ -644,3 +652,5 @@ void UFlowSubsystem::FindComponents(const FGameplayTagContainer& Tags, const EGa } } } + +#undef LOCTEXT_NAMESPACE From 3befefd49543001e9c87c96bea3ec4eff0048a02 Mon Sep 17 00:00:00 2001 From: "Satheesh (ryanjon2040)" Date: Fri, 31 Mar 2023 21:04:36 +0530 Subject: [PATCH 284/338] Add custom color support to nodes (#135) --- Source/Flow/Private/Nodes/FlowNode.cpp | 12 ++++++++++++ Source/Flow/Public/FlowTypes.h | 3 ++- Source/Flow/Public/Nodes/FlowNode.h | 6 +++++- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index e6a48bb3a..c5f48260e 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -39,6 +39,7 @@ UFlowNode::UFlowNode(const FObjectInitializer& ObjectInitializer) #if WITH_EDITOR Category = TEXT("Uncategorized"); NodeStyle = EFlowNodeStyle::Default; + NodeColor = FLinearColor::Black; #endif InputPins = {DefaultInputPin}; @@ -121,6 +122,17 @@ FText UFlowNode::GetNodeToolTip() const return GetClass()->GetToolTipText(); } +bool UFlowNode::GetDynamicTitleColor(FLinearColor& OutColor) const +{ + if (NodeStyle == EFlowNodeStyle::Custom) + { + OutColor = NodeColor; + return true; + } + + return false; +} + FString UFlowNode::GetNodeDescription() const { return K2_GetNodeDescription(); diff --git a/Source/Flow/Public/FlowTypes.h b/Source/Flow/Public/FlowTypes.h index a1be09b7b..2a0f3793b 100644 --- a/Source/Flow/Public/FlowTypes.h +++ b/Source/Flow/Public/FlowTypes.h @@ -14,7 +14,8 @@ enum class EFlowNodeStyle : uint8 InOut UMETA(Hidden), Latent, Logic, - SubGraph UMETA(Hidden) + SubGraph UMETA(Hidden), + Custom }; #endif diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index e7543d435..845529b9b 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -53,6 +53,10 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UPROPERTY(EditDefaultsOnly, Category = "FlowNode") EFlowNodeStyle NodeStyle; + // Set Node Style to custom to use your own color for this node + UPROPERTY(EditDefaultsOnly, Category = "FlowNode", meta = (EditCondition = "NodeStyle == EFlowNodeStyle::Custom")) + FLinearColor NodeColor; + uint8 bCanDelete : 1; uint8 bCanDuplicate : 1; @@ -93,7 +97,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte virtual FText GetNodeToolTip() const; // This method allows to have different for every node instance, i.e. Red if node represents enemy, Green if node represents a friend - virtual bool GetDynamicTitleColor(FLinearColor& OutColor) const { return false; } + virtual bool GetDynamicTitleColor(FLinearColor& OutColor) const; EFlowNodeStyle GetNodeStyle() const { return NodeStyle; } From d552c2390f236a6f0cd01b217ef88b09113c5937 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 31 Mar 2023 17:35:08 +0200 Subject: [PATCH 285/338] readability tweak --- Source/Flow/Private/FlowSubsystem.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index db5b5562a..34bbfd491 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -75,16 +75,17 @@ void UFlowSubsystem::AbortActiveFlows() void UFlowSubsystem::StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances /* = true */) { - if (!FlowAsset) + if (FlowAsset) { - FMessageLog("PIE").Error(LOCTEXT("StartRootFlowNullAsset", "Attempted to start Root Flow with null asset.")) - ->AddToken(FUObjectToken::Create(Owner)); - return; + if (UFlowAsset* NewFlow = CreateRootFlow(Owner, FlowAsset, bAllowMultipleInstances)) + { + NewFlow->StartFlow(); + } } - UFlowAsset* NewFlow = CreateRootFlow(Owner, FlowAsset, bAllowMultipleInstances); - if (NewFlow) + else { - NewFlow->StartFlow(); + FMessageLog("PIE").Error(LOCTEXT("StartRootFlowNullAsset", "Attempted to start Root Flow with a null asset.")) + ->AddToken(FUObjectToken::Create(Owner)); } } From 594602ebda7b33e2fe9bc66939655fb0a72420c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 31 Mar 2023 17:59:54 +0200 Subject: [PATCH 286/338] non-editor compilation fix --- Source/Flow/Private/FlowSubsystem.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index 34bbfd491..847c342d4 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -82,11 +82,13 @@ void UFlowSubsystem::StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const NewFlow->StartFlow(); } } +#if WITH_EDITOR else { FMessageLog("PIE").Error(LOCTEXT("StartRootFlowNullAsset", "Attempted to start Root Flow with a null asset.")) ->AddToken(FUObjectToken::Create(Owner)); } +#endif } UFlowAsset* UFlowSubsystem::CreateRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances) From 21b1cba68f62d426aab0a2be35b2dea3f04d8627 Mon Sep 17 00:00:00 2001 From: LindyHopperGT <91915878+LindyHopperGT@users.noreply.github.com> Date: Wed, 26 Apr 2023 09:12:30 -0700 Subject: [PATCH 287/338] Added includes to fix compiler errors (#152) When compiling for UE 5.1 (Win64) we ran into some compile errors due to missing header includes. --- Source/Flow/Private/FlowSubsystem.cpp | 1 + Source/Flow/Private/Nodes/FlowNode.cpp | 3 +++ Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp | 1 + Source/FlowEditor/Private/Asset/FlowImportUtils.cpp | 1 + Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp | 1 + Source/FlowEditor/Public/Asset/FlowDebuggerSubsystem.h | 1 + Source/FlowEditor/Public/Asset/FlowImportUtils.h | 1 + 7 files changed, 9 insertions(+) diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index 847c342d4..ff45776bf 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -11,6 +11,7 @@ #include "Engine/GameInstance.h" #include "Engine/World.h" +#include "Logging/MessageLog.h" #include "Misc/Paths.h" #include "UObject/UObjectHash.h" diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index c5f48260e..13eb977a1 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -7,6 +7,9 @@ #include "FlowSubsystem.h" #include "FlowTypes.h" +#if WITH_EDITOR +#include "Editor.h" +#endif #include "Engine/Engine.h" #include "Engine/ViewportStatsSubsystem.h" #include "Engine/World.h" diff --git a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp index 712b24543..e3ac8f350 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp @@ -13,6 +13,7 @@ #include "EditorStyleSet.h" #include "Kismet2/DebuggerCommands.h" #include "Misc/Attribute.h" +#include "Misc/MessageDialog.h" #include "Subsystems/AssetEditorSubsystem.h" #include "ToolMenu.h" #include "ToolMenuSection.h" diff --git a/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp b/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp index 698def15c..f1c007ec7 100644 --- a/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp +++ b/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp @@ -13,6 +13,7 @@ #include "AssetRegistry/AssetRegistryModule.h" #include "AssetToolsModule.h" +#include "EdGraphSchema_K2.h" #include "EditorAssetLibrary.h" #include "Misc/ScopedSlowTask.h" diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 83f26e9d9..9f79b50b7 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -20,6 +20,7 @@ #include "Editor/EditorEngine.h" #include "Framework/Commands/GenericCommands.h" #include "GraphEditorActions.h" +#include "HAL/FileManager.h" #include "Kismet2/KismetEditorUtilities.h" #include "ScopedTransaction.h" #include "SourceCodeNavigation.h" diff --git a/Source/FlowEditor/Public/Asset/FlowDebuggerSubsystem.h b/Source/FlowEditor/Public/Asset/FlowDebuggerSubsystem.h index da10e3032..dae10ebae 100644 --- a/Source/FlowEditor/Public/Asset/FlowDebuggerSubsystem.h +++ b/Source/FlowEditor/Public/Asset/FlowDebuggerSubsystem.h @@ -3,6 +3,7 @@ #pragma once #include "EditorSubsystem.h" +#include "Logging/TokenizedMessage.h" #include "FlowDebuggerSubsystem.generated.h" class UFlowAsset; diff --git a/Source/FlowEditor/Public/Asset/FlowImportUtils.h b/Source/FlowEditor/Public/Asset/FlowImportUtils.h index 63e4c08e1..de38c1888 100644 --- a/Source/FlowEditor/Public/Asset/FlowImportUtils.h +++ b/Source/FlowEditor/Public/Asset/FlowImportUtils.h @@ -3,6 +3,7 @@ #pragma once #include "FlowAsset.h" +#include "Kismet/BlueprintFunctionLibrary.h" #include "Nodes/FlowPin.h" #include "FlowImportUtils.generated.h" From 86a8a5a281937d680af748dbd78dfbe6e738ff73 Mon Sep 17 00:00:00 2001 From: LindyHopperGT <91915878+LindyHopperGT@users.noreply.github.com> Date: Sun, 30 Apr 2023 05:10:19 -0700 Subject: [PATCH 288/338] Fixed bug where Owner parameter wasn't being used (#153) * Added includes to fix compiler errors When compiling for UE 5.1 (Win64) we ran into some compile errors due to missing header includes. * Fixed bug where Owner parameter wasn't being used Owner was passed into this function, presumably to be used instead of 'this', but it was just using 'this'. Changed the code to use Owner if specified, and default to 'this' otherwise. --- Source/Flow/Private/FlowComponent.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Source/Flow/Private/FlowComponent.cpp b/Source/Flow/Private/FlowComponent.cpp index 8635991ab..6575e49f6 100644 --- a/Source/Flow/Private/FlowComponent.cpp +++ b/Source/Flow/Private/FlowComponent.cpp @@ -385,9 +385,11 @@ void UFlowComponent::FinishRootFlow(UFlowAsset* TemplateAsset, const EFlowFinish TSet UFlowComponent::GetRootInstances(const UObject* Owner) const { + const UObject* OwnerToCheck = IsValid(Owner) ? Owner : this; + if (const UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) { - return FlowSubsystem->GetRootInstancesByOwner(this); + return FlowSubsystem->GetRootInstancesByOwner(OwnerToCheck); } return TSet(); From d13690ae858a082dd47d6da390409b34e1d3df34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 30 Apr 2023 14:19:26 +0200 Subject: [PATCH 289/338] comforting convention of separating engine headers from plugin headers --- Source/FlowEditor/Public/Asset/FlowImportUtils.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/FlowEditor/Public/Asset/FlowImportUtils.h b/Source/FlowEditor/Public/Asset/FlowImportUtils.h index de38c1888..183361ff1 100644 --- a/Source/FlowEditor/Public/Asset/FlowImportUtils.h +++ b/Source/FlowEditor/Public/Asset/FlowImportUtils.h @@ -2,8 +2,9 @@ #pragma once -#include "FlowAsset.h" #include "Kismet/BlueprintFunctionLibrary.h" + +#include "FlowAsset.h" #include "Nodes/FlowPin.h" #include "FlowImportUtils.generated.h" From c279633df19cc861f441bae5f5dbff3b4eb53e1f Mon Sep 17 00:00:00 2001 From: Alex van Mansom <45290811+Vi-So@users.noreply.github.com> Date: Sun, 30 Apr 2023 14:26:41 +0200 Subject: [PATCH 290/338] Extending the "GetAssignedGraphNodeClass()" function to support to return the correc "EdGraphNode" for grand child classes of "UFlowNode" (#151) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously it would return the first found "IsChildOf" and return the EdGraphNode of the foundclass. But lets say we got this situation just for example: UFlowNode->UMyBaseNode UFlowNode->UMyBaseNode->UMyQuestNode Both "UMyBaseNode" and "UMyQuestNode" could be in the list if we want different EdGraphNodes for both of them. If the "UMyQuestNode" goes into the itteration and it would find "UMyBaseNode" first it will be returned without checking the rest, because "UMyQuestNode" is dirived from "UMyBaseNode" (IsChildOf == true) and thus it returns the EdGraphNode of the base node directly. So that would mean I got the wrong EdGraphNode for my special quest node. This modification continues to try and find parent classes and returns the closest parent version. So lets say we have this situation: UFlowNode->UMyBaseNode UFlowNode->UMyBaseNode->UMyQuestNode->MyOtherQuestNode(BP class) Both “UMyBaseNode” and “UMyQuestNode” would be found, but the closest parent to “MyOtherQuestNode” would be returned, in this case the EdGraphNode of “UMyQuestNode” It only does this if we have found 2 or more parents though. If only 1 is found we would return that one, and if the exact class match is found lets say: "UMyQuestNode" finds "UMyQuestNode" it will return the EdGraphNode right away aswell. Hopefully this makes sence :P Otherwise feel free to ask. --- .../Private/Graph/FlowGraphSchema.cpp | 43 ++++++++++++++++++- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp index 83ff22706..5d0b2ca64 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -238,15 +238,54 @@ TArray> UFlowGraphSchema::GetFlowNodeCategories() UClass* UFlowGraphSchema::GetAssignedGraphNodeClass(const UClass* FlowNodeClass) { + TArray FoundParentClasses; + UClass* ReturnClass = nullptr; + + // Collect all possible parents and their corresponding GraphNodeClasses for (const TPair& GraphNodeByFlowNode : GraphNodesByFlowNodes) { - if (FlowNodeClass->IsChildOf(GraphNodeByFlowNode.Key)) + if (FlowNodeClass == GraphNodeByFlowNode.Key) { return GraphNodeByFlowNode.Value; } + + if (FlowNodeClass->IsChildOf(GraphNodeByFlowNode.Key)) + { + FoundParentClasses.Add(GraphNodeByFlowNode.Key); + } + } + + // Of only one parent found set the return to its GraphNodeClass + if (FoundParentClasses.Num() == 1) + { + ReturnClass = GraphNodesByFlowNodes.FindRef(FoundParentClasses[0]); } + + // If multiple parents found, find the closest one and set the return to its GraphNodeClass + else if (!FoundParentClasses.IsEmpty()) + { + TPair ClosestParentMatch = {1000, nullptr}; + for (const auto& ParentClass : FoundParentClasses) + { + int32 StepsTillExactMatch = 0; + const UClass* LocalParentClass = FlowNodeClass; + + while (IsValid(LocalParentClass) && LocalParentClass != ParentClass && LocalParentClass != UFlowNode::StaticClass()) + { + StepsTillExactMatch++; + LocalParentClass = LocalParentClass->GetSuperClass(); + } + + if (StepsTillExactMatch != 0 && StepsTillExactMatch < ClosestParentMatch.Key) + { + ClosestParentMatch = {StepsTillExactMatch, ParentClass}; + } + } - return UFlowGraphNode::StaticClass(); + ReturnClass = GraphNodesByFlowNodes.FindRef(ClosestParentMatch.Value); + } + + return IsValid(ReturnClass) ? ReturnClass : UFlowGraphNode::StaticClass(); } void UFlowGraphSchema::ApplyNodeFilter(const UFlowAsset* AssetClassDefaults, const UClass* FlowNodeClass, TArray& FilteredNodes) From 34b857ee0c10390d1c8e1b7bac5b1a28edbc425a Mon Sep 17 00:00:00 2001 From: Alex van Mansom <45290811+Vi-So@users.noreply.github.com> Date: Sun, 30 Apr 2023 14:26:41 +0200 Subject: [PATCH 291/338] Extending the "GetAssignedGraphNodeClass()" function to support to return the correc "EdGraphNode" for grand child classes of "UFlowNode" (#151) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously it would return the first found "IsChildOf" and return the EdGraphNode of the foundclass. But lets say we got this situation just for example: UFlowNode->UMyBaseNode UFlowNode->UMyBaseNode->UMyQuestNode Both "UMyBaseNode" and "UMyQuestNode" could be in the list if we want different EdGraphNodes for both of them. If the "UMyQuestNode" goes into the itteration and it would find "UMyBaseNode" first it will be returned without checking the rest, because "UMyQuestNode" is dirived from "UMyBaseNode" (IsChildOf == true) and thus it returns the EdGraphNode of the base node directly. So that would mean I got the wrong EdGraphNode for my special quest node. This modification continues to try and find parent classes and returns the closest parent version. So lets say we have this situation: UFlowNode->UMyBaseNode UFlowNode->UMyBaseNode->UMyQuestNode->MyOtherQuestNode(BP class) Both “UMyBaseNode” and “UMyQuestNode” would be found, but the closest parent to “MyOtherQuestNode” would be returned, in this case the EdGraphNode of “UMyQuestNode” It only does this if we have found 2 or more parents though. If only 1 is found we would return that one, and if the exact class match is found lets say: "UMyQuestNode" finds "UMyQuestNode" it will return the EdGraphNode right away aswell. Hopefully this makes sence :P Otherwise feel free to ask. From c72c476388339a530ee7370080a28f5c2981152a Mon Sep 17 00:00:00 2001 From: "Satheesh (ryanjon2040)" Date: Sun, 30 Apr 2023 18:33:00 +0530 Subject: [PATCH 292/338] Show pretty readable pin name even if friendly name is not provided (#140) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Show pretty readable pin name even if friendly name is not provided * Add missing else. Silly mistake 😋 --- .../Private/Graph/Nodes/FlowGraphNode.cpp | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 9f79b50b7..28f63727d 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -26,6 +26,7 @@ #include "SourceCodeNavigation.h" #include "Textures/SlateIcon.h" #include "ToolMenuSection.h" +#include "Settings/EditorStyleSettings.h" #define LOCTEXT_NAMESPACE "FlowGraphNode" @@ -775,7 +776,15 @@ void UFlowGraphNode::CreateInputPin(const FFlowPin& FlowPin, const int32 Index / UEdGraphPin* NewPin = CreatePin(EGPD_Input, PinType, FlowPin.PinName, Index); check(NewPin); - if (!FlowPin.PinFriendlyName.IsEmpty()) + if (FlowPin.PinFriendlyName.IsEmpty()) + { + if (GetDefault()->bShowFriendlyNames) + { + NewPin->bAllowFriendlyName = true; + NewPin->PinFriendlyName = FText::FromString(FName::NameToDisplayString(FlowPin.PinName.ToString(), false)); + } + } + else { NewPin->bAllowFriendlyName = true; NewPin->PinFriendlyName = FlowPin.PinFriendlyName; @@ -797,7 +806,15 @@ void UFlowGraphNode::CreateOutputPin(const FFlowPin& FlowPin, const int32 Index UEdGraphPin* NewPin = CreatePin(EGPD_Output, PinType, FlowPin.PinName, Index); check(NewPin); - if (!FlowPin.PinFriendlyName.IsEmpty()) + if (FlowPin.PinFriendlyName.IsEmpty()) + { + if (GetDefault()->bShowFriendlyNames) + { + NewPin->bAllowFriendlyName = true; + NewPin->PinFriendlyName = FText::FromString(FName::NameToDisplayString(FlowPin.PinName.ToString(), false)); + } + } + else { NewPin->bAllowFriendlyName = true; NewPin->PinFriendlyName = FlowPin.PinFriendlyName; From 6d29e57b8668051af79990079f6989f00268e2ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 30 Apr 2023 15:04:47 +0200 Subject: [PATCH 293/338] cosmetic tweaks of last PR --- Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp index 5d0b2ca64..ca8565ed2 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -2,7 +2,6 @@ #include "Graph/FlowGraphSchema.h" -#include "Asset/FlowAssetEditor.h" #include "Graph/FlowGraph.h" #include "Graph/FlowGraphEditor.h" #include "Graph/FlowGraphSchema_Actions.h" @@ -248,7 +247,7 @@ UClass* UFlowGraphSchema::GetAssignedGraphNodeClass(const UClass* FlowNodeClass) { return GraphNodeByFlowNode.Value; } - + if (FlowNodeClass->IsChildOf(GraphNodeByFlowNode.Key)) { FoundParentClasses.Add(GraphNodeByFlowNode.Key); @@ -260,22 +259,21 @@ UClass* UFlowGraphSchema::GetAssignedGraphNodeClass(const UClass* FlowNodeClass) { ReturnClass = GraphNodesByFlowNodes.FindRef(FoundParentClasses[0]); } - // If multiple parents found, find the closest one and set the return to its GraphNodeClass - else if (!FoundParentClasses.IsEmpty()) + else if (FoundParentClasses.Num() > 1) { TPair ClosestParentMatch = {1000, nullptr}; for (const auto& ParentClass : FoundParentClasses) { int32 StepsTillExactMatch = 0; const UClass* LocalParentClass = FlowNodeClass; - + while (IsValid(LocalParentClass) && LocalParentClass != ParentClass && LocalParentClass != UFlowNode::StaticClass()) { StepsTillExactMatch++; LocalParentClass = LocalParentClass->GetSuperClass(); } - + if (StepsTillExactMatch != 0 && StepsTillExactMatch < ClosestParentMatch.Key) { ClosestParentMatch = {StepsTillExactMatch, ParentClass}; @@ -284,7 +282,7 @@ UClass* UFlowGraphSchema::GetAssignedGraphNodeClass(const UClass* FlowNodeClass) ReturnClass = GraphNodesByFlowNodes.FindRef(ClosestParentMatch.Value); } - + return IsValid(ReturnClass) ? ReturnClass : UFlowGraphNode::StaticClass(); } From 473b7c3036023315062917a4b9cf7f469af5bf78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 30 Apr 2023 15:47:44 +0200 Subject: [PATCH 294/338] rework of PR #140 - added bEnforceFriendlyPinNames as separate flag from the Unreal editor config - moved creating a display name to `UFlowGraphSchema::GetPinDisplayName` without modifying graph node's instance --- .../Private/Graph/FlowGraphEditorSettings.cpp | 3 +- .../Private/Graph/FlowGraphSchema.cpp | 35 +++++++++++++++++++ .../Private/Graph/Nodes/FlowGraphNode.cpp | 21 ++--------- .../Private/Graph/Widgets/SFlowGraphNode.cpp | 1 - .../Public/Graph/FlowGraphEditorSettings.h | 6 +++- .../FlowEditor/Public/Graph/FlowGraphSchema.h | 1 + 6 files changed, 44 insertions(+), 23 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp b/Source/FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp index c555e64ab..0ecffa9fc 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphEditorSettings.cpp @@ -2,13 +2,12 @@ #include "Graph/FlowGraphEditorSettings.h" -#include "FlowAsset.h" - UFlowGraphEditorSettings::UFlowGraphEditorSettings(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) , NodeDoubleClickTarget(EFlowNodeDoubleClickTarget::PrimaryAsset) , bShowNodeClass(false) , bShowNodeDescriptionWhilePlaying(true) + , bEnforceFriendlyPinNames(false) , bShowSubGraphPreview(true) , bShowSubGraphPath(true) , SubGraphPreviewSize(FVector2D(640.f, 360.f)) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp index ca8565ed2..7aad96e06 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -4,6 +4,7 @@ #include "Graph/FlowGraph.h" #include "Graph/FlowGraphEditor.h" +#include "Graph/FlowGraphEditorSettings.h" #include "Graph/FlowGraphSchema_Actions.h" #include "Graph/FlowGraphSettings.h" #include "Graph/FlowGraphUtils.h" @@ -146,6 +147,40 @@ FLinearColor UFlowGraphSchema::GetPinTypeColor(const FEdGraphPinType& PinType) c return FLinearColor::White; } +FText UFlowGraphSchema::GetPinDisplayName(const UEdGraphPin* Pin) const +{ + FText ResultPinName; + check(Pin != nullptr); + if (Pin->PinFriendlyName.IsEmpty()) + { + // We don't want to display "None" for no name + if (Pin->PinName.IsNone()) + { + return FText::GetEmpty(); + } + if (GetDefault()->bEnforceFriendlyPinNames) // this option is only difference between this override and UEdGraphSchema::GetPinDisplayName + { + ResultPinName = FText::FromString(FName::NameToDisplayString(Pin->PinName.ToString(), true)); + } + else + { + ResultPinName = FText::FromName(Pin->PinName); + } + } + else + { + ResultPinName = Pin->PinFriendlyName; + + bool bShouldUseLocalizedNodeAndPinNames = false; + GConfig->GetBool(TEXT("Internationalization"), TEXT("ShouldUseLocalizedNodeAndPinNames"), bShouldUseLocalizedNodeAndPinNames, GEditorSettingsIni); + if (!bShouldUseLocalizedNodeAndPinNames) + { + ResultPinName = FText::FromString(ResultPinName.BuildSourceString()); + } + } + return ResultPinName; +} + void UFlowGraphSchema::BreakNodeLinks(UEdGraphNode& TargetNode) const { Super::BreakNodeLinks(TargetNode); diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 28f63727d..9f79b50b7 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -26,7 +26,6 @@ #include "SourceCodeNavigation.h" #include "Textures/SlateIcon.h" #include "ToolMenuSection.h" -#include "Settings/EditorStyleSettings.h" #define LOCTEXT_NAMESPACE "FlowGraphNode" @@ -776,15 +775,7 @@ void UFlowGraphNode::CreateInputPin(const FFlowPin& FlowPin, const int32 Index / UEdGraphPin* NewPin = CreatePin(EGPD_Input, PinType, FlowPin.PinName, Index); check(NewPin); - if (FlowPin.PinFriendlyName.IsEmpty()) - { - if (GetDefault()->bShowFriendlyNames) - { - NewPin->bAllowFriendlyName = true; - NewPin->PinFriendlyName = FText::FromString(FName::NameToDisplayString(FlowPin.PinName.ToString(), false)); - } - } - else + if (!FlowPin.PinFriendlyName.IsEmpty()) { NewPin->bAllowFriendlyName = true; NewPin->PinFriendlyName = FlowPin.PinFriendlyName; @@ -806,15 +797,7 @@ void UFlowGraphNode::CreateOutputPin(const FFlowPin& FlowPin, const int32 Index UEdGraphPin* NewPin = CreatePin(EGPD_Output, PinType, FlowPin.PinName, Index); check(NewPin); - if (FlowPin.PinFriendlyName.IsEmpty()) - { - if (GetDefault()->bShowFriendlyNames) - { - NewPin->bAllowFriendlyName = true; - NewPin->PinFriendlyName = FText::FromString(FName::NameToDisplayString(FlowPin.PinName.ToString(), false)); - } - } - else + if (!FlowPin.PinFriendlyName.IsEmpty()) { NewPin->bAllowFriendlyName = true; NewPin->PinFriendlyName = FlowPin.PinFriendlyName; diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp index a72eecf0f..3f8d8342c 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp @@ -21,7 +21,6 @@ #include "SNodePanel.h" #include "Styling/SlateColor.h" #include "TutorialMetaData.h" -#include "Graph/FlowGraphEditorSettings.h" #include "Widgets/Images/SImage.h" #include "Widgets/Layout/SBorder.h" #include "Widgets/SBoxPanel.h" diff --git a/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h b/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h index 8a8d10b73..54bd78465 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h @@ -30,10 +30,14 @@ class FLOWEDITOR_API UFlowGraphEditorSettings : public UDeveloperSettings UPROPERTY(config, EditAnywhere, Category = "Nodes") bool bShowNodeClass; - // Hides the node description when you play in editor and only shows node status string. + // Shows the node description when you play in editor UPROPERTY(config, EditAnywhere, Category = "Nodes") bool bShowNodeDescriptionWhilePlaying; + // Pin names will will be displayed in a format that is easier to read, even if PinFriendlyName wasn't set + UPROPERTY(EditAnywhere, config, Category = "Nodes") + bool bEnforceFriendlyPinNames; + // Renders preview of entire graph while hovering over UPROPERTY(config, EditAnywhere, Category = "Nodes") bool bShowSubGraphPreview; diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h index 8ceb89ff6..099700bc4 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h @@ -36,6 +36,7 @@ class FLOWEDITOR_API UFlowGraphSchema : public UEdGraphSchema virtual bool TryCreateConnection(UEdGraphPin* A, UEdGraphPin* B) const override; virtual bool ShouldHidePinDefaultValue(UEdGraphPin* Pin) const override; virtual FLinearColor GetPinTypeColor(const FEdGraphPinType& PinType) const override; + virtual FText GetPinDisplayName(const UEdGraphPin* Pin) const override; virtual void BreakNodeLinks(UEdGraphNode& TargetNode) const override; virtual void BreakPinLinks(UEdGraphPin& TargetPin, bool bSendsNodeNotification) const override; virtual int32 GetNodeSelectionCount(const UEdGraph* Graph) const override; From 7fd5b2531668415bbf2f13728ee1051c58b91ea5 Mon Sep 17 00:00:00 2001 From: LindyHopperGT <91915878+LindyHopperGT@users.noreply.github.com> Date: Mon, 8 May 2023 09:16:46 -0700 Subject: [PATCH 295/338] backported CustomInput & Output Details Customization and other cleanup #154 --- Source/Flow/Private/FlowAsset.cpp | 17 +- Source/Flow/Private/FlowSettings.cpp | 3 + Source/Flow/Private/Nodes/FlowNode.cpp | 41 +++++ .../Nodes/Route/FlowNode_CustomInput.cpp | 29 ++-- .../Nodes/Route/FlowNode_CustomNodeBase.cpp | 56 +++++++ .../Nodes/Route/FlowNode_CustomOutput.cpp | 31 ++-- .../World/FlowNode_PlayLevelSequence.cpp | 16 +- Source/Flow/Public/FlowAsset.h | 14 +- Source/Flow/Public/FlowComponent.h | 2 +- Source/Flow/Public/FlowSettings.h | 13 ++ Source/Flow/Public/FlowSubsystem.h | 2 +- Source/Flow/Public/Nodes/FlowNode.h | 15 +- .../Public/Nodes/Route/FlowNode_CustomInput.h | 11 +- .../Nodes/Route/FlowNode_CustomNodeBase.h | 30 ++++ .../Nodes/Route/FlowNode_CustomOutput.h | 11 +- .../Flow/Public/Nodes/Route/FlowNode_Start.h | 2 + .../Private/Asset/FlowAssetFactory.cpp | 3 +- .../Private/Asset/FlowImportUtils.cpp | 1 + .../FlowNode_CustomInputDetails.cpp | 92 ++--------- .../FlowNode_CustomNodeBaseDetails.cpp | 152 ++++++++++++++++++ .../FlowNode_CustomOutputDetails.cpp | 84 ++-------- .../Private/Graph/FlowGraphEditor.cpp | 8 + .../Private/Graph/FlowGraphSchema.cpp | 41 ++++- .../FlowEditor/Public/Asset/FlowImportUtils.h | 1 + .../FlowNode_CustomInputDetails.h | 18 +-- .../FlowNode_CustomNodeBaseDetails.h | 40 +++++ .../FlowNode_CustomOutputDetails.h | 18 +-- .../FlowEditor/Public/Graph/FlowGraphEditor.h | 1 + .../FlowEditor/Public/Graph/FlowGraphSchema.h | 5 + .../FlowEditor/Public/Graph/FlowGraphUtils.h | 2 + 30 files changed, 510 insertions(+), 249 deletions(-) create mode 100644 Source/Flow/Private/Nodes/Route/FlowNode_CustomNodeBase.cpp create mode 100644 Source/Flow/Public/Nodes/Route/FlowNode_CustomNodeBase.h create mode 100644 Source/FlowEditor/Private/DetailCustomizations/FlowNode_CustomNodeBaseDetails.cpp create mode 100644 Source/FlowEditor/Public/DetailCustomizations/FlowNode_CustomNodeBaseDetails.h diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 2dea57c62..0bb41ef19 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -189,7 +189,22 @@ void UFlowAsset::HarvestNodeConnections() } } } -#endif + +#endif // WITH_EDITOR + +void UFlowAsset::AddCustomInput(const FName& InName) +{ + check(!CustomInputs.Contains(InName)); + + CustomInputs.Add(InName); +} + +void UFlowAsset::RemoveCustomInput(const FName& InName) +{ + check(CustomInputs.Contains(InName)); + + CustomInputs.Remove(InName); +} UFlowNode_Start* UFlowAsset::GetStartNode() const { diff --git a/Source/Flow/Private/FlowSettings.cpp b/Source/Flow/Private/FlowSettings.cpp index c287a3aef..9c1070e4a 100644 --- a/Source/Flow/Private/FlowSettings.cpp +++ b/Source/Flow/Private/FlowSettings.cpp @@ -6,5 +6,8 @@ UFlowSettings::UFlowSettings(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) , bCreateFlowSubsystemOnClients(true) , bWarnAboutMissingIdentityTags(true) + , bLogOnSignalDisabled(true) + , bLogOnSignalPassthrough(true) + , bUseAdaptiveNodeTitles(false) { } diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 13eb977a1..8d12dfe6d 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -7,12 +7,14 @@ #include "FlowSubsystem.h" #include "FlowTypes.h" +#include "Components/ActorComponent.h" #if WITH_EDITOR #include "Editor.h" #endif #include "Engine/Engine.h" #include "Engine/ViewportStatsSubsystem.h" #include "Engine/World.h" +#include "GameFramework/Actor.h" #include "Misc/App.h" #include "Misc/Paths.h" #include "Serialization/MemoryReader.h" @@ -147,6 +149,45 @@ UFlowAsset* UFlowNode::GetFlowAsset() const return GetOuter() ? Cast(GetOuter()) : nullptr; } +AActor* UFlowNode::TryGetRootFlowActorOwner() const +{ + AActor* OwningActor = nullptr; + + UObject* RootFlowOwner = TryGetRootFlowObjectOwner(); + + if (IsValid(RootFlowOwner)) + { + // Check if the immediate parent is an AActor + OwningActor = Cast(RootFlowOwner); + + if (!IsValid(OwningActor)) + { + // Check if the if the immediate parent is an UActorComponent + // and return that Component's Owning actor + if (const UActorComponent* OwningComponent = Cast(RootFlowOwner)) + { + OwningActor = OwningComponent->GetOwner(); + } + } + } + + return OwningActor; +} + +UObject* UFlowNode::TryGetRootFlowObjectOwner() const +{ + const UFlowAsset* FlowAsset = GetFlowAsset(); + + if (IsValid(FlowAsset)) + { + return FlowAsset->GetOwner(); + } + else + { + return nullptr; + } +} + void UFlowNode::AddInputPins(TArray Pins) { for (const FFlowPin& Pin : Pins) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp index e7fa8c5ec..59982dc64 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp @@ -1,17 +1,14 @@ // Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors #include "Nodes/Route/FlowNode_CustomInput.h" +#include "FlowSettings.h" + +#define LOCTEXT_NAMESPACE "FlowNode" UFlowNode_CustomInput::UFlowNode_CustomInput(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { -#if WITH_EDITOR - Category = TEXT("Route"); - NodeStyle = EFlowNodeStyle::InOut; -#endif - InputPins.Empty(); - AllowedSignalModes = {EFlowSignalMode::Enabled, EFlowSignalMode::Disabled}; } void UFlowNode_CustomInput::ExecuteInput(const FName& PinName) @@ -20,19 +17,19 @@ void UFlowNode_CustomInput::ExecuteInput(const FName& PinName) } #if WITH_EDITOR -FString UFlowNode_CustomInput::GetNodeDescription() const +FText UFlowNode_CustomInput::GetNodeTitle() const { - return EventName.ToString(); -} + const bool bUseAdaptiveNodeTitles = UFlowSettings::Get()->bUseAdaptiveNodeTitles; -EDataValidationResult UFlowNode_CustomInput::ValidateNode() -{ - if (EventName.IsNone()) + if (bUseAdaptiveNodeTitles && !EventName.IsNone()) { - ValidationLog.Error(TEXT("Event Name is empty!"), this); - return EDataValidationResult::Invalid; + return FText::Format(LOCTEXT("CustomInputTitle", "{0} Input"), { FText::FromString(EventName.ToString()) }); + } + else + { + return Super::GetNodeTitle(); } - - return EDataValidationResult::Valid; } #endif + +#undef LOCTEXT_NAMESPACE diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_CustomNodeBase.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_CustomNodeBase.cpp new file mode 100644 index 000000000..b38f67786 --- /dev/null +++ b/Source/Flow/Private/Nodes/Route/FlowNode_CustomNodeBase.cpp @@ -0,0 +1,56 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#include "Nodes/Route/FlowNode_CustomNodeBase.h" +#include "FlowSettings.h" + +UFlowNode_CustomNodeBase::UFlowNode_CustomNodeBase(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ +#if WITH_EDITOR + Category = TEXT("Route"); + NodeStyle = EFlowNodeStyle::InOut; +#endif + + AllowedSignalModes = {EFlowSignalMode::Enabled, EFlowSignalMode::Disabled}; +} + +void UFlowNode_CustomNodeBase::SetEventName(const FName& InEventName) +{ + if (EventName != InEventName) + { + EventName = InEventName; + +#if WITH_EDITOR + // Must reconstruct the Graph Visuals if anything that is included in AdaptiveNodeTitles changes + OnReconstructionRequested.ExecuteIfBound(); +#endif // WITH_EDITOR + } +} + +#if WITH_EDITOR + +FString UFlowNode_CustomNodeBase::GetNodeDescription() const +{ + const bool bUseAdaptiveNodeTitles = UFlowSettings::Get()->bUseAdaptiveNodeTitles; + + if (bUseAdaptiveNodeTitles) + { + return Super::GetNodeDescription(); + } + else + { + return EventName.ToString(); + } +} + +EDataValidationResult UFlowNode_CustomNodeBase::ValidateNode() +{ + if (EventName.IsNone()) + { + ValidationLog.Error(TEXT("Event Name is empty!"), this); + return EDataValidationResult::Invalid; + } + + return EDataValidationResult::Valid; +} +#endif diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp index b53cbfc31..bab95e170 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp @@ -1,20 +1,15 @@ // Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors #include "Nodes/Route/FlowNode_CustomOutput.h" - #include "FlowAsset.h" -#include "Nodes/Route/FlowNode_SubGraph.h" +#include "FlowSettings.h" + +#define LOCTEXT_NAMESPACE "FlowNode" UFlowNode_CustomOutput::UFlowNode_CustomOutput(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { -#if WITH_EDITOR - Category = TEXT("Route"); - NodeStyle = EFlowNodeStyle::InOut; -#endif - OutputPins.Empty(); - AllowedSignalModes = {EFlowSignalMode::Enabled, EFlowSignalMode::Disabled}; } void UFlowNode_CustomOutput::ExecuteInput(const FName& PinName) @@ -26,19 +21,19 @@ void UFlowNode_CustomOutput::ExecuteInput(const FName& PinName) } #if WITH_EDITOR -FString UFlowNode_CustomOutput::GetNodeDescription() const +FText UFlowNode_CustomOutput::GetNodeTitle() const { - return EventName.ToString(); -} + const bool bUseAdaptiveNodeTitles = UFlowSettings::Get()->bUseAdaptiveNodeTitles; -EDataValidationResult UFlowNode_CustomOutput::ValidateNode() -{ - if (EventName.IsNone()) + if (bUseAdaptiveNodeTitles && !EventName.IsNone()) { - ValidationLog.Error(TEXT("Event Name is empty!"), this); - return EDataValidationResult::Invalid; + return FText::Format(LOCTEXT("CustomOutputTitle", "{0} Output"), { FText::FromString(EventName.ToString()) }); + } + else + { + return Super::GetNodeTitle(); } - - return EDataValidationResult::Valid; } #endif + +#undef LOCTEXT_NAMESPACE \ No newline at end of file diff --git a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp index 00c3cce6b..d9ee71cc9 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp @@ -132,21 +132,7 @@ void UFlowNode_PlayLevelSequence::CreatePlayer() { ALevelSequenceActor* SequenceActor; - AActor* OwningActor = nullptr; - if (GetFlowAsset()) - { - if (UObject* RootFlowOwner = GetFlowAsset()->GetOwner()) - { - OwningActor = Cast(RootFlowOwner); // in case Root Flow was created directly from some actor - if (OwningActor == nullptr) - { - if (const UActorComponent* OwningComponent = Cast(RootFlowOwner)) - { - OwningActor = OwningComponent->GetOwner(); - } - } - } - } + AActor* OwningActor = TryGetRootFlowActorOwner(); // Apply AActor::CustomTimeDilation from owner of the Root Flow if (IsValid(OwningActor)) diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 27aa62fe1..86d8b8219 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -133,7 +133,7 @@ class FLOW_API UFlowAsset : public UObject void HarvestNodeConnections(); #endif - TMap GetNodes() const { return Nodes; } + const TMap& GetNodes() const { return Nodes; } UFlowNode* GetNode(const FGuid& Guid) const { return Nodes.FindRef(Guid); } template @@ -184,8 +184,12 @@ class FLOW_API UFlowAsset : public UObject } public: - TArray GetCustomInputs() const { return CustomInputs; } - TArray GetCustomOutputs() const { return CustomOutputs; } + const TArray& GetCustomInputs() const { return CustomInputs; } + const TArray& GetCustomOutputs() const { return CustomOutputs; } + +protected: + void AddCustomInput(const FName& InName); + void RemoveCustomInput(const FName& InName); ////////////////////////////////////////////////////////////////////////// // Instances of the template asset @@ -318,11 +322,11 @@ class FLOW_API UFlowAsset : public UObject // Returns nodes that have any work left, not marked as Finished yet UFUNCTION(BlueprintPure, Category = "Flow") - TArray GetActiveNodes() const { return ActiveNodes; } + const TArray& GetActiveNodes() const { return ActiveNodes; } // Returns nodes active in the past, done their work UFUNCTION(BlueprintPure, Category = "Flow") - TArray GetRecordedNodes() const { return RecordedNodes; } + const TArray& GetRecordedNodes() const { return RecordedNodes; } ////////////////////////////////////////////////////////////////////////// // SaveGame support diff --git a/Source/Flow/Public/FlowComponent.h b/Source/Flow/Public/FlowComponent.h index abc83704a..f815e9cd5 100644 --- a/Source/Flow/Public/FlowComponent.h +++ b/Source/Flow/Public/FlowComponent.h @@ -109,7 +109,7 @@ class FLOW_API UFlowComponent : public UActorComponent FGameplayTagContainer RecentlySentNotifyTags; public: - FGameplayTagContainer GetRecentlySentNotifyTags() const { return RecentlySentNotifyTags; } + const FGameplayTagContainer& GetRecentlySentNotifyTags() const { return RecentlySentNotifyTags; } // Send single notification from the actor to Flow graphs // If set on server, it always going to be replicated to clients diff --git a/Source/Flow/Public/FlowSettings.h b/Source/Flow/Public/FlowSettings.h index 6b9e66f18..a206b4640 100644 --- a/Source/Flow/Public/FlowSettings.h +++ b/Source/Flow/Public/FlowSettings.h @@ -29,4 +29,17 @@ class FLOW_API UFlowSettings : public UDeveloperSettings UPROPERTY(Config, EditAnywhere, Category = "SaveSystem") bool bWarnAboutMissingIdentityTags; + + // If enabled, runtime logs will be added when a flow node signal mode is set to Disabled + UPROPERTY(Config, EditAnywhere, Category = "Flow") + bool bLogOnSignalDisabled; + + // If enabled, runtime logs will be added when a flow node signal mode is set to Pass-through + UPROPERTY(Config, EditAnywhere, Category = "Flow") + bool bLogOnSignalPassthrough; + + // Adjust the Titles for FlowNodes to be more expressive than default + // by incorporating data that would otherwise go in the Description + UPROPERTY(EditAnywhere, config, Category = "Nodes") + bool bUseAdaptiveNodeTitles; }; diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index 2255519de..3a3b5b47d 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -114,7 +114,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem /* Returns assets instanced by Sub Graph nodes */ UFUNCTION(BlueprintPure, Category = "FlowSubsystem") - TMap GetInstancedSubFlows() const { return InstancedSubFlows; } + const TMap& GetInstancedSubFlows() const { return InstancedSubFlows; } virtual UWorld* GetWorld() const override; diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 845529b9b..0d6478c96 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -44,7 +44,10 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte #if WITH_EDITORONLY_DATA protected: + UPROPERTY() TArray> AllowedAssetClasses; + + UPROPERTY() TArray> DeniedAssetClasses; UPROPERTY() @@ -121,7 +124,15 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UFUNCTION(BlueprintPure, Category = "FlowNode") UFlowAsset* GetFlowAsset() const; + // Gets the Owning Actor for this Node's RootFlow + // (if the immediate parent is an UActorComponent, it will get that Component's actor) + AActor* TryGetRootFlowActorOwner() const; + protected: + + // Gets the Owning Object for this Node's RootFlow + UObject* TryGetRootFlowObjectOwner() const; + virtual bool CanFinishGraph() const { return false; } protected: @@ -163,8 +174,8 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte uint8 CountNumberedInputs() const; uint8 CountNumberedOutputs() const; - TArray GetInputPins() const { return InputPins; } - TArray GetOutputPins() const { return OutputPins; } + const TArray& GetInputPins() const { return InputPins; } + const TArray& GetOutputPins() const { return OutputPins; } public: UFUNCTION(BlueprintPure, Category = "FlowNode") diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_CustomInput.h b/Source/Flow/Public/Nodes/Route/FlowNode_CustomInput.h index e1919866e..28a50e134 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_CustomInput.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_CustomInput.h @@ -2,26 +2,25 @@ #pragma once -#include "Nodes/FlowNode.h" +#include "FlowNode_CustomNodeBase.h" + #include "FlowNode_CustomInput.generated.h" /** * Triggers output upon activation of Input (matching this EventName) on the SubGraph node containing this graph */ UCLASS(NotBlueprintable, meta = (DisplayName = "Custom Input")) -class FLOW_API UFlowNode_CustomInput : public UFlowNode +class FLOW_API UFlowNode_CustomInput : public UFlowNode_CustomNodeBase { GENERATED_UCLASS_BODY() - UPROPERTY() - FName EventName; + friend class UFlowAsset; protected: virtual void ExecuteInput(const FName& PinName) override; #if WITH_EDITOR public: - virtual FString GetNodeDescription() const override; - virtual EDataValidationResult ValidateNode() override; + virtual FText GetNodeTitle() const override; #endif }; diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_CustomNodeBase.h b/Source/Flow/Public/Nodes/Route/FlowNode_CustomNodeBase.h new file mode 100644 index 000000000..fb5b76974 --- /dev/null +++ b/Source/Flow/Public/Nodes/Route/FlowNode_CustomNodeBase.h @@ -0,0 +1,30 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#pragma once + +#include "Nodes/FlowNode.h" + +#include "FlowNode_CustomNodeBase.generated.h" + +/** + * Base-class for CustomInput and CustomOutput node types + */ +UCLASS(Abstract, NotBlueprintable) +class FLOW_API UFlowNode_CustomNodeBase : public UFlowNode +{ + GENERATED_UCLASS_BODY() + +protected: + UPROPERTY() + FName EventName; + +public: + void SetEventName(const FName& InEventName); + const FName& GetEventName() const { return EventName; } + +#if WITH_EDITOR +public: + virtual FString GetNodeDescription() const override; + virtual EDataValidationResult ValidateNode() override; +#endif +}; diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_CustomOutput.h b/Source/Flow/Public/Nodes/Route/FlowNode_CustomOutput.h index c2624cb2f..e6d3dee53 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_CustomOutput.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_CustomOutput.h @@ -2,7 +2,8 @@ #pragma once -#include "Nodes/FlowNode.h" +#include "FlowNode_CustomNodeBase.h" + #include "FlowNode_CustomOutput.generated.h" /** @@ -10,18 +11,14 @@ * Triggered output name matches EventName selected on this node */ UCLASS(NotBlueprintable, meta = (DisplayName = "Custom Output")) -class FLOW_API UFlowNode_CustomOutput final : public UFlowNode +class FLOW_API UFlowNode_CustomOutput final : public UFlowNode_CustomNodeBase { GENERATED_UCLASS_BODY() - UPROPERTY() - FName EventName; - protected: virtual void ExecuteInput(const FName& PinName) override; #if WITH_EDITOR - virtual FString GetNodeDescription() const override; - virtual EDataValidationResult ValidateNode() override; + virtual FText GetNodeTitle() const override; #endif }; diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_Start.h b/Source/Flow/Public/Nodes/Route/FlowNode_Start.h index 9a0a09525..803cf42df 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_Start.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_Start.h @@ -13,6 +13,8 @@ class FLOW_API UFlowNode_Start : public UFlowNode { GENERATED_UCLASS_BODY() + friend class UFlowAsset; + protected: virtual void ExecuteInput(const FName& PinName) override; }; diff --git a/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp b/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp index 65ab06e68..d111fa79b 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp @@ -9,6 +9,7 @@ #include "ClassViewerModule.h" #include "Kismet2/KismetEditorUtilities.h" #include "Kismet2/SClassPickerDialog.h" +#include "Modules/ModuleManager.h" #define LOCTEXT_NAMESPACE "FlowAssetFactory" @@ -116,4 +117,4 @@ UObject* UFlowAssetFactory::FactoryCreateNew(UClass* Class, UObject* InParent, F return NewFlowAsset; } -#undef LOCTEXT_NAMESPACE \ No newline at end of file +#undef LOCTEXT_NAMESPACE diff --git a/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp b/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp index f1c007ec7..f2c2e173a 100644 --- a/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp +++ b/Source/FlowEditor/Private/Asset/FlowImportUtils.cpp @@ -3,6 +3,7 @@ #include "Asset/FlowImportUtils.h" #include "Asset/FlowAssetFactory.h" +#include "FlowEditorDefines.h" #include "FlowEditorModule.h" #include "Graph/FlowGraphSchema_Actions.h" #include "Graph/FlowGraph.h" diff --git a/Source/FlowEditor/Private/DetailCustomizations/FlowNode_CustomInputDetails.cpp b/Source/FlowEditor/Private/DetailCustomizations/FlowNode_CustomInputDetails.cpp index ca37aa4fb..5bcb3b60c 100644 --- a/Source/FlowEditor/Private/DetailCustomizations/FlowNode_CustomInputDetails.cpp +++ b/Source/FlowEditor/Private/DetailCustomizations/FlowNode_CustomInputDetails.cpp @@ -1,101 +1,35 @@ // Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors #include "DetailCustomizations/FlowNode_CustomInputDetails.h" +#include "DetailLayoutBuilder.h" #include "FlowAsset.h" -#include "Nodes/Route/FlowNode_CustomInput.h" - -#include "DetailCategoryBuilder.h" -#include "DetailWidgetRow.h" -#include "PropertyEditing.h" -#include "Widgets/Input/SComboBox.h" -#include "Widgets/Text/STextBlock.h" #define LOCTEXT_NAMESPACE "FlowNode_CustomInputDetails" -void FFlowNode_CustomInputDetails::CustomizeDetails(IDetailLayoutBuilder& DetailLayout) +FFlowNode_CustomInputDetails::FFlowNode_CustomInputDetails() { - DetailLayout.GetObjectsBeingCustomized(ObjectsBeingEdited); - GetEventNames(); - - IDetailCategoryBuilder& Category = DetailLayout.EditCategory("CustomInput", LOCTEXT("CustomInputCategory", "Custom Event")); - Category.AddCustomRow(LOCTEXT("CustomRowName", "Event Name")) - .NameContent() - [ - SNew(STextBlock) - .Text(LOCTEXT("EventName", "Event Name")) - ] - .ValueContent() - .HAlign(HAlign_Fill) - [ - SNew(SComboBox>) - .OptionsSource(&EventNames) - .OnGenerateWidget(this, &FFlowNode_CustomInputDetails::GenerateEventWidget) - .OnSelectionChanged(this, &FFlowNode_CustomInputDetails::PinSelectionChanged) - [ - SNew(STextBlock) - .Text(this, &FFlowNode_CustomInputDetails::GetSelectedEventText) - ] - ]; + bExcludeReferencedEvents = true; } -void FFlowNode_CustomInputDetails::GetEventNames() +void FFlowNode_CustomInputDetails::CustomizeDetails(IDetailLayoutBuilder& DetailLayout) { - EventNames.Empty(); - EventNames.Emplace(MakeShareable(new FName(NAME_None))); - - if (ObjectsBeingEdited[0].IsValid() && ObjectsBeingEdited[0].Get()->GetOuter()) - { - const UFlowAsset* FlowAsset = Cast(ObjectsBeingEdited[0].Get()->GetOuter()); - TArray SortedNames = FlowAsset->GetCustomInputs(); - - for (const TPair& Node : FlowAsset->GetNodes()) - { - if (Node.Value->GetClass()->IsChildOf(UFlowNode_CustomInput::StaticClass())) - { - SortedNames.Remove(Cast(Node.Value)->EventName); - } - } + // For backward compatability, these localized texts are in FlowNode_CustomInputDetails, + // not FlowNode_CustomNodeBase, so passing them in to a common function. - SortedNames.Sort([](const FName& A, const FName& B) - { - return A.LexicalLess(B); - }); + static const FText CustomRowNameText = LOCTEXT("CustomRowName", "Event Name"); + static const FText EventNameText = LOCTEXT("EventName", "Event Name"); - for (const FName& EventName : SortedNames) - { - if (!EventName.IsNone()) - { - EventNames.Emplace(MakeShareable(new FName(EventName))); - } - } - } + CustomizeDetailsInternal(DetailLayout, CustomRowNameText, EventNameText); } -TSharedRef FFlowNode_CustomInputDetails::GenerateEventWidget(const TSharedPtr Item) const +IDetailCategoryBuilder& FFlowNode_CustomInputDetails::CreateDetailCategory(IDetailLayoutBuilder& DetailLayout) const { - return SNew(STextBlock).Text(FText::FromName(*Item.Get())); -} - -FText FFlowNode_CustomInputDetails::GetSelectedEventText() const -{ - FText PropertyValue; - - ensure(ObjectsBeingEdited[0].IsValid()); - if (const UFlowNode_CustomInput* Node = Cast(ObjectsBeingEdited[0].Get())) - { - PropertyValue = FText::FromName(Node->EventName); - } - - return PropertyValue; + return DetailLayout.EditCategory("CustomInput", LOCTEXT("CustomInputCategory", "Custom Event")); } -void FFlowNode_CustomInputDetails::PinSelectionChanged(const TSharedPtr Item, ESelectInfo::Type SelectInfo) const +TArray FFlowNode_CustomInputDetails::BuildEventNames(const UFlowAsset& FlowAsset) const { - ensure(ObjectsBeingEdited[0].IsValid()); - if (UFlowNode_CustomInput* Node = Cast(ObjectsBeingEdited[0].Get())) - { - Node->EventName = *Item.Get(); - } + return FlowAsset.GetCustomInputs(); } #undef LOCTEXT_NAMESPACE diff --git a/Source/FlowEditor/Private/DetailCustomizations/FlowNode_CustomNodeBaseDetails.cpp b/Source/FlowEditor/Private/DetailCustomizations/FlowNode_CustomNodeBaseDetails.cpp new file mode 100644 index 000000000..945b62020 --- /dev/null +++ b/Source/FlowEditor/Private/DetailCustomizations/FlowNode_CustomNodeBaseDetails.cpp @@ -0,0 +1,152 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#include "DetailCustomizations/FlowNode_CustomNodeBaseDetails.h" +#include "FlowAsset.h" +#include "Nodes/Route/FlowNode_CustomNodeBase.h" + +#include "DetailCategoryBuilder.h" +#include "DetailWidgetRow.h" +#include "PropertyEditing.h" +#include "Widgets/Input/SComboBox.h" +#include "Widgets/Text/STextBlock.h" +#include "Widgets/SWidget.h" + + +void FFlowNode_CustomNodeBaseDetails::CustomizeDetails(IDetailLayoutBuilder& DetailLayout) +{ + // Subclasses must override this function (and call CustomizeDetailsInternal with the localized text) + checkNoEntry(); +} + +void FFlowNode_CustomNodeBaseDetails::CustomizeDetailsInternal(IDetailLayoutBuilder& DetailLayout, const FText& CustomRowNameText, const FText& EventNameText) +{ + DetailLayout.GetObjectsBeingCustomized(ObjectsBeingEdited); + + if (ObjectsBeingEdited[0].IsValid()) + { + UFlowNode_CustomNodeBase* FlowNodeBase = CastChecked(ObjectsBeingEdited[0]); + CachedEventNameSelected = MakeShared(FlowNodeBase->GetEventName()); + } + + IDetailCategoryBuilder& Category = CreateDetailCategory(DetailLayout); + + Category.AddCustomRow(CustomRowNameText) + .NameContent() + [ + SNew(STextBlock) + .Text(EventNameText) + ] + .ValueContent() + .HAlign(HAlign_Fill) + [ + SAssignNew(EventTextListWidget, SComboBox>) + .OptionsSource(&EventNames) + .OnGenerateWidget(this, &FFlowNode_CustomNodeBaseDetails::GenerateEventWidget) + .OnComboBoxOpening(this, &FFlowNode_CustomNodeBaseDetails::OnComboBoxOpening) + .OnSelectionChanged(this, &FFlowNode_CustomNodeBaseDetails::PinSelectionChanged) + [ + SNew(STextBlock) + .Text(this, &FFlowNode_CustomNodeBaseDetails::GetSelectedEventText) + ] + ]; +} + +void FFlowNode_CustomNodeBaseDetails::OnComboBoxOpening() +{ + RebuildEventNames(); +} + +void FFlowNode_CustomNodeBaseDetails::RebuildEventNames() +{ + EventNames.Empty(); + + check(CachedEventNameSelected.IsValid()); + EventNames.Add(CachedEventNameSelected); + + if (ObjectsBeingEdited[0].IsValid() && ObjectsBeingEdited[0].Get()->GetOuter()) + { + const UFlowAsset* FlowAsset = CastChecked(ObjectsBeingEdited[0].Get()->GetOuter()); + TArray SortedNames = BuildEventNames(*FlowAsset); + + if (bExcludeReferencedEvents) + { + for (const TPair& Node : FlowAsset->GetNodes()) + { + if (Node.Value->GetClass()->IsChildOf(UFlowNode_CustomNodeBase::StaticClass())) + { + SortedNames.Remove(Cast(Node.Value)->GetEventName()); + } + } + } + + SortedNames.Sort([](const FName& A, const FName& B) + { + return A.LexicalLess(B); + }); + + for (const FName& EventName : SortedNames) + { + const bool bIsCurrentSelection = (EventName == *CachedEventNameSelected); + if (!EventName.IsNone() && !bIsCurrentSelection) + { + EventNames.Add(MakeShared(EventName)); + } + } + } + + if (!IsInEventNames(NAME_None)) + { + EventNames.Add(MakeShared(NAME_None)); + } +} + +bool FFlowNode_CustomNodeBaseDetails::IsInEventNames(const FName& EventName) const +{ + const bool bIsInEventNames = + EventNames.ContainsByPredicate([&EventName](const TSharedPtr& ExistingName) + { + return *ExistingName == EventName; + }); + + return bIsInEventNames; +} + +TSharedRef FFlowNode_CustomNodeBaseDetails::GenerateEventWidget(const TSharedPtr Item) const +{ + return + SNew(STextBlock) + .Text(FText::FromName(*Item.Get())); +} + +FText FFlowNode_CustomNodeBaseDetails::GetSelectedEventText() const +{ + check(CachedEventNameSelected.IsValid()); + + return FText::FromName(*CachedEventNameSelected.Get()); +} + +void FFlowNode_CustomNodeBaseDetails::PinSelectionChanged(const TSharedPtr Item, ESelectInfo::Type SelectInfo) +{ + ensure(ObjectsBeingEdited[0].IsValid()); + + UFlowNode_CustomNodeBase* Node = Cast(ObjectsBeingEdited[0].Get()); + if (IsValid(Node) && Item) + { + const bool bIsChanged = (*CachedEventNameSelected != *Item); + + if (bIsChanged) + { + CachedEventNameSelected = Item; + + const FName ItemAsName = *CachedEventNameSelected; + + Node->SetEventName(ItemAsName); + + if (EventTextListWidget.IsValid()) + { + // Tell UDE to refresh the widget to show the new change + EventTextListWidget->Invalidate(EInvalidateWidgetReason::Paint); + } + } + } +} diff --git a/Source/FlowEditor/Private/DetailCustomizations/FlowNode_CustomOutputDetails.cpp b/Source/FlowEditor/Private/DetailCustomizations/FlowNode_CustomOutputDetails.cpp index d2ab37aee..652e768ae 100644 --- a/Source/FlowEditor/Private/DetailCustomizations/FlowNode_CustomOutputDetails.cpp +++ b/Source/FlowEditor/Private/DetailCustomizations/FlowNode_CustomOutputDetails.cpp @@ -1,93 +1,35 @@ // Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors #include "DetailCustomizations/FlowNode_CustomOutputDetails.h" +#include "DetailLayoutBuilder.h" #include "FlowAsset.h" -#include "Nodes/Route/FlowNode_CustomOutput.h" - -#include "DetailCategoryBuilder.h" -#include "DetailWidgetRow.h" -#include "PropertyEditing.h" -#include "Widgets/Input/SComboBox.h" -#include "Widgets/Text/STextBlock.h" #define LOCTEXT_NAMESPACE "FlowNode_CustomOutputDetails" -void FFlowNode_CustomOutputDetails::CustomizeDetails(IDetailLayoutBuilder& DetailLayout) +FFlowNode_CustomOutputDetails::FFlowNode_CustomOutputDetails() { - DetailLayout.GetObjectsBeingCustomized(ObjectsBeingEdited); - GetEventNames(); - - IDetailCategoryBuilder& Category = DetailLayout.EditCategory("CustomOutput", LOCTEXT("CustomEventsCategory", "Custom Output")); - Category.AddCustomRow(LOCTEXT("CustomRowName", "Event Name")) - .NameContent() - [ - SNew(STextBlock) - .Text(LOCTEXT("EventName", "Event Name")) - ] - .ValueContent() - .HAlign(HAlign_Fill) - [ - SNew(SComboBox>) - .OptionsSource(&EventNames) - .OnGenerateWidget(this, &FFlowNode_CustomOutputDetails::GenerateEventWidget) - .OnSelectionChanged(this, &FFlowNode_CustomOutputDetails::PinSelectionChanged) - [ - SNew(STextBlock) - .Text(this, &FFlowNode_CustomOutputDetails::GetSelectedEventText) - ] - ]; + check(bExcludeReferencedEvents == false); } -void FFlowNode_CustomOutputDetails::GetEventNames() +void FFlowNode_CustomOutputDetails::CustomizeDetails(IDetailLayoutBuilder& DetailLayout) { - EventNames.Empty(); - EventNames.Emplace(MakeShareable(new FName(NAME_None))); - - if (ObjectsBeingEdited[0].IsValid() && ObjectsBeingEdited[0].Get()->GetOuter()) - { - const UFlowAsset* FlowAsset = Cast(ObjectsBeingEdited[0].Get()->GetOuter()); - TArray SortedNames = FlowAsset->GetCustomOutputs(); + // For backward compatability, these localized texts are in FlowNode_CustomOutputDetails, + // not FlowNode_CustomNodeBase, so passing them in to a common function. - SortedNames.Sort([](const FName& A, const FName& B) - { - return A.LexicalLess(B); - }); + static const FText CustomRowNameText = LOCTEXT("CustomRowName", "Event Name"); + static const FText EventNameText = LOCTEXT("EventName", "Event Name"); - for (const FName& EventName : SortedNames) - { - if (!EventName.IsNone()) - { - EventNames.Emplace(MakeShareable(new FName(EventName))); - } - } - } + CustomizeDetailsInternal(DetailLayout, CustomRowNameText, EventNameText); } -TSharedRef FFlowNode_CustomOutputDetails::GenerateEventWidget(const TSharedPtr Item) const +IDetailCategoryBuilder& FFlowNode_CustomOutputDetails::CreateDetailCategory(IDetailLayoutBuilder& DetailLayout) const { - return SNew(STextBlock).Text(FText::FromName(*Item.Get())); -} - -FText FFlowNode_CustomOutputDetails::GetSelectedEventText() const -{ - FText PropertyValue; - - ensure(ObjectsBeingEdited[0].IsValid()); - if (const UFlowNode_CustomOutput* Node = Cast(ObjectsBeingEdited[0].Get())) - { - PropertyValue = FText::FromName(Node->EventName); - } - - return PropertyValue; + return DetailLayout.EditCategory("CustomOutput", LOCTEXT("CustomEventsCategory", "Custom Output")); } -void FFlowNode_CustomOutputDetails::PinSelectionChanged(const TSharedPtr Item, ESelectInfo::Type SelectInfo) const +TArray FFlowNode_CustomOutputDetails::BuildEventNames(const UFlowAsset& FlowAsset) const { - ensure(ObjectsBeingEdited[0].IsValid()); - if (UFlowNode_CustomOutput* Node = Cast(ObjectsBeingEdited[0].Get())) - { - Node->EventName = *Item.Get(); - } + return FlowAsset.GetCustomOutputs(); } #undef LOCTEXT_NAMESPACE diff --git a/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp b/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp index ba61997d0..e89a0ce87 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp @@ -15,6 +15,9 @@ #include "Framework/Commands/GenericCommands.h" #include "HAL/PlatformApplicationMisc.h" #include "LevelEditor.h" +#include "Modules/ModuleManager.h" +#include "ScopedTransaction.h" +#include "Widgets/Docking/SDockTab.h" #define LOCTEXT_NAMESPACE "FlowGraphEditor" @@ -33,6 +36,11 @@ void SFlowGraphEditor::Construct(const FArguments& InArgs, const TSharedPtrGetGraph(); Arguments._GraphEvents = InArgs._GraphEvents; Arguments._AutoExpandActionMenu = true; + + // QUESTION (gtaylor) Why is this code commented out? + // When commenting out code, please leave a comment as to *why* it is commented out + // and under what conditions it could be uncommented or removed. + // Stray commented code is an enigma to any future programmer trying to make sense of the code. //Arguments._ShowGraphStateOverlay = false; Arguments._GraphEvents.OnSelectionChanged = FOnSelectionChanged::CreateSP(this, &SFlowGraphEditor::OnSelectedNodesChanged); diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp index 7aad96e06..dcb3cbb86 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -13,11 +13,13 @@ #include "FlowAsset.h" #include "Nodes/FlowNode.h" #include "Nodes/FlowNodeBlueprint.h" +#include "Nodes/Route/FlowNode_CustomInput.h" #include "Nodes/Route/FlowNode_Start.h" #include "Nodes/Route/FlowNode_Reroute.h" #include "AssetRegistryModule.h" #include "EdGraph/EdGraph.h" +#include "Editor.h" #include "ScopedTransaction.h" #define LOCTEXT_NAMESPACE "FlowGraphSchema" @@ -72,17 +74,48 @@ void UFlowGraphSchema::GetGraphContextActions(FGraphContextMenuBuilder& ContextM void UFlowGraphSchema::CreateDefaultNodesForGraph(UEdGraph& Graph) const { + const UFlowAsset* AssetClassDefaults = GetAssetClassDefaults(&Graph); + + static const FVector2D NodeOffsetIncrement = FVector2D(0, 128); + + FVector2D NodeOffset = FVector2D::ZeroVector; + // Start node - UFlowGraphNode* NewGraphNode = FFlowGraphSchemaAction_NewNode::CreateNode(&Graph, nullptr, UFlowNode_Start::StaticClass(), FVector2D::ZeroVector); + const bool bStartNodePlacedAsGhostNode = IsValid(AssetClassDefaults) ? AssetClassDefaults->bStartNodePlacedAsGhostNode : false; + UFlowGraphNode* StartGraphNode = CreateDefaultNode(Graph, AssetClassDefaults, UFlowNode_Start::StaticClass(), NodeOffset, bStartNodePlacedAsGhostNode); + check(IsValid(StartGraphNode)); + + // Add default nodes for all of the CustomInputs + if (IsValid(AssetClassDefaults)) + { + for (const FName& CustomInputName : AssetClassDefaults->CustomInputs) + { + NodeOffset += NodeOffsetIncrement; + + constexpr bool bCustomInputPlacedAsGhostNode = true; + UFlowGraphNode* NewFlowGraphNode = CreateDefaultNode(Graph, AssetClassDefaults, UFlowNode_CustomInput::StaticClass(), NodeOffset, bCustomInputPlacedAsGhostNode); + UFlowNode_CustomInput* CustomInputNode = CastChecked(NewFlowGraphNode->GetFlowNode()); + + CustomInputNode->SetEventName(CustomInputName); + } + } + + CastChecked(&Graph)->GetFlowAsset()->HarvestNodeConnections(); +} + +UFlowGraphNode* UFlowGraphSchema::CreateDefaultNode(UEdGraph& Graph, const UFlowAsset* AssetClassDefaults, const TSubclassOf& NodeClass, const FVector2D& Offset, bool bPlacedAsGhostNode) const +{ + constexpr UEdGraphPin* FromNode = nullptr; + UFlowGraphNode* NewGraphNode = FFlowGraphSchemaAction_NewNode::CreateNode(&Graph, FromNode, NodeClass, Offset); + SetNodeMetaData(NewGraphNode, FNodeMetadata::DefaultGraphNode); - const UFlowAsset* AssetClassDefaults = GetAssetClassDefaults(&Graph); - if (AssetClassDefaults && AssetClassDefaults->bStartNodePlacedAsGhostNode) + if (bPlacedAsGhostNode) { NewGraphNode->MakeAutomaticallyPlacedGhostNode(); } - CastChecked(&Graph)->GetFlowAsset()->HarvestNodeConnections(); + return NewGraphNode; } const FPinConnectionResponse UFlowGraphSchema::CanCreateConnection(const UEdGraphPin* PinA, const UEdGraphPin* PinB) const diff --git a/Source/FlowEditor/Public/Asset/FlowImportUtils.h b/Source/FlowEditor/Public/Asset/FlowImportUtils.h index 183361ff1..3ef1799b7 100644 --- a/Source/FlowEditor/Public/Asset/FlowImportUtils.h +++ b/Source/FlowEditor/Public/Asset/FlowImportUtils.h @@ -5,6 +5,7 @@ #include "Kismet/BlueprintFunctionLibrary.h" #include "FlowAsset.h" +#include "Kismet/BlueprintFunctionLibrary.h" #include "Nodes/FlowPin.h" #include "FlowImportUtils.generated.h" diff --git a/Source/FlowEditor/Public/DetailCustomizations/FlowNode_CustomInputDetails.h b/Source/FlowEditor/Public/DetailCustomizations/FlowNode_CustomInputDetails.h index 2fe9b995a..409881bfb 100644 --- a/Source/FlowEditor/Public/DetailCustomizations/FlowNode_CustomInputDetails.h +++ b/Source/FlowEditor/Public/DetailCustomizations/FlowNode_CustomInputDetails.h @@ -2,13 +2,14 @@ #pragma once -#include "IDetailCustomization.h" +#include "FlowNode_CustomNodeBaseDetails.h" #include "Templates/SharedPointer.h" -#include "Widgets/SWidget.h" -class FFlowNode_CustomInputDetails final : public IDetailCustomization +class FFlowNode_CustomInputDetails final : public FFlowNode_CustomNodeBaseDetails { public: + FFlowNode_CustomInputDetails(); + static TSharedRef MakeInstance() { return MakeShareable(new FFlowNode_CustomInputDetails()); @@ -18,12 +19,7 @@ class FFlowNode_CustomInputDetails final : public IDetailCustomization virtual void CustomizeDetails(IDetailLayoutBuilder& DetailLayout) override; // -- -private: - void GetEventNames(); - TSharedRef GenerateEventWidget(TSharedPtr Item) const; - FText GetSelectedEventText() const; - void PinSelectionChanged(TSharedPtr Item, ESelectInfo::Type SelectInfo) const; - - TArray> ObjectsBeingEdited; - TArray> EventNames; +protected: + virtual IDetailCategoryBuilder& CreateDetailCategory(IDetailLayoutBuilder& DetailLayout) const override; + virtual TArray BuildEventNames(const UFlowAsset& FlowAsset) const override; }; diff --git a/Source/FlowEditor/Public/DetailCustomizations/FlowNode_CustomNodeBaseDetails.h b/Source/FlowEditor/Public/DetailCustomizations/FlowNode_CustomNodeBaseDetails.h new file mode 100644 index 000000000..559b06c40 --- /dev/null +++ b/Source/FlowEditor/Public/DetailCustomizations/FlowNode_CustomNodeBaseDetails.h @@ -0,0 +1,40 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#pragma once + +#include "IDetailCustomization.h" +#include "Templates/SharedPointer.h" +#include "Types/SlateEnums.h" +#include "Widgets/Input/SComboBox.h" + +// Forward Declarations +class IDetailCategoryBuilder; +class UFlowAsset; + +class FFlowNode_CustomNodeBaseDetails : public IDetailCustomization +{ +public: + // IDetailCustomization + virtual void CustomizeDetails(IDetailLayoutBuilder& DetailLayout) override; + // -- + +protected: + + void CustomizeDetailsInternal(IDetailLayoutBuilder& DetailLayout, const FText& CustomRowNameText, const FText& EventNameText); + + virtual IDetailCategoryBuilder& CreateDetailCategory(IDetailLayoutBuilder& DetailLayout) const = 0; + virtual TArray BuildEventNames(const UFlowAsset& FlowAsset) const = 0; + + void OnComboBoxOpening(); + void RebuildEventNames(); + TSharedRef GenerateEventWidget(TSharedPtr Item) const; + FText GetSelectedEventText() const; + void PinSelectionChanged(TSharedPtr Item, ESelectInfo::Type SelectInfo); + bool IsInEventNames(const FName& EventName) const; + + TArray> ObjectsBeingEdited; + TArray> EventNames; + TSharedPtr CachedEventNameSelected; + TSharedPtr>> EventTextListWidget; + bool bExcludeReferencedEvents = false; +}; diff --git a/Source/FlowEditor/Public/DetailCustomizations/FlowNode_CustomOutputDetails.h b/Source/FlowEditor/Public/DetailCustomizations/FlowNode_CustomOutputDetails.h index dba0de2c2..208903328 100644 --- a/Source/FlowEditor/Public/DetailCustomizations/FlowNode_CustomOutputDetails.h +++ b/Source/FlowEditor/Public/DetailCustomizations/FlowNode_CustomOutputDetails.h @@ -2,13 +2,14 @@ #pragma once -#include "IDetailCustomization.h" +#include "FlowNode_CustomNodeBaseDetails.h" #include "Templates/SharedPointer.h" -#include "Widgets/SWidget.h" -class FFlowNode_CustomOutputDetails final : public IDetailCustomization +class FFlowNode_CustomOutputDetails final : public FFlowNode_CustomNodeBaseDetails { public: + FFlowNode_CustomOutputDetails(); + static TSharedRef MakeInstance() { return MakeShareable(new FFlowNode_CustomOutputDetails()); @@ -18,12 +19,7 @@ class FFlowNode_CustomOutputDetails final : public IDetailCustomization virtual void CustomizeDetails(IDetailLayoutBuilder& DetailLayout) override; // -- -private: - void GetEventNames(); - TSharedRef GenerateEventWidget(TSharedPtr Item) const; - FText GetSelectedEventText() const; - void PinSelectionChanged(TSharedPtr Item, ESelectInfo::Type SelectInfo) const; - - TArray> ObjectsBeingEdited; - TArray> EventNames; +protected: + virtual IDetailCategoryBuilder& CreateDetailCategory(IDetailLayoutBuilder& DetailLayout) const override; + virtual TArray BuildEventNames(const UFlowAsset& FlowAsset) const override; }; diff --git a/Source/FlowEditor/Public/Graph/FlowGraphEditor.h b/Source/FlowEditor/Public/Graph/FlowGraphEditor.h index 5debee64c..ccba5175c 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphEditor.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphEditor.h @@ -11,6 +11,7 @@ #include "FlowGraph.h" class FFlowAssetEditor; +class IDetailsView; /** * diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h index 099700bc4..e52644f00 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h @@ -3,10 +3,12 @@ #pragma once #include "EdGraph/EdGraphSchema.h" +#include "Templates/SubclassOf.h" #include "FlowGraphSchema.generated.h" class UFlowAsset; class UFlowNode; +class UFlowGraphNode; DECLARE_MULTICAST_DELEGATE(FFlowGraphSchemaRefresh); @@ -47,6 +49,9 @@ class FLOWEDITOR_API UFlowGraphSchema : public UEdGraphSchema static TArray> GetFlowNodeCategories(); static UClass* GetAssignedGraphNodeClass(const UClass* FlowNodeClass); +protected: + UFlowGraphNode* CreateDefaultNode(UEdGraph& Graph, const UFlowAsset* AssetClassDefaults, const TSubclassOf& NodeClass, const FVector2D& Offset, bool bPlacedAsGhostNode) const; + private: static void ApplyNodeFilter(const UFlowAsset* AssetClassDefaults, const UClass* FlowNodeClass, TArray& FilteredNodes); static void GetFlowNodeActions(FGraphActionMenuBuilder& ActionMenuBuilder, const UFlowAsset* AssetClassDefaults, const FString& CategoryName); diff --git a/Source/FlowEditor/Public/Graph/FlowGraphUtils.h b/Source/FlowEditor/Public/Graph/FlowGraphUtils.h index 5747c7dc2..87b8e126c 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphUtils.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphUtils.h @@ -3,9 +3,11 @@ #pragma once #include "CoreMinimal.h" +#include "Templates/SharedPointer.h" class FFlowAssetEditor; class SFlowGraphEditor; +class UEdGraph; class FLOWEDITOR_API FFlowGraphUtils { From be4b916436103115867586fd0114c286ade49545 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Tue, 9 May 2023 21:12:26 +0200 Subject: [PATCH 296/338] removed a stray code --- Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp b/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp index e89a0ce87..0a9230a80 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp @@ -37,12 +37,6 @@ void SFlowGraphEditor::Construct(const FArguments& InArgs, const TSharedPtr Date: Tue, 9 May 2023 21:13:11 +0200 Subject: [PATCH 297/338] renamed base class to UFlowNode_CustomEventBase --- ...eBase.cpp => FlowNode_CustomEventBase.cpp} | 22 +++---- .../Nodes/Route/FlowNode_CustomInput.cpp | 14 ++-- .../Nodes/Route/FlowNode_CustomOutput.cpp | 16 ++--- ...mNodeBase.h => FlowNode_CustomEventBase.h} | 7 +- .../Public/Nodes/Route/FlowNode_CustomInput.h | 5 +- .../Nodes/Route/FlowNode_CustomOutput.h | 5 +- ...pp => FlowNode_CustomEventBaseDetails.cpp} | 66 +++++++++---------- ...ls.h => FlowNode_CustomEventBaseDetails.h} | 4 +- .../FlowNode_CustomInputDetails.h | 4 +- .../FlowNode_CustomOutputDetails.h | 4 +- 10 files changed, 63 insertions(+), 84 deletions(-) rename Source/Flow/Private/Nodes/Route/{FlowNode_CustomNodeBase.cpp => FlowNode_CustomEventBase.cpp} (54%) rename Source/Flow/Public/Nodes/Route/{FlowNode_CustomNodeBase.h => FlowNode_CustomEventBase.h} (73%) rename Source/FlowEditor/Private/DetailCustomizations/{FlowNode_CustomNodeBaseDetails.cpp => FlowNode_CustomEventBaseDetails.cpp} (54%) rename Source/FlowEditor/Public/DetailCustomizations/{FlowNode_CustomNodeBaseDetails.h => FlowNode_CustomEventBaseDetails.h} (93%) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_CustomNodeBase.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_CustomEventBase.cpp similarity index 54% rename from Source/Flow/Private/Nodes/Route/FlowNode_CustomNodeBase.cpp rename to Source/Flow/Private/Nodes/Route/FlowNode_CustomEventBase.cpp index b38f67786..0b75bc43b 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_CustomNodeBase.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_CustomEventBase.cpp @@ -1,9 +1,9 @@ // Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors -#include "Nodes/Route/FlowNode_CustomNodeBase.h" +#include "Nodes/Route/FlowNode_CustomEventBase.h" #include "FlowSettings.h" -UFlowNode_CustomNodeBase::UFlowNode_CustomNodeBase(const FObjectInitializer& ObjectInitializer) +UFlowNode_CustomEventBase::UFlowNode_CustomEventBase(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { #if WITH_EDITOR @@ -14,14 +14,14 @@ UFlowNode_CustomNodeBase::UFlowNode_CustomNodeBase(const FObjectInitializer& Obj AllowedSignalModes = {EFlowSignalMode::Enabled, EFlowSignalMode::Disabled}; } -void UFlowNode_CustomNodeBase::SetEventName(const FName& InEventName) +void UFlowNode_CustomEventBase::SetEventName(const FName& InEventName) { if (EventName != InEventName) { EventName = InEventName; #if WITH_EDITOR - // Must reconstruct the Graph Visuals if anything that is included in AdaptiveNodeTitles changes + // Must reconstruct the visual representation if anything that is included in AdaptiveNodeTitles changes OnReconstructionRequested.ExecuteIfBound(); #endif // WITH_EDITOR } @@ -29,21 +29,17 @@ void UFlowNode_CustomNodeBase::SetEventName(const FName& InEventName) #if WITH_EDITOR -FString UFlowNode_CustomNodeBase::GetNodeDescription() const +FString UFlowNode_CustomEventBase::GetNodeDescription() const { - const bool bUseAdaptiveNodeTitles = UFlowSettings::Get()->bUseAdaptiveNodeTitles; - - if (bUseAdaptiveNodeTitles) + if (UFlowSettings::Get()->bUseAdaptiveNodeTitles) { return Super::GetNodeDescription(); } - else - { - return EventName.ToString(); - } + + return EventName.ToString(); } -EDataValidationResult UFlowNode_CustomNodeBase::ValidateNode() +EDataValidationResult UFlowNode_CustomEventBase::ValidateNode() { if (EventName.IsNone()) { diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp index 59982dc64..2e1f594c8 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp @@ -3,7 +3,7 @@ #include "Nodes/Route/FlowNode_CustomInput.h" #include "FlowSettings.h" -#define LOCTEXT_NAMESPACE "FlowNode" +#define LOCTEXT_NAMESPACE "FlowNode_CustomInput" UFlowNode_CustomInput::UFlowNode_CustomInput(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) @@ -19,16 +19,12 @@ void UFlowNode_CustomInput::ExecuteInput(const FName& PinName) #if WITH_EDITOR FText UFlowNode_CustomInput::GetNodeTitle() const { - const bool bUseAdaptiveNodeTitles = UFlowSettings::Get()->bUseAdaptiveNodeTitles; - - if (bUseAdaptiveNodeTitles && !EventName.IsNone()) - { - return FText::Format(LOCTEXT("CustomInputTitle", "{0} Input"), { FText::FromString(EventName.ToString()) }); - } - else + if (!EventName.IsNone() && UFlowSettings::Get()->bUseAdaptiveNodeTitles) { - return Super::GetNodeTitle(); + return FText::Format(LOCTEXT("CustomInputTitle", "{0} Input"), {FText::FromString(EventName.ToString())}); } + + return Super::GetNodeTitle(); } #endif diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp index bab95e170..e6826702f 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp @@ -4,7 +4,7 @@ #include "FlowAsset.h" #include "FlowSettings.h" -#define LOCTEXT_NAMESPACE "FlowNode" +#define LOCTEXT_NAMESPACE "FlowNode_CustomOutput" UFlowNode_CustomOutput::UFlowNode_CustomOutput(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) @@ -23,17 +23,13 @@ void UFlowNode_CustomOutput::ExecuteInput(const FName& PinName) #if WITH_EDITOR FText UFlowNode_CustomOutput::GetNodeTitle() const { - const bool bUseAdaptiveNodeTitles = UFlowSettings::Get()->bUseAdaptiveNodeTitles; - - if (bUseAdaptiveNodeTitles && !EventName.IsNone()) - { - return FText::Format(LOCTEXT("CustomOutputTitle", "{0} Output"), { FText::FromString(EventName.ToString()) }); - } - else + if (!EventName.IsNone() && UFlowSettings::Get()->bUseAdaptiveNodeTitles) { - return Super::GetNodeTitle(); + return FText::Format(LOCTEXT("CustomOutputTitle", "{0} Output"), {FText::FromString(EventName.ToString())}); } + + return Super::GetNodeTitle(); } #endif -#undef LOCTEXT_NAMESPACE \ No newline at end of file +#undef LOCTEXT_NAMESPACE diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_CustomNodeBase.h b/Source/Flow/Public/Nodes/Route/FlowNode_CustomEventBase.h similarity index 73% rename from Source/Flow/Public/Nodes/Route/FlowNode_CustomNodeBase.h rename to Source/Flow/Public/Nodes/Route/FlowNode_CustomEventBase.h index fb5b76974..7e9944d25 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_CustomNodeBase.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_CustomEventBase.h @@ -3,14 +3,13 @@ #pragma once #include "Nodes/FlowNode.h" - -#include "FlowNode_CustomNodeBase.generated.h" +#include "FlowNode_CustomEventBase.generated.h" /** - * Base-class for CustomInput and CustomOutput node types + * Base class for nodes used to receive/send events between graphs */ UCLASS(Abstract, NotBlueprintable) -class FLOW_API UFlowNode_CustomNodeBase : public UFlowNode +class FLOW_API UFlowNode_CustomEventBase : public UFlowNode { GENERATED_UCLASS_BODY() diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_CustomInput.h b/Source/Flow/Public/Nodes/Route/FlowNode_CustomInput.h index 28a50e134..12f6012c0 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_CustomInput.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_CustomInput.h @@ -2,15 +2,14 @@ #pragma once -#include "FlowNode_CustomNodeBase.h" - +#include "FlowNode_CustomEventBase.h" #include "FlowNode_CustomInput.generated.h" /** * Triggers output upon activation of Input (matching this EventName) on the SubGraph node containing this graph */ UCLASS(NotBlueprintable, meta = (DisplayName = "Custom Input")) -class FLOW_API UFlowNode_CustomInput : public UFlowNode_CustomNodeBase +class FLOW_API UFlowNode_CustomInput : public UFlowNode_CustomEventBase { GENERATED_UCLASS_BODY() diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_CustomOutput.h b/Source/Flow/Public/Nodes/Route/FlowNode_CustomOutput.h index e6d3dee53..b0e93d422 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_CustomOutput.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_CustomOutput.h @@ -2,8 +2,7 @@ #pragma once -#include "FlowNode_CustomNodeBase.h" - +#include "FlowNode_CustomEventBase.h" #include "FlowNode_CustomOutput.generated.h" /** @@ -11,7 +10,7 @@ * Triggered output name matches EventName selected on this node */ UCLASS(NotBlueprintable, meta = (DisplayName = "Custom Output")) -class FLOW_API UFlowNode_CustomOutput final : public UFlowNode_CustomNodeBase +class FLOW_API UFlowNode_CustomOutput final : public UFlowNode_CustomEventBase { GENERATED_UCLASS_BODY() diff --git a/Source/FlowEditor/Private/DetailCustomizations/FlowNode_CustomNodeBaseDetails.cpp b/Source/FlowEditor/Private/DetailCustomizations/FlowNode_CustomEventBaseDetails.cpp similarity index 54% rename from Source/FlowEditor/Private/DetailCustomizations/FlowNode_CustomNodeBaseDetails.cpp rename to Source/FlowEditor/Private/DetailCustomizations/FlowNode_CustomEventBaseDetails.cpp index 945b62020..3a8b96b99 100644 --- a/Source/FlowEditor/Private/DetailCustomizations/FlowNode_CustomNodeBaseDetails.cpp +++ b/Source/FlowEditor/Private/DetailCustomizations/FlowNode_CustomEventBaseDetails.cpp @@ -1,8 +1,8 @@ // Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors -#include "DetailCustomizations/FlowNode_CustomNodeBaseDetails.h" +#include "DetailCustomizations/FlowNode_CustomEventBaseDetails.h" #include "FlowAsset.h" -#include "Nodes/Route/FlowNode_CustomNodeBase.h" +#include "Nodes/Route/FlowNode_CustomEventBase.h" #include "DetailCategoryBuilder.h" #include "DetailWidgetRow.h" @@ -12,51 +12,51 @@ #include "Widgets/SWidget.h" -void FFlowNode_CustomNodeBaseDetails::CustomizeDetails(IDetailLayoutBuilder& DetailLayout) +void FFlowNode_CustomEventBaseDetails::CustomizeDetails(IDetailLayoutBuilder& DetailLayout) { // Subclasses must override this function (and call CustomizeDetailsInternal with the localized text) checkNoEntry(); } -void FFlowNode_CustomNodeBaseDetails::CustomizeDetailsInternal(IDetailLayoutBuilder& DetailLayout, const FText& CustomRowNameText, const FText& EventNameText) +void FFlowNode_CustomEventBaseDetails::CustomizeDetailsInternal(IDetailLayoutBuilder& DetailLayout, const FText& CustomRowNameText, const FText& EventNameText) { DetailLayout.GetObjectsBeingCustomized(ObjectsBeingEdited); if (ObjectsBeingEdited[0].IsValid()) { - UFlowNode_CustomNodeBase* FlowNodeBase = CastChecked(ObjectsBeingEdited[0]); - CachedEventNameSelected = MakeShared(FlowNodeBase->GetEventName()); + const UFlowNode_CustomEventBase* EventNode = CastChecked(ObjectsBeingEdited[0]); + CachedEventNameSelected = MakeShared(EventNode->GetEventName()); } IDetailCategoryBuilder& Category = CreateDetailCategory(DetailLayout); Category.AddCustomRow(CustomRowNameText) - .NameContent() + .NameContent() [ SNew(STextBlock) - .Text(EventNameText) + .Text(EventNameText) ] - .ValueContent() + .ValueContent() .HAlign(HAlign_Fill) [ SAssignNew(EventTextListWidget, SComboBox>) - .OptionsSource(&EventNames) - .OnGenerateWidget(this, &FFlowNode_CustomNodeBaseDetails::GenerateEventWidget) - .OnComboBoxOpening(this, &FFlowNode_CustomNodeBaseDetails::OnComboBoxOpening) - .OnSelectionChanged(this, &FFlowNode_CustomNodeBaseDetails::PinSelectionChanged) - [ - SNew(STextBlock) - .Text(this, &FFlowNode_CustomNodeBaseDetails::GetSelectedEventText) - ] + .OptionsSource(&EventNames) + .OnGenerateWidget(this, &FFlowNode_CustomEventBaseDetails::GenerateEventWidget) + .OnComboBoxOpening(this, &FFlowNode_CustomEventBaseDetails::OnComboBoxOpening) + .OnSelectionChanged(this, &FFlowNode_CustomEventBaseDetails::PinSelectionChanged) + [ + SNew(STextBlock) + .Text(this, &FFlowNode_CustomEventBaseDetails::GetSelectedEventText) + ] ]; } -void FFlowNode_CustomNodeBaseDetails::OnComboBoxOpening() +void FFlowNode_CustomEventBaseDetails::OnComboBoxOpening() { RebuildEventNames(); } -void FFlowNode_CustomNodeBaseDetails::RebuildEventNames() +void FFlowNode_CustomEventBaseDetails::RebuildEventNames() { EventNames.Empty(); @@ -72,9 +72,9 @@ void FFlowNode_CustomNodeBaseDetails::RebuildEventNames() { for (const TPair& Node : FlowAsset->GetNodes()) { - if (Node.Value->GetClass()->IsChildOf(UFlowNode_CustomNodeBase::StaticClass())) + if (Node.Value->GetClass()->IsChildOf(UFlowNode_CustomEventBase::StaticClass())) { - SortedNames.Remove(Cast(Node.Value)->GetEventName()); + SortedNames.Remove(Cast(Node.Value)->GetEventName()); } } } @@ -100,36 +100,33 @@ void FFlowNode_CustomNodeBaseDetails::RebuildEventNames() } } -bool FFlowNode_CustomNodeBaseDetails::IsInEventNames(const FName& EventName) const +bool FFlowNode_CustomEventBaseDetails::IsInEventNames(const FName& EventName) const { - const bool bIsInEventNames = - EventNames.ContainsByPredicate([&EventName](const TSharedPtr& ExistingName) - { - return *ExistingName == EventName; - }); + const bool bIsInEventNames = EventNames.ContainsByPredicate([&EventName](const TSharedPtr& ExistingName) + { + return *ExistingName == EventName; + }); return bIsInEventNames; } -TSharedRef FFlowNode_CustomNodeBaseDetails::GenerateEventWidget(const TSharedPtr Item) const +TSharedRef FFlowNode_CustomEventBaseDetails::GenerateEventWidget(const TSharedPtr Item) const { - return - SNew(STextBlock) + return SNew(STextBlock) .Text(FText::FromName(*Item.Get())); } -FText FFlowNode_CustomNodeBaseDetails::GetSelectedEventText() const +FText FFlowNode_CustomEventBaseDetails::GetSelectedEventText() const { check(CachedEventNameSelected.IsValid()); - return FText::FromName(*CachedEventNameSelected.Get()); } -void FFlowNode_CustomNodeBaseDetails::PinSelectionChanged(const TSharedPtr Item, ESelectInfo::Type SelectInfo) +void FFlowNode_CustomEventBaseDetails::PinSelectionChanged(const TSharedPtr Item, ESelectInfo::Type SelectInfo) { ensure(ObjectsBeingEdited[0].IsValid()); - UFlowNode_CustomNodeBase* Node = Cast(ObjectsBeingEdited[0].Get()); + UFlowNode_CustomEventBase* Node = Cast(ObjectsBeingEdited[0].Get()); if (IsValid(Node) && Item) { const bool bIsChanged = (*CachedEventNameSelected != *Item); @@ -139,7 +136,6 @@ void FFlowNode_CustomNodeBaseDetails::PinSelectionChanged(const TSharedPtrSetEventName(ItemAsName); if (EventTextListWidget.IsValid()) diff --git a/Source/FlowEditor/Public/DetailCustomizations/FlowNode_CustomNodeBaseDetails.h b/Source/FlowEditor/Public/DetailCustomizations/FlowNode_CustomEventBaseDetails.h similarity index 93% rename from Source/FlowEditor/Public/DetailCustomizations/FlowNode_CustomNodeBaseDetails.h rename to Source/FlowEditor/Public/DetailCustomizations/FlowNode_CustomEventBaseDetails.h index 559b06c40..ce5f7d4f1 100644 --- a/Source/FlowEditor/Public/DetailCustomizations/FlowNode_CustomNodeBaseDetails.h +++ b/Source/FlowEditor/Public/DetailCustomizations/FlowNode_CustomEventBaseDetails.h @@ -7,11 +7,10 @@ #include "Types/SlateEnums.h" #include "Widgets/Input/SComboBox.h" -// Forward Declarations class IDetailCategoryBuilder; class UFlowAsset; -class FFlowNode_CustomNodeBaseDetails : public IDetailCustomization +class FFlowNode_CustomEventBaseDetails : public IDetailCustomization { public: // IDetailCustomization @@ -19,7 +18,6 @@ class FFlowNode_CustomNodeBaseDetails : public IDetailCustomization // -- protected: - void CustomizeDetailsInternal(IDetailLayoutBuilder& DetailLayout, const FText& CustomRowNameText, const FText& EventNameText); virtual IDetailCategoryBuilder& CreateDetailCategory(IDetailLayoutBuilder& DetailLayout) const = 0; diff --git a/Source/FlowEditor/Public/DetailCustomizations/FlowNode_CustomInputDetails.h b/Source/FlowEditor/Public/DetailCustomizations/FlowNode_CustomInputDetails.h index 409881bfb..7fe0c4a6e 100644 --- a/Source/FlowEditor/Public/DetailCustomizations/FlowNode_CustomInputDetails.h +++ b/Source/FlowEditor/Public/DetailCustomizations/FlowNode_CustomInputDetails.h @@ -2,10 +2,10 @@ #pragma once -#include "FlowNode_CustomNodeBaseDetails.h" +#include "FlowNode_CustomEventBaseDetails.h" #include "Templates/SharedPointer.h" -class FFlowNode_CustomInputDetails final : public FFlowNode_CustomNodeBaseDetails +class FFlowNode_CustomInputDetails final : public FFlowNode_CustomEventBaseDetails { public: FFlowNode_CustomInputDetails(); diff --git a/Source/FlowEditor/Public/DetailCustomizations/FlowNode_CustomOutputDetails.h b/Source/FlowEditor/Public/DetailCustomizations/FlowNode_CustomOutputDetails.h index 208903328..6e90889f7 100644 --- a/Source/FlowEditor/Public/DetailCustomizations/FlowNode_CustomOutputDetails.h +++ b/Source/FlowEditor/Public/DetailCustomizations/FlowNode_CustomOutputDetails.h @@ -2,10 +2,10 @@ #pragma once -#include "FlowNode_CustomNodeBaseDetails.h" +#include "FlowNode_CustomEventBaseDetails.h" #include "Templates/SharedPointer.h" -class FFlowNode_CustomOutputDetails final : public FFlowNode_CustomNodeBaseDetails +class FFlowNode_CustomOutputDetails final : public FFlowNode_CustomEventBaseDetails { public: FFlowNode_CustomOutputDetails(); From a4390642dafb5378ed429411a12c0dddec001128 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Tue, 9 May 2023 21:13:31 +0200 Subject: [PATCH 298/338] formatting and readability tweaks --- Source/Flow/Private/FlowAsset.cpp | 3 --- Source/Flow/Private/Nodes/FlowNode.cpp | 6 ++---- Source/Flow/Public/FlowSettings.h | 2 +- Source/Flow/Public/Nodes/FlowNode.h | 2 +- .../FlowEditor/Private/Graph/FlowGraphSchema.cpp | 16 ++++------------ Source/FlowEditor/Public/Graph/FlowGraphSchema.h | 2 +- 6 files changed, 9 insertions(+), 22 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 0bb41ef19..c560dadbe 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -189,20 +189,17 @@ void UFlowAsset::HarvestNodeConnections() } } } - #endif // WITH_EDITOR void UFlowAsset::AddCustomInput(const FName& InName) { check(!CustomInputs.Contains(InName)); - CustomInputs.Add(InName); } void UFlowAsset::RemoveCustomInput(const FName& InName) { check(CustomInputs.Contains(InName)); - CustomInputs.Remove(InName); } diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 8d12dfe6d..ff1940f63 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -182,10 +182,8 @@ UObject* UFlowNode::TryGetRootFlowObjectOwner() const { return FlowAsset->GetOwner(); } - else - { - return nullptr; - } + + return nullptr; } void UFlowNode::AddInputPins(TArray Pins) diff --git a/Source/Flow/Public/FlowSettings.h b/Source/Flow/Public/FlowSettings.h index a206b4640..0dc1a772e 100644 --- a/Source/Flow/Public/FlowSettings.h +++ b/Source/Flow/Public/FlowSettings.h @@ -39,7 +39,7 @@ class FLOW_API UFlowSettings : public UDeveloperSettings bool bLogOnSignalPassthrough; // Adjust the Titles for FlowNodes to be more expressive than default - // by incorporating data that would otherwise go in the Description + // by incorporating data that would otherwise go in the Description UPROPERTY(EditAnywhere, config, Category = "Nodes") bool bUseAdaptiveNodeTitles; }; diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 0d6478c96..f5bfc91b8 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -125,7 +125,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UFlowAsset* GetFlowAsset() const; // Gets the Owning Actor for this Node's RootFlow - // (if the immediate parent is an UActorComponent, it will get that Component's actor) + // (if the immediate parent is an UActorComponent, it will get that Component's actor) AActor* TryGetRootFlowActorOwner() const; protected: diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp index dcb3cbb86..c5ac83266 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -75,15 +75,11 @@ void UFlowGraphSchema::GetGraphContextActions(FGraphContextMenuBuilder& ContextM void UFlowGraphSchema::CreateDefaultNodesForGraph(UEdGraph& Graph) const { const UFlowAsset* AssetClassDefaults = GetAssetClassDefaults(&Graph); - static const FVector2D NodeOffsetIncrement = FVector2D(0, 128); - FVector2D NodeOffset = FVector2D::ZeroVector; // Start node - const bool bStartNodePlacedAsGhostNode = IsValid(AssetClassDefaults) ? AssetClassDefaults->bStartNodePlacedAsGhostNode : false; - UFlowGraphNode* StartGraphNode = CreateDefaultNode(Graph, AssetClassDefaults, UFlowNode_Start::StaticClass(), NodeOffset, bStartNodePlacedAsGhostNode); - check(IsValid(StartGraphNode)); + CreateDefaultNode(Graph, AssetClassDefaults, UFlowNode_Start::StaticClass(), NodeOffset, AssetClassDefaults->bStartNodePlacedAsGhostNode); // Add default nodes for all of the CustomInputs if (IsValid(AssetClassDefaults)) @@ -91,11 +87,9 @@ void UFlowGraphSchema::CreateDefaultNodesForGraph(UEdGraph& Graph) const for (const FName& CustomInputName : AssetClassDefaults->CustomInputs) { NodeOffset += NodeOffsetIncrement; + const UFlowGraphNode* NewFlowGraphNode = CreateDefaultNode(Graph, AssetClassDefaults, UFlowNode_CustomInput::StaticClass(), NodeOffset, true); - constexpr bool bCustomInputPlacedAsGhostNode = true; - UFlowGraphNode* NewFlowGraphNode = CreateDefaultNode(Graph, AssetClassDefaults, UFlowNode_CustomInput::StaticClass(), NodeOffset, bCustomInputPlacedAsGhostNode); UFlowNode_CustomInput* CustomInputNode = CastChecked(NewFlowGraphNode->GetFlowNode()); - CustomInputNode->SetEventName(CustomInputName); } } @@ -103,11 +97,9 @@ void UFlowGraphSchema::CreateDefaultNodesForGraph(UEdGraph& Graph) const CastChecked(&Graph)->GetFlowAsset()->HarvestNodeConnections(); } -UFlowGraphNode* UFlowGraphSchema::CreateDefaultNode(UEdGraph& Graph, const UFlowAsset* AssetClassDefaults, const TSubclassOf& NodeClass, const FVector2D& Offset, bool bPlacedAsGhostNode) const +UFlowGraphNode* UFlowGraphSchema::CreateDefaultNode(UEdGraph& Graph, const UFlowAsset* AssetClassDefaults, const TSubclassOf& NodeClass, const FVector2D& Offset, const bool bPlacedAsGhostNode) { - constexpr UEdGraphPin* FromNode = nullptr; - UFlowGraphNode* NewGraphNode = FFlowGraphSchemaAction_NewNode::CreateNode(&Graph, FromNode, NodeClass, Offset); - + UFlowGraphNode* NewGraphNode = FFlowGraphSchemaAction_NewNode::CreateNode(&Graph, nullptr, NodeClass, Offset); SetNodeMetaData(NewGraphNode, FNodeMetadata::DefaultGraphNode); if (bPlacedAsGhostNode) diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h index e52644f00..95be35b9f 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h @@ -50,7 +50,7 @@ class FLOWEDITOR_API UFlowGraphSchema : public UEdGraphSchema static UClass* GetAssignedGraphNodeClass(const UClass* FlowNodeClass); protected: - UFlowGraphNode* CreateDefaultNode(UEdGraph& Graph, const UFlowAsset* AssetClassDefaults, const TSubclassOf& NodeClass, const FVector2D& Offset, bool bPlacedAsGhostNode) const; + static UFlowGraphNode* CreateDefaultNode(UEdGraph& Graph, const UFlowAsset* AssetClassDefaults, const TSubclassOf& NodeClass, const FVector2D& Offset, bool bPlacedAsGhostNode); private: static void ApplyNodeFilter(const UFlowAsset* AssetClassDefaults, const UClass* FlowNodeClass, TArray& FilteredNodes); From 27c9d33c96e3b8e413ec676c3330a9f1819427b4 Mon Sep 17 00:00:00 2001 From: "Satheesh (ryanjon2040)" Date: Wed, 10 May 2023 00:52:15 +0530 Subject: [PATCH 299/338] Timer node complete in next tick if value is closer to 0 (#142) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Timer node complete in next tick if value is closer to 0 * Add tooltip and better description --------- Co-authored-by: Krzysiek Justyński --- .../Flow/Private/Nodes/Route/FlowNode_Timer.cpp | 15 +++++++++++---- Source/Flow/Public/Nodes/Route/FlowNode_Timer.h | 1 + 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp index bd32bf146..c0d494bd6 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp @@ -29,7 +29,7 @@ UFlowNode_Timer::UFlowNode_Timer(const FObjectInitializer& ObjectInitializer) void UFlowNode_Timer::ExecuteInput(const FName& PinName) { - if (CompletionTime == 0.0f) + if (CompletionTime < 0.0f) { LogError(TEXT("Invalid Timer settings")); TriggerOutput(TEXT("Completed"), true); @@ -65,7 +65,14 @@ void UFlowNode_Timer::SetTimer() GetWorld()->GetTimerManager().SetTimer(StepTimerHandle, this, &UFlowNode_Timer::OnStep, StepTime, true); } - GetWorld()->GetTimerManager().SetTimer(CompletionTimerHandle, this, &UFlowNode_Timer::OnCompletion, CompletionTime, false); + if (CompletionTime > UE_KINDA_SMALL_NUMBER) + { + GetWorld()->GetTimerManager().SetTimer(CompletionTimerHandle, this, &UFlowNode_Timer::OnCompletion, CompletionTime, false); + } + else + { + GetWorld()->GetTimerManager().SetTimerForNextTick(this, &UFlowNode_Timer::OnCompletion); + } } else { @@ -155,7 +162,7 @@ void UFlowNode_Timer::OnLoad_Implementation() #if WITH_EDITOR FString UFlowNode_Timer::GetNodeDescription() const { - if (CompletionTime > 0.0f) + if (CompletionTime > UE_KINDA_SMALL_NUMBER) { if (StepTime > 0.0f) { @@ -165,7 +172,7 @@ FString UFlowNode_Timer::GetNodeDescription() const return FString::Printf(TEXT("%.*f"), 2, CompletionTime); } - return TEXT("Invalid settings"); + return TEXT("Completes in next tick"); } FString UFlowNode_Timer::GetStatusString() const diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h b/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h index 70424bd63..984d2ced2 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h @@ -15,6 +15,7 @@ class FLOW_API UFlowNode_Timer : public UFlowNode GENERATED_UCLASS_BODY() protected: + // If the value is closer to 0, Timer will complete in next tick UPROPERTY(EditAnywhere, Category = "Timer", meta = (ClampMin = 0.0f)) float CompletionTime; From facac47930b903a0a078d633d3953c35f7072d57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Tue, 9 May 2023 21:24:54 +0200 Subject: [PATCH 300/338] merge fix actually we don't need to check values smaller than 0.0f, as editor prevents from entering such values --- Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp index c0d494bd6..1a0dd7c03 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp @@ -29,13 +29,6 @@ UFlowNode_Timer::UFlowNode_Timer(const FObjectInitializer& ObjectInitializer) void UFlowNode_Timer::ExecuteInput(const FName& PinName) { - if (CompletionTime < 0.0f) - { - LogError(TEXT("Invalid Timer settings")); - TriggerOutput(TEXT("Completed"), true); - return; - } - if (PinName == TEXT("In")) { if (CompletionTimerHandle.IsValid() || StepTimerHandle.IsValid()) From 3e93f4c78944215368cbb065741093f5854db460 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Tue, 9 May 2023 22:00:13 +0200 Subject: [PATCH 301/338] UE 5.0 compilation fixes --- Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp index 1a0dd7c03..14367e826 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp @@ -58,7 +58,7 @@ void UFlowNode_Timer::SetTimer() GetWorld()->GetTimerManager().SetTimer(StepTimerHandle, this, &UFlowNode_Timer::OnStep, StepTime, true); } - if (CompletionTime > UE_KINDA_SMALL_NUMBER) + if (CompletionTime > KINDA_SMALL_NUMBER) { GetWorld()->GetTimerManager().SetTimer(CompletionTimerHandle, this, &UFlowNode_Timer::OnCompletion, CompletionTime, false); } @@ -155,7 +155,7 @@ void UFlowNode_Timer::OnLoad_Implementation() #if WITH_EDITOR FString UFlowNode_Timer::GetNodeDescription() const { - if (CompletionTime > UE_KINDA_SMALL_NUMBER) + if (CompletionTime > KINDA_SMALL_NUMBER) { if (StepTime > 0.0f) { From b73ee039ba8a93069be417833a2068bc87a85ac2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Thu, 11 May 2023 23:58:48 +0200 Subject: [PATCH 302/338] Flow Asset no longers requires Start Node to be always a default entry node. It's still a default behavior, but you can change it by overriding UFlowAsset::GetDefaultEntryNode()! It opens door to use Custom Inputs as default node in customized Flow Asset classes. --- Source/Flow/Private/FlowAsset.cpp | 26 ++++++++++---------------- Source/Flow/Public/FlowAsset.h | 9 ++------- 2 files changed, 12 insertions(+), 23 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index c560dadbe..86dd4420f 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -25,7 +25,6 @@ UFlowAsset::UFlowAsset(const FObjectInitializer& ObjectInitializer) , AllowedNodeClasses({UFlowNode::StaticClass()}) , bStartNodePlacedAsGhostNode(false) , TemplateAsset(nullptr) - , StartNode(nullptr) , FinishPolicy(EFlowFinishPolicy::Keep) { if (!AssetGuid.IsValid()) @@ -203,18 +202,17 @@ void UFlowAsset::RemoveCustomInput(const FName& InName) CustomInputs.Remove(InName); } -UFlowNode_Start* UFlowAsset::GetStartNode() const +UFlowNode* UFlowAsset::GetDefaultEntryNode() const { for (const TPair& Node : Nodes) { - // there can be only one, automatically added while creating graph - if (UFlowNode_Start* TestedNode = Cast(Node.Value)) + UFlowNode_Start* StartNode = Cast(Node.Value); + if (StartNode && StartNode->GetConnectedNodes().Num() > 0) { - return TestedNode; + return StartNode; } } - // shouldn't ever get here, Start Node is a default node that can't be deleted by user return nullptr; } @@ -310,12 +308,6 @@ void UFlowAsset::InitializeInstance(const TWeakObjectPtr InOwner, UFlow UFlowNode* NewNodeInstance = NewObject(this, Node.Value->GetClass(), NAME_None, RF_Transient, Node.Value, false, nullptr); Node.Value = NewNodeInstance; - // there can be only one, automatically added while creating graph - if (UFlowNode_Start* InNode = Cast(NewNodeInstance)) - { - StartNode = InNode; - } - if (UFlowNode_CustomInput* CustomInput = Cast(NewNodeInstance)) { if (!CustomInput->EventName.IsNone()) @@ -342,7 +334,7 @@ void UFlowAsset::DeinitializeInstance() void UFlowAsset::PreloadNodes() { - TArray GraphEntryNodes = {StartNode}; + TArray GraphEntryNodes = {GetDefaultEntryNode()}; for (UFlowNode_CustomInput* CustomInput : CustomInputNodes) { GraphEntryNodes.Emplace(CustomInput); @@ -393,9 +385,11 @@ void UFlowAsset::StartFlow() { PreStartFlow(); - ensureAlways(StartNode); - RecordedNodes.Add(StartNode); - StartNode->TriggerFirstOutput(true); + if (UFlowNode* ConnectedEntryNode = GetDefaultEntryNode()) + { + RecordedNodes.Add(ConnectedEntryNode); + ConnectedEntryNode->TriggerFirstOutput(true); + } } void UFlowAsset::FinishFlow(const EFlowFinishPolicy InFinishPolicy, const bool bRemoveInstance /*= true*/) diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 86d8b8219..4d7e02232 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -11,7 +11,6 @@ #include "FlowAsset.generated.h" class UFlowNode_CustomInput; -class UFlowNode_Start; class UFlowNode_SubGraph; class UFlowSubsystem; @@ -149,14 +148,14 @@ class FLOW_API UFlowAsset : public UObject return nullptr; } - UFlowNode_Start* GetStartNode() const; + virtual UFlowNode* GetDefaultEntryNode() const; template void GetNodesInExecutionOrder(TArray& OutNodes) { static_assert(TPointerIsConvertibleFromTo::Value, "'T' template parameter to GetNodesInExecutionOrder must be derived from UFlowNode"); - if (UFlowNode_Start* FoundStartNode = GetStartNode()) + if (UFlowNode* FoundStartNode = GetDefaultEntryNode()) { TSet> IteratedNodes; GetNodesInExecutionOrder_Recursive(FoundStartNode, IteratedNodes, OutNodes); @@ -252,10 +251,6 @@ class FLOW_API UFlowAsset : public UObject // Flow Asset instances created by SubGraph nodes placed in the current graph TMap, TWeakObjectPtr> ActiveSubGraphs; - // Execution of the graph always starts from this node, there can be only one StartNode in the graph - UPROPERTY() - UFlowNode_Start* StartNode; - // Optional entry points to the graph, similar to blueprint Custom Events UPROPERTY() TSet CustomInputNodes; From 4ebb58eb6294d0d79b50732074ccdd15953a7a96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 12 May 2023 00:03:09 +0200 Subject: [PATCH 303/338] tweaking #154: changes to add/remove Custom Inputs - wrap it with WITH_EDITOR - replace check with with simple if-statement, we don't editor to crash on accidentally provided invalid data --- Source/Flow/Private/FlowAsset.cpp | 14 +++++++++----- Source/Flow/Public/FlowAsset.h | 2 ++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 86dd4420f..af26ab62a 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -188,19 +188,23 @@ void UFlowAsset::HarvestNodeConnections() } } } -#endif // WITH_EDITOR void UFlowAsset::AddCustomInput(const FName& InName) { - check(!CustomInputs.Contains(InName)); - CustomInputs.Add(InName); + if (!CustomInputs.Contains(InName)) + { + CustomInputs.Add(InName); + } } void UFlowAsset::RemoveCustomInput(const FName& InName) { - check(CustomInputs.Contains(InName)); - CustomInputs.Remove(InName); + if (CustomInputs.Contains(InName)) + { + CustomInputs.Remove(InName); + } } +#endif // WITH_EDITOR UFlowNode* UFlowAsset::GetDefaultEntryNode() const { diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 4d7e02232..8ab10aaa6 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -187,8 +187,10 @@ class FLOW_API UFlowAsset : public UObject const TArray& GetCustomOutputs() const { return CustomOutputs; } protected: +#if WITH_EDITOR void AddCustomInput(const FName& InName); void RemoveCustomInput(const FName& InName); +#endif ////////////////////////////////////////////////////////////////////////// // Instances of the template asset From 5ec99dedf99b8b60d3e6c3ef339b8f6d417a1321 Mon Sep 17 00:00:00 2001 From: twevs <77587819+twevs@users.noreply.github.com> Date: Tue, 16 May 2023 15:25:29 +0100 Subject: [PATCH 304/338] Play Level Sequence: fixed 'Pause at End' option. (#156) --- .../Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp index d9ee71cc9..81e0ac770 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp @@ -270,7 +270,10 @@ void UFlowNode_PlayLevelSequence::Cleanup() { SequencePlayer->SetFlowEventReceiver(nullptr); SequencePlayer->OnFinished.RemoveAll(this); - SequencePlayer->Stop(); + if (!PlaybackSettings.bPauseAtEnd) + { + SequencePlayer->Stop(); + } SequencePlayer = nullptr; } From 8aa48155de6267a3b1cffdb67c6409ef011a80de Mon Sep 17 00:00:00 2001 From: Soraphis Date: Fri, 26 May 2023 13:01:09 +0200 Subject: [PATCH 305/338] feat: made 'AbortActiveFlows' blueprint callable (#158) --- Source/Flow/Public/FlowSubsystem.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index 3a3b5b47d..ca9b3aa86 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -71,6 +71,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem virtual void Initialize(FSubsystemCollectionBase& Collection) override; virtual void Deinitialize() override; + UFUNCTION(BlueprintCallable, Category = "FlowSubsystem") virtual void AbortActiveFlows(); /* Start the root Flow, graph that will eventually instantiate next Flow Graphs through the SubGraph node */ From 32619ea36159f395dea318bf4f6fdcd55cb9cec5 Mon Sep 17 00:00:00 2001 From: LindyHopperGT <91915878+LindyHopperGT@users.noreply.github.com> Date: Fri, 26 May 2023 13:38:19 -0700 Subject: [PATCH 306/338] CustomOutput and quality of life changes #157 --- Source/Flow/Private/FlowAsset.cpp | 131 +++++++++++++++--- .../Nodes/Route/FlowNode_CustomOutput.cpp | 40 +++++- .../Private/Nodes/Route/FlowNode_SubGraph.cpp | 2 +- Source/Flow/Public/FlowAsset.h | 27 +++- Source/Flow/Public/FlowComponent.h | 27 ++++ Source/Flow/Public/Nodes/FlowNode.h | 4 + .../Private/Asset/FlowAssetEditor.cpp | 9 ++ .../Private/Asset/FlowAssetFactory.cpp | 12 +- .../Private/Asset/FlowAssetToolbar.cpp | 1 + .../Private/Asset/FlowDiffControl.cpp | 1 + Source/FlowEditor/Private/Asset/SFlowDiff.cpp | 5 + .../FlowEditor/Private/FlowEditorCommands.cpp | 2 + Source/FlowEditor/Private/FlowEditorStyle.cpp | 3 +- .../Private/Graph/FlowGraphEditor.cpp | 1 - .../FlowEditor/Public/Asset/FlowAssetEditor.h | 2 + .../Public/Asset/FlowAssetFactory.h | 5 + Source/FlowEditor/Public/FlowEditorCommands.h | 1 + 17 files changed, 238 insertions(+), 35 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index af26ab62a..a579b14ed 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -189,35 +189,73 @@ void UFlowAsset::HarvestNodeConnections() } } -void UFlowAsset::AddCustomInput(const FName& InName) +void UFlowAsset::AddCustomInput(const FName& EventName) { - if (!CustomInputs.Contains(InName)) + if (!CustomInputs.Contains(EventName)) { - CustomInputs.Add(InName); + CustomInputs.Add(EventName); } } -void UFlowAsset::RemoveCustomInput(const FName& InName) +void UFlowAsset::RemoveCustomInput(const FName& EventName) { - if (CustomInputs.Contains(InName)) + if (CustomInputs.Contains(EventName)) { - CustomInputs.Remove(InName); + CustomInputs.Remove(EventName); } } + +void UFlowAsset::AddCustomOutput(const FName& EventName) +{ + check(!CustomOutputs.Contains(EventName)); + + CustomOutputs.Add(EventName); +} + +void UFlowAsset::RemoveCustomOutput(const FName& EventName) +{ + check(CustomOutputs.Contains(EventName)); + + CustomOutputs.Remove(EventName); +} #endif // WITH_EDITOR +UFlowNode_CustomInput* UFlowAsset::TryFindCustomInputNodeByEventName(const FName& EventName) const +{ + for (UFlowNode_CustomInput* InputNode : CustomInputNodes) + { + if (IsValid(InputNode) && InputNode->GetEventName() == EventName) + { + return InputNode; + } + } + + return nullptr; +} + UFlowNode* UFlowAsset::GetDefaultEntryNode() const { + UFlowNode* FirstStartNode = nullptr; + for (const TPair& Node : Nodes) { UFlowNode_Start* StartNode = Cast(Node.Value); - if (StartNode && StartNode->GetConnectedNodes().Num() > 0) + if (StartNode) { - return StartNode; + if (StartNode->GetConnectedNodes().Num() > 0) + { + return StartNode; + } + else if (!FirstStartNode) + { + FirstStartNode = StartNode; + } } } - return nullptr; + // If none of the found start nodes have connections, + // fallback to the first start node we found + return FirstStartNode; } void UFlowAsset::AddInstance(UFlowAsset* Instance) @@ -300,7 +338,7 @@ void UFlowAsset::BroadcastRuntimeMessageAdded(const TSharedRef InOwner, UFlowAsset* InTemplateAsset) { @@ -326,6 +364,17 @@ void UFlowAsset::InitializeInstance(const TWeakObjectPtr InOwner, UFlow void UFlowAsset::DeinitializeInstance() { + for (auto& KV : Nodes) + { + const FGuid& Guid = KV.Key; + UFlowNode* Node = KV.Value; + + if (IsValid(Node)) + { + Node->DeinitializeInstance(); + } + } + if (TemplateAsset) { const int32 ActiveInstancesLeft = TemplateAsset->RemoveInstance(this); @@ -421,34 +470,76 @@ void UFlowAsset::FinishFlow(const EFlowFinishPolicy InFinishPolicy, const bool b } } +bool UFlowAsset::HasStartedFlow() const +{ + return RecordedNodes.Num() > 0; +} + +AActor* UFlowAsset::TryFindActorOwner() const +{ + UActorComponent* OwnerAsComponent = Cast(GetOwner()); + if (IsValid(OwnerAsComponent)) + { + return Cast(OwnerAsComponent->GetOwner()); + } + + return nullptr; +} + TWeakObjectPtr UFlowAsset::GetFlowInstance(UFlowNode_SubGraph* SubGraphNode) const { return ActiveSubGraphs.FindRef(SubGraphNode); } -void UFlowAsset::TriggerCustomEvent(UFlowNode_SubGraph* Node, const FName& EventName) const +void UFlowAsset::TriggerSubgraphCustomInput(UFlowNode_SubGraph& Node, const FName& EventName) const { - const TWeakObjectPtr FlowInstance = ActiveSubGraphs.FindRef(Node); + check(HasStartedFlow()); + + const TWeakObjectPtr FlowInstance = ActiveSubGraphs.FindRef(&Node); if (FlowInstance.IsValid()) { - for (UFlowNode_CustomInput* CustomInput : FlowInstance->CustomInputNodes) + FlowInstance->TriggerCustomInput(EventName); + } +} + +void UFlowAsset::TriggerCustomInput(const FName& EventName) +{ + check(HasStartedFlow()); + + for (UFlowNode_CustomInput* CustomInput : CustomInputNodes) + { + if (CustomInput->EventName == EventName) { - if (CustomInput->EventName == EventName) - { - FlowInstance->RecordedNodes.Add(CustomInput); - CustomInput->TriggerFirstOutput(true); - } + RecordedNodes.Add(CustomInput); + + CustomInput->ExecuteInput(EventName); } } } -void UFlowAsset::TriggerCustomOutput(const FName& EventName) const +void UFlowAsset::TriggerCustomOutput(const FName& EventName) { - NodeOwningThisAssetInstance->TriggerOutput(EventName); + check(HasStartedFlow()); + + const bool bIsSubgraph = NodeOwningThisAssetInstance.IsValid(); + if (bIsSubgraph) + { + NodeOwningThisAssetInstance->TriggerOutput(EventName); + } + else + { + // Non-subgraphs are Root instances, so call the OnTriggerCustomOutputEventDispatcher + if (UFlowComponent* FlowComponent = Cast(GetOwner())) + { + FlowComponent->OnTriggerRootFlowOutputEventDispatcher(*this, EventName); + } + } } void UFlowAsset::TriggerInput(const FGuid& NodeGuid, const FName& PinName) { + check(HasStartedFlow()); + if (UFlowNode* Node = Nodes.FindRef(NodeGuid)) { if (!ActiveNodes.Contains(Node)) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp index e6826702f..4fe382e5f 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp @@ -2,6 +2,7 @@ #include "Nodes/Route/FlowNode_CustomOutput.h" #include "FlowAsset.h" +#include "FlowMessageLog.h" #include "FlowSettings.h" #define LOCTEXT_NAMESPACE "FlowNode_CustomOutput" @@ -14,9 +15,44 @@ UFlowNode_CustomOutput::UFlowNode_CustomOutput(const FObjectInitializer& ObjectI void UFlowNode_CustomOutput::ExecuteInput(const FName& PinName) { - if (!EventName.IsNone() && GetFlowAsset()->GetCustomOutputs().Contains(EventName) && GetFlowAsset()->GetNodeOwningThisAssetInstance()) + UFlowAsset* FlowAsset = GetFlowAsset(); + check(IsValid(FlowAsset)); + + if (EventName.IsNone()) + { + LogWarning( + FString::Printf( + TEXT("Attempted to trigger a CustomOutput (Node %s, Asset %s), with no EventName"), + *GetName(), + *FlowAsset->GetPathName(), + *EventName.ToString())); + } + else if (!FlowAsset->GetCustomOutputs().Contains(EventName)) + { + const TArray& CustomOutputNames = FlowAsset->GetCustomOutputs(); + + FString CustomOutputsString; + for (const FName& OutputName : CustomOutputNames) + { + if (!CustomOutputsString.IsEmpty()) + { + CustomOutputsString += TEXT(", "); + } + + CustomOutputsString += OutputName.ToString(); + } + + LogWarning( + FString::Printf( + TEXT("Attempted to trigger a CustomOutput (Node %s, Asset %s), with EventName %s, which is not a listed CustomOutput { %s }"), + *GetName(), + *FlowAsset->GetPathName(), + *EventName.ToString(), + *CustomOutputsString)); + } + else { - GetFlowAsset()->TriggerCustomOutput(EventName); + FlowAsset->TriggerCustomOutput(EventName); } } diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp index 04bbe1e68..6f4d5af8d 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp @@ -69,7 +69,7 @@ void UFlowNode_SubGraph::ExecuteInput(const FName& PinName) } else if (!PinName.IsNone()) { - GetFlowAsset()->TriggerCustomEvent(this, PinName); + GetFlowAsset()->TriggerSubgraphCustomInput(*this, PinName); } } diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 8ab10aaa6..859b73040 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -186,12 +186,17 @@ class FLOW_API UFlowAsset : public UObject const TArray& GetCustomInputs() const { return CustomInputs; } const TArray& GetCustomOutputs() const { return CustomOutputs; } -protected: + UFlowNode_CustomInput* TryFindCustomInputNodeByEventName(const FName& EventName) const; + #if WITH_EDITOR - void AddCustomInput(const FName& InName); - void RemoveCustomInput(const FName& InName); -#endif +protected: + void AddCustomInput(const FName& EventName); + void RemoveCustomInput(const FName& EventName); + void AddCustomOutput(const FName& EventName); + void RemoveCustomOutput(const FName& EventName); +#endif // WITH_EDITOR + ////////////////////////////////////////////////////////////////////////// // Instances of the template asset @@ -287,6 +292,10 @@ class FLOW_API UFlowAsset : public UObject return Owner.IsValid() ? Cast(Owner) : nullptr; } + // Returns the Owner as an Actor, or if Owner is a Component, return its Owner as an Actor + UFUNCTION(BlueprintPure, Category = "Flow") + AActor* TryFindActorOwner() const; + virtual void PreloadNodes(); virtual void PreStartFlow(); @@ -294,12 +303,16 @@ class FLOW_API UFlowAsset : public UObject virtual void FinishFlow(const EFlowFinishPolicy InFinishPolicy, const bool bRemoveInstance = true); + bool HasStartedFlow() const; + void TriggerCustomInput(const FName& EventName); + // Get Flow Asset instance created by the given SubGraph node TWeakObjectPtr GetFlowInstance(UFlowNode_SubGraph* SubGraphNode) const; -private: - void TriggerCustomEvent(UFlowNode_SubGraph* Node, const FName& EventName) const; - void TriggerCustomOutput(const FName& EventName) const; +protected: + // Call TriggerCustomInput on the subgraph for Node + void TriggerSubgraphCustomInput(UFlowNode_SubGraph& Node, const FName& EventName) const; + void TriggerCustomOutput(const FName& EventName); void TriggerInput(const FGuid& NodeGuid, const FName& PinName); diff --git a/Source/Flow/Public/FlowComponent.h b/Source/Flow/Public/FlowComponent.h index f815e9cd5..d8ff6809f 100644 --- a/Source/Flow/Public/FlowComponent.h +++ b/Source/Flow/Public/FlowComponent.h @@ -203,9 +203,23 @@ class FLOW_API UFlowComponent : public UActorComponent UFUNCTION(BlueprintPure, Category = "RootFlow", meta = (DeprecatedFunction, DeprecationMessage="Use GetRootInstances() instead.")) UFlowAsset* GetRootFlowInstance() const; +////////////////////////////////////////////////////////////////////////// +// UFlowComponent overrideable events + +public: + // Called when a Root flow asset triggers a CustomOutput + UFUNCTION(BlueprintImplementableEvent, DisplayName = "OnTriggerRootFlowOutputEvent") + void BP_OnTriggerRootFlowOutputEvent(UFlowAsset* RootFlowInstance, const FName& EventName); + virtual void OnTriggerRootFlowOutputEvent(UFlowAsset& RootFlowInstance, const FName& EventName) { } + + //~Begin UFlowAsset-only access + FORCEINLINE void OnTriggerRootFlowOutputEventDispatcher(UFlowAsset& RootFlowInstance, const FName& EventName); + //~End UFlowAsset-only access + ////////////////////////////////////////////////////////////////////////// // SaveGame +public: UFUNCTION(BlueprintCallable, Category = "SaveGame") virtual void SaveRootFlow(TArray& SavedFlowInstances); @@ -232,3 +246,16 @@ class FLOW_API UFlowComponent : public UActorComponent UFlowSubsystem* GetFlowSubsystem() const; bool IsFlowNetMode(const EFlowNetMode NetMode) const; }; + + +// Inline Implementations + +void UFlowComponent::OnTriggerRootFlowOutputEventDispatcher(UFlowAsset& RootFlowInstance, const FName& EventName) +{ + // Call the blueprint overrideable function + BP_OnTriggerRootFlowOutputEvent(&RootFlowInstance, EventName); + + // Call the C++ overrideable function + OnTriggerRootFlowOutputEvent(RootFlowInstance, EventName); +} + diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index f5bfc91b8..f40e87a42 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -332,6 +332,10 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "Cleanup")) void K2_Cleanup(); + // Method called from UFlowAsset::DeinitializeInstance() + // (ie, when deinitializing the flow asset itself) + virtual void DeinitializeInstance() { } + public: // Define what happens when node is terminated from the outside virtual void ForceFinishNode(); diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index 3900e2cdf..284be7214 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -358,6 +358,10 @@ void FFlowAssetEditor::BindToolbarCommands() FExecuteAction::CreateSP(this, &FFlowAssetEditor::ValidateAsset_Internal), FCanExecuteAction()); + ToolkitCommands->MapAction(ToolbarCommands.EditAssetDefaults, + FExecuteAction::CreateSP(this, &FFlowAssetEditor::EditAssetDefaults_Clicked), + FCanExecuteAction()); + #if ENABLE_SEARCH_IN_ASSET_EDITOR ToolkitCommands->MapAction(ToolbarCommands.SearchInAsset, FExecuteAction::CreateSP(this, &FFlowAssetEditor::SearchInAsset), @@ -401,6 +405,11 @@ void FFlowAssetEditor::ValidateAsset(FFlowMessageLog& MessageLog) FlowAsset->ValidateAsset(MessageLog); } +void FFlowAssetEditor::EditAssetDefaults_Clicked() +{ + DetailsView->SetObject(FlowAsset); +} + #if ENABLE_SEARCH_IN_ASSET_EDITOR void FFlowAssetEditor::SearchInAsset() { diff --git a/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp b/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp index d111fa79b..c0900979a 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetFactory.cpp @@ -68,6 +68,13 @@ UFlowAssetFactory::UFlowAssetFactory(const FObjectInitializer& ObjectInitializer } bool UFlowAssetFactory::ConfigureProperties() +{ + const FText TitleText = LOCTEXT("CreateFlowAssetOptions", "Pick Flow Asset Class"); + + return ConfigurePropertiesInternal(TitleText); +} + +bool UFlowAssetFactory::ConfigurePropertiesInternal(const FText& TitleText) { AssetClass = UFlowGraphSettings::Get()->DefaultFlowAssetClass; if (AssetClass) // Class was set in settings @@ -84,13 +91,12 @@ bool UFlowAssetFactory::ConfigureProperties() const TSharedPtr Filter = MakeShareable(new FAssetClassParentFilter); Filter->DisallowedClassFlags = CLASS_Abstract | CLASS_Deprecated | CLASS_NewerVersionExists | CLASS_HideDropDown; - Filter->AllowedChildrenOfClasses.Add(UFlowAsset::StaticClass()); + Filter->AllowedChildrenOfClasses.Add(SupportedClass); Options.ClassFilters = {Filter.ToSharedRef()}; - const FText TitleText = LOCTEXT("CreateFlowAssetOptions", "Pick Flow Asset Class"); UClass* ChosenClass = nullptr; - const bool bPressedOk = SClassPickerDialog::PickClass(TitleText, Options, ChosenClass, UFlowAsset::StaticClass()); + const bool bPressedOk = SClassPickerDialog::PickClass(TitleText, Options, ChosenClass, SupportedClass); if (bPressedOk) { diff --git a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp index e3ac8f350..f41620195 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp @@ -204,6 +204,7 @@ void FFlowAssetToolbar::BuildAssetToolbar(UToolMenu* ToolbarMenu) const // add buttons Section.AddEntry(FToolMenuEntry::InitToolBarButton(FFlowToolbarCommands::Get().RefreshAsset)); Section.AddEntry(FToolMenuEntry::InitToolBarButton(FFlowToolbarCommands::Get().ValidateAsset)); + Section.AddEntry(FToolMenuEntry::InitToolBarButton(FFlowToolbarCommands::Get().EditAssetDefaults)); } #if defined ENABLE_SEARCH_IN_ASSET_EDITOR || defined ENABLE_FLOW_DIFF diff --git a/Source/FlowEditor/Private/Asset/FlowDiffControl.cpp b/Source/FlowEditor/Private/Asset/FlowDiffControl.cpp index cd68d6502..e8d9a1221 100644 --- a/Source/FlowEditor/Private/Asset/FlowDiffControl.cpp +++ b/Source/FlowEditor/Private/Asset/FlowDiffControl.cpp @@ -12,6 +12,7 @@ #include "FlowAsset.h" +#include "EdGraph/EdGraph.h" #include "GraphDiffControl.h" #include "SBlueprintDiff.h" diff --git a/Source/FlowEditor/Private/Asset/SFlowDiff.cpp b/Source/FlowEditor/Private/Asset/SFlowDiff.cpp index 037e767c3..d02bebca3 100644 --- a/Source/FlowEditor/Private/Asset/SFlowDiff.cpp +++ b/Source/FlowEditor/Private/Asset/SFlowDiff.cpp @@ -13,12 +13,17 @@ #include "FlowAsset.h" #include "EdGraphUtilities.h" +#include "Editor.h" #include "Framework/Commands/GenericCommands.h" +#include "Framework/MultiBox/MultiBoxBuilder.h" +#include "Framework/MultiBox/MultiBoxDefs.h" #include "GraphDiffControl.h" #include "HAL/PlatformApplicationMisc.h" #include "Internationalization/Text.h" #include "SBlueprintDiff.h" #include "SlateOptMacros.h" +#include "Subsystems/AssetEditorSubsystem.h" +#include "Widgets/Layout/SSpacer.h" #define LOCTEXT_NAMESPACE "SFlowDiff" diff --git a/Source/FlowEditor/Private/FlowEditorCommands.cpp b/Source/FlowEditor/Private/FlowEditorCommands.cpp index 033bc3767..4f4823d12 100644 --- a/Source/FlowEditor/Private/FlowEditorCommands.cpp +++ b/Source/FlowEditor/Private/FlowEditorCommands.cpp @@ -9,6 +9,7 @@ #include "EditorStyleSet.h" #include "Misc/ConfigCacheIni.h" +#include "Styling/AppStyle.h" #define LOCTEXT_NAMESPACE "FlowGraphCommands" @@ -21,6 +22,7 @@ void FFlowToolbarCommands::RegisterCommands() { UI_COMMAND(RefreshAsset, "Refresh", "Refresh asset and all nodes", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(ValidateAsset, "Validate", "Validate asset and all nodes", EUserInterfaceActionType::Button, FInputChord()); + UI_COMMAND(EditAssetDefaults, "Asset Defaults", "Edit the FlowAsset default properties", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(SearchInAsset, "Search", "Search in the current Flow Graph", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Control | EModifierKey::Shift, EKeys::F)); UI_COMMAND(GoToParentInstance, "Go To Parent", "Open editor for the Flow Asset that created this Flow instance", EUserInterfaceActionType::Button, FInputChord()); diff --git a/Source/FlowEditor/Private/FlowEditorStyle.cpp b/Source/FlowEditor/Private/FlowEditorStyle.cpp index 19d331783..ddc63376b 100644 --- a/Source/FlowEditor/Private/FlowEditorStyle.cpp +++ b/Source/FlowEditor/Private/FlowEditorStyle.cpp @@ -33,7 +33,8 @@ void FFlowEditorStyle::Initialize() StyleSet->Set("FlowToolbar.RefreshAsset", new IMAGE_BRUSH_SVG( "Starship/Common/Apply", Icon20)); StyleSet->Set("FlowToolbar.ValidateAsset", new IMAGE_BRUSH_SVG( "Starship/Common/Debug", Icon20)); - + StyleSet->Set("FlowToolbar.EditAssetDefaults", new IMAGE_BRUSH_SVG("Starship/Common/Details", Icon20)); + StyleSet->Set("FlowToolbar.SearchInAsset", new IMAGE_BRUSH_SVG( "Starship/Common/Search", Icon20)); StyleSet->Set("FlowToolbar.GoToParentInstance", new IMAGE_BRUSH("Icons/icon_DebugStepOut_40x", Icon40)); diff --git a/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp b/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp index 0a9230a80..7759ef52e 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp @@ -36,7 +36,6 @@ void SFlowGraphEditor::Construct(const FArguments& InArgs, const TSharedPtrGetGraph(); Arguments._GraphEvents = InArgs._GraphEvents; Arguments._AutoExpandActionMenu = true; - Arguments._GraphEvents.OnSelectionChanged = FOnSelectionChanged::CreateSP(this, &SFlowGraphEditor::OnSelectedNodesChanged); Arguments._GraphEvents.OnNodeDoubleClicked = FSingleNodeEvent::CreateSP(this, &SFlowGraphEditor::OnNodeDoubleClicked); Arguments._GraphEvents.OnTextCommitted = FOnNodeTextCommitted::CreateSP(this, &SFlowGraphEditor::OnNodeTitleCommitted); diff --git a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h index 44645c432..96b82dddf 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h @@ -124,6 +124,8 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit virtual void RefreshAsset(); + void EditAssetDefaults_Clicked(); + private: void ValidateAsset_Internal(); diff --git a/Source/FlowEditor/Public/Asset/FlowAssetFactory.h b/Source/FlowEditor/Public/Asset/FlowAssetFactory.h index e1c3f5274..b4297672d 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetFactory.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetFactory.h @@ -15,4 +15,9 @@ class FLOWEDITOR_API UFlowAssetFactory : public UFactory virtual bool ConfigureProperties() override; virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override; + +protected: + + // Parameterized guts of ConfigureProperties() + bool ConfigurePropertiesInternal(const FText& TitleText); }; diff --git a/Source/FlowEditor/Public/FlowEditorCommands.h b/Source/FlowEditor/Public/FlowEditorCommands.h index f2c31b847..8de8bee5c 100644 --- a/Source/FlowEditor/Public/FlowEditorCommands.h +++ b/Source/FlowEditor/Public/FlowEditorCommands.h @@ -14,6 +14,7 @@ class FLOWEDITOR_API FFlowToolbarCommands : public TCommands RefreshAsset; TSharedPtr ValidateAsset; + TSharedPtr EditAssetDefaults; TSharedPtr SearchInAsset; TSharedPtr GoToParentInstance; From 46977c8e0dabe0a84782ff74b2b190a2a4dc2620 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sat, 27 May 2023 00:17:01 +0200 Subject: [PATCH 307/338] mostly cosmetic tweaks to the last pull request - removed check() as this plugin avoids it as much as possible - moved the Asset Defaults button after Diff and Search buttons, this is more consistent with a blueprint toolbar --- Source/Flow/Private/FlowAsset.cpp | 54 +++++++------------ Source/Flow/Private/FlowComponent.cpp | 6 +++ Source/Flow/Private/Nodes/FlowNode.cpp | 5 ++ .../Nodes/Route/FlowNode_CustomOutput.cpp | 26 ++++----- .../Private/Nodes/Route/FlowNode_SubGraph.cpp | 2 +- Source/Flow/Public/FlowAsset.h | 3 +- Source/Flow/Public/FlowComponent.h | 22 ++------ Source/Flow/Public/Nodes/FlowNode.h | 9 ++-- .../Private/Asset/FlowAssetEditor.cpp | 24 ++++----- .../Private/Asset/FlowAssetToolbar.cpp | 13 +++-- .../FlowEditor/Private/FlowEditorCommands.cpp | 3 +- Source/FlowEditor/Private/FlowEditorStyle.cpp | 3 +- .../FlowEditor/Public/Asset/FlowAssetEditor.h | 4 +- .../Public/Asset/FlowAssetFactory.h | 1 - Source/FlowEditor/Public/FlowEditorCommands.h | 3 +- 15 files changed, 76 insertions(+), 102 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index a579b14ed..f32ff95c5 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -207,16 +207,18 @@ void UFlowAsset::RemoveCustomInput(const FName& EventName) void UFlowAsset::AddCustomOutput(const FName& EventName) { - check(!CustomOutputs.Contains(EventName)); - - CustomOutputs.Add(EventName); + if (!CustomOutputs.Contains(EventName)) + { + CustomOutputs.Add(EventName); + } } void UFlowAsset::RemoveCustomOutput(const FName& EventName) { - check(CustomOutputs.Contains(EventName)); - - CustomOutputs.Remove(EventName); + if (CustomOutputs.Contains(EventName)) + { + CustomOutputs.Remove(EventName); + } } #endif // WITH_EDITOR @@ -239,22 +241,20 @@ UFlowNode* UFlowAsset::GetDefaultEntryNode() const for (const TPair& Node : Nodes) { - UFlowNode_Start* StartNode = Cast(Node.Value); - if (StartNode) + if (UFlowNode_Start* StartNode = Cast(Node.Value)) { if (StartNode->GetConnectedNodes().Num() > 0) { return StartNode; } - else if (!FirstStartNode) + else if (FirstStartNode == nullptr) { FirstStartNode = StartNode; } } } - // If none of the found start nodes have connections, - // fallback to the first start node we found + // If none of the found start nodes have connections, fallback to the first start node we found return FirstStartNode; } @@ -364,14 +364,11 @@ void UFlowAsset::InitializeInstance(const TWeakObjectPtr InOwner, UFlow void UFlowAsset::DeinitializeInstance() { - for (auto& KV : Nodes) + for (const TPair& Node : Nodes) { - const FGuid& Guid = KV.Key; - UFlowNode* Node = KV.Value; - - if (IsValid(Node)) + if (IsValid(Node.Value)) { - Node->DeinitializeInstance(); + Node.Value->DeinitializeInstance(); } } @@ -477,7 +474,7 @@ bool UFlowAsset::HasStartedFlow() const AActor* UFlowAsset::TryFindActorOwner() const { - UActorComponent* OwnerAsComponent = Cast(GetOwner()); + const UActorComponent* OwnerAsComponent = Cast(GetOwner()); if (IsValid(OwnerAsComponent)) { return Cast(OwnerAsComponent->GetOwner()); @@ -491,11 +488,9 @@ TWeakObjectPtr UFlowAsset::GetFlowInstance(UFlowNode_SubGraph* SubGr return ActiveSubGraphs.FindRef(SubGraphNode); } -void UFlowAsset::TriggerSubgraphCustomInput(UFlowNode_SubGraph& Node, const FName& EventName) const +void UFlowAsset::TriggerCustomInput_FromSubGraph(UFlowNode_SubGraph* Node, const FName& EventName) const { - check(HasStartedFlow()); - - const TWeakObjectPtr FlowInstance = ActiveSubGraphs.FindRef(&Node); + const TWeakObjectPtr FlowInstance = ActiveSubGraphs.FindRef(Node); if (FlowInstance.IsValid()) { FlowInstance->TriggerCustomInput(EventName); @@ -504,14 +499,11 @@ void UFlowAsset::TriggerSubgraphCustomInput(UFlowNode_SubGraph& Node, const FNam void UFlowAsset::TriggerCustomInput(const FName& EventName) { - check(HasStartedFlow()); - for (UFlowNode_CustomInput* CustomInput : CustomInputNodes) { if (CustomInput->EventName == EventName) { RecordedNodes.Add(CustomInput); - CustomInput->ExecuteInput(EventName); } } @@ -519,27 +511,21 @@ void UFlowAsset::TriggerCustomInput(const FName& EventName) void UFlowAsset::TriggerCustomOutput(const FName& EventName) { - check(HasStartedFlow()); - - const bool bIsSubgraph = NodeOwningThisAssetInstance.IsValid(); - if (bIsSubgraph) + if (NodeOwningThisAssetInstance.IsValid()) // it's a SubGraph { NodeOwningThisAssetInstance->TriggerOutput(EventName); } - else + else // it's a Root Flow, so the intention here might be to call event on the Flow Component { - // Non-subgraphs are Root instances, so call the OnTriggerCustomOutputEventDispatcher if (UFlowComponent* FlowComponent = Cast(GetOwner())) { - FlowComponent->OnTriggerRootFlowOutputEventDispatcher(*this, EventName); + FlowComponent->OnTriggerRootFlowOutputEventDispatcher(this, EventName); } } } void UFlowAsset::TriggerInput(const FGuid& NodeGuid, const FName& PinName) { - check(HasStartedFlow()); - if (UFlowNode* Node = Nodes.FindRef(NodeGuid)) { if (!ActiveNodes.Contains(Node)) diff --git a/Source/Flow/Private/FlowComponent.cpp b/Source/Flow/Private/FlowComponent.cpp index 6575e49f6..7864a6461 100644 --- a/Source/Flow/Private/FlowComponent.cpp +++ b/Source/Flow/Private/FlowComponent.cpp @@ -409,6 +409,12 @@ UFlowAsset* UFlowComponent::GetRootFlowInstance() const return nullptr; } +void UFlowComponent::OnTriggerRootFlowOutputEventDispatcher(UFlowAsset* RootFlowInstance, const FName& EventName) +{ + BP_OnTriggerRootFlowOutputEvent(RootFlowInstance, EventName); + OnTriggerRootFlowOutputEvent(RootFlowInstance, EventName); +} + void UFlowComponent::SaveRootFlow(TArray& SavedFlowInstances) { if (UFlowAsset* FlowAssetInstance = GetRootFlowInstance()) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index ff1940f63..6c279e027 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -613,6 +613,11 @@ void UFlowNode::Cleanup() K2_Cleanup(); } +void UFlowNode::DeinitializeInstance() +{ + K2_DeinitializeInstance(); +} + void UFlowNode::ForceFinishNode() { K2_ForceFinishNode(); diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp index 4fe382e5f..a8a8a96cf 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp @@ -2,7 +2,6 @@ #include "Nodes/Route/FlowNode_CustomOutput.h" #include "FlowAsset.h" -#include "FlowMessageLog.h" #include "FlowSettings.h" #define LOCTEXT_NAMESPACE "FlowNode_CustomOutput" @@ -20,19 +19,14 @@ void UFlowNode_CustomOutput::ExecuteInput(const FName& PinName) if (EventName.IsNone()) { - LogWarning( - FString::Printf( - TEXT("Attempted to trigger a CustomOutput (Node %s, Asset %s), with no EventName"), - *GetName(), - *FlowAsset->GetPathName(), - *EventName.ToString())); + LogWarning(FString::Printf(TEXT("Attempted to trigger a CustomOutput (Node %s, Asset %s), with no EventName"), + *GetName(), + *FlowAsset->GetPathName())); } else if (!FlowAsset->GetCustomOutputs().Contains(EventName)) { - const TArray& CustomOutputNames = FlowAsset->GetCustomOutputs(); - FString CustomOutputsString; - for (const FName& OutputName : CustomOutputNames) + for (const FName& OutputName : FlowAsset->GetCustomOutputs()) { if (!CustomOutputsString.IsEmpty()) { @@ -42,13 +36,11 @@ void UFlowNode_CustomOutput::ExecuteInput(const FName& PinName) CustomOutputsString += OutputName.ToString(); } - LogWarning( - FString::Printf( - TEXT("Attempted to trigger a CustomOutput (Node %s, Asset %s), with EventName %s, which is not a listed CustomOutput { %s }"), - *GetName(), - *FlowAsset->GetPathName(), - *EventName.ToString(), - *CustomOutputsString)); + LogWarning(FString::Printf(TEXT("Attempted to trigger a CustomOutput (Node %s, Asset %s), with EventName %s, which is not a listed CustomOutput { %s }"), + *GetName(), + *FlowAsset->GetPathName(), + *EventName.ToString(), + *CustomOutputsString)); } else { diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp index 6f4d5af8d..1745624f1 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp @@ -69,7 +69,7 @@ void UFlowNode_SubGraph::ExecuteInput(const FName& PinName) } else if (!PinName.IsNone()) { - GetFlowAsset()->TriggerSubgraphCustomInput(*this, PinName); + GetFlowAsset()->TriggerCustomInput_FromSubGraph(this, PinName); } } diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 859b73040..a2e1f9aed 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -310,8 +310,7 @@ class FLOW_API UFlowAsset : public UObject TWeakObjectPtr GetFlowInstance(UFlowNode_SubGraph* SubGraphNode) const; protected: - // Call TriggerCustomInput on the subgraph for Node - void TriggerSubgraphCustomInput(UFlowNode_SubGraph& Node, const FName& EventName) const; + void TriggerCustomInput_FromSubGraph(UFlowNode_SubGraph* Node, const FName& EventName) const; void TriggerCustomOutput(const FName& EventName); void TriggerInput(const FGuid& NodeGuid, const FName& PinName); diff --git a/Source/Flow/Public/FlowComponent.h b/Source/Flow/Public/FlowComponent.h index d8ff6809f..2c74fac96 100644 --- a/Source/Flow/Public/FlowComponent.h +++ b/Source/Flow/Public/FlowComponent.h @@ -210,11 +210,12 @@ class FLOW_API UFlowComponent : public UActorComponent // Called when a Root flow asset triggers a CustomOutput UFUNCTION(BlueprintImplementableEvent, DisplayName = "OnTriggerRootFlowOutputEvent") void BP_OnTriggerRootFlowOutputEvent(UFlowAsset* RootFlowInstance, const FName& EventName); - virtual void OnTriggerRootFlowOutputEvent(UFlowAsset& RootFlowInstance, const FName& EventName) { } - //~Begin UFlowAsset-only access - FORCEINLINE void OnTriggerRootFlowOutputEventDispatcher(UFlowAsset& RootFlowInstance, const FName& EventName); - //~End UFlowAsset-only access + virtual void OnTriggerRootFlowOutputEvent(UFlowAsset* RootFlowInstance, const FName& EventName) {} + + // UFlowAsset-only access + FORCEINLINE void OnTriggerRootFlowOutputEventDispatcher(UFlowAsset* RootFlowInstance, const FName& EventName); + // --- ////////////////////////////////////////////////////////////////////////// // SaveGame @@ -246,16 +247,3 @@ class FLOW_API UFlowComponent : public UActorComponent UFlowSubsystem* GetFlowSubsystem() const; bool IsFlowNetMode(const EFlowNetMode NetMode) const; }; - - -// Inline Implementations - -void UFlowComponent::OnTriggerRootFlowOutputEventDispatcher(UFlowAsset& RootFlowInstance, const FName& EventName) -{ - // Call the blueprint overrideable function - BP_OnTriggerRootFlowOutputEvent(&RootFlowInstance, EventName); - - // Call the C++ overrideable function - OnTriggerRootFlowOutputEvent(RootFlowInstance, EventName); -} - diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index f40e87a42..e46f92fe6 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -332,9 +332,12 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "Cleanup")) void K2_Cleanup(); - // Method called from UFlowAsset::DeinitializeInstance() - // (ie, when deinitializing the flow asset itself) - virtual void DeinitializeInstance() { } + // Method called from UFlowAsset::DeinitializeInstance() + virtual void DeinitializeInstance(); + + // Event called from UFlowAsset::DeinitializeInstance() + UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "DeinitializeInstance")) + void K2_DeinitializeInstance(); public: // Define what happens when node is terminated from the outside diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index 284be7214..463bd0181 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -14,23 +14,17 @@ #include "Graph/Widgets/SFlowPalette.h" #include "FlowAsset.h" -#include "Nodes/FlowNode.h" -#include "EdGraphUtilities.h" #include "EdGraph/EdGraphNode.h" #include "Editor.h" #include "GraphEditor.h" -#include "GraphEditorActions.h" -#include "HAL/PlatformApplicationMisc.h" #include "IDetailsView.h" #include "IMessageLogListing.h" #include "Kismet2/DebuggerCommands.h" -#include "LevelEditor.h" #include "MessageLogModule.h" #include "Misc/UObjectToken.h" #include "Modules/ModuleManager.h" #include "PropertyEditorModule.h" -#include "SNodePanel.h" #include "ToolMenus.h" #include "Widgets/Docking/SDockTab.h" @@ -358,16 +352,16 @@ void FFlowAssetEditor::BindToolbarCommands() FExecuteAction::CreateSP(this, &FFlowAssetEditor::ValidateAsset_Internal), FCanExecuteAction()); - ToolkitCommands->MapAction(ToolbarCommands.EditAssetDefaults, - FExecuteAction::CreateSP(this, &FFlowAssetEditor::EditAssetDefaults_Clicked), - FCanExecuteAction()); - #if ENABLE_SEARCH_IN_ASSET_EDITOR ToolkitCommands->MapAction(ToolbarCommands.SearchInAsset, FExecuteAction::CreateSP(this, &FFlowAssetEditor::SearchInAsset), FCanExecuteAction()); #endif + ToolkitCommands->MapAction(ToolbarCommands.EditAssetDefaults, + FExecuteAction::CreateSP(this, &FFlowAssetEditor::EditAssetDefaults_Clicked), + FCanExecuteAction()); + // Engine's Play commands ToolkitCommands->Append(FPlayWorldCommands::GlobalPlayWorldActions.ToSharedRef()); @@ -405,11 +399,6 @@ void FFlowAssetEditor::ValidateAsset(FFlowMessageLog& MessageLog) FlowAsset->ValidateAsset(MessageLog); } -void FFlowAssetEditor::EditAssetDefaults_Clicked() -{ - DetailsView->SetObject(FlowAsset); -} - #if ENABLE_SEARCH_IN_ASSET_EDITOR void FFlowAssetEditor::SearchInAsset() { @@ -418,6 +407,11 @@ void FFlowAssetEditor::SearchInAsset() } #endif +void FFlowAssetEditor::EditAssetDefaults_Clicked() const +{ + DetailsView->SetObject(FlowAsset); +} + void FFlowAssetEditor::GoToParentInstance() { const UFlowAsset* AssetThatInstancedThisAsset = FlowAsset->GetInspectedInstance()->GetParentInstance(); diff --git a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp index f41620195..e7f7d7fcc 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp @@ -204,18 +204,12 @@ void FFlowAssetToolbar::BuildAssetToolbar(UToolMenu* ToolbarMenu) const // add buttons Section.AddEntry(FToolMenuEntry::InitToolBarButton(FFlowToolbarCommands::Get().RefreshAsset)); Section.AddEntry(FToolMenuEntry::InitToolBarButton(FFlowToolbarCommands::Get().ValidateAsset)); - Section.AddEntry(FToolMenuEntry::InitToolBarButton(FFlowToolbarCommands::Get().EditAssetDefaults)); } -#if defined ENABLE_SEARCH_IN_ASSET_EDITOR || defined ENABLE_FLOW_DIFF { FToolMenuSection& Section = ToolbarMenu->AddSection("View"); Section.InsertPosition = FToolMenuInsert("FlowAsset", EToolMenuInsertType::After); -#if ENABLE_SEARCH_IN_ASSET_EDITOR - Section.AddEntry(FToolMenuEntry::InitToolBarButton(FFlowToolbarCommands::Get().SearchInAsset)); -#endif - #if ENABLE_FLOW_DIFF // Visual Diff: menu to choose asset revision compared with the current one Section.AddDynamicEntry("SourceControlCommands", FNewToolMenuSectionDelegate::CreateLambda([this](FToolMenuSection& InSection) @@ -233,8 +227,13 @@ void FFlowAssetToolbar::BuildAssetToolbar(UToolMenu* ToolbarMenu) const InSection.AddEntry(DiffEntry); })); #endif + +#if ENABLE_SEARCH_IN_ASSET_EDITOR + Section.AddEntry(FToolMenuEntry::InitToolBarButton(FFlowToolbarCommands::Get().SearchInAsset)); +#endif + + Section.AddEntry(FToolMenuEntry::InitToolBarButton(FFlowToolbarCommands::Get().EditAssetDefaults)); } -#endif } /** Delegate called to diff a specific revision with the current */ diff --git a/Source/FlowEditor/Private/FlowEditorCommands.cpp b/Source/FlowEditor/Private/FlowEditorCommands.cpp index 4f4823d12..17e852e34 100644 --- a/Source/FlowEditor/Private/FlowEditorCommands.cpp +++ b/Source/FlowEditor/Private/FlowEditorCommands.cpp @@ -22,9 +22,10 @@ void FFlowToolbarCommands::RegisterCommands() { UI_COMMAND(RefreshAsset, "Refresh", "Refresh asset and all nodes", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(ValidateAsset, "Validate", "Validate asset and all nodes", EUserInterfaceActionType::Button, FInputChord()); - UI_COMMAND(EditAssetDefaults, "Asset Defaults", "Edit the FlowAsset default properties", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(SearchInAsset, "Search", "Search in the current Flow Graph", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Control | EModifierKey::Shift, EKeys::F)); + UI_COMMAND(EditAssetDefaults, "Asset Defaults", "Edit the FlowAsset default properties", EUserInterfaceActionType::Button, FInputChord()); + UI_COMMAND(GoToParentInstance, "Go To Parent", "Open editor for the Flow Asset that created this Flow instance", EUserInterfaceActionType::Button, FInputChord()); } diff --git a/Source/FlowEditor/Private/FlowEditorStyle.cpp b/Source/FlowEditor/Private/FlowEditorStyle.cpp index ddc63376b..f39409450 100644 --- a/Source/FlowEditor/Private/FlowEditorStyle.cpp +++ b/Source/FlowEditor/Private/FlowEditorStyle.cpp @@ -33,9 +33,10 @@ void FFlowEditorStyle::Initialize() StyleSet->Set("FlowToolbar.RefreshAsset", new IMAGE_BRUSH_SVG( "Starship/Common/Apply", Icon20)); StyleSet->Set("FlowToolbar.ValidateAsset", new IMAGE_BRUSH_SVG( "Starship/Common/Debug", Icon20)); - StyleSet->Set("FlowToolbar.EditAssetDefaults", new IMAGE_BRUSH_SVG("Starship/Common/Details", Icon20)); StyleSet->Set("FlowToolbar.SearchInAsset", new IMAGE_BRUSH_SVG( "Starship/Common/Search", Icon20)); + StyleSet->Set("FlowToolbar.EditAssetDefaults", new IMAGE_BRUSH_SVG("Starship/Common/Details", Icon20)); + StyleSet->Set("FlowToolbar.GoToParentInstance", new IMAGE_BRUSH("Icons/icon_DebugStepOut_40x", Icon40)); StyleSet->Set("FlowGraph.BreakpointEnabled", new IMAGE_BRUSH("Old/Kismet2/Breakpoint_Valid", FVector2D(24.0f, 24.0f))); diff --git a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h index 96b82dddf..3b14d32f8 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h @@ -124,8 +124,6 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit virtual void RefreshAsset(); - void EditAssetDefaults_Clicked(); - private: void ValidateAsset_Internal(); @@ -136,6 +134,8 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit virtual void SearchInAsset(); #endif + void EditAssetDefaults_Clicked() const; + virtual void GoToParentInstance(); virtual bool CanGoToParentInstance(); diff --git a/Source/FlowEditor/Public/Asset/FlowAssetFactory.h b/Source/FlowEditor/Public/Asset/FlowAssetFactory.h index b4297672d..5e6fd011a 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetFactory.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetFactory.h @@ -17,7 +17,6 @@ class FLOWEDITOR_API UFlowAssetFactory : public UFactory virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override; protected: - // Parameterized guts of ConfigureProperties() bool ConfigurePropertiesInternal(const FText& TitleText); }; diff --git a/Source/FlowEditor/Public/FlowEditorCommands.h b/Source/FlowEditor/Public/FlowEditorCommands.h index 8de8bee5c..3612577da 100644 --- a/Source/FlowEditor/Public/FlowEditorCommands.h +++ b/Source/FlowEditor/Public/FlowEditorCommands.h @@ -14,9 +14,10 @@ class FLOWEDITOR_API FFlowToolbarCommands : public TCommands RefreshAsset; TSharedPtr ValidateAsset; - TSharedPtr EditAssetDefaults; TSharedPtr SearchInAsset; + TSharedPtr EditAssetDefaults; + TSharedPtr GoToParentInstance; virtual void RegisterCommands() override; From 0bdfccd1dba9469747602e01928cb06b7dab638f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Mon, 5 Jun 2023 19:14:36 +0200 Subject: [PATCH 308/338] exposed GetNodesInExecutionOrder() to blueprints --- Source/Flow/Private/FlowAsset.cpp | 18 ++++++++++++++++++ Source/Flow/Public/FlowAsset.h | 3 +++ 2 files changed, 21 insertions(+) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index f32ff95c5..e7a1a1a09 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -258,6 +258,24 @@ UFlowNode* UFlowAsset::GetDefaultEntryNode() const return FirstStartNode; } +TArray UFlowAsset::GetNodesInExecutionOrder(const TSubclassOf FlowNodeClass) +{ + TArray FoundNodes; + GetNodesInExecutionOrder(FoundNodes); + + // filter out nodes by class + for (int32 i = FoundNodes.Num() - 1; i >= 0; i--) + { + if (!FoundNodes[i]->GetClass()->IsChildOf(FlowNodeClass)) + { + FoundNodes.RemoveAt(i); + } + } + FoundNodes.Shrink(); + + return FoundNodes; +} + void UFlowAsset::AddInstance(UFlowAsset* Instance) { ActiveInstances.Add(Instance); diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index a2e1f9aed..ff417c168 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -150,6 +150,9 @@ class FLOW_API UFlowAsset : public UObject virtual UFlowNode* GetDefaultEntryNode() const; + UFUNCTION(BlueprintPure, Category = "FlowAsset", meta = (DeterminesOutputType = "FlowNodeClass")) + TArray GetNodesInExecutionOrder(const TSubclassOf FlowNodeClass); + template void GetNodesInExecutionOrder(TArray& OutNodes) { From c5af59a392189b51ef64505dabe15caba28e266b Mon Sep 17 00:00:00 2001 From: Guy Lundvall <47373221+Drakynfly@users.noreply.github.com> Date: Sun, 18 Jun 2023 11:04:52 -0700 Subject: [PATCH 309/338] Add class hyperlink (#161) --- .../Private/Asset/FlowAssetEditor.cpp | 25 +++++++++++++++++++ .../FlowEditor/Public/Asset/FlowAssetEditor.h | 1 + 2 files changed, 26 insertions(+) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index 463bd0181..e1b1b6aa7 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -17,6 +17,7 @@ #include "EdGraph/EdGraphNode.h" #include "Editor.h" +#include "EditorClassUtils.h" #include "GraphEditor.h" #include "IDetailsView.h" #include "IMessageLogListing.h" @@ -163,6 +164,30 @@ void FFlowAssetEditor::InitToolMenuContext(FToolMenuContext& MenuContext) MenuContext.AddObject(Context); } +void FFlowAssetEditor::PostRegenerateMenusAndToolbars() +{ + // Provide a hyperlink to view our class + const TSharedRef MenuOverlayBox = SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + .VAlign(VAlign_Center) + [ + SNew(STextBlock) + .ColorAndOpacity(FSlateColor::UseSubduedForeground()) + .ShadowOffset(FVector2D::UnitVector) + .Text(LOCTEXT("FlowAssetEditor_AssetType", "Asset Type: ")) + ] + + SHorizontalBox::Slot() + .AutoWidth() + .VAlign(VAlign_Center) + .Padding(0.0f, 0.0f, 8.0f, 0.0f) + [ + FEditorClassUtils::GetSourceLink(FlowAsset->GetClass()) + ]; + + SetMenuOverlay(MenuOverlayBox); +} + bool FFlowAssetEditor::IsTabFocused(const FTabId& TabId) const { if (const TSharedPtr CurrentGraphTab = GetToolkitHost()->GetTabManager()->FindExistingLiveTab(TabId)) diff --git a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h index 3b14d32f8..93a8c80c0 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h @@ -100,6 +100,7 @@ class FLOWEDITOR_API FFlowAssetEditor : public FAssetEditorToolkit, public FEdit // FAssetEditorToolkit virtual void InitToolMenuContext(FToolMenuContext& MenuContext) override; + virtual void PostRegenerateMenusAndToolbars() override; // -- bool IsTabFocused(const FTabId& TabId) const; From 3cea26f29b55131dd2906193c4a102605040703c Mon Sep 17 00:00:00 2001 From: twevs <77587819+twevs@users.noreply.github.com> Date: Sun, 18 Jun 2023 19:05:02 +0100 Subject: [PATCH 310/338] Added Pause and Resume input pins. (#162) --- .../Private/Nodes/World/FlowNode_PlayLevelSequence.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp index 81e0ac770..8be05bbfd 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp @@ -38,6 +38,8 @@ UFlowNode_PlayLevelSequence::UFlowNode_PlayLevelSequence(const FObjectInitialize InputPins.Empty(); InputPins.Add(FFlowPin(TEXT("Start"))); InputPins.Add(FFlowPin(TEXT("Stop"))); + InputPins.Add(FFlowPin(TEXT("Pause"))); + InputPins.Add(FFlowPin(TEXT("Resume"))); OutputPins.Add(FFlowPin(TEXT("PreStart"))); OutputPins.Add(FFlowPin(TEXT("Started"))); @@ -192,6 +194,14 @@ void UFlowNode_PlayLevelSequence::ExecuteInput(const FName& PinName) { StopPlayback(); } + else if (PinName == TEXT("Pause")) + { + SequencePlayer->Pause(); + } + else if (PinName == TEXT("Resume") && SequencePlayer->IsPaused()) + { + SequencePlayer->Play(); + } } void UFlowNode_PlayLevelSequence::OnSave_Implementation() From 4a77db95598c4524e47251b9774a0adfb1f896fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 18 Jun 2023 20:15:25 +0200 Subject: [PATCH 311/338] moved Stop input to the bottom --- Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp index 8be05bbfd..33832c2c2 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp @@ -37,9 +37,9 @@ UFlowNode_PlayLevelSequence::UFlowNode_PlayLevelSequence(const FObjectInitialize InputPins.Empty(); InputPins.Add(FFlowPin(TEXT("Start"))); - InputPins.Add(FFlowPin(TEXT("Stop"))); InputPins.Add(FFlowPin(TEXT("Pause"))); InputPins.Add(FFlowPin(TEXT("Resume"))); + InputPins.Add(FFlowPin(TEXT("Stop"))); OutputPins.Add(FFlowPin(TEXT("PreStart"))); OutputPins.Add(FFlowPin(TEXT("Started"))); From af87fc0dbba25a80c85e10e67f0d2c8efaa2eb62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 18 Jun 2023 20:57:47 +0200 Subject: [PATCH 312/338] compilation fix --- Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index e1b1b6aa7..f58e6bf0b 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -182,7 +182,7 @@ void FFlowAssetEditor::PostRegenerateMenusAndToolbars() .VAlign(VAlign_Center) .Padding(0.0f, 0.0f, 8.0f, 0.0f) [ - FEditorClassUtils::GetSourceLink(FlowAsset->GetClass()) + FEditorClassUtils::GetSourceLink(FlowAsset->GetClass(), nullptr) ]; SetMenuOverlay(MenuOverlayBox); From 5ceeb83b5e719e9fafcb09bbed8253c75107892b Mon Sep 17 00:00:00 2001 From: Eddie Ataberk <48696693+eddieataberk@users.noreply.github.com> Date: Wed, 21 Jun 2023 18:26:38 +0300 Subject: [PATCH 313/338] It makes GetConnectedNodes accesible from Blueprints (#163) --- Source/Flow/Public/Nodes/FlowNode.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index e46f92fe6..929cb7696 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -219,7 +219,9 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte void SetConnections(const TMap& InConnections) { Connections = InConnections; } FConnectedPin GetConnection(const FName OutputName) const { return Connections.FindRef(OutputName); } + UFUNCTION(BlueprintPure, Category= "FlowNode") TSet GetConnectedNodes() const; + FName GetPinConnectedToNode(const FGuid& OtherNodeGuid); UFUNCTION(BlueprintPure, Category= "FlowNode") From bb07f2691e71f8865547f43641d6f4a6d6e1d197 Mon Sep 17 00:00:00 2001 From: James Keats Date: Wed, 21 Jun 2023 11:28:34 -0400 Subject: [PATCH 314/338] Fix JumpToInnerObject not working when SearchTree provides the GraphNode itself (#164) Co-authored-by: James Keats --- Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index f58e6bf0b..5a3e8a0d6 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -539,6 +539,10 @@ void FFlowAssetEditor::JumpToInnerObject(UObject* InnerObject) { GraphEditor->JumpToNode(FlowNode->GetGraphNode(), true); } + else if (const UEdGraphNode* GraphNode = Cast(InnerObject)) + { + GraphEditor->JumpToNode(GraphNode, true); + } } #endif From 6e29b786a5b8901a09f8620ff527cbf4f7dad5d5 Mon Sep 17 00:00:00 2001 From: "Satheesh (ryanjon2040)" Date: Sat, 8 Jul 2023 21:58:45 +0530 Subject: [PATCH 315/338] Consolidate flow settings to make it easier to find (#167) --- Source/Flow/Public/FlowSettings.h | 8 ++++++++ Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h | 5 +++++ Source/FlowEditor/Public/Graph/FlowGraphSettings.h | 5 +++++ 3 files changed, 18 insertions(+) diff --git a/Source/Flow/Public/FlowSettings.h b/Source/Flow/Public/FlowSettings.h index 0dc1a772e..c59e2580c 100644 --- a/Source/Flow/Public/FlowSettings.h +++ b/Source/Flow/Public/FlowSettings.h @@ -42,4 +42,12 @@ class FLOW_API UFlowSettings : public UDeveloperSettings // by incorporating data that would otherwise go in the Description UPROPERTY(EditAnywhere, config, Category = "Nodes") bool bUseAdaptiveNodeTitles; + +public: + +#if WITH_EDITORONLY_DATA + virtual FName GetCategoryName() const override { return FName("Flow Graph"); } + virtual FText GetSectionText() const override { return INVTEXT("Settings"); } +#endif + }; diff --git a/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h b/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h index 54bd78465..481f3087a 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h @@ -53,4 +53,9 @@ class FLOWEDITOR_API UFlowGraphEditorSettings : public UDeveloperSettings UPROPERTY(EditAnywhere, config, Category = "Wires") bool bHighlightOutputWiresOfSelectedNodes; + +public: + + virtual FName GetCategoryName() const override { return FName("Flow Graph"); } + virtual FText GetSectionText() const override { return INVTEXT("Editor Settings"); } }; diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h index 13eab763b..ac9ba8862 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h @@ -106,4 +106,9 @@ class FLOWEDITOR_API UFlowGraphSettings : public UDeveloperSettings UPROPERTY(EditAnywhere, config, Category = "Wires", meta = (ClampMin = 0.0f)) float SelectedWireThickness; + +public: + + virtual FName GetCategoryName() const override { return FName("Flow Graph"); } + virtual FText GetSectionText() const override { return INVTEXT("Graph Settings"); } }; From dabb8f6244b30f4e0b7698632b9a26543a0b8f97 Mon Sep 17 00:00:00 2001 From: Jani Hartikainen Date: Sat, 8 Jul 2023 19:34:38 +0300 Subject: [PATCH 316/338] Allow Sequence nodes to execute new connections (#130) --- .../Route/FlowNode_ExecutionSequence.cpp | 38 +++++++++++++++++++ .../Nodes/Route/FlowNode_ExecutionSequence.h | 24 ++++++++++++ 2 files changed, 62 insertions(+) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionSequence.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionSequence.cpp index e7d8d1631..c76a7533e 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionSequence.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionSequence.cpp @@ -16,6 +16,12 @@ UFlowNode_ExecutionSequence::UFlowNode_ExecutionSequence(const FObjectInitialize void UFlowNode_ExecutionSequence::ExecuteInput(const FName& PinName) { + if(bSavePinExecutionState) + { + ExecuteNewConnections(); + return; + } + for (const FFlowPin& Output : OutputPins) { TriggerOutput(Output.PinName, false); @@ -23,3 +29,35 @@ void UFlowNode_ExecutionSequence::ExecuteInput(const FName& PinName) Finish(); } + +#if WITH_EDITOR +FString UFlowNode_ExecutionSequence::GetNodeDescription() const +{ + if(bSavePinExecutionState) + { + return TEXT("Saves pin execution state"); + } + + return Super::GetNodeDescription(); +} +#endif + +void UFlowNode_ExecutionSequence::OnLoad_Implementation() +{ + ExecuteNewConnections(); +} + +void UFlowNode_ExecutionSequence::ExecuteNewConnections() +{ + for (const FFlowPin& Output : OutputPins) + { + const FConnectedPin& Connection = GetConnection(Output.PinName); + if(ExecutedConnections.Contains(Connection.NodeGuid)) + { + continue; + } + + TriggerOutput(Output.PinName, false); + ExecutedConnections.Emplace(Connection.NodeGuid); + } +} diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionSequence.h b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionSequence.h index bda6e8e57..2882b917e 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionSequence.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionSequence.h @@ -15,8 +15,32 @@ class FLOW_API UFlowNode_ExecutionSequence final : public UFlowNode #if WITH_EDITOR virtual bool CanUserAddOutput() const override { return true; } + + virtual FString GetNodeDescription() const override; #endif + virtual void OnLoad_Implementation() override; + protected: virtual void ExecuteInput(const FName& PinName) override; + + /** + * If enabled and the flowgraph is saved during gameplay, this node + * tracks and saves which pins it has executed. + * + * If you add new connections or replace old connections with with + * different nodes, this node will detect the changes. If during gameplay + * you load an old save game which had different connections, this node + * will automatically execute the updated connections you created. + * + * This is useful if you want the ability to add new parts to your + * graph after release. + */ + UPROPERTY(EditAnywhere) + bool bSavePinExecutionState = false; + + UPROPERTY(SaveGame) + TSet ExecutedConnections; + + void ExecuteNewConnections(); }; From dca920f254ce94071175df82b4a42d6f4151c128 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl?= Date: Sat, 8 Jul 2023 19:10:27 +0300 Subject: [PATCH 317/338] Add validation error on FlowAsset for disallowed node classes (#165) --- Source/Flow/Private/FlowAsset.cpp | 78 +++++++++++++++++++ Source/Flow/Public/FlowAsset.h | 5 ++ .../Private/Graph/FlowGraphSchema.cpp | 59 ++------------ 3 files changed, 89 insertions(+), 53 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index e7a1a1a09..4af039564 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -16,6 +16,10 @@ #include "Serialization/MemoryReader.h" #include "Serialization/MemoryWriter.h" +#if WITH_EDITOR +FString UFlowAsset::ValidationError_NodeClassNotAllowed = TEXT("Node class {0} is not allowed in this asset."); +#endif + UFlowAsset::UFlowAsset(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) , bWorldBound(true) @@ -71,6 +75,12 @@ EDataValidationResult UFlowAsset::ValidateAsset(FFlowMessageLog& MessageLog) { if (Node.Value) { + if (!IsNodeClassAllowed(Node.Value->GetClass())) + { + const FString ErrorMsg = FString::Format(*ValidationError_NodeClassNotAllowed, {*Node.Value->GetClass()->GetName()}); + MessageLog.Error(*ErrorMsg, Node.Value); + } + Node.Value->ValidationLog.Messages.Empty(); if (Node.Value->ValidateNode() == EDataValidationResult::Invalid) { @@ -82,6 +92,74 @@ EDataValidationResult UFlowAsset::ValidateAsset(FFlowMessageLog& MessageLog) return MessageLog.Messages.Num() > 0 ? EDataValidationResult::Invalid : EDataValidationResult::Valid; } +bool UFlowAsset::IsNodeClassAllowed(const UClass* FlowNodeClass) const +{ + if (FlowNodeClass == nullptr) + { + return false; + } + + UFlowNode* NodeDefaults = FlowNodeClass->GetDefaultObject(); + + // UFlowNode class limits which UFlowAsset class can use it + { + for (const UClass* DeniedAssetClass : NodeDefaults->DeniedAssetClasses) + { + if (DeniedAssetClass && GetClass()->IsChildOf(DeniedAssetClass)) + { + return false; + } + } + + if (NodeDefaults->AllowedAssetClasses.Num() > 0) + { + bool bAllowedInAsset = false; + for (const UClass* AllowedAssetClass : NodeDefaults->AllowedAssetClasses) + { + if (AllowedAssetClass && GetClass()->IsChildOf(AllowedAssetClass)) + { + bAllowedInAsset = true; + break; + } + } + if (!bAllowedInAsset) + { + return false; + } + } + } + + // UFlowAsset class can limit which UFlowNode classes can be used + { + for (const UClass* DeniedNodeClass : DeniedNodeClasses) + { + if (DeniedNodeClass && FlowNodeClass->IsChildOf(DeniedNodeClass)) + { + return false; + } + } + + if (AllowedNodeClasses.Num() > 0) + { + bool bAllowedInAsset = false; + for (const UClass* AllowedNodeClass : AllowedNodeClasses) + { + if (AllowedNodeClass && FlowNodeClass->IsChildOf(AllowedNodeClass)) + { + bAllowedInAsset = true; + break; + } + } + if (!bAllowedInAsset) + { + return false; + } + } + } + + return true; +} + TSharedPtr UFlowAsset::FlowGraphInterface = nullptr; void UFlowAsset::SetFlowGraphInterface(TSharedPtr InFlowAssetEditor) diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index ff417c168..36904eb07 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -71,6 +71,11 @@ class FLOW_API UFlowAsset : public UObject // -- virtual EDataValidationResult ValidateAsset(FFlowMessageLog& MessageLog); + + // Returns whether the node class is allowed in this flow asset + bool IsNodeClassAllowed(const UClass* FlowNodeClass) const; + + static FString ValidationError_NodeClassNotAllowed; #endif // IFlowGraphInterface diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp index c5ac83266..5930e52e2 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -353,64 +353,17 @@ void UFlowGraphSchema::ApplyNodeFilter(const UFlowAsset* AssetClassDefaults, con return; } - UFlowNode* NodeDefaults = FlowNodeClass->GetDefaultObject(); - - // UFlowNode class limits which UFlowAsset class can use it + if (AssetClassDefaults == nullptr) { - for (const UClass* DeniedAssetClass : NodeDefaults->DeniedAssetClasses) - { - if (DeniedAssetClass && AssetClassDefaults->GetClass()->IsChildOf(DeniedAssetClass)) - { - return; - } - } - - if (NodeDefaults->AllowedAssetClasses.Num() > 0) - { - bool bAllowedInAsset = false; - for (const UClass* AllowedAssetClass : NodeDefaults->AllowedAssetClasses) - { - if (AllowedAssetClass && AssetClassDefaults->GetClass()->IsChildOf(AllowedAssetClass)) - { - bAllowedInAsset = true; - break; - } - } - if (!bAllowedInAsset) - { - return; - } - } + return; } - // UFlowAsset class can limit which UFlowNode classes can be used + if (!AssetClassDefaults->IsNodeClassAllowed(FlowNodeClass)) { - for (const UClass* DeniedNodeClass : AssetClassDefaults->DeniedNodeClasses) - { - if (DeniedNodeClass && FlowNodeClass->IsChildOf(DeniedNodeClass)) - { - return; - } - } - - if (AssetClassDefaults->AllowedNodeClasses.Num() > 0) - { - bool bAllowedInAsset = false; - for (const UClass* AllowedNodeClass : AssetClassDefaults->AllowedNodeClasses) - { - if (AllowedNodeClass && FlowNodeClass->IsChildOf(AllowedNodeClass)) - { - bAllowedInAsset = true; - break; - } - } - if (!bAllowedInAsset) - { - return; - } - } + return; } - + + UFlowNode* NodeDefaults = FlowNodeClass->GetDefaultObject(); FilteredNodes.Emplace(NodeDefaults); } From f913fe237454b740065e7e7240193aea11da72f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl?= Date: Sat, 8 Jul 2023 19:17:41 +0300 Subject: [PATCH 318/338] Add ability to restrict which flow asset classes can be used in a subgraph node class (#166) --- Source/Flow/Private/FlowAsset.cpp | 1 + .../Private/Nodes/Route/FlowNode_SubGraph.cpp | 2 + Source/Flow/Public/FlowAsset.h | 4 ++ .../Public/Nodes/Route/FlowNode_SubGraph.h | 15 +++- .../FlowNode_SubGraphDetails.cpp | 70 +++++++++++++++++++ .../FlowEditor/Private/FlowEditorModule.cpp | 3 + .../FlowNode_SubGraphDetails.h | 16 +++++ 7 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 Source/FlowEditor/Private/DetailCustomizations/FlowNode_SubGraphDetails.cpp create mode 100644 Source/FlowEditor/Public/DetailCustomizations/FlowNode_SubGraphDetails.h diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 4af039564..cb80b5359 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -27,6 +27,7 @@ UFlowAsset::UFlowAsset(const FObjectInitializer& ObjectInitializer) , FlowGraph(nullptr) #endif , AllowedNodeClasses({UFlowNode::StaticClass()}) + , AllowedInSubgraphNodeClasses({UFlowNode_SubGraph::StaticClass()}) , bStartNodePlacedAsGhostNode(false) , TemplateAsset(nullptr) , FinishPolicy(EFlowFinishPolicy::Keep) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp index 1745624f1..f82a76aeb 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp @@ -16,6 +16,8 @@ UFlowNode_SubGraph::UFlowNode_SubGraph(const FObjectInitializer& ObjectInitializ #if WITH_EDITOR Category = TEXT("Route"); NodeStyle = EFlowNodeStyle::SubGraph; + + AllowedAssignedAssetClasses = {UFlowAsset::StaticClass()}; #endif InputPins = {StartPin}; diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 36904eb07..5e419347c 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -48,6 +48,7 @@ class FLOW_API UFlowAsset : public UObject friend class UFlowSubsystem; friend class FFlowAssetDetails; + friend class FFlowNode_SubGraphDetails; friend class UFlowGraphSchema; UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Flow Asset") @@ -104,6 +105,9 @@ class FLOW_API UFlowAsset : public UObject TArray> AllowedNodeClasses; TArray> DeniedNodeClasses; + TArray> AllowedInSubgraphNodeClasses; + TArray> DeniedInSubgraphNodeClasses; + bool bStartNodePlacedAsGhostNode; private: diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h b/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h index 394e631f9..49dbcf6d1 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h @@ -14,6 +14,7 @@ class FLOW_API UFlowNode_SubGraph : public UFlowNode GENERATED_UCLASS_BODY() friend class UFlowAsset; + friend class FFlowNode_SubGraphDetails; friend class UFlowSubsystem; static FFlowPin StartPin; @@ -48,8 +49,20 @@ class FLOW_API UFlowNode_SubGraph : public UFlowNode protected: virtual void OnLoad_Implementation() override; -public: + +#if WITH_EDITORONLY_DATA +protected: + // All the classes allowed to be used as assets on this subgraph node + UPROPERTY() + TArray> AllowedAssignedAssetClasses; + + // All the classes disallowed to be used as assets on this subgraph node + UPROPERTY() + TArray> DeniedAssignedAssetClasses; +#endif + #if WITH_EDITOR +public: virtual FString GetNodeDescription() const override; virtual UObject* GetAssetToEdit() override; virtual EDataValidationResult ValidateNode() override; diff --git a/Source/FlowEditor/Private/DetailCustomizations/FlowNode_SubGraphDetails.cpp b/Source/FlowEditor/Private/DetailCustomizations/FlowNode_SubGraphDetails.cpp new file mode 100644 index 000000000..1b6cf0f3f --- /dev/null +++ b/Source/FlowEditor/Private/DetailCustomizations/FlowNode_SubGraphDetails.cpp @@ -0,0 +1,70 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#include "DetailCustomizations/FlowNode_SubGraphDetails.h" + +#include "DetailLayoutBuilder.h" +#include "FlowAsset.h" +#include "Nodes/Route/FlowNode_SubGraph.h" + +void FFlowNode_SubGraphDetails::CustomizeDetails(IDetailLayoutBuilder& DetailLayout) +{ + TArray> ObjectsBeingEdited; + DetailLayout.GetObjectsBeingCustomized(ObjectsBeingEdited); + + if (ObjectsBeingEdited[0].IsValid()) + { + const UFlowNode_SubGraph* SubGraphNode = CastChecked(ObjectsBeingEdited[0]); + + // Generate the list of asset classes allowed or disallowed + TArray FlowAssetClasses; + GetDerivedClasses(UFlowAsset::StaticClass(), FlowAssetClasses, true); + FlowAssetClasses.Add(UFlowAsset::StaticClass()); + + TArray DisallowedClasses; + TArray AllowedClasses; + for (auto FlowAssetClass : FlowAssetClasses) + { + if (const UFlowAsset* DefaultAsset = Cast(FlowAssetClass->GetDefaultObject())) + { + if (DefaultAsset->DeniedInSubgraphNodeClasses.Contains(SubGraphNode->GetClass())) + { + DisallowedClasses.Add(FlowAssetClass); + } + + if (DefaultAsset->AllowedInSubgraphNodeClasses.Contains(SubGraphNode->GetClass())) + { + AllowedClasses.Add(FlowAssetClass); + } + } + } + + DisallowedClasses.Append(SubGraphNode->DeniedAssignedAssetClasses); + + for (auto FlowAssetClass : SubGraphNode->AllowedAssignedAssetClasses) + { + if (!DisallowedClasses.Contains(FlowAssetClass)) + { + AllowedClasses.AddUnique(FlowAssetClass); + } + } + + FString AllowedClassesString; + for (UClass* Class : AllowedClasses) + { + AllowedClassesString.Append(FString::Printf(TEXT("%s,"), *Class->GetClassPathName().ToString())); + } + + FString DisallowedClassesString; + for (UClass* Class : DisallowedClasses) + { + DisallowedClassesString.Append(FString::Printf(TEXT("%s,"), *Class->GetClassPathName().ToString())); + } + + const auto AssetProperty = DetailLayout.GetProperty(FName("Asset"), UFlowNode_SubGraph::StaticClass()); + if (FProperty* MetaDataProperty = AssetProperty->GetMetaDataProperty()) + { + MetaDataProperty->SetMetaData(TEXT("AllowedClasses"), *AllowedClassesString); + MetaDataProperty->SetMetaData(TEXT("DisallowedClasses"), *DisallowedClassesString); + } + } +} diff --git a/Source/FlowEditor/Private/FlowEditorModule.cpp b/Source/FlowEditor/Private/FlowEditorModule.cpp index 65a81745c..c43d64b8a 100644 --- a/Source/FlowEditor/Private/FlowEditorModule.cpp +++ b/Source/FlowEditor/Private/FlowEditorModule.cpp @@ -24,10 +24,12 @@ #include "DetailCustomizations/FlowNode_CustomInputDetails.h" #include "DetailCustomizations/FlowNode_CustomOutputDetails.h" #include "DetailCustomizations/FlowNode_PlayLevelSequenceDetails.h" +#include "DetailCustomizations/FlowNode_SubGraphDetails.h" #include "FlowAsset.h" #include "Nodes/Route/FlowNode_CustomInput.h" #include "Nodes/Route/FlowNode_CustomOutput.h" +#include "Nodes/Route/FlowNode_SubGraph.h" #include "Nodes/World/FlowNode_ComponentObserver.h" #include "Nodes/World/FlowNode_PlayLevelSequence.h" @@ -81,6 +83,7 @@ void FFlowEditorModule::StartupModule() RegisterCustomClassLayout(UFlowNode_CustomInput::StaticClass(), FOnGetDetailCustomizationInstance::CreateStatic(&FFlowNode_CustomInputDetails::MakeInstance)); RegisterCustomClassLayout(UFlowNode_CustomOutput::StaticClass(), FOnGetDetailCustomizationInstance::CreateStatic(&FFlowNode_CustomOutputDetails::MakeInstance)); RegisterCustomClassLayout(UFlowNode_PlayLevelSequence::StaticClass(), FOnGetDetailCustomizationInstance::CreateStatic(&FFlowNode_PlayLevelSequenceDetails::MakeInstance)); + RegisterCustomClassLayout(UFlowNode_SubGraph::StaticClass(), FOnGetDetailCustomizationInstance::CreateStatic(&FFlowNode_SubGraphDetails::MakeInstance)); FPropertyEditorModule& PropertyModule = FModuleManager::GetModuleChecked("PropertyEditor"); PropertyModule.NotifyCustomizationModuleChanged(); diff --git a/Source/FlowEditor/Public/DetailCustomizations/FlowNode_SubGraphDetails.h b/Source/FlowEditor/Public/DetailCustomizations/FlowNode_SubGraphDetails.h new file mode 100644 index 000000000..323e0b8d1 --- /dev/null +++ b/Source/FlowEditor/Public/DetailCustomizations/FlowNode_SubGraphDetails.h @@ -0,0 +1,16 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#pragma once + +#include "IDetailCustomization.h" + +class FFlowNode_SubGraphDetails final : public IDetailCustomization +{ +public: + static TSharedRef MakeInstance() + { + return MakeShareable(new FFlowNode_SubGraphDetails); + } + + virtual void CustomizeDetails(IDetailLayoutBuilder& DetailLayout) override; +}; From 14342d7b65755e574e4fab2c44122615c6656c53 Mon Sep 17 00:00:00 2001 From: LindyHopperGT <91915878+LindyHopperGT@users.noreply.github.com> Date: Sat, 8 Jul 2023 09:23:09 -0700 Subject: [PATCH 319/338] Call Owner Function feature + Updated code to build in 5.1 and 5.2 #160 --- Source/Flow/Private/FlowAsset.cpp | 2 + .../Flow/Private/FlowOwnerFunctionParams.cpp | 60 +++ Source/Flow/Private/FlowOwnerFunctionRef.cpp | 87 ++++ Source/Flow/Private/FlowSettings.cpp | 18 + Source/Flow/Private/Nodes/FlowNode.cpp | 76 +++ .../World/FlowNode_CallOwnerFunction.cpp | 477 ++++++++++++++++++ .../World/FlowNode_PlayLevelSequence.cpp | 5 + Source/Flow/Public/FlowAsset.h | 14 + Source/Flow/Public/FlowComponent.h | 5 +- Source/Flow/Public/FlowOwnerFunctionParams.h | 83 +++ Source/Flow/Public/FlowOwnerFunctionRef.h | 59 +++ Source/Flow/Public/FlowOwnerInterface.h | 22 + Source/Flow/Public/FlowSettings.h | 12 +- Source/Flow/Public/Nodes/FlowNode.h | 9 + .../Nodes/World/FlowNode_CallOwnerFunction.h | 95 ++++ .../Private/Asset/FlowDiffControl.cpp | 7 +- .../FlowOwnerFunctionRefCustomization.cpp | 158 ++++++ .../FlowEditor/Private/FlowEditorModule.cpp | 97 ++-- .../Private/MovieScene/FlowTrackEditor.cpp | 6 + .../IFlowCuratedNamePropertyCustomization.cpp | 262 ++++++++++ ...IFlowExtendedPropertyTypeCustomization.cpp | 82 +++ .../FlowOwnerFunctionRefCustomization.h | 53 ++ Source/FlowEditor/Public/FlowEditorModule.h | 6 +- .../IFlowCuratedNamePropertyCustomization.h | 65 +++ .../IFlowExtendedPropertyTypeCustomization.h | 78 +++ 25 files changed, 1798 insertions(+), 40 deletions(-) create mode 100644 Source/Flow/Private/FlowOwnerFunctionParams.cpp create mode 100644 Source/Flow/Private/FlowOwnerFunctionRef.cpp create mode 100644 Source/Flow/Private/Nodes/World/FlowNode_CallOwnerFunction.cpp create mode 100644 Source/Flow/Public/FlowOwnerFunctionParams.h create mode 100644 Source/Flow/Public/FlowOwnerFunctionRef.h create mode 100644 Source/Flow/Public/FlowOwnerInterface.h create mode 100644 Source/Flow/Public/Nodes/World/FlowNode_CallOwnerFunction.h create mode 100644 Source/FlowEditor/Private/DetailCustomizations/FlowOwnerFunctionRefCustomization.cpp create mode 100644 Source/FlowEditor/Private/UnrealExtensions/IFlowCuratedNamePropertyCustomization.cpp create mode 100644 Source/FlowEditor/Private/UnrealExtensions/IFlowExtendedPropertyTypeCustomization.cpp create mode 100644 Source/FlowEditor/Public/DetailCustomizations/FlowOwnerFunctionRefCustomization.h create mode 100644 Source/FlowEditor/Public/UnrealExtensions/IFlowCuratedNamePropertyCustomization.h create mode 100644 Source/FlowEditor/Public/UnrealExtensions/IFlowExtendedPropertyTypeCustomization.h diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index cb80b5359..e9ad55237 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -36,6 +36,8 @@ UFlowAsset::UFlowAsset(const FObjectInitializer& ObjectInitializer) { AssetGuid = FGuid::NewGuid(); } + + ExpectedOwnerClass = UFlowSettings::Get()->GetDefaultExpectedOwnerClass(); } #if WITH_EDITOR diff --git a/Source/Flow/Private/FlowOwnerFunctionParams.cpp b/Source/Flow/Private/FlowOwnerFunctionParams.cpp new file mode 100644 index 000000000..5c4af749e --- /dev/null +++ b/Source/Flow/Private/FlowOwnerFunctionParams.cpp @@ -0,0 +1,60 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#include "FlowOwnerFunctionParams.h" +#include "Nodes/FlowNode.h" +#include "Nodes/World/FlowNode_CallOwnerFunction.h" + + +// UFlowOwnerFunctionParams Implementation + +UFlowOwnerFunctionParams::UFlowOwnerFunctionParams() + : Super() +{ +#if WITH_EDITOR + InputNames.Add(UFlowNode::DefaultInputPin.PinName); + OutputNames.Add(UFlowNode::DefaultOutputPin.PinName); +#endif //WITH_EDITOR +} + +void UFlowOwnerFunctionParams::PreExecute(UFlowNode_CallOwnerFunction& InSourceNode, const FName& InputPinName) +{ + SourceNode = &InSourceNode; + ExecutedInputPinName = InputPinName; + + BP_PreExecute(); +} + +void UFlowOwnerFunctionParams::PostExecute() +{ + BP_PostExecute(); + + SourceNode = nullptr; + ExecutedInputPinName = NAME_None; +} + +bool UFlowOwnerFunctionParams::ShouldFinishForOutputName_Implementation(const FName& OutputName) const +{ + // Blueprint subclasses may want to declare certain outputs as "non-finishing" + // but by default, all outputs are 'finishing' + return true; +} + +TArray UFlowOwnerFunctionParams::BP_GetInputNames() const +{ + if (IsValid(SourceNode)) + { + return SourceNode->GetInputNames(); + } + + return TArray(); +} + +TArray UFlowOwnerFunctionParams::BP_GetOutputNames() const +{ + if (IsValid(SourceNode)) + { + return SourceNode->GetOutputNames(); + } + + return TArray(); +} diff --git a/Source/Flow/Private/FlowOwnerFunctionRef.cpp b/Source/Flow/Private/FlowOwnerFunctionRef.cpp new file mode 100644 index 000000000..d49bfbf2a --- /dev/null +++ b/Source/Flow/Private/FlowOwnerFunctionRef.cpp @@ -0,0 +1,87 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#include "FlowOwnerFunctionRef.h" +#include "FlowOwnerFunctionParams.h" +#include "FlowModule.h" +#include "FlowOwnerInterface.h" + +#include "UObject/Class.h" +#include "Logging/LogMacros.h" + + +// FFlowOwnerFunctionRef Implementation + +UFunction* FFlowOwnerFunctionRef::TryResolveFunction(const UClass& InClass) +{ + if (IsConfigured()) + { + Function = InClass.FindFunctionByName(FunctionName); + } + else + { + Function = nullptr; + } + + return Function; +} + +FName FFlowOwnerFunctionRef::CallFunction(IFlowOwnerInterface& InFlowOwnerInterface, UFlowOwnerFunctionParams& InParams) const +{ + if (!IsResolved()) + { + const UObject* FlowOwnerObject = CastChecked(&InFlowOwnerInterface); + + UE_LOG( + LogFlow, + Error, + TEXT("Could not resolve function named %s with flow owner class %s"), + *FunctionName.ToString(), + *FlowOwnerObject->GetClass()->GetName()); + + return NAME_None; + } + + UObject* FlowOwnerObject = CastChecked(&InFlowOwnerInterface); + + struct FFlowOwnerFunctionRef_Parms + { + // Single FunctionParams object parameter + UFlowOwnerFunctionParams* Params; + + // Return value + FName OutputPinName; + }; + + FFlowOwnerFunctionRef_Parms Parms = { &InParams, NAME_None }; + + // Call the owner function itself + FlowOwnerObject->ProcessEvent(Function, &Parms); + + // Ensure the return value is valid + if (!Parms.OutputPinName.IsNone()) + { + const TArray OutputNames = InParams.GatherOutputNames(); + + if (!OutputNames.Contains(Parms.OutputPinName)) + { + FString OutputNamesStr = TEXT("None"); + for (const FName& OutputName : OutputNames) + { + OutputNamesStr += TEXT(", ") + OutputName.ToString(); + } + + UE_LOG( + LogFlow, + Error, + TEXT("Flow Owner Function %s returned an invalid OutputPinName '%s', which is not in the valid outputs: { %s }"), + *FunctionName.ToString(), + *Parms.OutputPinName.ToString(), + *OutputNamesStr); + + // Replace the invalid output pin name with None + Parms.OutputPinName = NAME_None; + } + } + + return Parms.OutputPinName; +} diff --git a/Source/Flow/Private/FlowSettings.cpp b/Source/Flow/Private/FlowSettings.cpp index 9c1070e4a..56fff80ce 100644 --- a/Source/Flow/Private/FlowSettings.cpp +++ b/Source/Flow/Private/FlowSettings.cpp @@ -1,6 +1,8 @@ // Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors #include "FlowSettings.h" +#include "FlowComponent.h" +#include "FlowOwnerInterface.h" UFlowSettings::UFlowSettings(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) @@ -9,5 +11,21 @@ UFlowSettings::UFlowSettings(const FObjectInitializer& ObjectInitializer) , bLogOnSignalDisabled(true) , bLogOnSignalPassthrough(true) , bUseAdaptiveNodeTitles(false) + , DefaultExpectedOwnerClass(UFlowComponent::StaticClass()) { } + +UClass* UFlowSettings::GetDefaultExpectedOwnerClass() const +{ + return CastChecked(TryResolveOrLoadSoftClass(DefaultExpectedOwnerClass), ECastCheckedType::NullAllowed); +} + +UClass* UFlowSettings::TryResolveOrLoadSoftClass(const FSoftClassPath& SoftClassPath) +{ + if (UClass* Resolved = SoftClassPath.ResolveClass()) + { + return Resolved; + } + + return SoftClassPath.TryLoadClass(); +} \ No newline at end of file diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 6c279e027..105fcb1ca 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -4,6 +4,8 @@ #include "FlowAsset.h" #include "FlowModule.h" +#include "FlowOwnerInterface.h" +#include "FlowSettings.h" #include "FlowSubsystem.h" #include "FlowTypes.h" @@ -186,6 +188,80 @@ UObject* UFlowNode::TryGetRootFlowObjectOwner() const return nullptr; } +IFlowOwnerInterface* UFlowNode::GetFlowOwnerInterface() const +{ + const UFlowAsset* FlowAsset = GetFlowAsset(); + if (!IsValid(FlowAsset)) + { + return nullptr; + } + + const UClass* ExpectedOwnerClass = FlowAsset->GetExpectedOwnerClass(); + if (!IsValid(ExpectedOwnerClass)) + { + return nullptr; + } + + UObject* RootFlowOwner = FlowAsset->GetOwner(); + if (!IsValid(RootFlowOwner)) + { + return nullptr; + } + + if (IFlowOwnerInterface* FlowOwnerInterface = TryGetFlowOwnerInterfaceFromRootFlowOwner(*RootFlowOwner, *ExpectedOwnerClass)) + { + return FlowOwnerInterface; + } + + if (IFlowOwnerInterface* FlowOwnerInterface = TryGetFlowOwnerInterfaceActor(*RootFlowOwner, *ExpectedOwnerClass)) + { + return FlowOwnerInterface; + } + + return nullptr; +} + +IFlowOwnerInterface* UFlowNode::TryGetFlowOwnerInterfaceFromRootFlowOwner(UObject& RootFlowOwner, const UClass& ExpectedOwnerClass) const +{ + const UClass* RootFlowOwnerClass = RootFlowOwner.GetClass(); + if (!IsValid(RootFlowOwnerClass)) + { + return nullptr; + } + + if (!RootFlowOwnerClass->IsChildOf(&ExpectedOwnerClass)) + { + return nullptr; + } + + // If the immediate owner is the expected class type, return its FlowOwnerInterface + return CastChecked(&RootFlowOwner); +} + +IFlowOwnerInterface* UFlowNode::TryGetFlowOwnerInterfaceActor(UObject& RootFlowOwner, const UClass& ExpectedOwnerClass) const +{ + // Special case if the immediate owner is a component, also consider the component's owning actor + const UActorComponent* FlowComponent = Cast(&RootFlowOwner); + if (!IsValid(FlowComponent)) + { + return nullptr; + } + + AActor* ActorOwner = FlowComponent->GetOwner(); + if (!IsValid(ActorOwner)) + { + return nullptr; + } + + const UClass* ActorOwnerClass = ActorOwner->GetClass(); + if (!ActorOwnerClass->IsChildOf(&ExpectedOwnerClass)) + { + return nullptr; + } + + return CastChecked(ActorOwner); +} + void UFlowNode::AddInputPins(TArray Pins) { for (const FFlowPin& Pin : Pins) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_CallOwnerFunction.cpp b/Source/Flow/Private/Nodes/World/FlowNode_CallOwnerFunction.cpp new file mode 100644 index 000000000..048d56391 --- /dev/null +++ b/Source/Flow/Private/Nodes/World/FlowNode_CallOwnerFunction.cpp @@ -0,0 +1,477 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#include "Nodes/World/FlowNode_CallOwnerFunction.h" +#include "FlowAsset.h" +#include "FlowModule.h" +#include "FlowOwnerInterface.h" +#include "FlowOwnerFunctionParams.h" +#include "FlowSettings.h" + + +#define LOCTEXT_NAMESPACE "FlowNode" + +// UFlowNode_CallOwnerFunction Implementation + +UFlowNode_CallOwnerFunction::UFlowNode_CallOwnerFunction() + : Super() +{ +#if WITH_EDITOR + NodeStyle = EFlowNodeStyle::Default; + Category = TEXT("World"); +#endif // WITH_EDITOR +} + +void UFlowNode_CallOwnerFunction::ExecuteInput(const FName& PinName) +{ + Super::ExecuteInput(PinName); + + if (!IsValid(Params)) + { + UE_LOG(LogFlow, Error, TEXT("Expected a valid Params object")); + + return; + } + + IFlowOwnerInterface* FlowOwnerInterface = GetFlowOwnerInterface(); + if (!FlowOwnerInterface) + { + UE_LOG(LogFlow, Error, TEXT("Expected an owner that implements the IFlowOwnerInterface")); + + return; + } + + UObject* FlowOwnerObject = CastChecked(FlowOwnerInterface); + UClass* FlowOwnerClass = FlowOwnerObject->GetClass(); + check(IsValid(FlowOwnerClass)); + + if (!FunctionRef.TryResolveFunction(*FlowOwnerClass)) + { + UE_LOG( + LogFlow, + Error, + TEXT("Could not resolve function named %s with flow owner class %s"), + *FunctionRef.GetFunctionName().ToString(), + *FlowOwnerClass->GetName()); + + return; + } + + Params->PreExecute(*this, PinName); + + const FName ResultOutputName = FunctionRef.CallFunction(*FlowOwnerInterface, *Params); + + Params->PostExecute(); + + (void) TryExecuteOutputPin(ResultOutputName); +} + +bool UFlowNode_CallOwnerFunction::TryExecuteOutputPin(const FName& OutputName) +{ + if (OutputName.IsNone()) + { + return false; + } + + const bool bFinish = ShouldFinishForOutputName(OutputName); + TriggerOutput(OutputName, bFinish); + + return true; +} + +bool UFlowNode_CallOwnerFunction::ShouldFinishForOutputName(const FName& OutputName) const +{ + if (ensure(IsValid(Params))) + { + return Params->ShouldFinishForOutputName(OutputName); + } + + return true; +} + +#if WITH_EDITOR + +void UFlowNode_CallOwnerFunction::PostLoad() +{ + Super::PostLoad(); + + FObjectPropertyBase* ParamsProperty = FindFProperty(GetClass(), GET_MEMBER_NAME_CHECKED(UFlowNode_CallOwnerFunction, Params)); + check(ParamsProperty); + + UClass* RequiredParamsClass = GetRequiredParamsClass(); + if (IsValid(RequiredParamsClass)) + { + // Update the property to filter for just this class (and its subclasses) + ParamsProperty->SetPropertyClass(RequiredParamsClass); + } +} + +void UFlowNode_CallOwnerFunction::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) +{ + Super::PostEditChangeProperty(PropertyChangedEvent); + + const FName MemberPropertyName = PropertyChangedEvent.MemberProperty->GetFName(); + + if (MemberPropertyName == GET_MEMBER_NAME_CHECKED(UFlowNode_CallOwnerFunction, Params)) + { + OnChangedParamsObject(); + } + + const FName PropertyName = PropertyChangedEvent.Property->GetFName(); + if (PropertyName == GET_MEMBER_NAME_CHECKED(FFlowOwnerFunctionRef, FunctionName)) + { + if (TryAllocateParamsInstance()) + { + OnChangedParamsObject(); + } + } +} + +void UFlowNode_CallOwnerFunction::OnChangedParamsObject() +{ + bool bChangedPins = false; + + if (IsValid(Params)) + { + bChangedPins = RebuildPinArray(Params->GetInputNames(), InputPins, DefaultInputPin) || bChangedPins; + bChangedPins = RebuildPinArray(Params->GetOutputNames(), OutputPins, DefaultOutputPin) || bChangedPins; + } + else + { + bChangedPins = RebuildPinArray(TArray(&DefaultInputPin.PinName, 1), InputPins, DefaultInputPin) || bChangedPins; + bChangedPins = RebuildPinArray(TArray(&DefaultOutputPin.PinName, 1), OutputPins, DefaultOutputPin) || bChangedPins; + } + + if (bChangedPins) + { + OnReconstructionRequested.ExecuteIfBound(); + } +} + +bool UFlowNode_CallOwnerFunction::RebuildPinArray(const TArray& NewPinNames, TArray& InOutPins, const FFlowPin& DefaultPin) +{ + bool bIsChanged = false; + + TArray NewPins; + + if (NewPinNames.Num() == 0) + { + bIsChanged = true; + + NewPins.Reserve(1); + + NewPins.Add(DefaultPin); + } + else + { + const bool bIsSameNum = (NewPinNames.Num() == InOutPins.Num()); + + bIsChanged = !bIsSameNum; + + NewPins.Reserve(NewPinNames.Num()); + + for (int32 NewPinIndex = 0; NewPinIndex < NewPinNames.Num(); ++NewPinIndex) + { + const FName& NewPinName = NewPinNames[NewPinIndex]; + NewPins.Add(FFlowPin(NewPinName)); + + if (bIsSameNum) + { + bIsChanged = bIsChanged || (NewPinName != InOutPins[NewPinIndex].PinName); + } + } + } + + if (bIsChanged) + { + InOutPins.Reset(); + + check(NewPins.Num() > 0); + + if (&InOutPins == &InputPins) + { + AddInputPins(NewPins); + } + else + { + checkf(&InOutPins == &OutputPins, TEXT("Only expected to be called with one or the other of the pin arrays")); + + AddOutputPins(NewPins); + } + } + + return bIsChanged; +} + +EDataValidationResult UFlowNode_CallOwnerFunction::ValidateNode() +{ + const bool bHasFunction = FunctionRef.IsConfigured(); + if (!bHasFunction) + { + ValidationLog.Error(TEXT("CallOwnerFunction requires a valid Function reference"), this); + + return EDataValidationResult::Invalid; + } + + const bool bHasParams = IsValid(Params); + if (!bHasParams) + { + ValidationLog.Error(TEXT("CallOwnerFunction requires a valid Params object"), this); + + return EDataValidationResult::Invalid; + } + + checkf(bHasParams && bHasFunction, TEXT("This should be assured by the preceding logic")); + + const UClass* ExpectedOwnerClass = TryGetExpectedOwnerClass(); + if (!IsValid(ExpectedOwnerClass)) + { + ValidationLog.Error(TEXT("Invalid or null Expected Owner Class for this Flow Asset"), this); + + return EDataValidationResult::Invalid; + } + + // Check if the function can be found on the expected owner + const UFunction* Function = FunctionRef.TryResolveFunction(*ExpectedOwnerClass); + if (!IsValid(Function)) + { + ValidationLog.Error(TEXT("Could not resolve function for flow owner"), this); + + return EDataValidationResult::Invalid; + } + + // Check the function signature + if (!DoesFunctionHaveValidFlowOwnerFunctionSignature(*Function)) + { + ValidationLog.Error(TEXT("Flow Owner Function has an invalid signature"), this); + + return EDataValidationResult::Invalid; + } + + const UClass* RequiredParamsClass = GetRequiredParamsClass(); + checkf(IsValid(RequiredParamsClass), TEXT("GetRequiredParamsClass() cannot return null if DoesFunctionHaveValidFlowOwnerFunctionSignature() is true")); + + const UClass* ExistingParamsClass = GetExistingParamsClass(); + checkf(IsValid(ExistingParamsClass), TEXT("This should be assured, if bHasParams == true")); + + // Check if the params (existing) are compatible with the function's expected (required) params + if (!ExistingParamsClass->IsChildOf(RequiredParamsClass)) + { + ValidationLog.Error(TEXT("Params object is not of the correct type for the flow owner function"), this); + + return EDataValidationResult::Invalid; + } + + return EDataValidationResult::Valid; +} + +FString UFlowNode_CallOwnerFunction::GetStatusString() const +{ + if (ActivationState != EFlowNodeState::NeverActivated) + { + return UEnum::GetDisplayValueAsText(ActivationState).ToString(); + } + + return Super::GetStatusString(); +} + +UClass* UFlowNode_CallOwnerFunction::TryGetExpectedOwnerClass() const +{ + const UFlowAsset* FlowAsset = GetFlowAsset(); + if (IsValid(FlowAsset)) + { + return FlowAsset->GetExpectedOwnerClass(); + } + + return nullptr; +} + +bool UFlowNode_CallOwnerFunction::DoesFunctionHaveValidFlowOwnerFunctionSignature(const UFunction& Function) +{ + if (GetParamsClassForFunction(Function) == nullptr) + { + return false; + } + + checkf(Function.NumParms == 2, TEXT("This should be checked in GetParamsClassForFunction()")); + + if (!DoesFunctionHaveNameReturnType(Function)) + { + return false; + } + + return true; +} + +bool UFlowNode_CallOwnerFunction::DoesFunctionHaveNameReturnType(const UFunction& Function) +{ + checkf(Function.NumParms == 2, TEXT("This should have already been checked in DoesFunctionHaveValidFlowOwnerFunctionSignature()")); + + TFieldIterator Iterator(&Function); + + while (Iterator) + { + const bool bIsOutParm = EnumHasAllFlags(Iterator->PropertyFlags, CPF_Parm | CPF_OutParm); + + return bIsOutParm; + } + + return false; +} + +UClass* UFlowNode_CallOwnerFunction::GetParamsClassForFunction(const UFunction& Function) +{ + if (Function.NumParms != 2) + { + // Flow Owner Functions expect exactly two parameters: + // - FFlowOwnerFunctionParams* + // - FName (return) + // See FFlowOwnerFunctionSignature + + return nullptr; + } + + TFieldIterator Iterator(&Function); + + while (Iterator && (Iterator->PropertyFlags & CPF_Parm)) + { + const FObjectPropertyBase* Prop = *Iterator; + check(Prop); + + UClass* PropertyClass = Prop->PropertyClass; + + if (!IsValid(PropertyClass)) + { + return nullptr; + } + + if (!PropertyClass->IsChildOf()) + { + return nullptr; + } + + return PropertyClass; + } + + return nullptr; +} + +UClass* UFlowNode_CallOwnerFunction::GetParamsClassForFunctionName(const UClass& ExpectedOwnerClass, const FName& FunctionName) +{ + const UFunction* Function = ExpectedOwnerClass.FindFunctionByName(FunctionName); + if (IsValid(Function)) + { + return GetParamsClassForFunction(*Function); + } + + return nullptr; +} + +bool UFlowNode_CallOwnerFunction::TryAllocateParamsInstance() +{ + FObjectPropertyBase* ParamsProperty = FindFProperty(GetClass(), GET_MEMBER_NAME_CHECKED(UFlowNode_CallOwnerFunction, Params)); + check(ParamsProperty); + + UClass* RequiredParamsClass = GetRequiredParamsClass(); + + if (ParamsProperty) + { + // Update the property to filter for just this class (and its subclasses) + ParamsProperty->SetPropertyClass(RequiredParamsClass); + } + + if (FunctionRef.GetFunctionName().IsNone()) + { + return false; + } + + const UClass* ExistingParamsClass = GetExistingParamsClass(); + + const bool bNeedsAllocateParams = + !IsValid(ExistingParamsClass) || + !ExistingParamsClass->IsChildOf(RequiredParamsClass); + + if (!bNeedsAllocateParams) + { + return false; + } + + // Throw out the old params object (if any) + Params = nullptr; + + // Create the new params object + Params = NewObject(this, RequiredParamsClass); + + return true; +} + +UClass* UFlowNode_CallOwnerFunction::GetRequiredParamsClass() const +{ + const UClass* ExpectedOwnerClass = TryGetExpectedOwnerClass(); + if (!IsValid(ExpectedOwnerClass)) + { + return UFlowOwnerFunctionParams::StaticClass(); + } + + const FName FunctionNameAsName = FunctionRef.GetFunctionName(); + + if (FunctionNameAsName.IsNone()) + { + return UFlowOwnerFunctionParams::StaticClass(); + } + + UClass* RequiredParamsClass = GetParamsClassForFunctionName(*ExpectedOwnerClass, FunctionNameAsName); + return RequiredParamsClass; +} + +UClass* UFlowNode_CallOwnerFunction::GetExistingParamsClass() const +{ + if (!IsValid(Params)) + { + return nullptr; + } + + UClass* ExistingParamsClass = Params->GetClass(); + return ExistingParamsClass; +} + +bool UFlowNode_CallOwnerFunction::IsAcceptableParamsPropertyClass(const UClass* ParamsClass) const +{ + if (!IsValid(ParamsClass)) + { + return false; + } + + if (!ParamsClass->IsChildOf()) + { + return false; + } + + const UClass* ExistingParamsClass = GetExistingParamsClass(); + + if (IsValid(ExistingParamsClass) && ParamsClass != ExistingParamsClass) + { + return false; + } + + return true; +} + +FText UFlowNode_CallOwnerFunction::GetNodeTitle() const +{ + const bool bUseAdaptiveNodeTitles = UFlowSettings::Get()->bUseAdaptiveNodeTitles; + + if (bUseAdaptiveNodeTitles && !FunctionRef.GetFunctionName().IsNone()) + { + const FText FunctionNameText = FText::FromName(FunctionRef.FunctionName); + + return FText::Format(LOCTEXT("CallOwnerFunction", "Call {0}"), { FunctionNameText }); + } + else + { + return Super::GetNodeTitle(); + } +} + +#endif // WITH_EDITOR + +#undef LOCTEXT_NAMESPACE diff --git a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp index 33832c2c2..d02464a90 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp @@ -5,6 +5,7 @@ #include "FlowAsset.h" #include "FlowModule.h" #include "FlowSubsystem.h" +#include "Launch/Resources/Version.h" #include "LevelSequence/FlowLevelSequencePlayer.h" #include "MovieScene/MovieSceneFlowTrack.h" #include "MovieScene/MovieSceneFlowTriggerSection.h" @@ -60,7 +61,11 @@ TArray UFlowNode_PlayLevelSequence::GetContextOutputs() Sequence = Sequence.LoadSynchronous(); if (Sequence && Sequence->GetMovieScene()) { +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION < 2 for (const UMovieSceneTrack* Track : Sequence->GetMovieScene()->GetMasterTracks()) +#else + for (const UMovieSceneTrack* Track : Sequence->GetMovieScene()->GetTracks()) +#endif { if (Track->GetClass() == UMovieSceneFlowTrack::StaticClass()) { diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 5e419347c..57467169a 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -349,9 +349,23 @@ class FLOW_API UFlowAsset : public UObject UFUNCTION(BlueprintPure, Category = "Flow") const TArray& GetRecordedNodes() const { return RecordedNodes; } +////////////////////////////////////////////////////////////////////////// +// Expected Owner Class support (for use with CallOwnerFunction nodes) + +public: + UClass* GetExpectedOwnerClass() const { return ExpectedOwnerClass; } + +protected: + // Expects to be owned (at runtime) by an object with this class (or one of its subclasses) + // NOTE - If the class is an AActor, and the flow asset is owned by a component, + // it will consider the component's owner for the AActor + UPROPERTY(EditAnywhere, meta = (MustImplement = "FlowOwnerInterface")) + TSubclassOf ExpectedOwnerClass; + ////////////////////////////////////////////////////////////////////////// // SaveGame support +public: UFUNCTION(BlueprintCallable, Category = "SaveGame") FFlowAssetSaveData SaveInstance(TArray& SavedFlowInstances); diff --git a/Source/Flow/Public/FlowComponent.h b/Source/Flow/Public/FlowComponent.h index 2c74fac96..b800c2b07 100644 --- a/Source/Flow/Public/FlowComponent.h +++ b/Source/Flow/Public/FlowComponent.h @@ -7,6 +7,7 @@ #include "FlowSave.h" #include "FlowTypes.h" +#include "FlowOwnerInterface.h" #include "FlowComponent.generated.h" class UFlowAsset; @@ -41,7 +42,7 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FFlowComponentDynamicNotify, class * Base component of Flow System - makes possible to communicate between Actor, Flow Subsystem and Flow Graphs */ UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent)) -class FLOW_API UFlowComponent : public UActorComponent +class FLOW_API UFlowComponent : public UActorComponent, public IFlowOwnerInterface { GENERATED_UCLASS_BODY() @@ -214,7 +215,7 @@ class FLOW_API UFlowComponent : public UActorComponent virtual void OnTriggerRootFlowOutputEvent(UFlowAsset* RootFlowInstance, const FName& EventName) {} // UFlowAsset-only access - FORCEINLINE void OnTriggerRootFlowOutputEventDispatcher(UFlowAsset* RootFlowInstance, const FName& EventName); + void OnTriggerRootFlowOutputEventDispatcher(UFlowAsset* RootFlowInstance, const FName& EventName); // --- ////////////////////////////////////////////////////////////////////////// diff --git a/Source/Flow/Public/FlowOwnerFunctionParams.h b/Source/Flow/Public/FlowOwnerFunctionParams.h new file mode 100644 index 000000000..f3f49797f --- /dev/null +++ b/Source/Flow/Public/FlowOwnerFunctionParams.h @@ -0,0 +1,83 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#pragma once + +#include "CoreMinimal.h" + +#include "FlowOwnerFunctionParams.generated.h" + + +// Forward Declarations +class UFlowNode_CallOwnerFunction; + + +UCLASS(BlueprintType, Blueprintable, EditInlineNew) +class FLOW_API UFlowOwnerFunctionParams : public UObject +{ + GENERATED_BODY() + +public: + + UFlowOwnerFunctionParams(); + + void PreExecute(UFlowNode_CallOwnerFunction& InSourceNode, const FName& InputPinName); + void PostExecute(); + + UFUNCTION(BlueprintNativeEvent, BlueprintPure) + bool ShouldFinishForOutputName(const FName& OutputName) const; + +#if WITH_EDITORONLY_DATA + const TArray& GetInputNames() const { return InputNames; } + const TArray& GetOutputNames() const { return OutputNames; } +#endif // WITH_EDITORONLY_DATA + + // Get the input/output pin names for the SourceNode. + // Slightly slower than the editor-only counterparts owing to the deep copy of the array. + // Valid only if called between PreExecute() and PostExecute(), inclusive + TArray GatherInputNames() const { return BP_GetInputNames(); } + TArray GatherOutputNames() const { return BP_GetOutputNames(); } + +protected: + + // Called prior to the owner executing the function described by this object. + // Can be overridden to prepare the stateful data before execution. + UFUNCTION(BlueprintImplementableEvent, DisplayName = "PreExecute") + void BP_PreExecute(); + + // Cleans up the stateful data in this Params struct. + // Can be overridden to cleanup the stateful data after execution. + UFUNCTION(BlueprintImplementableEvent, DisplayName = "PostExecute") + void BP_PostExecute(); + + // Get the input pin names for the SourceNode + // Valid only if called between PreExecute() and PostExecute(), inclusive + UFUNCTION(BlueprintCallable, BlueprintPure, DisplayName = "GetInputNames") + TArray BP_GetInputNames() const; + + // Get the output pin names for the SourceNode + // Valid only if called between PreExecute() and PostExecute(), inclusive + UFUNCTION(BlueprintCallable, BlueprintPure, DisplayName = "GetOutputNames") + TArray BP_GetOutputNames() const; + +protected: + + // CallOwnerObjectFunction node that is executing this set of function params. + // Valid only if called between PreExecute() and PostExecute(), inclusive + UPROPERTY(Transient, BlueprintReadOnly) + UFlowNode_CallOwnerFunction* SourceNode = nullptr; + + // This is the Name from the Input Pin that caused this node to Execute. + // Valid only if called between PreExecute() and PostExecute(), inclusive + UPROPERTY(Transient, BlueprintReadOnly) + FName ExecutedInputPinName; + +#if WITH_EDITORONLY_DATA + // Input pin names for this function + UPROPERTY(EditDefaultsOnly) + TArray InputNames; + + // Output pin names for this function + UPROPERTY(EditDefaultsOnly) + TArray OutputNames; +#endif // WITH_EDITORONLY_DATA +}; diff --git a/Source/Flow/Public/FlowOwnerFunctionRef.h b/Source/Flow/Public/FlowOwnerFunctionRef.h new file mode 100644 index 000000000..4e628d1ab --- /dev/null +++ b/Source/Flow/Public/FlowOwnerFunctionRef.h @@ -0,0 +1,59 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#pragma once + +#include "CoreMinimal.h" +#include "Templates/SubclassOf.h" + +#include "FlowOwnerFunctionRef.generated.h" + + +// Forward Declarations +class UFlowOwnerFunctionParams; +class IFlowOwnerInterface; + + +// Similar to FAnimNodeFunctionRef, providing a FName-based function binding +// that is resolved at runtime +USTRUCT(BlueprintType) +struct FFlowOwnerFunctionRef +{ + GENERATED_BODY() + + // For GET_MEMBER_NAME_CHECKED access + friend class UFlowNode_CallOwnerFunction; + friend class FFlowOwnerFunctionRefCustomization; + +public: + + // Resolves the function and returns the UFunction + UFunction* TryResolveFunction(const UClass& InClass); + + // Returns a the resolved function + // (assumes TryResolveFunction was called previously) + UFunction* GetResolvedFunction() const { return Function; } + + // Call the function and return the Output Pin Name result + FName CallFunction(IFlowOwnerInterface& InFlowOwnerInterface, UFlowOwnerFunctionParams& InParams) const; + + // Accessors + FName GetFunctionName() const { return FunctionName; } + bool IsConfigured() const { return !FunctionName.IsNone(); } + bool IsResolved() const { return ::IsValid(Function); } + +protected: + + // The name of the function to call + UPROPERTY(VisibleAnywhere) + FName FunctionName = NAME_None; + + // The function to call + // (resolved by looking for a function named FunctionName on the ExpectedOwnerClass) + UPROPERTY(Transient) + TObjectPtr Function = nullptr; + +#if WITH_EDITORONLY_DATA + UPROPERTY(VisibleAnywhere, meta = (DisplayName = "Function Parameters Class")) + TSubclassOf ParamsClass; +#endif // WITH_EDITORONLY_DATA +}; diff --git a/Source/Flow/Public/FlowOwnerInterface.h b/Source/Flow/Public/FlowOwnerInterface.h new file mode 100644 index 000000000..a6ad53675 --- /dev/null +++ b/Source/Flow/Public/FlowOwnerInterface.h @@ -0,0 +1,22 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#pragma once + +#include "CoreMinimal.h" + +#include "UObject/Interface.h" + +#include "FlowOwnerInterface.generated.h" + + +// (optional) interface to enable a Flow owner object to execute CallOwnerFunction nodes +UINTERFACE(MinimalAPI, Blueprintable, BlueprintType) +class UFlowOwnerInterface : public UInterface +{ + GENERATED_BODY() +}; + +class FLOW_API IFlowOwnerInterface +{ + GENERATED_BODY() +}; diff --git a/Source/Flow/Public/FlowSettings.h b/Source/Flow/Public/FlowSettings.h index c59e2580c..29bf01f13 100644 --- a/Source/Flow/Public/FlowSettings.h +++ b/Source/Flow/Public/FlowSettings.h @@ -4,6 +4,7 @@ #include "Engine/DeveloperSettings.h" #include "Templates/SubclassOf.h" +#include "UObject/SoftObjectPath.h" #include "FlowSettings.generated.h" class UFlowNode; @@ -43,11 +44,20 @@ class FLOW_API UFlowSettings : public UDeveloperSettings UPROPERTY(EditAnywhere, config, Category = "Nodes") bool bUseAdaptiveNodeTitles; + // Default class to use as a FlowAsset's "ExpectedOwnerClass" + UPROPERTY(EditAnywhere, Config, meta = (MustImplement = "FlowOwnerInterface")) + FSoftClassPath DefaultExpectedOwnerClass; + +public: + UClass* GetDefaultExpectedOwnerClass() const; + + static UClass* TryResolveOrLoadSoftClass(const FSoftClassPath& SoftClassPath); + public: #if WITH_EDITORONLY_DATA virtual FName GetCategoryName() const override { return FName("Flow Graph"); } virtual FText GetSectionText() const override { return INVTEXT("Settings"); } #endif - + }; diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 929cb7696..49a59dc5e 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -15,6 +15,7 @@ class UFlowAsset; class UFlowSubsystem; +class IFlowOwnerInterface; #if WITH_EDITOR DECLARE_DELEGATE(FFlowNodeEvent); @@ -128,8 +129,16 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte // (if the immediate parent is an UActorComponent, it will get that Component's actor) AActor* TryGetRootFlowActorOwner() const; + // Returns the IFlowOwnerInterface for the owner object (if implemented) + // NOTE - will consider a UActorComponent owner's owning actor if appropriate + IFlowOwnerInterface* GetFlowOwnerInterface() const; + protected: + // Helper functions for GetFlowOwnerInterface() + IFlowOwnerInterface* TryGetFlowOwnerInterfaceFromRootFlowOwner(UObject& RootFlowOwner, const UClass& ExpectedOwnerClass) const; + IFlowOwnerInterface* TryGetFlowOwnerInterfaceActor(UObject& RootFlowOwner, const UClass& ExpectedOwnerClass) const; + // Gets the Owning Object for this Node's RootFlow UObject* TryGetRootFlowObjectOwner() const; diff --git a/Source/Flow/Public/Nodes/World/FlowNode_CallOwnerFunction.h b/Source/Flow/Public/Nodes/World/FlowNode_CallOwnerFunction.h new file mode 100644 index 000000000..2f3302af5 --- /dev/null +++ b/Source/Flow/Public/Nodes/World/FlowNode_CallOwnerFunction.h @@ -0,0 +1,95 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#pragma once + +#include "CoreMinimal.h" + +#include "GameplayTagContainer.h" + +#include "FlowOwnerFunctionRef.h" +#include "Nodes/FlowNode.h" + +#include "FlowNode_CallOwnerFunction.generated.h" + + +// Forward Declarations +class UFlowOwnerFunctionParams; +class IFlowOwnerInterface; + + +// Example signature for valid Flow Owner Functions +typedef TFunction FFlowOwnerFunctionSignature; + + +/** + * FlowNode to call an owner function + * - Owner must implement IFlowOwnerInterface + * - Callable functions must take a single input parameter deriving from UFlowOwnerFunctionParams + * and return FName for the Output event to trigger (or "None" to trigger none of the outputs) + */ +UCLASS(NotBlueprintable, meta = (DisplayName = "Call Owner Function")) +class FLOW_API UFlowNode_CallOwnerFunction : public UFlowNode +{ + GENERATED_BODY() + +public: + +#if WITH_EDITOR + //Begin UObject + virtual void PostLoad() override; + virtual void PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) override; + //End UObject + + //Begin UFlowNode public + virtual FText GetNodeTitle() const override; + virtual EDataValidationResult ValidateNode() override; + + virtual FString GetStatusString() const override; + //End UFlowNode public +#endif // WITH_EDITOR + + UFlowNode_CallOwnerFunction(); + + UClass* GetRequiredParamsClass() const; + UClass* GetExistingParamsClass() const; + + bool IsAcceptableParamsPropertyClass(const UClass* ParamsClass) const; + + UClass* TryGetExpectedOwnerClass() const; + + static bool DoesFunctionHaveValidFlowOwnerFunctionSignature(const UFunction& Function); + + static UClass* GetParamsClassForFunctionName(const UClass& ExpectedOwnerClass, const FName& FunctionName); + static UClass* GetParamsClassForFunction(const UFunction& Function); + +protected: + +#if WITH_EDITOR + // returns true if the InOutPins array was rebuilt + bool RebuildPinArray(const TArray& NewPinNames, TArray& InOutPins, const FFlowPin& DefaultPin); + + void OnChangedParamsObject(); +#endif // WITH_EDITOR + + //Begin UFlowNode protected + virtual void ExecuteInput(const FName& PinName) override; + //End UFlowNode protected + + bool ShouldFinishForOutputName(const FName& OutputName) const; + bool TryExecuteOutputPin(const FName& OutputName); + + bool TryAllocateParamsInstance(); + + // Helper function for DoesFunctionHaveValidFlowOwnerFunctionSignature() + static bool DoesFunctionHaveNameReturnType(const UFunction& Function); + +protected: + + // Function reference on the expected owner to call + UPROPERTY(EditAnywhere, meta = (DisplayName = "Function")) + FFlowOwnerFunctionRef FunctionRef; + + // Parameter object to pass to the function when called + UPROPERTY(EditAnywhere, Instanced) + UFlowOwnerFunctionParams* Params; +}; diff --git a/Source/FlowEditor/Private/Asset/FlowDiffControl.cpp b/Source/FlowEditor/Private/Asset/FlowDiffControl.cpp index e8d9a1221..28b8ea6fc 100644 --- a/Source/FlowEditor/Private/Asset/FlowDiffControl.cpp +++ b/Source/FlowEditor/Private/Asset/FlowDiffControl.cpp @@ -14,6 +14,7 @@ #include "EdGraph/EdGraph.h" #include "GraphDiffControl.h" +#include "Launch/Resources/Version.h" #include "SBlueprintDiff.h" #define LOCTEXT_NAMESPACE "SFlowDiffControl" @@ -22,7 +23,11 @@ /// FFlowAssetDiffControl FFlowAssetDiffControl::FFlowAssetDiffControl(const UFlowAsset* InOldFlowAsset, const UFlowAsset* InNewFlowAsset, FOnDiffEntryFocused InSelectionCallback) - : TDetailsDiffControl(InOldFlowAsset, InNewFlowAsset, InSelectionCallback) +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION < 2 + : FDetailsDiffControl(InOldFlowAsset, InNewFlowAsset, InSelectionCallback) +#else + : FDetailsDiffControl(InOldFlowAsset, InNewFlowAsset, InSelectionCallback, false) +#endif { } diff --git a/Source/FlowEditor/Private/DetailCustomizations/FlowOwnerFunctionRefCustomization.cpp b/Source/FlowEditor/Private/DetailCustomizations/FlowOwnerFunctionRefCustomization.cpp new file mode 100644 index 000000000..6d48f71e4 --- /dev/null +++ b/Source/FlowEditor/Private/DetailCustomizations/FlowOwnerFunctionRefCustomization.cpp @@ -0,0 +1,158 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#include "DetailCustomizations/FlowOwnerFunctionRefCustomization.h" + +#include "FlowAsset.h" +#include "FlowOwnerInterface.h" +#include "Nodes/FlowNode.h" +#include "Nodes/World/FlowNode_CallOwnerFunction.h" + +#include "UObject/UnrealType.h" +#include "FlowOwnerFunctionParams.h" + + +// FFlowOwnerFunctionRefCustomization Implementation + +void FFlowOwnerFunctionRefCustomization::CustomizeChildren(TSharedRef InStructPropertyHandle, IDetailChildrenBuilder& StructBuilder, IPropertyTypeCustomizationUtils& StructCustomizationUtils) +{ + // Do not include children properties (the header is all we need to show for this struct) +} + +TSharedPtr FFlowOwnerFunctionRefCustomization::GetCuratedNamePropertyHandle() const +{ + check(StructPropertyHandle->IsValidHandle()); + + TSharedPtr FoundHandle = StructPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FFlowOwnerFunctionRef, FunctionName)); + check(FoundHandle); + + return FoundHandle; +} + +TArray FFlowOwnerFunctionRefCustomization::GetCuratedNameOptions() const +{ + TArray Results; + + const UClass* ExpectedOwnerClass = TryGetExpectedOwnerClass(); + if (!IsValid(ExpectedOwnerClass)) + { + return Results; + } + + const UFlowNode_CallOwnerFunction* FlowNodeOwner = Cast(TryGetFlowNodeOuter()); + if (!IsValid(FlowNodeOwner)) + { + return Results; + } + + Results = GetFlowOwnerFunctionRefs(*FlowNodeOwner, *ExpectedOwnerClass); + + return Results; +} + +const UClass* FFlowOwnerFunctionRefCustomization::TryGetExpectedOwnerClass() const +{ + const UFlowNode* NodeOwner = TryGetFlowNodeOuter(); + const UFlowNode_CallOwnerFunction* CallOwnerFunctionNode = Cast(NodeOwner); + + if (IsValid(CallOwnerFunctionNode)) + { + return CallOwnerFunctionNode->TryGetExpectedOwnerClass(); + } + + return nullptr; +} + +TArray FFlowOwnerFunctionRefCustomization::GetFlowOwnerFunctionRefs( + const UFlowNode_CallOwnerFunction& FlowNodeOwner, + const UClass& ExpectedOwnerClass) +{ + TArray ValidFunctionNames; + + // Gather a list of potential functions + TArray PotentialFunctionNames; + ExpectedOwnerClass.GenerateFunctionList(PotentialFunctionNames); + + if (PotentialFunctionNames.Num() == 0) + { + return ValidFunctionNames; + } + + ValidFunctionNames.Reserve(PotentialFunctionNames.Num()); + + // Filter out any unusable functions (that do not match the expected signature) + for (const FName& PotentialFunctionName : PotentialFunctionNames) + { + const UFunction* PotentialFunction = ExpectedOwnerClass.FindFunctionByName(PotentialFunctionName); + check(IsValid(PotentialFunction)); + + if (IsFunctionUsable(*PotentialFunction, FlowNodeOwner)) + { + ValidFunctionNames.Add(PotentialFunctionName); + } + } + + return ValidFunctionNames; +} + +bool FFlowOwnerFunctionRefCustomization::IsFunctionUsable(const UFunction& Function, const UFlowNode_CallOwnerFunction& FlowNodeOwner) +{ + if (!UFlowNode_CallOwnerFunction::DoesFunctionHaveValidFlowOwnerFunctionSignature(Function)) + { + return false; + } + + if (!DoesFunctionHaveExpectedParamType(Function, FlowNodeOwner)) + { + return false; + } + + return true; +} + +bool FFlowOwnerFunctionRefCustomization::DoesFunctionHaveExpectedParamType(const UFunction& Function, const UFlowNode_CallOwnerFunction& FlowNodeOwner) +{ + const UClass* PropertyClass = UFlowNode_CallOwnerFunction::GetParamsClassForFunction(Function); + + return FlowNodeOwner.IsAcceptableParamsPropertyClass(PropertyClass); +} + +void FFlowOwnerFunctionRefCustomization::SetCuratedName(const FName& NewFunctionName) +{ + TSharedPtr FunctionNameHandle = StructPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FFlowOwnerFunctionRef, FunctionName)); + + check(FunctionNameHandle); + + FunctionNameHandle->SetPerObjectValue(0, NewFunctionName.ToString()); +} + +FName FFlowOwnerFunctionRefCustomization::GetCuratedName() const +{ + const FFlowOwnerFunctionRef* FlowOwnerFunction = GetFlowOwnerFunctionRef(); + if (FlowOwnerFunction) + { + return FlowOwnerFunction->FunctionName; + } + else + { + return NAME_None; + } +} + +UFlowNode* FFlowOwnerFunctionRefCustomization::TryGetFlowNodeOuter() const +{ + check(StructPropertyHandle->IsValidHandle()); + + TArray OuterObjects; + StructPropertyHandle->GetOuterObjects(OuterObjects); + + for (UObject* OuterObject : OuterObjects) + { + UFlowNode* FlowNodeOuter = Cast(OuterObject); + if (IsValid(FlowNodeOuter)) + { + return FlowNodeOuter; + } + } + + return nullptr; +} diff --git a/Source/FlowEditor/Private/FlowEditorModule.cpp b/Source/FlowEditor/Private/FlowEditorModule.cpp index c43d64b8a..a3382ffcb 100644 --- a/Source/FlowEditor/Private/FlowEditorModule.cpp +++ b/Source/FlowEditor/Private/FlowEditorModule.cpp @@ -24,6 +24,7 @@ #include "DetailCustomizations/FlowNode_CustomInputDetails.h" #include "DetailCustomizations/FlowNode_CustomOutputDetails.h" #include "DetailCustomizations/FlowNode_PlayLevelSequenceDetails.h" +#include "DetailCustomizations/FlowOwnerFunctionRefCustomization.h" #include "DetailCustomizations/FlowNode_SubGraphDetails.h" #include "FlowAsset.h" @@ -74,19 +75,7 @@ void FFlowEditorModule::StartupModule() ISequencerModule& SequencerModule = FModuleManager::Get().LoadModuleChecked("Sequencer"); FlowTrackCreateEditorHandle = SequencerModule.RegisterTrackEditor(FOnCreateTrackEditor::CreateStatic(&FFlowTrackEditor::CreateTrackEditor)); - RegisterPropertyCustomizations(); - - // register detail customizations - RegisterCustomClassLayout(UFlowAsset::StaticClass(), FOnGetDetailCustomizationInstance::CreateStatic(&FFlowAssetDetails::MakeInstance)); - RegisterCustomClassLayout(UFlowNode::StaticClass(), FOnGetDetailCustomizationInstance::CreateStatic(&FFlowNode_Details::MakeInstance)); - RegisterCustomClassLayout(UFlowNode_ComponentObserver::StaticClass(), FOnGetDetailCustomizationInstance::CreateStatic(&FFlowNode_ComponentObserverDetails::MakeInstance)); - RegisterCustomClassLayout(UFlowNode_CustomInput::StaticClass(), FOnGetDetailCustomizationInstance::CreateStatic(&FFlowNode_CustomInputDetails::MakeInstance)); - RegisterCustomClassLayout(UFlowNode_CustomOutput::StaticClass(), FOnGetDetailCustomizationInstance::CreateStatic(&FFlowNode_CustomOutputDetails::MakeInstance)); - RegisterCustomClassLayout(UFlowNode_PlayLevelSequence::StaticClass(), FOnGetDetailCustomizationInstance::CreateStatic(&FFlowNode_PlayLevelSequenceDetails::MakeInstance)); - RegisterCustomClassLayout(UFlowNode_SubGraph::StaticClass(), FOnGetDetailCustomizationInstance::CreateStatic(&FFlowNode_SubGraphDetails::MakeInstance)); - - FPropertyEditorModule& PropertyModule = FModuleManager::GetModuleChecked("PropertyEditor"); - PropertyModule.NotifyCustomizationModuleChanged(); + RegisterDetailCustomizations(); // register asset indexers if (FModuleManager::Get().IsModuleLoaded(AssetSearchModuleName)) @@ -100,26 +89,14 @@ void FFlowEditorModule::ShutdownModule() { FFlowEditorStyle::Shutdown(); + UnregisterDetailCustomizations(); + UnregisterAssets(); // unregister track editors ISequencerModule& SequencerModule = FModuleManager::Get().LoadModuleChecked("Sequencer"); SequencerModule.UnRegisterTrackEditor(FlowTrackCreateEditorHandle); - // unregister details customizations - if (FModuleManager::Get().IsModuleLoaded("PropertyEditor")) - { - FPropertyEditorModule& PropertyModule = FModuleManager::GetModuleChecked("PropertyEditor"); - - for (auto It = CustomClassLayouts.CreateConstIterator(); It; ++It) - { - if (It->IsValid()) - { - PropertyModule.UnregisterCustomClassLayout(*It); - } - } - } - FModuleManager::Get().OnModulesChanged().Remove(ModulesChangedHandle); } @@ -175,22 +152,72 @@ void FFlowEditorModule::UnregisterAssets() RegisteredAssetActions.Empty(); } -void FFlowEditorModule::RegisterPropertyCustomizations() const +void FFlowEditorModule::RegisterCustomClassLayout(const TSubclassOf Class, const FOnGetDetailCustomizationInstance DetailLayout) { - FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked("PropertyEditor"); + if (Class) + { + FPropertyEditorModule& PropertyModule = FModuleManager::GetModuleChecked("PropertyEditor"); + PropertyModule.RegisterCustomClassLayout(Class->GetFName(), DetailLayout); - // notify on customization change - PropertyModule.NotifyCustomizationModuleChanged(); + CustomClassLayouts.Add(Class->GetFName()); + } } -void FFlowEditorModule::RegisterCustomClassLayout(const TSubclassOf Class, const FOnGetDetailCustomizationInstance DetailLayout) +void FFlowEditorModule::RegisterCustomStructLayout(const UScriptStruct& Struct, const FOnGetPropertyTypeCustomizationInstance DetailLayout) { - if (Class) + if (FModuleManager::Get().IsModuleLoaded("PropertyEditor")) { - CustomClassLayouts.Add(Class->GetFName()); + FPropertyEditorModule& PropertyModule = FModuleManager::GetModuleChecked("PropertyEditor"); + PropertyModule.RegisterCustomPropertyTypeLayout(Struct.GetFName(), DetailLayout); + CustomStructLayouts.Add(Struct.GetFName()); + } +} + +void FFlowEditorModule::RegisterDetailCustomizations() +{ + // register detail customizations + if (FModuleManager::Get().IsModuleLoaded("PropertyEditor")) + { FPropertyEditorModule& PropertyModule = FModuleManager::GetModuleChecked("PropertyEditor"); - PropertyModule.RegisterCustomClassLayout(Class->GetFName(), DetailLayout); + + RegisterCustomClassLayout(UFlowAsset::StaticClass(), FOnGetDetailCustomizationInstance::CreateStatic(&FFlowAssetDetails::MakeInstance)); + RegisterCustomClassLayout(UFlowNode::StaticClass(), FOnGetDetailCustomizationInstance::CreateStatic(&FFlowNode_Details::MakeInstance)); + RegisterCustomClassLayout(UFlowNode_ComponentObserver::StaticClass(), FOnGetDetailCustomizationInstance::CreateStatic(&FFlowNode_ComponentObserverDetails::MakeInstance)); + RegisterCustomClassLayout(UFlowNode_CustomInput::StaticClass(), FOnGetDetailCustomizationInstance::CreateStatic(&FFlowNode_CustomInputDetails::MakeInstance)); + RegisterCustomClassLayout(UFlowNode_CustomOutput::StaticClass(), FOnGetDetailCustomizationInstance::CreateStatic(&FFlowNode_CustomOutputDetails::MakeInstance)); + RegisterCustomClassLayout(UFlowNode_PlayLevelSequence::StaticClass(), FOnGetDetailCustomizationInstance::CreateStatic(&FFlowNode_PlayLevelSequenceDetails::MakeInstance)); + RegisterCustomClassLayout(UFlowNode_SubGraph::StaticClass(), FOnGetDetailCustomizationInstance::CreateStatic(&FFlowNode_SubGraphDetails::MakeInstance)); + RegisterCustomStructLayout(*FFlowOwnerFunctionRef::StaticStruct(), FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FFlowOwnerFunctionRefCustomization::MakeInstance)); + + PropertyModule.NotifyCustomizationModuleChanged(); + } +} + +void FFlowEditorModule::UnregisterDetailCustomizations() +{ + // unregister details customizations + if (FModuleManager::Get().IsModuleLoaded("PropertyEditor")) + { + FPropertyEditorModule& PropertyModule = FModuleManager::GetModuleChecked("PropertyEditor"); + + for (auto It = CustomClassLayouts.CreateConstIterator(); It; ++It) + { + if (It->IsValid()) + { + PropertyModule.UnregisterCustomClassLayout(*It); + } + } + + for (auto It = CustomStructLayouts.CreateConstIterator(); It; ++It) + { + if (It->IsValid()) + { + PropertyModule.UnregisterCustomPropertyTypeLayout(*It); + } + } + + PropertyModule.NotifyCustomizationModuleChanged(); } } diff --git a/Source/FlowEditor/Private/MovieScene/FlowTrackEditor.cpp b/Source/FlowEditor/Private/MovieScene/FlowTrackEditor.cpp index f0e908683..c540d503b 100644 --- a/Source/FlowEditor/Private/MovieScene/FlowTrackEditor.cpp +++ b/Source/FlowEditor/Private/MovieScene/FlowTrackEditor.cpp @@ -9,6 +9,7 @@ #include "Framework/MultiBox/MultiBoxBuilder.h" #include "ISequencerSection.h" +#include "Launch/Resources/Version.h" #include "LevelSequence.h" #include "MovieSceneSequenceEditor.h" #include "Sections/MovieSceneEventSection.h" @@ -163,7 +164,12 @@ void FFlowTrackEditor::HandleAddFlowTrackMenuEntryExecute(UClass* SectionType) c TArray NewTracks; +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION < 2 UMovieSceneFlowTrack* NewMasterTrack = FocusedMovieScene->AddMasterTrack(); +#else + UMovieSceneFlowTrack* NewMasterTrack = FocusedMovieScene->AddTrack(); +#endif + NewTracks.Add(NewMasterTrack); if (GetSequencer().IsValid()) { diff --git a/Source/FlowEditor/Private/UnrealExtensions/IFlowCuratedNamePropertyCustomization.cpp b/Source/FlowEditor/Private/UnrealExtensions/IFlowCuratedNamePropertyCustomization.cpp new file mode 100644 index 000000000..30d9da6cc --- /dev/null +++ b/Source/FlowEditor/Private/UnrealExtensions/IFlowCuratedNamePropertyCustomization.cpp @@ -0,0 +1,262 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +// NOTE (gtaylor) This class is planned for submission to Epic to include in baseline UE. +// If/when that happens, we will want to remove this version and update to the latest one in the PropertyModule + +#include "UnrealExtensions/IFlowCuratedNamePropertyCustomization.h" + +#include "DetailLayoutBuilder.h" +#include "DetailWidgetRow.h" +#include "EditorClassUtils.h" +#include "IDetailPropertyRow.h" +#include "IDetailChildrenBuilder.h" +#include "Internationalization/Text.h" +#include "PropertyHandle.h" +#include "Widgets/Input/SComboBox.h" +#include "Widgets/Text/STextBlock.h" + + +// IFlowCuratedNamePropertyCustomization Implementation + +TSharedPtr IFlowCuratedNamePropertyCustomization::NoneAsText = nullptr; + +void IFlowCuratedNamePropertyCustomization::Initialize() +{ + // Cache off "None" as a sharable FText, for use later + if (!NoneAsText.IsValid()) + { + NoneAsText = MakeShared(FText::FromName(NAME_None)); + } + + // Cache the Name property handle + check(StructPropertyHandle.IsValid()); + CachedNameHandle = GetCuratedNamePropertyHandle(); + check(CachedNameHandle->IsValidHandle()); + + // Initial setup the CachedTextSelected and CachedTextList + // (via SetCuratedNameWithSideEffects) + check(!CachedTextSelected.IsValid()); + check(CachedTextList.IsEmpty()); + + const FName CuratedName = GetCuratedName(); + const bool bChangedValue = TrySetCuratedNameWithSideEffects(CuratedName); + + check(bChangedValue); + check(CachedTextSelected.IsValid()); + check(CachedTextList.Num() == 1); +} + +void IFlowCuratedNamePropertyCustomization::CreateHeaderRowWidget(FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils & StructCustomizationUtils) +{ + // Do one-time setup first + Initialize(); + + // Replace the default HeaderRow widget with one of our own + HeaderRow + .NameContent() + [ + SAssignNew(HeaderTextBlock, STextBlock) + .Text(BuildHeaderText()) + ] + .ValueContent() + .MaxDesiredWidth(250.0f) + [ + SAssignNew(TextListWidget, SComboBox>) + .OptionsSource(&CachedTextList) + .OnGenerateWidget(this, &IFlowCuratedNamePropertyCustomization::GenerateTextListWidget) + .OnComboBoxOpening(this, &IFlowCuratedNamePropertyCustomization::OnTextListComboBoxOpening) + .OnSelectionChanged(this, &IFlowCuratedNamePropertyCustomization::OnTextSelected) + [ + SNew(STextBlock) + .Text(this, &IFlowCuratedNamePropertyCustomization::GetCachedText) + .Font(IDetailLayoutBuilder::GetDetailFont()) + .ToolTipText(this, &IFlowCuratedNamePropertyCustomization::GetCachedText) + ] + ]; + + // Hook-up the ResetToDefault overrides + FIsResetToDefaultVisible IsResetVisible = + FIsResetToDefaultVisible::CreateSP( + this, + &IFlowCuratedNamePropertyCustomization::CustomIsResetToDefaultVisible); + FResetToDefaultHandler ResetHandler = + FResetToDefaultHandler::CreateSP( + this, + &IFlowCuratedNamePropertyCustomization::CustomResetToDefault); + FResetToDefaultOverride ResetOverride = FResetToDefaultOverride::Create(IsResetVisible, ResetHandler); + + HeaderRow.OverrideResetToDefault(ResetOverride); +} + +bool IFlowCuratedNamePropertyCustomization::CustomIsResetToDefaultVisible(TSharedPtr Property) const +{ + const FName CuratedName = GetCuratedName(); + return !CuratedName.IsNone(); +} + +void IFlowCuratedNamePropertyCustomization::CustomResetToDefault(TSharedPtr Property) +{ + if (TrySetCuratedNameWithSideEffects(NAME_None)) + { + RepaintTextListWidget(); + } +} + +bool IFlowCuratedNamePropertyCustomization::TrySetCuratedNameWithSideEffects(const FName& NewName) +{ + const FName ExistingName = GetCuratedName(); + + if (ExistingName != NewName) + { + // Set the new name on the actual struct first + SetCuratedName(NewName); + } + + // Ensure the FText representations are up to date + + TSharedPtr NewText = FindCachedOrCreateText(NewName); + + const bool bIsChanged = (NewText != CachedTextSelected); + + CachedTextSelected = NewText; + + InsertAtHeadOfCachedTextList(CachedTextSelected); + + // Set the Name property to the new value + check(CachedNameHandle.IsValid()); + CachedNameHandle->SetValue(NewName); + + return bIsChanged; +} + +FText IFlowCuratedNamePropertyCustomization::GetCachedText() const +{ + check(CachedTextSelected.IsValid()); + + return *CachedTextSelected.Get(); +} + +TSharedRef IFlowCuratedNamePropertyCustomization::GenerateTextListWidget(TSharedPtr InItem) +{ + return + SNew(STextBlock) + .Text(*InItem) + .ColorAndOpacity(FSlateColor::UseForeground()) + .Font(IDetailLayoutBuilder::GetDetailFont()); +} + +void IFlowCuratedNamePropertyCustomization::OnTextListComboBoxOpening() +{ + check(CachedTextSelected.IsValid()); + + // Create a dictionary of Names to their shared FTexts + // (to preserve the shared FText objects, if they already exist) + TMap> MapNameToText; + + const FName CurrentName = GetCuratedName(); + MapNameToText.Add(CurrentName, CachedTextSelected); + + for (TSharedPtr& Text : CachedTextList) + { + (void) MapNameToText.FindOrAdd(FName(Text.Get()->ToString()), Text); + } + + TArray CuratedNameOptions = GetCuratedNameOptions(); + + // (+2 to reserve space for the Selected and None entry) + CachedTextList.Empty(CuratedNameOptions.Num() + 2); + + // Populate the current selection at the top of the list + if (CuratedNameOptions.Contains(CurrentName) || CurrentName.IsNone()) + { + CachedTextList.Add(CachedTextSelected); + } + + // Populate the other curated name options + for (const FName& NameOption : CuratedNameOptions) + { + if (!NameOption.IsNone() && NameOption != CurrentName) + { + AddToCachedTextList(FindCachedOrCreateText(NameOption)); + } + } + + // Ensure "None" is in the list (if CurrentName is not None) + if (!CurrentName.IsNone()) + { + check(!CachedTextList.Contains(NoneAsText)); + + CachedTextList.Add(NoneAsText); + } +} + +void IFlowCuratedNamePropertyCustomization::OnTextSelected(TSharedPtr NewSelection, ESelectInfo::Type SelectInfo) +{ + // Called when the combo box has selected a new element + + // Process NewSelection and derive the matching Name + // (NewSelection can be null) + + FName NewName; + + if (NewSelection.IsValid()) + { + // Ensure NewSelection is in the CachedTextList + AddToCachedTextList(NewSelection); + + NewName = FName(NewSelection->ToString()); + } + else + { + NewName = NAME_None; + } + + if (TrySetCuratedNameWithSideEffects(NewName)) + { + RepaintTextListWidget(); + } +} + +TSharedPtr IFlowCuratedNamePropertyCustomization::FindCachedOrCreateText(const FName& NewName) +{ + if (NewName.IsNone()) + { + return NoneAsText; + } + + const FText NewText = FText::FromName(NewName); + + for (int32 Index = 0; Index < CachedTextList.Num(); ++Index) + { + const TSharedPtr& TextCur = CachedTextList[Index]; + + if (TextCur->EqualTo(NewText, ETextComparisonLevel::Default)) + { + return TextCur; + } + } + + TSharedPtr Result = MakeShareable(new FText(NewText)); + return Result; +} + +void IFlowCuratedNamePropertyCustomization::InsertAtHeadOfCachedTextList(TSharedPtr Text) +{ + CachedTextList.Remove(Text); + + CachedTextList.Insert(Text, 0); +} + +void IFlowCuratedNamePropertyCustomization::AddToCachedTextList(TSharedPtr Text) +{ + CachedTextList.AddUnique(Text); +} + +void IFlowCuratedNamePropertyCustomization::RepaintTextListWidget() +{ + if (TextListWidget.IsValid()) + { + // Prod UDE to refresh the widget to show the new change + TextListWidget->Invalidate(EInvalidateWidgetReason::Paint); + } +} diff --git a/Source/FlowEditor/Private/UnrealExtensions/IFlowExtendedPropertyTypeCustomization.cpp b/Source/FlowEditor/Private/UnrealExtensions/IFlowExtendedPropertyTypeCustomization.cpp new file mode 100644 index 000000000..033a27179 --- /dev/null +++ b/Source/FlowEditor/Private/UnrealExtensions/IFlowExtendedPropertyTypeCustomization.cpp @@ -0,0 +1,82 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +// NOTE (gtaylor) This class is planned for submission to Epic to include in baseline UE. +// If/when that happens, we will want to remove this version and update to the latest one in the PropertyModule + +#include "UnrealExtensions/IFlowExtendedPropertyTypeCustomization.h" + +#include "DetailWidgetRow.h" +#include "IDetailChildrenBuilder.h" +#include "IDetailPropertyRow.h" +#include "Widgets/Text/STextBlock.h" + + +// IFlowExtendedPropertyTypeCustomization Implementation + +void IFlowExtendedPropertyTypeCustomization::CustomizeHeader(TSharedRef InStructPropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils) +{ + StructPropertyHandle = InStructPropertyHandle; + + // Connect our property callback to any of the children properties changing + uint32 NumChildren; + StructPropertyHandle->GetNumChildren(NumChildren); + + for (uint32 ChildIndex = 0; ChildIndex < NumChildren; ++ChildIndex) + { + const TSharedRef ChildHandle = StructPropertyHandle->GetChildHandle(ChildIndex).ToSharedRef(); + + ChildHandle->SetOnPropertyValueChanged( + FSimpleDelegate::CreateSP(this, &IFlowExtendedPropertyTypeCustomization::OnAnyChildPropertyChanged)); + } + + CreateHeaderRowWidget(HeaderRow, StructCustomizationUtils); +} + +void IFlowExtendedPropertyTypeCustomization::CustomizeChildrenDefaultImpl(TSharedRef PropertyHandle, IDetailChildrenBuilder& StructBuilder, IPropertyTypeCustomizationUtils& StructCustomizationUtils) +{ + // A 'default' implementation of CustomizeChildren + + uint32 NumChildren = 0; + PropertyHandle->GetNumChildren(NumChildren); + + for (uint32 ChildNum = 0; ChildNum < NumChildren; ++ChildNum) + { + StructBuilder.AddProperty(PropertyHandle->GetChildHandle(ChildNum).ToSharedRef()); + } +} + +void IFlowExtendedPropertyTypeCustomization::CreateHeaderRowWidget(FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils) +{ + // Build the Slate widget for the header row + HeaderRow + .NameContent() + [ + SAssignNew(HeaderTextBlock, STextBlock) + .Text(BuildHeaderText()) + ]; +} + +void IFlowExtendedPropertyTypeCustomization::OnAnyChildPropertyChanged() +{ + RefreshHeader(); +} + +void IFlowExtendedPropertyTypeCustomization::RefreshHeader() const +{ + if (HeaderTextBlock.IsValid() && StructPropertyHandle.IsValid()) + { + HeaderTextBlock->SetText(BuildHeaderText()); + } +} + +FText IFlowExtendedPropertyTypeCustomization::BuildHeaderText() const +{ + if (StructPropertyHandle.IsValid()) + { + return StructPropertyHandle->GetPropertyDisplayName(); + } + else + { + return FText(); + } +} diff --git a/Source/FlowEditor/Public/DetailCustomizations/FlowOwnerFunctionRefCustomization.h b/Source/FlowEditor/Public/DetailCustomizations/FlowOwnerFunctionRefCustomization.h new file mode 100644 index 000000000..d3cb3f2a2 --- /dev/null +++ b/Source/FlowEditor/Public/DetailCustomizations/FlowOwnerFunctionRefCustomization.h @@ -0,0 +1,53 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +#pragma once + +#include "UnrealExtensions/IFlowCuratedNamePropertyCustomization.h" + +#include "FlowOwnerFunctionRef.h" + + +// Forward Declaration +class UFlowAsset; +class UFlowNode; +class UObject; +class UClass; +class UFunction; +class UFlowNode_CallOwnerFunction; + + +// Details customization for FFlowOwnerFunctionRef +class FFlowOwnerFunctionRefCustomization : public IFlowCuratedNamePropertyCustomization +{ +private: + typedef IFlowCuratedNamePropertyCustomization Super; + +public: + static TSharedRef MakeInstance() { return MakeShareable(new FFlowOwnerFunctionRefCustomization()); } + +protected: + + //~Begin IPropertyTypeCustomization + virtual void CustomizeChildren(TSharedRef InStructPropertyHandle, IDetailChildrenBuilder& StructBuilder, IPropertyTypeCustomizationUtils& StructCustomizationUtils) override; + //~End IPropertyTypeCustomization + + //~Begin ICuratedNamePropertyCustomization + virtual TSharedPtr GetCuratedNamePropertyHandle() const override; + virtual void SetCuratedName(const FName& NewName) override; + virtual FName GetCuratedName() const override; + virtual TArray GetCuratedNameOptions() const override; + //~End ICuratedNamePropertyCustomization + + // Accessor to return the actual struct being edited + FORCEINLINE FFlowOwnerFunctionRef* GetFlowOwnerFunctionRef() const + { return IFlowExtendedPropertyTypeCustomization::TryGetTypedStructValue(StructPropertyHandle); } + + const UClass* TryGetExpectedOwnerClass() const; + UFlowNode* TryGetFlowNodeOuter() const; + + static TArray GetFlowOwnerFunctionRefs(const UFlowNode_CallOwnerFunction& FlowNodeOwner, const UClass& ExpectedOwnerClass); + + static bool IsFunctionUsable(const UFunction& Function, const UFlowNode_CallOwnerFunction& FlowNodeOwner); + static bool DoesFunctionHaveExpectedParamType(const UFunction& Function, const UFlowNode_CallOwnerFunction& FlowNodeOwner); + +}; diff --git a/Source/FlowEditor/Public/FlowEditorModule.h b/Source/FlowEditor/Public/FlowEditorModule.h index 74fb82b8e..2bc6c5a61 100644 --- a/Source/FlowEditor/Public/FlowEditorModule.h +++ b/Source/FlowEditor/Public/FlowEditorModule.h @@ -22,6 +22,7 @@ class FLOWEDITOR_API FFlowEditorModule : public IModuleInterface private: TArray> RegisteredAssetActions; TSet CustomClassLayouts; + TSet CustomStructLayouts; public: virtual void StartupModule() override; @@ -31,8 +32,11 @@ class FLOWEDITOR_API FFlowEditorModule : public IModuleInterface void RegisterAssets(); void UnregisterAssets(); - void RegisterPropertyCustomizations() const; + void RegisterDetailCustomizations(); + void UnregisterDetailCustomizations(); + void RegisterCustomClassLayout(const TSubclassOf Class, const FOnGetDetailCustomizationInstance DetailLayout); + void RegisterCustomStructLayout(const UScriptStruct& Struct, const FOnGetPropertyTypeCustomizationInstance DetailLayout); public: FDelegateHandle FlowTrackCreateEditorHandle; diff --git a/Source/FlowEditor/Public/UnrealExtensions/IFlowCuratedNamePropertyCustomization.h b/Source/FlowEditor/Public/UnrealExtensions/IFlowCuratedNamePropertyCustomization.h new file mode 100644 index 000000000..034f26edc --- /dev/null +++ b/Source/FlowEditor/Public/UnrealExtensions/IFlowCuratedNamePropertyCustomization.h @@ -0,0 +1,65 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +// NOTE (gtaylor) This class is planned for submission to Epic to include in baseline UE. +// If/when that happens, we will want to remove this version and update to the latest one in the PropertyModule + +#pragma once + +#include "IFlowExtendedPropertyTypeCustomization.h" +#include "Widgets/Input/SComboBox.h" + + +// A base-class to do property Customization for a struct that presents a curated list of FNames for selection +class FLOWEDITOR_API IFlowCuratedNamePropertyCustomization : public IFlowExtendedPropertyTypeCustomization +{ +public: + +protected: + + //Begin IExtendedPropertyTypeCustomization + virtual void CreateHeaderRowWidget(FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils) override; + //End IExtendedPropertyTypeCustomization + + void Initialize(); + + // Helper function to set the property to a specified value + // (and handle all of the side-effects) + bool TrySetCuratedNameWithSideEffects(const FName& NewName); + + // Callbacks for the TextListWidget (see CreateHeaderRowWidget) + FText GetCachedText() const; + TSharedRef GenerateTextListWidget(TSharedPtr InItem); + void OnTextListComboBoxOpening(); + void OnTextSelected(TSharedPtr NewSelection, ESelectInfo::Type SelectInfo); + + void RepaintTextListWidget(); + + TSharedPtr FindCachedOrCreateText(const FName& NewName); + void AddToCachedTextList(TSharedPtr Text); + void InsertAtHeadOfCachedTextList(TSharedPtr Text); + + bool CustomIsResetToDefaultVisible(TSharedPtr Property) const; + void CustomResetToDefault(TSharedPtr Property); + + //Begin IFlowCuratedNamePropertyCustomization + virtual TSharedPtr GetCuratedNamePropertyHandle() const = 0; + virtual void SetCuratedName(const FName& NewName) = 0; + virtual FName GetCuratedName() const = 0; + virtual TArray GetCuratedNameOptions() const = 0; + //End IFlowCuratedNamePropertyCustomization + +public: + + // Cached property handle for the Curated Name property that is being customized + TSharedPtr CachedNameHandle; + + // Cache FTexts for the ComboBox dropdown & current selected + TArray> CachedTextList; + TSharedPtr CachedTextSelected; + + // Preallocated NAME_None as FText + static TSharedPtr NoneAsText; + + // Combo Box widget for displaying the curated list of Names + TSharedPtr>> TextListWidget; +}; diff --git a/Source/FlowEditor/Public/UnrealExtensions/IFlowExtendedPropertyTypeCustomization.h b/Source/FlowEditor/Public/UnrealExtensions/IFlowExtendedPropertyTypeCustomization.h new file mode 100644 index 000000000..35647cd28 --- /dev/null +++ b/Source/FlowEditor/Public/UnrealExtensions/IFlowExtendedPropertyTypeCustomization.h @@ -0,0 +1,78 @@ +// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors + +// NOTE (gtaylor) This class is planned for submission to Epic to include in baseline UE. +// If/when that happens, we will want to remove this version and update to the latest one in the PropertyModule + +#pragma once + +#include "IPropertyTypeCustomization.h" +#include "PropertyHandle.h" +#include "Templates/SharedPointer.h" + +#include "IPropertyTypeCustomization.h" + + +// Forward Declarations +class STextBlock; +class FDetailWidgetRow; +class IDetailChildrenBuilder; +class IPropertyTypeCustomizationUtils; +class IDetailPropertyRow; +class IPropertyHandle; + + +// An extension of IPropertyTypeCustomization +// which adds some quality-of-life improvements for subclasses +class FLOWEDITOR_API IFlowExtendedPropertyTypeCustomization : public IPropertyTypeCustomization +{ +public: + + // IPropertyTypeCustomization interface + virtual void CustomizeHeader( TSharedRef InStructPropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils ) override; + virtual void CustomizeChildren(TSharedRef InStructPropertyHandle, IDetailChildrenBuilder& StructBuilder, IPropertyTypeCustomizationUtils& StructCustomizationUtils) override + { CustomizeChildrenDefaultImpl(InStructPropertyHandle, StructBuilder, StructCustomizationUtils); } + + static void CustomizeChildrenDefaultImpl(TSharedRef StructPropertyHandle, IDetailChildrenBuilder& StructBuilder, IPropertyTypeCustomizationUtils& StructCustomizationUtils); + + template + static StructT* TryGetTypedStructValue(const TSharedPtr& StructPropertyHandle); + +protected: + + void RefreshHeader() const; + + virtual void CreateHeaderRowWidget(FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils); + virtual FText BuildHeaderText() const; + + // Callbacks for property editor delegates + void OnAnyChildPropertyChanged(); + +protected: + + // Cached struct property + TSharedPtr StructPropertyHandle; + + // Header property text block, (re-)built in RefreshHeader + TSharedPtr HeaderTextBlock; +}; + + +// Inline Implementations + +template +StructT* IFlowExtendedPropertyTypeCustomization::TryGetTypedStructValue(const TSharedPtr& StructPropertyHandle) +{ + if (StructPropertyHandle.IsValid()) + { + // Get the actual struct data from the handle and cast it to the correct type + TArray RawData; + StructPropertyHandle->AccessRawData(RawData); + + if (RawData.Num() > 0) + { + return reinterpret_cast(RawData[0]); + } + } + + return nullptr; +} From 2c202f09a387577af0c415056b51aa914cb31eaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sat, 8 Jul 2023 18:53:12 +0200 Subject: [PATCH 320/338] cosmetic tweaks to PR #167 --- Source/Flow/Public/FlowSettings.h | 3 --- Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h | 3 +-- Source/FlowEditor/Public/Graph/FlowGraphSettings.h | 1 - 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/Source/Flow/Public/FlowSettings.h b/Source/Flow/Public/FlowSettings.h index 29bf01f13..1f7c93ad9 100644 --- a/Source/Flow/Public/FlowSettings.h +++ b/Source/Flow/Public/FlowSettings.h @@ -53,11 +53,8 @@ class FLOW_API UFlowSettings : public UDeveloperSettings static UClass* TryResolveOrLoadSoftClass(const FSoftClassPath& SoftClassPath); -public: - #if WITH_EDITORONLY_DATA virtual FName GetCategoryName() const override { return FName("Flow Graph"); } virtual FText GetSectionText() const override { return INVTEXT("Settings"); } #endif - }; diff --git a/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h b/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h index 481f3087a..51d00ef27 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphEditorSettings.h @@ -55,7 +55,6 @@ class FLOWEDITOR_API UFlowGraphEditorSettings : public UDeveloperSettings bool bHighlightOutputWiresOfSelectedNodes; public: - virtual FName GetCategoryName() const override { return FName("Flow Graph"); } - virtual FText GetSectionText() const override { return INVTEXT("Editor Settings"); } + virtual FText GetSectionText() const override { return INVTEXT("User Settings"); } }; diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h index ac9ba8862..a21116bb6 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h @@ -108,7 +108,6 @@ class FLOWEDITOR_API UFlowGraphSettings : public UDeveloperSettings float SelectedWireThickness; public: - virtual FName GetCategoryName() const override { return FName("Flow Graph"); } virtual FText GetSectionText() const override { return INVTEXT("Graph Settings"); } }; From c7e9052c874f4045d83a50a99269fc941eff616e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sat, 8 Jul 2023 19:06:10 +0200 Subject: [PATCH 321/338] compilation fix --- Source/Flow/Public/FlowAsset.h | 2 +- Source/Flow/Public/FlowOwnerFunctionParams.h | 18 +++++++++--------- Source/Flow/Public/FlowOwnerFunctionRef.h | 4 ++-- Source/Flow/Public/FlowSettings.h | 2 +- .../Nodes/Route/FlowNode_ExecutionSequence.h | 2 +- .../Nodes/World/FlowNode_CallOwnerFunction.h | 4 ++-- .../Private/Asset/FlowDiffControl.cpp | 2 +- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 57467169a..6941109bd 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -359,7 +359,7 @@ class FLOW_API UFlowAsset : public UObject // Expects to be owned (at runtime) by an object with this class (or one of its subclasses) // NOTE - If the class is an AActor, and the flow asset is owned by a component, // it will consider the component's owner for the AActor - UPROPERTY(EditAnywhere, meta = (MustImplement = "FlowOwnerInterface")) + UPROPERTY(EditAnywhere, Category = "Flow", meta = (MustImplement = "FlowOwnerInterface")) TSubclassOf ExpectedOwnerClass; ////////////////////////////////////////////////////////////////////////// diff --git a/Source/Flow/Public/FlowOwnerFunctionParams.h b/Source/Flow/Public/FlowOwnerFunctionParams.h index f3f49797f..f627fe875 100644 --- a/Source/Flow/Public/FlowOwnerFunctionParams.h +++ b/Source/Flow/Public/FlowOwnerFunctionParams.h @@ -23,7 +23,7 @@ class FLOW_API UFlowOwnerFunctionParams : public UObject void PreExecute(UFlowNode_CallOwnerFunction& InSourceNode, const FName& InputPinName); void PostExecute(); - UFUNCTION(BlueprintNativeEvent, BlueprintPure) + UFUNCTION(BlueprintNativeEvent, BlueprintPure, Category = "FlowOwnerFunction") bool ShouldFinishForOutputName(const FName& OutputName) const; #if WITH_EDITORONLY_DATA @@ -41,43 +41,43 @@ class FLOW_API UFlowOwnerFunctionParams : public UObject // Called prior to the owner executing the function described by this object. // Can be overridden to prepare the stateful data before execution. - UFUNCTION(BlueprintImplementableEvent, DisplayName = "PreExecute") + UFUNCTION(BlueprintImplementableEvent, Category = "FlowOwnerFunction", DisplayName = "PreExecute") void BP_PreExecute(); // Cleans up the stateful data in this Params struct. // Can be overridden to cleanup the stateful data after execution. - UFUNCTION(BlueprintImplementableEvent, DisplayName = "PostExecute") + UFUNCTION(BlueprintImplementableEvent, Category = "FlowOwnerFunction", DisplayName = "PostExecute") void BP_PostExecute(); // Get the input pin names for the SourceNode // Valid only if called between PreExecute() and PostExecute(), inclusive - UFUNCTION(BlueprintCallable, BlueprintPure, DisplayName = "GetInputNames") + UFUNCTION(BlueprintCallable, BlueprintPure, Category = "FlowOwnerFunction", DisplayName = "GetInputNames") TArray BP_GetInputNames() const; // Get the output pin names for the SourceNode // Valid only if called between PreExecute() and PostExecute(), inclusive - UFUNCTION(BlueprintCallable, BlueprintPure, DisplayName = "GetOutputNames") + UFUNCTION(BlueprintCallable, BlueprintPure, Category = "FlowOwnerFunction", DisplayName = "GetOutputNames") TArray BP_GetOutputNames() const; protected: // CallOwnerObjectFunction node that is executing this set of function params. // Valid only if called between PreExecute() and PostExecute(), inclusive - UPROPERTY(Transient, BlueprintReadOnly) + UPROPERTY(Transient, BlueprintReadOnly, Category = "FlowOwnerFunction") UFlowNode_CallOwnerFunction* SourceNode = nullptr; // This is the Name from the Input Pin that caused this node to Execute. // Valid only if called between PreExecute() and PostExecute(), inclusive - UPROPERTY(Transient, BlueprintReadOnly) + UPROPERTY(Transient, BlueprintReadOnly, Category = "FlowOwnerFunction") FName ExecutedInputPinName; #if WITH_EDITORONLY_DATA // Input pin names for this function - UPROPERTY(EditDefaultsOnly) + UPROPERTY(EditDefaultsOnly, Category = "FlowOwnerFunction") TArray InputNames; // Output pin names for this function - UPROPERTY(EditDefaultsOnly) + UPROPERTY(EditDefaultsOnly, Category = "FlowOwnerFunction") TArray OutputNames; #endif // WITH_EDITORONLY_DATA }; diff --git a/Source/Flow/Public/FlowOwnerFunctionRef.h b/Source/Flow/Public/FlowOwnerFunctionRef.h index 4e628d1ab..629949c8d 100644 --- a/Source/Flow/Public/FlowOwnerFunctionRef.h +++ b/Source/Flow/Public/FlowOwnerFunctionRef.h @@ -44,7 +44,7 @@ struct FFlowOwnerFunctionRef protected: // The name of the function to call - UPROPERTY(VisibleAnywhere) + UPROPERTY(VisibleAnywhere, Category = "FlowOwnerFunction") FName FunctionName = NAME_None; // The function to call @@ -53,7 +53,7 @@ struct FFlowOwnerFunctionRef TObjectPtr Function = nullptr; #if WITH_EDITORONLY_DATA - UPROPERTY(VisibleAnywhere, meta = (DisplayName = "Function Parameters Class")) + UPROPERTY(VisibleAnywhere, Category = "FlowOwnerFunction", meta = (DisplayName = "Function Parameters Class")) TSubclassOf ParamsClass; #endif // WITH_EDITORONLY_DATA }; diff --git a/Source/Flow/Public/FlowSettings.h b/Source/Flow/Public/FlowSettings.h index 1f7c93ad9..d02e9776d 100644 --- a/Source/Flow/Public/FlowSettings.h +++ b/Source/Flow/Public/FlowSettings.h @@ -45,7 +45,7 @@ class FLOW_API UFlowSettings : public UDeveloperSettings bool bUseAdaptiveNodeTitles; // Default class to use as a FlowAsset's "ExpectedOwnerClass" - UPROPERTY(EditAnywhere, Config, meta = (MustImplement = "FlowOwnerInterface")) + UPROPERTY(EditAnywhere, Config, Category = "Nodes", meta = (MustImplement = "FlowOwnerInterface")) FSoftClassPath DefaultExpectedOwnerClass; public: diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionSequence.h b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionSequence.h index 2882b917e..ef7482ca2 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionSequence.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionSequence.h @@ -36,7 +36,7 @@ class FLOW_API UFlowNode_ExecutionSequence final : public UFlowNode * This is useful if you want the ability to add new parts to your * graph after release. */ - UPROPERTY(EditAnywhere) + UPROPERTY(EditAnywhere, Category = "Sequence") bool bSavePinExecutionState = false; UPROPERTY(SaveGame) diff --git a/Source/Flow/Public/Nodes/World/FlowNode_CallOwnerFunction.h b/Source/Flow/Public/Nodes/World/FlowNode_CallOwnerFunction.h index 2f3302af5..55d8266ce 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_CallOwnerFunction.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_CallOwnerFunction.h @@ -86,10 +86,10 @@ class FLOW_API UFlowNode_CallOwnerFunction : public UFlowNode protected: // Function reference on the expected owner to call - UPROPERTY(EditAnywhere, meta = (DisplayName = "Function")) + UPROPERTY(EditAnywhere, Category = "Call Owner", meta = (DisplayName = "Function")) FFlowOwnerFunctionRef FunctionRef; // Parameter object to pass to the function when called - UPROPERTY(EditAnywhere, Instanced) + UPROPERTY(EditAnywhere, Category = "Call Owner", Instanced) UFlowOwnerFunctionParams* Params; }; diff --git a/Source/FlowEditor/Private/Asset/FlowDiffControl.cpp b/Source/FlowEditor/Private/Asset/FlowDiffControl.cpp index 28b8ea6fc..6fc3aa500 100644 --- a/Source/FlowEditor/Private/Asset/FlowDiffControl.cpp +++ b/Source/FlowEditor/Private/Asset/FlowDiffControl.cpp @@ -24,7 +24,7 @@ FFlowAssetDiffControl::FFlowAssetDiffControl(const UFlowAsset* InOldFlowAsset, const UFlowAsset* InNewFlowAsset, FOnDiffEntryFocused InSelectionCallback) #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION < 2 - : FDetailsDiffControl(InOldFlowAsset, InNewFlowAsset, InSelectionCallback) + : TDetailsDiffControl(InOldFlowAsset, InNewFlowAsset, InSelectionCallback) #else : FDetailsDiffControl(InOldFlowAsset, InNewFlowAsset, InSelectionCallback, false) #endif From 7875c55e81d6c427510b5730aef497f499a7599a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sat, 8 Jul 2023 20:00:20 +0200 Subject: [PATCH 322/338] UE 5.0 compilation fix --- .../DetailCustomizations/FlowNode_SubGraphDetails.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Source/FlowEditor/Private/DetailCustomizations/FlowNode_SubGraphDetails.cpp b/Source/FlowEditor/Private/DetailCustomizations/FlowNode_SubGraphDetails.cpp index 1b6cf0f3f..d7cfff658 100644 --- a/Source/FlowEditor/Private/DetailCustomizations/FlowNode_SubGraphDetails.cpp +++ b/Source/FlowEditor/Private/DetailCustomizations/FlowNode_SubGraphDetails.cpp @@ -4,6 +4,7 @@ #include "DetailLayoutBuilder.h" #include "FlowAsset.h" +#include "Launch/Resources/Version.h" #include "Nodes/Route/FlowNode_SubGraph.h" void FFlowNode_SubGraphDetails::CustomizeDetails(IDetailLayoutBuilder& DetailLayout) @@ -51,13 +52,21 @@ void FFlowNode_SubGraphDetails::CustomizeDetails(IDetailLayoutBuilder& DetailLay FString AllowedClassesString; for (UClass* Class : AllowedClasses) { +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION < 1 + AllowedClassesString.Append(FString::Printf(TEXT("%s,"), *Class->GetFName().ToString())); +#else AllowedClassesString.Append(FString::Printf(TEXT("%s,"), *Class->GetClassPathName().ToString())); +#endif } FString DisallowedClassesString; for (UClass* Class : DisallowedClasses) { +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION < 1 + DisallowedClassesString.Append(FString::Printf(TEXT("%s,"), *Class->GetFName().ToString())); +#else DisallowedClassesString.Append(FString::Printf(TEXT("%s,"), *Class->GetClassPathName().ToString())); +#endif } const auto AssetProperty = DetailLayout.GetProperty(FName("Asset"), UFlowNode_SubGraph::StaticClass()); From 87151106dad00f02aefda5ae5b0d7159a20c2ce7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 23 Jul 2023 18:30:36 +0200 Subject: [PATCH 323/338] Cleanup * `GetNodesInExecutionOrder` - added `UFlowNode* FirstIteratedNode` parameter, allowing to start iteration from any node. * Remove the default implementation of `UFlowAsset::PreloadNodes`, it was a forever prototype. You can still implement this method on your own. * Corrected class layout. --- Source/Flow/Private/FlowAsset.cpp | 87 +++++++++++-------------------- Source/Flow/Public/FlowAsset.h | 41 ++++++++------- Source/Flow/Public/FlowSettings.h | 4 -- 3 files changed, 50 insertions(+), 82 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index e9ad55237..c542f016c 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -269,7 +269,32 @@ void UFlowAsset::HarvestNodeConnections() } } } +#endif + +UFlowNode* UFlowAsset::GetDefaultEntryNode() const +{ + UFlowNode* FirstStartNode = nullptr; + + for (const TPair& Node : Nodes) + { + if (UFlowNode_Start* StartNode = Cast(Node.Value)) + { + if (StartNode->GetConnectedNodes().Num() > 0) + { + return StartNode; + } + else if (FirstStartNode == nullptr) + { + FirstStartNode = StartNode; + } + } + } + // If none of the found start nodes have connections, fallback to the first start node we found + return FirstStartNode; +} + +#if WITH_EDITOR void UFlowAsset::AddCustomInput(const FName& EventName) { if (!CustomInputs.Contains(EventName)) @@ -301,7 +326,7 @@ void UFlowAsset::RemoveCustomOutput(const FName& EventName) CustomOutputs.Remove(EventName); } } -#endif // WITH_EDITOR +#endif UFlowNode_CustomInput* UFlowAsset::TryFindCustomInputNodeByEventName(const FName& EventName) const { @@ -316,33 +341,10 @@ UFlowNode_CustomInput* UFlowAsset::TryFindCustomInputNodeByEventName(const FName return nullptr; } -UFlowNode* UFlowAsset::GetDefaultEntryNode() const -{ - UFlowNode* FirstStartNode = nullptr; - - for (const TPair& Node : Nodes) - { - if (UFlowNode_Start* StartNode = Cast(Node.Value)) - { - if (StartNode->GetConnectedNodes().Num() > 0) - { - return StartNode; - } - else if (FirstStartNode == nullptr) - { - FirstStartNode = StartNode; - } - } - } - - // If none of the found start nodes have connections, fallback to the first start node we found - return FirstStartNode; -} - -TArray UFlowAsset::GetNodesInExecutionOrder(const TSubclassOf FlowNodeClass) +TArray UFlowAsset::GetNodesInExecutionOrder(UFlowNode* FirstIteratedNode, const TSubclassOf FlowNodeClass) { TArray FoundNodes; - GetNodesInExecutionOrder(FoundNodes); + GetNodesInExecutionOrder(FirstIteratedNode, FoundNodes); // filter out nodes by class for (int32 i = FoundNodes.Num() - 1; i >= 0; i--) @@ -481,37 +483,6 @@ void UFlowAsset::DeinitializeInstance() } } -void UFlowAsset::PreloadNodes() -{ - TArray GraphEntryNodes = {GetDefaultEntryNode()}; - for (UFlowNode_CustomInput* CustomInput : CustomInputNodes) - { - GraphEntryNodes.Emplace(CustomInput); - } - - // NOTE: this is just the example algorithm of gathering nodes for pre-load - for (UFlowNode* EntryNode : GraphEntryNodes) - { - for (const TPair, int32>& Node : UFlowSettings::Get()->DefaultPreloadDepth) - { - if (Node.Value > 0) - { - TArray FoundNodes; - UFlowNode::RecursiveFindNodesByClass(EntryNode, Node.Key, Node.Value, FoundNodes); - - for (UFlowNode* FoundNode : FoundNodes) - { - if (!PreloadedNodes.Contains(FoundNode)) - { - FoundNode->TriggerPreload(); - PreloadedNodes.Emplace(FoundNode); - } - } - } - } - } -} - void UFlowAsset::PreStartFlow() { ResetNodes(); @@ -699,7 +670,7 @@ FFlowAssetSaveData UFlowAsset::SaveInstance(TArray& SavedFlo // iterate nodes TArray NodesInExecutionOrder; - GetNodesInExecutionOrder(NodesInExecutionOrder); + GetNodesInExecutionOrder(GetDefaultEntryNode(), NodesInExecutionOrder); for (UFlowNode* Node : NodesInExecutionOrder) { if (Node && Node->ActivationState == EFlowNodeState::Active) diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 6941109bd..56a0a1548 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -159,18 +159,33 @@ class FLOW_API UFlowAsset : public UObject virtual UFlowNode* GetDefaultEntryNode() const; +#if WITH_EDITOR +protected: + void AddCustomInput(const FName& EventName); + void RemoveCustomInput(const FName& EventName); + + void AddCustomOutput(const FName& EventName); + void RemoveCustomOutput(const FName& EventName); +#endif + +public: + const TArray& GetCustomInputs() const { return CustomInputs; } + const TArray& GetCustomOutputs() const { return CustomOutputs; } + + UFlowNode_CustomInput* TryFindCustomInputNodeByEventName(const FName& EventName) const; + UFUNCTION(BlueprintPure, Category = "FlowAsset", meta = (DeterminesOutputType = "FlowNodeClass")) - TArray GetNodesInExecutionOrder(const TSubclassOf FlowNodeClass); + TArray GetNodesInExecutionOrder(UFlowNode* FirstIteratedNode, const TSubclassOf FlowNodeClass); template - void GetNodesInExecutionOrder(TArray& OutNodes) + void GetNodesInExecutionOrder(UFlowNode* FirstIteratedNode, TArray& OutNodes) { static_assert(TPointerIsConvertibleFromTo::Value, "'T' template parameter to GetNodesInExecutionOrder must be derived from UFlowNode"); - if (UFlowNode* FoundStartNode = GetDefaultEntryNode()) + if (FirstIteratedNode) { TSet> IteratedNodes; - GetNodesInExecutionOrder_Recursive(FoundStartNode, IteratedNodes, OutNodes); + GetNodesInExecutionOrder_Recursive(FirstIteratedNode, IteratedNodes, OutNodes); } } @@ -194,21 +209,6 @@ class FLOW_API UFlowAsset : public UObject } } -public: - const TArray& GetCustomInputs() const { return CustomInputs; } - const TArray& GetCustomOutputs() const { return CustomOutputs; } - - UFlowNode_CustomInput* TryFindCustomInputNodeByEventName(const FName& EventName) const; - -#if WITH_EDITOR -protected: - void AddCustomInput(const FName& EventName); - void RemoveCustomInput(const FName& EventName); - - void AddCustomOutput(const FName& EventName); - void RemoveCustomOutput(const FName& EventName); -#endif // WITH_EDITOR - ////////////////////////////////////////////////////////////////////////// // Instances of the template asset @@ -308,7 +308,8 @@ class FLOW_API UFlowAsset : public UObject UFUNCTION(BlueprintPure, Category = "Flow") AActor* TryFindActorOwner() const; - virtual void PreloadNodes(); + // Opportunity to preload content of project-specific nodes + virtual void PreloadNodes() {} virtual void PreStartFlow(); virtual void StartFlow(); diff --git a/Source/Flow/Public/FlowSettings.h b/Source/Flow/Public/FlowSettings.h index d02e9776d..ddb491d13 100644 --- a/Source/Flow/Public/FlowSettings.h +++ b/Source/Flow/Public/FlowSettings.h @@ -24,10 +24,6 @@ class FLOW_API UFlowSettings : public UDeveloperSettings UPROPERTY(Config, EditAnywhere, Category = "Networking") bool bCreateFlowSubsystemOnClients; - // How many nodes of given class should be preloaded with the Flow Asset instance? - UPROPERTY(Config, EditAnywhere, Category = "Preload") - TMap, int32> DefaultPreloadDepth; - UPROPERTY(Config, EditAnywhere, Category = "SaveSystem") bool bWarnAboutMissingIdentityTags; From a2a0348367afa37243554188ec333813bbdb2b76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 23 Jul 2023 18:31:10 +0200 Subject: [PATCH 324/338] Removed RecursiveFindNodesByClass method, superseded by UFlowAsset::GetNodesInExecutionOrder --- Source/Flow/Private/Nodes/FlowNode.cpp | 23 ----------------------- Source/Flow/Public/Nodes/FlowNode.h | 2 -- 2 files changed, 25 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 105fcb1ca..3a8b87da5 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -468,29 +468,6 @@ bool UFlowNode::IsOutputConnected(const FName& PinName) const return OutputPins.Contains(PinName) && Connections.Contains(PinName); } -void UFlowNode::RecursiveFindNodesByClass(UFlowNode* Node, const TSubclassOf Class, uint8 Depth, TArray& OutNodes) -{ - if (Node) - { - // Record the node if it is the desired type - if (Node->GetClass() == Class) - { - OutNodes.AddUnique(Node); - } - - if (OutNodes.Num() == Depth) - { - return; - } - - // Recurse - for (UFlowNode* ConnectedNode : Node->GetConnectedNodes()) - { - RecursiveFindNodesByClass(ConnectedNode, Class, Depth, OutNodes); - } - } -} - UFlowSubsystem* UFlowNode::GetFlowSubsystem() const { return GetFlowAsset() ? GetFlowAsset()->GetFlowSubsystem() : nullptr; diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 49a59dc5e..a6260736f 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -239,8 +239,6 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UFUNCTION(BlueprintPure, Category= "FlowNode") bool IsOutputConnected(const FName& PinName) const; - static void RecursiveFindNodesByClass(UFlowNode* Node, const TSubclassOf Class, uint8 Depth, TArray& OutNodes); - ////////////////////////////////////////////////////////////////////////// // Debugger protected: From 506e7dc0d28180238a669788925bd8c13d262697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 23 Jul 2023 18:31:34 +0200 Subject: [PATCH 325/338] Removed the use of FStreamableManager --- Source/Flow/Private/FlowSubsystem.cpp | 29 +++++++++++---------------- Source/Flow/Public/FlowSubsystem.h | 3 --- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index ff45776bf..404d19042 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -83,7 +83,7 @@ void UFlowSubsystem::StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const NewFlow->StartFlow(); } } -#if WITH_EDITOR +#if WITH_EDITOR else { FMessageLog("PIE").Error(LOCTEXT("StartRootFlowNullAsset", "Attempted to start Root Flow with a null asset.")) @@ -204,33 +204,32 @@ void UFlowSubsystem::RemoveSubFlow(UFlowNode_SubGraph* SubGraphNode, const EFlow UFlowAsset* UFlowSubsystem::CreateFlowInstance(const TWeakObjectPtr Owner, TSoftObjectPtr FlowAsset, FString NewInstanceName) { - check(!FlowAsset.IsNull()); - - if (FlowAsset.IsPending() || !FlowAsset.IsValid()) + UFlowAsset* LoadedFlowAsset = FlowAsset.LoadSynchronous(); + if (!ensureAlways(LoadedFlowAsset)) { - FlowAsset = Cast(Streamable.LoadSynchronous(FlowAsset.ToSoftObjectPath(), false)); + return nullptr; } - AddInstancedTemplate(FlowAsset.Get()); + AddInstancedTemplate(LoadedFlowAsset); #if WITH_EDITOR if (GetWorld()->WorldType != EWorldType::Game) { // Fix connections - even in packaged game if assets haven't been re-saved in the editor after changing node's definition - FlowAsset.Get()->HarvestNodeConnections(); + LoadedFlowAsset->HarvestNodeConnections(); } #endif // it won't be empty, if we're restoring Flow Asset instance from the SaveGame if (NewInstanceName.IsEmpty()) { - NewInstanceName = MakeUniqueObjectName(this, UFlowAsset::StaticClass(), *FPaths::GetBaseFilename(FlowAsset.Get()->GetPathName())).ToString(); + NewInstanceName = MakeUniqueObjectName(this, UFlowAsset::StaticClass(), *FPaths::GetBaseFilename(LoadedFlowAsset->GetPathName())).ToString(); } - UFlowAsset* NewInstance = NewObject(this, FlowAsset->GetClass(), *NewInstanceName, RF_Transient, FlowAsset.Get(), false, nullptr); - NewInstance->InitializeInstance(Owner, FlowAsset.Get()); + UFlowAsset* NewInstance = NewObject(this, LoadedFlowAsset->GetClass(), *NewInstanceName, RF_Transient, LoadedFlowAsset, false, nullptr); + NewInstance->InitializeInstance(Owner, LoadedFlowAsset); - FlowAsset.Get()->AddInstance(NewInstance); + LoadedFlowAsset->AddInstance(NewInstance); return NewInstance; } @@ -393,16 +392,12 @@ void UFlowSubsystem::LoadSubFlow(UFlowNode_SubGraph* SubGraphNode, const FString return; } - if (SubGraphNode->Asset.IsPending()) - { - const FSoftObjectPath& AssetRef = SubGraphNode->Asset.ToSoftObjectPath(); - Streamable.LoadSynchronous(AssetRef, false); - } + UFlowAsset* SubGraphAsset = SubGraphNode->Asset.LoadSynchronous(); for (const FFlowAssetSaveData& AssetRecord : LoadedSaveGame->FlowInstances) { if (AssetRecord.InstanceName == SavedAssetInstanceName - && ((SubGraphNode->Asset && SubGraphNode->Asset->IsBoundToWorld() == false) || AssetRecord.WorldName == GetWorld()->GetName())) + && ((SubGraphAsset && SubGraphAsset->IsBoundToWorld() == false) || AssetRecord.WorldName == GetWorld()->GetName())) { UFlowAsset* LoadedInstance = CreateSubFlow(SubGraphNode, SavedAssetInstanceName); if (LoadedInstance) diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index ca9b3aa86..4633eef40 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -2,7 +2,6 @@ #pragma once -#include "Engine/StreamableManager.h" #include "GameFramework/Actor.h" #include "GameplayTagContainer.h" #include "Subsystems/GameInstanceSubsystem.h" @@ -50,8 +49,6 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem UPROPERTY() TMap InstancedSubFlows; - FStreamableManager Streamable; - #if WITH_EDITOR public: /* Called after creating the first instance of given Flow Asset */ From 3ce33c27b9b1a85d620eb479d0e81b3b0e6baacb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 23 Jul 2023 18:46:14 +0200 Subject: [PATCH 326/338] Moved declaration of FStreamableManager to only Flow Node class actually using it --- Source/Flow/Public/Nodes/FlowNode.h | 3 --- Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h | 4 ++++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index a6260736f..ef47720b5 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -3,7 +3,6 @@ #pragma once #include "EdGraph/EdGraphNode.h" -#include "Engine/StreamableManager.h" #include "GameplayTagContainer.h" #include "Templates/SubclassOf.h" #include "VisualLogger/VisualLoggerDebugSnapshotInterface.h" @@ -254,8 +253,6 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte bool bPreloaded; protected: - FStreamableManager StreamableManager; - UPROPERTY(SaveGame) EFlowNodeState ActivationState; diff --git a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h index ad118d008..d7ef98831 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h @@ -3,6 +3,7 @@ #pragma once #include "EngineDefines.h" +#include "Engine/StreamableManager.h" #include "LevelSequencePlayer.h" #include "MovieSceneSequencePlayer.h" @@ -26,6 +27,7 @@ class FLOW_API UFlowNode_PlayLevelSequence : public UFlowNode GENERATED_UCLASS_BODY() friend struct FFlowTrackExecutionToken; +public: static FFlowNodeLevelSequenceEvent OnPlaybackStarted; static FFlowNodeLevelSequenceEvent OnPlaybackCompleted; @@ -79,6 +81,8 @@ class FLOW_API UFlowNode_PlayLevelSequence : public UFlowNode UPROPERTY(SaveGame) float TimeDilation; + FStreamableManager StreamableManager; + public: #if WITH_EDITOR virtual bool SupportsContextPins() const override { return true; } From b452b32dc40d24daed2dd9816a47505c564b1018 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 23 Jul 2023 19:48:27 +0200 Subject: [PATCH 327/338] removed unused include --- Source/Flow/Private/FlowSettings.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Source/Flow/Private/FlowSettings.cpp b/Source/Flow/Private/FlowSettings.cpp index 56fff80ce..0e44fd35c 100644 --- a/Source/Flow/Private/FlowSettings.cpp +++ b/Source/Flow/Private/FlowSettings.cpp @@ -2,7 +2,6 @@ #include "FlowSettings.h" #include "FlowComponent.h" -#include "FlowOwnerInterface.h" UFlowSettings::UFlowSettings(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) From cc83e4fca79d4fae716cf9de4917922114543ce3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 23 Jul 2023 19:54:02 +0200 Subject: [PATCH 328/338] reworked FFlowBreakpoint into FFlowPinTrait - inviting to use for things other than breakpoints --- Config/BaseFlow.ini | 2 + Config/DefaultFlow.ini | 2 + Source/Flow/Private/Nodes/FlowPin.cpp | 87 ++++++++++++++++++- Source/Flow/Public/Nodes/FlowPin.h | 44 ++++++++++ .../Private/Graph/FlowGraphEditor.cpp | 35 ++++---- .../Private/Graph/Nodes/FlowGraphNode.cpp | 85 ++---------------- .../Private/Graph/Widgets/SFlowGraphNode.cpp | 16 ++-- .../Public/Graph/Nodes/FlowGraphNode.h | 36 +------- .../Public/Graph/Widgets/SFlowGraphNode.h | 2 +- 9 files changed, 169 insertions(+), 140 deletions(-) diff --git a/Config/BaseFlow.ini b/Config/BaseFlow.ini index f42430df5..7ec2bf1d9 100644 --- a/Config/BaseFlow.ini +++ b/Config/BaseFlow.ini @@ -1,3 +1,5 @@ [CoreRedirects] +ClassRedirects=(OldName="/Script/Flow.FlowNode_CustomEvent",NewName="/Script/Flow.FlowNode_CustomInput") +PropertyRedirects=(OldName="FlowAsset.CustomEvents",NewName="CustomInputs") ++StructRedirects=(OldName="/Script/Flow.FlowBreakpoint",NewName="/Script/Flow.FlowPinTrait") ++PropertyRedirects=(OldName="FlowPinTrait.bHasBreakpoint",NewName="bAllowed") \ No newline at end of file diff --git a/Config/DefaultFlow.ini b/Config/DefaultFlow.ini index f42430df5..7ec2bf1d9 100644 --- a/Config/DefaultFlow.ini +++ b/Config/DefaultFlow.ini @@ -1,3 +1,5 @@ [CoreRedirects] +ClassRedirects=(OldName="/Script/Flow.FlowNode_CustomEvent",NewName="/Script/Flow.FlowNode_CustomInput") +PropertyRedirects=(OldName="FlowAsset.CustomEvents",NewName="CustomInputs") ++StructRedirects=(OldName="/Script/Flow.FlowBreakpoint",NewName="/Script/Flow.FlowPinTrait") ++PropertyRedirects=(OldName="FlowPinTrait.bHasBreakpoint",NewName="bAllowed") \ No newline at end of file diff --git a/Source/Flow/Private/Nodes/FlowPin.cpp b/Source/Flow/Private/Nodes/FlowPin.cpp index d072bd140..368ffa312 100644 --- a/Source/Flow/Private/Nodes/FlowPin.cpp +++ b/Source/Flow/Private/Nodes/FlowPin.cpp @@ -2,8 +2,10 @@ #include "Nodes/FlowPin.h" -#if !UE_BUILD_SHIPPING +////////////////////////////////////////////////////////////////////////// +// Pin Record +#if !UE_BUILD_SHIPPING FString FPinRecord::NoActivations = TEXT("No activations"); FString FPinRecord::PinActivations = TEXT("Pin activations"); FString FPinRecord::ForcedActivation = TEXT(" (forced activation)"); @@ -31,5 +33,86 @@ FORCEINLINE FString FPinRecord::DoubleDigit(const int32 Number) { return Number > 9 ? FString::FromInt(Number) : TEXT("0") + FString::FromInt(Number); } - #endif + +////////////////////////////////////////////////////////////////////////// +// Pin Trait + +void FFlowPinTrait::AllowTrait() +{ + if (!bTraitAllowed) + { + bTraitAllowed = true; + bEnabled = true; + } +} + +void FFlowPinTrait::DisallowTrait() +{ + if (bTraitAllowed) + { + bTraitAllowed = false; + bEnabled = false; + } +} + +bool FFlowPinTrait::IsAllowed() const +{ + return bTraitAllowed; +} + +void FFlowPinTrait::EnableTrait() +{ + if (bTraitAllowed && !bEnabled) + { + bEnabled = true; + } +} + +void FFlowPinTrait::DisableTrait() +{ + if (bTraitAllowed && bEnabled) + { + bEnabled = false; + } +} + +void FFlowPinTrait::ToggleTrait() +{ + if (bTraitAllowed) + { + bTraitAllowed = false; + bEnabled = false; + } + else + { + bTraitAllowed = true; + bEnabled = true; + } +} + +bool FFlowPinTrait::CanEnable() const +{ + return bTraitAllowed && !bEnabled; +} + +bool FFlowPinTrait::IsEnabled() const +{ + return bTraitAllowed && bEnabled; +} + +void FFlowPinTrait::MarkAsHit() +{ + bHit = true; +} + +void FFlowPinTrait::ResetHit() +{ + bHit = false; +} + +bool FFlowPinTrait::IsHit() const +{ + return bHit; +} + diff --git a/Source/Flow/Public/Nodes/FlowPin.h b/Source/Flow/Public/Nodes/FlowPin.h index 1f5c2d82b..950e9373f 100644 --- a/Source/Flow/Public/Nodes/FlowPin.h +++ b/Source/Flow/Public/Nodes/FlowPin.h @@ -210,3 +210,47 @@ struct FLOW_API FPinRecord FORCEINLINE static FString DoubleDigit(const int32 Number); }; #endif + +// It can represent any trait added on the specific node instance, i.e. breakpoint +USTRUCT() +struct FLOW_API FFlowPinTrait +{ + GENERATED_USTRUCT_BODY() + +protected: + UPROPERTY() + uint8 bTraitAllowed : 1; + + uint8 bEnabled : 1; + uint8 bHit : 1; + +public: + FFlowPinTrait() + : bTraitAllowed(false) + , bEnabled(false) + , bHit(false) + { + }; + + explicit FFlowPinTrait(const bool bInitialState) + : bTraitAllowed(bInitialState) + , bEnabled(bInitialState) + , bHit(false) + { + }; + + void AllowTrait(); + void DisallowTrait(); + bool IsAllowed() const; + + void EnableTrait(); + void DisableTrait(); + void ToggleTrait(); + + bool CanEnable() const; + bool IsEnabled() const; + + void MarkAsHit(); + void ResetHit(); + bool IsHit() const; +}; diff --git a/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp b/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp index 7759ef52e..2ffc2022f 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp @@ -741,7 +741,7 @@ void SFlowGraphEditor::OnAddBreakpoint() const { for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) { - SelectedNode->NodeBreakpoint.AddBreakpoint(); + SelectedNode->NodeBreakpoint.AllowTrait(); } } @@ -751,8 +751,7 @@ void SFlowGraphEditor::OnAddPinBreakpoint() { if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) { - GraphNode->PinBreakpoints.Add(Pin, FFlowBreakpoint()); - GraphNode->PinBreakpoints[Pin].AddBreakpoint(); + GraphNode->PinBreakpoints.Add(Pin, FFlowPinTrait(true)); } } } @@ -761,7 +760,7 @@ bool SFlowGraphEditor::CanAddBreakpoint() const { for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) { - return !SelectedNode->NodeBreakpoint.HasBreakpoint(); + return !SelectedNode->NodeBreakpoint.IsAllowed(); } return false; @@ -773,7 +772,7 @@ bool SFlowGraphEditor::CanAddPinBreakpoint() { if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) { - return !GraphNode->PinBreakpoints.Contains(Pin) || !GraphNode->PinBreakpoints[Pin].HasBreakpoint(); + return !GraphNode->PinBreakpoints.Contains(Pin) || !GraphNode->PinBreakpoints[Pin].IsAllowed(); } } @@ -784,7 +783,7 @@ void SFlowGraphEditor::OnRemoveBreakpoint() const { for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) { - SelectedNode->NodeBreakpoint.RemoveBreakpoint(); + SelectedNode->NodeBreakpoint.DisallowTrait(); } } @@ -803,7 +802,7 @@ bool SFlowGraphEditor::CanRemoveBreakpoint() const { for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) { - return SelectedNode->NodeBreakpoint.HasBreakpoint(); + return SelectedNode->NodeBreakpoint.IsAllowed(); } return false; @@ -826,7 +825,7 @@ void SFlowGraphEditor::OnEnableBreakpoint() const { for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) { - SelectedNode->NodeBreakpoint.EnableBreakpoint(); + SelectedNode->NodeBreakpoint.EnableTrait(); } } @@ -836,7 +835,7 @@ void SFlowGraphEditor::OnEnablePinBreakpoint() { if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) { - GraphNode->PinBreakpoints[Pin].EnableBreakpoint(); + GraphNode->PinBreakpoints[Pin].EnableTrait(); } } } @@ -853,7 +852,7 @@ bool SFlowGraphEditor::CanEnableBreakpoint() for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) { - return SelectedNode->NodeBreakpoint.CanEnableBreakpoint(); + return SelectedNode->NodeBreakpoint.CanEnable(); } return false; @@ -865,7 +864,7 @@ bool SFlowGraphEditor::CanEnablePinBreakpoint() { if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) { - return GraphNode->PinBreakpoints.Contains(Pin) && GraphNode->PinBreakpoints[Pin].CanEnableBreakpoint(); + return GraphNode->PinBreakpoints.Contains(Pin) && GraphNode->PinBreakpoints[Pin].CanEnable(); } } @@ -876,7 +875,7 @@ void SFlowGraphEditor::OnDisableBreakpoint() const { for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) { - SelectedNode->NodeBreakpoint.DisableBreakpoint(); + SelectedNode->NodeBreakpoint.DisableTrait(); } } @@ -886,7 +885,7 @@ void SFlowGraphEditor::OnDisablePinBreakpoint() { if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) { - GraphNode->PinBreakpoints[Pin].DisableBreakpoint(); + GraphNode->PinBreakpoints[Pin].DisableTrait(); } } } @@ -895,7 +894,7 @@ bool SFlowGraphEditor::CanDisableBreakpoint() const { for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) { - return SelectedNode->NodeBreakpoint.IsBreakpointEnabled(); + return SelectedNode->NodeBreakpoint.IsEnabled(); } return false; @@ -907,7 +906,7 @@ bool SFlowGraphEditor::CanDisablePinBreakpoint() { if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) { - return GraphNode->PinBreakpoints.Contains(Pin) && GraphNode->PinBreakpoints[Pin].IsBreakpointEnabled(); + return GraphNode->PinBreakpoints.Contains(Pin) && GraphNode->PinBreakpoints[Pin].IsEnabled(); } } @@ -918,7 +917,7 @@ void SFlowGraphEditor::OnToggleBreakpoint() const { for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) { - SelectedNode->NodeBreakpoint.ToggleBreakpoint(); + SelectedNode->NodeBreakpoint.ToggleTrait(); } } @@ -928,8 +927,8 @@ void SFlowGraphEditor::OnTogglePinBreakpoint() { if (UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) { - GraphNode->PinBreakpoints.Add(Pin, FFlowBreakpoint()); - GraphNode->PinBreakpoints[Pin].ToggleBreakpoint(); + GraphNode->PinBreakpoints.Add(Pin, FFlowPinTrait()); + GraphNode->PinBreakpoints[Pin].ToggleTrait(); } } } diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 9f79b50b7..a6862c809 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -29,75 +29,6 @@ #define LOCTEXT_NAMESPACE "FlowGraphNode" -////////////////////////////////////////////////////////////////////////// -// Flow Breakpoint - -void FFlowBreakpoint::AddBreakpoint() -{ - if (!bHasBreakpoint) - { - bHasBreakpoint = true; - bBreakpointEnabled = true; - } -} - -void FFlowBreakpoint::RemoveBreakpoint() -{ - if (bHasBreakpoint) - { - bHasBreakpoint = false; - bBreakpointEnabled = false; - } -} - -bool FFlowBreakpoint::HasBreakpoint() const -{ - return bHasBreakpoint; -} - -void FFlowBreakpoint::EnableBreakpoint() -{ - if (bHasBreakpoint && !bBreakpointEnabled) - { - bBreakpointEnabled = true; - } -} - -bool FFlowBreakpoint::CanEnableBreakpoint() const -{ - return bHasBreakpoint && !bBreakpointEnabled; -} - -void FFlowBreakpoint::DisableBreakpoint() -{ - if (bHasBreakpoint && bBreakpointEnabled) - { - bBreakpointEnabled = false; - } -} - -bool FFlowBreakpoint::IsBreakpointEnabled() const -{ - return bHasBreakpoint && bBreakpointEnabled; -} - -void FFlowBreakpoint::ToggleBreakpoint() -{ - if (bHasBreakpoint) - { - bHasBreakpoint = false; - bBreakpointEnabled = false; - } - else - { - bHasBreakpoint = true; - bBreakpointEnabled = true; - } -} - -////////////////////////////////////////////////////////////////////////// -// Flow Graph Node - UFlowGraphNode::UFlowGraphNode(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) , FlowNode(nullptr) @@ -450,7 +381,7 @@ void UFlowGraphNode::ReconstructSinglePin(UEdGraphPin* NewPin, UEdGraphPin* OldP NewPin->MovePersistentDataFromOldPin(*OldPin); // Update the in breakpoints as the old pin will be going the way of the dodo - for (TPair& PinBreakpoint : PinBreakpoints) + for (TPair& PinBreakpoint : PinBreakpoints) { if (PinBreakpoint.Key.Get() == OldPin) { @@ -1003,7 +934,7 @@ void UFlowGraphNode::OnInputTriggered(const int32 Index) { if (InputPins.IsValidIndex(Index) && PinBreakpoints.Contains(InputPins[Index])) { - PinBreakpoints[InputPins[Index]].bBreakpointHit = true; + PinBreakpoints[InputPins[Index]].MarkAsHit(); TryPausingSession(true); } @@ -1014,7 +945,7 @@ void UFlowGraphNode::OnOutputTriggered(const int32 Index) { if (OutputPins.IsValidIndex(Index) && PinBreakpoints.Contains(OutputPins[Index])) { - PinBreakpoints[OutputPins[Index]].bBreakpointHit = true; + PinBreakpoints[OutputPins[Index]].MarkAsHit(); TryPausingSession(true); } @@ -1024,9 +955,9 @@ void UFlowGraphNode::OnOutputTriggered(const int32 Index) void UFlowGraphNode::TryPausingSession(bool bPauseSession) { // Node breakpoints waits on any pin triggered - if (NodeBreakpoint.IsBreakpointEnabled()) + if (NodeBreakpoint.IsEnabled()) { - NodeBreakpoint.bBreakpointHit = true; + NodeBreakpoint.MarkAsHit(); bPauseSession = true; } @@ -1054,10 +985,10 @@ void UFlowGraphNode::ResetBreakpoints() FEditorDelegates::ResumePIE.RemoveAll(this); FEditorDelegates::EndPIE.RemoveAll(this); - NodeBreakpoint.bBreakpointHit = false; - for (TPair& PinBreakpoint : PinBreakpoints) + NodeBreakpoint.ResetHit(); + for (TPair& PinBreakpoint : PinBreakpoints) { - PinBreakpoint.Value.bBreakpointHit = false; + PinBreakpoint.Value.ResetHit(); } } diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp index 3f8d8342c..5982d52c3 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp @@ -100,18 +100,18 @@ const FSlateBrush* SFlowGraphNode::GetShadowBrush(bool bSelected) const void SFlowGraphNode::GetOverlayBrushes(bool bSelected, const FVector2D WidgetSize, TArray& Brushes) const { // Node breakpoint - if (FlowGraphNode->NodeBreakpoint.bHasBreakpoint) + if (FlowGraphNode->NodeBreakpoint.IsAllowed()) { FOverlayBrushInfo NodeBrush; - if (FlowGraphNode->NodeBreakpoint.bBreakpointHit) + if (FlowGraphNode->NodeBreakpoint.IsHit()) { NodeBrush.Brush = FFlowEditorStyle::Get()->GetBrush(TEXT("FlowGraph.BreakpointHit")); NodeBrush.OverlayOffset.X = WidgetSize.X - 12.0f; } else { - NodeBrush.Brush = FFlowEditorStyle::Get()->GetBrush(FlowGraphNode->NodeBreakpoint.bBreakpointEnabled ? TEXT("FlowGraph.BreakpointEnabled") : TEXT("FlowGraph.BreakpointDisabled")); + NodeBrush.Brush = FFlowEditorStyle::Get()->GetBrush(FlowGraphNode->NodeBreakpoint.IsEnabled() ? TEXT("FlowGraph.BreakpointEnabled") : TEXT("FlowGraph.BreakpointDisabled")); NodeBrush.OverlayOffset.X = WidgetSize.X; } @@ -121,7 +121,7 @@ void SFlowGraphNode::GetOverlayBrushes(bool bSelected, const FVector2D WidgetSiz } // Pin breakpoints - for (const TPair& PinBreakpoint : FlowGraphNode->PinBreakpoints) + for (const TPair& PinBreakpoint : FlowGraphNode->PinBreakpoints) { if (PinBreakpoint.Key.Get()->Direction == EGPD_Input) { @@ -134,13 +134,13 @@ void SFlowGraphNode::GetOverlayBrushes(bool bSelected, const FVector2D WidgetSiz } } -void SFlowGraphNode::GetPinBrush(const bool bLeftSide, const float WidgetWidth, const int32 PinIndex, const FFlowBreakpoint& Breakpoint, TArray& Brushes) const +void SFlowGraphNode::GetPinBrush(const bool bLeftSide, const float WidgetWidth, const int32 PinIndex, const FFlowPinTrait& Breakpoint, TArray& Brushes) const { - if (Breakpoint.bHasBreakpoint) + if (Breakpoint.IsAllowed()) { FOverlayBrushInfo PinBrush; - if (Breakpoint.bBreakpointHit) + if (Breakpoint.IsHit()) { PinBrush.Brush = FFlowEditorStyle::Get()->GetBrush(TEXT("FlowGraph.PinBreakpointHit")); PinBrush.OverlayOffset.X = bLeftSide ? 0.0f : (WidgetWidth - 36.0f); @@ -148,7 +148,7 @@ void SFlowGraphNode::GetPinBrush(const bool bLeftSide, const float WidgetWidth, } else { - PinBrush.Brush = FFlowEditorStyle::Get()->GetBrush(Breakpoint.bBreakpointEnabled ? TEXT("FlowGraph.BreakpointEnabled") : TEXT("FlowGraph.BreakpointDisabled")); + PinBrush.Brush = FFlowEditorStyle::Get()->GetBrush(Breakpoint.IsEnabled() ? TEXT("FlowGraph.BreakpointEnabled") : TEXT("FlowGraph.BreakpointDisabled")); PinBrush.OverlayOffset.X = bLeftSide ? -24.0f : WidgetWidth; PinBrush.OverlayOffset.Y = 16.0f + PinIndex * 28.0f; } diff --git a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h index 35733f77d..8dba75821 100644 --- a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h +++ b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h @@ -11,40 +11,8 @@ #include "FlowGraphNode.generated.h" class UEdGraphSchema; - class UFlowNode; -USTRUCT() -struct FLOWEDITOR_API FFlowBreakpoint -{ - GENERATED_USTRUCT_BODY() - - UPROPERTY() - bool bHasBreakpoint; - - bool bBreakpointEnabled; - bool bBreakpointHit; - - FFlowBreakpoint() - { - bHasBreakpoint = false; - bBreakpointEnabled = false; - bBreakpointHit = false; - }; - - void AddBreakpoint(); - void RemoveBreakpoint(); - bool HasBreakpoint() const; - - void EnableBreakpoint(); - bool CanEnableBreakpoint() const; - - void DisableBreakpoint(); - bool IsBreakpointEnabled() const; - - void ToggleBreakpoint(); -}; - DECLARE_DELEGATE(FFlowGraphNodeEvent); /** @@ -106,7 +74,7 @@ class FLOWEDITOR_API UFlowGraphNode : public UEdGraphNode public: UPROPERTY() - FFlowBreakpoint NodeBreakpoint; + FFlowPinTrait NodeBreakpoint; // UEdGraphNode virtual bool CanCreateUnderSpecifiedSchema(const UEdGraphSchema* Schema) const override; @@ -179,7 +147,7 @@ class FLOWEDITOR_API UFlowGraphNode : public UEdGraphNode TArray OutputPins; UPROPERTY() - TMap PinBreakpoints; + TMap PinBreakpoints; void CreateInputPin(const FFlowPin& FlowPin, const int32 Index = INDEX_NONE); void CreateOutputPin(const FFlowPin& FlowPin, const int32 Index = INDEX_NONE); diff --git a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h index cc33a3e78..9ddda3fe3 100644 --- a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h +++ b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h @@ -33,7 +33,7 @@ class FLOWEDITOR_API SFlowGraphNode : public SGraphNode virtual void GetOverlayBrushes(bool bSelected, const FVector2D WidgetSize, TArray& Brushes) const override; // -- - virtual void GetPinBrush(const bool bLeftSide, const float WidgetWidth, const int32 PinIndex, const FFlowBreakpoint& Breakpoint, TArray& Brushes) const; + virtual void GetPinBrush(const bool bLeftSide, const float WidgetWidth, const int32 PinIndex, const FFlowPinTrait& Breakpoint, TArray& Brushes) const; // SGraphNode virtual void UpdateGraphNode() override; From e23d943c2aa74747e926a031385f592544a178bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Wed, 26 Jul 2023 13:14:07 +0200 Subject: [PATCH 329/338] prevent crash on missing or invalid asset --- Source/Flow/Private/FlowSubsystem.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index 404d19042..4f43e7250 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -110,7 +110,10 @@ UFlowAsset* UFlowSubsystem::CreateRootFlow(UObject* Owner, UFlowAsset* FlowAsset } UFlowAsset* NewFlow = CreateFlowInstance(Owner, FlowAsset); - RootInstances.Add(NewFlow, Owner); + if (NewFlow) + { + RootInstances.Add(NewFlow, Owner); + } return NewFlow; } @@ -162,15 +165,19 @@ UFlowAsset* UFlowSubsystem::CreateSubFlow(UFlowNode_SubGraph* SubGraphNode, cons { const TWeakObjectPtr Owner = SubGraphNode->GetFlowAsset() ? SubGraphNode->GetFlowAsset()->GetOwner() : nullptr; NewInstance = CreateFlowInstance(Owner, SubGraphNode->Asset, SavedInstanceName); - InstancedSubFlows.Add(SubGraphNode, NewInstance); - if (bPreloading) + if (NewInstance) { - NewInstance->PreloadNodes(); + InstancedSubFlows.Add(SubGraphNode, NewInstance); + + if (bPreloading) + { + NewInstance->PreloadNodes(); + } } } - if (!bPreloading) + if (InstancedSubFlows.Contains(SubGraphNode) && !bPreloading) { // get instanced asset from map - in case it was already instanced by calling CreateSubFlow() with bPreloading == true UFlowAsset* AssetInstance = InstancedSubFlows[SubGraphNode]; @@ -205,7 +212,7 @@ void UFlowSubsystem::RemoveSubFlow(UFlowNode_SubGraph* SubGraphNode, const EFlow UFlowAsset* UFlowSubsystem::CreateFlowInstance(const TWeakObjectPtr Owner, TSoftObjectPtr FlowAsset, FString NewInstanceName) { UFlowAsset* LoadedFlowAsset = FlowAsset.LoadSynchronous(); - if (!ensureAlways(LoadedFlowAsset)) + if (LoadedFlowAsset == nullptr) { return nullptr; } From 23ef5928e797af302e039bfc52457bb5966c44ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Wed, 26 Jul 2023 20:55:36 +0200 Subject: [PATCH 330/338] undef IMAGE_BRUSH_SVG --- Source/FlowEditor/Private/FlowEditorStyle.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Source/FlowEditor/Private/FlowEditorStyle.cpp b/Source/FlowEditor/Private/FlowEditorStyle.cpp index f39409450..23c067776 100644 --- a/Source/FlowEditor/Private/FlowEditorStyle.cpp +++ b/Source/FlowEditor/Private/FlowEditorStyle.cpp @@ -5,9 +5,9 @@ #include "Interfaces/IPluginManager.h" #include "Styling/SlateStyleRegistry.h" -#define IMAGE_BRUSH( RelativePath, ... ) FSlateImageBrush( StyleSet->RootToContentDir( RelativePath, TEXT(".png") ), __VA_ARGS__ ) -#define BOX_BRUSH( RelativePath, ... ) FSlateBoxBrush( StyleSet->RootToContentDir( RelativePath, TEXT(".png") ), __VA_ARGS__ ) #define BORDER_BRUSH( RelativePath, ... ) FSlateBorderBrush( StyleSet->RootToContentDir( RelativePath, TEXT(".png") ), __VA_ARGS__ ) +#define BOX_BRUSH( RelativePath, ... ) FSlateBoxBrush( StyleSet->RootToContentDir( RelativePath, TEXT(".png") ), __VA_ARGS__ ) +#define IMAGE_BRUSH( RelativePath, ... ) FSlateImageBrush( StyleSet->RootToContentDir( RelativePath, TEXT(".png") ), __VA_ARGS__ ) #define IMAGE_BRUSH_SVG( RelativePath, ... ) FSlateVectorImageBrush(StyleSet->RootToContentDir(RelativePath, TEXT(".svg")), __VA_ARGS__) TSharedPtr FFlowEditorStyle::StyleSet = nullptr; @@ -67,6 +67,7 @@ void FFlowEditorStyle::Shutdown() StyleSet.Reset(); } -#undef IMAGE_BRUSH -#undef BOX_BRUSH #undef BORDER_BRUSH +#undef BOX_BRUSH +#undef IMAGE_BRUSH +#undef IMAGE_BRUSH_SVG From df103eee33dace9872d8e78223322be7a29eb3e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Wed, 26 Jul 2023 21:04:50 +0200 Subject: [PATCH 331/338] merged in UE 5.1 and 5.2 versions of code --- .../Private/Asset/FlowDiffControl.cpp | 4 ++++ .../Private/MovieScene/FlowSection.cpp | 17 ++++++++++++++++- .../FlowEditor/Public/Asset/FlowDiffControl.h | 4 ++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/Source/FlowEditor/Private/Asset/FlowDiffControl.cpp b/Source/FlowEditor/Private/Asset/FlowDiffControl.cpp index 6fc3aa500..5dadd8c02 100644 --- a/Source/FlowEditor/Private/Asset/FlowDiffControl.cpp +++ b/Source/FlowEditor/Private/Asset/FlowDiffControl.cpp @@ -34,7 +34,11 @@ FFlowAssetDiffControl::FFlowAssetDiffControl(const UFlowAsset* InOldFlowAsset, c // TDetailsDiffControl::GenerateTreeEntries + "NoDifferences" entry + category label void FFlowAssetDiffControl::GenerateTreeEntries(TArray>& OutTreeEntries, TArray>& OutRealDifferences) { +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION < 2 TDetailsDiffControl::GenerateTreeEntries(OutTreeEntries, OutRealDifferences); +#else + FDetailsDiffControl::GenerateTreeEntries(OutTreeEntries, OutRealDifferences); +#endif const bool bHasDifferences = Children.Num() != 0; if (!bHasDifferences) diff --git a/Source/FlowEditor/Private/MovieScene/FlowSection.cpp b/Source/FlowEditor/Private/MovieScene/FlowSection.cpp index d88c773be..f4278317b 100644 --- a/Source/FlowEditor/Private/MovieScene/FlowSection.cpp +++ b/Source/FlowEditor/Private/MovieScene/FlowSection.cpp @@ -64,8 +64,15 @@ void FFlowSectionBase::PaintEventName(FSequencerSectionPainter& Painter, int32 L FSlateDrawElement::MakeBox( Painter.DrawElements, LayerId + 1, - Painter.SectionGeometry.ToPaintGeometry(BoxOffset, BoxSize), +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION < 1 FEditorStyle::GetBrush("WhiteBrush"), +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION < 2 + Painter.SectionGeometry.ToPaintGeometry(BoxOffset, BoxSize), + FAppStyle::GetBrush("WhiteBrush"), +#else + Painter.SectionGeometry.ToPaintGeometry(BoxSize, FSlateLayoutTransform(1.0f, TransformPoint(1.0f, UE::Slate::CastToVector2f(BoxOffset)))), + FAppStyle::GetBrush("WhiteBrush"), +#endif ESlateDrawEffect::None, FLinearColor::Black.CopyWithNewOpacity(0.5f) ); @@ -76,7 +83,11 @@ void FFlowSectionBase::PaintEventName(FSequencerSectionPainter& Painter, int32 L FSlateDrawElement::MakeText( Painter.DrawElements, LayerId + 2, +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION < 2 Painter.SectionGeometry.ToPaintGeometry(BoxOffset + IconOffset, IconSize), +#else + Painter.SectionGeometry.ToPaintGeometry(IconSize, FSlateLayoutTransform(1.0f, TransformPoint(1.0f, UE::Slate::CastToVector2f(BoxOffset + IconOffset)))), +#endif WarningString, FontAwesomeFont, Painter.bParentEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect, @@ -87,7 +98,11 @@ void FFlowSectionBase::PaintEventName(FSequencerSectionPainter& Painter, int32 L FSlateDrawElement::MakeText( Painter.DrawElements, LayerId + 2, +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION < 2 Painter.SectionGeometry.ToPaintGeometry(BoxOffset + TextOffset, TextSize), +#else + Painter.SectionGeometry.ToPaintGeometry(TextSize, FSlateLayoutTransform(1.0f, TransformPoint(1.0f, UE::Slate::CastToVector2f(BoxOffset + TextOffset)))), +#endif InEventString, SmallLayoutFont, Painter.bParentEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect, diff --git a/Source/FlowEditor/Public/Asset/FlowDiffControl.h b/Source/FlowEditor/Public/Asset/FlowDiffControl.h index f8fa7b6b7..bddb44776 100644 --- a/Source/FlowEditor/Public/Asset/FlowDiffControl.h +++ b/Source/FlowEditor/Public/Asset/FlowDiffControl.h @@ -22,7 +22,11 @@ class SFlowDiff; ///////////////////////////////////////////////////////////////////////////// /// FFlowAssetDiffControl +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION < 2 class FLOWEDITOR_API FFlowAssetDiffControl : public TDetailsDiffControl +#else +class FLOWEDITOR_API FFlowAssetDiffControl : public FDetailsDiffControl +#endif { public: FFlowAssetDiffControl(const UFlowAsset* InOldFlowAsset, const UFlowAsset* InNewFlowAsset, FOnDiffEntryFocused InSelectionCallback); From 2a74d564f5f90a8030c2ac9d4291ec993ff48136 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sun, 28 May 2023 21:45:35 +0200 Subject: [PATCH 332/338] removed empty overrides --- .../Flow/Private/Nodes/World/FlowNode_OnActorRegistered.cpp | 5 ----- .../Private/Nodes/World/FlowNode_OnActorUnregistered.cpp | 5 ----- .../Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp | 5 ----- Source/Flow/Public/Nodes/World/FlowNode_OnActorRegistered.h | 2 -- .../Flow/Public/Nodes/World/FlowNode_OnActorUnregistered.h | 2 -- Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h | 2 -- 6 files changed, 21 deletions(-) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_OnActorRegistered.cpp b/Source/Flow/Private/Nodes/World/FlowNode_OnActorRegistered.cpp index 6ad8ca537..ba6a712ef 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_OnActorRegistered.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_OnActorRegistered.cpp @@ -7,11 +7,6 @@ UFlowNode_OnActorRegistered::UFlowNode_OnActorRegistered(const FObjectInitialize { } -void UFlowNode_OnActorRegistered::ExecuteInput(const FName& PinName) -{ - Super::ExecuteInput(PinName); -} - void UFlowNode_OnActorRegistered::ObserveActor(TWeakObjectPtr Actor, TWeakObjectPtr Component) { if (!RegisteredActors.Contains(Actor)) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_OnActorUnregistered.cpp b/Source/Flow/Private/Nodes/World/FlowNode_OnActorUnregistered.cpp index a802ff41e..488e63b2f 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_OnActorUnregistered.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_OnActorUnregistered.cpp @@ -7,11 +7,6 @@ UFlowNode_OnActorUnregistered::UFlowNode_OnActorUnregistered(const FObjectInitia { } -void UFlowNode_OnActorUnregistered::ExecuteInput(const FName& PinName) -{ - Super::ExecuteInput(PinName); -} - void UFlowNode_OnActorUnregistered::ObserveActor(TWeakObjectPtr Actor, TWeakObjectPtr Component) { if (!RegisteredActors.Contains(Actor)) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp b/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp index ae59ecf3a..477f1a1ed 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp @@ -13,11 +13,6 @@ UFlowNode_OnNotifyFromActor::UFlowNode_OnNotifyFromActor(const FObjectInitialize #endif } -void UFlowNode_OnNotifyFromActor::ExecuteInput(const FName& PinName) -{ - Super::ExecuteInput(PinName); -} - void UFlowNode_OnNotifyFromActor::ObserveActor(TWeakObjectPtr Actor, TWeakObjectPtr Component) { if (!RegisteredActors.Contains(Actor)) diff --git a/Source/Flow/Public/Nodes/World/FlowNode_OnActorRegistered.h b/Source/Flow/Public/Nodes/World/FlowNode_OnActorRegistered.h index ecf4b9e56..d4045c667 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_OnActorRegistered.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_OnActorRegistered.h @@ -14,7 +14,5 @@ class FLOW_API UFlowNode_OnActorRegistered : public UFlowNode_ComponentObserver GENERATED_UCLASS_BODY() protected: - virtual void ExecuteInput(const FName& PinName) override; - virtual void ObserveActor(TWeakObjectPtr Actor, TWeakObjectPtr Component) override; }; diff --git a/Source/Flow/Public/Nodes/World/FlowNode_OnActorUnregistered.h b/Source/Flow/Public/Nodes/World/FlowNode_OnActorUnregistered.h index 4d44d740f..655e98082 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_OnActorUnregistered.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_OnActorUnregistered.h @@ -14,8 +14,6 @@ class FLOW_API UFlowNode_OnActorUnregistered : public UFlowNode_ComponentObserve GENERATED_UCLASS_BODY() protected: - virtual void ExecuteInput(const FName& PinName) override; - virtual void ObserveActor(TWeakObjectPtr Actor, TWeakObjectPtr Component) override; virtual void ForgetActor(TWeakObjectPtr Actor, TWeakObjectPtr Component) override; }; diff --git a/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h b/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h index 9c5f77a7d..b64c4068b 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h @@ -22,8 +22,6 @@ class FLOW_API UFlowNode_OnNotifyFromActor : public UFlowNode_ComponentObserver UPROPERTY(EditAnywhere, Category = "Notify") bool bRetroactive; - virtual void ExecuteInput(const FName& PinName) override; - virtual void ObserveActor(TWeakObjectPtr Actor, TWeakObjectPtr Component) override; virtual void ForgetActor(TWeakObjectPtr Actor, TWeakObjectPtr Component) override; From f3f81d8a7447d2390c6ceb388a79ff35f8e21920 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Wed, 26 Jul 2023 21:21:40 +0200 Subject: [PATCH 333/338] missing merges from other branches --- Source/Flow/Private/Nodes/FlowNode.cpp | 10 ++++++++-- Source/Flow/Public/FlowSave.h | 1 - Source/Flow/Public/Nodes/Route/FlowNode_Timer.h | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 3a8b87da5..6ab023a92 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -562,10 +562,16 @@ void UFlowNode::TriggerInput(const FName& PinName, const EFlowPinActivationType ExecuteInput(PinName); break; case EFlowSignalMode::Disabled: - LogNote(FString::Printf(TEXT("Node disabled while triggering input %s"), *PinName.ToString())); + if (UFlowSettings::Get()->bLogOnSignalDisabled) + { + LogNote(FString::Printf(TEXT("Node disabled while triggering input %s"), *PinName.ToString())); + } break; case EFlowSignalMode::PassThrough: - LogNote(FString::Printf(TEXT("Signal pass-through on triggering input %s"), *PinName.ToString())); + if (UFlowSettings::Get()->bLogOnSignalPassthrough) + { + LogNote(FString::Printf(TEXT("Signal pass-through on triggering input %s"), *PinName.ToString())); + } OnPassThrough(); break; default: ; diff --git a/Source/Flow/Public/FlowSave.h b/Source/Flow/Public/FlowSave.h index d3330eeaa..f79711f9c 100644 --- a/Source/Flow/Public/FlowSave.h +++ b/Source/Flow/Public/FlowSave.h @@ -2,7 +2,6 @@ #pragma once -#include "CoreMinimal.h" #include "GameFramework/SaveGame.h" #include "Serialization/ObjectAndNameAsStringProxyArchive.h" #include "FlowSave.generated.h" diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h b/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h index 984d2ced2..c920c8662 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h @@ -9,7 +9,7 @@ /** * Triggers outputs after time elapsed */ -UCLASS(NotBlueprintable, meta = (DisplayName = "Timer", Keywords = "delay, wait, step, tick")) +UCLASS(NotBlueprintable, meta = (DisplayName = "Timer", Keywords = "delay, step, tick")) class FLOW_API UFlowNode_Timer : public UFlowNode { GENERATED_UCLASS_BODY() From 44cb9917dbc2f77979a1eca14d2111a19469472a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Wed, 26 Jul 2023 21:26:16 +0200 Subject: [PATCH 334/338] Revert "merged in UE 5.1 and 5.2 versions of code" This reverts commit df103eee33dace9872d8e78223322be7a29eb3e4. --- .../Private/Asset/FlowDiffControl.cpp | 4 ---- .../Private/MovieScene/FlowSection.cpp | 17 +---------------- .../FlowEditor/Public/Asset/FlowDiffControl.h | 4 ---- 3 files changed, 1 insertion(+), 24 deletions(-) diff --git a/Source/FlowEditor/Private/Asset/FlowDiffControl.cpp b/Source/FlowEditor/Private/Asset/FlowDiffControl.cpp index 5dadd8c02..6fc3aa500 100644 --- a/Source/FlowEditor/Private/Asset/FlowDiffControl.cpp +++ b/Source/FlowEditor/Private/Asset/FlowDiffControl.cpp @@ -34,11 +34,7 @@ FFlowAssetDiffControl::FFlowAssetDiffControl(const UFlowAsset* InOldFlowAsset, c // TDetailsDiffControl::GenerateTreeEntries + "NoDifferences" entry + category label void FFlowAssetDiffControl::GenerateTreeEntries(TArray>& OutTreeEntries, TArray>& OutRealDifferences) { -#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION < 2 TDetailsDiffControl::GenerateTreeEntries(OutTreeEntries, OutRealDifferences); -#else - FDetailsDiffControl::GenerateTreeEntries(OutTreeEntries, OutRealDifferences); -#endif const bool bHasDifferences = Children.Num() != 0; if (!bHasDifferences) diff --git a/Source/FlowEditor/Private/MovieScene/FlowSection.cpp b/Source/FlowEditor/Private/MovieScene/FlowSection.cpp index f4278317b..d88c773be 100644 --- a/Source/FlowEditor/Private/MovieScene/FlowSection.cpp +++ b/Source/FlowEditor/Private/MovieScene/FlowSection.cpp @@ -64,15 +64,8 @@ void FFlowSectionBase::PaintEventName(FSequencerSectionPainter& Painter, int32 L FSlateDrawElement::MakeBox( Painter.DrawElements, LayerId + 1, -#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION < 1 - FEditorStyle::GetBrush("WhiteBrush"), -#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION < 2 Painter.SectionGeometry.ToPaintGeometry(BoxOffset, BoxSize), - FAppStyle::GetBrush("WhiteBrush"), -#else - Painter.SectionGeometry.ToPaintGeometry(BoxSize, FSlateLayoutTransform(1.0f, TransformPoint(1.0f, UE::Slate::CastToVector2f(BoxOffset)))), - FAppStyle::GetBrush("WhiteBrush"), -#endif + FEditorStyle::GetBrush("WhiteBrush"), ESlateDrawEffect::None, FLinearColor::Black.CopyWithNewOpacity(0.5f) ); @@ -83,11 +76,7 @@ void FFlowSectionBase::PaintEventName(FSequencerSectionPainter& Painter, int32 L FSlateDrawElement::MakeText( Painter.DrawElements, LayerId + 2, -#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION < 2 Painter.SectionGeometry.ToPaintGeometry(BoxOffset + IconOffset, IconSize), -#else - Painter.SectionGeometry.ToPaintGeometry(IconSize, FSlateLayoutTransform(1.0f, TransformPoint(1.0f, UE::Slate::CastToVector2f(BoxOffset + IconOffset)))), -#endif WarningString, FontAwesomeFont, Painter.bParentEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect, @@ -98,11 +87,7 @@ void FFlowSectionBase::PaintEventName(FSequencerSectionPainter& Painter, int32 L FSlateDrawElement::MakeText( Painter.DrawElements, LayerId + 2, -#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION < 2 Painter.SectionGeometry.ToPaintGeometry(BoxOffset + TextOffset, TextSize), -#else - Painter.SectionGeometry.ToPaintGeometry(TextSize, FSlateLayoutTransform(1.0f, TransformPoint(1.0f, UE::Slate::CastToVector2f(BoxOffset + TextOffset)))), -#endif InEventString, SmallLayoutFont, Painter.bParentEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect, diff --git a/Source/FlowEditor/Public/Asset/FlowDiffControl.h b/Source/FlowEditor/Public/Asset/FlowDiffControl.h index bddb44776..f8fa7b6b7 100644 --- a/Source/FlowEditor/Public/Asset/FlowDiffControl.h +++ b/Source/FlowEditor/Public/Asset/FlowDiffControl.h @@ -22,11 +22,7 @@ class SFlowDiff; ///////////////////////////////////////////////////////////////////////////// /// FFlowAssetDiffControl -#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION < 2 class FLOWEDITOR_API FFlowAssetDiffControl : public TDetailsDiffControl -#else -class FLOWEDITOR_API FFlowAssetDiffControl : public FDetailsDiffControl -#endif { public: FFlowAssetDiffControl(const UFlowAsset* InOldFlowAsset, const UFlowAsset* InNewFlowAsset, FOnDiffEntryFocused InSelectionCallback); From 61a8ee9a28fbd2007d66df2a88ec843bb12ee0bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Wed, 26 Jul 2023 21:29:47 +0200 Subject: [PATCH 335/338] removing version of code from UE 5.1, 5.2 code on this branch won't be unified with other branches, as this branch won't support after upcoming release --- .../Private/Nodes/World/FlowNode_PlayLevelSequence.cpp | 4 ---- Source/FlowEditor/Private/Asset/FlowDiffControl.cpp | 4 ---- .../DetailCustomizations/FlowNode_SubGraphDetails.cpp | 9 --------- Source/FlowEditor/Private/MovieScene/FlowTrackEditor.cpp | 5 ----- 4 files changed, 22 deletions(-) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp index d02464a90..60aa544e1 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp @@ -61,11 +61,7 @@ TArray UFlowNode_PlayLevelSequence::GetContextOutputs() Sequence = Sequence.LoadSynchronous(); if (Sequence && Sequence->GetMovieScene()) { -#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION < 2 for (const UMovieSceneTrack* Track : Sequence->GetMovieScene()->GetMasterTracks()) -#else - for (const UMovieSceneTrack* Track : Sequence->GetMovieScene()->GetTracks()) -#endif { if (Track->GetClass() == UMovieSceneFlowTrack::StaticClass()) { diff --git a/Source/FlowEditor/Private/Asset/FlowDiffControl.cpp b/Source/FlowEditor/Private/Asset/FlowDiffControl.cpp index 6fc3aa500..b71e2563d 100644 --- a/Source/FlowEditor/Private/Asset/FlowDiffControl.cpp +++ b/Source/FlowEditor/Private/Asset/FlowDiffControl.cpp @@ -23,11 +23,7 @@ /// FFlowAssetDiffControl FFlowAssetDiffControl::FFlowAssetDiffControl(const UFlowAsset* InOldFlowAsset, const UFlowAsset* InNewFlowAsset, FOnDiffEntryFocused InSelectionCallback) -#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION < 2 : TDetailsDiffControl(InOldFlowAsset, InNewFlowAsset, InSelectionCallback) -#else - : FDetailsDiffControl(InOldFlowAsset, InNewFlowAsset, InSelectionCallback, false) -#endif { } diff --git a/Source/FlowEditor/Private/DetailCustomizations/FlowNode_SubGraphDetails.cpp b/Source/FlowEditor/Private/DetailCustomizations/FlowNode_SubGraphDetails.cpp index d7cfff658..81fbaadd5 100644 --- a/Source/FlowEditor/Private/DetailCustomizations/FlowNode_SubGraphDetails.cpp +++ b/Source/FlowEditor/Private/DetailCustomizations/FlowNode_SubGraphDetails.cpp @@ -4,7 +4,6 @@ #include "DetailLayoutBuilder.h" #include "FlowAsset.h" -#include "Launch/Resources/Version.h" #include "Nodes/Route/FlowNode_SubGraph.h" void FFlowNode_SubGraphDetails::CustomizeDetails(IDetailLayoutBuilder& DetailLayout) @@ -52,21 +51,13 @@ void FFlowNode_SubGraphDetails::CustomizeDetails(IDetailLayoutBuilder& DetailLay FString AllowedClassesString; for (UClass* Class : AllowedClasses) { -#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION < 1 AllowedClassesString.Append(FString::Printf(TEXT("%s,"), *Class->GetFName().ToString())); -#else - AllowedClassesString.Append(FString::Printf(TEXT("%s,"), *Class->GetClassPathName().ToString())); -#endif } FString DisallowedClassesString; for (UClass* Class : DisallowedClasses) { -#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION < 1 DisallowedClassesString.Append(FString::Printf(TEXT("%s,"), *Class->GetFName().ToString())); -#else - DisallowedClassesString.Append(FString::Printf(TEXT("%s,"), *Class->GetClassPathName().ToString())); -#endif } const auto AssetProperty = DetailLayout.GetProperty(FName("Asset"), UFlowNode_SubGraph::StaticClass()); diff --git a/Source/FlowEditor/Private/MovieScene/FlowTrackEditor.cpp b/Source/FlowEditor/Private/MovieScene/FlowTrackEditor.cpp index c540d503b..6bb5a9541 100644 --- a/Source/FlowEditor/Private/MovieScene/FlowTrackEditor.cpp +++ b/Source/FlowEditor/Private/MovieScene/FlowTrackEditor.cpp @@ -163,12 +163,7 @@ void FFlowTrackEditor::HandleAddFlowTrackMenuEntryExecute(UClass* SectionType) c FocusedMovieScene->Modify(); TArray NewTracks; - -#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION < 2 UMovieSceneFlowTrack* NewMasterTrack = FocusedMovieScene->AddMasterTrack(); -#else - UMovieSceneFlowTrack* NewMasterTrack = FocusedMovieScene->AddTrack(); -#endif NewTracks.Add(NewMasterTrack); if (GetSequencer().IsValid()) From f5494bdbf6a281744c65159808ae1fe75c116c20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Wed, 26 Jul 2023 22:17:22 +0200 Subject: [PATCH 336/338] set version to 1.5 --- Flow.uplugin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.uplugin b/Flow.uplugin index d650ea904..8328fd44e 100644 --- a/Flow.uplugin +++ b/Flow.uplugin @@ -1,6 +1,6 @@ { "FileVersion" : 3, - "Version" : 1.4, + "Version" : 1.5, "FriendlyName" : "Flow", "Description" : "Design-agnostic node editor for scripting game’s flow.", "Category" : "Gameplay", From 3846bbde1ae5a149efa0b93ea8f06c8ab0574cbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 1 Sep 2023 10:59:35 +0200 Subject: [PATCH 337/338] exposed GetDefaultEntryNode to blueprints --- Source/Flow/Public/FlowAsset.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 56a0a1548..bae194724 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -157,6 +157,7 @@ class FLOW_API UFlowAsset : public UObject return nullptr; } + UFUNCTION(BlueprintPure, Category = "FlowAsset") virtual UFlowNode* GetDefaultEntryNode() const; #if WITH_EDITOR From 2e6eeff6db6444525909b501273ab347efaa525a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 1 Sep 2023 11:01:10 +0200 Subject: [PATCH 338/338] Sequence node: bSavePinExecutionState is now True by default This addressed a common issue with handling SaveGame for a directed graph. --- .../Route/FlowNode_ExecutionSequence.cpp | 19 ++++++++++--------- .../Nodes/Route/FlowNode_ExecutionSequence.h | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionSequence.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionSequence.cpp index c76a7533e..55402fe21 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionSequence.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionSequence.cpp @@ -4,6 +4,7 @@ UFlowNode_ExecutionSequence::UFlowNode_ExecutionSequence(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) + , bSavePinExecutionState(true) { #if WITH_EDITOR Category = TEXT("Route"); @@ -16,12 +17,12 @@ UFlowNode_ExecutionSequence::UFlowNode_ExecutionSequence(const FObjectInitialize void UFlowNode_ExecutionSequence::ExecuteInput(const FName& PinName) { - if(bSavePinExecutionState) + if (bSavePinExecutionState) { ExecuteNewConnections(); return; } - + for (const FFlowPin& Output : OutputPins) { TriggerOutput(Output.PinName, false); @@ -33,11 +34,11 @@ void UFlowNode_ExecutionSequence::ExecuteInput(const FName& PinName) #if WITH_EDITOR FString UFlowNode_ExecutionSequence::GetNodeDescription() const { - if(bSavePinExecutionState) + if (bSavePinExecutionState) { return TEXT("Saves pin execution state"); } - + return Super::GetNodeDescription(); } #endif @@ -52,12 +53,12 @@ void UFlowNode_ExecutionSequence::ExecuteNewConnections() for (const FFlowPin& Output : OutputPins) { const FConnectedPin& Connection = GetConnection(Output.PinName); - if(ExecutedConnections.Contains(Connection.NodeGuid)) + if (!ExecutedConnections.Contains(Connection.NodeGuid)) { - continue; + ExecutedConnections.Emplace(Connection.NodeGuid); + TriggerOutput(Output.PinName, false); } - - TriggerOutput(Output.PinName, false); - ExecutedConnections.Emplace(Connection.NodeGuid); } + + Finish(); } diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionSequence.h b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionSequence.h index ef7482ca2..ea7f4f5a8 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionSequence.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionSequence.h @@ -37,7 +37,7 @@ class FLOW_API UFlowNode_ExecutionSequence final : public UFlowNode * graph after release. */ UPROPERTY(EditAnywhere, Category = "Sequence") - bool bSavePinExecutionState = false; + bool bSavePinExecutionState; UPROPERTY(SaveGame) TSet ExecutedConnections;