From 85eb5a72618cea8e676d592d2153e36d7725c947 Mon Sep 17 00:00:00 2001 From: jadebenn Date: Tue, 17 Dec 2024 22:06:41 -0600 Subject: [PATCH] testing iteration --- dECS/CMakeLists.txt | 1 + dECS/Core.h | 56 +++++++++++ dECS/Iter.h | 12 +++ dGame/dComponents/Component.cpp | 13 --- dGame/dComponents/Component.h | 7 +- tests/dECSTests/TestECS.cpp | 171 ++++++++++++++++++++++++++++++-- 6 files changed, 235 insertions(+), 25 deletions(-) create mode 100644 dECS/Iter.h diff --git a/dECS/CMakeLists.txt b/dECS/CMakeLists.txt index b9c55052..c100db7e 100644 --- a/dECS/CMakeLists.txt +++ b/dECS/CMakeLists.txt @@ -3,6 +3,7 @@ set(msvc_cxx "$") add_library(dECS STATIC "Core.h" + "Iter.h" "Core.cpp" ) target_include_directories(dECS PUBLIC .) diff --git a/dECS/Core.h b/dECS/Core.h index 200cb2ad..e3bc22c9 100644 --- a/dECS/Core.h +++ b/dECS/Core.h @@ -1,6 +1,8 @@ #pragma once #include #include +#include +#include #include #include @@ -12,8 +14,13 @@ namespace dECS { // template // concept IsComponent = std::derived_from; + // Data structures struct WorldData; class World; + + template + class System; + class Entity; struct IStorage; @@ -30,10 +37,59 @@ namespace dECS { [[nodiscard]] Entity MakeEntity(); + template + [[nodiscard]] + System MakeSystem() { + return System{}; + } + + template + [[nodiscard]] + System MakeSystem(S&& name) { + return System{ std::forward(name) }; + } + private: WorldPtr m_World; }; + template + class System { + public: + friend System World::MakeSystem(); + + template + friend System World::MakeSystem(S&&); + + /*template + requires std::is_invocable_r_v + void ForEach(Fn&& f) { + for (ObjId i = 0; i < mT.size(); ++i) { + auto& c = mT[i]; + f(i, std::get(c)...); + } + }*/ + + template + requires std::is_invocable_r_v + void ForEach(Fn&& fn) { + std::tuple comps; // some sort of iterator that returns a tuple each 'step?' + for (size_t i = 0; i < 5; ++i) { + fn(std::get(comps)...); + } + } + + private: + System() = default; + + template + explicit System(S&& name) + : m_name{ std::forward(name) } + {} + + std::string m_name; + }; + class Entity { public: friend Entity World::MakeEntity(); diff --git a/dECS/Iter.h b/dECS/Iter.h new file mode 100644 index 00000000..def6818e --- /dev/null +++ b/dECS/Iter.h @@ -0,0 +1,12 @@ +#include "Core.h" + +namespace dECS { + class Iter { + public: + [[nodiscard]] + bool Next(); + + private: + WeakWorldPtr m_World; + }; +} diff --git a/dGame/dComponents/Component.cpp b/dGame/dComponents/Component.cpp index 8f38fb61..dbd952eb 100644 --- a/dGame/dComponents/Component.cpp +++ b/dGame/dComponents/Component.cpp @@ -1,18 +1,5 @@ #include "Component.h" - -Component::Component(Entity* parent) { - m_Parent = parent; -} - -Component::~Component() { - -} - -Entity* Component::GetParent() const { - return m_Parent; -} - void Component::Update(float deltaTime) { } diff --git a/dGame/dComponents/Component.h b/dGame/dComponents/Component.h index 3e9de3a8..db6b49cc 100644 --- a/dGame/dComponents/Component.h +++ b/dGame/dComponents/Component.h @@ -13,14 +13,15 @@ class Entity; */ class Component { public: - Component(Entity* parent); - virtual ~Component(); + Component() = default; + Component(Entity* parent) : m_Parent{ parent } {} + virtual ~Component() = default; /** * Gets the owner of this component * @return the owner of this component */ - Entity* GetParent() const; + Entity* GetParent() const { return m_Parent; } /** * Updates the component in the game loop diff --git a/tests/dECSTests/TestECS.cpp b/tests/dECSTests/TestECS.cpp index f235522a..c5e1c1cc 100644 --- a/tests/dECSTests/TestECS.cpp +++ b/tests/dECSTests/TestECS.cpp @@ -1,3 +1,6 @@ +#include +#include +#include #include #include #include "Core.h" @@ -6,11 +9,122 @@ using namespace dECS; -struct TestComponent { - static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::CHOICE_BUILD; +namespace TestECS { + using LegacyComponent = ::Component; - int value; -}; + namespace Component { + using enum eReplicaComponentType; + + void* NULL_PARENT = nullptr; + + struct Legacy : public LegacyComponent { + static constexpr eReplicaComponentType ComponentType = CHANGLING; + + Legacy() = default; + + void Update(float deltaTime) { + std::printf("Legacy updated!\n"); + } + }; + + struct Invalid { + static constexpr eReplicaComponentType ComponentType = INVALID; + + int value; + }; + + struct Destroyable { + static constexpr eReplicaComponentType ComponentType = DESTROYABLE; + + using FactionId = int32_t; + + float health; + float maxHealth; + float armor; + float maxArmor; + float imag; + float maxImag; + uint32_t damageToAbsorb; + bool immune; + bool gmImmune; + bool shielded; + float actualMaxHealth; + float actualMaxArmor; + float actualMaxImagination; + std::vector factionIds; + bool smashable; + }; + } + + struct IFakeSystem { + virtual ~IFakeSystem() = default; + + [[nodiscard]] + constexpr virtual size_t Count() const noexcept = 0; + + constexpr virtual void EmplaceBack() = 0; + }; + + template + struct FakeSystem : public IFakeSystem { + template + using Storage = std::vector>; + + std::tuple...> data; + + [[nodiscard]] + constexpr size_t Count() const noexcept override { + return std::get<0>(data).size(); + } + + constexpr void EmplaceBack() override { + (std::get>(data).emplace_back(), ...); + } + + template + requires std::disjunction_v...> + [[nodiscard]] + std::span Get() { + return std::get>(data); + } + + template + requires std::disjunction_v...> + [[nodiscard]] + std::span Get() const { + return std::get>(data); + } + + template + requires std::is_invocable_r_v + void ForEach(Fn&& fn); + }; + + class FakeIter { + public: + constexpr FakeIter(const IFakeSystem& fakeSys) noexcept + : m_System{ fakeSys } + {} + + [[nodiscard]] + constexpr bool Next() { + return m_Count++ > m_System.Count(); + } + + private: + size_t m_Count; + const IFakeSystem& m_System; + }; + + template + template + requires std::is_invocable_r_v + void FakeSystem::ForEach(Fn&& fn){ + for (size_t i = 0; i < Count(); ++i) { + fn(Get()[i]...); + } + } +} // Test that entity IDs increment correctly TEST(ECSTest, IncrementEntityIdsSingleThread) { @@ -28,19 +142,21 @@ TEST(ECSTest, IncrementEntityIdsSingleThread) { // Test adding and getting components TEST(ECSTest, MakeOneEntityAndAddComponents) { + using namespace TestECS::Component; + auto w = World{}; auto e = w.MakeEntity(); ASSERT_EQ(e.GetObjectID(), 1); // add component - auto* const testCompPtr = e.AddComponent(); + auto* const testCompPtr = e.AddComponent(); ASSERT_NE(testCompPtr, nullptr); - ASSERT_EQ(testCompPtr->ComponentType, eReplicaComponentType::CHOICE_BUILD); + ASSERT_EQ(testCompPtr->ComponentType, Invalid::ComponentType); ASSERT_EQ(testCompPtr->value, 0); testCompPtr->value = 15; // try getting the same component we just added - auto* const gotTestCompPtr = e.GetComponent(); + auto* const gotTestCompPtr = e.GetComponent(); ASSERT_NE(gotTestCompPtr, nullptr); ASSERT_EQ(gotTestCompPtr, testCompPtr); ASSERT_NE(gotTestCompPtr->value, 0); @@ -49,6 +165,8 @@ TEST(ECSTest, MakeOneEntityAndAddComponents) { // Test world scoping TEST(ECSTest, WorldScope) { + using namespace TestECS::Component; + auto e = std::optional{}; { @@ -57,11 +175,46 @@ TEST(ECSTest, WorldScope) { ASSERT_EQ(e->GetObjectID(), 1); // add component within scope - auto* const cPtr = e->AddComponent(); + auto* const cPtr = e->AddComponent(); ASSERT_NE(cPtr, nullptr); } // Attempting to access this component should return nullptr // now that the world has gone out of scope - ASSERT_EQ(e->GetComponent(), nullptr); + ASSERT_EQ(e->GetComponent(), nullptr); +} + +// Create and iterate over a system +TEST(ECSTest, CreateAndIterateOverSystem) { + using namespace TestECS::Component; + + auto w = World{}; + auto s = w.MakeSystem("DestInvalid"); + + size_t count = 0; + s.ForEach([&](Destroyable& d, const Invalid& i) { + std::printf("i = %ld: d.health = %f\n", ++count, d.health); + d.health += 1; + }); +} + +TEST(ECSTest, FakeIterationForTestingPurposes) { + using namespace TestECS; + using namespace TestECS::Component; + + auto s = FakeSystem{}; + + auto const r = 2 + std::rand() % 8; + for (size_t i = 0; i < r; ++i) { + s.EmplaceBack(); + } + + size_t count = 0; + s.ForEach([&](Legacy& l, Destroyable& d) { + l.Update(0.0f); + std::printf("i = %ld: d.health = %f\n", ++count, d.health); + d.health += 1; + }); + std::printf("Total count = %ld\n", count); + ASSERT_EQ(r, count); }