Add actor dispatcher

This commit is contained in:
nsubiron 2018-07-15 21:01:22 +02:00
parent a8ebcbd505
commit 2a8b8e2e4f
12 changed files with 293 additions and 77 deletions

View File

@ -16,17 +16,25 @@
class FActorDefinitionValidator {
public:
/// Iterate all actor definitions and properties and display messages on
/// Iterate all actor definitions and their properties and display messages on
/// error.
bool AreValid(const TArray<FActorDefinition> &ActorDefinitions)
{
return AreValid(TEXT("Actor Definition"), ActorDefinitions);
}
/// Validate @a ActorDefinition and display messages on error.
bool SingleIsValid(const FActorDefinition &Definition)
{
auto ScopeText = FString::Printf(TEXT("[Actor Definition : %s]"), *Definition.Id);
auto Scope = Stack.PushScope(ScopeText);
return IsValid(Definition);
}
private:
/// If @a Predicate is false, print an error message. If possible the message
/// is printed too in the editor window.
/// is printed to the editor window.
template <typename T, typename ... ARGS>
bool OnScreenAssert(bool Predicate, const T &Format, ARGS && ... Args) const
{
@ -141,6 +149,12 @@ private:
FScopedStack<FString> Stack;
};
bool UActorBlueprintFunctionLibrary::CheckActorDefinition(const FActorDefinition &ActorDefinition)
{
FActorDefinitionValidator Validator;
return Validator.SingleIsValid(ActorDefinition);
}
bool UActorBlueprintFunctionLibrary::CheckActorDefinitions(const TArray<FActorDefinition> &ActorDefinitions)
{
FActorDefinitionValidator Validator;

View File

@ -17,6 +17,12 @@ class UActorBlueprintFunctionLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
/// Return whether the actor definition is valid. Prints all the errors found.
UFUNCTION(Category = "Carla Actor", BlueprintCallable)
static bool CheckActorDefinition(const FActorDefinition &ActorDefinitions);
/// Return whether the list of actor definitions is valid. Prints all the
/// errors found.
UFUNCTION(Category = "Carla Actor", BlueprintCallable)

View File

@ -18,6 +18,9 @@ struct FActorDefinition
{
GENERATED_BODY()
/// Uniquely identifies the definition (no need to fill it).
uint32 UId = 0u;
/// Display ID that identifies the actor.
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FString Id;

View File

@ -16,6 +16,9 @@ struct FActorDescription
{
GENERATED_BODY()
/// Uniquely identifies the definition.
uint32 UId = 0u;
/// Display ID that identifies the actor.
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FString Id;

View File

@ -0,0 +1,61 @@
// 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/Actor/ActorDispatcher.h"
#include "Carla/Actor/ActorBlueprintFunctionLibrary.h"
#include "Carla/Actor/ActorSpawner.h"
void AActorDispatcher::Bind(FActorDefinition Definition, SpawnFunctionType Functor)
{
if (UActorBlueprintFunctionLibrary::CheckActorDefinition(Definition))
{
Definition.UId = static_cast<uint32>(SpawnFunctions.Num()) + 1u;
Definitions.Emplace(Definition);
SpawnFunctions.Emplace(Functor);
}
else
{
UE_LOG(LogCarla, Warning, TEXT("Invalid definition ignored"));
}
}
void AActorDispatcher::Bind(IActorSpawner &ActorSpawner)
{
for (const auto &Definition : ActorSpawner.MakeDefinitions())
{
Bind(Definition, [&](const FTransform &Transform, const FActorDescription &Description) {
return ActorSpawner.SpawnActor(Transform, Description);
});
}
}
AActor *AActorDispatcher::SpawnActor(
const FTransform &Transform,
const FActorDescription &Description)
{
if ((Description.UId == 0) || (Description.UId > SpawnFunctions.Num()))
{
UE_LOG(LogCarla, Error, TEXT("Invalid ActorDescription \"%s\" (UId=%d)"), *Description.Id, Description.UId);
return nullptr;
}
auto *Actor = SpawnFunctions[Description.UId](Transform, Description);
if (Actor != nullptr)
{
Registry.Register(*Actor);
}
return Actor;
}
void AActorDispatcher::DestroyActor(AActor *Actor)
{
if (Actor != nullptr)
{
Registry.Deregister(Actor);
Actor->Destroy();
}
}

View File

@ -0,0 +1,74 @@
// 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/ActorDefinition.h"
#include "Carla/Actor/ActorDescription.h"
#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
{
GENERATED_BODY()
public:
using SpawnFunctionType = TFunction<AActor*(const FTransform &, const FActorDescription &)>;
/// Bind a definition to a spawn function. When SpawnActor is called with a
/// matching description @a Functor is called.
///
/// @warning Invalid definitions are ignored.
void Bind(FActorDefinition Definition, SpawnFunctionType SpawnFunction);
/// Bind all the definitions of @a ActorSpawner to its spawn function.
///
/// @warning Invalid definitions are ignored.
void Bind(IActorSpawner &ActorSpawner);
/// 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);
/// Destroys an actor, properly removing it from the registry.
UFUNCTION(BlueprintCallable)
void DestroyActor(AActor *Actor);
UFUNCTION(BlueprintCallable)
const TArray<FActorDefinition> &GetActorDefinitions() const
{
return Definitions;
}
const FActorRegistry &GetActorRegistry() const
{
return Registry;
}
private:
TArray<FActorDefinition> Definitions;
TArray<SpawnFunctionType> SpawnFunctions;
FActorRegistry Registry;
};

View File

@ -9,21 +9,34 @@
#include "Carla.h"
#include "Carla/Actor/ActorRegistry.h"
FActorView UActorRegistry::Register(AActor &Actor)
FActorView FActorRegistry::Register(AActor &Actor)
{
static IdType ID_COUNTER = 0u;
auto Id = ++ID_COUNTER;
const auto Id = ++ID_COUNTER;
Actors.Emplace(Id, &Actor);
Ids.Emplace(&Actor, Id);
auto Result = ActorDatabase.emplace(Id, FActorView(Id, Actor));
check(Result.second);
check(static_cast<size_t>(Actors.Num()) == ActorDatabase.size());
check(static_cast<size_t>(Ids.Num()) == ActorDatabase.size());
return Result.first->second;
}
void UActorRegistry::Deregister(IdType Id)
void FActorRegistry::Deregister(IdType Id)
{
check(Contains(Id));
AActor *Actor = FindActor(Id);
check(Actor != nullptr);
ActorDatabase.erase(Id);
Actors.Remove(Id);
Ids.Remove(Actor);
check(static_cast<size_t>(Actors.Num()) == ActorDatabase.size());
check(static_cast<size_t>(Ids.Num()) == ActorDatabase.size());
}
void FActorRegistry::Deregister(AActor *Actor)
{
auto View = Find(Actor);
check(View.IsValid());
Deregister(View.GetActorId());
}

View File

@ -12,14 +12,9 @@
#include <unordered_map>
#include "ActorRegistry.generated.h"
/// A registry of all the Carla actors.
UCLASS(BlueprintType, Blueprintable)
class CARLA_API UActorRegistry : public UObject
class FActorRegistry
{
GENERATED_BODY()
private:
using DatabaseType = std::unordered_map<FActorView::IdType, FActorView>;
@ -42,42 +37,45 @@ public:
void Deregister(IdType Id);
void Deregister(AActor *Actor);
/// @}
// ===========================================================================
/// @name Look up functions
// ===========================================================================
/// @{
int32 Num() const
{
return Actors.Num();
}
bool IsEmpty() const
{
return ActorDatabase.empty();
}
bool Contains(uint32 Id) const
{
return ActorDatabase.find(Id) != ActorDatabase.end();
}
FActorView Find(IdType Id) const
{
auto it = ActorDatabase.find(Id);
return it != ActorDatabase.end() ? it->second : FActorView();
}
/// @}
// ===========================================================================
/// @name Blueprint support
// ===========================================================================
/// @{
public:
// UPROPERTY(BlueprintCallable)
int32 Num() const
FActorView Find(AActor *Actor) const
{
return Actors.Num();
auto PtrToId = Ids.Find(Actor);
return PtrToId != nullptr ? Find(*PtrToId) : FActorView();
}
// UPROPERTY(BlueprintCallable)
bool IsEmpty() const
{
return ActorDatabase.empty();
}
// UPROPERTY(BlueprintCallable)
bool Contains(IdType Id) const
{
return ActorDatabase.find(Id) != ActorDatabase.end();
}
// UPROPERTY(BlueprintCallable)
AActor *FindActor(IdType Id) const
{
auto PtrToPtr = Actors.Find(Id);
return PtrToPtr != nullptr ? *PtrToPtr : nullptr;
auto View = Find(Id);
return View.IsValid() ? View.GetActor() : nullptr;
}
/// @}
@ -105,12 +103,9 @@ public:
/// @}
private:
// Because UPROPERTY doesn't understand aliases...
static_assert(sizeof(IdType) == sizeof(uint32), "Id type missmatch!");
TMap<IdType, AActor *> Actors;
// This one makes sure actors are not garbage collected.
UPROPERTY(VisibleAnywhere)
TMap<uint32, AActor *> Actors;
TMap<AActor *, IdType> Ids;
DatabaseType ActorDatabase;
};

View File

@ -0,0 +1,32 @@
// 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/ActorDefinition.h"
#include "Carla/Actor/ActorDescription.h"
#include "Containers/Array.h"
#include "GameFramework/Actor.h"
/// Interface for Carla actor spawners.
class IActorSpawner
{
public:
virtual ~IActorSpawner() {}
/// Retrieve the list of actor definitions that this class is able to spawn.
virtual TArray<FActorDefinition> MakeDefinitions() = 0;
/// Spawn an actor based on @a ActorDescription and @a Transform.
///
/// @pre ActorDescription is expected to be derived from one of the
/// definitions retrieved with MakeDefinitions.
virtual AActor *SpawnActor(
const FTransform &SpawnAtTransform,
const FActorDescription &ActorDescription) = 0;
};

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 "Carla/Actor/ActorDefinition.h"
#include "Carla/Actor/ActorDescription.h"
#include "Containers/Array.h"
#include "GameFramework/Actor.h"
#include <algorithm>
#include "ActorSpawnerBase.generated.h"
/// Interface for the actor spawner. It is implemented in blueprints.
UCLASS(BlueprintType, Blueprintable)
class CARLA_API AActorSpawnerBase : public AActor
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintImplementableEvent)
TArray<FActorDefinition> GenerateDefinitions();
UFUNCTION(BlueprintImplementableEvent)
void SpawnActor(
const FTransform &SpawnAtTransform,
const FActorDescription &ActorDescription,
AActor *&Actor);
};

View File

@ -0,0 +1,50 @@
// 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/ActorSpawner.h"
#include "ActorSpawnerBlueprintBase.generated.h"
/// Base class for Blueprints implementing IActorSpawner interface.
///
/// Blueprints deriving from this class are expected to override
/// GenerateDefinitions and SpawnActor functions.
UCLASS(BlueprintType, Blueprintable)
class CARLA_API AActorSpawnerBlueprintBase
: public AActor,
public IActorSpawner
{
GENERATED_BODY()
public:
virtual TArray<FActorDefinition> MakeDefinitions() final
{
return GenerateDefinitions();
}
virtual AActor *SpawnActor(
const FTransform &SpawnAtTransform,
const FActorDescription &ActorDescription) final
{
AActor *Actor = nullptr;
SpawnActor(SpawnAtTransform, ActorDescription, Actor);
return Actor;
}
protected:
UFUNCTION(BlueprintImplementableEvent)
TArray<FActorDefinition> GenerateDefinitions();
UFUNCTION(BlueprintImplementableEvent)
void SpawnActor(
const FTransform &SpawnAtTransform,
const FActorDescription &ActorDescription,
AActor *&Actor);
};

View File

@ -40,7 +40,7 @@ public:
private:
friend class UActorRegistry;
friend class FActorRegistry;
FActorView(IdType ActorId, AActor &Actor)
: Id(ActorId),