CARLA
LoadAssetMaterialsCommandlet.cpp
Go to the documentation of this file.
1 // Copyright (c) 2021 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 #if WITH_EDITOR
10 #include "FileHelpers.h"
11 #endif
12 #include "JsonObject.h"
13 #include "JsonSerializer.h"
14 #include "UObject/ConstructorHelpers.h"
15 #include "Runtime/Engine/Classes/Kismet/GameplayStatics.h"
16 #include "Engine/StreamableManager.h"
17 #include "Engine/StaticMeshActor.h"
19 #include "Engine/DecalActor.h"
20 #include "Components/DecalComponent.h"
21 
23 {
24  // Set necessary flags to run commandlet
25  IsClient = false;
26  IsEditor = true;
27  IsServer = false;
28  LogToConsole = true;
29  FilledData = false;
30  ReadConfigFile = true;
31 
32 #if WITH_EDITORONLY_DATA
33 
34  static ConstructorHelpers::FObjectFinder<UBlueprint> RoadPainterBlueprint(TEXT(
35  "Blueprint'/Game/Carla/Blueprints/LevelDesign/RoadPainterPreset.RoadPainterPreset'"));
36 
37  RoadPainterSubclass = (UClass*)RoadPainterBlueprint.Object->GeneratedClass;
38 
39  // Dirt
40  DecalNamesMap.Add("dirt1", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/RoadDirt/DI_RoadDirt_01.DI_RoadDirt_01'");
41  DecalNamesMap.Add("dirt2", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/RoadDirt/DI_RoadDirt_02.DI_RoadDirt_02'");
42  DecalNamesMap.Add("dirt3", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/RoadDirt/DI_RoadDirt_03.DI_RoadDirt_03'");
43  DecalNamesMap.Add("dirt4", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/RoadDirt/DI_RoadDirt_04.DI_RoadDirt_04'");
44  DecalNamesMap.Add("dirt5", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/RoadDirt/DI_RoadDirt_05.DI_RoadDirt_05'");
45 
46  // Drip
47  DecalNamesMap.Add("drip1", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/RoadDirt/DI_RoadDrip_01.DI_RoadDrip_01'");
48  DecalNamesMap.Add("drip2", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/RoadDirt/DI_RoadDrip_02.DI_RoadDrip_02'");
49  DecalNamesMap.Add("drip3", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/RoadDirt/DI_RoadDrip_03.DI_RoadDrip_03'");
50 
51  // Road lines
52  DecalNamesMap.Add("roadline1", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/RoadDirt/DI_RoadLine_01.DI_RoadLine_01'");
53  DecalNamesMap.Add("roadline2", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/RoadDirt/DI_RoadLine_02.DI_RoadLine_02'");
54  DecalNamesMap.Add("roadline3", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/RoadDirt/DI_RoadLine_03.DI_RoadLine_03'");
55  DecalNamesMap.Add("roadline4", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/RoadDirt/DI_RoadLine_04.DI_RoadLine_04'");
56  DecalNamesMap.Add("roadline5", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/RoadDirt/DI_RoadLine_05.DI_RoadLine_05'");
57 
58  // Tiremarks
59  DecalNamesMap.Add("tiremark1", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/RoadDirt/DI_TireMark_01.DI_TireMark_01'");
60  DecalNamesMap.Add("tiremark2", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/RoadDirt/DI_TireMark_02.DI_TireMark_02'");
61  DecalNamesMap.Add("tiremark3", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/RoadDirt/DI_TireMark_03.DI_TireMark_03'");
62 
63  // Tarsnakes
64  DecalNamesMap.Add("tarsnake1", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/TarSnakes/DI_tarsnake1.DI_tarsnake1'");
65  DecalNamesMap.Add("tarsnake2", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/TarSnakes/DI_tarsnake2.DI_tarsnake2'");
66  DecalNamesMap.Add("tarsnake3", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/TarSnakes/DI_tarsnake3.DI_tarsnake3'");
67  DecalNamesMap.Add("tarsnake4", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/TarSnakes/DI_tarsnake4.DI_tarsnake4'");
68  DecalNamesMap.Add("tarsnake5", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/TarSnakes/DI_tarsnake5.DI_tarsnake5'");
69  DecalNamesMap.Add("tarsnake6", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/TarSnakes/DI_tarsnake6.DI_tarsnake6'");
70  DecalNamesMap.Add("tarsnake7", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/TarSnakes/DI_tarsnake7.DI_tarsnake7'");
71  DecalNamesMap.Add("tarsnake8", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/TarSnakes/DI_tarsnake8.DI_tarsnake8'");
72  DecalNamesMap.Add("tarsnake9", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/TarSnakes/DI_tarsnake9.DI_tarsnake9'");
73  DecalNamesMap.Add("tarsnake10", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/TarSnakes/DI_tarsnake10.DI_tarsnake10'");
74  DecalNamesMap.Add("tarsnake11", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/TarSnakes/DI_tarsnake11.DI_tarsnake11'");
75 
76  // Cracks big
77  DecalNamesMap.Add("cracksbig1", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/Cracks/DI_cracksBig1.DI_cracksBig1'");
78  DecalNamesMap.Add("cracksbig2", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/Cracks/DI_cracksBig2.DI_cracksBig2'");
79  DecalNamesMap.Add("cracksbig3", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/Cracks/DI_cracksBig3.DI_cracksBig3'");
80  DecalNamesMap.Add("cracksbig4", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/Cracks/DI_cracksBig4.DI_cracksBig4'");
81  DecalNamesMap.Add("cracksbig5", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/Cracks/DI_cracksBig5.DI_cracksBig5'");
82  DecalNamesMap.Add("cracksbig6", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/Cracks/DI_cracksBig6.DI_cracksBig6'");
83  DecalNamesMap.Add("cracksbig7", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/Cracks/DI_cracksBig7.DI_cracksBig7'");
84  DecalNamesMap.Add("cracksbig8", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/Cracks/DI_cracksBig8.DI_cracksBig8'");
85 
86  // Cracks
87  DecalNamesMap.Add("crack1", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/Cracks/DI_RoadCrack01.DI_RoadCrack01'");
88  DecalNamesMap.Add("crack2", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/Cracks/DI_RoadCrack02.DI_RoadCrack02'");
89  DecalNamesMap.Add("crack3", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/Cracks/DI_RoadCrack05.DI_RoadCrack05'");
90  DecalNamesMap.Add("crack4", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/Cracks/DI_RoadCrack09.DI_RoadCrack09'");
91  DecalNamesMap.Add("crack5", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/Cracks/DI_RoadCrack11.DI_RoadCrack11'");
92  DecalNamesMap.Add("crack6", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/Cracks/DI_RoadCrack13.DI_RoadCrack13'");
93  DecalNamesMap.Add("crack7", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/Cracks/DI_RoadCrack15.DI_RoadCrack15'");
94  DecalNamesMap.Add("crack8", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/Cracks/DI_RoadCrack16.DI_RoadCrack16'");
95 
96  // Manholes
97  DecalNamesMap.Add("manhole1", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/Manhole/DI_Manhole01.DI_Manhole01'");
98  DecalNamesMap.Add("manhole2", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/Manhole/DI_Manhole02.DI_Manhole02'");
99  DecalNamesMap.Add("manhole3", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/Manhole/DI_Manhole03.DI_Manhole03'");
100 
101  // Mud
102  DecalNamesMap.Add("mud1", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/MudDecal/DI_Mud_1.DI_Mud_1'");
103  DecalNamesMap.Add("mud2", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/MudDecal/DI_Mud_2.DI_Mud_2'");
104  DecalNamesMap.Add("mud3", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/MudDecal/DI_Mud_3.DI_Mud_3'");
105  DecalNamesMap.Add("mud4", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/MudDecal/DI_Mud_4.DI_Mud_4'");
106  DecalNamesMap.Add("mud5", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/MudDecal/DI_Mud_5.DI_Mud_5'");
107 
108  // Oil splats
109  DecalNamesMap.Add("oilsplat1", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/OilSplats/DI_OilSplat1.DI_OilSplat1'");
110  DecalNamesMap.Add("oilsplat2", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/OilSplats/DI_OilSplat2.DI_OilSplat2'");
111  DecalNamesMap.Add("oilsplat3", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/OilSplats/DI_OilSplat3.DI_OilSplat3'");
112  DecalNamesMap.Add("oilsplat4", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/OilSplats/DI_OilSplat4.DI_OilSplat4'");
113  DecalNamesMap.Add("oilsplat5", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/OilSplats/DI_OilSplat5.DI_OilSplat5'");
114 
115  // Misc
116  DecalNamesMap.Add("gum", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/OilSplats/DI_Gum.DI_Gum'");
117  DecalNamesMap.Add("grate", "MaterialInstanceConstant'/Game/Carla/Static/Decals/Road/Manhole/DI_Grate_01_v2.DI_Grate_01_v2'");
118 
119 #endif
120 }
121 
122 #if WITH_EDITORONLY_DATA
123 
124 void ULoadAssetMaterialsCommandlet::ApplyRoadPainterMaterials(const FString &LoadedMapName, bool IsInTiles)
125 {
126  if (IsInTiles == true) {
127 
128  if (FilledData == false) {
129 
130  // As the OpenDrive file has the same name as level, build the path to the
131  // xodr file using the label name and the game content directory.
132  FString MapName = LoadedMapName;
133  if (IsInTiles)
134  {
135  int32 idx = MapName.Find("_Tile_");
136  if(idx > -1)
137  {
138  MapName = MapName.Mid(0, idx);
139  }
140  }
141  const FString XodrContent = UOpenDrive::LoadXODR(MapName);
142  XODRMap = carla::opendrive::OpenDriveParser::Load(carla::rpc::FromLongFString(XodrContent));
143 
144  // Acquire the TilesInfo.txt file for storing the tile data (offset and size)
145  TArray<FString> FileList;
146  IFileManager::Get().FindFilesRecursive(FileList, *(FPaths::ProjectContentDir()), *(FString("TilesInfo.txt")), true, false, false);
147 
148  FString TxtFile;
149  if (FFileHelper::LoadFileToString(TxtFile, *FileList[0]) == true) {
150 
151  TArray<FString> Out;
152  TxtFile.ParseIntoArray(Out, TEXT(","), true);
153 
154  TileData.FirstTileCenterX = (float) FCString::Atoi(*Out[0]);
155  TileData.FirstTileCenterY = (float) FCString::Atoi(*Out[1]);
156  TileData.Size = (float) FCString::Atoi(*Out[2]);
157  }
158  else {
159 
160  UE_LOG(LogTemp, Warning, TEXT("Could not read TilesInfo.txt file"));
161  return;
162  }
163 
164  FilledData = true;
165  }
166 
167  TArray<FString> StringArray = {};
168  LoadedMapName.ParseIntoArray(StringArray, TEXT("_"), false);
169  // From the loaded map name (in style mymap_Tile_200_400) get the X and the Y (Tile_200_400 -> X = 200, Y = 400)
170  int32 XIndex = FCString::Atoi(*StringArray[StringArray.Num() - 2]);
171  int32 YIndex = FCString::Atoi(*StringArray[StringArray.Num() - 1]);
172 
173  FVector TilePosition;
174  // This means it's the initial tile (mymap_Tile_0_0)
175  // This is in RELATIVE coords
176  if(XIndex == 0 && YIndex == 0) {
177 
178  TilePosition.X = TileData.FirstTileCenterX;
179  TilePosition.Y = TileData.FirstTileCenterY;
180  }
181  else {
182 
183  TilePosition.X = TileData.FirstTileCenterX + (TileData.Size * (float)XIndex);
184  TilePosition.Y = TileData.FirstTileCenterY - (TileData.Size * (float)YIndex);
185  }
186 
187  TilePosition.Z = 0.0f;
188 
189  float HalfSize = TileData.Size / 2.0f;
190 
191  float MinXSize = (TilePosition.X - HalfSize);
192  float MaxXSize = (TilePosition.X + HalfSize);
193 
194  float MinYSize = (TilePosition.Y - HalfSize);
195  float MaxYSize = (TilePosition.Y + HalfSize);
196 
197  if (ReadConfigFile == true) {
198 
199  DecalsProperties = ReadDecalsConfigurationFile();
200  ReadConfigFile = false;
201  }
202 
203  carla::geom::Location DecalLocation;
204 
205  //Store results for avoiding excessive calculations
206  float MinXSizeCm = MinXSize * 100.0f;
207  float MaxXSizeCm = MaxXSize * 100.0f;
208  float MinYSizeCm = MinYSize * 100.0f;
209  float MaxYSizeCm = MaxYSize * 100.0f;
210 
211  float TileSizeCm = TileData.Size * 100.0f;
212  float TileWorldLocationX = TileData.FirstTileCenterX * 100.0f;
213  float TileWorldLocationY = TileData.FirstTileCenterY * 100.0f;
214 
215  for (int32 i = 0; i < DecalsProperties.DecalMaterials.Num(); ++i) {
216 
217  for (int32 j = 0; j < DecalsProperties.DecalNumToSpawn[i]; ++j) {
218 
219  DecalLocation.x = FMath::RandRange(MinXSize, MaxXSize);
220  DecalLocation.y = FMath::RandRange(MinYSize, MaxYSize);
221  DecalLocation.z = 0.0f;
222 
223  // Get the closest road waypoint from the random location calculated
224  auto Wp = XODRMap->GetClosestWaypointOnRoad(DecalLocation);
225  FVector FinalLocation(XODRMap->ComputeTransform(Wp.get()).location);
226 
227  // Check we don't exceed the map boundaries
228  if (FinalLocation.X > MinXSizeCm && FinalLocation.X < MaxXSizeCm) {
229 
230  if (FinalLocation.Y > MinYSizeCm && FinalLocation.Y < MaxYSizeCm) {
231 
232  FRotator FinalRotation(XODRMap->ComputeTransform(Wp.get()).rotation);
233 
234  // Transform the location from world coords to tile coordinates.
235  // The location we get is the location of the XODR waypoint, which is in WORLD coordinates
236  // The Y coordinates are reversed! -Y = Y and Y = -Y
237  FinalLocation.X -= TileWorldLocationX + (XIndex * TileSizeCm);
238  FinalLocation.Y -= TileWorldLocationY - (YIndex * TileSizeCm);
239 
240  FActorSpawnParameters SpawnParams;
241  SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
242  SpawnParams.bNoFail = true;
243  ADecalActor* Decal = World->SpawnActor<ADecalActor>(FinalLocation, FRotator(), SpawnParams);
244  Decal->SetDecalMaterial(DecalsProperties.DecalMaterials[i]);
245 
246  // Calculate random scale for decal
247  float RandScale = FMath::RandRange(DecalsProperties.DecalMinScale, DecalsProperties.DecalMaxScale);
248  FVector FinalDecalScale;
249  FinalDecalScale.X = DecalsProperties.DecalScale.X + RandScale;
250  FinalDecalScale.Y = DecalsProperties.DecalScale.Y + RandScale;
251  FinalDecalScale.Z = 1.0f;
252  Decal->SetActorScale3D(FinalDecalScale);
253 
254  // Calculate random yaw for decal
255  float RandomYaw = FMath::RandRange(0.0f, DecalsProperties.DecalRandomYaw);
256  FinalRotation.Yaw += RandomYaw;
257  FinalRotation.Pitch = -90.0f;
258  Decal->SetActorRotation(FinalRotation);
259  Decal->SetActorLabel("RoadDecal", true);
260  }
261  }
262  }
263  }
264 
265 #if WITH_EDITOR
266  UEditorLoadingAndSavingUtils::SaveDirtyPackages(true, true);
267 #endif
268  }
269 }
270 
271 FDecalsProperties ULoadAssetMaterialsCommandlet::ReadDecalsConfigurationFile() {
272 
273  // Get road painter configuration file
274  FString JsonConfigFile;
275 
276  TArray<FString> FileList;
277  IFileManager::Get().FindFilesRecursive(FileList, *(FPaths::ProjectContentDir()),
278  *(FString("roadpainter_decals.json")), true, false, false);
279 
280  FDecalsProperties DecalConfiguration;
281  if (FFileHelper::LoadFileToString(JsonConfigFile, *(IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead(*FileList[0]))))
282  {
283  TSharedPtr<FJsonObject> JsonParsed;
284  TSharedRef<TJsonReader<TCHAR>> JsonReader = TJsonReaderFactory<TCHAR>::Create(JsonConfigFile);
285  if (FJsonSerializer::Deserialize(JsonReader, JsonParsed))
286  {
287  // Get decals object array
288  auto DecalJsonArray = JsonParsed->GetArrayField(TEXT("decals"));
289  for (auto &DecalJsonValue : DecalJsonArray)
290  {
291  const auto DecalJsonObject = DecalJsonValue->AsObject();
292 
293  // With the decal name array we created earlier, we traverse it
294  // and look up it's name in the .json file
295  for (const TPair<FString, FString>& Pair : DecalNamesMap) {
296  if (DecalJsonObject->HasField(Pair.Key) == true) {
297  DecalConfiguration.DecalMaterials.Add(LoadObject<UMaterialInstanceConstant>(nullptr, *Pair.Value));
298  DecalConfiguration.DecalNumToSpawn.Add(DecalJsonObject->GetIntegerField(Pair.Key));
299  }
300  }
301 
302  TSharedPtr<FJsonObject> VectorObject = DecalJsonObject->GetObjectField(TEXT("decal_scale"));
303  FVector DecalScale;
304  DecalScale.X = (float)VectorObject->GetNumberField(TEXT("x_axis"));
305  DecalScale.Y = (float)VectorObject->GetNumberField(TEXT("y_axis"));
306  DecalScale.Z = (float)VectorObject->GetNumberField(TEXT("z_axis"));
307  DecalConfiguration.DecalScale = DecalScale;
308  DecalConfiguration.FixedDecalOffset = DecalScale;
309  DecalConfiguration.DecalMinScale = (float)DecalJsonObject->GetNumberField(TEXT("decal_min_scale"));
310  DecalConfiguration.DecalMaxScale = (float)DecalJsonObject->GetNumberField(TEXT("decal_max_scale"));
311  DecalConfiguration.DecalRandomYaw = (float)DecalJsonObject->GetNumberField(TEXT("decal_random_yaw"));
312  DecalConfiguration.RandomOffset = (float)DecalJsonObject->GetNumberField(TEXT("random_offset"));
313  }
314  }
315  }
316  return DecalConfiguration;
317 }
318 
319 FString ULoadAssetMaterialsCommandlet::GetFirstPackagePath(const FString &PackageName) const
320 {
321  // Get all Package names
322  TArray<FString> PackageList;
323  IFileManager::Get().FindFilesRecursive(PackageList, *(FPaths::ProjectContentDir()),
324  *(PackageName + TEXT(".Package.json")), true, false, false);
325 
326  if (PackageList.Num() == 0)
327  {
328  UE_LOG(LogTemp, Error, TEXT("Package json file not found."));
329  return {};
330  }
331 
332  return IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead(*PackageList[0]);
333 }
334 
335 void ULoadAssetMaterialsCommandlet::LoadAssetsMaterials(const FString &PackageName, const TArray<FMapData> &MapsPaths)
336 {
337  // Load World
338  FAssetData AssetData;
339  MapObjectLibrary = UObjectLibrary::CreateLibrary(UWorld::StaticClass(), false, GIsEditor);
340  const FString DefaultPath = TEXT("/Game/") + PackageName + TEXT("/Maps/");
341  MapObjectLibrary->AddToRoot();
342  MapObjectLibrary->LoadAssetDataFromPath(*DefaultPath);
343  MapObjectLibrary->LoadAssetsFromAssetData();
344  MapObjectLibrary->GetAssetDataList(AssetDatas);
345 
346  if (AssetDatas.Num() > 0)
347  {
348  int32 NumAssets = AssetDatas.Num();
349  //If the map is tiled, there will be several umaps in the same folder
350  for (int32 i = 0; i < NumAssets; ++i) {
351 
352  // Extract first asset found in folder path (i.e. the imported map)
353  AssetData = AssetDatas.Pop();
354  World = Cast<UWorld>(AssetData.GetAsset());
355  if (World != nullptr) {
356 
357  World->InitWorld();
358 
359  // Check if there's any road meshes in the world for spawning the decals.
360  TArray<AActor*> FoundActors;
361  UGameplayStatics::GetAllActorsOfClass(World, AStaticMeshActor::StaticClass(), FoundActors);
362  bool HasRoadMesh = false;
363  for (int32 j = 0; j < FoundActors.Num() && HasRoadMesh == false; ++j) {
364 
365  AStaticMeshActor *MeshActor = Cast<AStaticMeshActor>(FoundActors[j]);
366  if (MeshActor->GetName().Contains("Roads") || MeshActor->GetName().Contains("Road")){
367 
368  HasRoadMesh = true;
369  }
370  }
371 
372  if (HasRoadMesh == true) {
373 
374  bool IsTiledMap = World->GetName().Contains("_Tile_", ESearchCase::Type::CaseSensitive);
375  ApplyRoadPainterMaterials(World->GetName(), IsTiledMap);
376  }
377 
378 #if WITH_EDITOR
379  UEditorLoadingAndSavingUtils::SaveDirtyPackages(true, true);
380 #endif
381  }
382  }
383  }
384 }
385 
386 FPackageParams ULoadAssetMaterialsCommandlet::ParseParams(const FString &InParams) const
387 {
388  TArray<FString> Tokens;
389  TArray<FString> Params;
390  TMap<FString, FString> ParamVals;
391 
392  ParseCommandLine(*InParams, Tokens, Params);
393 
394  FPackageParams PackageParams;
395 
396  // Parse and store Package name
397  FParse::Value(*InParams, TEXT("PackageName="), PackageParams.Name);
398 
399  return PackageParams;
400 }
401 
402 FAssetsPaths ULoadAssetMaterialsCommandlet::GetAssetsPathFromPackage(const FString &PackageName) const
403 {
404  const FString PackageJsonFilePath = GetFirstPackagePath(PackageName);
405 
406  FAssetsPaths AssetsPaths;
407 
408  // Get All Maps Path
409  FString MapsFileJsonContent;
410  if (FFileHelper::LoadFileToString(MapsFileJsonContent, *PackageJsonFilePath))
411  {
412  TSharedPtr<FJsonObject> JsonParsed;
413  TSharedRef<TJsonReader<TCHAR>> JsonReader = TJsonReaderFactory<TCHAR>::Create(MapsFileJsonContent);
414  if (FJsonSerializer::Deserialize(JsonReader, JsonParsed))
415  {
416  // Add Maps Path
417  auto MapsJsonArray = JsonParsed->GetArrayField(TEXT("maps"));
418 
419  for (auto &MapJsonValue : MapsJsonArray)
420  {
421  TSharedPtr<FJsonObject> MapJsonObject = MapJsonValue->AsObject();
422 
423  FMapData MapData;
424  MapData.Name = MapJsonObject->GetStringField(TEXT("name"));
425  MapData.Path = MapJsonObject->GetStringField(TEXT("path"));
426  MapData.bUseCarlaMapMaterials = MapJsonObject->GetBoolField(TEXT("use_carla_materials"));
427 
428  AssetsPaths.MapsPaths.Add(std::move(MapData));
429  }
430 
431  // Add Props Path
432  auto PropJsonArray = JsonParsed->GetArrayField(TEXT("props"));
433 
434  for (auto &PropJsonValue : PropJsonArray)
435  {
436  TSharedPtr<FJsonObject> PropJsonObject = PropJsonValue->AsObject();
437 
438  const FString PropAssetPath = PropJsonObject->GetStringField(TEXT("path"));
439 
440  AssetsPaths.PropsPaths.Add(std::move(PropAssetPath));
441  }
442  }
443  }
444  return AssetsPaths;
445 }
446 
447 int32 ULoadAssetMaterialsCommandlet::Main(const FString &Params)
448 {
449  FPackageParams PackageParams = ParseParams(Params);
450 
451  // Get Props and Maps Path
452  FAssetsPaths AssetsPaths = GetAssetsPathFromPackage(PackageParams.Name);
453 
454  LoadAssetsMaterials(PackageParams.Name, AssetsPaths.MapsPaths);
455 
456 #if WITH_EDITOR
457  UEditorLoadingAndSavingUtils::SaveDirtyPackages(true, true);
458 #endif
459 
460  return 0;
461 }
462 
463 #endif
float DecalMaxScale
Maximum scale to be applied to the decals.
FVector FixedDecalOffset
Min offset from one decal to another.
float DecalRandomYaw
The decal yaw to be applied randomly.
Struct containing Package with Name and bOnlyPrepareMaps flag used to separate the cooking of maps an...
TArray< UMaterialInstance * > DecalMaterials
The decals used on the road.
Struct containing map data read from .Package.json file.
TArray< FAssetData > AssetDatas
Loaded assets from any object library.
ULoadAssetMaterialsCommandlet()
Default constructor.
static T Get(carla::rpc::Response< T > &response)
UObjectLibrary * MapObjectLibrary
Used for loading maps in object library.
static boost::optional< road::Map > Load(const std::string &opendrive)
Struct containing all assets data read from .Package.json file.
boost::optional< carla::road::Map > XODRMap
TArray< int32 > DecalNumToSpawn
How many decals (or material instances) of each, should be applied to the road.
FString GetFirstPackagePath(const FString &PackageName) const
Gets the first .Package.json file found in Unreal Content Directory with PackageName.
TMap< FString, FString > DecalNamesMap
Dictionary for translating the JSON file "decal_names" array to already loaded Material Instances...
float DecalMinScale
Min scale to be applied to the decals.
TSubclassOf< ARoadPainterWrapper > RoadPainterSubclass
Subclass for acquiring the RoadPainter blueprint.
float RandomOffset
Random offset from one decal to another.
FVector DecalScale
Scale of each decal on the road.