diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index 521ed3e3..5400f90e 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -1193,11 +1193,27 @@ void UFlowAsset::PreStartFlow() #endif } -void UFlowAsset::StartFlow(IFlowDataPinValueSupplierInterface* DataPinValueSupplier) +void UFlowAsset::StartFlow(IFlowDataPinValueSupplierInterface* DataPinValueSupplier /*= nullptr*/, const FGuid& StartingNodeGuid /*= FGuid()*/) { PreStartFlow(); - if (UFlowNode* ConnectedEntryNode = GetDefaultEntryNode()) + if (StartingNodeGuid.IsValid()) + { + if (UFlowNode* StartingNode = Nodes.FindRef(StartingNodeGuid)) + { + RecordedNodes.Add(StartingNode); + + if (StartingNode->GetInputPins().Num() > 0) + { + StartingNode->TriggerInput(StartingNode->GetInputPins()[0].PinName); + } + else + { + StartingNode->TriggerFirstOutput(true); + } + } + } + else if (UFlowNode* ConnectedEntryNode = GetDefaultEntryNode()) { RecordedNodes.Add(ConnectedEntryNode); diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index 94661063..ec533fea 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -76,7 +76,7 @@ void UFlowSubsystem::AbortActiveFlows() RootInstances.Empty(); } -void UFlowSubsystem::StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances /* = true */) +void UFlowSubsystem::StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances /* = true */, const FGuid& StartingNodeGuid /* = FGuid() */) { if (FlowAsset) { @@ -84,7 +84,7 @@ void UFlowSubsystem::StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const { // todo: (gtaylor) In the future, we may want to provide a way to set a data pin value supplier // for the root flow graph. - NewFlow->StartFlow(); + NewFlow->StartFlow(nullptr, StartingNodeGuid); } } #if WITH_EDITOR diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index 38b9e206..417145d8 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -378,7 +378,7 @@ class FLOW_API UFlowAsset : public UObject virtual void PreloadNodes() {} virtual void PreStartFlow(); - virtual void StartFlow(IFlowDataPinValueSupplierInterface* DataPinValueSupplier = nullptr); + virtual void StartFlow(IFlowDataPinValueSupplierInterface* DataPinValueSupplier = nullptr, const FGuid& StartingNodeGuid = FGuid()); virtual void FinishFlow(const EFlowFinishPolicy InFinishPolicy, const bool bRemoveInstance = true); diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index 4852cb51..5df69ec5 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -73,7 +73,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", meta = (DefaultToSelf = "Owner")) - virtual void StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances = true); + virtual void StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances = true, const FGuid& StartingNodeGuid = FGuid()); virtual UFlowAsset* CreateRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances = true, const FString& NewInstanceName = FString()); diff --git a/Source/FlowEditor/Private/FlowEditorCommands.cpp b/Source/FlowEditor/Private/FlowEditorCommands.cpp index 8e681ede..5e46981e 100644 --- a/Source/FlowEditor/Private/FlowEditorCommands.cpp +++ b/Source/FlowEditor/Private/FlowEditorCommands.cpp @@ -53,6 +53,7 @@ void FFlowGraphCommands::RegisterCommands() 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()); + UI_COMMAND(RunFromNode, "Run from this node", "Run the flow starting from this node", EUserInterfaceActionType::Button, FInputChord()); } FFlowSpawnNodeCommands::FFlowSpawnNodeCommands() diff --git a/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp b/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp index ccdd093f..7416a953 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp @@ -4,9 +4,13 @@ #include "Asset/FlowAssetEditor.h" #include "FlowEditorCommands.h" +#include "FlowSubsystem.h" +#include "Graph/FlowGraphSchema.h" #include "Graph/FlowGraphSchema_Actions.h" #include "Graph/Nodes/FlowGraphNode.h" +#include "Engine/GameInstance.h" + #include "Debugger/FlowDebuggerSubsystem.h" #include "EdGraphUtilities.h" @@ -237,6 +241,10 @@ void SFlowGraphEditor::BindGraphCommands() FExecuteAction::CreateSP(this, &SFlowGraphEditor::JumpToNodeDefinition), FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanJumpToNodeDefinition)); + CommandList->MapAction(FlowGraphCommands.RunFromNode, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::RunFromNode), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanRunFromNode)); + // Organisation Commands CommandList->MapAction(GraphEditorCommands.AlignNodesTop, FExecuteAction::CreateSP(this, &SFlowGraphEditor::OnAlignTop)); @@ -1451,7 +1459,34 @@ void SFlowGraphEditor::JumpToNodeDefinition() const bool SFlowGraphEditor::CanJumpToNodeDefinition() const { - return GetSelectedFlowNodes().Num() == 1; + return GetSelectedFlowNodes().Num() == 1 && GetSelectedFlowNodes().Array()[0]->CanJumpToDefinition(); +} + +void SFlowGraphEditor::RunFromNode() const +{ + if (IsPIE()) + { + const TSet SelectedNodes = GetSelectedFlowNodes(); + if (SelectedNodes.Num() == 1) + { + if (const UFlowGraphNode* SelectedNode = SelectedNodes.Array()[0]) + { + if (const UFlowNode* HelperNode = Cast(SelectedNode->GetFlowNodeBase())) + { + if (UFlowSubsystem* FlowSubsystem = GEditor->PlayWorld->GetGameInstance()->GetSubsystem()) + { + FlowSubsystem->AbortActiveFlows(); + FlowSubsystem->StartRootFlow(GEditor->PlayWorld->GetGameInstance(), const_cast(FlowAsset.Get()), true, HelperNode->GetGuid()); + } + } + } + } + } +} + +bool SFlowGraphEditor::CanRunFromNode() const +{ + return IsPIE() && GetSelectedFlowNodes().Num() == 1; } #undef LOCTEXT_NAMESPACE diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index f041c028..84ddfe4f 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -10,6 +10,7 @@ #include "FlowEditorCommands.h" #include "Graph/FlowGraph.h" +#include "Graph/FlowGraphEditor.h" #include "Graph/FlowGraphEditorSettings.h" #include "Graph/FlowGraphSchema.h" #include "Graph/FlowGraphSettings.h" @@ -570,6 +571,10 @@ void UFlowGraphNode::GetNodeContextMenuActions(class UToolMenu* Menu, class UGra { Section.AddMenuEntry(FlowGraphCommands.JumpToNodeDefinition); } + if (SFlowGraphEditor::IsPIE()) + { + Section.AddMenuEntry(FlowGraphCommands.RunFromNode); + } } { diff --git a/Source/FlowEditor/Public/FlowEditorCommands.h b/Source/FlowEditor/Public/FlowEditorCommands.h index d83f84d5..b7e56961 100644 --- a/Source/FlowEditor/Public/FlowEditorCommands.h +++ b/Source/FlowEditor/Public/FlowEditorCommands.h @@ -53,6 +53,7 @@ class FLOWEDITOR_API FFlowGraphCommands : public TCommands /** Jumps */ TSharedPtr FocusViewport; TSharedPtr JumpToNodeDefinition; + TSharedPtr RunFromNode; virtual void RegisterCommands() override; }; diff --git a/Source/FlowEditor/Public/Graph/FlowGraphEditor.h b/Source/FlowEditor/Public/Graph/FlowGraphEditor.h index 331ebb1e..79057406 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphEditor.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphEditor.h @@ -157,4 +157,7 @@ class FLOWEDITOR_API SFlowGraphEditor : public SGraphEditor void JumpToNodeDefinition() const; bool CanJumpToNodeDefinition() const; + + void RunFromNode() const; + bool CanRunFromNode() const; }; \ No newline at end of file