LifePlay-Revival/Source/LifePlayEditorTools/LPDumpWidgetTreeCommandlet.cpp

125 lines
3.6 KiB
C++
Raw Permalink Normal View History

// Voir LPDumpWidgetTreeCommandlet.h
#include "LPDumpWidgetTreeCommandlet.h"
#include "AssetRegistry/AssetRegistryModule.h"
#include "Blueprint/UserWidget.h"
#include "Blueprint/WidgetTree.h"
#include "Components/PanelSlot.h"
#include "Components/PanelWidget.h"
#include "Components/Widget.h"
#include "WidgetBlueprint.h"
DEFINE_LOG_CATEGORY_STATIC(LogLPWidgetDump, Log, All);
namespace
{
/** Proprietes de Obj qui different du CDO de sa classe, une par ligne. */
void DumpNonDefault(const UObject* Obj, const FString& Indent, const TCHAR* Label)
{
if (!Obj)
{
return;
}
const UObject* Defaults = Obj->GetClass()->GetDefaultObject();
for (TFieldIterator<FProperty> It(Obj->GetClass()); It; ++It)
{
const FProperty* Prop = *It;
if (Prop->HasAnyPropertyFlags(CPF_Transient | CPF_DuplicateTransient) || Prop->IsA<FMulticastDelegateProperty>()
|| Prop->IsA<FDelegateProperty>())
{
continue;
}
if (Prop->Identical_InContainer(Obj, Defaults, 0, PPF_None))
{
continue;
}
FString Value;
Prop->ExportText_InContainer(0, Value, Obj, Defaults, const_cast<UObject*>(Obj), PPF_None);
if (Value.Len() > 4000)
{
Value = Value.Left(4000) + TEXT("...");
}
UE_LOG(LogLPWidgetDump, Warning, TEXT("%s %s.%s = %s"), *Indent, Label, *Prop->GetName(), *Value);
}
}
void DumpWidget(const UWidget* Widget, int32 Depth)
{
if (!Widget)
{
return;
}
const FString Indent = FString::ChrN(Depth * 2, TEXT(' '));
UE_LOG(LogLPWidgetDump, Warning, TEXT("%s[%s] %s"), *Indent, *Widget->GetClass()->GetName(), *Widget->GetName());
DumpNonDefault(Widget->Slot, Indent, TEXT("slot"));
DumpNonDefault(Widget, Indent, TEXT("w"));
if (const UPanelWidget* Panel = Cast<UPanelWidget>(Widget))
{
for (int32 i = 0; i < Panel->GetChildrenCount(); ++i)
{
DumpWidget(Panel->GetChildAt(i), Depth + 1);
}
}
}
}
ULPDumpWidgetTreeCommandlet::ULPDumpWidgetTreeCommandlet()
{
IsClient = false;
IsServer = false;
IsEditor = true;
LogToConsole = true;
}
int32 ULPDumpWidgetTreeCommandlet::Main(const FString& Params)
{
TArray<FString> Tokens, Switches;
TMap<FString, FString> ParamsMap;
ParseCommandLine(*Params, Tokens, Switches, ParamsMap);
const FString WantedBP = ParamsMap.FindRef(TEXT("BP"));
if (WantedBP.IsEmpty())
{
UE_LOG(LogLPWidgetDump, Error, TEXT("Usage : -BP=<WidgetBlueprint>"));
return 1;
}
FAssetRegistryModule& AssetRegistryModule =
FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
AssetRegistryModule.Get().SearchAllAssets(true);
TArray<FAssetData> Assets;
AssetRegistryModule.Get().GetAssetsByClass(UWidgetBlueprint::StaticClass()->GetClassPathName(), Assets, true);
// -BP=* : tous les Widget Blueprints de /Game, tries par chemin (diff avant/apres d'un correctif).
const bool bAll = (WantedBP == TEXT("*"));
Assets.Sort([](const FAssetData& A, const FAssetData& B) { return A.PackageName.LexicalLess(B.PackageName); });
int32 Dumped = 0;
for (const FAssetData& AssetData : Assets)
{
if (!AssetData.PackageName.ToString().StartsWith(TEXT("/Game/"))
|| (!bAll && AssetData.AssetName.ToString() != WantedBP))
{
continue;
}
const UWidgetBlueprint* Target = Cast<UWidgetBlueprint>(AssetData.GetAsset());
if (!Target || !Target->WidgetTree)
{
continue;
}
++Dumped;
UE_LOG(LogLPWidgetDump, Warning, TEXT("=== %s : arbre de widgets ==="), *Target->GetPathName());
DumpWidget(Target->WidgetTree->RootWidget, 0);
}
if (Dumped == 0)
{
UE_LOG(LogLPWidgetDump, Error, TEXT("Widget Blueprint '%s' introuvable sous /Game."), *WantedBP);
return 1;
}
return 0;
}