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"
28 const FString AssetName = Mesh->GetName();
31 if (AssetName.Contains(TEXT(
"light"), ESearchCase::IgnoreCase) ||
32 AssetName.Contains(TEXT(
"sign"), ESearchCase::IgnoreCase))
39 for (
int i = 0; i < Mesh->StaticMaterials.Num(); i++)
42 UMaterialInterface *Material = Mesh->GetMaterial(i);
45 Material = UMaterial::GetDefaultMaterial(MD_Surface);
48 const FString MaterialName = Material->GetName();
51 if (MaterialName.Contains(TEXT(
"light"), ESearchCase::IgnoreCase) ||
52 MaterialName.Contains(TEXT(
"sign"), ESearchCase::IgnoreCase))
71#if WITH_EDITORONLY_DATA
74 static ConstructorHelpers::FObjectFinder<UMaterialInstanceConstant> MarkingNodeYellowMaterial(TEXT(
75 "MaterialInstanceConstant'/Game/Carla/Static/GenericMaterials/RoadPainterMaterials/LargeMaps/M_Road_03_Tiled_V3.M_Road_03_Tiled_V3'"));
76 static ConstructorHelpers::FObjectFinder<UMaterialInstanceConstant> MarkingNodeWhiteMaterial(TEXT(
77 "MaterialInstanceConstant'/Game/Carla/Static/GenericMaterials/RoadPainterMaterials/M_Road_03_LMW.M_Road_03_LMW'"));
78 static ConstructorHelpers::FObjectFinder<UMaterialInstanceConstant> RoadNode(TEXT(
79 "MaterialInstanceConstant'/Game/Carla/Static/GenericMaterials/RoadPainterMaterials/LargeMaps/M_Road_03_Tiled_V2.M_Road_03_Tiled_V2'"));
80 static ConstructorHelpers::FObjectFinder<UMaterialInstanceConstant> TerrainNodeMaterial(TEXT(
81 "MaterialInstanceConstant'/Game/Carla/Static/GenericMaterials/00_MastersOpt/Large_Maps/materials/MI_LargeLandscape_Grass.MI_LargeLandscape_Grass'"));
82 static ConstructorHelpers::FObjectFinder<UMaterialInstanceConstant> CurbNodeMaterial(TEXT(
83 "MaterialInstanceConstant'/Game/Carla/Static/GenericMaterials/LargeMap_materials/largeM_curb/MI_largeM_curb01.MI_largeM_curb01'"));
84 static ConstructorHelpers::FObjectFinder<UMaterialInstanceConstant> GutterNodeMaterial(TEXT(
85 "MaterialInstanceConstant'/Game/Carla/Static/GenericMaterials/LargeMap_materials/largeM_gutter/MI_largeM_gutter01.MI_largeM_gutter01'"));
86 static ConstructorHelpers::FObjectFinder<UMaterialInstanceConstant> SidewalkNode(TEXT(
87 "MaterialInstanceConstant'/Game/Carla/Static/GenericMaterials/LargeMap_materials/largeM_sidewalk/tile01/MI_largeM_tile02.MI_largeM_tile02'"));
98#if WITH_EDITORONLY_DATA
100FPackageParams UPrepareAssetsForCookingCommandlet::ParseParams(
const FString &InParams)
const
102 TArray<FString> Tokens;
103 TArray<FString> Params;
104 TMap<FString, FString> ParamVals;
106 ParseCommandLine(*InParams, Tokens, Params);
111 FParse::Value(*InParams, TEXT(
"PackageName="), PackageParams.
Name);
114 FParse::Bool(*InParams, TEXT(
"OnlyPrepareMaps="), PackageParams.
bOnlyPrepareMaps);
115 return PackageParams;
118void UPrepareAssetsForCookingCommandlet::LoadWorld(FAssetData &AssetData)
121 const FString BaseMap = TEXT(
"/Game/Carla/Maps/BaseMap");
124 MapObjectLibrary = UObjectLibrary::CreateLibrary(UWorld::StaticClass(),
false, GIsEditor);
137void UPrepareAssetsForCookingCommandlet::LoadWorldTile(FAssetData &AssetData)
140 const FString BaseTile = TEXT(
"/Game/Carla/Maps/TestMaps");
143 MapObjectLibrary = UObjectLibrary::CreateLibrary(UWorld::StaticClass(),
false, GIsEditor);
156void UPrepareAssetsForCookingCommandlet::LoadLargeMapWorld(FAssetData &AssetData)
159 const FString BaseMap = TEXT(
"/Game/Carla/Maps/BaseLargeMap");
162 MapObjectLibrary = UObjectLibrary::CreateLibrary(UWorld::StaticClass(),
false, GIsEditor);
175TArray<AStaticMeshActor *> UPrepareAssetsForCookingCommandlet::SpawnMeshesToWorld(
176 const TArray<FString> &AssetsPaths,
177 bool bUseCarlaMaterials,
181 TArray<AStaticMeshActor *> SpawnedMeshes;
184 const FTransform ZeroTransform = FTransform();
188 AssetsObjectLibrary = UObjectLibrary::CreateLibrary(UStaticMesh::StaticClass(),
false, GIsEditor);
195 UStaticMesh *MeshAsset;
196 AStaticMeshActor *MeshActor;
202 TileName = FString::Printf(TEXT(
"_Tile_%d_%d"), i, j);
210 MeshAsset = Cast<UStaticMesh>(MapAsset.GetAsset());
214 MapAsset.AssetName.ToString(AssetName);
217 if (i == -1 || (i != -1 && (AssetName.EndsWith(TileName) || AssetName.Contains(TileName +
"_"))))
219 MeshActor =
World->SpawnActor<AStaticMeshActor>(AStaticMeshActor::StaticClass(), ZeroTransform);
220 UStaticMeshComponent *MeshComponent = MeshActor->GetStaticMeshComponent();
221 MeshComponent->SetStaticMesh(CastChecked<UStaticMesh>(MeshAsset));
222 MeshActor->SetActorLabel(AssetName,
true);
225 UBodySetup *BodySetup = MeshAsset->BodySetup;
228 BodySetup->CollisionTraceFlag = CTF_UseComplexAsSimple;
229 MeshAsset->MarkPackageDirty();
232 SpawnedMeshes.Add(MeshActor);
234 if (bUseCarlaMaterials)
238 if (AssetName.Contains(SSTags::R_MARKING1) || AssetName.Contains(SSTags::R_MARKING2))
240 for (int32 i = 0; i < MeshActor->GetStaticMeshComponent()->GetStaticMesh()->StaticMaterials.Num(); ++i)
242 if (MeshActor->GetStaticMeshComponent()->GetStaticMesh()->StaticMaterials[i].ImportedMaterialSlotName.ToString().Contains(
"Yellow"))
252 else if (AssetName.Contains(SSTags::R_ROAD1) || AssetName.Contains(SSTags::R_ROAD2))
256 else if (AssetName.Contains(SSTags::R_TERRAIN))
259 MeshActor->GetStaticMeshComponent()->bReceivesDecals =
false;
261 else if (AssetName.Contains(SSTags::R_SIDEWALK1) || AssetName.Contains(SSTags::R_SIDEWALK2))
264 MeshActor->GetStaticMeshComponent()->bReceivesDecals =
false;
266 else if (AssetName.Contains(SSTags::R_CURB1) || AssetName.Contains(SSTags::R_CURB2)) {
269 MeshActor->GetStaticMeshComponent()->bReceivesDecals =
false;
271 else if (AssetName.Contains(SSTags::R_GUTTER1) || AssetName.Contains(SSTags::R_GUTTER2)) {
274 MeshActor->GetStaticMeshComponent()->bReceivesDecals =
false;
285 World->MarkPackageDirty();
287 return SpawnedMeshes;
290bool UPrepareAssetsForCookingCommandlet::IsMapInTiles(
const TArray<FString> &AssetsPaths)
294 AssetsObjectLibrary = UObjectLibrary::CreateLibrary(UStaticMesh::StaticClass(),
false, GIsEditor);
301 UStaticMesh *MeshAsset;
308 MeshAsset = Cast<UStaticMesh>(MapAsset.GetAsset());
312 MapAsset.AssetName.ToString(AssetName);
315 if (AssetName.Contains(
"_Tile_"))
329void UPrepareAssetsForCookingCommandlet::DestroySpawnedActorsInWorld(
330 TArray<AStaticMeshActor *> &SpawnedActors)
333 for (
auto Actor : SpawnedActors)
339 World->MarkPackageDirty();
342bool UPrepareAssetsForCookingCommandlet::SaveWorld(
343 FAssetData &AssetData,
344 const FString &PackageName,
345 const FString &DestPath,
346 const FString &WorldName,
347 bool bGenerateSpawnPoints)
350 UPackage *Package = AssetData.GetPackage();
351 Package->SetFolderName(*WorldName);
352 Package->FullyLoad();
353 Package->MarkPackageDirty();
354 FAssetRegistryModule::AssetCreated(
World);
358 const FString PackagePath = DestPath +
"/" + WorldName;
359 FAssetRegistryModule::AssetRenamed(
World, *PackagePath);
360 World->MarkPackageDirty();
361 World->GetOuter()->MarkPackageDirty();
364 const FString PathXODR = FPaths::ProjectContentDir() + PackageName + TEXT(
"/Maps/") +
365 WorldName + TEXT(
"/OpenDrive/") + WorldName + TEXT(
".xodr");
367 bool bPackageSaved =
false;
368 if (FPaths::FileExists(PathXODR) && bGenerateSpawnPoints)
372 World->SpawnActor(AOpenDriveActor::StaticClass(),
384 OpenWorldActor->Destroy();
391 return bPackageSaved;
397 TArray<FString> PackageList;
398 IFileManager::Get().FindFilesRecursive(PackageList, *(FPaths::ProjectContentDir()),
399 *(PackageName + TEXT(
".Package.json")),
true,
false,
false);
401 if (PackageList.Num() == 0)
403 UE_LOG(LogTemp, Error, TEXT(
"Package json file not found."));
407 return IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead(*PackageList[0]);
410FAssetsPaths UPrepareAssetsForCookingCommandlet::GetAssetsPathFromPackage(
const FString &PackageName)
const
417 FString MapsFileJsonContent;
418 if (FFileHelper::LoadFileToString(MapsFileJsonContent, *PackageJsonFilePath))
420 TSharedPtr<FJsonObject> JsonParsed;
421 TSharedRef<TJsonReader<TCHAR>> JsonReader = TJsonReaderFactory<TCHAR>::Create(MapsFileJsonContent);
422 if (FJsonSerializer::Deserialize(JsonReader, JsonParsed))
425 auto MapsJsonArray = JsonParsed->GetArrayField(TEXT(
"maps"));
427 for (
auto &MapJsonValue : MapsJsonArray)
429 TSharedPtr<FJsonObject> MapJsonObject = MapJsonValue->AsObject();
432 MapData.
Name = MapJsonObject->GetStringField(TEXT(
"name"));
433 MapData.
Path = MapJsonObject->GetStringField(TEXT(
"path"));
436 AssetsPaths.
MapsPaths.Add(std::move(MapData));
440 auto PropJsonArray = JsonParsed->GetArrayField(TEXT(
"props"));
442 for (
auto &PropJsonValue : PropJsonArray)
444 TSharedPtr<FJsonObject> PropJsonObject = PropJsonValue->AsObject();
446 const FString PropAssetPath = PropJsonObject->GetStringField(TEXT(
"path"));
448 AssetsPaths.
PropsPaths.Add(std::move(PropAssetPath));
455bool SaveStringTextToFile(
456 FString SaveDirectory,
459 bool bAllowOverWriting)
461 IPlatformFile &PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
466 if (PlatformFile.CreateDirectoryTree(*SaveDirectory))
469 const FString AbsoluteFilePath = SaveDirectory +
"/" + FileName;
472 if (bAllowOverWriting || !PlatformFile.FileExists(*AbsoluteFilePath))
474 FFileHelper::SaveStringToFile(SaveText, *AbsoluteFilePath);
482 const FString PackageFileName = FPackageName::LongPackageNameToFilename(
484 FPackageName::GetMapPackageExtension());
486 if (FPaths::FileExists(*PackageFileName))
492 return UPackage::SavePackage(
495 EObjectFlags::RF_Public | EObjectFlags::RF_Standalone,
505void UPrepareAssetsForCookingCommandlet::GenerateMapPathsFile(
507 const FString &PropsMapPath)
511 FString MapPathDataLinux;
513 IFileManager &FileManager = IFileManager::Get();
515 for (
const auto &
Map : AssetsPaths.MapsPaths)
518 MapPathData.Append(
Map.Path + TEXT(
"/") +
Map.Name + TEXT(
"\n"));
519 MapPathDataLinux.Append(
Map.Path + TEXT(
"/") +
Map.Name + TEXT(
"+"));
521 TArray<FAssetData> AssetsData;
522 UObjectLibrary* ObjectLibrary = UObjectLibrary::CreateLibrary(UWorld::StaticClass(),
true,
true);
523 ObjectLibrary->LoadAssetDataFromPath(
Map.Path);
524 ObjectLibrary->GetAssetDataList(AssetsData);
527 for (FAssetData &AssetData : AssetsData)
529 FString AssetName = AssetData.AssetName.ToString();
530 if (AssetName.Contains(
Map.Name +
"_Tile_"))
533 MapPathData.Append(
Map.Path + TEXT(
"/") + AssetName + TEXT(
"\n"));
534 MapPathDataLinux.Append(
Map.Path + TEXT(
"/") + AssetName + TEXT(
"+"));
539 UE_LOG(LogTemp, Warning, TEXT(
"Found %d tiles"), NumTiles);
543 if (!PropsMapPath.IsEmpty())
545 MapPathData.Append(PropsMapPath + TEXT(
"/PropsMap"));
546 MapPathDataLinux.Append(PropsMapPath + TEXT(
"/PropsMap"));
551 MapPathDataLinux.RemoveFromEnd(TEXT(
"+"));
555 const FString SaveDirectory = FPaths::ProjectContentDir();
556 const FString FileName = FString(
"MapPaths.txt");
558 const FString FileNameLinux = FString(
"MapPathsLinux.txt");
559 SaveStringTextToFile(SaveDirectory, FileName, MapPathData,
true);
560 SaveStringTextToFile(SaveDirectory, FileNameLinux, MapPathDataLinux,
true);
564void UPrepareAssetsForCookingCommandlet::GeneratePackagePathFile(
const FString &PackageName)
567 FString SaveDirectory = FPaths::ProjectContentDir();
568 FString FileName = FString(
"PackagePath.txt");
572 SaveStringTextToFile(SaveDirectory, FileName, PackageJsonFilePath,
true);
575void UPrepareAssetsForCookingCommandlet::PrepareMapsForCooking(
576 const FString &PackageName,
577 const TArray<FMapData> &MapsPaths)
580 FString BasePath = TEXT(
"/Game/") + PackageName + TEXT(
"/Static/");
583 for (
const auto &
Map : MapsPaths)
586 const FString MapPath = TEXT(
"/") +
Map.Name;
589 const FString DefaultPath = TEXT(
"/Game/") + PackageName + TEXT(
"/Maps/") +
Map.Name;
590 const FString RoadsPath = BasePath + SSTags::ROAD + MapPath;
591 const FString RoadLinesPath = BasePath + SSTags::ROADLINE + MapPath;
592 const FString TerrainPath = BasePath + SSTags::TERRAIN + MapPath;
593 const FString SidewalkPath = BasePath + SSTags::SIDEWALK + MapPath;
596 TArray<FString> DataPath = {DefaultPath, RoadsPath, RoadLinesPath, TerrainPath, SidewalkPath};
599 if (!IsMapInTiles(DataPath))
601 UE_LOG(LogTemp, Log, TEXT(
"Cooking map"));
603 FAssetData AssetData;
604 LoadWorld(AssetData);
605 UObjectRedirector *BaseMapRedirector = Cast<UObjectRedirector>(AssetData.GetAsset());
606 if (BaseMapRedirector !=
nullptr) {
607 World = CastChecked<UWorld>(BaseMapRedirector->DestinationObject);
610 World = CastChecked<UWorld>(AssetData.GetAsset());
613 TArray<AStaticMeshActor *> SpawnedActors = SpawnMeshesToWorld(DataPath,
Map.bUseCarlaMapMaterials, -1, -1);
615 SaveWorld(AssetData, PackageName,
Map.Path,
Map.Name);
617 DestroySpawnedActorsInWorld(SpawnedActors);
622 TArray<TPair<FString, FIntVector>> MapPathsIds;
625 FVector PositionTile0 = FVector();
627 float TileSize = 200000.f;
631 FString TilesInfoPath = FPaths::ProjectContentDir() + PackageName + TEXT(
"/Maps/") +
Map.Name +
"/TilesInfo.txt";
633 UE_LOG(LogTemp, Warning, TEXT(
"Loading %s ..."), *TilesInfoPath);
635 if (FFileHelper::LoadFileToString(TxtFile, *(TilesInfoPath)) ==
true) {
639 TxtFile.ParseIntoArray(Out, TEXT(
","),
true);
644 const float METERSTOCM = 100.f;
646 PositionTile0.X = METERSTOCM * FCString::Atof(*Out[0]);
647 PositionTile0.Y = METERSTOCM * FCString::Atof(*Out[1]);
649 TileSize = METERSTOCM * FCString::Atof(*Out[2]);
654 UE_LOG(LogTemp, Warning, TEXT(
"TilesInfo.txt format is invalid file"));
659 UE_LOG(LogTemp, Warning, TEXT(
"Could not find TilesInfo.txt file"));
662 UE_LOG(LogTemp, Log, TEXT(
"Cooking tiles:"));
664 FAssetData AssetData;
665 LoadWorldTile(AssetData);
666 UObjectRedirector *BaseMapRedirector = Cast<UObjectRedirector>(AssetData.GetAsset());
667 if (BaseMapRedirector !=
nullptr) {
668 World = CastChecked<UWorld>(BaseMapRedirector->DestinationObject);
671 World = CastChecked<UWorld>(AssetData.GetAsset());
683 TArray<AStaticMeshActor *> SpawnedActors = SpawnMeshesToWorld(DataPath,
Map.bUseCarlaMapMaterials, i, j);
684 Res = SpawnedActors.Num() > 0;
687 UE_LOG(LogTemp, Log, TEXT(
" Tile %d,%d found"), i, j);
689 TileName = FString::Printf(TEXT(
"%s_Tile_%d_%d"), *
Map.Name, i, j);
692 SaveWorld(AssetData, PackageName,
Map.Path, TileName);
694 TPair<FString, FIntVector>(
695 Map.Path +
"/" + TileName, FIntVector(i, j, 0)));
697 DestroySpawnedActorsInWorld(SpawnedActors);
707 UEditorLoadingAndSavingUtils::SaveDirtyPackages(
true,
true);
710 LoadLargeMapWorld(AssetData);
711 BaseMapRedirector = Cast<UObjectRedirector>(AssetData.GetAsset());
712 if (BaseMapRedirector !=
nullptr) {
713 World = CastChecked<UWorld>(BaseMapRedirector->DestinationObject);
716 World = CastChecked<UWorld>(AssetData.GetAsset());
721 ALargeMapManager::StaticClass(), FTransform());
728 SaveWorld(AssetData, PackageName,
Map.Path,
Map.Name,
false);
730 UE_LOG(LogTemp, Log, TEXT(
"End cooking tiles"));
735void UPrepareAssetsForCookingCommandlet::PreparePropsForCooking(
736 FString &PackageName,
737 const TArray<FString> &PropsPaths,
738 FString &MapDestPath)
741 FAssetData AssetData;
743 LoadWorld(AssetData);
744 UObjectRedirector *BaseMapRedirector = Cast<UObjectRedirector>(AssetData.GetAsset());
745 if (BaseMapRedirector !=
nullptr) {
746 World = CastChecked<UWorld>(BaseMapRedirector->DestinationObject);
749 World = CastChecked<UWorld>(AssetData.GetAsset());
754 TArray<FString> PropPathDirs = PropsPaths;
756 for (
auto &PropPath : PropPathDirs)
758 PropPath.Split(TEXT(
"/"), &PropPath,
nullptr,
759 ESearchCase::Type::IgnoreCase, ESearchDir::Type::FromEnd);
763 TArray<AStaticMeshActor *> SpawnedActors = SpawnMeshesToWorld(PropPathDirs,
false);
765 const FString MapName(
"PropsMap");
766 SaveWorld(AssetData, PackageName, MapDestPath, MapName);
768 DestroySpawnedActorsInWorld(SpawnedActors);
772int32 UPrepareAssetsForCookingCommandlet::Main(
const FString &Params)
781 PrepareMapsForCooking(PackageParams.
Name, AssetsPaths.
MapsPaths);
785 FString PropsMapPath(
"");
789 PropsMapPath = TEXT(
"/Game/") + PackageParams.
Name + TEXT(
"/Maps/PropsMap");
790 PreparePropsForCooking(PackageParams.
Name, AssetsPaths.
PropsPaths, PropsMapPath);
794 GenerateMapPathsFile(AssetsPaths, PropsMapPath);
797 GeneratePackagePathFile(PackageParams.
Name);
801 UEditorLoadingAndSavingUtils::SaveDirtyPackages(
true,
true);
UE_LOG(LogCarla, Log, TEXT("UActorDispatcher::Destroying actor: '%s' %x"), *Id, Actor)
TSharedPtr< const FActorInfo > carla::rpc::ActorState UWorld Actor
static bool ValidateStaticMesh(UStaticMesh *Mesh)
void SetTile0Offset(const FVector &Offset)
void SetTileSize(float Size)
void GenerateMap(FString InAssetsPath)
void RemoveRoutes()
根据地图名称构建路径
地图类的前向声明,用于在LaneInvasionSensor类中可能的引用。
UMaterialInstance * RoadNodeMaterial
道路节点网格的替代材料
UMaterialInstance * CurbNodeMaterialInstance
用于道路路缘的材料
FString GetFirstPackagePath(const FString &PackageName) const
获取在虚幻内容目录中找到的第一个 .Package.json 文件,文件名为 PackageName
UPrepareAssetsForCookingCommandlet()
默认构造函数
UObjectLibrary * AssetsObjectLibrary
用于在对象库中加载资源。加载的数据存储在 AssetDatas 中
UWorld * World
基础地图世界从Carla内容中加载
UObjectLibrary * MapObjectLibrary
用于加载对象库中的地图。加载的数据存储在AssetDatas中
UMaterialInstance * GutterNodeMaterialInstance
用于道路排水沟的材料
UMaterialInstance * MarkingNodeYellow
中心车道标线的替代材料
UMaterialInstance * MarkingNodeWhite
用于外部车道的标线材料
TArray< FAssetData > AssetDatas
从任何对象库加载的资源
UMaterialInstance * SidewalkNodeMaterialInstance
用于SidewalkNodes的解决方法材料
bool SavePackage(const FString &PackagePath, UPackage *Package) const
将Package 保存为 .umap 格式的文件,路径为 Unreal 内容文件夹内的 PackagePath
TArray< FAssetData > MapContents
从任何对象库加载地图内容
UMaterialInstance * TerrainNodeMaterialInstance
地形节点的替代材料
包含从 .Package.json 文件中读取的所有资产数据的结构
TArray< FMapData > MapsPaths
TArray< FString > PropsPaths
包含从 .Package.json 文件中读取的地图数据的结构体
bool bUseCarlaMapMaterials
包含带有 Name 的 Package 和 bOnlyPrepareMaps 标志的结构体,用于 在不同阶段分离地图和道具的烹饪过程(地图将在 make import 命令期间导入,而道具将在 make...