Improvements to actor spawners
This commit is contained in:
parent
60d866d5b6
commit
8ae2770e1a
|
@ -23,7 +23,7 @@ namespace client {
|
||||||
SharedPtr<Actor> Client::SpawnActor(
|
SharedPtr<Actor> Client::SpawnActor(
|
||||||
const ActorBlueprint &blueprint,
|
const ActorBlueprint &blueprint,
|
||||||
const Transform &transform) {
|
const Transform &transform) {
|
||||||
auto actor = Call<carla::rpc::Actor>("spawn_actor", blueprint.MakeActorDescription(), transform);
|
auto actor = Call<carla::rpc::Actor>("spawn_actor", transform, blueprint.MakeActorDescription());
|
||||||
return SharedPtr<Actor>(new Actor{actor, GetWorld()});
|
return SharedPtr<Actor>(new Actor{actor, GetWorld()});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,11 +10,12 @@
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
void translator(rpc::rpc_error e) {
|
void translator(const rpc::rpc_error &e) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << e.what()
|
ss << e.what() << " in function " << e.get_function_name();
|
||||||
<< " in function " << e.get_function_name()
|
/// @todo Supposedly we can extract the error string here as provided by the
|
||||||
<< ": " << e.get_error().as<std::string>();
|
/// server with e.get_error().as<std::string>(), but it gives the wrong
|
||||||
|
/// string.
|
||||||
PyErr_SetString(PyExc_RuntimeError, ss.str().c_str());
|
PyErr_SetString(PyExc_RuntimeError, ss.str().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ struct CARLA_API FActorVariation
|
||||||
FString Id;
|
FString Id;
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||||
EActorAttributeType Type = EActorAttributeType::Int;
|
EActorAttributeType Type = EActorAttributeType::String;
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||||
TArray<FString> RecommendedValues;
|
TArray<FString> RecommendedValues;
|
||||||
|
@ -63,7 +63,7 @@ struct CARLA_API FActorAttribute
|
||||||
FString Id;
|
FString Id;
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||||
EActorAttributeType Type = EActorAttributeType::Int;
|
EActorAttributeType Type = EActorAttributeType::String;
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||||
FString Value;
|
FString Value;
|
||||||
|
|
|
@ -25,6 +25,13 @@ struct FActorDefinition
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||||
FString Id;
|
FString Id;
|
||||||
|
|
||||||
|
/// Class of the actor to be spawned (Optional).
|
||||||
|
///
|
||||||
|
/// Note that this parameter is not exposed on the client-side, only used by
|
||||||
|
/// the spawner itself.
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||||
|
TSubclassOf<AActor> Class;
|
||||||
|
|
||||||
/// A list of comma-separated tags.
|
/// A list of comma-separated tags.
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||||
FString Tags;
|
FString Tags;
|
||||||
|
|
|
@ -23,6 +23,10 @@ struct FActorDescription
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||||
FString Id;
|
FString Id;
|
||||||
|
|
||||||
|
/// Class of the actor to be spawned.
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||||
|
TSubclassOf<AActor> Class;
|
||||||
|
|
||||||
/// User selected variations of the actor. Note that at this point are
|
/// User selected variations of the actor. Note that at this point are
|
||||||
/// represented by non-modifiable attributes.
|
/// represented by non-modifiable attributes.
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||||
|
|
|
@ -17,6 +17,7 @@ void FActorDispatcher::Bind(FActorDefinition Definition, SpawnFunctionType Funct
|
||||||
Definition.UId = static_cast<uint32>(SpawnFunctions.Num()) + 1u;
|
Definition.UId = static_cast<uint32>(SpawnFunctions.Num()) + 1u;
|
||||||
Definitions.Emplace(Definition);
|
Definitions.Emplace(Definition);
|
||||||
SpawnFunctions.Emplace(Functor);
|
SpawnFunctions.Emplace(Functor);
|
||||||
|
Classes.Emplace(Definition.Class);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -24,7 +25,7 @@ void FActorDispatcher::Bind(FActorDefinition Definition, SpawnFunctionType Funct
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FActorDispatcher::Bind(IActorSpawner &ActorSpawner)
|
void FActorDispatcher::Bind(AActorSpawner &ActorSpawner)
|
||||||
{
|
{
|
||||||
for (const auto &Definition : ActorSpawner.MakeDefinitions())
|
for (const auto &Definition : ActorSpawner.MakeDefinitions())
|
||||||
{
|
{
|
||||||
|
@ -40,11 +41,30 @@ TPair<EActorSpawnResultStatus, FActorView> FActorDispatcher::SpawnActor(
|
||||||
{
|
{
|
||||||
if ((Description.UId == 0u) || (Description.UId > static_cast<uint32>(SpawnFunctions.Num())))
|
if ((Description.UId == 0u) || (Description.UId > static_cast<uint32>(SpawnFunctions.Num())))
|
||||||
{
|
{
|
||||||
UE_LOG(LogCarla, Error, TEXT("Invalid ActorDescription \"%s\" (UId=%d)"), *Description.Id, Description.UId);
|
UE_LOG(LogCarla, Error, TEXT("Invalid ActorDescription '%s' (UId=%d)"), *Description.Id, Description.UId);
|
||||||
return MakeTuple(EActorSpawnResultStatus::InvalidDescription, FActorView());
|
return MakeTuple(EActorSpawnResultStatus::InvalidDescription, FActorView());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UE_LOG(LogCarla, Log, TEXT("Spawning actor '%s'"), *Description.Id);
|
||||||
|
|
||||||
|
Description.Class = Classes[Description.UId - 1];
|
||||||
auto Result = SpawnFunctions[Description.UId - 1](Transform, Description);
|
auto Result = SpawnFunctions[Description.UId - 1](Transform, Description);
|
||||||
|
|
||||||
|
if ((Result.Status == EActorSpawnResultStatus::Success) && (Result.Actor == nullptr))
|
||||||
|
{
|
||||||
|
UE_LOG(LogCarla, Warning, TEXT("ActorSpawnResult: Trying to spawn '%s'"), *Description.Id);
|
||||||
|
UE_LOG(LogCarla, Warning, TEXT("ActorSpawnResult: Reported success but did not return an actor"));
|
||||||
|
Result.Status = EActorSpawnResultStatus::UnknownError;
|
||||||
|
}
|
||||||
|
|
||||||
auto View = Result.IsValid() ? Registry.Register(*Result.Actor, std::move(Description)) : FActorView();
|
auto View = Result.IsValid() ? Registry.Register(*Result.Actor, std::move(Description)) : FActorView();
|
||||||
|
|
||||||
|
if (!View.IsValid())
|
||||||
|
{
|
||||||
|
UE_LOG(LogCarla, Warning, TEXT("Failed to spawn actor '%s'"), *Description.Id);
|
||||||
|
check(Result.Status != EActorSpawnResultStatus::Success);
|
||||||
|
}
|
||||||
|
|
||||||
return MakeTuple(Result.Status, View);
|
return MakeTuple(Result.Status, View);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
#include "Containers/Array.h"
|
#include "Containers/Array.h"
|
||||||
#include "Templates/Function.h"
|
#include "Templates/Function.h"
|
||||||
|
|
||||||
class IActorSpawner;
|
class AActorSpawner;
|
||||||
|
|
||||||
/// Actor in charge of binding ActorDefinitions to spawn functions, as well as
|
/// Actor in charge of binding ActorDefinitions to spawn functions, as well as
|
||||||
/// keeping the registry of all the actors spawned.
|
/// keeping the registry of all the actors spawned.
|
||||||
|
@ -33,7 +33,7 @@ public:
|
||||||
/// Bind all the definitions of @a ActorSpawner to its spawn function.
|
/// Bind all the definitions of @a ActorSpawner to its spawn function.
|
||||||
///
|
///
|
||||||
/// @warning Invalid definitions are ignored.
|
/// @warning Invalid definitions are ignored.
|
||||||
void Bind(IActorSpawner &ActorSpawner);
|
void Bind(AActorSpawner &ActorSpawner);
|
||||||
|
|
||||||
/// Spawns an actor based on @a ActorDescription at @a Transform. To properly
|
/// Spawns an actor based on @a ActorDescription at @a Transform. To properly
|
||||||
/// despawn an actor created with this function call DestroyActor.
|
/// despawn an actor created with this function call DestroyActor.
|
||||||
|
@ -64,5 +64,7 @@ private:
|
||||||
|
|
||||||
TArray<SpawnFunctionType> SpawnFunctions;
|
TArray<SpawnFunctionType> SpawnFunctions;
|
||||||
|
|
||||||
|
TArray<TSubclassOf<AActor>> Classes;
|
||||||
|
|
||||||
FActorRegistry Registry;
|
FActorRegistry Registry;
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,7 +22,7 @@ FString FActorSpawnResult::StatusToString(EActorSpawnResultStatus InStatus)
|
||||||
case EActorSpawnResultStatus::InvalidDescription:
|
case EActorSpawnResultStatus::InvalidDescription:
|
||||||
return TEXT("Spawn failed because of invalid actor description");
|
return TEXT("Spawn failed because of invalid actor description");
|
||||||
case EActorSpawnResultStatus::Collision:
|
case EActorSpawnResultStatus::Collision:
|
||||||
return TEXT("Spawn failed because due to a collision at spawn position");
|
return TEXT("Spawn failed because of collision at spawn position");
|
||||||
case EActorSpawnResultStatus::UnknownError:
|
case EActorSpawnResultStatus::UnknownError:
|
||||||
default:
|
default:
|
||||||
return TEXT("Unknown error while trying to spawn actor");
|
return TEXT("Unknown error while trying to spawn actor");
|
||||||
|
|
|
@ -26,6 +26,14 @@ struct FActorSpawnResult
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
FActorSpawnResult() = default;
|
||||||
|
|
||||||
|
explicit FActorSpawnResult(AActor *InActor)
|
||||||
|
: Actor(InActor),
|
||||||
|
Status(Actor != nullptr ?
|
||||||
|
EActorSpawnResultStatus::Success :
|
||||||
|
EActorSpawnResultStatus::UnknownError) {}
|
||||||
|
|
||||||
static FString StatusToString(EActorSpawnResultStatus Status);
|
static FString StatusToString(EActorSpawnResultStatus Status);
|
||||||
|
|
||||||
bool IsValid() const
|
bool IsValid() const
|
||||||
|
|
|
@ -13,15 +13,27 @@
|
||||||
#include "Containers/Array.h"
|
#include "Containers/Array.h"
|
||||||
#include "GameFramework/Actor.h"
|
#include "GameFramework/Actor.h"
|
||||||
|
|
||||||
/// Interface for Carla actor spawners.
|
#include "ActorSpawner.generated.h"
|
||||||
class IActorSpawner
|
|
||||||
|
/// Base class for Carla actor spawners.
|
||||||
|
UCLASS(Abstract)
|
||||||
|
class CARLA_API AActorSpawner : public AActor
|
||||||
{
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual ~IActorSpawner() {}
|
AActorSpawner(const FObjectInitializer& ObjectInitializer)
|
||||||
|
: Super(ObjectInitializer)
|
||||||
|
{
|
||||||
|
PrimaryActorTick.bCanEverTick = false;
|
||||||
|
}
|
||||||
|
|
||||||
/// Retrieve the list of actor definitions that this class is able to spawn.
|
/// Retrieve the list of actor definitions that this class is able to spawn.
|
||||||
virtual TArray<FActorDefinition> MakeDefinitions() = 0;
|
virtual TArray<FActorDefinition> MakeDefinitions() {
|
||||||
|
unimplemented();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
/// Spawn an actor based on @a ActorDescription and @a Transform.
|
/// Spawn an actor based on @a ActorDescription and @a Transform.
|
||||||
///
|
///
|
||||||
|
@ -29,5 +41,8 @@ public:
|
||||||
/// definitions retrieved with MakeDefinitions.
|
/// definitions retrieved with MakeDefinitions.
|
||||||
virtual FActorSpawnResult SpawnActor(
|
virtual FActorSpawnResult SpawnActor(
|
||||||
const FTransform &SpawnAtTransform,
|
const FTransform &SpawnAtTransform,
|
||||||
const FActorDescription &ActorDescription) = 0;
|
const FActorDescription &ActorDescription) {
|
||||||
|
unimplemented();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,27 +9,27 @@
|
||||||
#include "Carla/Actor/ActorSpawner.h"
|
#include "Carla/Actor/ActorSpawner.h"
|
||||||
#include "Carla/Actor/ActorSpawnResult.h"
|
#include "Carla/Actor/ActorSpawnResult.h"
|
||||||
|
|
||||||
#include "ActorSpawnerBlueprintBase.generated.h"
|
#include "GameFramework/Actor.h"
|
||||||
|
|
||||||
/// Base class for Blueprints implementing IActorSpawner interface.
|
#include "ActorSpawnerBlueprint.generated.h"
|
||||||
|
|
||||||
|
/// Base class for Blueprints implementing AActorSpawner interface.
|
||||||
///
|
///
|
||||||
/// Blueprints deriving from this class are expected to override
|
/// Blueprints deriving from this class are expected to override
|
||||||
/// GenerateDefinitions and SpawnActor functions.
|
/// GenerateDefinitions and SpawnActor functions.
|
||||||
UCLASS(BlueprintType, Blueprintable)
|
UCLASS(Abstract, BlueprintType, Blueprintable)
|
||||||
class CARLA_API AActorSpawnerBlueprintBase
|
class CARLA_API AActorSpawnerBlueprint : public AActorSpawner
|
||||||
: public AActor,
|
|
||||||
public IActorSpawner
|
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual TArray<FActorDefinition> MakeDefinitions() final
|
TArray<FActorDefinition> MakeDefinitions() final
|
||||||
{
|
{
|
||||||
return GenerateDefinitions();
|
return GenerateDefinitions();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual FActorSpawnResult SpawnActor(
|
FActorSpawnResult SpawnActor(
|
||||||
const FTransform &SpawnAtTransform,
|
const FTransform &SpawnAtTransform,
|
||||||
const FActorDescription &ActorDescription) final
|
const FActorDescription &ActorDescription) final
|
||||||
{
|
{
|
|
@ -31,7 +31,7 @@ public:
|
||||||
return MapName;
|
return MapName;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegisterActorSpawner(IActorSpawner &ActorSpawner)
|
void RegisterActorSpawner(AActorSpawner &ActorSpawner)
|
||||||
{
|
{
|
||||||
ActorDispatcher.Bind(ActorSpawner);
|
ActorDispatcher.Bind(ActorSpawner);
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,15 +61,15 @@ void ATheNewCarlaGameModeBase::SpawnActorSpawners()
|
||||||
auto *World = GetWorld();
|
auto *World = GetWorld();
|
||||||
check(World != nullptr);
|
check(World != nullptr);
|
||||||
|
|
||||||
for (auto &SpawnerClass : BlueprintSpawners)
|
for (auto &SpawnerClass : ActorSpawners)
|
||||||
{
|
{
|
||||||
if (SpawnerClass != nullptr)
|
if (SpawnerClass != nullptr)
|
||||||
{
|
{
|
||||||
auto *Spawner = World->SpawnActor<AActorSpawnerBlueprintBase>(SpawnerClass);
|
auto *Spawner = World->SpawnActor<AActorSpawner>(SpawnerClass);
|
||||||
if (Spawner != nullptr)
|
if (Spawner != nullptr)
|
||||||
{
|
{
|
||||||
Episode->RegisterActorSpawner(*Spawner);
|
Episode->RegisterActorSpawner(*Spawner);
|
||||||
BlueprintSpawnerInstances.Add(Spawner);
|
ActorSpawnerInstances.Add(Spawner);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Carla/Actor/ActorSpawnerBlueprintBase.h"
|
#include "Carla/Actor/ActorSpawner.h"
|
||||||
#include "Carla/Game/CarlaEpisode.h"
|
#include "Carla/Game/CarlaEpisode.h"
|
||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
|
@ -44,9 +44,11 @@ private:
|
||||||
UPROPERTY()
|
UPROPERTY()
|
||||||
UCarlaEpisode *Episode = nullptr;
|
UCarlaEpisode *Episode = nullptr;
|
||||||
|
|
||||||
|
/// List of actor spawners that will be used to define and spawn the actors
|
||||||
|
/// available in game.
|
||||||
UPROPERTY(EditAnywhere)
|
UPROPERTY(EditAnywhere)
|
||||||
TArray<TSubclassOf<AActorSpawnerBlueprintBase>> BlueprintSpawners;
|
TSet<TSubclassOf<AActorSpawner>> ActorSpawners;
|
||||||
|
|
||||||
UPROPERTY()
|
UPROPERTY()
|
||||||
TArray<AActorSpawnerBlueprintBase *> BlueprintSpawnerInstances;
|
TArray<AActorSpawner *> ActorSpawnerInstances;
|
||||||
};
|
};
|
||||||
|
|
|
@ -28,6 +28,12 @@ static std::vector<T> MakeVectorFromTArray(const TArray<Other> &Array)
|
||||||
return {Array.GetData(), Array.GetData() + Array.Num()};
|
return {Array.GetData(), Array.GetData() + Array.Num()};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void AttachActors(AActor *Child, AActor *Parent)
|
||||||
|
{
|
||||||
|
Child->AttachToActor(Parent, FAttachmentTransformRules::KeepRelativeTransform);
|
||||||
|
Child->SetOwner(Parent);
|
||||||
|
}
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// -- FTheNewCarlaServer::FPimpl -----------------------------------------------
|
// -- FTheNewCarlaServer::FPimpl -----------------------------------------------
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
@ -64,6 +70,30 @@ private:
|
||||||
RespondErrorStr("episode not ready");
|
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())
|
||||||
|
{
|
||||||
|
RespondError("unable to attach actor: child actor not found");
|
||||||
|
}
|
||||||
|
if (!Parent.IsValid())
|
||||||
|
{
|
||||||
|
RespondError("unable to attach actor: parent actor not found");
|
||||||
|
}
|
||||||
|
::AttachActors(Child.GetActor(), Parent.GetActor());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
@ -87,12 +117,24 @@ void FTheNewCarlaServer::FPimpl::BindActions()
|
||||||
const cr::Transform &Transform,
|
const cr::Transform &Transform,
|
||||||
cr::ActorDescription Description) -> cr::Actor {
|
cr::ActorDescription Description) -> cr::Actor {
|
||||||
RequireEpisode();
|
RequireEpisode();
|
||||||
auto Result = Episode->SpawnActorWithInfo(Transform, std::move(Description));
|
return SpawnActor(Transform, Description);
|
||||||
if (Result.Key != EActorSpawnResultStatus::Success)
|
});
|
||||||
{
|
|
||||||
RespondError(FActorSpawnResult::StatusToString(Result.Key));
|
Server.BindSync("spawn_actor_with_parent", [this](
|
||||||
}
|
const cr::Transform &Transform,
|
||||||
return Result.Value;
|
cr::ActorDescription Description,
|
||||||
|
cr::Actor Parent) -> cr::Actor {
|
||||||
|
RequireEpisode();
|
||||||
|
auto ActorView = SpawnActor(Transform, Description);
|
||||||
|
auto ParentActorView = Episode->GetActorRegistry().Find(Parent.id);
|
||||||
|
AttachActors(ActorView, ParentActorView);
|
||||||
|
return ActorView;
|
||||||
|
});
|
||||||
|
|
||||||
|
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));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue