Skip to content

Commit

Permalink
Subsystem tooltips for #16:
Browse files Browse the repository at this point in the history
- Detailed owner name for WorldSubsystems
- Use smart meta for user tooltip
  • Loading branch information
aquanox committed Jul 3, 2024
1 parent 681c9c4 commit a0bbeb2
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ FSubsystemTreeSubsystemItem::FSubsystemTreeSubsystemItem(TSharedRef<FSubsystemMo
}
}

TOptional<FString> UserTooltipValue = FSubsystemBrowserUtils::GetMetadataHierarchical(InClass, FSubsystemBrowserUserMeta::MD_SBTooltip);
TOptional<FString> UserTooltipValue = FSubsystemBrowserUtils::GetSmartMetaValue(Instance, FSubsystemBrowserUserMeta::MD_SBTooltip, true);
if (UserTooltipValue.IsSet())
{
UserTooltip = UserTooltipValue;
Expand Down
4 changes: 2 additions & 2 deletions Source/SubsystemBrowser/SubsystemBrowserSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ struct FSubsystemBrowserConfigItem
bool operator==(const FName& OtherName) const { return Name == OtherName; }
};

// Dynamic delegate for owner name requesting
DECLARE_DYNAMIC_DELEGATE_RetVal(FString, FSubsystemBrowserGetOwnerName);
DECLARE_DYNAMIC_DELEGATE_RetVal(FString, FSubsystemBrowserGetStringProperty);
DECLARE_DYNAMIC_DELEGATE_RetVal(FText, FSubsystemBrowserGetTextProperty);

