From 52d6b7c4c3dd8dd0d7615aea0ba0c2ce45ada00d Mon Sep 17 00:00:00 2001 From: NukeBird <nukebird.dev@gmail.com> Date: Wed, 19 Feb 2025 22:50:21 +0300 Subject: [PATCH] Combine world and component_storage --- zecsy.hpp | 306 ++++++++++++++++++++++-------------------------------- 1 file changed, 127 insertions(+), 179 deletions(-) diff --git a/zecsy.hpp b/zecsy.hpp index cf1aa29..4c2279c 100644 --- a/zecsy.hpp +++ b/zecsy.hpp @@ -35,166 +35,6 @@ namespace zecsy */ using entities_set = std::set<entity_id>; - class component_storage final - { - public: - template<Component T> - bool has(entity_id e) const; - - template<Component First, Component Second, Component... Rest> - bool has(entity_id e) const; - - template<Component T> - T& get(entity_id e); - - template<Component T> - void set(entity_id e); - - template<Component T> - void set(entity_id e, const T& comp); - - template<Component First, Component Second, Component... Rest> - void set(entity_id e); - - template<Component First, Component Second, Component... Rest> - void set(entity_id e, const First& comp0, const Second& comp1, - const Rest&... rest_comps); - - template<Component T> - void remove(entity_id e); - - template<Component First, Component Second, Component... Rest> - void remove(entity_id e); - - private: - using comp_id = size_t; - - struct component_pool - { - std::vector<uint8_t> data; - std::vector<size_t> free_list; // Reusable indices - std::unordered_map<entity_id, size_t> entity_to_index; - std::unordered_map<size_t, entity_id> index_to_entity; - }; - - std::unordered_map<comp_id, component_pool> pools; - - template<typename T> - static comp_id get_component_id() - { - static comp_id id = next_component_id++; - return id; - } - - static comp_id next_component_id; - }; - - inline component_storage::comp_id component_storage::next_component_id = 0; - - template<Component T> - inline bool component_storage::has(entity_id e) const - { - auto id = get_component_id<T>(); - if(pools.contains(id)) - { - return pools.at(id).entity_to_index.contains(e); - } - return false; - } - - template<Component T> - inline T& component_storage::get(entity_id e) - { - auto id = get_component_id<T>(); - if(!has<T>(e)) - { - throw std::runtime_error( - std::format("Entity #{} doesn't have {}", e, typeid(T).name())); - } - - auto& pool = pools.at(id); - auto index = pool.entity_to_index.at(e); - return *reinterpret_cast<T*>(&pool.data[index * sizeof(T)]); - } - - template<Component T> - inline void component_storage::set(entity_id e, const T& comp) - { - auto id = get_component_id<T>(); - auto& pool = pools[id]; - - size_t index; - if(!pool.free_list.empty()) - { - index = pool.free_list.back(); - pool.free_list.pop_back(); - } - else - { - index = pool.data.size() / sizeof(T); - pool.data.resize(pool.data.size() + sizeof(T)); - } - - new(&pool.data[index * sizeof(T)]) T(comp); - pool.entity_to_index[e] = index; - pool.index_to_entity[index] = e; - } - - template<Component T> - inline void component_storage::set(entity_id e) - { - set(e, T{}); - } - - template<Component T> - inline void component_storage::remove(entity_id e) - { - auto id = get_component_id<T>(); - if(!has<T>(e)) - { - return; - } - - auto& pool = pools[id]; - auto index = pool.entity_to_index[e]; - - pool.free_list.push_back(index); - pool.entity_to_index.erase(e); - pool.index_to_entity.erase(index); - } - - template<Component First, Component Second, Component... Rest> - inline bool component_storage::has(entity_id e) const - { - return has<First>(e) && has<Second>(e) && (has<Rest>(e) && ...); - } - - template<Component First, Component Second, Component... Rest> - inline void component_storage::set(entity_id e) - { - set(e, First{}); - set(e, Second{}); - (set(e, Rest{}), ...); - } - - template<Component First, Component Second, Component... Rest> - inline void component_storage::set(entity_id e, const First& comp0, - const Second& comp1, - const Rest&... rest_comps) - { - set(e, comp0); - set(e, comp1); - (set(e, rest_comps), ...); - } - - template<Component First, Component Second, Component... Rest> - inline void component_storage::remove(entity_id e) - { - remove<First>(e); - remove<Second>(e); - (remove<Rest>(e), ...); - } - class system_scheduler final { public: @@ -248,19 +88,32 @@ namespace zecsy void destroy_entity(entity_id e); bool is_alive(entity_id e) const; - template<Component... T> + template<Component T> + bool has(entity_id e) const; + + template<Component First, Component Second, Component... Rest> bool has(entity_id e) const; template<Component T> T& get(entity_id e); - template<Component... T> + template<Component T> void set(entity_id e); - template<Component... T> - void set(entity_id e, const T&... comps); + template<Component T> + void set(entity_id e, const T& comp); - template<Component... T> + template<Component First, Component Second, Component... Rest> + void set(entity_id e); + + template<Component First, Component Second, Component... Rest> + void set(entity_id e, const First& comp0, const Second& comp1, + const Rest&... rest_comps); + + template<Component T> + void remove(entity_id e); + + template<Component First, Component Second, Component... Rest> void remove(entity_id e); template<Component... T> @@ -269,9 +122,31 @@ namespace zecsy private: entities_set alive_entities; entity_id entity_counter = 0; - component_storage storage; + + using comp_id = size_t; + + struct component_pool + { + std::vector<uint8_t> data; + std::vector<size_t> free_list; // Reusable indices + std::unordered_map<entity_id, size_t> entity_to_index; + std::unordered_map<size_t, entity_id> index_to_entity; + }; + + std::unordered_map<comp_id, component_pool> pools; + + template<typename T> + static comp_id get_component_id() + { + static comp_id id = next_component_id++; + return id; + } + + static comp_id next_component_id; }; + inline world::comp_id world::next_component_id = 0; + inline entity_id world::make_entity() { auto id = ++entity_counter; @@ -289,34 +164,107 @@ namespace zecsy return alive_entities.contains(e); } - template<Component... T> + template<Component T> inline bool world::has(entity_id e) const { - return storage.has<T...>(e); + auto id = get_component_id<T>(); + if(pools.contains(id)) + { + return pools.at(id).entity_to_index.contains(e); + } + return false; } template<Component T> inline T& world::get(entity_id e) { - return storage.get<T>(e); + auto id = get_component_id<T>(); + if(!has<T>(e)) + { + throw std::runtime_error( + std::format("Entity #{} doesn't have {}", e, typeid(T).name())); + } + + auto& pool = pools.at(id); + auto index = pool.entity_to_index.at(e); + return *reinterpret_cast<T*>(&pool.data[index * sizeof(T)]); } - template<Component... T> + template<Component T> + inline void world::set(entity_id e, const T& comp) + { + auto id = get_component_id<T>(); + auto& pool = pools[id]; + + size_t index; + if(!pool.free_list.empty()) + { + index = pool.free_list.back(); + pool.free_list.pop_back(); + } + else + { + index = pool.data.size() / sizeof(T); + pool.data.resize(pool.data.size() + sizeof(T)); + } + + new(&pool.data[index * sizeof(T)]) T(comp); + pool.entity_to_index[e] = index; + pool.index_to_entity[index] = e; + } + + template<Component T> inline void world::set(entity_id e) { - storage.set<T...>(e); + set(e, T{}); } - template<Component... T> - inline void world::set(entity_id e, const T&... comps) - { - storage.set(e, comps...); - } - - template<Component... T> + template<Component T> inline void world::remove(entity_id e) { - storage.remove<T...>(e); + auto id = get_component_id<T>(); + if(!has<T>(e)) + { + return; + } + + auto& pool = pools[id]; + auto index = pool.entity_to_index[e]; + + pool.free_list.push_back(index); + pool.entity_to_index.erase(e); + pool.index_to_entity.erase(index); + } + + template<Component First, Component Second, Component... Rest> + inline bool world::has(entity_id e) const + { + return has<First>(e) && has<Second>(e) && (has<Rest>(e) && ...); + } + + template<Component First, Component Second, Component... Rest> + inline void world::set(entity_id e) + { + set(e, First{}); + set(e, Second{}); + (set(e, Rest{}), ...); + } + + template<Component First, Component Second, Component... Rest> + inline void world::set(entity_id e, const First& comp0, const Second& comp1, + const Rest&... rest_comps) + { + set(e, comp0); + set(e, comp1); + (set(e, rest_comps), ...); + } + + template<Component First, Component Second, Component... Rest> + inline void world::remove(entity_id e) + { + remove<First>(e); + remove<Second>(e); + (remove<Rest>(e), ...); } template<Component... T>