#ifndef world_hpp #define world_hpp struct Arena; #include #include #include using Component_Mask = uint64_t; using Entity_Id = uint32_t; #define max_entities 1024 #define slinky_size 128 #define max_components 64 #define max_slinkies (max_entities / slinky_size) static_assert((!(slinky_size & (slinky_size - 1)))); /* slinky_size needs to be a power of 2 */ static consteval int get_slinky_size_bit() { int i; int m = slinky_size; for (i = 0; m; m >>= 1, i++); if (i == 0) throw "wtf"; return i - 1; } static constexpr int slinky_size_bit = get_slinky_size_bit(); struct Slinky { Entity_Id* entities; void* data; int count; void init(Arena* a, int size); void* add(Entity_Id eid, int size, int& mapping); void* get(Entity_Id eid, int mapping, int size); void remove(Entity_Id eid, int mapping, int size); }; struct Pool { struct Mapping { int slinky; int mapping; }; Component_Mask mask; Slinky slinkies[max_slinkies]; Mapping mapping[max_entities]; int offsets[max_components]; int size, count, slinky_count; void init(Arena* a, Component_Mask m); Slinky& get_slinky(Arena* a); 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 int get_component_id() { static int id = get_new_component_id(sizeof(T)); return id; } Entity_Id create_entity(); template Component_Mask get_mask() { return (... | ((Component_Mask)1 << get_component_id())); } template std::tuple add(Entity_Id e) { Component_Mask m = get_mask(); add(e, m); Pool& p = get_pool(masks[entity_index(e)]); return { *(T*)p.get(e, get_component_id())... }; } template T& get(Entity_Id e) { int id = get_component_id(); return *(T*)get(e, id); } template void remove(Entity_Id e) { int id = get_component_id(); remove(e, id); } template bool has(Entity_Id e) { int id = get_component_id(); 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 C& get() { Pool* p = v->pools[ind]; Slinky& s = p->slinkies[ptr >> slinky_size_bit]; int si = &s - p->slinkies; int off = ptr - (si << slinky_size_bit); return *(C*)( (char*)s.data + off * p->size + p->offsets[v->w->get_component_id()] ); } Iter& operator*() { return *this; } Entity_Id entity() { Pool* p = v->pools[ind]; Slinky& s = p->slinkies[ptr >> slinky_size_bit]; int si = &s - p->slinkies; int off = ptr - (si << slinky_size_bit); return s.entities[off]; } }; 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 View view() { int i; auto m = get_mask(); 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