📦Archetypes📦
This commit is contained in:
parent
f313d64d4a
commit
6bd041342a
1 changed files with 113 additions and 15 deletions
126
zecsy.hpp
126
zecsy.hpp
|
@ -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
|
||||||
|
{
|
||||||
|
size_t operator()(const archetype_signature& vec) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
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++;
|
static comp_id id = next_component_id++;
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
static comp_id next_component_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,12 +311,29 @@ 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)
|
||||||
|
{
|
||||||
|
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)...);
|
system(e, get<T>(e)...);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}; // namespace zecsy
|
}; // namespace zecsy
|
||||||
|
|
Loading…
Reference in a new issue