From 236899d812a53266c65071d359a5b9b08d369701 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sat, 6 Feb 2021 14:22:39 +0100 Subject: [PATCH 001/265] --- UE 4.26 --- --- Flow.uplugin | 1 + Source/Flow/Flow.Build.cs | 1 + Source/Flow/Public/MovieScene/MovieSceneFlowTrack.h | 4 +++- Source/Flow/Public/MovieScene/MovieSceneFlowTriggerSection.h | 2 +- Source/FlowEditor/FlowEditor.Build.cs | 1 + 5 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Flow.uplugin b/Flow.uplugin index 528941739..d7a2e1b8e 100644 --- a/Flow.uplugin +++ b/Flow.uplugin @@ -9,6 +9,7 @@ "DocsURL" : "https://github.com/MothCocoon/Flow", "MarketplaceURL" : "", "SupportURL" : "https://discord.com/channels/742802606874820619/752181877938323668", + "EngineVersion": "4.26.0", "EnabledByDefault" : true, "CanContainContent" : false, "IsBetaVersion" : false, diff --git a/Source/Flow/Flow.Build.cs b/Source/Flow/Flow.Build.cs index cb37205ac..a1c5597a9 100644 --- a/Source/Flow/Flow.Build.cs +++ b/Source/Flow/Flow.Build.cs @@ -10,6 +10,7 @@ public Flow(ReadOnlyTargetRules Target) : base(Target) { "Core", "CoreUObject", + "DeveloperSettings", "Engine", "GameplayTags", "LevelSequence", diff --git a/Source/Flow/Public/MovieScene/MovieSceneFlowTrack.h b/Source/Flow/Public/MovieScene/MovieSceneFlowTrack.h index 547706408..af7f07f4d 100644 --- a/Source/Flow/Public/MovieScene/MovieSceneFlowTrack.h +++ b/Source/Flow/Public/MovieScene/MovieSceneFlowTrack.h @@ -9,7 +9,9 @@ struct FMovieSceneEvaluationTrack; * Implements a movie scene track that triggers events in the Flow System during playback. */ UCLASS() -class FLOW_API UMovieSceneFlowTrack : public UMovieSceneNameableTrack +class FLOW_API UMovieSceneFlowTrack + : public UMovieSceneNameableTrack + , public IMovieSceneTrackTemplateProducer { GENERATED_BODY() diff --git a/Source/Flow/Public/MovieScene/MovieSceneFlowTriggerSection.h b/Source/Flow/Public/MovieScene/MovieSceneFlowTriggerSection.h index 1985b006a..880beb995 100644 --- a/Source/Flow/Public/MovieScene/MovieSceneFlowTriggerSection.h +++ b/Source/Flow/Public/MovieScene/MovieSceneFlowTriggerSection.h @@ -1,6 +1,6 @@ #pragma once -#include "Sections/MovieSceneStringChannel.h" +#include "Channels/MovieSceneStringChannel.h" #include "MovieSceneFlowSectionBase.h" #include "MovieSceneFlowTriggerSection.generated.h" diff --git a/Source/FlowEditor/FlowEditor.Build.cs b/Source/FlowEditor/FlowEditor.Build.cs index dbca62661..cf40227dd 100644 --- a/Source/FlowEditor/FlowEditor.Build.cs +++ b/Source/FlowEditor/FlowEditor.Build.cs @@ -21,6 +21,7 @@ public FlowEditor(ReadOnlyTargetRules Target) : base(Target) "Core", "CoreUObject", "DetailCustomizations", + "DeveloperSettings", "EditorStyle", "Engine", "GraphEditor", From 49c10bf8a00e5be09cf414a4e607506faac1b360 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 7 Feb 2021 18:48:23 +0100 Subject: [PATCH 002/265] typo fix --- Source/Flow/Public/FlowSubsystem.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index 771a81cc6..dad5fb2ff 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -10,7 +10,7 @@ class UFlowAsset; class UFlowNode_SubGraph; -DECLARE_MULTICAST_DELEGATE_OneParam(FSimpleFlowComponentnEvent, UFlowComponent* /*Component*/); +DECLARE_MULTICAST_DELEGATE_OneParam(FSimpleFlowComponentEvent, UFlowComponent* /*Component*/); /** * Flow Control System @@ -69,8 +69,8 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem virtual void RegisterComponent(UFlowComponent* Component); virtual void UnregisterComponent(UFlowComponent* Component); - FSimpleFlowComponentnEvent OnComponentRegistered; - FSimpleFlowComponentnEvent OnComponentUnregistered; + FSimpleFlowComponentEvent OnComponentRegistered; + FSimpleFlowComponentEvent OnComponentUnregistered; template TArray> GetComponents(const FGameplayTag& Tag) const From 99eb6b370e6434678d9107ebf5d466b5f25d7912 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sat, 20 Feb 2021 18:20:52 +0100 Subject: [PATCH 003/265] class comment added --- Source/Flow/Public/FlowSubsystem.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index dad5fb2ff..001cb1ef8 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -13,7 +13,10 @@ class UFlowNode_SubGraph; DECLARE_MULTICAST_DELEGATE_OneParam(FSimpleFlowComponentEvent, UFlowComponent* /*Component*/); /** - * Flow Control System + * Flow Subsystem + * - manages lifetime of Flow Graphs + * - connects Flow Graphs with actors containing the Flow Component + * - convenient base for project-specific systems */ UCLASS() class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem From 837e8d29c16c8ce5b6c5d1148f8f68bc8e71f10f Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 21 Feb 2021 12:59:27 +0100 Subject: [PATCH 004/265] added method to open primary node's asset by path --- Source/Flow/Private/Nodes/FlowNode.cpp | 9 ++++-- .../Private/Nodes/Route/FlowNode_SubGraph.cpp | 2 +- .../World/FlowNode_PlayLevelSequence.cpp | 2 +- Source/Flow/Public/Nodes/FlowNode.h | 10 +++++-- .../Public/Nodes/Route/FlowNode_SubGraph.h | 2 +- .../Nodes/World/FlowNode_PlayLevelSequence.h | 2 +- .../Private/Asset/FlowAssetEditor.cpp | 29 ++++++++++--------- .../Private/Graph/Nodes/FlowGraphNode.cpp | 7 +---- .../Public/Graph/Nodes/FlowGraphNode.h | 1 - 9 files changed, 35 insertions(+), 29 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 752fc0495..ede8c7168 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -325,9 +325,14 @@ FString UFlowNode::GetStatusString() const return K2_GetStatusString(); } -UObject* UFlowNode::GetAssetToOpen() +FString UFlowNode::GetAssetPath() { - return K2_GetAssetToOpen(); + return K2_GetAssetPath(); +} + +UObject* UFlowNode::GetAssetToEdit() +{ + return K2_GetAssetToEdit(); } AActor* UFlowNode::GetActorToFocus() diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp index b4b6de463..1e3ab78d2 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp @@ -73,7 +73,7 @@ FString UFlowNode_SubGraph::GetNodeDescription() const return Asset.IsNull() ? FString() : Asset.ToSoftObjectPath().GetAssetName(); } -UObject* UFlowNode_SubGraph::GetAssetToOpen() +UObject* UFlowNode_SubGraph::GetAssetToEdit() { return Asset.IsNull() ? nullptr : LoadAsset(Asset); } diff --git a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp index b5dba2d08..851c47f60 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp @@ -214,7 +214,7 @@ FString UFlowNode_PlayLevelSequence::GetStatusString() const return GetPlaybackProgress(); } -UObject* UFlowNode_PlayLevelSequence::GetAssetToOpen() +UObject* UFlowNode_PlayLevelSequence::GetAssetToEdit() { return Sequence.IsNull() ? nullptr : LoadAsset(Sequence); } diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index e4a54a90e..e79381ecf 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -269,7 +269,8 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte // Information displayed while node is working - displayed over node as NodeInfoPopup virtual FString GetStatusString() const; - virtual UObject* GetAssetToOpen(); + virtual FString GetAssetPath(); + virtual UObject* GetAssetToEdit(); virtual AActor* GetActorToFocus(); #endif @@ -278,8 +279,11 @@ 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 = "GetAssetToOpen")) - UObject* K2_GetAssetToOpen(); + UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "GetAssetPath")) + FString K2_GetAssetPath(); + + UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "GetAssetToEdit")) + UObject* K2_GetAssetToEdit(); UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "GetActorToFocus")) AActor* K2_GetActorToFocus(); diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h b/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h index 4f53a4d58..77c5d969d 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h @@ -32,7 +32,7 @@ class FLOW_API UFlowNode_SubGraph : public UFlowNode #if WITH_EDITOR virtual FString GetNodeDescription() const override; - virtual UObject* GetAssetToOpen() override; + virtual UObject* GetAssetToEdit() override; virtual bool SupportsContextPins() const override { return true; } virtual bool CanRefreshContextPinsOnLoad() const override { return true; } diff --git a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h index 5195a0528..806a0e753 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h @@ -76,7 +76,7 @@ class FLOW_API UFlowNode_PlayLevelSequence : public UFlowNode #if WITH_EDITOR virtual FString GetNodeDescription() const override; virtual FString GetStatusString() const override; - virtual UObject* GetAssetToOpen() override; + virtual UObject* GetAssetToEdit() override; #endif #if ENABLE_VISUAL_LOG diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index a8721e7d3..76c6560ce 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -932,27 +932,30 @@ void FFlowAssetEditor::OnNodeDoubleClicked(class UEdGraphNode* Node) const { UFlowNode* FlowNode = Cast(Node)->GetFlowNode(); - if (UObject* AssetToOpen = FlowNode->GetAssetToOpen()) + if (FlowNode) { - GEditor->GetEditorSubsystem()->OpenEditorForAsset(AssetToOpen); - - if (IsPIE()) + const FString AssetPath = FlowNode->GetAssetPath(); + if (!AssetPath.IsEmpty()) + { + GEditor->GetEditorSubsystem()->OpenEditorForAsset(AssetPath); + } + else if (UObject* AssetToEdit = FlowNode->GetAssetToEdit()) { - if (UFlowNode_SubGraph* SubGraphNode = Cast(FlowNode)) + GEditor->GetEditorSubsystem()->OpenEditorForAsset(AssetToEdit); + + if (IsPIE()) { - const TWeakObjectPtr SubFlowInstance = SubGraphNode->GetFlowAsset()->GetFlowInstance(SubGraphNode); - if (SubFlowInstance.IsValid()) + if (UFlowNode_SubGraph* SubGraphNode = Cast(FlowNode)) { - SubGraphNode->GetFlowAsset()->TemplateAsset->SetInspectedInstance(SubFlowInstance->GetDisplayName()); + const TWeakObjectPtr SubFlowInstance = SubGraphNode->GetFlowAsset()->GetFlowInstance(SubGraphNode); + if (SubFlowInstance.IsValid()) + { + SubGraphNode->GetFlowAsset()->TemplateAsset->SetInspectedInstance(SubFlowInstance->GetDisplayName()); + } } } } } - - /*if (ObjectsToView.Num() > 0) - { - GEditor->SyncBrowserToObjects(ObjectsToView); - }*/ } void FFlowAssetEditor::OnNodeTitleCommitted(const FText& NewText, ETextCommit::Type CommitInfo, UEdGraphNode* NodeBeingChanged) diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 4f3d8fe3d..baa191d51 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -611,14 +611,9 @@ bool UFlowGraphNode::IsContentPreloaded() const return false; } -UObject* UFlowGraphNode::GetAssetToOpen() const -{ - return FlowNode ? FlowNode->GetAssetToOpen() : nullptr; -} - bool UFlowGraphNode::CanFocusViewport() const { - return FlowNode ? (GEditor->bIsSimulatingInEditor && FlowNode->GetAssetToOpen()) : false; + return FlowNode ? (GEditor->bIsSimulatingInEditor && FlowNode->GetActorToFocus()) : false; } void UFlowGraphNode::CreateInputPin(const FName& PinName, const int32 Index /*= INDEX_NONE*/) diff --git a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h index 9164e4099..ccdac1f84 100644 --- a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h +++ b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h @@ -145,7 +145,6 @@ class FLOWEDITOR_API UFlowGraphNode : public UEdGraphNode // check this to display information while node is preloaded bool IsContentPreloaded() const; - UObject* GetAssetToOpen() const; bool CanFocusViewport() const; ////////////////////////////////////////////////////////////////////////// From ec173be74e9e15f2a53d11649b73eb0805d34237 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 8 Mar 2021 18:49:45 +0100 Subject: [PATCH 005/265] added generic error strings --- Source/Flow/Private/Nodes/FlowNode.cpp | 3 +++ .../Nodes/World/FlowNode_ComponentObserver.cpp | 12 +++++++++++- .../Private/Nodes/World/FlowNode_NotifyActor.cpp | 2 +- .../Nodes/World/FlowNode_OnNotifyFromActor .cpp | 2 +- Source/Flow/Public/Nodes/FlowNode.h | 10 +++++++++- .../Public/Nodes/World/FlowNode_ComponentObserver.h | 2 ++ 6 files changed, 27 insertions(+), 4 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index ede8c7168..b4e800a21 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -11,6 +11,9 @@ FName UFlowNode::DefaultInputName(TEXT("In")); FName UFlowNode::DefaultOutputName(TEXT("Out")); +FString UFlowNode::MissingIdentityTag = TEXT("Missing Identity Tag!"); +FString UFlowNode::NoActorsFound = TEXT("No actors found!"); + #if !UE_BUILD_SHIPPING FPinRecord::FPinRecord() { diff --git a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp index 93bbbb8a2..76a50bd3e 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp @@ -28,7 +28,7 @@ void UFlowNode_ComponentObserver::ExecuteInput(const FName& PinName) } else { - LogError("Missing Identity Tag"); + LogError(MissingIdentityTag); } } @@ -82,4 +82,14 @@ FString UFlowNode_ComponentObserver::GetNodeDescription() const { return IdentityTag.IsValid() ? IdentityTag.ToString() : TEXT("Missing Identity Tag!"); } + +FString UFlowNode_ComponentObserver::GetStatusString() const +{ + if (ActivationState == EFlowActivationState::Active && RegisteredActors.Num() == 0) + { + return NoActorsFound; + } + + return FString(); +} #endif diff --git a/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp b/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp index 873e03b8b..b6f8fdd12 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp @@ -28,7 +28,7 @@ void UFlowNode_NotifyActor::ExecuteInput(const FName& PinName) #if WITH_EDITOR FString UFlowNode_NotifyActor::GetNodeDescription() const { - const FString IdentityString = IdentityTag.IsValid() ? IdentityTag.ToString() : TEXT("Missing Identity Tag!"); + const FString IdentityString = IdentityTag.IsValid() ? IdentityTag.ToString() : MissingIdentityTag; const FString NotifyString = NotifyTag.IsValid() ? NotifyTag.ToString() : TEXT("---"); return IdentityString + LINE_TERMINATOR + NotifyString; diff --git a/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor .cpp b/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor .cpp index ba7f59979..a4c70fc56 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor .cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor .cpp @@ -41,7 +41,7 @@ void UFlowNode_OnNotifyFromActor::ForgetActor(TWeakObjectPtr Actor, TWea #if WITH_EDITOR FString UFlowNode_OnNotifyFromActor::GetNodeDescription() const { - const FString IdentityString = IdentityTag.IsValid() ? IdentityTag.ToString() : TEXT("Missing Identity Tag!"); + const FString IdentityString = IdentityTag.IsValid() ? IdentityTag.ToString() : MissingIdentityTag; const FString NotifyString = NotifyTag.IsValid() ? NotifyTag.ToString() : TEXT("---"); return IdentityString + LINE_TERMINATOR + NotifyString; diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index e79381ecf..d9833808f 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -177,6 +177,12 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte static void RecursiveFindNodesByClass(UFlowNode* Node, const TSubclassOf Class, uint8 Depth, TArray& OutNodes); +////////////////////////////////////////////////////////////////////////// +// Debugger +protected: + static FString MissingIdentityTag; + static FString NoActorsFound; + ////////////////////////////////////////////////////////////////////////// // Runtime @@ -187,10 +193,12 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte FStreamableManager StreamableManager; #if !UE_BUILD_SHIPPING +protected: + EFlowActivationState ActivationState; + private: TMap> InputRecords; TMap> OutputRecords; - EFlowActivationState ActivationState; #endif public: diff --git a/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h b/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h index 80b89f23c..6c730d399 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h @@ -24,6 +24,7 @@ class FLOW_API UFlowNode_ComponentObserver : public UFlowNode TMap, TWeakObjectPtr> RegisteredActors; +protected: virtual void ExecuteInput(const FName& PinName) override; virtual void StartObserving(); @@ -40,5 +41,6 @@ class FLOW_API UFlowNode_ComponentObserver : public UFlowNode #if WITH_EDITOR public: virtual FString GetNodeDescription() const override; + virtual FString GetStatusString() const override; #endif }; From c79eb2830c504681ebcf61c57f29f1153ece2ec2 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 8 Mar 2021 20:24:25 +0100 Subject: [PATCH 006/265] check if any Spawn Node shortcuts have been defined --- .../FlowEditor/Private/Asset/FlowAssetEditor.cpp | 14 ++++++++------ Source/FlowEditor/Private/FlowEditorCommands.cpp | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index 76c6560ce..e1c7320ff 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -552,13 +552,15 @@ FReply FFlowAssetEditor::OnSpawnGraphNodeByShortcut(FInputChord InChord, const F { UEdGraph* Graph = InGraph; - TSharedPtr Action = FFlowSpawnNodeCommands::Get().GetActionByChord(InChord); - - if (Action.IsValid()) + if (FFlowSpawnNodeCommands::IsRegistered()) { - TArray DummyPins; - Action->PerformAction(Graph, DummyPins, InPosition); - return FReply::Handled(); + TSharedPtr Action = FFlowSpawnNodeCommands::Get().GetActionByChord(InChord); + if (Action.IsValid()) + { + TArray DummyPins; + Action->PerformAction(Graph, DummyPins, InPosition); + return FReply::Handled(); + } } return FReply::Unhandled(); diff --git a/Source/FlowEditor/Private/FlowEditorCommands.cpp b/Source/FlowEditor/Private/FlowEditorCommands.cpp index f8511a2b2..e95e11795 100644 --- a/Source/FlowEditor/Private/FlowEditorCommands.cpp +++ b/Source/FlowEditor/Private/FlowEditorCommands.cpp @@ -138,7 +138,7 @@ TSharedPtr FFlowSpawnNodeCommands::GetActionByChord(FInput } } - return nullptr; + return TSharedPtr(); } TSharedPtr FFlowSpawnNodeCommands::GetActionByClass(UClass* NodeClass) const From 852e515fe9929ea201f2a4c5802c39b672253d1f Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 9 Mar 2021 10:19:22 +0100 Subject: [PATCH 007/265] fixed the support URL --- Flow.uplugin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.uplugin b/Flow.uplugin index d7a2e1b8e..ebef2d974 100644 --- a/Flow.uplugin +++ b/Flow.uplugin @@ -8,7 +8,7 @@ "CreatedByURL" : "https://twitter.com/MothDoctor", "DocsURL" : "https://github.com/MothCocoon/Flow", "MarketplaceURL" : "", - "SupportURL" : "https://discord.com/channels/742802606874820619/752181877938323668", + "SupportURL" : "https://discord.gg/aUuSw9ZP", "EngineVersion": "4.26.0", "EnabledByDefault" : true, "CanContainContent" : false, From 20b5a14fda0fdb3495ef578490fbd5bd12808bd1 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 9 Mar 2021 22:34:59 +0100 Subject: [PATCH 008/265] renamed FlowEditorSettings to FlowGraphSettings --- .../FlowGraphConnectionDrawingPolicy.cpp | 26 +++++++++---------- .../FlowGraphSettings.cpp} | 4 +-- .../Private/Graph/Nodes/FlowGraphNode.cpp | 6 ++--- .../Private/Graph/Widgets/SFlowGraphNode.cpp | 12 ++++----- .../FlowGraphSettings.h} | 8 +++--- 5 files changed, 28 insertions(+), 28 deletions(-) rename Source/FlowEditor/Private/{FlowEditorSettings.cpp => Graph/FlowGraphSettings.cpp} (91%) rename Source/FlowEditor/Public/{FlowEditorSettings.h => Graph/FlowGraphSettings.h} (88%) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp b/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp index 33c3f07b3..40e752b50 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp @@ -1,9 +1,9 @@ #include "Graph/FlowGraphConnectionDrawingPolicy.h" #include "Asset/FlowAssetEditor.h" -#include "FlowEditorSettings.h" #include "Graph/FlowGraph.h" #include "Graph/FlowGraphSchema.h" +#include "Graph/FlowGraphSettings.h" #include "Graph/FlowGraphUtils.h" #include "Graph/Nodes/FlowGraphNode.h" @@ -31,17 +31,17 @@ FFlowGraphConnectionDrawingPolicy::FFlowGraphConnectionDrawingPolicy(int32 InBac , GraphObj(InGraphObj) { // Cache off the editor options - RecentWireDuration = UFlowEditorSettings::Get()->RecentWireDuration; + RecentWireDuration = UFlowGraphSettings::Get()->RecentWireDuration; - InactiveColor = UFlowEditorSettings::Get()->InactiveWireColor; - RecentColor = UFlowEditorSettings::Get()->RecentWireColor; - RecordedColor = UFlowEditorSettings::Get()->RecordedWireColor; - SelectedColor = UFlowEditorSettings::Get()->SelectedWireColor; + InactiveColor = UFlowGraphSettings::Get()->InactiveWireColor; + RecentColor = UFlowGraphSettings::Get()->RecentWireColor; + RecordedColor = UFlowGraphSettings::Get()->RecordedWireColor; + SelectedColor = UFlowGraphSettings::Get()->SelectedWireColor; - InactiveWireThickness = UFlowEditorSettings::Get()->InactiveWireThickness; - RecentWireThickness = UFlowEditorSettings::Get()->RecentWireThickness; - RecordedWireThickness = UFlowEditorSettings::Get()->RecordedWireThickness; - SelectedWireThickness = UFlowEditorSettings::Get()->SelectedWireThickness; + InactiveWireThickness = UFlowGraphSettings::Get()->InactiveWireThickness; + RecentWireThickness = UFlowGraphSettings::Get()->RecentWireThickness; + RecordedWireThickness = UFlowGraphSettings::Get()->RecordedWireThickness; + SelectedWireThickness = UFlowGraphSettings::Get()->SelectedWireThickness; // Don't want to draw ending arrowheads ArrowImage = nullptr; @@ -79,7 +79,7 @@ void FFlowGraphConnectionDrawingPolicy::BuildPaths() } } - if (GraphObj && (UFlowEditorSettings::Get()->bHighlightInputWiresOfSelectedNodes || UFlowEditorSettings::Get()->bHighlightOutputWiresOfSelectedNodes)) + if (GraphObj && (UFlowGraphSettings::Get()->bHighlightInputWiresOfSelectedNodes || UFlowGraphSettings::Get()->bHighlightOutputWiresOfSelectedNodes)) { const TSharedPtr FlowAssetEditor = FFlowGraphUtils::GetFlowAssetEditor(GraphObj); if (FlowAssetEditor.IsValid()) @@ -88,8 +88,8 @@ void FFlowGraphConnectionDrawingPolicy::BuildPaths() { for (UEdGraphPin* Pin : SelectedNode->Pins) { - if (Pin->Direction == EGPD_Input && UFlowEditorSettings::Get()->bHighlightInputWiresOfSelectedNodes - || Pin->Direction == EGPD_Output && UFlowEditorSettings::Get()->bHighlightOutputWiresOfSelectedNodes) + if (Pin->Direction == EGPD_Input && UFlowGraphSettings::Get()->bHighlightInputWiresOfSelectedNodes + || Pin->Direction == EGPD_Output && UFlowGraphSettings::Get()->bHighlightOutputWiresOfSelectedNodes) { for (UEdGraphPin* LinkedPin : Pin->LinkedTo) { diff --git a/Source/FlowEditor/Private/FlowEditorSettings.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp similarity index 91% rename from Source/FlowEditor/Private/FlowEditorSettings.cpp rename to Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp index a1cafafa8..623695d38 100644 --- a/Source/FlowEditor/Private/FlowEditorSettings.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSettings.cpp @@ -1,6 +1,6 @@ -#include "FlowEditorSettings.h" +#include "Graph/FlowGraphSettings.h" -UFlowEditorSettings::UFlowEditorSettings(const FObjectInitializer& ObjectInitializer) +UFlowGraphSettings::UFlowGraphSettings(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) , bShowDefaultPinNames(false) , ExecPinColorModifier(0.75f, 0.75f, 0.75f, 1.0f) diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index baa191d51..0da5e0b66 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -1,10 +1,10 @@ #include "Graph/Nodes/FlowGraphNode.h" -#include "FlowEditorSettings.h" -#include "Graph/FlowGraph.h" #include "Asset/FlowDebugger.h" #include "FlowEditorCommands.h" +#include "Graph/FlowGraph.h" #include "Graph/FlowGraphSchema.h" +#include "Graph/FlowGraphSettings.h" #include "Graph/Widgets/SFlowGraphNode.h" #include "FlowAsset.h" @@ -534,7 +534,7 @@ FLinearColor UFlowGraphNode::GetNodeTitleColor() const { if (FlowNode) { - if (const FLinearColor* Color = UFlowEditorSettings::Get()->NodeTitleColors.Find(FlowNode->GetNodeStyle())) + if (const FLinearColor* Color = UFlowGraphSettings::Get()->NodeTitleColors.Find(FlowNode->GetNodeStyle())) { return *Color; } diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp index 78d30e516..fe237b212 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp @@ -1,6 +1,6 @@ #include "Graph/Widgets/SFlowGraphNode.h" -#include "FlowEditorSettings.h" #include "FlowEditorStyle.h" +#include "Graph/FlowGraphSettings.h" #include "Nodes/FlowNode.h" @@ -17,7 +17,7 @@ SFlowGraphPinExec::SFlowGraphPinExec() { - PinColorModifier = UFlowEditorSettings::Get()->ExecPinColorModifier; + PinColorModifier = UFlowGraphSettings::Get()->ExecPinColorModifier; } void SFlowGraphPinExec::Construct(const FArguments& InArgs, UEdGraphPin* InPin) @@ -87,7 +87,7 @@ void SFlowGraphNode::GetNodeInfoPopups(FNodeInfoContext* Context, TArrayGetNodeDescription(); if (!Description.IsEmpty()) { - const FGraphInformationPopupInfo DescriptionPopup = FGraphInformationPopupInfo(nullptr, UFlowEditorSettings::Get()->NodeDescriptionBackground, Description); + const FGraphInformationPopupInfo DescriptionPopup = FGraphInformationPopupInfo(nullptr, UFlowGraphSettings::Get()->NodeDescriptionBackground, Description); Popups.Add(DescriptionPopup); } @@ -96,12 +96,12 @@ void SFlowGraphNode::GetNodeInfoPopups(FNodeInfoContext* Context, TArrayGetStatusString(); if (!Status.IsEmpty()) { - const FGraphInformationPopupInfo DescriptionPopup = FGraphInformationPopupInfo(nullptr, UFlowEditorSettings::Get()->NodeStatusBackground, Status); + const FGraphInformationPopupInfo DescriptionPopup = FGraphInformationPopupInfo(nullptr, UFlowGraphSettings::Get()->NodeStatusBackground, Status); Popups.Add(DescriptionPopup); } else if (FlowGraphNode->IsContentPreloaded()) { - const FGraphInformationPopupInfo DescriptionPopup = FGraphInformationPopupInfo(nullptr, UFlowEditorSettings::Get()->NodeStatusBackground, TEXT("Preloaded")); + const FGraphInformationPopupInfo DescriptionPopup = FGraphInformationPopupInfo(nullptr, UFlowGraphSettings::Get()->NodeStatusBackground, TEXT("Preloaded")); Popups.Add(DescriptionPopup); } } @@ -422,7 +422,7 @@ void SFlowGraphNode::CreateStandardPinWidget(UEdGraphPin* Pin) { TSharedPtr NewPin = SNew(SFlowGraphPinExec, Pin); - if (!UFlowEditorSettings::Get()->bShowDefaultPinNames && FlowGraphNode->GetFlowNode()) + if (!UFlowGraphSettings::Get()->bShowDefaultPinNames && FlowGraphNode->GetFlowNode()) { if (Pin->Direction == EGPD_Input) { diff --git a/Source/FlowEditor/Public/FlowEditorSettings.h b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h similarity index 88% rename from Source/FlowEditor/Public/FlowEditorSettings.h rename to Source/FlowEditor/Public/Graph/FlowGraphSettings.h index 4128da0bf..5dd0f2659 100644 --- a/Source/FlowEditor/Public/FlowEditorSettings.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h @@ -3,17 +3,17 @@ #include "Engine/DeveloperSettings.h" #include "FlowTypes.h" -#include "FlowEditorSettings.generated.h" +#include "FlowGraphSettings.generated.h" /** * */ -UCLASS(Config = Editor, defaultconfig, meta = (DisplayName = "Flow Editor")) -class UFlowEditorSettings final : public UDeveloperSettings +UCLASS(Config = Editor, defaultconfig, meta = (DisplayName = "Flow Graph")) +class UFlowGraphSettings final : public UDeveloperSettings { GENERATED_UCLASS_BODY() - static UFlowEditorSettings* Get() { return CastChecked(UFlowEditorSettings::StaticClass()->GetDefaultObject()); } + static UFlowGraphSettings* Get() { return CastChecked(UFlowGraphSettings::StaticClass()->GetDefaultObject()); } /** Hide default pin names on simple nodes, reduces UI clutter */ UPROPERTY(EditAnywhere, config, Category = "Nodes") From 6b2b13afc0923b90587d104a1cbdad4c421dcd11 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Wed, 10 Mar 2021 12:17:56 +0100 Subject: [PATCH 009/265] marking FlowComponent as Blueprintable --- Source/Flow/Public/FlowComponent.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Flow/Public/FlowComponent.h b/Source/Flow/Public/FlowComponent.h index 0fba84e0a..d55e63008 100644 --- a/Source/Flow/Public/FlowComponent.h +++ b/Source/Flow/Public/FlowComponent.h @@ -10,7 +10,7 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FFlowComponentDynamicNotify, class /** * Base component of Flow System - makes possible to communicate between Flow graph and actors */ -UCLASS(meta = (BlueprintSpawnableComponent)) +UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent)) class FLOW_API UFlowComponent : public UActorComponent { GENERATED_UCLASS_BODY() From ae433cd4d4b349b0ec2da5161434d5ee28499053 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Wed, 10 Mar 2021 15:10:49 +0100 Subject: [PATCH 010/265] exposed Flow Subsystem method to blueprints --- Source/Flow/Private/FlowSubsystem.cpp | 55 ++++++++++++++++++- .../World/FlowNode_ComponentObserver.cpp | 4 +- Source/Flow/Public/FlowSubsystem.h | 43 ++++++++++----- .../Nodes/World/FlowNode_ComponentObserver.h | 3 + 4 files changed, 88 insertions(+), 17 deletions(-) diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index c8fa05e6f..06b138497 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -26,7 +26,7 @@ void UFlowSubsystem::Deinitialize() InstancedTemplates[i]->ClearInstances(); } } - + InstancedTemplates.Empty(); InstancedSubFlows.Empty(); } @@ -38,7 +38,7 @@ void UFlowSubsystem::StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset) UE_LOG(LogFlow, Warning, TEXT("Attempted to start Root Flow again. Owner: %s. Flow Asset: %s."), *Owner->GetName(), *FlowAsset->GetName()); return; } - + UFlowAsset* NewFlow = CreateFlowInstance(FlowAsset); RootInstances.Add(Owner, NewFlow); @@ -144,3 +144,54 @@ void UFlowSubsystem::UnregisterComponent(UFlowComponent* Component) OnComponentUnregistered.Broadcast(Component); } + +TArray UFlowSubsystem::GetFlowComponents(const FGameplayTag& Tag) const +{ + TArray> FoundComponents; + FlowComponents.MultiFind(Tag, FoundComponents); + + TArray ResultComponents; + for (const TWeakObjectPtr& Component : FoundComponents) + { + if (Component.IsValid()) + { + ResultComponents.Emplace(Component.Get()); + } + } + + return ResultComponents; +} + +TArray UFlowSubsystem::GetFlowActors(const FGameplayTag& Tag) const +{ + TArray> FoundComponents; + FlowComponents.MultiFind(Tag, FoundComponents); + + TArray ResultActors; + for (const TWeakObjectPtr& Component : FoundComponents) + { + if (Component.IsValid()) + { + ResultActors.Emplace(Component->GetOwner()); + } + } + + return ResultActors; +} + +TMap UFlowSubsystem::GetFlowActorsAndComponents(const FGameplayTag& Tag) const +{ + TArray> FoundComponents; + FlowComponents.MultiFind(Tag, FoundComponents); + + TMap ResultActors; + for (const TWeakObjectPtr& Component : FoundComponents) + { + if (Component.IsValid()) + { + ResultActors.Emplace(Component->GetOwner(), Component.Get()); + } + } + + return ResultActors; +} diff --git a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp index 76a50bd3e..e970b90e8 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp @@ -39,8 +39,8 @@ void UFlowNode_ComponentObserver::StartObserving() ObserveActor(FoundComponent->GetOwner(), FoundComponent); } - GetFlowSubsystem()->OnComponentRegistered.AddUObject(this, &UFlowNode_ComponentObserver::OnComponentRegistered); - GetFlowSubsystem()->OnComponentUnregistered.AddUObject(this, &UFlowNode_ComponentObserver::OnComponentUnregistered); + GetFlowSubsystem()->OnComponentRegistered.AddDynamic(this, &UFlowNode_ComponentObserver::OnComponentRegistered); + GetFlowSubsystem()->OnComponentUnregistered.AddDynamic(this, &UFlowNode_ComponentObserver::OnComponentUnregistered); } void UFlowNode_ComponentObserver::StopObserving() diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index 001cb1ef8..302309d65 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -10,7 +10,7 @@ class UFlowAsset; class UFlowNode_SubGraph; -DECLARE_MULTICAST_DELEGATE_OneParam(FSimpleFlowComponentEvent, UFlowComponent* /*Component*/); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FSimpleFlowComponentEvent, UFlowComponent*, Component); /** * Flow Subsystem @@ -26,7 +26,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem UFlowSubsystem(); FStreamableManager Streamable; - + // all asset templates with active instances UPROPERTY() TArray InstancedTemplates; @@ -34,7 +34,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem // asset instanced by object from another system like World Settings, not SubGraph node UPROPERTY() TMap RootInstances; - + // assets instanced by Sub Graph nodes UPROPERTY() TMap InstancedSubFlows; @@ -72,46 +72,63 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem virtual void RegisterComponent(UFlowComponent* Component); virtual void UnregisterComponent(UFlowComponent* Component); + // Called when actor with Flow Component appears in the world + UPROPERTY(BlueprintAssignable, Category = "FlowSubsystem") FSimpleFlowComponentEvent OnComponentRegistered; + + // Called when actor with Flow Component disappears from the world + UPROPERTY(BlueprintAssignable, Category = "FlowSubsystem") FSimpleFlowComponentEvent OnComponentUnregistered; - template + // Returns all registered Flow Components with given tag + UFUNCTION(BlueprintPure, Category = "FlowSubsystem") + TArray GetFlowComponents(const FGameplayTag& Tag) const; + + // Returns all registered actors containing Flow Component with given tag + UFUNCTION(BlueprintPure, Category = "FlowSubsystem") + TArray GetFlowActors(const FGameplayTag& Tag) const; + + // Returns all registered actors as pairs: Actor as key, its Flow Component as value + UFUNCTION(BlueprintPure, Category = "FlowSubsystem") + TMap GetFlowActorsAndComponents(const FGameplayTag& Tag) const; + + template TArray> GetComponents(const FGameplayTag& Tag) const { static_assert(TPointerIsConvertibleFromTo::Value, "'T' template parameter to GetComponents must be derived from UActorComponent"); - + TArray> FoundComponents; FlowComponents.MultiFind(Tag, FoundComponents); - TArray> ResultComponents; + TArray> Result; for (const TWeakObjectPtr& Component : FoundComponents) { if (Component->GetClass()->IsChildOf(T::StaticClass())) { - ResultComponents.Emplace(Cast(Component)); + Result.Emplace(Cast(Component)); } } - return ResultComponents; + return Result; } - template + template TMap, TWeakObjectPtr> GetActors(const FGameplayTag& Tag) const { static_assert(TPointerIsConvertibleFromTo::Value, "'T' template parameter to GetComponents must be derived from AActor"); - + TArray> FoundComponents; FlowComponents.MultiFind(Tag, FoundComponents); - TMap, TWeakObjectPtr> ResultActors; + TMap, TWeakObjectPtr> Result; for (const TWeakObjectPtr& Component : FoundComponents) { if (Component->GetOwner()->GetClass()->IsChildOf(T::StaticClass())) { - ResultActors.Emplace(Cast(Component->GetOwner()), Component); + Result.Emplace(Cast(Component->GetOwner()), Component); } } - return ResultActors; + return Result; } }; diff --git a/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h b/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h index 6c730d399..0a5250d97 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h @@ -30,7 +30,10 @@ class FLOW_API UFlowNode_ComponentObserver : public UFlowNode virtual void StartObserving(); virtual void StopObserving(); + UFUNCTION() virtual void OnComponentRegistered(UFlowComponent* Component); + + UFUNCTION() virtual void OnComponentUnregistered(UFlowComponent* Component); virtual void ObserveActor(TWeakObjectPtr Actor, TWeakObjectPtr Component) {} From a4ca034af06f853c33417a00753da52c9fe3ec69 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Wed, 10 Mar 2021 15:55:47 +0100 Subject: [PATCH 011/265] updating .ini --- Config/BaseFlow.ini | 1 + Config/DefaultFlow.ini | 1 + 2 files changed, 2 insertions(+) create mode 100644 Config/BaseFlow.ini create mode 100644 Config/DefaultFlow.ini diff --git a/Config/BaseFlow.ini b/Config/BaseFlow.ini new file mode 100644 index 000000000..f2fdc43eb --- /dev/null +++ b/Config/BaseFlow.ini @@ -0,0 +1 @@ +[CoreRedirects] diff --git a/Config/DefaultFlow.ini b/Config/DefaultFlow.ini new file mode 100644 index 000000000..f2fdc43eb --- /dev/null +++ b/Config/DefaultFlow.ini @@ -0,0 +1 @@ +[CoreRedirects] From 069877ea0dc00c04e761494eedbd5ac34b523b98 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Thu, 11 Mar 2021 13:32:04 +0100 Subject: [PATCH 012/265] marking IdentityTags as BlueprintReadOnly --- Source/Flow/Public/FlowComponent.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Flow/Public/FlowComponent.h b/Source/Flow/Public/FlowComponent.h index d55e63008..8f1f61915 100644 --- a/Source/Flow/Public/FlowComponent.h +++ b/Source/Flow/Public/FlowComponent.h @@ -15,7 +15,7 @@ class FLOW_API UFlowComponent : public UActorComponent { GENERATED_UCLASS_BODY() - UPROPERTY(EditAnywhere, Category = "Flow") + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Flow") FGameplayTagContainer IdentityTags; FFlowComponentNotify OnNotifyFromComponent; From ee6cb4f6bc597a78ccb2c92f77cd85d71153bcb8 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Thu, 11 Mar 2021 21:21:50 +0100 Subject: [PATCH 013/265] getting Flow Components by multiple tags --- Source/Flow/Private/FlowSubsystem.cpp | 106 +++++++++++++++++++++++--- Source/Flow/Public/FlowSubsystem.h | 73 ++++++++++++++++-- 2 files changed, 160 insertions(+), 19 deletions(-) diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index 06b138497..a9886cdba 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -145,53 +145,135 @@ void UFlowSubsystem::UnregisterComponent(UFlowComponent* Component) OnComponentUnregistered.Broadcast(Component); } -TArray UFlowSubsystem::GetFlowComponents(const FGameplayTag& Tag) const +TArray UFlowSubsystem::GetFlowComponentsByTag(const FGameplayTag Tag) const { TArray> FoundComponents; FlowComponents.MultiFind(Tag, FoundComponents); - TArray ResultComponents; + TArray Result; for (const TWeakObjectPtr& Component : FoundComponents) { if (Component.IsValid()) { - ResultComponents.Emplace(Component.Get()); + Result.Emplace(Component.Get()); } } - return ResultComponents; + return Result; } -TArray UFlowSubsystem::GetFlowActors(const FGameplayTag& Tag) const +TArray UFlowSubsystem::GetFlowComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType) const +{ + TSet> FoundComponents; + FindComponents(Tags, FoundComponents, MatchType); + + TArray Result; + for (const TWeakObjectPtr& Component : FoundComponents) + { + if (Component.IsValid()) + { + Result.Emplace(Component.Get()); + } + } + + return Result; +} + +TArray UFlowSubsystem::GetFlowActorsByTag(const FGameplayTag Tag) const { TArray> FoundComponents; FlowComponents.MultiFind(Tag, FoundComponents); - TArray ResultActors; + TArray Result; for (const TWeakObjectPtr& Component : FoundComponents) { if (Component.IsValid()) { - ResultActors.Emplace(Component->GetOwner()); + Result.Emplace(Component->GetOwner()); } } - return ResultActors; + return Result; } -TMap UFlowSubsystem::GetFlowActorsAndComponents(const FGameplayTag& Tag) const +TArray UFlowSubsystem::GetFlowActorsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType) const +{ + TSet> FoundComponents; + FindComponents(Tags, FoundComponents, MatchType); + + TArray Result; + for (const TWeakObjectPtr& Component : FoundComponents) + { + if (Component.IsValid()) + { + Result.Emplace(Component->GetOwner()); + } + } + + return Result; +} + +TMap UFlowSubsystem::GetFlowActorsAndComponentsByTag(const FGameplayTag Tag) const { TArray> FoundComponents; FlowComponents.MultiFind(Tag, FoundComponents); - TMap ResultActors; + TMap Result; + for (const TWeakObjectPtr& Component : FoundComponents) + { + if (Component.IsValid()) + { + Result.Emplace(Component->GetOwner(), Component.Get()); + } + } + + return Result; +} + +TMap UFlowSubsystem::GetFlowActorsAndComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType) const +{ + TSet> FoundComponents; + FindComponents(Tags, FoundComponents, MatchType); + + TMap Result; for (const TWeakObjectPtr& Component : FoundComponents) { if (Component.IsValid()) { - ResultActors.Emplace(Component->GetOwner(), Component.Get()); + Result.Emplace(Component->GetOwner(), Component.Get()); } } - return ResultActors; + return Result; +} + +void UFlowSubsystem::FindComponents(const FGameplayTagContainer& Tags, TSet>& OutComponents, const EGameplayContainerMatchType MatchType) const +{ + if (MatchType == EGameplayContainerMatchType::Any) + { + for (const FGameplayTag& Tag : Tags) + { + TArray> ComponentsPerTag; + FlowComponents.MultiFind(Tag, ComponentsPerTag); + OutComponents.Append(ComponentsPerTag); + } + } + else // EGameplayContainerMatchType::All + { + TSet> ComponentsWithAnyTag; + for (const FGameplayTag& Tag : Tags) + { + TArray> ComponentsPerTag; + FlowComponents.MultiFind(Tag, ComponentsPerTag); + ComponentsWithAnyTag.Append(ComponentsPerTag); + } + + for (const TWeakObjectPtr& Component : ComponentsWithAnyTag) + { + if (Component.IsValid() && Component->IdentityTags.HasAllExact(Tags)) + { + OutComponents.Emplace(Component); + } + } + } } diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index 302309d65..c957c22e5 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -80,18 +80,31 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem UPROPERTY(BlueprintAssignable, Category = "FlowSubsystem") FSimpleFlowComponentEvent OnComponentUnregistered; - // Returns all registered Flow Components with given tag + // Returns all registered Flow Components identified by given tag UFUNCTION(BlueprintPure, Category = "FlowSubsystem") - TArray GetFlowComponents(const FGameplayTag& Tag) const; + TArray GetFlowComponentsByTag(const FGameplayTag Tag) const; - // Returns all registered actors containing Flow Component with given tag + // Returns all registered Flow Components identified by at least one of given tags UFUNCTION(BlueprintPure, Category = "FlowSubsystem") - TArray GetFlowActors(const FGameplayTag& Tag) const; + TArray GetFlowComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType) const; + + // Returns all registered actors with Flow Component identified by given tag + UFUNCTION(BlueprintPure, Category = "FlowSubsystem") + TArray GetFlowActorsByTag(const FGameplayTag Tag) const; + + // Returns all registered actors with Flow Component identified by at least one of given tags + UFUNCTION(BlueprintPure, Category = "FlowSubsystem") + TArray GetFlowActorsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType) const; // Returns all registered actors as pairs: Actor as key, its Flow Component as value UFUNCTION(BlueprintPure, Category = "FlowSubsystem") - TMap GetFlowActorsAndComponents(const FGameplayTag& Tag) const; + TMap GetFlowActorsAndComponentsByTag(const FGameplayTag Tag) const; + // Returns all registered actors as pairs: Actor as key, its Flow Component as value + UFUNCTION(BlueprintPure, Category = "FlowSubsystem") + TMap GetFlowActorsAndComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType) const; + + // Returns all registered Flow Components identified by given tag template TArray> GetComponents(const FGameplayTag& Tag) const { @@ -103,7 +116,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem TArray> Result; for (const TWeakObjectPtr& Component : FoundComponents) { - if (Component->GetClass()->IsChildOf(T::StaticClass())) + if (Component.IsValid() && Component->GetClass()->IsChildOf(T::StaticClass())) { Result.Emplace(Cast(Component)); } @@ -112,6 +125,28 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem return Result; } + // Returns all registered Flow Components identified by at least one of given tags + template + TArray> GetComponents(const FGameplayTagContainer& Tags, const EGameplayContainerMatchType MatchType) const + { + static_assert(TPointerIsConvertibleFromTo::Value, "'T' template parameter to GetComponents must be derived from UActorComponent"); + + TSet> FoundComponents; + FindComponents(Tags, FoundComponents, MatchType); + + TArray> Result; + for (const TWeakObjectPtr& Component : FoundComponents) + { + if (Component.IsValid() && Component->GetClass()->IsChildOf(T::StaticClass())) + { + Result.Emplace(Cast(Component)); + } + } + + return Result; + } + + // Returns all registered actors with Flow Component identified by given tag template TMap, TWeakObjectPtr> GetActors(const FGameplayTag& Tag) const { @@ -123,7 +158,28 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem TMap, TWeakObjectPtr> Result; for (const TWeakObjectPtr& Component : FoundComponents) { - if (Component->GetOwner()->GetClass()->IsChildOf(T::StaticClass())) + if (Component.IsValid() && Component->GetOwner()->GetClass()->IsChildOf(T::StaticClass())) + { + Result.Emplace(Cast(Component->GetOwner()), Component); + } + } + + 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 + { + static_assert(TPointerIsConvertibleFromTo::Value, "'T' template parameter to GetComponents must be derived from AActor"); + + TSet> FoundComponents; + FindComponents(Tags, FoundComponents, MatchType); + + TMap, TWeakObjectPtr> Result; + for (const TWeakObjectPtr& Component : FoundComponents) + { + if (Component.IsValid() && Component->GetOwner()->GetClass()->IsChildOf(T::StaticClass())) { Result.Emplace(Cast(Component->GetOwner()), Component); } @@ -131,4 +187,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem return Result; } + +private: + void FindComponents(const FGameplayTagContainer& Tags, TSet>& OutComponents, const EGameplayContainerMatchType MatchType) const; }; From b06a96af1db71fec745f324cbe104412ff5f0700 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Thu, 11 Mar 2021 22:29:27 +0100 Subject: [PATCH 014/265] exposed obtaining active graphs and nodes (for debugging) --- Source/Flow/Public/FlowAsset.h | 16 +++++++++--- Source/Flow/Public/FlowSubsystem.h | 26 ++++++++++++------- .../FlowGraphConnectionDrawingPolicy.cpp | 4 +-- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 830ef1014..67dfbad9d 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -168,16 +168,18 @@ class FLOW_API UFlowAsset : public UObject UPROPERTY() TSet PreloadedNodes; + // Nodes that have any work left, not marked as Finished yet UPROPERTY() TArray ActiveNodes; + // All nodes active in the past, done their work UPROPERTY() TArray RecordedNodes; public: void InitInstance(UFlowAsset* InTemplateAsset); void PreloadNodes(); - + virtual void StartFlow(); virtual void StartAsSubFlow(UFlowNode_SubGraph* SubGraphNode); virtual void FinishFlow(const bool bFlowCompleted); @@ -201,7 +203,15 @@ class FLOW_API UFlowAsset : public UObject UFlowAsset* GetMasterInstance() const; UFlowNode* GetNodeInstance(const FGuid Guid) const; + // Are there any active nodes? + UFUNCTION(BlueprintPure, Category = "Flow") bool IsActive() const { return ActiveNodes.Num() > 0; } - void GetActiveNodes(TArray& OutNodes) const { OutNodes = ActiveNodes; } - void GetRecordedNodes(TArray& OutNodes) const { OutNodes = RecordedNodes; } + + // Returns nodes that have any work left, not marked as Finished yet + UFUNCTION(BlueprintPure, Category = "Flow") + TArray GetActiveNodes() const { return ActiveNodes; } + + // Returns nodes active in the past, done their work + UFUNCTION(BlueprintPure, Category = "Flow") + TArray GetRecordedNodes() const { return RecordedNodes; } }; diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index c957c22e5..26cbd2f53 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -27,15 +27,15 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem FStreamableManager Streamable; - // all asset templates with active instances + // All asset templates with active instances UPROPERTY() TArray InstancedTemplates; - // asset instanced by object from another system like World Settings, not SubGraph node + // Assets instanced by object from another system like World Settings, not SubGraph node UPROPERTY() TMap RootInstances; - // assets instanced by Sub Graph nodes + // Assets instanced by Sub Graph nodes UPROPERTY() TMap InstancedSubFlows; @@ -59,13 +59,21 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem UFlowAsset* CreateFlowInstance(TSoftObjectPtr FlowAsset); public: + // Returns assets instanced by object from another system like World Settings + UFUNCTION(BlueprintPure, Category = "FlowSubsystem") + TMap GetRootInstances() const { return RootInstances; } + + // Returns assets instanced by Sub Graph nodes + UFUNCTION(BlueprintPure, Category = "FlowSubsystem") + TMap GetInstancedSubFlows() const { return InstancedSubFlows; } + virtual UWorld* GetWorld() const override; ////////////////////////////////////////////////////////////////////////// // Component Registry private: - // all the Flow Components currently existing in the world + // All the Flow Components currently existing in the world TMultiMap> FlowComponents; public: @@ -86,7 +94,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem // Returns all registered Flow Components identified by at least one of given tags UFUNCTION(BlueprintPure, Category = "FlowSubsystem") - TArray GetFlowComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType) const; + TArray GetFlowComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType) const; // Returns all registered actors with Flow Component identified by given tag UFUNCTION(BlueprintPure, Category = "FlowSubsystem") @@ -94,7 +102,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem // Returns all registered actors with Flow Component identified by at least one of given tags UFUNCTION(BlueprintPure, Category = "FlowSubsystem") - TArray GetFlowActorsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType) const; + TArray GetFlowActorsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType) const; // Returns all registered actors as pairs: Actor as key, its Flow Component as value UFUNCTION(BlueprintPure, Category = "FlowSubsystem") @@ -102,7 +110,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem // Returns all registered actors as pairs: Actor as key, its Flow Component as value UFUNCTION(BlueprintPure, Category = "FlowSubsystem") - TMap GetFlowActorsAndComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType) const; + TMap GetFlowActorsAndComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType) const; // Returns all registered Flow Components identified by given tag template @@ -127,7 +135,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem // Returns all registered Flow Components identified by at least one of given tags template - TArray> GetComponents(const FGameplayTagContainer& Tags, const EGameplayContainerMatchType MatchType) const + TArray> GetComponents(const FGameplayTagContainer& Tags, const EGameplayContainerMatchType MatchType) const { static_assert(TPointerIsConvertibleFromTo::Value, "'T' template parameter to GetComponents must be derived from UActorComponent"); @@ -169,7 +177,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem // 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 + TMap, TWeakObjectPtr> GetActors(const FGameplayTagContainer& Tags, const EGameplayContainerMatchType MatchType) const { static_assert(TPointerIsConvertibleFromTo::Value, "'T' template parameter to GetComponents must be derived from AActor"); diff --git a/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp b/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp index 40e752b50..b31478200 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp @@ -54,9 +54,7 @@ void FFlowGraphConnectionDrawingPolicy::BuildPaths() { const double CurrentTime = FApp::GetCurrentTime(); - TArray Nodes; - FlowInstance->GetRecordedNodes(Nodes); - for (const UFlowNode* Node : Nodes) + for (const UFlowNode* Node : FlowInstance->GetRecordedNodes()) { const UFlowGraphNode* FlowGraphNode = Cast(Node->GetGraphNode()); From 47ca46f208330d98b8cef030cfc204c46806d07c Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Thu, 11 Mar 2021 22:58:44 +0100 Subject: [PATCH 015/265] #13 refresh graph node in opened graph after changing Input/Output names in blueprint node --- Source/Flow/Private/Nodes/FlowNode.cpp | 11 +++++++++++ Source/Flow/Public/Nodes/FlowNode.h | 4 ++++ .../Private/Graph/Nodes/FlowGraphNode.cpp | 14 ++++++++++++-- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index b4e800a21..a9f225090 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -58,6 +58,17 @@ UFlowNode::UFlowNode(const FObjectInitializer& ObjectInitializer) } #if WITH_EDITOR +void UFlowNode::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) +{ + Super::PostEditChangeProperty(PropertyChangedEvent); + + if (PropertyChangedEvent.Property + && (PropertyChangedEvent.GetPropertyName() == GET_MEMBER_NAME_CHECKED(UFlowNode, InputNames) || PropertyChangedEvent.GetPropertyName() == GET_MEMBER_NAME_CHECKED(UFlowNode, OutputNames))) + { + OnReconstructionRequested.ExecuteIfBound(); + } +} + void UFlowNode::SetGraphNode(UEdGraphNode* NewGraph) { GraphNode = NewGraph; diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index d9833808f..5fe634d4c 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -88,6 +88,10 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte #endif public: + // UObject + virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; + // -- + UEdGraphNode* GetGraphNode() const { return GraphNode; } #if WITH_EDITOR diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 0da5e0b66..322986bae 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -618,16 +618,26 @@ bool UFlowGraphNode::CanFocusViewport() const void UFlowGraphNode::CreateInputPin(const FName& PinName, const int32 Index /*= INDEX_NONE*/) { + if (PinName.IsNone()) + { + return; + } + const FEdGraphPinType PinType = FEdGraphPinType(UEdGraphSchema_K2::PC_Exec, FName(NAME_None), nullptr, EPinContainerType::None, false, FEdGraphTerminalType()); - UEdGraphPin* NewPin = CreatePin(EGPD_Input, PinType, PinName.IsNone() ? UFlowNode::DefaultInputName : PinName, Index); + UEdGraphPin* NewPin = CreatePin(EGPD_Input, PinType, PinName, Index); InputPins.Emplace(NewPin); } void UFlowGraphNode::CreateOutputPin(const FName PinName, const int32 Index /*= INDEX_NONE*/) { + if (PinName.IsNone()) + { + return; + } + const FEdGraphPinType PinType = FEdGraphPinType(UEdGraphSchema_K2::PC_Exec, FName(NAME_None), nullptr, EPinContainerType::None, false, FEdGraphTerminalType()); - UEdGraphPin* NewPin = CreatePin(EGPD_Output, PinType, PinName.IsNone() ? UFlowNode::DefaultOutputName : PinName, Index); + UEdGraphPin* NewPin = CreatePin(EGPD_Output, PinType, PinName, Index); OutputPins.Emplace(NewPin); } From 80a9645f597a50c47220cfb33983296fd24a907d Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 12 Mar 2021 12:25:43 +0100 Subject: [PATCH 016/265] don't create Flow Subsystem on clients --- Source/Flow/Private/FlowSubsystem.cpp | 5 +++++ Source/Flow/Public/FlowSubsystem.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index a9886cdba..15a308df9 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -13,6 +13,11 @@ UFlowSubsystem::UFlowSubsystem() { } +bool UFlowSubsystem::ShouldCreateSubsystem(UObject* Outer) const +{ + return Outer->GetWorld()->GetNetMode() < NM_Client && Outer->GetWorld()->IsServer(); +} + void UFlowSubsystem::Initialize(FSubsystemCollectionBase& Collection) { } diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index 26cbd2f53..6baf42a85 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -40,6 +40,8 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem TMap InstancedSubFlows; public: + virtual bool ShouldCreateSubsystem(UObject* Outer) const override; + virtual void Initialize(FSubsystemCollectionBase& Collection) override; virtual void Deinitialize() override; From e9c93bfb3181839d979262d1eea23a0fdb3f838a Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 14 Mar 2021 16:59:38 +0100 Subject: [PATCH 017/265] removed debugging leftover than prevented listing some of blueprint nodes --- Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp | 3 +-- Source/FlowEditor/Public/Graph/FlowGraphSchema.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp index c535a78ce..b536ea836 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -19,7 +19,6 @@ #define LOCTEXT_NAMESPACE "FlowGraphSchema" -FName UFlowGraphSchema::FlowNodeClassName = TEXT("FlowNode"); TArray UFlowGraphSchema::NativeFlowNodes; TMap UFlowGraphSchema::BlueprintFlowNodes; TArray UFlowGraphSchema::FlowNodeClasses; @@ -309,7 +308,7 @@ void UFlowGraphSchema::AddAsset(const FAssetData& AssetData, const bool bBatch) UClass* NativeParentClass = FindObject(ANY_PACKAGE, *NativeParentClassPath); // accept only Flow Node blueprints - if (NativeParentClass && NativeParentClass->GetFName() == FlowNodeClassName) + if (NativeParentClass && NativeParentClass->IsChildOf(UFlowNode::StaticClass())) { FString GeneratedClassPath; AssetData.GetTagValue(FBlueprintTags::GeneratedClassPath, GeneratedClassPath); diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h index b323cd839..e0f14db45 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h @@ -46,7 +46,6 @@ class FLOWEDITOR_API UFlowGraphSchema : public UEdGraphSchema static FFlowGraphSchemaRefresh OnNodeListChanged; private: - static FName FlowNodeClassName; static TArray NativeFlowNodes; static TMap BlueprintFlowNodes; static TArray FlowNodeClasses; From e6ee93ba69a933e0620f9f3ad73d8ce1f52b4eaf Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 14 Mar 2021 18:49:46 +0100 Subject: [PATCH 018/265] return TSet while obtaining Flow Components/Actors from the registry - TArray wouldn't actually be that useful as we can't rely on the order of returned elements - it's cheaper way to ensure uniqueness of actors - TSet actually has advantage thanks to methods like Difference() --- Source/Flow/Private/FlowSubsystem.cpp | 16 ++++++++-------- Source/Flow/Public/FlowSubsystem.h | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index 15a308df9..94167cb09 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -150,12 +150,12 @@ void UFlowSubsystem::UnregisterComponent(UFlowComponent* Component) OnComponentUnregistered.Broadcast(Component); } -TArray UFlowSubsystem::GetFlowComponentsByTag(const FGameplayTag Tag) const +TSet UFlowSubsystem::GetFlowComponentsByTag(const FGameplayTag Tag) const { TArray> FoundComponents; FlowComponents.MultiFind(Tag, FoundComponents); - TArray Result; + TSet Result; for (const TWeakObjectPtr& Component : FoundComponents) { if (Component.IsValid()) @@ -167,12 +167,12 @@ TArray UFlowSubsystem::GetFlowComponentsByTag(const FGameplayTa return Result; } -TArray UFlowSubsystem::GetFlowComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType) const +TSet UFlowSubsystem::GetFlowComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType) const { TSet> FoundComponents; FindComponents(Tags, FoundComponents, MatchType); - TArray Result; + TSet Result; for (const TWeakObjectPtr& Component : FoundComponents) { if (Component.IsValid()) @@ -184,12 +184,12 @@ TArray UFlowSubsystem::GetFlowComponentsByTags(const FGameplayT return Result; } -TArray UFlowSubsystem::GetFlowActorsByTag(const FGameplayTag Tag) const +TSet UFlowSubsystem::GetFlowActorsByTag(const FGameplayTag Tag) const { TArray> FoundComponents; FlowComponents.MultiFind(Tag, FoundComponents); - TArray Result; + TSet Result; for (const TWeakObjectPtr& Component : FoundComponents) { if (Component.IsValid()) @@ -201,12 +201,12 @@ TArray UFlowSubsystem::GetFlowActorsByTag(const FGameplayTag Tag) const return Result; } -TArray UFlowSubsystem::GetFlowActorsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType) const +TSet UFlowSubsystem::GetFlowActorsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType) const { TSet> FoundComponents; FindComponents(Tags, FoundComponents, MatchType); - TArray Result; + TSet Result; for (const TWeakObjectPtr& Component : FoundComponents) { if (Component.IsValid()) diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index 6baf42a85..1f7a52984 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -92,19 +92,19 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem // Returns all registered Flow Components identified by given tag UFUNCTION(BlueprintPure, Category = "FlowSubsystem") - TArray GetFlowComponentsByTag(const FGameplayTag Tag) const; + TSet GetFlowComponentsByTag(const FGameplayTag Tag) const; // Returns all registered Flow Components identified by at least one of given tags UFUNCTION(BlueprintPure, Category = "FlowSubsystem") - TArray GetFlowComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType) const; + TSet GetFlowComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType) const; // Returns all registered actors with Flow Component identified by given tag UFUNCTION(BlueprintPure, Category = "FlowSubsystem") - TArray GetFlowActorsByTag(const FGameplayTag Tag) const; + TSet GetFlowActorsByTag(const FGameplayTag Tag) const; // Returns all registered actors with Flow Component identified by at least one of given tags UFUNCTION(BlueprintPure, Category = "FlowSubsystem") - TArray GetFlowActorsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType) const; + TSet GetFlowActorsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType) const; // Returns all registered actors as pairs: Actor as key, its Flow Component as value UFUNCTION(BlueprintPure, Category = "FlowSubsystem") @@ -116,14 +116,14 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem // Returns all registered Flow Components identified by given tag template - TArray> GetComponents(const FGameplayTag& Tag) const + TSet> GetComponents(const FGameplayTag& Tag) const { static_assert(TPointerIsConvertibleFromTo::Value, "'T' template parameter to GetComponents must be derived from UActorComponent"); TArray> FoundComponents; FlowComponents.MultiFind(Tag, FoundComponents); - TArray> Result; + TSet> Result; for (const TWeakObjectPtr& Component : FoundComponents) { if (Component.IsValid() && Component->GetClass()->IsChildOf(T::StaticClass())) @@ -137,14 +137,14 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem // Returns all registered Flow Components identified by at least one of given tags template - TArray> GetComponents(const FGameplayTagContainer& Tags, const EGameplayContainerMatchType MatchType) const + TSet> GetComponents(const FGameplayTagContainer& Tags, const EGameplayContainerMatchType MatchType) const { static_assert(TPointerIsConvertibleFromTo::Value, "'T' template parameter to GetComponents must be derived from UActorComponent"); TSet> FoundComponents; FindComponents(Tags, FoundComponents, MatchType); - TArray> Result; + TSet> Result; for (const TWeakObjectPtr& Component : FoundComponents) { if (Component.IsValid() && Component->GetClass()->IsChildOf(T::StaticClass())) From dc0d4f55cdcbd9b19b7adb5ef361312eba57cf4f Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 15 Mar 2021 11:45:13 +0100 Subject: [PATCH 019/265] missing ifdef --- Source/Flow/Public/Nodes/FlowNode.h | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 5fe634d4c..06d3b53ff 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -74,7 +74,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte private: UPROPERTY() UEdGraphNode* GraphNode; - + #if WITH_EDITORONLY_DATA protected: UPROPERTY(EditDefaultsOnly, Category = "FlowNode") @@ -88,12 +88,14 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte #endif public: +#if WITH_EDITOR // UObject virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; // -- - +#endif + UEdGraphNode* GetGraphNode() const { return GraphNode; } - + #if WITH_EDITOR void SetGraphNode(UEdGraphNode* NewGraph); @@ -186,7 +188,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte protected: static FString MissingIdentityTag; static FString NoActorsFound; - + ////////////////////////////////////////////////////////////////////////// // Runtime @@ -199,7 +201,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte #if !UE_BUILD_SHIPPING protected: EFlowActivationState ActivationState; - + private: TMap> InputRecords; TMap> OutputRecords; @@ -292,10 +294,10 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte FString K2_GetStatusString() const; UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "GetAssetPath")) - FString K2_GetAssetPath(); - + FString K2_GetAssetPath(); + UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "GetAssetToEdit")) - UObject* K2_GetAssetToEdit(); + UObject* K2_GetAssetToEdit(); UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "GetActorToFocus")) AActor* K2_GetActorToFocus(); From c8e9c76e147951dd94e2a2fe59a7a53f2ec48363 Mon Sep 17 00:00:00 2001 From: sturcotte06 Date: Mon, 15 Mar 2021 15:52:38 -0400 Subject: [PATCH 020/265] Merge pull request #20 * adds is data valid to flow asset to validate nodes * adds missing forward declare and include --- Source/Flow/Private/FlowAsset.cpp | 14 ++++++++++++++ Source/Flow/Public/FlowAsset.h | 2 ++ Source/Flow/Public/FlowSettings.h | 1 + 3 files changed, 17 insertions(+) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 36c6cf411..7cc07f285 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -48,6 +48,20 @@ void UFlowAsset::PostDuplicate(bool bDuplicateForPIE) } } +EDataValidationResult UFlowAsset::IsDataValid(TArray& ValidationErrors) +{ + for (const TPair& NodePair : Nodes) + { + EDataValidationResult Result = NodePair.Value->IsDataValid(ValidationErrors); + if (Result == EDataValidationResult::Invalid) + { + return EDataValidationResult::Invalid; + } + } + + return EDataValidationResult::Valid; +} + TSharedPtr UFlowAsset::FlowGraphInterface = nullptr; void UFlowAsset::SetFlowGraphInterface(TSharedPtr InFlowAssetEditor) diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 67dfbad9d..49e5e49ce 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -10,6 +10,7 @@ class UFlowNode_SubGraph; class UFlowSubsystem; class UEdGraph; +class UEdGraphNode; class UFlowAsset; #if WITH_EDITOR @@ -52,6 +53,7 @@ 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; // -- #endif diff --git a/Source/Flow/Public/FlowSettings.h b/Source/Flow/Public/FlowSettings.h index 65c237066..76e5eacdd 100644 --- a/Source/Flow/Public/FlowSettings.h +++ b/Source/Flow/Public/FlowSettings.h @@ -1,6 +1,7 @@ #pragma once #include "Engine/DeveloperSettings.h" +#include "Templates/SubclassOf.h" #include "FlowSettings.generated.h" class UFlowNode; From 1c97d209efe92573b0c00656b1124e1d9009395e Mon Sep 17 00:00:00 2001 From: sturcotte06 Date: Tue, 16 Mar 2021 10:43:40 -0400 Subject: [PATCH 021/265] fix includes for linux builds (#21) * fix includes for linux builds * fix more includes for linux and non-unity builds * fix more includes for linux and non-unity builds Co-authored-by: Simon Turcotte-Langevin --- Source/Flow/Private/FlowComponent.cpp | 1 + Source/Flow/Private/FlowModule.cpp | 2 ++ Source/Flow/Private/Nodes/FlowNode.cpp | 1 + Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp | 3 +++ Source/Flow/Public/FlowModule.h | 1 + Source/Flow/Public/FlowSubsystem.h | 1 + Source/Flow/Public/Nodes/Route/FlowNode_Timer.h | 1 + Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h | 1 + 8 files changed, 11 insertions(+) diff --git a/Source/Flow/Private/FlowComponent.cpp b/Source/Flow/Private/FlowComponent.cpp index a6ec04389..af9ce24bd 100644 --- a/Source/Flow/Private/FlowComponent.cpp +++ b/Source/Flow/Private/FlowComponent.cpp @@ -1,6 +1,7 @@ #include "FlowComponent.h" #include "FlowSubsystem.h" +#include "Engine/GameInstance.h" #include "Engine/World.h" UFlowComponent::UFlowComponent(const FObjectInitializer& ObjectInitializer) diff --git a/Source/Flow/Private/FlowModule.cpp b/Source/Flow/Private/FlowModule.cpp index b3e9ebfd2..0b8a9a35d 100644 --- a/Source/Flow/Private/FlowModule.cpp +++ b/Source/Flow/Private/FlowModule.cpp @@ -1,5 +1,7 @@ #include "FlowModule.h" +#include "Modules/ModuleManager.h" + #define LOCTEXT_NAMESPACE "Flow" void FFlowModule::StartupModule() diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index a9f225090..f76784da9 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -5,6 +5,7 @@ #include "FlowSubsystem.h" #include "FlowTypes.h" +#include "Engine/Engine.h" #include "Engine/World.h" #include "Misc/App.h" diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp index 1075393b9..ad41488f1 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp @@ -1,5 +1,8 @@ #include "Nodes/Route/FlowNode_Timer.h" +#include "Engine/World.h" +#include "TimerManager.h" + UFlowNode_Timer::UFlowNode_Timer(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) , CompletionTime(1.0f) diff --git a/Source/Flow/Public/FlowModule.h b/Source/Flow/Public/FlowModule.h index 03d3c20af..ef7b470ed 100644 --- a/Source/Flow/Public/FlowModule.h +++ b/Source/Flow/Public/FlowModule.h @@ -1,5 +1,6 @@ #pragma once +#include "Logging/LogMacros.h" #include "Modules/ModuleInterface.h" DECLARE_LOG_CATEGORY_EXTERN(LogFlow, Log, All) diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index 1f7a52984..d7bfb26ae 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -1,6 +1,7 @@ #pragma once #include "Engine/StreamableManager.h" +#include "GameFramework/Actor.h" #include "GameplayTagContainer.h" #include "Subsystems/GameInstanceSubsystem.h" diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h b/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h index 5aa002a7c..7807926ad 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h @@ -1,5 +1,6 @@ #pragma once +#include "Engine/EngineTypes.h" #include "Nodes/FlowNode.h" #include "FlowNode_Timer.generated.h" diff --git a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h index 806a0e753..dc5ae9281 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h @@ -1,5 +1,6 @@ #pragma once +#include "EngineDefines.h" #include "MovieSceneSequencePlayer.h" #include "Nodes/FlowNode.h" #include "FlowNode_PlayLevelSequence.generated.h" From 54abd708064acfd0b8b0588e86f7a15b93012a06 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 16 Mar 2021 18:45:31 +0100 Subject: [PATCH 022/265] implemented PostPlacedNewNode method --- .../FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp | 11 +++++++++++ Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h | 1 + 2 files changed, 12 insertions(+) diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 322986bae..0ee1e3efe 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -172,12 +172,23 @@ void UFlowGraphNode::PostDuplicate(bool bDuplicateForPIE) void UFlowGraphNode::PostEditImport() { + Super::PostEditImport(); + PostCopyNode(); SubscribeToExternalChanges(); } +void UFlowGraphNode::PostPlacedNewNode() +{ + Super::PostPlacedNewNode(); + + SubscribeToExternalChanges(); +} + void UFlowGraphNode::PrepareForCopying() { + Super::PrepareForCopying(); + if (FlowNode) { // Temporarily take ownership of the FlowNode, so that it is not deleted when cutting diff --git a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h index ccdac1f84..dea01c429 100644 --- a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h +++ b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h @@ -75,6 +75,7 @@ class FLOWEDITOR_API UFlowGraphNode : public UEdGraphNode // -- // UEdGraphNode + virtual void PostPlacedNewNode() override; virtual void PrepareForCopying() override; // -- From 128aefbe6eca60083692e702bf5983ce69f42871 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 16 Mar 2021 19:59:31 +0100 Subject: [PATCH 023/265] new context menu option: Jump to Node Definition task #17 --- .../Private/Asset/FlowAssetEditor.cpp | 21 +++++++- .../FlowEditor/Private/FlowEditorCommands.cpp | 1 + .../Private/Graph/Nodes/FlowGraphNode.cpp | 53 ++++++++++++++++--- .../FlowEditor/Public/Asset/FlowAssetEditor.h | 3 ++ Source/FlowEditor/Public/FlowEditorCommands.h | 3 +- .../Public/Graph/Nodes/FlowGraphNode.h | 5 ++ 6 files changed, 78 insertions(+), 8 deletions(-) diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index e1c7320ff..3e8ae1053 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -532,10 +532,14 @@ void FFlowAssetEditor::BindGraphCommands() FIsActionButtonVisible::CreateSP(this, &FFlowAssetEditor::CanTogglePinBreakpoint) ); - // Extra debug commands + // 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() @@ -1308,4 +1312,19 @@ bool FFlowAssetEditor::CanFocusViewport() const return GetSelectedFlowNodes().Num() == 1; } +void FFlowAssetEditor::JumpToNodeDefinition() const +{ + // Iterator used but should only contain one node + for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + { + SelectedNode->JumpToDefinition(); + return; + } +} + +bool FFlowAssetEditor::CanJumpToNodeDefinition() const +{ + return GetSelectedFlowNodes().Num() == 1; +} + #undef LOCTEXT_NAMESPACE diff --git a/Source/FlowEditor/Private/FlowEditorCommands.cpp b/Source/FlowEditor/Private/FlowEditorCommands.cpp index e95e11795..ef6d8b88a 100644 --- a/Source/FlowEditor/Private/FlowEditorCommands.cpp +++ b/Source/FlowEditor/Private/FlowEditorCommands.cpp @@ -41,6 +41,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()); } FFlowSpawnNodeCommands::FFlowSpawnNodeCommands() diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 0ee1e3efe..144e1c157 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -18,10 +18,11 @@ #include "Editor/EditorEngine.h" #include "Framework/Commands/GenericCommands.h" #include "GraphEditorActions.h" +#include "Kismet2/KismetEditorUtilities.h" #include "ScopedTransaction.h" +#include "SourceCodeNavigation.h" #include "UnrealEd.h" -#undef LOCTEXT_NAMESPACE #define LOCTEXT_NAMESPACE "FlowGraphNode" ////////////////////////////////////////////////////////////////////////// @@ -173,7 +174,7 @@ void UFlowGraphNode::PostDuplicate(bool bDuplicateForPIE) void UFlowGraphNode::PostEditImport() { Super::PostEditImport(); - + PostCopyNode(); SubscribeToExternalChanges(); } @@ -188,7 +189,7 @@ void UFlowGraphNode::PostPlacedNewNode() void UFlowGraphNode::PrepareForCopying() { Super::PrepareForCopying(); - + if (FlowNode) { // Temporarily take ownership of the FlowNode, so that it is not deleted when cutting @@ -517,11 +518,15 @@ void UFlowGraphNode::GetNodeContextMenuActions(class UToolMenu* Menu, class UGra } { - FToolMenuSection& Section = Menu->AddSection("FlowGraphNodeExtras", LOCTEXT("NodeExtrasMenuHeader", "Node Extras")); + FToolMenuSection& Section = Menu->AddSection("FlowGraphNodeJumps", LOCTEXT("NodeJumpsMenuHeader", "Jumps")); if (CanFocusViewport()) { Section.AddMenuEntry(FlowGraphCommands.FocusViewport); } + if (CanJumpToDefinition()) + { + Section.AddMenuEntry(FlowGraphCommands.JumpToNodeDefinition); + } } } } @@ -627,13 +632,49 @@ bool UFlowGraphNode::CanFocusViewport() const return FlowNode ? (GEditor->bIsSimulatingInEditor && FlowNode->GetActorToFocus()) : false; } +bool UFlowGraphNode::CanJumpToDefinition() const +{ + return FlowNode != nullptr; +} + +void UFlowGraphNode::JumpToDefinition() const +{ + if (FlowNode) + { + if (FlowNode->GetClass()->IsNative()) + { + if (FSourceCodeNavigation::CanNavigateToClass(FlowNode->GetClass())) + { + const bool bSucceeded = FSourceCodeNavigation::NavigateToClass(FlowNode->GetClass()); + if (bSucceeded) + { + return; + } + } + + // Failing that, fall back to the older method which will still get the file open assuming it exists + FString NativeParentClassHeaderPath; + const bool bFileFound = FSourceCodeNavigation::FindClassHeaderPath(FlowNode->GetClass(), NativeParentClassHeaderPath) && (IFileManager::Get().FileSize(*NativeParentClassHeaderPath) != INDEX_NONE); + if (bFileFound) + { + const FString AbsNativeParentClassHeaderPath = FPaths::ConvertRelativePathToFull(NativeParentClassHeaderPath); + FSourceCodeNavigation::OpenSourceFile(AbsNativeParentClassHeaderPath); + } + } + else + { + FKismetEditorUtilities::BringKismetToFocusAttentionOnObject(FlowNode->GetClass()); + } + } +} + void UFlowGraphNode::CreateInputPin(const FName& PinName, const int32 Index /*= INDEX_NONE*/) { if (PinName.IsNone()) { return; } - + const FEdGraphPinType PinType = FEdGraphPinType(UEdGraphSchema_K2::PC_Exec, FName(NAME_None), nullptr, EPinContainerType::None, false, FEdGraphTerminalType()); UEdGraphPin* NewPin = CreatePin(EGPD_Input, PinType, PinName, Index); @@ -646,7 +687,7 @@ void UFlowGraphNode::CreateOutputPin(const FName PinName, const int32 Index /*= { return; } - + const FEdGraphPinType PinType = FEdGraphPinType(UEdGraphSchema_K2::PC_Exec, FName(NAME_None), nullptr, EPinContainerType::None, false, FEdGraphTerminalType()); UEdGraphPin* NewPin = CreatePin(EGPD_Output, PinType, PinName, Index); diff --git a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h index 116d2da35..120f412de 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h @@ -210,4 +210,7 @@ class FFlowAssetEditor : public FAssetEditorToolkit, void FocusViewport() const; bool CanFocusViewport() const; + + void JumpToNodeDefinition() const; + bool CanJumpToNodeDefinition() const; }; diff --git a/Source/FlowEditor/Public/FlowEditorCommands.h b/Source/FlowEditor/Public/FlowEditorCommands.h index 4ae76a0b3..7d3a769f1 100644 --- a/Source/FlowEditor/Public/FlowEditorCommands.h +++ b/Source/FlowEditor/Public/FlowEditorCommands.h @@ -34,8 +34,9 @@ class FFlowGraphCommands final : public TCommands TSharedPtr DisablePinBreakpoint; TSharedPtr TogglePinBreakpoint; - /** Double-click on node */ + /** Jumps */ TSharedPtr FocusViewport; + TSharedPtr JumpToNodeDefinition; virtual void RegisterCommands() override; }; diff --git a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h index dea01c429..703eb39fa 100644 --- a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h +++ b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h @@ -148,6 +148,11 @@ class FLOWEDITOR_API UFlowGraphNode : public UEdGraphNode bool CanFocusViewport() const; + // UEdGraphNode + virtual bool CanJumpToDefinition() const override; + virtual void JumpToDefinition() const override; + // -- + ////////////////////////////////////////////////////////////////////////// // Pins From bdfc36077d11c4e65ebb5275418ead9f141f752a Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Wed, 17 Mar 2021 01:02:30 +0100 Subject: [PATCH 024/265] removing conflicting input chords for now --- Source/FlowEditor/Private/FlowEditorCommands.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/FlowEditor/Private/FlowEditorCommands.cpp b/Source/FlowEditor/Private/FlowEditorCommands.cpp index ef6d8b88a..bbe728ec2 100644 --- a/Source/FlowEditor/Private/FlowEditorCommands.cpp +++ b/Source/FlowEditor/Private/FlowEditorCommands.cpp @@ -17,8 +17,8 @@ FFlowToolbarCommands::FFlowToolbarCommands() void FFlowToolbarCommands::RegisterCommands() { - UI_COMMAND(RefreshAsset, "Refresh Asset", "Refresh this asset", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Alt | EModifierKey::Shift, EKeys::F11)); - UI_COMMAND(GoToMasterInstance, "Go To Master", "Open editor for the Flow Asset that created this Flow instance", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Alt | EModifierKey::Shift, EKeys::F11)); + UI_COMMAND(RefreshAsset, "Refresh Asset", "Refresh this asset", EUserInterfaceActionType::Button, FInputChord()); + UI_COMMAND(GoToMasterInstance, "Go To Master", "Open editor for the Flow Asset that created this Flow instance", EUserInterfaceActionType::Button, FInputChord()); } FFlowGraphCommands::FFlowGraphCommands() From b65814fc730ca35e81c1b826cd45d1b4258140ca Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Wed, 17 Mar 2021 00:44:08 +0100 Subject: [PATCH 025/265] optimized obtaining Flow Node blueprints for Palette blueprint node category is now provided by engine BlueprintCategory instead of custom Flow Node property --- Source/Flow/Public/Nodes/FlowNode.h | 4 +- .../Private/Graph/FlowGraphSchema.cpp | 152 +++++++----------- .../Private/Graph/FlowGraphSchema_Actions.cpp | 12 +- .../Private/Graph/Widgets/SFlowPalette.cpp | 2 +- .../FlowEditor/Public/Graph/FlowGraphSchema.h | 19 ++- .../Public/Graph/FlowGraphSchema_Actions.h | 24 ++- 6 files changed, 104 insertions(+), 109 deletions(-) diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 06d3b53ff..978884088 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -77,7 +77,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte #if WITH_EDITORONLY_DATA protected: - UPROPERTY(EditDefaultsOnly, Category = "FlowNode") + UPROPERTY() FString Category; UPROPERTY(EditDefaultsOnly, Category = "FlowNode") @@ -99,7 +99,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte #if WITH_EDITOR void SetGraphNode(UEdGraphNode* NewGraph); - FString GetCategory() const { return Category; } + FString GetNativeCategory() const { return Category; } EFlowNodeStyle GetNodeStyle() const { return NodeStyle; } virtual FText GetTitle() const { return GetClass()->GetDisplayNameText(); } diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp index b536ea836..2aadb56d1 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -20,8 +20,9 @@ #define LOCTEXT_NAMESPACE "FlowGraphSchema" TArray UFlowGraphSchema::NativeFlowNodes; -TMap UFlowGraphSchema::BlueprintFlowNodes; -TArray UFlowGraphSchema::FlowNodeClasses; +TMap UFlowGraphSchema::BlueprintFlowNodes; + +TSet UFlowGraphSchema::UnsortedCategories; TArray> UFlowGraphSchema::FlowNodeCategories; TMap UFlowGraphSchema::AssignedGraphNodeClasses; @@ -163,6 +164,16 @@ void UFlowGraphSchema::BreakPinLinks(UEdGraphPin& TargetPin, bool bSendsNodeNoti } } +int32 UFlowGraphSchema::GetNodeSelectionCount(const UEdGraph* Graph) const +{ + return FFlowGraphUtils::GetFlowAssetEditor(Graph)->GetNumberOfSelectedNodes(); +} + +TSharedPtr UFlowGraphSchema::GetCreateCommentAction() const +{ + return TSharedPtr(static_cast(new FFlowGraphSchemaAction_NewComment)); +} + TArray> UFlowGraphSchema::GetFlowNodeCategories() { if (FlowNodeCategories.Num() == 0) @@ -185,20 +196,30 @@ UClass* UFlowGraphSchema::GetAssignedGraphNodeClass(const UClass* FlowNodeClass) void UFlowGraphSchema::GetFlowNodeActions(FGraphActionMenuBuilder& ActionMenuBuilder, const FString& CategoryName) { - if (FlowNodeClasses.Num() == 0) + if (NativeFlowNodes.Num() == 0) { GatherFlowNodes(); } - for (UClass* FlowNodeClass : FlowNodeClasses) + for (UClass* FlowNodeClass : NativeFlowNodes) { const UFlowNode* FlowNode = FlowNodeClass->GetDefaultObject(); - if (CategoryName.IsEmpty() || CategoryName.Equals(FlowNode->GetCategory())) + if (CategoryName.IsEmpty() || CategoryName.Equals(FlowNode->GetNativeCategory())) { TSharedPtr NewNodeAction(new FFlowGraphSchemaAction_NewNode(FlowNode)); ActionMenuBuilder.AddAction(NewNodeAction); } } + + for (const TPair& AssetData : BlueprintFlowNodes) + { + UBlueprint* Blueprint = GetNodeBlueprint(AssetData.Value); + if (CategoryName.IsEmpty() || CategoryName.Equals(Blueprint->BlueprintCategory)) + { + TSharedPtr NewNodeAction(new FFlowGraphSchemaAction_NewNode(Blueprint)); + ActionMenuBuilder.AddAction(NewNodeAction); + } + } } void UFlowGraphSchema::GetCommentAction(FGraphActionMenuBuilder& ActionMenuBuilder, const UEdGraph* CurrentGraph /*= nullptr*/) @@ -227,8 +248,6 @@ void UFlowGraphSchema::GatherFlowNodes() return; } - FlowNodeClasses.Empty(); - // collect C++ nodes once per editor session if (NativeFlowNodes.Num() == 0) { @@ -239,6 +258,9 @@ void UFlowGraphSchema::GatherFlowNodes() if (It->ClassGeneratedBy == nullptr && IsFlowNodePlaceable(*It)) { NativeFlowNodes.Emplace(*It); + + const UFlowNode* DefaultObject = It->GetDefaultObject(); + UnsortedCategories.Emplace(DefaultObject->GetNativeCategory()); } } else if (It->IsChildOf(UFlowGraphNode::StaticClass())) @@ -254,7 +276,6 @@ void UFlowGraphSchema::GatherFlowNodes() } } } - FlowNodeClasses.Append(NativeFlowNodes); // retrieve all blueprint nodes FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(AssetRegistryConstants::ModuleName); @@ -286,62 +307,42 @@ void UFlowGraphSchema::OnAssetAdded(const FAssetData& AssetData) void UFlowGraphSchema::AddAsset(const FAssetData& AssetData, const bool bBatch) { - FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(AssetRegistryConstants::ModuleName); - if (AssetRegistryModule.Get().IsLoadingAssets()) - { - return; - } - - TArray AncestorClassNames; - AssetRegistryModule.Get().GetAncestorClassNames(AssetData.AssetClass, AncestorClassNames); - if (!AncestorClassNames.Contains(UBlueprintCore::StaticClass()->GetFName())) + if (!BlueprintFlowNodes.Contains(AssetData.PackageName)) { - return; - } + FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(AssetRegistryConstants::ModuleName); + if (AssetRegistryModule.Get().IsLoadingAssets()) + { + return; + } - FString NativeParentClassPath; - AssetData.GetTagValue(FBlueprintTags::NativeParentClassPath, NativeParentClassPath); - if (!NativeParentClassPath.IsEmpty()) - { - UObject* Outer = nullptr; - ResolveName(Outer, NativeParentClassPath, false, false); - UClass* NativeParentClass = FindObject(ANY_PACKAGE, *NativeParentClassPath); + TArray AncestorClassNames; + AssetRegistryModule.Get().GetAncestorClassNames(AssetData.AssetClass, AncestorClassNames); + if (!AncestorClassNames.Contains(UBlueprintCore::StaticClass()->GetFName())) + { + return; + } - // accept only Flow Node blueprints - if (NativeParentClass && NativeParentClass->IsChildOf(UFlowNode::StaticClass())) + FString NativeParentClassPath; + AssetData.GetTagValue(FBlueprintTags::NativeParentClassPath, NativeParentClassPath); + if (!NativeParentClassPath.IsEmpty()) { - FString GeneratedClassPath; - AssetData.GetTagValue(FBlueprintTags::GeneratedClassPath, GeneratedClassPath); + UObject* Outer = nullptr; + ResolveName(Outer, NativeParentClassPath, false, false); + UClass* NativeParentClass = FindObject(ANY_PACKAGE, *NativeParentClassPath); - // add class once - if (!GeneratedClassPath.IsEmpty()) + // accept only Flow Node blueprints + if (NativeParentClass && NativeParentClass->IsChildOf(UFlowNode::StaticClass())) { - UObject* NodeOuter = nullptr; - ResolveName(NodeOuter, GeneratedClassPath, false, false); - UClass* NodeClass = FindObject(ANY_PACKAGE, *GeneratedClassPath); - - if (NodeClass == nullptr) + UBlueprint* Blueprint = GetNodeBlueprint(AssetData); + if (Blueprint && IsFlowNodePlaceable(Blueprint->GeneratedClass)) { - // this should be fine - assuming that Flow Node blueprints shouldn't include hard references to heavy assets! - NodeClass = LoadObject(nullptr, *GeneratedClassPath); - } + BlueprintFlowNodes.Emplace(AssetData.PackageName, AssetData); + UnsortedCategories.Emplace(Blueprint->BlueprintCategory); - if (NodeClass && IsFlowNodePlaceable(NodeClass) && FlowNodeClasses.Contains(NodeClass) == false) - { - // filter out intermediate blueprint classes - const FString ClassName = NodeClass->GetName(); - if (ClassName.StartsWith(TEXT("SKEL_")) || ClassName.StartsWith(TEXT("REINST_"))) + if (!bBatch) { - return; + RefreshNodeList(); } - - BlueprintFlowNodes.Emplace(GeneratedClassPath, NodeClass); - FlowNodeClasses.Emplace(NodeClass); - } - - if (!bBatch) - { - RefreshNodeList(); } } } @@ -350,26 +351,10 @@ void UFlowGraphSchema::AddAsset(const FAssetData& AssetData, const bool bBatch) void UFlowGraphSchema::RemoveAsset(const FAssetData& AssetData) { - FString GeneratedClassPath; - if (AssetData.GetTagValue(FBlueprintTags::GeneratedClassPath, GeneratedClassPath)) - { - GeneratedClassPath = FPackageName::ExportTextPathToObjectPath(GeneratedClassPath); - - if (GeneratedClassPath == TEXT("None")) - { - // This can happen if the generated class was already deleted prior to the notification being sent - // Let's try to reconstruct the generated class name from the object path. - GeneratedClassPath = AssetData.ObjectPath.ToString() + TEXT("_C"); - } - } - - if (BlueprintFlowNodes.Contains(GeneratedClassPath)) + if (BlueprintFlowNodes.Contains(AssetData.PackageName)) { - FlowNodeClasses.Remove(BlueprintFlowNodes[GeneratedClassPath]); - FlowNodeClasses.Shrink(); - - BlueprintFlowNodes.Remove(GeneratedClassPath); - BlueprintFlowNodes.Compact(); + BlueprintFlowNodes.Remove(AssetData.PackageName); + BlueprintFlowNodes.Shrink(); RefreshNodeList(); } @@ -377,17 +362,7 @@ void UFlowGraphSchema::RemoveAsset(const FAssetData& AssetData) void UFlowGraphSchema::RefreshNodeList() { - // sort node classes - FlowNodeClasses.Sort(); - - // collect categories - TSet UnsortedCategories; - for (const UClass* FlowNodeClass : FlowNodeClasses) - { - const UFlowNode* DefaultObject = FlowNodeClass->GetDefaultObject(); - UnsortedCategories.Emplace(DefaultObject->GetCategory()); - } - + // sort categories TArray SortedCategories = UnsortedCategories.Array(); SortedCategories.Sort(); @@ -401,14 +376,9 @@ void UFlowGraphSchema::RefreshNodeList() OnNodeListChanged.Broadcast(); } -int32 UFlowGraphSchema::GetNodeSelectionCount(const UEdGraph* Graph) const +UBlueprint* UFlowGraphSchema::GetNodeBlueprint(const FAssetData& AssetData) { - return FFlowGraphUtils::GetFlowAssetEditor(Graph)->GetNumberOfSelectedNodes(); -} - -TSharedPtr UFlowGraphSchema::GetCreateCommentAction() const -{ - return TSharedPtr(static_cast(new FFlowGraphSchemaAction_NewComment)); + return Cast(StaticLoadObject(AssetData.GetClass(), /*Outer =*/nullptr, *AssetData.ObjectPath.ToString(), nullptr, LOAD_NoWarn | LOAD_DisableCompileOnLoad)); } #undef LOCTEXT_NAMESPACE diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp index 8e1e6a3c9..bd129eb42 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp @@ -29,7 +29,17 @@ UEdGraphNode* FFlowGraphSchemaAction_NewNode::PerformAction(class UEdGraph* Pare return nullptr; } - return CreateNode(ParentGraph, FromPin, NodeClass, Location, bSelectNewNode); + if (NativeNodeClass) + { + return CreateNode(ParentGraph, FromPin, NativeNodeClass, Location, bSelectNewNode); + } + + if (Blueprint) + { + return CreateNode(ParentGraph, FromPin, Blueprint->GeneratedClass, Location, bSelectNewNode); + } + + return nullptr; } UFlowGraphNode* FFlowGraphSchemaAction_NewNode::CreateNode(UEdGraph* ParentGraph, UEdGraphPin* FromPin, UClass* NodeClass, const FVector2D Location, const bool bSelectNewNode /*= true*/) diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp index 97b82180d..1cd18fd6d 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp @@ -28,7 +28,7 @@ void SFlowPaletteItem::Construct(const FArguments& InArgs, FCreateWidgetForActio { if (GraphAction->GetTypeId() == FFlowGraphSchemaAction_NewNode::StaticGetTypeId()) { - UClass* FlowNodeClass = StaticCastSharedPtr(GraphAction)->NodeClass; + UClass* FlowNodeClass = StaticCastSharedPtr(GraphAction)->NativeNodeClass; HotkeyChord = FFlowSpawnNodeCommands::Get().GetChordByClass(FlowNodeClass); } else if (GraphAction->GetTypeId() == FFlowGraphSchemaAction_NewComment::StaticGetTypeId()) diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h index e0f14db45..f961eb174 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSchema.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSchema.h @@ -10,6 +10,16 @@ class FLOWEDITOR_API UFlowGraphSchema : public UEdGraphSchema { GENERATED_UCLASS_BODY() +private: + static TArray NativeFlowNodes; + static TMap BlueprintFlowNodes; + + static TSet UnsortedCategories; + static TArray> FlowNodeCategories; + + static TMap AssignedGraphNodeClasses; + +public: static void SubscribeToAssetChanges(); static void GetPaletteActions(FGraphActionMenuBuilder& ActionMenuBuilder, const FString& CategoryName); @@ -44,12 +54,5 @@ class FLOWEDITOR_API UFlowGraphSchema : public UEdGraphSchema public: static FFlowGraphSchemaRefresh OnNodeListChanged; - -private: - static TArray NativeFlowNodes; - static TMap BlueprintFlowNodes; - static TArray FlowNodeClasses; - static TArray> FlowNodeCategories; - - static TMap AssignedGraphNodeClasses; + static UBlueprint* GetNodeBlueprint(const FAssetData& AssetData); }; diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h b/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h index 26a86a911..d970a245b 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h @@ -12,9 +12,11 @@ struct FLOWEDITOR_API FFlowGraphSchemaAction_NewNode : public FEdGraphSchemaActi { GENERATED_USTRUCT_BODY() - /** Class of node we want to create */ UPROPERTY() - class UClass* NodeClass; + class UClass* NativeNodeClass; + + UPROPERTY() + class UBlueprint* Blueprint; static FName StaticGetTypeId() { @@ -26,19 +28,29 @@ struct FLOWEDITOR_API FFlowGraphSchemaAction_NewNode : public FEdGraphSchemaActi FFlowGraphSchemaAction_NewNode() : FEdGraphSchemaAction() - , NodeClass(nullptr) + , NativeNodeClass(nullptr) + , Blueprint(nullptr) { } FFlowGraphSchemaAction_NewNode(UClass* Node) : FEdGraphSchemaAction() - , NodeClass(Node) + , NativeNodeClass(Node) + , Blueprint(nullptr) { } FFlowGraphSchemaAction_NewNode(const UFlowNode* Node) - : FEdGraphSchemaAction(FText::FromString(Node->GetCategory()), Node->GetTitle(), Node->GetClass()->GetToolTipText(), 0) - , NodeClass(Node->GetClass()) + : FEdGraphSchemaAction(FText::FromString(Node->GetNativeCategory()), Node->GetTitle(), Node->GetClass()->GetToolTipText(), 0) + , NativeNodeClass(Node->GetClass()) + , Blueprint(nullptr) + { + } + + FFlowGraphSchemaAction_NewNode(UBlueprint* InBlueprint) + : FEdGraphSchemaAction(FText::FromString(InBlueprint->BlueprintCategory), FText::FromString(InBlueprint->BlueprintDisplayName), FText::FromString(InBlueprint->BlueprintDescription), 0) + , NativeNodeClass(nullptr) + , Blueprint(InBlueprint) { } From 4fbf273acd8c237493a000a93afe52f471336360 Mon Sep 17 00:00:00 2001 From: Simon Turcotte-Langevin Date: Wed, 17 Mar 2021 15:21:23 -0400 Subject: [PATCH 026/265] forwards owner object into flow asset instance --- Source/Flow/Private/FlowAsset.cpp | 8 +++++++- Source/Flow/Private/FlowSubsystem.cpp | 12 +++++++----- Source/Flow/Public/FlowAsset.h | 6 +++++- Source/Flow/Public/FlowSubsystem.h | 2 +- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 7cc07f285..f7ba6e394 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -222,8 +222,9 @@ void UFlowAsset::SetInspectedInstance(const FName& NewInspectedInstanceName) } #endif -void UFlowAsset::InitInstance(UFlowAsset* InTemplateAsset) +void UFlowAsset::InitInstance(UObject* InOwner, UFlowAsset* InTemplateAsset) { + Owner = InOwner; TemplateAsset = InTemplateAsset; for (TPair& Node : Nodes) @@ -343,6 +344,11 @@ void UFlowAsset::FinishFlow(const bool bFlowCompleted) } } +UObject* UFlowAsset::GetOwner() const +{ + return Owner; +} + TWeakObjectPtr UFlowAsset::GetFlowInstance(UFlowNode_SubGraph* SubGraphNode) const { return ActiveSubGraphs.FindRef(SubGraphNode); diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index 94167cb09..379d9ed60 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -44,7 +44,7 @@ void UFlowSubsystem::StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset) return; } - UFlowAsset* NewFlow = CreateFlowInstance(FlowAsset); + UFlowAsset* NewFlow = CreateFlowInstance(Owner, FlowAsset); RootInstances.Add(Owner, NewFlow); NewFlow->StartFlow(); @@ -63,7 +63,8 @@ void UFlowSubsystem::PreloadSubFlow(UFlowNode_SubGraph* SubFlow) { if (!InstancedSubFlows.Contains(SubFlow)) { - UFlowAsset* NewFlow = CreateFlowInstance(SubFlow->Asset); + UObject* Owner = SubFlow->Asset.IsNull() ? nullptr : SubFlow->Asset->GetOwner(); + UFlowAsset* NewFlow = CreateFlowInstance(Owner, SubFlow->Asset); InstancedSubFlows.Add(SubFlow, NewFlow); NewFlow->PreloadNodes(); @@ -74,7 +75,8 @@ void UFlowSubsystem::StartSubFlow(UFlowNode_SubGraph* SubFlow) { if (!InstancedSubFlows.Contains(SubFlow)) { - UFlowAsset* NewFlow = CreateFlowInstance(SubFlow->Asset); + UObject* Owner = SubFlow->Asset.IsNull() ? nullptr : SubFlow->Asset->GetOwner(); + UFlowAsset* NewFlow = CreateFlowInstance(Owner, SubFlow->Asset); InstancedSubFlows.Add(SubFlow, NewFlow); } @@ -96,7 +98,7 @@ void UFlowSubsystem::RemoveInstancedTemplate(UFlowAsset* Template) InstancedTemplates.Remove(Template); } -UFlowAsset* UFlowSubsystem::CreateFlowInstance(TSoftObjectPtr FlowAsset) +UFlowAsset* UFlowSubsystem::CreateFlowInstance(UObject* Owner, TSoftObjectPtr FlowAsset) { check(!FlowAsset.IsNull()); @@ -118,7 +120,7 @@ UFlowAsset* UFlowSubsystem::CreateFlowInstance(TSoftObjectPtr FlowAs const FString NewInstanceName = FPaths::GetBaseFilename(FlowAsset.Get()->GetPathName()) + TEXT("_") + FString::FromInt(FlowAsset.Get()->GetInstancesNum()); UFlowAsset* NewInstance = NewObject(this, FlowAsset->GetClass(), *NewInstanceName, RF_Transient, FlowAsset.Get(), false, nullptr); - NewInstance->InitInstance(FlowAsset.Get()); + NewInstance->InitInstance(Owner, FlowAsset.Get()); FlowAsset.Get()->AddInstance(NewInstance); diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 49e5e49ce..b5b1a4337 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -161,6 +161,9 @@ class FLOW_API UFlowAsset : public UObject TWeakObjectPtr NodeOwningThisAssetInstance; TMap, TWeakObjectPtr> ActiveSubGraphs; + UPROPERTY() + UObject* Owner; + UPROPERTY() UFlowNode_Start* StartNode; @@ -179,13 +182,14 @@ class FLOW_API UFlowAsset : public UObject TArray RecordedNodes; public: - void InitInstance(UFlowAsset* InTemplateAsset); + void InitInstance(UObject* InOwner, UFlowAsset* InTemplateAsset); void PreloadNodes(); virtual void StartFlow(); virtual void StartAsSubFlow(UFlowNode_SubGraph* SubGraphNode); virtual void FinishFlow(const bool bFlowCompleted); + UObject* GetOwner() const; TWeakObjectPtr GetFlowInstance(UFlowNode_SubGraph* SubGraphNode) const; private: diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index d7bfb26ae..e67933c1b 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -59,7 +59,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem void RemoveInstancedTemplate(UFlowAsset* Template); private: - UFlowAsset* CreateFlowInstance(TSoftObjectPtr FlowAsset); + UFlowAsset* CreateFlowInstance(UObject* Owner, TSoftObjectPtr FlowAsset); public: // Returns assets instanced by object from another system like World Settings From c212ebe435e40ee4670450f30591713052a8714a Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Thu, 18 Mar 2021 16:08:07 +0100 Subject: [PATCH 027/265] by default: allow to create Flow Subsystem on clients, still disallow creating world's Flow on client advantages of this approach - It's possible to ignore HasAuthority check by simply using custom World Settings class in project. Useful if someone would like to instantiate client-side Flow Graphs from asset assigned to the map. - It's possible to have Flow Subsystem on clients and access the Flow Component registry. - It's possible to disable Flow Subsystem on clients by changing flag in the Flow Settings. --- Source/Flow/Private/FlowSettings.cpp | 1 + Source/Flow/Private/FlowSubsystem.cpp | 9 ++++++++- Source/Flow/Private/FlowWorldSettings.cpp | 4 ++-- Source/Flow/Public/FlowSettings.h | 5 +++++ 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/Source/Flow/Private/FlowSettings.cpp b/Source/Flow/Private/FlowSettings.cpp index 5928eb11c..f31c414ed 100644 --- a/Source/Flow/Private/FlowSettings.cpp +++ b/Source/Flow/Private/FlowSettings.cpp @@ -2,5 +2,6 @@ UFlowSettings::UFlowSettings(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) + , bCreateFlowSubsystemOnClients(true) { } diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index 379d9ed60..02505775f 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -2,6 +2,7 @@ #include "FlowAsset.h" #include "FlowComponent.h" #include "FlowModule.h" +#include "FlowSettings.h" #include "Nodes/Route/FlowNode_SubGraph.h" #include "Engine/GameInstance.h" @@ -15,6 +16,12 @@ UFlowSubsystem::UFlowSubsystem() bool UFlowSubsystem::ShouldCreateSubsystem(UObject* Outer) const { + // 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(); } @@ -274,7 +281,7 @@ void UFlowSubsystem::FindComponents(const FGameplayTagContainer& Tags, TSet& Component : ComponentsWithAnyTag) { if (Component.IsValid() && Component->IdentityTags.HasAllExact(Tags)) diff --git a/Source/Flow/Private/FlowWorldSettings.cpp b/Source/Flow/Private/FlowWorldSettings.cpp index cc67c16b4..d5239f877 100644 --- a/Source/Flow/Private/FlowWorldSettings.cpp +++ b/Source/Flow/Private/FlowWorldSettings.cpp @@ -11,7 +11,7 @@ void AFlowWorldSettings::BeginPlay() { Super::BeginPlay(); - if (FlowAsset) + if (FlowAsset && HasAuthority()) { if (UFlowSubsystem* FlowSubsystem = GetWorld()->GetGameInstance()->GetSubsystem()) { @@ -22,7 +22,7 @@ void AFlowWorldSettings::BeginPlay() void AFlowWorldSettings::EndPlay(const EEndPlayReason::Type EndPlayReason) { - if (FlowAsset) + if (FlowAsset && HasAuthority()) { if (UFlowSubsystem* FlowSubsystem = GetWorld()->GetGameInstance()->GetSubsystem()) { diff --git a/Source/Flow/Public/FlowSettings.h b/Source/Flow/Public/FlowSettings.h index 76e5eacdd..62c9a1d59 100644 --- a/Source/Flow/Public/FlowSettings.h +++ b/Source/Flow/Public/FlowSettings.h @@ -16,6 +16,11 @@ class UFlowSettings final : public UDeveloperSettings static UFlowSettings* Get() { return CastChecked(UFlowSettings::StaticClass()->GetDefaultObject()); } + // Set if to False, if you don't want to create client-side Flow Graphs + // And you don't access to the Flow Component registry on clients + 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; From abb709afb3a530c3235925fde91c03271e36aefb Mon Sep 17 00:00:00 2001 From: sturcotte06 Date: Thu, 18 Mar 2021 16:11:00 -0400 Subject: [PATCH 028/265] fix include in flow node implementation (#25) Co-authored-by: Simon Turcotte-Langevin --- Source/Flow/Private/Nodes/FlowNode.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index f76784da9..95f3f756d 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -8,6 +8,7 @@ #include "Engine/Engine.h" #include "Engine/World.h" #include "Misc/App.h" +#include "Misc/Paths.h" FName UFlowNode::DefaultInputName(TEXT("In")); FName UFlowNode::DefaultOutputName(TEXT("Out")); From 2c71d00c2861afa0805621684e266cf08c1d4821 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 22 Mar 2021 19:04:05 +0100 Subject: [PATCH 029/265] ensure we always check if Node Class exists --- Source/FlowEditor/Private/FlowEditorCommands.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Source/FlowEditor/Private/FlowEditorCommands.cpp b/Source/FlowEditor/Private/FlowEditorCommands.cpp index bbe728ec2..641fb7fb3 100644 --- a/Source/FlowEditor/Private/FlowEditorCommands.cpp +++ b/Source/FlowEditor/Private/FlowEditorCommands.cpp @@ -17,7 +17,7 @@ FFlowToolbarCommands::FFlowToolbarCommands() void FFlowToolbarCommands::RegisterCommands() { - UI_COMMAND(RefreshAsset, "Refresh Asset", "Refresh this asset", EUserInterfaceActionType::Button, FInputChord()); + 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()); } @@ -76,11 +76,12 @@ void FFlowSpawnNodeCommands::RegisterCommands() { NodeClass = UFlowNode::StaticClass(); } - else - { - // Matching node not found - continue; - } + } + + if (NodeClass == nullptr) + { + // Matching node not found + continue; } // Setup a UI Command for key-binding From 4cb6cd89f9ff6b746ef7f35fe2133964f88beb6e Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 22 Mar 2021 19:03:28 +0100 Subject: [PATCH 030/265] renaming Custom Event node to Custom Input, it should fix the confusion --- Config/BaseFlow.ini | 2 ++ Config/DefaultFlow.ini | 2 ++ Source/Flow/Private/FlowAsset.cpp | 10 +++--- ...stomEvent.cpp => FlowNode_CustomInput.cpp} | 8 ++--- .../Private/Nodes/Route/FlowNode_SubGraph.cpp | 2 +- Source/Flow/Public/FlowAsset.h | 10 +++--- ...e_CustomEvent.h => FlowNode_CustomInput.h} | 6 ++-- .../Public/Nodes/Route/FlowNode_SubGraph.h | 1 - .../Private/Asset/FlowAssetDetails.cpp | 2 +- .../FlowEditor/Private/FlowEditorModule.cpp | 6 ++-- ...ls.cpp => FlowNode_CustomInputDetails.cpp} | 34 +++++++++---------- ...etails.h => FlowNode_CustomInputDetails.h} | 4 +-- 12 files changed, 45 insertions(+), 42 deletions(-) rename Source/Flow/Private/Nodes/Route/{FlowNode_CustomEvent.cpp => FlowNode_CustomInput.cpp} (52%) rename Source/Flow/Public/Nodes/Route/{FlowNode_CustomEvent.h => FlowNode_CustomInput.h} (70%) rename Source/FlowEditor/Private/Graph/Customizations/{FlowNode_CustomEventDetails.cpp => FlowNode_CustomInputDetails.cpp} (62%) rename Source/FlowEditor/Private/Graph/Customizations/{FlowNode_CustomEventDetails.h => FlowNode_CustomInputDetails.h} (81%) diff --git a/Config/BaseFlow.ini b/Config/BaseFlow.ini index f2fdc43eb..f42430df5 100644 --- a/Config/BaseFlow.ini +++ b/Config/BaseFlow.ini @@ -1 +1,3 @@ [CoreRedirects] ++ClassRedirects=(OldName="/Script/Flow.FlowNode_CustomEvent",NewName="/Script/Flow.FlowNode_CustomInput") ++PropertyRedirects=(OldName="FlowAsset.CustomEvents",NewName="CustomInputs") diff --git a/Config/DefaultFlow.ini b/Config/DefaultFlow.ini index f2fdc43eb..f42430df5 100644 --- a/Config/DefaultFlow.ini +++ b/Config/DefaultFlow.ini @@ -1 +1,3 @@ [CoreRedirects] ++ClassRedirects=(OldName="/Script/Flow.FlowNode_CustomEvent",NewName="/Script/Flow.FlowNode_CustomInput") ++PropertyRedirects=(OldName="FlowAsset.CustomEvents",NewName="CustomInputs") diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index f7ba6e394..1e3b97701 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -3,7 +3,7 @@ #include "FlowSubsystem.h" #include "Nodes/FlowNode.h" -#include "Nodes/Route/FlowNode_CustomEvent.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" @@ -31,7 +31,7 @@ void UFlowAsset::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEv { Super::PostEditChangeProperty(PropertyChangedEvent); - if (PropertyChangedEvent.Property && (PropertyChangedEvent.GetPropertyName() == GET_MEMBER_NAME_CHECKED(UFlowAsset, CustomEvents) + if (PropertyChangedEvent.Property && (PropertyChangedEvent.GetPropertyName() == GET_MEMBER_NAME_CHECKED(UFlowAsset, CustomInputs) || PropertyChangedEvent.GetPropertyName() == GET_MEMBER_NAME_CHECKED(UFlowAsset, CustomOutputs))) { OnSubGraphReconstructionRequested.ExecuteIfBound(); @@ -238,7 +238,7 @@ void UFlowAsset::InitInstance(UObject* InOwner, UFlowAsset* InTemplateAsset) StartNode = InNode; } - if (UFlowNode_CustomEvent* CustomEvent = Cast(NewInstance)) + if (UFlowNode_CustomInput* CustomEvent = Cast(NewInstance)) { const FName& EventName = CustomEvent->EventName; if (!EventName.IsNone() && !CustomEventNodes.Contains(CustomEvent->EventName)) @@ -252,7 +252,7 @@ void UFlowAsset::InitInstance(UObject* InOwner, UFlowAsset* InTemplateAsset) void UFlowAsset::PreloadNodes() { TArray GraphEntryNodes = {StartNode}; - for (const TPair& CustomEvent : CustomEventNodes) + for (const TPair& CustomEvent : CustomEventNodes) { GraphEntryNodes.Emplace(CustomEvent.Value); } @@ -359,7 +359,7 @@ void UFlowAsset::TriggerCustomEvent(UFlowNode_SubGraph* Node, const FName& Event const TWeakObjectPtr FlowInstance = ActiveSubGraphs.FindRef(Node); if (FlowInstance.IsValid()) { - if (UFlowNode_CustomEvent* CustomEvent = FlowInstance->CustomEventNodes.FindRef(EventName)) + if (UFlowNode_CustomInput* CustomEvent = FlowInstance->CustomEventNodes.FindRef(EventName)) { RecordedNodes.Add(CustomEvent); CustomEvent->TriggerFirstOutput(true); diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_CustomEvent.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp similarity index 52% rename from Source/Flow/Private/Nodes/Route/FlowNode_CustomEvent.cpp rename to Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp index 02dced6e2..9dc05d7cf 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_CustomEvent.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp @@ -1,6 +1,6 @@ -#include "Nodes/Route/FlowNode_CustomEvent.h" +#include "Nodes/Route/FlowNode_CustomInput.h" -UFlowNode_CustomEvent::UFlowNode_CustomEvent(const FObjectInitializer& ObjectInitializer) +UFlowNode_CustomInput::UFlowNode_CustomInput(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { #if WITH_EDITOR @@ -11,13 +11,13 @@ UFlowNode_CustomEvent::UFlowNode_CustomEvent(const FObjectInitializer& ObjectIni InputNames.Empty(); } -void UFlowNode_CustomEvent::ExecuteInput(const FName& PinName) +void UFlowNode_CustomInput::ExecuteInput(const FName& PinName) { TriggerFirstOutput(true); } #if WITH_EDITOR -FString UFlowNode_CustomEvent::GetNodeDescription() const +FString UFlowNode_CustomInput::GetNodeDescription() const { return EventName.ToString(); } diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp index 1e3ab78d2..ee789f398 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp @@ -85,7 +85,7 @@ TArray UFlowNode_SubGraph::GetContextInputs() if (!Asset.IsNull()) { Asset.LoadSynchronous(); - for (const FName& PinName : Asset.Get()->GetCustomEvents()) + for (const FName& PinName : Asset.Get()->GetCustomInputs()) { if (!PinName.IsNone()) { diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index b5b1a4337..74eb2f5f5 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -4,7 +4,7 @@ #include "FlowAsset.generated.h" class UFlowNode; -class UFlowNode_CustomEvent; +class UFlowNode_CustomInput; class UFlowNode_Start; class UFlowNode_SubGraph; class UFlowSubsystem; @@ -83,11 +83,11 @@ class FLOW_API UFlowAsset : public UObject TMap Nodes; /** - * Custom Events define custom entry points in graph, it's similar to blueprint Custom Events + * 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(EditDefaultsOnly, Category = "Flow") - TArray CustomEvents; + TArray CustomInputs; /** * Custom Outputs define custom graph outputs, this allow to send signals to the parent graph while executing this graph @@ -112,7 +112,7 @@ class FLOW_API UFlowAsset : public UObject UFlowNode* GetNode(const FGuid& Guid) const; TMap GetNodes() const { return Nodes; } - TArray GetCustomEvents() const { return CustomEvents; } + TArray GetCustomInputs() const { return CustomInputs; } TArray GetCustomOutputs() const { return CustomOutputs; } ////////////////////////////////////////////////////////////////////////// @@ -168,7 +168,7 @@ class FLOW_API UFlowAsset : public UObject UFlowNode_Start* StartNode; UPROPERTY() - TMap CustomEventNodes; + TMap CustomEventNodes; UPROPERTY() TSet PreloadedNodes; diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_CustomEvent.h b/Source/Flow/Public/Nodes/Route/FlowNode_CustomInput.h similarity index 70% rename from Source/Flow/Public/Nodes/Route/FlowNode_CustomEvent.h rename to Source/Flow/Public/Nodes/Route/FlowNode_CustomInput.h index 414013aa6..9a0e244c9 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_CustomEvent.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_CustomInput.h @@ -1,13 +1,13 @@ #pragma once #include "Nodes/FlowNode.h" -#include "FlowNode_CustomEvent.generated.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 Event")) -class FLOW_API UFlowNode_CustomEvent : public UFlowNode +UCLASS(NotBlueprintable, meta = (DisplayName = "Custom Input")) +class FLOW_API UFlowNode_CustomInput : public UFlowNode { GENERATED_UCLASS_BODY() diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h b/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h index 77c5d969d..43cb1d125 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h @@ -35,7 +35,6 @@ class FLOW_API UFlowNode_SubGraph : public UFlowNode virtual UObject* GetAssetToEdit() override; virtual bool SupportsContextPins() const override { return true; } - virtual bool CanRefreshContextPinsOnLoad() const override { return true; } virtual TArray GetContextInputs() override; virtual TArray GetContextOutputs() override; diff --git a/Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp b/Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp index 0e166f4d9..44d63f878 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp @@ -11,7 +11,7 @@ void FFlowAssetDetails::CustomizeDetails(IDetailLayoutBuilder& DetailLayout) { IDetailCategoryBuilder& FlowAssetCategory = DetailLayout.EditCategory("FlowAsset", LOCTEXT("FlowAssetCategory", "FlowAsset")); - const TSharedPtr EventsPropertyHandle = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(UFlowAsset, CustomEvents)); + const TSharedPtr EventsPropertyHandle = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(UFlowAsset, CustomInputs)); if (EventsPropertyHandle.IsValid()) { TSharedRef EventsArrayBuilder = MakeShareable(new FDetailArrayBuilder(EventsPropertyHandle.ToSharedRef())); diff --git a/Source/FlowEditor/Private/FlowEditorModule.cpp b/Source/FlowEditor/Private/FlowEditorModule.cpp index 7d0faa4d8..371ffe9fd 100644 --- a/Source/FlowEditor/Private/FlowEditorModule.cpp +++ b/Source/FlowEditor/Private/FlowEditorModule.cpp @@ -6,7 +6,7 @@ #include "Asset/FlowAssetEditor.h" #include "Graph/Customizations/FlowNode_Details.h" #include "Graph/Customizations/FlowNode_ComponentObserverDetails.h" -#include "Graph/Customizations/FlowNode_CustomEventDetails.h" +#include "Graph/Customizations/FlowNode_CustomInputDetails.h" #include "Graph/Customizations/FlowNode_CustomOutputDetails.h" #include "Graph/Customizations/FlowNode_PlayLevelSequenceDetails.h" #include "Graph/FlowGraphConnectionDrawingPolicy.h" @@ -15,7 +15,7 @@ #include "Nodes/AssetTypeActions_FlowNodeBlueprint.h" #include "FlowAsset.h" -#include "Nodes/Route/FlowNode_CustomEvent.h" +#include "Nodes/Route/FlowNode_CustomInput.h" #include "Nodes/Route/FlowNode_CustomOutput.h" #include "Nodes/World/FlowNode_ComponentObserver.h" #include "Nodes/World/FlowNode_PlayLevelSequence.h" @@ -59,7 +59,7 @@ void FFlowEditorModule::StartupModule() 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_CustomEvent::StaticClass(), FOnGetDetailCustomizationInstance::CreateStatic(&FFlowNode_CustomEventDetails::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)); diff --git a/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomEventDetails.cpp b/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomInputDetails.cpp similarity index 62% rename from Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomEventDetails.cpp rename to Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomInputDetails.cpp index 5ae086d88..872a83aea 100644 --- a/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomEventDetails.cpp +++ b/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomInputDetails.cpp @@ -1,19 +1,19 @@ -#include "FlowNode_CustomEventDetails.h" +#include "FlowNode_CustomInputDetails.h" #include "FlowAsset.h" -#include "Nodes/Route/FlowNode_CustomEvent.h" +#include "Nodes/Route/FlowNode_CustomInput.h" #include "DetailWidgetRow.h" #include "PropertyEditing.h" #include "UnrealEd.h" -#define LOCTEXT_NAMESPACE "FlowNode_CustomEventDetails" +#define LOCTEXT_NAMESPACE "FlowNode_CustomInputDetails" -void FFlowNode_CustomEventDetails::CustomizeDetails(IDetailLayoutBuilder& DetailLayout) +void FFlowNode_CustomInputDetails::CustomizeDetails(IDetailLayoutBuilder& DetailLayout) { DetailLayout.GetObjectsBeingCustomized(ObjectsBeingEdited); GetEventNames(); - IDetailCategoryBuilder& Category = DetailLayout.EditCategory("CustomEvent", LOCTEXT("CustomEventCategory", "Custom Event")); + IDetailCategoryBuilder& Category = DetailLayout.EditCategory("CustomInput", LOCTEXT("CustomInputCategory", "Custom Event")); Category.AddCustomRow(LOCTEXT("CustomRowName", "Event Name")) .NameContent() [ @@ -25,16 +25,16 @@ void FFlowNode_CustomEventDetails::CustomizeDetails(IDetailLayoutBuilder& Detail [ SNew(SComboBox>) .OptionsSource(&EventNames) - .OnGenerateWidget(this, &FFlowNode_CustomEventDetails::GenerateEventWidget) - .OnSelectionChanged(this, &FFlowNode_CustomEventDetails::PinSelectionChanged) + .OnGenerateWidget(this, &FFlowNode_CustomInputDetails::GenerateEventWidget) + .OnSelectionChanged(this, &FFlowNode_CustomInputDetails::PinSelectionChanged) [ SNew(STextBlock) - .Text(this, &FFlowNode_CustomEventDetails::GetSelectedEventText) + .Text(this, &FFlowNode_CustomInputDetails::GetSelectedEventText) ] ]; } -void FFlowNode_CustomEventDetails::GetEventNames() +void FFlowNode_CustomInputDetails::GetEventNames() { EventNames.Empty(); EventNames.Emplace(MakeShareable(new FName(NAME_None))); @@ -42,13 +42,13 @@ void FFlowNode_CustomEventDetails::GetEventNames() if (ObjectsBeingEdited[0].IsValid() && ObjectsBeingEdited[0].Get()->GetOuter()) { const UFlowAsset* FlowAsset = Cast(ObjectsBeingEdited[0].Get()->GetOuter()); - TArray SortedNames = FlowAsset->GetCustomEvents(); + TArray SortedNames = FlowAsset->GetCustomInputs(); for (const TPair& Node : FlowAsset->GetNodes()) { - if (Node.Value->GetClass()->IsChildOf(UFlowNode_CustomEvent::StaticClass())) + if (Node.Value->GetClass()->IsChildOf(UFlowNode_CustomInput::StaticClass())) { - SortedNames.Remove(Cast(Node.Value)->EventName); + SortedNames.Remove(Cast(Node.Value)->EventName); } } @@ -67,17 +67,17 @@ void FFlowNode_CustomEventDetails::GetEventNames() } } -TSharedRef FFlowNode_CustomEventDetails::GenerateEventWidget(const TSharedPtr Item) const +TSharedRef FFlowNode_CustomInputDetails::GenerateEventWidget(const TSharedPtr Item) const { return SNew(STextBlock).Text(FText::FromName(*Item.Get())); } -FText FFlowNode_CustomEventDetails::GetSelectedEventText() const +FText FFlowNode_CustomInputDetails::GetSelectedEventText() const { FText PropertyValue; ensure(ObjectsBeingEdited[0].IsValid()); - if (const UFlowNode_CustomEvent* Node = Cast(ObjectsBeingEdited[0].Get())) + if (const UFlowNode_CustomInput* Node = Cast(ObjectsBeingEdited[0].Get())) { PropertyValue = FText::FromName(Node->EventName); } @@ -85,10 +85,10 @@ FText FFlowNode_CustomEventDetails::GetSelectedEventText() const return PropertyValue; } -void FFlowNode_CustomEventDetails::PinSelectionChanged(const TSharedPtr Item, ESelectInfo::Type SelectInfo) const +void FFlowNode_CustomInputDetails::PinSelectionChanged(const TSharedPtr Item, ESelectInfo::Type SelectInfo) const { ensure(ObjectsBeingEdited[0].IsValid()); - if (UFlowNode_CustomEvent* Node = Cast(ObjectsBeingEdited[0].Get())) + if (UFlowNode_CustomInput* Node = Cast(ObjectsBeingEdited[0].Get())) { Node->EventName = *Item.Get(); } diff --git a/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomEventDetails.h b/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomInputDetails.h similarity index 81% rename from Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomEventDetails.h rename to Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomInputDetails.h index 219ed409a..efa077262 100644 --- a/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomEventDetails.h +++ b/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomInputDetails.h @@ -2,12 +2,12 @@ #include "IDetailCustomization.h" -class FFlowNode_CustomEventDetails final : public IDetailCustomization +class FFlowNode_CustomInputDetails final : public IDetailCustomization { public: static TSharedRef MakeInstance() { - return MakeShareable(new FFlowNode_CustomEventDetails()); + return MakeShareable(new FFlowNode_CustomInputDetails()); } // IDetailCustomization From 562fec85243bb4c6392b4aecb1a392bd46f68fdb Mon Sep 17 00:00:00 2001 From: moadib Date: Tue, 23 Mar 2021 16:32:53 +0400 Subject: [PATCH 031/265] fix compiler errors caused by [-Werror,-Wlogical-op-parentheses] and LOCTEXT_NAMESPACE' macro redefinition --- .../Private/Graph/FlowGraphConnectionDrawingPolicy.cpp | 4 ++-- Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp b/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp index b31478200..348596dac 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphConnectionDrawingPolicy.cpp @@ -86,8 +86,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 && UFlowGraphSettings::Get()->bHighlightInputWiresOfSelectedNodes) + || (Pin->Direction == EGPD_Output && UFlowGraphSettings::Get()->bHighlightOutputWiresOfSelectedNodes)) { for (UEdGraphPin* LinkedPin : Pin->LinkedTo) { diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp index bd129eb42..ed16ae542 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp @@ -120,3 +120,5 @@ UEdGraphNode* FFlowGraphSchemaAction_NewComment::PerformAction(class UEdGraph* P return FEdGraphSchemaAction_NewNode::SpawnNodeFromTemplate(ParentGraph, CommentTemplate, SpawnLocation); } + +#undef LOCTEXT_NAMESPACE \ No newline at end of file From 76656589e7dccd56095483cd95beb9ec7ae300fc Mon Sep 17 00:00:00 2001 From: sturcotte06 Date: Wed, 24 Mar 2021 09:55:27 -0400 Subject: [PATCH 032/265] Fix includes for non-unity builds for FlowEditor module (#28) Co-authored-by: Simon Turcotte-Langevin --- .../Private/Asset/AssetTypeActions_FlowAsset.cpp | 2 ++ .../FlowEditor/Private/Asset/FlowAssetDetails.cpp | 2 ++ Source/FlowEditor/Private/Asset/FlowAssetDetails.h | 6 ++++++ .../FlowEditor/Private/Asset/FlowAssetToolbar.cpp | 2 ++ Source/FlowEditor/Private/Asset/FlowDebugger.cpp | 4 ++++ .../Private/Asset/FlowDebuggerToolbar.cpp | 8 +++++++- Source/FlowEditor/Private/FlowEditorCommands.cpp | 1 + Source/FlowEditor/Private/FlowEditorModule.cpp | 1 + .../Customizations/FlowNode_CustomInputDetails.cpp | 3 +++ .../FlowNode_CustomOutputDetails.cpp | 3 +++ .../Private/Graph/Nodes/FlowGraphNode.cpp | 4 ++++ .../Nodes/FlowGraphNode_ExecutionSequence.cpp | 2 ++ .../Private/Graph/Widgets/SFlowGraphNode.cpp | 14 +++++++++++++- .../Private/Graph/Widgets/SFlowPalette.cpp | 5 +++++ .../Private/Nodes/FlowNodeBlueprintFactory.cpp | 10 ++++++++++ Source/FlowEditor/Public/Asset/FlowAssetEditor.h | 1 + .../FlowEditor/Public/Asset/FlowDebuggerToolbar.h | 1 + Source/FlowEditor/Public/FlowEditorCommands.h | 1 + .../Public/Graph/FlowGraphSchema_Actions.h | 1 + .../FlowEditor/Public/Graph/Nodes/FlowGraphNode.h | 3 ++- .../Public/LevelEditor/SLevelEditorFlow.h | 3 +++ 21 files changed, 74 insertions(+), 3 deletions(-) diff --git a/Source/FlowEditor/Private/Asset/AssetTypeActions_FlowAsset.cpp b/Source/FlowEditor/Private/Asset/AssetTypeActions_FlowAsset.cpp index 5f7979ab9..180d87a0b 100644 --- a/Source/FlowEditor/Private/Asset/AssetTypeActions_FlowAsset.cpp +++ b/Source/FlowEditor/Private/Asset/AssetTypeActions_FlowAsset.cpp @@ -3,6 +3,8 @@ #include "FlowAsset.h" +#include "Toolkits/IToolkit.h" + #define LOCTEXT_NAMESPACE "AssetTypeActions_FlowAsset" FText FAssetTypeActions_FlowAsset::GetName() const diff --git a/Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp b/Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp index 44d63f878..a010a85a2 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp @@ -2,8 +2,10 @@ #include "FlowAsset.h" #include "Nodes/Route/FlowNode_SubGraph.h" +#include "DetailLayoutBuilder.h" #include "PropertyCustomizationHelpers.h" #include "PropertyEditing.h" +#include "Widgets/Input/SEditableTextBox.h" #define LOCTEXT_NAMESPACE "FlowAssetDetails" diff --git a/Source/FlowEditor/Private/Asset/FlowAssetDetails.h b/Source/FlowEditor/Private/Asset/FlowAssetDetails.h index fe1641853..c9b7fdf2b 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetDetails.h +++ b/Source/FlowEditor/Private/Asset/FlowAssetDetails.h @@ -1,6 +1,12 @@ #pragma once #include "IDetailCustomization.h" +#include "Templates/SharedPointer.h" +#include "Types/SlateEnums.h" + +class IDetailChildrenBuilder; +class IDetailLayoutBuilder; +class IPropertyHandle; class FFlowAssetDetails final : public IDetailCustomization { diff --git a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp index b0dd65aed..8fd02b2e5 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp @@ -2,6 +2,8 @@ #include "Asset/FlowAssetEditor.h" #include "FlowEditorCommands.h" +#include "Framework/MultiBox/MultiBoxBuilder.h" + #define LOCTEXT_NAMESPACE "FlowAssetToolbar" FFlowAssetToolbar::FFlowAssetToolbar(TSharedPtr InNodeEditor) diff --git a/Source/FlowEditor/Private/Asset/FlowDebugger.cpp b/Source/FlowEditor/Private/Asset/FlowDebugger.cpp index fb5280d11..7b918af01 100644 --- a/Source/FlowEditor/Private/Asset/FlowDebugger.cpp +++ b/Source/FlowEditor/Private/Asset/FlowDebugger.cpp @@ -1,4 +1,8 @@ #include "Asset/FlowDebugger.h" + +#include "Engine/Engine.h" +#include "Engine/World.h" +#include "Templates/Function.h" #include "UnrealEd.h" FFlowDebugger::FFlowDebugger() diff --git a/Source/FlowEditor/Private/Asset/FlowDebuggerToolbar.cpp b/Source/FlowEditor/Private/Asset/FlowDebuggerToolbar.cpp index ddd9fdf5e..087020ded 100644 --- a/Source/FlowEditor/Private/Asset/FlowDebuggerToolbar.cpp +++ b/Source/FlowEditor/Private/Asset/FlowDebuggerToolbar.cpp @@ -4,7 +4,13 @@ #include "FlowAsset.h" -#include "Widgets/Navigation/SBreadcrumbTrail.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" diff --git a/Source/FlowEditor/Private/FlowEditorCommands.cpp b/Source/FlowEditor/Private/FlowEditorCommands.cpp index 641fb7fb3..87b4c06ec 100644 --- a/Source/FlowEditor/Private/FlowEditorCommands.cpp +++ b/Source/FlowEditor/Private/FlowEditorCommands.cpp @@ -6,6 +6,7 @@ #include "Nodes/FlowNode.h" +#include "EditorStyleSet.h" #include "Misc/ConfigCacheIni.h" #define LOCTEXT_NAMESPACE "FlowGraphCommands" diff --git a/Source/FlowEditor/Private/FlowEditorModule.cpp b/Source/FlowEditor/Private/FlowEditorModule.cpp index 371ffe9fd..4d36d355a 100644 --- a/Source/FlowEditor/Private/FlowEditorModule.cpp +++ b/Source/FlowEditor/Private/FlowEditorModule.cpp @@ -22,6 +22,7 @@ #include "AssetToolsModule.h" #include "EdGraphUtilities.h" +#include "Framework/Multibox/MultiBoxBuilder.h" #include "ISequencerChannelInterface.h" #include "ISequencerModule.h" #include "LevelEditor.h" diff --git a/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomInputDetails.cpp b/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomInputDetails.cpp index 872a83aea..55687cf7a 100644 --- a/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomInputDetails.cpp +++ b/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomInputDetails.cpp @@ -2,9 +2,12 @@ #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/Input/STextBlock.h" #define LOCTEXT_NAMESPACE "FlowNode_CustomInputDetails" diff --git a/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomOutputDetails.cpp b/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomOutputDetails.cpp index 85a0e09c3..afeb4d065 100644 --- a/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomOutputDetails.cpp +++ b/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomOutputDetails.cpp @@ -2,9 +2,12 @@ #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/Input/STextBlock.h" #define LOCTEXT_NAMESPACE "FlowNode_CustomOutputDetails" diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 144e1c157..e8d28c317 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -10,6 +10,7 @@ #include "FlowAsset.h" #include "Nodes/FlowNode.h" +#include "AssetData.h" #include "AssetRegistryModule.h" #include "Developer/ToolMenus/Public/ToolMenus.h" #include "EdGraph/EdGraphSchema.h" @@ -19,8 +20,11 @@ #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" +#include "ToolMenuSection.h" #include "UnrealEd.h" #define LOCTEXT_NAMESPACE "FlowGraphNode" diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_ExecutionSequence.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_ExecutionSequence.cpp index 982ec9776..e9aab0e8c 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_ExecutionSequence.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_ExecutionSequence.cpp @@ -1,6 +1,8 @@ #include "Graph/Nodes/FlowGraphNode_ExecutionSequence.h" #include "Nodes/Route/FlowNode_ExecutionSequence.h" +#include "Textures/SlateIcon.h" + UFlowGraphNode_ExecutionSequence::UFlowGraphNode_ExecutionSequence(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp index fe237b212..ab5ad123c 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp @@ -4,14 +4,26 @@ #include "Nodes/FlowNode.h" +#include "EdGraph/EdGraphPin.h" #include "Editor.h" #include "GraphEditorSettings.h" #include "IDocumentation.h" +#include "Input/Reply.h" +#include "Layout/Margin.h" +#include "Misc/Attribute.h" #include "SCommentBubble.h" -#include "SlateOptMacros.h" +#include "SGraphNode.h" +#include "SGraphPin.h" #include "SLevelOfDetailBranchNode.h" +#include "SNodePanel.h" +#include "SlateOptMacros.h" +#include "Styling/SlateColor.h" #include "TutorialMetaData.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" diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp index 1cd18fd6d..1d635022a 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp @@ -8,7 +8,12 @@ #include "EditorStyleSet.h" #include "Styling/CoreStyle.h" +#include "Styling/SlateBrush.h" +#include "Styling/SlateColor.h" +#include "Widgets/Input/STextBlock.h" #include "Widgets/Input/STextComboBox.h" +#include "Widgets/Layout/SBorder.h" +#include "Widgets/SBoxPanel.h" #define LOCTEXT_NAMESPACE "FlowGraphPalette" diff --git a/Source/FlowEditor/Private/Nodes/FlowNodeBlueprintFactory.cpp b/Source/FlowEditor/Private/Nodes/FlowNodeBlueprintFactory.cpp index e203885a7..402526c0a 100644 --- a/Source/FlowEditor/Private/Nodes/FlowNodeBlueprintFactory.cpp +++ b/Source/FlowEditor/Private/Nodes/FlowNodeBlueprintFactory.cpp @@ -6,9 +6,19 @@ #include "BlueprintEditorSettings.h" #include "ClassViewerFilter.h" #include "ClassViewerModule.h" +#include "Editor.h" +#include "EditorStyleSet.h" #include "Kismet2/KismetEditorUtilities.h" +#include "Misc/MessageDialog.h" +#include "Modules/ModuleManager.h" #include "SlateOptMacros.h" +#include "Widgets/Input/SButton.h" +#include "Widgets/Layout/SBorder.h" +#include "Widgets/Layout/SBox.h" #include "Widgets/Layout/SUniformGridPanel.h" +#include "Widgets/SBoxPanel.h" +#include "Widgets/SCompoundWidget.h" +#include "Widgets/SWindow.h" #define LOCTEXT_NAMESPACE "FlowNodeBlueprintFactory" diff --git a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h index 120f412de..b05ea3fa2 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h @@ -1,6 +1,7 @@ #pragma once #include "EditorUndoClient.h" +#include "GraphEditor.h" #include "Misc/NotifyHook.h" #include "Toolkits/AssetEditorToolkit.h" #include "Toolkits/IToolkitHost.h" diff --git a/Source/FlowEditor/Public/Asset/FlowDebuggerToolbar.h b/Source/FlowEditor/Public/Asset/FlowDebuggerToolbar.h index fa51daf2c..aab77fe2e 100644 --- a/Source/FlowEditor/Public/Asset/FlowDebuggerToolbar.h +++ b/Source/FlowEditor/Public/Asset/FlowDebuggerToolbar.h @@ -2,6 +2,7 @@ #include "CoreMinimal.h" #include "Widgets/Input/SComboBox.h" +#include "Widgets/Navigation/SBreadcrumbTrail.h" #include "FlowAsset.h" diff --git a/Source/FlowEditor/Public/FlowEditorCommands.h b/Source/FlowEditor/Public/FlowEditorCommands.h index 7d3a769f1..f4429ce95 100644 --- a/Source/FlowEditor/Public/FlowEditorCommands.h +++ b/Source/FlowEditor/Public/FlowEditorCommands.h @@ -1,6 +1,7 @@ #pragma once #include "EdGraph/EdGraphSchema.h" +#include "Framework/Commands/Commands.h" class FFlowToolbarCommands final : public TCommands { diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h b/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h index d970a245b..018635ab5 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h @@ -1,6 +1,7 @@ #pragma once #include "EdGraph/EdGraphSchema.h" +#include "Engine/Blueprint.h" #include "Nodes/FlowGraphNode.h" #include "Nodes/FlowNode.h" diff --git a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h index 703eb39fa..fd41298bf 100644 --- a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h +++ b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h @@ -1,11 +1,12 @@ #pragma once #include "EdGraph/EdGraphNode.h" +#include "EdGraph/EdGraphPin.h" +#include "Templates/SubclassOf.h" #include "FlowTypes.h" #include "FlowGraphNode.generated.h" -class UEdGraphPin; class UEdGraphSchema; class UFlowNode; diff --git a/Source/FlowEditor/Public/LevelEditor/SLevelEditorFlow.h b/Source/FlowEditor/Public/LevelEditor/SLevelEditorFlow.h index 3bddae762..3dbbd26f0 100644 --- a/Source/FlowEditor/Public/LevelEditor/SLevelEditorFlow.h +++ b/Source/FlowEditor/Public/LevelEditor/SLevelEditorFlow.h @@ -1,8 +1,11 @@ #pragma once #include "CoreMinimal.h" +#include "Widgets/DeclarativeSyntaxSupport.h" #include "Widgets/SCompoundWidget.h" +struct FAssetData; + class SLevelEditorFlow : public SCompoundWidget { public: From 6767c4a86ac075e131d90caa2d01560ec6895b45 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Wed, 24 Mar 2021 15:04:17 +0100 Subject: [PATCH 033/265] merge fix --- .../Graph/Customizations/FlowNode_CustomInputDetails.cpp | 2 +- .../Graph/Customizations/FlowNode_CustomOutputDetails.cpp | 2 +- Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomInputDetails.cpp b/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomInputDetails.cpp index 55687cf7a..5919e37aa 100644 --- a/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomInputDetails.cpp +++ b/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomInputDetails.cpp @@ -7,7 +7,7 @@ #include "PropertyEditing.h" #include "UnrealEd.h" #include "Widgets/Input/SComboBox.h" -#include "Widgets/Input/STextBlock.h" +#include "Widgets/Text/STextBlock.h" #define LOCTEXT_NAMESPACE "FlowNode_CustomInputDetails" diff --git a/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomOutputDetails.cpp b/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomOutputDetails.cpp index afeb4d065..d3795dc14 100644 --- a/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomOutputDetails.cpp +++ b/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomOutputDetails.cpp @@ -7,7 +7,7 @@ #include "PropertyEditing.h" #include "UnrealEd.h" #include "Widgets/Input/SComboBox.h" -#include "Widgets/Input/STextBlock.h" +#include "Widgets/Text/STextBlock.h" #define LOCTEXT_NAMESPACE "FlowNode_CustomOutputDetails" diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp index 1d635022a..61308800b 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp @@ -10,10 +10,10 @@ #include "Styling/CoreStyle.h" #include "Styling/SlateBrush.h" #include "Styling/SlateColor.h" -#include "Widgets/Input/STextBlock.h" #include "Widgets/Input/STextComboBox.h" #include "Widgets/Layout/SBorder.h" #include "Widgets/SBoxPanel.h" +#include "Widgets/Text/STextBlock.h" #define LOCTEXT_NAMESPACE "FlowGraphPalette" From 13568acc06143415614b05262d8025aa63110a1c Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Wed, 24 Mar 2021 17:08:51 +0100 Subject: [PATCH 034/265] Update .gitignore --- .gitignore | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..cc9b78ed9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +/.idea +/.vs +/_ReSharper.Caches +/Binaries +/Intermediate + +*.sln + +*.exe +*.exp +*.lib +*.patch_* +*.pdb +*.target From 931f9a6b367c2b91175e00d0f2c492798d02244c Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Wed, 24 Mar 2021 17:09:06 +0100 Subject: [PATCH 035/265] Create LICENSE --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..c7838761a --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 UnrealEngineCommunityWiki + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 956f3c20a981790b9046319acab25e67f9ee1315 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Wed, 24 Mar 2021 17:09:19 +0100 Subject: [PATCH 036/265] Update README.md --- README.md | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 000000000..97bf5fa69 --- /dev/null +++ b/README.md @@ -0,0 +1,95 @@ +# Flow + +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. +* Licensed under MIT license. You are free to use it for commercial projects, modify it however you see fit, and distribute it further. + +## Concept +It's s design-agnostic event node editor. + +![Flow101](https://user-images.githubusercontent.com/5065057/103543817-6d924080-4e9f-11eb-87d9-15ab092c3875.png) + +* A single node in this graph is a simple UObject, not a function like in blueprints. This allows you to encapsulate the entire gameplay element (logic with its data) within a single Flow Node. The idea is that your write a repeatable "event script" only once for the entire game! +* Unlike blueprints, Flow Node is async/latent by design. Active node usually subscribe to delegates, so it can react to event by triggering output pin (or whatever you choose to). +* Every node defines its own set of input/output pins. It's dead simple to design the flow of the game - just connect nodes representing features. +* Developers creating a Flow Node can call the execution of pins any way they need. API is extremely simple. +* Editor supports convenient displaying debug information on nodes and wires while playing a game. You simply provide what kind of message would be displayed over active Flow Nodes - you can't have that with blueprint functions. + +## Base for your own systems and tools +* It's up to you to add game-specific functionalities by writing your nodes and editor customizations. It's not like a marketplace providing the very specific implementation of systems. It's a convenient base for building systems tailored to fit your needs. +* Quickly build your own Quest system, Dialogue system or any other custom system that would control the flow of events in the game. +* Expand it, build Articy:draft equivalent right in the Unreal Engine. + +## Getting started +In Releases, you can find an example project called Flower, so you can easily check how this plug-in works. + +And if you'd decide to use Flow in your project... +1. Unpack plug-in to the Plugins folder in your project folder. If you don't have such a folder yet, simply create it. +2. Open Project Settings in the editor. Change World Settings to the Flow World Settings class and restart the editor. This class starts the Flow Graph assigned to the map. + +## 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) + +## Simplicity is a key +* It's all about simplifying the cooperation between gameplay programmers and content designers by providing a clean interface between "code of systems" and "using systems". +* Code of gameplay mechanics wouldn't ever be mixed with each other. Usually, system X shouldn't even know about the existence of system Y. Flow Graph is a place to combine features by connecting nodes. +* Every mechanic is exposed to content designers once, in one way only - as the Flow Node. It greatly reduces the number of bugs. Refactoring mechanics is easy since you don't have to update dozens of level blueprints directly calling system functions. +* Systems based on such editor are simple to use for least technical team members, i.e. narrative designers, writers, QA. Every time I ask designers why they love working with such a system, they usually reply: "it's so simple to understand and make a game with it". +* Even a complex game might end up only with a few dozens of Flow Nodes. It's easy to manage the game's complexity - a lot of mechanics, mission scripting, narrative events. It makes it very efficient to develop lengthy campaigns and multiplayer games. + +## Blueprints +* Programmer writing a new gameplay feature can quickly expose it to content creators by creating a new Flow Node. A given C++ feature doesn't have to be exposed to blueprints at all. +* However, Flow Nodes can be created in blueprints by anyone. Personally, I would recommend using blueprint nodes mostly for prototyping and rarely used custom actions, if you have a gameplay programmer in a team. If not, sure, you can implement your systems in blueprints entirely. + +## Performance +* Performance loss in blueprint graphs comes from executing a large network of nodes, processing pins and connections between them. Moving away from overcomplicated level blueprints and messy "system blueprints" to simple Flow Graph might improve framerate and memory management. +* As Flow Nodes are designed to be event-based, executing graph connection might happen only like few times per minute or so. (heavily depends on your logic and event mechanics). Finally, Flow Graph has its own execution logic, doesn't utilize blueprint VM. +* Flow-based event systems are generally more performant than blueprint counterparts. Especially if frequently used nodes are implemented in C++. + +## Flexibility of the system design +Flow Graph communicates with actors in the world by using [Gameplay Tags](https://docs.unrealengine.com/en-US/Gameplay/Tags/index.html). No direct references to actors are used in this variant of scripting - that brings a lot of new possibilities. +* Simply add Flow Component to every "event actor", assign Gameplay Tags identifying this actor. Flow Component registers itself to the Flow Subsystem (or any derived system) when it appears in the world. It's easy to find any event actor this way, just ask Flow Subsystem for actors registered with a given Gameplay Tag. +* It allows for reusing entire Flow Graphs in different maps. Unlike level blueprints, Flow Graphs aren't bound to levels. +* It's possible to place actors used by the single Flow Graph in different sublevels or even worlds. This removes one of the workflow limitations related to the level design. +* It should work well with the World Partition system coming to Unreal Engine - a truly open-world way of building maps where every actor instance is saved separately to disk. That probably means no sublevels and no level blueprints (except the blueprint of the "persistent level"). +* Flow Graph could live as long as the game session, not even bound to the specific world. You can have a meta Flow Graph waiting for events happening anywhere during the game. +* Using Gameplay Tags allows scripting an action on any actor spawned in runtime, typically NPCs. +* In some cases actor with a given Gameplay Tag doesn't even have to exist when starting a related action! Example: On Trigger Enter in the image above would pick up the required trigger after loading a sublevel with this trigger. + +## Recommended workflow +* Flow Graph is meant to entirely replace a need to use Level Blueprints (also known as Flying Spaghetti Monster) in production maps. The flow of the game - the connection between consecutive events and actors - should be scripted by using Flow Graphs only. Otherwise, you ending up creating a mess, using multiple tools for the same job. +* This graph also entirely replaces another way of doing things: referencing different actors directly, i.e. hooking up Spawner actor directly to the Trigger actor. Technically it works fine, but it's impossible to read the designed flow of events scripted this way. Debugging can be very cumbersome and time-consuming. +* Actor blueprints are supposed to be used only to script the inner logic of actors, not connections between actors belonging to different systems. +* Flow Nodes can send and receive blueprint events via Flow Component. This recommended way of communicating between Flow Graph and blueprints. +* Technically, it's always possible to call custom blueprint events directly from blueprint Flow Node, but this would require creating a new Flow Node for every custom blueprint actor. Effectively, you would throw a simplicity of Flow Graph out of the window. + +## State of the development +* Flow editor and runtime system are ready for production. +* Plugin and the code of the sample project are available for every engine version since 4.22. I'm not planning on backporting code to older engine versions since the runtime code relies on [programming subsystems](https://docs.unrealengine.com/en-US/ProgrammingAndScripting/Subsystems/index.html) introduced with UE 4.22. +* Currently, the example content is... modest. I hope to prepare better samples in the future. +* Development continues. Check [Issues](https://github.com/MothCocoon/Flow/issues) for a list of useful things I'm hoping to work on in the future. +* Your feedback is much welcome! It's all about developing a toolset for any kind of game. +* In the short term, code might need a bit of love to support creating multiple flow-based systems without modifying the plugin code at all. For example, the quest and dialogue system based on the Flow Subsystem. It's not a huge work, plugin was designed for it. I just need time to create a few different systems, play with it, update the plugin where's needed. +* I'm planning to release the Flow plugin on the Marketplace, so more people could discover it and conveniently add it to their asset libraries. It will be free of charge, obviously. + +## Contact +* Catch me on Twitter: [@MothDoctor](https://twitter.com/MothDoctor) +* Discuss thins related to plugin on the Discord server named Flow. + +## 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 only the one who decided it would be crazy useful to adopt it for Unreal Engine. And make it publically available as my humble contribution to the open-source community. +* 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. Written from the scratch, 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. + +## Related resources +* [Introduction to Gameplay Tags](https://docs.unrealengine.com/en-US/ProgrammingAndScripting/Tags/index.html) +* [Behind the Scenes of the Cinematic Dialogues in The Witcher 3: Wild Hunt](https://www.youtube.com/watch?v=chf3REzAjgI) +* [Sinking City - story scripting for the open-world game](https://youtu.be/W_yiopwoXt0?t=929) as part of their talk on Sinking City development +* [Unreal Engine Open World Preview and Landscape Tools | Unreal Dev Days 2019](https://www.youtube.com/watch?v=wXbyqGYfM1I) - starts from describing the upcoming open-world streaming system that might no longer use level blueprints +* [Blueprints In-depth - Part 1 | Unreal Fest Europe 2019](https://youtu.be/j6mskTgL7kU?t=1048) - great talk on blueprint system, the timestamp at the Performance part. +* [Blueprints In-depth - Part 2 | Unreal Fest Europe 2019](https://www.youtube.com/watch?v=0YMS2wnykbc) +* [The Visual Logger: For All Your Gameplay Needs!](https://www.youtube.com/watch?v=hWpbco3F4L4) +* [Gamedec exemplifies how to incorporate complex branching pathways using Unreal Engine](https://www.unrealengine.com/en-US/tech-blog/gamedec-exemplifies-how-to-incorporate-complex-branching-pathways-using-unreal-engine) - example how the integration of Artict:Draft with Unreal Engine looks like From 4968f1b21a96e52114ac9d91d63cd5753b9ba251 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Wed, 24 Mar 2021 17:29:32 +0100 Subject: [PATCH 037/265] Clang compilation fixes --- .../Private/Graph/Customizations/FlowNode_CustomInputDetails.h | 2 ++ .../Private/Graph/Customizations/FlowNode_CustomOutputDetails.h | 2 ++ Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp | 1 + Source/FlowEditor/Public/Asset/FlowAssetEditor.h | 1 + Source/FlowEditor/Public/FlowEditorCommands.h | 2 ++ 5 files changed, 8 insertions(+) diff --git a/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomInputDetails.h b/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomInputDetails.h index efa077262..3f3cbd352 100644 --- a/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomInputDetails.h +++ b/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomInputDetails.h @@ -1,6 +1,8 @@ #pragma once #include "IDetailCustomization.h" +#include "Templates/SharedPointer.h" +#include "Widgets/SWidget.h" class FFlowNode_CustomInputDetails final : public IDetailCustomization { diff --git a/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomOutputDetails.h b/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomOutputDetails.h index 726d8df5d..982f795b6 100644 --- a/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomOutputDetails.h +++ b/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomOutputDetails.h @@ -1,6 +1,8 @@ #pragma once #include "IDetailCustomization.h" +#include "Templates/SharedPointer.h" +#include "Widgets/SWidget.h" class FFlowNode_CustomOutputDetails final : public IDetailCustomization { diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp index 61308800b..ff410bbe1 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 "Fonts/SlateFontInfo.h" #include "Styling/CoreStyle.h" #include "Styling/SlateBrush.h" #include "Styling/SlateColor.h" diff --git a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h index b05ea3fa2..41d6bbdbd 100644 --- a/Source/FlowEditor/Public/Asset/FlowAssetEditor.h +++ b/Source/FlowEditor/Public/Asset/FlowAssetEditor.h @@ -15,6 +15,7 @@ class IDetailsView; class SDockableTab; class SGraphEditor; class UEdGraphNode; +struct FSlateBrush; struct FPropertyChangedEvent; struct Rect; diff --git a/Source/FlowEditor/Public/FlowEditorCommands.h b/Source/FlowEditor/Public/FlowEditorCommands.h index f4429ce95..9f3045992 100644 --- a/Source/FlowEditor/Public/FlowEditorCommands.h +++ b/Source/FlowEditor/Public/FlowEditorCommands.h @@ -2,6 +2,8 @@ #include "EdGraph/EdGraphSchema.h" #include "Framework/Commands/Commands.h" +#include "Framework/Commands/UICommandInfo.h" +#include "Templates/SharedPointer.h" class FFlowToolbarCommands final : public TCommands { From 826528001d0f7d76b8043e1a90e8806c79fac7a8 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Wed, 24 Mar 2021 19:41:37 +0100 Subject: [PATCH 038/265] Update Flow.uplugin --- Flow.uplugin | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Flow.uplugin b/Flow.uplugin index ebef2d974..9f1668167 100644 --- a/Flow.uplugin +++ b/Flow.uplugin @@ -6,9 +6,8 @@ "Category" : "Gameplay", "CreatedBy" : "Krzysztof Justyński", "CreatedByURL" : "https://twitter.com/MothDoctor", - "DocsURL" : "https://github.com/MothCocoon/Flow", + "DocsURL" : "https://github.com/MothCocoon/FlowGraph", "MarketplaceURL" : "", - "SupportURL" : "https://discord.gg/aUuSw9ZP", "EngineVersion": "4.26.0", "EnabledByDefault" : true, "CanContainContent" : false, From d9f24cf045a6a8fbb7bf1f18a9a9acc03cdd9c20 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Wed, 24 Mar 2021 22:06:58 +0100 Subject: [PATCH 039/265] Update README.md --- README.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 97bf5fa69..b79f3fbe9 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,11 @@ It's s design-agnostic event node editor. * Quickly build your own Quest system, Dialogue system or any other custom system that would control the flow of events in the game. * Expand it, build Articy:draft equivalent right in the Unreal Engine. +## 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) + ## Getting started In Releases, you can find an example project called Flower, so you can easily check how this plug-in works. @@ -26,10 +31,10 @@ And if you'd decide to use Flow in your project... 1. Unpack plug-in to the Plugins folder in your project folder. If you don't have such a folder yet, simply create it. 2. Open Project Settings in the editor. Change World Settings to the Flow World Settings class and restart the editor. This class starts the Flow Graph assigned to the map. -## 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) +You can include this plugin repository as dependency of your own Git project. It can be done by using Git submodules. +``` +git submodule add -b 4.26 https://github.com/MothCocoon/FlowGraph.git Plugins/Flow +``` ## Simplicity is a key * It's all about simplifying the cooperation between gameplay programmers and content designers by providing a clean interface between "code of systems" and "using systems". From 90e5e0d55adfaa3b6680937e9450b3de6fa03067 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 26 Mar 2021 14:02:03 +0100 Subject: [PATCH 040/265] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b79f3fbe9..23a99ad2a 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ 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. * Licensed under MIT license. You are free to use it for commercial projects, modify it however you see fit, and distribute it further. +* This a fresh repository, extracted plugin itself from the [previous repository](https://github.com/MothCocoon/Flow). ## Concept It's s design-agnostic event node editor. From 32e43795f4da97cc296cee668bdb2aa9c1d3de8c Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 26 Mar 2021 21:23:01 +0100 Subject: [PATCH 041/265] quality pass: adding comments, exposing methods, fixes --- Source/Flow/Private/FlowAsset.cpp | 27 ++++----- Source/Flow/Private/FlowSubsystem.cpp | 58 ++++++++++--------- .../Private/Nodes/Route/FlowNode_SubGraph.cpp | 2 +- Source/Flow/Public/FlowAsset.h | 43 +++++++++----- Source/Flow/Public/FlowSubsystem.h | 29 ++++++---- .../Private/Asset/FlowAssetEditor.cpp | 6 +- .../Public/Asset/FlowDebuggerToolbar.h | 2 +- 7 files changed, 96 insertions(+), 71 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 1e3b97701..0423eb31c 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -52,7 +52,7 @@ EDataValidationResult UFlowAsset::IsDataValid(TArray& ValidationErrors) { for (const TPair& NodePair : Nodes) { - EDataValidationResult Result = NodePair.Value->IsDataValid(ValidationErrors); + const EDataValidationResult Result = NodePair.Value->IsDataValid(ValidationErrors); if (Result == EDataValidationResult::Invalid) { return EDataValidationResult::Invalid; @@ -222,28 +222,28 @@ void UFlowAsset::SetInspectedInstance(const FName& NewInspectedInstanceName) } #endif -void UFlowAsset::InitInstance(UObject* InOwner, UFlowAsset* InTemplateAsset) +void UFlowAsset::InitializeInstance(const TWeakObjectPtr InOwner, UFlowAsset* InTemplateAsset) { Owner = InOwner; TemplateAsset = InTemplateAsset; for (TPair& Node : Nodes) { - UFlowNode* NewInstance = NewObject(this, Node.Value->GetClass(), NAME_None, RF_Transient, Node.Value, false, nullptr); - Node.Value = NewInstance; + 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(NewInstance)) + if (UFlowNode_Start* InNode = Cast(NewNodeInstance)) { StartNode = InNode; } - if (UFlowNode_CustomInput* CustomEvent = Cast(NewInstance)) + if (UFlowNode_CustomInput* CustomInput = Cast(NewNodeInstance)) { - const FName& EventName = CustomEvent->EventName; - if (!EventName.IsNone() && !CustomEventNodes.Contains(CustomEvent->EventName)) + const FName& EventName = CustomInput->EventName; + if (!EventName.IsNone() && !CustomInputNodes.Contains(CustomInput->EventName)) { - CustomEventNodes.Emplace(CustomEvent->EventName, CustomEvent); + CustomInputNodes.Emplace(CustomInput->EventName, CustomInput); } } } @@ -252,7 +252,7 @@ void UFlowAsset::InitInstance(UObject* InOwner, UFlowAsset* InTemplateAsset) void UFlowAsset::PreloadNodes() { TArray GraphEntryNodes = {StartNode}; - for (const TPair& CustomEvent : CustomEventNodes) + for (const TPair& CustomEvent : CustomInputNodes) { GraphEntryNodes.Emplace(CustomEvent.Value); } @@ -344,11 +344,6 @@ void UFlowAsset::FinishFlow(const bool bFlowCompleted) } } -UObject* UFlowAsset::GetOwner() const -{ - return Owner; -} - TWeakObjectPtr UFlowAsset::GetFlowInstance(UFlowNode_SubGraph* SubGraphNode) const { return ActiveSubGraphs.FindRef(SubGraphNode); @@ -359,7 +354,7 @@ void UFlowAsset::TriggerCustomEvent(UFlowNode_SubGraph* Node, const FName& Event const TWeakObjectPtr FlowInstance = ActiveSubGraphs.FindRef(Node); if (FlowInstance.IsValid()) { - if (UFlowNode_CustomInput* CustomEvent = FlowInstance->CustomEventNodes.FindRef(EventName)) + if (UFlowNode_CustomInput* CustomEvent = FlowInstance->CustomInputNodes.FindRef(EventName)) { RecordedNodes.Add(CustomEvent); CustomEvent->TriggerFirstOutput(true); diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index 02505775f..867177772 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -66,46 +66,37 @@ void UFlowSubsystem::FinishRootFlow(UObject* Owner, UFlowAsset* FlowAsset) } } -void UFlowSubsystem::PreloadSubFlow(UFlowNode_SubGraph* SubFlow) +void UFlowSubsystem::StartSubFlow(UFlowNode_SubGraph* SubGraphNode, const bool bPreloading /* = false */) { - if (!InstancedSubFlows.Contains(SubFlow)) + if (!InstancedSubFlows.Contains(SubGraphNode)) { - UObject* Owner = SubFlow->Asset.IsNull() ? nullptr : SubFlow->Asset->GetOwner(); - UFlowAsset* NewFlow = CreateFlowInstance(Owner, SubFlow->Asset); - InstancedSubFlows.Add(SubFlow, NewFlow); + const TWeakObjectPtr Owner = SubGraphNode->GetFlowAsset() ? SubGraphNode->GetFlowAsset()->GetOwner() : nullptr; + UFlowAsset* NewFlow = CreateFlowInstance(Owner, SubGraphNode->Asset); + InstancedSubFlows.Add(SubGraphNode, NewFlow); - NewFlow->PreloadNodes(); + if (bPreloading) + { + NewFlow->PreloadNodes(); + } } -} -void UFlowSubsystem::StartSubFlow(UFlowNode_SubGraph* SubFlow) -{ - if (!InstancedSubFlows.Contains(SubFlow)) + if (!bPreloading) { - UObject* Owner = SubFlow->Asset.IsNull() ? nullptr : SubFlow->Asset->GetOwner(); - UFlowAsset* NewFlow = CreateFlowInstance(Owner, SubFlow->Asset); - InstancedSubFlows.Add(SubFlow, NewFlow); + // get instanced asset from map - in case it was already instanced by calling StartSubFlow() with bPreloading == true + InstancedSubFlows[SubGraphNode]->StartAsSubFlow(SubGraphNode); } - - // get instanced asset from map - in case it was already instanced by PreloadSubFlow() - InstancedSubFlows[SubFlow]->StartAsSubFlow(SubFlow); } -void UFlowSubsystem::FinishSubFlow(UFlowNode_SubGraph* SubFlow) +void UFlowSubsystem::FinishSubFlow(UFlowNode_SubGraph* SubGraphNode) { - if (UFlowAsset* Instance = InstancedSubFlows.FindRef(SubFlow)) + if (UFlowAsset* Instance = InstancedSubFlows.FindRef(SubGraphNode)) { - InstancedSubFlows.Remove(SubFlow); + InstancedSubFlows.Remove(SubGraphNode); Instance->FinishFlow(false); } } -void UFlowSubsystem::RemoveInstancedTemplate(UFlowAsset* Template) -{ - InstancedTemplates.Remove(Template); -} - -UFlowAsset* UFlowSubsystem::CreateFlowInstance(UObject* Owner, TSoftObjectPtr FlowAsset) +UFlowAsset* UFlowSubsystem::CreateFlowInstance(const TWeakObjectPtr Owner, TSoftObjectPtr FlowAsset) { check(!FlowAsset.IsNull()); @@ -127,13 +118,28 @@ UFlowAsset* UFlowSubsystem::CreateFlowInstance(UObject* Owner, TSoftObjectPtrGetPathName()) + TEXT("_") + FString::FromInt(FlowAsset.Get()->GetInstancesNum()); UFlowAsset* NewInstance = NewObject(this, FlowAsset->GetClass(), *NewInstanceName, RF_Transient, FlowAsset.Get(), false, nullptr); - NewInstance->InitInstance(Owner, FlowAsset.Get()); + NewInstance->InitializeInstance(Owner, FlowAsset.Get()); FlowAsset.Get()->AddInstance(NewInstance); return NewInstance; } +void UFlowSubsystem::RemoveInstancedTemplate(UFlowAsset* Template) +{ + InstancedTemplates.Remove(Template); +} + +TMap UFlowSubsystem::GetRootInstances() const +{ + TMap Result; + for (const TPair, UFlowAsset*>& Pair : RootInstances) + { + Result.Emplace(Pair.Key.Get(), Pair.Value); + } + return Result; +} + UWorld* UFlowSubsystem::GetWorld() const { return GetGameInstance()->GetWorld(); diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp index ee789f398..a56bd8623 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp @@ -22,7 +22,7 @@ void UFlowNode_SubGraph::PreloadContent() { if (!Asset.IsNull()) { - GetFlowSubsystem()->PreloadSubFlow(this); + GetFlowSubsystem()->StartSubFlow(this, true); } } diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 74eb2f5f5..3802fe6eb 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -116,7 +116,7 @@ class FLOW_API UFlowAsset : public UObject TArray GetCustomOutputs() const { return CustomOutputs; } ////////////////////////////////////////////////////////////////////////// -// Instanced asset +// Instances of the template asset private: // Original object holds references to instances @@ -141,9 +141,7 @@ class FLOW_API UFlowAsset : public UObject UFlowAsset* GetInspectedInstance() const { return InspectedInstance.IsValid() ? InspectedInstance.Get() : nullptr; } DECLARE_EVENT(UFlowAsset, FRegenerateToolbarsEvent); - FRegenerateToolbarsEvent& OnRegenerateToolbars() { return RegenerateToolbarsEvent; } - FRegenerateToolbarsEvent RegenerateToolbarsEvent; private: @@ -151,24 +149,29 @@ class FLOW_API UFlowAsset : public UObject #endif ////////////////////////////////////////////////////////////////////////// -// Executing graph +// Executing asset instance -public: +private: UPROPERTY() UFlowAsset* TemplateAsset; -private: + // 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 + TWeakObjectPtr Owner; + + // SubGraph node that created this Flow Asset instance TWeakObjectPtr NodeOwningThisAssetInstance; - TMap, TWeakObjectPtr> ActiveSubGraphs; - UPROPERTY() - UObject* Owner; + // 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() - TMap CustomEventNodes; + TMap CustomInputNodes; UPROPERTY() TSet PreloadedNodes; @@ -182,14 +185,28 @@ class FLOW_API UFlowAsset : public UObject TArray RecordedNodes; public: - void InitInstance(UObject* InOwner, UFlowAsset* InTemplateAsset); - void PreloadNodes(); + void InitializeInstance(const TWeakObjectPtr InOwner, UFlowAsset* InTemplateAsset); + + 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") + UObject* GetOwner() const { return Owner.Get(); } + + template + TWeakObjectPtr GetOwner() const + { + return Owner.IsValid() ? Cast(Owner) : nullptr; + } + + virtual void PreloadNodes(); virtual void StartFlow(); virtual void StartAsSubFlow(UFlowNode_SubGraph* SubGraphNode); virtual void FinishFlow(const bool bFlowCompleted); - UObject* GetOwner() const; + // Get Flow Asset instance created by the given SubGraph node TWeakObjectPtr GetFlowInstance(UFlowNode_SubGraph* SubGraphNode) const; private: diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index e67933c1b..11a5c9afa 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -26,20 +26,23 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem UFlowSubsystem(); - FStreamableManager Streamable; - + friend class UFlowAsset; + friend class UFlowNode_SubGraph; + // All asset templates with active instances UPROPERTY() TArray InstancedTemplates; - // Assets instanced by object from another system like World Settings, not SubGraph node + // Assets instanced by object from another system, i.e. World Settings or Player Controller UPROPERTY() - TMap RootInstances; + TMap, UFlowAsset*> RootInstances; // Assets instanced by Sub Graph nodes UPROPERTY() TMap InstancedSubFlows; + FStreamableManager Streamable; + public: virtual bool ShouldCreateSubsystem(UObject* Outer) const override; @@ -47,24 +50,28 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem virtual void Deinitialize() override; // 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); // Finish the root Flow, typically when closing world that created this flow + UFUNCTION(BlueprintCallable, Category = "FlowSubsystem") void FinishRootFlow(UObject* Owner, UFlowAsset* FlowAsset); - void PreloadSubFlow(UFlowNode_SubGraph* SubFlow); - void StartSubFlow(UFlowNode_SubGraph* SubFlow); - void FinishSubFlow(UFlowNode_SubGraph* SubFlow); +private: + void StartSubFlow(UFlowNode_SubGraph* SubGraphNode, const bool bPreloading = false); + void FinishSubFlow(UFlowNode_SubGraph* SubGraphNode); + UFlowAsset* CreateFlowInstance(const TWeakObjectPtr Owner, TSoftObjectPtr FlowAsset); void RemoveInstancedTemplate(UFlowAsset* Template); -private: - UFlowAsset* CreateFlowInstance(UObject* Owner, TSoftObjectPtr FlowAsset); - 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 UFUNCTION(BlueprintPure, Category = "FlowSubsystem") - TMap GetRootInstances() const { return RootInstances; } + TMap GetRootInstances() const; // Returns assets instanced by Sub Graph nodes UFUNCTION(BlueprintPure, Category = "FlowSubsystem") diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index 3e8ae1053..ce717d64e 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -335,8 +335,8 @@ void FFlowAssetEditor::GoToMasterInstance() { UFlowAsset* AssetThatInstancedThisAsset = FlowAsset->GetInspectedInstance()->GetMasterInstance(); - GEditor->GetEditorSubsystem()->OpenEditorForAsset(AssetThatInstancedThisAsset->TemplateAsset); - AssetThatInstancedThisAsset->TemplateAsset->SetInspectedInstance(AssetThatInstancedThisAsset->GetDisplayName()); + GEditor->GetEditorSubsystem()->OpenEditorForAsset(AssetThatInstancedThisAsset->GetTemplateAsset()); + AssetThatInstancedThisAsset->GetTemplateAsset()->SetInspectedInstance(AssetThatInstancedThisAsset->GetDisplayName()); } bool FFlowAssetEditor::CanGoToMasterInstance() @@ -956,7 +956,7 @@ void FFlowAssetEditor::OnNodeDoubleClicked(class UEdGraphNode* Node) const const TWeakObjectPtr SubFlowInstance = SubGraphNode->GetFlowAsset()->GetFlowInstance(SubGraphNode); if (SubFlowInstance.IsValid()) { - SubGraphNode->GetFlowAsset()->TemplateAsset->SetInspectedInstance(SubFlowInstance->GetDisplayName()); + SubGraphNode->GetFlowAsset()->GetTemplateAsset()->SetInspectedInstance(SubFlowInstance->GetDisplayName()); } } } diff --git a/Source/FlowEditor/Public/Asset/FlowDebuggerToolbar.h b/Source/FlowEditor/Public/Asset/FlowDebuggerToolbar.h index aab77fe2e..15037329c 100644 --- a/Source/FlowEditor/Public/Asset/FlowDebuggerToolbar.h +++ b/Source/FlowEditor/Public/Asset/FlowDebuggerToolbar.h @@ -54,7 +54,7 @@ struct FFlowBreadcrumb {} FFlowBreadcrumb(const UFlowAsset* FlowAsset) - : AssetPathName(FlowAsset->TemplateAsset->GetPathName()) + : AssetPathName(FlowAsset->GetTemplateAsset()->GetPathName()) , InstanceName(FlowAsset->GetDisplayName()) {} }; From c3fb540850801fae04385a63d2ed051f79787fef Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 26 Mar 2021 21:27:50 +0100 Subject: [PATCH 042/265] PR #22: added InitializeInstance method to Flow Node --- Source/Flow/Private/FlowAsset.cpp | 2 ++ Source/Flow/Private/Nodes/FlowNode.cpp | 5 +++++ Source/Flow/Public/Nodes/FlowNode.h | 13 ++++++++++++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 0423eb31c..710511297 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -246,6 +246,8 @@ void UFlowAsset::InitializeInstance(const TWeakObjectPtr InOwner, UFlow CustomInputNodes.Emplace(CustomInput->EventName, CustomInput); } } + + NewNodeInstance->InitializeInstance(); } } diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 95f3f756d..4e64792f1 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -169,6 +169,11 @@ UWorld* UFlowNode::GetWorld() const return nullptr; } +void UFlowNode::InitializeInstance() +{ + K2_InitializeInstance(); +} + void UFlowNode::TriggerPreload() { bPreloaded = true; diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 978884088..d558f0bf2 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -190,7 +190,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte static FString NoActorsFound; ////////////////////////////////////////////////////////////////////////// -// Runtime +// Executing node instance public: bool bPreloaded; @@ -213,6 +213,17 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte virtual UWorld* GetWorld() const override; +protected: + // Method called just after creating the node instance, while initialize Flow Asset instance + // This happens before executing graph, only called during gameplay + virtual void InitializeInstance(); + + // Event called just after creating the node instance, while initialize Flow Asset instance + // This happens before executing graph, only called during gameplay + UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "InitInstance")) + void K2_InitializeInstance(); + +public: void TriggerPreload(); void TriggerFlush(); From 1697e2e379ebadad4af026decbc22f00c93974d1 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sat, 27 Mar 2021 13:11:45 +0100 Subject: [PATCH 043/265] Update LICENSE --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index c7838761a..60c62699d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020 UnrealEngineCommunityWiki +Copyright (c) Krzysztof Justyński Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From cb55358e8f2af5b5d3f49bab11b61a23305ad493 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sat, 27 Mar 2021 13:33:49 +0100 Subject: [PATCH 044/265] typo fix --- Source/Flow/Public/Nodes/FlowNode.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index d558f0bf2..96b77905c 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -214,11 +214,11 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte virtual UWorld* GetWorld() const override; protected: - // Method called just after creating the node instance, while initialize Flow Asset instance + // Method called just after creating the node instance, while initializing the Flow Asset instance // This happens before executing graph, only called during gameplay virtual void InitializeInstance(); - // Event called just after creating the node instance, while initialize Flow Asset instance + // 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")) void K2_InitializeInstance(); From 1120bb59a91148eafa48ba396403f8198ec4b7e7 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 28 Mar 2021 15:08:11 +0200 Subject: [PATCH 045/265] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 23a99ad2a..051da20ad 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ 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. * Licensed under MIT license. You are free to use it for commercial projects, modify it however you see fit, and distribute it further. -* This a fresh repository, extracted plugin itself from the [previous repository](https://github.com/MothCocoon/Flow). +* This a fresh repository, extracted plugin itself from [the legacy repository](https://github.com/MothCocoon/Flow). Also created the 2nd repository where I gonna put sample modues containting quest or dialogue systems: [FlowSamples](https://github.com/MothCocoon/FlowSamples) ## Concept It's s design-agnostic event node editor. @@ -74,14 +74,14 @@ Flow Graph communicates with actors in the world by using [Gameplay Tags](https: * Flow editor and runtime system are ready for production. * Plugin and the code of the sample project are available for every engine version since 4.22. I'm not planning on backporting code to older engine versions since the runtime code relies on [programming subsystems](https://docs.unrealengine.com/en-US/ProgrammingAndScripting/Subsystems/index.html) introduced with UE 4.22. * Currently, the example content is... modest. I hope to prepare better samples in the future. -* Development continues. Check [Issues](https://github.com/MothCocoon/Flow/issues) for a list of useful things I'm hoping to work on in the future. +* Development continues. Check [Issues](https://github.com/MothCocoon/FlowGraph/issues) for a list of useful things I'm hoping to work on in the future. * Your feedback is much welcome! It's all about developing a toolset for any kind of game. * In the short term, code might need a bit of love to support creating multiple flow-based systems without modifying the plugin code at all. For example, the quest and dialogue system based on the Flow Subsystem. It's not a huge work, plugin was designed for it. I just need time to create a few different systems, play with it, update the plugin where's needed. * I'm planning to release the Flow plugin on the Marketplace, so more people could discover it and conveniently add it to their asset libraries. It will be free of charge, obviously. ## Contact * Catch me on Twitter: [@MothDoctor](https://twitter.com/MothDoctor) -* Discuss thins related to plugin on the Discord server named Flow. +* Discuss things related to plugin on the Discord server named Flow. ## 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 only the one who decided it would be crazy useful to adopt it for Unreal Engine. And make it publically available as my humble contribution to the open-source community. From 179e46bdca72828feaa91a2c355ee07c0a61d174 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 30 Mar 2021 23:36:27 +0200 Subject: [PATCH 046/265] support for adding/removing Identity Tags during gameplay --- Source/Flow/Private/FlowComponent.cpp | 90 +++++++++++++++++++ Source/Flow/Private/FlowSubsystem.cpp | 86 ++++++++++++++++-- .../World/FlowNode_ComponentObserver.cpp | 22 ++++- Source/Flow/Public/FlowComponent.h | 36 ++++++-- Source/Flow/Public/FlowSubsystem.h | 26 +++++- .../Nodes/World/FlowNode_ComponentObserver.h | 6 ++ 6 files changed, 248 insertions(+), 18 deletions(-) diff --git a/Source/Flow/Private/FlowComponent.cpp b/Source/Flow/Private/FlowComponent.cpp index af9ce24bd..8c24e179c 100644 --- a/Source/Flow/Private/FlowComponent.cpp +++ b/Source/Flow/Private/FlowComponent.cpp @@ -31,6 +31,86 @@ void UFlowComponent::EndPlay(const EEndPlayReason::Type EndPlayReason) Super::EndPlay(EndPlayReason); } +void UFlowComponent::AddIdentityTag(const FGameplayTag Tag) +{ + ensure(GetOwner()->HasAuthority()); + + if (Tag.IsValid() && !IdentityTags.HasTagExact(Tag)) + { + IdentityTags.AddTag(Tag); + + if (HasBegunPlay()) + { + if (UFlowSubsystem* FlowSubsystem = GetWorld()->GetGameInstance()->GetSubsystem()) + { + FlowSubsystem->OnIdentityTagAdded(this, Tag); + } + } + } +} + +void UFlowComponent::AddIdentityTags(FGameplayTagContainer Tags) +{ + ensure(GetOwner()->HasAuthority()); + + // todo: iterator and remove invalid tags + for (const FGameplayTag& Tag : Tags) + { + if (Tag.IsValid() && !IdentityTags.HasTagExact(Tag)) + { + IdentityTags.AddTag(Tag); + } + } + + if (Tags.Num() > 0 && HasBegunPlay()) + { + if (UFlowSubsystem* FlowSubsystem = GetWorld()->GetGameInstance()->GetSubsystem()) + { + FlowSubsystem->OnIdentityTagsAdded(this, Tags); + } + } +} + +void UFlowComponent::RemoveIdentityTag(const FGameplayTag Tag) +{ + ensure(GetOwner()->HasAuthority()); + + if (Tag.IsValid() && IdentityTags.HasTagExact(Tag)) + { + IdentityTags.RemoveTag(Tag); + + if (HasBegunPlay()) + { + if (UFlowSubsystem* FlowSubsystem = GetWorld()->GetGameInstance()->GetSubsystem()) + { + FlowSubsystem->OnIdentityTagRemoved(this, Tag); + } + } + } +} + +void UFlowComponent::RemoveIdentityTags(FGameplayTagContainer Tags) +{ + ensure(GetOwner()->HasAuthority()); + + // todo: iterator and remove invalid tags + for (const FGameplayTag& Tag : Tags) + { + if (Tag.IsValid() && IdentityTags.HasTagExact(Tag)) + { + IdentityTags.RemoveTag(Tag); + } + } + + if (Tags.Num() > 0 && HasBegunPlay()) + { + if (UFlowSubsystem* FlowSubsystem = GetWorld()->GetGameInstance()->GetSubsystem()) + { + FlowSubsystem->OnIdentityTagsRemoved(this, Tags); + } + } +} + void UFlowComponent::NotifyGraph(const FGameplayTag NotifyTag) { OnNotifyFromComponent.Broadcast(this, NotifyTag); @@ -51,3 +131,13 @@ void UFlowComponent::NotifyActor(const FGameplayTag ActorTag, const FGameplayTag } } } + +UFlowSubsystem* UFlowComponent::GetFlowSubsystem() const +{ + if (GetOwner()->GetGameInstance()) + { + return GetOwner()->GetGameInstance()->GetSubsystem(); + } + + return nullptr; +} diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index 867177772..c64b9c639 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -149,26 +149,98 @@ void UFlowSubsystem::RegisterComponent(UFlowComponent* Component) { for (const FGameplayTag& Tag : Component->IdentityTags) { - FlowComponents.Emplace(Tag, Component); + if (Tag.IsValid()) + { + FlowComponentRegistry.Emplace(Tag, Component); + } } OnComponentRegistered.Broadcast(Component); } +void UFlowSubsystem::OnIdentityTagAdded(UFlowComponent* Component, const FGameplayTag& AddedTag) +{ + FlowComponentRegistry.Emplace(AddedTag, Component); + + // broadcast OnComponentRegistered only if this component wasn't present in the registry previously + if (Component->IdentityTags.Num() > 1) + { + OnComponentTagAdded.Broadcast(Component, FGameplayTagContainer(AddedTag)); + } + else + { + OnComponentRegistered.Broadcast(Component); + } +} + +void UFlowSubsystem::OnIdentityTagsAdded(UFlowComponent* Component, const FGameplayTagContainer& AddedTags) +{ + for (const FGameplayTag& Tag : AddedTags) + { + FlowComponentRegistry.Emplace(Tag, Component); + } + + // broadcast OnComponentRegistered only if this component wasn't present in the registry previously + if (Component->IdentityTags.Num() > AddedTags.Num()) + { + OnComponentTagAdded.Broadcast(Component, AddedTags); + } + else + { + OnComponentRegistered.Broadcast(Component); + } +} + void UFlowSubsystem::UnregisterComponent(UFlowComponent* Component) { for (const FGameplayTag& Tag : Component->IdentityTags) { - FlowComponents.Remove(Tag, Component); + if (Tag.IsValid()) + { + FlowComponentRegistry.Remove(Tag, Component); + } } OnComponentUnregistered.Broadcast(Component); } +void UFlowSubsystem::OnIdentityTagRemoved(UFlowComponent* Component, const FGameplayTag& RemovedTag) +{ + FlowComponentRegistry.Emplace(RemovedTag, Component); + + // broadcast OnComponentUnregistered only if this component isn't present in the registry anymore + if (Component->IdentityTags.Num() > 0) + { + OnComponentTagRemoved.Broadcast(Component, FGameplayTagContainer(RemovedTag)); + } + else + { + OnComponentUnregistered.Broadcast(Component); + } +} + +void UFlowSubsystem::OnIdentityTagsRemoved(UFlowComponent* Component, const FGameplayTagContainer& RemovedTags) +{ + for (const FGameplayTag& Tag : RemovedTags) + { + FlowComponentRegistry.Remove(Tag, Component); + } + + // broadcast OnComponentUnregistered only if this component isn't present in the registry anymore + if (Component->IdentityTags.Num() > 0) + { + OnComponentTagRemoved.Broadcast(Component, RemovedTags); + } + else + { + OnComponentUnregistered.Broadcast(Component); + } +} + TSet UFlowSubsystem::GetFlowComponentsByTag(const FGameplayTag Tag) const { TArray> FoundComponents; - FlowComponents.MultiFind(Tag, FoundComponents); + FlowComponentRegistry.MultiFind(Tag, FoundComponents); TSet Result; for (const TWeakObjectPtr& Component : FoundComponents) @@ -202,7 +274,7 @@ TSet UFlowSubsystem::GetFlowComponentsByTags(const FGameplayTag TSet UFlowSubsystem::GetFlowActorsByTag(const FGameplayTag Tag) const { TArray> FoundComponents; - FlowComponents.MultiFind(Tag, FoundComponents); + FlowComponentRegistry.MultiFind(Tag, FoundComponents); TSet Result; for (const TWeakObjectPtr& Component : FoundComponents) @@ -236,7 +308,7 @@ TSet UFlowSubsystem::GetFlowActorsByTags(const FGameplayTagContainer Ta TMap UFlowSubsystem::GetFlowActorsAndComponentsByTag(const FGameplayTag Tag) const { TArray> FoundComponents; - FlowComponents.MultiFind(Tag, FoundComponents); + FlowComponentRegistry.MultiFind(Tag, FoundComponents); TMap Result; for (const TWeakObjectPtr& Component : FoundComponents) @@ -274,7 +346,7 @@ void UFlowSubsystem::FindComponents(const FGameplayTagContainer& Tags, TSet> ComponentsPerTag; - FlowComponents.MultiFind(Tag, ComponentsPerTag); + FlowComponentRegistry.MultiFind(Tag, ComponentsPerTag); OutComponents.Append(ComponentsPerTag); } } @@ -284,7 +356,7 @@ void UFlowSubsystem::FindComponents(const FGameplayTagContainer& Tags, TSet> ComponentsPerTag; - FlowComponents.MultiFind(Tag, ComponentsPerTag); + FlowComponentRegistry.MultiFind(Tag, ComponentsPerTag); ComponentsWithAnyTag.Append(ComponentsPerTag); } diff --git a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp index e970b90e8..1b902fa82 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp @@ -40,7 +40,10 @@ 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()->OnComponentTagRemoved.AddDynamic(this, &UFlowNode_ComponentObserver::OnComponentTagRemoved); } void UFlowNode_ComponentObserver::StopObserving() @@ -51,7 +54,15 @@ void UFlowNode_ComponentObserver::StopObserving() void UFlowNode_ComponentObserver::OnComponentRegistered(UFlowComponent* Component) { - if (Component->IdentityTags.HasTagExact(IdentityTag)) + if (!RegisteredActors.Contains(Component->GetOwner()) && Component->IdentityTags.HasTagExact(IdentityTag)) + { + ObserveActor(Component->GetOwner(), Component); + } +} + +void UFlowNode_ComponentObserver::OnComponentTagAdded(UFlowComponent* Component, const FGameplayTagContainer& AddedTags) +{ + if (!RegisteredActors.Contains(Component->GetOwner()) && AddedTags.HasTagExact(IdentityTag)) { ObserveActor(Component->GetOwner(), Component); } @@ -66,6 +77,15 @@ void UFlowNode_ComponentObserver::OnComponentUnregistered(UFlowComponent* Compon } } +void UFlowNode_ComponentObserver::OnComponentTagRemoved(UFlowComponent* Component, const FGameplayTagContainer& RemovedTags) +{ + if (RegisteredActors.Contains(Component->GetOwner()) && RemovedTags.HasTagExact(IdentityTag)) + { + RegisteredActors.Remove(Component->GetOwner()); + ForgetActor(Component->GetOwner(), Component); + } +} + void UFlowNode_ComponentObserver::Cleanup() { StopObserving(); diff --git a/Source/Flow/Public/FlowComponent.h b/Source/Flow/Public/FlowComponent.h index 8f1f61915..a349052ff 100644 --- a/Source/Flow/Public/FlowComponent.h +++ b/Source/Flow/Public/FlowComponent.h @@ -4,6 +4,8 @@ #include "GameplayTagContainer.h" #include "FlowComponent.generated.h" +class UFlowSubsystem; + DECLARE_MULTICAST_DELEGATE_TwoParams(FFlowComponentNotify, class UFlowComponent*, const FGameplayTag&); DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FFlowComponentDynamicNotify, class UFlowComponent*, FlowComponent, const FGameplayTag&, NotifyTag); @@ -15,25 +17,47 @@ class FLOW_API UFlowComponent : public UActorComponent { GENERATED_UCLASS_BODY() +////////////////////////////////////////////////////////////////////////// +// Identity Tags + friend class UFlowSubsystem; + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Flow") FGameplayTagContainer IdentityTags; - FFlowComponentNotify OnNotifyFromComponent; - virtual void BeginPlay() override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; + UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category = "Flow") + void AddIdentityTag(const FGameplayTag Tag); + + UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category = "Flow") + void AddIdentityTags(FGameplayTagContainer Tags); + + UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category = "Flow") + void RemoveIdentityTag(const FGameplayTag Tag); + + UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category = "Flow") + void RemoveIdentityTags(FGameplayTagContainer Tags); + +////////////////////////////////////////////////////////////////////////// +// Notify Tags: set only in runtime + + // Send notification from the actor to Flow graphs + UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category = "Flow") + void NotifyGraph(const FGameplayTag NotifyTag); + + FFlowComponentNotify OnNotifyFromComponent; + // Receive notification from Flow graph or another Flow Component UPROPERTY(BlueprintAssignable, Category = "Flow") FFlowComponentDynamicNotify ReceiveNotify; - // Send notification from the actor to Flow graphs - UFUNCTION(BlueprintCallable, Category = "Flow") - void NotifyGraph(const FGameplayTag NotifyTag); - virtual void NotifyFromGraph(const FGameplayTag NotifyTag); // Send notification to another actor containing Flow Component UFUNCTION(BlueprintCallable, Category = "Flow") virtual void NotifyActor(const FGameplayTag ActorTag, const FGameplayTag NotifyTag); + +protected: + UFlowSubsystem* GetFlowSubsystem() const; }; diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index 11a5c9afa..bc25d5354 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -12,6 +12,7 @@ class UFlowAsset; class UFlowNode_SubGraph; DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FSimpleFlowComponentEvent, UFlowComponent*, Component); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FTaggedFlowComponentEvent, UFlowComponent*, Component, const FGameplayTagContainer&, Tags); /** * Flow Subsystem @@ -27,6 +28,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem UFlowSubsystem(); friend class UFlowAsset; + friend class UFlowComponent; friend class UFlowNode_SubGraph; // All asset templates with active instances @@ -84,20 +86,36 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem private: // All the Flow Components currently existing in the world - TMultiMap> FlowComponents; + TMultiMap> FlowComponentRegistry; -public: +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 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 + UPROPERTY(BlueprintAssignable, Category = "FlowSubsystem") + FTaggedFlowComponentEvent OnComponentTagAdded; + // 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 + UPROPERTY(BlueprintAssignable, Category = "FlowSubsystem") + FTaggedFlowComponentEvent OnComponentTagRemoved; + // Returns all registered Flow Components identified by given tag UFUNCTION(BlueprintPure, Category = "FlowSubsystem") TSet GetFlowComponentsByTag(const FGameplayTag Tag) const; @@ -129,7 +147,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem static_assert(TPointerIsConvertibleFromTo::Value, "'T' template parameter to GetComponents must be derived from UActorComponent"); TArray> FoundComponents; - FlowComponents.MultiFind(Tag, FoundComponents); + FlowComponentRegistry.MultiFind(Tag, FoundComponents); TSet> Result; for (const TWeakObjectPtr& Component : FoundComponents) @@ -171,7 +189,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem static_assert(TPointerIsConvertibleFromTo::Value, "'T' template parameter to GetComponents must be derived from AActor"); TArray> FoundComponents; - FlowComponents.MultiFind(Tag, FoundComponents); + FlowComponentRegistry.MultiFind(Tag, FoundComponents); TMap, TWeakObjectPtr> Result; for (const TWeakObjectPtr& Component : FoundComponents) diff --git a/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h b/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h index 0a5250d97..daa1e45f8 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h @@ -33,9 +33,15 @@ class FLOW_API UFlowNode_ComponentObserver : public UFlowNode UFUNCTION() virtual void OnComponentRegistered(UFlowComponent* Component); + UFUNCTION() + virtual void OnComponentTagAdded(UFlowComponent* Component, const FGameplayTagContainer& AddedTags); + UFUNCTION() virtual void OnComponentUnregistered(UFlowComponent* Component); + UFUNCTION() + virtual void OnComponentTagRemoved(UFlowComponent* Component, const FGameplayTagContainer& RemovedTags); + virtual void ObserveActor(TWeakObjectPtr Actor, TWeakObjectPtr Component) {} virtual void ForgetActor(TWeakObjectPtr Actor, TWeakObjectPtr Component) {} From 9663873af30d8d9fa1aa4af68d9536df2e09940b Mon Sep 17 00:00:00 2001 From: Marat Yakupov Date: Wed, 31 Mar 2021 12:50:51 +0400 Subject: [PATCH 047/265] P4 #26: Fix header include in FlowEditorModule.cpp Filenames in linux case sensitive --- 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 4d36d355a..5864ae443 100644 --- a/Source/FlowEditor/Private/FlowEditorModule.cpp +++ b/Source/FlowEditor/Private/FlowEditorModule.cpp @@ -22,7 +22,7 @@ #include "AssetToolsModule.h" #include "EdGraphUtilities.h" -#include "Framework/Multibox/MultiBoxBuilder.h" +#include "Framework/MultiBox/MultiBoxBuilder.h" #include "ISequencerChannelInterface.h" #include "ISequencerModule.h" #include "LevelEditor.h" From 693bf1b651ead5c02816c36afae803fffb9938e7 Mon Sep 17 00:00:00 2001 From: Marat Yakupov Date: Thu, 1 Apr 2021 18:15:35 +0400 Subject: [PATCH 048/265] PR #28: Allow to specify multiple tags in FlowNode_OnNotifyFromActor --- .../Nodes/World/FlowNode_OnNotifyFromActor .cpp | 15 +++++++++++++-- .../Nodes/World/FlowNode_OnNotifyFromActor.h | 7 ++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor .cpp b/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor .cpp index a4c70fc56..248fb1311 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor .cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor .cpp @@ -10,6 +10,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); @@ -25,7 +35,7 @@ void UFlowNode_OnNotifyFromActor::ObserveActor(TWeakObjectPtr Actor, TWe Component->OnNotifyFromComponent.AddWeakLambda(this, [SelfWeakPtr](UFlowComponent* FlowComponent, const FGameplayTag& Tag) { if (SelfWeakPtr.IsValid() && FlowComponent->IdentityTags.HasTagExact(SelfWeakPtr.Get()->IdentityTag) - && (!SelfWeakPtr.Get()->NotifyTag.IsValid() || SelfWeakPtr.Get()->NotifyTag == Tag)) + && (!SelfWeakPtr.Get()->NotifyTags.IsValid() || SelfWeakPtr.Get()->NotifyTags.HasTagExact(Tag))) { SelfWeakPtr->TriggerFirstOutput(true); } @@ -42,7 +52,8 @@ void UFlowNode_OnNotifyFromActor::ForgetActor(TWeakObjectPtr Actor, TWea FString UFlowNode_OnNotifyFromActor::GetNodeDescription() const { const FString IdentityString = IdentityTag.IsValid() ? IdentityTag.ToString() : MissingIdentityTag; - const FString NotifyString = NotifyTag.IsValid() ? NotifyTag.ToString() : TEXT("---"); + const FString NotifyString = !NotifyTags.IsValid() ? TEXT("---") : + FString::JoinBy(NotifyTags, LINE_TERMINATOR, [](const FGameplayTag& Tag) { return Tag.ToString(); }); return IdentityString + LINE_TERMINATOR + NotifyString; } diff --git a/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h b/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h index a337b931a..7b395e9ae 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h @@ -13,7 +13,9 @@ class FLOW_API UFlowNode_OnNotifyFromActor : public UFlowNode_ComponentObserver protected: UPROPERTY(EditDefaultsOnly, Category = "ObservedComponent") - FGameplayTag NotifyTag; + FGameplayTagContainer NotifyTags; + + void PostLoad() override; virtual void ExecuteInput(const FName& PinName) override; @@ -24,4 +26,7 @@ class FLOW_API UFlowNode_OnNotifyFromActor : public UFlowNode_ComponentObserver public: virtual FString GetNodeDescription() const override; #endif +private: + UPROPERTY() + FGameplayTag NotifyTag_DEPRECATED; }; From 20c932411ec85b06f42dfe9b44763687087ab5d0 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Thu, 1 Apr 2021 22:14:14 +0200 Subject: [PATCH 049/265] replacing single Gameplay Tag properties with Gameplay Tag Container - in a few Flow Nodes --- Source/Flow/Private/FlowComponent.cpp | 7 +++-- Source/Flow/Private/Nodes/FlowNode.cpp | 11 ++++++++ .../World/FlowNode_ComponentObserver.cpp | 25 +++++++++++++----- .../Nodes/World/FlowNode_NotifyActor.cpp | 26 ++++++++++++++----- .../World/FlowNode_OnNotifyFromActor .cpp | 9 +++---- Source/Flow/Public/FlowComponent.h | 4 +-- Source/Flow/Public/FlowSubsystem.h | 6 ++--- Source/Flow/Public/Nodes/FlowNode.h | 8 ++++++ .../Nodes/World/FlowNode_ComponentObserver.h | 10 +++++-- .../Public/Nodes/World/FlowNode_NotifyActor.h | 18 ++++++++++--- .../Nodes/World/FlowNode_OnNotifyFromActor.h | 3 ++- .../FlowNode_ComponentObserverDetails.cpp | 2 +- 12 files changed, 95 insertions(+), 34 deletions(-) diff --git a/Source/Flow/Private/FlowComponent.cpp b/Source/Flow/Private/FlowComponent.cpp index 8c24e179c..4c53134a7 100644 --- a/Source/Flow/Private/FlowComponent.cpp +++ b/Source/Flow/Private/FlowComponent.cpp @@ -116,9 +116,12 @@ void UFlowComponent::NotifyGraph(const FGameplayTag NotifyTag) OnNotifyFromComponent.Broadcast(this, NotifyTag); } -void UFlowComponent::NotifyFromGraph(const FGameplayTag NotifyTag) +void UFlowComponent::NotifyFromGraph(const FGameplayTagContainer& NotifyTags) { - ReceiveNotify.Broadcast(nullptr, NotifyTag); + for (const FGameplayTag& NotifyTag : NotifyTags) + { + ReceiveNotify.Broadcast(nullptr, NotifyTag); + } } void UFlowComponent::NotifyActor(const FGameplayTag ActorTag, const FGameplayTag NotifyTag) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 4e64792f1..f734ac40a 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -14,6 +14,7 @@ FName UFlowNode::DefaultInputName(TEXT("In")); FName UFlowNode::DefaultOutputName(TEXT("Out")); FString UFlowNode::MissingIdentityTag = TEXT("Missing Identity Tag!"); +FString UFlowNode::MissingNotifyTag = TEXT("Missing Notify Tag!"); FString UFlowNode::NoActorsFound = TEXT("No actors found!"); #if !UE_BUILD_SHIPPING @@ -362,6 +363,16 @@ AActor* UFlowNode::GetActorToFocus() } #endif +FString UFlowNode::GetIdentityDescription(const FGameplayTagContainer& Tags) +{ + return Tags.IsEmpty() ? MissingIdentityTag : FString::JoinBy(Tags, LINE_TERMINATOR, [](const FGameplayTag& Tag) { return Tag.ToString(); }); +} + +FString UFlowNode::GetNotifyDescription(const FGameplayTagContainer& Tags) +{ + return Tags.IsEmpty() ? MissingNotifyTag : FString::JoinBy(Tags, LINE_TERMINATOR, [](const FGameplayTag& Tag) { return Tag.ToString(); }); +} + FString UFlowNode::GetProgressAsString(float Value) { // Avoids negative zero diff --git a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp index 1b902fa82..de398db30 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp @@ -13,9 +13,20 @@ UFlowNode_ComponentObserver::UFlowNode_ComponentObserver(const FObjectInitialize OutputNames = {TEXT("Success"), TEXT("Stopped")}; } +void UFlowNode_ComponentObserver::PostLoad() +{ + Super::PostLoad(); + + if (IdentityTag_DEPRECATED.IsValid()) + { + IdentityTags = FGameplayTagContainer(IdentityTag_DEPRECATED); + IdentityTag_DEPRECATED = FGameplayTag(); + } +} + void UFlowNode_ComponentObserver::ExecuteInput(const FName& PinName) { - if (IdentityTag.IsValid()) + if (IdentityTags.IsValid()) { if (PinName == TEXT("Start")) { @@ -34,7 +45,7 @@ void UFlowNode_ComponentObserver::ExecuteInput(const FName& PinName) void UFlowNode_ComponentObserver::StartObserving() { - for (const TWeakObjectPtr& FoundComponent : GetFlowSubsystem()->GetComponents(IdentityTag)) + for (const TWeakObjectPtr& FoundComponent : GetFlowSubsystem()->GetComponents(IdentityTags, EGameplayContainerMatchType::Any)) { ObserveActor(FoundComponent->GetOwner(), FoundComponent); } @@ -54,7 +65,7 @@ void UFlowNode_ComponentObserver::StopObserving() void UFlowNode_ComponentObserver::OnComponentRegistered(UFlowComponent* Component) { - if (!RegisteredActors.Contains(Component->GetOwner()) && Component->IdentityTags.HasTagExact(IdentityTag)) + if (!RegisteredActors.Contains(Component->GetOwner()) && Component->IdentityTags.HasAnyExact(IdentityTags)) { ObserveActor(Component->GetOwner(), Component); } @@ -62,7 +73,7 @@ void UFlowNode_ComponentObserver::OnComponentRegistered(UFlowComponent* Componen void UFlowNode_ComponentObserver::OnComponentTagAdded(UFlowComponent* Component, const FGameplayTagContainer& AddedTags) { - if (!RegisteredActors.Contains(Component->GetOwner()) && AddedTags.HasTagExact(IdentityTag)) + if (!RegisteredActors.Contains(Component->GetOwner()) && AddedTags.HasAnyExact(IdentityTags)) { ObserveActor(Component->GetOwner(), Component); } @@ -70,7 +81,7 @@ void UFlowNode_ComponentObserver::OnComponentTagAdded(UFlowComponent* Component, void UFlowNode_ComponentObserver::OnComponentUnregistered(UFlowComponent* Component) { - if (RegisteredActors.Contains(Component->GetOwner()) && Component->IdentityTags.HasTagExact(IdentityTag)) + if (RegisteredActors.Contains(Component->GetOwner()) && Component->IdentityTags.HasAnyExact(IdentityTags)) { RegisteredActors.Remove(Component->GetOwner()); ForgetActor(Component->GetOwner(), Component); @@ -79,7 +90,7 @@ void UFlowNode_ComponentObserver::OnComponentUnregistered(UFlowComponent* Compon void UFlowNode_ComponentObserver::OnComponentTagRemoved(UFlowComponent* Component, const FGameplayTagContainer& RemovedTags) { - if (RegisteredActors.Contains(Component->GetOwner()) && RemovedTags.HasTagExact(IdentityTag)) + if (RegisteredActors.Contains(Component->GetOwner()) && RemovedTags.HasAnyExact(IdentityTags)) { RegisteredActors.Remove(Component->GetOwner()); ForgetActor(Component->GetOwner(), Component); @@ -100,7 +111,7 @@ void UFlowNode_ComponentObserver::Cleanup() #if WITH_EDITOR FString UFlowNode_ComponentObserver::GetNodeDescription() const { - return IdentityTag.IsValid() ? IdentityTag.ToString() : TEXT("Missing Identity Tag!"); + return GetIdentityDescription(IdentityTags); } FString UFlowNode_ComponentObserver::GetStatusString() const diff --git a/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp b/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp index b6f8fdd12..343203d0b 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp @@ -12,13 +12,30 @@ UFlowNode_NotifyActor::UFlowNode_NotifyActor(const FObjectInitializer& ObjectIni #endif } +void UFlowNode_NotifyActor::PostLoad() +{ + Super::PostLoad(); + + if (IdentityTag_DEPRECATED.IsValid()) + { + IdentityTags = FGameplayTagContainer(IdentityTag_DEPRECATED); + IdentityTag_DEPRECATED = FGameplayTag(); + } + + if (NotifyTag_DEPRECATED.IsValid()) + { + NotifyTags = FGameplayTagContainer(NotifyTag_DEPRECATED); + NotifyTag_DEPRECATED = FGameplayTag(); + } +} + void UFlowNode_NotifyActor::ExecuteInput(const FName& PinName) { if (UFlowSubsystem* FlowSubsystem = GetWorld()->GetGameInstance()->GetSubsystem()) { - for (TWeakObjectPtr& Component : FlowSubsystem->GetComponents(IdentityTag)) + for (TWeakObjectPtr& Component : FlowSubsystem->GetComponents(IdentityTags, EGameplayContainerMatchType::Any)) { - Component->NotifyFromGraph(NotifyTag); + Component->NotifyFromGraph(NotifyTags); } } @@ -28,9 +45,6 @@ void UFlowNode_NotifyActor::ExecuteInput(const FName& PinName) #if WITH_EDITOR FString UFlowNode_NotifyActor::GetNodeDescription() const { - const FString IdentityString = IdentityTag.IsValid() ? IdentityTag.ToString() : MissingIdentityTag; - const FString NotifyString = NotifyTag.IsValid() ? NotifyTag.ToString() : TEXT("---"); - - return IdentityString + LINE_TERMINATOR + NotifyString; + return GetIdentityDescription(IdentityTags) + LINE_TERMINATOR + GetNotifyDescription(NotifyTags); } #endif diff --git a/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor .cpp b/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor .cpp index 248fb1311..b8b4c8f9d 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor .cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor .cpp @@ -17,6 +17,7 @@ void UFlowNode_OnNotifyFromActor::PostLoad() if (NotifyTag_DEPRECATED.IsValid()) { NotifyTags = FGameplayTagContainer(NotifyTag_DEPRECATED); + NotifyTag_DEPRECATED = FGameplayTag(); } } @@ -34,7 +35,7 @@ void UFlowNode_OnNotifyFromActor::ObserveActor(TWeakObjectPtr Actor, TWe TWeakObjectPtr SelfWeakPtr(this); Component->OnNotifyFromComponent.AddWeakLambda(this, [SelfWeakPtr](UFlowComponent* FlowComponent, const FGameplayTag& Tag) { - if (SelfWeakPtr.IsValid() && FlowComponent->IdentityTags.HasTagExact(SelfWeakPtr.Get()->IdentityTag) + if (SelfWeakPtr.IsValid() && FlowComponent->IdentityTags.HasAnyExact(SelfWeakPtr.Get()->IdentityTags) && (!SelfWeakPtr.Get()->NotifyTags.IsValid() || SelfWeakPtr.Get()->NotifyTags.HasTagExact(Tag))) { SelfWeakPtr->TriggerFirstOutput(true); @@ -51,10 +52,6 @@ void UFlowNode_OnNotifyFromActor::ForgetActor(TWeakObjectPtr Actor, TWea #if WITH_EDITOR FString UFlowNode_OnNotifyFromActor::GetNodeDescription() const { - const FString IdentityString = IdentityTag.IsValid() ? IdentityTag.ToString() : MissingIdentityTag; - const FString NotifyString = !NotifyTags.IsValid() ? TEXT("---") : - FString::JoinBy(NotifyTags, LINE_TERMINATOR, [](const FGameplayTag& Tag) { return Tag.ToString(); }); - - return IdentityString + LINE_TERMINATOR + NotifyString; + return GetIdentityDescription(IdentityTags) + LINE_TERMINATOR + GetNotifyDescription(NotifyTags); } #endif diff --git a/Source/Flow/Public/FlowComponent.h b/Source/Flow/Public/FlowComponent.h index a349052ff..e4afd763a 100644 --- a/Source/Flow/Public/FlowComponent.h +++ b/Source/Flow/Public/FlowComponent.h @@ -45,14 +45,14 @@ class FLOW_API UFlowComponent : public UActorComponent // Send notification from the actor to Flow graphs UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category = "Flow") void NotifyGraph(const FGameplayTag NotifyTag); - + FFlowComponentNotify OnNotifyFromComponent; // Receive notification from Flow graph or another Flow Component UPROPERTY(BlueprintAssignable, Category = "Flow") FFlowComponentDynamicNotify ReceiveNotify; - virtual void NotifyFromGraph(const FGameplayTag NotifyTag); + virtual void NotifyFromGraph(const FGameplayTagContainer& NotifyTags); // Send notification to another actor containing Flow Component UFUNCTION(BlueprintCallable, Category = "Flow") diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index bc25d5354..487750494 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -120,7 +120,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem UFUNCTION(BlueprintPure, Category = "FlowSubsystem") TSet GetFlowComponentsByTag(const FGameplayTag Tag) const; - // Returns all registered Flow Components identified by at least one of given tags + // Returns all registered Flow Components identified by Any or All provided tags UFUNCTION(BlueprintPure, Category = "FlowSubsystem") TSet GetFlowComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType) const; @@ -128,7 +128,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem UFUNCTION(BlueprintPure, Category = "FlowSubsystem") TSet GetFlowActorsByTag(const FGameplayTag Tag) const; - // Returns all registered actors with Flow Component identified by at least one of given tags + // Returns all registered actors with Flow Component identified by Any or All provided tags UFUNCTION(BlueprintPure, Category = "FlowSubsystem") TSet GetFlowActorsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType) const; @@ -161,7 +161,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem return Result; } - // Returns all registered Flow Components identified by at least one of given tags + // Returns all registered Flow Components identified by Any or All provided tags template TSet> GetComponents(const FGameplayTagContainer& Tags, const EGameplayContainerMatchType MatchType) const { diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 96b77905c..558fe7217 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -2,6 +2,7 @@ #include "CoreMinimal.h" #include "Engine/StreamableManager.h" +#include "GameplayTagContainer.h" #include "VisualLogger/VisualLoggerDebugSnapshotInterface.h" #include "FlowTypes.h" @@ -187,6 +188,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte // Debugger protected: static FString MissingIdentityTag; + static FString MissingNotifyTag; static FString NoActorsFound; ////////////////////////////////////////////////////////////////////////// @@ -329,6 +331,12 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte public: UFUNCTION(BlueprintPure, Category = "FlowNode") + static FString GetIdentityDescription(const FGameplayTagContainer& Tags); + + UFUNCTION(BlueprintPure, Category = "FlowNode") + static FString GetNotifyDescription(const FGameplayTagContainer& Tags); + + UFUNCTION(BlueprintPure, Category = "FlowNode") static FString GetProgressAsString(float Value); UFUNCTION(BlueprintCallable, Category = "FlowNode") diff --git a/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h b/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h index daa1e45f8..c301e61fb 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h @@ -20,11 +20,13 @@ class FLOW_API UFlowNode_ComponentObserver : public UFlowNode protected: UPROPERTY(EditDefaultsOnly, Category = "ObservedComponent") - FGameplayTag IdentityTag; - + FGameplayTagContainer IdentityTags; + TMap, TWeakObjectPtr> RegisteredActors; protected: + virtual void PostLoad() override; + virtual void ExecuteInput(const FName& PinName) override; virtual void StartObserving(); @@ -52,4 +54,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 426627d31..4b613febb 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h @@ -14,11 +14,13 @@ class FLOW_API UFlowNode_NotifyActor : public UFlowNode GENERATED_UCLASS_BODY() protected: - UPROPERTY(EditDefaultsOnly, Category = "Notify") - FGameplayTag IdentityTag; + UPROPERTY(EditDefaultsOnly, Category = "ObservedComponent") + FGameplayTagContainer IdentityTags; + + UPROPERTY(EditDefaultsOnly, Category = "ObservedComponent") + FGameplayTagContainer NotifyTags; - UPROPERTY(EditDefaultsOnly, Category = "Notify") - FGameplayTag NotifyTag; + virtual void PostLoad() override; virtual void ExecuteInput(const FName& PinName) override; @@ -26,4 +28,12 @@ class FLOW_API UFlowNode_NotifyActor : public UFlowNode 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 7b395e9ae..9799381d7 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h @@ -15,7 +15,7 @@ class FLOW_API UFlowNode_OnNotifyFromActor : public UFlowNode_ComponentObserver UPROPERTY(EditDefaultsOnly, Category = "ObservedComponent") FGameplayTagContainer NotifyTags; - void PostLoad() override; + virtual void PostLoad() override; virtual void ExecuteInput(const FName& PinName) override; @@ -26,6 +26,7 @@ class FLOW_API UFlowNode_OnNotifyFromActor : public UFlowNode_ComponentObserver public: virtual FString GetNodeDescription() const override; #endif + private: UPROPERTY() FGameplayTag NotifyTag_DEPRECATED; diff --git a/Source/FlowEditor/Private/Graph/Customizations/FlowNode_ComponentObserverDetails.cpp b/Source/FlowEditor/Private/Graph/Customizations/FlowNode_ComponentObserverDetails.cpp index 358dad69a..a20c5e2c7 100644 --- a/Source/FlowEditor/Private/Graph/Customizations/FlowNode_ComponentObserverDetails.cpp +++ b/Source/FlowEditor/Private/Graph/Customizations/FlowNode_ComponentObserverDetails.cpp @@ -7,5 +7,5 @@ void FFlowNode_ComponentObserverDetails::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) { IDetailCategoryBuilder& SequenceCategory = DetailBuilder.EditCategory("ObservedComponent"); - SequenceCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UFlowNode_ComponentObserver, IdentityTag)); + SequenceCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UFlowNode_ComponentObserver, IdentityTags)); } From 55b725910e028c1fa9ff648387b05b09ff551ab8 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 2 Apr 2021 11:02:10 +0200 Subject: [PATCH 050/265] today I learned that clearing value of _DEPREACATED is redundant --- Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp | 1 - Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp | 1 - Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor .cpp | 1 - 3 files changed, 3 deletions(-) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp index de398db30..0997c64fb 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp @@ -20,7 +20,6 @@ void UFlowNode_ComponentObserver::PostLoad() if (IdentityTag_DEPRECATED.IsValid()) { IdentityTags = FGameplayTagContainer(IdentityTag_DEPRECATED); - IdentityTag_DEPRECATED = FGameplayTag(); } } diff --git a/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp b/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp index 343203d0b..1a7be40f5 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp @@ -19,7 +19,6 @@ void UFlowNode_NotifyActor::PostLoad() if (IdentityTag_DEPRECATED.IsValid()) { IdentityTags = FGameplayTagContainer(IdentityTag_DEPRECATED); - IdentityTag_DEPRECATED = FGameplayTag(); } if (NotifyTag_DEPRECATED.IsValid()) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor .cpp b/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor .cpp index b8b4c8f9d..2e424467a 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor .cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor .cpp @@ -17,7 +17,6 @@ void UFlowNode_OnNotifyFromActor::PostLoad() if (NotifyTag_DEPRECATED.IsValid()) { NotifyTags = FGameplayTagContainer(NotifyTag_DEPRECATED); - NotifyTag_DEPRECATED = FGameplayTag(); } } From f6fe9663b58a8e5e5f83b5ea5527a3e77d89139e Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 2 Apr 2021 17:48:49 +0200 Subject: [PATCH 051/265] remove unnecessary call to Asset Registry that broadcast common delegate --- 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 e8d28c317..db8008a4a 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -139,13 +139,13 @@ 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) { - FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(AssetRegistryConstants::ModuleName); - AssetRegistryModule.Get().SearchAllAssets(true); - TArray FlowAssets; + + FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(AssetRegistryConstants::ModuleName); AssetRegistryModule.Get().GetAssetsByClass(UFlowAsset::StaticClass()->GetFName(), FlowAssets, true); for (FAssetData const& Asset : FlowAssets) From 702ce16202c825e3bfc0a8b9c3102b2e9b6029a7 Mon Sep 17 00:00:00 2001 From: Sergey Vikhirev Date: Mon, 5 Apr 2021 02:45:39 +0400 Subject: [PATCH 052/265] Remove unnecessary space from "FlowNode_OnNotifyFromActor .cpp" filename (#30) --- ...Node_OnNotifyFromActor .cpp => FlowNode_OnNotifyFromActor.cpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Source/Flow/Private/Nodes/World/{FlowNode_OnNotifyFromActor .cpp => FlowNode_OnNotifyFromActor.cpp} (100%) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor .cpp b/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp similarity index 100% rename from Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor .cpp rename to Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp From 374f8209d2141bed1cd5d558e7881f54e6b1ef3f Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 5 Apr 2021 12:30:42 +0200 Subject: [PATCH 053/265] refactored starting Root Flow: logic moved from AFlowWorldSettings to Flow Component Inspired by PR #29. * Added generic method to start/finish Root Flow from the Flow Component, so it's possible to reduce boilerplate code in actor classes. * You can now specify on Flow Component, should it start RootFlow on BeginPlay? If not, you can freely script when it would be started. * You can now specify on Flow Component, under which Net Mode would be allowed to start RootFlow? Single-player only (Standalone), Server-only, Authority (both single-player and server), Client-only, Any Mode. * Flow Toolbar (available above the main editor viewport) isn't tied to AFlowWorldSettings class anymore. It assigns Flow Asset to Flow Component added AFlowWorldSettings. So toolbar will now work with any World Settings class, as long as it contains Flow Component. --- Source/Flow/Private/FlowComponent.cpp | 75 ++++++++++++++++--- Source/Flow/Private/FlowSubsystem.cpp | 7 +- Source/Flow/Private/FlowWorldSettings.cpp | 28 ++----- Source/Flow/Public/FlowComponent.h | 37 ++++++++- Source/Flow/Public/FlowSubsystem.h | 2 +- Source/Flow/Public/FlowTypes.h | 10 +++ Source/Flow/Public/FlowWorldSettings.h | 17 ++++- .../Private/LevelEditor/SLevelEditorFlow.cpp | 53 ++++++++----- .../Public/LevelEditor/SLevelEditorFlow.h | 2 + 9 files changed, 174 insertions(+), 57 deletions(-) diff --git a/Source/Flow/Private/FlowComponent.cpp b/Source/Flow/Private/FlowComponent.cpp index 4c53134a7..0de60db23 100644 --- a/Source/Flow/Private/FlowComponent.cpp +++ b/Source/Flow/Private/FlowComponent.cpp @@ -1,4 +1,5 @@ #include "FlowComponent.h" +#include "FlowSettings.h" #include "FlowSubsystem.h" #include "Engine/GameInstance.h" @@ -6,6 +7,9 @@ UFlowComponent::UFlowComponent(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) + , RootFlow(nullptr) + , bAutoStartRootFlow(true) + , RootFlowMode(EFlowNetMode::Authority) { PrimaryComponentTick.bCanEverTick = false; PrimaryComponentTick.bStartWithTickEnabled = false; @@ -15,15 +19,20 @@ void UFlowComponent::BeginPlay() { Super::BeginPlay(); - if (UFlowSubsystem* FlowSubsystem = GetWorld()->GetGameInstance()->GetSubsystem()) + if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) { FlowSubsystem->RegisterComponent(this); } + + if (RootFlow && bAutoStartRootFlow) + { + StartRootFlow(); + } } void UFlowComponent::EndPlay(const EEndPlayReason::Type EndPlayReason) { - if (UFlowSubsystem* FlowSubsystem = GetWorld()->GetGameInstance()->GetSubsystem()) + if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) { FlowSubsystem->UnregisterComponent(this); } @@ -41,7 +50,7 @@ void UFlowComponent::AddIdentityTag(const FGameplayTag Tag) if (HasBegunPlay()) { - if (UFlowSubsystem* FlowSubsystem = GetWorld()->GetGameInstance()->GetSubsystem()) + if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) { FlowSubsystem->OnIdentityTagAdded(this, Tag); } @@ -64,7 +73,7 @@ void UFlowComponent::AddIdentityTags(FGameplayTagContainer Tags) if (Tags.Num() > 0 && HasBegunPlay()) { - if (UFlowSubsystem* FlowSubsystem = GetWorld()->GetGameInstance()->GetSubsystem()) + if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) { FlowSubsystem->OnIdentityTagsAdded(this, Tags); } @@ -81,7 +90,7 @@ void UFlowComponent::RemoveIdentityTag(const FGameplayTag Tag) if (HasBegunPlay()) { - if (UFlowSubsystem* FlowSubsystem = GetWorld()->GetGameInstance()->GetSubsystem()) + if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) { FlowSubsystem->OnIdentityTagRemoved(this, Tag); } @@ -104,7 +113,7 @@ void UFlowComponent::RemoveIdentityTags(FGameplayTagContainer Tags) if (Tags.Num() > 0 && HasBegunPlay()) { - if (UFlowSubsystem* FlowSubsystem = GetWorld()->GetGameInstance()->GetSubsystem()) + if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) { FlowSubsystem->OnIdentityTagsRemoved(this, Tags); } @@ -126,7 +135,7 @@ void UFlowComponent::NotifyFromGraph(const FGameplayTagContainer& NotifyTags) void UFlowComponent::NotifyActor(const FGameplayTag ActorTag, const FGameplayTag NotifyTag) { - if (UFlowSubsystem* FlowSubsystem = GetWorld()->GetGameInstance()->GetSubsystem()) + if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) { for (TWeakObjectPtr& Component : FlowSubsystem->GetComponents(ActorTag)) { @@ -135,12 +144,60 @@ void UFlowComponent::NotifyActor(const FGameplayTag ActorTag, const FGameplayTag } } +void UFlowComponent::StartRootFlow() const +{ + if (RootFlow && IsFlowNetMode(RootFlowMode)) + { + if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) + { + FlowSubsystem->StartRootFlow(GetOwner(), RootFlow); + } + } +} + +void UFlowComponent::FinishRootFlow() const +{ + if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) + { + FlowSubsystem->FinishRootFlow(GetOwner()); + } +} + +UFlowAsset* UFlowComponent::GetRootFlowInstance() +{ + if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) + { + return FlowSubsystem->GetRootFlow(this); + } + + return nullptr; +} + UFlowSubsystem* UFlowComponent::GetFlowSubsystem() const { - if (GetOwner()->GetGameInstance()) + if (GetWorld() && GetWorld()->GetGameInstance()) { - return GetOwner()->GetGameInstance()->GetSubsystem(); + return GetWorld()->GetGameInstance()->GetSubsystem(); } return nullptr; } + +bool UFlowComponent::IsFlowNetMode(const EFlowNetMode NetMode) const +{ + switch (NetMode) + { + case EFlowNetMode::Any: + return true; + case EFlowNetMode::Authority: + return GetOwner()->HasAuthority(); + case EFlowNetMode::ClientOnly: + return IsNetMode(NM_Client) && UFlowSettings::Get()->bCreateFlowSubsystemOnClients; + case EFlowNetMode::ServerOnly: + return IsNetMode(NM_DedicatedServer) || IsNetMode(NM_ListenServer); + case EFlowNetMode::SinglePlayerOnly: + return IsNetMode(NM_Standalone); + default: + return false; + } +} diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index c64b9c639..1f79c4237 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -57,11 +57,11 @@ void UFlowSubsystem::StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset) NewFlow->StartFlow(); } -void UFlowSubsystem::FinishRootFlow(UObject* Owner, UFlowAsset* FlowAsset) +void UFlowSubsystem::FinishRootFlow(UObject* Owner) { if (UFlowAsset* Instance = RootInstances.FindRef(Owner)) { - RootInstances.Remove(FlowAsset); + RootInstances.Remove(Owner); Instance->FinishFlow(false); } } @@ -193,6 +193,9 @@ void UFlowSubsystem::OnIdentityTagsAdded(UFlowComponent* Component, const FGamep void UFlowSubsystem::UnregisterComponent(UFlowComponent* Component) { + // first, remove Flow Assets instantiated by this component + FinishRootFlow(Component); + for (const FGameplayTag& Tag : Component->IdentityTags) { if (Tag.IsValid()) diff --git a/Source/Flow/Private/FlowWorldSettings.cpp b/Source/Flow/Private/FlowWorldSettings.cpp index d5239f877..f3941fa5f 100644 --- a/Source/Flow/Private/FlowWorldSettings.cpp +++ b/Source/Flow/Private/FlowWorldSettings.cpp @@ -1,34 +1,18 @@ #include "FlowWorldSettings.h" -#include "FlowSubsystem.h" +#include "FlowComponent.h" AFlowWorldSettings::AFlowWorldSettings(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) - , FlowAsset(nullptr) { + FlowComponent = CreateDefaultSubobject(TEXT("FlowComponent")); } -void AFlowWorldSettings::BeginPlay() +void AFlowWorldSettings::PostLoad() { - Super::BeginPlay(); + Super::PostLoad(); - if (FlowAsset && HasAuthority()) + if (FlowAsset_DEPRECATED) { - if (UFlowSubsystem* FlowSubsystem = GetWorld()->GetGameInstance()->GetSubsystem()) - { - FlowSubsystem->StartRootFlow(GetWorld(), FlowAsset); - } + FlowComponent->RootFlow = FlowAsset_DEPRECATED; } } - -void AFlowWorldSettings::EndPlay(const EEndPlayReason::Type EndPlayReason) -{ - if (FlowAsset && HasAuthority()) - { - if (UFlowSubsystem* FlowSubsystem = GetWorld()->GetGameInstance()->GetSubsystem()) - { - FlowSubsystem->FinishRootFlow(GetWorld(), FlowAsset); - } - } - - Super::EndPlay(EndPlayReason); -} diff --git a/Source/Flow/Public/FlowComponent.h b/Source/Flow/Public/FlowComponent.h index e4afd763a..d27049b01 100644 --- a/Source/Flow/Public/FlowComponent.h +++ b/Source/Flow/Public/FlowComponent.h @@ -2,15 +2,18 @@ #include "Components/ActorComponent.h" #include "GameplayTagContainer.h" + +#include "FlowTypes.h" #include "FlowComponent.generated.h" +class UFlowAsset; class UFlowSubsystem; DECLARE_MULTICAST_DELEGATE_TwoParams(FFlowComponentNotify, class UFlowComponent*, const FGameplayTag&); DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FFlowComponentDynamicNotify, class UFlowComponent*, FlowComponent, const FGameplayTag&, NotifyTag); /** -* Base component of Flow System - makes possible to communicate between Flow graph and actors +* 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 @@ -58,6 +61,36 @@ class FLOW_API UFlowComponent : public UActorComponent UFUNCTION(BlueprintCallable, Category = "Flow") virtual void NotifyActor(const FGameplayTag ActorTag, const FGameplayTag NotifyTag); -protected: +////////////////////////////////////////////////////////////////////////// +// Root Flow + +public: + // Asset that might instantiated as "Root Flow" + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "RootFlow") + UFlowAsset* RootFlow; + + // If true, component will start Root Flow on Begin Play + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "RootFlow") + bool bAutoStartRootFlow; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "RootFlow") + EFlowNetMode RootFlowMode; + + // This will instantiate Flow Asset assigned on this component. + // Created Flow Asset instance will be a "root flow", as additional Flow Assets can be instantiated via Sub Graph node + UFUNCTION(BlueprintCallable, Category = "RootFlow") + void StartRootFlow() const; + + // This will destroy instantiated Flow Asset - created from asset assigned on this component. + UFUNCTION(BlueprintCallable, Category = "RootFlow") + void FinishRootFlow() const; + + UFUNCTION(BlueprintPure, Category = "RootFlow") + UFlowAsset* GetRootFlowInstance(); + +////////////////////////////////////////////////////////////////////////// +// Helpers + UFlowSubsystem* GetFlowSubsystem() const; + bool IsFlowNetMode(const EFlowNetMode NetMode) const; }; diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index 487750494..7f4ad5917 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -57,7 +57,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem // Finish the root Flow, typically when closing world that created this flow UFUNCTION(BlueprintCallable, Category = "FlowSubsystem") - void FinishRootFlow(UObject* Owner, UFlowAsset* FlowAsset); + void FinishRootFlow(UObject* Owner); private: void StartSubFlow(UFlowNode_SubGraph* SubGraphNode, const bool bPreloading = false); diff --git a/Source/Flow/Public/FlowTypes.h b/Source/Flow/Public/FlowTypes.h index 25102e31e..738732183 100644 --- a/Source/Flow/Public/FlowTypes.h +++ b/Source/Flow/Public/FlowTypes.h @@ -23,3 +23,13 @@ enum class EFlowActivationState : uint8 WasActive }; #endif + +UENUM(BlueprintType) +enum class EFlowNetMode : uint8 +{ + 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"), + SinglePlayerOnly UMETA(ToolTip = "Executed only in the single player, not available in multiplayer.") +}; diff --git a/Source/Flow/Public/FlowWorldSettings.h b/Source/Flow/Public/FlowWorldSettings.h index a7d825dfe..97402469f 100644 --- a/Source/Flow/Public/FlowWorldSettings.h +++ b/Source/Flow/Public/FlowWorldSettings.h @@ -3,6 +3,8 @@ #include "GameFramework/WorldSettings.h" #include "FlowWorldSettings.generated.h" +class UFlowComponent; + /** * World Settings used to start a Flow for this world */ @@ -11,9 +13,16 @@ class FLOW_API AFlowWorldSettings : public AWorldSettings { GENERATED_UCLASS_BODY() - UPROPERTY(EditAnywhere, Category = "Flow") - class UFlowAsset* FlowAsset; +private: + UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Flow", meta = (AllowPrivateAccess = "true")) + UFlowComponent* FlowComponent; + +public: + UFlowComponent* GetFlowComponent() const { return FlowComponent; } + + virtual void PostLoad() override; - virtual void BeginPlay() override; - virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; +private: + UPROPERTY() + class UFlowAsset* FlowAsset_DEPRECATED; }; diff --git a/Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp b/Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp index 3704fa605..0a7a03d3d 100644 --- a/Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp +++ b/Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp @@ -1,5 +1,6 @@ #include "LevelEditor/SLevelEditorFlow.h" #include "FlowAsset.h" +#include "FlowComponent.h" #include "FlowWorldSettings.h" #include "Editor.h" @@ -22,12 +23,14 @@ void SLevelEditorFlow::OnMapOpened(const FString& Filename, bool bAsTemplate) void SLevelEditorFlow::CreateFlowWidget() { - if (UWorld* World = GEditor->GetEditorWorldContext().World()) + UFlowComponent* FlowComponent = FindFlowComponent(); + if (FlowComponent && FlowComponent->RootFlow) { - if (const AFlowWorldSettings* WorldSettings = Cast(World->GetWorldSettings())) - { - FlowPath = WorldSettings->FlowAsset ? FName(*WorldSettings->FlowAsset->GetPathName()) : FName(); - } + FlowPath = FName(*FlowComponent->RootFlow->GetPathName()); + } + else + { + FlowPath = FName(); } const TSharedRef FlowWidget = SNew(SHorizontalBox) @@ -72,21 +75,20 @@ void SLevelEditorFlow::OnFlowChanged(const FAssetData& NewAsset) { FlowPath = NewAsset.ObjectPath; - if (UWorld* World = GEditor->GetEditorWorldContext().World()) + UFlowComponent* FlowComponent = FindFlowComponent(); + if (FlowComponent && FlowComponent->RootFlow) { - if (AFlowWorldSettings* WorldSettings = Cast(World->GetWorldSettings())) + if (UObject* NewObject = NewAsset.GetAsset()) { - if (UObject* NewObject = NewAsset.GetAsset()) - { - WorldSettings->FlowAsset = Cast(NewObject); - } - else - { - WorldSettings->FlowAsset = nullptr; - } - - WorldSettings->MarkPackageDirty(); + FlowComponent->RootFlow = Cast(NewObject); + } + else + { + FlowComponent->RootFlow = nullptr; } + + const bool bSuccess = FlowComponent->MarkPackageDirty(); + ensureMsgf(bSuccess, TEXT("World Settings couldn't be marked dirty while changing the assigned Flow Asset.")); } } @@ -95,4 +97,21 @@ FString SLevelEditorFlow::GetFlowPath() const return FlowPath.IsValid() ? FlowPath.ToString() : FString(); } +UFlowComponent* SLevelEditorFlow::FindFlowComponent() const +{ + if (UWorld* World = GEditor->GetEditorWorldContext().World()) + { + if (const AWorldSettings* WorldSettings = World->GetWorldSettings()) + { + UActorComponent* FoundComponent = WorldSettings->GetComponentByClass(UFlowComponent::StaticClass()); + if (FoundComponent) + { + return Cast(FoundComponent); + } + } + } + + return nullptr; +} + #undef LOCTEXT_NAMESPACE diff --git a/Source/FlowEditor/Public/LevelEditor/SLevelEditorFlow.h b/Source/FlowEditor/Public/LevelEditor/SLevelEditorFlow.h index 3dbbd26f0..f9dd30881 100644 --- a/Source/FlowEditor/Public/LevelEditor/SLevelEditorFlow.h +++ b/Source/FlowEditor/Public/LevelEditor/SLevelEditorFlow.h @@ -21,5 +21,7 @@ class SLevelEditorFlow : public SCompoundWidget void OnFlowChanged(const FAssetData& NewAsset); FString GetFlowPath() const; + class UFlowComponent* FindFlowComponent() const; + FName FlowPath; }; From b3f57babb317562872b7ca4262d09490714bec65 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 5 Apr 2021 14:28:51 +0200 Subject: [PATCH 054/265] Component Observer nodes now can work indefinitely --- .../World/FlowNode_ComponentObserver.cpp | 19 +++++++++++++++++-- .../World/FlowNode_OnNotifyFromActor.cpp | 2 +- .../Nodes/World/FlowNode_ComponentObserver.h | 12 ++++++++++++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp index 0997c64fb..005e260dd 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp @@ -3,6 +3,8 @@ UFlowNode_ComponentObserver::UFlowNode_ComponentObserver(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) + , SuccessLimit(1) + , SuccessCount(0) { #if WITH_EDITOR NodeStyle = EFlowNodeStyle::Condition; @@ -10,7 +12,7 @@ UFlowNode_ComponentObserver::UFlowNode_ComponentObserver(const FObjectInitialize #endif InputNames = {TEXT("Start"), TEXT("Stop")}; - OutputNames = {TEXT("Success"), TEXT("Stopped")}; + OutputNames = {TEXT("Success"), TEXT("Completed"), TEXT("Stopped")}; } void UFlowNode_ComponentObserver::PostLoad() @@ -51,7 +53,7 @@ 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()->OnComponentTagRemoved.AddDynamic(this, &UFlowNode_ComponentObserver::OnComponentTagRemoved); } @@ -96,6 +98,17 @@ void UFlowNode_ComponentObserver::OnComponentTagRemoved(UFlowComponent* Componen } } +void UFlowNode_ComponentObserver::OnEventReceived() +{ + TriggerFirstOutput(false); + + SuccessCount++; + if (SuccessLimit > 0 && SuccessCount == SuccessLimit) + { + TriggerOutput(TEXT("Completed"), true); + } +} + void UFlowNode_ComponentObserver::Cleanup() { StopObserving(); @@ -105,6 +118,8 @@ void UFlowNode_ComponentObserver::Cleanup() ForgetActor(RegisteredActor.Key, RegisteredActor.Value); } RegisteredActors.Empty(); + + SuccessCount = 0; } #if WITH_EDITOR diff --git a/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp b/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp index 2e424467a..bdbc4ae44 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp @@ -37,7 +37,7 @@ void UFlowNode_OnNotifyFromActor::ObserveActor(TWeakObjectPtr Actor, TWe if (SelfWeakPtr.IsValid() && FlowComponent->IdentityTags.HasAnyExact(SelfWeakPtr.Get()->IdentityTags) && (!SelfWeakPtr.Get()->NotifyTags.IsValid() || SelfWeakPtr.Get()->NotifyTags.HasTagExact(Tag))) { - SelfWeakPtr->TriggerFirstOutput(true); + SelfWeakPtr->OnEventReceived(); } }); } diff --git a/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h b/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h index c301e61fb..5100a7af4 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h @@ -21,6 +21,15 @@ class FLOW_API UFlowNode_ComponentObserver : public UFlowNode protected: UPROPERTY(EditDefaultsOnly, Category = "ObservedComponent") FGameplayTagContainer IdentityTags; + + // 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(EditDefaultsOnly, Category = "Lifetime", meta = (ClampMin = 0)) + int32 SuccessLimit; + + // This node will become Completed, if Success Limit > 0 and Success Count reaches this limit + UPROPERTY(VisibleAnywhere, Category = "Lifetime") + int32 SuccessCount; TMap, TWeakObjectPtr> RegisteredActors; @@ -47,6 +56,9 @@ class FLOW_API UFlowNode_ComponentObserver : public UFlowNode 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 676e6ccad96960b8f1917d504a8d1641c149068e Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 5 Apr 2021 15:09:05 +0200 Subject: [PATCH 055/265] Test if array index is still valid, clearing instance might remove template while iterating the loop --- Source/Flow/Private/FlowSubsystem.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index 1f79c4237..3685c1f70 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -31,16 +31,19 @@ void UFlowSubsystem::Initialize(FSubsystemCollectionBase& Collection) void UFlowSubsystem::Deinitialize() { - for (int32 i = InstancedTemplates.Num() - 1; i >= 0; i--) + if (InstancedTemplates.Num() > 0) { - if (InstancedTemplates[i]) + for (int32 i = InstancedTemplates.Num() - 1; i >= 0; i--) { - InstancedTemplates[i]->ClearInstances(); + if (InstancedTemplates.IsValidIndex(i)) + { + InstancedTemplates[i]->ClearInstances(); + } } - } - InstancedTemplates.Empty(); - InstancedSubFlows.Empty(); + InstancedTemplates.Empty(); + InstancedSubFlows.Empty(); + } } void UFlowSubsystem::StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset) From 3881851bcae185b6ccd19c10c73288233046e425 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Wed, 7 Apr 2021 12:12:01 +0200 Subject: [PATCH 056/265] Update README.md --- README.md | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 051da20ad..f37070d22 100644 --- a/README.md +++ b/README.md @@ -26,16 +26,7 @@ This 24-minute presentation breaks down the concept of the Flow Graph. It goes t [![Introducing Flow Graph for Unreal Engine](https://img.youtube.com/vi/Rj76JP1f-I4/0.jpg)](https://www.youtube.com/watch?v=Rj76JP1f-I4) ## Getting started -In Releases, you can find an example project called Flower, so you can easily check how this plug-in works. - -And if you'd decide to use Flow in your project... -1. Unpack plug-in to the Plugins folder in your project folder. If you don't have such a folder yet, simply create it. -2. Open Project Settings in the editor. Change World Settings to the Flow World Settings class and restart the editor. This class starts the Flow Graph assigned to the map. - -You can include this plugin repository as dependency of your own Git project. It can be done by using Git submodules. -``` -git submodule add -b 4.26 https://github.com/MothCocoon/FlowGraph.git Plugins/Flow -``` +It's simple, follow this short [Getting Started](https://github.com/MothCocoon/FlowGraph/wiki/Getting-Started) guide. ## Simplicity is a key * It's all about simplifying the cooperation between gameplay programmers and content designers by providing a clean interface between "code of systems" and "using systems". @@ -81,7 +72,7 @@ Flow Graph communicates with actors in the world by using [Gameplay Tags](https: ## Contact * Catch me on Twitter: [@MothDoctor](https://twitter.com/MothDoctor) -* Discuss things related to plugin on the Discord server named Flow. +* Discuss things related to the plugin on dedicated [Discord server](https://discord.gg/zMtMQ2vUUa). ## 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 only the one who decided it would be crazy useful to adopt it for Unreal Engine. And make it publically available as my humble contribution to the open-source community. From b6a519ca3dff7d83231d8fe521461df208324b7f Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Wed, 7 Apr 2021 13:26:29 +0200 Subject: [PATCH 057/265] Root Flow fixes --- Source/Flow/Private/FlowComponent.cpp | 10 ++++++---- Source/Flow/Private/FlowSubsystem.cpp | 13 ++++++++----- Source/Flow/Private/FlowWorldSettings.cpp | 4 ++++ Source/Flow/Public/FlowComponent.h | 9 +++++++-- Source/Flow/Public/FlowSubsystem.h | 2 +- 5 files changed, 26 insertions(+), 12 deletions(-) diff --git a/Source/Flow/Private/FlowComponent.cpp b/Source/Flow/Private/FlowComponent.cpp index 0de60db23..4b9418f7a 100644 --- a/Source/Flow/Private/FlowComponent.cpp +++ b/Source/Flow/Private/FlowComponent.cpp @@ -9,6 +9,7 @@ UFlowComponent::UFlowComponent(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) , RootFlow(nullptr) , bAutoStartRootFlow(true) + , bAllowMultipleInstances(true) , RootFlowMode(EFlowNetMode::Authority) { PrimaryComponentTick.bCanEverTick = false; @@ -34,6 +35,7 @@ void UFlowComponent::EndPlay(const EEndPlayReason::Type EndPlayReason) { if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) { + FlowSubsystem->FinishRootFlow(this); FlowSubsystem->UnregisterComponent(this); } @@ -144,22 +146,22 @@ void UFlowComponent::NotifyActor(const FGameplayTag ActorTag, const FGameplayTag } } -void UFlowComponent::StartRootFlow() const +void UFlowComponent::StartRootFlow() { if (RootFlow && IsFlowNetMode(RootFlowMode)) { if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) { - FlowSubsystem->StartRootFlow(GetOwner(), RootFlow); + FlowSubsystem->StartRootFlow(this, RootFlow, bAllowMultipleInstances); } } } -void UFlowComponent::FinishRootFlow() const +void UFlowComponent::FinishRootFlow() { if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) { - FlowSubsystem->FinishRootFlow(GetOwner()); + FlowSubsystem->FinishRootFlow(this); } } diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index 3685c1f70..cc94a7708 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -46,11 +46,17 @@ void UFlowSubsystem::Deinitialize() } } -void UFlowSubsystem::StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset) +void UFlowSubsystem::StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances /* = true */) { if (RootInstances.Contains(Owner)) { - UE_LOG(LogFlow, Warning, TEXT("Attempted to start Root Flow again. Owner: %s. Flow Asset: %s."), *Owner->GetName(), *FlowAsset->GetName()); + 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; + } + + if (!bAllowMultipleInstances && InstancedTemplates.Contains(FlowAsset)) + { + UE_LOG(LogFlow, Warning, TEXT("Attempted to start Root Flow, although there can be only a single instance. Owner: %s. Flow Asset: %s."), *Owner->GetName(), *FlowAsset->GetName()); return; } @@ -196,9 +202,6 @@ void UFlowSubsystem::OnIdentityTagsAdded(UFlowComponent* Component, const FGamep void UFlowSubsystem::UnregisterComponent(UFlowComponent* Component) { - // first, remove Flow Assets instantiated by this component - FinishRootFlow(Component); - for (const FGameplayTag& Tag : Component->IdentityTags) { if (Tag.IsValid()) diff --git a/Source/Flow/Private/FlowWorldSettings.cpp b/Source/Flow/Private/FlowWorldSettings.cpp index f3941fa5f..4a0fcf988 100644 --- a/Source/Flow/Private/FlowWorldSettings.cpp +++ b/Source/Flow/Private/FlowWorldSettings.cpp @@ -5,6 +5,10 @@ AFlowWorldSettings::AFlowWorldSettings(const FObjectInitializer& ObjectInitializ : Super(ObjectInitializer) { FlowComponent = CreateDefaultSubobject(TEXT("FlowComponent")); + + // We need this if project uses custom AWorldSettings classed inherited after this one + // In this case engine would call BeginPlay multiple times... for AFlowWorldSettings and every inherited AWorldSettings class... + FlowComponent->bAllowMultipleInstances = false; } void AFlowWorldSettings::PostLoad() diff --git a/Source/Flow/Public/FlowComponent.h b/Source/Flow/Public/FlowComponent.h index d27049b01..768e9d0f1 100644 --- a/Source/Flow/Public/FlowComponent.h +++ b/Source/Flow/Public/FlowComponent.h @@ -73,17 +73,22 @@ class FLOW_API UFlowComponent : public UActorComponent UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "RootFlow") bool bAutoStartRootFlow; + // Networking mode for creating this Root Flow UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "RootFlow") EFlowNetMode RootFlowMode; + // If false, another Root Flow instance won't be created from this component, if this Flow Asset is already instantiated + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "RootFlow") + bool bAllowMultipleInstances; + // This will instantiate Flow Asset assigned on this component. // Created Flow Asset instance will be a "root flow", as additional Flow Assets can be instantiated via Sub Graph node UFUNCTION(BlueprintCallable, Category = "RootFlow") - void StartRootFlow() const; + void StartRootFlow(); // This will destroy instantiated Flow Asset - created from asset assigned on this component. UFUNCTION(BlueprintCallable, Category = "RootFlow") - void FinishRootFlow() const; + void FinishRootFlow(); UFUNCTION(BlueprintPure, Category = "RootFlow") UFlowAsset* GetRootFlowInstance(); diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index 7f4ad5917..40552bfcb 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -53,7 +53,7 @@ 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); + void StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances = true); // Finish the root Flow, typically when closing world that created this flow UFUNCTION(BlueprintCallable, Category = "FlowSubsystem") From 826976c7b1e9cfa8db8cab265c50621b3eee8314 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Wed, 7 Apr 2021 13:55:13 +0200 Subject: [PATCH 058/265] fixed initialization order --- Source/Flow/Private/FlowComponent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Flow/Private/FlowComponent.cpp b/Source/Flow/Private/FlowComponent.cpp index 4b9418f7a..5c1f3749a 100644 --- a/Source/Flow/Private/FlowComponent.cpp +++ b/Source/Flow/Private/FlowComponent.cpp @@ -9,8 +9,8 @@ UFlowComponent::UFlowComponent(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) , RootFlow(nullptr) , bAutoStartRootFlow(true) - , bAllowMultipleInstances(true) , RootFlowMode(EFlowNetMode::Authority) + , bAllowMultipleInstances(true) { PrimaryComponentTick.bCanEverTick = false; PrimaryComponentTick.bStartWithTickEnabled = false; From 09cc0acfae739950850ec734abbd532483b729f7 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Wed, 7 Apr 2021 13:57:17 +0200 Subject: [PATCH 059/265] Update Flow.uplugin --- Flow.uplugin | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Flow.uplugin b/Flow.uplugin index 9f1668167..911691588 100644 --- a/Flow.uplugin +++ b/Flow.uplugin @@ -6,8 +6,9 @@ "Category" : "Gameplay", "CreatedBy" : "Krzysztof Justyński", "CreatedByURL" : "https://twitter.com/MothDoctor", - "DocsURL" : "https://github.com/MothCocoon/FlowGraph", + "DocsURL" : "https://github.com/MothCocoon/FlowGraph/wiki", "MarketplaceURL" : "", + "SupportURL": "https://discord.gg/zMtMQ2vUUa", "EngineVersion": "4.26.0", "EnabledByDefault" : true, "CanContainContent" : false, From f877d276744c4f347ffaeb1bf582d52e21107003 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Thu, 8 Apr 2021 21:24:05 +0200 Subject: [PATCH 060/265] Flow Asset is now a blueprint type --- 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 3802fe6eb..0b37ccc45 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -32,7 +32,7 @@ DECLARE_DELEGATE(FFlowAssetEvent); /** * Single asset containing flow nodes. */ -UCLASS(hideCategories = Object) +UCLASS(BlueprintType, hideCategories = Object) class FLOW_API UFlowAsset : public UObject { GENERATED_UCLASS_BODY() From 713bb8cd4058a812aeaa2741b8d4ec0af44b0f3c Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Thu, 8 Apr 2021 22:02:12 +0200 Subject: [PATCH 061/265] Flow Component now supports multiplayer - replicating added/removed Identity Tags - replicating recent Notify Tags --- Source/Flow/Private/FlowComponent.cpp | 231 +++++++++++++++--- .../World/FlowNode_OnNotifyFromActor.cpp | 21 +- Source/Flow/Public/FlowComponent.h | 133 ++++++++-- .../Nodes/World/FlowNode_OnNotifyFromActor.h | 7 + 4 files changed, 328 insertions(+), 64 deletions(-) diff --git a/Source/Flow/Private/FlowComponent.cpp b/Source/Flow/Private/FlowComponent.cpp index 5c1f3749a..fa038cab7 100644 --- a/Source/Flow/Private/FlowComponent.cpp +++ b/Source/Flow/Private/FlowComponent.cpp @@ -4,6 +4,7 @@ #include "Engine/GameInstance.h" #include "Engine/World.h" +#include "Net/UnrealNetwork.h" UFlowComponent::UFlowComponent(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) @@ -14,6 +15,20 @@ UFlowComponent::UFlowComponent(const FObjectInitializer& ObjectInitializer) { PrimaryComponentTick.bCanEverTick = false; PrimaryComponentTick.bStartWithTickEnabled = false; + + SetIsReplicatedByDefault(true); +} + +void UFlowComponent::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const +{ + Super::GetLifetimeReplicatedProps(OutLifetimeProps); + + DOREPLIFETIME(UFlowComponent, AddedIdentityTags); + DOREPLIFETIME(UFlowComponent, RemovedIdentityTags); + + DOREPLIFETIME(UFlowComponent, RecentlySentNotifyTags); + DOREPLIFETIME(UFlowComponent, NotifyTagsFromGraph); + DOREPLIFETIME(UFlowComponent, NotifyTagsFromAnotherComponent); } void UFlowComponent::BeginPlay() @@ -42,106 +57,248 @@ void UFlowComponent::EndPlay(const EEndPlayReason::Type EndPlayReason) Super::EndPlay(EndPlayReason); } -void UFlowComponent::AddIdentityTag(const FGameplayTag Tag) +void UFlowComponent::AddIdentityTag(const FGameplayTag Tag, const EFlowNetMode NetMode /* = EFlowNetMode::Authority*/) { - ensure(GetOwner()->HasAuthority()); - - if (Tag.IsValid() && !IdentityTags.HasTagExact(Tag)) + if (IsFlowNetMode(NetMode) && Tag.IsValid() && !IdentityTags.HasTagExact(Tag)) { IdentityTags.AddTag(Tag); if (HasBegunPlay()) { + OnIdentityTagsAdded.Broadcast(this, FGameplayTagContainer(Tag)); + if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) { FlowSubsystem->OnIdentityTagAdded(this, Tag); } + + if (IsNetMode(NM_DedicatedServer) || IsNetMode(NM_ListenServer)) + { + AddedIdentityTags = FGameplayTagContainer(Tag); + } } } } -void UFlowComponent::AddIdentityTags(FGameplayTagContainer Tags) +void UFlowComponent::AddIdentityTags(FGameplayTagContainer Tags, const EFlowNetMode NetMode /* = EFlowNetMode::Authority*/) { - ensure(GetOwner()->HasAuthority()); - - // todo: iterator and remove invalid tags - for (const FGameplayTag& Tag : Tags) + if (IsFlowNetMode(NetMode) && Tags.IsValid()) { - if (Tag.IsValid() && !IdentityTags.HasTagExact(Tag)) + FGameplayTagContainer ValidatedTags; + + for (const FGameplayTag& Tag : Tags) { - IdentityTags.AddTag(Tag); + if (Tag.IsValid() && !IdentityTags.HasTagExact(Tag)) + { + IdentityTags.AddTag(Tag); + ValidatedTags.AddTag(Tag); + } } - } - if (Tags.Num() > 0 && HasBegunPlay()) - { - if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) + if (ValidatedTags.Num() > 0 && HasBegunPlay()) { - FlowSubsystem->OnIdentityTagsAdded(this, Tags); + OnIdentityTagsAdded.Broadcast(this, ValidatedTags); + + if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) + { + FlowSubsystem->OnIdentityTagsAdded(this, ValidatedTags); + } + + if (IsNetMode(NM_DedicatedServer) || IsNetMode(NM_ListenServer)) + { + AddedIdentityTags = ValidatedTags; + } } } } -void UFlowComponent::RemoveIdentityTag(const FGameplayTag Tag) +void UFlowComponent::RemoveIdentityTag(const FGameplayTag Tag, const EFlowNetMode NetMode /* = EFlowNetMode::Authority*/) { - ensure(GetOwner()->HasAuthority()); - - if (Tag.IsValid() && IdentityTags.HasTagExact(Tag)) + if (IsFlowNetMode(NetMode) && Tag.IsValid() && IdentityTags.HasTagExact(Tag)) { IdentityTags.RemoveTag(Tag); if (HasBegunPlay()) { + OnIdentityTagsRemoved.Broadcast(this, FGameplayTagContainer(Tag)); + if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) { FlowSubsystem->OnIdentityTagRemoved(this, Tag); } + + if (IsNetMode(NM_DedicatedServer) || IsNetMode(NM_ListenServer)) + { + RemovedIdentityTags = FGameplayTagContainer(Tag); + } } } } -void UFlowComponent::RemoveIdentityTags(FGameplayTagContainer Tags) +void UFlowComponent::RemoveIdentityTags(FGameplayTagContainer Tags, const EFlowNetMode NetMode /* = EFlowNetMode::Authority*/) { - ensure(GetOwner()->HasAuthority()); - - // todo: iterator and remove invalid tags - for (const FGameplayTag& Tag : Tags) + if (IsFlowNetMode(NetMode) && Tags.IsValid()) { - if (Tag.IsValid() && IdentityTags.HasTagExact(Tag)) + FGameplayTagContainer ValidatedTags; + + for (const FGameplayTag& Tag : Tags) { - IdentityTags.RemoveTag(Tag); + if (Tag.IsValid() && IdentityTags.HasTagExact(Tag)) + { + IdentityTags.RemoveTag(Tag); + ValidatedTags.AddTag(Tag); + } + } + + if (ValidatedTags.Num() > 0 && HasBegunPlay()) + { + OnIdentityTagsRemoved.Broadcast(this, ValidatedTags); + + if (UFlowSubsystem* FlowSubsystem = GetWorld()->GetGameInstance()->GetSubsystem()) + { + FlowSubsystem->OnIdentityTagsRemoved(this, ValidatedTags); + } + + if (IsNetMode(NM_DedicatedServer) || IsNetMode(NM_ListenServer)) + { + RemovedIdentityTags = ValidatedTags; + } } } +} - if (Tags.Num() > 0 && HasBegunPlay()) +void UFlowComponent::OnRep_AddedIdentityTags() +{ + IdentityTags.AppendTags(AddedIdentityTags); + OnIdentityTagsAdded.Broadcast(this, AddedIdentityTags); + + if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) { - if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) + FlowSubsystem->OnIdentityTagsAdded(this, AddedIdentityTags); + } +} + +void UFlowComponent::OnRep_RemovedIdentityTags() +{ + IdentityTags.RemoveTags(RemovedIdentityTags); + OnIdentityTagsRemoved.Broadcast(this, RemovedIdentityTags); + + if (UFlowSubsystem* FlowSubsystem = GetWorld()->GetGameInstance()->GetSubsystem()) + { + FlowSubsystem->OnIdentityTagsRemoved(this, RemovedIdentityTags); + } +} + +void UFlowComponent::NotifyGraph(const FGameplayTag NotifyTag, const EFlowNetMode NetMode /* = EFlowNetMode::Authority*/) +{ + if (IsFlowNetMode(NetMode) && NotifyTag.IsValid() && HasBegunPlay()) + { + // 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 = FGameplayTagContainer(NotifyTag); + + OnRep_SentNotifyTags(); + } +} + +void UFlowComponent::BulkNotifyGraph(const FGameplayTagContainer NotifyTags, const EFlowNetMode NetMode /* = EFlowNetMode::Authority*/) +{ + if (IsFlowNetMode(NetMode) && NotifyTags.IsValid() && HasBegunPlay()) + { + FGameplayTagContainer ValidatedTags; + for (const FGameplayTag& Tag : NotifyTags) + { + if (Tag.IsValid()) + { + ValidatedTags.AddTag(Tag); + } + } + + if (ValidatedTags.Num() > 0) { - FlowSubsystem->OnIdentityTagsRemoved(this, Tags); + // 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; + + OnRep_SentNotifyTags(); } } } -void UFlowComponent::NotifyGraph(const FGameplayTag NotifyTag) +void UFlowComponent::OnRep_SentNotifyTags() { - OnNotifyFromComponent.Broadcast(this, NotifyTag); + for (const FGameplayTag& NotifyTag : RecentlySentNotifyTags) + { + OnNotifyFromComponent.Broadcast(this, NotifyTag); + } +} + +void UFlowComponent::NotifyFromGraph(const FGameplayTagContainer& NotifyTags, const EFlowNetMode NetMode /* = EFlowNetMode::Authority*/) +{ + if (IsFlowNetMode(NetMode) && NotifyTags.IsValid() && HasBegunPlay()) + { + FGameplayTagContainer ValidatedTags; + for (const FGameplayTag& Tag : NotifyTags) + { + if (Tag.IsValid()) + { + ValidatedTags.AddTag(Tag); + } + } + + if (ValidatedTags.Num() > 0) + { + for (const FGameplayTag& NotifyTag : NotifyTags) + { + ReceiveNotify.Broadcast(nullptr, NotifyTag); + } + + if (IsNetMode(NM_DedicatedServer) || IsNetMode(NM_ListenServer)) + { + NotifyTagsFromGraph = NotifyTags; + } + } + } } -void UFlowComponent::NotifyFromGraph(const FGameplayTagContainer& NotifyTags) +void UFlowComponent::OnRep_NotifyTagsFromGraph() { - for (const FGameplayTag& NotifyTag : NotifyTags) + for (const FGameplayTag& NotifyTag : NotifyTagsFromGraph) { ReceiveNotify.Broadcast(nullptr, NotifyTag); } } -void UFlowComponent::NotifyActor(const FGameplayTag ActorTag, const FGameplayTag NotifyTag) +void UFlowComponent::NotifyActor(const FGameplayTag ActorTag, const FGameplayTag NotifyTag, const EFlowNetMode NetMode /* = EFlowNetMode::Authority*/) +{ + if (IsFlowNetMode(NetMode) && NotifyTag.IsValid() && HasBegunPlay()) + { + if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) + { + for (TWeakObjectPtr& Component : FlowSubsystem->GetComponents(ActorTag)) + { + Component->ReceiveNotify.Broadcast(this, NotifyTag); + } + } + + if (IsNetMode(NM_DedicatedServer) || IsNetMode(NM_ListenServer)) + { + NotifyTagsFromAnotherComponent.Empty(); + NotifyTagsFromAnotherComponent.Add(FNotifyTagReplication(ActorTag, NotifyTag)); + } + } +} + +void UFlowComponent::OnRep_NotifyTagsFromAnotherComponent() { if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) { - for (TWeakObjectPtr& Component : FlowSubsystem->GetComponents(ActorTag)) + for (const FNotifyTagReplication& Notify : NotifyTagsFromAnotherComponent) { - Component->ReceiveNotify.Broadcast(this, NotifyTag); + for (TWeakObjectPtr& Component : FlowSubsystem->GetComponents(Notify.ActorTag)) + { + Component->ReceiveNotify.Broadcast(this, Notify.NotifyTag); + } } } } diff --git a/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp b/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp index bdbc4ae44..8d58d5a15 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp @@ -3,6 +3,7 @@ UFlowNode_OnNotifyFromActor::UFlowNode_OnNotifyFromActor(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) + , bRetroactive(false) { #if WITH_EDITOR Category = TEXT("Notifies"); @@ -30,16 +31,12 @@ void UFlowNode_OnNotifyFromActor::ObserveActor(TWeakObjectPtr Actor, TWe if (!RegisteredActors.Contains(Actor)) { RegisteredActors.Emplace(Actor, Component); + Component->OnNotifyFromComponent.AddUObject(this, &UFlowNode_OnNotifyFromActor::OnNotifyFromComponent); - TWeakObjectPtr SelfWeakPtr(this); - Component->OnNotifyFromComponent.AddWeakLambda(this, [SelfWeakPtr](UFlowComponent* FlowComponent, const FGameplayTag& Tag) + if (bRetroactive && Component->GetRecentlySentNotifyTags().HasAnyExact(NotifyTags)) { - if (SelfWeakPtr.IsValid() && FlowComponent->IdentityTags.HasAnyExact(SelfWeakPtr.Get()->IdentityTags) - && (!SelfWeakPtr.Get()->NotifyTags.IsValid() || SelfWeakPtr.Get()->NotifyTags.HasTagExact(Tag))) - { - SelfWeakPtr->OnEventReceived(); - } - }); + OnEventReceived(); + } } } @@ -48,6 +45,14 @@ void UFlowNode_OnNotifyFromActor::ForgetActor(TWeakObjectPtr Actor, TWea Component->OnNotifyFromComponent.RemoveAll(this); } +void UFlowNode_OnNotifyFromActor::OnNotifyFromComponent(UFlowComponent* Component, const FGameplayTag& Tag) +{ + if (Component->IdentityTags.HasAnyExact(IdentityTags) && (!NotifyTags.IsValid() || NotifyTags.HasTagExact(Tag))) + { + OnEventReceived(); + } +} + #if WITH_EDITOR FString UFlowNode_OnNotifyFromActor::GetNodeDescription() const { diff --git a/Source/Flow/Public/FlowComponent.h b/Source/Flow/Public/FlowComponent.h index 768e9d0f1..0dd333ea4 100644 --- a/Source/Flow/Public/FlowComponent.h +++ b/Source/Flow/Public/FlowComponent.h @@ -9,6 +9,28 @@ class UFlowAsset; class UFlowSubsystem; +USTRUCT() +struct FNotifyTagReplication +{ + GENERATED_BODY() + + UPROPERTY() + FGameplayTag ActorTag; + + UPROPERTY() + FGameplayTag NotifyTag; + + FNotifyTagReplication() {} + + FNotifyTagReplication(const FGameplayTag& InActorTag, const FGameplayTag& InNotifyTag) + : ActorTag(InActorTag) + , NotifyTag(InNotifyTag) + { + } +}; + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FFlowComponentTagsReplicated, class UFlowComponent*, FlowComponent, const FGameplayTagContainer&, CurrentTags); + DECLARE_MULTICAST_DELEGATE_TwoParams(FFlowComponentNotify, class UFlowComponent*, const FGameplayTag&); DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FFlowComponentDynamicNotify, class UFlowComponent*, FlowComponent, const FGameplayTag&, NotifyTag); @@ -20,53 +42,126 @@ class FLOW_API UFlowComponent : public UActorComponent { GENERATED_UCLASS_BODY() + friend class UFlowSubsystem; + + virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; + ////////////////////////////////////////////////////////////////////////// // Identity Tags - friend class UFlowSubsystem; UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Flow") FGameplayTagContainer IdentityTags; +private: + // Used to replicate tags added during gameplay + UPROPERTY(ReplicatedUsing = OnRep_AddedIdentityTags) + FGameplayTagContainer AddedIdentityTags; + + // Used to replicate tags removed during gameplay + UPROPERTY(ReplicatedUsing = OnRep_RemovedIdentityTags) + FGameplayTagContainer RemovedIdentityTags; + +public: virtual void BeginPlay() override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; - UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category = "Flow") - void AddIdentityTag(const FGameplayTag Tag); + UFUNCTION(BlueprintCallable, Category = "Flow") + void AddIdentityTag(const FGameplayTag Tag, const EFlowNetMode NetMode = EFlowNetMode::Authority); - UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category = "Flow") - void AddIdentityTags(FGameplayTagContainer Tags); + UFUNCTION(BlueprintCallable, Category = "Flow") + void AddIdentityTags(FGameplayTagContainer Tags, const EFlowNetMode NetMode = EFlowNetMode::Authority); - UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category = "Flow") - void RemoveIdentityTag(const FGameplayTag Tag); + UFUNCTION(BlueprintCallable, Category = "Flow") + void RemoveIdentityTag(const FGameplayTag Tag, const EFlowNetMode NetMode = EFlowNetMode::Authority); + + UFUNCTION(BlueprintCallable, Category = "Flow") + void RemoveIdentityTags(FGameplayTagContainer Tags, const EFlowNetMode NetMode = EFlowNetMode::Authority); - UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category = "Flow") - void RemoveIdentityTags(FGameplayTagContainer Tags); +private: + UFUNCTION() + void OnRep_AddedIdentityTags(); + + UFUNCTION() + void OnRep_RemovedIdentityTags(); + +public: + UPROPERTY(BlueprintAssignable, Category = "Flow") + FFlowComponentTagsReplicated OnIdentityTagsAdded; + + UPROPERTY(BlueprintAssignable, Category = "Flow") + FFlowComponentTagsReplicated OnIdentityTagsRemoved; ////////////////////////////////////////////////////////////////////////// -// Notify Tags: set only in runtime - - // Send notification from the actor to Flow graphs - UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category = "Flow") - void NotifyGraph(const FGameplayTag NotifyTag); +// Component sending Notify Tags to Flow Graph, or any other listener + +private: + // Stores only recently sent tags + UPROPERTY(ReplicatedUsing = OnRep_SentNotifyTags) + FGameplayTagContainer RecentlySentNotifyTags; + +public: + 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 + UFUNCTION(BlueprintCallable, Category = "Flow") + void NotifyGraph(const FGameplayTag NotifyTag, const EFlowNetMode NetMode = EFlowNetMode::Authority); + + // Send multiple notifications at once - from the actor to Flow graphs + // If set on server, it always going to be replicated to clients + UFUNCTION(BlueprintCallable, Category = "Flow") + void BulkNotifyGraph(const FGameplayTagContainer NotifyTags, const EFlowNetMode NetMode = EFlowNetMode::Authority); + +private: + UFUNCTION() + void OnRep_SentNotifyTags(); + +public: FFlowComponentNotify OnNotifyFromComponent; - + +////////////////////////////////////////////////////////////////////////// +// Component receiving Notify Tags from Flow Graph + +private: + // Stores only recently replicated tags + UPROPERTY(ReplicatedUsing = OnRep_NotifyTagsFromGraph) + FGameplayTagContainer NotifyTagsFromGraph; + +public: + virtual void NotifyFromGraph(const FGameplayTagContainer& NotifyTags, const EFlowNetMode NetMode = EFlowNetMode::Authority); + +private: + UFUNCTION() + void OnRep_NotifyTagsFromGraph(); + +public: // Receive notification from Flow graph or another Flow Component UPROPERTY(BlueprintAssignable, Category = "Flow") FFlowComponentDynamicNotify ReceiveNotify; - virtual void NotifyFromGraph(const FGameplayTagContainer& NotifyTags); +////////////////////////////////////////////////////////////////////////// +// Sending Notify Tags between Flow components +private: + // Stores only recently replicated tags + UPROPERTY(ReplicatedUsing = OnRep_NotifyTagsFromAnotherComponent) + TArray NotifyTagsFromAnotherComponent; + +public: // Send notification to another actor containing Flow Component UFUNCTION(BlueprintCallable, Category = "Flow") - virtual void NotifyActor(const FGameplayTag ActorTag, const FGameplayTag NotifyTag); + virtual void NotifyActor(const FGameplayTag ActorTag, const FGameplayTag NotifyTag, const EFlowNetMode NetMode = EFlowNetMode::Authority); + +private: + UFUNCTION() + void OnRep_NotifyTagsFromAnotherComponent(); ////////////////////////////////////////////////////////////////////////// // Root Flow public: // Asset that might instantiated as "Root Flow" - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "RootFlow") + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "RootFlow") UFlowAsset* RootFlow; // If true, component will start Root Flow on Begin Play @@ -95,7 +190,7 @@ class FLOW_API UFlowComponent : public UActorComponent ////////////////////////////////////////////////////////////////////////// // Helpers - + UFlowSubsystem* GetFlowSubsystem() const; bool IsFlowNetMode(const EFlowNetMode NetMode) const; }; diff --git a/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h b/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h index 9799381d7..30a5c2c6c 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h @@ -15,6 +15,11 @@ class FLOW_API UFlowNode_OnNotifyFromActor : public UFlowNode_ComponentObserver UPROPERTY(EditDefaultsOnly, Category = "ObservedComponent") 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(EditDefaultsOnly, Category = "ObservedComponent") + bool bRetroactive; + virtual void PostLoad() override; virtual void ExecuteInput(const FName& PinName) override; @@ -22,6 +27,8 @@ class FLOW_API UFlowNode_OnNotifyFromActor : public UFlowNode_ComponentObserver virtual void ObserveActor(TWeakObjectPtr Actor, TWeakObjectPtr Component) override; virtual void ForgetActor(TWeakObjectPtr Actor, TWeakObjectPtr Component) override; + virtual void OnNotifyFromComponent(UFlowComponent* Component, const FGameplayTag& Tag); + #if WITH_EDITOR public: virtual FString GetNodeDescription() const override; From f592621f66b4517526d20f9c00820ae02897a542 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 9 Apr 2021 12:31:42 +0200 Subject: [PATCH 062/265] rogue check removed --- Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp b/Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp index 0a7a03d3d..ca076ec83 100644 --- a/Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp +++ b/Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp @@ -76,7 +76,7 @@ void SLevelEditorFlow::OnFlowChanged(const FAssetData& NewAsset) FlowPath = NewAsset.ObjectPath; UFlowComponent* FlowComponent = FindFlowComponent(); - if (FlowComponent && FlowComponent->RootFlow) + if (FlowComponent) { if (UObject* NewObject = NewAsset.GetAsset()) { From 96ee752049d1aac23c21d54447b82ebddfe0b9bb Mon Sep 17 00:00:00 2001 From: Sergey Vikhirev Date: Fri, 9 Apr 2021 12:39:50 +0400 Subject: [PATCH 063/265] PR #31: new MultiGate node which replicates behavior similar Blueprint node MultiGate has Random, Loop and StartIndex properties --- .../Route/FlowNode_ExecutionMultiGate.cpp | 124 ++++++++++++++++++ .../Nodes/Route/FlowNode_ExecutionMultiGate.h | 42 ++++++ 2 files changed, 166 insertions(+) create mode 100644 Source/Flow/Private/Nodes/Route/FlowNode_ExecutionMultiGate.cpp create mode 100644 Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionMultiGate.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionMultiGate.cpp new file mode 100644 index 000000000..c6415abce --- /dev/null +++ b/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionMultiGate.cpp @@ -0,0 +1,124 @@ +#include "Nodes/Route/FlowNode_ExecutionMultiGate.h" + +#include "Misc/StringBuilder.h" + +const FName UFlowNode_ExecutionMultiGate::ResetInputName = TEXT("Reset"); + +UFlowNode_ExecutionMultiGate::UFlowNode_ExecutionMultiGate(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ +#if WITH_EDITOR + Category = TEXT("Route"); + NodeStyle = EFlowNodeStyle::Logic; +#endif + + InputNames.Empty(); + InputNames.Add(DefaultInputName); + InputNames.Add(ResetInputName); + + SetNumericalOutputs(0, 1); +} + +void UFlowNode_ExecutionMultiGate::ExecuteInput(const FName& PinName) +{ + if (PinName == ResetInputName) + { + Finish(); + return; + } + + if (Completed.Num() == 0) + { + Completed.Init(false, OutputNames.Num()); + } + + if (!Completed.Contains(false)) + { + return; + } + + const bool bUseStartIndex = !Completed.Contains(true) && Completed.IsValidIndex(StartIndex); + + if (bRandom) + { + int32 Index = INDEX_NONE; + if (bUseStartIndex) + { + Index = StartIndex; + } + else + { + TArray AvailableIndexes; + AvailableIndexes.Reserve(Completed.Num()); + + for (int32 Idx = 0; Idx < Completed.Num(); Idx++) + { + if (Completed[Idx] == false) + { + AvailableIndexes.Add(Idx); + } + } + + const int32 Random = FMath::RandRange(0, AvailableIndexes.Num() - 1); + Index = AvailableIndexes[Random]; + } + + Completed[Index] = true; + TriggerOutput(OutputNames[Index], false); + } + else + { + if (bUseStartIndex) + { + NextOutput = StartIndex; + } + + const int32 CurrentOutput = NextOutput; + //We have to calculate NextOutput before TriggerOutput(..) + //TriggerOutput may call Reset and Cleanup + NextOutput = ++NextOutput % OutputNames.Num(); + + Completed[CurrentOutput] = true; + TriggerOutput(OutputNames[CurrentOutput], false); + } + + if (!Completed.Contains(false) && bLoop) + { + Finish(); + } +} + +void UFlowNode_ExecutionMultiGate::Cleanup() +{ + NextOutput = 0; + Completed.Reset(); +} + +#if WITH_EDITOR +FString UFlowNode_ExecutionMultiGate::GetNodeDescription() const +{ + TStringBuilder<128> Builder; + + if (bRandom) + Builder += TEXT("Random"); + + if (bRandom && bLoop) + Builder += TEXT(", "); + + if (bLoop) + Builder += TEXT("Loop"); + + if (StartIndex != INDEX_NONE) + { + if (bRandom || bLoop) + Builder += TEXT(", "); + + if (OutputNames.IsValidIndex(StartIndex)) + Builder += TEXT("StartIndex: ") + FString::FromInt(StartIndex); + else + Builder += TEXT("StartIndex: Invalid"); + } + + return Builder.ToString(); +} +#endif diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h new file mode 100644 index 000000000..1e2bcfe45 --- /dev/null +++ b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h @@ -0,0 +1,42 @@ +#pragma once + +#include "Nodes/FlowNode.h" +#include "FlowNode_ExecutionMultiGate.generated.h" + +/** + * Executes a series of pins in order + */ +UCLASS(NotBlueprintable, meta = (DisplayName = "MultiGate")) +class FLOW_API UFlowNode_ExecutionMultiGate final : public UFlowNode +{ + GENERATED_UCLASS_BODY() +public: + UPROPERTY(EditDefaultsOnly, Category = "MultiGate") + bool bRandom; + + UPROPERTY(EditDefaultsOnly, Category = "MultiGate") + bool bLoop; + + UPROPERTY(EditDefaultsOnly, Category = "MultiGate") + int32 StartIndex = INDEX_NONE; + +#if WITH_EDITOR + virtual bool CanUserAddOutput() const override { return true; } +#endif + +protected: + virtual void ExecuteInput(const FName& PinName) override; + virtual void Cleanup() override; + +#if WITH_EDITOR + virtual FString GetNodeDescription() const override; +#endif + + UPROPERTY() + int32 NextOutput; + + UPROPERTY() + TArray Completed; + + static const FName ResetInputName; +}; From 9448c98015040e63d435c0960aea94ae54585012 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 9 Apr 2021 12:55:05 +0200 Subject: [PATCH 064/265] cosmetic polishing --- .../Route/FlowNode_ExecutionMultiGate.cpp | 138 +++++++++--------- .../Nodes/Route/FlowNode_ExecutionMultiGate.h | 28 ++-- .../Nodes/FlowGraphNode_ExecutionSequence.cpp | 3 +- 3 files changed, 90 insertions(+), 79 deletions(-) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionMultiGate.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionMultiGate.cpp index c6415abce..f4c9cdf0e 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionMultiGate.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionMultiGate.cpp @@ -1,88 +1,83 @@ #include "Nodes/Route/FlowNode_ExecutionMultiGate.h" -#include "Misc/StringBuilder.h" - -const FName UFlowNode_ExecutionMultiGate::ResetInputName = TEXT("Reset"); - UFlowNode_ExecutionMultiGate::UFlowNode_ExecutionMultiGate(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) + , StartIndex(INDEX_NONE) { #if WITH_EDITOR Category = TEXT("Route"); NodeStyle = EFlowNodeStyle::Logic; #endif - InputNames.Empty(); - InputNames.Add(DefaultInputName); - InputNames.Add(ResetInputName); - + InputNames.Add(TEXT("Reset")); SetNumericalOutputs(0, 1); } void UFlowNode_ExecutionMultiGate::ExecuteInput(const FName& PinName) { - if (PinName == ResetInputName) + if (PinName == DefaultInputName) { - Finish(); - return; - } + if (Completed.Num() == 0) + { + Completed.Init(false, OutputNames.Num()); + } - if (Completed.Num() == 0) - { - Completed.Init(false, OutputNames.Num()); - } + if (!Completed.Contains(false)) + { + return; + } - if (!Completed.Contains(false)) - { - return; - } + const bool bUseStartIndex = !Completed.Contains(true) && Completed.IsValidIndex(StartIndex); - const bool bUseStartIndex = !Completed.Contains(true) && Completed.IsValidIndex(StartIndex); - - if (bRandom) - { - int32 Index = INDEX_NONE; - if (bUseStartIndex) + if (bRandom) { - Index = StartIndex; + int32 Index; + if (bUseStartIndex) + { + Index = StartIndex; + } + else + { + TArray AvailableIndexes; + AvailableIndexes.Reserve(Completed.Num()); // todo + + for (int32 i = 0; i < Completed.Num(); i++) + { + if (Completed[i] == false) + { + AvailableIndexes.Emplace(i); + } + } + + const int32 Random = FMath::RandRange(0, AvailableIndexes.Num() - 1); + Index = AvailableIndexes[Random]; + } + + Completed[Index] = true; + TriggerOutput(OutputNames[Index], false); } else { - TArray AvailableIndexes; - AvailableIndexes.Reserve(Completed.Num()); - - for (int32 Idx = 0; Idx < Completed.Num(); Idx++) + if (bUseStartIndex) { - if (Completed[Idx] == false) - { - AvailableIndexes.Add(Idx); - } + NextOutput = StartIndex; } - const int32 Random = FMath::RandRange(0, AvailableIndexes.Num() - 1); - Index = AvailableIndexes[Random]; + const int32 CurrentOutput = NextOutput; + // We have to calculate NextOutput before TriggerOutput(..) + // TriggerOutput may call Reset and Cleanup + NextOutput = ++NextOutput % OutputNames.Num(); + + Completed[CurrentOutput] = true; + TriggerOutput(OutputNames[CurrentOutput], false); } - Completed[Index] = true; - TriggerOutput(OutputNames[Index], false); - } - else - { - if (bUseStartIndex) + if (!Completed.Contains(false) && bLoop) { - NextOutput = StartIndex; + Finish(); } - - const int32 CurrentOutput = NextOutput; - //We have to calculate NextOutput before TriggerOutput(..) - //TriggerOutput may call Reset and Cleanup - NextOutput = ++NextOutput % OutputNames.Num(); - - Completed[CurrentOutput] = true; - TriggerOutput(OutputNames[CurrentOutput], false); } - - if (!Completed.Contains(false) && bLoop) + else if (PinName == TEXT("Reset")) { Finish(); } @@ -97,28 +92,41 @@ void UFlowNode_ExecutionMultiGate::Cleanup() #if WITH_EDITOR FString UFlowNode_ExecutionMultiGate::GetNodeDescription() const { - TStringBuilder<128> Builder; + FString Result; + Result.Reserve(128); if (bRandom) - Builder += TEXT("Random"); + { + Result.Append(TEXT("Random")); + } if (bRandom && bLoop) - Builder += TEXT(", "); - + { + Result.Append(TEXT(", ")); + } + if (bLoop) - Builder += TEXT("Loop"); + { + Result.Append(TEXT("Loop")); + } if (StartIndex != INDEX_NONE) { if (bRandom || bLoop) - Builder += TEXT(", "); - + { + Result.Append(TEXT(", ")); + } + if (OutputNames.IsValidIndex(StartIndex)) - Builder += TEXT("StartIndex: ") + FString::FromInt(StartIndex); + { + Result.Appendf(TEXT("Start Index: %d"), StartIndex); + } else - Builder += TEXT("StartIndex: Invalid"); + { + Result.Append(TEXT("StartIndex: Invalid")); + } } - - return Builder.ToString(); + + return Result; } #endif diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h index 1e2bcfe45..ef9ed58d1 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h @@ -6,24 +6,34 @@ /** * Executes a series of pins in order */ -UCLASS(NotBlueprintable, meta = (DisplayName = "MultiGate")) +UCLASS(NotBlueprintable, meta = (DisplayName = "Multi Gate")) class FLOW_API UFlowNode_ExecutionMultiGate final : public UFlowNode { GENERATED_UCLASS_BODY() -public: + UPROPERTY(EditDefaultsOnly, Category = "MultiGate") bool bRandom; + // Allow executing output pins again, without triggering Reset pin + // If set to False, every output pin can be triggered only once UPROPERTY(EditDefaultsOnly, Category = "MultiGate") bool bLoop; UPROPERTY(EditDefaultsOnly, Category = "MultiGate") - int32 StartIndex = INDEX_NONE; - + int32 StartIndex; + +private: + UPROPERTY() + int32 NextOutput; + + UPROPERTY() + TArray Completed; + +public: #if WITH_EDITOR virtual bool CanUserAddOutput() const override { return true; } #endif - + protected: virtual void ExecuteInput(const FName& PinName) override; virtual void Cleanup() override; @@ -31,12 +41,4 @@ class FLOW_API UFlowNode_ExecutionMultiGate final : public UFlowNode #if WITH_EDITOR virtual FString GetNodeDescription() const override; #endif - - UPROPERTY() - int32 NextOutput; - - UPROPERTY() - TArray Completed; - - static const FName ResetInputName; }; diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_ExecutionSequence.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_ExecutionSequence.cpp index e9aab0e8c..6b093c1c8 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_ExecutionSequence.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode_ExecutionSequence.cpp @@ -1,4 +1,5 @@ #include "Graph/Nodes/FlowGraphNode_ExecutionSequence.h" +#include "Nodes/Route/FlowNode_ExecutionMultiGate.h" #include "Nodes/Route/FlowNode_ExecutionSequence.h" #include "Textures/SlateIcon.h" @@ -6,7 +7,7 @@ UFlowGraphNode_ExecutionSequence::UFlowGraphNode_ExecutionSequence(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { - AssignedNodeClasses = {UFlowNode_ExecutionSequence::StaticClass()}; + AssignedNodeClasses = {UFlowNode_ExecutionSequence::StaticClass(), UFlowNode_ExecutionMultiGate::StaticClass()}; } FSlateIcon UFlowGraphNode_ExecutionSequence::GetIconAndTint(FLinearColor& OutColor) const From 7b59f1ed6e49eecce9817bbce4ea8a81bcb9c1e9 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 9 Apr 2021 13:22:11 +0200 Subject: [PATCH 065/265] using Append() in few places --- Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp | 2 +- Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp | 2 +- 2 files 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 ad41488f1..0ff872428 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp @@ -103,7 +103,7 @@ FString UFlowNode_Timer::GetNodeDescription() const { if (StepTime > 0.0f) { - return FString::SanitizeFloat(CompletionTime, 2) + TEXT(", step by ") + FString::SanitizeFloat(StepTime, 2); + return FString::SanitizeFloat(CompletionTime, 2).Append(TEXT(", step by ")).Append(FString::SanitizeFloat(StepTime, 2)); } return FString::SanitizeFloat(CompletionTime, 2); diff --git a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp index 851c47f60..cf604768e 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp @@ -197,7 +197,7 @@ FString UFlowNode_PlayLevelSequence::GetPlaybackProgress() const { if (SequencePlayer && SequencePlayer->IsPlaying()) { - return GetProgressAsString(SequencePlayer->GetCurrentTime().AsSeconds() - StartTime) + TEXT(" / ") + GetProgressAsString(SequencePlayer->GetDuration().AsSeconds()); + return GetProgressAsString(SequencePlayer->GetCurrentTime().AsSeconds() - StartTime).Append(TEXT(" / ")).Append(GetProgressAsString(SequencePlayer->GetDuration().AsSeconds())); } return FString(); From 66380dd9c4304649c6d74491d61f389e3f82a2a0 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 9 Apr 2021 14:16:00 +0200 Subject: [PATCH 066/265] moving folder with node customizations --- Source/FlowEditor/Private/FlowEditorModule.cpp | 10 +++++----- .../FlowNode_ComponentObserverDetails.cpp | 2 +- .../Customizations/FlowNode_ComponentObserverDetails.h | 0 .../Customizations/FlowNode_CustomInputDetails.cpp | 0 .../Customizations/FlowNode_CustomInputDetails.h | 0 .../Customizations/FlowNode_CustomOutputDetails.cpp | 0 .../Customizations/FlowNode_CustomOutputDetails.h | 0 .../Customizations/FlowNode_Details.cpp | 0 .../{Graph => Nodes}/Customizations/FlowNode_Details.h | 0 .../FlowNode_PlayLevelSequenceDetails.cpp | 2 +- .../Customizations/FlowNode_PlayLevelSequenceDetails.h | 0 11 files changed, 7 insertions(+), 7 deletions(-) rename Source/FlowEditor/Private/{Graph => Nodes}/Customizations/FlowNode_ComponentObserverDetails.cpp (85%) rename Source/FlowEditor/Private/{Graph => Nodes}/Customizations/FlowNode_ComponentObserverDetails.h (100%) rename Source/FlowEditor/Private/{Graph => Nodes}/Customizations/FlowNode_CustomInputDetails.cpp (100%) rename Source/FlowEditor/Private/{Graph => Nodes}/Customizations/FlowNode_CustomInputDetails.h (100%) rename Source/FlowEditor/Private/{Graph => Nodes}/Customizations/FlowNode_CustomOutputDetails.cpp (100%) rename Source/FlowEditor/Private/{Graph => Nodes}/Customizations/FlowNode_CustomOutputDetails.h (100%) rename Source/FlowEditor/Private/{Graph => Nodes}/Customizations/FlowNode_Details.cpp (100%) rename Source/FlowEditor/Private/{Graph => Nodes}/Customizations/FlowNode_Details.h (100%) rename Source/FlowEditor/Private/{Graph => Nodes}/Customizations/FlowNode_PlayLevelSequenceDetails.cpp (85%) rename Source/FlowEditor/Private/{Graph => Nodes}/Customizations/FlowNode_PlayLevelSequenceDetails.h (100%) diff --git a/Source/FlowEditor/Private/FlowEditorModule.cpp b/Source/FlowEditor/Private/FlowEditorModule.cpp index 5864ae443..f2fdf4333 100644 --- a/Source/FlowEditor/Private/FlowEditorModule.cpp +++ b/Source/FlowEditor/Private/FlowEditorModule.cpp @@ -4,15 +4,15 @@ #include "Asset/AssetTypeActions_FlowAsset.h" #include "Asset/FlowAssetDetails.h" #include "Asset/FlowAssetEditor.h" -#include "Graph/Customizations/FlowNode_Details.h" -#include "Graph/Customizations/FlowNode_ComponentObserverDetails.h" -#include "Graph/Customizations/FlowNode_CustomInputDetails.h" -#include "Graph/Customizations/FlowNode_CustomOutputDetails.h" -#include "Graph/Customizations/FlowNode_PlayLevelSequenceDetails.h" #include "Graph/FlowGraphConnectionDrawingPolicy.h" #include "LevelEditor/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 "FlowAsset.h" #include "Nodes/Route/FlowNode_CustomInput.h" diff --git a/Source/FlowEditor/Private/Graph/Customizations/FlowNode_ComponentObserverDetails.cpp b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_ComponentObserverDetails.cpp similarity index 85% rename from Source/FlowEditor/Private/Graph/Customizations/FlowNode_ComponentObserverDetails.cpp rename to Source/FlowEditor/Private/Nodes/Customizations/FlowNode_ComponentObserverDetails.cpp index a20c5e2c7..5ddf96576 100644 --- a/Source/FlowEditor/Private/Graph/Customizations/FlowNode_ComponentObserverDetails.cpp +++ b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_ComponentObserverDetails.cpp @@ -1,4 +1,4 @@ -#include "Graph/Customizations/FlowNode_ComponentObserverDetails.h" +#include "FlowNode_ComponentObserverDetails.h" #include "Nodes/World/FlowNode_ComponentObserver.h" #include "DetailCategoryBuilder.h" diff --git a/Source/FlowEditor/Private/Graph/Customizations/FlowNode_ComponentObserverDetails.h b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_ComponentObserverDetails.h similarity index 100% rename from Source/FlowEditor/Private/Graph/Customizations/FlowNode_ComponentObserverDetails.h rename to Source/FlowEditor/Private/Nodes/Customizations/FlowNode_ComponentObserverDetails.h diff --git a/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomInputDetails.cpp b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomInputDetails.cpp similarity index 100% rename from Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomInputDetails.cpp rename to Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomInputDetails.cpp diff --git a/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomInputDetails.h b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomInputDetails.h similarity index 100% rename from Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomInputDetails.h rename to Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomInputDetails.h diff --git a/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomOutputDetails.cpp b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomOutputDetails.cpp similarity index 100% rename from Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomOutputDetails.cpp rename to Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomOutputDetails.cpp diff --git a/Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomOutputDetails.h b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomOutputDetails.h similarity index 100% rename from Source/FlowEditor/Private/Graph/Customizations/FlowNode_CustomOutputDetails.h rename to Source/FlowEditor/Private/Nodes/Customizations/FlowNode_CustomOutputDetails.h diff --git a/Source/FlowEditor/Private/Graph/Customizations/FlowNode_Details.cpp b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_Details.cpp similarity index 100% rename from Source/FlowEditor/Private/Graph/Customizations/FlowNode_Details.cpp rename to Source/FlowEditor/Private/Nodes/Customizations/FlowNode_Details.cpp diff --git a/Source/FlowEditor/Private/Graph/Customizations/FlowNode_Details.h b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_Details.h similarity index 100% rename from Source/FlowEditor/Private/Graph/Customizations/FlowNode_Details.h rename to Source/FlowEditor/Private/Nodes/Customizations/FlowNode_Details.h diff --git a/Source/FlowEditor/Private/Graph/Customizations/FlowNode_PlayLevelSequenceDetails.cpp b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.cpp similarity index 85% rename from Source/FlowEditor/Private/Graph/Customizations/FlowNode_PlayLevelSequenceDetails.cpp rename to Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.cpp index 22219f672..c95540ee3 100644 --- a/Source/FlowEditor/Private/Graph/Customizations/FlowNode_PlayLevelSequenceDetails.cpp +++ b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.cpp @@ -1,4 +1,4 @@ -#include "Graph/Customizations/FlowNode_PlayLevelSequenceDetails.h" +#include "FlowNode_PlayLevelSequenceDetails.h" #include "Nodes/World/FlowNode_PlayLevelSequence.h" #include "DetailCategoryBuilder.h" diff --git a/Source/FlowEditor/Private/Graph/Customizations/FlowNode_PlayLevelSequenceDetails.h b/Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.h similarity index 100% rename from Source/FlowEditor/Private/Graph/Customizations/FlowNode_PlayLevelSequenceDetails.h rename to Source/FlowEditor/Private/Nodes/Customizations/FlowNode_PlayLevelSequenceDetails.h From db255fc28ba7c9322376584e0187f611e9d255c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Sat, 10 Apr 2021 16:23:51 +0200 Subject: [PATCH 067/265] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f37070d22..c84ba017d 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,10 @@ 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. * Licensed under MIT license. You are free to use it for commercial projects, modify it however you see fit, and distribute it further. -* This a fresh repository, extracted plugin itself from [the legacy repository](https://github.com/MothCocoon/Flow). Also created the 2nd repository where I gonna put sample modues containting quest or dialogue systems: [FlowSamples](https://github.com/MothCocoon/FlowSamples) + +## Getting started +* It's easy to include pluing in your own project, follow this short [Getting Started](https://github.com/MothCocoon/FlowGraph/wiki/Getting-Started) guide. +* The [legacy repository](https://github.com/MothCocoon/Flow) gonna be upgraded in future, so it would includ FlowGraph (this repo) and FlowSamples as git submodules. ## Concept It's s design-agnostic event node editor. @@ -25,9 +28,6 @@ This 24-minute presentation breaks down the concept of the Flow Graph. It goes t [![Introducing Flow Graph for Unreal Engine](https://img.youtube.com/vi/Rj76JP1f-I4/0.jpg)](https://www.youtube.com/watch?v=Rj76JP1f-I4) -## Getting started -It's simple, follow this short [Getting Started](https://github.com/MothCocoon/FlowGraph/wiki/Getting-Started) guide. - ## Simplicity is a key * It's all about simplifying the cooperation between gameplay programmers and content designers by providing a clean interface between "code of systems" and "using systems". * Code of gameplay mechanics wouldn't ever be mixed with each other. Usually, system X shouldn't even know about the existence of system Y. Flow Graph is a place to combine features by connecting nodes. From cfdeb59252408452c91c0cb282c454d6e3a2745a Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sat, 10 Apr 2021 22:21:53 +0200 Subject: [PATCH 068/265] #32 Allow blueprint nodes to have user-added numerical inputs --- Source/Flow/Private/Nodes/FlowNode.cpp | 10 ++++++++++ Source/Flow/Public/Nodes/FlowNode.h | 21 ++++++++++++++------- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index f734ac40a..55f1f13f3 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -88,6 +88,16 @@ UFlowAsset* UFlowNode::GetFlowAsset() const return GetOuter() ? Cast(GetOuter()) : nullptr; } +bool UFlowNode::CanUserAddInput() const +{ + return K2_CanUserAddInput(); +} + +bool UFlowNode::CanUserAddOutput() const +{ + return K2_CanUserAddOutput(); +} + #if WITH_EDITOR void UFlowNode::RemoveUserInput() { diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 558fe7217..542d82280 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -58,7 +58,7 @@ DECLARE_DELEGATE(FFlowNodeEvent); #endif /** - * Base Flow Node class + * A Flow Node is UObject-based node designed to handle entire gameplay feature within single node. */ UCLASS(Abstract, Blueprintable, HideCategories = Object) class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInterface @@ -157,13 +157,20 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte virtual TArray GetContextInputs() { return TArray(); } virtual TArray GetContextOutputs() { return TArray(); } - virtual bool CanUserAddInput() const { return false; } - virtual bool CanUserAddOutput() const { return false; } + virtual bool CanUserAddInput() const; + virtual bool CanUserAddOutput() const; void RemoveUserInput(); void RemoveUserOutput(); #endif +protected: + UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "CanUserAddInput")) + bool K2_CanUserAddInput() const; + + UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "CanUserAddOutput")) + bool K2_CanUserAddOutput() const; + protected: // always use default range for nodes with user-created outputs i.e. Execution Sequence void SetNumericalInputs(const uint8 FirstNumber = 0, const uint8 LastNumber = 1); @@ -223,7 +230,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")) - void K2_InitializeInstance(); + void K2_InitializeInstance(); public: void TriggerPreload(); @@ -331,11 +338,11 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte public: UFUNCTION(BlueprintPure, Category = "FlowNode") - static FString GetIdentityDescription(const FGameplayTagContainer& Tags); - + static FString GetIdentityDescription(const FGameplayTagContainer& Tags); + UFUNCTION(BlueprintPure, Category = "FlowNode") static FString GetNotifyDescription(const FGameplayTagContainer& Tags); - + UFUNCTION(BlueprintPure, Category = "FlowNode") static FString GetProgressAsString(float Value); From 475d8e9d5d88a2d7b9e8ab14a1657b3b3d16e930 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sat, 10 Apr 2021 22:39:05 +0200 Subject: [PATCH 069/265] non-editor build fix --- 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 55f1f13f3..3826788dc 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -88,6 +88,7 @@ UFlowAsset* UFlowNode::GetFlowAsset() const return GetOuter() ? Cast(GetOuter()) : nullptr; } +#if WITH_EDITOR bool UFlowNode::CanUserAddInput() const { return K2_CanUserAddInput(); @@ -98,7 +99,6 @@ bool UFlowNode::CanUserAddOutput() const return K2_CanUserAddOutput(); } -#if WITH_EDITOR void UFlowNode::RemoveUserInput() { Modify(); From 350389441872561ea9145573878bd3a6d89488fd Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 11 Apr 2021 15:37:00 +0200 Subject: [PATCH 070/265] default log message --- Source/Flow/Private/Nodes/Utils/FlowNode_Log.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Flow/Private/Nodes/Utils/FlowNode_Log.cpp b/Source/Flow/Private/Nodes/Utils/FlowNode_Log.cpp index 8a504f712..01fb7fdbc 100644 --- a/Source/Flow/Private/Nodes/Utils/FlowNode_Log.cpp +++ b/Source/Flow/Private/Nodes/Utils/FlowNode_Log.cpp @@ -5,6 +5,7 @@ UFlowNode_Log::UFlowNode_Log(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) + , Message(TEXT("Log!")) , bPrintToScreen(true) , Duration(5.0f) , TextColor(FColor::Yellow) From 8160952de229fb1dd03c1269f6d4e5dc61d4a97f Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sat, 17 Apr 2021 18:57:35 +0200 Subject: [PATCH 071/265] added virtual GetNodeTitleColor() to runtime Flow Node allows to set different node color per node instance --- Source/Flow/Public/Nodes/FlowNode.h | 3 +++ .../FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp | 10 ++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 542d82280..69d4f29f1 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -105,6 +105,9 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte virtual FText GetTitle() const { return GetClass()->GetDisplayNameText(); } + // 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; } + // Short summary of node's content - displayed over node as NodeInfoPopup virtual FString GetNodeDescription() const; #endif diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index db8008a4a..7ebc8a769 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -554,9 +554,15 @@ FLinearColor UFlowGraphNode::GetNodeTitleColor() const { if (FlowNode) { - if (const FLinearColor* Color = UFlowGraphSettings::Get()->NodeTitleColors.Find(FlowNode->GetNodeStyle())) + FLinearColor DynamicColor; + if (FlowNode->GetNodeTitleColor(DynamicColor)) { - return *Color; + return DynamicColor; + } + + if (const FLinearColor* StyleColor = UFlowGraphSettings::Get()->NodeTitleColors.Find(FlowNode->GetNodeStyle())) + { + return *StyleColor; } } From 343561a879330d33448eab0dc2b650cf06162c89 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 18 Apr 2021 22:11:18 +0200 Subject: [PATCH 072/265] #8 Flow Node pins refactored to structs - pins can have tooltips now! - will be very useful while implementing variables support --- Source/Flow/Private/Nodes/FlowNode.cpp | 207 ++++++++++++------ Source/Flow/Private/Nodes/FlowPin.cpp | 29 +++ .../Nodes/Operators/FlowNode_LogicalAND.cpp | 4 +- .../Nodes/Operators/FlowNode_LogicalOR.cpp | 2 +- .../Private/Nodes/Route/FlowNode_Counter.cpp | 18 +- .../Nodes/Route/FlowNode_CustomInput.cpp | 2 +- .../Nodes/Route/FlowNode_CustomOutput.cpp | 2 +- .../Route/FlowNode_ExecutionMultiGate.cpp | 20 +- .../Route/FlowNode_ExecutionSequence.cpp | 6 +- .../Private/Nodes/Route/FlowNode_Finish.cpp | 2 +- .../Private/Nodes/Route/FlowNode_Start.cpp | 2 +- .../Private/Nodes/Route/FlowNode_SubGraph.cpp | 8 +- .../Private/Nodes/Route/FlowNode_Timer.cpp | 10 +- .../World/FlowNode_ComponentObserver.cpp | 6 +- .../Nodes/World/FlowNode_NotifyActor.cpp | 2 +- .../World/FlowNode_OnNotifyFromActor.cpp | 2 +- .../World/FlowNode_PlayLevelSequence.cpp | 16 +- Source/Flow/Public/Nodes/FlowNode.h | 98 ++++----- Source/Flow/Public/Nodes/FlowPin.h | 142 ++++++++++++ .../Public/Nodes/Route/FlowNode_SubGraph.h | 4 +- .../Private/Asset/FlowAssetDetails.cpp | 20 +- .../Private/Asset/FlowAssetDetails.h | 4 +- .../FlowEditor/Private/FlowEditorModule.cpp | 14 ++ .../Private/Graph/Nodes/FlowGraphNode.cpp | 81 +++++-- .../Private/Graph/Widgets/SFlowGraphNode.cpp | 51 +---- .../Customizations/FlowPinCustomization.cpp | 77 +++++++ .../Customizations/FlowPinCustomization.h | 20 ++ Source/FlowEditor/Public/FlowEditorModule.h | 1 + .../Public/Graph/Nodes/FlowGraphNode.h | 9 +- .../Public/Graph/Widgets/SFlowGraphNode.h | 4 - 30 files changed, 597 insertions(+), 266 deletions(-) create mode 100644 Source/Flow/Private/Nodes/FlowPin.cpp create mode 100644 Source/Flow/Public/Nodes/FlowPin.h create mode 100644 Source/FlowEditor/Private/Nodes/Customizations/FlowPinCustomization.cpp create mode 100644 Source/FlowEditor/Private/Nodes/Customizations/FlowPinCustomization.h diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 3826788dc..926e572c8 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -10,37 +10,14 @@ #include "Misc/App.h" #include "Misc/Paths.h" -FName UFlowNode::DefaultInputName(TEXT("In")); -FName UFlowNode::DefaultOutputName(TEXT("Out")); +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!"); -#if !UE_BUILD_SHIPPING -FPinRecord::FPinRecord() -{ - Time = 0.0f; - HumanReadableTime = FString(); -} - -FPinRecord::FPinRecord(const double InTime) -{ - Time = InTime; - - const FDateTime SystemTime(FDateTime::Now()); - HumanReadableTime = DoubleDigit(SystemTime.GetHour()) + TEXT(".") - + DoubleDigit(SystemTime.GetMinute()) + TEXT(".") - + DoubleDigit(SystemTime.GetSecond()) + TEXT(":") - + DoubleDigit(SystemTime.GetMillisecond()).Left(3); -} - -FORCEINLINE FString FPinRecord::DoubleDigit(const int32 Number) -{ - return Number > 9 ? FString::FromInt(Number) : TEXT("0") + FString::FromInt(Number); -} -#endif - UFlowNode::UFlowNode(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) #if WITH_EDITOR @@ -56,8 +33,8 @@ UFlowNode::UFlowNode(const FObjectInitializer& ObjectInitializer) NodeStyle = EFlowNodeStyle::Default; #endif - InputNames = {DefaultInputName}; - OutputNames = {DefaultOutputName}; + InputPins = {DefaultInputPin}; + OutputPins = {DefaultOutputPin}; } #if WITH_EDITOR @@ -66,12 +43,34 @@ void UFlowNode::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEve Super::PostEditChangeProperty(PropertyChangedEvent); if (PropertyChangedEvent.Property - && (PropertyChangedEvent.GetPropertyName() == GET_MEMBER_NAME_CHECKED(UFlowNode, InputNames) || PropertyChangedEvent.GetPropertyName() == GET_MEMBER_NAME_CHECKED(UFlowNode, OutputNames))) + && (PropertyChangedEvent.GetPropertyName() == GET_MEMBER_NAME_CHECKED(UFlowNode, InputPins) || PropertyChangedEvent.GetPropertyName() == GET_MEMBER_NAME_CHECKED(UFlowNode, OutputPins))) { OnReconstructionRequested.ExecuteIfBound(); } } +void UFlowNode::FixNode(UEdGraphNode* NewGraph) +{ + // Fix any node pointers that may be out of date + GraphNode = NewGraph; + + // 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) { GraphNode = NewGraph; @@ -88,49 +87,91 @@ UFlowAsset* UFlowNode::GetFlowAsset() const return GetOuter() ? Cast(GetOuter()) : nullptr; } -#if WITH_EDITOR -bool UFlowNode::CanUserAddInput() const +void UFlowNode::AddInputPins(TArray PinNames) { - return K2_CanUserAddInput(); + for (const FName& PinName : PinNames) + { + InputPins.Emplace(PinName); + } } -bool UFlowNode::CanUserAddOutput() const +void UFlowNode::AddOutputPins(TArray PinNames) { - return K2_CanUserAddOutput(); + for (const FName& PinName : PinNames) + { + OutputPins.Emplace(PinName); + } } -void UFlowNode::RemoveUserInput() +void UFlowNode::SetNumberedInputPins(const uint8 FirstNumber, const uint8 LastNumber) { - Modify(); - InputNames.RemoveAt(InputNames.Num() - 1); -} + InputPins.Empty(); -void UFlowNode::RemoveUserOutput() -{ - Modify(); - OutputNames.RemoveAt(OutputNames.Num() - 1); + for (uint8 i = FirstNumber; i <= LastNumber; i++) + { + InputPins.Emplace(i); + } } -#endif -void UFlowNode::SetNumericalInputs(const uint8 FirstNumber, const uint8 LastNumber) +void UFlowNode::SetNumberedOutputPins(const uint8 FirstNumber /*= 0*/, const uint8 LastNumber /*= 1*/) { - InputNames.Empty(); + OutputPins.Empty(); for (uint8 i = FirstNumber; i <= LastNumber; i++) { - InputNames.Emplace(FName(*FString::FromInt(i))); + OutputPins.Emplace(i); } } -void UFlowNode::SetNumericalOutputs(const uint8 FirstNumber /*= 0*/, const uint8 LastNumber /*= 1*/) +TArray UFlowNode::GetInputNames() const { - OutputNames.Empty(); + TArray Result; + for (const FFlowPin& Pin : InputPins) + { + if (!Pin.PinName.IsNone()) + { + Result.Emplace(Pin.PinName); + } + } + return Result; +} - for (uint8 i = FirstNumber; i <= LastNumber; i++) +TArray UFlowNode::GetOutputNames() const +{ + TArray Result; + for (const FFlowPin& Pin : OutputPins) { - OutputNames.Emplace(FName(*FString::FromInt(i))); + if (!Pin.PinName.IsNone()) + { + Result.Emplace(Pin.PinName); + } } + return Result; +} + +#if WITH_EDITOR +bool UFlowNode::CanUserAddInput() const +{ + return K2_CanUserAddInput(); +} + +bool UFlowNode::CanUserAddOutput() const +{ + return K2_CanUserAddOutput(); +} + +void UFlowNode::RemoveUserInput() +{ + Modify(); + InputPins.RemoveAt(InputPins.Num() - 1); +} + +void UFlowNode::RemoveUserOutput() +{ + Modify(); + OutputPins.RemoveAt(OutputPins.Num() - 1); } +#endif TSet UFlowNode::GetConnectedNodes() const { @@ -209,10 +250,10 @@ void UFlowNode::FlushContent() void UFlowNode::TriggerInput(const FName& PinName) { - ensureAlways(InputNames.Num() > 0); + ensureAlways(InputPins.Num() > 0); #if !UE_BUILD_SHIPPING - if (InputNames.Contains(PinName)) + if (InputPins.Contains(PinName)) { // record for debugging TArray& Records = InputRecords.FindOrAdd(PinName); @@ -223,7 +264,7 @@ void UFlowNode::TriggerInput(const FName& PinName) #if WITH_EDITOR if (GetWorld()->WorldType == EWorldType::PIE && UFlowAsset::GetFlowGraphInterface().IsValid()) { - UFlowAsset::GetFlowGraphInterface()->OnInputTriggered(GraphNode, InputNames.IndexOfByKey(PinName)); + UFlowAsset::GetFlowGraphInterface()->OnInputTriggered(GraphNode, InputPins.IndexOfByKey(PinName)); } #endif // WITH_EDITOR } @@ -243,18 +284,18 @@ void UFlowNode::ExecuteInput(const FName& PinName) void UFlowNode::TriggerFirstOutput(const bool bFinish) { - if (OutputNames.Num() > 0) + if (OutputPins.Num() > 0) { - TriggerOutput(OutputNames[0], bFinish); + TriggerOutput(OutputPins[0].PinName, bFinish); } } void UFlowNode::TriggerOutput(const FName& PinName, const bool bFinish /*= false*/) { - ensureAlways(OutputNames.Num() > 0); + ensureAlways(OutputPins.Num() > 0); #if !UE_BUILD_SHIPPING - if (OutputNames.Contains(PinName)) + if (OutputPins.Contains(PinName)) { // record for debugging, even if nothing is connected to this pin TArray& Records = OutputRecords.FindOrAdd(PinName); @@ -263,7 +304,7 @@ void UFlowNode::TriggerOutput(const FName& PinName, const bool bFinish /*= false #if WITH_EDITOR if (GetWorld()->WorldType == EWorldType::PIE && UFlowAsset::GetFlowGraphInterface().IsValid()) { - UFlowAsset::GetFlowGraphInterface()->OnOutputTriggered(GraphNode, OutputNames.IndexOfByKey(PinName)); + UFlowAsset::GetFlowGraphInterface()->OnOutputTriggered(GraphNode, OutputPins.IndexOfByKey(PinName)); } #endif // WITH_EDITOR } @@ -280,13 +321,28 @@ void UFlowNode::TriggerOutput(const FName& PinName, const bool bFinish /*= false } // call the next node - if (OutputNames.Contains(PinName) && Connections.Contains(PinName)) + if (OutputPins.Contains(PinName) && Connections.Contains(PinName)) { const FConnectedPin FlowPin = GetConnection(PinName); GetFlowAsset()->TriggerInput(FlowPin.NodeGuid, FlowPin.PinName); } } +void UFlowNode::TriggerOutput(const FString& PinName, const bool bFinish) +{ + TriggerOutput(*PinName, bFinish); +} + +void UFlowNode::TriggerOutput(const FText& PinName, const bool bFinish) +{ + TriggerOutput(*PinName.ToString(), bFinish); +} + +void UFlowNode::TriggerOutput(const TCHAR* PinName, const bool bFinish) +{ + TriggerOutput(FName(PinName), bFinish); +} + void UFlowNode::Finish() { Deactivate(); @@ -337,19 +393,22 @@ TMap UFlowNode::GetWireRecords() const TMap Result; for (const TPair>& Record : OutputRecords) { - Result.Emplace(OutputNames.IndexOfByKey(Record.Key), Record.Value.Last()); + Result.Emplace(OutputPins.IndexOfByKey(Record.Key), Record.Value.Last()); } return Result; } -TArray UFlowNode::GetInputRecords(const FName& PinName) const -{ - return InputRecords.FindRef(PinName); -} - -TArray UFlowNode::GetOutputRecords(const FName& PinName) const +TArray UFlowNode::GetPinRecords(const FName& PinName, const EEdGraphPinDirection PinDirection) const { - return OutputRecords.FindRef(PinName); + switch (PinDirection) + { + case EGPD_Input: + return InputRecords.FindRef(PinName); + case EGPD_Output: + return OutputRecords.FindRef(PinName); + default: + return TArray(); + } } FString UFlowNode::GetStatusString() const @@ -373,16 +432,26 @@ AActor* UFlowNode::GetActorToFocus() } #endif -FString UFlowNode::GetIdentityDescription(const FGameplayTagContainer& Tags) +FString UFlowNode::GetIdentityTagDescription(const FGameplayTag& Tag) +{ + return Tag.IsValid() ? Tag.ToString() : MissingIdentityTag; +} + +FString UFlowNode::GetIdentityTagsDescription(const FGameplayTagContainer& Tags) { return Tags.IsEmpty() ? MissingIdentityTag : FString::JoinBy(Tags, LINE_TERMINATOR, [](const FGameplayTag& Tag) { return Tag.ToString(); }); } -FString UFlowNode::GetNotifyDescription(const FGameplayTagContainer& Tags) +FString UFlowNode::GetNotifyTagsDescription(const FGameplayTagContainer& Tags) { return Tags.IsEmpty() ? MissingNotifyTag : FString::JoinBy(Tags, LINE_TERMINATOR, [](const FGameplayTag& Tag) { return Tag.ToString(); }); } +FString UFlowNode::GetClassDescription(const TSubclassOf Class) +{ + return Class ? Class->GetName() : MissingClass; +} + FString UFlowNode::GetProgressAsString(float Value) { // Avoids negative zero diff --git a/Source/Flow/Private/Nodes/FlowPin.cpp b/Source/Flow/Private/Nodes/FlowPin.cpp new file mode 100644 index 000000000..8faca4ae1 --- /dev/null +++ b/Source/Flow/Private/Nodes/FlowPin.cpp @@ -0,0 +1,29 @@ +#include "Nodes/FlowPin.h" + +#if !UE_BUILD_SHIPPING + +FString FPinRecord::NoActivations = TEXT("No activations"); +FString FPinRecord::PinActivations = TEXT("Pin activations"); + +FPinRecord::FPinRecord() +{ + Time = 0.0f; + HumanReadableTime = FString(); +} + +FPinRecord::FPinRecord(const double InTime) +{ + Time = InTime; + + const FDateTime SystemTime(FDateTime::Now()); + HumanReadableTime = DoubleDigit(SystemTime.GetHour()) + TEXT(".") + + DoubleDigit(SystemTime.GetMinute()) + TEXT(".") + + DoubleDigit(SystemTime.GetSecond()) + TEXT(":") + + DoubleDigit(SystemTime.GetMillisecond()).Left(3); +} + +FORCEINLINE FString FPinRecord::DoubleDigit(const int32 Number) +{ + return Number > 9 ? FString::FromInt(Number) : TEXT("0") + FString::FromInt(Number); +} +#endif diff --git a/Source/Flow/Private/Nodes/Operators/FlowNode_LogicalAND.cpp b/Source/Flow/Private/Nodes/Operators/FlowNode_LogicalAND.cpp index 35b0d8386..4d57bc96a 100644 --- a/Source/Flow/Private/Nodes/Operators/FlowNode_LogicalAND.cpp +++ b/Source/Flow/Private/Nodes/Operators/FlowNode_LogicalAND.cpp @@ -8,14 +8,14 @@ UFlowNode_LogicalAND::UFlowNode_LogicalAND(const FObjectInitializer& ObjectIniti NodeStyle = EFlowNodeStyle::Logic; #endif - SetNumericalInputs(0, 1); + SetNumberedInputPins(0, 1); } void UFlowNode_LogicalAND::ExecuteInput(const FName& PinName) { ExecutedInputNames.Add(PinName); - if (ExecutedInputNames.Num() == InputNames.Num()) + if (ExecutedInputNames.Num() == InputPins.Num()) { TriggerFirstOutput(true); } diff --git a/Source/Flow/Private/Nodes/Operators/FlowNode_LogicalOR.cpp b/Source/Flow/Private/Nodes/Operators/FlowNode_LogicalOR.cpp index 4a577dab3..5b1dcc0ad 100644 --- a/Source/Flow/Private/Nodes/Operators/FlowNode_LogicalOR.cpp +++ b/Source/Flow/Private/Nodes/Operators/FlowNode_LogicalOR.cpp @@ -8,7 +8,7 @@ UFlowNode_LogicalOR::UFlowNode_LogicalOR(const FObjectInitializer& ObjectInitial NodeStyle = EFlowNodeStyle::Logic; #endif - SetNumericalInputs(0, 1); + SetNumberedInputPins(0, 1); } void UFlowNode_LogicalOR::ExecuteInput(const FName& PinName) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_Counter.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_Counter.cpp index bc2862c7d..8ab4dd443 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_Counter.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_Counter.cpp @@ -10,16 +10,16 @@ UFlowNode_Counter::UFlowNode_Counter(const FObjectInitializer& ObjectInitializer NodeStyle = EFlowNodeStyle::Condition; #endif - InputNames.Empty(); - InputNames.Add(TEXT("Increment")); - InputNames.Add(TEXT("Decrement")); - InputNames.Add(TEXT("Skip")); + InputPins.Empty(); + InputPins.Add(FFlowPin(TEXT("Increment"))); + InputPins.Add(FFlowPin(TEXT("Decrement"))); + InputPins.Add(FFlowPin(TEXT("Skip"))); - OutputNames.Empty(); - OutputNames.Add(TEXT("Zero")); - OutputNames.Add(TEXT("Step")); - OutputNames.Add(TEXT("Goal")); - OutputNames.Add(TEXT("Skipped")); + OutputPins.Empty(); + OutputPins.Add(FFlowPin(TEXT("Zero"))); + OutputPins.Add(FFlowPin(TEXT("Step"))); + OutputPins.Add(FFlowPin(TEXT("Goal"))); + OutputPins.Add(FFlowPin(TEXT("Skipped"))); } void UFlowNode_Counter::ExecuteInput(const FName& PinName) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp index 9dc05d7cf..06a61ae40 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_CustomInput.cpp @@ -8,7 +8,7 @@ UFlowNode_CustomInput::UFlowNode_CustomInput(const FObjectInitializer& ObjectIni NodeStyle = EFlowNodeStyle::InOut; #endif - InputNames.Empty(); + InputPins.Empty(); } 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 deb3ed604..64d907f3e 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_CustomOutput.cpp @@ -11,7 +11,7 @@ UFlowNode_CustomOutput::UFlowNode_CustomOutput(const FObjectInitializer& ObjectI NodeStyle = EFlowNodeStyle::InOut; #endif - OutputNames.Empty(); + OutputPins.Empty(); } 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 f4c9cdf0e..0b8858177 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionMultiGate.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionMultiGate.cpp @@ -9,17 +9,21 @@ UFlowNode_ExecutionMultiGate::UFlowNode_ExecutionMultiGate(const FObjectInitiali NodeStyle = EFlowNodeStyle::Logic; #endif - InputNames.Add(TEXT("Reset")); - SetNumericalOutputs(0, 1); + FString ResetPinTooltip = TEXT("Finish work of this node."); + ResetPinTooltip += LINE_TERMINATOR; + ResetPinTooltip += TEXT("Calling In input will start triggering output pins once again."); + + InputPins.Add(FFlowPin(TEXT("Reset"), ResetPinTooltip)); + SetNumberedOutputPins(0, 1); } void UFlowNode_ExecutionMultiGate::ExecuteInput(const FName& PinName) { - if (PinName == DefaultInputName) + if (PinName == DefaultInputPin.PinName) { if (Completed.Num() == 0) { - Completed.Init(false, OutputNames.Num()); + Completed.Init(false, OutputPins.Num()); } if (!Completed.Contains(false)) @@ -54,7 +58,7 @@ void UFlowNode_ExecutionMultiGate::ExecuteInput(const FName& PinName) } Completed[Index] = true; - TriggerOutput(OutputNames[Index], false); + TriggerOutput(OutputPins[Index].PinName, false); } else { @@ -66,10 +70,10 @@ void UFlowNode_ExecutionMultiGate::ExecuteInput(const FName& PinName) const int32 CurrentOutput = NextOutput; // We have to calculate NextOutput before TriggerOutput(..) // TriggerOutput may call Reset and Cleanup - NextOutput = ++NextOutput % OutputNames.Num(); + NextOutput = ++NextOutput % OutputPins.Num(); Completed[CurrentOutput] = true; - TriggerOutput(OutputNames[CurrentOutput], false); + TriggerOutput(OutputPins[CurrentOutput].PinName, false); } if (!Completed.Contains(false) && bLoop) @@ -117,7 +121,7 @@ FString UFlowNode_ExecutionMultiGate::GetNodeDescription() const Result.Append(TEXT(", ")); } - if (OutputNames.IsValidIndex(StartIndex)) + if (OutputPins.IsValidIndex(StartIndex)) { Result.Appendf(TEXT("Start Index: %d"), StartIndex); } diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionSequence.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionSequence.cpp index cae9d2e78..4aacc2667 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionSequence.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionSequence.cpp @@ -8,14 +8,14 @@ UFlowNode_ExecutionSequence::UFlowNode_ExecutionSequence(const FObjectInitialize NodeStyle = EFlowNodeStyle::Logic; #endif - SetNumericalOutputs(0, 1); + SetNumberedOutputPins(0, 1); } void UFlowNode_ExecutionSequence::ExecuteInput(const FName& PinName) { - for (const FName& Output : OutputNames) + for (const FFlowPin& Output : OutputPins) { - TriggerOutput(Output, false); + TriggerOutput(Output.PinName, false); } Finish(); diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_Finish.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_Finish.cpp index b6ee9c018..9012dec8b 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_Finish.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_Finish.cpp @@ -8,7 +8,7 @@ UFlowNode_Finish::UFlowNode_Finish(const FObjectInitializer& ObjectInitializer) NodeStyle = EFlowNodeStyle::InOut; #endif - OutputNames = {}; + OutputPins = {}; } void UFlowNode_Finish::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 b3a457ffb..4334f0451 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_Start.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_Start.cpp @@ -8,7 +8,7 @@ UFlowNode_Start::UFlowNode_Start(const FObjectInitializer& ObjectInitializer) NodeStyle = EFlowNodeStyle::InOut; #endif - InputNames = {}; + InputPins = {}; } void UFlowNode_Start::ExecuteInput(const FName& PinName) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp index a56bd8623..f85c3b7d6 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp @@ -3,8 +3,8 @@ #include "FlowAsset.h" #include "FlowSubsystem.h" -FName UFlowNode_SubGraph::StartPinName(TEXT("Start")); -FName UFlowNode_SubGraph::FinishPinName(TEXT("Finish")); +FFlowPin UFlowNode_SubGraph::StartPin(TEXT("Start")); +FFlowPin UFlowNode_SubGraph::FinishPin(TEXT("Finish")); UFlowNode_SubGraph::UFlowNode_SubGraph(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) @@ -14,8 +14,8 @@ UFlowNode_SubGraph::UFlowNode_SubGraph(const FObjectInitializer& ObjectInitializ NodeStyle = EFlowNodeStyle::SubGraph; #endif - InputNames = {StartPinName}; - OutputNames = {FinishPinName}; + InputPins = {StartPin}; + OutputPins = {FinishPin}; } void UFlowNode_SubGraph::PreloadContent() diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp index 0ff872428..1252b1ac1 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp @@ -14,12 +14,12 @@ UFlowNode_Timer::UFlowNode_Timer(const FObjectInitializer& ObjectInitializer) NodeStyle = EFlowNodeStyle::Latent; #endif - InputNames.Add(TEXT("Skip")); + InputPins.Add(FFlowPin(TEXT("Skip"))); - OutputNames.Empty(); - OutputNames.Add(TEXT("Completed")); - OutputNames.Add(TEXT("Step")); - OutputNames.Add(TEXT("Skipped")); + OutputPins.Empty(); + OutputPins.Add(FFlowPin(TEXT("Completed"))); + OutputPins.Add(FFlowPin(TEXT("Step"))); + OutputPins.Add(FFlowPin(TEXT("Skipped"))); } void UFlowNode_Timer::ExecuteInput(const FName& PinName) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp index 005e260dd..3e745b841 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp @@ -11,8 +11,8 @@ UFlowNode_ComponentObserver::UFlowNode_ComponentObserver(const FObjectInitialize Category = TEXT("World"); #endif - InputNames = {TEXT("Start"), TEXT("Stop")}; - OutputNames = {TEXT("Success"), TEXT("Completed"), TEXT("Stopped")}; + InputPins = {FFlowPin(TEXT("Start")), FFlowPin(TEXT("Stop"))}; + OutputPins = {FFlowPin(TEXT("Success")), FFlowPin(TEXT("Completed")), FFlowPin(TEXT("Stopped"))}; } void UFlowNode_ComponentObserver::PostLoad() @@ -125,7 +125,7 @@ void UFlowNode_ComponentObserver::Cleanup() #if WITH_EDITOR FString UFlowNode_ComponentObserver::GetNodeDescription() const { - return GetIdentityDescription(IdentityTags); + return GetIdentityTagsDescription(IdentityTags); } FString UFlowNode_ComponentObserver::GetStatusString() const diff --git a/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp b/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp index 1a7be40f5..6f1f67309 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_NotifyActor.cpp @@ -44,6 +44,6 @@ void UFlowNode_NotifyActor::ExecuteInput(const FName& PinName) #if WITH_EDITOR FString UFlowNode_NotifyActor::GetNodeDescription() const { - return GetIdentityDescription(IdentityTags) + LINE_TERMINATOR + GetNotifyDescription(NotifyTags); + return GetIdentityTagsDescription(IdentityTags) + LINE_TERMINATOR + GetNotifyTagsDescription(NotifyTags); } #endif diff --git a/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp b/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp index 8d58d5a15..131128097 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_OnNotifyFromActor.cpp @@ -56,6 +56,6 @@ void UFlowNode_OnNotifyFromActor::OnNotifyFromComponent(UFlowComponent* Componen #if WITH_EDITOR FString UFlowNode_OnNotifyFromActor::GetNodeDescription() const { - return GetIdentityDescription(IdentityTags) + LINE_TERMINATOR + GetNotifyDescription(NotifyTags); + return GetIdentityTagsDescription(IdentityTags) + LINE_TERMINATOR + GetNotifyTagsDescription(NotifyTags); } #endif diff --git a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp index cf604768e..c36a7f71d 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp @@ -24,14 +24,14 @@ UFlowNode_PlayLevelSequence::UFlowNode_PlayLevelSequence(const FObjectInitialize NodeStyle = EFlowNodeStyle::Latent; #endif - InputNames.Empty(); - InputNames.Add(TEXT("Start")); - InputNames.Add(TEXT("Stop")); - - OutputNames.Add(TEXT("PreStart")); - OutputNames.Add(TEXT("Started")); - OutputNames.Add(TEXT("Completed")); - OutputNames.Add(TEXT("Stopped")); + InputPins.Empty(); + InputPins.Add(FFlowPin(TEXT("Start"))); + InputPins.Add(FFlowPin(TEXT("Stop"))); + + OutputPins.Add(FFlowPin(TEXT("PreStart"))); + OutputPins.Add(FFlowPin(TEXT("Started"))); + OutputPins.Add(FFlowPin(TEXT("Completed"))); + OutputPins.Add(FFlowPin(TEXT("Stopped"))); } #if WITH_EDITOR diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 69d4f29f1..d8b8d2fc2 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -6,6 +6,7 @@ #include "VisualLogger/VisualLoggerDebugSnapshotInterface.h" #include "FlowTypes.h" +#include "Nodes/FlowPin.h" #include "FlowNode.generated.h" class UEdGraphNode; @@ -13,46 +14,6 @@ class UEdGraphNode; class UFlowAsset; class UFlowSubsystem; -// Processing Flow Nodes creates map of connected pins -USTRUCT() -struct FLOW_API FConnectedPin -{ - GENERATED_USTRUCT_BODY() - - UPROPERTY() - FGuid NodeGuid; - - UPROPERTY() - FName PinName; - - FConnectedPin() - { - NodeGuid = FGuid(); - PinName = NAME_None; - } - - FConnectedPin(const FGuid InNodeId, const FName& InPinName) - { - NodeGuid = InNodeId; - PinName = InPinName; - } -}; - -// 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; - - FPinRecord(); - FPinRecord(const double InTime); - -private: - FORCEINLINE static FString DoubleDigit(const int32 Number); -}; -#endif - #if WITH_EDITOR DECLARE_DELEGATE(FFlowNodeEvent); #endif @@ -90,9 +51,12 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte public: #if WITH_EDITOR - // UObject + // UObject virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; // -- + + // Opportunity to update node's data before UFlowGraphNode would call ReconstructNode() + virtual void FixNode(UEdGraphNode* NewGraph); #endif UEdGraphNode* GetGraphNode() const { return GraphNode; } @@ -132,23 +96,33 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte // All created pins (default, class-specific and added by user) public: - static FName DefaultInputName; - static FName DefaultOutputName; + static FFlowPin DefaultInputPin; + static FFlowPin DefaultOutputPin; protected: // Class-specific and user-added inputs UPROPERTY(EditDefaultsOnly, Category = "FlowNode") - TArray InputNames; + TArray InputPins; // Class-specific and user-added outputs UPROPERTY(EditDefaultsOnly, Category = "FlowNode") - TArray OutputNames; + TArray OutputPins; + + void AddInputPins(TArray PinNames); + void AddOutputPins(TArray PinNames); + + // always use default range for nodes with user-created outputs i.e. Execution Sequence + void SetNumberedInputPins(const uint8 FirstNumber = 0, const uint8 LastNumber = 1); + void SetNumberedOutputPins(const uint8 FirstNumber = 0, const uint8 LastNumber = 1); + + TArray GetInputPins() const { return InputPins; } + TArray GetOutputPins() const { return OutputPins; } UFUNCTION(BlueprintPure, Category = "FlowNode") - TArray GetInputNames() const { return InputNames; } + TArray GetInputNames() const; UFUNCTION(BlueprintPure, Category = "FlowNode") - TArray GetOutputNames() const { return OutputNames; } + TArray GetOutputNames() const; public: #if WITH_EDITOR @@ -174,11 +148,6 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "CanUserAddOutput")) bool K2_CanUserAddOutput() const; -protected: - // always use default range for nodes with user-created outputs i.e. Execution Sequence - void SetNumericalInputs(const uint8 FirstNumber = 0, const uint8 LastNumber = 1); - void SetNumericalOutputs(const uint8 FirstNumber = 0, const uint8 LastNumber = 1); - ////////////////////////////////////////////////////////////////////////// // Connections to other nodes @@ -199,6 +168,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte protected: static FString MissingIdentityTag; static FString MissingNotifyTag; + static FString MissingClass; static FString NoActorsFound; ////////////////////////////////////////////////////////////////////////// @@ -267,6 +237,10 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UFUNCTION(BlueprintCallable, Category = "FlowNode") void TriggerOutput(const FName& PinName, const bool bFinish = false); + 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); + // Finish execution of node, it will call Cleanup UFUNCTION(BlueprintCallable, Category = "FlowNode") void Finish(); @@ -300,8 +274,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte EFlowActivationState GetActivationState() const { return ActivationState; } TMap GetWireRecords() const; - TArray GetInputRecords(const FName& PinName) const; - TArray GetOutputRecords(const FName& PinName) const; + TArray GetPinRecords(const FName& PinName, const EEdGraphPinDirection PinDirection) const; // Information displayed while node is working - displayed over node as NodeInfoPopup virtual FString GetStatusString() const; @@ -341,14 +314,27 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte public: UFUNCTION(BlueprintPure, Category = "FlowNode") - static FString GetIdentityDescription(const FGameplayTagContainer& Tags); + static FString GetIdentityTagDescription(const FGameplayTag& Tag); + + UFUNCTION(BlueprintPure, Category = "FlowNode") + static FString GetIdentityTagsDescription(const FGameplayTagContainer& Tags); + + UFUNCTION(BlueprintPure, Category = "FlowNode") + static FString GetNotifyTagsDescription(const FGameplayTagContainer& Tags); UFUNCTION(BlueprintPure, Category = "FlowNode") - static FString GetNotifyDescription(const FGameplayTagContainer& Tags); + static FString GetClassDescription(const TSubclassOf Class); UFUNCTION(BlueprintPure, Category = "FlowNode") static FString GetProgressAsString(float Value); UFUNCTION(BlueprintCallable, Category = "FlowNode") void LogError(FString Message); + +private: + UPROPERTY() + TArray InputNames_DEPRECATED; + + UPROPERTY() + TArray OutputNames_DEPRECATED; }; diff --git a/Source/Flow/Public/Nodes/FlowPin.h b/Source/Flow/Public/Nodes/FlowPin.h new file mode 100644 index 000000000..116677f8f --- /dev/null +++ b/Source/Flow/Public/Nodes/FlowPin.h @@ -0,0 +1,142 @@ +#pragma once + +#include "FlowPin.generated.h" + +USTRUCT() +struct FLOW_API FFlowPin +{ + GENERATED_BODY() + + UPROPERTY(EditDefaultsOnly, Category = "FlowPin") + FName PinName; + + UPROPERTY(EditDefaultsOnly, Category = "FlowPin") + FString PinToolTip; + + FFlowPin() + : PinName(NAME_None) + { + } + + FFlowPin(const FName& InPinName) + : PinName(InPinName) + { + } + + FFlowPin(const FString& InPinName) + : PinName(*InPinName) + { + } + + FFlowPin(const FText& InPinName) + : PinName(*InPinName.ToString()) + { + } + + FFlowPin(const TCHAR* InPinName) + : PinName(FName(InPinName)) + { + } + + FFlowPin(const uint8& InPinName) + : PinName(FName(*FString::FromInt(InPinName))) + { + } + + FFlowPin(const int32& InPinName) + : PinName(FName(*FString::FromInt(InPinName))) + { + } + + FFlowPin(const FName& InPinName, const FString& InPinTooltip) + : PinName(InPinName) + , PinToolTip(InPinTooltip) + { + } + + FFlowPin(const FString& 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)) + , PinToolTip(InPinTooltip) + { + } + + FORCEINLINE bool IsValid() const + { + return !PinName.IsNone(); + } + + FORCEINLINE bool operator==(const FFlowPin& Other) const + { + return PinName == Other.PinName; + } + + FORCEINLINE bool operator!=(const FFlowPin& Other) const + { + return PinName != Other.PinName; + } + + FORCEINLINE bool operator==(const FName& Other) const + { + return PinName == Other; + } + + FORCEINLINE bool operator!=(const FName& Other) const + { + return PinName != Other; + } +}; + +// Processing Flow Nodes creates map of connected pins +USTRUCT() +struct FLOW_API FConnectedPin +{ + GENERATED_USTRUCT_BODY() + + UPROPERTY() + FGuid NodeGuid; + + UPROPERTY() + FName PinName; + + FConnectedPin() + : NodeGuid(FGuid()) + , PinName(NAME_None) + { + } + + FConnectedPin(const FGuid InNodeId, const FName& InPinName) + : NodeGuid(InNodeId) + , PinName(InPinName) + { + } +}; + +// 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; + + static FString NoActivations; + static FString PinActivations; + + FPinRecord(); + FPinRecord(const double InTime); + + private: + FORCEINLINE static FString DoubleDigit(const int32 Number); +}; +#endif diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h b/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h index 43cb1d125..114743d33 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h @@ -13,8 +13,8 @@ class FLOW_API UFlowNode_SubGraph : public UFlowNode friend class UFlowSubsystem; - static FName StartPinName; - static FName FinishPinName; + static FFlowPin StartPin; + static FFlowPin FinishPin; private: UPROPERTY(EditDefaultsOnly, Category = "Graph") diff --git a/Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp b/Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp index a010a85a2..dee37ae78 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp @@ -43,8 +43,8 @@ void FFlowAssetDetails::GenerateCustomPinArray(TSharedRef Prope [ SNew(SEditableTextBox) .Text(this, &FFlowAssetDetails::GetCustomPinText, PropertyHandle) - .OnVerifyTextChanged_Static(&FFlowAssetDetails::OnCustomPinTextVerifyChanged) - .OnTextCommitted(this, &FFlowAssetDetails::OnCustomPinTextCommited, PropertyHandle) + .OnTextCommitted_Static(&FFlowAssetDetails::OnCustomPinTextCommitted, PropertyHandle) + .OnVerifyTextChanged_Static(&FFlowAssetDetails::VerifyNewCustomPinText) ]; } @@ -56,11 +56,17 @@ FText FFlowAssetDetails::GetCustomPinText(TSharedRef PropertyHa return PropertyValue; } -bool FFlowAssetDetails::OnCustomPinTextVerifyChanged(const FText& InNewText, FText& OutErrorMessage) +void FFlowAssetDetails::OnCustomPinTextCommitted(const FText& InText, ETextCommit::Type InCommitType, TSharedRef PropertyHandle) +{ + const FPropertyAccess::Result SetValueResult = PropertyHandle->SetValueFromFormattedString(InText.ToString()); + ensure(SetValueResult == FPropertyAccess::Success); +} + +bool FFlowAssetDetails::VerifyNewCustomPinText(const FText& InNewText, FText& OutErrorMessage) { const FName NewString = *InNewText.ToString(); - if (NewString == UFlowNode_SubGraph::StartPinName || NewString == UFlowNode_SubGraph::FinishPinName) + if (NewString == UFlowNode_SubGraph::StartPin.PinName || NewString == UFlowNode_SubGraph::FinishPin.PinName) { OutErrorMessage = LOCTEXT("VerifyTextFailed", "This is a standard pin name of Sub Graph node!"); return false; @@ -69,10 +75,4 @@ bool FFlowAssetDetails::OnCustomPinTextVerifyChanged(const FText& InNewText, FTe return true; } -void FFlowAssetDetails::OnCustomPinTextCommited(const FText& InText, ETextCommit::Type InCommitType, TSharedRef PropertyHandle) -{ - const FPropertyAccess::Result SetValueResult = PropertyHandle->SetValueFromFormattedString(InText.ToString()); - ensure(SetValueResult == FPropertyAccess::Success); -} - #undef LOCTEXT_NAMESPACE diff --git a/Source/FlowEditor/Private/Asset/FlowAssetDetails.h b/Source/FlowEditor/Private/Asset/FlowAssetDetails.h index c9b7fdf2b..ccc2d33d8 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetDetails.h +++ b/Source/FlowEditor/Private/Asset/FlowAssetDetails.h @@ -24,6 +24,6 @@ class FFlowAssetDetails final : public IDetailCustomization void GenerateCustomPinArray(TSharedRef PropertyHandle, int32 ArrayIndex, IDetailChildrenBuilder& ChildrenBuilder); FText GetCustomPinText(TSharedRef PropertyHandle) const; - static bool OnCustomPinTextVerifyChanged(const FText& InNewText, FText& OutErrorMessage); - void OnCustomPinTextCommited(const FText& InText, ETextCommit::Type InCommitType, TSharedRef PropertyHandle); + static void OnCustomPinTextCommitted(const FText& InText, ETextCommit::Type InCommitType, TSharedRef PropertyHandle); + static bool VerifyNewCustomPinText(const FText& InNewText, FText& OutErrorMessage); }; diff --git a/Source/FlowEditor/Private/FlowEditorModule.cpp b/Source/FlowEditor/Private/FlowEditorModule.cpp index f2fdf4333..fdc871db6 100644 --- a/Source/FlowEditor/Private/FlowEditorModule.cpp +++ b/Source/FlowEditor/Private/FlowEditorModule.cpp @@ -14,6 +14,8 @@ #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" @@ -56,6 +58,8 @@ 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)); @@ -130,6 +134,16 @@ void FFlowEditorModule::UnregisterAssets() RegisteredAssetActions.Empty(); } +void FFlowEditorModule::RegisterPropertyCustomizations() const +{ + FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked("PropertyEditor"); + + PropertyModule.RegisterCustomPropertyTypeLayout("FlowPin", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FFlowPinCustomization::MakeInstance)); + + // notify on customization change + PropertyModule.NotifyCustomizationModuleChanged(); +} + void FFlowEditorModule::RegisterCustomClassLayout(const TSubclassOf Class, const FOnGetDetailCustomizationInstance DetailLayout) { if (Class) diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 7ebc8a769..5011d2544 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -10,7 +10,6 @@ #include "FlowAsset.h" #include "Nodes/FlowNode.h" -#include "AssetData.h" #include "AssetRegistryModule.h" #include "Developer/ToolMenus/Public/ToolMenus.h" #include "EdGraph/EdGraphSchema.h" @@ -132,10 +131,9 @@ void UFlowGraphNode::PostLoad() { Super::PostLoad(); - // Fix any node pointers that may be out of date if (FlowNode) { - FlowNode->SetGraphNode(this); + FlowNode->FixNode(this); SubscribeToExternalChanges(); } @@ -352,14 +350,14 @@ void UFlowGraphNode::AllocateDefaultPins() if (FlowNode) { - for (const FName& InputName : FlowNode->InputNames) + for (const FFlowPin& InputPin : FlowNode->InputPins) { - CreateInputPin(InputName); + CreateInputPin(InputPin); } - for (const FName& OutputName : FlowNode->OutputNames) + for (const FFlowPin& OutputPin : FlowNode->OutputPins) { - CreateOutputPin(OutputName); + CreateOutputPin(OutputPin); } } } @@ -678,28 +676,32 @@ void UFlowGraphNode::JumpToDefinition() const } } -void UFlowGraphNode::CreateInputPin(const FName& PinName, const int32 Index /*= INDEX_NONE*/) +void UFlowGraphNode::CreateInputPin(const FFlowPin& FlowPin, const int32 Index /*= INDEX_NONE*/) { - if (PinName.IsNone()) + if (FlowPin.PinName.IsNone()) { return; } const FEdGraphPinType PinType = FEdGraphPinType(UEdGraphSchema_K2::PC_Exec, FName(NAME_None), nullptr, EPinContainerType::None, false, FEdGraphTerminalType()); - UEdGraphPin* NewPin = CreatePin(EGPD_Input, PinType, PinName, Index); + UEdGraphPin* NewPin = CreatePin(EGPD_Input, PinType, FlowPin.PinName, Index); + check(NewPin); + NewPin->PinToolTip = FlowPin.PinToolTip; InputPins.Emplace(NewPin); } -void UFlowGraphNode::CreateOutputPin(const FName PinName, const int32 Index /*= INDEX_NONE*/) +void UFlowGraphNode::CreateOutputPin(const FFlowPin& FlowPin, const int32 Index /*= INDEX_NONE*/) { - if (PinName.IsNone()) + if (FlowPin.PinName.IsNone()) { return; } const FEdGraphPinType PinType = FEdGraphPinType(UEdGraphSchema_K2::PC_Exec, FName(NAME_None), nullptr, EPinContainerType::None, false, FEdGraphTerminalType()); - UEdGraphPin* NewPin = CreatePin(EGPD_Output, PinType, PinName, Index); + UEdGraphPin* NewPin = CreatePin(EGPD_Output, PinType, FlowPin.PinName, Index); + check(NewPin); + NewPin->PinToolTip = FlowPin.PinToolTip; OutputPins.Emplace(NewPin); } @@ -735,12 +737,12 @@ bool UFlowGraphNode::CanUserAddOutput() const bool UFlowGraphNode::CanUserRemoveInput(const UEdGraphPin* Pin) const { - return FlowNode && FlowNode->InputNames.Num() > FlowNode->GetClass()->GetDefaultObject()->InputNames.Num(); + return FlowNode && FlowNode->InputPins.Num() > FlowNode->GetClass()->GetDefaultObject()->InputPins.Num(); } bool UFlowGraphNode::CanUserRemoveOutput(const UEdGraphPin* Pin) const { - return FlowNode && FlowNode->OutputNames.Num() > FlowNode->GetClass()->GetDefaultObject()->OutputNames.Num(); + return FlowNode && FlowNode->OutputPins.Num() > FlowNode->GetClass()->GetDefaultObject()->OutputPins.Num(); } void UFlowGraphNode::AddUserInput() @@ -760,13 +762,13 @@ void UFlowGraphNode::AddInstancePin(const EEdGraphPinDirection Direction, const if (Direction == EGPD_Input) { - FlowNode->InputNames.Add(PinName); - CreateInputPin(PinName); + FlowNode->InputPins.Emplace(PinName); + CreateInputPin(FlowNode->InputPins.Last()); } else { - FlowNode->OutputNames.Add(PinName); - CreateOutputPin(PinName); + FlowNode->OutputPins.Emplace(PinName); + CreateOutputPin(FlowNode->OutputPins.Last()); } GetGraph()->NotifyGraphChanged(); @@ -816,12 +818,12 @@ void UFlowGraphNode::RefreshContextPins(const bool bReconstructNode) const UFlowNode* NodeDefaults = FlowNode->GetClass()->GetDefaultObject(); // recreate inputs - FlowNode->InputNames = NodeDefaults->InputNames; - FlowNode->InputNames.Append(FlowNode->GetContextInputs()); + FlowNode->InputPins = NodeDefaults->InputPins; + FlowNode->AddInputPins(FlowNode->GetContextInputs()); // recreate outputs - FlowNode->OutputNames = NodeDefaults->OutputNames; - FlowNode->OutputNames.Append(FlowNode->GetContextOutputs()); + FlowNode->OutputPins = NodeDefaults->OutputPins; + FlowNode->AddOutputPins(FlowNode->GetContextOutputs()); if (bReconstructNode) { @@ -831,6 +833,39 @@ void UFlowGraphNode::RefreshContextPins(const bool bReconstructNode) } } +void UFlowGraphNode::GetPinHoverText(const UEdGraphPin& Pin, FString& HoverTextOut) const +{ + // start with the default hover text (from the pin's tool-tip) + Super::GetPinHoverText(Pin, HoverTextOut); + + // add information on pin activations + if (GEditor->PlayWorld) + { + if (UFlowNode* InspectedNodeInstance = GetInspectedNodeInstance()) + { + if (!HoverTextOut.IsEmpty()) + { + HoverTextOut.Append(LINE_TERMINATOR).Append(LINE_TERMINATOR); + } + + const TArray& PinRecords = InspectedNodeInstance->GetPinRecords(Pin.PinName, Pin.Direction); + if (PinRecords.Num() == 0) + { + HoverTextOut.Append(FPinRecord::NoActivations); + } + else + { + HoverTextOut.Append(FPinRecord::PinActivations); + for (int32 i = 0; i < PinRecords.Num(); i++) + { + HoverTextOut.Append(LINE_TERMINATOR); + HoverTextOut.Appendf(TEXT("%d) %s"), i + 1, *PinRecords[i].HumanReadableTime); + } + } + } + } +} + void UFlowGraphNode::OnInputTriggered(const int32 Index) { if (InputPins.IsValidIndex(Index) && PinBreakpoints.Contains(InputPins[Index])) diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp index ab5ad123c..1ba970672 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp @@ -38,53 +38,6 @@ void SFlowGraphPinExec::Construct(const FArguments& InArgs, UEdGraphPin* InPin) bUsePinColorForText = true; } -void SFlowGraphPinExec::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) -{ - SGraphPinExec::Tick(AllottedGeometry, InCurrentTime, InDeltaTime); - - if (IsHovered()) - { - if (GEditor->PlayWorld) - { - UFlowGraphNode* GraphNode = Cast(GraphPinObj->GetOwningNode()); - if (UFlowNode* FlowNode = GraphNode->GetInspectedNodeInstance()) - { - TArray PinRecords; - if (GetDirection() == EGPD_Input) - { - PinRecords = FlowNode->GetInputRecords(GetPinObj()->PinName); - } - else - { - PinRecords = FlowNode->GetOutputRecords(GetPinObj()->PinName); - } - - if (PinRecords.Num() > 0) - { - FString TooltipString = FString(); - for (int32 i = 0; i < PinRecords.Num(); i++) - { - TooltipString += FString::FromInt(i + 1) + TEXT(") ") + PinRecords[i].HumanReadableTime; - if (i < PinRecords.Num() - 1) - { - TooltipString += LINE_TERMINATOR; - } - } - GraphPinObj->PinToolTip = TooltipString; - } - else - { - GraphPinObj->PinToolTip = TEXT("0 calls"); - } - } - } - else - { - GraphPinObj->PinToolTip = FString(); - } - } -} - void SFlowGraphNode::Construct(const FArguments& InArgs, UFlowGraphNode* InNode) { GraphNode = InNode; @@ -438,14 +391,14 @@ void SFlowGraphNode::CreateStandardPinWidget(UEdGraphPin* Pin) { if (Pin->Direction == EGPD_Input) { - if (FlowGraphNode->GetFlowNode()->GetInputNames().Num() == 1 && Pin->PinName == UFlowNode::DefaultInputName) + if (FlowGraphNode->GetFlowNode()->GetInputPins().Num() == 1 && Pin->PinName == UFlowNode::DefaultInputPin.PinName) { NewPin->SetShowLabel(false); } } else { - if (FlowGraphNode->GetFlowNode()->GetOutputNames().Num() == 1 && Pin->PinName == UFlowNode::DefaultOutputName) + if (FlowGraphNode->GetFlowNode()->GetOutputPins().Num() == 1 && Pin->PinName == UFlowNode::DefaultOutputPin.PinName) { NewPin->SetShowLabel(false); } diff --git a/Source/FlowEditor/Private/Nodes/Customizations/FlowPinCustomization.cpp b/Source/FlowEditor/Private/Nodes/Customizations/FlowPinCustomization.cpp new file mode 100644 index 000000000..af243ebec --- /dev/null +++ b/Source/FlowEditor/Private/Nodes/Customizations/FlowPinCustomization.cpp @@ -0,0 +1,77 @@ +#include "FlowPinCustomization.h" +#include "Nodes/FlowPin.h" + +#include "PropertyEditing.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 new file mode 100644 index 000000000..883fd7ef2 --- /dev/null +++ b/Source/FlowEditor/Private/Nodes/Customizations/FlowPinCustomization.h @@ -0,0 +1,20 @@ +#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); +}; diff --git a/Source/FlowEditor/Public/FlowEditorModule.h b/Source/FlowEditor/Public/FlowEditorModule.h index 0a340fa8e..5abc5cdea 100644 --- a/Source/FlowEditor/Public/FlowEditorModule.h +++ b/Source/FlowEditor/Public/FlowEditorModule.h @@ -50,6 +50,7 @@ class FFlowEditorModule : public IModuleInterface void RegisterAssets(); void UnregisterAssets(); + void RegisterPropertyCustomizations() const; void RegisterCustomClassLayout(const TSubclassOf Class, const FOnGetDetailCustomizationInstance DetailLayout); public: diff --git a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h index fd41298bf..d35348235 100644 --- a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h +++ b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h @@ -5,6 +5,7 @@ #include "Templates/SubclassOf.h" #include "FlowTypes.h" +#include "Nodes/FlowPin.h" #include "FlowGraphNode.generated.h" class UEdGraphSchema; @@ -164,8 +165,8 @@ class FLOWEDITOR_API UFlowGraphNode : public UEdGraphNode UPROPERTY() TMap PinBreakpoints; - void CreateInputPin(const FName& PinName, const int32 Index = INDEX_NONE); - void CreateOutputPin(const FName PinName, const int32 Index = INDEX_NONE); + void CreateInputPin(const FFlowPin& FlowPin, const int32 Index = INDEX_NONE); + void CreateOutputPin(const FFlowPin& FlowPin, const int32 Index = INDEX_NONE); void RemoveOrphanedPin(UEdGraphPin* Pin); @@ -189,6 +190,10 @@ class FLOWEDITOR_API UFlowGraphNode : public UEdGraphNode // Create pins from the context asset, i.e. Sequencer events void RefreshContextPins(const bool bReconstructNode); + // UEdGraphNode + virtual void GetPinHoverText(const UEdGraphPin& Pin, FString& HoverTextOut) const override; + // -- + ////////////////////////////////////////////////////////////////////////// // Breakpoints diff --git a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h index 8742c2cef..dd21aab64 100644 --- a/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h +++ b/Source/FlowEditor/Public/Graph/Widgets/SFlowGraphNode.h @@ -14,10 +14,6 @@ class SFlowGraphPinExec final : public SGraphPinExec SLATE_END_ARGS() void Construct(const FArguments& InArgs, UEdGraphPin* InPin); - - // SWidget - virtual void Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) override; - // -- }; class SFlowGraphNode : public SGraphNode From 6e2692e5a2d5b7ba8c63b8f6defa35323ed5ee1f Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 20 Apr 2021 18:23:50 +0200 Subject: [PATCH 073/265] blueprint methods now returns actors and Flow Components of required type --- Source/Flow/Private/FlowSubsystem.cpp | 24 ++++++++++++------------ Source/Flow/Public/FlowSubsystem.h | 24 ++++++++++++------------ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index cc94a7708..d3b902ede 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -246,7 +246,7 @@ void UFlowSubsystem::OnIdentityTagsRemoved(UFlowComponent* Component, const FGam } } -TSet UFlowSubsystem::GetFlowComponentsByTag(const FGameplayTag Tag) const +TSet UFlowSubsystem::GetFlowComponentsByTag(const FGameplayTag Tag, const TSubclassOf ComponentClass) const { TArray> FoundComponents; FlowComponentRegistry.MultiFind(Tag, FoundComponents); @@ -254,7 +254,7 @@ TSet UFlowSubsystem::GetFlowComponentsByTag(const FGameplayTag TSet Result; for (const TWeakObjectPtr& Component : FoundComponents) { - if (Component.IsValid()) + if (Component.IsValid() && Component->GetClass()->IsChildOf(ComponentClass)) { Result.Emplace(Component.Get()); } @@ -263,7 +263,7 @@ TSet UFlowSubsystem::GetFlowComponentsByTag(const FGameplayTag return Result; } -TSet UFlowSubsystem::GetFlowComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType) const +TSet UFlowSubsystem::GetFlowComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType, const TSubclassOf ComponentClass) const { TSet> FoundComponents; FindComponents(Tags, FoundComponents, MatchType); @@ -271,7 +271,7 @@ TSet UFlowSubsystem::GetFlowComponentsByTags(const FGameplayTag TSet Result; for (const TWeakObjectPtr& Component : FoundComponents) { - if (Component.IsValid()) + if (Component.IsValid() && Component->GetClass()->IsChildOf(ComponentClass)) { Result.Emplace(Component.Get()); } @@ -280,7 +280,7 @@ TSet UFlowSubsystem::GetFlowComponentsByTags(const FGameplayTag return Result; } -TSet UFlowSubsystem::GetFlowActorsByTag(const FGameplayTag Tag) const +TSet UFlowSubsystem::GetFlowActorsByTag(const FGameplayTag Tag, const TSubclassOf ActorClass) const { TArray> FoundComponents; FlowComponentRegistry.MultiFind(Tag, FoundComponents); @@ -288,7 +288,7 @@ TSet UFlowSubsystem::GetFlowActorsByTag(const FGameplayTag Tag) const TSet Result; for (const TWeakObjectPtr& Component : FoundComponents) { - if (Component.IsValid()) + if (Component.IsValid() && Component->GetOwner()->GetClass()->IsChildOf(ActorClass)) { Result.Emplace(Component->GetOwner()); } @@ -297,7 +297,7 @@ TSet UFlowSubsystem::GetFlowActorsByTag(const FGameplayTag Tag) const return Result; } -TSet UFlowSubsystem::GetFlowActorsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType) const +TSet UFlowSubsystem::GetFlowActorsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType, const TSubclassOf ActorClass) const { TSet> FoundComponents; FindComponents(Tags, FoundComponents, MatchType); @@ -305,7 +305,7 @@ TSet UFlowSubsystem::GetFlowActorsByTags(const FGameplayTagContainer Ta TSet Result; for (const TWeakObjectPtr& Component : FoundComponents) { - if (Component.IsValid()) + if (Component.IsValid() && Component->GetOwner()->GetClass()->IsChildOf(ActorClass)) { Result.Emplace(Component->GetOwner()); } @@ -314,7 +314,7 @@ TSet UFlowSubsystem::GetFlowActorsByTags(const FGameplayTagContainer Ta return Result; } -TMap UFlowSubsystem::GetFlowActorsAndComponentsByTag(const FGameplayTag Tag) const +TMap UFlowSubsystem::GetFlowActorsAndComponentsByTag(const FGameplayTag Tag, const TSubclassOf ActorClass) const { TArray> FoundComponents; FlowComponentRegistry.MultiFind(Tag, FoundComponents); @@ -322,7 +322,7 @@ TMap UFlowSubsystem::GetFlowActorsAndComponentsByTag(c TMap Result; for (const TWeakObjectPtr& Component : FoundComponents) { - if (Component.IsValid()) + if (Component.IsValid() && Component->GetOwner()->GetClass()->IsChildOf(ActorClass)) { Result.Emplace(Component->GetOwner(), Component.Get()); } @@ -331,7 +331,7 @@ TMap UFlowSubsystem::GetFlowActorsAndComponentsByTag(c return Result; } -TMap UFlowSubsystem::GetFlowActorsAndComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType) const +TMap UFlowSubsystem::GetFlowActorsAndComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType, const TSubclassOf ActorClass) const { TSet> FoundComponents; FindComponents(Tags, FoundComponents, MatchType); @@ -339,7 +339,7 @@ TMap UFlowSubsystem::GetFlowActorsAndComponentsByTags( TMap Result; for (const TWeakObjectPtr& Component : FoundComponents) { - if (Component.IsValid()) + if (Component.IsValid() && Component->GetOwner()->GetClass()->IsChildOf(ActorClass)) { Result.Emplace(Component->GetOwner(), Component.Get()); } diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index 40552bfcb..73c5671ba 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -117,28 +117,28 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem FTaggedFlowComponentEvent OnComponentTagRemoved; // Returns all registered Flow Components identified by given tag - UFUNCTION(BlueprintPure, Category = "FlowSubsystem") - TSet GetFlowComponentsByTag(const FGameplayTag Tag) const; + UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "ComponentClass")) + TSet GetFlowComponentsByTag(const FGameplayTag Tag, const TSubclassOf ComponentClass) const; // Returns all registered Flow Components identified by Any or All provided tags - UFUNCTION(BlueprintPure, Category = "FlowSubsystem") - TSet GetFlowComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType) const; + UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "ComponentClass")) + TSet GetFlowComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType, const TSubclassOf ComponentClass) const; // Returns all registered actors with Flow Component identified by given tag - UFUNCTION(BlueprintPure, Category = "FlowSubsystem") - TSet GetFlowActorsByTag(const FGameplayTag Tag) const; + UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "ActorClass")) + TSet GetFlowActorsByTag(const FGameplayTag Tag, const TSubclassOf ActorClass) const; // Returns all registered actors with Flow Component identified by Any or All provided tags - UFUNCTION(BlueprintPure, Category = "FlowSubsystem") - TSet GetFlowActorsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType) const; + UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "ActorClass")) + TSet GetFlowActorsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType, const TSubclassOf ActorClass) const; // Returns all registered actors as pairs: Actor as key, its Flow Component as value - UFUNCTION(BlueprintPure, Category = "FlowSubsystem") - TMap GetFlowActorsAndComponentsByTag(const FGameplayTag Tag) const; + UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "ActorClass")) + TMap GetFlowActorsAndComponentsByTag(const FGameplayTag Tag, const TSubclassOf ActorClass) const; // Returns all registered actors as pairs: Actor as key, its Flow Component as value - UFUNCTION(BlueprintPure, Category = "FlowSubsystem") - TMap GetFlowActorsAndComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType) const; + UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "ActorClass")) + TMap GetFlowActorsAndComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType, const TSubclassOf ActorClass) const; // Returns all registered Flow Components identified by given tag template From 44a1c0f0ef2c7f7b3747167314a4bcec050b5bfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Thu, 22 Apr 2021 21:05:54 +0200 Subject: [PATCH 074/265] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c84ba017d..dde21227c 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Flow plug-in for Unreal Engine provides a graph editor tailored for scripting fl ## Getting started * It's easy to include pluing in your own project, follow this short [Getting Started](https://github.com/MothCocoon/FlowGraph/wiki/Getting-Started) guide. -* The [legacy repository](https://github.com/MothCocoon/Flow) gonna be upgraded in future, so it would includ FlowGraph (this repo) and FlowSamples as git submodules. +* The [legacy repository](https://github.com/MothCocoon/Flow) gonna be upgraded in future, so it would includ FlowGraph (this repo) and [FlowSamples](https://github.com/MothCocoon/FlowSamples) as git submodules. ## Concept It's s design-agnostic event node editor. From c61baaa9f64beff34256136ec191055306a2fe65 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 23 Apr 2021 18:28:39 +0200 Subject: [PATCH 075/265] added proper fallback for getting blueprint metadata, fixes #36 --- Source/Flow/Private/Nodes/FlowNode.cpp | 42 +++++++++++++++++++ Source/Flow/Public/Nodes/FlowNode.h | 11 ++--- .../Private/Graph/FlowGraphSchema.cpp | 22 +++++----- .../Private/Graph/FlowGraphSchema_Actions.cpp | 11 ++--- .../Private/Graph/Nodes/FlowGraphNode.cpp | 2 +- .../Private/Graph/Widgets/SFlowPalette.cpp | 2 +- .../Public/Graph/FlowGraphSchema_Actions.h | 24 +++-------- 7 files changed, 70 insertions(+), 44 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 926e572c8..da593f579 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -76,6 +76,48 @@ void UFlowNode::SetGraphNode(UEdGraphNode* NewGraph) GraphNode = NewGraph; } +FString UFlowNode::GetNodeCategory() const +{ + if (GetClass()->ClassGeneratedBy) + { + const FString& BlueprintCategory = Cast(GetClass()->ClassGeneratedBy)->BlueprintCategory; + if (!BlueprintCategory.IsEmpty()) + { + return BlueprintCategory; + } + } + + return Category; +} + +FText UFlowNode::GetNodeTitle() const +{ + if (GetClass()->ClassGeneratedBy) + { + const FString& BlueprintTitle = Cast(GetClass()->ClassGeneratedBy)->BlueprintDisplayName; + if (!BlueprintTitle.IsEmpty()) + { + return FText::FromString(BlueprintTitle); + } + } + + return GetClass()->GetDisplayNameText(); +} + +FText UFlowNode::GetNodeToolTip() const +{ + if (GetClass()->ClassGeneratedBy) + { + const FString& BlueprintToolTip = Cast(GetClass()->ClassGeneratedBy)->BlueprintDescription; + if (!BlueprintToolTip.IsEmpty()) + { + return FText::FromString(BlueprintToolTip); + } + } + + return GetClass()->GetToolTipText(); +} + FString UFlowNode::GetNodeDescription() const { return K2_GetNodeDescription(); diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index d8b8d2fc2..f352e8559 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -64,14 +64,15 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte #if WITH_EDITOR void SetGraphNode(UEdGraphNode* NewGraph); - FString GetNativeCategory() const { return Category; } - EFlowNodeStyle GetNodeStyle() const { return NodeStyle; } - - virtual FText GetTitle() const { return GetClass()->GetDisplayNameText(); } - + 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 GetNodeTitleColor(FLinearColor& OutColor) const { return false; } + EFlowNodeStyle GetNodeStyle() const { return NodeStyle; } + // Short summary of node's content - displayed over node as NodeInfoPopup virtual FString GetNodeDescription() const; #endif diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp index 2aadb56d1..dc0ec76d4 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -201,22 +201,24 @@ void UFlowGraphSchema::GetFlowNodeActions(FGraphActionMenuBuilder& ActionMenuBui GatherFlowNodes(); } + TArray FlowNodes; + FlowNodes.Reserve(NativeFlowNodes.Num() + BlueprintFlowNodes.Num()); + for (UClass* FlowNodeClass : NativeFlowNodes) { - const UFlowNode* FlowNode = FlowNodeClass->GetDefaultObject(); - if (CategoryName.IsEmpty() || CategoryName.Equals(FlowNode->GetNativeCategory())) - { - TSharedPtr NewNodeAction(new FFlowGraphSchemaAction_NewNode(FlowNode)); - ActionMenuBuilder.AddAction(NewNodeAction); - } + FlowNodes.Emplace(FlowNodeClass->GetDefaultObject()); } - for (const TPair& AssetData : BlueprintFlowNodes) { UBlueprint* Blueprint = GetNodeBlueprint(AssetData.Value); - if (CategoryName.IsEmpty() || CategoryName.Equals(Blueprint->BlueprintCategory)) + FlowNodes.Emplace(Blueprint->GeneratedClass->GetDefaultObject()); + } + + for (const UFlowNode* FlowNode : FlowNodes) + { + if (CategoryName.IsEmpty() || CategoryName.Equals(FlowNode->GetNodeCategory())) { - TSharedPtr NewNodeAction(new FFlowGraphSchemaAction_NewNode(Blueprint)); + TSharedPtr NewNodeAction(new FFlowGraphSchemaAction_NewNode(FlowNode)); ActionMenuBuilder.AddAction(NewNodeAction); } } @@ -260,7 +262,7 @@ void UFlowGraphSchema::GatherFlowNodes() NativeFlowNodes.Emplace(*It); const UFlowNode* DefaultObject = It->GetDefaultObject(); - UnsortedCategories.Emplace(DefaultObject->GetNativeCategory()); + UnsortedCategories.Emplace(DefaultObject->GetNodeCategory()); } } else if (It->IsChildOf(UFlowGraphNode::StaticClass())) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp index ed16ae542..2915a968b 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp @@ -29,14 +29,9 @@ UEdGraphNode* FFlowGraphSchemaAction_NewNode::PerformAction(class UEdGraph* Pare return nullptr; } - if (NativeNodeClass) + if (NodeClass) { - return CreateNode(ParentGraph, FromPin, NativeNodeClass, Location, bSelectNewNode); - } - - if (Blueprint) - { - return CreateNode(ParentGraph, FromPin, Blueprint->GeneratedClass, Location, bSelectNewNode); + return CreateNode(ParentGraph, FromPin, NodeClass, Location, bSelectNewNode); } return nullptr; @@ -121,4 +116,4 @@ UEdGraphNode* FFlowGraphSchemaAction_NewComment::PerformAction(class UEdGraph* P return FEdGraphSchemaAction_NewNode::SpawnNodeFromTemplate(ParentGraph, CommentTemplate, SpawnLocation); } -#undef LOCTEXT_NAMESPACE \ No newline at end of file +#undef LOCTEXT_NAMESPACE diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 5011d2544..6e970c79d 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -542,7 +542,7 @@ FText UFlowGraphNode::GetNodeTitle(ENodeTitleType::Type TitleType) const { if (FlowNode) { - return FlowNode->GetTitle(); + return FlowNode->GetNodeTitle(); } return Super::GetNodeTitle(TitleType); diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp index ff410bbe1..77a96f83b 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowPalette.cpp @@ -34,7 +34,7 @@ void SFlowPaletteItem::Construct(const FArguments& InArgs, FCreateWidgetForActio { if (GraphAction->GetTypeId() == FFlowGraphSchemaAction_NewNode::StaticGetTypeId()) { - UClass* FlowNodeClass = StaticCastSharedPtr(GraphAction)->NativeNodeClass; + UClass* FlowNodeClass = StaticCastSharedPtr(GraphAction)->NodeClass; HotkeyChord = FFlowSpawnNodeCommands::Get().GetChordByClass(FlowNodeClass); } else if (GraphAction->GetTypeId() == FFlowGraphSchemaAction_NewComment::StaticGetTypeId()) diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h b/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h index 018635ab5..1d7eb3ea1 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSchema_Actions.h @@ -1,7 +1,6 @@ #pragma once #include "EdGraph/EdGraphSchema.h" -#include "Engine/Blueprint.h" #include "Nodes/FlowGraphNode.h" #include "Nodes/FlowNode.h" @@ -14,10 +13,7 @@ struct FLOWEDITOR_API FFlowGraphSchemaAction_NewNode : public FEdGraphSchemaActi GENERATED_USTRUCT_BODY() UPROPERTY() - class UClass* NativeNodeClass; - - UPROPERTY() - class UBlueprint* Blueprint; + class UClass* NodeClass; static FName StaticGetTypeId() { @@ -29,29 +25,19 @@ struct FLOWEDITOR_API FFlowGraphSchemaAction_NewNode : public FEdGraphSchemaActi FFlowGraphSchemaAction_NewNode() : FEdGraphSchemaAction() - , NativeNodeClass(nullptr) - , Blueprint(nullptr) + , NodeClass(nullptr) { } FFlowGraphSchemaAction_NewNode(UClass* Node) : FEdGraphSchemaAction() - , NativeNodeClass(Node) - , Blueprint(nullptr) + , NodeClass(Node) { } FFlowGraphSchemaAction_NewNode(const UFlowNode* Node) - : FEdGraphSchemaAction(FText::FromString(Node->GetNativeCategory()), Node->GetTitle(), Node->GetClass()->GetToolTipText(), 0) - , NativeNodeClass(Node->GetClass()) - , Blueprint(nullptr) - { - } - - FFlowGraphSchemaAction_NewNode(UBlueprint* InBlueprint) - : FEdGraphSchemaAction(FText::FromString(InBlueprint->BlueprintCategory), FText::FromString(InBlueprint->BlueprintDisplayName), FText::FromString(InBlueprint->BlueprintDescription), 0) - , NativeNodeClass(nullptr) - , Blueprint(InBlueprint) + : FEdGraphSchemaAction(FText::FromString(Node->GetNodeCategory()), Node->GetNodeTitle(), Node->GetNodeToolTip(), 0) + , NodeClass(Node->GetClass()) { } From a7c146e190c22bfde8c97956d85721c89e61085e Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 23 Apr 2021 19:48:55 +0200 Subject: [PATCH 076/265] oh my, forgot to restore this after debugging --- Source/Flow/Private/Nodes/FlowNode.cpp | 13 ++++++++++++- Source/Flow/Public/Nodes/FlowNode.h | 1 + .../Private/Graph/Nodes/FlowGraphNode.cpp | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index da593f579..2619eeb28 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -49,10 +49,21 @@ void UFlowNode::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEve } } +void UFlowNode::PostLoad() +{ + Super::PostLoad(); + + // fix Class Default Object + FixNode(nullptr); +} + void UFlowNode::FixNode(UEdGraphNode* NewGraph) { // Fix any node pointers that may be out of date - GraphNode = NewGraph; + if (NewGraph) + { + GraphNode = NewGraph; + } // v1.1 upgraded pins to be defined as structs if (InputNames_DEPRECATED.Num() > InputPins.Num()) diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index f352e8559..e3380a145 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -53,6 +53,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte #if WITH_EDITOR // UObject virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; + virtual void PostLoad() override; // -- // Opportunity to update node's data before UFlowGraphNode would call ReconstructNode() diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 6e970c79d..f541429f1 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -133,7 +133,7 @@ void UFlowGraphNode::PostLoad() if (FlowNode) { - FlowNode->FixNode(this); + FlowNode->FixNode(this); // fix already created nodes SubscribeToExternalChanges(); } From 6a18c7ae9a56d6c6fff85f21a0140d4152eb3d75 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sat, 24 Apr 2021 15:10:33 +0200 Subject: [PATCH 077/265] fix #41 - hide EditDefaultsOnly properties in Flow Asset details view --- Source/Flow/Public/FlowAsset.h | 4 ++-- Source/Flow/Public/Nodes/Route/FlowNode_Counter.h | 2 +- .../Public/Nodes/Route/FlowNode_ExecutionMultiGate.h | 6 +++--- Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h | 2 +- Source/Flow/Public/Nodes/Route/FlowNode_Timer.h | 4 ++-- Source/Flow/Public/Nodes/Utils/FlowNode_Log.h | 8 ++++---- .../Public/Nodes/World/FlowNode_ComponentObserver.h | 4 ++-- .../Flow/Public/Nodes/World/FlowNode_NotifyActor.h | 4 ++-- .../Public/Nodes/World/FlowNode_OnNotifyFromActor.h | 4 ++-- .../Public/Nodes/World/FlowNode_PlayLevelSequence.h | 2 +- Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp | 12 ++++++------ Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp | 2 ++ 12 files changed, 28 insertions(+), 26 deletions(-) diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 0b37ccc45..ef47c6495 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -86,14 +86,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(EditDefaultsOnly, Category = "Flow") + UPROPERTY(EditAnywhere, Category = "Flow") 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(EditDefaultsOnly, Category = "Flow") + UPROPERTY(EditAnywhere, Category = "Flow") TArray CustomOutputs; public: diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_Counter.h b/Source/Flow/Public/Nodes/Route/FlowNode_Counter.h index d549ae47a..2a83ba140 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_Counter.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_Counter.h @@ -12,7 +12,7 @@ class FLOW_API UFlowNode_Counter final : public UFlowNode GENERATED_UCLASS_BODY() protected: - UPROPERTY(EditDefaultsOnly, Category = "Counter", meta = (ClampMin = 2)) + UPROPERTY(EditAnywhere, Category = "Counter", meta = (ClampMin = 2)) int32 Goal; private: diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h index ef9ed58d1..a9f5b76cd 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h @@ -11,15 +11,15 @@ class FLOW_API UFlowNode_ExecutionMultiGate final : public UFlowNode { GENERATED_UCLASS_BODY() - UPROPERTY(EditDefaultsOnly, Category = "MultiGate") + UPROPERTY(EditAnywhere, Category = "MultiGate") bool bRandom; // Allow executing output pins again, without triggering Reset pin // If set to False, every output pin can be triggered only once - UPROPERTY(EditDefaultsOnly, Category = "MultiGate") + UPROPERTY(EditAnywhere, Category = "MultiGate") bool bLoop; - UPROPERTY(EditDefaultsOnly, Category = "MultiGate") + UPROPERTY(EditAnywhere, Category = "MultiGate") int32 StartIndex; private: diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h b/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h index 114743d33..3d46be823 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h @@ -17,7 +17,7 @@ class FLOW_API UFlowNode_SubGraph : public UFlowNode static FFlowPin FinishPin; private: - UPROPERTY(EditDefaultsOnly, Category = "Graph") + UPROPERTY(EditAnywhere, Category = "Graph") TSoftObjectPtr Asset; protected: diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h b/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h index 7807926ad..d0fd311b7 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h @@ -13,11 +13,11 @@ class FLOW_API UFlowNode_Timer final : public UFlowNode GENERATED_UCLASS_BODY() protected: - UPROPERTY(EditDefaultsOnly, Category = "Timer", meta = (ClampMin = 0.0f)) + UPROPERTY(EditAnywhere, Category = "Timer", meta = (ClampMin = 0.0f)) float CompletionTime; // this allows to trigger other nodes multiple times before completing the Timer - UPROPERTY(EditDefaultsOnly, Category = "Timer", meta = (ClampMin = 0.0f)) + UPROPERTY(EditAnywhere, Category = "Timer", meta = (ClampMin = 0.0f)) float StepTime; private: diff --git a/Source/Flow/Public/Nodes/Utils/FlowNode_Log.h b/Source/Flow/Public/Nodes/Utils/FlowNode_Log.h index 51e13ebeb..c20daa9f6 100644 --- a/Source/Flow/Public/Nodes/Utils/FlowNode_Log.h +++ b/Source/Flow/Public/Nodes/Utils/FlowNode_Log.h @@ -13,16 +13,16 @@ class FLOW_API UFlowNode_Log : public UFlowNode GENERATED_UCLASS_BODY() private: - UPROPERTY(EditDefaultsOnly, Category = "Flow") + UPROPERTY(EditAnywhere, Category = "Flow") FString Message; - UPROPERTY(EditDefaultsOnly, Category = "Flow") + UPROPERTY(EditAnywhere, Category = "Flow") bool bPrintToScreen; - UPROPERTY(EditDefaultsOnly, Category = "Flow", meta = (EditCondition = "bPrintToScreen")) + UPROPERTY(EditAnywhere, Category = "Flow", meta = (EditCondition = "bPrintToScreen")) float Duration; - UPROPERTY(EditDefaultsOnly, Category = "Flow", meta = (EditCondition = "bPrintToScreen")) + UPROPERTY(EditAnywhere, Category = "Flow", meta = (EditCondition = "bPrintToScreen")) FColor TextColor; protected: diff --git a/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h b/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h index 5100a7af4..6832570b3 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h @@ -19,12 +19,12 @@ class FLOW_API UFlowNode_ComponentObserver : public UFlowNode friend class FFlowNode_ComponentObserverDetails; protected: - UPROPERTY(EditDefaultsOnly, Category = "ObservedComponent") + UPROPERTY(EditAnywhere, Category = "ObservedComponent") FGameplayTagContainer IdentityTags; // 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(EditDefaultsOnly, Category = "Lifetime", meta = (ClampMin = 0)) + UPROPERTY(EditAnywhere, Category = "Lifetime", meta = (ClampMin = 0)) int32 SuccessLimit; // This node will become Completed, if Success Limit > 0 and Success Count reaches this limit diff --git a/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h b/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h index 4b613febb..ae0201d80 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_NotifyActor.h @@ -14,10 +14,10 @@ class FLOW_API UFlowNode_NotifyActor : public UFlowNode GENERATED_UCLASS_BODY() protected: - UPROPERTY(EditDefaultsOnly, Category = "ObservedComponent") + UPROPERTY(EditAnywhere, Category = "ObservedComponent") FGameplayTagContainer IdentityTags; - UPROPERTY(EditDefaultsOnly, Category = "ObservedComponent") + UPROPERTY(EditAnywhere, Category = "ObservedComponent") FGameplayTagContainer NotifyTags; 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 30a5c2c6c..251c2c0b3 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_OnNotifyFromActor.h @@ -12,12 +12,12 @@ class FLOW_API UFlowNode_OnNotifyFromActor : public UFlowNode_ComponentObserver GENERATED_UCLASS_BODY() protected: - UPROPERTY(EditDefaultsOnly, Category = "ObservedComponent") + UPROPERTY(EditAnywhere, Category = "ObservedComponent") 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(EditDefaultsOnly, Category = "ObservedComponent") + UPROPERTY(EditAnywhere, Category = "ObservedComponent") bool bRetroactive; 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 dc5ae9281..9b907974f 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h @@ -27,7 +27,7 @@ class FLOW_API UFlowNode_PlayLevelSequence : public UFlowNode static FFlowNodeLevelSequenceEvent OnPlaybackStarted; static FFlowNodeLevelSequenceEvent OnPlaybackCompleted; - UPROPERTY(EditDefaultsOnly, Category = "Sequence") + UPROPERTY(EditAnywhere, Category = "Sequence") TSoftObjectPtr Sequence; protected: diff --git a/Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp b/Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp index dee37ae78..aa37b8293 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetDetails.cpp @@ -13,17 +13,17 @@ void FFlowAssetDetails::CustomizeDetails(IDetailLayoutBuilder& DetailLayout) { IDetailCategoryBuilder& FlowAssetCategory = DetailLayout.EditCategory("FlowAsset", LOCTEXT("FlowAssetCategory", "FlowAsset")); - const TSharedPtr EventsPropertyHandle = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(UFlowAsset, CustomInputs)); - if (EventsPropertyHandle.IsValid()) + const TSharedPtr InputsPropertyHandle = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(UFlowAsset, CustomInputs)); + if (InputsPropertyHandle.IsValid() && InputsPropertyHandle->AsArray().IsValid()) { - TSharedRef EventsArrayBuilder = MakeShareable(new FDetailArrayBuilder(EventsPropertyHandle.ToSharedRef())); - EventsArrayBuilder->OnGenerateArrayElementWidget(FOnGenerateArrayElementWidget::CreateSP(this, &FFlowAssetDetails::GenerateCustomPinArray)); + TSharedRef InputsArrayBuilder = MakeShareable(new FDetailArrayBuilder(InputsPropertyHandle.ToSharedRef())); + InputsArrayBuilder->OnGenerateArrayElementWidget(FOnGenerateArrayElementWidget::CreateSP(this, &FFlowAssetDetails::GenerateCustomPinArray)); - FlowAssetCategory.AddCustomBuilder(EventsArrayBuilder); + FlowAssetCategory.AddCustomBuilder(InputsArrayBuilder); } const TSharedPtr OutputsPropertyHandle = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(UFlowAsset, CustomOutputs)); - if (OutputsPropertyHandle.IsValid()) + if (OutputsPropertyHandle.IsValid() && OutputsPropertyHandle->AsArray().IsValid()) { TSharedRef OutputsArrayBuilder = MakeShareable(new FDetailArrayBuilder(OutputsPropertyHandle.ToSharedRef())); OutputsArrayBuilder->OnGenerateArrayElementWidget(FOnGenerateArrayElementWidget::CreateSP(this, &FFlowAssetDetails::GenerateCustomPinArray)); diff --git a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp index ce717d64e..8866a0d35 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -351,10 +351,12 @@ void FFlowAssetEditor::CreateWidgets() 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); Palette = SNew(SFlowPalette, SharedThis(this)); From 8f4e6f2d633a57abf11fcf12f0af954afab2bb6e Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sat, 24 Apr 2021 15:11:56 +0200 Subject: [PATCH 078/265] changed LoadingPhase of runtime module to PreDefault fixes rare issues with plugin not being loaded on time while blueprint actors already try to load Flow Component --- Flow.uplugin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.uplugin b/Flow.uplugin index 911691588..e8919641e 100644 --- a/Flow.uplugin +++ b/Flow.uplugin @@ -19,7 +19,7 @@ { "Name" : "Flow", "Type" : "Runtime", - "LoadingPhase" : "Default" + "LoadingPhase" : "PreDefault" }, { "Name" : "FlowEditor", From e2a710c7ca614a7c70bf8e6f62b76fdacfbf1bb2 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 25 Apr 2021 17:55:22 +0200 Subject: [PATCH 079/265] #37 - exposed IsOutputConnected method --- Source/Flow/Private/Nodes/FlowNode.cpp | 5 +++++ Source/Flow/Public/Nodes/FlowNode.h | 3 +++ 2 files changed, 8 insertions(+) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 2619eeb28..0035fcc4d 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -236,6 +236,11 @@ TSet UFlowNode::GetConnectedNodes() const return Result; } +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) diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index e3380a145..d9c5d7098 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -163,6 +163,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 IsOutputConnected(const FName& PinName) const; + static void RecursiveFindNodesByClass(UFlowNode* Node, const TSubclassOf Class, uint8 Depth, TArray& OutNodes); ////////////////////////////////////////////////////////////////////////// From 762eca27d49385fbeb7567fe6a070e9f7e8df40e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Wed, 28 Apr 2021 12:59:59 +0200 Subject: [PATCH 080/265] Update README.md --- README.md | 68 +++++++------------------------------------------------ 1 file changed, 8 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index dde21227c..a43c4bae5 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,6 @@ -# Flow - +## 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. -* Licensed under MIT license. You are free to use it for commercial projects, modify it however you see fit, and distribute it further. - -## Getting started -* It's easy to include pluing in your own project, follow this short [Getting Started](https://github.com/MothCocoon/FlowGraph/wiki/Getting-Started) guide. -* The [legacy repository](https://github.com/MothCocoon/Flow) gonna be upgraded in future, so it would includ FlowGraph (this repo) and [FlowSamples](https://github.com/MothCocoon/FlowSamples) as git submodules. -## Concept It's s design-agnostic event node editor. ![Flow101](https://user-images.githubusercontent.com/5065057/103543817-6d924080-4e9f-11eb-87d9-15ab092c3875.png) @@ -28,51 +21,12 @@ This 24-minute presentation breaks down the concept of the Flow Graph. It goes t [![Introducing Flow Graph for Unreal Engine](https://img.youtube.com/vi/Rj76JP1f-I4/0.jpg)](https://www.youtube.com/watch?v=Rj76JP1f-I4) -## Simplicity is a key -* It's all about simplifying the cooperation between gameplay programmers and content designers by providing a clean interface between "code of systems" and "using systems". -* Code of gameplay mechanics wouldn't ever be mixed with each other. Usually, system X shouldn't even know about the existence of system Y. Flow Graph is a place to combine features by connecting nodes. -* Every mechanic is exposed to content designers once, in one way only - as the Flow Node. It greatly reduces the number of bugs. Refactoring mechanics is easy since you don't have to update dozens of level blueprints directly calling system functions. -* Systems based on such editor are simple to use for least technical team members, i.e. narrative designers, writers, QA. Every time I ask designers why they love working with such a system, they usually reply: "it's so simple to understand and make a game with it". -* Even a complex game might end up only with a few dozens of Flow Nodes. It's easy to manage the game's complexity - a lot of mechanics, mission scripting, narrative events. It makes it very efficient to develop lengthy campaigns and multiplayer games. - -## Blueprints -* Programmer writing a new gameplay feature can quickly expose it to content creators by creating a new Flow Node. A given C++ feature doesn't have to be exposed to blueprints at all. -* However, Flow Nodes can be created in blueprints by anyone. Personally, I would recommend using blueprint nodes mostly for prototyping and rarely used custom actions, if you have a gameplay programmer in a team. If not, sure, you can implement your systems in blueprints entirely. - -## Performance -* Performance loss in blueprint graphs comes from executing a large network of nodes, processing pins and connections between them. Moving away from overcomplicated level blueprints and messy "system blueprints" to simple Flow Graph might improve framerate and memory management. -* As Flow Nodes are designed to be event-based, executing graph connection might happen only like few times per minute or so. (heavily depends on your logic and event mechanics). Finally, Flow Graph has its own execution logic, doesn't utilize blueprint VM. -* Flow-based event systems are generally more performant than blueprint counterparts. Especially if frequently used nodes are implemented in C++. - -## Flexibility of the system design -Flow Graph communicates with actors in the world by using [Gameplay Tags](https://docs.unrealengine.com/en-US/Gameplay/Tags/index.html). No direct references to actors are used in this variant of scripting - that brings a lot of new possibilities. -* Simply add Flow Component to every "event actor", assign Gameplay Tags identifying this actor. Flow Component registers itself to the Flow Subsystem (or any derived system) when it appears in the world. It's easy to find any event actor this way, just ask Flow Subsystem for actors registered with a given Gameplay Tag. -* It allows for reusing entire Flow Graphs in different maps. Unlike level blueprints, Flow Graphs aren't bound to levels. -* It's possible to place actors used by the single Flow Graph in different sublevels or even worlds. This removes one of the workflow limitations related to the level design. -* It should work well with the World Partition system coming to Unreal Engine - a truly open-world way of building maps where every actor instance is saved separately to disk. That probably means no sublevels and no level blueprints (except the blueprint of the "persistent level"). -* Flow Graph could live as long as the game session, not even bound to the specific world. You can have a meta Flow Graph waiting for events happening anywhere during the game. -* Using Gameplay Tags allows scripting an action on any actor spawned in runtime, typically NPCs. -* In some cases actor with a given Gameplay Tag doesn't even have to exist when starting a related action! Example: On Trigger Enter in the image above would pick up the required trigger after loading a sublevel with this trigger. - -## Recommended workflow -* Flow Graph is meant to entirely replace a need to use Level Blueprints (also known as Flying Spaghetti Monster) in production maps. The flow of the game - the connection between consecutive events and actors - should be scripted by using Flow Graphs only. Otherwise, you ending up creating a mess, using multiple tools for the same job. -* This graph also entirely replaces another way of doing things: referencing different actors directly, i.e. hooking up Spawner actor directly to the Trigger actor. Technically it works fine, but it's impossible to read the designed flow of events scripted this way. Debugging can be very cumbersome and time-consuming. -* Actor blueprints are supposed to be used only to script the inner logic of actors, not connections between actors belonging to different systems. -* Flow Nodes can send and receive blueprint events via Flow Component. This recommended way of communicating between Flow Graph and blueprints. -* Technically, it's always possible to call custom blueprint events directly from blueprint Flow Node, but this would require creating a new Flow Node for every custom blueprint actor. Effectively, you would throw a simplicity of Flow Graph out of the window. - -## State of the development -* Flow editor and runtime system are ready for production. +## Getting started +* It's easy to include pluing in your own project, follow this short [Getting Started](https://github.com/MothCocoon/FlowGraph/wiki/Getting-Started) guide. +* The [legacy repository](https://github.com/MothCocoon/Flow) gonna be upgraded in future, so it would includ FlowGraph (this repo) and [FlowSamples](https://github.com/MothCocoon/FlowSamples) as git submodules. * Plugin and the code of the sample project are available for every engine version since 4.22. I'm not planning on backporting code to older engine versions since the runtime code relies on [programming subsystems](https://docs.unrealengine.com/en-US/ProgrammingAndScripting/Subsystems/index.html) introduced with UE 4.22. -* Currently, the example content is... modest. I hope to prepare better samples in the future. -* Development continues. Check [Issues](https://github.com/MothCocoon/FlowGraph/issues) for a list of useful things I'm hoping to work on in the future. -* Your feedback is much welcome! It's all about developing a toolset for any kind of game. -* In the short term, code might need a bit of love to support creating multiple flow-based systems without modifying the plugin code at all. For example, the quest and dialogue system based on the Flow Subsystem. It's not a huge work, plugin was designed for it. I just need time to create a few different systems, play with it, update the plugin where's needed. * I'm planning to release the Flow plugin on the Marketplace, so more people could discover it and conveniently add it to their asset libraries. It will be free of charge, obviously. - -## Contact -* Catch me on Twitter: [@MothDoctor](https://twitter.com/MothDoctor) -* Discuss things related to the plugin on dedicated [Discord server](https://discord.gg/zMtMQ2vUUa). +* Read documentation (in progress) on the project wiki. I'd recommend starting from reading about [design philosophy](https://github.com/MothCocoon/FlowGraph/wiki). ## 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 only the one who decided it would be crazy useful to adopt it for Unreal Engine. And make it publically available as my humble contribution to the open-source community. @@ -81,12 +35,6 @@ I feel it's important to mention that I didn't invent anything new here, with th * 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. Written from the scratch, 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. -## Related resources -* [Introduction to Gameplay Tags](https://docs.unrealengine.com/en-US/ProgrammingAndScripting/Tags/index.html) -* [Behind the Scenes of the Cinematic Dialogues in The Witcher 3: Wild Hunt](https://www.youtube.com/watch?v=chf3REzAjgI) -* [Sinking City - story scripting for the open-world game](https://youtu.be/W_yiopwoXt0?t=929) as part of their talk on Sinking City development -* [Unreal Engine Open World Preview and Landscape Tools | Unreal Dev Days 2019](https://www.youtube.com/watch?v=wXbyqGYfM1I) - starts from describing the upcoming open-world streaming system that might no longer use level blueprints -* [Blueprints In-depth - Part 1 | Unreal Fest Europe 2019](https://youtu.be/j6mskTgL7kU?t=1048) - great talk on blueprint system, the timestamp at the Performance part. -* [Blueprints In-depth - Part 2 | Unreal Fest Europe 2019](https://www.youtube.com/watch?v=0YMS2wnykbc) -* [The Visual Logger: For All Your Gameplay Needs!](https://www.youtube.com/watch?v=hWpbco3F4L4) -* [Gamedec exemplifies how to incorporate complex branching pathways using Unreal Engine](https://www.unrealengine.com/en-US/tech-blog/gamedec-exemplifies-how-to-incorporate-complex-branching-pathways-using-unreal-engine) - example how the integration of Artict:Draft with Unreal Engine looks like +## Contact +* Catch me on Twitter: [@MothDoctor](https://twitter.com/MothDoctor) +* Discuss things related to the plugin on dedicated [Discord server](https://discord.gg/zMtMQ2vUUa). From 092579131c96e9a6fc177c101b269d5e374e884e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Wed, 28 Apr 2021 13:10:45 +0200 Subject: [PATCH 081/265] Update README.md --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index a43c4bae5..237f0614d 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,7 @@ It's s design-agnostic event node editor. * Every node defines its own set of input/output pins. It's dead simple to design the flow of the game - just connect nodes representing features. * Developers creating a Flow Node can call the execution of pins any way they need. API is extremely simple. * Editor supports convenient displaying debug information on nodes and wires while playing a game. You simply provide what kind of message would be displayed over active Flow Nodes - you can't have that with blueprint functions. - -## Base for your own systems and tools * It's up to you to add game-specific functionalities by writing your nodes and editor customizations. It's not like a marketplace providing the very specific implementation of systems. It's a convenient base for building systems tailored to fit your needs. -* Quickly build your own Quest system, Dialogue system or any other custom system that would control the flow of events in the game. -* Expand it, build Articy:draft equivalent right in the Unreal Engine. ## 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. From 7b6a6eb9722f738322f6a877519fd77cb39e43b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Wed, 28 Apr 2021 13:11:53 +0200 Subject: [PATCH 082/265] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 237f0614d..12207aa7b 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ It's s design-agnostic event node editor. * Developers creating a Flow Node can call the execution of pins any way they need. API is extremely simple. * Editor supports convenient displaying debug information on nodes and wires while playing a game. You simply provide what kind of message would be displayed over active Flow Nodes - you can't have that with blueprint functions. * It's up to you to add game-specific functionalities by writing your nodes and editor customizations. It's not like a marketplace providing the very specific implementation of systems. It's a convenient base for building systems tailored to fit your needs. +* Read documentation on the project wiki. I'd recommend starting from reading about [design philosophy](https://github.com/MothCocoon/FlowGraph/wiki). ## 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. @@ -22,7 +23,6 @@ This 24-minute presentation breaks down the concept of the Flow Graph. It goes t * The [legacy repository](https://github.com/MothCocoon/Flow) gonna be upgraded in future, so it would includ FlowGraph (this repo) and [FlowSamples](https://github.com/MothCocoon/FlowSamples) as git submodules. * Plugin and the code of the sample project are available for every engine version since 4.22. I'm not planning on backporting code to older engine versions since the runtime code relies on [programming subsystems](https://docs.unrealengine.com/en-US/ProgrammingAndScripting/Subsystems/index.html) introduced with UE 4.22. * I'm planning to release the Flow plugin on the Marketplace, so more people could discover it and conveniently add it to their asset libraries. It will be free of charge, obviously. -* Read documentation (in progress) on the project wiki. I'd recommend starting from reading about [design philosophy](https://github.com/MothCocoon/FlowGraph/wiki). ## 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 only the one who decided it would be crazy useful to adopt it for Unreal Engine. And make it publically available as my humble contribution to the open-source community. From 0ec2d1bee53dc9a864900f0f3cd4c54994100fcd Mon Sep 17 00:00:00 2001 From: IceRiver Date: Fri, 30 Apr 2021 07:24:17 +0800 Subject: [PATCH 083/265] AutowireNewNode (#43) --- Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp index 2915a968b..ce8152c6c 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema_Actions.cpp @@ -66,6 +66,8 @@ UFlowGraphNode* FFlowGraphSchemaAction_NewNode::CreateNode(UEdGraph* ParentGraph NewGraphNode->PostPlacedNewNode(); NewGraphNode->AllocateDefaultPins(); + NewGraphNode->AutowireNewNode(FromPin); + ParentGraph->NotifyGraphChanged(); const TSharedPtr FlowEditor = FFlowGraphUtils::GetFlowAssetEditor(ParentGraph); From 77b1de75cfe5777c98437ba2435a600236c604fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Mon, 3 May 2021 12:58:59 +0200 Subject: [PATCH 084/265] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 12207aa7b..8c004f3e5 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. -It's s design-agnostic event node editor. +It's a design-agnostic event node editor. ![Flow101](https://user-images.githubusercontent.com/5065057/103543817-6d924080-4e9f-11eb-87d9-15ab092c3875.png) @@ -25,7 +25,7 @@ This 24-minute presentation breaks down the concept of the Flow Graph. It goes t * I'm planning to release the Flow plugin on the Marketplace, so more people could discover it and conveniently add it to their asset libraries. It will be free of charge, obviously. ## 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 only the one who decided it would be crazy useful to adopt it for Unreal Engine. And make it publically available as my humble contribution to the open-source community. +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. * 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. From e8b83f49a85dfbe0134577bf2aa9a750f65e932e Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 4 May 2021 13:53:49 +0200 Subject: [PATCH 085/265] add NodesHiddenFromPalette --- Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp | 3 ++- Source/FlowEditor/Public/Graph/FlowGraphSettings.h | 10 +++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp index dc0ec76d4..7599caf26 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -3,6 +3,7 @@ #include "Asset/FlowAssetEditor.h" #include "Graph/FlowGraph.h" #include "Graph/FlowGraphSchema_Actions.h" +#include "Graph/FlowGraphSettings.h" #include "Graph/FlowGraphUtils.h" #include "Graph/Nodes/FlowGraphNode.h" @@ -216,7 +217,7 @@ void UFlowGraphSchema::GetFlowNodeActions(FGraphActionMenuBuilder& ActionMenuBui for (const UFlowNode* FlowNode : FlowNodes) { - if (CategoryName.IsEmpty() || CategoryName.Equals(FlowNode->GetNodeCategory())) + if ((CategoryName.IsEmpty() || CategoryName.Equals(FlowNode->GetNodeCategory())) && !UFlowGraphSettings::Get()->NodesHiddenFromPalette.Contains(FlowNode->GetClass())) { TSharedPtr NewNodeAction(new FFlowGraphSchemaAction_NewNode(FlowNode)); ActionMenuBuilder.AddAction(NewNodeAction); diff --git a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h index 5dd0f2659..ef693731d 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphSettings.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphSettings.h @@ -12,9 +12,13 @@ UCLASS(Config = Editor, defaultconfig, meta = (DisplayName = "Flow Graph")) class UFlowGraphSettings final : public UDeveloperSettings { GENERATED_UCLASS_BODY() - static UFlowGraphSettings* Get() { return CastChecked(UFlowGraphSettings::StaticClass()->GetDefaultObject()); } + /** Hide specific nodes from the Flow Palette without changing the source code. + * Requires restart after making a change. */ + UPROPERTY(EditAnywhere, config, Category = "Nodes") + TArray> NodesHiddenFromPalette; + /** Hide default pin names on simple nodes, reduces UI clutter */ UPROPERTY(EditAnywhere, config, Category = "Nodes") bool bShowDefaultPinNames; @@ -39,7 +43,7 @@ class UFlowGraphSettings final : public UDeveloperSettings UPROPERTY(EditAnywhere, config, Category = "Wires", meta = (ClampMin = 0.0f)) float InactiveWireThickness; - + UPROPERTY(EditAnywhere, config, Category = "Wires", meta = (ClampMin = 1.0f)) float RecentWireDuration; @@ -61,7 +65,7 @@ class UFlowGraphSettings final : public UDeveloperSettings UPROPERTY(EditAnywhere, config, Category = "Wires") bool bHighlightOutputWiresOfSelectedNodes; - + UPROPERTY(EditAnywhere, config, Category = "Wires") FLinearColor SelectedWireColor; From ba942cf681d4e56bdd00346bb9eb520180ad9bf3 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 4 May 2021 13:58:38 +0200 Subject: [PATCH 086/265] SaveGame, first iteration WIP - saving Flow Asset Instances (Root Flow and Sub Graphs), Flow Nodes - saving components in progress - Save system self-contained in plugin, it might be overridden by game's save systems --- Source/Flow/Private/FlowAsset.cpp | 42 +++++++ Source/Flow/Private/FlowComponent.cpp | 89 ++++++++++++- Source/Flow/Private/FlowSettings.cpp | 1 + Source/Flow/Private/FlowSubsystem.cpp | 119 ++++++++++++++++-- Source/Flow/Private/Nodes/FlowNode.cpp | 27 ++++ .../Private/Nodes/Route/FlowNode_SubGraph.cpp | 26 +++- .../Private/Nodes/Route/FlowNode_Timer.cpp | 31 +++++ .../Nodes/Utils/FlowNode_Checkpoint.cpp | 18 +++ Source/Flow/Public/FlowAsset.h | 7 ++ Source/Flow/Public/FlowComponent.h | 27 ++++ Source/Flow/Public/FlowSave.h | 94 ++++++++++++++ Source/Flow/Public/FlowSettings.h | 3 + Source/Flow/Public/FlowSubsystem.h | 34 ++++- Source/Flow/Public/FlowTypes.h | 1 + Source/Flow/Public/Nodes/FlowNode.h | 13 ++ .../Public/Nodes/Route/FlowNode_SubGraph.h | 8 ++ .../Flow/Public/Nodes/Route/FlowNode_Timer.h | 13 +- .../Public/Nodes/Utils/FlowNode_Checkpoint.h | 17 +++ 18 files changed, 553 insertions(+), 17 deletions(-) create mode 100644 Source/Flow/Private/Nodes/Utils/FlowNode_Checkpoint.cpp create mode 100644 Source/Flow/Public/FlowSave.h create mode 100644 Source/Flow/Public/Nodes/Utils/FlowNode_Checkpoint.h diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 710511297..99e7cbbe2 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -432,3 +432,45 @@ UFlowNode* UFlowAsset::GetNodeInstance(const FGuid Guid) const { return Nodes.FindRef(Guid); } + +FFlowAssetSaveData UFlowAsset::SaveInstance() +{ + FFlowAssetSaveData AssetRecord; + + //FSoftObjectPtr FlowAsset; + //FArchiveUObject::SerializeSoftObjectPtr(AssetRecord.AssetClass, FlowAsset); + AssetRecord.AssetPath = GetPathName(); + AssetRecord.InstanceName = GetName(); + + for (const TPair& Node : Nodes) + { + if (Node.Value) + { + FFlowNodeSaveData NodeRecord; + Node.Value->SaveInstance(NodeRecord); + + AssetRecord.NodeRecords.Emplace(NodeRecord); + } + } + + FMemoryWriter MemoryWriter(AssetRecord.AssetData, true); + FFlowArchive Ar(MemoryWriter); + Serialize(Ar); + + return AssetRecord; +} + +void UFlowAsset::LoadInstance(const FFlowAssetSaveData& AssetRecord) +{ + FMemoryReader MemoryReader(AssetRecord.AssetData, true); + FFlowArchive Ar(MemoryReader); + Serialize(Ar); + + for (const FFlowNodeSaveData& NodeRecord : AssetRecord.NodeRecords) + { + if (UFlowNode* Node = Nodes.FindRef(NodeRecord.NodeGuid)) + { + Node->LoadInstance(NodeRecord); + } + } +} diff --git a/Source/Flow/Private/FlowComponent.cpp b/Source/Flow/Private/FlowComponent.cpp index fa038cab7..c9dacb0bc 100644 --- a/Source/Flow/Private/FlowComponent.cpp +++ b/Source/Flow/Private/FlowComponent.cpp @@ -1,4 +1,6 @@ #include "FlowComponent.h" + +#include "FlowAsset.h" #include "FlowSettings.h" #include "FlowSubsystem.h" @@ -37,12 +39,32 @@ void UFlowComponent::BeginPlay() if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) { + bool bComponentLoadedFromSaveGame = false; + if (GetFlowSubsystem()->IsSaveGameLoaded()) + { + // temp hack, checking if Flow Component is inside World Settings + if (bAllowMultipleInstances == false) + { + bComponentLoadedFromSaveGame = LoadInstance(); + } + } + FlowSubsystem->RegisterComponent(this); - } - if (RootFlow && bAutoStartRootFlow) - { - StartRootFlow(); + if (RootFlow) + { + if (bComponentLoadedFromSaveGame) + { + LoadRootFlow(); + } + else + { + if (bAutoStartRootFlow) + { + StartRootFlow(); + } + } + } } } @@ -332,6 +354,65 @@ UFlowAsset* UFlowComponent::GetRootFlowInstance() return nullptr; } +FFlowAssetSaveData UFlowComponent::SaveRootFlow() +{ + SavedAssetInstance = FFlowAssetSaveData(); + + if (UFlowAsset* FlowAssetInstance = GetRootFlowInstance()) + { + SavedAssetInstance = FlowAssetInstance->SaveInstance(); + } + + return SavedAssetInstance; +} + +void UFlowComponent::LoadRootFlow() +{ + if (RootFlow && GetFlowSubsystem()) + { + GetFlowSubsystem()->LoadRootFlow(this, RootFlow, SavedAssetInstance); + } +} + +FFlowComponentSaveData UFlowComponent::SaveInstance() +{ + FFlowComponentSaveData ComponentRecord; + PrepareSaveData(); + + FMemoryWriter MemoryWriter(ComponentRecord.ComponentData, true); + FFlowArchive Ar(MemoryWriter); + Serialize(Ar); + + return ComponentRecord; +} + +bool UFlowComponent::LoadInstance() +{ + const FFlowSaveData SaveData = GetFlowSubsystem()->GetLoadedSaveGame(); + if (SaveData.SavedFlowComponents.Num() > 0) + { + // temp hack, checking if Flow Component is inside World Settings + const FFlowComponentSaveData& ComponentRecord = SaveData.SavedFlowComponents[0]; + + FMemoryReader MemoryReader(ComponentRecord.ComponentData, true); + FFlowArchive Ar(MemoryReader); + Serialize(Ar); + + OnSaveDataLoaded(); + return true; + } + + return false; +} + +void UFlowComponent::OnSaveDataLoaded_Implementation() +{ +} + +void UFlowComponent::PrepareSaveData_Implementation() +{ +} + UFlowSubsystem* UFlowComponent::GetFlowSubsystem() const { if (GetWorld() && GetWorld()->GetGameInstance()) diff --git a/Source/Flow/Private/FlowSettings.cpp b/Source/Flow/Private/FlowSettings.cpp index f31c414ed..6b6fcbf5f 100644 --- a/Source/Flow/Private/FlowSettings.cpp +++ b/Source/Flow/Private/FlowSettings.cpp @@ -3,5 +3,6 @@ UFlowSettings::UFlowSettings(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) , bCreateFlowSubsystemOnClients(true) + , SaveFolderName(TEXT("Saves")) { } diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index d3b902ede..198fa9298 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -1,13 +1,17 @@ #include "FlowSubsystem.h" + #include "FlowAsset.h" #include "FlowComponent.h" #include "FlowModule.h" +#include "FlowSave.h" #include "FlowSettings.h" #include "Nodes/Route/FlowNode_SubGraph.h" #include "Engine/GameInstance.h" #include "Engine/World.h" +#include "Misc/FileHelper.h" #include "Misc/Paths.h" +#include "Serialization/BufferArchive.h" UFlowSubsystem::UFlowSubsystem() : UGameInstanceSubsystem() @@ -27,6 +31,8 @@ bool UFlowSubsystem::ShouldCreateSubsystem(UObject* Outer) const void UFlowSubsystem::Initialize(FSubsystemCollectionBase& Collection) { + // temp for testing, game should control this + LoadGame(); } void UFlowSubsystem::Deinitialize() @@ -46,24 +52,25 @@ void UFlowSubsystem::Deinitialize() } } -void UFlowSubsystem::StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances /* = true */) +UFlowAsset* UFlowSubsystem::StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances /* = true */) { if (RootInstances.Contains(Owner)) { 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; + return nullptr; } if (!bAllowMultipleInstances && InstancedTemplates.Contains(FlowAsset)) { UE_LOG(LogFlow, Warning, TEXT("Attempted to start Root Flow, although there can be only a single instance. Owner: %s. Flow Asset: %s."), *Owner->GetName(), *FlowAsset->GetName()); - return; + return nullptr; } UFlowAsset* NewFlow = CreateFlowInstance(Owner, FlowAsset); RootInstances.Add(Owner, NewFlow); NewFlow->StartFlow(); + return NewFlow; } void UFlowSubsystem::FinishRootFlow(UObject* Owner) @@ -75,12 +82,14 @@ void UFlowSubsystem::FinishRootFlow(UObject* Owner) } } -void UFlowSubsystem::StartSubFlow(UFlowNode_SubGraph* SubGraphNode, const bool bPreloading /* = false */) +UFlowAsset* UFlowSubsystem::StartSubFlow(UFlowNode_SubGraph* SubGraphNode, const FString NewInstanceName, const bool bPreloading /* = false */) { + UFlowAsset* NewFlow = nullptr; + if (!InstancedSubFlows.Contains(SubGraphNode)) { const TWeakObjectPtr Owner = SubGraphNode->GetFlowAsset() ? SubGraphNode->GetFlowAsset()->GetOwner() : nullptr; - UFlowAsset* NewFlow = CreateFlowInstance(Owner, SubGraphNode->Asset); + NewFlow = CreateFlowInstance(Owner, SubGraphNode->Asset, NewInstanceName); InstancedSubFlows.Add(SubGraphNode, NewFlow); if (bPreloading) @@ -94,6 +103,8 @@ void UFlowSubsystem::StartSubFlow(UFlowNode_SubGraph* SubGraphNode, const bool b // get instanced asset from map - in case it was already instanced by calling StartSubFlow() with bPreloading == true InstancedSubFlows[SubGraphNode]->StartAsSubFlow(SubGraphNode); } + + return NewFlow; } void UFlowSubsystem::FinishSubFlow(UFlowNode_SubGraph* SubGraphNode) @@ -105,7 +116,7 @@ void UFlowSubsystem::FinishSubFlow(UFlowNode_SubGraph* SubGraphNode) } } -UFlowAsset* UFlowSubsystem::CreateFlowInstance(const TWeakObjectPtr Owner, TSoftObjectPtr FlowAsset) +UFlowAsset* UFlowSubsystem::CreateFlowInstance(const TWeakObjectPtr Owner, TSoftObjectPtr FlowAsset, FString NewInstanceName) { check(!FlowAsset.IsNull()); @@ -125,7 +136,12 @@ UFlowAsset* UFlowSubsystem::CreateFlowInstance(const TWeakObjectPtr Own } #endif - const FString NewInstanceName = FPaths::GetBaseFilename(FlowAsset.Get()->GetPathName()) + TEXT("_") + FString::FromInt(FlowAsset.Get()->GetInstancesNum()); + // 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()); + } + UFlowAsset* NewInstance = NewObject(this, FlowAsset->GetClass(), *NewInstanceName, RF_Transient, FlowAsset.Get(), false, nullptr); NewInstance->InitializeInstance(Owner, FlowAsset.Get()); @@ -154,6 +170,95 @@ UWorld* UFlowSubsystem::GetWorld() const return GetGameInstance()->GetWorld(); } +void UFlowSubsystem::SaveGame() +{ + FFlowSaveData SaveGameData; + SaveGameData.Timestamp = FDateTime::Now(); + + for (const TPair, UFlowAsset*>& Pair : RootInstances) + { + if (Pair.Key.IsValid() && Pair.Value) + { + if (UFlowComponent* FlowComponent = Cast(Pair.Key)) + { + SaveGameData.SavedRootFlowInstances.Emplace(FlowComponent->SaveRootFlow()); + } + else + { + SaveGameData.SavedRootFlowInstances.Emplace(Pair.Value->SaveInstance()); + } + } + } + + TArray> ComponentsArray; + FlowComponentRegistry.GenerateValueArray(ComponentsArray); + const TSet> FlowComponents = TSet>(ComponentsArray); + for (TWeakObjectPtr FlowComponent : FlowComponents) + { + // temp hack, checking if Flow Component is inside World Settings + if (FlowComponent->bAllowMultipleInstances == false) + { + SaveGameData.SavedFlowComponents.Emplace(FlowComponent->SaveInstance()); + } + } + + FBufferArchive BinaryData; + BinaryData << SaveGameData; + + const FString SaveFolder = GetSaveFolderDir() + FString("TestSave.sav"); + if (FFileHelper::SaveArrayToFile(BinaryData, *SaveFolder)) + { + UE_LOG(LogFlow, Warning, TEXT("Save Success! %s"), FPlatformProcess::BaseDir()); + } + else + { + UE_LOG(LogFlow, Warning, TEXT("Save Failed!")); + } + + BinaryData.FlushCache(); + BinaryData.Empty(); +} + +void UFlowSubsystem::LoadGame() +{ + const FString SaveFolder = GetSaveFolderDir() + FString("TestSave.sav"); + TArray BinaryData; + + if (FFileHelper::LoadFileToArray(BinaryData, *SaveFolder)) + { + UE_LOG(LogFlow, Warning, TEXT("Load Succeeded!")); + + FMemoryReader FromBinary = FMemoryReader(BinaryData, true); + FromBinary.Seek(0); + FromBinary << LoadedSaveGame;; + + FromBinary.FlushCache(); + BinaryData.Empty(); + FromBinary.Close(); + } + else + { + UE_LOG(LogFlow, Warning, TEXT("Load Failed!")); + } +} + +void UFlowSubsystem::LoadRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const FFlowAssetSaveData AssetRecord) +{ + UFlowAsset* LoadedInstance = StartRootFlow(Owner, FlowAsset, false); + LoadedInstance->LoadInstance(AssetRecord); +} + +void UFlowSubsystem::LoadSubFlow(UFlowNode_SubGraph* SubGraphNode, const FFlowAssetSaveData AssetRecord) +{ + UFlowAsset* LoadedInstance = StartSubFlow(SubGraphNode, AssetRecord.InstanceName); + LoadedInstance->LoadInstance(AssetRecord); +} + +FString UFlowSubsystem::GetSaveFolderDir() +{ + return FPaths::ProjectSavedDir() + UFlowSettings::Get()->SaveFolderName + TEXT("/"); +} + void UFlowSubsystem::RegisterComponent(UFlowComponent* Component) { for (const FGameplayTag& Tag : Component->IdentityTags) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 0035fcc4d..9214a4756 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -554,3 +554,30 @@ void UFlowNode::LogError(FString Message) GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, Message); UE_LOG(LogFlow, Error, TEXT("%s"), *Message); } + +void UFlowNode::SaveInstance(FFlowNodeSaveData& NodeRecord) +{ + NodeRecord.NodeGuid = NodeGuid; + PrepareSaveData(); + + 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); + + OnSaveDataLoaded(); +} + +void UFlowNode::OnSaveDataLoaded_Implementation() +{ +} + +void UFlowNode::PrepareSaveData_Implementation() +{ +} diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp index f85c3b7d6..a80c77c6b 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp @@ -22,7 +22,7 @@ void UFlowNode_SubGraph::PreloadContent() { if (!Asset.IsNull()) { - GetFlowSubsystem()->StartSubFlow(this, true); + GetFlowSubsystem()->StartSubFlow(this, FString(), true); } } @@ -67,6 +67,30 @@ void UFlowNode_SubGraph::ForceFinishNode() TriggerFirstOutput(true); } +void UFlowNode_SubGraph::PrepareSaveData_Implementation() +{ + if (GetFlowAsset()) + { + const TWeakObjectPtr FlowInstance = GetFlowAsset()->GetFlowInstance(this); + if (FlowInstance.IsValid()) + { + SavedAssetInstance = FlowInstance->SaveInstance(); + return; + } + } + + SavedAssetInstance = FFlowAssetSaveData(); +} + +void UFlowNode_SubGraph::OnSaveDataLoaded_Implementation() +{ + if (!SavedAssetInstance.InstanceName.IsEmpty() && !Asset.IsNull()) + { + GetFlowSubsystem()->LoadSubFlow(this, SavedAssetInstance); + SavedAssetInstance = FFlowAssetSaveData(); + } +} + #if WITH_EDITOR FString UFlowNode_SubGraph::GetNodeDescription() const { diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp index 1252b1ac1..75e69aa57 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp @@ -8,6 +8,8 @@ UFlowNode_Timer::UFlowNode_Timer(const FObjectInitializer& ObjectInitializer) , CompletionTime(1.0f) , StepTime(0.0f) , SumOfSteps(0.0f) + , RemainingCompletionTime(0.0f) + , RemainingStepTime(0.0f) { #if WITH_EDITOR Category = TEXT("Route"); @@ -96,6 +98,35 @@ void UFlowNode_Timer::Cleanup() SumOfSteps = 0.0f; } +void UFlowNode_Timer::PrepareSaveData_Implementation() +{ + if (GetWorld()) + { + if (CompletionTimerHandle.IsValid()) + { + RemainingCompletionTime = GetWorld()->GetTimerManager().GetTimerRemaining(CompletionTimerHandle); + } + + if (StepTimerHandle.IsValid()) + { + RemainingStepTime = GetWorld()->GetTimerManager().GetTimerRemaining(StepTimerHandle); + } + } +} + +void UFlowNode_Timer::OnSaveDataLoaded_Implementation() +{ + if (RemainingStepTime > 0.0f) + { + GetWorld()->GetTimerManager().SetTimer(StepTimerHandle, this, &UFlowNode_Timer::OnStep, RemainingStepTime, true); + } + + GetWorld()->GetTimerManager().SetTimer(CompletionTimerHandle, this, &UFlowNode_Timer::OnCompletion, RemainingCompletionTime, false); + + RemainingStepTime = 0.0f; + RemainingCompletionTime = 0.0f; +} + #if WITH_EDITOR FString UFlowNode_Timer::GetNodeDescription() const { diff --git a/Source/Flow/Private/Nodes/Utils/FlowNode_Checkpoint.cpp b/Source/Flow/Private/Nodes/Utils/FlowNode_Checkpoint.cpp new file mode 100644 index 000000000..ea752d51e --- /dev/null +++ b/Source/Flow/Private/Nodes/Utils/FlowNode_Checkpoint.cpp @@ -0,0 +1,18 @@ +#include "Nodes/Utils/FlowNode_Checkpoint.h" +#include "FlowSubsystem.h" + +UFlowNode_Checkpoint::UFlowNode_Checkpoint(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ +#if WITH_EDITOR + Category = TEXT("Utils"); +#endif +} + +void UFlowNode_Checkpoint::ExecuteInput(const FName& PinName) +{ + if (GetFlowSubsystem()) + { + GetFlowSubsystem()->SaveGame(); + } +} diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index ef47c6495..2caf55070 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -1,6 +1,7 @@ #pragma once #include "CoreMinimal.h" +#include "FlowSave.h" #include "FlowAsset.generated.h" class UFlowNode; @@ -237,4 +238,10 @@ class FLOW_API UFlowAsset : public UObject // Returns nodes active in the past, done their work UFUNCTION(BlueprintPure, Category = "Flow") TArray GetRecordedNodes() const { return RecordedNodes; } + + UFUNCTION(BlueprintCallable, Category = "Flow") + FFlowAssetSaveData SaveInstance(); + + UFUNCTION(BlueprintCallable, Category = "Flow") + void LoadInstance(const FFlowAssetSaveData& AssetRecord); }; diff --git a/Source/Flow/Public/FlowComponent.h b/Source/Flow/Public/FlowComponent.h index 0dd333ea4..4dbed6251 100644 --- a/Source/Flow/Public/FlowComponent.h +++ b/Source/Flow/Public/FlowComponent.h @@ -3,6 +3,7 @@ #include "Components/ActorComponent.h" #include "GameplayTagContainer.h" +#include "FlowSave.h" #include "FlowTypes.h" #include "FlowComponent.generated.h" @@ -175,6 +176,9 @@ class FLOW_API UFlowComponent : public UActorComponent // If false, another Root Flow instance won't be created from this component, if this Flow Asset is already instantiated UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "RootFlow") bool bAllowMultipleInstances; + + UPROPERTY(SaveGame) + FFlowAssetSaveData SavedAssetInstance; // This will instantiate Flow Asset assigned on this component. // Created Flow Asset instance will be a "root flow", as additional Flow Assets can be instantiated via Sub Graph node @@ -188,9 +192,32 @@ class FLOW_API UFlowComponent : public UActorComponent UFUNCTION(BlueprintPure, Category = "RootFlow") UFlowAsset* GetRootFlowInstance(); +////////////////////////////////////////////////////////////////////////// +// SaveGame + + UFUNCTION(BlueprintCallable, Category = "SaveGame") + virtual FFlowAssetSaveData SaveRootFlow(); + + UFUNCTION(BlueprintCallable, Category = "SaveGame") + virtual void LoadRootFlow(); + + UFUNCTION(BlueprintCallable, Category = "SaveGame") + FFlowComponentSaveData SaveInstance(); + + UFUNCTION(BlueprintCallable, Category = "SaveGame") + bool LoadInstance(); + +protected: + UFUNCTION(BlueprintNativeEvent, Category = "SaveGame") + void PrepareSaveData(); + + UFUNCTION(BlueprintNativeEvent, Category = "SaveGame") + void OnSaveDataLoaded(); + ////////////////////////////////////////////////////////////////////////// // Helpers +public: UFlowSubsystem* GetFlowSubsystem() const; bool IsFlowNetMode(const EFlowNetMode NetMode) const; }; diff --git a/Source/Flow/Public/FlowSave.h b/Source/Flow/Public/FlowSave.h new file mode 100644 index 000000000..52456acfd --- /dev/null +++ b/Source/Flow/Public/FlowSave.h @@ -0,0 +1,94 @@ +#pragma once + +#include "CoreMinimal.h" +#include "Serialization/ObjectAndNameAsStringProxyArchive.h" +#include "FlowSave.generated.h" + +USTRUCT(BlueprintType) +struct FLOW_API FFlowNodeSaveData +{ + GENERATED_USTRUCT_BODY() + + FGuid NodeGuid; + TArray NodeData; + + friend FArchive& operator<<(FArchive& Ar, FFlowNodeSaveData& InNodeData) + { + Ar << InNodeData.NodeGuid; + Ar << InNodeData.NodeData; + return Ar; + } +}; + +USTRUCT(BlueprintType) +struct FLOW_API FFlowAssetSaveData +{ + GENERATED_USTRUCT_BODY() + + FString AssetPath; + FString InstanceName; + TArray AssetData; + + TArray NodeRecords; + TArray FlowRecords; + + friend FArchive& operator<<(FArchive& Ar, FFlowAssetSaveData& InAssetData) + { + Ar << InAssetData.AssetPath; + Ar << InAssetData.InstanceName; + Ar << InAssetData.AssetData; + Ar << InAssetData.NodeRecords; + Ar << InAssetData.FlowRecords; + return Ar; + } +}; + +USTRUCT(BlueprintType) +struct FLOW_API FFlowComponentSaveData +{ + GENERATED_USTRUCT_BODY() + + FString AssetPath; + FString InstanceName; + + TArray ComponentData; + + friend FArchive& operator<<(FArchive& Ar, FFlowComponentSaveData& InComponentData) + { + Ar << InComponentData.AssetPath; + Ar << InComponentData.InstanceName; + Ar << InComponentData.ComponentData; + return Ar; + } +}; + +struct FLOW_API FFlowArchive : public FObjectAndNameAsStringProxyArchive +{ + FFlowArchive(FArchive& InInnerArchive) : FObjectAndNameAsStringProxyArchive(InInnerArchive, true) + { + ArIsSaveGame = true; + } +}; + +// it's just an example +USTRUCT(BlueprintType) +struct FLOW_API FFlowSaveData +{ + GENERATED_USTRUCT_BODY() + + FDateTime Timestamp; + TArray SavedFlowComponents; + TArray SavedRootFlowInstances; + + friend FArchive& operator<<(FArchive& Ar, FFlowSaveData& FlowData) + { + Ar << FlowData.Timestamp; + Ar << FlowData.SavedRootFlowInstances; + return Ar; + } + + bool IsValid() const + { + return SavedRootFlowInstances.Num() > 0; + } +}; diff --git a/Source/Flow/Public/FlowSettings.h b/Source/Flow/Public/FlowSettings.h index 62c9a1d59..fae8c9d25 100644 --- a/Source/Flow/Public/FlowSettings.h +++ b/Source/Flow/Public/FlowSettings.h @@ -20,6 +20,9 @@ class UFlowSettings final : public UDeveloperSettings // And you don't access to the Flow Component registry on clients UPROPERTY(Config, EditAnywhere, Category = "Networking") bool bCreateFlowSubsystemOnClients; + + UPROPERTY(Config, EditAnywhere, Category = "Networking") + FString SaveFolderName; // How many nodes of given class should be preloaded with the Flow Asset instance? UPROPERTY(Config, EditAnywhere, Category = "Preload") diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index 73c5671ba..edc122992 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -11,6 +11,7 @@ class UFlowAsset; class UFlowNode_SubGraph; +DECLARE_DYNAMIC_MULTICAST_DELEGATE(FSimpleFlowEvent); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FSimpleFlowComponentEvent, UFlowComponent*, Component); DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FTaggedFlowComponentEvent, UFlowComponent*, Component, const FGameplayTagContainer&, Tags); @@ -44,6 +45,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem TMap InstancedSubFlows; FStreamableManager Streamable; + FFlowSaveData LoadedSaveGame; public: virtual bool ShouldCreateSubsystem(UObject* Outer) const override; @@ -53,17 +55,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); + UFlowAsset* StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances = true); // Finish the root Flow, typically when closing world that created this flow UFUNCTION(BlueprintCallable, Category = "FlowSubsystem") void FinishRootFlow(UObject* Owner); private: - void StartSubFlow(UFlowNode_SubGraph* SubGraphNode, const bool bPreloading = false); + UFlowAsset* StartSubFlow(UFlowNode_SubGraph* SubGraphNode, const FString NewInstanceName = FString(), const bool bPreloading = false); void FinishSubFlow(UFlowNode_SubGraph* SubGraphNode); - UFlowAsset* CreateFlowInstance(const TWeakObjectPtr Owner, TSoftObjectPtr FlowAsset); + UFlowAsset* CreateFlowInstance(const TWeakObjectPtr Owner, TSoftObjectPtr FlowAsset, FString NewInstanceName = FString()); void RemoveInstancedTemplate(UFlowAsset* Template); public: @@ -78,8 +80,32 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem // Returns assets instanced by Sub Graph nodes UFUNCTION(BlueprintPure, Category = "FlowSubsystem") TMap GetInstancedSubFlows() const { return InstancedSubFlows; } - + virtual UWorld* GetWorld() const override; + +////////////////////////////////////////////////////////////////////////// +// SaveGame + + UPROPERTY(BlueprintAssignable, Category = "FlowSubsystem") + FSimpleFlowEvent OnSaveGame; + + UFUNCTION(BlueprintCallable, Category = "FlowSubsystem") + virtual void SaveGame(); + + UFUNCTION(BlueprintCallable, Category = "FlowSubsystem") + virtual void LoadGame(); + + virtual void LoadRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const FFlowAssetSaveData AssetRecord); + virtual void LoadSubFlow(UFlowNode_SubGraph* SubGraphNode, const FFlowAssetSaveData AssetRecord); + + UFUNCTION(BlueprintPure, Category = "FlowSubsystem") + bool IsSaveGameLoaded() const { return LoadedSaveGame.IsValid(); } + + UFUNCTION(BlueprintPure, Category = "FlowSubsystem") + FFlowSaveData GetLoadedSaveGame() const { return LoadedSaveGame; } + + UFUNCTION(BlueprintPure, Category = "FlowSubsystem") + static FString GetSaveFolderDir(); ////////////////////////////////////////////////////////////////////////// // Component Registry diff --git a/Source/Flow/Public/FlowTypes.h b/Source/Flow/Public/FlowTypes.h index 738732183..52a62cd34 100644 --- a/Source/Flow/Public/FlowTypes.h +++ b/Source/Flow/Public/FlowTypes.h @@ -1,5 +1,6 @@ #pragma once +#include "FlowSave.h" #include "FlowTypes.generated.h" #if WITH_EDITORONLY_DATA diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index d9c5d7098..3a0edc33b 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -336,6 +336,19 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UFUNCTION(BlueprintCallable, Category = "FlowNode") void LogError(FString Message); + UFUNCTION(BlueprintCallable, Category = "FlowNode") + void SaveInstance(FFlowNodeSaveData& NodeRecord); + + UFUNCTION(BlueprintCallable, Category = "FlowNode") + void LoadInstance(const FFlowNodeSaveData& NodeRecord); + +protected: + UFUNCTION(BlueprintNativeEvent, Category = "FlowNode") + void PrepareSaveData(); + + UFUNCTION(BlueprintNativeEvent, Category = "FlowNode") + void OnSaveDataLoaded(); + private: UPROPERTY() TArray InputNames_DEPRECATED; diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h b/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h index 3d46be823..ca1cb8d39 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h @@ -20,6 +20,9 @@ class FLOW_API UFlowNode_SubGraph : public UFlowNode UPROPERTY(EditAnywhere, Category = "Graph") TSoftObjectPtr Asset; + UPROPERTY(SaveGame) + FFlowAssetSaveData SavedAssetInstance; + protected: virtual void PreloadContent() override; virtual void FlushContent() override; @@ -30,6 +33,11 @@ class FLOW_API UFlowNode_SubGraph : public UFlowNode public: virtual void ForceFinishNode() override; +protected: + virtual void PrepareSaveData_Implementation() override; + virtual void OnSaveDataLoaded_Implementation() override; + +public: #if WITH_EDITOR virtual FString GetNodeDescription() const override; virtual UObject* GetAssetToEdit() override; diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h b/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h index d0fd311b7..d3fc70c79 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h @@ -22,21 +22,32 @@ class FLOW_API UFlowNode_Timer final : public UFlowNode private: FTimerHandle CompletionTimerHandle; - + FTimerHandle StepTimerHandle; float SumOfSteps; + UPROPERTY(SaveGame) + float RemainingCompletionTime; + + UPROPERTY(SaveGame) + float RemainingStepTime; + protected: virtual void ExecuteInput(const FName& PinName) override; +private: UFUNCTION() void OnStep(); UFUNCTION() void OnCompletion(); +protected: virtual void Cleanup() override; + virtual void PrepareSaveData_Implementation() override; + virtual void OnSaveDataLoaded_Implementation() override; + #if WITH_EDITOR virtual FString GetNodeDescription() const override; virtual FString GetStatusString() const override; diff --git a/Source/Flow/Public/Nodes/Utils/FlowNode_Checkpoint.h b/Source/Flow/Public/Nodes/Utils/FlowNode_Checkpoint.h new file mode 100644 index 000000000..2e77b9e0f --- /dev/null +++ b/Source/Flow/Public/Nodes/Utils/FlowNode_Checkpoint.h @@ -0,0 +1,17 @@ +#pragma once + +#include "Nodes/FlowNode.h" +#include "FlowNode_Checkpoint.generated.h" + +/** + * Save the state of the game + * 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 : public UFlowNode +{ + GENERATED_UCLASS_BODY() + +protected: + virtual void ExecuteInput(const FName& PinName) override; +}; From 5836b85effe8391c961800c3de03f32b667e34eb Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 4 May 2021 14:08:40 +0200 Subject: [PATCH 087/265] includes --- Source/Flow/Private/FlowAsset.cpp | 3 +++ Source/Flow/Private/FlowComponent.cpp | 2 ++ Source/Flow/Private/FlowSubsystem.cpp | 2 ++ 3 files changed, 7 insertions(+) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 99e7cbbe2..b89a4b845 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -8,6 +8,9 @@ #include "Nodes/Route/FlowNode_Finish.h" #include "Nodes/Route/FlowNode_SubGraph.h" +#include "Serialization/MemoryReader.h" +#include "Serialization/MemoryWriter.h" + UFlowAsset::UFlowAsset(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) #if WITH_EDITOR diff --git a/Source/Flow/Private/FlowComponent.cpp b/Source/Flow/Private/FlowComponent.cpp index c9dacb0bc..3598e40b6 100644 --- a/Source/Flow/Private/FlowComponent.cpp +++ b/Source/Flow/Private/FlowComponent.cpp @@ -7,6 +7,8 @@ #include "Engine/GameInstance.h" #include "Engine/World.h" #include "Net/UnrealNetwork.h" +#include "Serialization/MemoryReader.h" +#include "Serialization/MemoryWriter.h" UFlowComponent::UFlowComponent(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index 198fa9298..f561e2fe5 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -12,6 +12,8 @@ #include "Misc/FileHelper.h" #include "Misc/Paths.h" #include "Serialization/BufferArchive.h" +#include "Serialization/MemoryReader.h" +#include "Serialization/MemoryWriter.h" UFlowSubsystem::UFlowSubsystem() : UGameInstanceSubsystem() From 29a48a6b3b733a276c0f12f4f14532abbe56a469 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 4 May 2021 16:30:38 +0200 Subject: [PATCH 088/265] SaveGame fixes --- Source/Flow/Private/FlowAsset.cpp | 11 ++++- Source/Flow/Private/FlowComponent.cpp | 38 +++++++-------- Source/Flow/Private/FlowSubsystem.cpp | 46 ++++++++++++++----- .../Nodes/Utils/FlowNode_Checkpoint.cpp | 2 + Source/Flow/Public/FlowAsset.h | 2 + Source/Flow/Public/FlowComponent.h | 2 +- Source/Flow/Public/FlowSave.h | 9 ++-- Source/Flow/Public/FlowSubsystem.h | 8 +++- Source/Flow/Public/FlowTypes.h | 3 +- Source/Flow/Public/Nodes/FlowNode.h | 6 +-- 10 files changed, 83 insertions(+), 44 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index b89a4b845..0a09507bb 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -285,7 +285,7 @@ void UFlowAsset::PreloadNodes() } } -void UFlowAsset::StartFlow() +void UFlowAsset::PreStartFlow() { ResetNodes(); @@ -299,6 +299,11 @@ void UFlowAsset::StartFlow() TemplateAsset->BroadcastRegenerateToolbars(); } #endif +} + +void UFlowAsset::StartFlow() +{ + PreStartFlow(); ensureAlways(StartNode); RecordedNodes.Add(StartNode); @@ -447,7 +452,7 @@ FFlowAssetSaveData UFlowAsset::SaveInstance() for (const TPair& Node : Nodes) { - if (Node.Value) + if (Node.Value && Node.Value->ActivationState == EFlowActivationState::Active) { FFlowNodeSaveData NodeRecord; Node.Value->SaveInstance(NodeRecord); @@ -469,6 +474,8 @@ void UFlowAsset::LoadInstance(const FFlowAssetSaveData& AssetRecord) FFlowArchive Ar(MemoryReader); Serialize(Ar); + PreStartFlow(); + for (const FFlowNodeSaveData& NodeRecord : AssetRecord.NodeRecords) { if (UFlowNode* Node = Nodes.FindRef(NodeRecord.NodeGuid)) diff --git a/Source/Flow/Private/FlowComponent.cpp b/Source/Flow/Private/FlowComponent.cpp index 3598e40b6..a4c2500e4 100644 --- a/Source/Flow/Private/FlowComponent.cpp +++ b/Source/Flow/Private/FlowComponent.cpp @@ -44,11 +44,7 @@ void UFlowComponent::BeginPlay() bool bComponentLoadedFromSaveGame = false; if (GetFlowSubsystem()->IsSaveGameLoaded()) { - // temp hack, checking if Flow Component is inside World Settings - if (bAllowMultipleInstances == false) - { - bComponentLoadedFromSaveGame = LoadInstance(); - } + bComponentLoadedFromSaveGame = LoadInstance(); } FlowSubsystem->RegisterComponent(this); @@ -358,27 +354,30 @@ UFlowAsset* UFlowComponent::GetRootFlowInstance() FFlowAssetSaveData UFlowComponent::SaveRootFlow() { - SavedAssetInstance = FFlowAssetSaveData(); - if (UFlowAsset* FlowAssetInstance = GetRootFlowInstance()) { - SavedAssetInstance = FlowAssetInstance->SaveInstance(); + const FFlowAssetSaveData AssetRecord = FlowAssetInstance->SaveInstance(); + SavedAssetInstanceName = AssetRecord.InstanceName; + return AssetRecord; } - return SavedAssetInstance; + return FFlowAssetSaveData(); } void UFlowComponent::LoadRootFlow() { if (RootFlow && GetFlowSubsystem()) { - GetFlowSubsystem()->LoadRootFlow(this, RootFlow, SavedAssetInstance); + GetFlowSubsystem()->LoadRootFlow(this, RootFlow, SavedAssetInstanceName); } } FFlowComponentSaveData UFlowComponent::SaveInstance() { FFlowComponentSaveData ComponentRecord; + ComponentRecord.WorldName = GetWorld()->GetName(); + ComponentRecord.ActorInstanceName = GetOwner()->GetName(); + PrepareSaveData(); FMemoryWriter MemoryWriter(ComponentRecord.ComponentData, true); @@ -393,15 +392,18 @@ bool UFlowComponent::LoadInstance() const FFlowSaveData SaveData = GetFlowSubsystem()->GetLoadedSaveGame(); if (SaveData.SavedFlowComponents.Num() > 0) { - // temp hack, checking if Flow Component is inside World Settings - const FFlowComponentSaveData& ComponentRecord = SaveData.SavedFlowComponents[0]; - - FMemoryReader MemoryReader(ComponentRecord.ComponentData, true); - FFlowArchive Ar(MemoryReader); - Serialize(Ar); + for (const FFlowComponentSaveData& ComponentRecord : SaveData.SavedFlowComponents) + { + if (ComponentRecord.WorldName == GetWorld()->GetName() && ComponentRecord.ActorInstanceName == GetOwner()->GetName()) + { + FMemoryReader MemoryReader(ComponentRecord.ComponentData, true); + FFlowArchive Ar(MemoryReader); + Serialize(Ar); - OnSaveDataLoaded(); - return true; + OnSaveDataLoaded(); + return true; + } + } } return false; diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index f561e2fe5..049254e29 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -34,7 +34,7 @@ bool UFlowSubsystem::ShouldCreateSubsystem(UObject* Outer) const void UFlowSubsystem::Initialize(FSubsystemCollectionBase& Collection) { // temp for testing, game should control this - LoadGame(); + //LoadGame(); } void UFlowSubsystem::Deinitialize() @@ -54,7 +54,16 @@ void UFlowSubsystem::Deinitialize() } } -UFlowAsset* UFlowSubsystem::StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances /* = true */) +void UFlowSubsystem::StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances /* = true */) +{ + UFlowAsset* NewFlow = CreateRootFlow(Owner, FlowAsset, bAllowMultipleInstances); + if (NewFlow) + { + NewFlow->StartFlow(); + } +} + +UFlowAsset* UFlowSubsystem::CreateRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances) { if (RootInstances.Contains(Owner)) { @@ -71,7 +80,6 @@ UFlowAsset* UFlowSubsystem::StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset, UFlowAsset* NewFlow = CreateFlowInstance(Owner, FlowAsset); RootInstances.Add(Owner, NewFlow); - NewFlow->StartFlow(); return NewFlow; } @@ -197,11 +205,7 @@ void UFlowSubsystem::SaveGame() const TSet> FlowComponents = TSet>(ComponentsArray); for (TWeakObjectPtr FlowComponent : FlowComponents) { - // temp hack, checking if Flow Component is inside World Settings - if (FlowComponent->bAllowMultipleInstances == false) - { - SaveGameData.SavedFlowComponents.Emplace(FlowComponent->SaveInstance()); - } + SaveGameData.SavedFlowComponents.Emplace(FlowComponent->SaveInstance()); } FBufferArchive BinaryData; @@ -244,16 +248,34 @@ void UFlowSubsystem::LoadGame() } } -void UFlowSubsystem::LoadRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const FFlowAssetSaveData AssetRecord) +void UFlowSubsystem::LoadRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const FString& SavedAssetInstanceName) { - UFlowAsset* LoadedInstance = StartRootFlow(Owner, FlowAsset, false); - LoadedInstance->LoadInstance(AssetRecord); + if (SavedAssetInstanceName.IsEmpty()) + { + return; + } + + for (const FFlowAssetSaveData& AssetRecord : LoadedSaveGame.SavedRootFlowInstances) + { + if (AssetRecord.InstanceName == SavedAssetInstanceName) + { + UFlowAsset* LoadedInstance = CreateRootFlow(Owner, FlowAsset, false); + if (LoadedInstance) + { + LoadedInstance->LoadInstance(AssetRecord); + } + return; + } + } } void UFlowSubsystem::LoadSubFlow(UFlowNode_SubGraph* SubGraphNode, const FFlowAssetSaveData AssetRecord) { UFlowAsset* LoadedInstance = StartSubFlow(SubGraphNode, AssetRecord.InstanceName); - LoadedInstance->LoadInstance(AssetRecord); + if (LoadedInstance) + { + LoadedInstance->LoadInstance(AssetRecord); + } } FString UFlowSubsystem::GetSaveFolderDir() diff --git a/Source/Flow/Private/Nodes/Utils/FlowNode_Checkpoint.cpp b/Source/Flow/Private/Nodes/Utils/FlowNode_Checkpoint.cpp index ea752d51e..550d9192e 100644 --- a/Source/Flow/Private/Nodes/Utils/FlowNode_Checkpoint.cpp +++ b/Source/Flow/Private/Nodes/Utils/FlowNode_Checkpoint.cpp @@ -15,4 +15,6 @@ void UFlowNode_Checkpoint::ExecuteInput(const FName& PinName) { GetFlowSubsystem()->SaveGame(); } + + TriggerFirstOutput(true); } diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 2caf55070..e2df814da 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -203,8 +203,10 @@ class FLOW_API UFlowAsset : public UObject virtual void PreloadNodes(); + virtual void PreStartFlow(); virtual void StartFlow(); virtual void StartAsSubFlow(UFlowNode_SubGraph* SubGraphNode); + virtual void FinishFlow(const bool bFlowCompleted); // Get Flow Asset instance created by the given SubGraph node diff --git a/Source/Flow/Public/FlowComponent.h b/Source/Flow/Public/FlowComponent.h index 4dbed6251..c1ce17d85 100644 --- a/Source/Flow/Public/FlowComponent.h +++ b/Source/Flow/Public/FlowComponent.h @@ -178,7 +178,7 @@ class FLOW_API UFlowComponent : public UActorComponent bool bAllowMultipleInstances; UPROPERTY(SaveGame) - FFlowAssetSaveData SavedAssetInstance; + FString SavedAssetInstanceName; // This will instantiate Flow Asset assigned on this component. // Created Flow Asset instance will be a "root flow", as additional Flow Assets can be instantiated via Sub Graph node diff --git a/Source/Flow/Public/FlowSave.h b/Source/Flow/Public/FlowSave.h index 52456acfd..6d3e239b7 100644 --- a/Source/Flow/Public/FlowSave.h +++ b/Source/Flow/Public/FlowSave.h @@ -48,15 +48,15 @@ struct FLOW_API FFlowComponentSaveData { GENERATED_USTRUCT_BODY() - FString AssetPath; - FString InstanceName; + FString WorldName; + FString ActorInstanceName; TArray ComponentData; friend FArchive& operator<<(FArchive& Ar, FFlowComponentSaveData& InComponentData) { - Ar << InComponentData.AssetPath; - Ar << InComponentData.InstanceName; + Ar << InComponentData.WorldName; + Ar << InComponentData.ActorInstanceName; Ar << InComponentData.ComponentData; return Ar; } @@ -83,6 +83,7 @@ struct FLOW_API FFlowSaveData friend FArchive& operator<<(FArchive& Ar, FFlowSaveData& FlowData) { Ar << FlowData.Timestamp; + Ar << FlowData.SavedFlowComponents; Ar << FlowData.SavedRootFlowInstances; return Ar; } diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index edc122992..fe4d79204 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -55,8 +55,12 @@ 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") - UFlowAsset* StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances = true); + 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); @@ -95,7 +99,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem UFUNCTION(BlueprintCallable, Category = "FlowSubsystem") virtual void LoadGame(); - virtual void LoadRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const FFlowAssetSaveData AssetRecord); + virtual void LoadRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const FString& SavedAssetInstanceName); virtual void LoadSubFlow(UFlowNode_SubGraph* SubGraphNode, const FFlowAssetSaveData AssetRecord); UFUNCTION(BlueprintPure, Category = "FlowSubsystem") diff --git a/Source/Flow/Public/FlowTypes.h b/Source/Flow/Public/FlowTypes.h index 52a62cd34..8c569c158 100644 --- a/Source/Flow/Public/FlowTypes.h +++ b/Source/Flow/Public/FlowTypes.h @@ -16,14 +16,13 @@ enum class EFlowNodeStyle : uint8 }; #endif -#if !UE_BUILD_SHIPPING +UENUM(BlueprintType) enum class EFlowActivationState : uint8 { NeverActivated, Active, WasActive }; -#endif UENUM(BlueprintType) enum class EFlowNetMode : uint8 diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 3a0edc33b..60081a9b7 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -185,10 +185,10 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte protected: FStreamableManager StreamableManager; -#if !UE_BUILD_SHIPPING -protected: + UPROPERTY(SaveGame) EFlowActivationState ActivationState; - + +#if !UE_BUILD_SHIPPING private: TMap> InputRecords; TMap> OutputRecords; From 97e3beec23d6cb2899bed8601e52dbff75aae3d5 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 4 May 2021 17:48:25 +0200 Subject: [PATCH 089/265] restoring Sub Graps from GameSave --- Source/Flow/Private/FlowAsset.cpp | 30 ++++++++++++++++--- Source/Flow/Private/FlowComponent.cpp | 26 ++++++++-------- Source/Flow/Private/FlowSubsystem.cpp | 21 ++++++++----- Source/Flow/Private/Nodes/FlowNode.cpp | 12 ++++---- .../Private/Nodes/Route/FlowNode_SubGraph.cpp | 23 +++----------- .../Private/Nodes/Route/FlowNode_Timer.cpp | 4 +-- Source/Flow/Public/FlowAsset.h | 12 +++++++- Source/Flow/Public/FlowComponent.h | 6 ++-- Source/Flow/Public/FlowSave.h | 8 ++--- Source/Flow/Public/FlowSubsystem.h | 2 +- Source/Flow/Public/Nodes/FlowNode.h | 6 ++-- .../Public/Nodes/Route/FlowNode_SubGraph.h | 8 ++--- .../Flow/Public/Nodes/Route/FlowNode_Timer.h | 4 +-- 13 files changed, 91 insertions(+), 71 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 0a09507bb..740fd2928 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -441,21 +441,32 @@ UFlowNode* UFlowAsset::GetNodeInstance(const FGuid Guid) const return Nodes.FindRef(Guid); } -FFlowAssetSaveData UFlowAsset::SaveInstance() +FFlowAssetSaveData UFlowAsset::SaveInstance(TArray& SavedFlowInstances) { FFlowAssetSaveData AssetRecord; //FSoftObjectPtr FlowAsset; //FArchiveUObject::SerializeSoftObjectPtr(AssetRecord.AssetClass, FlowAsset); - AssetRecord.AssetPath = GetPathName(); AssetRecord.InstanceName = GetName(); + PrepareGameSave(); + for (const TPair& Node : Nodes) { if (Node.Value && Node.Value->ActivationState == EFlowActivationState::Active) { + if (UFlowNode_SubGraph* SubGraphNode = Cast(Node.Value)) + { + const TWeakObjectPtr SubFlowInstance = GetFlowInstance(SubGraphNode); + if (SubFlowInstance.IsValid()) + { + const FFlowAssetSaveData SubAssetRecord = SubFlowInstance->SaveInstance(SavedFlowInstances); + SubGraphNode->SavedAssetInstanceName = SubAssetRecord.InstanceName; + } + } + FFlowNodeSaveData NodeRecord; - Node.Value->SaveInstance(NodeRecord); + Node.Value->SaveInstance(NodeRecord, SavedFlowInstances); AssetRecord.NodeRecords.Emplace(NodeRecord); } @@ -465,6 +476,7 @@ FFlowAssetSaveData UFlowAsset::SaveInstance() FFlowArchive Ar(MemoryWriter); Serialize(Ar); + SavedFlowInstances.Emplace(AssetRecord); return AssetRecord; } @@ -475,7 +487,7 @@ void UFlowAsset::LoadInstance(const FFlowAssetSaveData& AssetRecord) Serialize(Ar); PreStartFlow(); - + for (const FFlowNodeSaveData& NodeRecord : AssetRecord.NodeRecords) { if (UFlowNode* Node = Nodes.FindRef(NodeRecord.NodeGuid)) @@ -483,4 +495,14 @@ void UFlowAsset::LoadInstance(const FFlowAssetSaveData& AssetRecord) Node->LoadInstance(NodeRecord); } } + + OnGameSaveLoaded(); +} + +void UFlowAsset::PrepareGameSave_Implementation() +{ +} + +void UFlowAsset::OnGameSaveLoaded_Implementation() +{ } diff --git a/Source/Flow/Private/FlowComponent.cpp b/Source/Flow/Private/FlowComponent.cpp index a4c2500e4..c394935e3 100644 --- a/Source/Flow/Private/FlowComponent.cpp +++ b/Source/Flow/Private/FlowComponent.cpp @@ -55,12 +55,9 @@ void UFlowComponent::BeginPlay() { LoadRootFlow(); } - else + else if (bAutoStartRootFlow) { - if (bAutoStartRootFlow) - { - StartRootFlow(); - } + StartRootFlow(); } } } @@ -352,23 +349,24 @@ UFlowAsset* UFlowComponent::GetRootFlowInstance() return nullptr; } -FFlowAssetSaveData UFlowComponent::SaveRootFlow() +void UFlowComponent::SaveRootFlow(TArray& SavedFlowInstances) { if (UFlowAsset* FlowAssetInstance = GetRootFlowInstance()) { - const FFlowAssetSaveData AssetRecord = FlowAssetInstance->SaveInstance(); + const FFlowAssetSaveData AssetRecord = FlowAssetInstance->SaveInstance(SavedFlowInstances); SavedAssetInstanceName = AssetRecord.InstanceName; - return AssetRecord; + return; } - return FFlowAssetSaveData(); + SavedAssetInstanceName = FString(); } void UFlowComponent::LoadRootFlow() { - if (RootFlow && GetFlowSubsystem()) + if (RootFlow && !SavedAssetInstanceName.IsEmpty() && GetFlowSubsystem()) { GetFlowSubsystem()->LoadRootFlow(this, RootFlow, SavedAssetInstanceName); + SavedAssetInstanceName = FString(); } } @@ -378,7 +376,7 @@ FFlowComponentSaveData UFlowComponent::SaveInstance() ComponentRecord.WorldName = GetWorld()->GetName(); ComponentRecord.ActorInstanceName = GetOwner()->GetName(); - PrepareSaveData(); + PrepareGameSave(); FMemoryWriter MemoryWriter(ComponentRecord.ComponentData, true); FFlowArchive Ar(MemoryWriter); @@ -400,7 +398,7 @@ bool UFlowComponent::LoadInstance() FFlowArchive Ar(MemoryReader); Serialize(Ar); - OnSaveDataLoaded(); + OnGameSaveLoaded(); return true; } } @@ -409,11 +407,11 @@ bool UFlowComponent::LoadInstance() return false; } -void UFlowComponent::OnSaveDataLoaded_Implementation() +void UFlowComponent::PrepareGameSave_Implementation() { } -void UFlowComponent::PrepareSaveData_Implementation() +void UFlowComponent::OnGameSaveLoaded_Implementation() { } diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index 049254e29..f2d12c876 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -191,11 +191,11 @@ void UFlowSubsystem::SaveGame() { if (UFlowComponent* FlowComponent = Cast(Pair.Key)) { - SaveGameData.SavedRootFlowInstances.Emplace(FlowComponent->SaveRootFlow()); + FlowComponent->SaveRootFlow(SaveGameData.SavedFlowInstances); } else { - SaveGameData.SavedRootFlowInstances.Emplace(Pair.Value->SaveInstance()); + Pair.Value->SaveInstance(SaveGameData.SavedFlowInstances); } } } @@ -255,7 +255,7 @@ void UFlowSubsystem::LoadRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const F return; } - for (const FFlowAssetSaveData& AssetRecord : LoadedSaveGame.SavedRootFlowInstances) + for (const FFlowAssetSaveData& AssetRecord : LoadedSaveGame.SavedFlowInstances) { if (AssetRecord.InstanceName == SavedAssetInstanceName) { @@ -269,12 +269,19 @@ void UFlowSubsystem::LoadRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const F } } -void UFlowSubsystem::LoadSubFlow(UFlowNode_SubGraph* SubGraphNode, const FFlowAssetSaveData AssetRecord) +void UFlowSubsystem::LoadSubFlow(UFlowNode_SubGraph* SubGraphNode, const FString& SavedAssetInstanceName) { - UFlowAsset* LoadedInstance = StartSubFlow(SubGraphNode, AssetRecord.InstanceName); - if (LoadedInstance) + for (const FFlowAssetSaveData& AssetRecord : LoadedSaveGame.SavedFlowInstances) { - LoadedInstance->LoadInstance(AssetRecord); + if (AssetRecord.InstanceName == SavedAssetInstanceName) + { + UFlowAsset* LoadedInstance = StartSubFlow(SubGraphNode, SavedAssetInstanceName); + if (LoadedInstance) + { + LoadedInstance->LoadInstance(AssetRecord); + } + return; + } } } diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 9214a4756..990006777 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -555,11 +555,11 @@ void UFlowNode::LogError(FString Message) UE_LOG(LogFlow, Error, TEXT("%s"), *Message); } -void UFlowNode::SaveInstance(FFlowNodeSaveData& NodeRecord) +void UFlowNode::SaveInstance(FFlowNodeSaveData& NodeRecord, TArray& SavedFlowInstances) { NodeRecord.NodeGuid = NodeGuid; - PrepareSaveData(); - + PrepareGameSave(); + FMemoryWriter MemoryWriter(NodeRecord.NodeData, true); FFlowArchive Ar(MemoryWriter); Serialize(Ar); @@ -571,13 +571,13 @@ void UFlowNode::LoadInstance(const FFlowNodeSaveData& NodeRecord) FFlowArchive Ar(MemoryReader); Serialize(Ar); - OnSaveDataLoaded(); + OnGameSaveLoaded(); } -void UFlowNode::OnSaveDataLoaded_Implementation() +void UFlowNode::PrepareGameSave_Implementation() { } -void UFlowNode::PrepareSaveData_Implementation() +void UFlowNode::OnGameSaveLoaded_Implementation() { } diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp index a80c77c6b..581b723cd 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp @@ -67,27 +67,12 @@ void UFlowNode_SubGraph::ForceFinishNode() TriggerFirstOutput(true); } -void UFlowNode_SubGraph::PrepareSaveData_Implementation() +void UFlowNode_SubGraph::OnGameSaveLoaded_Implementation() { - if (GetFlowAsset()) + if (!SavedAssetInstanceName.IsEmpty() && !Asset.IsNull()) { - const TWeakObjectPtr FlowInstance = GetFlowAsset()->GetFlowInstance(this); - if (FlowInstance.IsValid()) - { - SavedAssetInstance = FlowInstance->SaveInstance(); - return; - } - } - - SavedAssetInstance = FFlowAssetSaveData(); -} - -void UFlowNode_SubGraph::OnSaveDataLoaded_Implementation() -{ - if (!SavedAssetInstance.InstanceName.IsEmpty() && !Asset.IsNull()) - { - GetFlowSubsystem()->LoadSubFlow(this, SavedAssetInstance); - SavedAssetInstance = FFlowAssetSaveData(); + GetFlowSubsystem()->LoadSubFlow(this, SavedAssetInstanceName); + SavedAssetInstanceName = FString(); } } diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp index 75e69aa57..e5c60fe04 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp @@ -98,7 +98,7 @@ void UFlowNode_Timer::Cleanup() SumOfSteps = 0.0f; } -void UFlowNode_Timer::PrepareSaveData_Implementation() +void UFlowNode_Timer::PrepareGameSave_Implementation() { if (GetWorld()) { @@ -114,7 +114,7 @@ void UFlowNode_Timer::PrepareSaveData_Implementation() } } -void UFlowNode_Timer::OnSaveDataLoaded_Implementation() +void UFlowNode_Timer::OnGameSaveLoaded_Implementation() { if (RemainingStepTime > 0.0f) { diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index e2df814da..5986882a7 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -241,9 +241,19 @@ class FLOW_API UFlowAsset : public UObject UFUNCTION(BlueprintPure, Category = "Flow") TArray GetRecordedNodes() const { return RecordedNodes; } +////////////////////////////////////////////////////////////////////////// +// SaveGame + UFUNCTION(BlueprintCallable, Category = "Flow") - FFlowAssetSaveData SaveInstance(); + FFlowAssetSaveData SaveInstance(TArray& SavedFlowInstances); UFUNCTION(BlueprintCallable, Category = "Flow") void LoadInstance(const FFlowAssetSaveData& AssetRecord); + +protected: + UFUNCTION(BlueprintNativeEvent, Category = "SaveGame") + void PrepareGameSave(); + + UFUNCTION(BlueprintNativeEvent, Category = "SaveGame") + void OnGameSaveLoaded(); }; diff --git a/Source/Flow/Public/FlowComponent.h b/Source/Flow/Public/FlowComponent.h index c1ce17d85..3ee4fd883 100644 --- a/Source/Flow/Public/FlowComponent.h +++ b/Source/Flow/Public/FlowComponent.h @@ -196,7 +196,7 @@ class FLOW_API UFlowComponent : public UActorComponent // SaveGame UFUNCTION(BlueprintCallable, Category = "SaveGame") - virtual FFlowAssetSaveData SaveRootFlow(); + virtual void SaveRootFlow(TArray& SavedFlowInstances); UFUNCTION(BlueprintCallable, Category = "SaveGame") virtual void LoadRootFlow(); @@ -209,10 +209,10 @@ class FLOW_API UFlowComponent : public UActorComponent protected: UFUNCTION(BlueprintNativeEvent, Category = "SaveGame") - void PrepareSaveData(); + void PrepareGameSave(); UFUNCTION(BlueprintNativeEvent, Category = "SaveGame") - void OnSaveDataLoaded(); + void OnGameSaveLoaded(); ////////////////////////////////////////////////////////////////////////// // Helpers diff --git a/Source/Flow/Public/FlowSave.h b/Source/Flow/Public/FlowSave.h index 6d3e239b7..caf613d6b 100644 --- a/Source/Flow/Public/FlowSave.h +++ b/Source/Flow/Public/FlowSave.h @@ -25,7 +25,6 @@ struct FLOW_API FFlowAssetSaveData { GENERATED_USTRUCT_BODY() - FString AssetPath; FString InstanceName; TArray AssetData; @@ -34,7 +33,6 @@ struct FLOW_API FFlowAssetSaveData friend FArchive& operator<<(FArchive& Ar, FFlowAssetSaveData& InAssetData) { - Ar << InAssetData.AssetPath; Ar << InAssetData.InstanceName; Ar << InAssetData.AssetData; Ar << InAssetData.NodeRecords; @@ -78,18 +76,18 @@ struct FLOW_API FFlowSaveData FDateTime Timestamp; TArray SavedFlowComponents; - TArray SavedRootFlowInstances; + TArray SavedFlowInstances; friend FArchive& operator<<(FArchive& Ar, FFlowSaveData& FlowData) { Ar << FlowData.Timestamp; Ar << FlowData.SavedFlowComponents; - Ar << FlowData.SavedRootFlowInstances; + Ar << FlowData.SavedFlowInstances; return Ar; } bool IsValid() const { - return SavedRootFlowInstances.Num() > 0; + return SavedFlowInstances.Num() > 0; } }; diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index fe4d79204..f4321ab0c 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -100,7 +100,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem virtual void LoadGame(); virtual void LoadRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const FString& SavedAssetInstanceName); - virtual void LoadSubFlow(UFlowNode_SubGraph* SubGraphNode, const FFlowAssetSaveData AssetRecord); + virtual void LoadSubFlow(UFlowNode_SubGraph* SubGraphNode, const FString& SavedAssetInstanceName); UFUNCTION(BlueprintPure, Category = "FlowSubsystem") bool IsSaveGameLoaded() const { return LoadedSaveGame.IsValid(); } diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 60081a9b7..d21b5c03a 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -337,17 +337,17 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte void LogError(FString Message); UFUNCTION(BlueprintCallable, Category = "FlowNode") - void SaveInstance(FFlowNodeSaveData& NodeRecord); + void SaveInstance(FFlowNodeSaveData& NodeRecord, TArray& SavedFlowInstances); UFUNCTION(BlueprintCallable, Category = "FlowNode") void LoadInstance(const FFlowNodeSaveData& NodeRecord); protected: UFUNCTION(BlueprintNativeEvent, Category = "FlowNode") - void PrepareSaveData(); + void PrepareGameSave(); UFUNCTION(BlueprintNativeEvent, Category = "FlowNode") - void OnSaveDataLoaded(); + void OnGameSaveLoaded(); private: UPROPERTY() diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h b/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h index ca1cb8d39..cde84fb9f 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h @@ -10,7 +10,8 @@ UCLASS(NotBlueprintable, meta = (DisplayName = "Sub Graph")) class FLOW_API UFlowNode_SubGraph : public UFlowNode { GENERATED_UCLASS_BODY() - + + friend class UFlowAsset; friend class UFlowSubsystem; static FFlowPin StartPin; @@ -21,7 +22,7 @@ class FLOW_API UFlowNode_SubGraph : public UFlowNode TSoftObjectPtr Asset; UPROPERTY(SaveGame) - FFlowAssetSaveData SavedAssetInstance; + FString SavedAssetInstanceName; protected: virtual void PreloadContent() override; @@ -34,8 +35,7 @@ class FLOW_API UFlowNode_SubGraph : public UFlowNode virtual void ForceFinishNode() override; protected: - virtual void PrepareSaveData_Implementation() override; - virtual void OnSaveDataLoaded_Implementation() override; + virtual void OnGameSaveLoaded_Implementation() override; public: #if WITH_EDITOR diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h b/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h index d3fc70c79..a5d5d0811 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h @@ -45,8 +45,8 @@ class FLOW_API UFlowNode_Timer final : public UFlowNode protected: virtual void Cleanup() override; - virtual void PrepareSaveData_Implementation() override; - virtual void OnSaveDataLoaded_Implementation() override; + virtual void PrepareGameSave_Implementation() override; + virtual void OnGameSaveLoaded_Implementation() override; #if WITH_EDITOR virtual FString GetNodeDescription() const override; From 04f27d627ae36ab6be6dd51a68c46eaf6e2c9843 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Tue, 4 May 2021 17:52:50 +0200 Subject: [PATCH 090/265] Update README.md --- README.md | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 8c004f3e5..1c45bd292 100644 --- a/README.md +++ b/README.md @@ -12,24 +12,19 @@ It's a design-agnostic event node editor. * Editor supports convenient displaying debug information on nodes and wires while playing a game. You simply provide what kind of message would be displayed over active Flow Nodes - you can't have that with blueprint functions. * It's up to you to add game-specific functionalities by writing your nodes and editor customizations. It's not like a marketplace providing the very specific implementation of systems. It's a convenient base for building systems tailored to fit your needs. * Read documentation on the project wiki. I'd recommend starting from reading about [design philosophy](https://github.com/MothCocoon/FlowGraph/wiki). +* It's easy to include pluing 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. [![Introducing Flow Graph for Unreal Engine](https://img.youtube.com/vi/Rj76JP1f-I4/0.jpg)](https://www.youtube.com/watch?v=Rj76JP1f-I4) -## Getting started -* It's easy to include pluing in your own project, follow this short [Getting Started](https://github.com/MothCocoon/FlowGraph/wiki/Getting-Started) guide. -* The [legacy repository](https://github.com/MothCocoon/Flow) gonna be upgraded in future, so it would includ FlowGraph (this repo) and [FlowSamples](https://github.com/MothCocoon/FlowSamples) as git submodules. -* Plugin and the code of the sample project are available for every engine version since 4.22. I'm not planning on backporting code to older engine versions since the runtime code relies on [programming subsystems](https://docs.unrealengine.com/en-US/ProgrammingAndScripting/Subsystems/index.html) introduced with UE 4.22. -* I'm planning to release the Flow plugin on the Marketplace, so more people could discover it and conveniently add it to their asset libraries. It will be free of charge, obviously. - ## 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. * 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. Written from the scratch, 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. +* 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. ## Contact * Catch me on Twitter: [@MothDoctor](https://twitter.com/MothDoctor) From 7f66cec2415045cc30a56ea6285072da177cbb8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Tue, 4 May 2021 18:03:31 +0200 Subject: [PATCH 091/265] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1c45bd292..827d4bd04 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ It's a design-agnostic event node editor. * Editor supports convenient displaying debug information on nodes and wires while playing a game. You simply provide what kind of message would be displayed over active Flow Nodes - you can't have that with blueprint functions. * It's up to you to add game-specific functionalities by writing your nodes and editor customizations. It's not like a marketplace providing the very specific implementation of systems. It's a convenient base for building systems tailored to fit your needs. * Read documentation on the project wiki. I'd recommend starting from reading about [design philosophy](https://github.com/MothCocoon/FlowGraph/wiki). -* It's easy to include pluing in your own project, follow this short [Getting Started](https://github.com/MothCocoon/FlowGraph/wiki/Getting-Started) guide. +* 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. From e502cc024aa0eccd45ace8542de5af5d5766a245 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 9 May 2021 18:37:03 +0200 Subject: [PATCH 092/265] #10: SaveGame system now uses USaveGame --- Source/Flow/Private/FlowAsset.cpp | 10 +-- Source/Flow/Private/FlowComponent.cpp | 16 ++--- Source/Flow/Private/FlowSettings.cpp | 1 - Source/Flow/Private/FlowSubsystem.cpp | 67 +++---------------- Source/Flow/Private/Nodes/FlowNode.cpp | 10 +-- .../Private/Nodes/Route/FlowNode_SubGraph.cpp | 2 +- .../Private/Nodes/Route/FlowNode_Timer.cpp | 4 +- .../Nodes/Utils/FlowNode_Checkpoint.cpp | 12 +++- .../World/FlowNode_ComponentObserver.cpp | 8 +++ .../World/FlowNode_PlayLevelSequence.cpp | 35 +++++++++- Source/Flow/Public/FlowAsset.h | 4 +- Source/Flow/Public/FlowComponent.h | 4 +- Source/Flow/Public/FlowSave.h | 58 ++++++++-------- Source/Flow/Public/FlowSettings.h | 3 - Source/Flow/Public/FlowSubsystem.h | 20 +++--- Source/Flow/Public/Nodes/FlowNode.h | 6 +- .../Nodes/Operators/FlowNode_LogicalAND.h | 1 + .../Public/Nodes/Route/FlowNode_Counter.h | 1 + .../Nodes/Route/FlowNode_ExecutionMultiGate.h | 4 +- .../Public/Nodes/Route/FlowNode_SubGraph.h | 2 +- .../Flow/Public/Nodes/Route/FlowNode_Timer.h | 7 +- .../Public/Nodes/Utils/FlowNode_Checkpoint.h | 7 +- .../Nodes/World/FlowNode_ComponentObserver.h | 3 +- .../Nodes/World/FlowNode_PlayLevelSequence.h | 12 +++- 24 files changed, 156 insertions(+), 141 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 740fd2928..5184bcc4a 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -449,7 +449,7 @@ FFlowAssetSaveData UFlowAsset::SaveInstance(TArray& SavedFlo //FArchiveUObject::SerializeSoftObjectPtr(AssetRecord.AssetClass, FlowAsset); AssetRecord.InstanceName = GetName(); - PrepareGameSave(); + OnSave(); for (const TPair& Node : Nodes) { @@ -466,7 +466,7 @@ FFlowAssetSaveData UFlowAsset::SaveInstance(TArray& SavedFlo } FFlowNodeSaveData NodeRecord; - Node.Value->SaveInstance(NodeRecord, SavedFlowInstances); + Node.Value->SaveInstance(NodeRecord); AssetRecord.NodeRecords.Emplace(NodeRecord); } @@ -496,13 +496,13 @@ void UFlowAsset::LoadInstance(const FFlowAssetSaveData& AssetRecord) } } - OnGameSaveLoaded(); + OnLoad(); } -void UFlowAsset::PrepareGameSave_Implementation() +void UFlowAsset::OnSave_Implementation() { } -void UFlowAsset::OnGameSaveLoaded_Implementation() +void UFlowAsset::OnLoad_Implementation() { } diff --git a/Source/Flow/Private/FlowComponent.cpp b/Source/Flow/Private/FlowComponent.cpp index c394935e3..6ff88bc1b 100644 --- a/Source/Flow/Private/FlowComponent.cpp +++ b/Source/Flow/Private/FlowComponent.cpp @@ -42,7 +42,7 @@ void UFlowComponent::BeginPlay() if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) { bool bComponentLoadedFromSaveGame = false; - if (GetFlowSubsystem()->IsSaveGameLoaded()) + if (GetFlowSubsystem()->GetLoadedSaveGame()) { bComponentLoadedFromSaveGame = LoadInstance(); } @@ -376,7 +376,7 @@ FFlowComponentSaveData UFlowComponent::SaveInstance() ComponentRecord.WorldName = GetWorld()->GetName(); ComponentRecord.ActorInstanceName = GetOwner()->GetName(); - PrepareGameSave(); + OnSave(); FMemoryWriter MemoryWriter(ComponentRecord.ComponentData, true); FFlowArchive Ar(MemoryWriter); @@ -387,10 +387,10 @@ FFlowComponentSaveData UFlowComponent::SaveInstance() bool UFlowComponent::LoadInstance() { - const FFlowSaveData SaveData = GetFlowSubsystem()->GetLoadedSaveGame(); - if (SaveData.SavedFlowComponents.Num() > 0) + const UFlowSaveGame* SaveGame = GetFlowSubsystem()->GetLoadedSaveGame(); + if (SaveGame->FlowComponents.Num() > 0) { - for (const FFlowComponentSaveData& ComponentRecord : SaveData.SavedFlowComponents) + for (const FFlowComponentSaveData& ComponentRecord : SaveGame->FlowComponents) { if (ComponentRecord.WorldName == GetWorld()->GetName() && ComponentRecord.ActorInstanceName == GetOwner()->GetName()) { @@ -398,7 +398,7 @@ bool UFlowComponent::LoadInstance() FFlowArchive Ar(MemoryReader); Serialize(Ar); - OnGameSaveLoaded(); + OnLoad(); return true; } } @@ -407,11 +407,11 @@ bool UFlowComponent::LoadInstance() return false; } -void UFlowComponent::PrepareGameSave_Implementation() +void UFlowComponent::OnSave_Implementation() { } -void UFlowComponent::OnGameSaveLoaded_Implementation() +void UFlowComponent::OnLoad_Implementation() { } diff --git a/Source/Flow/Private/FlowSettings.cpp b/Source/Flow/Private/FlowSettings.cpp index 6b6fcbf5f..f31c414ed 100644 --- a/Source/Flow/Private/FlowSettings.cpp +++ b/Source/Flow/Private/FlowSettings.cpp @@ -3,6 +3,5 @@ UFlowSettings::UFlowSettings(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) , bCreateFlowSubsystemOnClients(true) - , SaveFolderName(TEXT("Saves")) { } diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index f2d12c876..ba8350c74 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -11,9 +11,6 @@ #include "Engine/World.h" #include "Misc/FileHelper.h" #include "Misc/Paths.h" -#include "Serialization/BufferArchive.h" -#include "Serialization/MemoryReader.h" -#include "Serialization/MemoryWriter.h" UFlowSubsystem::UFlowSubsystem() : UGameInstanceSubsystem() @@ -33,8 +30,6 @@ bool UFlowSubsystem::ShouldCreateSubsystem(UObject* Outer) const void UFlowSubsystem::Initialize(FSubsystemCollectionBase& Collection) { - // temp for testing, game should control this - //LoadGame(); } void UFlowSubsystem::Deinitialize() @@ -180,72 +175,37 @@ UWorld* UFlowSubsystem::GetWorld() const return GetGameInstance()->GetWorld(); } -void UFlowSubsystem::SaveGame() +void UFlowSubsystem::OnGameSaved(UFlowSaveGame* SaveGame) { - FFlowSaveData SaveGameData; - SaveGameData.Timestamp = FDateTime::Now(); - + // save graphs with nodes for (const TPair, UFlowAsset*>& Pair : RootInstances) { if (Pair.Key.IsValid() && Pair.Value) { if (UFlowComponent* FlowComponent = Cast(Pair.Key)) { - FlowComponent->SaveRootFlow(SaveGameData.SavedFlowInstances); + FlowComponent->SaveRootFlow(SaveGame->FlowInstances); } else { - Pair.Value->SaveInstance(SaveGameData.SavedFlowInstances); + Pair.Value->SaveInstance(SaveGame->FlowInstances); } } } + // save components TArray> ComponentsArray; FlowComponentRegistry.GenerateValueArray(ComponentsArray); const TSet> FlowComponents = TSet>(ComponentsArray); for (TWeakObjectPtr FlowComponent : FlowComponents) { - SaveGameData.SavedFlowComponents.Emplace(FlowComponent->SaveInstance()); - } - - FBufferArchive BinaryData; - BinaryData << SaveGameData; - - const FString SaveFolder = GetSaveFolderDir() + FString("TestSave.sav"); - if (FFileHelper::SaveArrayToFile(BinaryData, *SaveFolder)) - { - UE_LOG(LogFlow, Warning, TEXT("Save Success! %s"), FPlatformProcess::BaseDir()); + SaveGame->FlowComponents.Emplace(FlowComponent->SaveInstance()); } - else - { - UE_LOG(LogFlow, Warning, TEXT("Save Failed!")); - } - - BinaryData.FlushCache(); - BinaryData.Empty(); } -void UFlowSubsystem::LoadGame() +void UFlowSubsystem::OnGameLoaded(UFlowSaveGame* SaveGame) { - const FString SaveFolder = GetSaveFolderDir() + FString("TestSave.sav"); - TArray BinaryData; - - if (FFileHelper::LoadFileToArray(BinaryData, *SaveFolder)) - { - UE_LOG(LogFlow, Warning, TEXT("Load Succeeded!")); - - FMemoryReader FromBinary = FMemoryReader(BinaryData, true); - FromBinary.Seek(0); - FromBinary << LoadedSaveGame;; - - FromBinary.FlushCache(); - BinaryData.Empty(); - FromBinary.Close(); - } - else - { - UE_LOG(LogFlow, Warning, TEXT("Load Failed!")); - } + LoadedSaveGame = SaveGame; } void UFlowSubsystem::LoadRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const FString& SavedAssetInstanceName) @@ -254,8 +214,8 @@ void UFlowSubsystem::LoadRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const F { return; } - - for (const FFlowAssetSaveData& AssetRecord : LoadedSaveGame.SavedFlowInstances) + + for (const FFlowAssetSaveData& AssetRecord : LoadedSaveGame->FlowInstances) { if (AssetRecord.InstanceName == SavedAssetInstanceName) { @@ -271,7 +231,7 @@ void UFlowSubsystem::LoadRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const F void UFlowSubsystem::LoadSubFlow(UFlowNode_SubGraph* SubGraphNode, const FString& SavedAssetInstanceName) { - for (const FFlowAssetSaveData& AssetRecord : LoadedSaveGame.SavedFlowInstances) + for (const FFlowAssetSaveData& AssetRecord : LoadedSaveGame->FlowInstances) { if (AssetRecord.InstanceName == SavedAssetInstanceName) { @@ -285,11 +245,6 @@ void UFlowSubsystem::LoadSubFlow(UFlowNode_SubGraph* SubGraphNode, const FString } } -FString UFlowSubsystem::GetSaveFolderDir() -{ - return FPaths::ProjectSavedDir() + UFlowSettings::Get()->SaveFolderName + TEXT("/"); -} - void UFlowSubsystem::RegisterComponent(UFlowComponent* Component) { for (const FGameplayTag& Tag : Component->IdentityTags) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 990006777..5edd9529e 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -555,10 +555,10 @@ void UFlowNode::LogError(FString Message) UE_LOG(LogFlow, Error, TEXT("%s"), *Message); } -void UFlowNode::SaveInstance(FFlowNodeSaveData& NodeRecord, TArray& SavedFlowInstances) +void UFlowNode::SaveInstance(FFlowNodeSaveData& NodeRecord) { NodeRecord.NodeGuid = NodeGuid; - PrepareGameSave(); + OnSave(); FMemoryWriter MemoryWriter(NodeRecord.NodeData, true); FFlowArchive Ar(MemoryWriter); @@ -571,13 +571,13 @@ void UFlowNode::LoadInstance(const FFlowNodeSaveData& NodeRecord) FFlowArchive Ar(MemoryReader); Serialize(Ar); - OnGameSaveLoaded(); + OnLoad(); } -void UFlowNode::PrepareGameSave_Implementation() +void UFlowNode::OnSave_Implementation() { } -void UFlowNode::OnGameSaveLoaded_Implementation() +void UFlowNode::OnLoad_Implementation() { } diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp index 581b723cd..84519ac41 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp @@ -67,7 +67,7 @@ void UFlowNode_SubGraph::ForceFinishNode() TriggerFirstOutput(true); } -void UFlowNode_SubGraph::OnGameSaveLoaded_Implementation() +void UFlowNode_SubGraph::OnLoad_Implementation() { if (!SavedAssetInstanceName.IsEmpty() && !Asset.IsNull()) { diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp index e5c60fe04..06423bb1a 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_Timer.cpp @@ -98,7 +98,7 @@ void UFlowNode_Timer::Cleanup() SumOfSteps = 0.0f; } -void UFlowNode_Timer::PrepareGameSave_Implementation() +void UFlowNode_Timer::OnSave_Implementation() { if (GetWorld()) { @@ -114,7 +114,7 @@ void UFlowNode_Timer::PrepareGameSave_Implementation() } } -void UFlowNode_Timer::OnGameSaveLoaded_Implementation() +void UFlowNode_Timer::OnLoad_Implementation() { if (RemainingStepTime > 0.0f) { diff --git a/Source/Flow/Private/Nodes/Utils/FlowNode_Checkpoint.cpp b/Source/Flow/Private/Nodes/Utils/FlowNode_Checkpoint.cpp index 550d9192e..a8e44589c 100644 --- a/Source/Flow/Private/Nodes/Utils/FlowNode_Checkpoint.cpp +++ b/Source/Flow/Private/Nodes/Utils/FlowNode_Checkpoint.cpp @@ -1,6 +1,8 @@ #include "Nodes/Utils/FlowNode_Checkpoint.h" #include "FlowSubsystem.h" +#include "Kismet/GameplayStatics.h" + UFlowNode_Checkpoint::UFlowNode_Checkpoint(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { @@ -13,8 +15,16 @@ void UFlowNode_Checkpoint::ExecuteInput(const FName& PinName) { if (GetFlowSubsystem()) { - GetFlowSubsystem()->SaveGame(); + UFlowSaveGame* NewSaveGame = Cast(UGameplayStatics::CreateSaveGameObject(UFlowSaveGame::StaticClass())); + GetFlowSubsystem()->OnGameSaved(NewSaveGame); + + UGameplayStatics::SaveGameToSlot(NewSaveGame, NewSaveGame->SaveSlotName, 0); } TriggerFirstOutput(true); } + +void UFlowNode_Checkpoint::OnLoad_Implementation() +{ + TriggerFirstOutput(true); +} diff --git a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp index 3e745b841..35c3b4fb0 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp @@ -44,6 +44,14 @@ void UFlowNode_ComponentObserver::ExecuteInput(const FName& PinName) } } +void UFlowNode_ComponentObserver::OnLoad_Implementation() +{ + if (IdentityTags.IsValid()) + { + StartObserving(); + } +} + void UFlowNode_ComponentObserver::StartObserving() { for (const TWeakObjectPtr& FoundComponent : GetFlowSubsystem()->GetComponents(IdentityTags, EGameplayContainerMatchType::Any)) diff --git a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp index c36a7f71d..da1bb26b4 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_PlayLevelSequence.cpp @@ -17,7 +17,9 @@ UFlowNode_PlayLevelSequence::UFlowNode_PlayLevelSequence(const FObjectInitialize : Super(ObjectInitializer) , LoadedSequence(nullptr) , SequencePlayer(nullptr) - , StartTime(0) + , StartTime(0.0f) + , ElapsedTime(0.0f) + , TimeDilation(1.0f) { #if WITH_EDITOR Category = TEXT("World"); @@ -147,15 +149,42 @@ void UFlowNode_PlayLevelSequence::ExecuteInput(const FName& PinName) } } +void UFlowNode_PlayLevelSequence::OnSave_Implementation() +{ + if (SequencePlayer) + { + ElapsedTime = SequencePlayer->GetCurrentTime().AsSeconds(); + } +} + +void UFlowNode_PlayLevelSequence::OnLoad_Implementation() +{ + if (ElapsedTime != 0.0f) + { + LoadedSequence = LoadAsset(Sequence); + + if (GetFlowSubsystem()->GetWorld() && LoadedSequence) + { + CreatePlayer(FMovieSceneSequencePlaybackSettings()); + SequencePlayer->OnFinished.AddDynamic(this, &UFlowNode_PlayLevelSequence::OnPlaybackFinished); + + SequencePlayer->SetPlayRate(TimeDilation); + SequencePlayer->SetPlaybackPosition(FMovieSceneSequencePlaybackParams(ElapsedTime, EUpdatePositionMethod::Jump)); + SequencePlayer->Play(); + } + } +} + void UFlowNode_PlayLevelSequence::TriggerEvent(const FString& EventName) { TriggerOutput(*EventName, false); } -void UFlowNode_PlayLevelSequence::OnTimeDilationUpdate(const float NewTimeDilation) const +void UFlowNode_PlayLevelSequence::OnTimeDilationUpdate(const float NewTimeDilation) { if (SequencePlayer) { + TimeDilation = NewTimeDilation; SequencePlayer->SetPlayRate(NewTimeDilation); } } @@ -187,6 +216,8 @@ void UFlowNode_PlayLevelSequence::Cleanup() LoadedSequence = nullptr; StartTime = 0.0f; + ElapsedTime = 0.0f; + TimeDilation = 1.0f; #if ENABLE_VISUAL_LOG UE_VLOG(this, LogFlow, Log, TEXT("Finished playback: %s"), *Sequence.ToString()); diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 5986882a7..a6b9d7b78 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -252,8 +252,8 @@ class FLOW_API UFlowAsset : public UObject protected: UFUNCTION(BlueprintNativeEvent, Category = "SaveGame") - void PrepareGameSave(); + void OnSave(); UFUNCTION(BlueprintNativeEvent, Category = "SaveGame") - void OnGameSaveLoaded(); + void OnLoad(); }; diff --git a/Source/Flow/Public/FlowComponent.h b/Source/Flow/Public/FlowComponent.h index 3ee4fd883..34790abe4 100644 --- a/Source/Flow/Public/FlowComponent.h +++ b/Source/Flow/Public/FlowComponent.h @@ -209,10 +209,10 @@ class FLOW_API UFlowComponent : public UActorComponent protected: UFUNCTION(BlueprintNativeEvent, Category = "SaveGame") - void PrepareGameSave(); + void OnSave(); UFUNCTION(BlueprintNativeEvent, Category = "SaveGame") - void OnGameSaveLoaded(); + void OnLoad(); ////////////////////////////////////////////////////////////////////////// // Helpers diff --git a/Source/Flow/Public/FlowSave.h b/Source/Flow/Public/FlowSave.h index caf613d6b..7c98ab50b 100644 --- a/Source/Flow/Public/FlowSave.h +++ b/Source/Flow/Public/FlowSave.h @@ -1,6 +1,8 @@ #pragma once #include "CoreMinimal.h" +#include "GameFramework/SaveGame.h" +#include "Serialization/BufferArchive.h" #include "Serialization/ObjectAndNameAsStringProxyArchive.h" #include "FlowSave.generated.h" @@ -9,13 +11,14 @@ struct FLOW_API FFlowNodeSaveData { GENERATED_USTRUCT_BODY() + UPROPERTY(SaveGame, VisibleAnywhere, Category = "Flow") FGuid NodeGuid; + + UPROPERTY(SaveGame, VisibleAnywhere, Category = "Flow") TArray NodeData; friend FArchive& operator<<(FArchive& Ar, FFlowNodeSaveData& InNodeData) { - Ar << InNodeData.NodeGuid; - Ar << InNodeData.NodeData; return Ar; } }; @@ -25,18 +28,17 @@ struct FLOW_API FFlowAssetSaveData { GENERATED_USTRUCT_BODY() + UPROPERTY(SaveGame, VisibleAnywhere, Category = "Flow") FString InstanceName; + + UPROPERTY(SaveGame, VisibleAnywhere, Category = "Flow") TArray AssetData; - + + UPROPERTY(SaveGame, VisibleAnywhere, Category = "Flow") TArray NodeRecords; - TArray FlowRecords; friend FArchive& operator<<(FArchive& Ar, FFlowAssetSaveData& InAssetData) { - Ar << InAssetData.InstanceName; - Ar << InAssetData.AssetData; - Ar << InAssetData.NodeRecords; - Ar << InAssetData.FlowRecords; return Ar; } }; @@ -46,16 +48,17 @@ struct FLOW_API FFlowComponentSaveData { GENERATED_USTRUCT_BODY() + UPROPERTY(SaveGame, VisibleAnywhere, Category = "Flow") FString WorldName; + + UPROPERTY(SaveGame, VisibleAnywhere, Category = "Flow") FString ActorInstanceName; + UPROPERTY(SaveGame) TArray ComponentData; friend FArchive& operator<<(FArchive& Ar, FFlowComponentSaveData& InComponentData) { - Ar << InComponentData.WorldName; - Ar << InComponentData.ActorInstanceName; - Ar << InComponentData.ComponentData; return Ar; } }; @@ -68,26 +71,27 @@ struct FLOW_API FFlowArchive : public FObjectAndNameAsStringProxyArchive } }; -// it's just an example -USTRUCT(BlueprintType) -struct FLOW_API FFlowSaveData +UCLASS(BlueprintType) +class FLOW_API UFlowSaveGame : public USaveGame { - GENERATED_USTRUCT_BODY() + GENERATED_BODY() - FDateTime Timestamp; - TArray SavedFlowComponents; - TArray SavedFlowInstances; +public: + UFlowSaveGame() {}; - friend FArchive& operator<<(FArchive& Ar, FFlowSaveData& FlowData) - { - Ar << FlowData.Timestamp; - Ar << FlowData.SavedFlowComponents; - Ar << FlowData.SavedFlowInstances; - return Ar; - } + UPROPERTY(VisibleAnywhere, Category = "SaveGame") + FString SaveSlotName = TEXT("FlowSave"); - bool IsValid() const + UPROPERTY(VisibleAnywhere, Category = "Flow") + TArray FlowComponents; + + UPROPERTY(VisibleAnywhere, Category = "Flow") + TArray FlowInstances; + + friend FArchive& operator<<(FArchive& Ar, UFlowSaveGame& SaveGame) { - return SavedFlowInstances.Num() > 0; + Ar << SaveGame.FlowComponents; + Ar << SaveGame.FlowInstances; + return Ar; } }; diff --git a/Source/Flow/Public/FlowSettings.h b/Source/Flow/Public/FlowSettings.h index fae8c9d25..608bae1ce 100644 --- a/Source/Flow/Public/FlowSettings.h +++ b/Source/Flow/Public/FlowSettings.h @@ -21,9 +21,6 @@ class UFlowSettings final : public UDeveloperSettings UPROPERTY(Config, EditAnywhere, Category = "Networking") bool bCreateFlowSubsystemOnClients; - UPROPERTY(Config, EditAnywhere, Category = "Networking") - FString SaveFolderName; - // How many nodes of given class should be preloaded with the Flow Asset instance? UPROPERTY(Config, EditAnywhere, Category = "Preload") TMap, int32> DefaultPreloadDepth; diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index f4321ab0c..1c440965d 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -45,7 +45,9 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem TMap InstancedSubFlows; FStreamableManager Streamable; - FFlowSaveData LoadedSaveGame; + + UPROPERTY() + UFlowSaveGame* LoadedSaveGame; public: virtual bool ShouldCreateSubsystem(UObject* Outer) const override; @@ -92,24 +94,18 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem UPROPERTY(BlueprintAssignable, Category = "FlowSubsystem") FSimpleFlowEvent OnSaveGame; - + UFUNCTION(BlueprintCallable, Category = "FlowSubsystem") - virtual void SaveGame(); + virtual void OnGameSaved(UFlowSaveGame* SaveGame); UFUNCTION(BlueprintCallable, Category = "FlowSubsystem") - virtual void LoadGame(); + virtual void OnGameLoaded(UFlowSaveGame* SaveGame); virtual void LoadRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const FString& SavedAssetInstanceName); virtual void LoadSubFlow(UFlowNode_SubGraph* SubGraphNode, const FString& SavedAssetInstanceName); - - UFUNCTION(BlueprintPure, Category = "FlowSubsystem") - bool IsSaveGameLoaded() const { return LoadedSaveGame.IsValid(); } UFUNCTION(BlueprintPure, Category = "FlowSubsystem") - FFlowSaveData GetLoadedSaveGame() const { return LoadedSaveGame; } - - UFUNCTION(BlueprintPure, Category = "FlowSubsystem") - static FString GetSaveFolderDir(); + UFlowSaveGame* GetLoadedSaveGame() const { return LoadedSaveGame; } ////////////////////////////////////////////////////////////////////////// // Component Registry @@ -256,4 +252,4 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem private: void FindComponents(const FGameplayTagContainer& Tags, TSet>& OutComponents, const EGameplayContainerMatchType MatchType) const; -}; +}; \ No newline at end of file diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index d21b5c03a..c5654fc47 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -337,17 +337,17 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte void LogError(FString Message); UFUNCTION(BlueprintCallable, Category = "FlowNode") - void SaveInstance(FFlowNodeSaveData& NodeRecord, TArray& SavedFlowInstances); + void SaveInstance(FFlowNodeSaveData& NodeRecord); UFUNCTION(BlueprintCallable, Category = "FlowNode") void LoadInstance(const FFlowNodeSaveData& NodeRecord); protected: UFUNCTION(BlueprintNativeEvent, Category = "FlowNode") - void PrepareGameSave(); + void OnSave(); UFUNCTION(BlueprintNativeEvent, Category = "FlowNode") - void OnGameSaveLoaded(); + void OnLoad(); private: UPROPERTY() diff --git a/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalAND.h b/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalAND.h index 3b2103af1..1b27942fd 100644 --- a/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalAND.h +++ b/Source/Flow/Public/Nodes/Operators/FlowNode_LogicalAND.h @@ -13,6 +13,7 @@ class FLOW_API UFlowNode_LogicalAND final : public UFlowNode GENERATED_UCLASS_BODY() private: + UPROPERTY(SaveGame) TSet ExecutedInputNames; #if WITH_EDITOR diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_Counter.h b/Source/Flow/Public/Nodes/Route/FlowNode_Counter.h index 2a83ba140..0bce7ea28 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_Counter.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_Counter.h @@ -16,6 +16,7 @@ class FLOW_API UFlowNode_Counter final : public UFlowNode int32 Goal; private: + UPROPERTY(SaveGame) int32 CurrentSum; protected: diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h index a9f5b76cd..29c03f6f8 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h @@ -23,10 +23,10 @@ class FLOW_API UFlowNode_ExecutionMultiGate final : public UFlowNode int32 StartIndex; private: - UPROPERTY() + UPROPERTY(SaveGame) int32 NextOutput; - UPROPERTY() + UPROPERTY(SaveGame) TArray Completed; public: diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h b/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h index cde84fb9f..e017b972a 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h @@ -35,7 +35,7 @@ class FLOW_API UFlowNode_SubGraph : public UFlowNode virtual void ForceFinishNode() override; protected: - virtual void OnGameSaveLoaded_Implementation() override; + virtual void OnLoad_Implementation() override; public: #if WITH_EDITOR diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h b/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h index a5d5d0811..35562d387 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_Timer.h @@ -22,8 +22,9 @@ class FLOW_API UFlowNode_Timer final : public UFlowNode private: FTimerHandle CompletionTimerHandle; - FTimerHandle StepTimerHandle; + + UPROPERTY(SaveGame) float SumOfSteps; UPROPERTY(SaveGame) @@ -45,8 +46,8 @@ class FLOW_API UFlowNode_Timer final : public UFlowNode protected: virtual void Cleanup() override; - virtual void PrepareGameSave_Implementation() override; - virtual void OnGameSaveLoaded_Implementation() override; + virtual void OnSave_Implementation() override; + virtual void OnLoad_Implementation() override; #if WITH_EDITOR virtual FString GetNodeDescription() const override; diff --git a/Source/Flow/Public/Nodes/Utils/FlowNode_Checkpoint.h b/Source/Flow/Public/Nodes/Utils/FlowNode_Checkpoint.h index 2e77b9e0f..b5ca71382 100644 --- a/Source/Flow/Public/Nodes/Utils/FlowNode_Checkpoint.h +++ b/Source/Flow/Public/Nodes/Utils/FlowNode_Checkpoint.h @@ -4,14 +4,15 @@ #include "FlowNode_Checkpoint.generated.h" /** - * Save the state of the game - * It's recommended to replace this with game-specific variant and this node to UFlowGraphSettings::HiddenNodes + * 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")) -class FLOW_API UFlowNode_Checkpoint : public UFlowNode +class FLOW_API UFlowNode_Checkpoint final : public UFlowNode { GENERATED_UCLASS_BODY() protected: virtual void ExecuteInput(const FName& PinName) override; + virtual void OnLoad_Implementation() override; }; diff --git a/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h b/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h index 6832570b3..d19b647d4 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_ComponentObserver.h @@ -37,6 +37,7 @@ class FLOW_API UFlowNode_ComponentObserver : public UFlowNode virtual void PostLoad() override; virtual void ExecuteInput(const FName& PinName) override; + virtual void OnLoad_Implementation() override; virtual void StartObserving(); virtual void StopObserving(); @@ -58,7 +59,7 @@ class FLOW_API UFlowNode_ComponentObserver : public UFlowNode UFUNCTION() virtual void OnEventReceived(); - + virtual void Cleanup() override; #if WITH_EDITOR diff --git a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h index 9b907974f..4ef7e914b 100644 --- a/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h +++ b/Source/Flow/Public/Nodes/World/FlowNode_PlayLevelSequence.h @@ -37,8 +37,15 @@ class FLOW_API UFlowNode_PlayLevelSequence : public UFlowNode UPROPERTY() UFlowLevelSequencePlayer* SequencePlayer; + UPROPERTY(SaveGame) float StartTime; + UPROPERTY(SaveGame) + float ElapsedTime; + + UPROPERTY(SaveGame) + float TimeDilation; + public: #if WITH_EDITOR virtual bool SupportsContextPins() const override { return true; } @@ -54,12 +61,15 @@ class FLOW_API UFlowNode_PlayLevelSequence : public UFlowNode protected: virtual void ExecuteInput(const FName& PinName) override; + + virtual void OnSave_Implementation() override; + virtual void OnLoad_Implementation() override; private: void TriggerEvent(const FString& EventName); public: - void OnTimeDilationUpdate(const float NewTimeDilation) const; + void OnTimeDilationUpdate(const float NewTimeDilation); protected: UFUNCTION() From 711027be0ee3a80a115aab249a07ae91e85d3393 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Wed, 12 May 2021 19:29:13 +0200 Subject: [PATCH 093/265] Update README.md --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index 827d4bd04..92374bc1c 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,3 @@ I feel it's important to mention that I didn't invent anything new here, with th * 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. - -## Contact -* Catch me on Twitter: [@MothDoctor](https://twitter.com/MothDoctor) -* Discuss things related to the plugin on dedicated [Discord server](https://discord.gg/zMtMQ2vUUa). From 8890b8fb5e7187bc0e0d690155b48e4a1a1b82a4 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sat, 19 Jun 2021 14:55:14 +0200 Subject: [PATCH 094/265] #47: LogError should be const --- Source/Flow/Private/Nodes/FlowNode.cpp | 2 +- Source/Flow/Public/Nodes/FlowNode.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 5edd9529e..7702eb8fe 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -546,7 +546,7 @@ FString UFlowNode::GetProgressAsString(float Value) return TempString; } -void UFlowNode::LogError(FString Message) +void UFlowNode::LogError(FString Message) const { const FString TemplatePath = GetFlowAsset()->TemplateAsset->GetPathName(); Message += TEXT(" in node ") + GetName() + TEXT(", asset ") + FPaths::GetPath(TemplatePath) + TEXT("/") + FPaths::GetBaseFilename(TemplatePath); diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index c5654fc47..5736185f6 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -334,7 +334,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte static FString GetProgressAsString(float Value); UFUNCTION(BlueprintCallable, Category = "FlowNode") - void LogError(FString Message); + void LogError(FString Message) const; UFUNCTION(BlueprintCallable, Category = "FlowNode") void SaveInstance(FFlowNodeSaveData& NodeRecord); From 0a71b80e85d18eaaaedca50f99a3440b39d5efdb Mon Sep 17 00:00:00 2001 From: Markus Ahrweiler Date: Sun, 20 Jun 2021 16:42:52 +0200 Subject: [PATCH 095/265] fix UFlowAsset::ClearInstances (#49) If you load a savegame and exit the game afterwards you can get an exception because activeInstances is empty. I've sticked to your style and added a check like in FlowSubSystem::Deinitialize --- 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 5184bcc4a..ce13f230c 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -182,7 +182,7 @@ void UFlowAsset::ClearInstances() for (int32 i = ActiveInstances.Num() - 1; i >= 0; i--) { - if (ActiveInstances[i]) + if (ActiveInstances.IsValidIndex(i)) { ActiveInstances[i]->FinishFlow(false); } From daad3815a1d8c44356b37f7797aa0e52227eb1c4 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 20 Jun 2021 16:58:22 +0200 Subject: [PATCH 096/265] double check if template is valid --- 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 ba8350c74..a79db7051 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -38,7 +38,7 @@ void UFlowSubsystem::Deinitialize() { for (int32 i = InstancedTemplates.Num() - 1; i >= 0; i--) { - if (InstancedTemplates.IsValidIndex(i)) + if (InstancedTemplates.IsValidIndex(i) && InstancedTemplates[i]) { InstancedTemplates[i]->ClearInstances(); } From 5742a9d4a4ea496465d0b6f5ef2e3d55b1b7c664 Mon Sep 17 00:00:00 2001 From: sturcotte06 Date: Sun, 20 Jun 2021 11:01:27 -0400 Subject: [PATCH 097/265] Fix missing includes (#48) --- Source/Flow/Private/Nodes/FlowNode.cpp | 2 ++ Source/Flow/Public/Nodes/FlowNode.h | 3 +-- .../Private/Nodes/Customizations/FlowPinCustomization.cpp | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 7702eb8fe..55c218831 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -9,6 +9,8 @@ #include "Engine/World.h" #include "Misc/App.h" #include "Misc/Paths.h" +#include "Serialization/MemoryReader.h" +#include "Serialization/MemoryWriter.h" FFlowPin UFlowNode::DefaultInputPin(TEXT("In")); FFlowPin UFlowNode::DefaultOutputPin(TEXT("Out")); diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 5736185f6..a632ab86b 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -1,6 +1,7 @@ #pragma once #include "CoreMinimal.h" +#include "EdGraph/EdGraphNode.h" #include "Engine/StreamableManager.h" #include "GameplayTagContainer.h" #include "VisualLogger/VisualLoggerDebugSnapshotInterface.h" @@ -9,8 +10,6 @@ #include "Nodes/FlowPin.h" #include "FlowNode.generated.h" -class UEdGraphNode; - class UFlowAsset; class UFlowSubsystem; diff --git a/Source/FlowEditor/Private/Nodes/Customizations/FlowPinCustomization.cpp b/Source/FlowEditor/Private/Nodes/Customizations/FlowPinCustomization.cpp index af243ebec..1f7e44742 100644 --- a/Source/FlowEditor/Private/Nodes/Customizations/FlowPinCustomization.cpp +++ b/Source/FlowEditor/Private/Nodes/Customizations/FlowPinCustomization.cpp @@ -2,6 +2,7 @@ #include "Nodes/FlowPin.h" #include "PropertyEditing.h" +#include "Widgets/Input/SEditableTextBox.h" #define LOCTEXT_NAMESPACE "FlowPinCustomization" From 5cccde76873d342d44045468ec6578dcb78a2925 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 4 Jul 2021 17:23:13 +0200 Subject: [PATCH 098/265] Exposed AbortActiveFlows method, way to reset system before loading a SaveGame Refactored parts logic for creating/finishing Flow Instances --- Source/Flow/Private/FlowAsset.cpp | 36 ++++--------- Source/Flow/Private/FlowComponent.cpp | 6 +-- Source/Flow/Private/FlowSubsystem.cpp | 49 +++++++++++------- Source/Flow/Private/Nodes/FlowNode.cpp | 50 ++++++++++--------- .../Private/Nodes/Route/FlowNode_SubGraph.cpp | 19 ++++--- .../World/FlowNode_ComponentObserver.cpp | 2 +- Source/Flow/Public/FlowAsset.h | 7 ++- Source/Flow/Public/FlowComponent.h | 2 +- Source/Flow/Public/FlowSubsystem.h | 10 ++-- Source/Flow/Public/FlowTypes.h | 12 ++++- Source/Flow/Public/Nodes/FlowNode.h | 6 +-- .../Public/Nodes/Route/FlowNode_SubGraph.h | 2 + .../Private/Graph/Nodes/FlowGraphNode.cpp | 4 +- .../Private/Graph/Widgets/SFlowGraphNode.cpp | 8 +-- .../Public/Graph/Nodes/FlowGraphNode.h | 2 +- 15 files changed, 117 insertions(+), 98 deletions(-) diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index ce13f230c..3449b6ae5 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -18,6 +18,7 @@ UFlowAsset::UFlowAsset(const FObjectInitializer& ObjectInitializer) #endif , TemplateAsset(nullptr) , StartNode(nullptr) + , FinishPolicy(EFlowFinishPolicy::Keep) { } @@ -182,9 +183,9 @@ void UFlowAsset::ClearInstances() for (int32 i = ActiveInstances.Num() - 1; i >= 0; i--) { - if (ActiveInstances.IsValidIndex(i)) + if (ActiveInstances.IsValidIndex(i) && ActiveInstances[i]) { - ActiveInstances[i]->FinishFlow(false); + ActiveInstances[i]->FinishFlow(EFlowFinishPolicy::Keep); } } @@ -310,16 +311,10 @@ void UFlowAsset::StartFlow() StartNode->TriggerFirstOutput(true); } -void UFlowAsset::StartAsSubFlow(UFlowNode_SubGraph* SubGraphNode) +void UFlowAsset::FinishFlow(const EFlowFinishPolicy InFinishPolicy) { - NodeOwningThisAssetInstance = SubGraphNode; - NodeOwningThisAssetInstance->GetFlowAsset()->ActiveSubGraphs.Add(SubGraphNode, this); + FinishPolicy = InFinishPolicy; - StartFlow(); -} - -void UFlowAsset::FinishFlow(const bool bFlowCompleted) -{ // end execution of this asset and all of its nodes for (UFlowNode* Node : ActiveNodes) { @@ -340,18 +335,6 @@ void UFlowAsset::FinishFlow(const bool bFlowCompleted) { GetFlowSubsystem()->RemoveInstancedTemplate(TemplateAsset); } - - // if this instance was created by SubGraph node - if (NodeOwningThisAssetInstance.IsValid()) - { - NodeOwningThisAssetInstance->GetFlowAsset()->ActiveSubGraphs.Remove(NodeOwningThisAssetInstance.Get()); - if (bFlowCompleted) - { - NodeOwningThisAssetInstance.Get()->TriggerFirstOutput(true); - } - - NodeOwningThisAssetInstance = nullptr; - } } TWeakObjectPtr UFlowAsset::GetFlowInstance(UFlowNode_SubGraph* SubGraphNode) const @@ -397,21 +380,20 @@ void UFlowAsset::FinishNode(UFlowNode* Node) { ActiveNodes.Remove(Node); - if (Node->GetClass()->IsChildOf(UFlowNode_Finish::StaticClass())) + // if graph reached Finish and this asset instance was created by SubGraph node + if (Node->GetClass()->IsChildOf(UFlowNode_Finish::StaticClass()) && NodeOwningThisAssetInstance.IsValid()) { - FinishFlow(true); + NodeOwningThisAssetInstance.Get()->TriggerFirstOutput(true); } } } void UFlowAsset::ResetNodes() { -#if !UE_BUILD_SHIPPING for (UFlowNode* Node : RecordedNodes) { Node->ResetRecords(); } -#endif RecordedNodes.Empty(); } @@ -453,7 +435,7 @@ FFlowAssetSaveData UFlowAsset::SaveInstance(TArray& SavedFlo for (const TPair& Node : Nodes) { - if (Node.Value && Node.Value->ActivationState == EFlowActivationState::Active) + if (Node.Value && Node.Value->ActivationState == EFlowNodeState::Active) { if (UFlowNode_SubGraph* SubGraphNode = Cast(Node.Value)) { diff --git a/Source/Flow/Private/FlowComponent.cpp b/Source/Flow/Private/FlowComponent.cpp index 6ff88bc1b..813707933 100644 --- a/Source/Flow/Private/FlowComponent.cpp +++ b/Source/Flow/Private/FlowComponent.cpp @@ -67,7 +67,7 @@ void UFlowComponent::EndPlay(const EEndPlayReason::Type EndPlayReason) { if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) { - FlowSubsystem->FinishRootFlow(this); + FlowSubsystem->FinishRootFlow(this, EFlowFinishPolicy::Keep); FlowSubsystem->UnregisterComponent(this); } @@ -331,11 +331,11 @@ void UFlowComponent::StartRootFlow() } } -void UFlowComponent::FinishRootFlow() +void UFlowComponent::FinishRootFlow(const EFlowFinishPolicy FinishPolicy) { if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) { - FlowSubsystem->FinishRootFlow(this); + FlowSubsystem->FinishRootFlow(this, FinishPolicy); } } diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index a79db7051..10e079aae 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -33,6 +33,11 @@ void UFlowSubsystem::Initialize(FSubsystemCollectionBase& Collection) } void UFlowSubsystem::Deinitialize() +{ + AbortActiveFlows(); +} + +void UFlowSubsystem::AbortActiveFlows() { if (InstancedTemplates.Num() > 0) { @@ -43,10 +48,10 @@ void UFlowSubsystem::Deinitialize() InstancedTemplates[i]->ClearInstances(); } } - - InstancedTemplates.Empty(); - InstancedSubFlows.Empty(); } + + InstancedTemplates.Empty(); + InstancedSubFlows.Empty(); } void UFlowSubsystem::StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances /* = true */) @@ -78,46 +83,56 @@ UFlowAsset* UFlowSubsystem::CreateRootFlow(UObject* Owner, UFlowAsset* FlowAsset return NewFlow; } -void UFlowSubsystem::FinishRootFlow(UObject* Owner) +void UFlowSubsystem::FinishRootFlow(UObject* Owner, const EFlowFinishPolicy FinishPolicy) { if (UFlowAsset* Instance = RootInstances.FindRef(Owner)) { RootInstances.Remove(Owner); - Instance->FinishFlow(false); + Instance->FinishFlow(FinishPolicy); } } -UFlowAsset* UFlowSubsystem::StartSubFlow(UFlowNode_SubGraph* SubGraphNode, const FString NewInstanceName, const bool bPreloading /* = false */) +UFlowAsset* UFlowSubsystem::CreateSubFlow(UFlowNode_SubGraph* SubGraphNode, const FString NewInstanceName, const bool bPreloading /* = false */) { - UFlowAsset* NewFlow = nullptr; + UFlowAsset* NewInstance = nullptr; if (!InstancedSubFlows.Contains(SubGraphNode)) { const TWeakObjectPtr Owner = SubGraphNode->GetFlowAsset() ? SubGraphNode->GetFlowAsset()->GetOwner() : nullptr; - NewFlow = CreateFlowInstance(Owner, SubGraphNode->Asset, NewInstanceName); - InstancedSubFlows.Add(SubGraphNode, NewFlow); + NewInstance = CreateFlowInstance(Owner, SubGraphNode->Asset, NewInstanceName); + InstancedSubFlows.Add(SubGraphNode, NewInstance); if (bPreloading) { - NewFlow->PreloadNodes(); + NewInstance->PreloadNodes(); } } if (!bPreloading) { - // get instanced asset from map - in case it was already instanced by calling StartSubFlow() with bPreloading == true - InstancedSubFlows[SubGraphNode]->StartAsSubFlow(SubGraphNode); + // 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); + + AssetInstance->StartFlow(); } - return NewFlow; + return NewInstance; } -void UFlowSubsystem::FinishSubFlow(UFlowNode_SubGraph* SubGraphNode) +void UFlowSubsystem::RemoveSubFlow(UFlowNode_SubGraph* SubGraphNode, const EFlowFinishPolicy FinishPolicy) { - if (UFlowAsset* Instance = InstancedSubFlows.FindRef(SubGraphNode)) + if (InstancedSubFlows.Contains(SubGraphNode)) { + UFlowAsset* AssetInstance = InstancedSubFlows[SubGraphNode]; + AssetInstance->NodeOwningThisAssetInstance = nullptr; + + SubGraphNode->GetFlowAsset()->ActiveSubGraphs.Remove(SubGraphNode); InstancedSubFlows.Remove(SubGraphNode); - Instance->FinishFlow(false); + + AssetInstance->FinishFlow(FinishPolicy); } } @@ -235,7 +250,7 @@ void UFlowSubsystem::LoadSubFlow(UFlowNode_SubGraph* SubGraphNode, const FString { if (AssetRecord.InstanceName == SavedAssetInstanceName) { - UFlowAsset* LoadedInstance = StartSubFlow(SubGraphNode, SavedAssetInstanceName); + UFlowAsset* LoadedInstance = CreateSubFlow(SubGraphNode, SavedAssetInstanceName); if (LoadedInstance) { LoadedInstance->LoadInstance(AssetRecord); diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 55c218831..8a3ed84c5 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -26,9 +26,7 @@ UFlowNode::UFlowNode(const FObjectInitializer& ObjectInitializer) , GraphNode(nullptr) #endif , bPreloaded(false) -#if !UE_BUILD_SHIPPING - , ActivationState(EFlowActivationState::NeverActivated) -#endif + , ActivationState(EFlowNodeState::NeverActivated) { #if WITH_EDITOR Category = TEXT("Uncategorized"); @@ -310,16 +308,15 @@ void UFlowNode::FlushContent() void UFlowNode::TriggerInput(const FName& PinName) { - ensureAlways(InputPins.Num() > 0); - -#if !UE_BUILD_SHIPPING if (InputPins.Contains(PinName)) { + ActivationState = EFlowNodeState::Active; + +#if !UE_BUILD_SHIPPING // record for debugging TArray& Records = InputRecords.FindOrAdd(PinName); Records.Add(FPinRecord(FApp::GetCurrentTime())); - - ActivationState = EFlowActivationState::Active; +#endif // UE_BUILD_SHIPPING #if WITH_EDITOR if (GetWorld()->WorldType == EWorldType::PIE && UFlowAsset::GetFlowGraphInterface().IsValid()) @@ -330,9 +327,11 @@ void UFlowNode::TriggerInput(const FName& PinName) } else { +#if !UE_BUILD_SHIPPING LogError(FString::Printf(TEXT("Input Pin name %s invalid"), *PinName.ToString())); - } #endif // UE_BUILD_SHIPPING + return; + } ExecuteInput(PinName); } @@ -352,8 +351,12 @@ void UFlowNode::TriggerFirstOutput(const bool bFinish) void UFlowNode::TriggerOutput(const FName& PinName, const bool bFinish /*= false*/) { - ensureAlways(OutputPins.Num() > 0); - + // clean up node, if needed + if (bFinish) + { + Finish(); + } + #if !UE_BUILD_SHIPPING if (OutputPins.Contains(PinName)) { @@ -374,12 +377,6 @@ void UFlowNode::TriggerOutput(const FName& PinName, const bool bFinish /*= false } #endif // UE_BUILD_SHIPPING - // clean up node, if needed - if (bFinish) - { - Finish(); - } - // call the next node if (OutputPins.Contains(PinName) && Connections.Contains(PinName)) { @@ -411,9 +408,15 @@ void UFlowNode::Finish() void UFlowNode::Deactivate() { -#if !UE_BUILD_SHIPPING - ActivationState = EFlowActivationState::WasActive; -#endif + if (GetFlowAsset()->FinishPolicy == EFlowFinishPolicy::Revert) + { + // this happens when the Flow progress should be reverted, i.e. prior to loading SaveGame + ActivationState = EFlowNodeState::Aborted; + } + else + { + ActivationState = EFlowNodeState::Completed; + } Cleanup(); } @@ -428,14 +431,15 @@ void UFlowNode::ForceFinishNode() K2_ForceFinishNode(); } -#if !UE_BUILD_SHIPPING void UFlowNode::ResetRecords() { + ActivationState = EFlowNodeState::NeverActivated; + +#if !UE_BUILD_SHIPPING InputRecords.Empty(); OutputRecords.Empty(); - ActivationState = EFlowActivationState::NeverActivated; -} #endif +} #if WITH_EDITOR UFlowNode* UFlowNode::GetInspectedInstance() const diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp index 84519ac41..df10a52c6 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp @@ -20,17 +20,17 @@ UFlowNode_SubGraph::UFlowNode_SubGraph(const FObjectInitializer& ObjectInitializ void UFlowNode_SubGraph::PreloadContent() { - if (!Asset.IsNull()) + if (!Asset.IsNull() && GetFlowSubsystem()) { - GetFlowSubsystem()->StartSubFlow(this, FString(), true); + GetFlowSubsystem()->CreateSubFlow(this, FString(), true); } } void UFlowNode_SubGraph::FlushContent() { - if (!Asset.IsNull()) + if (!Asset.IsNull() && GetFlowSubsystem()) { - GetFlowSubsystem()->FinishSubFlow(this); + GetFlowSubsystem()->RemoveSubFlow(this, EFlowFinishPolicy::Revert); } } @@ -45,7 +45,10 @@ void UFlowNode_SubGraph::ExecuteInput(const FName& PinName) { if (PinName == TEXT("Start")) { - GetFlowSubsystem()->StartSubFlow(this); + if (GetFlowSubsystem()) + { + GetFlowSubsystem()->CreateSubFlow(this); + } } else { @@ -56,9 +59,9 @@ void UFlowNode_SubGraph::ExecuteInput(const FName& PinName) void UFlowNode_SubGraph::Cleanup() { - if (!Asset.IsNull()) + if (!Asset.IsNull() && GetFlowSubsystem()) { - GetFlowSubsystem()->FinishSubFlow(this); + GetFlowSubsystem()->RemoveSubFlow(this, EFlowFinishPolicy::Keep); } } @@ -128,7 +131,7 @@ TArray UFlowNode_SubGraph::GetContextOutputs() void UFlowNode_SubGraph::PostLoad() { Super::PostLoad(); - + SubscribeToAssetChanges(); } diff --git a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp index 35c3b4fb0..2d4e76b61 100644 --- a/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp +++ b/Source/Flow/Private/Nodes/World/FlowNode_ComponentObserver.cpp @@ -138,7 +138,7 @@ FString UFlowNode_ComponentObserver::GetNodeDescription() const FString UFlowNode_ComponentObserver::GetStatusString() const { - if (ActivationState == EFlowActivationState::Active && RegisteredActors.Num() == 0) + if (ActivationState == EFlowNodeState::Active && RegisteredActors.Num() == 0) { return NoActorsFound; } diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index a6b9d7b78..4fe578d94 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -2,6 +2,7 @@ #include "CoreMinimal.h" #include "FlowSave.h" +#include "FlowTypes.h" #include "FlowAsset.generated.h" class UFlowNode; @@ -41,6 +42,7 @@ class FLOW_API UFlowAsset : public UObject friend class UFlowNode; friend class UFlowNode_CustomOutput; friend class UFlowNode_SubGraph; + friend class UFlowSubsystem; friend class FFlowAssetDetails; @@ -185,6 +187,8 @@ class FLOW_API UFlowAsset : public UObject UPROPERTY() TArray RecordedNodes; + EFlowFinishPolicy FinishPolicy; + public: void InitializeInstance(const TWeakObjectPtr InOwner, UFlowAsset* InTemplateAsset); @@ -205,9 +209,8 @@ class FLOW_API UFlowAsset : public UObject virtual void PreStartFlow(); virtual void StartFlow(); - virtual void StartAsSubFlow(UFlowNode_SubGraph* SubGraphNode); - virtual void FinishFlow(const bool bFlowCompleted); + virtual void FinishFlow(const EFlowFinishPolicy InFinishPolicy); // Get Flow Asset instance created by the given SubGraph node TWeakObjectPtr GetFlowInstance(UFlowNode_SubGraph* SubGraphNode) const; diff --git a/Source/Flow/Public/FlowComponent.h b/Source/Flow/Public/FlowComponent.h index 34790abe4..a282ae3e0 100644 --- a/Source/Flow/Public/FlowComponent.h +++ b/Source/Flow/Public/FlowComponent.h @@ -187,7 +187,7 @@ 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(); + void FinishRootFlow(const EFlowFinishPolicy FinishPolicy); UFUNCTION(BlueprintPure, Category = "RootFlow") UFlowAsset* GetRootFlowInstance(); diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index 1c440965d..7f6ba58d2 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -31,7 +31,7 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem friend class UFlowAsset; friend class UFlowComponent; friend class UFlowNode_SubGraph; - + // All asset templates with active instances UPROPERTY() TArray InstancedTemplates; @@ -55,6 +55,8 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem virtual void Initialize(FSubsystemCollectionBase& Collection) override; virtual void Deinitialize() override; + virtual void AbortActiveFlows(); + // 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); @@ -65,11 +67,11 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem public: // Finish the root Flow, typically when closing world that created this flow UFUNCTION(BlueprintCallable, Category = "FlowSubsystem") - void FinishRootFlow(UObject* Owner); + void FinishRootFlow(UObject* Owner, const EFlowFinishPolicy FinishPolicy); private: - UFlowAsset* StartSubFlow(UFlowNode_SubGraph* SubGraphNode, const FString NewInstanceName = FString(), const bool bPreloading = false); - void FinishSubFlow(UFlowNode_SubGraph* SubGraphNode); + UFlowAsset* CreateSubFlow(UFlowNode_SubGraph* SubGraphNode, const FString NewInstanceName = FString(), const bool bPreloading = false); + void RemoveSubFlow(UFlowNode_SubGraph* SubGraphNode, const EFlowFinishPolicy FinishPolicy); UFlowAsset* CreateFlowInstance(const TWeakObjectPtr Owner, TSoftObjectPtr FlowAsset, FString NewInstanceName = FString()); void RemoveInstancedTemplate(UFlowAsset* Template); diff --git a/Source/Flow/Public/FlowTypes.h b/Source/Flow/Public/FlowTypes.h index 8c569c158..3a15caf72 100644 --- a/Source/Flow/Public/FlowTypes.h +++ b/Source/Flow/Public/FlowTypes.h @@ -17,11 +17,19 @@ enum class EFlowNodeStyle : uint8 #endif UENUM(BlueprintType) -enum class EFlowActivationState : uint8 +enum class EFlowNodeState : uint8 { NeverActivated, Active, - WasActive + Completed, + Aborted +}; + +UENUM(BlueprintType) +enum class EFlowFinishPolicy : uint8 +{ + Keep, + Revert }; UENUM(BlueprintType) diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index a632ab86b..66103f648 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -185,7 +185,7 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte FStreamableManager StreamableManager; UPROPERTY(SaveGame) - EFlowActivationState ActivationState; + EFlowNodeState ActivationState; #if !UE_BUILD_SHIPPING private: @@ -267,15 +267,13 @@ class FLOW_API UFlowNode : public UObject, public IVisualLoggerDebugSnapshotInte UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "ForceFinishNode")) void K2_ForceFinishNode(); -#if !UE_BUILD_SHIPPING private: void ResetRecords(); -#endif #if WITH_EDITOR public: UFlowNode* GetInspectedInstance() const; - EFlowActivationState GetActivationState() const { return ActivationState; } + EFlowNodeState GetActivationState() const { return ActivationState; } TMap GetWireRecords() const; TArray GetPinRecords(const FName& PinName, const EEdGraphPinDirection PinDirection) const; diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h b/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h index e017b972a..4702fa367 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_SubGraph.h @@ -21,6 +21,8 @@ class FLOW_API UFlowNode_SubGraph : public UFlowNode UPROPERTY(EditAnywhere, Category = "Graph") TSoftObjectPtr Asset; + TWeakObjectPtr AssetInstance; + UPROPERTY(SaveGame) FString SavedAssetInstanceName; diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index f541429f1..5d9ee7556 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -596,7 +596,7 @@ UFlowNode* UFlowGraphNode::GetInspectedNodeInstance() const return FlowNode ? FlowNode->GetInspectedInstance() : nullptr; } -EFlowActivationState UFlowGraphNode::GetActivationState() const +EFlowNodeState UFlowGraphNode::GetActivationState() const { if (FlowNode) { @@ -606,7 +606,7 @@ EFlowActivationState UFlowGraphNode::GetActivationState() const } } - return EFlowActivationState::NeverActivated; + return EFlowNodeState::NeverActivated; } FString UFlowGraphNode::GetStatusString() const diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp index 1ba970672..21ad855fe 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp @@ -78,12 +78,14 @@ const FSlateBrush* SFlowGraphNode::GetShadowBrush(bool bSelected) const { switch (FlowGraphNode->GetActivationState()) { - case EFlowActivationState::NeverActivated: + case EFlowNodeState::NeverActivated: return SGraphNode::GetShadowBrush(bSelected); - case EFlowActivationState::Active: + case EFlowNodeState::Active: return FFlowEditorStyle::Get()->GetBrush(TEXT("Flow.Node.ActiveShadow")); - case EFlowActivationState::WasActive: + case EFlowNodeState::Completed: + case EFlowNodeState::Aborted: return FFlowEditorStyle::Get()->GetBrush(TEXT("Flow.Node.WasActiveShadow")); + default: ; } } diff --git a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h index d35348235..6ce9e450c 100644 --- a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h +++ b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h @@ -140,7 +140,7 @@ class FLOWEDITOR_API UFlowGraphNode : public UEdGraphNode UFlowNode* GetInspectedNodeInstance() const; // used for highlighting active nodes of the inspected asset instance - EFlowActivationState GetActivationState() const; + EFlowNodeState GetActivationState() const; // information displayed while node is active FString GetStatusString() const; From 7676fdc656952e555a9fdd3dd513318613a4c914 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 4 Jul 2021 17:32:36 +0200 Subject: [PATCH 099/265] removing misleading comment --- Source/Flow/Private/Nodes/FlowNode.cpp | 3 +-- Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp | 2 +- Source/Flow/Public/FlowTypes.h | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index 8a3ed84c5..48353f6bd 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -408,9 +408,8 @@ void UFlowNode::Finish() void UFlowNode::Deactivate() { - if (GetFlowAsset()->FinishPolicy == EFlowFinishPolicy::Revert) + if (GetFlowAsset()->FinishPolicy == EFlowFinishPolicy::Abort) { - // this happens when the Flow progress should be reverted, i.e. prior to loading SaveGame ActivationState = EFlowNodeState::Aborted; } else diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp index df10a52c6..149e41615 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_SubGraph.cpp @@ -30,7 +30,7 @@ void UFlowNode_SubGraph::FlushContent() { if (!Asset.IsNull() && GetFlowSubsystem()) { - GetFlowSubsystem()->RemoveSubFlow(this, EFlowFinishPolicy::Revert); + GetFlowSubsystem()->RemoveSubFlow(this, EFlowFinishPolicy::Abort); } } diff --git a/Source/Flow/Public/FlowTypes.h b/Source/Flow/Public/FlowTypes.h index 3a15caf72..b1a6b390a 100644 --- a/Source/Flow/Public/FlowTypes.h +++ b/Source/Flow/Public/FlowTypes.h @@ -29,7 +29,7 @@ UENUM(BlueprintType) enum class EFlowFinishPolicy : uint8 { Keep, - Revert + Abort }; UENUM(BlueprintType) From dad937c80d7e5a5aa345df90124f38b1f61f05eb Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Wed, 14 Jul 2021 10:57:25 +0200 Subject: [PATCH 100/265] added FLOWEDITOR_API export --- Source/FlowEditor/Public/FlowEditorModule.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/FlowEditor/Public/FlowEditorModule.h b/Source/FlowEditor/Public/FlowEditorModule.h index 5abc5cdea..fe91883ef 100644 --- a/Source/FlowEditor/Public/FlowEditorModule.h +++ b/Source/FlowEditor/Public/FlowEditorModule.h @@ -31,7 +31,7 @@ struct FExtensibilityManagers DECLARE_LOG_CATEGORY_EXTERN(LogFlowEditor, Log, All) -class FFlowEditorModule : public IModuleInterface +class FLOWEDITOR_API FFlowEditorModule : public IModuleInterface { public: static EAssetTypeCategories::Type FlowAssetCategory; From 52d5d9f2137aab711be83333e5da807382115fd3 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Wed, 4 Aug 2021 21:04:09 +0200 Subject: [PATCH 101/265] 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 9705938d98c3c900329b4749f141bd015ac68b1f Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Thu, 5 Aug 2021 14:17:56 +0200 Subject: [PATCH 102/265] 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 a91e2ea53dbffdf294945957bf7673c22ef8ad70 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 16 Aug 2021 22:27:21 +0200 Subject: [PATCH 103/265] 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 15bfb7355..198a6dda8 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("Game", 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 bc3c8f50bcbc091e0dc17d9d32e367a24f38fa5d Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 16 Aug 2021 23:10:41 +0200 Subject: [PATCH 104/265] 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 59c23ebe1b5904c3136940816d2797b8b11e72bc Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 23 Aug 2021 23:50:20 +0200 Subject: [PATCH 105/265] 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 b7f8ed77ac42837aa1748b90127c39265b261a97 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 3 Sep 2021 00:50:26 +0200 Subject: [PATCH 106/265] 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 334a8c5a3702fd32a05e97c3d36cb213ea631c36 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 3 Sep 2021 00:50:39 +0200 Subject: [PATCH 107/265] 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 b813c21dbccea46707531c9d4f556e60aa0a2dab Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 3 Sep 2021 00:51:36 +0200 Subject: [PATCH 108/265] 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 174df3e36bed401e5bf9ecd7c8236fa1ac0d9de9 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 3 Sep 2021 00:52:25 +0200 Subject: [PATCH 109/265] 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 4e87c7b9dfdbe0a77bbe7b368994788787762c68 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 5 Sep 2021 18:53:14 +0200 Subject: [PATCH 110/265] 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 6f3ceac4b33e58f47b8582fff26e2ebbf3f533bf Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 20 Sep 2021 23:26:20 +0200 Subject: [PATCH 111/265] 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 18373a9cf648fd3b0c6f6d3485439e75afb2c75c Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 24 Sep 2021 13:57:54 +0200 Subject: [PATCH 112/265] 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 0282a99003ac079ac1e3fdb31d2bdaab191265fd Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 24 Sep 2021 14:07:41 +0200 Subject: [PATCH 113/265] 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 91a59cdce704fac010937a8aeca58755f081c66f Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 28 Sep 2021 20:43:06 +0200 Subject: [PATCH 114/265] 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 b67de77b5209eb97cd91520fecb3776d34cfa686 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 28 Sep 2021 20:43:50 +0200 Subject: [PATCH 115/265] 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 4e0f04a6cb96397d6021c14bd974934a9a9a4091 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 28 Sep 2021 20:59:08 +0200 Subject: [PATCH 116/265] toolbar classes merged, a lot of Flow Asset methods made virtual --- .../Private/Asset/FlowAssetEditor.cpp | 155 +++++---------- .../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, 341 insertions(+), 435 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 8866a0d35..6d318cc37 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" @@ -180,13 +178,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_v2") ->AddArea @@ -222,52 +220,16 @@ void FFlowAssetEditor::InitFlowAssetEditor(const EToolkitMode::Type Mode, const ) ); - const bool bCreateDefaultStandaloneMenu = true; - const bool bCreateDefaultToolbar = true; - FAssetEditorToolkit::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())); + constexpr bool bCreateDefaultStandaloneMenu = true; + constexpr bool bCreateDefaultToolbar = true; + InitAssetEditor(Mode, InitToolkitHost, TEXT("FlowEditorApp"), StandaloneDefaultLayout, bCreateDefaultStandaloneMenu, bCreateDefaultToolbar, ObjectToEdit, false); + 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); @@ -280,40 +242,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(), @@ -333,7 +280,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()); @@ -368,7 +315,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) @@ -385,7 +332,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"); } @@ -400,6 +347,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(); @@ -414,11 +365,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, @@ -560,7 +511,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; @@ -658,7 +609,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())); } @@ -709,7 +660,7 @@ void FFlowAssetEditor::DeleteSelectedNodes() if (Node->CanUserDeleteNode()) { - if (UFlowGraphNode* FlowGraphNode = Cast(Node)) + if (const UFlowGraphNode* FlowGraphNode = Cast(Node)) { if (FlowGraphNode->GetFlowNode()) { @@ -725,7 +676,7 @@ void FFlowAssetEditor::DeleteSelectedNodes() } } -void FFlowAssetEditor::DeleteSelectedDuplicatableNodes() +void FFlowAssetEditor::DeleteSelectedDuplicableNodes() { // Cache off the old selection const FGraphPanelSelectionSet OldSelectedNodes = FocusedGraphEditor->GetSelectedNodes(); @@ -749,7 +700,7 @@ void FFlowAssetEditor::DeleteSelectedDuplicatableNodes() } } - // Delete the duplicatable nodes + // Delete the duplicable nodes DeleteSelectedNodes(); for (FGraphPanelSelectionSet::TConstIterator SelectedIt(RemainingNodes); SelectedIt; ++SelectedIt) @@ -788,7 +739,7 @@ void FFlowAssetEditor::CutSelectedNodes() CopySelectedNodes(); // Cut should only delete nodes that can be duplicated - DeleteSelectedDuplicatableNodes(); + DeleteSelectedDuplicableNodes(); } bool FFlowAssetEditor::CanCutNodes() const @@ -869,7 +820,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; } @@ -888,7 +839,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()); } @@ -988,7 +939,7 @@ bool FFlowAssetEditor::CanRefreshContextPins() const { if (CanEdit() && GetSelectedFlowNodes().Num() == 1) { - for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) { return SelectedNode->SupportsContextPins(); } @@ -1009,7 +960,7 @@ bool FFlowAssetEditor::CanAddInput() const { if (CanEdit() && GetSelectedFlowNodes().Num() == 1) { - for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) { return SelectedNode->CanUserAddInput(); } @@ -1030,7 +981,7 @@ bool FFlowAssetEditor::CanAddOutput() const { if (CanEdit() && GetSelectedFlowNodes().Num() == 1) { - for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) { return SelectedNode->CanUserAddOutput(); } @@ -1054,9 +1005,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) { @@ -1095,7 +1046,7 @@ void FFlowAssetEditor::OnAddPinBreakpoint() const bool FFlowAssetEditor::CanAddBreakpoint() const { - for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) { return !SelectedNode->NodeBreakpoint.HasBreakpoint(); } @@ -1137,7 +1088,7 @@ void FFlowAssetEditor::OnRemovePinBreakpoint() const bool FFlowAssetEditor::CanRemoveBreakpoint() const { - for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) { return SelectedNode->NodeBreakpoint.HasBreakpoint(); } @@ -1149,7 +1100,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); } @@ -1181,13 +1132,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(); } @@ -1229,7 +1180,7 @@ void FFlowAssetEditor::OnDisablePinBreakpoint() const bool FFlowAssetEditor::CanDisableBreakpoint() const { - for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) + for (const UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) { return SelectedNode->NodeBreakpoint.IsBreakpointEnabled(); } @@ -1285,7 +1236,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()) @@ -1296,8 +1247,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(); @@ -1317,7 +1268,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 087020ded..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, 0.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 cb3f44c687d3000abda1d18e3d33d54b1e051434 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 28 Sep 2021 20:59:50 +0200 Subject: [PATCH 117/265] 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 198a6dda8..12a7c1b52 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 b7d6c86ac2808cfe3a221f81130f62113c3e2076 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 28 Sep 2021 22:10:40 +0200 Subject: [PATCH 118/265] 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 79e52f419fa97d8a4a844a94e059daba3edffb77 Mon Sep 17 00:00:00 2001 From: "Satheesh (ryanjon2040)" Date: Wed, 29 Sep 2021 01:28:59 +0530 Subject: [PATCH 119/265] 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 7fdcc0ddb66bd9fb38a440a6d997a74c2ad630b5 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 28 Sep 2021 22:18:35 +0200 Subject: [PATCH 120/265] 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 455c5f1096812d484d25058b4fae1e8e8aba2f52 Mon Sep 17 00:00:00 2001 From: "Satheesh (ryanjon2040)" Date: Wed, 6 Oct 2021 02:00:47 +0530 Subject: [PATCH 121/265] 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 6f51a132e1ba06f54b9b1154fee3daee62f03831 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 10 Oct 2021 00:49:43 +0200 Subject: [PATCH 122/265] #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 7599caf26..9539faa0f 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -40,7 +40,7 @@ void UFlowGraphSchema::SubscribeToAssetChanges() 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); IHotReloadInterface& HotReloadSupport = FModuleManager::LoadModuleChecked("HotReload"); HotReloadSupport.OnHotReload().AddStatic(&UFlowGraphSchema::OnHotReload); @@ -205,14 +205,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) @@ -254,34 +256,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()); @@ -312,7 +316,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; @@ -352,7 +356,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 f961eb174..3b2872110 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 f4fdc247f16832bfb20ddf812aea072d00879cb5 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 11 Oct 2021 20:43:09 +0200 Subject: [PATCH 123/265] 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 ca076ec83..f123fe514 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 e33c989dc53427cf8ff458c06af8ad0623679d6d Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Wed, 13 Oct 2021 20:55:36 +0200 Subject: [PATCH 124/265] 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 7d028b9976890127dced3158a33e45efe3adc0af Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 24 Oct 2021 19:11:18 +0200 Subject: [PATCH 125/265] #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 9539faa0f..22b32e0b6 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -22,10 +22,6 @@ TArray UFlowGraphSchema::NativeFlowNodes; TMap UFlowGraphSchema::BlueprintFlowNodes; - -TSet UFlowGraphSchema::UnsortedCategories; -TArray> UFlowGraphSchema::FlowNodeCategories; - TMap UFlowGraphSchema::AssignedGraphNodeClasses; FFlowGraphSchemaRefresh UFlowGraphSchema::OnNodeListChanged; @@ -177,12 +173,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) @@ -211,7 +237,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()); } @@ -263,9 +289,6 @@ void UFlowGraphSchema::GatherFlowNodes() if (Class->ClassGeneratedBy == nullptr && IsFlowNodePlaceable(Class)) { NativeFlowNodes.Emplace(Class); - - const UFlowNode* DefaultObject = Class->GetDefaultObject(); - UnsortedCategories.Emplace(DefaultObject->GetNodeCategory()); } } @@ -299,7 +322,7 @@ void UFlowGraphSchema::GatherFlowNodes() AddAsset(AssetData, true); } - RefreshNodeList(); + OnNodeListChanged.Broadcast(); } void UFlowGraphSchema::OnHotReload(bool bWasTriggeredAutomatically) @@ -340,16 +363,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(); } } } @@ -363,29 +381,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 3b2872110..879372e23 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 2d74c2e189f07579fec62415786fd3786ae85add Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 24 Oct 2021 21:00:41 +0200 Subject: [PATCH 126/265] #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 22b32e0b6..c859c6751 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -24,6 +24,8 @@ TArray UFlowGraphSchema::NativeFlowNodes; TMap UFlowGraphSchema::BlueprintFlowNodes; TMap UFlowGraphSchema::AssignedGraphNodeClasses; +bool UFlowGraphSchema::bBlueprintCompilationPending; + FFlowGraphSchemaRefresh UFlowGraphSchema::OnNodeListChanged; UFlowGraphSchema::UFlowGraphSchema(const FObjectInitializer& ObjectInitializer) @@ -43,8 +45,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); } } @@ -271,11 +273,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 879372e23..9fb69a1dd 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(bool bWasTriggeredAutomatically); 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 d7caa63a57c242d928a38fccba710976725d3916 Mon Sep 17 00:00:00 2001 From: "Satheesh (ryanjon2040)" Date: Tue, 26 Oct 2021 01:17:44 +0530 Subject: [PATCH 127/265] 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 d97342624b865da20bfb1fbd48247d9d5689b08c Mon Sep 17 00:00:00 2001 From: "Satheesh (ryanjon2040)" Date: Tue, 26 Oct 2021 01:17:52 +0530 Subject: [PATCH 128/265] 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 27e99e7dc9c8199c24d49ea95bf27f1c908ac6f6 Mon Sep 17 00:00:00 2001 From: "Satheesh (ryanjon2040)" Date: Tue, 26 Oct 2021 01:19:26 +0530 Subject: [PATCH 129/265] 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 f9b76825586bea4a49f6d6afff4ad9fc0eab0c84 Mon Sep 17 00:00:00 2001 From: Markus Ahrweiler Date: Mon, 25 Oct 2021 21:48:38 +0200 Subject: [PATCH 130/265] 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 b5ca1c25795e33ca3d8f1c6e3005627204f7749c Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 25 Oct 2021 22:19:17 +0200 Subject: [PATCH 131/265] 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 a53f3dd28ca1f603deba1f37dbd735355e4432e6 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 25 Oct 2021 22:53:57 +0200 Subject: [PATCH 132/265] 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 33180b3c460829b35eea1ec221e600a3a2cf2c8b Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 25 Oct 2021 23:09:00 +0200 Subject: [PATCH 133/265] 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 4a89abdbc3202184d9bfc2e23bd79c63e6796b08 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 26 Oct 2021 12:47:21 +0200 Subject: [PATCH 134/265] 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 27c6adf54df10741679c29a1c97bcd4d5e317b89 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 31 Oct 2021 16:07:22 +0100 Subject: [PATCH 135/265] 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 7dae0aa1cdb9089375a87dddb9a9a32af5f57d38 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 1 Nov 2021 12:47:15 +0100 Subject: [PATCH 136/265] 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 b359bec933bd20739de2273782850f5f5b9b9b95 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 1 Nov 2021 16:26:17 +0100 Subject: [PATCH 137/265] 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 af1f9936c66898d470d25850e92ac892c77a3fa7 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Thu, 4 Nov 2021 15:11:54 +0100 Subject: [PATCH 138/265] 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 46cd463c053a6c3b98ff0e204452d0c8fd5d1f70 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 9 Nov 2021 11:18:28 +0100 Subject: [PATCH 139/265] 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 c859c6751..ec41f1d08 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -50,15 +50,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()) @@ -223,27 +229,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 77a96f83b..072d3e80d 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 9fb69a1dd..be1c11e8c 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 6451554d60ce0e8f46f31d7bf5e54a1dad71e7be Mon Sep 17 00:00:00 2001 From: "Satheesh (ryanjon2040)" Date: Thu, 11 Nov 2021 19:58:51 +0530 Subject: [PATCH 140/265] #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 ec41f1d08..623ac5aad 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" @@ -179,6 +180,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 be1c11e8c..848edac9e 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 d23c03d3d77161cbc0daefa62dc92964c6899b7a Mon Sep 17 00:00:00 2001 From: Proboszcz777 Date: Wed, 17 Nov 2021 20:55:52 +0100 Subject: [PATCH 141/265] 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 93bb70ae118f160496c74570d33f85c80a72d56b Mon Sep 17 00:00:00 2001 From: Sergey Vikhirev Date: Mon, 29 Nov 2021 23:26:42 +0400 Subject: [PATCH 142/265] 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 cfdeab9af0e0487a856f02f0b12ef70d333c2a3d Mon Sep 17 00:00:00 2001 From: Sergey Vikhirev Date: Mon, 29 Nov 2021 23:27:01 +0400 Subject: [PATCH 143/265] 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 6d318cc37..446fb2045 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -633,6 +633,7 @@ void FFlowAssetEditor::OnSelectedNodesChanged(const TSet& Nodes) void FFlowAssetEditor::SelectSingleNode(UEdGraphNode* Node) const { + FocusedGraphEditor->ClearSelectionSet(); FocusedGraphEditor->SetNodeSelection(Node, true); } From 9cceb3ae76e78b0e07839b2ab8edd15f161960f5 Mon Sep 17 00:00:00 2001 From: Sergey Vikhirev Date: Mon, 29 Nov 2021 23:45:09 +0400 Subject: [PATCH 144/265] 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 2e864631745d519af70ecbc1cbea7d9b54673c7f Mon Sep 17 00:00:00 2001 From: Mahoukyou Date: Mon, 29 Nov 2021 20:52:46 +0100 Subject: [PATCH 145/265] 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 446fb2045..d36942240 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -651,6 +651,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 41aa756cbf90add1eb31b20eff3bd43084b7776b Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 29 Nov 2021 21:09:57 +0100 Subject: [PATCH 146/265] 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 b387ca80c7d79d7956b9be27d4c78d29ff5b8119 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 29 Nov 2021 21:14:15 +0100 Subject: [PATCH 147/265] 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 67b7dbdb10ffcacb08acf63a60f87bab3f4b2431 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 29 Nov 2021 21:59:47 +0100 Subject: [PATCH 148/265] 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 072d3e80d..fa513578a 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 5284049c1de7ac95d50ca9389d91699b02297244 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 29 Nov 2021 21:59:47 +0100 Subject: [PATCH 149/265] tweaked include order From 3041d8f2766962c6c38b3de674c09e5229eb7149 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Thu, 16 Dec 2021 19:52:05 +0100 Subject: [PATCH 150/265] 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 05e46d188e4a30bbeed4add2d5f826c50f0baec9 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sat, 18 Dec 2021 15:20:11 +0100 Subject: [PATCH 151/265] 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 a0fd2c510f1530cefaaa5808f5af86cf8bc4b7b3 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sat, 18 Dec 2021 19:08:35 +0100 Subject: [PATCH 152/265] 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 2879fbc51..894e71db6 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 6b93c0a38a003e7539a34bb2ef5afb9e39658eef Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sat, 18 Dec 2021 19:08:55 +0100 Subject: [PATCH 153/265] 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 e56f8c8c1851ae24c9ed84b13585cbc8e02c65a5 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sat, 18 Dec 2021 19:09:24 +0100 Subject: [PATCH 154/265] 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 f123fe514..1112c0c3f 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 "Framework/MultiBox/MultiBoxDefs.h" #include "PropertyCustomizationHelpers.h" @@ -23,8 +25,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()); } @@ -75,8 +76,7 @@ void SLevelEditorFlow::OnFlowChanged(const FAssetData& NewAsset) { FlowPath = NewAsset.ObjectPath; - UFlowComponent* FlowComponent = FindFlowComponent(); - if (FlowComponent) + if (UFlowComponent* FlowComponent = FindFlowComponent()) { if (UObject* NewObject = NewAsset.GetAsset()) { @@ -99,12 +99,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 8f6c4946a25f0717ac461808eabe49dcc7a2d87e Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sat, 18 Dec 2021 19:09:56 +0100 Subject: [PATCH 155/265] 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 5b4950d845af26248869cd8c9d22549cc685b391 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sat, 18 Dec 2021 19:36:23 +0100 Subject: [PATCH 156/265] reverted 'init-statements in if/switch' as compiler flag '/std:c++17' isn't set --- Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp b/Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp index 1112c0c3f..b9da79660 100644 --- a/Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp +++ b/Source/FlowEditor/Private/LevelEditor/SLevelEditorFlow.cpp @@ -25,7 +25,8 @@ void SLevelEditorFlow::OnMapOpened(const FString& Filename, bool bAsTemplate) void SLevelEditorFlow::CreateFlowWidget() { - if (UFlowComponent* FlowComponent = FindFlowComponent(); FlowComponent && FlowComponent->RootFlow) + UFlowComponent* FlowComponent = FindFlowComponent(); + if (FlowComponent && FlowComponent->RootFlow) { FlowPath = FName(*FlowComponent->RootFlow->GetPathName()); } From b39bcaafad8a3c88bc5813dd102a19331244be4d Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 19 Dec 2021 14:03:27 +0100 Subject: [PATCH 157/265] 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 40f267b2c896cc71758ed6fbce31c77fdb0a14b1 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 19 Dec 2021 14:11:55 +0100 Subject: [PATCH 158/265] 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 0119308aeec24f65848688d48a66db79b4d14178 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 21 Dec 2021 20:23:28 +0100 Subject: [PATCH 159/265] 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 472add5e63d9d8d951eefa458b5e6f0711000896 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Thu, 23 Dec 2021 21:22:14 +0100 Subject: [PATCH 160/265] 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 31ab4f12ea6e2276be69d9263b35cd42a8cf731c Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 16 Jan 2022 20:31:12 +0100 Subject: [PATCH 161/265] 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 d36942240..1a9080e21 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 12a7c1b52..c598abd78 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 aa09237b689c0e86f8935667a0ae2df456e36a59 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 24 Jan 2022 11:56:16 +0100 Subject: [PATCH 162/265] bump version to 1.2 --- Flow.uplugin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.uplugin b/Flow.uplugin index e8919641e..4e3b5a3f5 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 c0537b60f8cbd1da2b3dc9ad7a0a6c2c0ee57d08 Mon Sep 17 00:00:00 2001 From: Luna Ryuko Zaremba Date: Thu, 27 Jan 2022 17:02:55 +0100 Subject: [PATCH 163/265] 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 d36af68be1ebe6ae0537adbc48a70fee5d12ff36 Mon Sep 17 00:00:00 2001 From: Luna Ryuko Zaremba Date: Thu, 27 Jan 2022 17:02:55 +0100 Subject: [PATCH 164/265] Make UFlowNodeBlueprint not final, so it can be subclassed (#87) From f0017f7bf7c4760159840437073f0af08d9957d6 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 165/265] 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 88f5cadbc0cd0a31940c706ea7f387687b9874cd Mon Sep 17 00:00:00 2001 From: "Satheesh (ryanjon2040)" Date: Fri, 28 Jan 2022 16:36:08 +0530 Subject: [PATCH 166/265] 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 894e71db6..c2cad395d 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 f7349c710e26cff9585778dab71b3ad9d4b6893f Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 28 Jan 2022 15:57:09 +0100 Subject: [PATCH 167/265] 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 1a9080e21..32ffe2b2d 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -225,7 +225,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 dd7d058b621a3a06f645a71ffbb7e501041dc1d1 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 28 Jan 2022 16:01:07 +0100 Subject: [PATCH 168/265] 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 d67763c6c35903859383d739f169303d3ffc34e8 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 28 Jan 2022 16:18:23 +0100 Subject: [PATCH 169/265] 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 6f61394166d99fb6d6119ac4eca9818ffb86810c Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 13 Feb 2022 19:35:59 +0100 Subject: [PATCH 170/265] #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 623ac5aad..550bf3a67 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -308,7 +308,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 d11aa846dbffdb4d26ab10c4768df96f4d9f5e31 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 22 Feb 2022 16:23:07 +0100 Subject: [PATCH 171/265] 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 ad3c79e0fbf90e8733baceb4e68fb07377952600 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 172/265] 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 ba2a84255ce99273d2771785a6f22841f518cd53 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 173/265] 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 add9c6e6215a4c33d1e801f9e16810b30df5db4c Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Thu, 10 Mar 2022 14:20:32 +0100 Subject: [PATCH 174/265] 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 43db38c1b1365a38f0aec69e12fa5131241faf2f Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 25 Mar 2022 17:02:57 +0100 Subject: [PATCH 175/265] 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 2f179270da2b977a7ca04136e91a81950c5daa88 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 25 Mar 2022 17:28:58 +0100 Subject: [PATCH 176/265] 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 d2e684be18549d7ea62cef8922bd6f0ecb611ceb Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Fri, 25 Mar 2022 19:10:01 +0100 Subject: [PATCH 177/265] 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 71cb14828a2f8334be2bea54b9fed56255978b98 Mon Sep 17 00:00:00 2001 From: Markus Ahrweiler Date: Wed, 30 Mar 2022 18:58:44 +0200 Subject: [PATCH 178/265] 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 550bf3a67..fa6a23826 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -186,10 +186,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]); @@ -245,6 +245,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) @@ -260,12 +273,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) @@ -318,7 +333,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 848edac9e..bca77e88d 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 fd6cf942bfe90edd8db4a894834ce39846618844 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 179/265] 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 1fb5fc6465e0316c29257cafe0c275ac07ea2b28 Mon Sep 17 00:00:00 2001 From: Joseph Date: Thu, 31 Mar 2022 02:13:17 +0900 Subject: [PATCH 180/265] 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 93196ec7921d3b04804707e829bcea0ec0e5a2e3 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Wed, 30 Mar 2022 19:49:32 +0200 Subject: [PATCH 181/265] 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 bca77e88d..07203fd11 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 ffe28a28ff280c280c94bad9f8f0d96f241959dd Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Wed, 30 Mar 2022 20:25:27 +0200 Subject: [PATCH 182/265] 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 13f447816f2f5b43fe8467b91f946e43b6c853c9 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Tue, 5 Apr 2022 18:03:07 +0200 Subject: [PATCH 183/265] contributors link --- Flow.uplugin | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Flow.uplugin b/Flow.uplugin index 4e3b5a3f5..ce4c339a2 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 2735372f97ab9693461c13da8d140d30063a07e4 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 10 Apr 2022 12:55:16 +0200 Subject: [PATCH 184/265] bump to 1.3 --- Flow.uplugin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.uplugin b/Flow.uplugin index ce4c339a2..ecaa3d492 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 a0da39fdf56de230ff716b9bc6a238a006264fd5 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 11 Apr 2022 00:40:12 +0200 Subject: [PATCH 185/265] #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 ecaa3d492..f90e1f8cc 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 cf40227dd..0a6671862 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 c598abd78..c4f080ef7 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 26084cc130a543d160e2f186d4091c442fafcff1 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 11 Apr 2022 01:03:56 +0200 Subject: [PATCH 186/265] 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 0a6671862..8b876ece1 100644 --- a/Source/FlowEditor/FlowEditor.Build.cs +++ b/Source/FlowEditor/FlowEditor.Build.cs @@ -27,6 +27,8 @@ public FlowEditor(ReadOnlyTargetRules Target) : base(Target) "Engine", "GraphEditor", "InputCore", + "Json", + "JsonUtilities", "KismetWidgets", "LevelEditor", "MovieScene", From 03aed7f646faa5a42cad71e9ebbeced415c986f5 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Wed, 13 Apr 2022 21:30:42 +0200 Subject: [PATCH 187/265] 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 ba501cedfbc6a1076942d80f38ced0a0899891b4 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Wed, 27 Apr 2022 15:35:17 +0200 Subject: [PATCH 188/265] 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 ab61569217e85e7d096cce6e7ef4287b3a7a8c02 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 8 May 2022 16:35:49 +0200 Subject: [PATCH 189/265] 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 5b0344845b3696eb9bb8f6dd3c2ca9ed262c377b Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 8 May 2022 17:42:16 +0200 Subject: [PATCH 190/265] #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 8a07368a23be89010f9104d6037872cc46519045 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 8 May 2022 22:52:02 +0200 Subject: [PATCH 191/265] 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 50a09f6f1ab5ccd96f1ae0b5cf3c3e784d28e11e Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sun, 8 May 2022 22:52:54 +0200 Subject: [PATCH 192/265] 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 ac168d7205df8e708363727abd55fc57d23e04d6 Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Mon, 9 May 2022 15:09:59 +0200 Subject: [PATCH 193/265] 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 f23d4da734d9f6833c5798deefe5588af002447b Mon Sep 17 00:00:00 2001 From: Moth Doctor Date: Sat, 14 May 2022 00:31:42 +0200 Subject: [PATCH 194/265] 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 43dc4cfa9..0e46eca29 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 8b876ece1..5540310a9 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 07203fd11..13b64a284 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 f7cbcce63270009a61b88039bff92212a43a018a 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 195/265] 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 e1cc1d64b5a0423dc5dd8a8c95e7f15e4edbb27c Mon Sep 17 00:00:00 2001 From: "Satheesh (ryanjon2040)" Date: Sun, 29 May 2022 01:19:49 +0530 Subject: [PATCH 196/265] 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 32ffe2b2d..d5420b9e8 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -915,6 +915,10 @@ void FFlowAssetEditor::OnNodeDoubleClicked(class UEdGraphNode* Node) const } } } + else if (UObject* BlueprintAsset = FlowNode->GetClass()->ClassGeneratedBy) + { + GEditor->GetEditorSubsystem()->OpenEditorForAsset(BlueprintAsset); + } } } From 2a56d98a0b29822d1a91ffc0c1f3c66ecd47c2bd Mon Sep 17 00:00:00 2001 From: "Satheesh (ryanjon2040)" Date: Sun, 29 May 2022 01:21:14 +0530 Subject: [PATCH 197/265] 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 fa6a23826..24384cdc6 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -79,6 +79,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 6b52a5f2f10a4b558f23619bbb5e99b4e4ad7a46 Mon Sep 17 00:00:00 2001 From: Joseph Date: Sun, 29 May 2022 04:51:26 +0900 Subject: [PATCH 198/265] 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 0e46eca29..10e223cc7 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 3a19ef98b00ea5ae806e22c28401a745cdaed89f 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 199/265] 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 | 44 ++++++++++++------- .../FlowEditor/Public/Graph/FlowGraphSchema.h | 8 +++- 4 files changed, 38 insertions(+), 19 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 24384cdc6..88043097b 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -36,7 +36,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::OnAssetRemoved); @@ -51,21 +51,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()) @@ -79,9 +73,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(); } @@ -259,21 +258,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; @@ -442,7 +439,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())) @@ -480,4 +477,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 13b64a284..53deb6b70 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 2f3ad40df336cac7d84533526b3375308b418d28 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 200/265] 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 fa513578a..399a3f0c4 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(NameFont, 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 6a318d3a69cce384aa87408db8367245b621a7e6 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 201/265] #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 180c948cbbb2a088e6b0a295be2645251250f48a 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 202/265] 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 d5420b9e8..3b2406bd0 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" @@ -780,7 +781,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; @@ -894,31 +895,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 0e92825c20cdc59ef2a887d5f722bb19f072408c 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 203/265] 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 10e223cc7..50d94e34d 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 e31781b8a4a5ce18949d27f5635009cafb87f158 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 204/265] #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 3b2406bd0..948915755 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -485,6 +485,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), @@ -1240,6 +1248,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 c2cad395d..e29ac8056 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 a1a00d4c3c415bd301cd07b4ed955c0d0e60e983 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 205/265] 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 948915755..37e5e885b 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 c4f080ef7..42768d90a 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 88043097b..9b8a66f0f 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 e29ac8056..410e1feed 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 399a3f0c4..a7eb58b4d 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 b9da79660..dca3022b6 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 402526c0a..f134c04ea 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 eda9c6102b3fb0906e43014939fd5bd454fb5b43 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 206/265] 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 8674940d5c16386c2793d26e32adf0953efc07bb 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 207/265] 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 25ef58a0c5f00eab16e87269f4627a826c3be124 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 208/265] 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 88052a37e20c91f592a01c2e23c0095ad7f3f2a6 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 209/265] 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 9012ab68f090daa4422b829c72e668871d710cf1 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 210/265] 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 3712effd578e3d9da8e2c83db30fc386df8ee010 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 211/265] 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 b0140ef3ead751d6125e2669fd13554b17efc73f 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 212/265] 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 9b8a66f0f..f970b530c 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -323,7 +323,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 b4f5534899443adc4dd3a25e343f005e97da3b04 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 213/265] 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 386a7ff54bc6568cfb65fe3b2b66592e9d03cf05 Mon Sep 17 00:00:00 2001 From: Markus Ahrweiler Date: Sat, 20 Aug 2022 09:52:22 +0200 Subject: [PATCH 214/265] 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 5f9e89053bed1eda553663decbb88ec3b078bfeb 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 215/265] 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 471269de29f2e219b448df7bfb085e2adb7392af 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 216/265] 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 772aec1ce28983ed52eeaf80e8d1844d128a1ea0 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 217/265] #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 a1b95a97a3cfd5f0f2fa60afa3cbd9ac04bd7dfe 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 218/265] #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 410e1feed..f3c5962d3 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 fbe1cdf5e20d6d22c16b68f2f3887b739e73986f 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 219/265] 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 fc67472675527511cef93d6f78854d88ca59f33d 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 220/265] #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 f3c5962d3..c371288ff 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 b4bd8845f..a9f248725 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 7122f851d8b3dd95e6fb5b1e2b6ed630e80047cc 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 221/265] 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 c562a2921b15ff0b12ff8339d0d1ed65b7764459 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 222/265] 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 f2b993881bb56b7cc309093dd7d22f42e9df1540 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 223/265] 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 37e5e885b..62297802c 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -1254,7 +1254,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 b8c1f88ecb6135613832854c32413d34b5e4f821 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 224/265] 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 4ab211330acadd87bd4d6db2e2f942177e8c1800 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 225/265] 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 e1ac27bf7a83a1527c6599092bd5a27bc737ae9d 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 226/265] 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 52ea05a79345d6e02f930c7e973d66d40831f28c 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 227/265] 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 9769bc4d92da747c95ef0eaffa53830050151b4a 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 228/265] #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 42768d90a..6f8c769bc 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 8f4ca8842135535077ba63616900ebc2d43a434f 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 229/265] Sequence replication option #115 by @ArseniyZvezda --- .../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..6edbd06af 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()) + { + LevelSequence = Asset; + ReplicatedLevelSequenceAsset = LevelSequence; + } +} + +void AFlowLevelSequenceActor::OnRep_ReplicatedLevelSequenceAsset() +{ + LevelSequence = ReplicatedLevelSequenceAsset; +} + +void AFlowLevelSequenceActor::RPC_InitializePlayer_Implementation() +{ + InitializePlayer(); +}; diff --git a/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp b/Source/Flow/Private/LevelSequence/FlowLevelSequencePlayer.cpp index 50d94e34d..67466d48f 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, 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->LevelSequence = LevelSequence; Actor->CameraSettings = CameraSettings; - - Actor->InitializePlayer(); + if (bReplicates) + { + Actor->SetReplicatedLevelSequenceAsset(LevelSequence); + Actor->SetReplicatePlayback(true); + Actor->bAlwaysRelevant = true; + Actor->RPC_InitializePlayer(); + } + else + { + Actor->LevelSequence = 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..30aae4e41 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) + FSoftObjectPath ReplicatedLevelSequenceAsset; + + UFUNCTION() + void OnRep_ReplicatedLevelSequenceAsset(); }; diff --git a/Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h b/Source/Flow/Public/LevelSequence/FlowLevelSequencePlayer.h index 75110ff63..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, const 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 26f7d88649260b4babe5806cfcc762097db27579 Mon Sep 17 00:00:00 2001 From: "Satheesh (ryanjon2040)" Date: Thu, 1 Sep 2022 15:41:39 +0530 Subject: [PATCH 230/265] 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 70bc9b88733ae1652af515de2f5029dd13db30e4 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 231/265] 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 cca10a12f59d156eab5eb25e0c5eda3583fb80e7 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 232/265] 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 6613885f6e9dbd9f4c4c11339d876b158dfb6d9d 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 233/265] 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 00d1d34de401be0d82254635d870bfc572449b8c 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 234/265] 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 06cd37c8d33fee4aa92fd9a859b624461397e94a 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 235/265] 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 69fcc0debdd0ef4bf3c72cb1e83879641e3a9ab9 Mon Sep 17 00:00:00 2001 From: Bargestt Date: Thu, 8 Sep 2022 22:48:30 +0700 Subject: [PATCH 236/265] 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 6f8c769bc..a3271819d 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 2a819b8fbff74bd9e1423d3bcac762ad03f30a66 Mon Sep 17 00:00:00 2001 From: Bargestt Date: Thu, 8 Sep 2022 22:48:45 +0700 Subject: [PATCH 237/265] 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 4d2ae6edb7e138531cf2ea161183fa32d63453fc 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 238/265] 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 a3271819d..756b722d2 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 9a0c3cb6445eecc2d6aac2dfd57d476bb4aa5358 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 239/265] 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 47b1d1e3172dbfdb06b9e07a15f0acaa28715ee3 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 240/265] 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 f970b530c..c60a36190 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphSchema.cpp @@ -19,7 +19,6 @@ #include "EdGraph/EdGraph.h" #include "Misc/HotReloadInterface.h" #include "ScopedTransaction.h" -#include "UObject/UObjectIterator.h" #define LOCTEXT_NAMESPACE "FlowGraphSchema" @@ -247,17 +246,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) @@ -267,38 +321,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 53deb6b70..5ed6e4db3 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 4d00ad7b4f0a5d9315055d2783177d62b33f8000 Mon Sep 17 00:00:00 2001 From: Jani Hartikainen Date: Sun, 25 Sep 2022 13:25:08 +0300 Subject: [PATCH 241/265] 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 2cf40886d9cbaacd7c87180123166c8ecc4723c1 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 242/265] 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 c70f51b0b36b156d32d4ad2d58b913686ae345eb 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 243/265] 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 | 9 +++++++++ 4 files changed, 36 insertions(+), 11 deletions(-) create mode 100644 Source/FlowEditor/Public/FlowEditorDefines.h 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 756b722d2..31e0c59af 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 new file mode 100644 index 000000000..f14784241 --- /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/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 ba2db4f9a70c06e174a3062717500e977ab78647 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 244/265] 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 62297802c..b74032bbd 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -262,11 +262,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() @@ -280,15 +280,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 99259929d..a7b80cbfb 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetToolbar.cpp @@ -143,10 +143,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) @@ -202,7 +202,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 ab4046e05..21acc39a6 100644 --- a/Source/FlowEditor/Private/FlowEditorStyle.cpp +++ b/Source/FlowEditor/Private/FlowEditorStyle.cpp @@ -33,8 +33,8 @@ void FFlowEditorStyle::Initialize() 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)); + 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 086512d2d529660700048e4159e715a63e8b2433 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 245/265] 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 b479100f2aabc3e7ec81c8dd745a1851b99ae835 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 246/265] 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 c0bc58c974e7cb16587680c7771bb106337230cb 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 247/265] 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 4c0fd66c9aa0e6f69a3b756cca7e72004784610f 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 248/265] 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 65019575b6ac3594701ede0440091b3782b6c95b 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 249/265] 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 49fe78661be1d065bb9c4351f10454b32c76e0a5 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 250/265] 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 5540310a9..ada4927c0 100644 --- a/Source/FlowEditor/FlowEditor.Build.cs +++ b/Source/FlowEditor/FlowEditor.Build.cs @@ -33,6 +33,7 @@ public FlowEditor(ReadOnlyTargetRules Target) : base(Target) "JsonUtilities", "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 e97b170356808b8eff50c872aca72d7e54d2c1af 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 251/265] #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 c371288ff..6495a4cad 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->MarkPendingKill(); 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->MarkPendingKill(); 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 4cdc8baec1bbefebdb3ca13eac0727914bc78fec 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 252/265] 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 4f02840d192d96b2e85a8d211f4c2bb8bfcc65fc 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 253/265] 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 c60a36190..a4dfb4e67 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 "Misc/HotReloadInterface.h" #include "ScopedTransaction.h" @@ -472,30 +472,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 53edca98656a3e86dd37659f9c2bfc7abfab072c 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 254/265] 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 6495a4cad..638b96ee3 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 a8fe0fc7e6e83e06a3bf56b72a989d2e24e74429 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 255/265] 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 6edbd06af..04d4a081f 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() { LevelSequence = 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 67466d48f..af37c6791 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->LevelSequence = 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 30aae4e41..423b3ddac 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) + FSoftObjectPath ReplicatedLevelSequenceAsset; + virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; - + public: void SetReplicatedLevelSequenceAsset(ULevelSequence* Asset); - UFUNCTION(NetMulticast, Reliable) - void RPC_InitializePlayer(); - protected: - UPROPERTY(ReplicatedUsing = OnRep_ReplicatedLevelSequenceAsset) - FSoftObjectPath 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 62534d39b6cfd7a436c9e081117cd1d6a20da610 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 256/265] 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 5e9e9331eb055b457ad9b1b3effd71846e98d441 Mon Sep 17 00:00:00 2001 From: sturcotte06 Date: Tue, 8 Nov 2022 11:15:00 -0500 Subject: [PATCH 257/265] 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 d41d16502631a9cdef3a9dc629e25e76938ea1fa 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 258/265] 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 88fb2a368cc45ae7a91b4145a7814f16fcb33f95 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 259/265] 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 a45e6fdd20cde173dc51bc01a85f1049e416fb0b 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 260/265] 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 b74032bbd..03d6cb103 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -488,13 +488,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), @@ -1250,6 +1271,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 638b96ee3..0b513957f 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 a9f248725..f19825de5 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 47a39088f011be92b78c7b0f83c5ccfa665cd7cb 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 261/265] 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 35fd68fab8112e55973f56d62fc5147f0c1c9379 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 262/265] 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 f175c96d1964a16dcee4e76e816241d2fe3133c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysiek=20Justy=C5=84ski?= Date: Fri, 11 Nov 2022 14:45:33 +0100 Subject: [PATCH 263/265] compilation fixes --- Source/Flow/Private/Nodes/FlowPin.cpp | 2 ++ Source/Flow/Public/Nodes/FlowPin.h | 2 +- Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowPin.cpp b/Source/Flow/Private/Nodes/FlowPin.cpp index d072bd140..ac32c356a 100644 --- a/Source/Flow/Private/Nodes/FlowPin.cpp +++ b/Source/Flow/Private/Nodes/FlowPin.cpp @@ -4,6 +4,8 @@ #if !UE_BUILD_SHIPPING +FName FFlowPin::AnyPinName = TEXT("AnyPinName"); + FString FPinRecord::NoActivations = TEXT("No activations"); FString FPinRecord::PinActivations = TEXT("Pin activations"); FString FPinRecord::ForcedActivation = TEXT(" (forced activation)"); diff --git a/Source/Flow/Public/Nodes/FlowPin.h b/Source/Flow/Public/Nodes/FlowPin.h index 78ef72c41..85c70ef0a 100644 --- a/Source/Flow/Public/Nodes/FlowPin.h +++ b/Source/Flow/Public/Nodes/FlowPin.h @@ -20,7 +20,7 @@ struct FLOW_API FFlowPin UPROPERTY(EditDefaultsOnly, Category = "FlowPin") FString PinToolTip; - static inline FName AnyPinName = TEXT("AnyPinName"); + static FName AnyPinName; FFlowPin() : PinName(NAME_None) diff --git a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp index f19825de5..8c1568c75 100644 --- a/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Widgets/SFlowGraphNode.cpp @@ -375,7 +375,7 @@ void SFlowGraphNode::UpdateErrorInfo() TSharedRef SFlowGraphNode::CreateTitleWidget(TSharedPtr NodeTitle) { SAssignNew(InlineEditableText, SInlineEditableTextBlock) - .Style(FAppStyle::Get(), "Graph.Node.NodeTitleInlineEditableText") + .Style(FEditorStyle::Get(), "Graph.Node.NodeTitleInlineEditableText") .Text(NodeTitle.Get(), &SNodeTitle::GetHeadTitle) .OnVerifyTextChanged(this, &SFlowGraphNode::OnVerifyNameTextChanged) .OnTextCommitted(this, &SFlowGraphNode::OnNameTextCommited) From 222673013ec0c7273cc12ad783edffe12d9bad90 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 264/265] 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 0b513957f..de340781a 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 1b40609e6320b70216dec01f07b2e215d980cd99 Mon Sep 17 00:00:00 2001 From: ryanjon2040 Date: Fri, 18 Nov 2022 18:57:00 +0530 Subject: [PATCH 265/265] 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 03d6cb103..0d73bff84 100644 --- a/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp +++ b/Source/FlowEditor/Private/Asset/FlowAssetEditor.cpp @@ -1277,6 +1277,8 @@ void FFlowAssetEditor::SetSignalMode(const EFlowSignalMode Mode) const { SelectedNode->SetSignalMode(Mode); } + + FlowAsset->Modify(); } bool FFlowAssetEditor::CanSetSignalMode(const EFlowSignalMode Mode) const