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
116 changes: 89 additions & 27 deletions Source/Flow/Private/FlowAsset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "FlowLogChannels.h"
#include "FlowSettings.h"
#include "FlowSubsystem.h"
#include "FlowUserSettings.h"

#include "AddOns/FlowNodeAddOn.h"
#include "Interfaces/FlowDataPinGeneratorNodeInterface.h"
Expand All @@ -17,6 +18,7 @@
#include "Engine/World.h"
#include "Serialization/MemoryReader.h"
#include "Serialization/MemoryWriter.h"
#include "Algo/AnyOf.h"

#if WITH_EDITOR
#include "Editor.h"
Expand Down Expand Up @@ -1061,7 +1063,16 @@ int32 UFlowAsset::RemoveInstance(UFlowAsset* Instance)
#if WITH_EDITOR
if (InspectedInstance.IsValid() && InspectedInstance.Get() == Instance)
{
SetInspectedInstance(NAME_None);
if (UFlowUserSettings::Get()->bKeepLastInspectedInstance)
{
FString LastPath = LastInspectedInstanceName;
SetInspectedInstance(nullptr, false);
LastInspectedInstanceName = LastPath;
}
else
{
SetInspectedInstance(nullptr);
}
}
#endif

Expand All @@ -1074,7 +1085,16 @@ void UFlowAsset::ClearInstances()
#if WITH_EDITOR
if (InspectedInstance.IsValid())
{
SetInspectedInstance(NAME_None);
if (UFlowUserSettings::Get()->bKeepLastInspectedInstance)
{
FString LastPath = LastInspectedInstanceName;
SetInspectedInstance(nullptr, false);
LastInspectedInstanceName = LastPath;
}
else
{
SetInspectedInstance(nullptr);
}
}
#endif

Expand All @@ -1090,36 +1110,78 @@ void UFlowAsset::ClearInstances()
}

#if WITH_EDITOR
void UFlowAsset::GetInstanceDisplayNames(TArray<TSharedPtr<FName>>& OutDisplayNames) const
FString UFlowAsset::GetDebugName() const
{
for (const UFlowAsset* Instance : ActiveInstances)
auto GetNumLocalWorlds = []()
{
OutDisplayNames.Emplace(MakeShareable(new FName(Instance->GetDisplayName())));
int32 LocalWorldCount = 0;
for (const FWorldContext& Context : GEngine->GetWorldContexts())
{
if (Context.WorldType == EWorldType::PIE && Context.World() != nullptr)
{
++LocalWorldCount;
}
}
return LocalWorldCount;
};

FString Name = GetDisplayName().ToString();

if (GetNumLocalWorlds() > 1 || GetWorld()->GetNetMode() == NM_ListenServer)
{
FString Context = GetDebugStringForWorld(GetWorld());
if (!Context.IsEmpty())
{
Name = FString::Printf(TEXT("%s (%s)"), *Name, *Context);
}

return Name;
}

return Name;
}

void UFlowAsset::SetInspectedInstance(const FName& NewInspectedInstanceName)
void UFlowAsset::SetInspectedInstance(TWeakObjectPtr<const UFlowAsset> NewInspectedInstance, bool bRefreshDebugger)
{
if (NewInspectedInstanceName.IsNone())
if (NewInspectedInstance.IsValid())
{
if (InspectedInstance == NewInspectedInstance)
{
// Nothing changed
return;
}

bool bIsNewInstancePresent = Algo::AnyOf(ActiveInstances, [NewInspectedInstance](const UFlowAsset* ActiveInstance)
{
return ActiveInstance && ActiveInstance == NewInspectedInstance;
});

if (!ensureMsgf(bIsNewInstancePresent, TEXT("Trying to set %s as InspectedInstance, but it is not one of the ActiveInstances"), *NewInspectedInstance->GetName()))
{
NewInspectedInstance = nullptr;
}
}

InspectedInstance = NewInspectedInstance;

if (InspectedInstance.IsValid())
{
InspectedInstance = nullptr;
LastInspectedInstanceName = NewInspectedInstance->GetDebugName();
}
else
{
for (UFlowAsset* ActiveInstance : ActiveInstances)
{
if (ActiveInstance && ActiveInstance->GetDisplayName() == NewInspectedInstanceName)
{
if (!InspectedInstance.IsValid() || InspectedInstance != ActiveInstance)
{
InspectedInstance = ActiveInstance;
}
break;
}
}
LastInspectedInstanceName = FString();
}

BroadcastDebuggerRefresh();
if (bRefreshDebugger)
{
BroadcastDebuggerRefresh();
}
}

