2025-02-14 21:35:40 +03:00
|
|
|
#pragma once
|
|
|
|
#include <cstdint>
|
|
|
|
#include <bitset>
|
2025-02-14 22:18:00 +03:00
|
|
|
#include <format>
|
2025-02-14 22:27:52 +03:00
|
|
|
#include <stdexcept>
|
2025-02-14 23:42:01 +03:00
|
|
|
#include <typeindex>
|
|
|
|
#include <unordered_map>
|
|
|
|
#include <new>
|
2025-02-14 21:35:40 +03:00
|
|
|
|
|
|
|
#ifndef MAX_ZECSY_ENTITIES
|
|
|
|
#define MAX_ZECSY_ENTITIES 65536
|
|
|
|
#endif // !MAX_ZECSY_ENTITIES
|
|
|
|
|
|
|
|
|
|
|
|
namespace zecsy
|
|
|
|
{
|
|
|
|
using entity_id = uint64_t;
|
|
|
|
|
2025-02-14 22:18:00 +03:00
|
|
|
class entity final
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
entity(class world* w, entity_id id);
|
|
|
|
|
|
|
|
entity() = default;
|
|
|
|
entity(const entity &) = default;
|
|
|
|
entity(entity &&) = default;
|
|
|
|
entity &operator=(const entity &) = default;
|
|
|
|
entity &operator=(entity &&) = default;
|
|
|
|
operator entity_id() const;
|
|
|
|
|
|
|
|
bool is_alive() const;
|
2025-02-14 23:42:01 +03:00
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
bool has() const;
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
T& get();
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
void set(const T& comp = T{});
|
2025-02-14 22:18:00 +03:00
|
|
|
private:
|
|
|
|
entity_id id = 0;
|
|
|
|
class world* w = nullptr;
|
|
|
|
};
|
|
|
|
|
2025-02-14 23:42:01 +03:00
|
|
|
using zecsy_bits = std::bitset<MAX_ZECSY_ENTITIES + 1>;
|
|
|
|
|
|
|
|
class component_storage
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
template<typename T>
|
|
|
|
bool has(entity_id e) const;
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
T& get(entity_id e);
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
void set(entity_id e, const T& comp = T{});
|
|
|
|
private:
|
|
|
|
using comp_index = std::type_index;
|
|
|
|
using comp_to_bitset = std::unordered_map<comp_index, zecsy_bits>;
|
|
|
|
using entity_to_index = std::unordered_map<entity_id, size_t>;
|
|
|
|
|
|
|
|
using comp_to_entity_dict = std::unordered_map<comp_index,
|
|
|
|
entity_to_index>;
|
|
|
|
|
|
|
|
using comp_to_storage = std::unordered_map<comp_index,
|
|
|
|
std::vector<uint8_t>>;
|
|
|
|
|
|
|
|
comp_to_bitset bitset_dict;
|
|
|
|
comp_to_entity_dict entity_dict;
|
|
|
|
comp_to_storage storage_dict;
|
|
|
|
};
|
|
|
|
|
2025-02-14 21:35:40 +03:00
|
|
|
class world final
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
world() = default;
|
|
|
|
world(const world &) = default;
|
|
|
|
world(world &&) = default;
|
|
|
|
world &operator=(const world &) = default;
|
|
|
|
world &operator=(world &&) = default;
|
|
|
|
|
2025-02-14 22:18:00 +03:00
|
|
|
entity make_entity();
|
2025-02-14 21:41:36 +03:00
|
|
|
void destroy_entity(entity_id e);
|
2025-02-14 21:35:40 +03:00
|
|
|
bool is_alive(entity_id e) const;
|
2025-02-14 23:42:01 +03:00
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
bool has(entity_id e) const;
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
T& get(entity_id e);
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
void set(entity_id e, const T& comp = T{});
|
2025-02-14 21:35:40 +03:00
|
|
|
private:
|
2025-02-14 23:42:01 +03:00
|
|
|
zecsy_bits entities_bitset;
|
2025-02-14 21:35:40 +03:00
|
|
|
entity_id entity_counter = 0;
|
2025-02-14 23:42:01 +03:00
|
|
|
component_storage storage;
|
2025-02-14 21:35:40 +03:00
|
|
|
};
|
|
|
|
|
2025-02-14 22:18:00 +03:00
|
|
|
inline entity::entity(class world* w, entity_id id): w(w), id(id)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
inline entity::operator entity_id() const
|
2025-02-14 21:35:40 +03:00
|
|
|
{
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
2025-02-14 22:18:00 +03:00
|
|
|
inline bool entity::is_alive() const
|
|
|
|
{
|
|
|
|
return w && w->is_alive(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline entity world::make_entity()
|
|
|
|
{
|
2025-02-14 22:27:52 +03:00
|
|
|
auto id = ++entity_counter;
|
|
|
|
|
|
|
|
if(id > MAX_ZECSY_ENTITIES)
|
2025-02-14 22:18:00 +03:00
|
|
|
{
|
2025-02-14 22:27:52 +03:00
|
|
|
throw std::runtime_error(std::format("Entity id {} exceeds "
|
|
|
|
"MAX_ZECSY_ENTITIES ({})", id, MAX_ZECSY_ENTITIES));
|
2025-02-14 22:18:00 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
entities_bitset.set(id);
|
|
|
|
return entity(this, id);
|
|
|
|
}
|
|
|
|
|
2025-02-14 21:41:36 +03:00
|
|
|
inline void world::destroy_entity(entity_id e)
|
|
|
|
{
|
|
|
|
entities_bitset.reset(e);
|
|
|
|
}
|
|
|
|
|
2025-02-14 21:35:40 +03:00
|
|
|
inline bool world::is_alive(entity_id e) const
|
|
|
|
{
|
|
|
|
return entities_bitset.test(e);
|
|
|
|
}
|
2025-02-14 23:42:01 +03:00
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
inline bool world::has(entity_id e) const
|
|
|
|
{
|
|
|
|
return storage.has<T>(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
inline bool component_storage::has(entity_id e) const
|
|
|
|
{
|
|
|
|
if(bitset_dict.contains(typeid(T)))
|
|
|
|
{
|
|
|
|
return bitset_dict.at(typeid(T)).test(e);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
inline T& component_storage::get(entity_id e)
|
|
|
|
{
|
|
|
|
if(!has<T>(e))
|
|
|
|
{
|
|
|
|
throw std::runtime_error(std::format("Entity #{} doesn't have {}",
|
|
|
|
e, typeid(T).name()));
|
|
|
|
}
|
|
|
|
|
|
|
|
auto index = entity_dict[typeid(T)].at(e);
|
|
|
|
|
|
|
|
auto* ptr = reinterpret_cast<T*>(&storage_dict[typeid(T)][0]);
|
|
|
|
ptr += index;
|
|
|
|
|
|
|
|
return *ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
inline bool entity::has() const
|
|
|
|
{
|
|
|
|
return w->has<T>(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
inline T& world::get(entity_id e)
|
|
|
|
{
|
|
|
|
return storage.get<T>(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
inline T& entity::get()
|
|
|
|
{
|
|
|
|
return w->get<T>(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
inline void component_storage::set(entity_id id, const T& comp)
|
|
|
|
{
|
|
|
|
bitset_dict[typeid(T)].set(id);
|
|
|
|
|
|
|
|
auto& storage = storage_dict[typeid(T)];
|
|
|
|
|
|
|
|
size_t T_size = sizeof(T);
|
|
|
|
size_t old_size = storage.size();
|
|
|
|
|
|
|
|
storage.resize(old_size + T_size);
|
|
|
|
void* ptr = &storage[0] + old_size;
|
|
|
|
new(ptr) T(comp);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
inline void world::set(entity_id e, const T& comp)
|
|
|
|
{
|
|
|
|
storage.set(e, comp);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
inline void entity::set(const T& comp)
|
|
|
|
{
|
|
|
|
w->set(id, comp);
|
|
|
|
}
|
2025-02-14 21:35:40 +03:00
|
|
|
};
|