CARLA
Loading...
Searching...
No Matches
CarlaServer.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"
26#include "Carla/Game/Tagger.h"
34#include "Carla/Game/CarlaHUD.h"
35#include "Components/SceneComponent.h"
36#include "Components/SkinnedMeshComponent.h"
37#include "ProceduralMeshComponent.h"
38#include "Engine/Engine.h"
39
41#include <carla/Functional.h>
43#include <carla/Sockets.h>
44#include <carla/Version.h>
46#include <carla/rpc/Actor.h>
50#include <carla/rpc/Command.h>
60#include <carla/rpc/MapInfo.h>
61#include <carla/rpc/MapLayer.h>
62#include <carla/rpc/Response.h>
63#include <carla/rpc/Server.h>
64#include <carla/rpc/String.h>
65#include <carla/rpc/Transform.h>
66#include <carla/rpc/Vector2D.h>
67#include <carla/rpc/Vector3D.h>
81#include <carla/rpc/Texture.h>
84
85#include <util/ue-header-guard-begin.h>
86#include "EngineUtils.h"
87#include "GameFramework/CharacterMovementComponent.h"
88#include "Misc/App.h"
89#include "Misc/FileHelper.h"
90#include "Animation/PoseSnapshot.h"
91#include <util/ue-header-guard-end.h>
92
93#include <vector>
94#include <atomic>
95#include <map>
96#include <tuple>
97
98template <typename T>
100
101// =============================================================================
102// -- Static local functions ---------------------------------------------------
103// =============================================================================
104
105template <typename T, typename Other>
106static std::vector<T> MakeVectorFromTArray(const TArray<Other> &Array)
107{
108 return {Array.GetData(), Array.GetData() + Array.Num()};
109}
110
112{
114 Info.name = carla::rpc::FromFString(Pack.GetName());
115 Info.version = carla::rpc::FromFString(Pack.Manifest.Version);
116 Info.base_release = carla::rpc::FromFString(Pack.Manifest.BaseRelease);
117 Info.path = carla::rpc::FromFString(Pack.PackDir);
118 Info.mounted = Pack.bMounted;
119 for (const FCarlaContentPackMap &Map : Pack.Manifest.Maps)
120 {
121 Info.maps.emplace_back(carla::rpc::FromFString(Map.Name));
122 }
123 return Info;
124}
125
126/// True when the stream belongs to a camera and this process has no RHI
127/// (-nullrhi): a local token for it could never deliver a frame, so the
128/// camera must be owned by a rendering Multi-GPU secondary instead.
130 UCarlaEpisode &Episode,
132{
133 if (FApp::CanEverRender())
134 {
135 return false;
136 }
137 const FCarlaActor *CarlaActor = Episode.FindCarlaActorFromStream(StreamId);
138 if (CarlaActor == nullptr)
139 {
140 return false;
141 }
142 const AActor *Actor = CarlaActor->GetActor();
143 return Actor != nullptr &&
144 (Actor->IsA<ASceneCaptureSensor>() || Actor->IsA<ASceneCaptureSensor_WideAngleLens>());
145}
146
147/// Resolve the AWalkerController behind a walker-navigation RPC actor id.
148/// Accepts either the walker pawn itself or the controller.ai.walker handle
149/// actor (which clients spawn attached to the walker). Returns nullptr for
150/// unknown, dormant or dead actors -- the navigation RPCs answer false in
151/// that case instead of raising, per the phase-1 contract.
153{
154 if (CarlaActor == nullptr || CarlaActor->IsDormant())
155 {
156 return nullptr;
157 }
158 AActor *Actor = CarlaActor->GetActor();
159 if (Actor == nullptr)
160 {
161 return nullptr;
162 }
163 if (Cast<AWalkerAIController>(Actor) != nullptr)
164 {
165 Actor = Actor->GetAttachParentActor();
166 if (Actor == nullptr)
167 {
168 return nullptr;
169 }
170 }
171 auto *Walker = Cast<AWalkerBase>(Actor);
172 if (Walker != nullptr && !Walker->bAlive)
173 {
174 return nullptr;
175 }
176 auto *Pawn = Cast<APawn>(Actor);
177 if (Pawn == nullptr)
178 {
179 return nullptr;
180 }
181 return Cast<AWalkerController>(Pawn->GetController());
182}
183
184// =============================================================================
185// -- FCarlaServer::FPimpl -----------------------------------------------
186// =============================================================================
187
189{
190public:
191
192 FPimpl(uint16_t RPCPort, uint16_t StreamingPort, uint16_t SecondaryPort)
193 : Server(RPCPort),
194 StreamingServer(StreamingPort),
195 BroadcastStream(StreamingServer.MakeStream())
196 {
197 // we need to create shared_ptr from the router for some handlers to live
198 SecondaryServer = std::make_shared<carla::multigpu::Router>(SecondaryPort);
199 SecondaryServer->SetCallbacks();
200 BindActions();
201 }
202
203 std::shared_ptr<carla::multigpu::Router> GetSecondaryServer() {
204 return SecondaryServer;
205 }
206
207 /// Map of pairs < port , ip > with all the Traffic Managers active in the simulation
208 std::map<uint16_t, std::string> TrafficManagerInfo;
209
211
213
215
216 std::shared_ptr<carla::multigpu::Router> SecondaryServer;
217
219
220 std::atomic_size_t TickCuesReceived { 0u };
221
222 /// Set once, when the engine starts as a Multi-GPU secondary; read by RPC
223 /// handlers, which may already be serving then.
224 std::atomic_bool bIsSecondaryServer { false };
225
226private:
227
228 void BindActions();
229};
230
231// =============================================================================
232// -- Define helper macros -----------------------------------------------------
233// =============================================================================
234
235#if WITH_EDITOR
236# define CARLA_ENSURE_GAME_THREAD() check(IsInGameThread());
237#else
238# define CARLA_ENSURE_GAME_THREAD()
239#endif // WITH_EDITOR
240
241#define RESPOND_ERROR(str) { \
242 UE_LOG(LogCarlaServer, Log, TEXT("Responding error: %s"), TEXT(str)); \
243 return carla::rpc::ResponseError(str); }
244
245#define RESPOND_ERROR_FSTRING(fstr) { \
246 UE_LOG(LogCarlaServer, Log, TEXT("Responding error: %s"), *fstr); \
247 return carla::rpc::ResponseError(carla::rpc::FromFString(fstr)); }
248
249#define REQUIRE_CARLA_EPISODE() \
250 CARLA_ENSURE_GAME_THREAD(); \
251 if (Episode == nullptr) { RESPOND_ERROR("episode not ready"); }
252
253#define REQUIRE_CARLA_GAME_MODE() \
254 ACarlaGameModeBase* GameMode = UCarlaStatics::GetGameMode(Episode->GetWorld()); \
255 if (!GameMode) \
256 { \
257 RESPOND_ERROR("unable to find CARLA game mode"); \
258 }
259
260// A Multi-GPU secondary only mirrors the primary: a call that would change its
261// world (or that only the primary can answer) would make it diverge.
262#define REQUIRE_PRIMARY_SERVER() \
263 if (bIsSecondaryServer) \
264 { \
265 RESPOND_ERROR("this is a Multi-GPU secondary server: it mirrors the primary and answers read-only calls only; send this call to the primary server"); \
266 }
267
268static std::vector<std::string> MakeStringVector(const TArray<FString> &Names)
269{
270 std::vector<std::string> Result;
271 Result.reserve(Names.Num());
272 for (const FString &Name : Names)
273 {
274 Result.push_back(TCHAR_TO_UTF8(*Name));
275 }
276 return Result;
277}
278
280 const FString& FuncName,
281 const FString& ErrorMessage,
282 const FString& ExtraInfo = "")
283{
284 FString TotalMessage = "Responding error from function " + FuncName + ": " +
285 ErrorMessage + ". " + ExtraInfo;
286 UE_LOG(LogCarlaServer, Log, TEXT("%s"), *TotalMessage);
287 return carla::rpc::ResponseError(carla::rpc::FromFString(TotalMessage));
288}
289
291 const FString& FuncName,
292 const ECarlaServerResponse& Error,
293 const FString& ExtraInfo = "")
294{
295 return RespondError(FuncName, CarlaGetStringError(Error), ExtraInfo);
296}
297
298template <typename T>
300 UCarlaEpisode* Episode,
301 carla::rpc::ActorId ActorId,
302 const carla::rpc::MaterialParameter& MaterialParameter,
303 T&& Texture)
304{
305 auto CarlaActor = Episode->FindCarlaActor(ActorId);
306 if (CarlaActor == nullptr)
307 {
308 RESPOND_ERROR("Could not find CARLA Actor.");
309 }
310 auto Actor = CarlaActor->GetActor();
311 check(Actor);
313 auto TextureUE = GameMode->CreateUETexture(Texture);
314 if (TextureUE == nullptr)
315 {
316 RESPOND_ERROR("CreateUETexture failed.");
317 }
318 GameMode->ApplyTextureToActor(Actor, TextureUE, MaterialParameter);
319 return R<void>::Success();
320}
321
323{
324public:
325
326 constexpr ServerBinder(const char *name, carla::rpc::Server &srv, bool sync)
327 : _name(name),
328 _server(srv),
329 _sync(sync) {}
330
331 template <typename FuncT>
332 auto operator<<(FuncT func)
333 {
334 if (_sync)
335 {
336 _server.BindSync(_name, func);
337 }
338 else
339 {
340 _server.BindAsync(_name, func);
341 }
342 return func;
343 }
344
345private:
346
347 const char *_name;
348
350
351 bool _sync;
352};
353
354#define BIND_SYNC(name) auto name = ServerBinder(# name, Server, true)
355#define BIND_ASYNC(name) auto name = ServerBinder(# name, Server, false)
356
357// =============================================================================
358// -- Bind Actions -------------------------------------------------------------
359// =============================================================================
360
362{
363 namespace cr = carla::rpc;
364 namespace cg = carla::geom;
365
366 /// Looks for a Traffic Manager running on port
367 BIND_SYNC(is_traffic_manager_running) << [this] (uint16_t port) ->R<bool>
368 {
369 return (TrafficManagerInfo.find(port) != TrafficManagerInfo.end());
370 };
371
372 /// Gets a pair filled with the <IP, port> of the Trafic Manager running on port.
373 /// If there is no Traffic Manager running the pair will be ("", 0)
374 BIND_SYNC(get_traffic_manager_running) << [this] (uint16_t port) ->R<std::pair<std::string, uint16_t>>
375 {
376 auto it = TrafficManagerInfo.find(port);
377 if(it != TrafficManagerInfo.end()) {
378 return std::pair<std::string, uint16_t>(it->second, it->first);
379 }
380 return std::pair<std::string, uint16_t>("",0);
381 };
382
383 /// Add a new Traffic Manager running on <IP, port>
384 BIND_SYNC(add_traffic_manager_running) << [this] (std::pair<std::string, uint16_t> trafficManagerInfo) ->R<bool>
385 {
387 uint16_t port = trafficManagerInfo.second;
388 auto it = TrafficManagerInfo.find(port);
389 if(it == TrafficManagerInfo.end()) {
390 TrafficManagerInfo.insert(
391 std::pair<uint16_t, std::string>(port, trafficManagerInfo.first));
392 return true;
393 }
394 return false;
395
396 };
397
398 BIND_SYNC(destroy_traffic_manager) << [this] (uint16_t port) ->R<bool>
399 {
401 auto it = TrafficManagerInfo.find(port);
402 if(it != TrafficManagerInfo.end()) {
403 TrafficManagerInfo.erase(it);
404 return true;
405 }
406 return false;
407 };
408
409 BIND_ASYNC(version) << [] () -> R<std::string>
410 {
411 return carla::version();
412 };
413
414 // ~~ Tick ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
415
416 BIND_SYNC(tick_cue) << [this]() -> R<uint64_t>
417 {
419 TRACE_CPUPROFILER_EVENT_SCOPE(TickCueReceived);
420 auto Current = FCarlaEngine::GetFrameCounter();
421 (void)TickCuesReceived.fetch_add(1, std::memory_order_release);
422 return Current + 1;
423 };
424
425 // ~~ Load new episode ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
426
427 // Sync (game thread): the asset registry query behind GetAllMapNames
428 // asserts IsInGameThread, and the content pack list is mutated there.
429 BIND_SYNC(get_available_maps) << [this]() -> R<std::vector<std::string>>
430 {
432 const auto MapNames = UCarlaStatics::GetAllMapNames();
433 std::vector<std::string> result;
434 result.reserve(MapNames.Num());
435 for (const auto &MapName : MapNames)
436 {
437 if (MapName.Contains("/Sublevels/"))
438 continue;
439 if (MapName.Contains("/BaseMap/"))
440 continue;
441 if (MapName.Contains("/BaseLargeMap/"))
442 continue;
443 if (MapName.Contains("_Tile_"))
444 continue;
445
446 result.emplace_back(cr::FromFString(MapName));
447 }
448 return result;
449 };
450
451 BIND_SYNC(load_new_episode) << [this](const std::string &map_name, const bool reset_settings, cr::MapLayer MapLayers) -> R<void>
452 {
455
456 UCarlaGameInstance* GameInstance = UCarlaStatics::GetGameInstance(Episode->GetWorld());
457 if (!GameInstance)
458 {
459 RESPOND_ERROR("unable to find CARLA game instance");
460 }
461 GameInstance->SetMapLayer(static_cast<int32>(MapLayers));
462
463 // reload_world sends an empty name: reload the current map.
464 const FString MapToLoad = map_name.empty()
466 : cr::ToFString(map_name);
467 if(!Episode->LoadNewEpisode(MapToLoad, reset_settings))
468 {
469 FString Str(TEXT("Map '"));
470 Str += cr::ToFString(map_name);
471 Str += TEXT("' not found");
473 }
474
475 return R<void>::Success();
476 };
477
478 // ~~ Content packs ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
479
480 BIND_SYNC(get_content_packs) << [this]() -> R<std::vector<cr::ContentPackInfo>>
481 {
484 if (ContentPacks == nullptr)
485 {
486 RESPOND_ERROR("content pack manager not available");
487 }
488 std::vector<cr::ContentPackInfo> result;
489 for (const FCarlaContentPack &Pack : ContentPacks->GetPacks())
490 {
491 result.emplace_back(MakeContentPackInfo(Pack));
492 }
493 return result;
494 };
495
496 BIND_SYNC(mount_content_pack) << [this](const std::string &path) -> R<cr::ContentPackInfo>
497 {
500 if (ContentPacks == nullptr)
501 {
502 RESPOND_ERROR("content pack manager not available");
503 }
504 FString Error;
505 const FCarlaContentPack *Pack = nullptr;
506 if (!ContentPacks->Mount(cr::ToFString(path), Error, &Pack))
507 {
508 FString Str(TEXT("mount_content_pack: "));
509 Str += Error;
511 }
512 return MakeContentPackInfo(*Pack);
513 };
514
515 BIND_SYNC(unmount_content_pack) << [this](const std::string &name) -> R<bool>
516 {
520 if (ContentPacks == nullptr)
521 {
522 RESPOND_ERROR("content pack manager not available");
523 }
524 FString Error;
525 if (!ContentPacks->Unmount(cr::ToFString(name), Error))
526 {
527 FString Str(TEXT("unmount_content_pack: "));
528 Str += Error;
530 }
531 return true;
532 };
533
534 BIND_SYNC(load_map_layer) << [this](cr::MapLayer MapLayers) -> R<void>
535 {
538
540 if (!GameMode)
541 {
542 RESPOND_ERROR("unable to find CARLA game mode");
543 }
544 GameMode->LoadMapLayer(static_cast<int32>(MapLayers));
545
546 return R<void>::Success();
547 };
548
549 BIND_SYNC(unload_map_layer) << [this](cr::MapLayer MapLayers) -> R<void>
550 {
553
555 if (!GameMode)
556 {
557 RESPOND_ERROR("unable to find CARLA game mode");
558 }
559 GameMode->UnLoadMapLayer(static_cast<int32>(MapLayers));
560
561 return R<void>::Success();
562 };
563
564 BIND_SYNC(copy_opendrive_to_file) << [this](const std::string &opendrive, cr::OpendriveGenerationParameters Params) -> R<void>
565 {
568 if (!Episode->LoadNewOpendriveEpisode(cr::ToLongFString(opendrive), Params))
569 {
570 RESPOND_ERROR("opendrive could not be correctly parsed");
571 }
572 return R<void>::Success();
573 };
574
575 BIND_SYNC(apply_texture_to_actor) << [this](
576 cr::ActorId ActorId,
577 const cr::MaterialParameter& MaterialParameter,
578 const cr::TextureColor& Texture) -> R<void>
579 {
582 ::ApplyTextureToActor(Episode, ActorId, MaterialParameter, Texture);
583 return R<void>::Success();
584 };
585
586 BIND_SYNC(apply_texture_to_actor_float) << [this](
587 cr::ActorId ActorId,
588 const cr::MaterialParameter& MaterialParameter,
589 const cr::TextureFloatColor& Texture) -> R<void>
590 {
593 ::ApplyTextureToActor(Episode, ActorId, MaterialParameter, Texture);
594 return R<void>::Success();
595 };
596
597 BIND_SYNC(apply_color_texture_to_objects) << [this](
598 const std::vector<std::string> &actors_name,
599 const cr::MaterialParameter& parameter,
600 const cr::TextureColor& Texture) -> R<void>
601 {
605 if (!GameMode)
606 {
607 RESPOND_ERROR("unable to find CARLA game mode");
608 }
609 TArray<AActor*> ActorsToPaint;
610 for(const std::string& actor_name : actors_name)
611 {
612 AActor* ActorToPaint = GameMode->FindActorByName(cr::ToFString(actor_name));
613 if (ActorToPaint)
614 {
615 ActorsToPaint.Add(ActorToPaint);
616 }
617 }
618
619 if(!ActorsToPaint.Num())
620 {
621 RESPOND_ERROR("unable to find Actor to apply the texture");
622 }
623
624 UTexture2D* UETexture = GameMode->CreateUETexture(Texture);
625
626 for(AActor* ActorToPaint : ActorsToPaint)
627 {
628 GameMode->ApplyTextureToActor(
629 ActorToPaint,
630 UETexture,
631 parameter);
632 }
633 return R<void>::Success();
634 };
635
636 BIND_SYNC(apply_float_color_texture_to_objects) << [this](
637 const std::vector<std::string> &actors_name,
638 const cr::MaterialParameter& parameter,
639 const cr::TextureFloatColor& Texture) -> R<void>
640 {
644 if (!GameMode)
645 {
646 RESPOND_ERROR("unable to find CARLA game mode");
647 }
648 TArray<AActor*> ActorsToPaint;
649 for(const std::string& actor_name : actors_name)
650 {
651 AActor* ActorToPaint = GameMode->FindActorByName(cr::ToFString(actor_name));
652 if (ActorToPaint)
653 {
654 ActorsToPaint.Add(ActorToPaint);
655 }
656 }
657
658 if(!ActorsToPaint.Num())
659 {
660 RESPOND_ERROR("unable to find Actor to apply the texture");
661 }
662
663 UTexture2D* UETexture = GameMode->CreateUETexture(Texture);
664
665 for(AActor* ActorToPaint : ActorsToPaint)
666 {
667 GameMode->ApplyTextureToActor(
668 ActorToPaint,
669 UETexture,
670 parameter);
671 }
672 return R<void>::Success();
673 };
674
675 BIND_SYNC(get_names_of_all_objects) << [this]() -> R<std::vector<std::string>>
676 {
679 if (!GameMode)
680 {
681 RESPOND_ERROR("unable to find CARLA game mode");
682 }
683 TArray<FString> NamesFString = GameMode->GetNamesOfAllActors();
684 std::vector<std::string> NamesStd;
685 for (const FString &Name : NamesFString)
686 {
687 NamesStd.emplace_back(cr::FromFString(Name));
688 }
689 return NamesStd;
690 };
691
692 // ~~ Episode settings and info ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
693
694 BIND_SYNC(get_episode_info) << [this]() -> R<cr::EpisodeInfo>
695 {
697 return cr::EpisodeInfo{Episode->GetId(), BroadcastStream.token()};
698 };
699
700 BIND_SYNC(get_map_info) << [this]() -> R<cr::MapInfo>
701 {
704 const auto &SpawnPoints = Episode->GetRecommendedSpawnPoints();
705 FString FullMapPath = GameMode->GetFullMapPath();
706 FString MapDir = FullMapPath.RightChop(FullMapPath.Find("Content/", ESearchCase::CaseSensitive) + 8);
707 MapDir += "/" + Episode->GetMapName();
708 return cr::MapInfo{
709 cr::FromFString(MapDir),
710 MakeVectorFromTArray<cg::Transform>(SpawnPoints)};
711 };
712
713 BIND_SYNC(get_map_data) << [this]() -> R<std::string>
714 {
716 return cr::FromLongFString(UOpenDrive::GetXODR(Episode->GetWorld()));
717 };
718
719 BIND_SYNC(get_navigation_mesh) << [this]() -> R<std::vector<uint8_t>>
720 {
722 // A Multi-GPU secondary builds no navigation mesh for a world generated
723 // from OpenDRIVE; the one in a shared Saved/ folder can be another run's.
724 if (bIsSecondaryServer && Episode->GetMapName().Equals(TEXT("OpenDriveMap"), ESearchCase::IgnoreCase))
725 {
726 return std::vector<uint8_t>{};
727 }
728 // A generated OpenDRIVE world builds its navmesh in the background.
730 auto FileContents = FNavigationMesh::Load(Episode->GetMapName());
731 // make a mem copy (from TArray to std::vector)
732 std::vector<uint8_t> Result(FileContents.Num());
733 memcpy(&Result[0], FileContents.GetData(), FileContents.Num());
734 return Result;
735 };
736
737 BIND_SYNC(get_required_files) << [this](std::string folder = "") -> R<std::vector<std::string>>
738 {
740
741 // Check that the path ends in a slash, add it otherwise
742 if (!folder.empty() && folder[folder.size() - 1] != '/' && folder[folder.size() - 1] != '\\') {
743 folder += "/";
744 }
745
746 // Get the map's folder absolute path and check if it's in its own folder
748 const auto mapDir = GameMode->GetFullMapPath();
749 const auto folderDir = mapDir + "/" + folder.c_str();
750 const auto fileName = mapDir.EndsWith(Episode->GetMapName()) ? "*" : Episode->GetMapName();
751
752 // Find all the xodr and bin files from the map. A generated OpenDRIVE
753 // world only ever has current files in Saved/ (see
754 // UCarlaEpisode::LoadNewOpendriveEpisode); copies of OpenDriveMap.* in
755 // the content dir (cooked into the base pak) are stale by construction
756 // and must never be served.
757 const bool bGeneratedWorld = Episode->GetMapName().Equals(TEXT("OpenDriveMap"), ESearchCase::IgnoreCase);
758 TArray<FString> Files;
759 if (!bGeneratedWorld)
760 {
761 IFileManager::Get().FindFilesRecursive(Files, *folderDir, *(fileName + ".xodr"), true, false, false);
762 IFileManager::Get().FindFilesRecursive(Files, *folderDir, *(fileName + ".bin"), true, false, false);
763 }
764
765 // Generated OpenDRIVE worlds keep their xodr/nav in Saved/; they are
766 // served under the conventional Carla/Maps/{OpenDrive,Nav}/ names and
767 // filtered by the requested sub-folder like the content walk above.
768 const FString SavedDir = FPaths::ConvertRelativePathToFull(FPaths::ProjectSavedDir()) / TEXT("");
769 if (bGeneratedWorld)
770 {
771 const FString Folder = UTF8_TO_TCHAR(folder.c_str());
772 const bool bWantXODR = Folder.IsEmpty() || Folder.StartsWith(TEXT("OpenDrive"), ESearchCase::IgnoreCase);
773 const bool bWantNav = Folder.IsEmpty() || Folder.StartsWith(TEXT("Nav"), ESearchCase::IgnoreCase);
774 if (bWantNav)
775 {
776 // The client asks for the navmesh right after load_world; RecastBuilder
777 // may still be running (bounded wait, logs on failure).
779 }
780 // Where this server keeps the xodr: a Multi-GPU secondary has its own
781 // folder, and builds no navigation mesh.
782 const FString SavedXODR = UOpenDrive::GetSavedXODRPath(Episode->GetMapName());
783 const FString SavedNav = SavedDir / TEXT("Nav") / (Episode->GetMapName() + TEXT(".bin"));
784 if (bWantXODR && IFileManager::Get().FileExists(*SavedXODR)) Files.Add(SavedXODR);
785 if (bWantNav && !bIsSecondaryServer && IFileManager::Get().FileExists(*SavedNav)) Files.Add(SavedNav);
786 }
787
788 // Remove the start of the path until the content folder and put each file
789 // in the result. In a packaged build the file manager hands back
790 // pak-relative paths ("../../../<Project>/Content/..."), so normalize each
791 // file to an absolute path before stripping the absolute content dir;
792 // otherwise the raw relative path leaks to the client, which would try to
793 // resolve it against its cache folder and escape it. Files of a content
794 // pack are named Packs/<Pack>/<path under its Content dir>.
795 // Every prefix carries a trailing '/', so a sibling dir such as
796 // "ContentBackup" can never match.
797 const FString ContentDir = FPaths::ConvertRelativePathToFull(FPaths::ProjectContentDir()) / TEXT("");
799 std::vector<std::string> result;
800 for (auto File : Files) {
801 File = FPaths::ConvertRelativePathToFull(File);
802 if (File.StartsWith(SavedDir) && File.EndsWith(TEXT(".xodr")))
803 {
804 // Under its conventional name, whatever folder this server keeps it in.
805 File = TEXT("Carla/Maps/OpenDrive") / FPaths::GetCleanFilename(File);
806 }
807 else if (File.StartsWith(SavedDir))
808 {
809 File.RemoveFromStart(SavedDir);
810 File = TEXT("Carla/Maps") / File;
811 }
812 else if (File.StartsWith(ContentDir))
813 {
814 File.RemoveFromStart(ContentDir);
815 }
816 else if (ContentPacks != nullptr)
817 {
818 for (const FCarlaContentPack &Pack : ContentPacks->GetPacks())
819 {
820 const FString PackContentDir = Pack.ContentDir / TEXT("");
821 if (Pack.bMounted && File.StartsWith(PackContentDir))
822 {
823 File.RemoveFromStart(PackContentDir);
824 File = FString::Printf(TEXT("Packs/%s"), *Pack.GetName()) / File;
825 break;
826 }
827 }
828 }
829 result.emplace_back(TCHAR_TO_UTF8(*File));
830 }
831
832 return result;
833 };
834 BIND_SYNC(request_file) << [this](std::string name) -> R<std::vector<uint8_t>>
835 {
837
838 // Get the absolute path of the file, refusing names that escape the
839 // content folder: the name comes from the client, and ".." segments would
840 // otherwise let it read arbitrary files on the server host.
841 const FString ContentDir = FPaths::ConvertRelativePathToFull(FPaths::ProjectContentDir());
842 FString path = ContentDir;
843 path.Append(name.c_str());
844 path = FPaths::ConvertRelativePathToFull(path);
845 if (!path.StartsWith(ContentDir))
846 {
847 RESPOND_ERROR("file requested outside the content folder");
848 }
849
850 // Names produced by get_required_files for a content pack
851 // (Packs/<Pack>/...) resolve inside that pack's Content dir. The
852 // generated OpenDRIVE world's files (Carla/Maps/{OpenDrive,Nav}/...) are
853 // served from Saved/ whenever a copy exists there: the content-dir copy
854 // cooked into the base pak is stale by construction.
855 {
856 FString Rest = path;
857 Rest.RemoveFromStart(ContentDir);
858 FString PackName, PackRelative;
859 FString SavedRelative = Rest;
860 if (Rest.RemoveFromStart(TEXT("Packs/")) && Rest.Split(TEXT("/"), &PackName, &PackRelative))
861 {
863 const FCarlaContentPack *Pack = ContentPacks ? ContentPacks->FindPack(PackName) : nullptr;
864 if (Pack != nullptr && Pack->bMounted)
865 {
866 const FString PackContentDir = Pack->ContentDir / TEXT("");
867 const FString PackPath = FPaths::ConvertRelativePathToFull(PackContentDir / PackRelative);
868 if (!PackPath.StartsWith(PackContentDir))
869 {
870 RESPOND_ERROR("file requested outside the content pack folder");
871 }
872 path = PackPath;
873 }
874 }
875 else if (SavedRelative.RemoveFromStart(TEXT("Carla/Maps/")) &&
876 (SavedRelative.StartsWith(TEXT("OpenDrive/")) || SavedRelative.StartsWith(TEXT("Nav/"))))
877 {
878 const FString SavedDir = FPaths::ConvertRelativePathToFull(FPaths::ProjectSavedDir()) / TEXT("");
879 // The xodr from where this server keeps it (a Multi-GPU secondary has
880 // a folder of its own); a secondary builds no navigation mesh, and the
881 // one in a shared Saved/ folder can be another run's.
882 const bool bOwnXODR = bIsSecondaryServer &&
883 (FPaths::GetPath(SavedRelative) == TEXT("OpenDrive")) &&
884 FPaths::GetExtension(SavedRelative).Equals(TEXT("xodr"), ESearchCase::IgnoreCase);
885 const FString SavedPath = bOwnXODR ?
886 UOpenDrive::GetSavedXODRPath(FPaths::GetBaseFilename(SavedRelative)) :
887 FPaths::ConvertRelativePathToFull(SavedDir / SavedRelative);
888 if (SavedPath.StartsWith(SavedDir) && IFileManager::Get().FileExists(*SavedPath) &&
889 !(bIsSecondaryServer && SavedRelative.StartsWith(TEXT("Nav/"))))
890 {
891 path = SavedPath;
892 }
893 }
894 }
895
896 // Copy the binary data of the file into the result and return it
897 TArray<uint8_t> Content;
898 FFileHelper::LoadFileToArray(Content, *path, 0);
899 std::vector<uint8_t> Result(Content.Num());
900 memcpy(&Result[0], Content.GetData(), Content.Num());
901
902 return Result;
903 };
904
905 BIND_SYNC(get_episode_settings) << [this]() -> R<cr::EpisodeSettings>
906 {
908 return cr::EpisodeSettings{Episode->GetSettings()};
909 };
910
911 BIND_SYNC(set_episode_settings) << [this](
912 const cr::EpisodeSettings &settings) -> R<uint64_t>
913 {
916 Episode->ApplySettings(settings);
917 StreamingServer.SetSynchronousMode(settings.synchronous_mode);
918
920 if (!GameMode)
921 {
922 RESPOND_ERROR("unable to find CARLA game mode");
923 }
924 ALargeMapManager* LargeMap = GameMode->GetLMManager();
925 if (LargeMap)
926 {
927 LargeMap->ConsiderSpectatorAsEgo(settings.spectator_as_ego);
928 }
929
930 if (ATrafficLightManager* TrafficLightManager = GameMode->GetTrafficLightManager())
931 {
932 TrafficLightManager->SetAdjustSignsHeightToGround(
933 settings.adjust_signs_height_to_ground);
934 }
935
937 };
938
939 BIND_SYNC(get_actor_definitions) << [this]() -> R<std::vector<cr::ActorDefinition>>
940 {
942 return MakeVectorFromTArray<cr::ActorDefinition>(Episode->GetActorDefinitions());
943 };
944
945 BIND_SYNC(get_spectator) << [this]() -> R<cr::Actor>
946 {
949 if (!CarlaActor)
950 {
951 RESPOND_ERROR("internal error: unable to find spectator");
952 }
953 return Episode->SerializeActor(CarlaActor);
954 };
955
956 BIND_SYNC(get_all_level_BBs) << [this](uint8 QueriedTag) -> R<std::vector<cg::BoundingBox>>
957 {
959 TArray<FBoundingBox> Result;
961 if (!GameMode)
962 {
963 RESPOND_ERROR("unable to find CARLA game mode");
964 }
965 Result = GameMode->GetAllBBsOfLevel(QueriedTag);
966 ALargeMapManager* LargeMap = GameMode->GetLMManager();
967 if (LargeMap)
968 {
969 for(auto& Box : Result)
970 {
971 Box.Origin = LargeMap->LocalToGlobalLocation(Box.Origin);
972 }
973 }
974 return MakeVectorFromTArray<cg::BoundingBox>(Result);
975 };
976
977 BIND_SYNC(get_environment_objects) << [this](uint8 QueriedTag) -> R<std::vector<cr::EnvironmentObject>>
978 {
981 if (!GameMode)
982 {
983 RESPOND_ERROR("unable to find CARLA game mode");
984 }
985 TArray<FEnvironmentObject> Result = GameMode->GetEnvironmentObjects(QueriedTag);
986 ALargeMapManager* LargeMap = GameMode->GetLMManager();
987 if (LargeMap)
988 {
989 for(auto& Object : Result)
990 {
991 Object.Transform = LargeMap->LocalToGlobalTransform(Object.Transform);
992 }
993 }
994 return MakeVectorFromTArray<cr::EnvironmentObject>(Result);
995 };
996
997 BIND_SYNC(enable_environment_objects) << [this](std::vector<uint64_t> EnvObjectIds, bool Enable) -> R<void>
998 {
1001 ACarlaGameModeBase* GameMode = UCarlaStatics::GetGameMode(Episode->GetWorld());
1002 if (!GameMode)
1003 {
1004 RESPOND_ERROR("unable to find CARLA game mode");
1005 }
1006
1007 TSet<uint64> EnvObjectIdsSet;
1008 for(uint64 Id : EnvObjectIds)
1009 {
1010 EnvObjectIdsSet.Emplace(Id);
1011 }
1012
1013 GameMode->EnableEnvironmentObjects(EnvObjectIdsSet, Enable);
1014 return R<void>::Success();
1015 };
1016
1017 // ~~ Weather ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1018
1019 BIND_SYNC(get_weather_parameters) << [this]() -> R<cr::WeatherParameters>
1020 {
1022 auto *Weather = Episode->GetWeather();
1023 if (Weather == nullptr)
1024 {
1025 UE_LOG(LogCarla, Log, TEXT("internal error: unable to find weather:: weather is disabled"));
1026 return cr::WeatherParameters();
1027 }
1028 return Weather->GetCurrentWeather();
1029 };
1030
1031 BIND_SYNC(set_weather_parameters) << [this](
1032 const cr::WeatherParameters &weather) -> R<void>
1033 {
1036 auto *Weather = Episode->GetWeather();
1037 if (Weather == nullptr)
1038 {
1039 RESPOND_ERROR("set_weather_parameters internal error: unable to find weather:: weather is disabled");
1040 }
1041 Weather->ApplyWeather(weather);
1042 return R<void>::Success();
1043 };
1044
1045 // Environment map for the sky light: an equirectangular linear RGB(A) float
1046 // panorama in the CARLA world frame (see Weather/SkyLightMap.h for the
1047 // column/row convention) becomes a transient HDR cubemap on the rig's sky
1048 // light, replacing the real-time atmosphere capture until cleared.
1049 BIND_SYNC(set_sky_light_map) << [this](
1050 const cr::TextureFloatColor &panorama, float intensity, int32_t face_size) -> R<void>
1051 {
1054 if (panorama.GetWidth() < 2 || panorama.GetHeight() < 2)
1055 {
1056 RESPOND_ERROR("set_sky_light_map: panorama must be at least 2x2");
1057 }
1058 static_assert(sizeof(cr::FloatColor) == 4 * sizeof(float), "FloatColor must be 4 packed floats");
1059 UTextureCube* Cubemap = CarlaSkyLightMap::CreateCubemapFromEquirect(
1060 reinterpret_cast<const float*>(panorama.GetDataPtr()),
1061 int32(panorama.GetWidth()), int32(panorama.GetHeight()),
1062 face_size > 0 ? face_size : 512);
1063 if (Cubemap == nullptr)
1064 {
1065 RESPOND_ERROR("set_sky_light_map: could not build the cubemap");
1066 }
1067 if (!AWeather::SetSkyLightMap(Episode->GetWorld(), Cubemap, intensity))
1068 {
1069 RESPOND_ERROR("set_sky_light_map: no sky rig (ASkyBase) in the level");
1070 }
1071 return R<void>::Success();
1072 };
1073
1074 BIND_SYNC(clear_sky_light_map) << [this]() -> R<void>
1075 {
1079 return R<void>::Success();
1080 };
1081
1082 BIND_SYNC(has_sky_light_map) << [this]() -> R<bool>
1083 {
1085 return AWeather::HasSkyLightMap();
1086 };
1087
1088 // ~~ IMU gravity ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1089
1090 BIND_SYNC(get_imu_gravity) << [this]() -> R<float>
1091 {
1094 return GameMode->IMUSensorGravity;
1095 };
1096
1097 BIND_SYNC(set_imu_gravity) << [this](float new_imu_gravity) -> R<void>
1098 {
1102 GameMode->IMUSensorGravity = new_imu_gravity;
1103 return R<void>::Success();
1104 };
1105
1106 BIND_SYNC(is_weather_enabled) << [this]() -> R<bool>
1107 {
1109 auto *Weather = Episode->GetWeather();
1110 if (Weather == nullptr)
1111 {
1112 return false;
1113 }
1114 return true;
1115 };
1116
1117 // ~~ ROS2 TF ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1118
1119 BIND_SYNC(set_publish_tf) << [this](bool publish_tf) -> R<void>
1120 {
1121 #if defined(WITH_ROS2)
1124 auto ROS2 = carla::ros2::ROS2::GetInstance();
1125 if (ROS2 && ROS2->IsEnabled()) {
1126 ROS2->SetPublishTF(publish_tf);
1127 return R<void>::Success();
1128 }
1129 RESPOND_ERROR("set_publish_tf: ROS2 is not enabled");
1130 #else
1131 RESPOND_ERROR("set_publish_tf: Server was compiled without ROS2 support");
1132 #endif
1133 };
1134
1135 BIND_SYNC(get_publish_tf) << [this]() -> R<bool>
1136 {
1137 #if defined(WITH_ROS2)
1139 auto ROS2 = carla::ros2::ROS2::GetInstance();
1140 if (ROS2 && ROS2->IsEnabled()) {
1141 return ROS2->GetPublishTF();
1142 }
1143 return false;
1144 #else
1145 return false;
1146 #endif
1147 };
1148
1149 BIND_SYNC(get_ego_spawn_points) << [this]() -> R<std::vector<carla::geom::Transform>>
1150 {
1152 const auto &SpawnPoints = Episode->GetRecommendedSpawnPoints();
1153 auto result = MakeVectorFromTArray<cg::Transform>(SpawnPoints);
1154 return result;
1155 };
1156
1157 // ~~ Actor operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1158
1159 BIND_SYNC(get_actors_by_id) << [this](
1160 const std::vector<FCarlaActor::IdType> &ids) -> R<std::vector<cr::Actor>>
1161 {
1163 std::vector<cr::Actor> Result;
1164 Result.reserve(ids.size());
1165 for (auto &&Id : ids)
1166 {
1167 FCarlaActor* View = Episode->FindCarlaActor(Id);
1168 if (View)
1169 {
1170 Result.emplace_back(Episode->SerializeActor(View));
1171 }
1172 }
1173 return Result;
1174 };
1175
1176 BIND_SYNC(spawn_actor) << [this](
1177 cr::ActorDescription Description,
1178 const cr::Transform &Transform) -> R<cr::Actor>
1179 {
1182
1183 auto Result = Episode->SpawnActorWithInfo(Transform, std::move(Description));
1184
1185 if (Result.Key != EActorSpawnResultStatus::Success)
1186 {
1187 UE_LOG(LogCarla, Error, TEXT("Actor not Spawned"));
1189 }
1190
1192 if(LargeMap)
1193 {
1194 LargeMap->OnActorSpawned(*Result.Value);
1195 }
1196
1197 return Episode->SerializeActor(Result.Value);
1198 };
1199
1200 BIND_SYNC(spawn_actor_with_parent) << [this](
1201 cr::ActorDescription Description,
1202 const cr::Transform &Transform,
1203 cr::ActorId ParentId,
1204 cr::AttachmentType InAttachmentType) -> R<cr::Actor>
1205 {
1208
1209 auto Result = Episode->SpawnActorWithInfo(Transform, std::move(Description));
1210 if (Result.Key != EActorSpawnResultStatus::Success)
1211 {
1213 }
1214
1215 FCarlaActor* CarlaActor = Episode->FindCarlaActor(Result.Value->GetActorId());
1216 if (!CarlaActor)
1217 {
1218 RESPOND_ERROR("internal error: actor could not be spawned");
1219 }
1220
1221 FCarlaActor* ParentCarlaActor = Episode->FindCarlaActor(ParentId);
1222
1223 if (!ParentCarlaActor)
1224 {
1225 RESPOND_ERROR("unable to attach actor: parent actor not found");
1226 }
1227
1228 CarlaActor->SetParent(ParentId);
1229 CarlaActor->SetAttachmentType(InAttachmentType);
1230 ParentCarlaActor->AddChildren(CarlaActor->GetActorId());
1231
1232 Episode->AddRosParentNames(*CarlaActor);
1233
1234 // Only is possible to attach if the actor has been really spawned and
1235 // is not in dormant state
1236 if(!ParentCarlaActor->IsDormant())
1237 {
1239 CarlaActor->GetActor(),
1240 ParentCarlaActor->GetActor(),
1241 static_cast<EAttachmentType>(InAttachmentType));
1242 }
1243 else
1244 {
1245 Episode->PutActorToSleep(CarlaActor->GetActorId());
1246 }
1247
1248 return Episode->SerializeActor(CarlaActor);
1249 };
1250
1251 BIND_SYNC(destroy_actor) << [this](cr::ActorId ActorId) -> R<bool>
1252 {
1255 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
1256 if ( !CarlaActor )
1257 {
1258 RESPOND_ERROR("unable to destroy actor: not found");
1259 }
1260 UE_LOG(LogCarla, Log, TEXT("CarlaServer destroy_actor %d"), ActorId);
1261 std::optional<carla::streaming::detail::stream_id_type> SensorStreamId;
1262 const ASensor *Sensor = Cast<ASensor>(CarlaActor->GetActor());
1263 if (Sensor != nullptr && Episode->bIsPrimaryServer)
1264 {
1265 SensorStreamId = carla::streaming::detail::token_type(Sensor->GetToken()).get_stream_id();
1266 }
1267 // We need to force the actor state change, since dormant actors
1268 // will ignore the FCarlaActor destruction
1269 CarlaActor->SetActorState(cr::ActorState::PendingKill);
1270 if (!Episode->DestroyActor(ActorId))
1271 {
1272 RESPOND_ERROR("internal error: unable to destroy actor");
1273 }
1274 if (SensorStreamId && SecondaryServer)
1275 {
1276 SecondaryServer->GetCommander().ForgetSensor(*SensorStreamId);
1277 }
1278 return true;
1279 };
1280
1281 BIND_SYNC(console_command) << [this](std::string cmd) -> R<bool>
1282 {
1285 APlayerController* PController= UGameplayStatics::GetPlayerController(Episode->GetWorld(), 0);
1286 if( PController )
1287 {
1288 auto result = PController->ConsoleCommand(UTF8_TO_TCHAR(cmd.c_str()), true);
1289 return !(
1290 result.Contains(FString(TEXT("Command not recognized"))) ||
1291 result.Contains(FString(TEXT("Error")))
1292 );
1293 }
1294 bool success = false;
1295#if WITH_EDITOR
1296 success = GEngine->Exec(Episode->GetWorld(), UTF8_TO_TCHAR(cmd.c_str()));
1297#endif
1298 return success;
1299 };
1300
1301 BIND_SYNC(get_sensor_token) << [this](carla::streaming::detail::stream_id_type sensor_id) ->
1303 {
1305 bool ForceInPrimary = false;
1306
1307 // check for the world observer (always in primary server)
1308 if (sensor_id == 1)
1309 {
1310 ForceInPrimary = true;
1311 }
1312
1313 // A Multi-GPU secondary serves its own world snapshots, which every client
1314 // of it subscribes to in get_world(); the sensor streams are the primary's
1315 // to route.
1316 const bool bOwnWorldObserver = (sensor_id ==
1318 if (!bOwnWorldObserver)
1319 {
1321 }
1322
1323 // collision sensor always in primary server in multi-gpu
1324 FString Desc = Episode->GetActorDescriptionFromStream(sensor_id);
1325 if (Desc == "" || Desc == "sensor.other.collision")
1326 {
1327 ForceInPrimary = true;
1328 }
1329
1330 // V2X sensors too: they exchange messages between the primary's own
1331 // actors and keep per-process state, so a mirror could never match them.
1332 if (Desc == "sensor.other.v2x" || Desc == "sensor.other.v2x_custom")
1333 {
1334 ForceInPrimary = true;
1335 }
1336
1337 if (SecondaryServer->HasClientsConnected() && !ForceInPrimary)
1338 {
1339 // multi-gpu
1340 UE_LOG(LogCarla, Log, TEXT("Sensor %d '%s' created in secondary server"), sensor_id, *Desc);
1341 const FCarlaActor *SensorActor = Episode->FindCarlaActorFromStream(sensor_id);
1342 if (SensorActor == nullptr)
1343 {
1344 RESPOND_ERROR("sensor stream has no actor");
1345 }
1346 auto Token = SecondaryServer->GetCommander().GetToken(sensor_id, SensorActor->GetActorId());
1347 if (!Token)
1348 {
1349 RESPOND_ERROR("no secondary server could provide a token for this sensor");
1350 }
1351 return *Token;
1352 }
1353 else
1354 {
1355 // single-gpu
1357 {
1358 UE_LOG(LogCarla, Warning,
1359 TEXT("Sensor %d '%s' refused: this server cannot render (-nullrhi) and no secondary server is connected"),
1360 sensor_id, *Desc);
1361 RESPOND_ERROR("this server cannot render (-nullrhi) and no rendering secondary server is connected to own this camera sensor");
1362 }
1363 UE_LOG(LogCarla, Log, TEXT("Sensor %d '%s' created in primary server"), sensor_id, *Desc);
1364 return StreamingServer.GetToken(sensor_id);
1365 }
1366 };
1367
1368 BIND_SYNC(enable_sensor_for_ros) << [this](carla::streaming::detail::stream_id_type sensor_id) ->
1369 R<void>
1370 {
1373 bool ForceInPrimary = false;
1374
1375 // check for the world observer (always in primary server)
1376 if (sensor_id == 1)
1377 {
1378 ForceInPrimary = true;
1379 }
1380
1381 // collision sensor always in primary server in multi-gpu
1382 FString Desc = Episode->GetActorDescriptionFromStream(sensor_id);
1383 if (Desc == "" || Desc == "sensor.other.collision")
1384 {
1385 ForceInPrimary = true;
1386 }
1387
1388 if (SecondaryServer->HasClientsConnected() && !ForceInPrimary)
1389 {
1390 // multi-gpu
1391 const FCarlaActor *SensorActor = Episode->FindCarlaActorFromStream(sensor_id);
1392 if (SensorActor == nullptr)
1393 {
1394 RESPOND_ERROR("sensor stream has no actor");
1395 }
1396 if (!SecondaryServer->GetCommander().EnableForROS(sensor_id, SensorActor->GetActorId()))
1397 {
1398 RESPOND_ERROR("no secondary server could enable ROS for this sensor");
1399 }
1400 }
1401 else
1402 {
1403 // single-gpu
1405 {
1406 UE_LOG(LogCarla, Warning,
1407 TEXT("ROS 2 for sensor %d '%s' refused: this server cannot render (-nullrhi) and no secondary server is connected"),
1408 sensor_id, *Desc);
1409 RESPOND_ERROR("this server cannot render (-nullrhi) and no rendering secondary server is connected to publish this camera sensor");
1410 }
1411 StreamingServer.EnableForROS(sensor_id);
1412 }
1413 return R<void>::Success();
1414 };
1415
1416 BIND_SYNC(disable_sensor_for_ros) << [this](carla::streaming::detail::stream_id_type sensor_id) ->
1417 R<void>
1418 {
1421 bool ForceInPrimary = false;
1422
1423 // check for the world observer (always in primary server)
1424 if (sensor_id == 1)
1425 {
1426 ForceInPrimary = true;
1427 }
1428
1429 // collision sensor always in primary server in multi-gpu
1430 FString Desc = Episode->GetActorDescriptionFromStream(sensor_id);
1431 if (Desc == "" || Desc == "sensor.other.collision")
1432 {
1433 ForceInPrimary = true;
1434 }
1435
1436 if (SecondaryServer->HasClientsConnected() && !ForceInPrimary)
1437 {
1438 // multi-gpu
1439 SecondaryServer->GetCommander().DisableForROS(sensor_id);
1440 }
1441 else
1442 {
1443 // single-gpu
1444 StreamingServer.DisableForROS(sensor_id);
1445 }
1446 return R<void>::Success();
1447 };
1448
1449BIND_SYNC(is_sensor_enabled_for_ros) << [this](carla::streaming::detail::stream_id_type sensor_id) ->
1450 R<bool>
1451 {
1453 bool ForceInPrimary = false;
1454
1455 // check for the world observer (always in primary server)
1456 if (sensor_id == 1)
1457 {
1458 ForceInPrimary = true;
1459 }
1460
1461 // collision sensor always in primary server in multi-gpu
1462 FString Desc = Episode->GetActorDescriptionFromStream(sensor_id);
1463 if (Desc == "" || Desc == "sensor.other.collision")
1464 {
1465 ForceInPrimary = true;
1466 }
1467
1468 if (SecondaryServer->HasClientsConnected() && !ForceInPrimary)
1469 {
1470 // multi-gpu
1471 return SecondaryServer->GetCommander().IsEnabledForROS(sensor_id);
1472 }
1473 else
1474 {
1475 // single-gpu
1476 return StreamingServer.IsEnabledForROS(sensor_id);
1477 }
1478 };
1479
1480 BIND_SYNC(send) << [this](
1481 cr::ActorId ActorId,
1482 cr::CustomV2XBytes Data) -> R<void>
1483 {
1486 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
1487 if (!CarlaActor)
1488 {
1489 return RespondError(
1490 "send",
1492 " Actor Id: " + FString::FromInt(ActorId));
1493 }
1494
1495 if (CarlaActor->IsDormant())
1496 {
1497 return RespondError(
1498 "send",
1500 " Actor Id: " + FString::FromInt(ActorId));
1501 }
1502 ACustomV2XSensor* Sensor = Cast<ACustomV2XSensor>(CarlaActor->GetActor());
1503 if (!Sensor)
1504 {
1505 return RespondError(
1506 "send",
1508 " Actor Id: " + FString::FromInt(ActorId));
1509 }
1510
1511 Sensor->Send(Data);
1512 return R<void>::Success();
1513 };
1514
1515 // ~~ Actor physics ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1516
1517 BIND_SYNC(set_actor_location) << [this](
1518 cr::ActorId ActorId,
1519 cr::Location Location) -> R<void>
1520 {
1523 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
1524 if (!CarlaActor)
1525 {
1526 return RespondError(
1527 "set_actor_location",
1529 " Actor Id: " + FString::FromInt(ActorId));
1530 }
1531
1532 CarlaActor->SetActorGlobalLocation(
1533 Location, ETeleportType::TeleportPhysics);
1534 return R<void>::Success();
1535 };
1536
1537 BIND_SYNC(set_actor_transform) << [this](
1538 cr::ActorId ActorId,
1539 cr::Transform Transform) -> R<void>
1540 {
1543 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
1544 if (!CarlaActor)
1545 {
1546 return RespondError(
1547 "set_actor_transform",
1549 " Actor Id: " + FString::FromInt(ActorId));
1550 }
1551
1552 CarlaActor->SetActorGlobalTransform(
1553 Transform, ETeleportType::TeleportPhysics);
1554 return R<void>::Success();
1555 };
1556
1557 BIND_SYNC(set_walker_state) << [this] (
1558 cr::ActorId ActorId,
1559 cr::Transform Transform,
1560 float Speed) -> R<void>
1561 {
1564 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
1565 if (!CarlaActor)
1566 {
1567 return RespondError(
1568 "set_walker_state",
1570 " Actor Id: " + FString::FromInt(ActorId));
1571 }
1572
1573 // apply walker transform
1574 ECarlaServerResponse Response =
1575 CarlaActor->SetWalkerState(
1576 Transform,
1577 cr::WalkerControl(
1578 Transform.GetForwardVector(), Speed, false));
1579 if (Response != ECarlaServerResponse::Success)
1580 {
1581 return RespondError(
1582 "set_walker_state",
1583 Response,
1584 " Actor Id: " + FString::FromInt(ActorId));
1585 }
1586 return R<void>::Success();
1587 };
1588
1589 BIND_SYNC(set_actor_target_velocity) << [this](
1590 cr::ActorId ActorId,
1591 cr::Vector3D vector) -> R<void>
1592 {
1595 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
1596 if (!CarlaActor)
1597 {
1598 return RespondError(
1599 "set_actor_target_velocity",
1601 " Actor Id: " + FString::FromInt(ActorId));
1602 }
1603 ECarlaServerResponse Response =
1604 CarlaActor->SetActorTargetVelocity(vector.ToCentimeters().ToFVector());
1605 if (Response != ECarlaServerResponse::Success)
1606 {
1607 return RespondError(
1608 "set_actor_target_velocity",
1609 Response,
1610 " Actor Id: " + FString::FromInt(ActorId));
1611 }
1612 return R<void>::Success();
1613 };
1614
1615 BIND_SYNC(set_actor_target_angular_velocity) << [this](
1616 cr::ActorId ActorId,
1617 cr::Vector3D vector) -> R<void>
1618 {
1621 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
1622 if (!CarlaActor)
1623 {
1624 return RespondError(
1625 "set_actor_target_angular_velocity",
1627 " Actor Id: " + FString::FromInt(ActorId));
1628 }
1629 ECarlaServerResponse Response =
1630 CarlaActor->SetActorTargetAngularVelocity(vector.ToFVector());
1631 if (Response != ECarlaServerResponse::Success)
1632 {
1633 return RespondError(
1634 "set_actor_target_angular_velocity",
1635 Response,
1636 " Actor Id: " + FString::FromInt(ActorId));
1637 }
1638 return R<void>::Success();
1639 };
1640
1641 BIND_SYNC(enable_actor_constant_velocity) << [this](
1642 cr::ActorId ActorId,
1643 cr::Vector3D vector) -> R<void>
1644 {
1647 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
1648 if (!CarlaActor)
1649 {
1650 return RespondError(
1651 "enable_actor_constant_velocity",
1653 " Actor Id: " + FString::FromInt(ActorId));
1654 }
1655
1656 ECarlaServerResponse Response =
1657 CarlaActor->EnableActorConstantVelocity(vector.ToCentimeters().ToFVector());
1658 if (Response != ECarlaServerResponse::Success)
1659 {
1660 return RespondError(
1661 "enable_actor_constant_velocity",
1662 Response,
1663 " Actor Id: " + FString::FromInt(ActorId));
1664 }
1665
1666 return R<void>::Success();
1667 };
1668
1669 BIND_SYNC(disable_actor_constant_velocity) << [this](
1670 cr::ActorId ActorId) -> R<void>
1671 {
1674 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
1675 if (!CarlaActor)
1676 {
1677 return RespondError(
1678 "disable_actor_constant_velocity",
1680 " Actor Id: " + FString::FromInt(ActorId));
1681 }
1682
1683 ECarlaServerResponse Response =
1684 CarlaActor->DisableActorConstantVelocity();
1685 if (Response != ECarlaServerResponse::Success)
1686 {
1687 return RespondError(
1688 "disable_actor_constant_velocity",
1689 Response,
1690 " Actor Id: " + FString::FromInt(ActorId));
1691 }
1692
1693 return R<void>::Success();
1694 };
1695
1696 BIND_SYNC(enable_actor_constant_acceleration) << [this](
1697 cr::ActorId ActorId,
1698 cr::Vector3D vector) -> R<void>
1699 {
1702 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
1703 if (!CarlaActor)
1704 {
1705 return RespondError(
1706 "enable_actor_constant_acceleration",
1708 " Actor Id: " + FString::FromInt(ActorId));
1709 }
1710
1711 ECarlaServerResponse Response =
1712 CarlaActor->EnableActorConstantAcceleration(vector.ToCentimeters().ToFVector());
1713 if (Response != ECarlaServerResponse::Success)
1714 {
1715 return RespondError(
1716 "enable_actor_constant_acceleration",
1717 Response,
1718 " Actor Id: " + FString::FromInt(ActorId));
1719 }
1720
1721 return R<void>::Success();
1722 };
1723
1724 BIND_SYNC(disable_actor_constant_acceleration) << [this](
1725 cr::ActorId ActorId) -> R<void>
1726 {
1729 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
1730 if (!CarlaActor)
1731 {
1732 return RespondError(
1733 "disable_actor_constant_acceleration",
1735 " Actor Id: " + FString::FromInt(ActorId));
1736 }
1737
1738 ECarlaServerResponse Response =
1740 if (Response != ECarlaServerResponse::Success)
1741 {
1742 return RespondError(
1743 "disable_actor_constant_acceleration",
1744 Response,
1745 " Actor Id: " + FString::FromInt(ActorId));
1746 }
1747
1748 return R<void>::Success();
1749 };
1750
1751 BIND_SYNC(add_actor_impulse) << [this](
1752 cr::ActorId ActorId,
1753 cr::Vector3D vector) -> R<void>
1754 {
1757 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
1758 if (!CarlaActor)
1759 {
1760 return RespondError(
1761 "add_actor_impulse",
1763 " Actor Id: " + FString::FromInt(ActorId));
1764 }
1765
1766 ECarlaServerResponse Response =
1767 CarlaActor->AddActorImpulse(vector.ToCentimeters().ToFVector());
1768 if (Response != ECarlaServerResponse::Success)
1769 {
1770 return RespondError(
1771 "add_actor_impulse",
1772 Response,
1773 " Actor Id: " + FString::FromInt(ActorId));
1774 }
1775 return R<void>::Success();
1776 };
1777
1778 BIND_SYNC(add_actor_impulse_at_location) << [this](
1779 cr::ActorId ActorId,
1780 cr::Vector3D impulse,
1781 cr::Vector3D location) -> R<void>
1782 {
1785 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
1786 if (!CarlaActor)
1787 {
1788 return RespondError(
1789 "add_actor_impulse_at_location",
1791 " Actor Id: " + FString::FromInt(ActorId));
1792 }
1793 FVector UELocation = location.ToCentimeters().ToFVector();
1794 ACarlaGameModeBase* GameMode = UCarlaStatics::GetGameMode(Episode->GetWorld());
1795 ALargeMapManager* LargeMap = GameMode->GetLMManager();
1796 if (LargeMap)
1797 {
1798 UELocation = LargeMap->GlobalToLocalLocation(UELocation);
1799 }
1800 ECarlaServerResponse Response =
1801 CarlaActor->AddActorImpulseAtLocation(impulse.ToCentimeters().ToFVector(), UELocation);
1802 if (Response != ECarlaServerResponse::Success)
1803 {
1804 return RespondError(
1805 "add_actor_impulse_at_location",
1806 Response,
1807 " Actor Id: " + FString::FromInt(ActorId));
1808 }
1809
1810 return R<void>::Success();
1811 };
1812
1813 BIND_SYNC(add_actor_force) << [this](
1814 cr::ActorId ActorId,
1815 cr::Vector3D vector) -> R<void>
1816 {
1819 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
1820 if (!CarlaActor)
1821 {
1822 return RespondError(
1823 "add_actor_force",
1825 " Actor Id: " + FString::FromInt(ActorId));
1826 }
1827 ECarlaServerResponse Response =
1828 CarlaActor->AddActorForce(vector.ToCentimeters().ToFVector());
1829 if (Response != ECarlaServerResponse::Success)
1830 {
1831 return RespondError(
1832 "add_actor_force",
1833 Response,
1834 " Actor Id: " + FString::FromInt(ActorId));
1835 }
1836 return R<void>::Success();
1837 };
1838
1839 BIND_SYNC(add_actor_force_at_location) << [this](
1840 cr::ActorId ActorId,
1841 cr::Vector3D force,
1842 cr::Vector3D location) -> R<void>
1843 {
1846 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
1847 if (!CarlaActor)
1848 {
1849 return RespondError(
1850 "add_actor_force_at_location",
1852 " Actor Id: " + FString::FromInt(ActorId));
1853 }
1854 FVector UELocation = location.ToCentimeters().ToFVector();
1855 ACarlaGameModeBase* GameMode = UCarlaStatics::GetGameMode(Episode->GetWorld());
1856 ALargeMapManager* LargeMap = GameMode->GetLMManager();
1857 if (LargeMap)
1858 {
1859 UELocation = LargeMap->GlobalToLocalLocation(UELocation);
1860 }
1861 ECarlaServerResponse Response =
1862 CarlaActor->AddActorForceAtLocation(force.ToCentimeters().ToFVector(), UELocation);
1863 if (Response != ECarlaServerResponse::Success)
1864 {
1865 return RespondError(
1866 "add_actor_force_at_location",
1867 Response,
1868 " Actor Id: " + FString::FromInt(ActorId));
1869 }
1870 return R<void>::Success();
1871 };
1872
1873 BIND_SYNC(add_actor_angular_impulse) << [this](
1874 cr::ActorId ActorId,
1875 cr::Vector3D vector) -> R<void>
1876 {
1879 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
1880 if (!CarlaActor)
1881 {
1882 return RespondError(
1883 "add_actor_angular_impulse",
1885 " Actor Id: " + FString::FromInt(ActorId));
1886 }
1887 ECarlaServerResponse Response =
1888 CarlaActor->AddActorAngularImpulse(vector.ToFVector());
1889 if (Response != ECarlaServerResponse::Success)
1890 {
1891 return RespondError(
1892 "add_actor_angular_impulse",
1893 Response,
1894 " Actor Id: " + FString::FromInt(ActorId));
1895 }
1896 return R<void>::Success();
1897 };
1898
1899 BIND_SYNC(add_actor_torque) << [this](
1900 cr::ActorId ActorId,
1901 cr::Vector3D vector) -> R<void>
1902 {
1905 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
1906 if (!CarlaActor)
1907 {
1908 return RespondError(
1909 "add_actor_torque",
1911 " Actor Id: " + FString::FromInt(ActorId));
1912 }
1913 ECarlaServerResponse Response =
1914 CarlaActor->AddActorTorque(vector.ToFVector());
1915 if (Response != ECarlaServerResponse::Success)
1916 {
1917 return RespondError(
1918 "add_actor_torque",
1919 Response,
1920 " Actor Id: " + FString::FromInt(ActorId));
1921 }
1922 return R<void>::Success();
1923 };
1924
1925 BIND_SYNC(get_actor_component_world_transform) << [this](
1926 cr::ActorId ActorId,
1927 const std::string &component_name) -> R<cr::Transform>
1928 {
1930 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
1931 if (!CarlaActor)
1932 {
1933 return RespondError(
1934 "get_actor_component_world_transform",
1936 " Actor Id: " + FString::FromInt(ActorId));
1937 }
1938
1939 const FString TargetName(UTF8_TO_TCHAR(component_name.c_str()));
1940 FTransform Transform;
1941 ECarlaServerResponse Response = CarlaActor->GetActorComponentWorldTransform(TargetName, Transform);
1942 if (Response != ECarlaServerResponse::Success)
1943 {
1944 return RespondError(
1945 "get_actor_component_world_transform",
1946 Response,
1947 " Component Name: " + TargetName);
1948 }
1949 return cr::Transform(Transform);
1950 };
1951
1952 BIND_SYNC(get_actor_component_relative_transform) << [this](
1953 cr::ActorId ActorId,
1954 const std::string &component_name) -> R<cr::Transform>
1955 {
1957 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
1958 if (!CarlaActor)
1959 {
1960 return RespondError(
1961 "get_actor_component_relative_transform",
1963 " Actor Id: " + FString::FromInt(ActorId));
1964 }
1965
1966 const FString TargetName(UTF8_TO_TCHAR(component_name.c_str()));
1967 FTransform Transform;
1968 ECarlaServerResponse Response = CarlaActor->GetActorComponentRelativeTransform(TargetName, Transform);
1969 if (Response != ECarlaServerResponse::Success)
1970 {
1971 return RespondError(
1972 "get_actor_component_relative_transform",
1973 Response,
1974 " Component Name: " + TargetName);
1975 }
1976 return cr::Transform(Transform);
1977 };
1978
1979 BIND_SYNC(get_actor_bone_world_transforms) << [this](
1980 cr::ActorId ActorId) -> R<std::vector<cr::Transform>>
1981 {
1983 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
1984 if (!CarlaActor)
1985 {
1986 return RespondError(
1987 "get_actor_bone_world_transforms",
1989 " Actor Id: " + FString::FromInt(ActorId));
1990 }
1991
1992 TArray<FTransform> Transforms;
1993 ECarlaServerResponse Response = CarlaActor->GetActorBoneWorldTransforms(Transforms);
1994 if (Response != ECarlaServerResponse::Success)
1995 {
1996 return RespondError(
1997 "get_actor_bone_world_transforms",
1998 Response,
1999 " Actor Id: " + FString::FromInt(ActorId));
2000 }
2001 return MakeVectorFromTArray<cr::Transform>(Transforms);
2002 };
2003
2004 BIND_SYNC(get_actor_bone_relative_transforms) << [this](
2005 cr::ActorId ActorId) -> R<std::vector<cr::Transform>>
2006 {
2008 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2009 if (!CarlaActor)
2010 {
2011 return RespondError(
2012 "get_actor_bone_relative_transforms",
2014 " Actor Id: " + FString::FromInt(ActorId));
2015 }
2016
2017 TArray<FTransform> Transforms;
2018 ECarlaServerResponse Response = CarlaActor->GetActorBoneRelativeTransforms(Transforms);
2019 if (Response != ECarlaServerResponse::Success)
2020 {
2021 return RespondError(
2022 "get_actor_bone_relative_transforms",
2023 Response,
2024 " Actor Id: " + FString::FromInt(ActorId));
2025 }
2026 return MakeVectorFromTArray<cr::Transform>(Transforms);
2027 };
2028
2029 BIND_SYNC(get_actor_component_names) << [this](
2030 cr::ActorId ActorId) -> R<std::vector<std::string>>
2031 {
2033 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2034 if (!CarlaActor)
2035 {
2036 return RespondError(
2037 "get_actor_component_names",
2039 " Actor Id: " + FString::FromInt(ActorId));
2040 }
2041
2042 TArray<FString> Names;
2043 ECarlaServerResponse Response = CarlaActor->GetActorComponentNames(Names);
2044 if (Response != ECarlaServerResponse::Success)
2045 {
2046 return RespondError(
2047 "get_actor_component_names",
2048 Response,
2049 " Actor Id: " + FString::FromInt(ActorId));
2050 }
2051 return MakeStringVector(Names);
2052 };
2053
2054 BIND_SYNC(get_actor_bone_names) << [this](
2055 cr::ActorId ActorId) -> R<std::vector<std::string>>
2056 {
2058 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2059 if (!CarlaActor)
2060 {
2061 return RespondError(
2062 "get_actor_bone_names",
2064 " Actor Id: " + FString::FromInt(ActorId));
2065 }
2066
2067 TArray<FString> Names;
2068 ECarlaServerResponse Response = CarlaActor->GetActorBoneNames(Names);
2069 if (Response != ECarlaServerResponse::Success)
2070 {
2071 return RespondError(
2072 "get_actor_bone_names",
2073 Response,
2074 " Actor Id: " + FString::FromInt(ActorId));
2075 }
2076 return MakeStringVector(Names);
2077 };
2078
2079 BIND_SYNC(get_actor_socket_world_transforms) << [this](
2080 cr::ActorId ActorId) -> R<std::vector<cr::Transform>>
2081 {
2083 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2084 if (!CarlaActor)
2085 {
2086 return RespondError(
2087 "get_actor_socket_world_transforms",
2089 " Actor Id: " + FString::FromInt(ActorId));
2090 }
2091
2092 TArray<FTransform> Transforms;
2093 ECarlaServerResponse Response = CarlaActor->GetActorSocketWorldTransforms(Transforms);
2094 if (Response != ECarlaServerResponse::Success)
2095 {
2096 return RespondError(
2097 "get_actor_socket_world_transforms",
2098 Response,
2099 " Actor Id: " + FString::FromInt(ActorId));
2100 }
2101 return MakeVectorFromTArray<cr::Transform>(Transforms);
2102 };
2103
2104 BIND_SYNC(get_actor_socket_relative_transforms) << [this](
2105 cr::ActorId ActorId) -> R<std::vector<cr::Transform>>
2106 {
2108 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2109 if (!CarlaActor)
2110 {
2111 return RespondError(
2112 "get_actor_socket_relative_transforms",
2114 " Actor Id: " + FString::FromInt(ActorId));
2115 }
2116
2117 TArray<FTransform> Transforms;
2118 ECarlaServerResponse Response = CarlaActor->GetActorSocketRelativeTransforms(Transforms);
2119 if (Response != ECarlaServerResponse::Success)
2120 {
2121 return RespondError(
2122 "get_actor_socket_relative_transforms",
2123 Response,
2124 " Actor Id: " + FString::FromInt(ActorId));
2125 }
2126 return MakeVectorFromTArray<cr::Transform>(Transforms);
2127 };
2128
2129 BIND_SYNC(get_actor_socket_names) << [this](
2130 cr::ActorId ActorId) -> R<std::vector<std::string>>
2131 {
2133 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2134 if (!CarlaActor)
2135 {
2136 return RespondError(
2137 "get_actor_socket_names",
2139 " Actor Id: " + FString::FromInt(ActorId));
2140 }
2141
2142 TArray<FString> Names;
2143 ECarlaServerResponse Response = CarlaActor->GetActorSocketNames(Names);
2144 if (Response != ECarlaServerResponse::Success)
2145 {
2146 return RespondError(
2147 "get_actor_socket_names",
2148 Response,
2149 " Actor Id: " + FString::FromInt(ActorId));
2150 }
2151 return MakeStringVector(Names);
2152 };
2153
2154 BIND_SYNC(get_physics_control) << [this](
2155 cr::ActorId ActorId) -> R<cr::VehiclePhysicsControl>
2156 {
2158 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2159 if (!CarlaActor)
2160 {
2161 return RespondError(
2162 "get_physics_control",
2164 " Actor Id: " + FString::FromInt(ActorId));
2165 }
2167 ECarlaServerResponse Response =
2168 CarlaActor->GetPhysicsControl(PhysicsControl);
2169 if (Response != ECarlaServerResponse::Success)
2170 {
2171 return RespondError(
2172 "get_physics_control",
2173 Response,
2174 " Actor Id: " + FString::FromInt(ActorId));
2175 }
2176 return cr::VehiclePhysicsControl::FromFVehiclePhysicsControl(PhysicsControl);
2177 };
2178
2179 BIND_SYNC(get_telemetry_data) << [this](
2180 cr::ActorId ActorId) -> R<cr::VehicleTelemetryData>
2181 {
2184 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2185 if (!CarlaActor)
2186 {
2187 return RespondError(
2188 "get_telemetry_data",
2190 " Actor Id: " + FString::FromInt(ActorId));
2191 }
2192 FVehicleTelemetryData TelemetryData;
2193 ECarlaServerResponse Response =
2194 CarlaActor->GetVehicleTelemetryData(TelemetryData);
2195 if (Response != ECarlaServerResponse::Success)
2196 {
2197 return RespondError(
2198 "get_telemetry_data",
2199 Response,
2200 " Actor Id: " + FString::FromInt(ActorId));
2201 }
2202 return cr::VehicleTelemetryData(TelemetryData);
2203 };
2204
2205 BIND_SYNC(get_vehicle_light_state) << [this](
2206 cr::ActorId ActorId) -> R<cr::VehicleLightState>
2207 {
2209 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2210 if (!CarlaActor)
2211 {
2212 return RespondError(
2213 "get_vehicle_light_state",
2215 " Actor Id: " + FString::FromInt(ActorId));
2216 }
2217 FVehicleLightState LightState;
2218 ECarlaServerResponse Response =
2219 CarlaActor->GetVehicleLightState(LightState);
2220 if (Response != ECarlaServerResponse::Success)
2221 {
2222 return RespondError(
2223 "get_vehicle_light_state",
2224 Response,
2225 " Actor Id: " + FString::FromInt(ActorId));
2226 }
2227 return cr::VehicleLightState(LightState);
2228 };
2229
2230 BIND_SYNC(apply_physics_control) << [this](
2231 cr::ActorId ActorId,
2232 cr::VehiclePhysicsControl PhysicsControl) -> R<void>
2233 {
2236 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2237 if (!CarlaActor)
2238 {
2239 return RespondError(
2240 "apply_physics_control",
2242 " Actor Id: " + FString::FromInt(ActorId));
2243 }
2244 ECarlaServerResponse Response =
2246 if (Response != ECarlaServerResponse::Success)
2247 {
2248 return RespondError(
2249 "apply_physics_control",
2250 Response,
2251 " Actor Id: " + FString::FromInt(ActorId));
2252 }
2253 return R<void>::Success();
2254 };
2255
2256 BIND_SYNC(set_vehicle_light_state) << [this](
2257 cr::ActorId ActorId,
2258 cr::VehicleLightState LightState) -> R<void>
2259 {
2262 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2263 if (!CarlaActor)
2264 {
2265 return RespondError(
2266 "set_vehicle_light_state",
2268 " Actor Id: " + FString::FromInt(ActorId));
2269 }
2270 ECarlaServerResponse Response =
2271 CarlaActor->SetVehicleLightState(FVehicleLightState(LightState));
2272 if (Response != ECarlaServerResponse::Success)
2273 {
2274 return RespondError(
2275 "set_vehicle_light_state",
2276 Response,
2277 " Actor Id: " + FString::FromInt(ActorId));
2278 }
2279 return R<void>::Success();
2280 };
2281
2282
2283 BIND_SYNC(open_vehicle_door) << [this](
2284 cr::ActorId ActorId,
2285 cr::VehicleDoor DoorIdx) -> R<void>
2286 {
2289 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2290 if (!CarlaActor)
2291 {
2292 return RespondError(
2293 "open_vehicle_door",
2295 " Actor Id: " + FString::FromInt(ActorId));
2296 }
2297 ECarlaServerResponse Response =
2298 CarlaActor->OpenVehicleDoor(static_cast<EVehicleDoor>(DoorIdx));
2299 if (Response != ECarlaServerResponse::Success)
2300 {
2301 return RespondError(
2302 "open_vehicle_door",
2303 Response,
2304 " Actor Id: " + FString::FromInt(ActorId));
2305 }
2306 return R<void>::Success();
2307 };
2308
2309 BIND_SYNC(close_vehicle_door) << [this](
2310 cr::ActorId ActorId,
2311 cr::VehicleDoor DoorIdx) -> R<void>
2312 {
2315 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2316 if (!CarlaActor)
2317 {
2318 return RespondError(
2319 "close_vehicle_door",
2321 " Actor Id: " + FString::FromInt(ActorId));
2322 }
2323 ECarlaServerResponse Response =
2324 CarlaActor->CloseVehicleDoor(static_cast<EVehicleDoor>(DoorIdx));
2325 if (Response != ECarlaServerResponse::Success)
2326 {
2327 return RespondError(
2328 "close_vehicle_door",
2329 Response,
2330 " Actor Id: " + FString::FromInt(ActorId));
2331 }
2332 return R<void>::Success();
2333 };
2334
2335 BIND_SYNC(set_wheel_steer_direction) << [this](
2336 cr::ActorId ActorId,
2337 cr::VehicleWheelLocation WheelLocation,
2338 float AngleInDeg) -> R<void>
2339 {
2342 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2343 if(!CarlaActor){
2344 return RespondError(
2345 "set_wheel_steer_direction",
2347 " Actor Id: " + FString::FromInt(ActorId));
2348 }
2349 ECarlaServerResponse Response =
2350 CarlaActor->SetWheelSteerDirection(
2351 static_cast<EVehicleWheelLocation>(WheelLocation), AngleInDeg);
2352 if (Response != ECarlaServerResponse::Success)
2353 {
2354 return RespondError(
2355 "set_wheel_steer_direction",
2356 Response,
2357 " Actor Id: " + FString::FromInt(ActorId));
2358 }
2359 return R<void>::Success();
2360 };
2361
2362 BIND_SYNC(get_wheel_steer_angle) << [this](
2363 const cr::ActorId ActorId,
2364 cr::VehicleWheelLocation WheelLocation) -> R<float>
2365 {
2367 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2368 if(!CarlaActor){
2369 return RespondError(
2370 "get_wheel_steer_angle",
2372 " Actor Id: " + FString::FromInt(ActorId));
2373 }
2374 float Angle;
2375 ECarlaServerResponse Response =
2376 CarlaActor->GetWheelSteerAngle(
2377 static_cast<EVehicleWheelLocation>(WheelLocation), Angle);
2378 if (Response != ECarlaServerResponse::Success)
2379 {
2380 return RespondError(
2381 "get_wheel_steer_angle",
2382 Response,
2383 " Actor Id: " + FString::FromInt(ActorId));
2384 }
2385 return Angle;
2386 };
2387
2388 BIND_SYNC(set_wheel_pitch_angle) << [this](
2389 cr::ActorId ActorId,
2390 cr::VehicleWheelLocation WheelLocation,
2391 float AngleInDeg) -> R<void>
2392 {
2395 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2396 if(!CarlaActor){
2397 return RespondError(
2398 "set_wheel_pitch_angle",
2400 " Actor Id: " + FString::FromInt(ActorId));
2401 }
2402 ECarlaServerResponse Response =
2403 CarlaActor->SetWheelPitchAngle(
2404 static_cast<EVehicleWheelLocation>(WheelLocation), AngleInDeg);
2405 if (Response != ECarlaServerResponse::Success)
2406 {
2407 return RespondError(
2408 "set_wheel_pitch_angle",
2409 Response,
2410 " Actor Id: " + FString::FromInt(ActorId));
2411 }
2412 return R<void>::Success();
2413 };
2414
2415 BIND_SYNC(get_wheel_pitch_angle) << [this](
2416 const cr::ActorId ActorId,
2417 cr::VehicleWheelLocation WheelLocation) -> R<float>
2418 {
2420 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2421 if(!CarlaActor){
2422 return RespondError(
2423 "get_wheel_pitch_angle",
2425 " Actor Id: " + FString::FromInt(ActorId));
2426 }
2427 float Value;
2428 ECarlaServerResponse Response =
2429 CarlaActor->GetWheelPitchAngle(
2430 static_cast<EVehicleWheelLocation>(WheelLocation), Value);
2431 if (Response != ECarlaServerResponse::Success)
2432 {
2433 return RespondError(
2434 "get_wheel_pitch_angle",
2435 Response,
2436 " Actor Id: " + FString::FromInt(ActorId));
2437 }
2438 return Value;
2439 };
2440
2441 BIND_SYNC(set_wheel_suspension_offset) << [this](
2442 cr::ActorId ActorId,
2443 cr::VehicleWheelLocation WheelLocation,
2444 float Offset) -> R<void>
2445 {
2448 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2449 if(!CarlaActor){
2450 return RespondError(
2451 "set_wheel_suspension_offset",
2453 " Actor Id: " + FString::FromInt(ActorId));
2454 }
2455 ECarlaServerResponse Response =
2456 CarlaActor->SetWheelSuspensionOffset(
2457 static_cast<EVehicleWheelLocation>(WheelLocation), Offset);
2458 if (Response != ECarlaServerResponse::Success)
2459 {
2460 return RespondError(
2461 "set_wheel_suspension_offset",
2462 Response,
2463 " Actor Id: " + FString::FromInt(ActorId));
2464 }
2465 return R<void>::Success();
2466 };
2467
2468 BIND_SYNC(get_wheel_suspension_offset) << [this](
2469 const cr::ActorId ActorId,
2470 cr::VehicleWheelLocation WheelLocation) -> R<float>
2471 {
2473 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2474 if(!CarlaActor){
2475 return RespondError(
2476 "get_wheel_suspension_offset",
2478 " Actor Id: " + FString::FromInt(ActorId));
2479 }
2480 float Value;
2481 ECarlaServerResponse Response =
2482 CarlaActor->GetWheelSuspensionOffset(
2483 static_cast<EVehicleWheelLocation>(WheelLocation), Value);
2484 if (Response != ECarlaServerResponse::Success)
2485 {
2486 return RespondError(
2487 "get_wheel_suspension_offset",
2488 Response,
2489 " Actor Id: " + FString::FromInt(ActorId));
2490 }
2491 return Value;
2492 };
2493
2494 BIND_SYNC(set_wheel_animation_override) << [this](
2495 cr::ActorId ActorId,
2496 bool bEnabled) -> R<void>
2497 {
2500 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2501 if(!CarlaActor){
2502 return RespondError(
2503 "set_wheel_animation_override",
2505 " Actor Id: " + FString::FromInt(ActorId));
2506 }
2507 ECarlaServerResponse Response = CarlaActor->SetWheelAnimationOverride(bEnabled);
2508 if (Response != ECarlaServerResponse::Success)
2509 {
2510 return RespondError(
2511 "set_wheel_animation_override",
2512 Response,
2513 " Actor Id: " + FString::FromInt(ActorId));
2514 }
2515 return R<void>::Success();
2516 };
2517
2518 BIND_SYNC(set_actor_simulate_physics) << [this](
2519 cr::ActorId ActorId,
2520 bool bEnabled) -> R<void>
2521 {
2524 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2525 if (!CarlaActor)
2526 {
2527 return RespondError(
2528 "set_actor_simulate_physics",
2530 " Actor Id: " + FString::FromInt(ActorId));
2531 }
2532 ECarlaServerResponse Response =
2533 CarlaActor->SetActorSimulatePhysics(bEnabled);
2534 if (Response != ECarlaServerResponse::Success)
2535 {
2536 return RespondError(
2537 "set_actor_simulate_physics",
2538 Response,
2539 " Actor Id: " + FString::FromInt(ActorId));
2540 }
2541 return R<void>::Success();
2542 };
2543
2544 BIND_SYNC(set_actor_collisions) << [this](
2545 cr::ActorId ActorId,
2546 bool bEnabled) -> R<void>
2547 {
2550 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2551 if (!CarlaActor)
2552 {
2553 return RespondError(
2554 "set_actor_collisions",
2556 " Actor Id: " + FString::FromInt(ActorId));
2557 }
2558 ECarlaServerResponse Response =
2559 CarlaActor->SetActorCollisions(bEnabled);
2560 if (Response != ECarlaServerResponse::Success)
2561 {
2562 return RespondError(
2563 "set_actor_collisions",
2564 Response,
2565 " Actor Id: " + FString::FromInt(ActorId));
2566 }
2567 return R<void>::Success();
2568 };
2569
2570 BIND_SYNC(set_actor_dead) << [this](
2571 cr::ActorId ActorId) -> R<void>
2572 {
2575 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2576 if (!CarlaActor)
2577 {
2578 return RespondError(
2579 "set_actor_dead",
2581 " Actor Id: " + FString::FromInt(ActorId));
2582 }
2583 ECarlaServerResponse Response =
2584 CarlaActor->SetActorDead();
2585 if (Response != ECarlaServerResponse::Success)
2586 {
2587 return RespondError(
2588 "set_actor_dead",
2589 Response,
2590 " Actor Id: " + FString::FromInt(ActorId));
2591 }
2592 return R<void>::Success();
2593 };
2594
2595 BIND_SYNC(set_actor_enable_gravity) << [this](
2596 cr::ActorId ActorId,
2597 bool bEnabled) -> R<void>
2598 {
2601 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2602 if (!CarlaActor)
2603 {
2604 return RespondError(
2605 "set_actor_enable_gravity",
2607 " Actor Id: " + FString::FromInt(ActorId));
2608 }
2609 ECarlaServerResponse Response =
2610 CarlaActor->SetActorEnableGravity(bEnabled);
2611 if (Response != ECarlaServerResponse::Success)
2612 {
2613 return RespondError(
2614 "set_actor_enable_gravity",
2615 Response,
2616 " Actor Id: " + FString::FromInt(ActorId));
2617 }
2618 return R<void>::Success();
2619 };
2620
2621 BIND_SYNC(get_vehicle_bone_world_transforms) << [this](
2622 cr::ActorId ActorId) -> R<std::vector<cr::Transform>>
2623 {
2625 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2626 if (!CarlaActor)
2627 {
2628 return RespondError(
2629 "get_vehicle_bone_world_transforms",
2631 " Actor Id: " + FString::FromInt(ActorId));
2632 }
2633 TArray<FTransform> Transforms;
2634 ECarlaServerResponse Response = CarlaActor->GetActorBoneWorldTransforms(Transforms);
2635 if (Response != ECarlaServerResponse::Success)
2636 {
2637 return RespondError(
2638 "get_vehicle_bone_world_transforms",
2639 Response,
2640 " Actor Id: " + FString::FromInt(ActorId));
2641 }
2642 return MakeVectorFromTArray<cr::Transform>(Transforms);
2643 };
2644
2645 // ~~ Apply control ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2646
2647 BIND_SYNC(apply_control_to_vehicle) << [this](
2648 cr::ActorId ActorId,
2649 cr::VehicleControl Control) -> R<void>
2650 {
2653 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2654 if (!CarlaActor)
2655 {
2656 return RespondError(
2657 "apply_control_to_vehicle",
2659 " Actor Id: " + FString::FromInt(ActorId));
2660 }
2661 ECarlaServerResponse Response =
2662 CarlaActor->ApplyControlToVehicle(Control, EVehicleInputPriority::Client);
2663 if (Response != ECarlaServerResponse::Success)
2664 {
2665 return RespondError(
2666 "apply_control_to_vehicle",
2667 Response,
2668 " Actor Id: " + FString::FromInt(ActorId));
2669 }
2670 return R<void>::Success();
2671 };
2672
2673 BIND_SYNC(apply_ackermann_control_to_vehicle) << [this](
2674 cr::ActorId ActorId,
2675 cr::VehicleAckermannControl Control) -> R<void>
2676 {
2679 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2680 if (!CarlaActor)
2681 {
2682 return RespondError(
2683 "apply_ackermann_control_to_vehicle",
2685 " Actor Id: " + FString::FromInt(ActorId));
2686 }
2687 ECarlaServerResponse Response =
2688 CarlaActor->ApplyAckermannControlToVehicle(Control, EVehicleInputPriority::Client);
2689 if (Response != ECarlaServerResponse::Success)
2690 {
2691 return RespondError(
2692 "apply_ackermann_control_to_vehicle",
2693 Response,
2694 " Actor Id: " + FString::FromInt(ActorId));
2695 }
2696 return R<void>::Success();
2697 };
2698
2699 BIND_SYNC(get_ackermann_controller_settings) << [this](
2700 cr::ActorId ActorId) -> R<cr::AckermannControllerSettings>
2701 {
2703 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2704 if (!CarlaActor)
2705 {
2706 return RespondError(
2707 "get_ackermann_controller_settings",
2709 " Actor Id: " + FString::FromInt(ActorId));
2710 }
2712 ECarlaServerResponse Response =
2713 CarlaActor->GetAckermannControllerSettings(Settings);
2714 if (Response != ECarlaServerResponse::Success)
2715 {
2716 return RespondError(
2717 "get_ackermann_controller_settings",
2718 Response,
2719 " Actor Id: " + FString::FromInt(ActorId));
2720 }
2721 return cr::AckermannControllerSettings(Settings);
2722 };
2723
2724 BIND_SYNC(apply_ackermann_controller_settings) << [this](
2725 cr::ActorId ActorId,
2726 cr::AckermannControllerSettings AckermannSettings) -> R<void>
2727 {
2730 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2731 if (!CarlaActor)
2732 {
2733 return RespondError(
2734 "apply_ackermann_controller_settings",
2736 " Actor Id: " + FString::FromInt(ActorId));
2737 }
2738 ECarlaServerResponse Response =
2739 CarlaActor->ApplyAckermannControllerSettings(FAckermannControllerSettings(AckermannSettings));
2740 if (Response != ECarlaServerResponse::Success)
2741 {
2742 return RespondError(
2743 "apply_ackermann_controller_settings",
2744 Response,
2745 " Actor Id: " + FString::FromInt(ActorId));
2746 }
2747 return R<void>::Success();
2748 };
2749
2750 BIND_SYNC(apply_control_to_walker) << [this](
2751 cr::ActorId ActorId,
2752 cr::WalkerControl Control) -> R<void>
2753 {
2756 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2757 if (!CarlaActor)
2758 {
2759 return RespondError(
2760 "apply_control_to_walker",
2762 " Actor Id: " + FString::FromInt(ActorId));
2763 }
2764 ECarlaServerResponse Response =
2765 CarlaActor->ApplyControlToWalker(Control);
2766 if (Response != ECarlaServerResponse::Success)
2767 {
2768 return RespondError(
2769 "apply_control_to_walker",
2770 Response,
2771 " Actor Id: " + FString::FromInt(ActorId));
2772 }
2773 return R<void>::Success();
2774 };
2775
2776 BIND_SYNC(get_bones_transform) << [this](
2777 cr::ActorId ActorId) -> R<cr::WalkerBoneControlOut>
2778 {
2780 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2781 if (!CarlaActor)
2782 {
2783 return RespondError(
2784 "get_bones_transform",
2786 " Actor Id: " + FString::FromInt(ActorId));
2787 }
2789 ECarlaServerResponse Response =
2790 CarlaActor->GetBonesTransform(Bones);
2791 if (Response != ECarlaServerResponse::Success)
2792 {
2793 return RespondError(
2794 "get_bones_transform",
2795 Response,
2796 " Actor Id: " + FString::FromInt(ActorId));
2797 }
2798
2799 std::vector<carla::rpc::BoneTransformDataOut> BoneData;
2800 for (auto Bone : Bones.BoneTransforms)
2801 {
2803 Data.bone_name = std::string(TCHAR_TO_UTF8(*Bone.Get<0>()));
2804 FWalkerBoneControlOutData Transforms = Bone.Get<1>();
2805 Data.world = Transforms.World;
2806 Data.component = Transforms.Component;
2807 Data.relative = Transforms.Relative;
2808 BoneData.push_back(Data);
2809 }
2810 return carla::rpc::WalkerBoneControlOut(BoneData);
2811 };
2812
2813 BIND_SYNC(set_bones_transform) << [this](
2814 cr::ActorId ActorId,
2816 {
2819 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2820 if (!CarlaActor)
2821 {
2822 return RespondError(
2823 "set_bones_transform",
2825 " Actor Id: " + FString::FromInt(ActorId));
2826 }
2827
2829 ECarlaServerResponse Response = CarlaActor->SetBonesTransform(Bones2);
2830 if (Response != ECarlaServerResponse::Success)
2831 {
2832 return RespondError(
2833 "set_bones_transform",
2834 Response,
2835 " Actor Id: " + FString::FromInt(ActorId));
2836 }
2837
2838 return R<void>::Success();
2839 };
2840
2841 // ~~ Walker navigation (server-side, engine navmesh) ~~~~~~~~~~~~~~~~~~~~
2842
2843 BIND_SYNC(is_navigation_server_side) << [this]() -> R<bool>
2844 {
2846 auto *NavSubsystem = UCarlaNavigationSubsystem::Get(Episode->GetWorld());
2847 return (NavSubsystem != nullptr) && NavSubsystem->HasServerSideNavigation();
2848 };
2849
2850 BIND_SYNC(get_random_location_from_navigation) << [this]() -> R<cr::Location>
2851 {
2853 // Failure sentinel per the phase-1 contract: the client retries or falls
2854 // back to the legacy client-side navigation.
2855 const cr::Location Sentinel{0.0f, 0.0f, -1e6f};
2856 auto *NavSubsystem = UCarlaNavigationSubsystem::Get(Episode->GetWorld());
2857 if (NavSubsystem == nullptr)
2858 {
2859 return Sentinel;
2860 }
2861 FVector Location;
2862 if (!NavSubsystem->GetRandomNavLocation(Location))
2863 {
2864 return Sentinel;
2865 }
2866 ACarlaGameModeBase *GameMode = UCarlaStatics::GetGameMode(Episode->GetWorld());
2867 ALargeMapManager *LargeMap = GameMode ? GameMode->GetLMManager() : nullptr;
2868 if (LargeMap)
2869 {
2870 Location = LargeMap->LocalToGlobalLocation(Location);
2871 }
2872 return cr::Location(Location);
2873 };
2874
2875 // Starts navigation, drawing the walker's crosser flag from the episode
2876 // RNG exactly once (repeated starts keep the first draw, preserving the
2877 // set_pedestrians_seed determinism guarantee).
2878 const auto EnsureWalkerNavigationStarted =
2879 [](UCarlaEpisode *Episode, AWalkerController *Controller) -> bool
2880 {
2881 if (Controller == nullptr)
2882 {
2883 return false;
2884 }
2885 if (Controller->IsNavigationActive())
2886 {
2887 return Controller->StartNavigation();
2888 }
2889 return Controller->StartNavigation(Episode->DrawWalkerIsCrosser());
2890 };
2891
2892 BIND_SYNC(walker_start_navigation) << [this, EnsureWalkerNavigationStarted](
2893 cr::ActorId ActorId) -> R<bool>
2894 {
2897 auto *Controller = ResolveWalkerNavController(Episode->FindCarlaActor(ActorId));
2898 return EnsureWalkerNavigationStarted(Episode, Controller);
2899 };
2900
2901 BIND_SYNC(walker_go_to_location) << [this, EnsureWalkerNavigationStarted](
2902 cr::ActorId ActorId,
2903 cr::Location Location) -> R<bool>
2904 {
2907 auto *Controller = ResolveWalkerNavController(Episode->FindCarlaActor(ActorId));
2908 if (!EnsureWalkerNavigationStarted(Episode, Controller))
2909 {
2910 return false;
2911 }
2912 FVector UELocation = Location;
2913 ACarlaGameModeBase *GameMode = UCarlaStatics::GetGameMode(Episode->GetWorld());
2914 ALargeMapManager *LargeMap = GameMode ? GameMode->GetLMManager() : nullptr;
2915 if (LargeMap)
2916 {
2917 UELocation = LargeMap->GlobalToLocalLocation(UELocation);
2918 }
2919 return Controller->GoToNavLocation(UELocation);
2920 };
2921
2922 BIND_SYNC(walker_set_max_speed) << [this](
2923 cr::ActorId ActorId,
2924 float SpeedMPerSec) -> R<bool>
2925 {
2928 auto *Controller = ResolveWalkerNavController(Episode->FindCarlaActor(ActorId));
2929 constexpr float MeterToCentimeter = 100.0f;
2930 return (Controller != nullptr) &&
2931 Controller->SetNavMaxSpeed(MeterToCentimeter * SpeedMPerSec);
2932 };
2933
2934 BIND_SYNC(walker_stop_navigation) << [this](cr::ActorId ActorId) -> R<bool>
2935 {
2938 auto *Controller = ResolveWalkerNavController(Episode->FindCarlaActor(ActorId));
2939 return (Controller != nullptr) && Controller->StopNavigation();
2940 };
2941
2942 BIND_SYNC(set_pedestrians_cross_factor) << [this](float CrossFactor) -> R<bool>
2943 {
2946 // Applies to walkers whose navigation starts after this call (legacy
2947 // semantics); a no-op success when no navmesh exists.
2948 Episode->SetPedestriansCrossFactor(CrossFactor);
2949 return true;
2950 };
2951
2952 BIND_SYNC(set_pedestrians_seed) << [this](uint32_t Seed) -> R<bool>
2953 {
2957 return true;
2958 };
2959
2960 BIND_SYNC(blend_pose) << [this](
2961 cr::ActorId ActorId,
2962 float Blend) -> R<void>
2963 {
2966 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2967 if (!CarlaActor)
2968 {
2969 return RespondError(
2970 "blend_pose",
2972 " Actor Id: " + FString::FromInt(ActorId));
2973 }
2974
2975 ECarlaServerResponse Response = CarlaActor->BlendPose(Blend);
2976 if (Response != ECarlaServerResponse::Success)
2977 {
2978 return RespondError(
2979 "blend_pose",
2980 Response,
2981 " Actor Id: " + FString::FromInt(ActorId));
2982 }
2983
2984 return R<void>::Success();
2985 };
2986
2987 BIND_SYNC(get_pose_from_animation) << [this](
2988 cr::ActorId ActorId) -> R<void>
2989 {
2992 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
2993 if (!CarlaActor)
2994 {
2995 return RespondError(
2996 "get_pose_from_animation",
2998 " Actor Id: " + FString::FromInt(ActorId));
2999 }
3000
3001 ECarlaServerResponse Response = CarlaActor->GetPoseFromAnimation();
3002 if (Response != ECarlaServerResponse::Success)
3003 {
3004 return RespondError(
3005 "get_pose_from_animation",
3006 Response,
3007 " Actor Id: " + FString::FromInt(ActorId));
3008 }
3009
3010 return R<void>::Success();
3011 };
3012
3013 BIND_SYNC(set_actor_autopilot) << [this](
3014 cr::ActorId ActorId,
3015 bool bEnabled) -> R<void>
3016 {
3019 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
3020 if (!CarlaActor)
3021 {
3022 return RespondError(
3023 "set_actor_autopilot",
3025 " Actor Id: " + FString::FromInt(ActorId));
3026 }
3027 ECarlaServerResponse Response =
3028 CarlaActor->SetActorAutopilot(bEnabled);
3029 if (Response != ECarlaServerResponse::Success)
3030 {
3031 return RespondError(
3032 "set_actor_autopilot",
3033 Response,
3034 " Actor Id: " + FString::FromInt(ActorId));
3035 }
3036 return R<void>::Success();
3037 };
3038
3039 BIND_SYNC(show_vehicle_debug_telemetry) << [this](
3040 cr::ActorId ActorId,
3041 bool bEnabled) -> R<void>
3042 {
3045 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
3046 if (!CarlaActor)
3047 {
3048 return RespondError(
3049 "show_vehicle_debug_telemetry",
3051 " Actor Id: " + FString::FromInt(ActorId));
3052 }
3053 ECarlaServerResponse Response =
3054 CarlaActor->ShowVehicleDebugTelemetry(bEnabled);
3055 if (Response != ECarlaServerResponse::Success)
3056 {
3057 return RespondError(
3058 "show_vehicle_debug_telemetry",
3059 Response,
3060 " Actor Id: " + FString::FromInt(ActorId));
3061 }
3062 return R<void>::Success();
3063 };
3064
3065 BIND_SYNC(enable_carsim) << [this](
3066 cr::ActorId ActorId,
3067 std::string SimfilePath) -> R<void>
3068 {
3071 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
3072 if (!CarlaActor)
3073 {
3074 return RespondError(
3075 "enable_carsim",
3077 " Actor Id: " + FString::FromInt(ActorId));
3078 }
3079 ECarlaServerResponse Response =
3080 CarlaActor->EnableCarSim(carla::rpc::ToFString(SimfilePath));
3081 if (Response != ECarlaServerResponse::Success)
3082 {
3083 return RespondError(
3084 "enable_carsim",
3085 Response,
3086 " Actor Id: " + FString::FromInt(ActorId));
3087 }
3088 return R<void>::Success();
3089 };
3090
3091 BIND_SYNC(use_carsim_road) << [this](
3092 cr::ActorId ActorId,
3093 bool bEnabled) -> R<void>
3094 {
3097 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
3098 if (!CarlaActor)
3099 {
3100 return RespondError(
3101 "use_carsim_road",
3103 " Actor Id: " + FString::FromInt(ActorId));
3104 }
3105 ECarlaServerResponse Response =
3106 CarlaActor->UseCarSimRoad(bEnabled);
3107 if (Response != ECarlaServerResponse::Success)
3108 {
3109 return RespondError(
3110 "use_carsim_road",
3111 Response,
3112 " Actor Id: " + FString::FromInt(ActorId));
3113 }
3114 return R<void>::Success();
3115 };
3116
3117 BIND_SYNC(enable_chrono_physics) << [this](
3118 cr::ActorId ActorId,
3119 uint64_t MaxSubsteps,
3120 float MaxSubstepDeltaTime,
3121 std::string VehicleJSON,
3122 std::string PowertrainJSON,
3123 std::string TireJSON,
3124 std::string BaseJSONPath) -> R<void>
3125 {
3128 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
3129 if (!CarlaActor)
3130 {
3131 return RespondError(
3132 "enable_chrono_physics",
3134 " Actor Id: " + FString::FromInt(ActorId));
3135 }
3136 ECarlaServerResponse Response =
3137 CarlaActor->EnableChronoPhysics(
3138 MaxSubsteps, MaxSubstepDeltaTime,
3139 cr::ToFString(VehicleJSON),
3140 cr::ToFString(PowertrainJSON),
3141 cr::ToFString(TireJSON),
3142 cr::ToFString(BaseJSONPath));
3143 if (Response != ECarlaServerResponse::Success)
3144 {
3145 return RespondError(
3146 "enable_chrono_physics",
3147 Response,
3148 " Actor Id: " + FString::FromInt(ActorId));
3149 }
3150 return R<void>::Success();
3151 };
3152
3153 // ~~ Traffic lights ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3154
3155 BIND_SYNC(set_traffic_light_state) << [this](
3156 cr::ActorId ActorId,
3157 cr::TrafficLightState trafficLightState) -> R<void>
3158 {
3161 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
3162 if (!CarlaActor)
3163 {
3164 return RespondError(
3165 "set_traffic_light_state",
3167 " Actor Id: " + FString::FromInt(ActorId));
3168 }
3169 ECarlaServerResponse Response =
3170 CarlaActor->SetTrafficLightState(
3171 static_cast<ETrafficLightState>(trafficLightState));
3172 if (Response != ECarlaServerResponse::Success)
3173 {
3174 return RespondError(
3175 "set_traffic_light_state",
3176 Response,
3177 " Actor Id: " + FString::FromInt(ActorId));
3178 }
3179 return R<void>::Success();
3180 };
3181
3182 BIND_SYNC(set_traffic_light_green_time) << [this](
3183 cr::ActorId ActorId,
3184 float GreenTime) -> R<void>
3185 {
3188 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
3189 if (!CarlaActor)
3190 {
3191 return RespondError(
3192 "set_traffic_light_green_time",
3194 " Actor Id: " + FString::FromInt(ActorId));
3195 }
3196 ECarlaServerResponse Response =
3197 CarlaActor->SetLightGreenTime(GreenTime);
3198 if (Response != ECarlaServerResponse::Success)
3199 {
3200 return RespondError(
3201 "set_traffic_light_green_time",
3202 Response,
3203 " Actor Id: " + FString::FromInt(ActorId));
3204 }
3205 return R<void>::Success();
3206 };
3207
3208 BIND_SYNC(set_traffic_light_yellow_time) << [this](
3209 cr::ActorId ActorId,
3210 float YellowTime) -> R<void>
3211 {
3214 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
3215 if (!CarlaActor)
3216 {
3217 return RespondError(
3218 "set_traffic_light_yellow_time",
3220 " Actor Id: " + FString::FromInt(ActorId));
3221 }
3222 ECarlaServerResponse Response =
3223 CarlaActor->SetLightYellowTime(YellowTime);
3224 if (Response != ECarlaServerResponse::Success)
3225 {
3226 return RespondError(
3227 "set_traffic_light_yellow_time",
3228 Response,
3229 " Actor Id: " + FString::FromInt(ActorId));
3230 }
3231 return R<void>::Success();
3232 };
3233
3234 BIND_SYNC(set_traffic_light_red_time) << [this](
3235 cr::ActorId ActorId,
3236 float RedTime) -> R<void>
3237 {
3240 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
3241 if (!CarlaActor)
3242 {
3243 return RespondError(
3244 "set_traffic_light_red_time",
3246 " Actor Id: " + FString::FromInt(ActorId));
3247 }
3248 ECarlaServerResponse Response =
3249 CarlaActor->SetLightRedTime(RedTime);
3250 if (Response != ECarlaServerResponse::Success)
3251 {
3252 return RespondError(
3253 "set_traffic_light_red_time",
3254 Response,
3255 " Actor Id: " + FString::FromInt(ActorId));
3256 }
3257 return R<void>::Success();
3258 };
3259
3260 BIND_SYNC(freeze_traffic_light) << [this](
3261 cr::ActorId ActorId,
3262 bool Freeze) -> R<void>
3263 {
3266 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
3267 if (!CarlaActor)
3268 {
3269 return RespondError(
3270 "freeze_traffic_light",
3272 " Actor Id: " + FString::FromInt(ActorId));
3273 }
3274 ECarlaServerResponse Response =
3275 CarlaActor->FreezeTrafficLight(Freeze);
3276 if (Response != ECarlaServerResponse::Success)
3277 {
3278 return RespondError(
3279 "freeze_traffic_light",
3280 Response,
3281 " Actor Id: " + FString::FromInt(ActorId));
3282 }
3283 return R<void>::Success();
3284 };
3285
3286 BIND_SYNC(reset_traffic_light_group) << [this](
3287 cr::ActorId ActorId) -> R<void>
3288 {
3291 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
3292 if (!CarlaActor)
3293 {
3294 return RespondError(
3295 "reset_traffic_light_group",
3297 " Actor Id: " + FString::FromInt(ActorId));
3298 }
3299 ECarlaServerResponse Response =
3300 CarlaActor->ResetTrafficLightGroup();
3301 if (Response != ECarlaServerResponse::Success)
3302 {
3303 return RespondError(
3304 "reset_traffic_light_group",
3305 Response,
3306 " Actor Id: " + FString::FromInt(ActorId));
3307 }
3308 return R<void>::Success();
3309 };
3310
3311 BIND_SYNC(reset_all_traffic_lights) << [this]() -> R<void>
3312 {
3315 for (TActorIterator<ATrafficLightGroup> It(Episode->GetWorld()); It; ++It)
3316 {
3317 It->ResetGroup();
3318 }
3319 return R<void>::Success();
3320 };
3321
3322 BIND_SYNC(freeze_all_traffic_lights) << [this]
3323 (bool frozen) -> R<void>
3324 {
3327 auto* GameMode = UCarlaStatics::GetGameMode(Episode->GetWorld());
3328 if (!GameMode)
3329 {
3330 RESPOND_ERROR("unable to find CARLA game mode");
3331 }
3332 auto* TraffiLightManager = GameMode->GetTrafficLightManager();
3333 TraffiLightManager->SetFrozen(frozen);
3334 return R<void>::Success();
3335 };
3336
3337 BIND_SYNC(get_vehicle_light_states) << [this]() -> R<cr::VehicleLightStateList>
3338 {
3340 cr::VehicleLightStateList List;
3341
3342 auto It = Episode->GetActorRegistry().begin();
3343 for (; It != Episode->GetActorRegistry().end(); ++It)
3344 {
3345 const FCarlaActor& View = *(It->Value.Get());
3347 {
3348 if(View.IsDormant())
3349 {
3350 // todo: implement
3351 }
3352 else
3353 {
3354 auto Actor = View.GetActor();
3355 if (IsValid(Actor))
3356 {
3357 const ACarlaWheeledVehicle *Vehicle = Cast<ACarlaWheeledVehicle>(Actor);
3358 List.emplace_back(
3359 View.GetActorId(),
3360 cr::VehicleLightState(Vehicle->GetVehicleLightState()).GetLightStateAsValue());
3361 }
3362 }
3363 }
3364 }
3365 return List;
3366 };
3367
3368 BIND_SYNC(get_group_traffic_lights) << [this](
3369 const cr::ActorId ActorId) -> R<std::vector<cr::ActorId>>
3370 {
3372 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
3373 if (!CarlaActor)
3374 {
3375 RESPOND_ERROR("unable to get group traffic lights: actor not found");
3376 }
3377 if (CarlaActor->IsDormant())
3378 {
3379 //todo implement
3380 return std::vector<cr::ActorId>();
3381 }
3382 else
3383 {
3384 auto TrafficLight = Cast<ATrafficLightBase>(CarlaActor->GetActor());
3385 if (TrafficLight == nullptr)
3386 {
3387 RESPOND_ERROR("unable to get group traffic lights: actor is not a traffic light");
3388 }
3389 std::vector<cr::ActorId> Result;
3390 for (auto* TLight : TrafficLight->GetGroupTrafficLights())
3391 {
3392 auto* View = Episode->FindCarlaActor(TLight);
3393 if (View)
3394 {
3395 Result.push_back(View->GetActorId());
3396 }
3397 }
3398 return Result;
3399 }
3400 };
3401
3402 BIND_SYNC(get_light_boxes) << [this](
3403 const cr::ActorId ActorId) -> R<std::vector<cg::BoundingBox>>
3404 {
3406 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
3407 if (!CarlaActor)
3408 {
3409 return RespondError(
3410 "get_light_boxes",
3412 " Actor Id: " + FString::FromInt(ActorId));
3413 }
3414 if (CarlaActor->IsDormant())
3415 {
3416 return RespondError(
3417 "get_light_boxes",
3419 " Actor Id: " + FString::FromInt(ActorId));
3420 }
3421 else
3422 {
3423 ATrafficLightBase* TrafficLight = Cast<ATrafficLightBase>(CarlaActor->GetActor());
3424 if (!TrafficLight)
3425 {
3426 return RespondError(
3427 "get_light_boxes",
3429 " Actor Id: " + FString::FromInt(ActorId));
3430 }
3431 TArray<FBoundingBox> Result;
3432 TArray<uint8> OutTag;
3434 TrafficLight, Result, OutTag,
3435 static_cast<uint8>(carla::rpc::CityObjectLabel::TrafficLight));
3436 return MakeVectorFromTArray<cg::BoundingBox>(Result);
3437 }
3438 };
3439
3440 // ~~ GBuffer tokens ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3441 BIND_SYNC(get_gbuffer_token) << [this](const cr::ActorId ActorId, uint32_t GBufferId) -> R<std::vector<unsigned char>>
3442 {
3445 FCarlaActor* CarlaActor = Episode->FindCarlaActor(ActorId);
3446 if(!CarlaActor)
3447 {
3448 return RespondError(
3449 "get_gbuffer_token",
3451 " Actor Id: " + FString::FromInt(ActorId));
3452 }
3453 if (CarlaActor->IsDormant())
3454 {
3455 return RespondError(
3456 "get_gbuffer_token",
3458 " Actor Id: " + FString::FromInt(ActorId));
3459 }
3460 ASceneCaptureSensor* Sensor = Cast<ASceneCaptureSensor>(CarlaActor->GetActor());
3461 if (!Sensor)
3462 {
3463 return RespondError(
3464 "get_gbuffer_token",
3466 " Actor Id: " + FString::FromInt(ActorId));
3467 }
3468 if (!FApp::CanEverRender())
3469 {
3470 return RespondError(
3471 "get_gbuffer_token",
3472 "this server cannot render (-nullrhi), GBuffer streams are not available",
3473 " Actor Id: " + FString::FromInt(ActorId));
3474 }
3475
3476 switch (GBufferId)
3477 {
3478 case 0:
3479 {
3480 const auto &Token = Sensor->CameraGBuffers.SceneColor.GetToken();
3481 return std::vector<unsigned char>(std::begin(Token.data), std::end(Token.data));
3482 }
3483 case 1:
3484 {
3485 const auto &Token = Sensor->CameraGBuffers.SceneDepth.GetToken();
3486 return std::vector<unsigned char>(std::begin(Token.data), std::end(Token.data));
3487 }
3488 case 2:
3489 {
3490 const auto& Token = Sensor->CameraGBuffers.SceneStencil.GetToken();
3491 return std::vector<unsigned char>(std::begin(Token.data), std::end(Token.data));
3492 }
3493 case 3:
3494 {
3495 const auto &Token = Sensor->CameraGBuffers.GBufferA.GetToken();
3496 return std::vector<unsigned char>(std::begin(Token.data), std::end(Token.data));
3497 }
3498 case 4:
3499 {
3500 const auto &Token = Sensor->CameraGBuffers.GBufferB.GetToken();
3501 return std::vector<unsigned char>(std::begin(Token.data), std::end(Token.data));
3502 }
3503 case 5:
3504 {
3505 const auto &Token = Sensor->CameraGBuffers.GBufferC.GetToken();
3506 return std::vector<unsigned char>(std::begin(Token.data), std::end(Token.data));
3507 }
3508 case 6:
3509 {
3510 const auto &Token = Sensor->CameraGBuffers.GBufferD.GetToken();
3511 return std::vector<unsigned char>(std::begin(Token.data), std::end(Token.data));
3512 }
3513 case 7:
3514 {
3515 const auto &Token = Sensor->CameraGBuffers.GBufferE.GetToken();
3516 return std::vector<unsigned char>(std::begin(Token.data), std::end(Token.data));
3517 }
3518 case 8:
3519 {
3520 const auto &Token = Sensor->CameraGBuffers.GBufferF.GetToken();
3521 return std::vector<unsigned char>(std::begin(Token.data), std::end(Token.data));
3522 }
3523 case 9:
3524 {
3525 const auto &Token = Sensor->CameraGBuffers.Velocity.GetToken();
3526 return std::vector<unsigned char>(std::begin(Token.data), std::end(Token.data));
3527 }
3528 case 10:
3529 {
3530 const auto &Token = Sensor->CameraGBuffers.SSAO.GetToken();
3531 return std::vector<unsigned char>(std::begin(Token.data), std::end(Token.data));
3532 }
3533 case 11:
3534 {
3535 const auto& Token = Sensor->CameraGBuffers.CustomDepth.GetToken();
3536 return std::vector<unsigned char>(std::begin(Token.data), std::end(Token.data));
3537 }
3538 case 12:
3539 {
3540 const auto& Token = Sensor->CameraGBuffers.CustomStencil.GetToken();
3541 return std::vector<unsigned char>(std::begin(Token.data), std::end(Token.data));
3542 }
3543 default:
3544 UE_LOG(LogCarla, Error, TEXT("Requested invalid GBuffer ID %u"), GBufferId);
3545 return {};
3546 }
3547 };
3548
3549 // ~~ Logging and playback ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3550
3551 BIND_SYNC(start_recorder) << [this](std::string name, bool AdditionalData, bool StopReplayer) -> R<std::string>
3552 {
3555 return R<std::string>(Episode->StartRecorder(name, AdditionalData, StopReplayer));
3556 };
3557
3558 BIND_SYNC(stop_recorder) << [this]() -> R<void>
3559 {
3562 Episode->GetRecorder()->Stop();
3563 return R<void>::Success();
3564 };
3565
3566 BIND_SYNC(show_recorder_file_info) << [this](
3567 std::string name,
3568 bool show_all) -> R<std::string>
3569 {
3572 name,
3573 show_all));
3574 };
3575
3576 BIND_SYNC(show_recorder_collisions) << [this](
3577 std::string name,
3578 char type1,
3579 char type2) -> R<std::string>
3580 {
3583 name,
3584 type1,
3585 type2));
3586 };
3587
3588 BIND_SYNC(show_recorder_actors_blocked) << [this](
3589 std::string name,
3590 double min_time,
3591 double min_distance) -> R<std::string>
3592 {
3595 name,
3596 min_time,
3597 min_distance));
3598 };
3599
3600 BIND_SYNC(replay_file) << [this](
3601 std::string name,
3602 double start,
3603 double duration,
3604 uint32_t follow_id,
3605 bool replay_sensors,
3606 bool replay_weather,
3607 const cr::Transform& offset,
3608 std::string map_override) -> R<std::string>
3609 {
3613 name,
3614 start,
3615 duration,
3616 follow_id,
3617 offset,
3618 replay_sensors,
3619 replay_weather,
3620 map_override));
3621 };
3622
3623 BIND_SYNC(set_replayer_time_factor) << [this](double time_factor) -> R<void>
3624 {
3627 Episode->GetRecorder()->SetReplayerTimeFactor(time_factor);
3628 return R<void>::Success();
3629 };
3630
3631 BIND_SYNC(set_replayer_ignore_hero) << [this](bool ignore_hero) -> R<void>
3632 {
3635 Episode->GetRecorder()->SetReplayerIgnoreHero(ignore_hero);
3636 return R<void>::Success();
3637 };
3638
3639 BIND_SYNC(set_replayer_ignore_spectator) << [this](bool ignore_spectator) -> R<void>
3640 {
3643 Episode->GetRecorder()->SetReplayerIgnoreSpectator(ignore_spectator);
3644 return R<void>::Success();
3645 };
3646
3647 BIND_SYNC(stop_replayer) << [this](bool keep_actors) -> R<void>
3648 {
3651 Episode->GetRecorder()->StopReplayer(keep_actors);
3652 return R<void>::Success();
3653 };
3654
3655 // ~~ Draw debug shapes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3656
3657 BIND_SYNC(draw_debug_shape) << [this](const cr::DebugShape &shape) -> R<void>
3658 {
3661 auto *World = Episode->GetWorld();
3662 check(World != nullptr);
3663 FDebugShapeDrawer Drawer(*World);
3664 Drawer.Draw(shape);
3665 return R<void>::Success();
3666 };
3667
3668 // ~~ Clear debug shapes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3669
3670 BIND_SYNC(clear_debug_shape) << [this]() -> R<void>
3671 {
3674 auto *World = Episode->GetWorld();
3675 check(World != nullptr);
3676 FDebugShapeDrawer Drawer(*World);
3677 Drawer.Clear();
3678 return R<void>::Success();
3679 };
3680
3681 // ~~ Spawn custom mesh ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3682
3683 BIND_SYNC(spawn_custom_mesh) << [this](
3684 std::vector<float> vertices,
3685 std::vector<uint32_t> triangles,
3686 std::string material) -> R<void>
3687 {
3690 auto *World = Episode->GetWorld();
3691 check(World != nullptr);
3692 if (vertices.empty() || (vertices.size() % 3u) != 0u)
3693 {
3694 RESPOND_ERROR("spawn_custom_mesh: vertices must be a non-empty flat (x, y, z) triple list");
3695 }
3696 if (triangles.empty() || (triangles.size() % 3u) != 0u)
3697 {
3698 RESPOND_ERROR("spawn_custom_mesh: triangles must be a non-empty index-triple list");
3699 }
3700 const uint32_t NumVertices = vertices.size() / 3u;
3701 for (const uint32_t Index : triangles)
3702 {
3703 if (Index >= NumVertices)
3704 {
3705 RESPOND_ERROR("spawn_custom_mesh: triangle index out of range");
3706 }
3707 }
3708
3709 // Client sends metres in the client (UE-handed) frame; UE wants cm.
3710 TArray<FVector> Verts;
3711 Verts.Reserve(NumVertices);
3712 for (uint32_t i = 0u; i < NumVertices; ++i)
3713 {
3714 Verts.Add(FVector(
3715 vertices[3u * i + 0u] * 100.0f,
3716 vertices[3u * i + 1u] * 100.0f,
3717 vertices[3u * i + 2u] * 100.0f));
3718 }
3719 TArray<int32> Tris;
3720 Tris.Reserve(triangles.size());
3721 for (const uint32_t Index : triangles)
3722 {
3723 Tris.Add(static_cast<int32>(Index));
3724 }
3725
3726 // Area-weighted vertex normals. UE's left-handed winding means the
3727 // front face is the one from which the vertices wind clockwise, so the
3728 // outward normal of triangle (V0, V1, V2) is (V2-V0) x (V1-V0).
3729 TArray<FVector> Normals;
3730 Normals.Init(FVector::ZeroVector, Verts.Num());
3731 for (int32 i = 0; i + 2 < Tris.Num(); i += 3)
3732 {
3733 const FVector &V0 = Verts[Tris[i]];
3734 const FVector &V1 = Verts[Tris[i + 1]];
3735 const FVector &V2 = Verts[Tris[i + 2]];
3736 const FVector FaceNormal = FVector::CrossProduct(V2 - V0, V1 - V0);
3737 Normals[Tris[i]] += FaceNormal;
3738 Normals[Tris[i + 1]] += FaceNormal;
3739 Normals[Tris[i + 2]] += FaceNormal;
3740 }
3741 for (FVector &Normal : Normals)
3742 {
3743 Normal = Normal.GetSafeNormal(1e-8, FVector::UpVector);
3744 }
3745
3746 // Planar world-space UVs so tiled materials repeat sensibly (5 m tile).
3747 TArray<FVector2D> UV0;
3748 UV0.Reserve(Verts.Num());
3749 for (const FVector &V : Verts)
3750 {
3751 UV0.Add(FVector2D(V.X / 500.0f, V.Y / 500.0f));
3752 }
3753
3754 ACarlaProceduralMeshActor *MeshActor = World->SpawnActor<ACarlaProceduralMeshActor>();
3755 if (MeshActor == nullptr)
3756 {
3757 RESPOND_ERROR("spawn_custom_mesh: failed to spawn mesh actor");
3758 }
3759 UProceduralMeshComponent *PMC = MeshActor->MeshComponent;
3760 PMC->bUseAsyncCooking = true;
3761 PMC->bUseComplexAsSimpleCollision = true;
3762 PMC->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
3763 PMC->CreateMeshSection_LinearColor(
3764 0,
3765 Verts,
3766 Tris,
3767 Normals,
3768 UV0,
3769 TArray<FLinearColor>(),
3770 TArray<FProcMeshTangent>(),
3771 true);
3772
3773 static const TMap<FString, FString> MaterialHints = {
3774 {TEXT("grass"), TEXT("/Game/Carla/Static/GenericMaterials/Ground/MI_LargeLandscape_Grass.MI_LargeLandscape_Grass")},
3775 {TEXT("dirt"), TEXT("/Game/Carla/Static/GenericMaterials/Ground/MI_Dirt.MI_Dirt")},
3776 {TEXT("road"), TEXT("/Game/Carla/Static/GenericMaterials/Roads/MI_RoadAsphalt_Town15.MI_RoadAsphalt_Town15")},
3777 {TEXT("sidewalk"), TEXT("/Game/Carla/Static/GenericMaterials/Sidewalk/MI_Sidewalk_Apartment.MI_Sidewalk_Apartment")}};
3778 const FString MaterialName = cr::ToFString(material);
3779 const FString *MaterialPath = MaterialHints.Find(MaterialName.ToLower());
3780 const FString ResolvedPath = (MaterialPath != nullptr) ? *MaterialPath : MaterialName;
3781 if (UMaterialInterface *Material = LoadObject<UMaterialInterface>(nullptr, *ResolvedPath))
3782 {
3783 PMC->SetMaterial(0, Material);
3784 }
3785
3786 // Tag as terrain for semantic segmentation, mirroring the generated
3787 // ground plane (OpenDriveGenerator's TagGeneratedComponent).
3788 ATagger::SetStencilValue(*PMC, MeshActor->GetUniqueID(), cr::CityObjectLabel::Terrain, true);
3789 PMC->ComponentTags.Add(FName(*ATagger::GetTagAsString(cr::CityObjectLabel::Terrain)));
3790
3791 return R<void>::Success();
3792 };
3793
3794 // ~~ Clear debug strings ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3795
3796 BIND_SYNC(clear_debug_string) << [this]() -> R<void>
3797 {
3800 auto *World = Episode->GetWorld();
3801 check(World != nullptr);
3802 APlayerController *PlayerController = World->GetFirstPlayerController();
3803 if (PlayerController != nullptr)
3804 {
3805 ACarlaHUD *CarlaHUD = Cast<ACarlaHUD>(PlayerController->GetHUD());
3806 if (CarlaHUD != nullptr)
3807 {
3808 CarlaHUD->ClearDebugStrings();
3809 }
3810 }
3811 if (GEngine != nullptr)
3812 {
3813 GEngine->ClearOnScreenDebugMessages();
3814 }
3815 return R<void>::Success();
3816 };
3817
3818 // ~~ Apply commands in batch ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3819
3820 using C = cr::Command;
3821 using CR = cr::CommandResponse;
3822 using ActorId = carla::ActorId;
3823
3824 auto parse_result = [](ActorId id, const auto &response) {
3825 return response.HasError() ? CR{response.GetError()} : CR{id};
3826 };
3827
3828#define MAKE_RESULT(operation) return parse_result(c.actor, operation);
3829
3830 auto command_visitor = carla::Functional::MakeRecursiveOverload(
3831 [=](auto self, const C::SpawnActor &c) -> CR {
3832 auto result = c.parent.has_value() ?
3833 spawn_actor_with_parent(
3834 c.description,
3835 c.transform,
3836 *c.parent,
3837 cr::AttachmentType::Rigid) :
3838 spawn_actor(c.description, c.transform);
3839 if (!result.HasError())
3840 {
3841 ActorId id = result.Get().id;
3842 auto set_id = carla::Functional::MakeOverload(
3843 [](C::SpawnActor &) {},
3844 [](C::ConsoleCommand &) {},
3845 [id](auto &s) { s.actor = id; });
3846 for (auto command : c.do_after)
3847 {
3848 std::visit(set_id, command.command);
3849 std::visit(self, command.command);
3850 }
3851 return id;
3852 }
3853 return result.GetError();
3854 },
3855 [=](auto, const C::DestroyActor &c) { MAKE_RESULT(destroy_actor(c.actor)); },
3856 [=](auto, const C::ApplyVehicleControl &c) { MAKE_RESULT(apply_control_to_vehicle(c.actor, c.control)); },
3857 [=](auto, const C::ApplyVehicleAckermannControl &c) { MAKE_RESULT(apply_ackermann_control_to_vehicle(c.actor, c.control)); },
3858 [=](auto, const C::ApplyWalkerControl &c) { MAKE_RESULT(apply_control_to_walker(c.actor, c.control)); },
3859 [=](auto, const C::ApplyVehiclePhysicsControl &c) { MAKE_RESULT(apply_physics_control(c.actor, c.physics_control)); },
3860 [=](auto, const C::ApplyTransform &c) { MAKE_RESULT(set_actor_transform(c.actor, c.transform)); },
3861 [=](auto, const C::ApplyTargetVelocity &c) { MAKE_RESULT(set_actor_target_velocity(c.actor, c.velocity)); },
3862 [=](auto, const C::ApplyTargetAngularVelocity &c) { MAKE_RESULT(set_actor_target_angular_velocity(c.actor, c.angular_velocity)); },
3863 [=](auto, const C::ApplyImpulse &c) { MAKE_RESULT(add_actor_impulse(c.actor, c.impulse)); },
3864 [=](auto, const C::ApplyForce &c) { MAKE_RESULT(add_actor_force(c.actor, c.force)); },
3865 [=](auto, const C::ApplyAngularImpulse &c) { MAKE_RESULT(add_actor_angular_impulse(c.actor, c.impulse)); },
3866 [=](auto, const C::ApplyTorque &c) { MAKE_RESULT(add_actor_torque(c.actor, c.torque)); },
3867 [=](auto, const C::SetSimulatePhysics &c) { MAKE_RESULT(set_actor_simulate_physics(c.actor, c.enabled)); },
3868 [=](auto, const C::SetEnableGravity &c) { MAKE_RESULT(set_actor_enable_gravity(c.actor, c.enabled)); },
3869 // TODO: SetAutopilot should be removed. This is the old way to control the vehicles
3870 [=](auto, const C::SetAutopilot &c) { MAKE_RESULT(set_actor_autopilot(c.actor, c.enabled)); },
3871 [=](auto, const C::ShowDebugTelemetry &c) { MAKE_RESULT(show_vehicle_debug_telemetry(c.actor, c.enabled)); },
3872 [=](auto, const C::SetVehicleLightState &c) { MAKE_RESULT(set_vehicle_light_state(c.actor, c.light_state)); },
3873// [=](auto, const C::OpenVehicleDoor &c) { MAKE_RESULT(open_vehicle_door(c.actor, c.door_idx)); },
3874// [=](auto, const C::CloseVehicleDoor &c) { MAKE_RESULT(close_vehicle_door(c.actor, c.door_idx)); },
3875 [=](auto, const C::ApplyWalkerState &c) { MAKE_RESULT(set_walker_state(c.actor, c.transform, c.speed)); },
3876 [=](auto, const C::ConsoleCommand& c) -> CR { return console_command(c.cmd); },
3877 [=](auto, const C::SetTrafficLightState& c) { MAKE_RESULT(set_traffic_light_state(c.actor, c.traffic_light_state)); },
3878 [=](auto, const C::ApplyLocation& c) { MAKE_RESULT(set_actor_location(c.actor, c.location)); }
3879 );
3880
3881#undef MAKE_RESULT
3882
3883 BIND_SYNC(apply_batch) << [=](
3884 const std::vector<cr::Command> &commands,
3885 bool do_tick_cue)
3886 {
3887 std::vector<CR> result;
3888 result.reserve(commands.size());
3889 for (const auto &command : commands)
3890 {
3891 result.emplace_back(std::visit(command_visitor, command.command));
3892 }
3893 if (do_tick_cue)
3894 {
3895 tick_cue();
3896 }
3897 return result;
3898 };
3899
3900 // ~~ Light Subsystem ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3901
3902 BIND_SYNC(query_lights_state) << [this](std::string client) -> R<std::vector<cr::LightState>>
3903 {
3905 std::vector<cr::LightState> result;
3906 auto *World = Episode->GetWorld();
3907 if(World) {
3908 UCarlaLightSubsystem* CarlaLightSubsystem = World->GetSubsystem<UCarlaLightSubsystem>();
3909 result = CarlaLightSubsystem->GetLights(FString(client.c_str()));
3910 }
3911 return result;
3912 };
3913
3914 BIND_SYNC(update_lights_state) << [this]
3915 (std::string client, const std::vector<cr::LightState>& lights, bool discard_client) -> R<void>
3916 {
3919 auto *World = Episode->GetWorld();
3920 if(World) {
3921 UCarlaLightSubsystem* CarlaLightSubsystem = World->GetSubsystem<UCarlaLightSubsystem>();
3922 CarlaLightSubsystem->SetLights(FString(client.c_str()), lights, discard_client);
3923 }
3924 return R<void>::Success();
3925 };
3926
3927 BIND_SYNC(update_day_night_cycle) << [this]
3928 (std::string client, const bool active) -> R<void>
3929 {
3932 auto *World = Episode->GetWorld();
3933 if(World) {
3934 UCarlaLightSubsystem* CarlaLightSubsystem = World->GetSubsystem<UCarlaLightSubsystem>();
3935 CarlaLightSubsystem->SetDayNightCycle(active);
3936 }
3937 return R<void>::Success();
3938 };
3939
3940
3941 // ~~ Ray Casting ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3942
3943 BIND_SYNC(project_point) << [this]
3944 (cr::Location Location, cr::Vector3D Direction, float SearchDistance)
3945 -> R<std::pair<bool,cr::LabelledPoint>>
3946 {
3948 auto *World = Episode->GetWorld();
3949 constexpr float meter_to_centimeter = 100.0f;
3950 FVector UELocation = Location;
3951 ACarlaGameModeBase* GameMode = UCarlaStatics::GetGameMode(Episode->GetWorld());
3952 ALargeMapManager* LargeMap = GameMode->GetLMManager();
3953 if (LargeMap)
3954 {
3955 UELocation = LargeMap->GlobalToLocalLocation(UELocation);
3956 }
3957 return URayTracer::ProjectPoint(UELocation, Direction.ToFVector(),
3958 meter_to_centimeter * SearchDistance, World);
3959 };
3960
3961 BIND_SYNC(cast_ray) << [this]
3962 (cr::Location StartLocation, cr::Location EndLocation)
3963 -> R<std::vector<cr::LabelledPoint>>
3964 {
3966 auto *World = Episode->GetWorld();
3967 FVector UEStartLocation = StartLocation;
3968 FVector UEEndLocation = EndLocation;
3969 ACarlaGameModeBase* GameMode = UCarlaStatics::GetGameMode(Episode->GetWorld());
3970 ALargeMapManager* LargeMap = GameMode->GetLMManager();
3971 if (LargeMap)
3972 {
3973 UEStartLocation = LargeMap->GlobalToLocalLocation(UEStartLocation);
3974 UEEndLocation = LargeMap->GlobalToLocalLocation(UEEndLocation);
3975 }
3976 return URayTracer::CastRay(StartLocation, EndLocation, World);
3977 };
3978
3979 BIND_SYNC(get_actor_name) << [this](
3980 cr::ActorId ActorID) -> R<std::string>
3981 {
3983 auto CarlaActor = Episode->FindCarlaActor(ActorID);
3984 if (CarlaActor == nullptr)
3985 return std::string();
3986 auto Actor = CarlaActor->GetActor();
3987 if (Actor == nullptr)
3988 return std::string();
3989 auto Name = Actor->GetName();
3990 if (Name.Len() == 0)
3991 return std::string();
3992 auto NameStr = StringCast<UTF8CHAR>(*Name, Name.Len());
3993 return std::string((const char*)NameStr.Get(), NameStr.Length());
3994 };
3995
3996 BIND_SYNC(get_actor_class_name) << [this](
3997 cr::ActorId ActorID) -> R<std::string>
3998 {
4000 auto CarlaActor = Episode->FindCarlaActor(ActorID);
4001 if (CarlaActor == nullptr)
4002 return std::string();
4003 auto Actor = CarlaActor->GetActor();
4004 if (Actor == nullptr)
4005 return std::string();
4006 auto Class = Actor->GetClass();
4007 if (Class == nullptr)
4008 return std::string();
4009 auto Name = Class->GetName();
4010 if (Name.Len() == 0)
4011 return std::string();
4012 auto NameStr = StringCast<UTF8CHAR>(*Name, Name.Len());
4013 return std::string((const char*)NameStr.Get(), NameStr.Length());
4014 };
4015
4016}
4017
4018// =============================================================================
4019// -- Undef helper macros ------------------------------------------------------
4020// =============================================================================
4021
4022#undef BIND_ASYNC
4023#undef BIND_SYNC
4024#undef REQUIRE_PRIMARY_SERVER
4025#undef REQUIRE_CARLA_EPISODE
4026#undef RESPOND_ERROR_FSTRING
4027#undef RESPOND_ERROR
4028#undef CARLA_ENSURE_GAME_THREAD
4029
4030// =============================================================================
4031// -- FCarlaServer -------------------------------------------------------
4032// =============================================================================
4033
4035
4039
4040FDataMultiStream FCarlaServer::Start(uint16_t RPCPort, uint16_t StreamingPort, uint16_t SecondaryPort)
4041{
4042 Pimpl = MakeUnique<FPimpl>(RPCPort, StreamingPort, SecondaryPort);
4043 StreamingPort = Pimpl->StreamingServer.GetLocalEndpoint().port();
4044 SecondaryPort = Pimpl->SecondaryServer->GetLocalEndpoint().port();
4045
4046#if PLATFORM_LINUX || PLATFORM_MAC
4047 // The vendored rpclib server (Pimpl->Server) hides its listening-socket
4048 // acceptor behind a PIMPL with no public accessor, so unlike the
4049 // streaming/secondary listeners (which mark themselves close-on-exec at
4050 // construction, see carla/streaming/detail/tcp/Server.cpp and
4051 // carla/multigpu/listener.cpp) it can't be fixed at the point it's
4052 // created. Without this, a forked child (e.g. RecastBuilder, launched by
4053 // UCarlaEpisode::LoadNewOpendriveEpisode for pedestrian-nav generation)
4054 // inherits the RPC listen socket; if the child outlives the server, it
4055 // keeps the port bound and the next server boot aborts in asio's bind().
4056 // rpc::server's constructor already binds+listens by the time FPimpl's
4057 // constructor above returns, so the socket exists and is found by port.
4059#endif // !_WIN32
4060
4061 UE_LOG(
4062 LogCarlaServer,
4063 Log,
4064 TEXT("Initialized CarlaServer: Ports(rpc=%d, streaming=%d, secondary=%d)"),
4065 RPCPort,
4066 StreamingPort,
4067 SecondaryPort);
4068 return Pimpl->BroadcastStream;
4069}
4070
4072{
4073 check(Pimpl != nullptr);
4074 UE_LOG(LogCarlaServer, Log, TEXT("New episode '%s' started"), *Episode.GetMapName());
4075 Pimpl->Episode = &Episode;
4076}
4077
4079{
4080 check(Pimpl != nullptr);
4081 Pimpl->Episode = nullptr;
4082}
4083
4084void FCarlaServer::AsyncRun(uint32 NumberOfWorkerThreads)
4085{
4086 check(Pimpl != nullptr);
4087 /// @todo Define better the number of threads each server gets.
4088 int ThreadsPerServer = std::max(2u, NumberOfWorkerThreads / 3u);
4089 int32_t RPCThreads;
4090 int32_t StreamingThreads;
4091 int32_t SecondaryThreads;
4092
4093 UE_LOG(LogCarla, Log, TEXT("FCommandLine %s"), FCommandLine::Get());
4094
4095 if(!FParse::Value(FCommandLine::Get(), TEXT("-RPCThreads="), RPCThreads))
4096 {
4097 RPCThreads = ThreadsPerServer;
4098 }
4099 if(!FParse::Value(FCommandLine::Get(), TEXT("-StreamingThreads="), StreamingThreads))
4100 {
4101 StreamingThreads = ThreadsPerServer;
4102 }
4103 if(!FParse::Value(FCommandLine::Get(), TEXT("-SecondaryThreads="), SecondaryThreads))
4104 {
4105 SecondaryThreads = ThreadsPerServer;
4106 }
4107
4108 UE_LOG(LogCarla, Log, TEXT("FCarlaServer AsyncRun %d, RPCThreads %d, StreamingThreads %d, SecondaryThreads %d"),
4109 NumberOfWorkerThreads, RPCThreads, StreamingThreads, SecondaryThreads);
4110
4111 Pimpl->Server.AsyncRun(RPCThreads);
4112 Pimpl->StreamingServer.AsyncRun(StreamingThreads);
4113 Pimpl->SecondaryServer->AsyncRun(SecondaryThreads);
4114}
4115
4116void FCarlaServer::RunSome(uint32 Milliseconds)
4117{
4118 TRACE_CPUPROFILER_EVENT_SCOPE_STR(__FUNCTION__);
4119 Pimpl->Server.SyncRunFor(carla::time_duration::milliseconds(Milliseconds));
4120}
4121
4123{
4124 TRACE_CPUPROFILER_EVENT_SCOPE(FCarlaServer::Tick);
4125 (void)Pimpl->TickCuesReceived.fetch_add(1, std::memory_order_release);
4126}
4127
4129{
4130 check(Pimpl != nullptr);
4131 Pimpl->bIsSecondaryServer = bIsSecondary;
4132}
4133
4135{
4136 TRACE_CPUPROFILER_EVENT_SCOPE(FCarlaServer::TickCueReceived);
4137 auto k = Pimpl->TickCuesReceived.fetch_sub(1, std::memory_order_acquire);
4138 bool flag = (k > 0);
4139 if (!flag)
4140 (void)Pimpl->TickCuesReceived.fetch_add(1, std::memory_order_release);
4141 return flag;
4142}
4143
4145{
4146 if (Pimpl)
4147 {
4148 Pimpl->Server.Stop();
4149 Pimpl->SecondaryServer->Stop();
4150 }
4151}
4152
4154{
4155 check(Pimpl != nullptr);
4156 return Pimpl->StreamingServer.MakeStream();
4157}
4158
4159std::shared_ptr<carla::multigpu::Router> FCarlaServer::GetSecondaryServer()
4160{
4161 return Pimpl->GetSecondaryServer();
4162}
4163
4165{
4166 return Pimpl->StreamingServer;
4167}
EAttachmentType
float intensity
FString CarlaGetStringError(ECarlaServerResponse Response)
ECarlaServerResponse
static AWalkerController * ResolveWalkerNavController(FCarlaActor *CarlaActor)
Resolve the AWalkerController behind a walker-navigation RPC actor id.
#define REQUIRE_CARLA_EPISODE()
#define REQUIRE_PRIMARY_SERVER()
#define REQUIRE_CARLA_GAME_MODE()
static R< void > ApplyTextureToActor(UCarlaEpisode *Episode, carla::rpc::ActorId ActorId, const carla::rpc::MaterialParameter &MaterialParameter, T &&Texture)
#define MAKE_RESULT(operation)
#define RESPOND_ERROR(str)
#define BIND_SYNC(name)
#define RESPOND_ERROR_FSTRING(fstr)
static carla::rpc::ContentPackInfo MakeContentPackInfo(const FCarlaContentPack &Pack)
carla::rpc::ResponseError RespondError(const FString &FuncName, const FString &ErrorMessage, const FString &ExtraInfo="")
static std::vector< T > MakeVectorFromTArray(const TArray< Other > &Array)
#define BIND_ASYNC(name)
static std::vector< std::string > MakeStringVector(const TArray< FString > &Names)
#define CARLA_ENSURE_GAME_THREAD()
static bool IsUnrenderableLocalSensorStream(UCarlaEpisode &Episode, carla::streaming::detail::stream_id_type StreamId)
True when the stream belongs to a camera and this process has no RHI (-nullrhi): a local token for it...
EVehicleWheelLocation
EVehicleDoor
Type of door to open/close.
static bool IsValid(const ACarlaWheeledVehicle *Vehicle)
Base class for the CARLA Game Mode.
void UnLoadMapLayer(int32 MapLayers)
void EnableEnvironmentObjects(const TSet< uint64 > &EnvObjectIds, bool Enable)
TArray< FEnvironmentObject > GetEnvironmentObjects(uint8 QueriedTag=0xFF) const
AActor * FindActorByName(const FString &ActorName)
void LoadMapLayer(int32 MapLayers)
void ApplyTextureToActor(AActor *Actor, UTexture2D *Texture, const carla::rpc::MaterialParameter &TextureParam)
const FString GetFullMapPath() const
ALargeMapManager * GetLMManager() const
ATrafficLightManager * GetTrafficLightManager()
TArray< FString > GetNamesOfAllActors()
TArray< FBoundingBox > GetAllBBsOfLevel(uint8 TagQueried=0xFF) const
UTexture2D * CreateUETexture(const carla::rpc::TextureColor &Texture)
Class to draw on HUD.
Definition CarlaHUD.h:45
void ClearDebugStrings()
Definition CarlaHUD.h:70
TObjectPtr< UProceduralMeshComponent > MeshComponent
std::string ShowFileCollisions(std::string Name, char Type1, char Type2)
void StopReplayer(bool KeepActors=false)
std::string ShowFileInfo(std::string Name, bool bShowAll=false)
std::string ShowFileActorsBlocked(std::string Name, double MinTime=30, double MinDistance=10)
std::string ReplayFile(std::string Name, double TimeStart, double Duration, uint32_t FollowId, const FTransform &Offset, bool ReplaySensors, bool ReplayWeather, std::string MapOverride)
void SetReplayerIgnoreSpectator(bool IgnoreSpectator)
void SetReplayerIgnoreHero(bool IgnoreHero)
void SetReplayerTimeFactor(double TimeFactor)
Base class for CARLA wheeled vehicles.
void Send(const carla::rpc::CustomV2XBytes &data)
void ConsiderSpectatorAsEgo(bool _SpectatorAsEgo)
void OnActorSpawned(const FCarlaActor &CarlaActor)
FVector GlobalToLocalLocation(const FVector &InLocation) const
FTransform LocalToGlobalTransform(const FTransform &InTransform) const
FVector LocalToGlobalLocation(const FVector &InLocation) const
Base class for sensors using a USceneCaptureComponent2D for rendering the scene.
FCameraGBufferUint8 CustomDepth
FCameraGBufferUint8 GBufferD
struct ASceneCaptureSensor::@0 CameraGBuffers
FCameraGBufferUint8 GBufferE
FCameraGBufferUint8 GBufferF
FCameraGBufferUint8 GBufferA
FCameraGBufferUint8 SceneDepth
FCameraGBufferUint8 SceneStencil
FCameraGBufferUint8 SSAO
FCameraGBufferUint8 GBufferC
FCameraGBufferUint8 CustomStencil
FCameraGBufferUint8 Velocity
FCameraGBufferUint8 SceneColor
FCameraGBufferUint8 GBufferB
auto GetToken() const
Return the token that allows subscribing to this sensor's stream.
static FString GetTagAsString(crp::CityObjectLabel Tag)
Transform a CityObjectLabel into a string.
Definition Tagger.cpp:269
static void SetStencilValue(UPrimitiveComponent &Component, const uint32 ActorID, const crp::CityObjectLabel &Label, const bool bSetRenderCustomDepth)
Definition Tagger.cpp:63
Class In charge of creating and assigning traffic light groups, controllers and components.
Possesses every walker pawn.
static bool SetSkyLightMap(UWorld *World, class UTextureCube *Cubemap, float Intensity)
Environment-map override for the sky light (set_sky_light_map RPC): every ASkyBase rig in World switc...
Definition Weather.cpp:1465
static bool HasSkyLightMap()
Definition Weather.cpp:1530
static void ClearSkyLightMap(UWorld *World)
Drops the override and restores the real-time atmosphere capture with the curve-driven intensity.
Definition Weather.cpp:1500
auto begin() const noexcept
A view over an actor and its properties.
Definition CarlaActor.h:25
ECarlaServerResponse GetActorComponentNames(TArray< FString > &Names) const
ECarlaServerResponse AddActorImpulseAtLocation(const FVector &Impulse, const FVector &Location)
virtual ECarlaServerResponse GetPhysicsControl(FVehiclePhysicsControl &)
Definition CarlaActor.h:329
ECarlaServerResponse GetActorSocketNames(TArray< FString > &Names) const
ECarlaServerResponse GetActorBoneWorldTransforms(TArray< FTransform > &Transforms) const
virtual ECarlaServerResponse EnableActorConstantAcceleration(const FVector &)
Definition CarlaActor.h:319
ECarlaServerResponse AddActorForceAtLocation(const FVector &Force, const FVector &Location)
virtual ECarlaServerResponse SetActorEnableGravity(bool bEnabled)
virtual ECarlaServerResponse GetBonesTransform(FWalkerBoneControlOut &)
Definition CarlaActor.h:514
virtual ECarlaServerResponse GetAckermannControllerSettings(FAckermannControllerSettings &)
Definition CarlaActor.h:426
virtual ECarlaServerResponse SetLightRedTime(float)
Definition CarlaActor.h:489
virtual ECarlaServerResponse ResetTrafficLightGroup()
Definition CarlaActor.h:544
virtual ECarlaServerResponse DisableActorConstantAcceleration()
Definition CarlaActor.h:324
ActorType GetActorType() const
Definition CarlaActor.h:86
ECarlaServerResponse GetActorBoneRelativeTransforms(TArray< FTransform > &Transforms) const
virtual ECarlaServerResponse SetLightYellowTime(float)
Definition CarlaActor.h:484
virtual ECarlaServerResponse GetPoseFromAnimation()
Definition CarlaActor.h:529
virtual ECarlaServerResponse SetActorAutopilot(bool, bool bKeepState=false)
Definition CarlaActor.h:436
virtual ECarlaServerResponse SetWheelAnimationOverride(bool)
Definition CarlaActor.h:399
ECarlaServerResponse AddActorTorque(const FVector &Torque)
ECarlaServerResponse SetActorTargetAngularVelocity(const FVector &AngularVelocity)
bool IsDormant() const
Definition CarlaActor.h:71
ECarlaServerResponse AddActorImpulse(const FVector &Impulse)
AActor * GetActor()
Definition CarlaActor.h:91
virtual ECarlaServerResponse SetVehicleLightState(const FVehicleLightState &)
Definition CarlaActor.h:364
virtual ECarlaServerResponse SetActorDead()
Definition CarlaActor.h:534
virtual ECarlaServerResponse ApplyControlToVehicle(const FVehicleControl &, const EVehicleInputPriority &)
Definition CarlaActor.h:404
virtual ECarlaServerResponse GetWheelSteerAngle(const EVehicleWheelLocation &, float &)
Definition CarlaActor.h:374
virtual ECarlaServerResponse ApplyAckermannControllerSettings(const FAckermannControllerSettings &)
Definition CarlaActor.h:431
virtual ECarlaServerResponse SetActorCollisions(bool bEnabled)
virtual ECarlaServerResponse SetWheelSuspensionOffset(const EVehicleWheelLocation &, float)
Definition CarlaActor.h:389
virtual ECarlaServerResponse GetVehicleTelemetryData(FVehicleTelemetryData &)
Definition CarlaActor.h:334
virtual ECarlaServerResponse CloseVehicleDoor(const EVehicleDoor)
Definition CarlaActor.h:354
virtual ECarlaServerResponse ApplyAckermannControlToVehicle(const FVehicleAckermannControl &, const EVehicleInputPriority &)
Definition CarlaActor.h:410
virtual ECarlaServerResponse GetWheelPitchAngle(const EVehicleWheelLocation &, float &)
Definition CarlaActor.h:384
void SetParent(IdType InParentId)
Definition CarlaActor.h:116
void SetAttachmentType(carla::rpc::AttachmentType InAttachmentType)
Definition CarlaActor.h:189
virtual ECarlaServerResponse SetWalkerState(const FTransform &Transform, carla::rpc::WalkerControl WalkerControl)
Definition CarlaActor.h:497
virtual ECarlaServerResponse DisableActorConstantVelocity()
Definition CarlaActor.h:314
ECarlaServerResponse GetActorComponentWorldTransform(const FString &ComponentName, FTransform &Transform) const
ECarlaServerResponse GetActorSocketWorldTransforms(TArray< FTransform > &Transforms) const
ECarlaServerResponse GetActorBoneNames(TArray< FString > &Names) const
ECarlaServerResponse GetActorSocketRelativeTransforms(TArray< FTransform > &Transforms) const
virtual ECarlaServerResponse GetVehicleLightState(FVehicleLightState &)
Definition CarlaActor.h:344
virtual ECarlaServerResponse SetBonesTransform(const FWalkerBoneControlIn &)
Definition CarlaActor.h:519
virtual ECarlaServerResponse FreezeTrafficLight(bool)
Definition CarlaActor.h:539
void SetActorGlobalTransform(const FTransform &Transform, ETeleportType Teleport=ETeleportType::TeleportPhysics)
virtual ECarlaServerResponse ApplyControlToWalker(const FWalkerControl &)
Definition CarlaActor.h:504
void SetActorState(carla::rpc::ActorState InState)
Definition CarlaActor.h:111
void SetActorGlobalLocation(const FVector &Location, ETeleportType Teleport=ETeleportType::TeleportPhysics)
virtual ECarlaServerResponse UseCarSimRoad(bool)
Definition CarlaActor.h:451
virtual ECarlaServerResponse ApplyPhysicsControl(const FVehiclePhysicsControl &)
Definition CarlaActor.h:359
virtual ECarlaServerResponse SetLightGreenTime(float)
Definition CarlaActor.h:479
void AddChildren(IdType ChildId)
Definition CarlaActor.h:126
ECarlaServerResponse GetActorComponentRelativeTransform(const FString &ComponentName, FTransform &Transform) const
virtual ECarlaServerResponse OpenVehicleDoor(const EVehicleDoor)
Definition CarlaActor.h:349
IdType GetActorId() const
Definition CarlaActor.h:81
virtual ECarlaServerResponse EnableActorConstantVelocity(const FVector &)
Definition CarlaActor.h:309
virtual ECarlaServerResponse SetWheelSteerDirection(const EVehicleWheelLocation &, float)
Definition CarlaActor.h:369
virtual ECarlaServerResponse EnableCarSim(const FString &)
Definition CarlaActor.h:446
ECarlaServerResponse SetActorTargetVelocity(const FVector &Velocity)
virtual ECarlaServerResponse SetWheelPitchAngle(const EVehicleWheelLocation &, float)
Definition CarlaActor.h:379
ECarlaServerResponse AddActorForce(const FVector &Force)
virtual ECarlaServerResponse BlendPose(float Blend)
Definition CarlaActor.h:524
virtual ECarlaServerResponse ShowVehicleDebugTelemetry(bool)
Definition CarlaActor.h:441
virtual ECarlaServerResponse SetActorSimulatePhysics(bool bEnabled)
virtual ECarlaServerResponse EnableChronoPhysics(uint64_t, float, const FString &, const FString &, const FString &, const FString &)
Definition CarlaActor.h:456
ECarlaServerResponse AddActorAngularImpulse(const FVector &AngularInpulse)
virtual ECarlaServerResponse SetTrafficLightState(const ETrafficLightState &)
Definition CarlaActor.h:464
virtual ECarlaServerResponse GetWheelSuspensionOffset(const EVehicleWheelLocation &, float &)
Definition CarlaActor.h:394
static uint64_t GetFrameCounter()
Definition CarlaEngine.h:73
carla::streaming::Stream BroadcastStream
carla::streaming::Server StreamingServer
std::atomic_bool bIsSecondaryServer
Set once, when the engine starts as a Multi-GPU secondary; read by RPC handlers, which may already be...
std::shared_ptr< carla::multigpu::Router > SecondaryServer
std::shared_ptr< carla::multigpu::Router > GetSecondaryServer()
UCarlaEpisode * Episode
carla::rpc::Server Server
std::atomic_size_t TickCuesReceived
FPimpl(uint16_t RPCPort, uint16_t StreamingPort, uint16_t SecondaryPort)
std::map< uint16_t, std::string > TrafficManagerInfo
Map of pairs < port , ip > with all the Traffic Managers active in the simulation.
bool TickCueReceived()
std::shared_ptr< carla::multigpu::Router > GetSecondaryServer()
void RunSome(uint32 Milliseconds)
TUniquePtr< FPimpl > Pimpl
Definition CarlaServer.h:60
carla::streaming::Server & GetStreamingServer()
FDataStream OpenStream() const
void NotifyEndEpisode()
void NotifyBeginEpisode(UCarlaEpisode &Episode)
void SetIsSecondaryServer(bool bIsSecondary)
A Multi-GPU secondary refuses every call that would change its world.
FDataMultiStream Start(uint16_t RPCPort, uint16_t StreamingPort, uint16_t SecondaryPort)
void AsyncRun(uint32 NumberOfWorkerThreads)
void Draw(const carla::rpc::DebugShape &Shape)
static TArray< uint8 > Load(FString MapName)
Return the Navigation Mesh Binary associated to MapName, or empty if the such file wasn't serialized.
constexpr ServerBinder(const char *name, carla::rpc::Server &srv, bool sync)
auto operator<<(FuncT func)
const char * _name
carla::rpc::Server & _server
static void GetTrafficLightBoundingBox(const ATrafficLightBase *TrafficLight, TArray< FBoundingBox > &OutBB, TArray< uint8 > &OutTag, uint8 InTagQueried=0xFF)
Mounts CARLA content packs (content-only Unreal plugins cooked as DLC against a base release,...
const TArray< FCarlaContentPack > & GetPacks() const
bool Unmount(const FString &Name, FString &OutError)
Unmount a pack by name.
static UCarlaContentPackManager * Get()
const FCarlaContentPack * FindPack(const FString &Name) const
bool Mount(const FString &Path, FString &OutError, const FCarlaContentPack **OutPack=nullptr)
Mount a pack.
A simulation episode.
auto GetId() const
Return the unique id of this episode.
carla::rpc::Actor SerializeActor(FCarlaActor *CarlaActor) const
Create a serializable object describing the actor.
void PutActorToSleep(carla::rpc::ActorId ActorId)
void SetPedestriansCrossFactor(float InCrossFactor)
Probability that a walker whose navigation starts after this call is a "crosser" (may traverse crossw...
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.
std::string StartRecorder(std::string name, bool AdditionalData, bool StopReplayer)
const FString & GetMapName() const
AWeather * GetWeather() const
void SetPedestriansSeed(uint32 InSeed)
Seed the RNG behind the crosser draw (and any future navigation randomness).
void ApplySettings(const FEpisodeSettings &Settings)
static bool WaitForPendingNavigationBuild(double TimeoutSeconds)
Return the name of the map loaded in this episode.
FString GetActorDescriptionFromStream(carla::streaming::detail::stream_id_type StreamId)
Get the description of the Carla actor (sensor) using specific stream id.
TPair< EActorSpawnResultStatus, FCarlaActor * > SpawnActorWithInfo(const FTransform &Transform, FActorDescription thisActorDescription, FCarlaActor::IdType DesiredId=0)
Spawns an actor based on ActorDescription at Transform.
const FEpisodeSettings & GetSettings() const
FCarlaActor * FindCarlaActorFromStream(carla::streaming::detail::stream_id_type StreamId)
Find the Carla actor (sensor) that owns the stream StreamId, or nullptr.
APawn * GetSpectatorPawn() const
void AddRosParentNames(FCarlaActor &Child)
ROS 2: registers the ros_name of each of Child's ancestors as one of its parent frames.
const FActorRegistry & GetActorRegistry() const
ACarlaRecorder * GetRecorder() const
bool DrawWalkerIsCrosser()
Draw once per walker at navigation start: crosser or not.
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.
bool DestroyActor(AActor *Actor)
The game instance contains elements that must be kept alive in between levels.
void SetMapLayer(int32 MapLayer)
std::vector< carla::rpc::LightState > GetLights(FString Client)
void SetLights(FString Client, std::vector< carla::rpc::LightState > LightsToSet, bool DiscardClient=false)
void SetDayNightCycle(const bool active)
static UCarlaNavigationSubsystem * Get(UWorld *World)
static UCarlaGameInstance * GetGameInstance(const UObject *WorldContextObject)
static ALargeMapManager * GetLargeMapManager(const UObject *WorldContextObject)
static TArray< FString > GetAllMapNames()
static ACarlaGameModeBase * GetGameMode(const UObject *WorldContextObject)
static FString GetSavedXODRPath(const FString &MapName)
Where a generated OpenDRIVE world stores its xodr: <ProjectSavedDir>/OpenDrive/<MapName>....
static FString GetXODR(const UWorld *World)
Return the OpenDrive XML associated to MapName, or empty if the file is not found.
static std::pair< bool, carla::rpc::LabelledPoint > ProjectPoint(FVector StartLocation, FVector Direction, float MaxDistance, UWorld *World)
Definition RayTracer.cpp:46
static std::vector< carla::rpc::LabelledPoint > CastRay(FVector StartLocation, FVector EndLocation, UWorld *World)
Definition RayTracer.cpp:15
static auto MakeOverload(FuncTs &&... fs)
Creates an "overloaded callable object" out of one or more callable objects, each callable object wil...
Definition Functional.h:27
static auto MakeRecursiveOverload(FuncTs &&... fs)
Definition Functional.h:33
Vector3D GetForwardVector() const
static std::shared_ptr< ROS2 > GetInstance()
Definition ROS2.h:61
Description of a CARLA content pack known to the server (see UCarlaContentPackManager).
std::vector< std::string > maps
Map names declared by the pack manifest (loadable with load_world).
std::string path
Absolute path of the pack directory on the server host.
std::string name
Pack name (== plugin name == mount point "/<name>/").
std::string base_release
Base release the pack was cooked against, e.g. "carla-0.10.2-Linux".
std::string version
Pack version from the manifest.
bool mounted
True while the pack is mounted in the running server.
An RPC server in which functions can be bind to run synchronously or asynchronously.
Definition rpc/Server.h:40
void BindSync(const std::string &name, FunctorT &&functor)
Definition rpc/Server.h:165
void BindAsync(const std::string &name, FunctorT &&functor)
Definition rpc/Server.h:173
A streaming server.
token_type GetToken(stream_id sensor_id)
bool IsEnabledForROS(stream_id sensor_id)
void EnableForROS(stream_id sensor_id)
void DisableForROS(stream_id sensor_id)
void SetSynchronousMode(bool is_synchro)
Token token() const
Token associated with this stream.
Serializes a stream endpoint.
constexpr size_t milliseconds() const noexcept
Definition Time.h:62
CARLA_API UTextureCube * CreateCubemapFromEquirect(const float *RGBA, int32 Width, int32 Height, int32 FaceSize=512)
Resamples the panorama into a transient 6-face HDR cubemap (PF_FloatRGBA, FaceSize x FaceSize per fac...
uint32_t ActorId
Definition ActorId.h:14
rpc::ActorId ActorId
Definition ActorId.h:18
void SetCloseOnExecForListeningPort(uint16_t Port)
Fallback for listening sockets we have no direct handle to (e.g.
Definition Sockets.h:60
static FString StatusToString(EActorSpawnResultStatus Status)
auto GetToken() const
Return the token that allows subscribing to this sensor's stream.
TArray< FCarlaContentPackMap > Maps
One map declared by a content pack manifest.
A content pack known to the manager (discovered or mounted explicitly).
FString ContentDir
Absolute path of the plugin content dir (<PackDir>/Content), the filesystem side of the "/<Name>/" mo...
const FString & GetName() const
FString PackDir
Absolute pack directory (contains carla-pack.json and <Name>.uplugin).
FCarlaContentPackManifest Manifest