void UFlowAsset::SetWorldBeingDebugged(const TWeakObjectPtr<const UWorld> NewWorld)
{
CurrentWorldBeingDebugged = NewWorld;
}

void UFlowAsset::BroadcastDebuggerRefresh() const
Expand Down Expand Up @@ -1186,16 +1248,16 @@ void UFlowAsset::PreStartFlow()
#if WITH_EDITOR
check(IsInstanceInitialized());

if (TemplateAsset->ActiveInstances.Num() == 1)
bool bCanSetInstanceAsInspected = UFlowUserSettings::Get()->bSetFirstAssetInstanceAsInspected && TemplateAsset->ActiveInstances.Num() == 1;
bool bKeepLastInstance = UFlowUserSettings::Get()->bKeepLastInspectedInstance && TemplateAsset->GetLastInspectedInstanceName().IsEmpty();
if (bCanSetInstanceAsInspected && !bKeepLastInstance)
{
// this instance is the only active one, set it directly as Inspected Instance
TemplateAsset->SetInspectedInstance(GetDisplayName());
}
else
{
// request to refresh list to show newly created instance
TemplateAsset->BroadcastDebuggerRefresh();
TemplateAsset->SetInspectedInstance(this, false);
}

// request to refresh list to show newly created instance
TemplateAsset->BroadcastDebuggerRefresh();
#endif
}

Expand Down
10 changes: 10 additions & 0 deletions Source/Flow/Private/FlowUserSettings.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Fill out your copyright notice in the Description page of Project Settings.

#include "FlowUserSettings.h"

