diff --git a/Config/DefaultFlow.ini b/Config/DefaultFlow.ini index fe550471..703e8278 100644 --- a/Config/DefaultFlow.ini +++ b/Config/DefaultFlow.ini @@ -4,3 +4,5 @@ +PropertyRedirects=(OldName="FlowGraphNode.FlowNode",NewName="FlowGraphNode.NodeInstance") +StructRedirects=(OldName="/Script/Flow.FlowNamedDataPinOutputProperty",NewName="/Script/Flow.FlowNamedDataPinProperty") +PropertyRedirects=(OldName="FlowNode_DefineProperties.OutputProperties",NewName="NamedProperties") ++FunctionRedirects=(OldName="/Script/Flow.FlowSubsystem.FinishRootFlow",NewName="/Script/Flow.FlowSubsystem.FinishAndDeinitializeRootFlow") ++FunctionRedirects=(OldName="/Script/Flow.FlowSubsystem.FinishAllRootFlows",NewName="/Script/Flow.FlowSubsystem.FinishAndDeinitializeAllRootFlows") \ No newline at end of file diff --git a/Source/Flow/Private/FlowAsset.cpp b/Source/Flow/Private/FlowAsset.cpp index aba46958..34d29198 100644 --- a/Source/Flow/Private/FlowAsset.cpp +++ b/Source/Flow/Private/FlowAsset.cpp @@ -896,7 +896,7 @@ void UFlowAsset::ClearInstances() { if (ActiveInstances.IsValidIndex(i) && ActiveInstances[i]) { - ActiveInstances[i]->FinishFlow(EFlowFinishPolicy::Keep); + ActiveInstances[i]->FinishFlowAndDeinitializeInstance(EFlowFinishPolicy::Keep); } } @@ -1023,6 +1023,12 @@ AActor* UFlowAsset::TryFindActorOwner() const return nullptr; } +void UFlowAsset::FinishFlowAndDeinitializeInstance(const EFlowFinishPolicy InFinishPolicy) +{ + FinishFlow(InFinishPolicy); + DeinitializeInstance(); +} + void UFlowAsset::PreStartFlow() { ResetNodes(); @@ -1081,13 +1087,14 @@ void UFlowAsset::FinishNode(UFlowNode* Node) return; } - // if this instance is a Root Flow, we need to deregister it from the subsystem first + // if this instance is a Root Flow, we need to deregister it from the subsystem first. This will + // finalize and deinitialize the root flow. if (Owner.IsValid()) { const TSet& RootFlowInstances = GetFlowSubsystem()->GetRootInstancesByOwner(Owner.Get()); if (RootFlowInstances.Contains(this)) { - GetFlowSubsystem()->FinishRootFlow(Owner.Get(), TemplateAsset, EFlowFinishPolicy::Keep); + GetFlowSubsystem()->FinishAndDeinitializeRootFlow(Owner.Get(), TemplateAsset, EFlowFinishPolicy::Keep); return; } @@ -1108,7 +1115,7 @@ void UFlowAsset::ResetNodes() RecordedNodes.Empty(); } -void UFlowAsset::FinishFlow(const EFlowFinishPolicy InFinishPolicy, const bool bRemoveInstance /*= true*/) +void UFlowAsset::FinishFlow(const EFlowFinishPolicy InFinishPolicy) { FinishPolicy = InFinishPolicy; @@ -1120,12 +1127,6 @@ void UFlowAsset::FinishFlow(const EFlowFinishPolicy InFinishPolicy, const bool b Node->Deactivate(); } ActiveNodes.Empty(); - - // provides option to finish game-specific logic prior to removing asset instance - if (bRemoveInstance) - { - DeinitializeInstance(); - } } UFlowSubsystem* UFlowAsset::GetFlowSubsystem() const diff --git a/Source/Flow/Private/FlowComponent.cpp b/Source/Flow/Private/FlowComponent.cpp index da1dbe1f..62ca1dbc 100644 --- a/Source/Flow/Private/FlowComponent.cpp +++ b/Source/Flow/Private/FlowComponent.cpp @@ -99,7 +99,7 @@ void UFlowComponent::UnregisterWithFlowSubsystem() { if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) { - FlowSubsystem->FinishAllRootFlows(this, EFlowFinishPolicy::Keep); + FlowSubsystem->FinishAndDeinitializeAllRootFlows(this, EFlowFinishPolicy::Keep); FlowSubsystem->UnregisterComponent(this); } } @@ -461,7 +461,7 @@ void UFlowComponent::FinishRootFlow(UFlowAsset* TemplateAsset, const EFlowFinish { if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem()) { - FlowSubsystem->FinishRootFlow(this, TemplateAsset, FinishPolicy); + FlowSubsystem->FinishAndDeinitializeRootFlow(this, TemplateAsset, FinishPolicy); } } diff --git a/Source/Flow/Private/FlowSubsystem.cpp b/Source/Flow/Private/FlowSubsystem.cpp index 65c49e9b..ad4d2c72 100644 --- a/Source/Flow/Private/FlowSubsystem.cpp +++ b/Source/Flow/Private/FlowSubsystem.cpp @@ -123,7 +123,7 @@ UFlowAsset* UFlowSubsystem::CreateRootFlow(UObject* Owner, UFlowAsset* FlowAsset return NewFlow; } -void UFlowSubsystem::FinishRootFlow(UObject* Owner, UFlowAsset* TemplateAsset, const EFlowFinishPolicy FinishPolicy) +void UFlowSubsystem::FinishAndDeinitializeRootFlow(UObject* Owner, UFlowAsset* TemplateAsset, const EFlowFinishPolicy FinishPolicy) { UFlowAsset* InstanceToFinish = nullptr; @@ -139,11 +139,11 @@ void UFlowSubsystem::FinishRootFlow(UObject* Owner, UFlowAsset* TemplateAsset, c if (InstanceToFinish) { RootInstances.Remove(InstanceToFinish); - InstanceToFinish->FinishFlow(FinishPolicy); + InstanceToFinish->FinishFlowAndDeinitializeInstance(FinishPolicy); } } -void UFlowSubsystem::FinishAllRootFlows(UObject* Owner, const EFlowFinishPolicy FinishPolicy) +void UFlowSubsystem::FinishAndDeinitializeAllRootFlows(UObject* Owner, const EFlowFinishPolicy FinishPolicy) { TArray InstancesToFinish; @@ -158,7 +158,7 @@ void UFlowSubsystem::FinishAllRootFlows(UObject* Owner, const EFlowFinishPolicy for (UFlowAsset* InstanceToFinish : InstancesToFinish) { RootInstances.Remove(InstanceToFinish); - InstanceToFinish->FinishFlow(FinishPolicy); + InstanceToFinish->FinishFlowAndDeinitializeInstance(FinishPolicy); } } @@ -182,7 +182,12 @@ 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; + if (!AssetInstance->NodeOwningThisAssetInstance.IsValid()) + { + AssetInstance->NodeOwningThisAssetInstance = SubGraphNode; + } + check(AssetInstance->NodeOwningThisAssetInstance == SubGraphNode); + SubGraphNode->GetFlowAsset()->ActiveSubGraphs.Add(SubGraphNode, AssetInstance); // don't activate Start Node if we're loading Sub Graph from SaveGame @@ -195,6 +200,23 @@ UFlowAsset* UFlowSubsystem::CreateSubFlow(UFlowNode_SubGraph* SubGraphNode, cons return NewInstance; } +void UFlowSubsystem::FinishSubFlow(UFlowNode_SubGraph* SubGraphNode, const EFlowFinishPolicy FinishPolicy) +{ + if (InstancedSubFlows.Contains(SubGraphNode)) + { + // The flow asset running on the subgraph node. + UFlowAsset* SubgraphFlowAsset = InstancedSubFlows[SubGraphNode]; + + // This is the flow asset that has the subgraph node. Do not confuse with the flow asset that the node is running. + // Remove the subgraph flow from the owning flow active subgraph list. + UFlowAsset* SubgraphNodeParentFlow = SubGraphNode->GetFlowAsset(); + SubgraphNodeParentFlow->ActiveSubGraphs.Remove(SubGraphNode); + + // Finish the flow but do not remove the instance. + SubgraphFlowAsset->FinishFlow(FinishPolicy); + } +} + void UFlowSubsystem::RemoveSubFlow(UFlowNode_SubGraph* SubGraphNode, const EFlowFinishPolicy FinishPolicy) { if (InstancedSubFlows.Contains(SubGraphNode)) @@ -204,7 +226,12 @@ void UFlowSubsystem::RemoveSubFlow(UFlowNode_SubGraph* SubGraphNode, const EFlow SubGraphNode->GetFlowAsset()->ActiveSubGraphs.Remove(SubGraphNode); InstancedSubFlows.Remove(SubGraphNode); - AssetInstance->FinishFlow(FinishPolicy); + if (AssetInstance->IsActive()) + { + AssetInstance->FinishFlow(FinishPolicy); + } + + AssetInstance->DeinitializeInstance(); // Make sure to set the NodeOwningThisAssetInstance after the FinishFlow call, as it may be needed in the FinishFlow method AssetInstance->NodeOwningThisAssetInstance = nullptr; diff --git a/Source/Flow/Private/Nodes/Graph/FlowNode_SubGraph.cpp b/Source/Flow/Private/Nodes/Graph/FlowNode_SubGraph.cpp index 3c07698f..0ad873f2 100644 --- a/Source/Flow/Private/Nodes/Graph/FlowNode_SubGraph.cpp +++ b/Source/Flow/Private/Nodes/Graph/FlowNode_SubGraph.cpp @@ -97,14 +97,26 @@ void UFlowNode_SubGraph::ExecuteInput(const FName& PinName) void UFlowNode_SubGraph::Cleanup() { - if (CanBeAssetInstanced() && GetFlowSubsystem()) + UFlowSubsystem* FlowSubsystem = GetFlowSubsystem(); + if (CanBeAssetInstanced() && FlowSubsystem) { - GetFlowSubsystem()->RemoveSubFlow(this, EFlowFinishPolicy::Keep); + FlowSubsystem->FinishSubFlow(this, EFlowFinishPolicy::Keep); } Super::Cleanup(); } +void UFlowNode_SubGraph::DeinitializeInstance() +{ + UFlowSubsystem* FlowSubsystem = GetFlowSubsystem(); + if (CanBeAssetInstanced() && FlowSubsystem) + { + FlowSubsystem->RemoveSubFlow(this, EFlowFinishPolicy::Keep); + } + + Super::DeinitializeInstance(); +} + void UFlowNode_SubGraph::ForceFinishNode() { TriggerFirstOutput(true); diff --git a/Source/Flow/Public/FlowAsset.h b/Source/Flow/Public/FlowAsset.h index fa1048b0..6bc0cf41 100644 --- a/Source/Flow/Public/FlowAsset.h +++ b/Source/Flow/Public/FlowAsset.h @@ -362,6 +362,8 @@ class FLOW_API UFlowAsset : public UObject virtual void DeinitializeInstance(); bool IsInstanceInitialized() const { return IsValid(TemplateAsset); } + void FinishFlowAndDeinitializeInstance(const EFlowFinishPolicy InFinishPolicy); + UFlowAsset* GetTemplateAsset() const { return TemplateAsset; } /* Object that spawned Root Flow instance, i.e. World Settings or Player Controller. @@ -381,6 +383,8 @@ class FLOW_API UFlowAsset : public UObject virtual void PreStartFlow(); virtual void StartFlow(IFlowDataPinValueSupplierInterface* DataPinValueSupplier = nullptr); + virtual void FinishFlow(const EFlowFinishPolicy InFinishPolicy); + bool HasStartedFlow() const; protected: diff --git a/Source/Flow/Public/FlowSubsystem.h b/Source/Flow/Public/FlowSubsystem.h index ea68d892..5cf33058 100644 --- a/Source/Flow/Public/FlowSubsystem.h +++ b/Source/Flow/Public/FlowSubsystem.h @@ -78,16 +78,21 @@ class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem * 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 FinishRootFlow(UObject* Owner, UFlowAsset* TemplateAsset, const EFlowFinishPolicy FinishPolicy); + virtual void FinishAndDeinitializeRootFlow(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); + virtual void FinishAndDeinitializeAllRootFlows(UObject* Owner, const EFlowFinishPolicy FinishPolicy); protected: UFlowAsset* CreateSubFlow(UFlowNode_SubGraph* SubGraphNode, const FString& SavedInstanceName = FString(), const bool bPreloading = false); + + /* Finishes the SubFlow running in the SubGraphNode. It does not deinitialize or removes from the internal InstancedSubFlows list */ + void FinishSubFlow(UFlowNode_SubGraph* SubGraphNode, const EFlowFinishPolicy FinishPolicy); + + /* Removes the Subflow from the InstancedSubFlows list; and Finishes and Deinitializes it. */ void RemoveSubFlow(UFlowNode_SubGraph* SubGraphNode, const EFlowFinishPolicy FinishPolicy); public: diff --git a/Source/Flow/Public/Nodes/Graph/FlowNode_SubGraph.h b/Source/Flow/Public/Nodes/Graph/FlowNode_SubGraph.h index 5d7dfaf6..547c8fdc 100644 --- a/Source/Flow/Public/Nodes/Graph/FlowNode_SubGraph.h +++ b/Source/Flow/Public/Nodes/Graph/FlowNode_SubGraph.h @@ -18,7 +18,7 @@ class FLOW_API UFlowNode_SubGraph GENERATED_BODY() public: - UFlowNode_SubGraph(); + UFlowNode_SubGraph(); friend class UFlowAsset; friend class FFlowNode_SubGraphDetails; @@ -53,6 +53,7 @@ class FLOW_API UFlowNode_SubGraph virtual void ExecuteInput(const FName& PinName) override; virtual void Cleanup() override; + virtual void DeinitializeInstance() override; public: virtual void ForceFinishNode() override;