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);
37 const FString MaterialName = Material->GetName();
39 if (MaterialName.Contains(TEXT(
"light"), ESearchCase::IgnoreCase) ||
40 MaterialName.Contains(TEXT(
"sign"), ESearchCase::IgnoreCase))
57 #if WITH_EDITORONLY_DATA 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'"));
84 #if WITH_EDITORONLY_DATA 86 FPackageParams UPrepareAssetsForCookingCommandlet::ParseParams(
const FString &InParams)
const 88 TArray<FString> Tokens;
89 TArray<FString> Params;
90 TMap<FString, FString> ParamVals;
92 ParseCommandLine(*InParams, Tokens, Params);
97 FParse::Value(*InParams, TEXT(
"PackageName="), PackageParams.
Name);
100 FParse::Bool(*InParams, TEXT(
"OnlyPrepareMaps="), PackageParams.
bOnlyPrepareMaps);
101 return PackageParams;
104 void UPrepareAssetsForCookingCommandlet::LoadWorld(FAssetData &AssetData)
107 const FString BaseMap = TEXT(
"/Game/Carla/Maps/BaseMap");
110 MapObjectLibrary = UObjectLibrary::CreateLibrary(UWorld::StaticClass(),
false, GIsEditor);
123 void UPrepareAssetsForCookingCommandlet::LoadWorldTile(FAssetData &AssetData)
126 const FString BaseTile = TEXT(
"/Game/Carla/Maps/TestMaps");
129 MapObjectLibrary = UObjectLibrary::CreateLibrary(UWorld::StaticClass(),
false, GIsEditor);
142 void UPrepareAssetsForCookingCommandlet::LoadLargeMapWorld(FAssetData &AssetData)
145 const FString BaseMap = TEXT(
"/Game/Carla/Maps/BaseLargeMap");
148 MapObjectLibrary = UObjectLibrary::CreateLibrary(UWorld::StaticClass(),
false, GIsEditor);
161 TArray<AStaticMeshActor *> UPrepareAssetsForCookingCommandlet::SpawnMeshesToWorld(
162 const TArray<FString> &AssetsPaths,
163 bool bUseCarlaMaterials,
167 TArray<AStaticMeshActor *> SpawnedMeshes;
170 const FTransform ZeroTransform = FTransform();
174 AssetsObjectLibrary = UObjectLibrary::CreateLibrary(UStaticMesh::StaticClass(),
false, GIsEditor);
181 UStaticMesh *MeshAsset;
182 AStaticMeshActor *MeshActor;
188 TileName = FString::Printf(TEXT(
"_Tile_%d_%d"), i, j);
196 MeshAsset = Cast<UStaticMesh>(MapAsset.GetAsset());
200 MapAsset.AssetName.ToString(AssetName);
203 if (i == -1 || (i != -1 && (AssetName.EndsWith(TileName) || AssetName.Contains(TileName +
"_"))))
205 MeshActor =
World->SpawnActor<AStaticMeshActor>(AStaticMeshActor::StaticClass(), ZeroTransform);
206 UStaticMeshComponent *MeshComponent = MeshActor->GetStaticMeshComponent();
207 MeshComponent->SetStaticMesh(CastChecked<UStaticMesh>(MeshAsset));
208 MeshActor->SetActorLabel(AssetName,
true);
211 UBodySetup *BodySetup = MeshAsset->BodySetup;
214 BodySetup->CollisionTraceFlag = CTF_UseComplexAsSimple;
215 MeshAsset->MarkPackageDirty();
218 SpawnedMeshes.Add(MeshActor);
220 if (bUseCarlaMaterials)
224 if (AssetName.Contains(SSTags::R_MARKING1) || AssetName.Contains(SSTags::R_MARKING2))
226 for (int32 i = 0; i < MeshActor->GetStaticMeshComponent()->GetStaticMesh()->StaticMaterials.Num(); ++i)
228 if (MeshActor->GetStaticMeshComponent()->GetStaticMesh()->StaticMaterials[i].ImportedMaterialSlotName.ToString().Contains(
"Yellow"))
238 else if (AssetName.Contains(SSTags::R_ROAD1) || AssetName.Contains(SSTags::R_ROAD2))
242 else if (AssetName.Contains(SSTags::R_TERRAIN))
245 MeshActor->GetStaticMeshComponent()->bReceivesDecals =
false;
247 else if (AssetName.Contains(SSTags::R_SIDEWALK1) || AssetName.Contains(SSTags::R_SIDEWALK2))
250 MeshActor->GetStaticMeshComponent()->bReceivesDecals =
false;
252 else if (AssetName.Contains(SSTags::R_CURB1) || AssetName.Contains(SSTags::R_CURB2)) {
255 MeshActor->GetStaticMeshComponent()->bReceivesDecals =
false;
257 else if (AssetName.Contains(SSTags::R_GUTTER1) || AssetName.Contains(SSTags::R_GUTTER2)) {
260 MeshActor->GetStaticMeshComponent()->bReceivesDecals =
false;
271 World->MarkPackageDirty();
273 return SpawnedMeshes;
276 bool UPrepareAssetsForCookingCommandlet::IsMapInTiles(
const TArray<FString> &AssetsPaths)
280 AssetsObjectLibrary = UObjectLibrary::CreateLibrary(UStaticMesh::StaticClass(),
false, GIsEditor);
287 UStaticMesh *MeshAsset;
291 for (
auto MapAsset : MapContents)
294 MeshAsset = Cast<UStaticMesh>(MapAsset.GetAsset());
298 MapAsset.AssetName.ToString(AssetName);
301 if (AssetName.Contains(
"_Tile_"))
315 void UPrepareAssetsForCookingCommandlet::DestroySpawnedActorsInWorld(
316 TArray<AStaticMeshActor *> &SpawnedActors)
319 for (
auto Actor : SpawnedActors)
325 World->MarkPackageDirty();
328 bool UPrepareAssetsForCookingCommandlet::SaveWorld(
329 FAssetData &AssetData,
330 const FString &PackageName,
331 const FString &DestPath,
332 const FString &WorldName,
333 bool bGenerateSpawnPoints)
336 UPackage *Package = AssetData.GetPackage();
337 Package->SetFolderName(*WorldName);
338 Package->FullyLoad();
339 Package->MarkPackageDirty();
340 FAssetRegistryModule::AssetCreated(
World);
344 const FString PackagePath = DestPath +
"/" + WorldName;
345 FAssetRegistryModule::AssetRenamed(
World, *PackagePath);
346 World->MarkPackageDirty();
347 World->GetOuter()->MarkPackageDirty();
350 const FString PathXODR = FPaths::ProjectContentDir() + PackageName + TEXT(
"/Maps/") +
351 WorldName + TEXT(
"/OpenDrive/") + WorldName + TEXT(
".xodr");
353 bool bPackageSaved =
false;
354 if (FPaths::FileExists(PathXODR) && bGenerateSpawnPoints)
358 World->SpawnActor(AOpenDriveActor::StaticClass(),
370 OpenWorldActor->Destroy();
377 return bPackageSaved;
383 TArray<FString> PackageList;
384 IFileManager::Get().FindFilesRecursive(PackageList, *(FPaths::ProjectContentDir()),
385 *(PackageName + TEXT(
".Package.json")),
true,
false,
false);
387 if (PackageList.Num() == 0)
389 UE_LOG(LogTemp, Error, TEXT(
"Package json file not found."));
393 return IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead(*PackageList[0]);
396 FAssetsPaths UPrepareAssetsForCookingCommandlet::GetAssetsPathFromPackage(
const FString &PackageName)
const 403 FString MapsFileJsonContent;
404 if (FFileHelper::LoadFileToString(MapsFileJsonContent, *PackageJsonFilePath))
406 TSharedPtr<FJsonObject> JsonParsed;
407 TSharedRef<TJsonReader<TCHAR>> JsonReader = TJsonReaderFactory<TCHAR>::Create(MapsFileJsonContent);
408 if (FJsonSerializer::Deserialize(JsonReader, JsonParsed))
411 auto MapsJsonArray = JsonParsed->GetArrayField(TEXT(
"maps"));
413 for (
auto &MapJsonValue : MapsJsonArray)
415 TSharedPtr<FJsonObject> MapJsonObject = MapJsonValue->AsObject();
418 MapData.
Name = MapJsonObject->GetStringField(TEXT(
"name"));
419 MapData.
Path = MapJsonObject->GetStringField(TEXT(
"path"));
422 AssetsPaths.
MapsPaths.Add(std::move(MapData));
426 auto PropJsonArray = JsonParsed->GetArrayField(TEXT(
"props"));
428 for (
auto &PropJsonValue : PropJsonArray)
430 TSharedPtr<FJsonObject> PropJsonObject = PropJsonValue->AsObject();
432 const FString PropAssetPath = PropJsonObject->GetStringField(TEXT(
"path"));
434 AssetsPaths.
PropsPaths.Add(std::move(PropAssetPath));
441 bool SaveStringTextToFile(
442 FString SaveDirectory,
445 bool bAllowOverWriting)
452 if (PlatformFile.CreateDirectoryTree(*SaveDirectory))
455 const FString AbsoluteFilePath = SaveDirectory +
"/" + FileName;
458 if (bAllowOverWriting || !PlatformFile.FileExists(*AbsoluteFilePath))
460 FFileHelper::SaveStringToFile(SaveText, *AbsoluteFilePath);
468 const FString PackageFileName = FPackageName::LongPackageNameToFilename(
470 FPackageName::GetMapPackageExtension());
472 if (FPaths::FileExists(*PackageFileName))
478 return UPackage::SavePackage(
481 EObjectFlags::RF_Public | EObjectFlags::RF_Standalone,
490 void UPrepareAssetsForCookingCommandlet::GenerateMapPathsFile(
492 const FString &PropsMapPath)
495 FString MapPathDataLinux;
497 for (
const auto &Map : AssetsPaths.
MapsPaths)
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);
506 for (FAssetData &AssetData : AssetsData)
508 FString AssetName = AssetData.AssetName.ToString();
509 if (AssetName.Contains(Map.Name +
"_Tile_"))
511 MapPathData.Append(Map.Path + TEXT(
"/") + AssetName + TEXT(
"\n"));
512 MapPathDataLinux.Append(Map.Path + TEXT(
"/") + AssetName + TEXT(
"+"));
516 UE_LOG(LogTemp, Warning, TEXT(
"Found %d tiles"), NumTiles);
519 if (!PropsMapPath.IsEmpty())
521 MapPathData.Append(PropsMapPath + TEXT(
"/PropsMap"));
522 MapPathDataLinux.Append(PropsMapPath + TEXT(
"/PropsMap"));
526 MapPathDataLinux.RemoveFromEnd(TEXT(
"+"));
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);
536 void UPrepareAssetsForCookingCommandlet::GeneratePackagePathFile(
const FString &PackageName)
538 FString SaveDirectory = FPaths::ProjectContentDir();
539 FString FileName = FString(
"PackagePath.txt");
541 SaveStringTextToFile(SaveDirectory, FileName, PackageJsonFilePath,
true);
544 void UPrepareAssetsForCookingCommandlet::PrepareMapsForCooking(
545 const FString &PackageName,
546 const TArray<FMapData> &MapsPaths)
548 FString BasePath = TEXT(
"/Game/") + PackageName + TEXT(
"/Static/");
550 for (
const auto &Map : MapsPaths)
552 const FString MapPath = TEXT(
"/") + Map.Name;
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;
561 TArray<FString> DataPath = {DefaultPath, RoadsPath, RoadLinesPath, TerrainPath, SidewalkPath};
564 if (!IsMapInTiles(DataPath))
566 UE_LOG(LogTemp, Log, TEXT(
"Cooking map"));
568 FAssetData AssetData;
569 LoadWorld(AssetData);
570 UObjectRedirector *BaseMapRedirector = Cast<UObjectRedirector>(AssetData.GetAsset());
571 if (BaseMapRedirector !=
nullptr) {
572 World = CastChecked<UWorld>(BaseMapRedirector->DestinationObject);
575 World = CastChecked<UWorld>(AssetData.GetAsset());
578 TArray<AStaticMeshActor *> SpawnedActors = SpawnMeshesToWorld(DataPath, Map.bUseCarlaMapMaterials, -1, -1);
580 SaveWorld(AssetData, PackageName, Map.Path, Map.Name);
582 DestroySpawnedActorsInWorld(SpawnedActors);
586 TArray<TPair<FString, FIntVector>> MapPathsIds;
588 FVector PositionTile0 = FVector();
589 float TileSize = 200000.f;
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) {
596 TxtFile.ParseIntoArray(Out, TEXT(
","),
true);
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]);
606 UE_LOG(LogTemp, Warning, TEXT(
"TilesInfo.txt format is invalid file"));
610 UE_LOG(LogTemp, Warning, TEXT(
"Could not find TilesInfo.txt file"));
613 UE_LOG(LogTemp, Log, TEXT(
"Cooking tiles:"));
615 FAssetData AssetData;
616 LoadWorldTile(AssetData);
617 UObjectRedirector *BaseMapRedirector = Cast<UObjectRedirector>(AssetData.GetAsset());
618 if (BaseMapRedirector !=
nullptr) {
619 World = CastChecked<UWorld>(BaseMapRedirector->DestinationObject);
622 World = CastChecked<UWorld>(AssetData.GetAsset());
634 TArray<AStaticMeshActor *> SpawnedActors = SpawnMeshesToWorld(DataPath, Map.bUseCarlaMapMaterials, i, j);
635 Res = SpawnedActors.Num() > 0;
638 UE_LOG(LogTemp, Log, TEXT(
" Tile %d,%d found"), i, j);
640 TileName = FString::Printf(TEXT(
"%s_Tile_%d_%d"), *Map.Name, i, j);
643 SaveWorld(AssetData, PackageName, Map.Path, TileName);
645 TPair<FString, FIntVector>(
646 Map.Path +
"/" + TileName, FIntVector(i, j, 0)));
648 DestroySpawnedActorsInWorld(SpawnedActors);
658 UEditorLoadingAndSavingUtils::SaveDirtyPackages(
true,
true);
661 LoadLargeMapWorld(AssetData);
662 BaseMapRedirector = Cast<UObjectRedirector>(AssetData.GetAsset());
663 if (BaseMapRedirector !=
nullptr) {
664 World = CastChecked<UWorld>(BaseMapRedirector->DestinationObject);
667 World = CastChecked<UWorld>(AssetData.GetAsset());
672 ALargeMapManager::StaticClass(), FTransform());
674 LargeMapManager->LargeMapName = Map.Name;
675 LargeMapManager->SetTile0Offset(PositionTile0);
676 LargeMapManager->SetTileSize(TileSize);
677 LargeMapManager->GenerateMap(MapPathsIds);
679 SaveWorld(AssetData, PackageName, Map.Path, Map.Name,
false);
681 UE_LOG(LogTemp, Log, TEXT(
"End cooking tiles"));
686 void UPrepareAssetsForCookingCommandlet::PreparePropsForCooking(
687 FString &PackageName,
688 const TArray<FString> &PropsPaths,
689 FString &MapDestPath)
692 FAssetData AssetData;
694 LoadWorld(AssetData);
695 UObjectRedirector *BaseMapRedirector = Cast<UObjectRedirector>(AssetData.GetAsset());
696 if (BaseMapRedirector !=
nullptr) {
697 World = CastChecked<UWorld>(BaseMapRedirector->DestinationObject);
700 World = CastChecked<UWorld>(AssetData.GetAsset());
705 TArray<FString> PropPathDirs = PropsPaths;
707 for (
auto &PropPath : PropPathDirs)
709 PropPath.Split(TEXT(
"/"), &PropPath,
nullptr,
710 ESearchCase::Type::IgnoreCase, ESearchDir::Type::FromEnd);
714 TArray<AStaticMeshActor *> SpawnedActors = SpawnMeshesToWorld(PropPathDirs,
false);
716 const FString MapName(
"PropsMap");
717 SaveWorld(AssetData, PackageName, MapDestPath, MapName);
719 DestroySpawnedActorsInWorld(SpawnedActors);
723 int32 UPrepareAssetsForCookingCommandlet::Main(
const FString &Params)
732 PrepareMapsForCooking(PackageParams.
Name, AssetsPaths.
MapsPaths);
736 FString PropsMapPath(
"");
740 PropsMapPath = TEXT(
"/Game/") + PackageParams.
Name + TEXT(
"/Maps/PropsMap");
741 PreparePropsForCooking(PackageParams.
Name, AssetsPaths.
PropsPaths, PropsMapPath);
745 GenerateMapPathsFile(AssetsPaths, PropsMapPath);
748 GeneratePackagePathFile(PackageParams.
Name);
752 UEditorLoadingAndSavingUtils::SaveDirtyPackages(
true,
true);
UMaterialInstance * RoadNodeMaterial
Workaround material for the RoadNode mesh.
TArray< FMapData > MapsPaths
UPrepareAssetsForCookingCommandlet()
Default constructor.
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.
TArray< FString > PropsPaths
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.
bool bUseCarlaMapMaterials
UMaterialInstance * GutterNodeMaterialInstance
Material to apply to gutters on the road.