Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
76 changes: 73 additions & 3 deletions Source/Flow/Private/FlowAsset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@
#include "Asset/FlowAssetParams.h"
#include "Asset/FlowAssetParamsUtils.h"
#include "Interfaces/FlowExecutionGate.h"
#include "Interfaces/FlowGraphOutputDataReceiverInterface.h"
#include "Types/FlowNamedDataPinProperty.h"
#include "Nodes/FlowNodeBase.h"
#include "Nodes/Graph/FlowNode_CustomInput.h"
#include "Nodes/Graph/FlowNode_CustomOutput.h"
#include "Nodes/Graph/FlowNode_Start.h"
#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 All @@ -25,6 +28,7 @@
#include "Algo/AnyOf.h"

#if WITH_EDITOR
#include "Nodes/Graph/FlowNode_SetGraphOutput.h"
#include "AssetRegistry/AssetRegistryModule.h"
#include "AssetToolsModule.h"
#include "ContentBrowserModule.h"
Expand Down Expand Up @@ -77,11 +81,26 @@ void UFlowAsset::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEv
{
Super::PostEditChangeProperty(PropertyChangedEvent);

if (PropertyChangedEvent.Property && (PropertyChangedEvent.GetPropertyName() == GET_MEMBER_NAME_CHECKED(UFlowAsset, CustomInputs)
|| PropertyChangedEvent.GetPropertyName() == GET_MEMBER_NAME_CHECKED(UFlowAsset, CustomOutputs)))
const FName ChangedPropertyName = PropertyChangedEvent.GetPropertyName();
const FName ChangedMemberPropertyName = PropertyChangedEvent.GetMemberPropertyName();
if (PropertyChangedEvent.Property && (ChangedPropertyName == GET_MEMBER_NAME_CHECKED(UFlowAsset, CustomInputs)
|| ChangedPropertyName == GET_MEMBER_NAME_CHECKED(UFlowAsset, CustomOutputs)
|| ChangedMemberPropertyName == GET_MEMBER_NAME_CHECKED(UFlowAsset, OutputDataPinDeclarations)))
{
OnSubGraphReconstructionRequested.ExecuteIfBound();
}

if (PropertyChangedEvent.Property && ChangedMemberPropertyName == GET_MEMBER_NAME_CHECKED(UFlowAsset, OutputDataPinDeclarations))
{
for (const TPair<FGuid, UFlowNode*>& NodePair : GetNodes())
{
UFlowNode_SetGraphOutput* SetOutputNode = Cast<UFlowNode_SetGraphOutput>(NodePair.Value);
if (IsValid(SetOutputNode) && SetOutputNode->TryUpdateAutoDataPins())
{
SetOutputNode->OnReconstructionRequested.ExecuteIfBound();
}
}
}
}

void UFlowAsset::PostDuplicate(bool bDuplicateForPIE)
Expand Down Expand Up @@ -1043,8 +1062,10 @@ void UFlowAsset::PreStartFlow()
#endif
}