UFlowUserSettings::UFlowUserSettings(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
, bSetFirstAssetInstanceAsInspected(true)
, bKeepLastInspectedInstance(false)
{
}
4 changes: 2 additions & 2 deletions Source/Flow/Private/Nodes/FlowNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -809,7 +809,7 @@ void UFlowNode::TriggerInput(const FName& PinName, const EFlowPinActivationType

if (const UFlowAsset* FlowAssetTemplate = GetFlowAsset()->GetTemplateAsset())
{
(void)FlowAssetTemplate->OnPinTriggered.ExecuteIfBound(NodeGuid, PinName);
(void)FlowAssetTemplate->OnPinTriggered.ExecuteIfBound(GetFlowAsset(), NodeGuid, PinName);
}
#endif
}
Expand Down Expand Up @@ -875,7 +875,7 @@ void UFlowNode::TriggerOutput(const FName PinName, const bool bFinish /*= false*

if (const UFlowAsset* FlowAssetTemplate = GetFlowAsset()->GetTemplateAsset())
{
FlowAssetTemplate->OnPinTriggered.ExecuteIfBound(NodeGuid, PinName);
FlowAssetTemplate->OnPinTriggered.ExecuteIfBound(GetFlowAsset(), NodeGuid, PinName);
}
}
else
Expand Down
27 changes: 22 additions & 5 deletions Source/Flow/Public/FlowAsset.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ class UEdGraph;
class UEdGraphNode;
class UFlowAsset;

class UWorld;

#if !UE_BUILD_SHIPPING
DECLARE_DELEGATE(FFlowGraphEvent);
DECLARE_DELEGATE_TwoParams(FFlowSignalEvent, const FGuid& /*NodeGuid*/, const FName& /*PinName*/);
DECLARE_DELEGATE_ThreeParams(FFlowSignalEvent, const UFlowAsset* /*Instance*/, const FGuid& /*NodeGuid*/, const FName& /*PinName*/);
#endif

// Working Data struct for the Harvest Data Pins operation
Expand Down Expand Up @@ -279,7 +281,12 @@ class FLOW_API UFlowAsset : public UObject
TArray<TObjectPtr<UFlowAsset>> ActiveInstances;

#if WITH_EDITORONLY_DATA
TWeakObjectPtr<UFlowAsset> InspectedInstance;
TWeakObjectPtr<const UFlowAsset> InspectedInstance;

FString LastInspectedInstanceName;

/** Current world being debugged for this asset */
TWeakObjectPtr<const UWorld> CurrentWorldBeingDebugged;

// Message log for storing runtime errors/notes/warnings that will only last until the next game run
// Log lives in the asset template, so it can be inspected after ending the PIE
Expand All @@ -289,15 +296,25 @@ class FLOW_API UFlowAsset : public UObject
public:
void AddInstance(UFlowAsset* Instance);
int32 RemoveInstance(UFlowAsset* Instance);
TConstArrayView<TObjectPtr<UFlowAsset>> GetActiveInstances() const { return ActiveInstances; }

void ClearInstances();
int32 GetInstancesNum() const { return ActiveInstances.Num(); }

#if WITH_EDITOR
void GetInstanceDisplayNames(TArray<TSharedPtr<FName>>& OutDisplayNames) const;
FString GetDebugName() const;

void SetInspectedInstance(TWeakObjectPtr<const UFlowAsset> NewInspectedInstance, bool bRefreshDebugger = true);
const UFlowAsset* GetInspectedInstance() const { return InspectedInstance.IsValid() ? InspectedInstance.Get() : nullptr; }

void SetInspectedInstance(const FName& NewInspectedInstanceName);
UFlowAsset* GetInspectedInstance() const { return InspectedInstance.IsValid() ? InspectedInstance.Get() : nullptr; }
/** @return debug name of instance that should be debugged, may be from previous PIE session */
const FStringView GetLastInspectedInstanceName() const
{
return LastInspectedInstanceName;
}

void SetWorldBeingDebugged(const TWeakObjectPtr<const UWorld> NewWorld);
const TWeakObjectPtr<const UWorld> GetWorldBeingDebugged() const { return CurrentWorldBeingDebugged; }

DECLARE_EVENT(UFlowAsset, FRefreshDebuggerEvent);

Expand Down
29 changes: 29 additions & 0 deletions Source/Flow/Public/FlowUserSettings.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "Engine/DeveloperSettings.h"
#include "FlowUserSettings.generated.h"

/**
*
*/
UCLASS(Config = EditorPerProjectUserSettings, meta = (DisplayName = "Flow"))
class FLOW_API UFlowUserSettings : public UDeveloperSettings
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Class for user settings, that can't be moved to Editor module for now. I would also move here UFlowSettings::bUseAdaptiveNodeTitles, but it is beyond the scope of this PR.

{
GENERATED_UCLASS_BODY()

static UFlowUserSettings* Get() { return CastChecked<UFlowUserSettings>(UFlowUserSettings::StaticClass()->GetDefaultObject()); }

UPROPERTY(EditDefaultsOnly, config, Category = "Debug")
bool bSetFirstAssetInstanceAsInspected;

// Keep last inspected instance of this FlowAsset between PIE sessions
UPROPERTY(EditDefaultsOnly, config, Category = "Debug")
bool bKeepLastInspectedInstance;

virtual FName GetCategoryName() const override { return FName("Flow Graph"); }
#if WITH_EDITORONLY_DATA
virtual FText GetSectionText() const override { return INVTEXT("User Settings"); }
#endif
};
Loading