9#include "AssetRegistry/AssetRegistryModule.h"
14#include "FileHelpers.h"
16#include "Misc/FileHelper.h"
17#include "Serialization/JsonReader.h"
18#include "Serialization/JsonSerializer.h"
19#include "HAL/PlatformFilemanager.h"
20#include "UObject/ConstructorHelpers.h"
21#include "Materials/MaterialInstanceConstant.h"
26 const FString AssetName = Mesh->GetName();
28 if (AssetName.Contains(TEXT(
"light"), ESearchCase::IgnoreCase) ||
29 AssetName.Contains(TEXT(
"sign"), ESearchCase::IgnoreCase))
34 for (
int i = 0; i < Mesh->StaticMaterials.Num(); i++)
36 UMaterialInterface *Material = Mesh->GetMaterial(i);
38 Material = UMaterial::GetDefaultMaterial(MD_Surface);
40 const FString MaterialName = Material->GetName();
42 if (MaterialName.Contains(TEXT(
"light"), ESearchCase::IgnoreCase) ||
43 MaterialName.Contains(TEXT(
"sign"), ESearchCase::IgnoreCase))
60#if WITH_EDITORONLY_DATA
63 static ConstructorHelpers::FObjectFinder<UMaterialInstanceConstant> MarkingNodeYellowMaterial(TEXT(
64 "MaterialInstanceConstant'/Game/Carla/Static/GenericMaterials/RoadPainterMaterials/LargeMaps/M_Road_03_Tiled_V3.M_Road_03_Tiled_V3'"));
65 static ConstructorHelpers::FObjectFinder<UMaterialInstanceConstant> MarkingNodeWhiteMaterial(TEXT(
66 "MaterialInstanceConstant'/Game/Carla/Static/GenericMaterials/RoadPainterMaterials/M_Road_03_LMW.M_Road_03_LMW'"));
67 static ConstructorHelpers::FObjectFinder<UMaterialInstanceConstant> RoadNode(TEXT(
68 "MaterialInstanceConstant'/Game/Carla/Static/GenericMaterials/RoadPainterMaterials/LargeMaps/M_Road_03_Tiled_V2.M_Road_03_Tiled_V2'"));
69 static ConstructorHelpers::FObjectFinder<UMaterialInstanceConstant> TerrainNodeMaterial(TEXT(
70 "MaterialInstanceConstant'/Game/Carla/Static/GenericMaterials/00_MastersOpt/Large_Maps/materials/MI_LargeLandscape_Grass.MI_LargeLandscape_Grass'"));
71 static ConstructorHelpers::FObjectFinder<UMaterialInstanceConstant> CurbNodeMaterial(TEXT(
72 "MaterialInstanceConstant'/Game/Carla/Static/GenericMaterials/LargeMap_materials/largeM_curb/MI_largeM_curb01.MI_largeM_curb01'"));
73 static ConstructorHelpers::FObjectFinder<UMaterialInstanceConstant> GutterNodeMaterial(TEXT(
74 "MaterialInstanceConstant'/Game/Carla/Static/GenericMaterials/LargeMap_materials/largeM_gutter/MI_largeM_gutter01.MI_largeM_gutter01'"));
75 static ConstructorHelpers::FObjectFinder<UMaterialInstanceConstant> SidewalkNode(TEXT(
76 "MaterialInstanceConstant'/Game/Carla/Static/GenericMaterials/LargeMap_materials/largeM_sidewalk/tile01/MI_largeM_tile02.MI_largeM_tile02'"));
87#if WITH_EDITORONLY_DATA
89FPackageParams UPrepareAssetsForCookingCommandlet::ParseParams(
const FString &InParams)
const
91 TArray<FString> Tokens;
92 TArray<FString> Params;
93 TMap<FString, FString> ParamVals;
95 ParseCommandLine(*InParams, Tokens, Params);
100 FParse::Value(*InParams, TEXT(
"PackageName="), PackageParams.
Name);
103 FParse::Bool(*InParams, TEXT(
"OnlyPrepareMaps="), PackageParams.
bOnlyPrepareMaps);
104 return PackageParams;
107void UPrepareAssetsForCookingCommandlet::LoadWorld(FAssetData &AssetData)
110 const FString BaseMap = TEXT(
"/Game/Carla/Maps/BaseMap");
113 MapObjectLibrary = UObjectLibrary::CreateLibrary(UWorld::StaticClass(),
false, GIsEditor);
126void UPrepareAssetsForCookingCommandlet::LoadWorldTile(FAssetData &AssetData)
129 const FString BaseTile = TEXT(
"/Game/Carla/Maps/TestMaps");
132 MapObjectLibrary = UObjectLibrary::CreateLibrary(UWorld::StaticClass(),
false, GIsEditor);
145void UPrepareAssetsForCookingCommandlet::LoadLargeMapWorld(FAssetData &AssetData)
148 const FString BaseMap = TEXT(
"/Game/Carla/Maps/BaseLargeMap");
151 MapObjectLibrary = UObjectLibrary::CreateLibrary(UWorld::StaticClass(),
false, GIsEditor);
164TArray<AStaticMeshActor *> UPrepareAssetsForCookingCommandlet::SpawnMeshesToWorld(
165 const TArray<FString> &AssetsPaths,
166 bool bUseCarlaMaterials,
170 TArray<AStaticMeshActor *> SpawnedMeshes;
173 const FTransform ZeroTransform = FTransform();
177 AssetsObjectLibrary = UObjectLibrary::CreateLibrary(UStaticMesh::StaticClass(),
false, GIsEditor);
184 UStaticMesh *MeshAsset;
185 AStaticMeshActor *MeshActor;
191 TileName = FString::Printf(TEXT(
"_Tile_%d_%d"), i, j);
199 MeshAsset = Cast<UStaticMesh>(MapAsset.GetAsset());
203 MapAsset.AssetName.ToString(AssetName);
206 if (i == -1 || (i != -1 && (AssetName.EndsWith(TileName) || AssetName.Contains(TileName +
"_"))))
208 MeshActor =
World->SpawnActor<AStaticMeshActor>(AStaticMeshActor::StaticClass(), ZeroTransform);
209 UStaticMeshComponent *MeshComponent = MeshActor->GetStaticMeshComponent();
210 MeshComponent->SetStaticMesh(CastChecked<UStaticMesh>(MeshAsset));
211 MeshActor->SetActorLabel(AssetName,
true);
214 UBodySetup *BodySetup = MeshAsset->BodySetup;
217 BodySetup->CollisionTraceFlag = CTF_UseComplexAsSimple;
218 MeshAsset->MarkPackageDirty();
221 SpawnedMeshes.Add(MeshActor);
223 if (bUseCarlaMaterials)
227 if (AssetName.Contains(SSTags::R_MARKING1) || AssetName.Contains(SSTags::R_MARKING2))
229 for (int32 i = 0; i < MeshActor->GetStaticMeshComponent()->GetStaticMesh()->StaticMaterials.Num(); ++i)
231 if (MeshActor->GetStaticMeshComponent()->GetStaticMesh()->StaticMaterials[i].ImportedMaterialSlotName.ToString().Contains(
"Yellow"))
241 else if (AssetName.Contains(SSTags::R_ROAD1) || AssetName.Contains(SSTags::R_ROAD2))
245 else if (AssetName.Contains(SSTags::R_TERRAIN))
248 MeshActor->GetStaticMeshComponent()->bReceivesDecals =
false;
250 else if (AssetName.Contains(SSTags::R_SIDEWALK1) || AssetName.Contains(SSTags::R_SIDEWALK2))
253 MeshActor->GetStaticMeshComponent()->bReceivesDecals =
false;
255 else if (AssetName.Contains(SSTags::R_CURB1) || AssetName.Contains(SSTags::R_CURB2)) {
258 MeshActor->GetStaticMeshComponent()->bReceivesDecals =
false;
260 else if (AssetName.Contains(SSTags::R_GUTTER1) || AssetName.Contains(SSTags::R_GUTTER2)) {
263 MeshActor->GetStaticMeshComponent()->bReceivesDecals =
false;
274 World->MarkPackageDirty();
276 return SpawnedMeshes;
279bool UPrepareAssetsForCookingCommandlet::IsMapInTiles(
const TArray<FString> &AssetsPaths)
283 AssetsObjectLibrary = UObjectLibrary::CreateLibrary(UStaticMesh::StaticClass(),
false, GIsEditor);
290 UStaticMesh *MeshAsset;
297 MeshAsset = Cast<UStaticMesh>(MapAsset.GetAsset());
301 MapAsset.AssetName.ToString(AssetName);
304 if (AssetName.Contains(
"_Tile_"))
318void UPrepareAssetsForCookingCommandlet::DestroySpawnedActorsInWorld(
319 TArray<AStaticMeshActor *> &SpawnedActors)
322 for (
auto Actor : SpawnedActors)
328 World->MarkPackageDirty();
331bool UPrepareAssetsForCookingCommandlet::SaveWorld(
332 FAssetData &AssetData,
333 const FString &PackageName,
334 const FString &DestPath,
335 const FString &WorldName,
336 bool bGenerateSpawnPoints)
339 UPackage *Package = AssetData.GetPackage();
340 Package->SetFolderName(*WorldName);
341 Package->FullyLoad();
342 Package->MarkPackageDirty();
343 FAssetRegistryModule::AssetCreated(
World);
347 const FString PackagePath = DestPath +
"/" + WorldName;
348 FAssetRegistryModule::AssetRenamed(
World, *PackagePath);
349 World->MarkPackageDirty();
350 World->GetOuter()->MarkPackageDirty();
353 const FString PathXODR = FPaths::ProjectContentDir() + PackageName + TEXT(
"/Maps/") +
354 WorldName + TEXT(
"/OpenDrive/") + WorldName + TEXT(
".xodr");
356 bool bPackageSaved =
false;
357 if (FPaths::FileExists(PathXODR) && bGenerateSpawnPoints)
361 World->SpawnActor(AOpenDriveActor::StaticClass(),
373 OpenWorldActor->Destroy();
380 return bPackageSaved;
386 TArray<FString> PackageList;
387 IFileManager::Get().FindFilesRecursive(PackageList, *(FPaths::ProjectContentDir()),
388 *(PackageName + TEXT(
".Package.json")),
true,
false,
false);
390 if (PackageList.Num() == 0)
392 UE_LOG(LogTemp, Error, TEXT(
"Package json file not found."));
396 return IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead(*PackageList[0]);
399FAssetsPaths UPrepareAssetsForCookingCommandlet::GetAssetsPathFromPackage(
const FString &PackageName)
const
406 FString MapsFileJsonContent;
407 if (FFileHelper::LoadFileToString(MapsFileJsonContent, *PackageJsonFilePath))
409 TSharedPtr<FJsonObject> JsonParsed;
410 TSharedRef<TJsonReader<TCHAR>> JsonReader = TJsonReaderFactory<TCHAR>::Create(MapsFileJsonContent);
411 if (FJsonSerializer::Deserialize(JsonReader, JsonParsed))
414 auto MapsJsonArray = JsonParsed->GetArrayField(TEXT(
"maps"));
416 for (
auto &MapJsonValue : MapsJsonArray)
418 TSharedPtr<FJsonObject> MapJsonObject = MapJsonValue->AsObject();
421 MapData.
Name = MapJsonObject->GetStringField(TEXT(
"name"));
422 MapData.
Path = MapJsonObject->GetStringField(TEXT(
"path"));
425 AssetsPaths.
MapsPaths.Add(std::move(MapData));
429 auto PropJsonArray = JsonParsed->GetArrayField(TEXT(
"props"));
431 for (
auto &PropJsonValue : PropJsonArray)
433 TSharedPtr<FJsonObject> PropJsonObject = PropJsonValue->AsObject();
435 const FString PropAssetPath = PropJsonObject->GetStringField(TEXT(
"path"));
437 AssetsPaths.
PropsPaths.Add(std::move(PropAssetPath));
444bool SaveStringTextToFile(
445 FString SaveDirectory,
448 bool bAllowOverWriting)
450 IPlatformFile &PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
455 if (PlatformFile.CreateDirectoryTree(*SaveDirectory))
458 const FString AbsoluteFilePath = SaveDirectory +
"/" + FileName;
461 if (bAllowOverWriting || !PlatformFile.FileExists(*AbsoluteFilePath))
463 FFileHelper::SaveStringToFile(SaveText, *AbsoluteFilePath);
471 const FString PackageFileName = FPackageName::LongPackageNameToFilename(
473 FPackageName::GetMapPackageExtension());
475 if (FPaths::FileExists(*PackageFileName))
481 return UPackage::SavePackage(
484 EObjectFlags::RF_Public | EObjectFlags::RF_Standalone,
493void UPrepareAssetsForCookingCommandlet::GenerateMapPathsFile(
495 const FString &PropsMapPath)
498 FString MapPathDataLinux;
499 IFileManager &FileManager = IFileManager::Get();
500 for (
const auto &Map : AssetsPaths.MapsPaths)
502 MapPathData.Append(Map.Path + TEXT(
"/") + Map.Name + TEXT(
"\n"));
503 MapPathDataLinux.Append(Map.Path + TEXT(
"/") + Map.Name + TEXT(
"+"));
504 TArray<FAssetData> AssetsData;
505 UObjectLibrary* ObjectLibrary = UObjectLibrary::CreateLibrary(UWorld::StaticClass(),
true,
true);
506 ObjectLibrary->LoadAssetDataFromPath(Map.Path);
507 ObjectLibrary->GetAssetDataList(AssetsData);
509 for (FAssetData &AssetData : AssetsData)
511 FString AssetName = AssetData.AssetName.ToString();
512 if (AssetName.Contains(Map.Name +
"_Tile_"))
514 MapPathData.Append(Map.Path + TEXT(
"/") + AssetName + TEXT(
"\n"));
515 MapPathDataLinux.Append(Map.Path + TEXT(
"/") + AssetName + TEXT(
"+"));
519 UE_LOG(LogTemp, Warning, TEXT(
"Found %d tiles"), NumTiles);
522 if (!PropsMapPath.IsEmpty())
524 MapPathData.Append(PropsMapPath + TEXT(
"/PropsMap"));
525 MapPathDataLinux.Append(PropsMapPath + TEXT(
"/PropsMap"));
529 MapPathDataLinux.RemoveFromEnd(TEXT(
"+"));
532 const FString SaveDirectory = FPaths::ProjectContentDir();
533 const FString FileName = FString(
"MapPaths.txt");
534 const FString FileNameLinux = FString(
"MapPathsLinux.txt");
535 SaveStringTextToFile(SaveDirectory, FileName, MapPathData,
true);
536 SaveStringTextToFile(SaveDirectory, FileNameLinux, MapPathDataLinux,
true);
539void UPrepareAssetsForCookingCommandlet::GeneratePackagePathFile(
const FString &PackageName)
541 FString SaveDirectory = FPaths::ProjectContentDir();
542 FString FileName = FString(
"PackagePath.txt");
544 SaveStringTextToFile(SaveDirectory, FileName, PackageJsonFilePath,
true);
547void UPrepareAssetsForCookingCommandlet::PrepareMapsForCooking(
548 const FString &PackageName,
549 const TArray<FMapData> &MapsPaths)
551 FString BasePath = TEXT(
"/Game/") + PackageName + TEXT(
"/Static/");
553 for (
const auto &Map : MapsPaths)
555 const FString MapPath = TEXT(
"/") + Map.Name;
557 const FString DefaultPath = TEXT(
"/Game/") + PackageName + TEXT(
"/Maps/") + Map.Name;
558 const FString RoadsPath = BasePath + SSTags::ROAD + MapPath;
559 const FString RoadLinesPath = BasePath + SSTags::ROADLINE + MapPath;
560 const FString TerrainPath = BasePath + SSTags::TERRAIN + MapPath;
561 const FString SidewalkPath = BasePath + SSTags::SIDEWALK + MapPath;
564 TArray<FString> DataPath = {DefaultPath, RoadsPath, RoadLinesPath, TerrainPath, SidewalkPath};
567 if (!IsMapInTiles(DataPath))
569 UE_LOG(LogTemp, Log, TEXT(
"Cooking map"));
571 FAssetData AssetData;
572 LoadWorld(AssetData);
573 UObjectRedirector *BaseMapRedirector = Cast<UObjectRedirector>(AssetData.GetAsset());
574 if (BaseMapRedirector !=
nullptr) {
575 World = CastChecked<UWorld>(BaseMapRedirector->DestinationObject);
578 World = CastChecked<UWorld>(AssetData.GetAsset());
581 TArray<AStaticMeshActor *> SpawnedActors = SpawnMeshesToWorld(DataPath, Map.bUseCarlaMapMaterials, -1, -1);
583 SaveWorld(AssetData, PackageName, Map.Path, Map.Name);
585 DestroySpawnedActorsInWorld(SpawnedActors);
589 TArray<TPair<FString, FIntVector>> MapPathsIds;
591 FVector PositionTile0 = FVector();
592 float TileSize = 200000.f;
594 FString TilesInfoPath = FPaths::ProjectContentDir() + PackageName + TEXT(
"/Maps/") + Map.Name +
"/TilesInfo.txt";
595 UE_LOG(LogTemp, Warning, TEXT(
"Loading %s ..."), *TilesInfoPath);
596 if (FFileHelper::LoadFileToString(TxtFile, *(TilesInfoPath)) ==
true) {
599 TxtFile.ParseIntoArray(Out, TEXT(
","),
true);
602 const float METERSTOCM = 100.f;
603 PositionTile0.X = METERSTOCM * FCString::Atof(*Out[0]);
604 PositionTile0.Y = METERSTOCM * FCString::Atof(*Out[1]);
605 TileSize = METERSTOCM * FCString::Atof(*Out[2]);
609 UE_LOG(LogTemp, Warning, TEXT(
"TilesInfo.txt format is invalid file"));
613 UE_LOG(LogTemp, Warning, TEXT(
"Could not find TilesInfo.txt file"));
616 UE_LOG(LogTemp, Log, TEXT(
"Cooking tiles:"));
618 FAssetData AssetData;
619 LoadWorldTile(AssetData);
620 UObjectRedirector *BaseMapRedirector = Cast<UObjectRedirector>(AssetData.GetAsset());
621 if (BaseMapRedirector !=
nullptr) {
622 World = CastChecked<UWorld>(BaseMapRedirector->DestinationObject);
625 World = CastChecked<UWorld>(AssetData.GetAsset());
637 TArray<AStaticMeshActor *> SpawnedActors = SpawnMeshesToWorld(DataPath, Map.bUseCarlaMapMaterials, i, j);
638 Res = SpawnedActors.Num() > 0;
641 UE_LOG(LogTemp, Log, TEXT(
" Tile %d,%d found"), i, j);
643 TileName = FString::Printf(TEXT(
"%s_Tile_%d_%d"), *Map.Name, i, j);
646 SaveWorld(AssetData, PackageName, Map.Path, TileName);
648 TPair<FString, FIntVector>(
649 Map.Path +
"/" + TileName, FIntVector(i, j, 0)));
651 DestroySpawnedActorsInWorld(SpawnedActors);
661 UEditorLoadingAndSavingUtils::SaveDirtyPackages(
true,
true);
664 LoadLargeMapWorld(AssetData);
665 BaseMapRedirector = Cast<UObjectRedirector>(AssetData.GetAsset());
666 if (BaseMapRedirector !=
nullptr) {
667 World = CastChecked<UWorld>(BaseMapRedirector->DestinationObject);
670 World = CastChecked<UWorld>(AssetData.GetAsset());
675 ALargeMapManager::StaticClass(), FTransform());
682 SaveWorld(AssetData, PackageName, Map.Path, Map.Name,
false);
684 UE_LOG(LogTemp, Log, TEXT(
"End cooking tiles"));
689void UPrepareAssetsForCookingCommandlet::PreparePropsForCooking(
690 FString &PackageName,
691 const TArray<FString> &PropsPaths,
692 FString &MapDestPath)
695 FAssetData AssetData;
697 LoadWorld(AssetData);
698 UObjectRedirector *BaseMapRedirector = Cast<UObjectRedirector>(AssetData.GetAsset());
699 if (BaseMapRedirector !=
nullptr) {
700 World = CastChecked<UWorld>(BaseMapRedirector->DestinationObject);
703 World = CastChecked<UWorld>(AssetData.GetAsset());
708 TArray<FString> PropPathDirs = PropsPaths;
710 for (
auto &PropPath : PropPathDirs)
712 PropPath.Split(TEXT(
"/"), &PropPath,
nullptr,
713 ESearchCase::Type::IgnoreCase, ESearchDir::Type::FromEnd);
717 TArray<AStaticMeshActor *> SpawnedActors = SpawnMeshesToWorld(PropPathDirs,
false);
719 const FString MapName(
"PropsMap");
720 SaveWorld(AssetData, PackageName, MapDestPath, MapName);
722 DestroySpawnedActorsInWorld(SpawnedActors);
726int32 UPrepareAssetsForCookingCommandlet::Main(
const FString &Params)
735 PrepareMapsForCooking(PackageParams.
Name, AssetsPaths.
MapsPaths);
739 FString PropsMapPath(
"");
743 PropsMapPath = TEXT(
"/Game/") + PackageParams.
Name + TEXT(
"/Maps/PropsMap");
744 PreparePropsForCooking(PackageParams.
Name, AssetsPaths.
PropsPaths, PropsMapPath);
748 GenerateMapPathsFile(AssetsPaths, PropsMapPath);
751 GeneratePackagePathFile(PackageParams.
Name);
755 UEditorLoadingAndSavingUtils::SaveDirtyPackages(
true,
true);
static bool ValidateStaticMesh(UStaticMesh *Mesh)
void SetTile0Offset(const FVector &Offset)
void SetTileSize(float Size)
void GenerateMap(FString InAssetsPath)
void RemoveRoutes()
Remove all the existing ARoutePlanner and VehicleSpawners previously generated by this class to avoid...
UMaterialInstance * RoadNodeMaterial
Workaround material for the RoadNode mesh
UMaterialInstance * CurbNodeMaterialInstance
Material to apply to curbs on the road
FString GetFirstPackagePath(const FString &PackageName) const
Gets the first .Package.json file found in Unreal Content Directory with PackageName
UPrepareAssetsForCookingCommandlet()
Default constructor.
UObjectLibrary * AssetsObjectLibrary
Used for loading assets in object library.
UWorld * World
Base map world loaded from Carla Content
UObjectLibrary * MapObjectLibrary
Used for loading maps in object library.
UMaterialInstance * GutterNodeMaterialInstance
Material to apply to gutters on the road
UMaterialInstance * MarkingNodeYellow
Workaround material for the center lane markings
UMaterialInstance * MarkingNodeWhite
Workaround material for exterior lane markings
TArray< FAssetData > AssetDatas
Loaded assets from any object library
UMaterialInstance * SidewalkNodeMaterialInstance
Workaround material for the SidewalkNodes
bool SavePackage(const FString &PackagePath, UPackage *Package) const
Saves Package in .umap format in path PackagePath inside Unreal Content folder
TArray< FAssetData > MapContents
Loaded map content from any object library
UMaterialInstance * TerrainNodeMaterialInstance
Workaround material for the TerrainNodes
carla::SharedPtr< cc::Actor > Actor
Struct containing all assets data read from .Package.json file.
TArray< FMapData > MapsPaths
TArray< FString > PropsPaths
Struct containing map data read from .Package.json file.
bool bUseCarlaMapMaterials
Struct containing Package with Name and bOnlyPrepareMaps flag used to separate the cooking of maps an...