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