Skip to content
Closed
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
2 changes: 2 additions & 0 deletions Config/BaseFlow.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")
+PropertyRedirects=(OldName="FlowAsset.CustomEvents",NewName="FlowAsset.CustomInputs")
+PropertyRedirects=(OldName="FlowGraphNode.FlowNode",NewName="FlowGraphNode.NodeInstance")
+StructRedirects=(OldName="/Script/Flow.FlowNamedDataPinOutputProperty",NewName="/Script/Flow.FlowNamedDataPinProperty")
+PropertyRedirects=(OldName="FlowNode_DefineProperties.OutputProperties",NewName="NamedProperties")
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")
+PropertyRedirects=(OldName="FlowAsset.CustomEvents",NewName="FlowAsset.CustomInputs")
+PropertyRedirects=(OldName="FlowGraphNode.FlowNode",NewName="FlowGraphNode.NodeInstance")
+StructRedirects=(OldName="/Script/Flow.FlowNamedDataPinOutputProperty",NewName="/Script/Flow.FlowNamedDataPinProperty")
+PropertyRedirects=(OldName="FlowNode_DefineProperties.OutputProperties",NewName="NamedProperties")
50 changes: 38 additions & 12 deletions Source/Flow/Private/AddOns/FlowNodeAddOn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include "AddOns/FlowNodeAddOn.h"

#include "FlowLogChannels.h"
#include "Engine/World.h"

#include "Nodes/FlowNode.h"

#include "Misc/RuntimeErrors.h"
Expand Down Expand Up @@ -72,6 +74,35 @@ UFlowNode* UFlowNodeAddOn::GetFlowNode() const
return FlowNode;
}

UFlowNode* UFlowNodeAddOn::FindOwningFlowNode() const
{
UObject* OuterObject = GetOuter();
UFlowNode* ParentFlowNode = nullptr;

while (IsValid(OuterObject))
{
ParentFlowNode = Cast<UFlowNode>(OuterObject);
if (ParentFlowNode)
{
break;
}

OuterObject = OuterObject->GetOuter();
}

return ParentFlowNode;
}

int32 UFlowNodeAddOn::GetRandomSeed() const
{
if (ensure(FlowNode))
{
return FlowNode->GetRandomSeed();
}

return 0;
}

