Add game mode for new RPC server

This commit is contained in:
nsubiron 2018-07-23 16:42:26 +02:00
parent 5a8bb66c5d
commit 03c5ccc9d2
16 changed files with 388 additions and 279 deletions

View File

@ -6,10 +6,14 @@
#pragma once
#include "carla/Time.h"
#include <boost/asio/io_service.hpp>
#include <rpc/server.h>
#include <future>
namespace carla {
namespace rpc {
@ -94,10 +98,9 @@ namespace detail {
_server.async_run(worker_threads);
}
template <typename Duration>
void SyncRunFor(Duration duration) {
void SyncRunFor(time_duration duration) {
_sync_io_service.reset();
_sync_io_service.run_for(duration);
_sync_io_service.run_for(duration.to_chrono());
}
/// @warning does not stop the game thread.

View File

@ -13,7 +13,7 @@ AppliedDefaultGraphicsPerformance=Maximum
EditorStartupMap=/Game/Maps/Town01.Town01
GameDefaultMap=/Game/Maps/Town01.Town01
ServerDefaultMap=/Game/Maps/Town01.Town01
GlobalDefaultGameMode=/Game/Blueprints/Game/CarlaGameMode.CarlaGameMode_C
GlobalDefaultGameMode=/Script/Carla.TheNewCarlaGameModeBase
GameInstanceClass=/Script/Carla.CarlaGameInstance
TransitionMap=/Game/Maps/Town01.Town01

View File

@ -10,7 +10,7 @@
#include "Carla/Actor/ActorBlueprintFunctionLibrary.h"
#include "Carla/Actor/ActorSpawner.h"
void AActorDispatcher::Bind(FActorDefinition Definition, SpawnFunctionType Functor)
void FActorDispatcher::Bind(FActorDefinition Definition, SpawnFunctionType Functor)
{
if (UActorBlueprintFunctionLibrary::CheckActorDefinition(Definition))
{
@ -24,7 +24,7 @@ void AActorDispatcher::Bind(FActorDefinition Definition, SpawnFunctionType Funct
}
}
void AActorDispatcher::Bind(IActorSpawner &ActorSpawner)
void FActorDispatcher::Bind(IActorSpawner &ActorSpawner)
{
for (const auto &Definition : ActorSpawner.MakeDefinitions())
{
@ -34,7 +34,7 @@ void AActorDispatcher::Bind(IActorSpawner &ActorSpawner)
}
}
AActor *AActorDispatcher::SpawnActor(
AActor *FActorDispatcher::SpawnActor(
const FTransform &Transform,
const FActorDescription &Description)
{
@ -51,7 +51,7 @@ AActor *AActorDispatcher::SpawnActor(
return Actor;
}
void AActorDispatcher::DestroyActor(AActor *Actor)
void FActorDispatcher::DestroyActor(AActor *Actor)
{
if (Actor != nullptr)
{

View File

@ -11,20 +11,14 @@
#include "Carla/Actor/ActorRegistry.h"
#include "Containers/Array.h"
#include "GameFramework/Actor.h"
#include "Templates/Function.h"
#include "ActorDispatcher.generated.h"
class IActorSpawner;
/// Actor in charge of binding ActorDefinitions to spawn functions, as well as
/// keeping the registry of all the actors spawned.
UCLASS()
class CARLA_API AActorDispatcher : public AActor
class FActorDispatcher
{
GENERATED_BODY()
public:
using SpawnFunctionType = TFunction<AActor*(const FTransform &, const FActorDescription &)>;
@ -44,16 +38,13 @@ public:
/// despawn an actor created with this function call DestroyActor.
///
/// Return nullptr on failure.
UFUNCTION(BlueprintCallable)
AActor *SpawnActor(
const FTransform &Transform,
const FActorDescription &ActorDescription);
/// Destroys an actor, properly removing it from the registry.
UFUNCTION(BlueprintCallable)
void DestroyActor(AActor *Actor);
UFUNCTION(BlueprintCallable)
const TArray<FActorDefinition> &GetActorDefinitions() const
{
return Definitions;

View File

@ -14,12 +14,11 @@
#include "Engine/Engine.h"
#include "Kismet/GameplayStatics.h"
static FDataRouter &GetDataRouter(UWorld *World)
static FDataRouter *GetDataRouter(UWorld *World)
{
check(World != nullptr);
ACarlaGameModeBase *GameMode = Cast<ACarlaGameModeBase>(World->GetAuthGameMode());
check(GameMode != nullptr);
return GameMode->GetDataRouter();
return GameMode != nullptr ? &GameMode->GetDataRouter() : nullptr;
}
UAgentComponent::UAgentComponent(const FObjectInitializer& ObjectInitializer)
@ -43,14 +42,18 @@ void UAgentComponent::BeginPlay()
if (bRegisterAgentComponent)
{
/**
* This only returns true if the current game mode is not null
* This only returns true if the current game mode is not null
* because you can only access a game mode if you are the host
* @param oftheworld UWorld is needed to access the game mode
* @return true if there is a game mode and it is not null
*/
if(UGameplayStatics::GetGameMode(GetWorld())!=nullptr)
{
GetDataRouter(GetWorld()).RegisterAgent(this);
auto *DataRouter = GetDataRouter(GetWorld());
if (DataRouter != nullptr)
{
DataRouter->RegisterAgent(this);
}
} else
{
UCarlaGameInstance* GameInstance = Cast<UCarlaGameInstance>(UGameplayStatics::GetGameInstance(GetWorld()));
@ -64,15 +67,22 @@ void UAgentComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
if (bAgentComponentIsRegistered)
{
FDataRouter *DataRouter = nullptr;
if(UGameplayStatics::GetGameMode(GetWorld())!=nullptr)
{
GetDataRouter(GetWorld()).DeregisterAgent(this);
DataRouter = GetDataRouter(GetWorld());
}
else
{
UCarlaGameInstance* GameInstance = Cast<UCarlaGameInstance>(UGameplayStatics::GetGameInstance(GetWorld()));
if(GameInstance)
GameInstance->GetDataRouter().DeregisterAgent(this);
UCarlaGameInstance *GameInstance = Cast<UCarlaGameInstance>(UGameplayStatics::GetGameInstance(GetWorld()));
if(GameInstance)
{
DataRouter = &GameInstance->GetDataRouter();
}
}
if (DataRouter != nullptr)
{
DataRouter->DeregisterAgent(this);
}
bAgentComponentIsRegistered = false;
}

View File

@ -0,0 +1,77 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "Carla/Actor/ActorDispatcher.h"
#include "CarlaEpisode.generated.h"
/// A simulation episode.
///
/// Each time the level is restarted a new episode is created.
UCLASS(BlueprintType, Blueprintable)
class CARLA_API UCarlaEpisode : public UObject
{
GENERATED_BODY()
public:
void Initialize(const FString &InMapName)
{
MapName = InMapName;
}
UFUNCTION(BlueprintCallable)
const FString &GetMapName() const
{
return MapName;
}
void RegisterActorSpawner(IActorSpawner &ActorSpawner)
{
ActorDispatcher.Bind(ActorSpawner);
}
/// Return the list of actor definitions that are available to be spawned this
/// episode.
UFUNCTION(BlueprintCallable)
const TArray<FActorDefinition> &GetActorDefinitions() const
{
return ActorDispatcher.GetActorDefinitions();
}
/// Spawns an actor based on @a ActorDescription at @a Transform. To properly
/// despawn an actor created with this function call DestroyActor.
///
/// Return nullptr on failure.
UFUNCTION(BlueprintCallable)
AActor *SpawnActor(
const FTransform &Transform,
const FActorDescription &ActorDescription)
{
return ActorDispatcher.SpawnActor(Transform, ActorDescription);
}
/// Destroys an actor, properly removing it from the registry.
UFUNCTION(BlueprintCallable)
void DestroyActor(AActor *Actor)
{
ActorDispatcher.DestroyActor(Actor);
}
const FActorRegistry &GetActorRegistry() const
{
return ActorDispatcher.GetActorRegistry();
}
private:
UPROPERTY(VisibleAnywhere)
FString MapName;
FActorDispatcher ActorDispatcher;
};

View File

@ -11,6 +11,13 @@
#include "Server/ServerGameController.h"
#include "Settings/CarlaSettings.h"
#include <thread>
static uint32 GetNumberOfThreadsForRPCServer()
{
return std::max(std::thread::hardware_concurrency(), 4u) - 2u;
}
UCarlaGameInstance::UCarlaGameInstance() {
CarlaSettings = CreateDefaultSubobject<UCarlaSettings>(TEXT("CarlaSettings"));
check(CarlaSettings != nullptr);
@ -32,3 +39,19 @@ void UCarlaGameInstance::InitializeGameControllerIfNotPresent(
}
}
}
void UCarlaGameInstance::NotifyBeginEpisode(UCarlaEpisode &Episode)
{
if (!bServerIsRunning)
{
Server.Start(CarlaSettings->WorldPort);
Server.AsyncRun(GetNumberOfThreadsForRPCServer());
bServerIsRunning = true;
}
Server.NotifyBeginEpisode(Episode);
}
void UCarlaGameInstance::NotifyEndEpisode()
{
Server.NotifyEndEpisode();
}

View File

@ -8,8 +8,9 @@
#include "Engine/GameInstance.h"
#include "Game/CarlaGameControllerBase.h"
#include "Game/DataRouter.h"
#include "Carla/Game/CarlaGameControllerBase.h"
#include "Carla/Game/DataRouter.h"
#include "Carla/Server/TheNewCarlaServer.h"
#include "CarlaGameInstance.generated.h"
@ -62,12 +63,26 @@ public:
return DataRouter;
}
void NotifyBeginEpisode(UCarlaEpisode &Episode);
void Tick(float /*DeltaSeconds*/)
{
Server.RunSome(10u); /// @todo
}
void NotifyEndEpisode();
private:
UPROPERTY(VisibleAnywhere)
bool bServerIsRunning = false;
UPROPERTY(Category = "CARLA Settings", EditAnywhere)
UCarlaSettings *CarlaSettings;
UCarlaSettings *CarlaSettings = nullptr;
FDataRouter DataRouter;
TUniquePtr<ICarlaGameControllerBase> GameController;
FTheNewCarlaServer Server;
};

View File

@ -0,0 +1,81 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include "Carla.h"
#include "Carla/Game/TheNewCarlaGameModeBase.h"
ATheNewCarlaGameModeBase::ATheNewCarlaGameModeBase(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
PrimaryActorTick.bCanEverTick = true;
PrimaryActorTick.TickGroup = TG_PrePhysics;
bAllowTickBeforeBeginPlay = false;
Episode = CreateDefaultSubobject<UCarlaEpisode>(TEXT("Episode"));
}
void ATheNewCarlaGameModeBase::InitGame(
const FString &MapName,
const FString &Options,
FString &ErrorMessage)
{
Super::InitGame(MapName, Options, ErrorMessage);
check(Episode != nullptr);
Episode->Initialize(MapName);
GameInstance = Cast<UCarlaGameInstance>(GetGameInstance());
checkf(
GameInstance != nullptr,
TEXT("GameInstance is not a UCarlaGameInstance, did you forget to set it in the project settings?"));
SpawnActorSpawners();
}
void ATheNewCarlaGameModeBase::BeginPlay()
{
Super::BeginPlay();
GameInstance->NotifyBeginEpisode(*Episode);
}
void ATheNewCarlaGameModeBase::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
GameInstance->Tick(DeltaSeconds);
}
void ATheNewCarlaGameModeBase::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
GameInstance->NotifyEndEpisode();
Super::EndPlay(EndPlayReason);
}
void ATheNewCarlaGameModeBase::SpawnActorSpawners()
{
auto *World = GetWorld();
check(World != nullptr);
for (auto &SpawnerClass : BlueprintSpawners)
{
if (SpawnerClass != nullptr)
{
auto *Spawner = World->SpawnActor<AActorSpawnerBlueprintBase>(SpawnerClass);
if (Spawner != nullptr)
{
Episode->RegisterActorSpawner(*Spawner);
BlueprintSpawnerInstances.Add(Spawner);
}
else
{
UE_LOG(LogCarla, Error, TEXT("Failed to spawn actor spawner"));
}
}
}
}

View File

@ -0,0 +1,52 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "Carla/Actor/ActorSpawnerBlueprintBase.h"
#include "Carla/Game/CarlaEpisode.h"
#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "TheNewCarlaGameModeBase.generated.h"
/// Base class for the CARLA Game Mode.
UCLASS(HideCategories=(ActorTick))
class CARLA_API ATheNewCarlaGameModeBase : public AGameModeBase
{
GENERATED_BODY()
public:
ATheNewCarlaGameModeBase(const FObjectInitializer& ObjectInitializer);
protected:
void InitGame(const FString &MapName, const FString &Options, FString &ErrorMessage) override;
void BeginPlay() override;
void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
void Tick(float DeltaSeconds) override;
private:
void SpawnActorSpawners();
UPROPERTY()
UCarlaGameInstance *GameInstance = nullptr;
UPROPERTY()
UCarlaEpisode *Episode = nullptr;
UPROPERTY(EditAnywhere)
TArray<TSubclassOf<AActorSpawnerBlueprintBase>> BlueprintSpawners;
UPROPERTY()
TArray<AActorSpawnerBlueprintBase *> BlueprintSpawnerInstances;
};

View File

@ -1,90 +0,0 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include "Carla.h"
#include "Server.h"
#include <compiler/disable-ue4-macros.h>
#include <carla/Version.h>
#include <carla/rpc/Actor.h>
#include <carla/rpc/Server.h>
#include <carla/rpc/Transform.h>
#include <carla/rpc/VehicleControl.h>
#include <compiler/enable-ue4-macros.h>
static FVehicleControl MakeControl(const carla::rpc::VehicleControl &cControl)
{
FVehicleControl Control;
Control.Throttle = cControl.throttle;
Control.Steer = cControl.steer;
Control.Brake = cControl.brake;
Control.bHandBrake = cControl.hand_brake;
Control.bReverse = cControl.reverse;
return Control;
}
class FRPCServer::Pimpl
{
public:
Pimpl(uint16_t port) : Server(port) {}
carla::rpc::Server Server;
};
FRPCServer::FRPCServer() : _Pimpl(nullptr) {}
FRPCServer::~FRPCServer() {}
void FRPCServer::Initialize(AServer &Server, uint16_t Port)
{
UE_LOG(LogTemp, Error, TEXT("Initializing rpc-server at port %d"), Port);
_Pimpl = std::make_unique<Pimpl>(Port);
namespace cr = carla::rpc;
auto &srv = _Pimpl->Server;
srv.BindAsync("ping", []() { return true; });
srv.BindAsync("version", []() { return std::string(carla::version()); });
// srv.BindAsync("get_blueprints", []() {
// return std::vector<cr::ActorBlueprint>{
// cr::ActorBlueprint{"vehicle.mustang.red"},
// cr::ActorBlueprint{"vehicle.mustang.also_red"},
// cr::ActorBlueprint{"vehicle.mustang.still_red"}
// };
// });
// srv.BindSync("spawn_actor", [&](
// const cr::ActorBlueprint &blueprint,
// const cr::Transform &transform) {
// auto id = Server.SpawnAgent(transform);
// return cr::Actor{static_cast<cr::Actor::id_type>(id), blueprint};
// });
srv.BindSync("apply_control_to_actor", [&](
const cr::Actor &actor,
const cr::VehicleControl &control) {
Server.ApplyControl(actor.id, MakeControl(control));
});
}
void FRPCServer::Run()
{
_Pimpl->Server.AsyncRun(4);
}
void FRPCServer::RunSome()
{
using namespace std::chrono_literals;
_Pimpl->Server.SyncRunFor(20ms);
}
void FRPCServer::Stop()
{
_Pimpl->Server.Stop();
}

View File

@ -1,35 +0,0 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "CoreMinimal.h"
#include <memory>
class AServer;
class FRPCServer
{
public:
FRPCServer();
~FRPCServer();
void Initialize(AServer &Server, uint16_t Port = 8080u);
void Run();
void RunSome();
void Stop();
private:
class Pimpl;
std::unique_ptr<Pimpl> _Pimpl;
};

View File

@ -1,72 +0,0 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include "Carla.h"
#include "Server.h"
// Sets default values
AServer::AServer()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
// Called when the game starts or when spawned
void AServer::BeginPlay()
{
Super::BeginPlay();
_Server.Initialize(*this);
_Server.Run();
}
void AServer::EndPlay(EEndPlayReason::Type EndPlayReason)
{
_Server.Stop();
}
// Called every frame
void AServer::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
_Server.RunSome();
}
int32 AServer::SpawnAgent(const FTransform &Transform)
{
check(IsInGameThread());
UE_LOG(LogTemp, Warning, TEXT("Spawning vehicle at %s"), *Transform.ToString());
static int32 COUNT = 0u;
++COUNT;
ACarlaWheeledVehicle *Vehicle;
SpawnVehicle(Transform, Vehicle);
if ((Vehicle != nullptr) && !Vehicle->IsPendingKill())
{
// Vehicle->AIControllerClass = AWheeledVehicleAIController::StaticClass();
Vehicle->SpawnDefaultController();
_Agents.Add(COUNT, Vehicle);
return COUNT;
}
return -1;
}
bool AServer::ApplyControl(int32 AgentId, const FVehicleControl &Control)
{
UE_LOG(LogTemp, Log, TEXT("Applying control to vehicle %d: throttle = %f, steer = %f"), AgentId, Control.Throttle, Control.Steer);
if (!_Agents.Contains(AgentId))
{
UE_LOG(LogTemp, Error, TEXT("Vehicle %d does not exist!"), AgentId);
return false;
}
auto *Vehicle = _Agents[AgentId];
Vehicle->ApplyVehicleControl(Control);
return true;
}

View File

@ -1,52 +0,0 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "Vehicle/CarlaWheeledVehicle.h"
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "RPCServer.h"
#include "Vehicle/VehicleControl.h"
#include <future>
#include <mutex>
#include <queue>
#include "Server.generated.h"
UCLASS()
class CARLA_API AServer : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AServer();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
virtual void EndPlay(EEndPlayReason::Type EndPlayReason) override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
UFUNCTION(BlueprintCallable)
int32 SpawnAgent(const FTransform &Transform);
UFUNCTION(BlueprintCallable)
bool ApplyControl(int32 AgentId, const FVehicleControl &Control);
UFUNCTION(BlueprintImplementableEvent)
void SpawnVehicle(const FTransform &SpawnTransform, ACarlaWheeledVehicle *&SpawnedCharacter);
private:
FRPCServer _Server;
UPROPERTY(VisibleAnywhere)
TMap<uint32, ACarlaWheeledVehicle *> _Agents;
};

View File

@ -0,0 +1,69 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include "Carla.h"
#include "TheNewCarlaServer.h"
#include <compiler/disable-ue4-macros.h>
#include <carla/Version.h>
#include <carla/rpc/Server.h>
#include <compiler/enable-ue4-macros.h>
class FTheNewCarlaServer::FPimpl
{
public:
FPimpl(uint16_t port) : Server(port) {}
carla::rpc::Server Server;
UCarlaEpisode *CurrentEpisode = nullptr;
};
FTheNewCarlaServer::FTheNewCarlaServer() : Pimpl(nullptr) {}
FTheNewCarlaServer::~FTheNewCarlaServer() {}
void FTheNewCarlaServer::Start(uint16_t Port)
{
UE_LOG(LogCarlaServer, Log, TEXT("Initializing rpc-server at port %d"), Port);
Pimpl = MakeUnique<FPimpl>(Port);
namespace cr = carla::rpc;
auto &srv = Pimpl->Server;
srv.BindAsync("ping", []() { return true; });
srv.BindAsync("version", []() { return std::string(carla::version()); });
}
void FTheNewCarlaServer::NotifyBeginEpisode(UCarlaEpisode &Episode)
{
UE_LOG(LogCarlaServer, Log, TEXT("New episode '%s' started"), *Episode.GetMapName());
Pimpl->CurrentEpisode = &Episode;
}
void FTheNewCarlaServer::NotifyEndEpisode()
{
Pimpl->CurrentEpisode = nullptr;
}
void FTheNewCarlaServer::AsyncRun(uint32 NumberOfWorkerThreads)
{
Pimpl->Server.AsyncRun(NumberOfWorkerThreads);
}
void FTheNewCarlaServer::RunSome(uint32 Milliseconds)
{
Pimpl->Server.SyncRunFor(carla::time_duration::milliseconds(Milliseconds));
}
void FTheNewCarlaServer::Stop()
{
Pimpl->Server.Stop();
}

View File

@ -0,0 +1,37 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "CoreMinimal.h"
class UCarlaEpisode;
class FTheNewCarlaServer
{
public:
FTheNewCarlaServer();
~FTheNewCarlaServer();
void Start(uint16_t Port);
void NotifyBeginEpisode(UCarlaEpisode &Episode);
void NotifyEndEpisode();
void AsyncRun(uint32 NumberOfWorkerThreads);
void RunSome(uint32 Milliseconds);
void Stop();
private:
class FPimpl;
TUniquePtr<FPimpl> Pimpl;
};