Refactor the server to always return a Response object, move some functionality to UCarlaEpisode
This commit is contained in:
parent
7a21d8a061
commit
027362bb48
|
@ -55,12 +55,7 @@ namespace client {
|
|||
const ActorBlueprint &blueprint,
|
||||
const geom::Transform &transform,
|
||||
Actor *parent_actor) {
|
||||
try {
|
||||
return _episode.Lock()->SpawnActor(blueprint, transform, parent_actor);
|
||||
} catch (const std::exception &e) {
|
||||
log_warning("SpawnActor: failed with:", e.what());
|
||||
throw;
|
||||
}
|
||||
return _episode.Lock()->SpawnActor(blueprint, transform, parent_actor);
|
||||
}
|
||||
|
||||
SharedPtr<Actor> World::TrySpawnActor(
|
||||
|
@ -69,7 +64,7 @@ namespace client {
|
|||
Actor *parent_actor) noexcept {
|
||||
try {
|
||||
return SpawnActor(blueprint, transform, parent_actor);
|
||||
} catch (const std::exception &) {
|
||||
} catch (const std::exception &e) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "carla/rpc/ActorDescription.h"
|
||||
#include "carla/rpc/Client.h"
|
||||
#include "carla/rpc/DebugShape.h"
|
||||
#include "carla/rpc/Response.h"
|
||||
#include "carla/rpc/VehicleControl.h"
|
||||
#include "carla/rpc/WalkerControl.h"
|
||||
#include "carla/streaming/Client.h"
|
||||
|
@ -20,6 +21,15 @@ namespace carla {
|
|||
namespace client {
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
static T Get(carla::rpc::Response<T> &response) {
|
||||
return response.Get();
|
||||
}
|
||||
|
||||
static bool Get(carla::rpc::Response<void> &) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// -- Client::Pimpl ----------------------------------------------------------
|
||||
// ===========================================================================
|
||||
|
@ -35,8 +45,14 @@ namespace detail {
|
|||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
T CallAndWait(const std::string &function, Args &&... args) {
|
||||
return rpc_client.call(function, std::forward<Args>(args)...).template as<T>();
|
||||
auto CallAndWait(const std::string &function, Args &&... args) {
|
||||
auto object = rpc_client.call(function, std::forward<Args>(args)...);
|
||||
using R = typename carla::rpc::Response<T>;
|
||||
auto response = object.template as<R>();
|
||||
if (response.HasError()) {
|
||||
throw_exception(std::runtime_error(response.GetError().What()));
|
||||
}
|
||||
return Get(response);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
|
@ -121,7 +137,13 @@ namespace detail {
|
|||
}
|
||||
|
||||
bool Client::DestroyActor(const rpc::Actor &actor) {
|
||||
return _pimpl->CallAndWait<bool>("destroy_actor", actor);
|
||||
try {
|
||||
return _pimpl->CallAndWait<void>("destroy_actor", actor);
|
||||
} catch (const std::exception &e) {
|
||||
log_error("failed to destroy actor:", actor.id, actor.description.id);
|
||||
log_error(e.what());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Client::SetActorLocation(const rpc::Actor &actor, const geom::Location &location) {
|
||||
|
|
|
@ -15,22 +15,26 @@
|
|||
|
||||
static FActorView::ActorType FActorRegistry_GetActorType(const FActorView &View)
|
||||
{
|
||||
if (View.IsValid())
|
||||
if (!View.IsValid())
|
||||
{
|
||||
if (nullptr != Cast<ACarlaWheeledVehicle>(View.GetActor()))
|
||||
{
|
||||
return FActorView::ActorType::Vehicle;
|
||||
}
|
||||
else if (nullptr != Cast<ACharacter>(View.GetActor()))
|
||||
{
|
||||
return FActorView::ActorType::Walker;
|
||||
}
|
||||
else if (nullptr != Cast<ATrafficLightBase>(View.GetActor()))
|
||||
{
|
||||
return FActorView::ActorType::TrafficLight;
|
||||
}
|
||||
return FActorView::ActorType::INVALID;
|
||||
}
|
||||
else if (nullptr != Cast<ACarlaWheeledVehicle>(View.GetActor()))
|
||||
{
|
||||
return FActorView::ActorType::Vehicle;
|
||||
}
|
||||
else if (nullptr != Cast<ACharacter>(View.GetActor()))
|
||||
{
|
||||
return FActorView::ActorType::Walker;
|
||||
}
|
||||
else if (nullptr != Cast<ATrafficLightBase>(View.GetActor()))
|
||||
{
|
||||
return FActorView::ActorType::TrafficLight;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FActorView::ActorType::Other;
|
||||
}
|
||||
return FActorView::ActorType::Other;
|
||||
}
|
||||
|
||||
static FString GetRelevantTagAsString(const TSet<ECityObjectLabel> &SemanticTags)
|
||||
|
@ -73,7 +77,7 @@ FActorView FActorRegistry::Register(AActor &Actor, FActorDescription Description
|
|||
void FActorRegistry::Deregister(IdType Id)
|
||||
{
|
||||
check(Contains(Id));
|
||||
AActor *Actor = FindActor(Id);
|
||||
AActor *Actor = Find(Id).GetActor();
|
||||
check(Actor != nullptr);
|
||||
ActorDatabase.erase(Id);
|
||||
Actors.Remove(Id);
|
||||
|
@ -83,15 +87,17 @@ void FActorRegistry::Deregister(IdType Id)
|
|||
|
||||
void FActorRegistry::Deregister(AActor *Actor)
|
||||
{
|
||||
check(Actor != nullptr);
|
||||
auto View = Find(Actor);
|
||||
check(View.IsValid());
|
||||
check(View.GetActor() == Actor);
|
||||
Deregister(View.GetActorId());
|
||||
}
|
||||
|
||||
FActorView FActorRegistry::FindOrFake(AActor *Actor) const
|
||||
{
|
||||
auto View = Find(Actor);
|
||||
return View.IsValid() ? View : MakeView(0u, *Actor, FActorDescription{});
|
||||
const bool bFakeActor = (View.GetActor() == nullptr) && (Actor != nullptr);
|
||||
return bFakeActor ? MakeView(0u, *Actor, FActorDescription{}) : View;
|
||||
}
|
||||
|
||||
FActorView FActorRegistry::MakeView(
|
||||
|
|
|
@ -76,12 +76,6 @@ public:
|
|||
return PtrToId != nullptr ? Find(*PtrToId) : FActorView();
|
||||
}
|
||||
|
||||
AActor *FindActor(IdType Id) const
|
||||
{
|
||||
auto View = Find(Id);
|
||||
return View.IsValid() ? View.GetActor() : nullptr;
|
||||
}
|
||||
|
||||
/// If the actor is not found in the registry, create a fake actor view. The
|
||||
/// returned FActorView has some information about the @a Actor but will have
|
||||
/// an invalid id.
|
||||
|
|
|
@ -21,7 +21,8 @@ public:
|
|||
Other,
|
||||
Vehicle,
|
||||
Walker,
|
||||
TrafficLight
|
||||
TrafficLight,
|
||||
INVALID
|
||||
};
|
||||
|
||||
FActorView() = default;
|
||||
|
@ -30,7 +31,7 @@ public:
|
|||
|
||||
bool IsValid() const
|
||||
{
|
||||
return (TheActor != nullptr) && Info.IsValid();
|
||||
return (TheActor != nullptr) && !TheActor->IsPendingKill();
|
||||
}
|
||||
|
||||
IdType GetActorId() const
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include "Carla.h"
|
||||
#include "Carla/Game/CarlaEpisode.h"
|
||||
|
||||
#include "Carla/Sensor/Sensor.h"
|
||||
#include "Carla/Util/BoundingBoxCalculator.h"
|
||||
#include "Carla/Vehicle/VehicleSpawnPoint.h"
|
||||
|
||||
#include "EngineUtils.h"
|
||||
|
@ -38,7 +40,7 @@ UCarlaEpisode::UCarlaEpisode(const FObjectInitializer &ObjectInitializer)
|
|||
return ++COUNTER;
|
||||
}()) {}
|
||||
|
||||
TArray<FTransform> UCarlaEpisode::GetRecommendedStartTransforms() const
|
||||
TArray<FTransform> UCarlaEpisode::GetRecommendedSpawnPoints() const
|
||||
{
|
||||
TArray<FTransform> SpawnPoints;
|
||||
for (TActorIterator<AVehicleSpawnPoint> It(GetWorld()); It; ++It) {
|
||||
|
@ -47,22 +49,29 @@ TArray<FTransform> UCarlaEpisode::GetRecommendedStartTransforms() const
|
|||
return SpawnPoints;
|
||||
}
|
||||
|
||||
const AWorldObserver *UCarlaEpisode::StartWorldObserver(carla::streaming::MultiStream Stream)
|
||||
carla::rpc::Actor UCarlaEpisode::SerializeActor(FActorView ActorView) const
|
||||
{
|
||||
UE_LOG(LogCarla, Log, TEXT("Starting AWorldObserver sensor"));
|
||||
check(WorldObserver == nullptr);
|
||||
auto *World = GetWorld();
|
||||
check(World != nullptr);
|
||||
WorldObserver = World->SpawnActorDeferred<AWorldObserver>(
|
||||
AWorldObserver::StaticClass(),
|
||||
FTransform(),
|
||||
nullptr,
|
||||
nullptr,
|
||||
ESpawnActorCollisionHandlingMethod::AlwaysSpawn);
|
||||
WorldObserver->SetEpisode(*this);
|
||||
WorldObserver->SetStream(std::move(Stream));
|
||||
UGameplayStatics::FinishSpawningActor(WorldObserver, FTransform());
|
||||
return WorldObserver;
|
||||
carla::rpc::Actor Actor;
|
||||
if (ActorView.IsValid())
|
||||
{
|
||||
Actor = ActorView.GetActorInfo()->SerializedData;
|
||||
auto Parent = ActorView.GetActor()->GetOwner();
|
||||
if (Parent != nullptr)
|
||||
{
|
||||
Actor.parent_id = FindActor(Parent).GetActorId();
|
||||
}
|
||||
} else {
|
||||
UE_LOG(LogCarla, Warning, TEXT("Trying to serialize invalid actor"));
|
||||
}
|
||||
return Actor;
|
||||
}
|
||||
|
||||
void UCarlaEpisode::AttachActors(AActor *Child, AActor *Parent)
|
||||
{
|
||||
check(Child != nullptr);
|
||||
check(Parent != nullptr);
|
||||
Child->AttachToActor(Parent, FAttachmentTransformRules::KeepRelativeTransform);
|
||||
Child->SetOwner(Parent);
|
||||
}
|
||||
|
||||
void UCarlaEpisode::InitializeAtBeginPlay()
|
||||
|
|
|
@ -10,6 +10,12 @@
|
|||
#include "Carla/Sensor/WorldObserver.h"
|
||||
#include "Carla/Weather/Weather.h"
|
||||
|
||||
#include "GameFramework/Pawn.h"
|
||||
|
||||
#include <compiler/disable-ue4-macros.h>
|
||||
#include <carla/rpc/Actor.h>
|
||||
#include <compiler/enable-ue4-macros.h>
|
||||
|
||||
#include "CarlaEpisode.generated.h"
|
||||
|
||||
/// A simulation episode.
|
||||
|
@ -20,21 +26,51 @@ class CARLA_API UCarlaEpisode : public UObject
|
|||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
// ===========================================================================
|
||||
// -- Constructor ------------------------------------------------------------
|
||||
// ===========================================================================
|
||||
|
||||
public:
|
||||
|
||||
UCarlaEpisode(const FObjectInitializer &ObjectInitializer);
|
||||
|
||||
// ===========================================================================
|
||||
// -- Retrieve info about this episode ---------------------------------------
|
||||
// ===========================================================================
|
||||
|
||||
public:
|
||||
|
||||
/// Return the unique id of this episode.
|
||||
auto GetId() const
|
||||
{
|
||||
return Id;
|
||||
}
|
||||
|
||||
/// Return the name of the map loaded in this episode.
|
||||
UFUNCTION(BlueprintCallable)
|
||||
const FString &GetMapName() const
|
||||
{
|
||||
return MapName;
|
||||
}
|
||||
|
||||
/// Return the list of actor definitions that are available to be spawned this
|
||||
/// episode.
|
||||
UFUNCTION(BlueprintCallable)
|
||||
const TArray<FActorDefinition> &GetActorDefinitions() const
|
||||
{
|
||||
return ActorDispatcher.GetActorDefinitions();
|
||||
}
|
||||
|
||||
/// Return the list of recommended spawn points for vehicles.
|
||||
UFUNCTION(BlueprintCallable)
|
||||
TArray<FTransform> GetRecommendedSpawnPoints() const;
|
||||
|
||||
// ===========================================================================
|
||||
// -- Retrieve special actors ------------------------------------------------
|
||||
// ===========================================================================
|
||||
|
||||
public:
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
APawn *GetSpectatorPawn() const
|
||||
{
|
||||
|
@ -47,17 +83,55 @@ public:
|
|||
return Weather;
|
||||
}
|
||||
|
||||
/// Return the list of actor definitions that are available to be spawned this
|
||||
/// episode.
|
||||
UFUNCTION(BlueprintCallable)
|
||||
const TArray<FActorDefinition> &GetActorDefinitions() const
|
||||
const AWorldObserver *GetWorldObserver() const
|
||||
{
|
||||
return ActorDispatcher.GetActorDefinitions();
|
||||
return WorldObserver;
|
||||
}
|
||||
|
||||
/// Return the list of recommended start positions.
|
||||
UFUNCTION(BlueprintCallable)
|
||||
TArray<FTransform> GetRecommendedStartTransforms() const;
|
||||
const FActorRegistry &GetActorRegistry() const
|
||||
{
|
||||
return ActorDispatcher.GetActorRegistry();
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// -- Actor look up methods --------------------------------------------------
|
||||
// ===========================================================================
|
||||
|
||||
public:
|
||||
|
||||
/// Find a Carla actor by id.
|
||||
///
|
||||
/// If the actor is not found or is pending kill, the returned view is
|
||||
/// invalid.
|
||||
FActorView FindActor(FActorView::IdType ActorId) const
|
||||
{
|
||||
return ActorDispatcher.GetActorRegistry().Find(ActorId);
|
||||
}
|
||||
|
||||
/// Find the actor view of @a Actor.
|
||||
///
|
||||
/// If the actor is not found or is pending kill, the returned view is
|
||||
/// invalid.
|
||||
FActorView FindActor(AActor *Actor) const
|
||||
{
|
||||
return ActorDispatcher.GetActorRegistry().Find(Actor);
|
||||
}
|
||||
|
||||
/// Find the actor view of @a Actor. If the actor is not found, a "fake" view
|
||||
/// is returned emulating an existing Carla actor. Use this to return views
|
||||
/// over static actors present in the map.
|
||||
///
|
||||
/// If the actor is pending kill, the returned view is invalid.
|
||||
FActorView FindOrFakeActor(AActor *Actor) const
|
||||
{
|
||||
return ActorDispatcher.GetActorRegistry().FindOrFake(Actor);
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// -- Actor handling methods -------------------------------------------------
|
||||
// ===========================================================================
|
||||
|
||||
public:
|
||||
|
||||
/// Spawns an actor based on @a ActorDescription at @a Transform. To properly
|
||||
/// despawn an actor created with this function call DestroyActor.
|
||||
|
@ -86,6 +160,12 @@ public:
|
|||
return SpawnActorWithInfo(Transform, std::move(ActorDescription)).Value.GetActor();
|
||||
}
|
||||
|
||||
/// Attach @a Child to @a Parent.
|
||||
///
|
||||
/// @pre Actors cannot be null.
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void AttachActors(AActor *Child, AActor *Parent);
|
||||
|
||||
/// @copydoc FActorDispatcher::DestroyActor(AActor*)
|
||||
UFUNCTION(BlueprintCallable)
|
||||
bool DestroyActor(AActor *Actor)
|
||||
|
@ -93,17 +173,18 @@ public:
|
|||
return ActorDispatcher.DestroyActor(Actor);
|
||||
}
|
||||
|
||||
const FActorRegistry &GetActorRegistry() const
|
||||
{
|
||||
return ActorDispatcher.GetActorRegistry();
|
||||
}
|
||||
// ===========================================================================
|
||||
// -- Other methods ----------------------------------------------------------
|
||||
// ===========================================================================
|
||||
|
||||
const AWorldObserver *StartWorldObserver(carla::streaming::MultiStream Stream);
|
||||
public:
|
||||
|
||||
const AWorldObserver *GetWorldObserver() const
|
||||
{
|
||||
return WorldObserver;
|
||||
}
|
||||
/// Create a serializable object describing the actor.
|
||||
carla::rpc::Actor SerializeActor(FActorView ActorView) const;
|
||||
|
||||
// ===========================================================================
|
||||
// -- Private methods and members --------------------------------------------
|
||||
// ===========================================================================
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ UCarlaGameInstance::UCarlaGameInstance() {
|
|||
CarlaSettings->LogSettings();
|
||||
}
|
||||
|
||||
UCarlaGameInstance::~UCarlaGameInstance() {}
|
||||
UCarlaGameInstance::~UCarlaGameInstance() = default;
|
||||
|
||||
void UCarlaGameInstance::InitializeGameControllerIfNotPresent(
|
||||
const FMockGameControllerSettings &MockControllerSettings)
|
||||
|
@ -40,7 +40,7 @@ void UCarlaGameInstance::InitializeGameControllerIfNotPresent(
|
|||
}
|
||||
}
|
||||
|
||||
void UCarlaGameInstance::NotifyBeginEpisode(UCarlaEpisode &Episode)
|
||||
void UCarlaGameInstance::StartServer()
|
||||
{
|
||||
if (!bServerIsRunning)
|
||||
{
|
||||
|
@ -48,10 +48,4 @@ void UCarlaGameInstance::NotifyBeginEpisode(UCarlaEpisode &Episode)
|
|||
Server.AsyncRun(GetNumberOfThreadsForRPCServer());
|
||||
bServerIsRunning = true;
|
||||
}
|
||||
Server.NotifyBeginEpisode(Episode);
|
||||
}
|
||||
|
||||
void UCarlaGameInstance::NotifyEndEpisode()
|
||||
{
|
||||
Server.NotifyEndEpisode();
|
||||
}
|
||||
|
|
|
@ -33,6 +33,9 @@ public:
|
|||
void InitializeGameControllerIfNotPresent(
|
||||
const FMockGameControllerSettings &MockControllerSettings);
|
||||
|
||||
/// Starts the Carla server if not already running.
|
||||
void StartServer();
|
||||
|
||||
ICarlaGameControllerBase &GetGameController()
|
||||
{
|
||||
check(GameController != nullptr);
|
||||
|
@ -63,14 +66,20 @@ public:
|
|||
return DataRouter;
|
||||
}
|
||||
|
||||
void NotifyBeginEpisode(UCarlaEpisode &Episode);
|
||||
void NotifyBeginEpisode(UCarlaEpisode &Episode)
|
||||
{
|
||||
Server.NotifyBeginEpisode(Episode);
|
||||
}
|
||||
|
||||
void Tick(float /*DeltaSeconds*/)
|
||||
{
|
||||
Server.RunSome(10u); /// @todo
|
||||
}
|
||||
|
||||
void NotifyEndEpisode();
|
||||
void NotifyEndEpisode()
|
||||
{
|
||||
Server.NotifyEndEpisode();
|
||||
}
|
||||
|
||||
const FTheNewCarlaServer &GetServer() const
|
||||
{
|
||||
|
|
|
@ -75,6 +75,12 @@ void ATheNewCarlaGameModeBase::InitGame(
|
|||
UE_LOG(LogCarla, Error, TEXT("Missing weather class!"));
|
||||
}
|
||||
|
||||
GameInstance->StartServer();
|
||||
|
||||
Episode->WorldObserver = World->SpawnActor<AWorldObserver>();
|
||||
Episode->WorldObserver->SetEpisode(*Episode);
|
||||
Episode->WorldObserver->SetStream(GameInstance->GetServer().OpenMultiStream());
|
||||
|
||||
SpawnActorFactories();
|
||||
}
|
||||
|
||||
|
|
|
@ -50,13 +50,6 @@ void ACollisionSensor::BeginPlay()
|
|||
return;
|
||||
}
|
||||
Episode = &GameMode->GetCarlaEpisode();
|
||||
|
||||
GameInstance = Cast<UCarlaGameInstance>(GetGameInstance());
|
||||
if (GameMode == nullptr)
|
||||
{
|
||||
UE_LOG(LogCarla, Error, TEXT("ACollisionSensor: Game instance not compatible with this sensor"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ACollisionSensor::OnCollisionEvent(
|
||||
|
@ -65,16 +58,14 @@ void ACollisionSensor::OnCollisionEvent(
|
|||
FVector NormalImpulse,
|
||||
const FHitResult &Hit)
|
||||
{
|
||||
if ((Episode != nullptr) && (GameInstance != nullptr) && (Actor != nullptr) && (OtherActor != nullptr))
|
||||
if ((Episode != nullptr) && (Actor != nullptr) && (OtherActor != nullptr))
|
||||
{
|
||||
const auto &Registry = Episode->GetActorRegistry();
|
||||
const auto &Server = GameInstance->GetServer();
|
||||
constexpr float TO_METERS = 1e-2;
|
||||
NormalImpulse *= TO_METERS;
|
||||
GetDataStream().Send_GameThread(
|
||||
*this,
|
||||
Server.SerializeActor(Registry.FindOrFake(Actor)),
|
||||
Server.SerializeActor(Registry.FindOrFake(OtherActor)),
|
||||
Episode->SerializeActor(Episode->FindOrFakeActor(Actor)),
|
||||
Episode->SerializeActor(Episode->FindOrFakeActor(OtherActor)),
|
||||
carla::geom::Vector3D{NormalImpulse.X, NormalImpulse.Y, NormalImpulse.Z});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,4 @@ private:
|
|||
|
||||
UPROPERTY()
|
||||
const UCarlaEpisode *Episode = nullptr;
|
||||
|
||||
UPROPERTY()
|
||||
const UCarlaGameInstance *GameInstance = nullptr;
|
||||
};
|
||||
|
|
|
@ -32,6 +32,7 @@ public:
|
|||
Stream = std::move(InStream);
|
||||
}
|
||||
|
||||
/// Return the token that allows subscribing to this sensor's stream.
|
||||
auto GetToken() const
|
||||
{
|
||||
return Stream.GetToken();
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "Carla.h"
|
||||
#include "Carla/Sensor/SensorFactory.h"
|
||||
|
||||
#include "Carla/Game/CarlaGameInstance.h"
|
||||
#include "Carla/Sensor/Sensor.h"
|
||||
|
||||
#include <compiler/disable-ue4-macros.h>
|
||||
|
@ -109,6 +110,15 @@ FActorSpawnResult ASensorFactory::SpawnActor(
|
|||
UE_LOG(LogCarla, Error, TEXT("ASensorFactory: cannot spawn sensor into an empty world."));
|
||||
return {};
|
||||
}
|
||||
|
||||
UCarlaGameInstance *GameInstance = Cast<UCarlaGameInstance>(
|
||||
UGameplayStatics::GetGameInstance(World));
|
||||
if (GameInstance == nullptr)
|
||||
{
|
||||
UE_LOG(LogCarla, Error, TEXT("ASensorFactory: cannot spawn sensor, incompatible game instance."));
|
||||
return {};
|
||||
}
|
||||
|
||||
auto *Sensor = World->SpawnActorDeferred<ASensor>(
|
||||
Description.Class,
|
||||
Transform,
|
||||
|
@ -122,6 +132,7 @@ FActorSpawnResult ASensorFactory::SpawnActor(
|
|||
else
|
||||
{
|
||||
Sensor->Set(Description);
|
||||
Sensor->SetDataStream(GameInstance->GetServer().OpenStream());
|
||||
}
|
||||
UGameplayStatics::FinishSpawningActor(Sensor, Transform);
|
||||
return FActorSpawnResult{Sensor};
|
||||
|
|
|
@ -22,11 +22,12 @@ class CARLA_API AWorldObserver : public AActor
|
|||
|
||||
public:
|
||||
|
||||
/// Prevent this sensor to be spawned by users.
|
||||
using not_spawnable = void;
|
||||
|
||||
AWorldObserver(const FObjectInitializer& ObjectInitializer);
|
||||
|
||||
/// Set the episode that will observe.
|
||||
/// Set the episode that will be observed.
|
||||
void SetEpisode(UCarlaEpisode &InEpisode)
|
||||
{
|
||||
checkf(Episode == nullptr, TEXT("Cannot set episode twice!"));
|
||||
|
@ -34,18 +35,19 @@ public:
|
|||
}
|
||||
|
||||
/// Replace the Stream associated with this sensor.
|
||||
///
|
||||
/// @warning Do not change the stream after BeginPlay. It is not thread-safe.
|
||||
void SetStream(FDataMultiStream InStream)
|
||||
{
|
||||
Stream = std::move(InStream);
|
||||
}
|
||||
|
||||
auto GetStreamToken() const
|
||||
/// Return the token that allows subscribing to this sensor's stream.
|
||||
auto GetToken() const
|
||||
{
|
||||
return Stream.GetToken();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void Tick(float DeltaSeconds) final;
|
||||
|
||||
private:
|
||||
|
|
|
@ -7,15 +7,11 @@
|
|||
#include "Carla.h"
|
||||
#include "Carla/Server/TheNewCarlaServer.h"
|
||||
|
||||
#include "Carla/Sensor/Sensor.h"
|
||||
#include "Carla/Util/BoundingBoxCalculator.h"
|
||||
#include "Carla/Util/DebugShapeDrawer.h"
|
||||
#include "Carla/Util/OpenDrive.h"
|
||||
#include "Carla/Vehicle/CarlaWheeledVehicle.h"
|
||||
#include "Carla/Walker/WalkerController.h"
|
||||
|
||||
#include "GameFramework/SpectatorPawn.h"
|
||||
|
||||
#include <compiler/disable-ue4-macros.h>
|
||||
#include <carla/Version.h>
|
||||
#include <carla/rpc/Actor.h>
|
||||
|
@ -24,6 +20,7 @@
|
|||
#include <carla/rpc/DebugShape.h>
|
||||
#include <carla/rpc/EpisodeInfo.h>
|
||||
#include <carla/rpc/MapInfo.h>
|
||||
#include <carla/rpc/Response.h>
|
||||
#include <carla/rpc/Server.h>
|
||||
#include <carla/rpc/Transform.h>
|
||||
#include <carla/rpc/Vector3D.h>
|
||||
|
@ -35,6 +32,9 @@
|
|||
|
||||
#include <vector>
|
||||
|
||||
template <typename T>
|
||||
using R = carla::rpc::Response<T>;
|
||||
|
||||
// =============================================================================
|
||||
// -- Static local functions ---------------------------------------------------
|
||||
// =============================================================================
|
||||
|
@ -45,12 +45,6 @@ static std::vector<T> MakeVectorFromTArray(const TArray<Other> &Array)
|
|||
return {Array.GetData(), Array.GetData() + Array.Num()};
|
||||
}
|
||||
|
||||
static void AttachActors(AActor *Child, AActor *Parent)
|
||||
{
|
||||
Child->AttachToActor(Parent, FAttachmentTransformRules::KeepRelativeTransform);
|
||||
Child->SetOwner(Parent);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// -- FTheNewCarlaServer::FPimpl -----------------------------------------------
|
||||
// =============================================================================
|
||||
|
@ -74,178 +68,120 @@ public:
|
|||
private:
|
||||
|
||||
void BindActions();
|
||||
|
||||
void RespondErrorStr(const std::string &ErrorMessage) {
|
||||
UE_LOG(LogCarlaServer, Log, TEXT("Responding error, %s"), *carla::rpc::ToFString(ErrorMessage));
|
||||
carla::rpc::Server::RespondError(ErrorMessage);
|
||||
}
|
||||
|
||||
void RespondError(const FString &ErrorMessage) {
|
||||
RespondErrorStr(carla::rpc::FromFString(ErrorMessage));
|
||||
}
|
||||
|
||||
void RequireEpisode()
|
||||
{
|
||||
if (Episode == nullptr)
|
||||
{
|
||||
RespondErrorStr("episode not ready");
|
||||
}
|
||||
}
|
||||
|
||||
auto SpawnActor(const FTransform &Transform, FActorDescription Description)
|
||||
{
|
||||
auto Result = Episode->SpawnActorWithInfo(Transform, std::move(Description));
|
||||
if (Result.Key != EActorSpawnResultStatus::Success)
|
||||
{
|
||||
RespondError(FActorSpawnResult::StatusToString(Result.Key));
|
||||
}
|
||||
check(Result.Value.IsValid());
|
||||
return Result.Value;
|
||||
}
|
||||
|
||||
void AttachActors(FActorView Child, FActorView Parent)
|
||||
{
|
||||
if (!Child.IsValid())
|
||||
{
|
||||
RespondErrorStr("unable to attach actor: child actor not found");
|
||||
}
|
||||
if (!Parent.IsValid())
|
||||
{
|
||||
RespondErrorStr("unable to attach actor: parent actor not found");
|
||||
}
|
||||
::AttachActors(Child.GetActor(), Parent.GetActor());
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
carla::rpc::Actor SerializeActor(FActorView ActorView)
|
||||
{
|
||||
carla::rpc::Actor Actor;
|
||||
Actor.id = ActorView.GetActorId();
|
||||
if (ActorView.IsValid() && !ActorView.GetActor()->IsPendingKill())
|
||||
{
|
||||
Actor.parent_id = Episode->GetActorRegistry().Find(ActorView.GetActor()->GetOwner()).GetActorId();
|
||||
Actor.description = *ActorView.GetActorDescription();
|
||||
Actor.bounding_box = UBoundingBoxCalculator::GetActorBoundingBox(ActorView.GetActor());
|
||||
Actor.semantic_tags.reserve(ActorView.GetSemanticTags().Num());
|
||||
using tag_t = decltype(Actor.semantic_tags)::value_type;
|
||||
for (auto &&Tag : ActorView.GetSemanticTags())
|
||||
{
|
||||
Actor.semantic_tags.emplace_back(static_cast<tag_t>(Tag));
|
||||
}
|
||||
auto *Sensor = Cast<ASensor>(ActorView.GetActor());
|
||||
if (Sensor != nullptr)
|
||||
{
|
||||
auto Stream = GetSensorStream(ActorView, *Sensor);
|
||||
const auto &Token = Stream.token();
|
||||
Actor.stream_token = decltype(Actor.stream_token)(std::begin(Token.data), std::end(Token.data));
|
||||
}
|
||||
} else {
|
||||
UE_LOG(LogCarla, Warning, TEXT("Trying to serialize invalid actor"));
|
||||
}
|
||||
return Actor;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
carla::streaming::Stream GetSensorStream(FActorView ActorView, ASensor &Sensor) {
|
||||
auto id = ActorView.GetActorId();
|
||||
auto it = _StreamMap.find(id);
|
||||
if (it == _StreamMap.end()) {
|
||||
UE_LOG(LogCarlaServer, Log, TEXT("Making a new sensor stream for '%s'"), *ActorView.GetActorDescription()->Id);
|
||||
auto result = _StreamMap.emplace(id, StreamingServer.MakeStream());
|
||||
check(result.second);
|
||||
it = result.first;
|
||||
Sensor.SetDataStream(it->second);
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void ClearSensorStream(FActorView ActorView) {
|
||||
_StreamMap.erase(ActorView.GetActorId());
|
||||
}
|
||||
|
||||
std::unordered_map<FActorView::IdType, carla::streaming::Stream> _StreamMap;
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
// -- FTheNewCarlaServer::FPimpl Bind Actions ----------------------------------
|
||||
// -- Define helper macros -----------------------------------------------------
|
||||
// =============================================================================
|
||||
|
||||
#if WITH_EDITOR
|
||||
# define CARLA_ENSURE_GAME_THREAD() check(IsInGameThread());
|
||||
#else
|
||||
# define CARLA_ENSURE_GAME_THREAD()
|
||||
#endif // WITH_EDITOR
|
||||
|
||||
#define RESPOND_ERROR(str) { \
|
||||
UE_LOG(LogCarlaServer, Log, TEXT("Responding error: %s"), TEXT(str)); \
|
||||
return carla::rpc::ResponseError(str); }
|
||||
|
||||
#define RESPOND_ERROR_FSTRING(fstr) { \
|
||||
UE_LOG(LogCarlaServer, Log, TEXT("Responding error: %s"), *fstr); \
|
||||
return carla::rpc::ResponseError(carla::rpc::FromFString(fstr)); }
|
||||
|
||||
#define REQUIRE_CARLA_EPISODE() \
|
||||
CARLA_ENSURE_GAME_THREAD(); \
|
||||
if (Episode == nullptr) { RESPOND_ERROR("episode not ready"); }
|
||||
|
||||
// =============================================================================
|
||||
// -- Bind Actions -------------------------------------------------------------
|
||||
// =============================================================================
|
||||
|
||||
void FTheNewCarlaServer::FPimpl::BindActions()
|
||||
{
|
||||
namespace cr = carla::rpc;
|
||||
namespace cg = carla::geom;
|
||||
|
||||
Server.BindAsync("ping", []() { return true; });
|
||||
Server.BindAsync("version", []() -> R<std::string>
|
||||
{
|
||||
return carla::version();
|
||||
});
|
||||
|
||||
Server.BindAsync("version", []() -> std::string { return carla::version(); });
|
||||
|
||||
Server.BindSync("get_episode_info", [this]() -> cr::EpisodeInfo {
|
||||
RequireEpisode();
|
||||
Server.BindSync("get_episode_info", [this]() -> R<cr::EpisodeInfo>
|
||||
{
|
||||
REQUIRE_CARLA_EPISODE();
|
||||
auto WorldObserver = Episode->GetWorldObserver();
|
||||
if (WorldObserver == nullptr) {
|
||||
WorldObserver = Episode->StartWorldObserver(StreamingServer.MakeMultiStream());
|
||||
RESPOND_ERROR("internal error: missing world observer");
|
||||
}
|
||||
return {Episode->GetId(), cr::FromFString(Episode->GetMapName()), WorldObserver->GetStreamToken()};
|
||||
return cr::EpisodeInfo{
|
||||
Episode->GetId(),
|
||||
cr::FromFString(Episode->GetMapName()),
|
||||
WorldObserver->GetToken()};
|
||||
});
|
||||
|
||||
Server.BindSync("get_map_info", [this]() -> cr::MapInfo {
|
||||
RequireEpisode();
|
||||
Server.BindSync("get_map_info", [this]() -> R<cr::MapInfo>
|
||||
{
|
||||
REQUIRE_CARLA_EPISODE();
|
||||
auto FileContents = FOpenDrive::Load(Episode->GetMapName());
|
||||
const auto &SpawnPoints = Episode->GetRecommendedStartTransforms();
|
||||
std::vector<carla::geom::Transform> spawn_points;
|
||||
spawn_points.reserve(SpawnPoints.Num());
|
||||
for (const auto &Transform : SpawnPoints)
|
||||
{
|
||||
spawn_points.emplace_back(Transform);
|
||||
}
|
||||
return {
|
||||
const auto &SpawnPoints = Episode->GetRecommendedSpawnPoints();
|
||||
return cr::MapInfo{
|
||||
cr::FromFString(Episode->GetMapName()),
|
||||
cr::FromFString(FileContents),
|
||||
spawn_points};
|
||||
MakeVectorFromTArray<cg::Transform>(SpawnPoints)};
|
||||
});
|
||||
|
||||
Server.BindSync("get_actor_definitions", [this]() {
|
||||
RequireEpisode();
|
||||
Server.BindSync("get_actor_definitions", [this]() -> R<std::vector<cr::ActorDefinition>>
|
||||
{
|
||||
REQUIRE_CARLA_EPISODE();
|
||||
return MakeVectorFromTArray<cr::ActorDefinition>(Episode->GetActorDefinitions());
|
||||
});
|
||||
|
||||
Server.BindSync("get_spectator", [this]() -> cr::Actor {
|
||||
RequireEpisode();
|
||||
auto ActorView = Episode->GetActorRegistry().Find(Episode->GetSpectatorPawn());
|
||||
if (!ActorView.IsValid() || ActorView.GetActor()->IsPendingKill()) {
|
||||
RespondErrorStr("unable to find spectator");
|
||||
Server.BindSync("get_spectator", [this]() -> R<cr::Actor> {
|
||||
REQUIRE_CARLA_EPISODE();
|
||||
auto ActorView = Episode->FindActor(Episode->GetSpectatorPawn());
|
||||
if (!ActorView.IsValid())
|
||||
{
|
||||
RESPOND_ERROR("internal error: unable to find spectator");
|
||||
}
|
||||
return SerializeActor(ActorView);
|
||||
return Episode->SerializeActor(ActorView);
|
||||
});
|
||||
|
||||
Server.BindSync("get_weather_parameters", [this]() -> cr::WeatherParameters {
|
||||
RequireEpisode();
|
||||
Server.BindSync("get_weather_parameters", [this]() -> R<cr::WeatherParameters>
|
||||
{
|
||||
REQUIRE_CARLA_EPISODE();
|
||||
auto *Weather = Episode->GetWeather();
|
||||
if (Weather == nullptr) {
|
||||
RespondErrorStr("unable to find weather");
|
||||
if (Weather == nullptr)
|
||||
{
|
||||
RESPOND_ERROR("internal error: unable to find weather");
|
||||
}
|
||||
return Weather->GetCurrentWeather();
|
||||
});
|
||||
|
||||
Server.BindSync("set_weather_parameters", [this](const cr::WeatherParameters &weather) {
|
||||
RequireEpisode();
|
||||
Server.BindSync("set_weather_parameters", [this](
|
||||
const cr::WeatherParameters &weather) -> R<void>
|
||||
{
|
||||
REQUIRE_CARLA_EPISODE();
|
||||
auto *Weather = Episode->GetWeather();
|
||||
if (Weather == nullptr) {
|
||||
RespondErrorStr("unable to find weather");
|
||||
if (Weather == nullptr)
|
||||
{
|
||||
RESPOND_ERROR("internal error: unable to find weather");
|
||||
}
|
||||
Weather->ApplyWeather(weather);
|
||||
return R<void>::Success();
|
||||
});
|
||||
|
||||
Server.BindSync("get_actors_by_id", [this](const std::vector<FActorView::IdType> &ids) {
|
||||
RequireEpisode();
|
||||
Server.BindSync("get_actors_by_id", [this](
|
||||
const std::vector<FActorView::IdType> &ids) -> R<std::vector<cr::Actor>>
|
||||
{
|
||||
REQUIRE_CARLA_EPISODE();
|
||||
std::vector<cr::Actor> Result;
|
||||
Result.reserve(ids.size());
|
||||
const auto &Registry = Episode->GetActorRegistry();
|
||||
for (auto &&Id : ids) {
|
||||
auto View = Registry.Find(Id);
|
||||
if (View.IsValid()) {
|
||||
Result.emplace_back(SerializeActor(View));
|
||||
for (auto &&Id : ids)
|
||||
{
|
||||
auto View = Episode->FindActor(Id);
|
||||
if (View.IsValid())
|
||||
{
|
||||
Result.emplace_back(Episode->SerializeActor(View));
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
|
@ -253,237 +189,287 @@ void FTheNewCarlaServer::FPimpl::BindActions()
|
|||
|
||||
Server.BindSync("spawn_actor", [this](
|
||||
cr::ActorDescription Description,
|
||||
const cr::Transform &Transform) -> cr::Actor {
|
||||
RequireEpisode();
|
||||
return SerializeActor(SpawnActor(Transform, Description));
|
||||
const cr::Transform &Transform) -> R<cr::Actor>
|
||||
{
|
||||
REQUIRE_CARLA_EPISODE();
|
||||
auto Result = Episode->SpawnActorWithInfo(Transform, std::move(Description));
|
||||
if (Result.Key != EActorSpawnResultStatus::Success)
|
||||
{
|
||||
RESPOND_ERROR_FSTRING(FActorSpawnResult::StatusToString(Result.Key));
|
||||
}
|
||||
if (!Result.Value.IsValid())
|
||||
{
|
||||
RESPOND_ERROR("internal error: actor could not be spawned");
|
||||
}
|
||||
return Episode->SerializeActor(Result.Value);
|
||||
});
|
||||
|
||||
Server.BindSync("spawn_actor_with_parent", [this](
|
||||
cr::ActorDescription Description,
|
||||
const cr::Transform &Transform,
|
||||
cr::Actor Parent) -> cr::Actor {
|
||||
RequireEpisode();
|
||||
auto ActorView = SpawnActor(Transform, Description);
|
||||
auto ParentActorView = Episode->GetActorRegistry().Find(Parent.id);
|
||||
AttachActors(ActorView, ParentActorView);
|
||||
return SerializeActor(ActorView);
|
||||
cr::Actor Parent) -> R<cr::Actor>
|
||||
{
|
||||
REQUIRE_CARLA_EPISODE();
|
||||
auto Result = Episode->SpawnActorWithInfo(Transform, std::move(Description));
|
||||
if (Result.Key != EActorSpawnResultStatus::Success)
|
||||
{
|
||||
RESPOND_ERROR_FSTRING(FActorSpawnResult::StatusToString(Result.Key));
|
||||
}
|
||||
if (!Result.Value.IsValid())
|
||||
{
|
||||
RESPOND_ERROR("internal error: actor could not be spawned");
|
||||
}
|
||||
auto ParentActorView = Episode->FindActor(Parent.id);
|
||||
if (!ParentActorView.IsValid())
|
||||
{
|
||||
RESPOND_ERROR("unable to attach actor: parent actor not found");
|
||||
}
|
||||
Episode->AttachActors(Result.Value.GetActor(), ParentActorView.GetActor());
|
||||
return Episode->SerializeActor(Result.Value);
|
||||
});
|
||||
|
||||
Server.BindSync("destroy_actor", [this](cr::Actor Actor) {
|
||||
RequireEpisode();
|
||||
auto ActorView = Episode->GetActorRegistry().Find(Actor.id);
|
||||
if (!ActorView.IsValid()) {
|
||||
UE_LOG(LogCarlaServer, Warning, TEXT("unable to destroy actor: not found"));
|
||||
return false;
|
||||
Server.BindSync("destroy_actor", [this](cr::Actor Actor) -> R<void>
|
||||
{
|
||||
REQUIRE_CARLA_EPISODE();
|
||||
auto ActorView = Episode->FindActor(Actor.id);
|
||||
if (!ActorView.IsValid())
|
||||
{
|
||||
RESPOND_ERROR("unable to destroy actor: not found");
|
||||
}
|
||||
ClearSensorStream(ActorView);
|
||||
return Episode->DestroyActor(ActorView.GetActor());
|
||||
if (!Episode->DestroyActor(ActorView.GetActor()))
|
||||
{
|
||||
RESPOND_ERROR("internal error: unable to destroy actor");
|
||||
}
|
||||
return R<void>::Success();
|
||||
});
|
||||
|
||||
Server.BindSync("attach_actors", [this](cr::Actor Child, cr::Actor Parent) {
|
||||
RequireEpisode();
|
||||
auto &Registry = Episode->GetActorRegistry();
|
||||
AttachActors(Registry.Find(Child.id), Registry.Find(Parent.id));
|
||||
});
|
||||
|
||||
Server.BindSync("get_actor_location", [this](cr::Actor Actor) -> cr::Location {
|
||||
RequireEpisode();
|
||||
auto ActorView = Episode->GetActorRegistry().Find(Actor.id);
|
||||
if (!ActorView.IsValid() || ActorView.GetActor()->IsPendingKill()) {
|
||||
RespondErrorStr("unable to get actor location: actor not found");
|
||||
Server.BindSync("attach_actors", [this](
|
||||
cr::Actor Child,
|
||||
cr::Actor Parent) -> R<void>
|
||||
{
|
||||
REQUIRE_CARLA_EPISODE();
|
||||
auto ChildView = Episode->FindActor(Child.id);
|
||||
if (!ChildView.IsValid())
|
||||
{
|
||||
RESPOND_ERROR("unable to attach actor: child actor not found");
|
||||
}
|
||||
return {ActorView.GetActor()->GetActorLocation()};
|
||||
});
|
||||
|
||||
Server.BindSync("get_actor_transform", [this](cr::Actor Actor) -> cr::Transform {
|
||||
RequireEpisode();
|
||||
auto ActorView = Episode->GetActorRegistry().Find(Actor.id);
|
||||
if (!ActorView.IsValid() || ActorView.GetActor()->IsPendingKill()) {
|
||||
RespondErrorStr("unable to get actor transform: actor not found");
|
||||
auto ParentView = Episode->FindActor(Parent.id);
|
||||
if (!ParentView.IsValid())
|
||||
{
|
||||
RESPOND_ERROR("unable to attach actor: parent actor not found");
|
||||
}
|
||||
return {ActorView.GetActor()->GetActorTransform()};
|
||||
});
|
||||
|
||||
Server.BindSync("get_actor_velocity", [this](cr::Actor Actor) -> cr::Vector3D {
|
||||
RequireEpisode();
|
||||
auto ActorView = Episode->GetActorRegistry().Find(Actor.id);
|
||||
if (!ActorView.IsValid() || ActorView.GetActor()->IsPendingKill()) {
|
||||
RespondErrorStr("unable to get actor velocity: actor not found");
|
||||
}
|
||||
return cr::Vector3D(ActorView.GetActor()->GetRootComponent()->GetComponentVelocity()).ToMeters();
|
||||
});
|
||||
|
||||
Server.BindSync("get_actor_angular_velocity", [this](cr::Actor Actor) -> cr::Vector3D {
|
||||
RequireEpisode();
|
||||
auto ActorView = Episode->GetActorRegistry().Find(Actor.id);
|
||||
if (!ActorView.IsValid() || ActorView.GetActor()->IsPendingKill()) {
|
||||
RespondErrorStr("unable to get actor angular velocity: actor not found");
|
||||
}
|
||||
auto RootComponent = Cast<UPrimitiveComponent>(ActorView.GetActor()->GetRootComponent());
|
||||
if (RootComponent == nullptr) {
|
||||
RespondErrorStr("unable to get actor angular velocity: not supported by actor");
|
||||
}
|
||||
return cr::Vector3D(RootComponent->GetPhysicsAngularVelocityInDegrees());
|
||||
});
|
||||
|
||||
Server.BindSync("set_actor_angular_velocity", [this](
|
||||
cr::Actor Actor,
|
||||
cr::Vector3D vector) {
|
||||
RequireEpisode();
|
||||
auto ActorView = Episode->GetActorRegistry().Find(Actor.id);
|
||||
if (!ActorView.IsValid() || ActorView.GetActor()->IsPendingKill()) {
|
||||
RespondErrorStr("unable to set actor angular velocity: actor not found");
|
||||
}
|
||||
auto RootComponent = Cast<UPrimitiveComponent>(ActorView.GetActor()->GetRootComponent());
|
||||
if (RootComponent == nullptr) {
|
||||
RespondErrorStr("unable to set actor angular velocity: not supported by actor");
|
||||
}
|
||||
RootComponent->SetPhysicsAngularVelocityInDegrees(
|
||||
vector,
|
||||
false,
|
||||
"None");
|
||||
});
|
||||
|
||||
Server.BindSync("set_actor_velocity", [this](
|
||||
cr::Actor Actor,
|
||||
cr::Vector3D vector) {
|
||||
RequireEpisode();
|
||||
auto ActorView = Episode->GetActorRegistry().Find(Actor.id);
|
||||
if (!ActorView.IsValid() || ActorView.GetActor()->IsPendingKill()) {
|
||||
RespondErrorStr("unable to set actor velocity: actor not found");
|
||||
}
|
||||
auto RootComponent = Cast<UPrimitiveComponent>(ActorView.GetActor()->GetRootComponent());
|
||||
if (RootComponent == nullptr) {
|
||||
RespondErrorStr("unable to set actor velocity: not supported by actor");
|
||||
}
|
||||
RootComponent->SetPhysicsLinearVelocity(
|
||||
vector.ToCentimeters(),
|
||||
false,
|
||||
"None");
|
||||
});
|
||||
|
||||
Server.BindSync("add_actor_impulse", [this](
|
||||
cr::Actor Actor,
|
||||
cr::Vector3D vector) {
|
||||
RequireEpisode();
|
||||
auto ActorView = Episode->GetActorRegistry().Find(Actor.id);
|
||||
if (!ActorView.IsValid() || ActorView.GetActor()->IsPendingKill()) {
|
||||
RespondErrorStr("unable to add actor impulse: actor not found");
|
||||
}
|
||||
auto RootComponent = Cast<UPrimitiveComponent>(ActorView.GetActor()->GetRootComponent());
|
||||
if (RootComponent == nullptr) {
|
||||
RespondErrorStr("unable to add actor impulse: not supported by actor");
|
||||
}
|
||||
RootComponent->AddImpulse(
|
||||
vector.ToCentimeters(),
|
||||
"None",
|
||||
false);
|
||||
Episode->AttachActors(ChildView.GetActor(), ParentView.GetActor());
|
||||
return R<void>::Success();
|
||||
});
|
||||
|
||||
Server.BindSync("set_actor_location", [this](
|
||||
cr::Actor Actor,
|
||||
cr::Location Location) {
|
||||
RequireEpisode();
|
||||
auto ActorView = Episode->GetActorRegistry().Find(Actor.id);
|
||||
if (!ActorView.IsValid() || ActorView.GetActor()->IsPendingKill()) {
|
||||
RespondErrorStr("unable to set actor location: actor not found");
|
||||
cr::Location Location) -> R<void>
|
||||
{
|
||||
REQUIRE_CARLA_EPISODE();
|
||||
auto ActorView = Episode->FindActor(Actor.id);
|
||||
if (!ActorView.IsValid())
|
||||
{
|
||||
RESPOND_ERROR("unable to set actor location: actor not found");
|
||||
}
|
||||
// This function only works with teleport physics, to reset speeds we need
|
||||
// another method.
|
||||
/// @todo print error instead of returning false.
|
||||
ActorView.GetActor()->SetActorRelativeLocation(
|
||||
Location,
|
||||
false,
|
||||
nullptr,
|
||||
ETeleportType::TeleportPhysics);
|
||||
return R<void>::Success();
|
||||
});
|
||||
|
||||
Server.BindSync("set_actor_transform", [this](
|
||||
cr::Actor Actor,
|
||||
cr::Transform Transform) {
|
||||
RequireEpisode();
|
||||
auto ActorView = Episode->GetActorRegistry().Find(Actor.id);
|
||||
if (!ActorView.IsValid() || ActorView.GetActor()->IsPendingKill()) {
|
||||
RespondErrorStr("unable to set actor transform: actor not found");
|
||||
cr::Transform Transform) -> R<void>
|
||||
{
|
||||
REQUIRE_CARLA_EPISODE();
|
||||
auto ActorView = Episode->FindActor(Actor.id);
|
||||
if (!ActorView.IsValid())
|
||||
{
|
||||
RESPOND_ERROR("unable to set actor transform: actor not found");
|
||||
}
|
||||
// This function only works with teleport physics, to reset speeds we need
|
||||
// another method.
|
||||
ActorView.GetActor()->SetActorRelativeTransform(
|
||||
Transform,
|
||||
false,
|
||||
nullptr,
|
||||
ETeleportType::TeleportPhysics);
|
||||
return R<void>::Success();
|
||||
});
|
||||
|
||||
Server.BindSync("set_actor_simulate_physics", [this](cr::Actor Actor, bool bEnabled) {
|
||||
RequireEpisode();
|
||||
auto ActorView = Episode->GetActorRegistry().Find(Actor.id);
|
||||
if (!ActorView.IsValid() || ActorView.GetActor()->IsPendingKill()) {
|
||||
RespondErrorStr("unable to set actor simulate physics: actor not found");
|
||||
Server.BindSync("set_actor_velocity", [this](
|
||||
cr::Actor Actor,
|
||||
cr::Vector3D vector) -> R<void>
|
||||
{
|
||||
REQUIRE_CARLA_EPISODE();
|
||||
auto ActorView = Episode->FindActor(Actor.id);
|
||||
if (!ActorView.IsValid())
|
||||
{
|
||||
RESPOND_ERROR("unable to set actor velocity: actor not found");
|
||||
}
|
||||
auto RootComponent = Cast<UPrimitiveComponent>(ActorView.GetActor()->GetRootComponent());
|
||||
if (RootComponent == nullptr) {
|
||||
RespondErrorStr("unable to set actor simulate physics: not supported by actor");
|
||||
if (RootComponent == nullptr)
|
||||
{
|
||||
RESPOND_ERROR("unable to set actor velocity: not supported by actor");
|
||||
}
|
||||
RootComponent->SetPhysicsLinearVelocity(
|
||||
vector.ToCentimeters(),
|
||||
false,
|
||||
"None");
|
||||
return R<void>::Success();
|
||||
});
|
||||
|
||||
Server.BindSync("set_actor_angular_velocity", [this](
|
||||
cr::Actor Actor,
|
||||
cr::Vector3D vector) -> R<void>
|
||||
{
|
||||
REQUIRE_CARLA_EPISODE();
|
||||
auto ActorView = Episode->FindActor(Actor.id);
|
||||
if (!ActorView.IsValid())
|
||||
{
|
||||
RESPOND_ERROR("unable to set actor angular velocity: actor not found");
|
||||
}
|
||||
auto RootComponent = Cast<UPrimitiveComponent>(ActorView.GetActor()->GetRootComponent());
|
||||
if (RootComponent == nullptr)
|
||||
{
|
||||
RESPOND_ERROR("unable to set actor angular velocity: not supported by actor");
|
||||
}
|
||||
RootComponent->SetPhysicsAngularVelocityInDegrees(
|
||||
vector,
|
||||
false,
|
||||
"None");
|
||||
return R<void>::Success();
|
||||
});
|
||||
|
||||
Server.BindSync("add_actor_impulse", [this](
|
||||
cr::Actor Actor,
|
||||
cr::Vector3D vector) -> R<void>
|
||||
{
|
||||
REQUIRE_CARLA_EPISODE();
|
||||
auto ActorView = Episode->FindActor(Actor.id);
|
||||
if (!ActorView.IsValid())
|
||||
{
|
||||
RESPOND_ERROR("unable to add actor impulse: actor not found");
|
||||
}
|
||||
auto RootComponent = Cast<UPrimitiveComponent>(ActorView.GetActor()->GetRootComponent());
|
||||
if (RootComponent == nullptr)
|
||||
{
|
||||
RESPOND_ERROR("unable to add actor impulse: not supported by actor");
|
||||
}
|
||||
RootComponent->AddImpulse(
|
||||
vector.ToCentimeters(),
|
||||
"None",
|
||||
false);
|
||||
return R<void>::Success();
|
||||
});
|
||||
|
||||
Server.BindSync("set_actor_simulate_physics", [this](
|
||||
cr::Actor Actor,
|
||||
bool bEnabled) -> R<void>
|
||||
{
|
||||
REQUIRE_CARLA_EPISODE();
|
||||
auto ActorView = Episode->FindActor(Actor.id);
|
||||
if (!ActorView.IsValid())
|
||||
{
|
||||
RESPOND_ERROR("unable to set actor simulate physics: actor not found");
|
||||
}
|
||||
auto RootComponent = Cast<UPrimitiveComponent>(ActorView.GetActor()->GetRootComponent());
|
||||
if (RootComponent == nullptr)
|
||||
{
|
||||
RESPOND_ERROR("unable to set actor simulate physics: not supported by actor");
|
||||
}
|
||||
RootComponent->SetSimulatePhysics(bEnabled);
|
||||
return R<void>::Success();
|
||||
});
|
||||
|
||||
Server.BindSync("apply_control_to_vehicle", [this](cr::Actor Actor, cr::VehicleControl Control) {
|
||||
RequireEpisode();
|
||||
auto ActorView = Episode->GetActorRegistry().Find(Actor.id);
|
||||
if (!ActorView.IsValid() || ActorView.GetActor()->IsPendingKill()) {
|
||||
RespondErrorStr("unable to apply control: actor not found");
|
||||
Server.BindSync("apply_control_to_vehicle", [this](
|
||||
cr::Actor Actor,
|
||||
cr::VehicleControl Control) -> R<void>
|
||||
{
|
||||
REQUIRE_CARLA_EPISODE();
|
||||
auto ActorView = Episode->FindActor(Actor.id);
|
||||
if (!ActorView.IsValid())
|
||||
{
|
||||
RESPOND_ERROR("unable to apply control: actor not found");
|
||||
}
|
||||
auto Vehicle = Cast<ACarlaWheeledVehicle>(ActorView.GetActor());
|
||||
if (Vehicle == nullptr) {
|
||||
RespondErrorStr("unable to apply control: actor is not a vehicle");
|
||||
if (Vehicle == nullptr)
|
||||
{
|
||||
RESPOND_ERROR("unable to apply control: actor is not a vehicle");
|
||||
}
|
||||
Vehicle->ApplyVehicleControl(Control);
|
||||
return R<void>::Success();
|
||||
});
|
||||
|
||||
Server.BindSync("apply_control_to_walker", [this](cr::Actor Actor, cr::WalkerControl Control) {
|
||||
RequireEpisode();
|
||||
auto ActorView = Episode->GetActorRegistry().Find(Actor.id);
|
||||
if (!ActorView.IsValid() || ActorView.GetActor()->IsPendingKill()) {
|
||||
RespondErrorStr("unable to apply control: actor not found");
|
||||
Server.BindSync("apply_control_to_walker", [this](
|
||||
cr::Actor Actor,
|
||||
cr::WalkerControl Control) -> R<void>
|
||||
{
|
||||
REQUIRE_CARLA_EPISODE();
|
||||
auto ActorView = Episode->FindActor(Actor.id);
|
||||
if (!ActorView.IsValid())
|
||||
{
|
||||
RESPOND_ERROR("unable to apply control: actor not found");
|
||||
}
|
||||
auto Pawn = Cast<APawn>(ActorView.GetActor());
|
||||
if (Pawn == nullptr) {
|
||||
RespondErrorStr("unable to apply control: actor is not a walker");
|
||||
if (Pawn == nullptr)
|
||||
{
|
||||
RESPOND_ERROR("unable to apply control: actor is not a walker");
|
||||
}
|
||||
auto Controller = Cast<AWalkerController>(Pawn->GetController());
|
||||
if (Controller == nullptr) {
|
||||
RespondErrorStr("unable to apply control: walker has an incompatible controller");
|
||||
if (Controller == nullptr)
|
||||
{
|
||||
RESPOND_ERROR("unable to apply control: walker has an incompatible controller");
|
||||
}
|
||||
Controller->ApplyWalkerControl(Control);
|
||||
return R<void>::Success();
|
||||
});
|
||||
|
||||
Server.BindSync("set_actor_autopilot", [this](cr::Actor Actor, bool bEnabled) {
|
||||
RequireEpisode();
|
||||
auto ActorView = Episode->GetActorRegistry().Find(Actor.id);
|
||||
if (!ActorView.IsValid() || ActorView.GetActor()->IsPendingKill()) {
|
||||
RespondErrorStr("unable to set autopilot: actor not found");
|
||||
Server.BindSync("set_actor_autopilot", [this](
|
||||
cr::Actor Actor,
|
||||
bool bEnabled) -> R<void>
|
||||
{
|
||||
REQUIRE_CARLA_EPISODE();
|
||||
auto ActorView = Episode->FindActor(Actor.id);
|
||||
if (!ActorView.IsValid())
|
||||
{
|
||||
RESPOND_ERROR("unable to set autopilot: actor not found");
|
||||
}
|
||||
auto Vehicle = Cast<ACarlaWheeledVehicle>(ActorView.GetActor());
|
||||
if (Vehicle == nullptr) {
|
||||
RespondErrorStr("unable to set autopilot: actor is not a vehicle");
|
||||
if (Vehicle == nullptr)
|
||||
{
|
||||
RESPOND_ERROR("unable to set autopilot: actor does not support autopilot");
|
||||
}
|
||||
auto Controller = Cast<AWheeledVehicleAIController>(Vehicle->GetController());
|
||||
if (Controller == nullptr) {
|
||||
RespondErrorStr("unable to set autopilot: vehicle has an incompatible controller");
|
||||
if (Controller == nullptr)
|
||||
{
|
||||
RESPOND_ERROR("unable to set autopilot: vehicle controller does not support autopilot");
|
||||
}
|
||||
Controller->SetAutopilot(bEnabled);
|
||||
return R<void>::Success();
|
||||
});
|
||||
|
||||
Server.BindSync("draw_debug_shape", [this](const cr::DebugShape &shape) {
|
||||
RequireEpisode();
|
||||
Server.BindSync("draw_debug_shape", [this](const cr::DebugShape &shape) -> R<void>
|
||||
{
|
||||
REQUIRE_CARLA_EPISODE();
|
||||
auto *World = Episode->GetWorld();
|
||||
check(World != nullptr);
|
||||
FDebugShapeDrawer Drawer(*World);
|
||||
Drawer.Draw(shape);
|
||||
return R<void>::Success();
|
||||
});
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// -- Undef helper macros ------------------------------------------------------
|
||||
// =============================================================================
|
||||
|
||||
#undef REQUIRE_CARLA_EPISODE
|
||||
#undef RESPOND_ERROR_FSTRING
|
||||
#undef RESPOND_ERROR
|
||||
#undef CARLA_ENSURE_GAME_THREAD
|
||||
|
||||
// =============================================================================
|
||||
// -- FTheNewCarlaServer -------------------------------------------------------
|
||||
// =============================================================================
|
||||
|
@ -500,17 +486,20 @@ void FTheNewCarlaServer::Start(uint16_t Port)
|
|||
|
||||
void FTheNewCarlaServer::NotifyBeginEpisode(UCarlaEpisode &Episode)
|
||||
{
|
||||
check(Pimpl != nullptr);
|
||||
UE_LOG(LogCarlaServer, Log, TEXT("New episode '%s' started"), *Episode.GetMapName());
|
||||
Pimpl->Episode = &Episode;
|
||||
}
|
||||
|
||||
void FTheNewCarlaServer::NotifyEndEpisode()
|
||||
{
|
||||
check(Pimpl != nullptr);
|
||||
Pimpl->Episode = nullptr;
|
||||
}
|
||||
|
||||
void FTheNewCarlaServer::AsyncRun(uint32 NumberOfWorkerThreads)
|
||||
{
|
||||
check(Pimpl != nullptr);
|
||||
/// @todo Define better the number of threads each server gets.
|
||||
auto RPCThreads = NumberOfWorkerThreads / 2u;
|
||||
auto StreamingThreads = NumberOfWorkerThreads - RPCThreads;
|
||||
|
@ -525,10 +514,18 @@ void FTheNewCarlaServer::RunSome(uint32 Milliseconds)
|
|||
|
||||
void FTheNewCarlaServer::Stop()
|
||||
{
|
||||
check(Pimpl != nullptr);
|
||||
Pimpl->Server.Stop();
|
||||
}
|
||||
|
||||
carla::rpc::Actor FTheNewCarlaServer::SerializeActor(FActorView View) const
|
||||
FDataStream FTheNewCarlaServer::OpenStream() const
|
||||
{
|
||||
return Pimpl->SerializeActor(View);
|
||||
check(Pimpl != nullptr);
|
||||
return Pimpl->StreamingServer.MakeStream();
|
||||
}
|
||||
|
||||
FDataMultiStream FTheNewCarlaServer::OpenMultiStream() const
|
||||
{
|
||||
check(Pimpl != nullptr);
|
||||
return Pimpl->StreamingServer.MakeMultiStream();
|
||||
}
|
||||
|
|
|
@ -7,13 +7,10 @@
|
|||
#pragma once
|
||||
|
||||
#include "Carla/Actor/ActorView.h"
|
||||
#include "Carla/Sensor/DataStream.h"
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
#include <compiler/disable-ue4-macros.h>
|
||||
#include <carla/rpc/Actor.h>
|
||||
#include <compiler/enable-ue4-macros.h>
|
||||
|
||||
class UCarlaEpisode;
|
||||
|
||||
class FTheNewCarlaServer
|
||||
|
@ -36,8 +33,9 @@ public:
|
|||
|
||||
void Stop();
|
||||
|
||||
// This is necessary for serializing sensors properly.
|
||||
carla::rpc::Actor SerializeActor(FActorView View) const;
|
||||
FDataStream OpenStream() const;
|
||||
|
||||
FDataMultiStream OpenMultiStream() const;
|
||||
|
||||
private:
|
||||
|
||||
|
|
Loading…
Reference in New Issue