From 6bd041342aa4b0a769dc85e793002420dce4aa62 Mon Sep 17 00:00:00 2001 From: NukeBird Date: Thu, 20 Feb 2025 01:42:06 +0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=A6Archetypes=F0=9F=93=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- zecsy.hpp | 128 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 113 insertions(+), 15 deletions(-) diff --git a/zecsy.hpp b/zecsy.hpp index 9f583e0..e7ec72b 100644 --- a/zecsy.hpp +++ b/zecsy.hpp @@ -1,4 +1,5 @@ #pragma once +#include #include #include #include @@ -74,30 +75,60 @@ namespace zecsy struct component_pool { std::vector data; - std::vector free_list; // Reusable indices + std::vector free_list; std::unordered_map entity_to_index; std::unordered_map index_to_entity; }; std::unordered_map pools; - template - static comp_id get_component_id() + using archetype_signature = std::vector; + using entity_group = std::vector; + + struct archetype_hash { - static comp_id id = next_component_id++; - return id; - } + size_t operator()(const archetype_signature& vec) const; + }; + + std::unordered_map + archetypes; + + template + static comp_id get_component_id(); static comp_id next_component_id; }; + inline size_t world::archetype_hash::operator()( + const world::archetype_signature& vec) const + { + size_t seed = vec.size(); + for(const auto& id: vec) + { + seed ^= id + 0x9e3779b9 + (seed << 6) + (seed >> 2); + } + return seed; + } + + template + inline world::comp_id world::get_component_id() + { + static comp_id id = next_component_id++; + return id; + } + inline world::comp_id world::next_component_id = 0; inline entity_id world::make_entity() { auto id = ++entity_counter; alive_entities.emplace(id); - // entity_to_comps[id] = {}; + entity_to_comps[id] = {}; + + std::vector key; + auto& group = archetypes[key]; + group.emplace_back(id); + return id; } @@ -105,7 +136,18 @@ namespace zecsy { alive_entities.erase(e); - for(comp_id id: entity_to_comps[e]) + auto& comp_set = entity_to_comps[e]; + std::vector key(comp_set.begin(), comp_set.end()); + + auto& group = archetypes[key]; + group.erase(std::remove(group.begin(), group.end(), e), group.end()); + + if(archetypes[key].empty()) + { + archetypes.erase(key); + } + + for(comp_id id: comp_set) { auto& pool = pools[id]; auto index = pool.entity_to_index[e]; @@ -169,7 +211,26 @@ namespace zecsy pool.entity_to_index[e] = index; pool.index_to_entity[index] = e; - entity_to_comps[e].emplace(id); + auto& comp_set = entity_to_comps[e]; + std::set old_set = comp_set; + auto [it, inserted] = comp_set.insert(id); + + if(inserted) + { + std::vector old_key(old_set.begin(), old_set.end()); + + auto& group = archetypes[old_key]; + group.erase(std::remove(group.begin(), group.end(), e), + group.end()); + + if(archetypes[old_key].empty()) + { + archetypes.erase(old_key); + } + + std::vector new_key(comp_set.begin(), comp_set.end()); + archetypes[new_key].emplace_back(e); + } } template @@ -182,18 +243,38 @@ namespace zecsy inline void world::remove(entity_id e) { auto id = get_component_id(); - if(!has(e)) + auto& comp_set = entity_to_comps[e]; + + if(!comp_set.contains(id)) { return; } + std::set old_set = comp_set; + size_t removed = comp_set.erase(id); + + if(removed > 0) + { + std::vector old_key(old_set.begin(), old_set.end()); + + auto& group = archetypes[old_key]; + group.erase(std::remove(group.begin(), group.end(), e), + group.end()); + + if(archetypes[old_key].empty()) + { + archetypes.erase(old_key); + } + + std::vector new_key(comp_set.begin(), comp_set.end()); + archetypes[new_key].emplace_back(e); + } + 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); - entity_to_comps[e].erase(id); } template @@ -230,11 +311,28 @@ namespace zecsy template inline void world::query(std::invocable auto&& system) { - for(auto e: alive_entities) + std::vector required = {get_component_id()...}; + std::sort(required.begin(), required.end()); + + for(const auto& [archetype_key, entities]: archetypes) { - if((has(e))) + bool match = true; + for(comp_id req_id: required) { - system(e, get(e)...); + if(!std::binary_search(archetype_key.begin(), + archetype_key.end(), req_id)) + { + match = false; + break; + } + } + + if(match) + { + for(entity_id e: entities) + { + system(e, get(e)...); + } } } }