CARLA
PrepareAssetsForCookingCommandlet.cpp
Go to the documentation of this file.
1 // Copyright (c) 2019 Computer Vision Center (CVC) at the Universitat Autonoma
2 // de Barcelona (UAB).
3 //
4 // This work is licensed under the terms of the MIT license.
5 // For a copy, see <https://opensource.org/licenses/MIT>.
6 
8 
9 #include "AssetRegistry/AssetRegistryModule.h"
10 
11 #include "SSTags.h"
12 
13 #if WITH_EDITOR
14 #include "FileHelpers.h"
15 #endif
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"
23 
24 static bool ValidateStaticMesh(UStaticMesh *Mesh)
25 {
26  const FString AssetName = Mesh->GetName();
27 
28  if (AssetName.Contains(TEXT("light"), ESearchCase::IgnoreCase) ||
29  AssetName.Contains(TEXT("sign"), ESearchCase::IgnoreCase))
30  {
31  return false;
32  }
33 
34  for (int i = 0; i < Mesh->StaticMaterials.Num(); i++)
35  {
36  UMaterialInterface *Material = Mesh->GetMaterial(i);
37  const FString MaterialName = Material->GetName();
38 
39  if (MaterialName.Contains(TEXT("light"), ESearchCase::IgnoreCase) ||
40  MaterialName.Contains(TEXT("sign"), ESearchCase::IgnoreCase))
41  {
42  return false;
43  }
44  }
45 
46  return true;
47 }
48 
50 {
51  // Set necessary flags to run commandlet
52  IsClient = false;
53  IsEditor = true;
54  IsServer = false;
55  LogToConsole = true;
56 
57 #if WITH_EDITORONLY_DATA
58  // Get Carla Default materials, these will be used for maps that need to use
59  // Carla materials
60  static ConstructorHelpers::FObjectFinder<UMaterialInstanceConstant> MarkingNodeYellowMaterial(TEXT(
61  "MaterialInstanceConstant'/Game/Carla/Static/GenericMaterials/RoadPainterMaterials/LargeMaps/M_Road_03_Tiled_V3.M_Road_03_Tiled_V3'"));
62  static ConstructorHelpers::FObjectFinder<UMaterialInstanceConstant> MarkingNodeWhiteMaterial(TEXT(
63  "MaterialInstanceConstant'/Game/Carla/Static/GenericMaterials/RoadPainterMaterials/M_Road_03_LMW.M_Road_03_LMW'"));
64  static ConstructorHelpers::FObjectFinder<UMaterialInstanceConstant> RoadNode(TEXT(
65  "MaterialInstanceConstant'/Game/Carla/Static/GenericMaterials/RoadPainterMaterials/LargeMaps/M_Road_03_Tiled_V2.M_Road_03_Tiled_V2'"));
66  static ConstructorHelpers::FObjectFinder<UMaterialInstanceConstant> TerrainNodeMaterial(TEXT(
67  "MaterialInstanceConstant'/Game/Carla/Static/GenericMaterials/00_MastersOpt/Large_Maps/materials/MI_LargeLandscape_Grass.MI_LargeLandscape_Grass'"));
68  static ConstructorHelpers::FObjectFinder<UMaterialInstanceConstant> CurbNodeMaterial(TEXT(
69  "MaterialInstanceConstant'/Game/Carla/Static/GenericMaterials/LargeMap_materials/largeM_curb/MI_largeM_curb01.MI_largeM_curb01'"));
70  static ConstructorHelpers::FObjectFinder<UMaterialInstanceConstant> GutterNodeMaterial(TEXT(
71  "MaterialInstanceConstant'/Game/Carla/Static/GenericMaterials/LargeMap_materials/largeM_gutter/MI_largeM_gutter01.MI_largeM_gutter01'"));
72  static ConstructorHelpers::FObjectFinder<UMaterialInstanceConstant> SidewalkNode(TEXT(
73  "MaterialInstanceConstant'/Game/Carla/Static/GenericMaterials/LargeMap_materials/largeM_sidewalk/tile01/MI_largeM_tile02.MI_largeM_tile02'"));
74 
75  GutterNodeMaterialInstance = (UMaterialInstance *) GutterNodeMaterial.Object;
76  CurbNodeMaterialInstance = (UMaterialInstance *) CurbNodeMaterial.Object;
77  TerrainNodeMaterialInstance = (UMaterialInstance *) TerrainNodeMaterial.Object;
78  MarkingNodeYellow = (UMaterialInstance *)MarkingNodeYellowMaterial.Object;
79  MarkingNodeWhite = (UMaterialInstance *)MarkingNodeWhiteMaterial.Object;
80  RoadNodeMaterial = (UMaterialInstance *) RoadNode.Object;
81  SidewalkNodeMaterialInstance = (UMaterialInstance *) SidewalkNode.Object;
82 #endif
83 }
84 #if WITH_EDITORONLY_DATA
85 
86 FPackageParams UPrepareAssetsForCookingCommandlet::ParseParams(const FString &InParams) const
87 {
88  TArray<FString> Tokens;
89  TArray<FString> Params;
90  TMap<FString, FString> ParamVals;
91 
92  ParseCommandLine(*InParams, Tokens, Params);
93 
94  FPackageParams PackageParams;
95 
96  // Parse and store Package name
97  FParse::Value(*InParams, TEXT("PackageName="), PackageParams.Name);
98 
99  // Parse and store flag for only preparing maps
100  FParse::Bool(*InParams, TEXT("OnlyPrepareMaps="), PackageParams.bOnlyPrepareMaps);
101  return PackageParams;
102 }
103 
104 void UPrepareAssetsForCookingCommandlet::LoadWorld(FAssetData &AssetData)
105 {
106  // BaseMap path inside Carla
107  const FString BaseMap = TEXT("/Game/Carla/Maps/BaseMap");
108 
109  // Load Map folder using object library
110  MapObjectLibrary = UObjectLibrary::CreateLibrary(UWorld::StaticClass(), false, GIsEditor);
111  MapObjectLibrary->AddToRoot();
112  MapObjectLibrary->LoadAssetDataFromPath(*BaseMap);
113  MapObjectLibrary->LoadAssetsFromAssetData();
114  MapObjectLibrary->GetAssetDataList(AssetDatas);
115 
116  if (AssetDatas.Num() > 0)
117  {
118  // Extract first asset found in folder path (i.e. the BaseMap)
119  AssetData = AssetDatas.Pop();
120  }
121 }
122 
123 void UPrepareAssetsForCookingCommandlet::LoadWorldTile(FAssetData &AssetData)
124 {
125  // BaseTile path inside Carla
126  const FString BaseTile = TEXT("/Game/Carla/Maps/TestMaps");
127 
128  // Load Map folder using object library
129  MapObjectLibrary = UObjectLibrary::CreateLibrary(UWorld::StaticClass(), false, GIsEditor);
130  MapObjectLibrary->AddToRoot();
131  MapObjectLibrary->LoadAssetDataFromPath(*BaseTile);
132  MapObjectLibrary->LoadAssetsFromAssetData();
133  MapObjectLibrary->GetAssetDataList(AssetDatas);
134 
135  if (AssetDatas.Num() > 0)
136  {
137  // Extract first asset found in folder path (i.e. the BaseTile)
138  AssetData = AssetDatas.Pop();
139  }
140 }
141 
142 void UPrepareAssetsForCookingCommandlet::LoadLargeMapWorld(FAssetData &AssetData)
143 {
144  // BaseMap path inside Carla
145  const FString BaseMap = TEXT("/Game/Carla/Maps/BaseLargeMap");
146 
147  // Load Map folder using object library
148  MapObjectLibrary = UObjectLibrary::CreateLibrary(UWorld::StaticClass(), false, GIsEditor);
149  MapObjectLibrary->AddToRoot();
150  MapObjectLibrary->LoadAssetDataFromPath(*BaseMap);
151  MapObjectLibrary->LoadAssetsFromAssetData();
152  MapObjectLibrary->GetAssetDataList(AssetDatas);
153 
154  if (AssetDatas.Num() > 0)
155  {
156  // Extract first asset found in folder path (i.e. the BaseMap)
157  AssetData = AssetDatas.Pop();
158  }
159 }
160 
161 TArray<AStaticMeshActor *> UPrepareAssetsForCookingCommandlet::SpawnMeshesToWorld(
162  const TArray<FString> &AssetsPaths,
163  bool bUseCarlaMaterials,
164  int i,
165  int j)
166 {
167  TArray<AStaticMeshActor *> SpawnedMeshes;
168 
169  // Create default Transform for all assets to spawn
170  const FTransform ZeroTransform = FTransform();
171 
172  // Load assets specified in AssetsPaths by using an object library
173  // for building map world
174  AssetsObjectLibrary = UObjectLibrary::CreateLibrary(UStaticMesh::StaticClass(), false, GIsEditor);
175  AssetsObjectLibrary->AddToRoot();
176  AssetsObjectLibrary->LoadAssetDataFromPaths(AssetsPaths);
177  AssetsObjectLibrary->LoadAssetsFromAssetData();
178  MapContents.Empty();
179  AssetsObjectLibrary->GetAssetDataList(MapContents);
180 
181  UStaticMesh *MeshAsset;
182  AStaticMeshActor *MeshActor;
183 
184  // name of current tile to cook
185  FString TileName;
186  if (i != -1)
187  {
188  TileName = FString::Printf(TEXT("_Tile_%d_%d"), i, j);
189  }
190 
191  // try to get the name of the map that precedes all assets name
192  FString AssetName;
193  for (auto MapAsset : MapContents)
194  {
195  // Spawn Static Mesh
196  MeshAsset = Cast<UStaticMesh>(MapAsset.GetAsset());
197  if (MeshAsset && ValidateStaticMesh(MeshAsset))
198  {
199  // get asset name
200  MapAsset.AssetName.ToString(AssetName);
201 
202  // check to ignore meshes from other tiles
203  if (i == -1 || (i != -1 && (AssetName.EndsWith(TileName) || AssetName.Contains(TileName + "_"))))
204  {
205  MeshActor = World->SpawnActor<AStaticMeshActor>(AStaticMeshActor::StaticClass(), ZeroTransform);
206  UStaticMeshComponent *MeshComponent = MeshActor->GetStaticMeshComponent();
207  MeshComponent->SetStaticMesh(CastChecked<UStaticMesh>(MeshAsset));
208  MeshActor->SetActorLabel(AssetName, true);
209 
210  // set complex collision as simple in asset
211  UBodySetup *BodySetup = MeshAsset->BodySetup;
212  if (BodySetup)
213  {
214  BodySetup->CollisionTraceFlag = CTF_UseComplexAsSimple;
215  MeshAsset->MarkPackageDirty();
216  }
217 
218  SpawnedMeshes.Add(MeshActor);
219 
220  if (bUseCarlaMaterials)
221  {
222  // Set Carla Materials depending on RoadRunner's Semantic Segmentation
223  // tag
224  if (AssetName.Contains(SSTags::R_MARKING1) || AssetName.Contains(SSTags::R_MARKING2))
225  {
226  for (int32 i = 0; i < MeshActor->GetStaticMeshComponent()->GetStaticMesh()->StaticMaterials.Num(); ++i)
227  {
228  if (MeshActor->GetStaticMeshComponent()->GetStaticMesh()->StaticMaterials[i].ImportedMaterialSlotName.ToString().Contains("Yellow"))
229  {
230  MeshActor->GetStaticMeshComponent()->SetMaterial(i, MarkingNodeYellow);
231  }
232  else
233  {
234  MeshActor->GetStaticMeshComponent()->SetMaterial(i, MarkingNodeWhite);
235  }
236  }
237  }
238  else if (AssetName.Contains(SSTags::R_ROAD1) || AssetName.Contains(SSTags::R_ROAD2))
239  {
240  MeshActor->GetStaticMeshComponent()->SetMaterial(0, RoadNodeMaterial);
241  }
242  else if (AssetName.Contains(SSTags::R_TERRAIN))
243  {
244  MeshActor->GetStaticMeshComponent()->SetMaterial(0, TerrainNodeMaterialInstance);
245  MeshActor->GetStaticMeshComponent()->bReceivesDecals = false;
246  }
247  else if (AssetName.Contains(SSTags::R_SIDEWALK1) || AssetName.Contains(SSTags::R_SIDEWALK2))
248  {
249  MeshActor->GetStaticMeshComponent()->SetMaterial(0, SidewalkNodeMaterialInstance);
250  MeshActor->GetStaticMeshComponent()->bReceivesDecals = false;
251  }
252  else if (AssetName.Contains(SSTags::R_CURB1) || AssetName.Contains(SSTags::R_CURB2)) {
253 
254  MeshActor->GetStaticMeshComponent()->SetMaterial(0, CurbNodeMaterialInstance);
255  MeshActor->GetStaticMeshComponent()->bReceivesDecals = false;
256  }
257  else if (AssetName.Contains(SSTags::R_GUTTER1) || AssetName.Contains(SSTags::R_GUTTER2)) {
258 
259  MeshActor->GetStaticMeshComponent()->SetMaterial(0, GutterNodeMaterialInstance);
260  MeshActor->GetStaticMeshComponent()->bReceivesDecals = false;
261  }
262  }
263  }
264  }
265  }
266 
267  // Clear loaded assets in library
268  AssetsObjectLibrary->ClearLoaded();
269 
270  // Mark package dirty
271  World->MarkPackageDirty();
272 
273  return SpawnedMeshes;
274 }
275 
276 bool UPrepareAssetsForCookingCommandlet::IsMapInTiles(const TArray<FString> &AssetsPaths)
277 {
278  // Load assets specified in AssetsPaths by using an object library
279  // for building map world
280  AssetsObjectLibrary = UObjectLibrary::CreateLibrary(UStaticMesh::StaticClass(), false, GIsEditor);
281  AssetsObjectLibrary->AddToRoot();
282  AssetsObjectLibrary->LoadAssetDataFromPaths(AssetsPaths);
283  AssetsObjectLibrary->LoadAssetsFromAssetData();
284  MapContents.Empty();
285  AssetsObjectLibrary->GetAssetDataList(MapContents);
286 
287  UStaticMesh *MeshAsset;
288 
289  FString AssetName;
290  bool Found = false;
291  for (auto MapAsset : MapContents)
292  {
293  // Spawn Static Mesh
294  MeshAsset = Cast<UStaticMesh>(MapAsset.GetAsset());
295  if (MeshAsset && ValidateStaticMesh(MeshAsset))
296  {
297  // get asset name
298  MapAsset.AssetName.ToString(AssetName);
299 
300  // check if the asset is a tile
301  if (AssetName.Contains("_Tile_"))
302  {
303  Found = true;
304  break;
305  }
306  }
307  }
308 
309  // Clear loaded assets in library
310  AssetsObjectLibrary->ClearLoaded();
311 
312  return Found;
313 }
314 
315 void UPrepareAssetsForCookingCommandlet::DestroySpawnedActorsInWorld(
316  TArray<AStaticMeshActor *> &SpawnedActors)
317 {
318  // Destroy all spawned actors
319  for (auto Actor : SpawnedActors)
320  {
321  Actor->Destroy();
322  }
323 
324  // Mark package dirty
325  World->MarkPackageDirty();
326 }
327 
328 bool UPrepareAssetsForCookingCommandlet::SaveWorld(
329  FAssetData &AssetData,
330  const FString &PackageName,
331  const FString &DestPath,
332  const FString &WorldName,
333  bool bGenerateSpawnPoints)
334 {
335  // Create Package to save
336  UPackage *Package = AssetData.GetPackage();
337  Package->SetFolderName(*WorldName);
338  Package->FullyLoad();
339  Package->MarkPackageDirty();
340  FAssetRegistryModule::AssetCreated(World);
341 
342  // Renaming map
343  World->Rename(*WorldName, World->GetOuter());
344  const FString PackagePath = DestPath + "/" + WorldName;
345  FAssetRegistryModule::AssetRenamed(World, *PackagePath);
346  World->MarkPackageDirty();
347  World->GetOuter()->MarkPackageDirty();
348 
349  // Check if OpenDrive file exists
350  const FString PathXODR = FPaths::ProjectContentDir() + PackageName + TEXT("/Maps/") +
351  WorldName + TEXT("/OpenDrive/") + WorldName + TEXT(".xodr");
352 
353  bool bPackageSaved = false;
354  if (FPaths::FileExists(PathXODR) && bGenerateSpawnPoints)
355  {
356  // We need to spawn OpenDrive assets before saving the map
357  AOpenDriveActor *OpenWorldActor = CastChecked<AOpenDriveActor>(
358  World->SpawnActor(AOpenDriveActor::StaticClass(),
359  new FVector(),
360  NULL));
361 
362  OpenWorldActor->BuildRoutes(WorldName);
363  OpenWorldActor->AddSpawners();
364 
365  bPackageSaved = SavePackage(PackagePath, Package);
366 
367  // We need to destroy OpenDrive assets once saved the map
368  OpenWorldActor->RemoveRoutes();
369  OpenWorldActor->RemoveSpawners();
370  OpenWorldActor->Destroy();
371  }
372  else
373  {
374  bPackageSaved = SavePackage(PackagePath, Package);
375  }
376 
377  return bPackageSaved;
378 }
379 
380 FString UPrepareAssetsForCookingCommandlet::GetFirstPackagePath(const FString &PackageName) const
381 {
382  // Get all Package names
383  TArray<FString> PackageList;
384  IFileManager::Get().FindFilesRecursive(PackageList, *(FPaths::ProjectContentDir()),
385  *(PackageName + TEXT(".Package.json")), true, false, false);
386 
387  if (PackageList.Num() == 0)
388  {
389  UE_LOG(LogTemp, Error, TEXT("Package json file not found."));
390  return {};
391  }
392 
393  return IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead(*PackageList[0]);
394 }
395 
396 FAssetsPaths UPrepareAssetsForCookingCommandlet::GetAssetsPathFromPackage(const FString &PackageName) const
397 {
398  const FString PackageJsonFilePath = GetFirstPackagePath(PackageName);
399 
400  FAssetsPaths AssetsPaths;
401 
402  // Get All Maps Path
403  FString MapsFileJsonContent;
404  if (FFileHelper::LoadFileToString(MapsFileJsonContent, *PackageJsonFilePath))
405  {
406  TSharedPtr<FJsonObject> JsonParsed;
407  TSharedRef<TJsonReader<TCHAR>> JsonReader = TJsonReaderFactory<TCHAR>::Create(MapsFileJsonContent);
408  if (FJsonSerializer::Deserialize(JsonReader, JsonParsed))
409  {
410  // Add Maps Path
411  auto MapsJsonArray = JsonParsed->GetArrayField(TEXT("maps"));
412 
413  for (auto &MapJsonValue : MapsJsonArray)
414  {
415  TSharedPtr<FJsonObject> MapJsonObject = MapJsonValue->AsObject();
416 
417  FMapData MapData;
418  MapData.Name = MapJsonObject->GetStringField(TEXT("name"));
419  MapData.Path = MapJsonObject->GetStringField(TEXT("path"));
420  MapData.bUseCarlaMapMaterials = MapJsonObject->GetBoolField(TEXT("use_carla_materials"));
421 
422  AssetsPaths.MapsPaths.Add(std::move(MapData));
423  }
424 
425  // Add Props Path
426  auto PropJsonArray = JsonParsed->GetArrayField(TEXT("props"));
427 
428  for (auto &PropJsonValue : PropJsonArray)
429  {
430  TSharedPtr<FJsonObject> PropJsonObject = PropJsonValue->AsObject();
431 
432  const FString PropAssetPath = PropJsonObject->GetStringField(TEXT("path"));
433 
434  AssetsPaths.PropsPaths.Add(std::move(PropAssetPath));
435  }
436  }
437  }
438  return AssetsPaths;
439 }
440 
441 bool SaveStringTextToFile(
442  FString SaveDirectory,
443  FString FileName,
444  FString SaveText,
445  bool bAllowOverWriting)
446 {
447  IPlatformFile &PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
448 
449  // CreateDirectoryTree returns true if the destination
450  // directory existed prior to call or has been created
451  // during the call.
452  if (PlatformFile.CreateDirectoryTree(*SaveDirectory))
453  {
454  // Get absolute file path
455  const FString AbsoluteFilePath = SaveDirectory + "/" + FileName;
456 
457  // Allow overwriting or file doesn't already exist
458  if (bAllowOverWriting || !PlatformFile.FileExists(*AbsoluteFilePath))
459  {
460  FFileHelper::SaveStringToFile(SaveText, *AbsoluteFilePath);
461  }
462  }
463  return true;
464 }
465 
466 bool UPrepareAssetsForCookingCommandlet::SavePackage(const FString &PackagePath, UPackage *Package) const
467 {
468  const FString PackageFileName = FPackageName::LongPackageNameToFilename(
469  PackagePath,
470  FPackageName::GetMapPackageExtension());
471 
472  if (FPaths::FileExists(*PackageFileName))
473  {
474  // Will not save package if it already exists
475  return false;
476  }
477 
478  return UPackage::SavePackage(
479  Package,
480  World,
481  EObjectFlags::RF_Public | EObjectFlags::RF_Standalone,
482  *PackageFileName,
483  GError,
484  nullptr,
485  true,
486  true,
487  SAVE_NoError);
488 }
489 
490 void UPrepareAssetsForCookingCommandlet::GenerateMapPathsFile(
491  const FAssetsPaths &AssetsPaths,
492  const FString &PropsMapPath)
493 {
494  FString MapPathData;
495  FString MapPathDataLinux;
496  IFileManager &FileManager = IFileManager::Get();
497  for (const auto &Map : AssetsPaths.MapsPaths)
498  {
499  MapPathData.Append(Map.Path + TEXT("/") + Map.Name + TEXT("\n"));
500  MapPathDataLinux.Append(Map.Path + TEXT("/") + Map.Name + TEXT("+"));
501  TArray<FAssetData> AssetsData;
502  UObjectLibrary* ObjectLibrary = UObjectLibrary::CreateLibrary(UWorld::StaticClass(), true, true);
503  ObjectLibrary->LoadAssetDataFromPath(Map.Path);
504  ObjectLibrary->GetAssetDataList(AssetsData);
505  int NumTiles = 0;
506  for (FAssetData &AssetData : AssetsData)
507  {
508  FString AssetName = AssetData.AssetName.ToString();
509  if (AssetName.Contains(Map.Name + "_Tile_"))
510  {
511  MapPathData.Append(Map.Path + TEXT("/") + AssetName + TEXT("\n"));
512  MapPathDataLinux.Append(Map.Path + TEXT("/") + AssetName + TEXT("+"));
513  NumTiles++;
514  }
515  }
516  UE_LOG(LogTemp, Warning, TEXT("Found %d tiles"), NumTiles);
517  }
518 
519  if (!PropsMapPath.IsEmpty())
520  {
521  MapPathData.Append(PropsMapPath + TEXT("/PropsMap"));
522  MapPathDataLinux.Append(PropsMapPath + TEXT("/PropsMap"));
523  }
524  else
525  {
526  MapPathDataLinux.RemoveFromEnd(TEXT("+"));
527  }
528 
529  const FString SaveDirectory = FPaths::ProjectContentDir();
530  const FString FileName = FString("MapPaths.txt");
531  const FString FileNameLinux = FString("MapPathsLinux.txt");
532  SaveStringTextToFile(SaveDirectory, FileName, MapPathData, true);
533  SaveStringTextToFile(SaveDirectory, FileNameLinux, MapPathDataLinux, true);
534 }
535 
536 void UPrepareAssetsForCookingCommandlet::GeneratePackagePathFile(const FString &PackageName)
537 {
538  FString SaveDirectory = FPaths::ProjectContentDir();
539  FString FileName = FString("PackagePath.txt");
540  FString PackageJsonFilePath = GetFirstPackagePath(PackageName);
541  SaveStringTextToFile(SaveDirectory, FileName, PackageJsonFilePath, true);
542 }
543 
544 void UPrepareAssetsForCookingCommandlet::PrepareMapsForCooking(
545  const FString &PackageName,
546  const TArray<FMapData> &MapsPaths)
547 {
548  FString BasePath = TEXT("/Game/") + PackageName + TEXT("/Static/");
549 
550  for (const auto &Map : MapsPaths)
551  {
552  const FString MapPath = TEXT("/") + Map.Name;
553 
554  const FString DefaultPath = TEXT("/Game/") + PackageName + TEXT("/Maps/") + Map.Name;
555  const FString RoadsPath = BasePath + SSTags::ROAD + MapPath;
556  const FString RoadLinesPath = BasePath + SSTags::ROADLINE + MapPath;
557  const FString TerrainPath = BasePath + SSTags::TERRAIN + MapPath;
558  const FString SidewalkPath = BasePath + SSTags::SIDEWALK + MapPath;
559 
560  // Spawn assets located in semantic segmentation folders
561  TArray<FString> DataPath = {DefaultPath, RoadsPath, RoadLinesPath, TerrainPath, SidewalkPath};
562 
563  // check whether we have a single map or a map in tiles
564  if (!IsMapInTiles(DataPath))
565  {
566  UE_LOG(LogTemp, Log, TEXT("Cooking map"));
567  // Load World
568  FAssetData AssetData;
569  LoadWorld(AssetData);
570  UObjectRedirector *BaseMapRedirector = Cast<UObjectRedirector>(AssetData.GetAsset());
571  if (BaseMapRedirector != nullptr) {
572  World = CastChecked<UWorld>(BaseMapRedirector->DestinationObject);
573  }
574  else {
575  World = CastChecked<UWorld>(AssetData.GetAsset());
576  }
577  // try to cook the whole map (no tiles)
578  TArray<AStaticMeshActor *> SpawnedActors = SpawnMeshesToWorld(DataPath, Map.bUseCarlaMapMaterials, -1, -1);
579  // Save the World in specified path
580  SaveWorld(AssetData, PackageName, Map.Path, Map.Name);
581  // Remove spawned actors from world to keep equal as BaseMap
582  DestroySpawnedActorsInWorld(SpawnedActors);
583  }
584  else
585  {
586  TArray<TPair<FString, FIntVector>> MapPathsIds;
587 
588  FVector PositionTile0 = FVector();
589  float TileSize = 200000.f;
590  FString TxtFile;
591  FString TilesInfoPath = FPaths::ProjectContentDir() + PackageName + TEXT("/Maps/") + Map.Name + "/TilesInfo.txt";
592  UE_LOG(LogTemp, Warning, TEXT("Loading %s ..."), *TilesInfoPath);
593  if (FFileHelper::LoadFileToString(TxtFile, *(TilesInfoPath)) == true) {
594 
595  TArray<FString> Out;
596  TxtFile.ParseIntoArray(Out, TEXT(","), true);
597  if (Out.Num() >= 3)
598  {
599  const float METERSTOCM = 100.f;
600  PositionTile0.X = METERSTOCM * FCString::Atof(*Out[0]);
601  PositionTile0.Y = METERSTOCM * FCString::Atof(*Out[1]);
602  TileSize = METERSTOCM * FCString::Atof(*Out[2]);
603  }
604  else
605  {
606  UE_LOG(LogTemp, Warning, TEXT("TilesInfo.txt format is invalid file"));
607  }
608  }
609  else {
610  UE_LOG(LogTemp, Warning, TEXT("Could not find TilesInfo.txt file"));
611  }
612 
613  UE_LOG(LogTemp, Log, TEXT("Cooking tiles:"));
614  // Load World
615  FAssetData AssetData;
616  LoadWorldTile(AssetData);
617  UObjectRedirector *BaseMapRedirector = Cast<UObjectRedirector>(AssetData.GetAsset());
618  if (BaseMapRedirector != nullptr) {
619  World = CastChecked<UWorld>(BaseMapRedirector->DestinationObject);
620  }
621  else {
622  World = CastChecked<UWorld>(AssetData.GetAsset());
623  }
624  // try to create each possible tile of the map
625  int i, j;
626  bool Res;
627  j = 0;
628  do
629  {
630  i = 0;
631  do
632  {
633  // Spawn
634  TArray<AStaticMeshActor *> SpawnedActors = SpawnMeshesToWorld(DataPath, Map.bUseCarlaMapMaterials, i, j);
635  Res = SpawnedActors.Num() > 0;
636  if (Res)
637  {
638  UE_LOG(LogTemp, Log, TEXT(" Tile %d,%d found"), i, j);
639  FString TileName;
640  TileName = FString::Printf(TEXT("%s_Tile_%d_%d"), *Map.Name, i, j);
641  // Save the World in specified path
642  // UE_LOG(LogTemp, Log, TEXT("Saving as %s to %s"), *TileName, *Map.Path);
643  SaveWorld(AssetData, PackageName, Map.Path, TileName);
644  MapPathsIds.Add(
645  TPair<FString, FIntVector>(
646  Map.Path + "/" + TileName, FIntVector(i, j, 0)));
647  // Remove spawned actors from world to keep equal as BaseMap
648  DestroySpawnedActorsInWorld(SpawnedActors);
649  ++i;
650  }
651  }
652  while (Res);
653  ++j;
654  }
655  while (i > 0);
656 
657  #if WITH_EDITOR
658  UEditorLoadingAndSavingUtils::SaveDirtyPackages(true, true);
659  #endif
660  // Load base map for tiled maps
661  LoadLargeMapWorld(AssetData);
662  BaseMapRedirector = Cast<UObjectRedirector>(AssetData.GetAsset());
663  if (BaseMapRedirector != nullptr) {
664  World = CastChecked<UWorld>(BaseMapRedirector->DestinationObject);
665  }
666  else {
667  World = CastChecked<UWorld>(AssetData.GetAsset());
668  }
669 
670  // Generate Large Map Manager
671  ALargeMapManager* LargeMapManager = World->SpawnActor<ALargeMapManager>(
672  ALargeMapManager::StaticClass(), FTransform());
673  LargeMapManager->LargeMapTilePath = Map.Path;
674  LargeMapManager->LargeMapName = Map.Name;
675  LargeMapManager->SetTile0Offset(PositionTile0);
676  LargeMapManager->SetTileSize(TileSize);
677  LargeMapManager->GenerateMap(MapPathsIds);
678 
679  SaveWorld(AssetData, PackageName, Map.Path, Map.Name, false);
680 
681  UE_LOG(LogTemp, Log, TEXT("End cooking tiles"));
682  }
683  }
684 }
685 
686 void UPrepareAssetsForCookingCommandlet::PreparePropsForCooking(
687  FString &PackageName,
688  const TArray<FString> &PropsPaths,
689  FString &MapDestPath)
690 {
691  // Load World
692  FAssetData AssetData;
693  // Loads the BaseMap
694  LoadWorld(AssetData);
695  UObjectRedirector *BaseMapRedirector = Cast<UObjectRedirector>(AssetData.GetAsset());
696  if (BaseMapRedirector != nullptr) {
697  World = CastChecked<UWorld>(BaseMapRedirector->DestinationObject);
698  }
699  else {
700  World = CastChecked<UWorld>(AssetData.GetAsset());
701  }
702 
703  // Remove the meshes names from the original path for props, so we can load
704  // props inside folder
705  TArray<FString> PropPathDirs = PropsPaths;
706 
707  for (auto &PropPath : PropPathDirs)
708  {
709  PropPath.Split(TEXT("/"), &PropPath, nullptr,
710  ESearchCase::Type::IgnoreCase, ESearchDir::Type::FromEnd);
711  }
712 
713  // Add props in a single Base Map
714  TArray<AStaticMeshActor *> SpawnedActors = SpawnMeshesToWorld(PropPathDirs, false);
715 
716  const FString MapName("PropsMap");
717  SaveWorld(AssetData, PackageName, MapDestPath, MapName);
718 
719  DestroySpawnedActorsInWorld(SpawnedActors);
720  MapObjectLibrary->ClearLoaded();
721 }
722 
723 int32 UPrepareAssetsForCookingCommandlet::Main(const FString &Params)
724 {
725  FPackageParams PackageParams = ParseParams(Params);
726 
727  // Get Props and Maps Path
728  FAssetsPaths AssetsPaths = GetAssetsPathFromPackage(PackageParams.Name);
729 
730  if (PackageParams.bOnlyPrepareMaps)
731  {
732  PrepareMapsForCooking(PackageParams.Name, AssetsPaths.MapsPaths);
733  }
734  else
735  {
736  FString PropsMapPath("");
737 
738  if (AssetsPaths.PropsPaths.Num() > 0)
739  {
740  PropsMapPath = TEXT("/Game/") + PackageParams.Name + TEXT("/Maps/PropsMap");
741  PreparePropsForCooking(PackageParams.Name, AssetsPaths.PropsPaths, PropsMapPath);
742  }
743 
744  // Save Map Path File for further use
745  GenerateMapPathsFile(AssetsPaths, PropsMapPath);
746 
747  // Saves Package path for further use
748  GeneratePackagePathFile(PackageParams.Name);
749  }
750 
751 #if WITH_EDITOR
752  UEditorLoadingAndSavingUtils::SaveDirtyPackages(true, true);
753 #endif
754 
755  return 0;
756 }
757 #endif
UMaterialInstance * RoadNodeMaterial
Workaround material for the RoadNode mesh.
Struct containing Package with Name and bOnlyPrepareMaps flag used to separate the cooking of maps an...
UMaterialInstance * SidewalkNodeMaterialInstance
Workaround material for the SidewalkNodes.
UMaterialInstance * TerrainNodeMaterialInstance
Workaround material for the TerrainNodes.
Struct containing map data read from .Package.json file.
static T Get(carla::rpc::Response< T > &response)
void RemoveRoutes()
Remove all the existing ARoutePlanner and VehicleSpawners previously generated by this class to avoid...
Struct containing all assets data read from .Package.json file.
FString GetFirstPackagePath(const FString &PackageName) const
Gets the first .Package.json file found in Unreal Content Directory with PackageName.
carla::SharedPtr< cc::Actor > Actor
TArray< FAssetData > MapContents
Loaded map content from any object library.
UObjectLibrary * AssetsObjectLibrary
Used for loading assets in object library.
bool SavePackage(const FString &PackagePath, UPackage *Package) const
Saves Package in .umap format in path PackagePath inside Unreal Content folder.
static bool ValidateStaticMesh(UStaticMesh *Mesh)
UMaterialInstance * CurbNodeMaterialInstance
Material to apply to curbs on the road.
TArray< FAssetData > AssetDatas
Loaded assets from any object library.
UMaterialInstance * MarkingNodeYellow
Workaround material for the center lane markings.
UWorld * World
Base map world loaded from Carla Content.
UMaterialInstance * MarkingNodeWhite
Workaround material for exterior lane markings.
UObjectLibrary * MapObjectLibrary
Used for loading maps in object library.
UMaterialInstance * GutterNodeMaterialInstance
Material to apply to gutters on the road.