bool UFlowNodeAddOn::IsSupportedInputPinName(const FName& PinName) const
{
if (InputPins.IsEmpty())
Expand All @@ -91,18 +122,8 @@ bool UFlowNodeAddOn::IsSupportedInputPinName(const FName& PinName) const

void UFlowNodeAddOn::CacheFlowNode()
{
UObject* OuterObject = GetOuter();
while (IsValid(OuterObject))
{
FlowNode = Cast<UFlowNode>(OuterObject);
if (FlowNode)
{
break;
}

OuterObject = OuterObject->GetOuter();
}

FlowNode = FindOwningFlowNode();

ensureAsRuntimeWarning(FlowNode);
}

Expand Down Expand Up @@ -137,4 +158,9 @@ TArray<FFlowPin> UFlowNodeAddOn::GetContextOutputs() const
{
return GetPinsForContext(OutputPins);
}

void UFlowNodeAddOn::RequestReconstructionOnOwningFlowNode() const
{
(void) OnAddOnRequestedParentReconstruction.ExecuteIfBound();
}
#endif // WITH_EDITOR
70 changes: 64 additions & 6 deletions Source/Flow/Private/FlowAsset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#if WITH_EDITOR
#include "Editor.h"
#include "Editor/EditorEngine.h"
#include "Misc/DataValidation.h"

FString UFlowAsset::ValidationError_NodeClassNotAllowed = TEXT("Node class {0} is not allowed in this asset.");
FString UFlowAsset::ValidationError_NullNodeInstance = TEXT("Node with GUID {0} is NULL");
Expand Down Expand Up @@ -105,6 +106,9 @@ void UFlowAsset::PostLoad()

EDataValidationResult UFlowAsset::ValidateAsset(FFlowMessageLog& MessageLog)
{
// TODO (gtaylor) We should further refactor the Flow validation to use FDataValidationContext throughout
FDataValidationContext Context;

// validate nodes
for (const TPair<FGuid, UFlowNode*>& Node : ObjectPtrDecay(Nodes))
{
Expand All @@ -122,9 +126,43 @@ EDataValidationResult UFlowAsset::ValidateAsset(FFlowMessageLog& MessageLog)
}

Node.Value->ValidationLog.Messages.Empty();
if (Node.Value->ValidateNode() == EDataValidationResult::Invalid)

if (Node.Value->ValidateNodeAndAddOns(Context) == EDataValidationResult::Invalid)
{
MessageLog.Messages.Append(Node.Value->ValidationLog.Messages);
// Convert the issues from UE format into Flow's expected format
for (const FDataValidationContext::FIssue& Issue : Context.GetIssues())
{
switch (Issue.Severity)
{
case EMessageSeverity::Error:
{
MessageLog.Error(*Issue.Message.ToString(), Node.Value);
}
break;

case EMessageSeverity::PerformanceWarning:
case EMessageSeverity::Warning:
{
MessageLog.Warning(*Issue.Message.ToString(), Node.Value);
}
break;

case EMessageSeverity::Info:
{
MessageLog.Note(*Issue.Message.ToString(), Node.Value);
}
break;

default:
{
const FString UnhandledSeverityString = FString::Printf(TEXT("Unhandled EMessageSeverity value %d! The code needs to be updated."), Issue.Severity);
MessageLog.Error(*UnhandledSeverityString, Node.Value);

MessageLog.Error(*Issue.Message.ToString(), Node.Value);
}
break;
}
}
}
}
else
Expand Down Expand Up @@ -224,7 +262,7 @@ bool UFlowAsset::CanFlowAssetUseFlowNodeClass(const UClass& FlowNodeClass) const

bool UFlowAsset::IsFlowNodeClassInDeniedClasses(const UClass& FlowNodeClass) const
{
for (const TSubclassOf<UFlowNodeBase>& DeniedNodeClass : DeniedNodeClasses)
for (const TSubclassOf<UFlowNodeBase> DeniedNodeClass : DeniedNodeClasses)
{
if (DeniedNodeClass && FlowNodeClass.IsChildOf(DeniedNodeClass))
{
Expand All @@ -239,13 +277,12 @@ bool UFlowAsset::IsFlowNodeClassInDeniedClasses(const UClass& FlowNodeClass) con
return false;
}

bool UFlowAsset::IsFlowNodeClassInAllowedClasses(const UClass& FlowNodeClass,
const TSubclassOf<UFlowNodeBase>& RequiredAncestor) const
bool UFlowAsset::IsFlowNodeClassInAllowedClasses(const UClass& FlowNodeClass, const TSubclassOf<UFlowNodeBase> RequiredAncestor) const
{
if (AllowedNodeClasses.Num() > 0)
{
bool bAllowedInAsset = false;
for (const TSubclassOf<UFlowNodeBase>& AllowedNodeClass : AllowedNodeClasses)
for (const TSubclassOf<UFlowNodeBase> AllowedNodeClass : AllowedNodeClasses)
{
// If a RequiredAncestor is provided, the AllowedNodeClass must be a subclass of the RequiredAncestor
if (AllowedNodeClass && FlowNodeClass.IsChildOf(AllowedNodeClass) && (!RequiredAncestor || AllowedNodeClass->IsChildOf(RequiredAncestor)))
Expand Down Expand Up @@ -1030,6 +1067,27 @@ TArray<UFlowNode*> UFlowAsset::GetNodesInExecutionOrder(UFlowNode* FirstIterated
return FoundNodes;
}

TArray<UFlowNode*> UFlowAsset::GatherNodesConnectedToAllInputs() const
{
TSet<TObjectKey<UFlowNode>> IteratedNodes;
TArray<UFlowNode*> ConnectedNodes;

// Nodes connected to the Start node
UFlowNode* DefaultEntryNode = GetDefaultEntryNode();
GetNodesInExecutionOrder_Recursive(DefaultEntryNode, IteratedNodes, ConnectedNodes);

// Nodes connected to Custom Input node(s)
for (const TPair<FGuid, UFlowNode*>& Node : ObjectPtrDecay(Nodes))
{
if (UFlowNode_CustomInput* CustomInput = Cast<UFlowNode_CustomInput>(Node.Value))
{
GetNodesInExecutionOrder_Recursive(CustomInput, IteratedNodes, ConnectedNodes);
}
}

return ConnectedNodes;
}

void UFlowAsset::AddInstance(UFlowAsset* Instance)
{
ActiveInstances.Add(Instance);
Expand Down
Loading