CARLA
CarlaEpisode.cpp
Go to the documentation of this file.
1 // Copyright (c) 2017 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 
7 #include "Carla.h"
9 
12 #include <carla/rpc/String.h>
14 
15 #include "Carla/Sensor/Sensor.h"
21 
22 #include "Engine/StaticMeshActor.h"
23 #include "EngineUtils.h"
24 #include "GameFramework/SpectatorPawn.h"
25 #include "GenericPlatform/GenericPlatformProcess.h"
26 #include "Kismet/GameplayStatics.h"
27 #include "Materials/MaterialParameterCollection.h"
28 #include "Materials/MaterialParameterCollectionInstance.h"
29 #include "Misc/FileHelper.h"
30 #include "Misc/Paths.h"
31 
33 {
34  using TSS = ETrafficSignState;
35  switch (State)
36  {
37  case TSS::TrafficLightRed:
38  case TSS::TrafficLightYellow:
39  case TSS::TrafficLightGreen: return TEXT("traffic.traffic_light");
40  case TSS::SpeedLimit_30: return TEXT("traffic.speed_limit.30");
41  case TSS::SpeedLimit_40: return TEXT("traffic.speed_limit.40");
42  case TSS::SpeedLimit_50: return TEXT("traffic.speed_limit.50");
43  case TSS::SpeedLimit_60: return TEXT("traffic.speed_limit.60");
44  case TSS::SpeedLimit_90: return TEXT("traffic.speed_limit.90");
45  case TSS::SpeedLimit_100: return TEXT("traffic.speed_limit.100");
46  case TSS::SpeedLimit_120: return TEXT("traffic.speed_limit.120");
47  case TSS::SpeedLimit_130: return TEXT("traffic.speed_limit.130");
48  case TSS::StopSign: return TEXT("traffic.stop");
49  case TSS::YieldSign: return TEXT("traffic.yield");
50  default: return TEXT("traffic.unknown");
51  }
52 }
53 
54 UCarlaEpisode::UCarlaEpisode(const FObjectInitializer &ObjectInitializer)
55  : Super(ObjectInitializer),
56  Id(URandomEngine::GenerateRandomId())
57 {
58  ActorDispatcher = CreateDefaultSubobject<UActorDispatcher>(TEXT("ActorDispatcher"));
59  FrameData.SetEpisode(this);
60 }
61 
62 bool UCarlaEpisode::LoadNewEpisode(const FString &MapString, bool ResetSettings)
63 {
64  bool bIsFileFound = false;
65 
66  FString FinalPath = MapString.IsEmpty() ? GetMapName() : MapString;
67  FinalPath += !MapString.EndsWith(".umap") ? ".umap" : "";
68 
69  if (MapString.StartsWith("/Game"))
70  {
71  // Some conversions...
72  FinalPath.RemoveFromStart(TEXT("/Game/"));
73  FinalPath = FPaths::ProjectContentDir() + FinalPath;
74  FinalPath = IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead(*FinalPath);
75 
76  if (FPaths::FileExists(FinalPath)) {
77  bIsFileFound = true;
78  FinalPath = MapString;
79  }
80  }
81  else
82  {
83  if (MapString.Contains("/")) return false;
84 
85  // Find the full path under Carla
86  TArray<FString> TempStrArray, PathList;
87  IFileManager::Get().FindFilesRecursive(PathList, *FPaths::ProjectContentDir(), *FinalPath, true, false, false);
88  if (PathList.Num() > 0)
89  {
90  FinalPath = PathList[0];
91  FinalPath.ParseIntoArray(TempStrArray, TEXT("Content/"), true);
92  FinalPath = TempStrArray[1];
93  FinalPath.ParseIntoArray(TempStrArray, TEXT("."), true);
94  FinalPath = "/Game/" + TempStrArray[0];
95 
96  return LoadNewEpisode(FinalPath, ResetSettings);
97  }
98  }
99 
100  if (bIsFileFound)
101  {
102  UE_LOG(LogCarla, Warning, TEXT("Loading a new episode: %s"), *FinalPath);
103  UGameplayStatics::OpenLevel(GetWorld(), *FinalPath, true);
104  if (ResetSettings)
106 
107  // send 'LOAD_MAP' command to all secondary servers (if any)
108  if (bIsPrimaryServer)
109  {
110  UCarlaGameInstance *GameInstance = UCarlaStatics::GetGameInstance(GetWorld());
111  if(GameInstance)
112  {
113  FCarlaEngine *CarlaEngine = GameInstance->GetCarlaEngine();
114  auto SecondaryServer = CarlaEngine->GetSecondaryServer();
115  if (SecondaryServer->HasClientsConnected())
116  {
117  SecondaryServer->GetCommander().SendLoadMap(std::string(TCHAR_TO_UTF8(*FinalPath)));
118  }
119  }
120  }
121  }
122  return bIsFileFound;
123 }
124 
125 static FString BuildRecastBuilderFile()
126 {
127  // Define filename with extension depending on if we are on Windows or not
128 #if PLATFORM_WINDOWS
129  const FString RecastToolName = "RecastBuilder.exe";
130 #else
131  const FString RecastToolName = "RecastBuilder";
132 #endif // PLATFORM_WINDOWS
133 
134  // Define path depending on the UE4 build type (Package or Editor)
135 #if UE_BUILD_SHIPPING
136  const FString AbsoluteRecastBuilderPath = FPaths::ConvertRelativePathToFull(
137  FPaths::RootDir() + "Tools/" + RecastToolName);
138 #else
139  const FString AbsoluteRecastBuilderPath = FPaths::ConvertRelativePathToFull(
140  FPaths::ProjectDir() + "../../Util/DockerUtils/dist/" + RecastToolName);
141 #endif
142  return AbsoluteRecastBuilderPath;
143 }
144 
146  const FString &OpenDriveString,
148 {
149  if (OpenDriveString.IsEmpty())
150  {
151  UE_LOG(LogCarla, Error, TEXT("The OpenDrive string is empty."));
152  return false;
153  }
154 
155  // Build the Map from the OpenDRIVE data
156  const auto CarlaMap = carla::opendrive::OpenDriveParser::Load(
157  carla::rpc::FromLongFString(OpenDriveString));
158 
159  // Check the Map is correclty generated
160  if (!CarlaMap.has_value())
161  {
162  UE_LOG(LogCarla, Error, TEXT("The OpenDrive string is invalid or not supported"));
163  return false;
164  }
165 
166  // Generate the OBJ (as string)
167  const auto RoadMesh = CarlaMap->GenerateMesh(Params.vertex_distance);
168  const auto CrosswalksMesh = CarlaMap->GetAllCrosswalkMesh();
169  const auto RecastOBJ = (RoadMesh + CrosswalksMesh).GenerateOBJForRecast();
170 
171  const FString AbsoluteOBJPath = FPaths::ConvertRelativePathToFull(
172  FPaths::ProjectContentDir() + "Carla/Maps/Nav/OpenDriveMap.obj");
173 
174  // Store the OBJ string to a file in order to that RecastBuilder can load it
175  FFileHelper::SaveStringToFile(
176  carla::rpc::ToLongFString(RecastOBJ),
177  *AbsoluteOBJPath,
178  FFileHelper::EEncodingOptions::ForceUTF8,
179  &IFileManager::Get());
180 
181  const FString AbsoluteXODRPath = FPaths::ConvertRelativePathToFull(
182  FPaths::ProjectContentDir() + "Carla/Maps/OpenDrive/OpenDriveMap.xodr");
183 
184  // Copy the OpenDrive as a file in the serverside
185  FFileHelper::SaveStringToFile(
186  OpenDriveString,
187  *AbsoluteXODRPath,
188  FFileHelper::EEncodingOptions::ForceUTF8,
189  &IFileManager::Get());
190 
191  if (!FPaths::FileExists(AbsoluteXODRPath))
192  {
193  UE_LOG(LogCarla, Error, TEXT("ERROR: XODR not copied!"));
194  return false;
195  }
196 
197  UCarlaGameInstance * GameInstance = UCarlaStatics::GetGameInstance(GetWorld());
198  if(GameInstance)
199  {
200  GameInstance->SetOpendriveGenerationParameters(Params);
201  }
202  else
203  {
204  carla::log_warning("Missing game instance");
205  }
206 
207  const FString AbsoluteRecastBuilderPath = BuildRecastBuilderFile();
208 
209  if (FPaths::FileExists(AbsoluteRecastBuilderPath) &&
211  {
212  /// @todo this can take too long to finish, clients need a method
213  /// to know if the navigation is available or not.
214  FPlatformProcess::CreateProc(
215  *AbsoluteRecastBuilderPath, *AbsoluteOBJPath,
216  true, true, true, nullptr, 0, nullptr, nullptr);
217  }
218  else
219  {
220  UE_LOG(LogCarla, Warning, TEXT("'RecastBuilder' not present under '%s', "
221  "the binaries for pedestrian navigation will not be created."),
222  *AbsoluteRecastBuilderPath);
223  }
224 
225  return true;
226 }
227 
229 {
230  EpisodeSettings = Settings;
232  {
233  UE_LOG(LogCarla, Warning, TEXT("Setting ActorActiveDistance is smaller that TileStreamingDistance, TileStreamingDistance will be increased"));
235  }
237 }
238 
240 {
242 
243  return GM->GetSpawnPointsTransforms();
244 }
245 
247 {
249  if (CarlaActor)
250  {
251  Actor = CarlaActor->GetActorInfo()->SerializedData;
252  auto ParentId = CarlaActor->GetParent();
253  if (ParentId)
254  {
255  Actor.parent_id = ParentId;
256  }
257  }
258  else
259  {
260  UE_LOG(LogCarla, Warning, TEXT("Trying to serialize invalid actor"));
261  }
262  return Actor;
263 }
264 
265 static FString GetRelevantTagAsString(const TSet<crp::CityObjectLabel> &SemanticTags);
266 
268 {
269  FCarlaActor* CarlaActor = FindCarlaActor(Actor);
270  if (CarlaActor)
271  {
272  return SerializeActor(CarlaActor);
273  }
274  else
275  {
276  carla::rpc::Actor SerializedActor;
277  SerializedActor.id = 0u;
279  TSet<crp::CityObjectLabel> SemanticTags;
280  ATagger::GetTagsOfTaggedActor(*Actor, SemanticTags);
281  FActorDescription Description;
282  Description.Id = TEXT("static.") + GetRelevantTagAsString(SemanticTags);
283  SerializedActor.description = Description;
284  SerializedActor.semantic_tags.reserve(SemanticTags.Num());
285  for (auto &&Tag : SemanticTags)
286  {
287  using tag_t = decltype(SerializedActor.semantic_tags)::value_type;
288  SerializedActor.semantic_tags.emplace_back(static_cast<tag_t>(Tag));
289  }
290  return SerializedActor;
291  }
292 }
293 
295  AActor *Child,
296  AActor *Parent,
297  EAttachmentType InAttachmentType)
298 {
299  Child->AddActorWorldOffset(FVector(CurrentMapOrigin));
300 
301  UActorAttacher::AttachActors(Child, Parent, InAttachmentType);
302 
303  if (bIsPrimaryServer)
304  {
307  FindCarlaActor(Child)->GetActorId(),
308  FindCarlaActor(Parent)->GetActorId()});
309  }
310  // recorder event
311  if (Recorder->IsEnabled())
312  {
313  CarlaRecorderEventParent RecEvent
314  {
315  FindCarlaActor(Child)->GetActorId(),
316  FindCarlaActor(Parent)->GetActorId()
317  };
318  Recorder->AddEvent(std::move(RecEvent));
319  }
320 }
321 
323 {
324  auto World = GetWorld();
325  check(World != nullptr);
326  auto PlayerController = UGameplayStatics::GetPlayerController(World, 0);
327  if (PlayerController == nullptr)
328  {
329  UE_LOG(LogCarla, Error, TEXT("Can't find player controller!"));
330  return;
331  }
332  Spectator = PlayerController->GetPawn();
333  if (Spectator != nullptr)
334  {
335  FActorDescription Description;
336  Description.Id = TEXT("spectator");
337  Description.Class = Spectator->GetClass();
338  ActorDispatcher->RegisterActor(*Spectator, Description);
339  }
340  else
341  {
342  UE_LOG(LogCarla, Error, TEXT("Can't find spectator!"));
343  }
344 
345  // material parameters collection
346  UMaterialParameterCollection *Collection = LoadObject<UMaterialParameterCollection>(nullptr, TEXT("/Game/Carla/Blueprints/Game/CarlaParameters.CarlaParameters"), nullptr, LOAD_None, nullptr);
347  if (Collection != nullptr)
348  {
349  MaterialParameters = World->GetParameterCollectionInstance(Collection);
350  if (MaterialParameters == nullptr)
351  {
352  UE_LOG(LogCarla, Error, TEXT("Can't find CarlaParameters instance!"));
353  }
354  }
355  else
356  {
357  UE_LOG(LogCarla, Error, TEXT("Can't find CarlaParameters asset!"));
358  }
359 
360  for (TActorIterator<ATrafficSignBase> It(World); It; ++It)
361  {
362  ATrafficSignBase *Actor = *It;
363  check(Actor != nullptr);
364  FActorDescription Description;
365  Description.Id = UCarlaEpisode_GetTrafficSignId(Actor->GetTrafficSignState());
366  Description.Class = Actor->GetClass();
367  ActorDispatcher->RegisterActor(*Actor, Description);
368  }
369 
370  // get the definition id for static.prop.mesh
371  auto Definitions = GetActorDefinitions();
372  uint32 StaticMeshUId = 0;
373  for (auto& Definition : Definitions)
374  {
375  if (Definition.Id == "static.prop.mesh")
376  {
377  StaticMeshUId = Definition.UId;
378  break;
379  }
380  }
381 
382  for (TActorIterator<AStaticMeshActor> It(World); It; ++It)
383  {
384  auto Actor = *It;
385  check(Actor != nullptr);
386  auto MeshComponent = Actor->GetStaticMeshComponent();
387  check(MeshComponent != nullptr);
388  if (MeshComponent->Mobility == EComponentMobility::Movable)
389  {
390  FActorDescription Description;
391  Description.Id = TEXT("static.prop.mesh");
392  Description.UId = StaticMeshUId;
393  Description.Class = Actor->GetClass();
394  Description.Variations.Add("mesh_path",
396  MeshComponent->GetStaticMesh()->GetPathName()});
397  Description.Variations.Add("mass",
399  FString::SanitizeFloat(MeshComponent->GetMass())});
400  ActorDispatcher->RegisterActor(*Actor, Description);
401  }
402  }
403 }
404 
406 {
407  // stop recorder and replayer
408  if (Recorder)
409  {
410  Recorder->Stop();
411  if (Recorder->GetReplayer()->IsEnabled())
412  {
413  Recorder->GetReplayer()->Stop();
414  }
415  }
416 }
417 
418 std::string UCarlaEpisode::StartRecorder(std::string Name, bool AdditionalData)
419 {
420  std::string result;
421 
422  if (Recorder)
423  {
424  result = Recorder->Start(Name, MapName, AdditionalData);
425  }
426  else
427  {
428  result = "Recorder is not ready";
429  }
430 
431  return result;
432 }
433 
434 TPair<EActorSpawnResultStatus, FCarlaActor*> UCarlaEpisode::SpawnActorWithInfo(
435  const FTransform &Transform,
436  FActorDescription thisActorDescription,
437  FCarlaActor::IdType DesiredId)
438 {
439  ALargeMapManager* LargeMap = UCarlaStatics::GetLargeMapManager(GetWorld());
440  FTransform LocalTransform = Transform;
441  if(LargeMap)
442  {
443  LocalTransform = LargeMap->GlobalToLocalTransform(LocalTransform);
444  }
445 
446  // NewTransform.AddToTranslation(-1.0f * FVector(CurrentMapOrigin));
447  auto result = ActorDispatcher->SpawnActor(LocalTransform, thisActorDescription, DesiredId);
448  if (result.Key == EActorSpawnResultStatus::Success && bIsPrimaryServer)
449  {
450  if (Recorder->IsEnabled())
451  {
453  result.Value->GetActorId(),
454  static_cast<uint8_t>(result.Value->GetActorType()),
455  Transform,
456  thisActorDescription
457  );
458  }
459  if (bIsPrimaryServer)
460  {
462  result.Value->GetActorId(),
463  static_cast<uint8_t>(result.Value->GetActorType()),
464  Transform,
465  std::move(thisActorDescription));
466  }
467  }
468 
469  return result;
470 }
FCarlaActor * FindCarlaActor(FCarlaActor::IdType ActorId)
Find a Carla actor by id.
Definition: CarlaEpisode.h:172
bool IsEnabled(void)
Definition: CarlaReplayer.h:65
Seting for map generation from opendrive without additional geometry.
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.
std::string Start(std::string Name, FString MapName, bool AdditionalData=false)
TPair< EActorSpawnResultStatus, FCarlaActor * > SpawnActor(const FTransform &Transform, FActorDescription ActorDescription, FCarlaActor::IdType DesiredId=0)
Spawns an actor based on ActorDescription at Transform.
FString MapName
Definition: CarlaEpisode.h:368
UActorDispatcher * ActorDispatcher
Definition: CarlaEpisode.h:374
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...
ETrafficSignState
static void AttachActors(AActor *Child, AActor *Parent, EAttachmentType AttachmentType)
EAttachmentType
Definition: ActorAttacher.h:20
The game instance contains elements that must be kept alive in between levels.
FFrameData FrameData
Definition: CarlaEpisode.h:391
carla::rpc::Actor SerializeActor(FCarlaActor *CarlaActor) const
Create a serializable object describing the actor.
static FOnEpisodeSettingsChange OnEpisodeSettingsChange
TArray< FTransform > GetRecommendedSpawnPoints() const
Return the list of recommended spawn points for vehicles.
void AddEvent(const CarlaRecorderEventAdd &Event)
static void GetTagsOfTaggedActor(const AActor &Actor, TSet< crp::CityObjectLabel > &Tags)
Retrieve the tags of an already tagged actor.
Definition: Tagger.cpp:234
std::shared_ptr< carla::multigpu::Router > GetSecondaryServer()
Definition: CarlaEngine.h:80
uint32 IdType
Definition: CarlaActor.h:27
FIntVector CurrentMapOrigin
Definition: CarlaEpisode.h:389
CarlaReplayer * GetReplayer(void)
static FString BuildRecastBuilderFile()
static T Get(carla::rpc::Response< T > &response)
ActorDescription description
Definition: rpc/Actor.h:29
static ACarlaGameModeBase * GetGameMode(const UObject *WorldContextObject)
Definition: CarlaStatics.h:58
static boost::optional< road::Map > Load(const std::string &opendrive)
const FString & GetMapName() const
Return the name of the map loaded in this episode.
Definition: CarlaEpisode.h:92
geom::BoundingBox bounding_box
Definition: rpc/Actor.h:31
void CreateRecorderEventAdd(uint32_t DatabaseId, uint8_t Type, const FTransform &Transform, FActorDescription ActorDescription)
TMap< FString, FActorAttribute > Variations
User selected variations of the actor.
std::string StartRecorder(std::string name, bool AdditionalData)
static FString GetRelevantTagAsString(const TSet< crp::CityObjectLabel > &SemanticTags)
static UCarlaGameInstance * GetGameInstance(const UObject *WorldContextObject)
Definition: CarlaStatics.h:63
carla::SharedPtr< cc::Actor > Actor
crp::Actor SerializedData
Definition: ActorInfo.h:32
TPair< EActorSpawnResultStatus, FCarlaActor * > SpawnActorWithInfo(const FTransform &Transform, FActorDescription thisActorDescription, FCarlaActor::IdType DesiredId=0)
Spawns an actor based on ActorDescription at Transform.
bool LoadNewEpisode(const FString &MapString, bool ResetSettings=true)
Load a new map and start a new episode.
const TArray< FActorDefinition > & GetActorDefinitions() const
Return the list of actor definitions that are available to be spawned this episode.
Definition: CarlaEpisode.h:123
TSubclassOf< AActor > Class
Class of the actor to be spawned.
static FBoundingBox GetActorBoundingBox(const AActor *Actor, uint8 InTagQueried=0xFF)
Compute the bounding box of the given Carla actor.
A description of a Carla Actor with all its variation.
bool IsEnabled(void)
Definition: CarlaRecorder.h:82
static void log_warning(Args &&... args)
Definition: Logging.h:96
const FActorInfo * GetActorInfo() const
Definition: CarlaActor.h:100
static FString UCarlaEpisode_GetTrafficSignId(ETrafficSignState State)
void SetEpisode(UCarlaEpisode *ThisEpisode)
Definition: FrameData.h:65
bool bIsPrimaryServer
Definition: CarlaEpisode.h:329
APawn * Spectator
Definition: CarlaEpisode.h:377
std::vector< uint8_t > semantic_tags
Definition: rpc/Actor.h:33
UCarlaEpisode(const FObjectInitializer &ObjectInitializer)
FFrameData & GetFrameData()
Definition: CarlaEpisode.h:325
void AttachActors(AActor *Child, AActor *Parent, EAttachmentType InAttachmentType=EAttachmentType::Rigid)
Attach Child to Parent.
FTransform GlobalToLocalTransform(const FTransform &InTransform) const
ACarlaRecorder * Recorder
Definition: CarlaEpisode.h:385
static ALargeMapManager * GetLargeMapManager(const UObject *WorldContextObject)
Definition: CarlaStatics.h:100
uint32 UId
UId of the definition in which this description was based.
Base class for the CARLA Game Mode.
void InitializeAtBeginPlay()
FEpisodeSettings EpisodeSettings
Definition: CarlaEpisode.h:371
void Stop(bool KeepActors=false)
ActorId parent_id
Definition: rpc/Actor.h:27
IdType GetActorId() const
Definition: CarlaActor.h:80
FCarlaEngine * GetCarlaEngine()
ETrafficSignState GetTrafficSignState() const
void SetOpendriveGenerationParameters(const carla::rpc::OpendriveGenerationParameters &Parameters)
void CreateRecorderEventAdd(uint32_t DatabaseId, uint8_t Type, const FTransform &Transform, FActorDescription ActorDescription, bool bAddOtherRelatedInfo=true)
Definition: FrameData.cpp:264
An actor attribute, may be an intrinsic (non-modifiable) attribute of the actor or an user-defined ac...
void AddEvent(const CarlaRecorderEventAdd &Event)
Definition: FrameData.cpp:502
UMaterialParameterCollectionInstance * MaterialParameters
Definition: CarlaEpisode.h:383
geom::Transform Transform
Definition: rpc/Transform.h:16
const TArray< FTransform > & GetSpawnPointsTransforms() const
A view over an actor and its properties.
Definition: CarlaActor.h:23
void ApplySettings(const FEpisodeSettings &Settings)
IdType GetParent() const
Definition: CarlaActor.h:120