Combine world and component_storage
This commit is contained in:
parent
9830ee2fd6
commit
52d6b7c4c3
1 changed files with 127 additions and 179 deletions
306
zecsy.hpp
306
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()));
|
||||
}
|
||||
|
||||
template<Component... T>
|
||||
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 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>
|
||||
|
|
Loading…
Reference in a new issue