156 lines
5 KiB
C++
156 lines
5 KiB
C++
|
|
// Voir LPDumpComponentsCommandlet.h
|
||
|
|
|
||
|
|
#include "LPDumpComponentsCommandlet.h"
|
||
|
|
|
||
|
|
#include "AssetRegistry/AssetRegistryModule.h"
|
||
|
|
#include "Components/ActorComponent.h"
|
||
|
|
#include "Engine/Blueprint.h"
|
||
|
|
#include "Engine/SCS_Node.h"
|
||
|
|
#include "Engine/SimpleConstructionScript.h"
|
||
|
|
#include "Engine/Level.h"
|
||
|
|
#include "Engine/World.h"
|
||
|
|
#include "GameFramework/Actor.h"
|
||
|
|
|
||
|
|
DEFINE_LOG_CATEGORY_STATIC(LogLPCompDump, Log, All);
|
||
|
|
|
||
|
|
namespace
|
||
|
|
{
|
||
|
|
void DumpObject(const UObject* Obj, bool bAll)
|
||
|
|
{
|
||
|
|
const UObject* Defaults = Obj->GetClass()->GetDefaultObject();
|
||
|
|
for (TFieldIterator<FProperty> It(Obj->GetClass()); It; ++It)
|
||
|
|
{
|
||
|
|
const FProperty* Prop = *It;
|
||
|
|
if (Prop->IsA<FMulticastDelegateProperty>() || Prop->IsA<FDelegateProperty>())
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
const bool bSame = Prop->Identical_InContainer(Obj, Defaults, 0, PPF_None);
|
||
|
|
if (bSame && !bAll)
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
FString Value;
|
||
|
|
Prop->ExportText_InContainer(0, Value, Obj, bSame ? nullptr : Defaults, const_cast<UObject*>(Obj), PPF_None);
|
||
|
|
if (Value.Len() > 4000)
|
||
|
|
{
|
||
|
|
Value = Value.Left(4000) + TEXT("...");
|
||
|
|
}
|
||
|
|
UE_LOG(LogLPCompDump, Warning, TEXT(" %s%s = %s"), bSame ? TEXT("(defaut) ") : TEXT(""), *Prop->GetName(), *Value);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
ULPDumpComponentsCommandlet::ULPDumpComponentsCommandlet()
|
||
|
|
{
|
||
|
|
IsClient = false;
|
||
|
|
IsServer = false;
|
||
|
|
IsEditor = true;
|
||
|
|
LogToConsole = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
int32 ULPDumpComponentsCommandlet::Main(const FString& Params)
|
||
|
|
{
|
||
|
|
TArray<FString> Tokens, Switches;
|
||
|
|
TMap<FString, FString> ParamsMap;
|
||
|
|
ParseCommandLine(*Params, Tokens, Switches, ParamsMap);
|
||
|
|
|
||
|
|
const FString WantedBP = ParamsMap.FindRef(TEXT("BP"));
|
||
|
|
const FString WantedMap = ParamsMap.FindRef(TEXT("Map"));
|
||
|
|
const FString Filter = ParamsMap.FindRef(TEXT("Filter"));
|
||
|
|
const bool bAll = Switches.Contains(TEXT("All"));
|
||
|
|
if (WantedBP.IsEmpty() && WantedMap.IsEmpty())
|
||
|
|
{
|
||
|
|
UE_LOG(LogLPCompDump, Error, TEXT("Usage : -BP=<Blueprint> [-All] | -Map=<chemin /Game/...> -Filter=<texte> [-All]"));
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
// -Map : acteurs d'une carte dont la classe ou le nom contient le filtre.
|
||
|
|
if (!WantedMap.IsEmpty())
|
||
|
|
{
|
||
|
|
UPackage* Package = LoadPackage(nullptr, *WantedMap, LOAD_None);
|
||
|
|
const UWorld* World = Package ? UWorld::FindWorldInPackage(Package) : nullptr;
|
||
|
|
if (!World || !World->PersistentLevel)
|
||
|
|
{
|
||
|
|
UE_LOG(LogLPCompDump, Error, TEXT("Carte '%s' introuvable."), *WantedMap);
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
UE_LOG(LogLPCompDump, Warning, TEXT("=== %s : acteurs '%s' ==="), *WantedMap, *Filter);
|
||
|
|
for (const AActor* Actor : World->PersistentLevel->Actors)
|
||
|
|
{
|
||
|
|
if (!Actor || (!Filter.IsEmpty() && !Actor->GetClass()->GetName().Contains(Filter) && !Actor->GetName().Contains(Filter)))
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
UE_LOG(LogLPCompDump, Warning, TEXT(" [acteur] %s (%s) a %s"), *Actor->GetName(), *Actor->GetClass()->GetName(),
|
||
|
|
*Actor->GetActorLocation().ToString());
|
||
|
|
DumpObject(Actor, bAll);
|
||
|
|
for (const UActorComponent* Comp : Actor->GetComponents())
|
||
|
|
{
|
||
|
|
if (Comp)
|
||
|
|
{
|
||
|
|
UE_LOG(LogLPCompDump, Warning, TEXT(" [composant] %s (%s)"), *Comp->GetName(), *Comp->GetClass()->GetName());
|
||
|
|
DumpObject(Comp, bAll);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
FAssetRegistryModule& AssetRegistryModule =
|
||
|
|
FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
|
||
|
|
AssetRegistryModule.Get().SearchAllAssets(true);
|
||
|
|
|
||
|
|
TArray<FAssetData> Assets;
|
||
|
|
AssetRegistryModule.Get().GetAssetsByClass(UBlueprint::StaticClass()->GetClassPathName(), Assets, true);
|
||
|
|
|
||
|
|
const UBlueprint* Target = nullptr;
|
||
|
|
for (const FAssetData& AssetData : Assets)
|
||
|
|
{
|
||
|
|
if (AssetData.PackageName.ToString().StartsWith(TEXT("/Game/")) && AssetData.AssetName.ToString() == WantedBP)
|
||
|
|
{
|
||
|
|
Target = Cast<UBlueprint>(AssetData.GetAsset());
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (!Target || !Target->GeneratedClass)
|
||
|
|
{
|
||
|
|
UE_LOG(LogLPCompDump, Error, TEXT("Blueprint '%s' introuvable sous /Game."), *WantedBP);
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
UE_LOG(LogLPCompDump, Warning, TEXT("=== %s ==="), *Target->GetPathName());
|
||
|
|
|
||
|
|
const UObject* CDO = Target->GeneratedClass->GetDefaultObject();
|
||
|
|
UE_LOG(LogLPCompDump, Warning, TEXT(" [CDO] %s"), *CDO->GetClass()->GetName());
|
||
|
|
DumpObject(CDO, false);
|
||
|
|
|
||
|
|
// Composants ajoutes dans l'editeur de Blueprint.
|
||
|
|
if (Target->SimpleConstructionScript)
|
||
|
|
{
|
||
|
|
for (const USCS_Node* Node : Target->SimpleConstructionScript->GetAllNodes())
|
||
|
|
{
|
||
|
|
if (Node && Node->ComponentTemplate)
|
||
|
|
{
|
||
|
|
UE_LOG(LogLPCompDump, Warning, TEXT(" [SCS] %s (%s) parent=%s"), *Node->GetVariableName().ToString(),
|
||
|
|
*Node->ComponentTemplate->GetClass()->GetName(), *Node->ParentComponentOrVariableName.ToString());
|
||
|
|
DumpObject(Node->ComponentTemplate, bAll);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Composants natifs (heritage C++) portes par le CDO.
|
||
|
|
if (const AActor* Actor = Cast<AActor>(CDO))
|
||
|
|
{
|
||
|
|
for (const UActorComponent* Comp : Actor->GetComponents())
|
||
|
|
{
|
||
|
|
if (Comp)
|
||
|
|
{
|
||
|
|
UE_LOG(LogLPCompDump, Warning, TEXT(" [natif] %s (%s)"), *Comp->GetName(), *Comp->GetClass()->GetName());
|
||
|
|
DumpObject(Comp, bAll);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|