LifePlay-Revival/Source/LifePlayEditorTools/LPImportCityOSMCommandlet.cpp
edujiro5972 56dfcfc3d2 LifePlay UE 5.8 : état de développement au 2026-10-20
Tickets : PUB-20261020-T1

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 17:35:10 +02:00

141 lines
5.6 KiB
C++

// Lot STM1 (STM1-IMPL-03). Voir LPImportCityOSMCommandlet.h.
#include "LPImportCityOSMCommandlet.h"
#include "AssetRegistry/AssetRegistryModule.h"
#include "Factories/Factory.h"
#include "HAL/FileManager.h"
#include "HAL/PlatformMemory.h"
#include "HAL/PlatformTime.h"
#include "Misc/FileHelper.h"
#include "Misc/PackageName.h"
#include "Modules/ModuleManager.h"
#include "StreetMap.h"
#include "UObject/Package.h"
#include "UObject/SavePackage.h"
DEFINE_LOG_CATEGORY_STATIC(LogLPImportCityOSM, Log, All);
ULPImportCityOSMCommandlet::ULPImportCityOSMCommandlet()
{
IsClient = false;
IsServer = false;
IsEditor = true;
LogToConsole = true;
}
int32 ULPImportCityOSMCommandlet::Main(const FString& Params)
{
TArray<FString> Tokens;
TArray<FString> Switches;
TMap<FString, FString> ParamsMap;
ParseCommandLine(*Params, Tokens, Switches, ParamsMap);
const FString OsmPath = ParamsMap.FindRef(TEXT("Osm"));
const FString PackageName = ParamsMap.FindRef(TEXT("Package"));
const FString ReportPath = ParamsMap.FindRef(TEXT("Report"));
TArray<FString> Report;
auto Line = [&Report](const FString& Text)
{
UE_LOG(LogLPImportCityOSM, Display, TEXT("%s"), *Text);
Report.Add(Text);
};
auto Finish = [&](int32 Code)
{
Line(FString::Printf(TEXT("CODE %d"), Code));
if (!ReportPath.IsEmpty())
{
FFileHelper::SaveStringArrayToFile(Report, *ReportPath, FFileHelper::EEncodingOptions::ForceUTF8WithoutBOM);
}
return Code;
};
if (OsmPath.IsEmpty() || PackageName.IsEmpty())
{
Line(TEXT("usage : -Osm=<fichier .osm> -Package=/Game/Heavy/StreetMap/_Pilot/<Ville> [-Report=<f.md>]"));
return Finish(2);
}
Line(FString::Printf(TEXT("# LPImportCityOSM %s <- %s"), *PackageName, *OsmPath));
// Gardes : paquet d'essai seulement, jamais d'ecrasement.
if (!PackageName.StartsWith(TEXT("/Game/Heavy/StreetMap/_Pilot/")) || !FPackageName::IsValidLongPackageName(PackageName))
{
Line(TEXT("ECHEC : le paquet doit etre sous /Game/Heavy/StreetMap/_Pilot/ (pilote) ; aucun asset ecrit"));
return Finish(1);
}
if (FPackageName::DoesPackageExist(PackageName))
{
Line(FString::Printf(TEXT("ECHEC : %s existe deja ; aucun asset ecrit"), *PackageName));
return Finish(1);
}
const int64 OsmBytes = IFileManager::Get().FileSize(*OsmPath);
if (OsmBytes <= 0)
{
Line(FString::Printf(TEXT("ECHEC : fichier introuvable ou vide : %s"), *OsmPath));
return Finish(1);
}
Line(FString::Printf(TEXT("fichier source : %lld octets"), OsmBytes));
// Fabrique du plugin, par reflexion (UStreetMapFactory n'est pas exportee).
FModuleManager::Get().LoadModule(TEXT("StreetMapImporting"));
UClass* FactoryClass = FindObject<UClass>(nullptr, TEXT("/Script/StreetMapImporting.StreetMapFactory"));
if (!FactoryClass || !FactoryClass->IsChildOf(UFactory::StaticClass()))
{
Line(TEXT("ECHEC : fabrique /Script/StreetMapImporting.StreetMapFactory introuvable"));
return Finish(1);
}
UFactory* Factory = NewObject<UFactory>(GetTransientPackage(), FactoryClass);
const FString AssetName = FPackageName::GetLongPackageAssetName(PackageName);
UPackage* Package = CreatePackage(*PackageName);
const double Start = FPlatformTime::Seconds();
bool bCanceled = false;
UObject* Imported = Factory->ImportObject(UStreetMap::StaticClass(), Package, *AssetName, RF_Public | RF_Standalone, OsmPath, nullptr, bCanceled);
const double ImportSeconds = FPlatformTime::Seconds() - Start;
const UStreetMap* StreetMap = Cast<UStreetMap>(Imported);
if (!StreetMap || bCanceled)
{
Line(FString::Printf(TEXT("ECHEC : import (%s) apres %.1f s ; aucun asset ecrit"), bCanceled ? TEXT("annule") : TEXT("objet nul"), ImportSeconds));
return Finish(1);
}
// Comptes.
int32 Named = 0, WithAmenity = 0;
TSet<FString> AmenityTypes;
for (const FStreetMapBuilding& Building : StreetMap->GetBuildings())
{
Named += Building.BuildingName.IsEmpty() ? 0 : 1;
if (!Building.Amenity.IsEmpty())
{
++WithAmenity;
AmenityTypes.Add(Building.Amenity);
}
}
const FVector2D Min = StreetMap->GetBoundsMin();
const FVector2D Max = StreetMap->GetBoundsMax();
Line(FString::Printf(TEXT("import : %.1f s ; routes %d, noeuds %d, batiments %d (nommes %d, avec amenite %d, %d types), parcs %d, eaux %d"),
ImportSeconds, StreetMap->GetRoads().Num(), StreetMap->GetNodes().Num(), StreetMap->GetBuildings().Num(), Named, WithAmenity,
AmenityTypes.Num(), StreetMap->GetParks().Num(), StreetMap->GetWaters().Num()));
Line(FString::Printf(TEXT("bornes (cm) : (%.0f, %.0f) a (%.0f, %.0f) ; soit %.2f x %.2f km"),
Min.X, Min.Y, Max.X, Max.Y, (Max.X - Min.X) / 100000.0, (Max.Y - Min.Y) / 100000.0));
// Sauvegarde du paquet d'essai.
FAssetRegistryModule::AssetCreated(const_cast<UStreetMap*>(StreetMap));
FSavePackageArgs SaveArgs;
SaveArgs.TopLevelFlags = RF_Public | RF_Standalone;
const FString FileName = FPackageName::LongPackageNameToFilename(PackageName, FPackageName::GetAssetPackageExtension());
const double SaveStart = FPlatformTime::Seconds();
if (!UPackage::SavePackage(Package, const_cast<UStreetMap*>(StreetMap), *FileName, SaveArgs))
{
Line(FString::Printf(TEXT("ECHEC : sauvegarde de %s"), *FileName));
return Finish(1);
}
const double SaveSeconds = FPlatformTime::Seconds() - SaveStart;
const FPlatformMemoryStats Mem = FPlatformMemory::GetStats();
Line(FString::Printf(TEXT("asset ecrit : %s (%s), %lld octets, sauvegarde %.1f s"),
*PackageName, *FileName, IFileManager::Get().FileSize(*FileName), SaveSeconds));
Line(FString::Printf(TEXT("memoire : pic physique du processus %.2f Go ; pic virtuel %.2f Go"),
double(Mem.PeakUsedPhysical) / (1024.0 * 1024.0 * 1024.0), double(Mem.PeakUsedVirtual) / (1024.0 * 1024.0 * 1024.0)));
return Finish(0);
}