Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Config/DefaultFlow.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@
+ClassRedirects=(OldName="/Script/Flow.FlowNode_CustomEvent",NewName="/Script/Flow.FlowNode_CustomInput")
+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")
67 changes: 57 additions & 10 deletions Source/Flow/Private/FlowAsset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "Nodes/Graph/FlowNode_SubGraph.h"
#include "Policies/FlowPinConnectionPolicy.h"
#include "Policies/FlowPreloadPolicy.h"
#include "Types/FlowAutoDataPinsWorkingData.h"
#include "Types/FlowDataPinValue.h"
#include "Types/FlowStructUtils.h"

Expand Down Expand Up @@ -914,7 +915,7 @@ void UFlowAsset::ClearInstances()
{
if (ActiveInstances.IsValidIndex(i) && ActiveInstances[i])
{
ActiveInstances[i]->FinishFlow(EFlowFinishPolicy::Keep);
ActiveInstances[i]->FinishFlowAndDeinitializeInstance(EFlowFinishPolicy::Keep);
}
}

Expand Down Expand Up @@ -1046,6 +1047,12 @@ AActor* UFlowAsset::TryFindActorOwner() const
return nullptr;
}

void UFlowAsset::FinishFlowAndDeinitializeInstance(const EFlowFinishPolicy InFinishPolicy)
{
FinishFlow(InFinishPolicy);
DeinitializeInstance();
}

void UFlowAsset::PreStartFlow()
{
ResetNodes();
Expand Down Expand Up @@ -1155,13 +1162,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<UFlowAsset*>& RootFlowInstances = GetFlowSubsystem()->GetRootInstancesByOwner(Owner.Get());
if (RootFlowInstances.Contains(this))
{
GetFlowSubsystem()->FinishRootFlow(Owner.Get(), TemplateAsset, EFlowFinishPolicy::Keep);
GetFlowSubsystem()->FinishAndDeinitializeRootFlow(Owner.Get(), TemplateAsset, EFlowFinishPolicy::Keep);

return;
}
Expand All @@ -1182,7 +1190,7 @@ void UFlowAsset::ResetNodes()
RecordedNodes.Empty();
}

void UFlowAsset::FinishFlow(const EFlowFinishPolicy InFinishPolicy, const bool bRemoveInstance /*= true*/)
void UFlowAsset::FinishFlow(const EFlowFinishPolicy InFinishPolicy)
{
FinishPolicy = InFinishPolicy;

Expand All @@ -1193,13 +1201,8 @@ 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();
}
ActiveNodes.Empty();
}

UFlowSubsystem* UFlowAsset::GetFlowSubsystem() const
Expand Down Expand Up @@ -1248,6 +1251,50 @@ const FFlowPreloadPolicy& UFlowAsset::GetPreloadPolicy() const
return PreloadPolicy.Get();
}

void UFlowAsset::InitializeOutputDataReceiverAndValues(IFlowGraphOutputDataReceiverInterface* InOutputDataReceiver)
{
OutputDataReceiver = Cast<UObject>(InOutputDataReceiver);

// Initialize the live output store from the template asset's declarations
OutputDataPinValues.Values.Reset();

if (const UFlowAsset* Template = TemplateAsset.Get())
{
for (const FFlowNamedDataPinProperty& Declaration : Template->OutputDataPinDeclarations)
{
if (Declaration.IsValid())
{
OutputDataPinValues.Values.Add(Declaration.Name, Declaration.DataPinValue);
}
else
{
UE_LOG(LogFlow, Warning, TEXT("Invalid OutputDataPin %s"), *Declaration.Name.ToString());
}
}
}
}

void UFlowAsset::WriteOutputDataPinValue(const FName& PinName, const TInstancedStruct<FFlowDataPinValue>& Value)
{
if (OutputDataPinValues.Values.Contains(PinName))
{
OutputDataPinValues.Values[PinName] = Value;
}
else
{
UE_LOG(LogFlow, Warning, TEXT("Could not find pin named %s in WriteOutputDataPinValue"), *PinName.ToString());
}
}

void UFlowAsset::FlushOutputDataPinValuesToReceiver()
{
if (IFlowGraphOutputDataReceiverInterface* Receiver = Cast<IFlowGraphOutputDataReceiverInterface>(OutputDataReceiver.Get()))
{
// Do an immediate push to the receiver
Receiver->ReceiveOutputDataSnapshot(OutputDataPinValues);
}
}