void UFlowAsset::StartFlow(IFlowDataPinValueSupplierInterface* DataPinValueSupplier)
void UFlowAsset::StartFlow(IFlowDataPinValueSupplierInterface* DataPinValueSupplier, IFlowGraphOutputDataReceiverInterface* InOutputDataReceiver)
{
InitializeOutputDataReceiverAndValues(InOutputDataReceiver);

PreStartFlow();

if (UFlowNode* ConnectedEntryNode = GetDefaultEntryNode())
Expand Down Expand Up @@ -1074,6 +1095,11 @@ void UFlowAsset::FinishNode(UFlowNode* Node)
// if graph reached Finish and this asset instance was created by SubGraph node
if (Node->CanFinishGraph())
{
if (IFlowGraphOutputDataReceiverInterface* Receiver = Cast<IFlowGraphOutputDataReceiverInterface>(OutputDataReceiver.Get()))
{
Receiver->ReceiveOutputDataSnapshot(OutputDataPinValues);
}

if (NodeOwningThisAssetInstance.IsValid())
{
NodeOwningThisAssetInstance.Get()->TriggerFirstOutput(true);
Expand Down Expand Up @@ -1174,6 +1200,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
15 changes: 12 additions & 3 deletions Source/Flow/Private/FlowSubsystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,11 @@ void UFlowSubsystem::StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const
{
if (UFlowAsset* NewFlow = CreateRootFlow(Owner, FlowAsset, bAllowMultipleInstances))
{
NewFlow->StartFlow(DataPinValueSupplier.GetInterface());
// TODO (gtaylor) Not implementing output parameters "yet",
// see Subgraph node for the pioneer implementation.
constexpr IFlowGraphOutputDataReceiverInterface* OutputDataReceiverInterface = nullptr;

NewFlow->StartFlow(DataPinValueSupplier.GetInterface(), OutputDataReceiverInterface);
}
}
#if WITH_EDITOR
Expand Down Expand Up @@ -182,13 +186,18 @@ 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
if (SavedInstanceName.IsEmpty())
{
AssetInstance->StartFlow(SubGraphNode);
AssetInstance->StartFlow(SubGraphNode, SubGraphNode);
}
}

Expand Down
10 changes: 4 additions & 6 deletions Source/Flow/Private/Nodes/Graph/FlowNode_Finish.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,19 @@

#include "Nodes/Graph/FlowNode_Finish.h"

#include "FlowAsset.h"

#include UE_INLINE_GENERATED_CPP_BY_NAME(FlowNode_Finish)

UFlowNode_Finish::UFlowNode_Finish()
{
#if WITH_EDITOR
Category = TEXT("Graph");
NodeDisplayStyle = FlowNodeStyle::InOut;
#endif

OutputPins = {};
AllowedSignalModes = {EFlowSignalMode::Enabled, EFlowSignalMode::Disabled};
}

void UFlowNode_Finish::ExecuteInput(const FName& PinName)
{
CommitOutputDataPinValues();

// this will call FinishFlow()
Finish();
}
113 changes: 113 additions & 0 deletions Source/Flow/Private/Nodes/Graph/FlowNode_SetGraphOutput.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors

#include "Nodes/Graph/FlowNode_SetGraphOutput.h"

#include "FlowAsset.h"
#include "Types/FlowDataPinResults.h"
#include "Types/FlowNamedDataPinProperty.h"

#if WITH_EDITOR
#include "Types/FlowAutoDataPinsWorkingData.h"
#endif

#include UE_INLINE_GENERATED_CPP_BY_NAME(FlowNode_SetGraphOutput)

UFlowNode_SetGraphOutput::UFlowNode_SetGraphOutput()
{
#if WITH_EDITOR
Category = TEXT("Graph");
NodeDisplayStyle = FlowNodeStyle::InOut;
#endif

AllowedSignalModes = {EFlowSignalMode::Enabled, EFlowSignalMode::Disabled};
}

void UFlowNode_SetGraphOutput::ExecuteInput(const FName& PinName)
{
CommitOutputDataPinValues();

TriggerFirstOutput(true);
}

void UFlowNode_SetGraphOutput::CommitOutputDataPinValues()
{
UFlowAsset* FlowAsset = GetFlowAsset();
if (!IsValid(FlowAsset))
{
return;
}

const UFlowAsset* TemplateAsset = FlowAsset->GetTemplateAsset();
if (!IsValid(TemplateAsset))
{
return;
}

bool bNeedsFlush = false;

for (const FFlowNamedDataPinProperty& Declaration : TemplateAsset->GetOutputDataPinDeclarations())
{
if (!Declaration.IsValid())
{
continue;
}

if (!IsInputConnected(Declaration.Name))
{
continue;
}

const FFlowDataPinResult PinResult = TryResolveDataPin_SetGraphOutputAccess(Declaration.Name);
if (PinResult.Result == EFlowDataPinResolveResult::Success)
{
bNeedsFlush = true;

FlowAsset->WriteOutputDataPinValue(Declaration.Name, PinResult.ResultValue);
}
}

if (bNeedsFlush)
{
FlowAsset->FlushOutputDataPinValuesToReceiver();
}
}

#if WITH_EDITOR
bool UFlowNode_SetGraphOutput::SupportsContextPins() const
{
const UFlowAsset* FlowAsset = GetFlowAsset();
if (IsValid(FlowAsset) && !FlowAsset->GetOutputDataPinDeclarations().IsEmpty())
{
return true;
}

return Super::SupportsContextPins();
}

void UFlowNode_SetGraphOutput::AutoGenerateDataPins(FFlowDataPinValueOwner& ValueOwner, FFlowAutoDataPinsWorkingData& InOutWorkingData)
{
Super::AutoGenerateDataPins(ValueOwner, InOutWorkingData);

const UFlowAsset* FlowAsset = GetFlowAsset();
if (!IsValid(FlowAsset))
{
return;
}

for (FFlowNamedDataPinProperty DeclarationCopy : FlowAsset->GetOutputDataPinDeclarations())
{
if (!DeclarationCopy.IsValid())
{
continue;
}

if (DeclarationCopy.DataPinValue.IsValid())
{
FFlowDataPinValue& Value = DeclarationCopy.DataPinValue.GetMutable<FFlowDataPinValue>();
Value.bIsInputPin = true;
}

DeclarationCopy.AutoGenerateDataPinForProperty(ValueOwner, InOutWorkingData);
}
}
#endif
34 changes: 34 additions & 0 deletions Source/Flow/Private/Nodes/Graph/FlowNode_SubGraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,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 Expand Up @@ -236,6 +241,22 @@ void UFlowNode_SubGraph::AutoGenerateDataPins(FFlowDataPinValueOwner& ValueOwner
}
}
}

for (FFlowNamedDataPinProperty Declaration : Asset->GetOutputDataPinDeclarations())
{
if (!Declaration.IsValid())
{
continue;
}

if (Declaration.DataPinValue.IsValid())
{
FFlowDataPinValue& Value = Declaration.DataPinValue.GetMutable<FFlowDataPinValue>();
Value.bIsInputPin = false;
}

Declaration.AutoGenerateDataPinForProperty(ValueOwner, InOutWorkingData);
}
}

FFlowDataPinResult UFlowNode_SubGraph::TrySupplyDataPin(FName PinName) const
Expand All @@ -248,6 +269,19 @@ FFlowDataPinResult UFlowNode_SubGraph::TrySupplyDataPin(FName PinName) const
return Super::TrySupplyDataPin(PinName);
}

// Check cached output data pin values first — output pins are never "input connected",
// so this must come before IsInputConnected to avoid a spurious "unknown input pin" error.
if (const TInstancedStruct<FFlowDataPinValue>* CachedValue = CachedOutputDataPinValues.Values.Find(PinName))
{
if (CachedValue->IsValid())
{
FFlowDataPinResult Result;
Result.Result = EFlowDataPinResolveResult::Success;
Result.ResultValue = *CachedValue;
return Result;
}
}

if (!IsInputConnected(PinName))
{
const bool bHasAssetParams = IsInputConnected(AssetParams_MemberName) || !AssetParams.IsNull();
Expand Down
5 changes: 5 additions & 0 deletions Source/Flow/Private/Policies/FlowPreloadPolicy.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors

#include "Policies/FlowPreloadPolicy.h"

#include UE_INLINE_GENERATED_CPP_BY_NAME(FlowPreloadPolicy)
Loading