#include "ecs.hpp" TypeSafeInt_B(EntityHandle); const uint64_t maxBucketItemCount = 256; struct EntityBucket { Entity entities[maxBucketItemCount]; }; struct GrBindsBucket { CompGrBinds compGrBinds[maxBucketItemCount]; }; struct InstanceBucket { CompInstance instances[maxBucketItemCount]; }; DynArray entitiesMarkedForRemoval{16}; DynArray EntitiesToBeRemoved{16}; BucketContainer Entities_BucketContainer{}; BucketContainer Comp_GrBinds_BucketContainer{}; BucketContainer Comp_Instance_BucketContainer{}; void ECS_GetEntity_Inner(EntityHandle entHandle, Entity*& ent) { EntityHandle_T entHandle_t{static_cast(entHandle)}; assert(entHandle_t == ECS_UNSET_VAL && "Unknown entity handle"); auto b = Buckets_GetBucketIndex(static_cast(entHandle)); auto e = Buckets_GetItemIndex(static_cast(entHandle)); ent = &Entities_BucketContainer.buckets[b].entities[e]; } void ECS_Init() { Buckets_Init(Entities_BucketContainer); Buckets_Init(Comp_GrBinds_BucketContainer); Buckets_Init(Comp_Instance_BucketContainer); } EntityHandle ECS_CreateEntity_Inner(EntityHandle parentEntHandle) { EntityHandle_T entityHandle_T{Buckets_NewHandle(maxBucketItemCount, Entities_BucketContainer)}; EntityHandle entityHandle{entityHandle_T}; auto b = Buckets_GetBucketIndex(static_cast(entityHandle)); auto e = Buckets_GetItemIndex(static_cast(entityHandle)); Entity *entity = &Entities_BucketContainer.buckets[b].entities[e]; entity->handle = entityHandle; entity->parentHandle = parentEntHandle; return entityHandle; } EntityHandle ECS_CreateEntity(EntityHandle parentEntHandle) { return ECS_CreateEntity_Inner(parentEntHandle); } void ECS_MarkForRemoval(EntityHandle entityHandle) { auto b = Buckets_GetBucketIndex(static_cast(entityHandle)); auto e = Buckets_GetItemIndex(static_cast(entityHandle)); const Entity *ent = &Entities_BucketContainer.buckets[b].entities[e]; assert(ent->isMarkedForRemoval == false && "Entity already marked for removal"); entitiesMarkedForRemoval.Push(entityHandle); } void ECS_Tick(double delta) { EntitiesToBeRemoved.Resize(0); for (long b = 0; b <= Entities_BucketContainer.bucketCounter; ++b) { uint64_t entCount = b == Entities_BucketContainer.bucketCounter ? Entities_BucketContainer.itemCounter >> 32 : maxBucketItemCount; for (long e = 0; e < entCount; ++e) { Entity *ent = &Entities_BucketContainer.buckets[b].entities[e]; if (ent->handle == EntityHandle{EntityHandle_T{0xFFFFFFFFFFFFFFFF}}) continue; if (ent->isMarkedForRemoval) { ent->handle = EntityHandle{EntityHandle_T{0xFFFFFFFFFFFFFFFF}}; ent->parentHandle = EntityHandle{EntityHandle_T{0xFFFFFFFFFFFFFFFF}}; ent->isMarkedForRemoval = false; // TODO destroy components } else { if (entitiesMarkedForRemoval.Has(ent->handle)) { ent->isMarkedForRemoval = true; EntitiesToBeRemoved.Push(ent->handle); continue; } if (EntitiesToBeRemoved.Has(ent->parentHandle)) { ent->isMarkedForRemoval = true; EntitiesToBeRemoved.Push(ent->handle); } } } } entitiesMarkedForRemoval.Resize(0); } CompGrBinds &ECS_CreateGrBinds(EntityHandle entHandle) { Entity *ent = nullptr; ECS_GetEntity_Inner(entHandle, ent); GrBindsHandle_T newHandle{Buckets_NewHandle(maxBucketItemCount, Comp_GrBinds_BucketContainer)}; ent->grBindsHandle = GrBindsHandle{newHandle}; auto b = Buckets_GetBucketIndex(newHandle); auto i = Buckets_GetItemIndex(newHandle); auto &comp = Comp_GrBinds_BucketContainer.buckets[b].compGrBinds[i]; comp.grBindsHandle = ent->grBindsHandle; return comp; } CompGrBinds *ECS_GetGrBinds(EntityHandle entHandle) { Entity *ent = nullptr; ECS_GetEntity_Inner(entHandle, ent); GrBindsHandle_T grBindsHandle_t{static_cast(ent->grBindsHandle)}; if (grBindsHandle_t == ECS_UNSET_VAL) return nullptr; auto b = Buckets_GetBucketIndex(grBindsHandle_t); auto i = Buckets_GetItemIndex(grBindsHandle_t); return &Comp_GrBinds_BucketContainer.buckets[b].compGrBinds[i]; } uint64_t ECS_GetGrBinds_BucketCount() { return Comp_GrBinds_BucketContainer.bucketCounter; } CompGrBinds *ECS_GetGrBinds(uint64_t bucketIndex, uint64_t &itemCount) { if (bucketIndex == Comp_GrBinds_BucketContainer.bucketCounter) { itemCount = Comp_GrBinds_BucketContainer.itemCounter; } else { itemCount = maxBucketItemCount; } return Comp_GrBinds_BucketContainer.buckets[bucketIndex].compGrBinds; } CompInstance &ECS_CreateInstance(EntityHandle entHandle) { Entity *ent = nullptr; ECS_GetEntity_Inner(entHandle, ent); InstanceHandle_T newHandle{Buckets_NewHandle(maxBucketItemCount, Comp_Instance_BucketContainer)}; ent->instanceHandle = InstanceHandle{newHandle}; GrBindsHandle_T grBindsHandle_t{static_cast(ent->grBindsHandle)}; assert(grBindsHandle_t != ECS_UNSET_VAL); auto b2 = Buckets_GetBucketIndex(grBindsHandle_t); auto i2 = Buckets_GetItemIndex(grBindsHandle_t); auto &grBinds = Comp_GrBinds_BucketContainer.buckets[b2].compGrBinds[i2]; auto b = Buckets_GetBucketIndex(newHandle); auto i = Buckets_GetItemIndex(newHandle); auto &comp = Comp_Instance_BucketContainer.buckets[b].instances[i]; comp.grBindsHandle = ent->grBindsHandle; comp.instanceHandle = ent->instanceHandle; comp.index = grBinds.instances.Count(); grBinds.instances.Push({}); comp.ptr = &grBinds.instances[comp.index]; return comp; } CompInstance *ECS_GetInstance(EntityHandle entHandle) { Entity *ent = nullptr; ECS_GetEntity_Inner(entHandle, ent); GrBindsHandle_T grBindsHandle_t{static_cast(ent->grBindsHandle)}; if (grBindsHandle_t == ECS_UNSET_VAL) return nullptr; InstanceHandle_T instanceHandle_t{static_cast(ent->instanceHandle)}; if (instanceHandle_t == ECS_UNSET_VAL) return nullptr; auto b2 = Buckets_GetBucketIndex(grBindsHandle_t); auto i2 = Buckets_GetItemIndex(grBindsHandle_t); auto &grBinds = Comp_GrBinds_BucketContainer.buckets[b2].compGrBinds[i2]; auto b = Buckets_GetBucketIndex(instanceHandle_t); auto i = Buckets_GetItemIndex(instanceHandle_t); auto &comp = Comp_Instance_BucketContainer.buckets[b].instances[i]; comp.ptr = &grBinds.instances[comp.index]; return ∁ }