struct FSubsystemBrowserUserMeta
{
Expand Down
121 changes: 106 additions & 15 deletions Source/SubsystemBrowser/SubsystemBrowserUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#include "UObject/Package.h"
#include "Misc/EngineVersionComparison.h"

#define LOCTEXT_NAMESPACE "SubsystemBrowser"

static FAutoConsoleCommandWithWorldArgsAndOutputDevice CmdPrintClassData(
TEXT("SB.PrintClass"), TEXT("Print class details"),
FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateStatic(&FSubsystemBrowserUtils::PrintClassDetails)
Expand All @@ -25,34 +27,65 @@ static FAutoConsoleCommandWithWorldArgsAndOutputDevice CmdPrintPropertyData(
FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateStatic(&FSubsystemBrowserUtils::PrintPropertyDetails)
);

FString FSubsystemBrowserUtils::GetSubsystemOwnerName(UObject* Instance)
TOptional<FString> FSubsystemBrowserUtils::GetSmartMetaValue(UObject* InObject, const FName& InName, bool bHierarchical, bool bWarn)
{
// First try searching for user function or
TOptional<FString> UserSource = GetMetadataHierarchical(Instance->GetClass(), FSubsystemBrowserUserMeta::MD_SBOwnerName);
if (UserSource.IsSet())
TOptional<FString> UserSource;

if (bHierarchical)
UserSource = GetMetadataHierarchical(InObject->GetClass(), InName);
else
UserSource = GetMetadataOptional(InObject->GetClass(), InName);

if (UserSource.IsSet() && FName::IsValidXName(UserSource.GetValue(), INVALID_OBJECTNAME_CHARACTERS))
{
const FName Name ( *UserSource.GetValue() );
if (const UFunction* Func = Instance->GetClass()->FindFunctionByName(Name))
if (const UFunction* Func = InObject->GetClass()->FindFunctionByName(Name))
{
if (Func->GetReturnProperty()->IsA(FStrProperty::StaticClass())
&& Func->HasAllFunctionFlags(FUNC_Native)
&& !Func->HasAnyFunctionFlags(FUNC_Static))
if (Func->HasAllFunctionFlags(FUNC_Native) && !Func->HasAnyFunctionFlags(FUNC_Static) && Func->GetReturnProperty())
{
FSubsystemBrowserGetOwnerName Delegate;
Delegate.BindUFunction(Instance, Name);
return Delegate.Execute();
if (Func->GetReturnProperty()->IsA(FStrProperty::StaticClass()))
{
FSubsystemBrowserGetStringProperty Delegate;
Delegate.BindUFunction(InObject, Name);
return Delegate.Execute();
}
else if (Func->GetReturnProperty()->IsA(FTextProperty::StaticClass()))
{
FSubsystemBrowserGetTextProperty Delegate;
Delegate.BindUFunction(InObject, Name);
return Delegate.Execute().ToString();
}
}
}
else if (const FProperty* Prop = Instance->GetClass()->FindPropertyByName(Name))
else if (const FProperty* Prop = InObject->GetClass()->FindPropertyByName(Name))
{
if (Prop->IsA(FStrProperty::StaticClass()))
{
return CastFieldChecked<FStrProperty>(Prop)->GetPropertyValue(Instance);
return CastFieldChecked<FStrProperty>(Prop)->GetPropertyValue(InObject);
}
else if (Prop->IsA(FTextProperty::StaticClass()))
{
return CastFieldChecked<FTextProperty>(Prop)->GetPropertyValue(InObject).ToString();
}
}

UE_LOG(LogSubsystemBrowser, Warning, TEXT("%s specifies OwnerSource %s but it is neither valid function or property"),
*GetNameSafe(Instance), *UserSource.GetValue());
if (bWarn)
{
UE_LOG(LogSubsystemBrowser, Warning, TEXT("%s specifies source %s but it is neither valid function or property"),
*GetNameSafe(InObject), *UserSource.GetValue());
}
}

return UserSource;
}

FString FSubsystemBrowserUtils::GetSubsystemOwnerName(UObject* Instance)
{
// First try searching for user function or
TOptional<FString> UserSource = GetSmartMetaValue(Instance, FSubsystemBrowserUserMeta::MD_SBOwnerName, true);
if (UserSource.IsSet())
{
return UserSource.GetValue();
}

if (ULocalPlayerSubsystem* PlayerSubsystem = Cast<ULocalPlayerSubsystem>(Instance))
Expand All @@ -62,6 +95,10 @@ FString FSubsystemBrowserUtils::GetSubsystemOwnerName(UObject* Instance)
return LocalPlayer->GetName();
}
}
else if (UWorldSubsystem* WorldSubsystem = Cast<UWorldSubsystem>(Instance))
{
return GetWorldDescription(WorldSubsystem->GetWorld()).ToString();
}
else if (UObject* Outer = Instance->GetOuter())
{
return Outer->GetName();
Expand Down Expand Up @@ -556,3 +593,57 @@ void FSubsystemBrowserUtils::PrintPropertyDetails(const TArray<FString>& InArgs,
InLog.Logf(TEXT("Type: %s"), *Property->GetClass()->GetName());
InLog.Logf(TEXT("Flags: %s"), *FlagsToString(Property->GetPropertyFlags(), GetPropertyFlagsMap()));
}

FText FSubsystemBrowserUtils::GetWorldDescription(const UWorld* World)
{
FText Description;
if(World)
{
FText PostFix;
const FWorldContext* WorldContext = nullptr;
for (const FWorldContext& Context : GEngine->GetWorldContexts())
{
if(Context.World() == World)
{
WorldContext = &Context;
break;
}
}

if (World->WorldType == EWorldType::PIE)
{
switch(World->GetNetMode())
{
case NM_Client:
if (WorldContext)
{
PostFix = FText::Format(LOCTEXT("ClientPostfixFormat", "(Client {0})"), FText::AsNumber(WorldContext->PIEInstance - 1));
}
else
{
PostFix = LOCTEXT("ClientPostfix", "(Client)");
}
break;
case NM_DedicatedServer:
case NM_ListenServer:
PostFix = LOCTEXT("ServerPostfix", "(Server)");
break;
case NM_Standalone:
PostFix = LOCTEXT("PlayInEditorPostfix", "(Play In Editor)");
break;
default:
break;
}
}
else if(World->WorldType == EWorldType::Editor)
{
PostFix = LOCTEXT("EditorPostfix", "(Editor)");
}

Description = FText::Format(LOCTEXT("WorldFormat", "{0} {1}"), FText::FromString(World->GetFName().GetPlainNameString()), PostFix);
}

return Description;
}

#undef LOCTEXT_NAMESPACE
16 changes: 16 additions & 0 deletions Source/SubsystemBrowser/SubsystemBrowserUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,17 @@
*/
struct SUBSYSTEMBROWSER_API FSubsystemBrowserUtils
{
/**
* Get "Smart metadata" property.
*
* Performs a lookup for possible function/property match, if none found uses raw string value.
*
* Functions should be a UFUNCTION() returning FString or FText
* Properties should be a UPROPERTY() of FString or FText type
*
*/
static TOptional<FString> GetSmartMetaValue(UObject* InObject, const FName& InName, bool bHierarchical = false, bool bWarn = false);

/**
* Get info about subsystem "Owner"
*/
Expand Down Expand Up @@ -109,4 +120,9 @@ struct SUBSYSTEMBROWSER_API FSubsystemBrowserUtils
* Example: `SB.PrintProperty /Script/SubsystemBrowser.SubsystemBrowserTestSubsystem SingleDelegate`
*/
static void PrintPropertyDetails(const TArray< FString >& InArgs, UWorld* InWorld, FOutputDevice& InLog);

/**
* Build a text description for a world
*/
static FText GetWorldDescription(const UWorld* World);
};
64 changes: 10 additions & 54 deletions Source/SubsystemBrowser/UI/SubsystemBrowserPanel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "SubsystemBrowserModule.h"
#include "SubsystemBrowserSettings.h"
#include "SubsystemBrowserStyle.h"
#include "SubsystemBrowserUtils.h"
#include "Components/SlateWrapperTypes.h"
#include "Widgets/Input/SSearchBox.h"
#include "Widgets/Layout/SSeparator.h"
Expand Down Expand Up @@ -821,61 +822,16 @@ const FSlateBrush* SSubsystemBrowserPanel::GetWorldsMenuBrush() const

FText SSubsystemBrowserPanel::GetCurrentWorldText() const
{
FFormatNamedArguments Args;
Args.Add(TEXT("World"), GetWorldDescription(SubsystemModel->GetCurrentWorld().Get()));
return FText::Format(LOCTEXT("WorldsSelectButton", "World: {World}"), Args);
}

FText SSubsystemBrowserPanel::GetWorldDescription(const UWorld* World) const
{
FText Description;
if(World)
if (SubsystemModel->GetCurrentWorld().IsValid())
{
FText PostFix;
const FWorldContext* WorldContext = nullptr;
for (const FWorldContext& Context : GEngine->GetWorldContexts())
{
if(Context.World() == World)
{
WorldContext = &Context;
break;
}
}

if (World->WorldType == EWorldType::PIE)
{
switch(World->GetNetMode())
{
case NM_Client:
if (WorldContext)
{
PostFix = FText::Format(LOCTEXT("ClientPostfixFormat", "(Client {0})"), FText::AsNumber(WorldContext->PIEInstance - 1));
}
else
{
PostFix = LOCTEXT("ClientPostfix", "(Client)");
}
break;
case NM_DedicatedServer:
case NM_ListenServer:
PostFix = LOCTEXT("ServerPostfix", "(Server)");
break;
case NM_Standalone:
PostFix = LOCTEXT("PlayInEditorPostfix", "(Play In Editor)");
break;
default:
break;
}
}
else if(World->WorldType == EWorldType::Editor)
{
PostFix = LOCTEXT("EditorPostfix", "(Editor)");
}

Description = FText::Format(LOCTEXT("WorldFormat", "{0} {1}"), FText::FromString(World->GetFName().GetPlainNameString()), PostFix);
FFormatNamedArguments Args;
Args.Add(TEXT("World"), FSubsystemBrowserUtils::GetWorldDescription(SubsystemModel->GetCurrentWorld().Get()));
return FText::Format(LOCTEXT("WorldsSelectButton", "World: {World}"), Args);
}
else
{
return LOCTEXT("WorldsSelectButton_Bad", "World: Invalid");
}

return Description;
}

void SSubsystemBrowserPanel::OnSelectWorld(TWeakObjectPtr<UWorld> InWorld)
Expand Down Expand Up @@ -903,7 +859,7 @@ TSharedRef<SWidget> SSubsystemBrowserPanel::GetWorldsButtonContent()
if (World && (World->WorldType == EWorldType::PIE || Context.WorldType == EWorldType::Editor))
{
MenuBuilder.AddMenuEntry(
GetWorldDescription(World),
FSubsystemBrowserUtils::GetWorldDescription(World),
LOCTEXT("ChooseWorldToolTip", "Display subsystems for this world."),
FSlateIcon(),
FUIAction(
Expand Down
1 change: 0 additions & 1 deletion Source/SubsystemBrowser/UI/SubsystemBrowserPanel.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@ class SSubsystemBrowserPanel : public SCompoundWidget

const FSlateBrush* GetWorldsMenuBrush() const;
FText GetCurrentWorldText() const;
FText GetWorldDescription(const UWorld* World) const;
void OnSelectWorld(TWeakObjectPtr<UWorld> InWorld);
bool IsWorldChecked(TWeakObjectPtr<UWorld> InWorld);
TSharedRef<SWidget> GetWorldsButtonContent();
Expand Down

0 comments on commit a0bbeb2

Please sign in to comment.