29#include <util/ue-header-guard-begin.h>
30#include "Async/Async.h"
31#include "HAL/PlatformProcess.h"
32#include "Components/WorldPartitionStreamingSourceComponent.h"
33#include "WorldPartition/WorldPartition.h"
34#include "WorldPartition/WorldPartitionSubsystem.h"
35#include "Engine/StaticMeshActor.h"
36#include "EngineUtils.h"
37#include "GameFramework/SpectatorPawn.h"
38#include "GenericPlatform/GenericPlatformProcess.h"
39#include "Kismet/GameplayStatics.h"
40#include "Materials/MaterialParameterCollection.h"
41#include "Materials/MaterialParameterCollectionInstance.h"
42#include "Misc/FileHelper.h"
43#include "Misc/PackageName.h"
44#include "Misc/Paths.h"
45#include <util/ue-header-guard-end.h>
51 auto Path = FPaths::RootDir();
53 Path += TEXT(
"Tools/RecastBuilder.exe");
55 Path += TEXT(
"Tools/RecastBuilder");
57 Path = FPaths::ConvertRelativePathToFull(Path);
59 if (FPaths::FileExists(Path))
73 const double Start = FPlatformTime::Seconds();
86 UE_LOG(LogCarla, Log, TEXT(
"Waiting for RecastBuilder to finish the pedestrian navigation (up to %.0f s)"),
90 if (FPlatformTime::Seconds() - Start > TimeoutSeconds)
92 UE_LOG(LogCarla, Error, TEXT(
"RecastBuilder did not finish within %.0f s; "
93 "the pedestrian navigation of this OpenDRIVE world is not available yet"), TimeoutSeconds);
96 FPlatformProcess::Sleep(0.05f);
104 const FString SavedDir = FPaths::ConvertRelativePathToFull(FPaths::ProjectSavedDir());
105 for (
const FString &File : {
106 SavedDir / TEXT(
"OpenDrive/OpenDriveMap.xodr"),
107 SavedDir / TEXT(
"Nav/OpenDriveMap.obj"),
108 SavedDir / TEXT(
"Nav/OpenDriveMap.bin")})
110 if (IFileManager::Get().FileExists(*File))
112 IFileManager::Get().Delete(*File,
false,
true,
true);
113 UE_LOG(LogCarla, Log, TEXT(
"Removed stale generated-world file '%s'"), *File);
125 return FString::Printf(TEXT(
"traffic.speed_limit.%d"), Kmh);
129 case TSS::TrafficLightRed:
130 case TSS::TrafficLightYellow:
131 case TSS::TrafficLightGreen:
return TEXT(
"traffic.traffic_light");
132 case TSS::StopSign:
return TEXT(
"traffic.stop");
133 case TSS::YieldSign:
return TEXT(
"traffic.yield");
134 default:
return TEXT(
"traffic.unknown");
139 : Super(ObjectInitializer),
142 ActorDispatcher = CreateDefaultSubobject<UActorDispatcher>(TEXT(
"ActorDispatcher"));
147 if (!FPaths::FileExists(AbsoluteRecastBuilderPath))
149 UE_LOG(LogCarla, Warning, TEXT(
"'RecastBuilder' not present under '%s', "
150 "the binaries for pedestrian navigation will not be created."),
151 *AbsoluteRecastBuilderPath);
158 const bool bIsFileFound = !FinalPath.IsEmpty();
162 UE_LOG(LogCarla, Warning, TEXT(
"Loading a new episode: %s"), *FinalPath);
163 UGameplayStatics::OpenLevel(GetWorld(), *FinalPath,
true);
177 TArray<uint8> OpenDrive;
178 if (FPaths::GetBaseFilename(FinalPath).Equals(TEXT(
"OpenDriveMap"), ESearchCase::IgnoreCase) &&
181 Extras.
opendrive = std::string(
reinterpret_cast<const char *
>(OpenDrive.GetData()), OpenDrive.Num());
184 std::string(
reinterpret_cast<const char *
>(Parameters.
data()), Parameters.
size());
186 SecondaryServer->GetCommander().SendLoadMap(std::string(TCHAR_TO_UTF8(*FinalPath)), Extras);
196 const FString &OpenDriveString,
199 if (OpenDriveString.IsEmpty())
201 UE_LOG(LogCarla, Error, TEXT(
"The OpenDrive string is empty."));
207 carla::rpc::FromLongFString(OpenDriveString));
210 if (!CarlaMap.has_value())
212 UE_LOG(LogCarla, Error, TEXT(
"The OpenDrive string is invalid or not supported"));
218 const auto CrosswalksMesh = CarlaMap->GetAllCrosswalkMesh();
219 const auto RecastOBJ = (RoadMesh + CrosswalksMesh).GenerateOBJForRecast();
228 const FString AbsoluteOBJPath = FPaths::ConvertRelativePathToFull(
229 FPaths::ProjectSavedDir() / TEXT(
"Nav/OpenDriveMap.obj"));
232 FFileHelper::SaveStringToFile(
233 carla::rpc::ToLongFString(RecastOBJ),
235 FFileHelper::EEncodingOptions::ForceUTF8,
236 &IFileManager::Get());
241 FFileHelper::SaveStringToFile(
244 FFileHelper::EEncodingOptions::ForceUTF8,
245 &IFileManager::Get());
247 if (!FPaths::FileExists(AbsoluteXODRPath))
249 UE_LOG(LogCarla, Error, TEXT(
"ERROR: XODR not copied!"));
264 if (FPaths::FileExists(AbsoluteRecastBuilderPath) &&
271 const FString AbsoluteBinPath = FPaths::ChangeExtension(AbsoluteOBJPath, TEXT(
"bin"));
272 IFileManager::Get().Delete(*AbsoluteBinPath,
false,
true,
true);
274 void *PipeRead =
nullptr;
275 void *PipeWrite =
nullptr;
276 FPlatformProcess::CreatePipe(PipeRead, PipeWrite);
280 FProcHandle RecastHandle = FPlatformProcess::CreateProc(
281 *AbsoluteRecastBuilderPath, *AbsoluteOBJPath,
282 true,
true,
true,
nullptr, 0,
nullptr, PipeWrite,
nullptr, PipeWrite);
283 if (!RecastHandle.IsValid())
285 FPlatformProcess::ClosePipe(PipeRead, PipeWrite);
286 UE_LOG(LogCarla, Error, TEXT(
"RecastBuilder could not be launched ('%s' '%s'); "
287 "no pedestrian navigation for this OpenDRIVE world."),
288 *AbsoluteRecastBuilderPath, *AbsoluteOBJPath);
292 UE_LOG(LogCarla, Log, TEXT(
"RecastBuilder started: '%s' '%s' -> '%s'"),
293 *AbsoluteRecastBuilderPath, *AbsoluteOBJPath, *AbsoluteBinPath);
299 Async(EAsyncExecution::Thread,
300 [RecastHandle, PipeRead, PipeWrite, AbsoluteBinPath, AbsoluteRecastBuilderPath]()
mutable
303 while (FPlatformProcess::IsProcRunning(RecastHandle))
305 Output += FPlatformProcess::ReadPipe(PipeRead);
306 FPlatformProcess::Sleep(0.1f);
308 Output += FPlatformProcess::ReadPipe(PipeRead);
309 int32 ReturnCode = -1;
310 FPlatformProcess::GetProcReturnCode(RecastHandle, &ReturnCode);
311 FPlatformProcess::CloseProc(RecastHandle);
312 FPlatformProcess::ClosePipe(PipeRead, PipeWrite);
313 Output.TrimEndInline();
314 const bool bSucceeded = ReturnCode == 0 && FPaths::FileExists(AbsoluteBinPath);
317 UE_LOG(LogCarla, Error, TEXT(
"RecastBuilder failed (exit code %d, '%s' %s): no pedestrian "
318 "navigation for this OpenDRIVE world. Output:\n%s"),
319 ReturnCode, *AbsoluteBinPath,
320 FPaths::FileExists(AbsoluteBinPath) ? TEXT(
"written") : TEXT(
"missing"), *Output);
324 UE_LOG(LogCarla, Log, TEXT(
"RecastBuilder finished: navmesh '%s' ready. Output:\n%s"),
325 *AbsoluteBinPath, *Output);
335 UE_LOG(LogCarla, Warning, TEXT(
"'RecastBuilder' not present under '%s', "
336 "the binaries for pedestrian navigation will not be created."),
337 *AbsoluteRecastBuilderPath);
348 UE_LOG(LogCarla, Warning, TEXT(
"Setting ActorActiveDistance is smaller that TileStreamingDistance, TileStreamingDistance will be increased"));
370 Actor.parent_id = ParentId;
375 UE_LOG(LogCarla, Warning, TEXT(
"Trying to serialize invalid actor"));
388 Serialized.
id = Mirror->GetPrimaryActorId();
394 Serialized.
parent_id = Parent->GetPrimaryActorId();
403#if defined(WITH_ROS2)
405 if (!ROS2->IsEnabled())
414 if (Attr.Key ==
"ros_name")
416 ROS2->AddActorParentRosName(
static_cast<void*
>(Child.
GetActor()),
static_cast<void*
>(CurrentActor->
GetActor()));
441 SerializedActor.
id = 0u;
443 TSet<crp::CityObjectLabel> SemanticTags;
449 for (
auto &&Tag : SemanticTags)
451 using tag_t =
decltype(SerializedActor.
semantic_tags)::value_type;
452 SerializedActor.
semantic_tags.emplace_back(
static_cast<tag_t
>(Tag));
454 return SerializedActor;
488 auto World = GetWorld();
489 check(World !=
nullptr);
490 auto PlayerController = UGameplayStatics::GetPlayerController(World, 0);
491 if (PlayerController ==
nullptr)
493 UE_LOG(LogCarla, Error, TEXT(
"Can't find player controller!"));
500 Description.
Id = TEXT(
"spectator");
506 UE_LOG(LogCarla, Error, TEXT(
"Can't find spectator!"));
510 UMaterialParameterCollection *Collection = LoadObject<UMaterialParameterCollection>(
nullptr, TEXT(
"/Game/Carla/Blueprints/Game/CarlaParameters.CarlaParameters"),
nullptr, LOAD_None,
nullptr);
511 if (Collection !=
nullptr)
516 UE_LOG(LogCarla, Error, TEXT(
"Can't find CarlaParameters instance!"));
521 UE_LOG(LogCarla, Error, TEXT(
"Can't find CarlaParameters asset!"));
524 for (TActorIterator<ATrafficSignBase> It(World); It; ++It)
527 check(Actor !=
nullptr);
530 Description.
Class = Actor->GetClass();
536 uint32 StaticMeshUId = 0;
537 for (
auto& Definition : Definitions)
539 if (Definition.Id ==
"static.prop.mesh")
541 StaticMeshUId = Definition.UId;
546 for (TActorIterator<AStaticMeshActor> It(World); It; ++It)
549 check(Actor !=
nullptr);
550 auto MeshComponent = Actor->GetStaticMeshComponent();
551 check(MeshComponent !=
nullptr);
552 if (MeshComponent->Mobility == EComponentMobility::Movable)
555 Description.
Id = TEXT(
"static.prop.mesh");
556 Description.
UId = StaticMeshUId;
557 Description.
Class = Actor->GetClass();
560 MeshComponent->GetStaticMesh()->GetPathName()});
563 FString::SanitizeFloat(MeshComponent->GetMass())});
592 result =
"Recorder is not ready";
599 const FTransform &Transform,
604 FTransform LocalTransform = Transform;
612 if (result.Key == EActorSpawnResultStatus::Success &&
613 GetWorld()->GetWorldPartition() !=
nullptr)
620 AActor* Actor = result.Value->GetActor();
621 const bool bNeedsGround =
622 Cast<ACarlaWheeledVehicle>(Actor) !=
nullptr ||
623 Cast<AWalkerBase>(Actor) !=
nullptr;
625 !Actor->FindComponentByClass<UWorldPartitionStreamingSourceComponent>())
630 thisActorDescription.
Variations.Find(
"role_name");
631 const bool bIsHero = Attribute && (Attribute->
Value.Contains(
"hero") ||
632 Attribute->
Value.Contains(
"ego_vehicle"));
633 auto* Source = NewObject<UWorldPartitionStreamingSourceComponent>(Actor);
634 FStreamingSourceShape Shape;
635 Shape.bUseGridLoadingRange =
false;
637 Source->Shapes.Add(Shape);
638 Source->RegisterComponent();
644 UWorldPartitionSubsystem* WPSubsystem =
645 GetWorld()->GetSubsystem<UWorldPartitionSubsystem>();
646 if (WPSubsystem !=
nullptr && !WPSubsystem->IsStreamingCompleted(Source))
648 WPSubsystem->OnUpdateStreamingState();
649 GetWorld()->BlockTillLevelStreamingCompleted();
651 UE_LOG(LogCarla, Log, TEXT(
652 "WP streaming source on %s (role %s, radius %.0f cm): completed=%d"),
653 *Actor->GetName(), Attribute ? *Attribute->
Value : TEXT(
"none"), Shape.Radius,
654 WPSubsystem ? WPSubsystem->IsStreamingCompleted(Source) : -1);
662 result.Value->GetActorId(),
663 static_cast<uint8_t
>(result.Value->GetActorType()),
671 result.Value->GetActorId(),
672 static_cast<uint8_t
>(result.Value->GetActorType()),
674 std::move(thisActorDescription));
static bool GNavBuildSucceeded
static FCriticalSection GNavBuildLock
static FString BuildRecastBuilderFile()
static FString UCarlaEpisode_GetTrafficSignId(const ATrafficSignBase &Sign)
constexpr TCHAR DefaultRecastBuilderPath[]
static bool GNavBuildPending
FString CarlaGetRelevantTagAsString(const TSet< carla::rpc::CityObjectLabel > &SemanticTags)
Base class for the CARLA Game Mode.
const TArray< FTransform > & GetSpawnPointsTransforms() const
void AddEvent(const CarlaRecorderEventAdd &Event)
CarlaReplayer * GetReplayer(void)
std::string Start(std::string Name, FString MapName, bool AdditionalData=false, bool StopReplayer=true)
void CreateRecorderEventAdd(uint32_t DatabaseId, uint8_t Type, const FTransform &Transform, FActorDescription ActorDescription)
FTransform GlobalToLocalTransform(const FTransform &InTransform) const
static void GetTagsOfTaggedActor(const AActor &Actor, TSet< crp::CityObjectLabel > &Tags)
Retrieve the tags of an already tagged actor.
ETrafficSignState GetTrafficSignState() const
int32 GetSpeedLimitKmh() const
km/h this sign limits to, -1 when it is not a speed-limit sign.
void Stop(bool KeepActors=false)
A registry of all the Carla actors.
FCarlaActor * FindCarlaActor(IdType Id)
A view over an actor and its properties.
const FActorInfo * GetActorInfo() const
IdType GetActorId() const
std::shared_ptr< carla::multigpu::Router > GetSecondaryServer()
static FOnEpisodeSettingsChange OnEpisodeSettingsChange
void SetEpisode(UCarlaEpisode *ThisEpisode)
void AddEvent(const CarlaRecorderEventAdd &Event)
void CreateRecorderEventAdd(uint32_t DatabaseId, uint8_t Type, const FTransform &Transform, FActorDescription ActorDescription, bool bAddOtherRelatedInfo=true)
static void AttachActors(AActor *Child, AActor *Parent, EAttachmentType AttachmentType)
const FActorRegistry & GetActorRegistry() const
FCarlaActor * RegisterActor(AActor &Actor, FActorDescription ActorDescription, FActorRegistry::IdType DesiredId=0)
Register an actor that was not created using "SpawnActor" function but that should be kept in the reg...
TPair< EActorSpawnResultStatus, FCarlaActor * > SpawnActor(const FTransform &Transform, FActorDescription ActorDescription, FCarlaActor::IdType DesiredId=0)
Spawns an actor based on ActorDescription at Transform.
static FBoundingBox GetActorBoundingBox(const AActor *Actor, uint8 InTagQueried=0xFF)
Compute the bounding box of the given Carla actor.
FFrameData & GetFrameData()
carla::rpc::Actor SerializeActor(FCarlaActor *CarlaActor) const
Create a serializable object describing the actor.
FEpisodeSettings EpisodeSettings
static void ClearGeneratedWorldFiles()
Delete Saved/OpenDrive|Nav/OpenDriveMap.
UCarlaEpisode(const FObjectInitializer &ObjectInitializer)
FIntVector CurrentMapOrigin
bool LoadNewOpendriveEpisode(const FString &OpenDriveString, const carla::rpc::OpendriveGenerationParameters &Params)
Load a new map generating the mesh from OpenDRIVE data and start a new episode.
const TArray< FActorDefinition > & GetActorDefinitions() const
Return the list of actor definitions that are available to be spawned this episode.
FCarlaActor * FindCarlaActor(FCarlaActor::IdType ActorId)
Find a Carla actor by id.
UActorDispatcher * ActorDispatcher
std::string StartRecorder(std::string name, bool AdditionalData, bool StopReplayer)
carla::rpc::Actor SerializeActorWithPrimaryIds(AActor *Actor) const
SerializeActor, with the ids the primary's clients know on a Multi-GPU secondary (for data a sensor s...
void ApplySettings(const FEpisodeSettings &Settings)
static bool WaitForPendingNavigationBuild(double TimeoutSeconds)
Return the name of the map loaded in this episode.
TPair< EActorSpawnResultStatus, FCarlaActor * > SpawnActorWithInfo(const FTransform &Transform, FActorDescription thisActorDescription, FCarlaActor::IdType DesiredId=0)
Spawns an actor based on ActorDescription at Transform.
UMaterialParameterCollectionInstance * MaterialParameters
ACarlaRecorder * Recorder
void InitializeAtBeginPlay()
void AddRosParentNames(FCarlaActor &Child)
ROS 2: registers the ros_name of each of Child's ancestors as one of its parent frames.
bool LoadNewEpisode(const FString &MapString, bool ResetSettings=true)
Load a new map and start a new episode.
void AttachActors(AActor *Child, AActor *Parent, EAttachmentType InAttachmentType=EAttachmentType::Rigid)
Attach Child to Parent.
TArray< FTransform > GetRecommendedSpawnPoints() const
Return the list of recommended spawn points for vehicles.
The game instance contains elements that must be kept alive in between levels.
const carla::rpc::OpendriveGenerationParameters & GetOpendriveGenerationParameters() const
FCarlaEngine * GetCarlaEngine()
void SetOpendriveGenerationParameters(const carla::rpc::OpendriveGenerationParameters &Parameters)
static FString FindMapPath(const FString &MapName)
static UCarlaGameInstance * GetGameInstance(const UObject *WorldContextObject)
static ALargeMapManager * GetLargeMapManager(const UObject *WorldContextObject)
static ACarlaGameModeBase * GetGameMode(const UObject *WorldContextObject)
static FString GetSavedXODRPath(const FString &MapName)
Where a generated OpenDRIVE world stores its xodr: <ProjectSavedDir>/OpenDrive/<MapName>....
const value_type * data() const noexcept
Direct access to the allocated memory or nullptr if no memory is allocated.
size_type size() const noexcept
static Buffer Pack(const T &obj)
static std::optional< road::Map > Load(const std::string &opendrive)
static std::shared_ptr< ROS2 > GetInstance()
std::vector< uint8_t > semantic_tags
ActorDescription description
geom::BoundingBox bounding_box
static void log_warning(Args &&... args)
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.
TSubclassOf< AActor > Class
Class of the actor to be spawned.
uint32 UId
UId of the definition in which this description was based.
FString Id
Display ID that identifies the actor.
FActorDescription Description
carla::rpc::Actor SerializedData
float TileStreamingDistance
float ActorActiveDistance
Seting for map generation from opendrive without additional geometry.
bool enable_pedestrian_navigation