mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-08-09 20:24:16 +00:00
initial implementation
This commit is contained in:
@@ -1,4 +1,7 @@
|
||||
add_library(dECS STATIC "ECS.cpp")
|
||||
add_library(dECS STATIC
|
||||
"Core.h"
|
||||
"Core.cpp"
|
||||
)
|
||||
target_include_directories(dECS PUBLIC .)
|
||||
target_link_libraries(dECS PRIVATE dCommon)
|
||||
target_link_libraries(dECS PRIVATE dCommon magic_enum::magic_enum)
|
||||
target_compile_options(dECS PRIVATE "-Wall")
|
||||
|
70
dECS/Core.cpp
Normal file
70
dECS/Core.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
#include <atomic>
|
||||
#include <magic_enum/magic_enum_containers.hpp>
|
||||
#include <eReplicaComponentType.h>
|
||||
#include "Core.h"
|
||||
|
||||
namespace dECS {
|
||||
struct WorldData {
|
||||
using CompSignature = magic_enum::containers::bitset<eReplicaComponentType>;
|
||||
using CompMap = std::unordered_map<LWOOBJID, CompSignature>;
|
||||
using CompStorage = std::unordered_map<eReplicaComponentType, std::unique_ptr<IStorage>>;
|
||||
|
||||
std::atomic<LWOOBJID> nextId = 1;
|
||||
CompMap map;
|
||||
CompStorage data;
|
||||
};
|
||||
|
||||
World::World() : m_World{ std::make_shared<WorldData>() } {};
|
||||
|
||||
Entity World::MakeEntity() {
|
||||
return Entity{ m_World->nextId.fetch_add(1, std::memory_order::relaxed),
|
||||
m_World };
|
||||
}
|
||||
|
||||
void* Entity::AddComponent(const eReplicaComponentType kind, const StorageConstructor storageConstructor) {
|
||||
if (auto w = m_World.lock()) {
|
||||
// add to kind signature
|
||||
w->map[m_Id].set(kind, true);
|
||||
|
||||
// get or add storage
|
||||
auto storageIt = w->data.find(kind);
|
||||
if (storageIt == w->data.cend()) {
|
||||
bool inserted = false;
|
||||
std::tie(storageIt, inserted) = w->data.try_emplace(kind, storageConstructor());
|
||||
if (!inserted) throw "storage emplacement failure";
|
||||
}
|
||||
auto& storage = *storageIt->second;
|
||||
|
||||
// return reference if already mapped, otherwise add component
|
||||
auto compIt = storage.rowMap.find(m_Id);
|
||||
if (compIt == storage.rowMap.cend()) {
|
||||
const auto curSize = storage.rowMap.size();
|
||||
storage.rowMap.emplace(m_Id, curSize);
|
||||
return storage.emplace_back();
|
||||
}
|
||||
const auto row = compIt->second;
|
||||
return storage.at(row);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const void* Entity::GetComponent(const eReplicaComponentType kind) const {
|
||||
if (auto const w = m_World.lock()) {
|
||||
const auto& compSig = w->map.at(m_Id);
|
||||
if (!compSig.test(kind)) return nullptr;
|
||||
|
||||
const auto& storage = *w->data.at(kind);
|
||||
const auto it = storage.rowMap.find(m_Id);
|
||||
if (it == storage.rowMap.cend()) return nullptr;
|
||||
|
||||
const auto row = it->second;
|
||||
return storage.at(row);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* Entity::GetComponent(const eReplicaComponentType kind) {
|
||||
// Casting away const for this overload is safe, if not at all pretty
|
||||
return const_cast<void*>(std::as_const(*this).GetComponent(kind));
|
||||
}
|
||||
}
|
124
dECS/Core.h
Normal file
124
dECS/Core.h
Normal file
@@ -0,0 +1,124 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
class Component;
|
||||
enum class eReplicaComponentType : uint32_t;
|
||||
using LWOOBJID = int64_t;
|
||||
|
||||
namespace dECS {
|
||||
// template <typename C>
|
||||
// concept IsComponent = std::derived_from<C, Component>;
|
||||
|
||||
struct WorldData;
|
||||
struct World;
|
||||
struct Entity;
|
||||
struct IStorage;
|
||||
|
||||
template <typename C>
|
||||
class Storage;
|
||||
|
||||
using WorldPtr = std::shared_ptr<WorldData>;
|
||||
using WeakWorldPtr = std::weak_ptr<WorldData>;
|
||||
|
||||
class World {
|
||||
public:
|
||||
World();
|
||||
|
||||
[[nodiscard]]
|
||||
Entity MakeEntity();
|
||||
|
||||
private:
|
||||
WorldPtr m_World;
|
||||
};
|
||||
|
||||
class Entity {
|
||||
public:
|
||||
friend Entity World::MakeEntity();
|
||||
|
||||
using StorageConstructor = std::function<std::unique_ptr<IStorage>()>;
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr LWOOBJID Id() const noexcept {
|
||||
return m_Id;
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
void* AddComponent(eReplicaComponentType, StorageConstructor);
|
||||
|
||||
template <typename C>
|
||||
[[maybe_unused]]
|
||||
C* AddComponent() {
|
||||
return static_cast<C*>(AddComponent(C::ComponentType, std::make_unique<Storage<C>>));
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const void* GetComponent(eReplicaComponentType) const;
|
||||
|
||||
[[nodiscard]]
|
||||
void* GetComponent(eReplicaComponentType);
|
||||
|
||||
template <typename C>
|
||||
[[nodiscard]]
|
||||
const C* GetComponent() const {
|
||||
return static_cast<const C*>(GetComponent(C::ComponentType));
|
||||
}
|
||||
|
||||
template <typename C>
|
||||
[[nodiscard]]
|
||||
C* GetComponent() {
|
||||
return static_cast<C*>(GetComponent(C::ComponentType));
|
||||
}
|
||||
|
||||
private:
|
||||
Entity(const LWOOBJID id, const WeakWorldPtr world)
|
||||
: m_Id{ id }
|
||||
, m_World { world }
|
||||
{}
|
||||
|
||||
LWOOBJID m_Id;
|
||||
|
||||
WeakWorldPtr m_World;
|
||||
};
|
||||
|
||||
struct IStorage {
|
||||
using RowMap = std::unordered_map<LWOOBJID, size_t>;
|
||||
|
||||
virtual ~IStorage() = default;
|
||||
|
||||
[[nodiscard]]
|
||||
virtual void* at(size_t) = 0;
|
||||
|
||||
[[nodiscard]]
|
||||
virtual const void* at(size_t) const = 0;
|
||||
|
||||
[[nodiscard]]
|
||||
virtual void* emplace_back() = 0;
|
||||
|
||||
RowMap rowMap;
|
||||
};
|
||||
|
||||
template <typename C>
|
||||
class Storage : public IStorage {
|
||||
public:
|
||||
[[nodiscard]]
|
||||
void* at(const size_t index) override {
|
||||
return static_cast<void*>(&m_Vec.at(index));
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const void* at(const size_t index) const override {
|
||||
return static_cast<const void*>(&m_Vec.at(index));
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
void* emplace_back() override {
|
||||
return static_cast<void*>(&m_Vec.emplace_back());
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<C> m_Vec;
|
||||
};
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
#include "ECS.h"
|
||||
#include "dCommonVars.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Component {
|
||||
|
||||
}
|
65
dECS/ECS.h
65
dECS/ECS.h
@@ -1,65 +0,0 @@
|
||||
#pragma once
|
||||
#include <bitset>
|
||||
#include <climits>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include "dCommonVars.h"
|
||||
#include "eReplicaComponentType.h"
|
||||
|
||||
namespace Component {
|
||||
constexpr size_t MAX_KINDS { 32 };
|
||||
|
||||
enum class Kind : uint32_t {
|
||||
NONE = 0,
|
||||
DESTROYABLE = 7,
|
||||
PET = 26,
|
||||
};
|
||||
|
||||
using Signature = std::bitset<MAX_KINDS>;
|
||||
|
||||
// Components
|
||||
struct Destroyable;
|
||||
struct Pet {
|
||||
static constexpr Kind KIND_ID = Kind::PET;
|
||||
|
||||
// The ID under which this pet is stored in the database (if it's tamed)
|
||||
LWOOBJID m_DatabaseId;
|
||||
|
||||
// The ID of the item from which this pet was creat
|
||||
LWOOBJID m_ItemId;
|
||||
|
||||
// The name of this pet
|
||||
std::string name;
|
||||
};
|
||||
|
||||
class IStorage {
|
||||
public:
|
||||
constexpr IStorage(const Kind kind) : m_Kind{ kind } {}
|
||||
virtual ~IStorage() = default;
|
||||
constexpr virtual void Remove(const size_t index) = 0;
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr Kind GetKind() const {
|
||||
return m_Kind;
|
||||
}
|
||||
|
||||
protected:
|
||||
Kind m_Kind;
|
||||
};
|
||||
|
||||
template <typename C>
|
||||
class Storage : public IStorage {
|
||||
public:
|
||||
constexpr Storage() : IStorage{ C::KIND_ID } {}
|
||||
|
||||
constexpr void Remove(const size_t index) override {
|
||||
auto& elementToDelete = m_Vec.at(index);
|
||||
auto& lastElement = m_Vec.back();
|
||||
std::swap(elementToDelete, lastElement);
|
||||
m_Vec.pop_back();
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<C> m_Vec;
|
||||
};
|
||||
}
|
Reference in New Issue
Block a user