📦Archetypes📦

This commit is contained in:
NukeBird 2025-02-20 01:42:06 +03:00
parent f313d64d4a
commit 6bd041342a

128
zecsy.hpp
View file

@ -1,4 +1,5 @@
#pragma once #pragma once
#include <algorithm>
#include <concepts> #include <concepts>
#include <cstdint> #include <cstdint>
#include <cstdlib> #include <cstdlib>
@ -74,30 +75,60 @@ namespace zecsy
struct component_pool struct component_pool
{ {
std::vector<uint8_t> data; std::vector<uint8_t> data;
std::vector<size_t> free_list; // Reusable indices std::vector<size_t> free_list;
std::unordered_map<entity_id, size_t> entity_to_index; std::unordered_map<entity_id, size_t> entity_to_index;
std::unordered_map<size_t, entity_id> index_to_entity; std::unordered_map<size_t, entity_id> index_to_entity;
}; };
std::unordered_map<comp_id, component_pool> pools; std::unordered_map<comp_id, component_pool> pools;
template<typename T> using archetype_signature = std::vector<comp_id>;
static comp_id get_component_id() using entity_group = std::vector<entity_id>;
struct archetype_hash
{ {
static comp_id id = next_component_id++; size_t operator()(const archetype_signature& vec) const;
return id; };
}
std::unordered_map<archetype_signature, entity_group, archetype_hash>
archetypes;
template<Component T>
static comp_id get_component_id();
static comp_id next_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<Component T>
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 world::comp_id world::next_component_id = 0;
inline entity_id world::make_entity() inline entity_id world::make_entity()
{ {
auto id = ++entity_counter; auto id = ++entity_counter;
alive_entities.emplace(id); alive_entities.emplace(id);
// entity_to_comps[id] = {}; entity_to_comps[id] = {};
std::vector<comp_id> key;
auto& group = archetypes[key];
group.emplace_back(id);
return id; return id;
} }
@ -105,7 +136,18 @@ namespace zecsy
{ {
alive_entities.erase(e); alive_entities.erase(e);
for(comp_id id: entity_to_comps[e]) auto& comp_set = entity_to_comps[e];
std::vector<comp_id> 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& pool = pools[id];
auto index = pool.entity_to_index[e]; auto index = pool.entity_to_index[e];
@ -169,7 +211,26 @@ namespace zecsy
pool.entity_to_index[e] = index; pool.entity_to_index[e] = index;
pool.index_to_entity[index] = e; pool.index_to_entity[index] = e;
entity_to_comps[e].emplace(id); auto& comp_set = entity_to_comps[e];
std::set<comp_id> old_set = comp_set;
auto [it, inserted] = comp_set.insert(id);
if(inserted)
{
std::vector<comp_id> 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<comp_id> new_key(comp_set.begin(), comp_set.end());
archetypes[new_key].emplace_back(e);
}
} }
template<Component T> template<Component T>
@ -182,18 +243,38 @@ namespace zecsy
inline void world::remove(entity_id e) inline void world::remove(entity_id e)
{ {
auto id = get_component_id<T>(); auto id = get_component_id<T>();
if(!has<T>(e)) auto& comp_set = entity_to_comps[e];
if(!comp_set.contains(id))
{ {
return; return;
} }
std::set<comp_id> old_set = comp_set;
size_t removed = comp_set.erase(id);
if(removed > 0)
{
std::vector<comp_id> 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<comp_id> new_key(comp_set.begin(), comp_set.end());
archetypes[new_key].emplace_back(e);
}
auto& pool = pools[id]; auto& pool = pools[id];
auto index = pool.entity_to_index[e]; auto index = pool.entity_to_index[e];
pool.free_list.push_back(index); pool.free_list.push_back(index);
pool.entity_to_index.erase(e); pool.entity_to_index.erase(e);
pool.index_to_entity.erase(index); pool.index_to_entity.erase(index);
entity_to_comps[e].erase(id);
} }
template<Component First, Component Second, Component... Rest> template<Component First, Component Second, Component... Rest>
@ -230,11 +311,28 @@ namespace zecsy
template<Component... T> template<Component... T>
inline void world::query(std::invocable<entity_id, T&...> auto&& system) inline void world::query(std::invocable<entity_id, T&...> auto&& system)
{ {
for(auto e: alive_entities) std::vector<comp_id> required = {get_component_id<T>()...};
std::sort(required.begin(), required.end());
for(const auto& [archetype_key, entities]: archetypes)
{ {
if((has<T...>(e))) bool match = true;
for(comp_id req_id: required)
{ {
system(e, get<T>(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<T>(e)...);
}
} }
} }
} }