void UFlowAsset::TriggerCustomInput(const FName& EventName, IFlowDataPinValueSupplierInterface* DataPinValueSupplier)
{
for (UFlowNode_CustomInput* CustomInputNode : CustomInputNodes)
Expand Down
4 changes: 2 additions & 2 deletions Source/Flow/Private/FlowComponent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ void UFlowComponent::UnregisterWithFlowSubsystem()
{
if (UFlowSubsystem* FlowSubsystem = GetFlowSubsystem())
{
FlowSubsystem->FinishAllRootFlows(this, EFlowFinishPolicy::Keep);
FlowSubsystem->FinishAndDeinitializeAllRootFlows(this, EFlowFinishPolicy::Keep);
FlowSubsystem->UnregisterComponent(this);
}
}
Expand Down Expand Up @@ -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);
}
}

Expand Down
32 changes: 27 additions & 5 deletions Source/Flow/Private/FlowSubsystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,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;

Expand All @@ -143,11 +143,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<UFlowAsset*> InstancesToFinish;

Expand All @@ -162,7 +162,7 @@ void UFlowSubsystem::FinishAllRootFlows(UObject* Owner, const EFlowFinishPolicy
for (UFlowAsset* InstanceToFinish : InstancesToFinish)
{
RootInstances.Remove(InstanceToFinish);
InstanceToFinish->FinishFlow(FinishPolicy);
InstanceToFinish->FinishFlowAndDeinitializeInstance(FinishPolicy);
}
}

Expand Down Expand Up @@ -205,6 +205,23 @@ UFlowAsset* UFlowSubsystem::CreateSubFlow(UFlowNode_SubGraph* SubGraphNode, cons
return AssetInstance;
}

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))
Expand All @@ -214,7 +231,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;
Expand Down
21 changes: 19 additions & 2 deletions Source/Flow/Private/Nodes/Graph/FlowNode_SubGraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,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);
Expand Down Expand Up @@ -178,6 +190,11 @@ void UFlowNode_SubGraph::OnLoad_Implementation()
}
}

void UFlowNode_SubGraph::ReceiveOutputDataSnapshot(const FFlowOutputDataPinValues& Snapshot)
{
CachedOutputDataPinValues = Snapshot;
}

#if WITH_EDITOR

FText UFlowNode_SubGraph::K2_GetNodeTitle_Implementation() const
Expand Down
13 changes: 13 additions & 0 deletions Source/Flow/Public/FlowAsset.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,15 @@ class FLOW_API UFlowAsset : public UObject
UPROPERTY()
TMap<FGuid, TObjectPtr<UFlowNode>> Nodes;

public:
const TArray<FFlowNamedDataPinProperty>& GetOutputDataPinDeclarations() const { return OutputDataPinDeclarations; }

protected:
/* Output Data Pins define typed data values that this graph produces when it finishes.
* Sub Graph node using this Flow Asset will generate a context Output Data Pin for every entry on this list. */
UPROPERTY(EditAnywhere, Category = "Sub Graph")
TArray<FFlowNamedDataPinProperty> OutputDataPinDeclarations;

public:
#if WITH_EDITOR
FFlowGraphEvent OnSubGraphReconstructionRequested;
Expand Down Expand Up @@ -388,6 +397,8 @@ class FLOW_API UFlowAsset : public UObject

virtual FName GetInstanceName() const;

void FinishFlowAndDeinitializeInstance(const EFlowFinishPolicy InFinishPolicy);

UFlowAsset* GetTemplateAsset() const { return TemplateAsset; }

/* Object that spawned Root Flow instance, i.e. World Settings or Player Controller.
Expand Down Expand Up @@ -425,6 +436,8 @@ class FLOW_API UFlowAsset : public UObject
virtual void FinishNode(UFlowNode* Node);
void ResetNodes();

void InitializeOutputDataReceiverAndValues(IFlowGraphOutputDataReceiverInterface* InOutputDataReceiver);

public:
virtual void FinishFlow(const EFlowFinishPolicy InFinishPolicy, const bool bRemoveInstance = true);

Expand Down
9 changes: 7 additions & 2 deletions Source/Flow/Public/FlowSubsystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
5 changes: 5 additions & 0 deletions Source/Flow/Public/Nodes/Graph/FlowNode_SubGraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ class FLOW_API UFlowNode_SubGraph
FFlowOutputDataPinValues CachedOutputDataPinValues;

protected:
// IFlowGraphOutputDataReceiverInterface
virtual void ReceiveOutputDataSnapshot(const FFlowOutputDataPinValues& Snapshot) override;
// --

virtual bool CanBeAssetInstanced() const;

public:
Expand All @@ -63,6 +67,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;
Expand Down