Add actor dispatcher
This commit is contained in:
parent
a8ebcbd505
commit
2a8b8e2e4f
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
};
|
|
@ -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);
|
||||
};
|
|
@ -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);
|
||||
};
|
|
@ -40,7 +40,7 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
friend class UActorRegistry;
|
||||
friend class FActorRegistry;
|
||||
|
||||
FActorView(IdType ActorId, AActor &Actor)
|
||||
: Id(ActorId),
|
||||
|
|
Loading…
Reference in New Issue