Skip to content

Commit

Permalink
implemented visitor pattern
Browse files Browse the repository at this point in the history
  • Loading branch information
jadebenn committed Jan 21, 2024
1 parent 50b7341 commit f97185e
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 31 deletions.
17 changes: 10 additions & 7 deletions dGame/dEntity/Archetype.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,15 @@ class Archetype final : public IArchetype {
/**
* Constructors and assignment operators
*/
Archetype(Archetype& other) noexcept : IArchetype{ std::copy(other) } { UpdatePointers(); } // Copy constructor
Archetype(Archetype&& other) noexcept : IArchetype{ std::move(other) } { UpdatePointers(); } // Move constructor
Archetype(Archetype& other) noexcept : IArchetype{ std::copy(other) } { /*UpdatePointers();*/ } // Copy constructor
Archetype(Archetype&& other) noexcept : IArchetype{ std::move(other) } { /*UpdatePointers();*/ } // Move constructor
Archetype& operator=(Archetype& other) noexcept { // Copy assignment operator
IArchetype::operator=(std::copy(other));
UpdatePointers();
/*UpdatePointers();*/
}
Archetype& operator=(Archetype&& other) noexcept { // Move assignment operator
IArchetype::operator=(std::move(other));
UpdatePointers();
/*UpdatePointers();*/
}

/**
Expand All @@ -104,7 +104,7 @@ class Archetype final : public IArchetype {
*/
template <ComponentType CType>
constexpr ContainerType<CType>& Container() noexcept {
static_assert(hasComponent<CType>, "Archetype does not have container of requested component!"); // Compile-time verification
static_assert(HasComponent<CType>(), "Archetype does not have container of requested component!"); // Compile-time verification

Check failure on line 107 in dGame/dEntity/Archetype.h

View workflow job for this annotation

GitHub Actions / Build & Test (macos-11)

static_assert failed due to requirement 'HasComponent<DestroyableComponent>()' "Archetype does not have container of requested component!"

Check failure on line 107 in dGame/dEntity/Archetype.h

View workflow job for this annotation

GitHub Actions / Build & Test (macos-11)

static_assert failed due to requirement 'HasComponent<DestroyableComponent>()' "Archetype does not have container of requested component!"
return std::get<ContainerType<CType>>(m_Components);
}

Expand Down Expand Up @@ -136,10 +136,13 @@ class Archetype final : public IArchetype {
}

/**
* Function-like static bool that "returns" if an archetype contains a specified component
* Static function that returns if an archetype contains a specified component
* @returns Boolean representing component's presence
*/
template <ComponentType CType>
static constexpr bool hasComponent = std::disjunction_v<std::is_same<CType, CTypes>...>;
static constexpr bool HasComponent() {
return std::disjunction_v<std::is_same<CType, CTypes>...>;
}

/**
* Contains the number of component types an archetype consists of
Expand Down
57 changes: 38 additions & 19 deletions dGame/dEntity/EntitySystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,31 @@
#include <variant>

#include "Archetype.h"
#include "CharacterComponent.h" // TEMP
#include "DestroyableComponent.h" // TEMP
#include "SimplePhysicsComponent.h" // TEMP
#include "dCommonVars.h"
#include "ObjectIDManager.h"

/**
* Archetype visitor struct (for use with std::visit)
*/
/*struct ArchetypeVisitor {
auto& operator()(auto& archetype) { return archetype->*hasComponent<CType>(); }
};*/
namespace {
/**
* Archetype visitor structs (for use with std::visit)
*/
template <ComponentType CType>
struct ComponentVisitor {
const size_t index;

explicit ComponentVisitor(const size_t index) noexcept : index{ index } {}

CType* const operator()(auto&& archetype) { // There might be a way to use this to do compile-time checking...
if constexpr (archetype->template HasComponent<CType>()) {

Check failure on line 29 in dGame/dEntity/EntitySystem.h

View workflow job for this annotation

GitHub Actions / Build & Test (macos-11)

constexpr if condition is not a constant expression

Check failure on line 29 in dGame/dEntity/EntitySystem.h

View workflow job for this annotation

GitHub Actions / Build & Test (macos-11)

constexpr if condition is not a constant expression

Check failure on line 29 in dGame/dEntity/EntitySystem.h

View workflow job for this annotation

GitHub Actions / Build & Test (macos-11)

constexpr if condition is not a constant expression

Check failure on line 29 in dGame/dEntity/EntitySystem.h

View workflow job for this annotation

GitHub Actions / Build & Test (macos-11)

constexpr if condition is not a constant expression

Check failure on line 29 in dGame/dEntity/EntitySystem.h

View workflow job for this annotation

GitHub Actions / Build & Test (macos-11)

constexpr if condition is not a constant expression
return &archetype->template Container<CType>()[index];
} else {
return nullptr;
}
}
};
}

/**
* TODO: Class documentation
Expand All @@ -32,9 +46,14 @@ class EntitySystem final {
using ArchetypeId = uint32_t;
using ArchetypeSet = std::unordered_set<ArchetypeId>;
using ArchetypeVariantPtr = std::variant<
Archetype<CharacterComponent>*,
Archetype<DestroyableComponent>*,
Archetype<SimplePhysicsComponent>*,
Archetype<DestroyableComponent, SimplePhysicsComponent>*

Archetype<CharacterComponent, DestroyableComponent>*,
Archetype<DestroyableComponent, SimplePhysicsComponent>*,

Archetype<CharacterComponent, DestroyableComponent, SimplePhysicsComponent>*
>; // TODO: Figure out how to generate this automatically
using ComponentTypeId = std::type_index;

Expand Down Expand Up @@ -79,7 +98,7 @@ class EntitySystem final {

/**
* Determine if an entity is associated with an Object ID
*
*
*/
bool EntityExists(const LWOOBJID entityId) noexcept {
return m_EntityIndex.count(entityId) != 0;
Expand All @@ -92,9 +111,11 @@ class EntitySystem final {
*/
template <ComponentType CType>
bool HasComponent(const LWOOBJID entityId) {
IArchetype* const archetype = m_EntityIndex[entityId].archetype; // Gets a pointer to the archetype containing the entity ID
ArchetypeSet& archetypeSet = m_ComponentTypeIndex[std::type_index(typeid(CType))]; // Gets the component container corresponding to the selected component type
return archetypeSet.count(archetype->id) != 0; // Check that the component exists within there
const auto& archetypeRecord = m_EntityIndex[entityId];

return std::visit(
[](auto&& archetype) { return archetype->template HasComponent<CType>(); },
archetypeRecord.archetypePtr); // Using visitor pattern
}

/**
Expand All @@ -103,12 +124,12 @@ class EntitySystem final {
* @returns The pointer if the component exists, or nullptr if it does not
*/
template <ComponentType CType>
CType* GetComponent(const LWOOBJID entityId) {
if (!HasComponent<CType>(entityId)) return nullptr;
CType* const GetComponent(const LWOOBJID entityId) {
const auto& archetypeRecord = m_EntityIndex[entityId];

auto& archetypeRecord = m_EntityIndex[entityId];
IArchetype* const archetype = archetypeRecord.archetype;
return &archetype->Container<CType>()[archetypeRecord.index];
return std::visit(
ComponentVisitor<CType>{ archetypeRecord.index },
archetypeRecord.archetypePtr); // Using visitor pattern
}

protected:
Expand Down Expand Up @@ -137,9 +158,7 @@ class EntitySystem final {
ArchetypeId m_CurrentArchetypeId{ 0 };

struct ArchetypeRecord {
IArchetype* archetype; // Could we potentially make this std::variant in order to deduce the type?
//ArchetypeVariantPtr archetype;
//size_t type = archetype.index();
ArchetypeVariantPtr archetypePtr;
size_t index;
};

Expand Down
11 changes: 6 additions & 5 deletions tests/dGameTests/dEntitiesTests/ArchetypeTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,19 +93,20 @@ TEST_F(ArchetypeTest, ArchetypeDeleteTest) {
//Deleting more entries than exist will cause a segfault currently. Wonder if that's actually an issue...
}

TEST_F(ArchetypeTest, ReadFromArchetypeTest) {
auto& simplePhysicsContainer = baseArchetype->Container<SimplePhysicsComponent>();
auto& destroyableContainer = baseArchetype->Container<DestroyableComponent>();
/*TEST_F(ArchetypeTest, ReadFromArchetypeTest) {
//auto& simplePhysicsContainer = baseArchetype->Container<SimplePhysicsComponent>();
//auto& destroyableContainer = baseArchetype->Container<DestroyableComponent>();
auto entitySystem = std::make_unique<EntitySystem>();
std::vector<std::unique_ptr<Entity>> tempEntity; // Vector of temporary entities (so they die when this test goes out of scope)
LOG("Number of entries per vector: %d", 1000); //simplePhysicsContainer.capacity()
LOG("Number of entries per vector: %d", 1000);
srand(time(NULL));
for (auto i = 0; i < 1000; ++i) {
tempEntity.emplace_back(std::make_unique<Entity>(rand() + i, GameDependenciesTest::info)); // Create a new entity
const auto tempEntityId = tempEntity[i]->GetObjectID();
baseArchetype->CreateComponents(DestroyableComponent(tempEntityId), SimplePhysicsComponent(tempEntityId, 2));
entitySystem->CreateEntity(tempEntityId, DestroyableComponent(tempEntityId), SimplePhysicsComponent(tempEntityId, 2));
}
// Benchmarking
Expand Down

0 comments on commit f97185e

Please sign in to comment.