mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2024-12-22 13:33:35 +00:00
testing iteration
This commit is contained in:
parent
93dcfddac5
commit
85eb5a7261
@ -3,6 +3,7 @@ set(msvc_cxx "$<COMPILE_LANG_AND_ID:CXX,MSVC>")
|
||||
|
||||
add_library(dECS STATIC
|
||||
"Core.h"
|
||||
"Iter.h"
|
||||
"Core.cpp"
|
||||
)
|
||||
target_include_directories(dECS PUBLIC .)
|
||||
|
56
dECS/Core.h
56
dECS/Core.h
@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
@ -12,8 +14,13 @@ namespace dECS {
|
||||
// template <typename C>
|
||||
// concept IsComponent = std::derived_from<C, Component>;
|
||||
|
||||
// Data structures
|
||||
struct WorldData;
|
||||
class World;
|
||||
|
||||
template <typename... Cs>
|
||||
class System;
|
||||
|
||||
class Entity;
|
||||
struct IStorage;
|
||||
|
||||
@ -30,10 +37,59 @@ namespace dECS {
|
||||
[[nodiscard]]
|
||||
Entity MakeEntity();
|
||||
|
||||
template <typename... Cs>
|
||||
[[nodiscard]]
|
||||
System<Cs...> MakeSystem() {
|
||||
return System<Cs...>{};
|
||||
}
|
||||
|
||||
template <typename... Cs, typename S>
|
||||
[[nodiscard]]
|
||||
System<Cs...> MakeSystem(S&& name) {
|
||||
return System<Cs...>{ std::forward<S>(name) };
|
||||
}
|
||||
|
||||
private:
|
||||
WorldPtr m_World;
|
||||
};
|
||||
|
||||
template <typename... Cs>
|
||||
class System {
|
||||
public:
|
||||
friend System World::MakeSystem<Cs...>();
|
||||
|
||||
template <typename... Ts, typename S>
|
||||
friend System<Ts...> World::MakeSystem(S&&);
|
||||
|
||||
/*template <typename Fn>
|
||||
requires std::is_invocable_r_v<void, Fn(Cs...), ObjId, Cs...>
|
||||
void ForEach(Fn&& f) {
|
||||
for (ObjId i = 0; i < mT.size(); ++i) {
|
||||
auto& c = mT[i];
|
||||
f(i, std::get<Cs>(c)...);
|
||||
}
|
||||
}*/
|
||||
|
||||
template <typename Fn>
|
||||
requires std::is_invocable_r_v<void, Fn(Cs...), Cs...>
|
||||
void ForEach(Fn&& fn) {
|
||||
std::tuple<Cs...> comps; // some sort of iterator that returns a tuple each 'step?'
|
||||
for (size_t i = 0; i < 5; ++i) {
|
||||
fn(std::get<Cs>(comps)...);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
System() = default;
|
||||
|
||||
template <typename S>
|
||||
explicit System(S&& name)
|
||||
: m_name{ std::forward<S>(name) }
|
||||
{}
|
||||
|
||||
std::string m_name;
|
||||
};
|
||||
|
||||
class Entity {
|
||||
public:
|
||||
friend Entity World::MakeEntity();
|
||||
|
12
dECS/Iter.h
Normal file
12
dECS/Iter.h
Normal file
@ -0,0 +1,12 @@
|
||||
#include "Core.h"
|
||||
|
||||
namespace dECS {
|
||||
class Iter {
|
||||
public:
|
||||
[[nodiscard]]
|
||||
bool Next();
|
||||
|
||||
private:
|
||||
WeakWorldPtr m_World;
|
||||
};
|
||||
}
|
@ -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) {
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -1,3 +1,6 @@
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <span>
|
||||
#include <optional>
|
||||
#include <gtest/gtest.h>
|
||||
#include "Core.h"
|
||||
@ -6,11 +9,122 @@
|
||||
|
||||
using namespace dECS;
|
||||
|
||||
struct TestComponent {
|
||||
static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::CHOICE_BUILD;
|
||||
namespace TestECS {
|
||||
using LegacyComponent = ::Component;
|
||||
|
||||
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<FactionId> factionIds;
|
||||
bool smashable;
|
||||
};
|
||||
}
|
||||
|
||||
struct IFakeSystem {
|
||||
virtual ~IFakeSystem() = default;
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr virtual size_t Count() const noexcept = 0;
|
||||
|
||||
constexpr virtual void EmplaceBack() = 0;
|
||||
};
|
||||
|
||||
template <typename... Cs>
|
||||
struct FakeSystem : public IFakeSystem {
|
||||
template <typename C>
|
||||
using Storage = std::vector<std::remove_const_t<C>>;
|
||||
|
||||
std::tuple<Storage<Cs>...> data;
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr size_t Count() const noexcept override {
|
||||
return std::get<0>(data).size();
|
||||
}
|
||||
|
||||
constexpr void EmplaceBack() override {
|
||||
(std::get<Storage<Cs>>(data).emplace_back(), ...);
|
||||
}
|
||||
|
||||
template <typename C>
|
||||
requires std::disjunction_v<std::is_same<C, Cs>...>
|
||||
[[nodiscard]]
|
||||
std::span<C> Get() {
|
||||
return std::get<Storage<C>>(data);
|
||||
}
|
||||
|
||||
template <typename C>
|
||||
requires std::disjunction_v<std::is_same<C, Cs>...>
|
||||
[[nodiscard]]
|
||||
std::span<const C> Get() const {
|
||||
return std::get<Storage<C>>(data);
|
||||
}
|
||||
|
||||
template <typename Fn>
|
||||
requires std::is_invocable_r_v<void, Fn(Cs...), Cs...>
|
||||
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 <typename... Cs>
|
||||
template <typename Fn>
|
||||
requires std::is_invocable_r_v<void, Fn(Cs...), Cs...>
|
||||
void FakeSystem<Cs...>::ForEach(Fn&& fn){
|
||||
for (size_t i = 0; i < Count(); ++i) {
|
||||
fn(Get<Cs>()[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<TestComponent>();
|
||||
auto* const testCompPtr = e.AddComponent<Invalid>();
|
||||
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<TestComponent>();
|
||||
auto* const gotTestCompPtr = e.GetComponent<Invalid>();
|
||||
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<dECS::Entity>{};
|
||||
|
||||
{
|
||||
@ -57,11 +175,46 @@ TEST(ECSTest, WorldScope) {
|
||||
ASSERT_EQ(e->GetObjectID(), 1);
|
||||
|
||||
// add component within scope
|
||||
auto* const cPtr = e->AddComponent<TestComponent>();
|
||||
auto* const cPtr = e->AddComponent<Invalid>();
|
||||
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<TestComponent>(), nullptr);
|
||||
ASSERT_EQ(e->GetComponent<Invalid>(), nullptr);
|
||||
}
|
||||
|
||||
// Create and iterate over a system
|
||||
TEST(ECSTest, CreateAndIterateOverSystem) {
|
||||
using namespace TestECS::Component;
|
||||
|
||||
auto w = World{};
|
||||
auto s = w.MakeSystem<Destroyable, const Invalid>("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<Legacy, Destroyable>{};
|
||||
|
||||
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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user