diff options
author | quou <quou@disroot.org> | 2025-01-18 16:19:34 +1100 |
---|---|---|
committer | quou <quou@disroot.org> | 2025-01-18 16:19:34 +1100 |
commit | 025510f2928e123d12a7d6d3574ca70fdd9d7717 (patch) | |
tree | 5295711f97c7a437c2b1192534ad62f98e89c177 /world.hpp | |
parent | 9c9073374e1a8a21f6f46f6abfc5be853dbf3b45 (diff) |
ECS
Diffstat (limited to 'world.hpp')
-rw-r--r-- | world.hpp | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/world.hpp b/world.hpp new file mode 100644 index 0000000..267b58a --- /dev/null +++ b/world.hpp @@ -0,0 +1,178 @@ +#ifndef world_hpp +#define world_hpp + +struct Arena; + +#include <stdint.h> + +#include <new> +#include <utility> + +using Component_Mask = uint64_t; +using Entity_Id = uint32_t; + +#define max_entities 1024 +#define pool_cap 128 +#define max_components 64 + +struct Pool { + Component_Mask mask; + Pool* next; + void* data; + Entity_Id entities[pool_cap]; + int mapping[max_entities]; + int offsets[max_components]; + int size, count; + + void init(Arena* a, Component_Mask m); + void* add(Arena* a, Entity_Id eid); + void* get(Entity_Id eid, int cid); + void* get(Entity_Id eid); + void remove(Entity_Id eid); +}; + +int entity_version(Entity_Id e); +int entity_index(Entity_Id e); +Entity_Id entity_id(int index, int version); +int get_new_component_id(int size); + +struct World { + static constexpr int max_pools = 32; + Pool pools[max_pools]; + Component_Mask masks[max_entities]; + uint8_t versions[max_entities]; + Entity_Id entities[max_entities]; + Entity_Id freelist[max_entities]; + Arena* arena; + int count, free_count; + + void init(Arena* a); + uint64_t hash_mask(Component_Mask m); + Pool& get_pool(Component_Mask m); + + template <typename T> + int get_component_id() { + static int id = get_new_component_id(sizeof(T)); + return id; + } + + Entity_Id create_entity(); + + template <typename... T> + Component_Mask get_mask() { + return (... | ((Component_Mask)1 << get_component_id<T>())); + } + + template <typename... T> + std::tuple<T&...> add(Entity_Id e) { + Component_Mask m = get_mask<T...>(); + add(e, m); + Pool& p = get_pool(masks[entity_index(e)]); + return { *(T*)p.get(e, get_component_id<T>())... }; + } + + template <typename T> + T& get(Entity_Id e) { + int id = get_component_id<T>(); + return *(T*)get(e, id); + } + + template <typename T> + void remove(Entity_Id e) { + int id = get_component_id<T>(); + remove(e, id); + } + + template <typename T> + bool has(Entity_Id e) { + int id = get_component_id<T>(); + Component_Mask m = masks[entity_index(e)]; + return (m & ((Component_Mask)1 << id)) != 0; + } + + void* add(Entity_Id eid, Component_Mask m); + void* get(Entity_Id eid, int cid); + void remove(Entity_Id eid, int cid); + void destroy(Entity_Id e); + + struct View { + World* w; + Pool* pools[max_pools]; + int pool_count; + + struct Iter { + View* v; + int ptr, ind; + + bool equals(const Iter& other) { + return ptr == other.ptr && ind == other.ind; + } + bool operator==(const Iter& other) { + return equals(other); + } + bool operator!=(const Iter& other) { + return !equals(other); + } + Iter operator++() { + Pool* p = v->pools[ind]; + ptr++; + if (ptr == p->count) { + ptr = 0; + ind++; + } + return *this; + } + + template <typename C> + C& get() { + Pool* p = v->pools[ind]; + return *(C*)( + (char*)p->data + ptr * p->size + + p->offsets[v->w->get_component_id<C>()] + ); + } + + Iter& operator*() { + return *this; + } + + Entity_Id entity() { + Pool* p = v->pools[ind]; + return p->entities[ptr]; + } + }; + + Iter begin() { + Iter i; + i.v = this; + i.ind = 0; + i.ptr = 0; + return i; + } + + Iter end() { + Iter i; + i.v = this; + i.ind = pool_count; + i.ptr = 0; + return i; + } + }; + + template <typename... T> + View view() { + int i; + auto m = get_mask<T...>(); + View v; + v.w = this; + v.pool_count = 0; + for (i = 0; i < max_pools; i++) { + Pool& p = pools[i]; + if (p.count && m == (p.mask & m)) + v.pools[v.pool_count++] = &p; + } + return v; + } +}; + +#endif |