CARLA
Loading...
Searching...
No Matches
CarlaGameModeBase.cpp
Go to the documentation of this file.
1// Copyright (c) 2026 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#include "Carla.h"
9#include "Carla/Game/Tagger.h"
10#include "Carla/Game/CarlaHUD.h"
16#include "Carla/Weather/Sky.h"
18
24#include <carla/rpc/MapLayer.h>
26
27#include <util/ue-header-guard-begin.h>
28#include "Components/DirectionalLightComponent.h"
29#include "Engine/DecalActor.h"
30#include "Engine/LevelStreaming.h"
31#include "Engine/LocalPlayer.h"
32#include "Materials/MaterialInstanceDynamic.h"
33#include "Engine/StaticMeshActor.h"
34#include "EngineUtils.h"
35#include "Async/ParallelFor.h"
36#include "DynamicRHI.h"
37#include "DrawDebugHelpers.h"
38#include "Kismet/KismetSystemLibrary.h"
39#include "Misc/PackageName.h"
40#include <util/ue-header-guard-end.h>
41
42namespace cr = carla::road;
43namespace crp = carla::rpc;
44namespace cre = carla::road::element;
45
46ACarlaGameModeBase::ACarlaGameModeBase(const FObjectInitializer& ObjectInitializer)
47 : Super(ObjectInitializer)
48{
49 PrimaryActorTick.bCanEverTick = true;
50 PrimaryActorTick.TickGroup = TG_PrePhysics;
51 bAllowTickBeforeBeginPlay = false;
52
53 Episode = CreateDefaultSubobject<UCarlaEpisode>(TEXT("Episode"));
54
55 Recorder = CreateDefaultSubobject<ACarlaRecorder>(TEXT("Recorder"));
56
57 ObjectRegister = CreateDefaultSubobject<UObjectRegister>(TEXT("ObjectRegister"));
58
59 // HUD
60 HUDClass = ACarlaHUD::StaticClass();
61
62 TaggerDelegate = CreateDefaultSubobject<UTaggerDelegate>(TEXT("TaggerDelegate"));
63 CarlaSettingsDelegate = CreateDefaultSubobject<UCarlaSettingsDelegate>(TEXT("CarlaSettingsDelegate"));
64}
65
67{
68 UWorld* World = GetWorld();
69 TSoftObjectPtr<UWorld> AssetPtr (World);
70 FString Path = FPaths::GetPath(AssetPtr.GetLongPackageName());
71 Path.RemoveFromStart("/Game/");
72 return Path;
73}
74
76{
77 // Maps of mounted content packs live under their own mount point
78 // (/<Pack>/Maps/...), so resolve through the package name table instead of
79 // assuming everything hangs off the project content dir.
80 UWorld* World = GetWorld();
81 const FString PackagePath = FPaths::GetPath(World->GetPackage()->GetName());
82 FString Filename;
83 if (!PackagePath.StartsWith(TEXT("/Game/")) &&
84 FPackageName::TryConvertLongPackageNameToFilename(PackagePath, Filename))
85 {
86 return FPaths::ConvertRelativePathToFull(Filename);
87 }
88 FString Path = GetRelativeMapPath();
89 return FPaths::ConvertRelativePathToFull(FPaths::ProjectContentDir()) + Path;
90}
91
93 const FString &MapName,
94 const FString &Options,
95 FString &ErrorMessage)
96{
97 TRACE_CPUPROFILER_EVENT_SCOPE(ACarlaGameModeBase::InitGame);
98 Super::InitGame(MapName, Options, ErrorMessage);
99
100 UWorld* World = GetWorld();
101 check(World != nullptr);
102 FString InMapName(MapName);
103
104 checkf(
105 Episode != nullptr,
106 TEXT("Missing episode, can't continue without an episode!"));
107
108 AActor* LMManagerActor =
109 UGameplayStatics::GetActorOfClass(GetWorld(), ALargeMapManager::StaticClass());
110 LMManager = Cast<ALargeMapManager>(LMManagerActor);
111 if (LMManager && World->GetWorldPartition() != nullptr)
112 {
113 // World Partition map (e.g. a legacy tiled map converted with the
114 // WorldPartitionConvert commandlet): the engine streams cells natively and
115 // keeps absolute double-precision coordinates, so the UE4-era large-map
116 // machinery (WorldComposition tiles + origin rebasing) must not run. The
117 // conversion carries the old manager actor over; remove it before it ticks.
118 UE_LOG(LogCarla, Log, TEXT(
119 "World Partition map detected: disabling legacy LargeMapManager"));
120 LMManager->Destroy();
121 LMManager = nullptr;
122 }
123 if (LMManager) {
124 if (LMManager->GetNumTiles() == 0)
125 {
127 }
128 InMapName = LMManager->LargeMapName;
129 }
130
131#if WITH_EDITOR
132 {
133 // When playing in editor the map name gets an extra prefix, here we
134 // remove it.
135 FString CorrectedMapName = InMapName;
136 constexpr auto PIEPrefix = TEXT("UEDPIE_0_");
137 CorrectedMapName.RemoveFromStart(PIEPrefix);
138 UE_LOG(LogCarla, Log, TEXT("Corrected map name from %s to %s"), *InMapName, *CorrectedMapName);
139 Episode->MapName = CorrectedMapName;
140 }
141#else
142 Episode->MapName = InMapName;
143#endif // WITH_EDITOR
144
145 GameInstance = Cast<UCarlaGameInstance>(GetGameInstance());
146 checkf(
147 GameInstance != nullptr,
148 TEXT("GameInstance is not a UCarlaGameInstance, did you forget to set "
149 "it in the project settings?"));
150
151 if (TaggerDelegate != nullptr) {
153 } else {
154 UE_LOG(LogCarla, Error, TEXT("Missing TaggerDelegate!"));
155 }
156
157 if(CarlaSettingsDelegate != nullptr) {
160 } else {
161 UE_LOG(LogCarla, Error, TEXT("Missing CarlaSettingsDelegate!"));
162 }
163
164 if (UGameplayStatics::GetActorOfClass(World, ASkyBase::StaticClass()) == nullptr)
165 {
166 // Imported maps and converted tiled maps carry no sun/sky rig, and
167 // BP_CarlaWeather drives all lighting through a single ASkyBase actor.
168 UClass* SkyClass = LoadClass<ASkyBase>(
169 nullptr,
170 TEXT("/Game/Carla/Blueprints/LevelDesign/BP_Carla_Sky.BP_Carla_Sky_C"));
171 if (SkyClass != nullptr)
172 {
173 ASkyBase* SkyActor = World->SpawnActor<ASkyBase>(SkyClass);
174 if (SkyActor != nullptr)
175 {
176 // A level-placed rig that is spatially loaded streams in after this,
177 // and replaces this one (see ASkyBase::BeginPlay).
178 SkyActor->Tags.Add(ASkyBase::FallbackSkyTag);
179 // The class defaults leave the sun at the horizon (pitch 0), which
180 // renders a black atmosphere and an unlit ground; level-placed rigs
181 // (Town10) carry a proper rotation in their instance data. Point the
182 // sun down as a sane noon default until the weather drives it.
183 TArray<UDirectionalLightComponent*> SunComponents;
184 SkyActor->GetComponents<UDirectionalLightComponent>(SunComponents);
185 for (UDirectionalLightComponent* SunComponent : SunComponents)
186 {
187 if (SunComponent->GetName().Contains(TEXT("Sun")))
188 {
189 SunComponent->SetWorldRotation(FRotator(-45.0f, 45.0f, 0.0f));
190 }
191 }
192 }
193 UE_LOG(LogCarla, Log, TEXT("Map without a sky rig: spawned BP_Carla_Sky"));
194 }
195 // BP_GeneralSceneSettings used to be spawned alongside the sky here too,
196 // but everything it did (post-process delta-baseline, cloud density) is
197 // now handled natively in AWeather::ApplyWeatherToSkyActor -- no actor
198 // needed.
199 }
200
201 AActor* WeatherActor =
202 UGameplayStatics::GetActorOfClass(GetWorld(), AWeather::StaticClass());
203 if (WeatherActor != nullptr) {
204 UE_LOG(LogCarla, Log, TEXT("Existing weather actor. Doing nothing then!"));
205 Episode->Weather = static_cast<AWeather*>(WeatherActor);
206 }
207 else {
208 // Fall back to BP_CarlaWeather if WeatherClass is unset on the BP
209 // game mode. Without this, set_weather() RPCs silently no-op because
210 // Episode->Weather stays null and CarlaServer::get_weather_parameters
211 // returns the default-constructed FWeatherParameters{}. Resolved at
212 // runtime (rather than via ConstructorHelpers) so the package cook is
213 // not forced to re-validate the BP asset registry every C++ rebuild.
214 if (WeatherClass == nullptr) {
215 WeatherClass = LoadClass<AWeather>(
216 nullptr,
217 TEXT("/Game/Carla/Blueprints/Weather/BP_CarlaWeather.BP_CarlaWeather_C"));
218 }
219 if (WeatherClass != nullptr) {
220 Episode->Weather = World->SpawnActor<AWeather>(WeatherClass);
221 } else {
222 UE_LOG(LogCarla, Error, TEXT("Missing weather class!"));
223 }
224 }
225
227
228 // Known before any actor of this map begins play: actors that behave
229 // differently on a Multi-GPU secondary check it in BeginPlay, while
230 // NotifyBeginEpisode only sets it once they all have.
231 if (FCarlaEngine *CarlaEngine = GameInstance->GetCarlaEngine())
232 {
233 Episode->bIsPrimaryServer = CarlaEngine->IsPrimaryServer();
234 }
235
237 this,
239
241
242 // make connection between Episode and Recorder
245
247}
248
250{
252
253 if(Map.has_value())
254 {
256 }
257}
258
260{
261 if (CarlaSettingsDelegate != nullptr)
262 {
264 }
265
266 Super::RestartPlayer(NewPlayer);
267}
268
269// Whether BP_CarlaWeather's per-town "DefaultWeathers" table (a blueprint
270// TMap<FString, FWeatherParameters> variable) has an entry for MapName. Looked
271// up by authored name through reflection, like the other blueprint variables
272// the C++ side reads (see AWeather::ApplyWeatherToSkyActor).
273static bool IsMapInBlueprintWeatherTable(const AWeather* Weather, const FString& MapName)
274{
275 if (Weather == nullptr)
276 {
277 return false;
278 }
279 for (TFieldIterator<FProperty> It(Weather->GetClass()); It; ++It)
280 {
281 if ((*It)->GetAuthoredName() != TEXT("DefaultWeathers") && (*It)->GetName() != TEXT("DefaultWeathers"))
282 {
283 continue;
284 }
285 const FMapProperty* MapProp = CastField<FMapProperty>(*It);
286 if (MapProp == nullptr)
287 {
288 return false;
289 }
290 const FStrProperty* KeyProp = CastField<FStrProperty>(MapProp->KeyProp);
291 if (KeyProp == nullptr)
292 {
293 return false;
294 }
295 FScriptMapHelper Helper(MapProp, MapProp->ContainerPtrToValuePtr<void>(Weather));
296 for (FScriptMapHelper::FIterator MapIt(Helper); MapIt; ++MapIt)
297 {
298 if (KeyProp->GetPropertyValue(Helper.GetKeyPtr(MapIt.GetInternalIndex())) == MapName)
299 {
300 return true;
301 }
302 }
303 return false;
304 }
305 return false;
306}
307
309{
310 Super::BeginPlay();
311
312 UWorld* World = GetWorld();
313 check(World != nullptr);
314
317
318 ATagger::TagActorsInLevel(*World, true);
320
321 // World Partition streams cells in after BeginPlay, and their actors are
322 // loaded, not spawned, so neither the tagging sweep above nor the
323 // TaggerDelegate spawn handler ever sees them. Tag each cell's level as it
324 // is added to the world (the legacy ALargeMapManager did this for
325 // WorldComposition tiles, but it retires itself on World Partition maps).
326 if (World->GetWorldPartition() != nullptr)
327 {
328 FWorldDelegates::LevelAddedToWorld.AddUObject(
330 }
331
332 // HACK: fix transparency see-through issues
333 // The problem: transparent objects are visible through walls.
334 // This is due to a weird interaction between the SkyAtmosphere component,
335 // the shadows of a directional light (the sun)
336 // and the custom depth set to 3 used for semantic segmentation
337 // The solution: Spawn a Decal.
338 // It just works!
339 World->SpawnActor<ADecalActor>(
340 FVector(0,0,-1000000), FRotator(0,0,0), FActorSpawnParameters());
341
343 Manager->InitializeTrafficLights();
344
348
349 if (Episode->Weather != nullptr)
350 {
351 // Per-map defaults now come from MapDefaults.json (either a named
352 // {time, condition} preset pair via ASkyBase::SetAsMapDefault, or a full
353 // inline snapshot via ASkyBase::SaveCurrentWeatherAsMapDefault --
354 // GetMapDefaultWeather resolves whichever shape the entry is), not the
355 // flat carla::rpc::WeatherParameters::Default sentinel (which forces e.g.
356 // SunAltitudeAngle to -1 regardless of what the map's sky rig was
357 // authored with). Fall back to the old sentinel only for maps with no
358 // MapDefaults.json entry yet.
359 FString MapName = World->GetMapName();
360 MapName.RemoveFromStart(World->StreamingLevelsPrefix);
361 FWeatherParameters DefaultWeather;
363 {
364 Episode->Weather->ApplyWeather(DefaultWeather);
365 // The weather actor was spawned during this BeginPlay, so its own
366 // BeginPlay (BP_CarlaWeather: per-town "DefaultWeathers" table, or a
367 // hard-coded fallback + "<map> default weather not found") is deferred
368 // until the world has begun play -- i.e. it runs AFTER the ApplyWeather
369 // above and silently replaces the MapDefaults.json entry (observed on
370 // every baked twin: sun 45/220 + fog 2.0 instead of the authored
371 // defaults). For maps the blueprint table does not know, re-apply the
372 // JSON entry on the next tick so the file wins over the fallback. Maps
373 // in the table (the stock towns) are left to the table on purpose: it
374 // is what they have always rendered with, and several JSON entries
375 // (e.g. Town10HD_Opt) disagree with it.
376 // A Multi-GPU secondary gets the primary's weather instead.
378 {
379 TWeakObjectPtr<AWeather> WeakWeather = Episode->Weather;
380 World->GetTimerManager().SetTimerForNextTick([WeakWeather, DefaultWeather]()
381 {
382 if (WeakWeather.IsValid())
383 {
384 WeakWeather->ApplyWeather(DefaultWeather);
385 }
386 });
387 }
388 }
389 else
390 {
392 }
393 }
394
395 /// @todo Recorder should not tick here, FCarlaEngine should do it.
396 // check if replayer is waiting to autostart
397 if (Recorder)
398 {
400 }
401
403 {
405 }
406
407 if (LMManager) {
410 }
411
412 // Manually run begin play on lights as it may not run on sublevels
413 TArray<AActor*> FoundActors;
414 UGameplayStatics::GetAllActorsOfClass(World, AActor::StaticClass(), FoundActors);
415 for(AActor* Actor : FoundActors)
416 {
417 TArray<UCarlaLight*> Lights;
418 Actor->GetComponents(Lights, false);
419 for(UCarlaLight* Light : Lights)
420 {
421 Light->RegisterLight();
422 }
423 }
425}
426
428{
429 TArray<FString> Names;
430 TArray<AActor*> Actors;
431 UGameplayStatics::GetAllActorsOfClass(GetWorld(), AActor::StaticClass(), Actors);
432 for (AActor* Actor : Actors)
433 {
434 TArray<UStaticMeshComponent*> StaticMeshes;
435 Actor->GetComponents(StaticMeshes);
436 if (StaticMeshes.Num())
437 {
438 Names.Add(Actor->GetName());
439 }
440 }
441 return Names;
442}
443
445{
446 TArray<AActor*> Actors;
447 UGameplayStatics::GetAllActorsOfClass(GetWorld(), AActor::StaticClass(), Actors);
448 for (AActor* Actor : Actors)
449 {
450 if(Actor->GetName() == ActorName)
451 {
452 return Actor;
453 break;
454 }
455 }
456 return nullptr;
457}
458
460{
461 FlushRenderingCommands();
462 TArray<FColor> Colors;
463 for (uint32_t y = 0; y < Texture.GetHeight(); y++)
464 {
465 for (uint32_t x = 0; x < Texture.GetWidth(); x++)
466 {
467 auto& Color = Texture.At(x,y);
468 Colors.Add(FColor(Color.r, Color.g, Color.b, Color.a));
469 }
470 }
471 UTexture2D* UETexture = UTexture2D::CreateTransient(Texture.GetWidth(), Texture.GetHeight(), EPixelFormat::PF_B8G8R8A8);
472 FTexture2DMipMap& Mip = UETexture->GetPlatformData()->Mips[0];
473 void* Data = Mip.BulkData.Lock( LOCK_READ_WRITE );
474 FMemory::Memcpy( Data,
475 &Colors[0],
476 Texture.GetWidth()*Texture.GetHeight()*sizeof(FColor));
477 Mip.BulkData.Unlock();
478 UETexture->UpdateResource();
479 return UETexture;
480}
481
483{
484 FlushRenderingCommands();
485 TArray<FFloat16Color> Colors;
486 for (uint32_t y = 0; y < Texture.GetHeight(); y++)
487 {
488 for (uint32_t x = 0; x < Texture.GetWidth(); x++)
489 {
490 auto& Color = Texture.At(x,y);
491 Colors.Add(FLinearColor(Color.r, Color.g, Color.b, Color.a));
492 }
493 }
494 UTexture2D* UETexture = UTexture2D::CreateTransient(Texture.GetWidth(), Texture.GetHeight(), EPixelFormat::PF_FloatRGBA);
495 FTexture2DMipMap& Mip = UETexture->GetPlatformData()->Mips[0];
496 void* Data = Mip.BulkData.Lock( LOCK_READ_WRITE );
497 FMemory::Memcpy( Data,
498 &Colors[0],
499 Texture.GetWidth()*Texture.GetHeight()*sizeof(FFloat16Color));
500 Mip.BulkData.Unlock();
501 UETexture->UpdateResource();
502 return UETexture;
503}
504
506 AActor* Actor,
507 UTexture2D* Texture,
508 const carla::rpc::MaterialParameter& TextureParam)
509{
510 namespace cr = carla::rpc;
511 TArray<UStaticMeshComponent*> StaticMeshes;
512 Actor->GetComponents(StaticMeshes);
513 for (UStaticMeshComponent* Mesh : StaticMeshes)
514 {
515 for (int i = 0; i < Mesh->GetNumMaterials(); ++i)
516 {
517 UMaterialInterface* OriginalMaterial = Mesh->GetMaterial(i);
518 UMaterialInstanceDynamic* DynamicMaterial = Cast<UMaterialInstanceDynamic>(OriginalMaterial);
519 if(!DynamicMaterial)
520 {
521 DynamicMaterial = UMaterialInstanceDynamic::Create(OriginalMaterial, NULL);
522 Mesh->SetMaterial(i, DynamicMaterial);
523 }
524
525 switch(TextureParam)
526 {
527 case cr::MaterialParameter::Tex_Diffuse:
528 DynamicMaterial->SetTextureParameterValue("BaseColor", Texture);
529 DynamicMaterial->SetTextureParameterValue("Difuse", Texture);
530 DynamicMaterial->SetTextureParameterValue("Difuse 2", Texture);
531 DynamicMaterial->SetTextureParameterValue("Difuse 3", Texture);
532 DynamicMaterial->SetTextureParameterValue("Difuse 4", Texture);
533 break;
534 case cr::MaterialParameter::Tex_Normal:
535 DynamicMaterial->SetTextureParameterValue("Normal", Texture);
536 DynamicMaterial->SetTextureParameterValue("Normal 2", Texture);
537 DynamicMaterial->SetTextureParameterValue("Normal 3", Texture);
538 DynamicMaterial->SetTextureParameterValue("Normal 4", Texture);
539 break;
540 case cr::MaterialParameter::Tex_Emissive:
541 DynamicMaterial->SetTextureParameterValue("Emissive", Texture);
542 break;
543 case cr::MaterialParameter::Tex_Ao_Roughness_Metallic_Emissive:
544 DynamicMaterial->SetTextureParameterValue("AO / Roughness / Metallic / Emissive", Texture);
545 DynamicMaterial->SetTextureParameterValue("ORMH", Texture);
546 DynamicMaterial->SetTextureParameterValue("ORMH 2", Texture);
547 DynamicMaterial->SetTextureParameterValue("ORMH 3", Texture);
548 DynamicMaterial->SetTextureParameterValue("ORMH 4", Texture);
549 break;
550 }
551 }
552 }
553}
554
555void ACarlaGameModeBase::Tick(float DeltaSeconds)
556{
557 TRACE_CPUPROFILER_EVENT_SCOPE(ACarlaGameModeBase::Tick);
558 Super::Tick(DeltaSeconds);
559
560 /// @todo Recorder should not tick here, FCarlaEngine should do it.
561 if (Recorder)
562 {
563 Recorder->Tick(DeltaSeconds);
564 }
565}
566
567void ACarlaGameModeBase::OnLevelAddedToWorld(ULevel* InLevel, UWorld* InWorld)
568{
569 if (InLevel == nullptr || InWorld != GetWorld())
570 {
571 return;
572 }
573 ATagger::TagActorsInLevel(*InLevel, true);
574
575 // A converted map's baked TrafficLightManager can stream in later as a
576 // duplicate of the persistent-level manager installed at BeginPlay (see
577 // GetTrafficLightManager); cull it before anything can find it.
578 TArray<AActor*> DuplicateManagers;
579 for (AActor* Actor : InLevel->Actors)
580 {
581 if (Actor != nullptr && Actor != TrafficLightManager &&
582 Actor->IsA<ATrafficLightManager>())
583 {
584 DuplicateManagers.Add(Actor);
585 }
586 }
587 for (AActor* Actor : DuplicateManagers)
588 {
589 UE_LOG(LogCarla, Log, TEXT("Destroying streamed-in duplicate TrafficLightManager %s"),
590 *Actor->GetName());
591 Actor->Destroy();
592 }
593}
594
595void ACarlaGameModeBase::EndPlay(const EEndPlayReason::Type EndPlayReason)
596{
597 FWorldDelegates::LevelAddedToWorld.RemoveAll(this);
599
600 Episode->EndPlay();
602
603 Super::EndPlay(EndPlayReason);
604
605 if ((CarlaSettingsDelegate != nullptr) && (EndPlayReason != EEndPlayReason::EndPlayInEditor))
606 {
608 }
609}
610
612{
613 auto *World = GetWorld();
614 check(World != nullptr);
615
616 for (auto &FactoryClass : ActorFactories)
617 {
618 if (FactoryClass != nullptr)
619 {
620 auto *Factory = World->SpawnActor<ACarlaActorFactory>(FactoryClass);
621 if (Factory != nullptr)
622 {
623 Episode->RegisterActorFactory(*Factory);
624 ActorFactoryInstances.Add(Factory);
625 }
626 else
627 {
628 UE_LOG(LogCarla, Error, TEXT("Failed to spawn actor spawner"));
629 }
630 }
631 }
632}
633
635{
636 for (TActorIterator<AVehicleSpawnPoint> It(GetWorld()); It; ++It)
637 {
638 SpawnPointsTransforms.Add(It->GetActorTransform());
639 }
640
641 if(SpawnPointsTransforms.Num() == 0)
642 {
644 }
645
646 UE_LOG(LogCarla, Log, TEXT("There are %d SpawnPoints in the map"), SpawnPointsTransforms.Num());
647}
648
650{
651 UE_LOG(LogCarla, Log, TEXT("Generating SpawnPoints ..."));
652 std::vector<std::pair<carla::road::element::Waypoint, carla::road::element::Waypoint>> Topology = Map->GenerateTopology();
653 UWorld* World = GetWorld();
654 for(auto& Pair : Topology)
655 {
656 carla::geom::Transform CarlaTransform = Map->ComputeTransform(Pair.first);
657 FTransform Transform(CarlaTransform);
658 Transform.AddToTranslation(FVector(0.f, 0.f, 50.0f));
659 SpawnPointsTransforms.Add(Transform);
660 }
661}
662
664{
665 std::string opendrive_xml = carla::rpc::FromLongFString(UOpenDrive::GetXODR(GetWorld()));
667 if (!Map.has_value()) {
668 UE_LOG(LogCarla, Error, TEXT("Invalid Map"));
669 }
670 else
671 {
672 Episode->MapGeoProjection = Map->GetGeoProjection();
673 }
674}
675
677{
679 {
680 UWorld* World = GetWorld();
681 AActor* TrafficLightManagerActor = UGameplayStatics::GetActorOfClass(World, ATrafficLightManager::StaticClass());
682 ATrafficLightManager* BakedInStreamedCell = nullptr;
683 if (TrafficLightManagerActor != nullptr &&
684 World->GetWorldPartition() != nullptr &&
685 TrafficLightManagerActor->GetLevel() != World->PersistentLevel)
686 {
687 // Converted World Partition maps carry the manager over as a
688 // spatially-loaded external actor inside a streamed cell; anything it
689 // owns dies with the cell. Replace it with a persistent-level manager
690 // that inherits the baked manager's model configuration.
691 BakedInStreamedCell = Cast<ATrafficLightManager>(TrafficLightManagerActor);
692 TrafficLightManagerActor = nullptr;
693 }
694 if(TrafficLightManagerActor == nullptr)
695 {
696 FActorSpawnParameters SpawnParams;
697 SpawnParams.OverrideLevel = GetULevelFromName("TrafficLights");
698 TrafficLightManager = World->SpawnActor<ATrafficLightManager>(SpawnParams);
699 if (BakedInStreamedCell != nullptr && TrafficLightManager != nullptr)
700 {
702 BakedInStreamedCell->Destroy();
703 }
704 }
705 else
706 {
707 TrafficLightManager = Cast<ATrafficLightManager>(TrafficLightManagerActor);
708 }
709 }
710 return TrafficLightManager;
711}
712
714{
715 TArray<AActor*> WorldActors;
716 UGameplayStatics::GetAllActorsOfClass(GetWorld(), AStaticMeshActor::StaticClass(), WorldActors);
717
718 for (AActor *Actor : WorldActors)
719 {
720 AStaticMeshActor *MeshActor = CastChecked<AStaticMeshActor>(Actor);
721 if (MeshActor->GetStaticMeshComponent()->GetStaticMesh() == NULL)
722 {
723 UE_LOG(LogTemp, Error, TEXT("The object : %s has no mesh"), *MeshActor->GetFullName());
724 }
725 }
726}
727
729{
730 TArray<AActor*> WorldActors;
731 UGameplayStatics::GetAllActorsOfClass(GetWorld(), AStaticMeshActor::StaticClass(), WorldActors);
732
733 for(AActor *Actor : WorldActors)
734 {
735 AStaticMeshActor *MeshActor = CastChecked<AStaticMeshActor>(Actor);
736 if(MeshActor->GetStaticMeshComponent()->GetStaticMesh() != NULL)
737 {
738 auto MeshTag = ATagger::GetTagOfTaggedComponent(*MeshActor->GetStaticMeshComponent());
739 namespace crp = carla::rpc;
740 if (MeshTag != crp::CityObjectLabel::Roads &&
741 MeshTag != crp::CityObjectLabel::Sidewalks &&
742 MeshTag != crp::CityObjectLabel::RoadLines &&
743 MeshTag != crp::CityObjectLabel::Ground &&
744 MeshTag != crp::CityObjectLabel::Terrain &&
745 MeshActor->GetStaticMeshComponent()->GetGenerateOverlapEvents() == false)
746 {
747 MeshActor->GetStaticMeshComponent()->SetGenerateOverlapEvents(true);
748 }
749 }
750 }
751}
752
754{
755
756 auto World = GetWorld();
757 check(World != nullptr);
758
759 if(!Map)
760 {
761 return;
762 }
763
764 if(!enable)
765 {
766 UKismetSystemLibrary::FlushDebugStrings(World);
767 UKismetSystemLibrary::FlushPersistentDebugLines(World);
768 return;
769 }
770
771 //const std::unordered_map<carla::road::SignId, std::unique_ptr<carla::road::Signal>>
772 const auto& Signals = Map->GetSignals();
773 const auto& Controllers = Map->GetControllers();
774
775 for(const auto& Signal : Signals) {
776 const auto& ODSignal = Signal.second;
777 const FTransform Transform = ODSignal->GetTransform();
778 const FVector Location = Transform.GetLocation();
779 const FQuat Rotation = Transform.GetRotation();
780 const FVector Up = Rotation.GetUpVector();
781 DrawDebugSphere(
782 World,
783 Location,
784 50.0f,
785 10,
786 FColor(0, 255, 0),
787 true
788 );
789 }
790
791 TArray<const cre::RoadInfoSignal*> References;
792 auto waypoints = Map->GenerateWaypointsOnRoadEntries();
793 std::unordered_set<cr::RoadId> ExploredRoads;
794 for (auto & waypoint : waypoints)
795 {
796 // Check if we already explored this road
797 if (ExploredRoads.count(waypoint.road_id) > 0)
798 {
799 continue;
800 }
801 ExploredRoads.insert(waypoint.road_id);
802
803 // Multiple times for same road (performance impact, not in behavior)
804 auto SignalReferences = Map->GetLane(waypoint).
805 GetRoad()->GetInfos<cre::RoadInfoSignal>();
806 for (auto *SignalReference : SignalReferences)
807 {
808 References.Add(SignalReference);
809 }
810 }
811 for (auto& Reference : References)
812 {
813 auto RoadId = Reference->GetRoadId();
814 const auto* SignalReference = Reference;
815 const FTransform SignalTransform = SignalReference->GetSignal()->GetTransform();
816 for(auto &validity : SignalReference->GetValidities())
817 {
818 for(auto lane : carla::geom::Math::GenerateRange(validity._from_lane, validity._to_lane))
819 {
820 if(lane == 0)
821 continue;
822
823 auto signal_waypoint = Map->GetWaypoint(
824 RoadId, lane, SignalReference->GetS()).value();
825
826 if(Map->GetLane(signal_waypoint).GetType() != cr::Lane::LaneType::Driving)
827 continue;
828
829 FTransform ReferenceTransform = Map->ComputeTransform(signal_waypoint);
830
831 DrawDebugSphere(
832 World,
833 ReferenceTransform.GetLocation(),
834 50.0f,
835 10,
836 FColor(0, 0, 255),
837 true
838 );
839
840 DrawDebugLine(
841 World,
842 ReferenceTransform.GetLocation(),
843 SignalTransform.GetLocation(),
844 FColor(0, 0, 255),
845 true
846 );
847 }
848 }
849 }
850
851}
852
853TArray<FBoundingBox> ACarlaGameModeBase::GetAllBBsOfLevel(uint8 TagQueried) const
854{
855 UWorld* World = GetWorld();
856
857 // Get all actors of the level
858 TArray<AActor*> FoundActors;
859 UGameplayStatics::GetAllActorsOfClass(World, AActor::StaticClass(), FoundActors);
860
861 TArray<FBoundingBox> BoundingBoxes;
862 BoundingBoxes = UBoundingBoxCalculator::GetBoundingBoxOfActors(FoundActors, TagQueried);
863
864 return BoundingBoxes;
865}
866
868{
869 // Get all actors of the level
870 TArray<AActor*> FoundActors;
871 UGameplayStatics::GetAllActorsOfClass(GetWorld(), AActor::StaticClass(), FoundActors);
872 // A disabled object whose actor is still in the world stays disabled, also
873 // when it registers again under another id (a hidden instance is moved
874 // away, and its id hashes its location; a hidden traffic-light box has no
875 // bounds). One that streamed out with its layer is gone, and comes back
876 // enabled.
877 TSet<uint64> StillLoaded;
878 if (DisabledEnvironmentObjects.Num() > 0)
879 {
880 TSet<const AActor*> LoadedActors;
881 LoadedActors.Reserve(FoundActors.Num());
882 for (const AActor* Actor : FoundActors)
883 {
884 LoadedActors.Add(Actor);
885 }
887 }
888 ObjectRegister->RegisterObjects(FoundActors);
890 if (DisabledEnvironmentObjects.Num() > 0)
891 {
892 TSet<uint64> Kept = StillLoaded.Union(ObjectRegister->FindEnvironmentObjects(DisabledEnvironmentObjects));
893 if (Kept.Num() != DisabledEnvironmentObjects.Num())
894 {
895 DisabledEnvironmentObjects = MoveTemp(Kept);
897 }
898 }
899}
900
902 const TSet<uint64>& EnvObjectIds,
903 bool Enable)
904{
905 ObjectRegister->EnableEnvironmentObjects(EnvObjectIds, Enable);
906 // Only objects that exist: an unknown id changes nothing.
907 for (const uint64 Id : ObjectRegister->FindEnvironmentObjects(EnvObjectIds))
908 {
909 if (Enable)
910 {
912 }
913 else
914 {
916 }
917 }
919}
920
922{
923 LoadedMapLayers |= MapLayers;
924 const UWorld* World = GetWorld();
925 UGameplayStatics::FlushLevelStreaming(World);
926
927 TArray<FName> LevelsToLoad;
928 ConvertMapLayerMaskToMapNames(MapLayers, LevelsToLoad);
929
930 FLatentActionInfo LatentInfo;
931 LatentInfo.CallbackTarget = this;
932 LatentInfo.ExecutionFunction = "OnLoadStreamLevel";
933 LatentInfo.Linkage = 0;
934 LatentInfo.UUID = LatentInfoUUID;
935
936 PendingLevelsToLoad = LevelsToLoad.Num();
937
938 for(FName& LevelName : LevelsToLoad)
939 {
941 UGameplayStatics::LoadStreamLevel(World, LevelName, true, true, LatentInfo);
942 LatentInfo.UUID = LatentInfoUUID;
943 UGameplayStatics::FlushLevelStreaming(World);
944 }
945}
946
948{
949 LoadedMapLayers &= ~MapLayers;
950 const UWorld* World = GetWorld();
951
952 TArray<FName> LevelsToUnLoad;
953 ConvertMapLayerMaskToMapNames(MapLayers, LevelsToUnLoad);
954
955 FLatentActionInfo LatentInfo;
956 LatentInfo.CallbackTarget = this;
957 LatentInfo.ExecutionFunction = "OnUnloadStreamLevel";
958 LatentInfo.UUID = LatentInfoUUID;
959 LatentInfo.Linkage = 0;
960
961 PendingLevelsToUnLoad = LevelsToUnLoad.Num();
962
963 for(FName& LevelName : LevelsToUnLoad)
964 {
966 UGameplayStatics::UnloadStreamLevel(World, LevelName, LatentInfo, false);
967 LatentInfo.UUID = LatentInfoUUID;
968 UGameplayStatics::FlushLevelStreaming(World);
969 }
970
971}
972
973void ACarlaGameModeBase::ConvertMapLayerMaskToMapNames(int32 MapLayer, TArray<FName>& OutLevelNames)
974{
975 UWorld* World = GetWorld();
976 const TArray <ULevelStreaming*> Levels = World->GetStreamingLevels();
977 TArray<FString> LayersToLoad;
978
979 // Get all the requested layers
980 int32 LayerMask = 1;
981 int32 AllLayersMask = static_cast<crp::MapLayerType>(crp::MapLayer::All);
982
983 while(LayerMask > 0)
984 {
985 // Convert enum to FString
986 FString LayerName = UTF8_TO_TCHAR(MapLayerToString(static_cast<crp::MapLayer>(LayerMask)).c_str());
987 bool included = static_cast<crp::MapLayerType>(MapLayer) & LayerMask;
988 if(included)
989 {
990 LayersToLoad.Emplace(LayerName);
991 }
992 LayerMask = (LayerMask << 1) & AllLayersMask;
993 }
994
995 // Get all the requested level maps
996 for(ULevelStreaming* Level : Levels)
997 {
998 TArray<FString> StringArray;
999 FString FullSubMapName = Level->GetWorldAssetPackageFName().ToString();
1000 // Discard full path, we just need the umap name
1001 FullSubMapName.ParseIntoArray(StringArray, TEXT("/"), false);
1002 FString SubMapName = StringArray[StringArray.Num() - 1];
1003 for(FString LayerName : LayersToLoad)
1004 {
1005 if(SubMapName.Contains(LayerName))
1006 {
1007 OutLevelNames.Emplace(FName(*SubMapName));
1008 break;
1009 }
1010 }
1011 }
1012
1013}
1014
1016{
1017 ULevel* OutLevel = nullptr;
1018 UWorld* World = GetWorld();
1019 const TArray <ULevelStreaming*> Levels = World->GetStreamingLevels();
1020
1021 for(ULevelStreaming* Level : Levels)
1022 {
1023 FString FullSubMapName = Level->GetWorldAssetPackageFName().ToString();
1024 if(FullSubMapName.Contains(LevelName))
1025 {
1026 OutLevel = Level->GetLoadedLevel();
1027 if(!OutLevel)
1028 {
1029 UE_LOG(LogCarla, Warning, TEXT("%s has not been loaded"), *LevelName);
1030 }
1031 break;
1032 }
1033 }
1034
1035 // With no matching sublevel the callers used to pass OverrideLevel=nullptr,
1036 // and UWorld::SpawnActor then falls back to the OWNER's level. On converted
1037 // World Partition maps the owner (the baked TrafficLightManager) lives in a
1038 // streamed cell, so every runtime signal landed in that one cell and was
1039 // silently torn down (no AActor::Destroy, no OnDestroyed) whenever the cell
1040 // streamed out. Fall back to the persistent level instead so runtime-spawned
1041 // managers, groups and signals always survive streaming.
1042 if (OutLevel == nullptr)
1043 {
1044 OutLevel = World->PersistentLevel;
1045 }
1046
1047 return OutLevel;
1048}
1049
1051{
1053
1054 // Register new actors and tag them
1056 {
1058 ATagger::TagActorsInLevel(*GetWorld(), true);
1059 }
1060}
1061
1063{
1065 // Update stored registered objects (discarding the deleted objects)
1067 {
1069 }
1070}
1071
static bool IsMapInBlueprintWeatherTable(const AWeather *Weather, const FString &MapName)
float y
float x
Base class for Carla actor factories.
TSubclassOf< AWeather > WeatherClass
The class of Weather to spawn.
void UnLoadMapLayer(int32 MapLayers)
TArray< FTransform > SpawnPointsTransforms
std::optional< carla::road::Map > Map
void EnableEnvironmentObjects(const TSet< uint64 > &EnvObjectIds, bool Enable)
TArray< ACarlaActorFactory * > ActorFactoryInstances
void DebugShowSignals(bool enable)
void BeginPlay() override
UCarlaGameInstance * GameInstance
UCarlaSettingsDelegate * CarlaSettingsDelegate
AActor * FindActorByName(const FString &ActorName)
void LoadMapLayer(int32 MapLayers)
void InitGame(const FString &MapName, const FString &Options, FString &ErrorMessage) override
void ApplyTextureToActor(AActor *Actor, UTexture2D *Texture, const carla::rpc::MaterialParameter &TextureParam)
const FString GetFullMapPath() const
ALargeMapManager * LMManager
void RestartPlayer(AController *NewPlayer) override
FOnEpisodeInitialisedDelegate OnEpisodeInitialisedDelegate
ACarlaRecorder * Recorder
TSet< uint64 > DisabledEnvironmentObjects
void EndPlay(const EEndPlayReason::Type EndPlayReason) override
ULevel * GetULevelFromName(FString LevelName)
void OnLevelAddedToWorld(ULevel *InLevel, UWorld *InWorld)
Tags actors of World Partition cells as they stream in.
FDelegateHandle OnEpisodeSettingsChangeHandle
const FString GetRelativeMapPath() const
void ConvertMapLayerMaskToMapNames(int32 MapLayer, TArray< FName > &OutLevelNames)
UTaggerDelegate * TaggerDelegate
ATrafficLightManager * TrafficLightManager
UObjectRegister * ObjectRegister
void OnEpisodeSettingsChanged(const FEpisodeSettings &Settings)
ATrafficLightManager * GetTrafficLightManager()
TArray< FString > GetNamesOfAllActors()
UCarlaEpisode * Episode
void Tick(float DeltaSeconds) override
TArray< FBoundingBox > GetAllBBsOfLevel(uint8 TagQueried=0xFF) const
ACarlaGameModeBase(const FObjectInitializer &ObjectInitializer)
TSet< TSubclassOf< ACarlaActorFactory > > ActorFactories
List of actor spawners that will be used to define and spawn the actors available in game.
virtual void LoadGeoReference()
Loads the episode georeference (parsing the map's OpenDRIVE by default) and stores the recommended sp...
UTexture2D * CreateUETexture(const carla::rpc::TextureColor &Texture)
CarlaReplayer * GetReplayer(void)
void SetEpisode(UCarlaEpisode *ThisEpisode)
int GetNumTiles() const
void ConsiderSpectatorAsEgo(bool _SpectatorAsEgo)
static const FName FallbackSkyTag
Definition Sky.h:118
static crp::CityObjectLabel GetTagOfTaggedComponent(const UPrimitiveComponent &Component)
Retrieve the tag of an already tagged component.
Definition Tagger.cpp:213
static void TagActorsInLevel(UWorld &World, bool bTagForSemanticSegmentation)
Set the tag of every actor in level.
Definition Tagger.cpp:177
Class In charge of creating and assigning traffic light groups, controllers and components.
void AdoptModelConfigurationFrom(const ATrafficLightManager &Other)
Copy the authored model configuration (traffic light / sign / speed limit blueprints) from another ma...
void ApplyWeather(const FWeatherParameters &WeatherParameters)
Update the weather parameters and notifies it to the blueprint's event.
Definition Weather.cpp:2597
const FWeatherParameters & GetCurrentWeather() const
Returns the current WeatherParameters.
Definition Weather.h:59
void CheckPlayAfterMapLoaded(void)
static FOnEpisodeSettingsChange OnEpisodeSettingsChange
static TArray< FBoundingBox > GetBoundingBoxOfActors(const TArray< AActor * > &Actors, uint8 InTagQueried=0xFF)
AWeather * Weather
void RegisterActorFactory(ACarlaActorFactory &ActorFactory)
const FEpisodeSettings & GetSettings() const
void SetRecorder(ACarlaRecorder *Rec)
void InitializeAtBeginPlay()
carla::geom::GeoProjection MapGeoProjection
void NotifyBeginEpisode(UCarlaEpisode &Episode)
FCarlaEngine * GetCarlaEngine()
int32 GetCurrentMapLayer() const
void ApplyQualityLevelPreRestart()
Before loading a level, apply the current settings.
void ApplyQualityLevelPostRestart()
After loading a level, apply the current settings.
void Reset()
Reset settings to default.
void SetAllActorsDrawDistance(UWorld *world, float max_draw_distance) const
void RegisterSpawnHandler(UWorld *World)
Create the event trigger handler for all the newly spawned actors to be processed with a custom funct...
void EnableEnvironmentObjects(const TSet< uint64 > &EnvObjectIds, bool Enable)
void RegisterObjects(TArray< AActor * > Actors)
TSet< uint64 > FindEnvironmentObjectsOf(const TSet< uint64 > &EnvObjectIds, const TSet< const AActor * > &Actors) const
The ids of EnvObjectIds registered now for an actor of Actors.
TSet< uint64 > FindEnvironmentObjects(const TSet< uint64 > &EnvObjectIds) const
The ids of EnvObjectIds that are registered now.
static FString GetXODR(const UWorld *World)
Return the OpenDrive XML associated to MapName, or empty if the file is not found.
void SetSemanticSegmentationEnabled(bool Enable=true)
void RegisterSpawnHandler(UWorld *World)
static bool GetMapDefaultWeather(const FString &MapName, const FWeatherParameters &Base, UPARAM(ref) FWeatherParameters &OutWeather)
static std::vector< int > GenerateRange(int a, int b)
Definition Math.cpp:159
Vector3D GetUpVector() const
Definition Rotation.h:83
A rigid transform in CARLA's / Unreal's left-handed frame: x forward, y right, z up,...
static std::optional< road::Map > Load(const std::string &opendrive)
T & At(uint32_t x, uint32_t y)
Definition Texture.h:43
uint32_t GetWidth() const
Definition Texture.h:29
uint32_t GetHeight() const
Definition Texture.h:33
uint16_t MapLayerType
Definition MapLayer.h:16