// Portage UE 5.5 (2026.9 beta) - voir LPAssetRegistryHelpers.h #include "LPAssetRegistryHelpers.h" #include "LifePlay.h" #include "AssetRegistry/AssetRegistryModule.h" #include "AssetRegistry/IAssetRegistry.h" #include "Modules/ModuleManager.h" FAssetData ULPAssetRegistryHelpers::GetAssetByObjectPath(const FName ObjectPath, bool bIncludeOnlyOnDiskAssets) { const FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(TEXT("AssetRegistry")); // 5.1+ : la surcharge prenant un FName est depreciee. La broche Blueprint reste un // FName (les noeuds rebranches par la commandlet en dependent), seule la conversion // vers FSoftObjectPath est faite ici. const FSoftObjectPath Path(ObjectPath.ToString()); const FAssetData Result = AssetRegistryModule.Get().GetAssetByObjectPath(Path, bIncludeOnlyOnDiskAssets); // Lot STM1 (STM1-SPEC-01, T1) : GI.MoveCity resout ici StreetMapName et StaticMeshName de la ville. Chaque // resolution d'un chemin de ville est tracee (sans le dedoublonnage ci-dessous) ; un chemin qui finit par '/' // est la valeur par defaut de la structure City, rendue par GetCityByName quand le nom de ville est introuvable. const FString PathString = ObjectPath.ToString(); if (PathString.StartsWith(TEXT("/Game/Heavy/StreetMap"), ESearchCase::IgnoreCase)) { const TCHAR* Label = PathString.EndsWith(TEXT("/")) ? TEXT(" (chemin par defaut de City : ville non trouvee)") : (PathString.Contains(TEXT("000Dummy"), ESearchCase::IgnoreCase) ? TEXT(" (ville factice)") : TEXT("")); UE_LOG(LogLPCity, Log, TEXT("[LPCity] RESOLUTION '%s' -> %s%s"), *PathString, Result.IsValid() ? TEXT("OK") : TEXT("ECHEC"), Label); } // Lot L5 (ERR-027) : tout chemin non resolu est signale une fois, avec la forme exacte // recue et celle interpretee par FSoftObjectPath. Les maillages charges par chemin // (corps, vetements, coiffures) passent tous par ici ; un echec produit un personnage // sans maillage, sans aucune autre trace. if (!Result.IsValid()) { // Appele depuis les Blueprints, donc sur le thread de jeu. static TSet ReportedFailures; bool bAlreadyReported = false; ReportedFailures.Add(ObjectPath, &bAlreadyReported); if (!bAlreadyReported) { UE_LOG(LogLifePlay, Warning, TEXT("GetAssetByObjectPath ECHEC | recu '%s' | interprete '%s' (valide=%d) | OnlyOnDisk=%d"), *ObjectPath.ToString(), *Path.ToString(), Path.IsValid() ? 1 : 0, bIncludeOnlyOnDiskAssets ? 1 : 0); } } else { UE_LOG(LogLifePlay, Verbose, TEXT("GetAssetByObjectPath OK | '%s'"), *ObjectPath.ToString()); } return Result; } bool ULPAssetRegistryHelpers::GetAssetsByClassName(FName ClassName, TArray& OutAssetData, bool bSearchSubClasses) { OutAssetData.Reset(); if (ClassName.IsNone()) { return false; } // TryFindTypeSlow resout un nom court ("SkeletalMesh") vers la classe reelle, quel que // soit son module : /Script/Engine.SkeletalMesh comme /Script/StreetMapRuntime.StreetMap. const UClass* ResolvedClass = UClass::TryFindTypeSlow(ClassName.ToString()); if (!ResolvedClass) { UE_LOG(LogTemp, Warning, TEXT("LPAssetRegistryHelpers : classe '%s' introuvable."), *ClassName.ToString()); return false; } const FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(TEXT("AssetRegistry")); return AssetRegistryModule.Get().GetAssetsByClass( FTopLevelAssetPath(ResolvedClass), OutAssetData, bSearchSubClasses); } FName ULPAssetRegistryHelpers::GetAssetObjectPath(const FAssetData& AssetData) { if (!AssetData.IsValid()) { return NAME_None; } return FName(*AssetData.GetSoftObjectPath().ToString()); }