CARLA
Loading...
Searching...
No Matches
LargeMapManager.cpp
Go to the documentation of this file.
1// Copyright (c) 2026 Computer Vision Center (CVC) at the Universitat Autonoma de Barcelona (UAB).
2// This work is licensed under the terms of the MIT license.
3// For a copy, see <https://opensource.org/licenses/MIT>.
4
5#include "LargeMapManager.h"
6
7#include "Game/CarlaStatics.h"
9#include "Game/CarlaEpisode.h"
10
12
13#include "Walker/WalkerBase.h"
14#include "Carla/Game/Tagger.h"
17
18#include <util/ue-header-guard-begin.h>
19#include "Engine/Engine.h"
20#include "Engine/WorldComposition.h"
21#include "Engine/ObjectLibrary.h"
22#include "Misc/FileHelper.h"
23#include "Misc/Paths.h"
24#include "Engine/EngineTypes.h"
25#include "Components/PrimitiveComponent.h"
26#include "Landscape.h"
27#include "LandscapeHeightfieldCollisionComponent.h"
28#include "LandscapeComponent.h"
29#include <util/ue-header-guard-end.h>
30
31#define LARGEMAP_LOGS 1
32
33#if LARGEMAP_LOGS
34#define LM_LOG(Level, Msg, ...) UE_LOG(LogCarla, Level, TEXT(Msg), ##__VA_ARGS__)
35#else
36#define LM_LOG(...)
37#endif
38
39// Sets default values
41{
42 PrimaryActorTick.bCanEverTick = true;
43 // PrimaryActorTick.TickInterval = TickInterval;
44}
45
47{
48 /// Remove delegates
49 // Origin rebase
50 FCoreDelegates::PreWorldOriginOffset.RemoveAll(this);
51 FCoreDelegates::PostWorldOriginOffset.RemoveAll(this);
52 // Level added/removed from world
53 FWorldDelegates::LevelRemovedFromWorld.RemoveAll(this);
54 FWorldDelegates::LevelAddedToWorld.RemoveAll(this);
55
56}
57
58// Called when the game starts or when spawned
60{
61 Super::BeginPlay();
62
63 UWorld* World = GetWorld();
64 if (World->GetWorldPartition() != nullptr || World->WorldComposition == nullptr)
65 {
66 // World Partition world (or no WorldComposition at all): the engine
67 // streams cells natively with absolute double-precision coordinates, and
68 // every code path below assumes a valid WorldComposition. Retire quietly.
69 UE_LOG(LogCarla, Warning, TEXT(
70 "LargeMapManager present in a World Partition world; destroying the "
71 "legacy tile manager (native streaming takes over)."));
72 Destroy();
73 return;
74 }
76 /// Setup delegates
77 // Origin rebase
78 FCoreDelegates::PreWorldOriginOffset.AddUObject(this, &ALargeMapManager::PreWorldOriginOffset);
79 FCoreDelegates::PostWorldOriginOffset.AddUObject(this, &ALargeMapManager::PostWorldOriginOffset);
80 // Level added/removed from world
81 FWorldDelegates::LevelAddedToWorld.AddUObject(this, &ALargeMapManager::OnLevelAddedToWorld);
82 FWorldDelegates::LevelRemovedFromWorld.AddUObject(this, &ALargeMapManager::OnLevelRemovedFromWorld);
83
84 // Setup Origin rebase settings
85 UWorldComposition* WorldComposition = World->WorldComposition;
86 WorldComposition->bRebaseOriginIn3DSpace = true;
87 WorldComposition->RebaseOriginDistance = RebaseOriginDistance;
88
92
93 // Look for terramechanics actor
94 TArray<AActor*> FoundActors;
95 UGameplayStatics::GetAllActorsOfClass(GetWorld(), AActor::StaticClass(), FoundActors);
96 for(auto CurrentActor : FoundActors)
97 {
98 if( CurrentActor->FindComponentByClass( UCustomTerrainPhysicsComponent::StaticClass() ) != nullptr )
99 {
100 bHasTerramechanics = true;
101 break;
102 }
103 }
104
105 // Get spectator
106 APlayerController* PlayerController = UGameplayStatics::GetPlayerController(GetWorld(), 0);
107 if(PlayerController)
108 {
109 Spectator = PlayerController->GetPawnOrSpectator();
110 }
111}
112
113void ALargeMapManager::PreWorldOriginOffset(UWorld* InWorld, FIntVector InSrcOrigin, FIntVector InDstOrigin)
114{
115 LM_LOG(Log, "PreWorldOriginOffset Src: %s -> Dst: %s", *InSrcOrigin.ToString(), *InDstOrigin.ToString());
116}
117
118void ALargeMapManager::PostWorldOriginOffset(UWorld* InWorld, FIntVector InSrcOrigin, FIntVector InDstOrigin)
119{
120 TRACE_CPUPROFILER_EVENT_SCOPE(ALargeMapManager::PostWorldOriginOffset);
121 CurrentOriginInt = InDstOrigin;
122 CurrentOriginD = FDVector(InDstOrigin);
123
124 UWorld* World = GetWorld();
125 UCarlaEpisode* CarlaEpisode = UCarlaStatics::GetCurrentEpisode(World);
127
128#if WITH_EDITOR
129 GEngine->AddOnScreenDebugMessage(66, MsgTime, FColor::Yellow,
130 FString::Printf(TEXT("Src: %s -> Dst: %s"), *InSrcOrigin.ToString(), *InDstOrigin.ToString()));
131 LM_LOG(Log, "PostWorldOriginOffset Src: %s -> Dst: %s", *InSrcOrigin.ToString(), *InDstOrigin.ToString());
132
133 // This is just to update the color of the msg with the same as the closest map
134 const TArray<ULevelStreaming*>& StreamingLevels = World->GetStreamingLevels();
135 FColor LevelColor = FColor::White;
136 float MinDistance = 10000000.0f;
137 for (const auto& TilePair : MapTiles)
138 {
139 const FCarlaMapTile& Tile = TilePair.Value;
140 const ULevelStreaming* Level = Tile.StreamingLevel;
141 FVector LevelLocation = Tile.Location;
142 float Distance = FVector::Dist(LevelLocation, FVector(InDstOrigin));
143 if (Distance < MinDistance)
144 {
145 MinDistance = Distance;
146 PositonMsgColor = Level->LevelColor.ToFColor(false);
147 }
148 }
149#endif // WITH_EDITOR
150}
151
152void ALargeMapManager::OnLevelAddedToWorld(ULevel* InLevel, UWorld* InWorld)
153{
154 LM_LOG(Warning, "OnLevelAddedToWorld");
155 ATagger::TagActorsInLevel(*InLevel, true);
156
158
159 //FDebug::DumpStackTraceToLog(ELogVerbosity::Log);
160}
161
162void ALargeMapManager::OnLevelRemovedFromWorld(ULevel* InLevel, UWorld* InWorld)
163{
164 LM_LOG(Warning, "OnLevelRemovedFromWorld");
165 //FDebug::DumpStackTraceToLog(ELogVerbosity::Log);
166 FCarlaMapTile& Tile = GetCarlaMapTile(InLevel);
167 Tile.TilesSpawned = false;
168}
169
171{
172 // Look the manager up read-only (do not spawn one) so this streaming
173 // callback has no side effects when there is no manager. The generated
174 // signs live in the persistent level, not in the tile, so the manager
175 // checks all of them and skips the ones that are already on the ground.
176 AActor* ManagerActor = UGameplayStatics::GetActorOfClass(
177 GetWorld(), ATrafficLightManager::StaticClass());
178 if (ATrafficLightManager* Manager = Cast<ATrafficLightManager>(ManagerActor))
179 {
180 Manager->SnapSignsToGround();
181 }
182}
183
185{
186 TRACE_CPUPROFILER_EVENT_SCOPE(ALargeMapManager::RegisterInitialObjects);
187 UWorld* World = GetWorld();
188 UCarlaEpisode* CurrentEpisode = UCarlaStatics::GetCurrentEpisode(World);
189 const FActorRegistry& ActorRegistry = CurrentEpisode->GetActorRegistry();
190 for (const auto& CarlaActorPair : ActorRegistry)
191 {
192 if (CarlaActorPair.Value->GetActorInfo()->Description.Id == "spectator")
193 {
194 continue;
195 }
196 OnActorSpawned(*CarlaActorPair.Value.Get());
197 }
198}
199
201 const FCarlaActor& CarlaActor)
202{
203 TRACE_CPUPROFILER_EVENT_SCOPE(ALargeMapManager::OnActorSpawned);
204 UWorld* World = GetWorld();
205 const FActorInfo* ActorInfo = CarlaActor.GetActorInfo();
206 AActor* Actor = const_cast<AActor*>(CarlaActor.GetActor());
207 bool IsHeroVehicle = false;
208
209 // LM_LOG(Warning, "ALargeMapManager::OnActorSpawned func %s %s", *Actor->GetName(), *Actor->GetTranslation().ToString());
210
211 if (Actor)
212 { // Check if is hero vehicle
213
214 assert(ActorInfo);
215
216 const FActorDescription& Description = ActorInfo->Description;
217 const FActorAttribute* Attribute = Description.Variations.Find("role_name");
218 // If is the hero vehicle
219 if(Attribute && (Attribute->Value.Contains("hero") || Attribute->Value.Contains("ego_vehicle")))
220 {
221 LM_LOG(Log, "HERO VEHICLE DETECTED");
222
223 if (ActorsToConsider.Num() == 1 && ActorsToConsider.Contains(Spectator))
224 {
225 ActorsToConsider.Reset();
226 }
227 ActorsToConsider.Add(Actor);
228
230
232
233 // Wait until the pending levels changes are finished to avoid spawning
234 // the car without ground underneath
235 World->FlushLevelStreaming();
236
238
239 IsHeroVehicle = true;
240 }
241 }
242
243 // Any other actor that its role is not "hero"
244 if(!IsHeroVehicle)
245 {
246 UCarlaEpisode* CurrentEpisode = UCarlaStatics::GetCurrentEpisode(World);
247 const FActorRegistry& ActorRegistry = CurrentEpisode->GetActorRegistry();
248
249 // Any actor that is not the hero vehicle could possible be destroyed at some point
250 // we need to store the CarlaActor information to be able to spawn it again if needed
251
252 if(IsValid(Actor))
253 { // Actor was spwaned succesfully
254 // TODO: not dormant but not hero => ActiveActor
255 // LM: Map<AActor* FActiveActor> maybe per tile and in a tile sublevel?
256
257 LM_LOG(Log, "ACTIVE VEHICLE DETECTED");
258 ActiveActors.Add(CarlaActor.GetActorId());
259 }
260 else
261 { // Actor was spawned as dormant
262 // TODO: dormant => no actor so Actorview stored per tile
263 // LM: Map<ActorId, TileID> , Tile: Map<ActorID, FDormantActor>
264 // In case of update: update Tile Map, update LM Map
265 LM_LOG(Log, "DORMANT VEHICLE DETECTED");
266 DormantActors.Add(CarlaActor.GetActorId());
267 }
268 }
269
270 if (IsValid(Actor)) {
271 Actor->OnDestroyed.AddDynamic(this, &ALargeMapManager::OnActorDestroyed);
272 FVector GlobalPosition = LocalToGlobalLocation(Actor->GetActorLocation());
273 LM_LOG(Warning, "Actor Spawned at %s", *GlobalPosition.ToString());
274 }
275
276}
277
279{
280 if (ActorsToConsider.Num() > 0)
281 {
282 ACarlaWheeledVehicle* Hero = Cast<ACarlaWheeledVehicle>(ActorsToConsider[0]);
283 if (IsValid(Hero))
284 return Hero;
285 }
286 return nullptr;
287}
288
290{
291 LM_LOG(Warning, "ALargeMapManager::OnActorDestroyed %s", *DestroyedActor->GetName());
292
293 UWorld* World = GetWorld();
294 UCarlaEpisode* CarlaEpisode = UCarlaStatics::GetCurrentEpisode(World);
295 FCarlaActor* CarlaActor = CarlaEpisode->FindCarlaActor(DestroyedActor);
296 if (CarlaActor)
297 const FActorInfo* ActorInfo = CarlaActor->GetActorInfo();
298
299 // Hero has been removed?
300 //
301
302}
303
304void ALargeMapManager::SetTile0Offset(const FVector& Offset)
305{
306 Tile0Offset = Offset;
307}
308
310{
311 TileSide = Size;
312}
313
315{
316 return TileSide;
317}
318
320{
321 return Tile0Offset;
322}
323
330
337
342
347
348FTransform ALargeMapManager::GlobalToLocalTransform(const FTransform& InTransform) const
349{
350 return FTransform(
351 InTransform.GetRotation(),
352 InTransform.GetLocation() - CurrentOriginD.ToFVector(),
353 InTransform.GetScale3D());
354}
355
356FVector ALargeMapManager::GlobalToLocalLocation(const FVector& InLocation) const
357{
358 return InLocation - CurrentOriginD.ToFVector();
359}
360
361FTransform ALargeMapManager::LocalToGlobalTransform(const FTransform& InTransform) const
362{
363 return FTransform(
364 InTransform.GetRotation(),
365 CurrentOriginD.ToFVector() + InTransform.GetLocation(),
366 InTransform.GetScale3D());
367}
368
369FVector ALargeMapManager::LocalToGlobalLocation(const FVector& InLocation) const
370{
371 return CurrentOriginD.ToFVector() + InLocation;
372}
373
375uint64_t num_ticks = 0;
376void ALargeMapManager::Tick(float DeltaTime)
377{
378 Super::Tick(DeltaTime);
379
380 // Update map tiles, load/unload based on actors to consider (heros) position
381 // Also, to avoid looping over the heros again, it checks if any actor to consider has been removed
383
384 // Check if active actors are still in range and inside a loaded tile or have to be converted to dormant
386
387 // Check if dormant actors have been moved to the load range
389
390 // Remove the hero actors that doesn't exits any more from the ActorsToConsider vector
392
394
396
398
399#if WITH_EDITOR
401#endif // WITH_EDITOR
402
403}
404
408
409void ALargeMapManager::GenerateMap(FString InAssetsPath)
410{
411 TRACE_CPUPROFILER_EVENT_SCOPE(ALargeMapManager::GenerateMap);
412 LM_LOG(Warning, "Generating Map %s ...", *InAssetsPath);
414
415 AssetsPath = InAssetsPath;
416
417 /// Retrive all the assets in the path
418 TArray<FAssetData> AssetsData;
419 UObjectLibrary* ObjectLibrary = UObjectLibrary::CreateLibrary(UWorld::StaticClass(), true, true);
420 ObjectLibrary->LoadAssetDataFromPath(InAssetsPath);
421 ObjectLibrary->GetAssetDataList(AssetsData);
422
423 /// Generate tiles based on mesh positions
424 UWorld* World = GetWorld();
425 MapTiles.Reset();
426 for (const FAssetData& AssetData : AssetsData)
427 {
428 #if WITH_EDITOR
429 // LM_LOG(Warning, "Loading asset name: %s", *(AssetData.AssetName.ToString()));
430 // LM_LOG(Warning, "Asset class: %s", *(AssetData.AssetClass.ToString()));
431 #endif
432 FString TileName = AssetData.AssetName.ToString();
433 if (!TileName.Contains("_Tile_"))
434 {
435 continue;
436 }
437 FString TileName_X = "";
438 FString TileName_Y = "";
439 size_t i = TileName.Len()-1;
440 for (; i > 0; i--) {
441 TCHAR character = TileName[i];
442 if (character == '_') {
443 break;
444 }
445 TileName_Y = FString::Chr(character) + TileName_Y;
446 }
447 i--;
448 for (; i > 0; i--) {
449 TCHAR character = TileName[i];
450 if (character == '_') {
451 break;
452 }
453 TileName_X = FString::Chr(character) + TileName_X;
454 }
455 FIntVector TileVectorID = FIntVector(FCString::Atoi(*TileName_X), FCString::Atoi(*TileName_Y), 0);
456 #if WITH_EDITOR
457 // LM_LOG(Warning, "Tile: %d, %d", TileVectorID.X, TileVectorID.Y);
458 #endif
459 TileID TileId = GetTileID(TileVectorID);
460 LoadCarlaMapTile(InAssetsPath + "/" + AssetData.AssetName.ToString(), TileId);
461 }
462 ObjectLibrary->ConditionalBeginDestroy();
463#if WITH_EDITOR
464 GEngine->ForceGarbageCollection(true);
465#endif
466 ActorsToConsider.Reset();
468 {
470 }
471
472#if WITH_EDITOR
473 LM_LOG(Warning, "GenerateMap num Tiles generated %d", MapTiles.Num());
475#endif // WITH_EDITOR
476}
477
478void ALargeMapManager::GenerateMap(TArray<TPair<FString, FIntVector>> MapPathsIds)
479{
480 TRACE_CPUPROFILER_EVENT_SCOPE(ALargeMapManager::GenerateMap);
481 LM_LOG(Warning, "Generating Large Map");
483
484 for (TPair<FString, FIntVector>& PathId : MapPathsIds)
485 {
486 FIntVector& TileVectorID = PathId.Value;
487 FString& Path = PathId.Key;
488 TileID TileId = GetTileID(TileVectorID);
489 LoadCarlaMapTile(Path, TileId);
490 }
491
492 #if WITH_EDITOR
493 LM_LOG(Warning, "GenerateMap num Tiles generated %d", MapTiles.Num());
494 #endif // WITH_EDITOR
495}
496
498{
499 MapTiles.Empty();
500}
501
503{
504 UWorld* World = GetWorld();
505 UWorldComposition* WorldComposition = World->WorldComposition;
506 if (WorldComposition == nullptr)
507 {
508 return;
509 }
510 World->ClearStreamingLevels();
511 WorldComposition->TilesStreaming.Empty();
512 WorldComposition->GetTilesList().Empty();
513
514 for (auto& It : MapTiles)
515 {
516 ULevelStreamingDynamic* StreamingLevel = It.Value.StreamingLevel;
517 World->AddStreamingLevel(StreamingLevel);
518 WorldComposition->TilesStreaming.Add(StreamingLevel);
519 }
520}
521
522// TODO: maybe remove this, I think I will not need it any more
523void ALargeMapManager::AddActorToUnloadedList(const FCarlaActor& CarlaActor, const FTransform& Transform)
524{
525 // ActiveActors.Add(CarlaActor.GetActorId(), {Transform, CarlaActor});
526}
527
529{
530 int32 MinX = 0;
531 int32 MaxX = 0;
532 int32 MinY = 0;
533 int32 MaxY = 0;
534 for (auto& It : MapTiles)
535 {
536 FIntVector TileID = GetTileVectorID(It.Key);
537 MinX = (TileID.X < MinX) ? TileID.X : MinX;
538 MaxX = (TileID.X > MaxX) ? TileID.X : MaxX;
539
540 MinY = (TileID.Y < MinY) ? TileID.Y : MinY;
541 MaxY = (TileID.Y > MaxY) ? TileID.Y : MaxY;
542 }
543 return { MaxX - MinX + 1, MaxY - MinY + 1, 0 };
544}
545
546bool ALargeMapManager::IsLevelOfTileLoaded(FIntVector InTileID) const
547{
548 TileID TileID = GetTileID(InTileID);
549
550 const FCarlaMapTile* Tile = MapTiles.Find(TileID);
551 if (!Tile)
552 {
553 if (bPrintErrors)
554 {
555 LM_LOG(Warning, "IsLevelOfTileLoaded Tile %s does not exist", *InTileID.ToString());
556 }
557 return false;
558 }
559
560 const ULevelStreamingDynamic* StreamingLevel = Tile->StreamingLevel;
561
562 return (StreamingLevel && StreamingLevel->GetLoadedLevel());
563}
564
565FIntVector ALargeMapManager::GetTileVectorID(FVector TileLocation) const
566{
567 FIntVector VectorId = FIntVector(
568 (TileLocation -
569 (Tile0Offset - FVector(0.5f*TileSide,-0.5f*TileSide, 0) + LocalTileOffset))
570 / TileSide);
571 VectorId.Y *= -1;
572 return VectorId;
573}
574
575FIntVector ALargeMapManager::GetTileVectorID(FDVector TileLocation) const
576{
577 FIntVector VectorId = (
578 (TileLocation -
579 (Tile0Offset - FVector(0.5f*TileSide,-0.5f*TileSide, 0) + LocalTileOffset))
580 / TileSide).ToFIntVector();
581 VectorId.Y *= -1;
582 return VectorId;
583}
584
586{
587 return FIntVector{
588 (int32)(TileID >> 32),
589 (int32)(TileID & (int32)(~0)),
590 0
591 };
592}
593
595{
596 FIntVector VTileId = GetTileVectorID(TileID);
597 return GetTileLocation(VTileId);
598}
599
600FVector ALargeMapManager::GetTileLocation(FIntVector TileVectorID) const
601{
602 TileVectorID.Y *= -1;
603 return FVector(TileVectorID)* TileSide + Tile0Offset;
604}
605
607{
608 FIntVector VTileId = GetTileVectorID(TileID);
609 return GetTileLocationD(VTileId);
610}
611
612FDVector ALargeMapManager::GetTileLocationD(FIntVector TileVectorID) const
613{
614 TileVectorID.Y *= -1;
615 return FDVector(TileVectorID) * TileSide + Tile0Offset;
616}
617
619{
620 int64 X = ((int64)(TileVectorID.X) << 32);
621 int64 Y = (int64)(TileVectorID.Y) & 0x00000000FFFFFFFF;
622 return (X | Y);
623}
624
626{
627 FIntVector TileID = GetTileVectorID(TileLocation);
628 return GetTileID(TileID);
629}
630
632{
633 FIntVector TileID = GetTileVectorID(TileLocation);
634 return GetTileID(TileID);
635}
636
638{
639 TileID TileID = GetTileID(Location);
640 return GetCarlaMapTile(TileID);
641}
642
644{
645 FCarlaMapTile* Tile = nullptr;
646 for (auto& It : MapTiles)
647 {
648 ULevelStreamingDynamic* StreamingLevel = It.Value.StreamingLevel;
649 ULevel* Level = StreamingLevel->GetLoadedLevel();
650 if (Level == InLevel)
651 {
652 Tile = &(It.Value);
653 break;
654 }
655 }
656 check(Tile);
657 return *Tile;
658}
659
661{
662 TileID TileID = GetTileID(TileVectorID);
663 FCarlaMapTile* Tile = MapTiles.Find(TileID);
664 return *Tile;
665}
666
668{
669 TileID TileID = GetTileID(TileVectorID);
670 FCarlaMapTile* Tile = MapTiles.Find(TileID);
671 return Tile;
672}
673
679
681 TRACE_CPUPROFILER_EVENT_SCOPE(ALargeMapManager::LoadCarlaMapTile);
682 // Need to generate a new Tile
683 FCarlaMapTile NewTile;
684 // 1 - Calculate the Tile position
685 FIntVector VTileID = GetTileVectorID(TileId);
686 NewTile.Location = GetTileLocation(TileId);
687 NewTile.Name = TileMapPath;
688
689 // 3 - Generate the StreamLevel
690 FVector TileLocation = NewTile.Location;
691 FString TileName = NewTile.Name;
692 UWorld* World = GetWorld();
693 UWorldComposition* WorldComposition = World->WorldComposition;
694
695 FString FullName = TileMapPath;
696 FString PackageFileName = FullName;
697 FString LongLevelPackageName = FPackageName::FilenameToLongPackageName(PackageFileName);
698 FString UniqueLevelPackageName = LongLevelPackageName;
699
700 ULevelStreamingDynamic* StreamingLevel = NewObject<ULevelStreamingDynamic>(World, *TileName);
701 check(StreamingLevel);
702
703 StreamingLevel->SetWorldAssetByPackageName(*UniqueLevelPackageName);
704
705#if WITH_EDITOR
706 if (World->IsPlayInEditor())
707 {
708 FWorldContext WorldContext = GEngine->GetWorldContextFromWorldChecked(World);
709 StreamingLevel->RenameForPIE(WorldContext.PIEInstance);
710 }
711 StreamingLevel->SetShouldBeVisibleInEditor(true);
712 StreamingLevel->LevelColor = FColor::MakeRandomColor();
713#endif // WITH_EDITOR
714
715 StreamingLevel->SetShouldBeLoaded(false);
716 StreamingLevel->SetShouldBeVisible(false);
717 StreamingLevel->bShouldBlockOnLoad = ShouldTilesBlockOnLoad;
718 StreamingLevel->bInitiallyLoaded = false;
719 StreamingLevel->bInitiallyVisible = false;
720 StreamingLevel->LevelTransform = FTransform(TileLocation);
721 StreamingLevel->PackageNameToLoad = *FullName;
722
723 if (!FPackageName::DoesPackageExist(FullName, &PackageFileName))
724 {
725 LM_LOG(Error, "Level does not exist in package with FullName variable -> %s", *FullName);
726 }
727
728 if (!FPackageName::DoesPackageExist(LongLevelPackageName, &PackageFileName))
729 {
730 LM_LOG(Error, "Level does not exist in package with LongLevelPackageName variable -> %s", *LongLevelPackageName);
731 }
732
733 //Actual map package to load
734 StreamingLevel->PackageNameToLoad = *LongLevelPackageName;
735
736 NewTile.StreamingLevel = StreamingLevel;
737
738 // 4 - Add it to the map
739 return MapTiles.Add(TileId, NewTile);
740}
741
743{
744 TRACE_CPUPROFILER_EVENT_SCOPE(ALargeMapManager::UpdateTilesState);
745 TSet<TileID> TilesToConsider;
746
747 // Loop over ActorsToConsider to update the state of the map tiles
748 // if the actor is not valid will be removed
749 for (AActor* Actor : ActorsToConsider)
750 {
751 if (IsValid(Actor))
752 {
753 GetTilesToConsider(Actor, TilesToConsider);
754 }
755 else
756 {
757 ActorsToRemove.Add(Actor);
758 }
759 }
760
761 TSet<TileID> TilesToBeVisible;
762 TSet<TileID> TilesToHidde;
763 GetTilesThatNeedToChangeState(TilesToConsider, TilesToBeVisible, TilesToHidde);
764
765 UpdateTileState(TilesToBeVisible, true, true, true);
766
767 UpdateTileState(TilesToHidde, false, false, false);
768
769 UpdateCurrentTilesLoaded(TilesToBeVisible, TilesToHidde);
770
771}
772
774{
775 TRACE_CPUPROFILER_EVENT_SCOPE(ALargeMapManager::RemovePendingActorsToRemove);
776 if(ActorsToRemove.Num() > 0 || ActivesToRemove.Num() > 0)
777 {
778 LM_LOG(Log, "ActorsToRemove %d ActivesToRemove %d", ActorsToRemove.Num(), ActivesToRemove.Num());
779 }
780
781 for (AActor* ActorToRemove : ActorsToRemove)
782 {
783 ActorsToConsider.Remove(ActorToRemove);
784 }
785 if(ActorsToConsider.Num() == 0 && SpectatorAsEgo && Spectator)
786 {
788 }
789 ActorsToRemove.Reset();
790
791
792 for (FCarlaActor::IdType ActorToRemove : ActivesToRemove)
793 {
794 ActiveActors.Remove(ActorToRemove);
795 }
796 ActivesToRemove.Reset();
797
799 {
800 DormantActors.Remove(Id);
801 }
802 DormantsToRemove.Reset();
803}
804
806{
807 TRACE_CPUPROFILER_EVENT_SCOPE(ALargeMapManager::CheckActiveActors);
808 UWorld* World = GetWorld();
809 UCarlaEpisode* CarlaEpisode = UCarlaStatics::GetCurrentEpisode(World);
810 // Check if they have to be destroyed
812 {
813 FCarlaActor* View = CarlaEpisode->FindCarlaActor(Id);
814 if (View)
815 {
816 AActor * Actor = View->GetActor();
817 FVector RelativeLocation = Actor->GetActorLocation();
818 FDVector WorldLocation = CurrentOriginD + RelativeLocation;
819
820 if(!IsTileLoaded(WorldLocation))
821 {
822 // Save to temporal container. Later will be converted to dormant
823 ActiveToDormantActors.Add(Id);
824 ActivesToRemove.Add(Id);
825 continue;
826 }
827
828 for(AActor* HeroActor : ActorsToConsider)
829 {
830 FVector HeroLocation = HeroActor->GetActorLocation();
831
832 float DistanceSquared = (RelativeLocation - HeroLocation).SizeSquared();
833
835 {
836 // Save to temporal container. Later will be converted to dormant
837 ActiveToDormantActors.Add(Id);
838 ActivesToRemove.Add(Id);
839 }
840 }
841 }
842 else
843 {
844 LM_LOG(Warning, "CheckActiveActors Actor does not exist -> Remove actor");
845 ActivesToRemove.Add(Id);
846 }
847 }
848}
849
851{
852 TRACE_CPUPROFILER_EVENT_SCOPE(ALargeMapManager::ConvertActiveToDormantActors);
853 UWorld* World = GetWorld();
854 UCarlaEpisode* CarlaEpisode = UCarlaStatics::GetCurrentEpisode(World);
855
856 // These actors are on dormant state so remove them from active actors
857 // But save them on the dormant array first
859 {
860 // To dormant state
861 CarlaEpisode->PutActorToSleep(Id);
862
863 LM_LOG(Warning, "Converting Active To Dormant... %d", Id);
864
865 // Need the ID of the dormant actor and save it
866 DormantActors.Add(Id);
867 }
868
869 ActiveToDormantActors.Reset();
870}
871
873{
874 TRACE_CPUPROFILER_EVENT_SCOPE(ALargeMapManager::CheckDormantActors);
875 UWorld* World = GetWorld();
876 UCarlaEpisode* CarlaEpisode = UCarlaStatics::GetCurrentEpisode(World);
877
878
880 {
881 FCarlaActor* CarlaActor = CarlaEpisode->FindCarlaActor(Id);
882
883 // If the Ids don't match, the actor has been removed
884 if(!CarlaActor)
885 {
886 LM_LOG(Log, "CheckDormantActors Carla Actor %d not found", Id);
887 DormantsToRemove.Add(Id);
888 continue;
889 }
890 if(CarlaActor->GetActorId() != Id)
891 {
892 LM_LOG(Warning, "CheckDormantActors IDs doesn't match!! Wanted = %d Received = %d", Id, CarlaActor->GetActorId());
893 DormantsToRemove.Add(Id);
894 continue;
895 }
896 if (!CarlaActor->IsDormant())
897 {
898 LM_LOG(Warning, "CheckDormantActors Carla Actor %d is not dormant", Id);
899 DormantsToRemove.Add(Id);
900 continue;
901 }
902
903 const FActorData* ActorData = CarlaActor->GetActorData();
904
905 for(AActor* Actor : ActorsToConsider)
906 {
907 FVector HeroLocation = Actor->GetActorLocation();
908
909 FDVector WorldLocation = ActorData->Location;
910 FDVector RelativeLocation = WorldLocation - CurrentOriginD;
911
912 float DistanceSquared = (RelativeLocation - HeroLocation).SizeSquared();
913
914 if(DistanceSquared < ActorStreamingDistanceSquared && IsTileLoaded(WorldLocation))
915 {
916 DormantToActiveActors.Add(Id);
917 DormantsToRemove.Add(Id);
918 break;
919 }
920 }
921 }
922}
923
925{
926 TRACE_CPUPROFILER_EVENT_SCOPE(ALargeMapManager::ConvertDormantToActiveActors);
927 UWorld* World = GetWorld();
928 UCarlaEpisode* CarlaEpisode = UCarlaStatics::GetCurrentEpisode(World);
929
931 {
932 LM_LOG(Warning, "Converting %d Dormant To Active", Id);
933
934 CarlaEpisode->WakeActorUp(Id);
935
936 FCarlaActor* View = CarlaEpisode->FindCarlaActor(Id);
937
938 if (View->IsActive()){
939 LM_LOG(Warning, "Spawning dormant at %s\n\tOrigin: %s\n\tRel. location: %s", \
940 *((CurrentOriginD + View->GetActor()->GetActorLocation()).ToString()), \
942 *((View->GetActor()->GetActorLocation()).ToString()) \
943 );
944 ActiveActors.Add(Id);
945 ATagger::TagActor(*View->GetActor(), true);
946 }
947 else
948 {
949 LM_LOG(Warning, "Actor %d could not be woken up, keeping sleep state", Id);
950 DormantActors.Add(Id);
951 }
952 }
953 DormantToActiveActors.Reset();
954}
955
957{
958 TRACE_CPUPROFILER_EVENT_SCOPE(ALargeMapManager::CheckIfRebaseIsNeeded);
959 if(ActorsToConsider.Num() > 0)
960 {
961 UWorld* World = GetWorld();
962 UWorldComposition* WorldComposition = World->WorldComposition;
963 // TODO: consider multiple hero vehicles for rebasing
964 AActor* ActorToConsider = ActorsToConsider[0];
965 if( IsValid(ActorToConsider) )
966 {
967 FVector ActorLocation = ActorToConsider->GetActorLocation();
968 FIntVector ILocation = FIntVector(ActorLocation.X, ActorLocation.Y, ActorLocation.Z);
969 if (ActorLocation.SizeSquared() > FMath::Square(RebaseOriginDistance) )
970 {
971 TileID TileId = GetTileID(CurrentOriginD + ActorLocation);
972 FVector NewOrigin = GetTileLocation(TileId);
973 World->SetNewWorldOrigin(FIntVector(NewOrigin));
974 }
975 }
976 }
977}
978
980 TSet<TileID>& OutTilesToConsider)
981{
982 TRACE_CPUPROFILER_EVENT_SCOPE(ALargeMapManager::GetTilesToConsider);
983 check(ActorToConsider);
984 // World location
985 FDVector ActorLocation = CurrentOriginD + ActorToConsider->GetActorLocation();
986
987 // Calculate Current Tile
988 FIntVector CurrentTile = GetTileVectorID(ActorLocation);
989
990 // Calculate tile bounds
992 FDVector LowerPos = ActorLocation + FDVector(-LayerStreamingDistance,-LayerStreamingDistance,0);
993 FIntVector UpperTileId = GetTileVectorID(UpperPos);
994 FIntVector LowerTileId = GetTileVectorID(LowerPos);
995 for (int Y = UpperTileId.Y; Y <= LowerTileId.Y; Y++)
996 {
997 for (int X = LowerTileId.X; X <= UpperTileId.X; X++)
998 {
999 // I don't check the bounds of the Tile map, if the Tile does not exist
1000 // I just simply discard it
1001 FIntVector TileToCheck = FIntVector(X, Y, 0);
1002
1003 TileID TileID = GetTileID(TileToCheck);
1004 FCarlaMapTile* Tile = MapTiles.Find(TileID);
1005 if (!Tile)
1006 {
1007 // LM_LOG(Warning, "Requested tile %d, %d but tile was not found", TileToCheck.X, TileToCheck.Y);
1008 continue; // Tile does not exist, discard
1009 }
1010
1011 OutTilesToConsider.Add(TileID);
1012 }
1013 }
1014}
1015
1017 const TSet<TileID>& InTilesToConsider,
1018 TSet<TileID>& OutTilesToBeVisible,
1019 TSet<TileID>& OutTilesToHidde)
1020{
1021 TRACE_CPUPROFILER_EVENT_SCOPE(ALargeMapManager::GetTilesThatNeedToChangeState);
1022 OutTilesToBeVisible = InTilesToConsider.Difference(CurrentTilesLoaded);
1023 OutTilesToHidde = CurrentTilesLoaded.Difference(InTilesToConsider);
1024}
1025
1027 const TSet<TileID>& InTilesToUpdate,
1028 bool InShouldBlockOnLoad,
1029 bool InShouldBeLoaded,
1030 bool InShouldBeVisible)
1031{
1032 TRACE_CPUPROFILER_EVENT_SCOPE(ALargeMapManager::UpdateTileState);
1033 UWorld* World = GetWorld();
1034 UWorldComposition* WorldComposition = World->WorldComposition;
1035
1036 // Gather all the locations of the levels to load
1037 for (const TileID TileID : InTilesToUpdate)
1038 {
1039 FCarlaMapTile* CarlaTile = MapTiles.Find(TileID);
1040 check(CarlaTile); // If an invalid ID reach here, we did something very wrong
1041 ULevelStreamingDynamic* StreamingLevel = CarlaTile->StreamingLevel;
1042 StreamingLevel->bShouldBlockOnLoad = InShouldBlockOnLoad;
1043 StreamingLevel->SetShouldBeLoaded(InShouldBeLoaded);
1044 StreamingLevel->SetShouldBeVisible(InShouldBeVisible);
1045 }
1046}
1047
1049 const TSet<TileID>& InTilesToBeVisible,
1050 const TSet<TileID>& InTilesToHidde)
1051{
1052 TRACE_CPUPROFILER_EVENT_SCOPE(ALargeMapManager::UpdateCurrentTilesLoaded);
1053 for (const TileID TileID : InTilesToHidde)
1054 {
1055 CurrentTilesLoaded.Remove(TileID);
1056 }
1057
1058 for (const TileID TileID : InTilesToBeVisible)
1059 {
1061 }
1062}
1063
1065{
1066 int32 X = (int32)(TileID >> 32);
1067 int32 Y = (int32)(TileID);
1068 return FString::Printf(TEXT("Tile_%d_%d"), X, Y);
1069}
1070
1072{
1073 int32 X = (int32)(TileID >> 32);
1074 int32 Y = (int32)(TileID);
1075 return FString::Printf(TEXT("%d_%d"), X, Y);
1076}
1077
1079{
1080 FString FileContent = "";
1081 FileContent += FString::Printf(TEXT("LargeMapManager state\n"));
1082
1083 FileContent += FString::Printf(TEXT("Tile:\n"));
1084 FileContent += FString::Printf(TEXT("ID\tName\tLocation\n"));
1085 for (auto& It : MapTiles)
1086 {
1087 const FCarlaMapTile& Tile = It.Value;
1088 FileContent += FString::Printf(TEXT(" %ld\t%s\t%s\n"), It.Key, *Tile.Name, *Tile.Location.ToString());
1089 }
1090 FileContent += FString::Printf(TEXT("\nNum generated tiles: %d\n"), MapTiles.Num());
1091
1092 // Generate the map name with the assets folder name
1093 TArray<FString> StringArray;
1094 AssetsPath.ParseIntoArray(StringArray, TEXT("/"), false);
1095
1096 FString FilePath = FPaths::ProjectSavedDir() + StringArray[StringArray.Num() - 1] + ".txt";
1097 FFileHelper::SaveStringToFile(
1098 FileContent,
1099 *FilePath,
1100 FFileHelper::EEncodingOptions::AutoDetect,
1101 &IFileManager::Get(),
1102 EFileWrite::FILEWRITE_Silent);
1103}
1104
1106{
1107#if WITH_EDITOR
1108 UWorld* World = GetWorld();
1109
1110 FDVector CurrentActorPosition;
1111 if (ActorsToConsider.Num() > 0)
1112 CurrentActorPosition = CurrentOriginD + ActorsToConsider[0]->GetActorLocation();
1113
1114 const TArray<FLevelCollection>& WorldLevelCollections = World->GetLevelCollections();
1115 const FLevelCollection* LevelCollection = World->GetActiveLevelCollection();
1116 const TArray<ULevel*>& Levels = World->GetLevels();
1117 const TArray<ULevelStreaming*>& StreamingLevels = World->GetStreamingLevels();
1118 ULevel* CurrentLevel = World->GetCurrentLevel();
1119
1120 FString Output = "";
1121 Output += FString::Printf(TEXT("Num levels in world composition: %d\n"),
1122 World->WorldComposition ? World->WorldComposition->TilesStreaming.Num() : 0);
1123 Output += FString::Printf(TEXT("Num levels loaded: %d\n"), Levels.Num() );
1124 Output += FString::Printf(TEXT("Num tiles loaded: %d\n"), CurrentTilesLoaded.Num() );
1125 Output += FString::Printf(TEXT("Tiles loaded: [ "));
1126 for(TileID& TileId : CurrentTilesLoaded)
1127 {
1128 Output += FString::Printf(TEXT("%s, "), *TileIDToString(TileId));
1129 }
1130 Output += FString::Printf(TEXT("]\n"));
1131 GEngine->AddOnScreenDebugMessage(0, MsgTime, FColor::Cyan, Output);
1132
1133 int LastMsgIndex = TilesDistMsgIndex;
1134 GEngine->AddOnScreenDebugMessage(LastMsgIndex++, MsgTime, FColor::White,
1135 FString::Printf(TEXT("\nActor Global Position: %s km"), *(FDVector(CurrentActorPosition) / (1000.0 * 100.0)).ToString()) );
1136
1137 FIntVector CurrentTile = GetTileVectorID(CurrentActorPosition);
1138 GEngine->AddOnScreenDebugMessage(LastMsgIndex++, MsgTime, FColor::White,
1139 FString::Printf(TEXT("\nActor Current Tile: %d_%d"), CurrentTile.X, CurrentTile.Y ));
1140
1141 LastMsgIndex = ClientLocMsgIndex;
1142 GEngine->AddOnScreenDebugMessage(LastMsgIndex++, MsgTime, FColor::White,
1143 FString::Printf(TEXT("\nOrigin: %s km"), *(FDVector(CurrentOriginInt) / (1000.0 * 100.0)).ToString()) );
1144 GEngine->AddOnScreenDebugMessage(LastMsgIndex++, MsgTime, FColor::White,
1145 FString::Printf(TEXT("Num active actors (%d)"), ActiveActors.Num()) );
1146 GEngine->AddOnScreenDebugMessage(LastMsgIndex++, MsgTime, FColor::White,
1147 FString::Printf(TEXT("Num dormant actors (%d)"), DormantActors.Num()));
1148 GEngine->AddOnScreenDebugMessage(LastMsgIndex++, MsgTime, FColor::White,
1149 FString::Printf(TEXT("Actors To Consider (%d)"), ActorsToConsider.Num()));
1150 for (const AActor* Actor : ActorsToConsider)
1151 {
1152 if (IsValid(Actor))
1153 {
1154 Output = "";
1155 float ToKm = 1000.0f * 100.0f;
1156 FVector TileActorLocation = Actor->GetActorLocation();
1157 FDVector ClientActorLocation = CurrentOriginD + FDVector(TileActorLocation);
1158
1159 Output += FString::Printf(TEXT("Local Loc: %s meters\n"), *(TileActorLocation / ToKm).ToString());
1160 Output += FString::Printf(TEXT("Client Loc: %s km\n"), *(ClientActorLocation / ToKm).ToString());
1161 Output += "---------------";
1162 GEngine->AddOnScreenDebugMessage(LastMsgIndex++, MsgTime, PositonMsgColor, Output);
1163
1164 if (LastMsgIndex > MaxClientLocMsgIndex) break;
1165 }
1166 }
1167#endif
1168}
1169
1171{
1172 SpectatorAsEgo = _SpectatorAsEgo;
1173 if(SpectatorAsEgo && ActorsToConsider.Num() == 0 && Spectator)
1174 {
1175 // Activating the spectator in an empty world
1177 }
1178 if (!SpectatorAsEgo && ActorsToConsider.Num() == 1 && ActorsToConsider.Contains(Spectator))
1179 {
1180 // Deactivating the spectator in a world with no other egos
1181 ActorsToConsider.Reset();
1182 }
1183}
float tick_execution_time
#define LM_LOG(...)
uint64_t num_ticks
static bool IsValid(const ACarlaWheeledVehicle *Vehicle)
Base class for CARLA wheeled vehicles.
void ConvertDormantToActiveActors()
FCarlaMapTile & LoadCarlaMapTile(FString TileMapPath, TileID TileId)
virtual void BeginPlay() override
FString TileIDToString(TileID TileID)
void UpdateCurrentTilesLoaded(const TSet< TileID > &InTilesToBeVisible, const TSet< TileID > &InTilesToHidde)
TSet< FCarlaActor::IdType > DormantToActiveActors
FTransform GlobalToLocalTransform(const FTransform &InTransform) const
float RebaseOriginDistanceSquared
float ActorStreamingDistanceSquared
ACarlaWheeledVehicle * GetHeroVehicle()
void PreWorldOriginOffset(UWorld *InWorld, FIntVector InSrcOrigin, FIntVector InDstOrigin)
void GetTilesToConsider(const AActor *ActorToConsider, TSet< TileID > &OutTilesToConsider)
void ConvertActiveToDormantActors()
float GetLayerStreamingDistance() const
void ConsiderSpectatorAsEgo(bool _SpectatorAsEgo)
void SetActorStreamingDistance(float Distance)
TSet< FCarlaActor::IdType > ActiveToDormantActors
FIntVector GetNumTilesInXY() const
void DumpTilesTable() const
FIntVector CurrentOriginInt
void OnActorSpawned(const FCarlaActor &CarlaActor)
FString GenerateTileName(TileID TileID)
FIntVector GetTileVectorID(FVector TileLocation) const
FVector GlobalToLocalLocation(const FVector &InLocation) const
void OnActorDestroyed(AActor *DestroyedActor)
TSet< AActor * > ActorsToRemove
const int32 ClientLocMsgIndex
FTransform LocalToGlobalTransform(const FTransform &InTransform) const
TSet< uint64 > CurrentTilesLoaded
TileID GetTileID(FVector TileLocation) const
From a given location it retrieves the TileID that covers that area.
FCarlaMapTile * GetCarlaMapTile(FVector Location)
TArray< FCarlaActor::IdType > ActiveActors
bool IsTileLoaded(TileID TileId) const
void GetTilesThatNeedToChangeState(const TSet< TileID > &InTilesToConsider, TSet< TileID > &OutTilesToBeVisible, TSet< TileID > &OutTilesToHidde)
FCarlaMapTile * GetCarlaMapTilePointer(FIntVector TileVectorID)
void OnLevelRemovedFromWorld(ULevel *InLevel, UWorld *InWorld)
FDVector GetTileLocationD(TileID TileID) const
void SetTile0Offset(const FVector &Offset)
void Tick(float DeltaTime) override
void RegisterTilesInWorldComposition()
void SetLayerStreamingDistance(float Distance)
const int32 MaxClientLocMsgIndex
float LayerStreamingDistanceSquared
FVector GetTileLocation(TileID TileID) const
void PostWorldOriginOffset(UWorld *InWorld, FIntVector InSrcOrigin, FIntVector InDstOrigin)
float GetActorStreamingDistance() const
TSet< FCarlaActor::IdType > DormantsToRemove
TArray< AActor * > ActorsToConsider
bool IsLevelOfTileLoaded(FIntVector InTileID) const
void SetTileSize(float Size)
void UpdateTileState(const TSet< TileID > &InTilesToUpdate, bool InShouldBlockOnLoad, bool InShouldBeLoaded, bool InShouldBeVisible)
void GenerateMap(FString InAssetsPath)
TArray< FCarlaActor::IdType > DormantActors
TSet< FCarlaActor::IdType > ActivesToRemove
FVector LocalToGlobalLocation(const FVector &InLocation) const
void OnLevelAddedToWorld(ULevel *InLevel, UWorld *InWorld)
const int32 TilesDistMsgIndex
void AddActorToUnloadedList(const FCarlaActor &CarlaActor, const FTransform &Transform)
TMap< uint64, FCarlaMapTile > MapTiles
static void TagActor(const AActor &Actor, bool bTagForSemanticSegmentation)
Set the tag of an actor.
Definition Tagger.cpp:130
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.
FDVector Location
Definition ActorData.h:48
A registry of all the Carla actors.
A view over an actor and its properties.
Definition CarlaActor.h:25
ActorType GetActorType() const
Definition CarlaActor.h:86
bool IsDormant() const
Definition CarlaActor.h:71
AActor * GetActor()
Definition CarlaActor.h:91
uint32 IdType
Definition CarlaActor.h:28
FActorData * GetActorData()
Definition CarlaActor.h:205
bool IsActive() const
Definition CarlaActor.h:66
const FActorInfo * GetActorInfo() const
Definition CarlaActor.h:101
IdType GetActorId() const
Definition CarlaActor.h:81
A simulation episode.
void PutActorToSleep(carla::rpc::ActorId ActorId)
void SetCurrentMapOrigin(const FIntVector &NewOrigin)
FCarlaActor * FindCarlaActor(FCarlaActor::IdType ActorId)
Find a Carla actor by id.
const FActorRegistry & GetActorRegistry() const
void WakeActorUp(carla::rpc::ActorId ActorId)
static UCarlaEpisode * GetCurrentEpisode(const UObject *WorldContextObject)
An actor attribute, may be an intrinsic (non-modifiable) attribute of the actor or an user-defined ac...
A description of a Carla Actor with all its variation.
TMap< FString, FActorAttribute > Variations
User selected variations of the actor.
A view over an actor and its properties.
Definition ActorInfo.h:18
FActorDescription Description
Definition ActorInfo.h:21
ULevelStreamingDynamic * StreamingLevel
FString ToString() const
Definition DVector.h:52
double Y
Definition DVector.h:14
FVector ToFVector() const
Definition DVector.h:47