summaryrefslogtreecommitdiff
path: root/world.hpp
diff options
context:
space:
mode:
authorquou <quou@disroot.org>2025-01-18 16:19:34 +1100
committerquou <quou@disroot.org>2025-01-18 16:19:34 +1100
commit025510f2928e123d12a7d6d3574ca70fdd9d7717 (patch)
tree5295711f97c7a437c2b1192534ad62f98e89c177 /world.hpp
parent9c9073374e1a8a21f6f46f6abfc5be853dbf3b45 (diff)
ECS
Diffstat (limited to 'world.hpp')
-rw-r--r--world.hpp178
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