// 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 It(Obj->GetClass()); It; ++It) { const FProperty* Prop = *It; if (Prop->IsA() || Prop->IsA()) { 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(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 Tokens, Switches; TMap 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= [-All] | -Map= -Filter= [-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(TEXT("AssetRegistry")); AssetRegistryModule.Get().SearchAllAssets(true); TArray 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(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(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; }