diff --git a/becs.h b/becs.h index 58c0ac1..9497e36 100644 --- a/becs.h +++ b/becs.h @@ -22,7 +22,7 @@ #include #include -#ifdef BECS_SLOW +#ifndef BECS_NO_ASSERT #include #else #define assert(expression) @@ -59,7 +59,7 @@ bool BECS_ComponentHas(BECS_ECS *ecs, BECS_Entity entity, BECS_ComponentID compo #define BECS_MAX_COMPONENTS 64 #endif /* BECS_MAX_COMPONENTS */ -#define BECS_NULL_ENTITY BECS_MAX_COMPONENTS + 1 +#define BECS_NULL_ENTITY BECS_MAX_ENTITIES + 1 #define BECS_INVALID_COMPONENT_ID UINT32_MAX typedef uint64_t BECS_Signature; @@ -86,7 +86,7 @@ struct BECS_ECS { BECS_Entity nextEntity; uint32_t entityCount; BECS_Signature entitySignatures[BECS_MAX_ENTITIES]; - bool aliveEntites[BECS_MAX_ENTITIES]; + bool aliveEntities[BECS_MAX_ENTITIES]; BECS_Entity freeEntities[BECS_MAX_ENTITIES]; uint32_t freeEntityCount; @@ -116,6 +116,10 @@ static bool BECS_SignatureMatches(BECS_Signature entitySig, BECS_Signature query BECS_Arena BECS_CreateArena(void *memory, size_t capacity) { + assert(memory != NULL); + assert(capacity > 0); + + /* Align base offset to 64 byte boundary */ uintptr_t baseOffset = 64 - ((uintptr_t)memory % 64); BECS_Arena arena = {}; arena.nextAllocation = baseOffset; @@ -126,6 +130,9 @@ BECS_Arena BECS_CreateArena(void *memory, size_t capacity) static void *BECS_AllocateMemory(BECS_Arena *arena, size_t size) { + assert(arena != NULL); + assert(size > 0); + size_t totalSizeBytes = size; uintptr_t nextAllocOffset = arena->nextAllocation + ((64 - (arena->nextAllocation % 64)) & 63); if (nextAllocOffset + totalSizeBytes <= arena->capacity) @@ -144,6 +151,9 @@ static void *BECS_AllocateMemory(BECS_Arena *arena, size_t size) static void BECS_ComponentPoolInit (BECS_Arena *arena, BECS_ComponentPool *pool ,size_t componentSize, size_t capacity) { + assert(arena != NULL); + assert(capacity <= BECS_MAX_ENTITIES); + pool->unitSize = componentSize; pool->capacity = capacity; pool->count = 0; @@ -160,6 +170,9 @@ static void BECS_ComponentPoolInit static void *BECS_ComponentPoolAdd(BECS_ComponentPool *pool, BECS_Entity entity) { + assert(pool->count < pool->capacity); + assert(entity < BECS_MAX_ENTITIES); + uint32_t index = pool->count; pool->count++; pool->denseEntityMapping[index] = entity; @@ -170,6 +183,8 @@ static void *BECS_ComponentPoolAdd(BECS_ComponentPool *pool, BECS_Entity entity) static void BECS_ComponentPoolRemove(BECS_ComponentPool *pool, BECS_Entity entity) { + assert(entity < BECS_MAX_ENTITIES); + uint32_t index = pool->sparseArray[entity]; if (index == UINT32_MAX) { @@ -194,6 +209,8 @@ static void BECS_ComponentPoolRemove(BECS_ComponentPool *pool, BECS_Entity entit static void *BECS_ComponentPoolGet(BECS_ComponentPool *pool, BECS_Entity entity) { + assert(entity < BECS_MAX_ENTITIES); + uint32_t index = pool->sparseArray[entity]; if (index == UINT32_MAX) { @@ -205,6 +222,7 @@ static void *BECS_ComponentPoolGet(BECS_ComponentPool *pool, BECS_Entity entity) static bool BECS_ComponentPoolHas(BECS_ComponentPool *pool, BECS_Entity entity) { + assert(entity < BECS_MAX_ENTITIES); return pool->sparseArray[entity] != UINT32_MAX; } @@ -212,7 +230,9 @@ static bool BECS_ComponentPoolHas(BECS_ComponentPool *pool, BECS_Entity entity) size_t BECS_GetMinMemoryArenaSize(size_t *componentSizes, size_t arrayLength) { - assert(arrayLength < BECS_MAX_COMPONENTS); + assert(componentSizes != NULL); + assert(arrayLength <= BECS_MAX_COMPONENTS); + size_t totalSize = 0; totalSize += sizeof(BECS_ECS); totalSize += sizeof(BECS_ComponentPool) * BECS_MAX_COMPONENTS; @@ -235,11 +255,14 @@ size_t BECS_GetMinMemoryArenaSize(size_t *componentSizes, size_t arrayLength) BECS_ECS BECS_InitECS(void *memory, size_t size) { + assert(memory != NULL); + assert(size > 0); + BECS_ECS ecs; ecs.arena = BECS_CreateArena(memory, size); ecs.entityCount = 0; memset(ecs.entitySignatures, 0, sizeof(BECS_Signature) * BECS_MAX_ENTITIES); - memset(ecs.aliveEntites, false, sizeof(bool) * BECS_MAX_ENTITIES); + memset(ecs.aliveEntities, false, sizeof(bool) * BECS_MAX_ENTITIES); memset(ecs.freeEntities, BECS_NULL_ENTITY, sizeof(BECS_Entity) * BECS_MAX_ENTITIES); ecs.freeEntityCount = 0; ecs.nextEntity = 0; @@ -257,10 +280,15 @@ BECS_ECS BECS_InitECS(void *memory, size_t size) void BECS_ResetECS(BECS_ECS *ecs) { + if (!ecs) + { + return; + } + ecs->arena = BECS_CreateArena(ecs->arena.memory, ecs->arena.capacity); ecs->entityCount = 0; memset(ecs->entitySignatures, 0, sizeof(BECS_Signature) * BECS_MAX_ENTITIES); - memset(ecs->aliveEntites, false, sizeof(bool) * BECS_MAX_ENTITIES); + memset(ecs->aliveEntities, false, sizeof(bool) * BECS_MAX_ENTITIES); memset(ecs->freeEntities, BECS_NULL_ENTITY, sizeof(BECS_Entity) * BECS_MAX_ENTITIES); ecs->freeEntityCount = 0; ecs->nextEntity = 0; @@ -278,9 +306,11 @@ void BECS_ResetECS(BECS_ECS *ecs) BECS_Entity BECS_EntityCreate(BECS_ECS *ecs) { + assert(ecs != NULL); + BECS_Entity entity = BECS_NULL_ENTITY; - if (ecs->nextEntity + 1 > BECS_NULL_ENTITY) + if (ecs->nextEntity + 1 > BECS_MAX_ENTITIES) { return entity; } @@ -290,12 +320,12 @@ BECS_Entity BECS_EntityCreate(BECS_ECS *ecs) /* Pop entity off the back of the free list */ entity = ecs->freeEntities[--ecs->freeEntityCount]; ecs->entitySignatures[entity] = 0; - ecs->aliveEntites[entity] = true; + ecs->aliveEntities[entity] = true; return entity; } entity = ecs->nextEntity; - ecs->aliveEntites[entity] = true; + ecs->aliveEntities[entity] = true; ecs->entitySignatures[entity] = 0; ecs->nextEntity++; ecs->entityCount++; @@ -304,7 +334,10 @@ BECS_Entity BECS_EntityCreate(BECS_ECS *ecs) void BECS_EntityDestroy(BECS_ECS *ecs, BECS_Entity entity) { - if (!ecs->aliveEntites[entity]) + assert(ecs != NULL); + assert(entity >= 0 && entity < BECS_MAX_ENTITIES); + + if (!ecs->aliveEntities[entity]) { return; } @@ -319,7 +352,7 @@ void BECS_EntityDestroy(BECS_ECS *ecs, BECS_Entity entity) } } - ecs->aliveEntites[entity] = false; + ecs->aliveEntities[entity] = false; ecs->entitySignatures[entity] = 0; ecs->freeEntities[ecs->freeEntityCount] = entity; ecs->entityCount--; @@ -328,13 +361,23 @@ void BECS_EntityDestroy(BECS_ECS *ecs, BECS_Entity entity) bool BECS_IsEntityAlive(BECS_ECS *ecs, BECS_Entity entity) { - return ecs->aliveEntites[entity]; + assert(ecs != NULL); + + if (entity >= BECS_MAX_ENTITIES || entity == BECS_NULL_ENTITY) + { + return false; + } + return ecs->aliveEntities[entity]; } /* Component API Functions */ BECS_ComponentID BECS_ComponentRegister(BECS_ECS *ecs, size_t componentSize, size_t maximumComponentCount) { + assert(ecs != NULL); + assert(ecs->componentTypeCount < BECS_MAX_COMPONENTS); + assert(componentSize > 0); + if (maximumComponentCount == 0) { maximumComponentCount = BECS_MAX_ENTITIES; @@ -350,6 +393,11 @@ BECS_ComponentID BECS_ComponentRegister(BECS_ECS *ecs, size_t componentSize, siz void *BECS_ComponentAdd(BECS_ECS *ecs, BECS_Entity entity, BECS_ComponentID componentId) { + assert(ecs != NULL); + assert(entity >= 0 && entity < BECS_MAX_ENTITIES); + assert(componentId < ecs->componentTypeCount); + assert(ecs->aliveEntities[entity]); + void *component = BECS_ComponentPoolAdd(&ecs->componentPools[componentId], entity); ecs->entitySignatures[entity] = BECS_SignatureSet(ecs->entitySignatures[entity], componentId); memset(component, 0, ecs->componentPools[componentId].unitSize); @@ -358,7 +406,11 @@ void *BECS_ComponentAdd(BECS_ECS *ecs, BECS_Entity entity, BECS_ComponentID comp void BECS_ComponentRemove(BECS_ECS *ecs, BECS_Entity entity, BECS_ComponentID componentId) { - if (!ecs->aliveEntites[entity]) + assert(ecs != NULL); + assert(entity >= 0 && entity < BECS_MAX_ENTITIES); + assert(componentId < ecs->componentTypeCount); + + if (!ecs->aliveEntities[entity]) { return; } @@ -368,8 +420,11 @@ void BECS_ComponentRemove(BECS_ECS *ecs, BECS_Entity entity, BECS_ComponentID co void *BECS_ComponentGet(BECS_ECS *ecs, BECS_Entity entity, BECS_ComponentID componentId) { + assert(ecs != NULL); + assert(entity >= 0 && entity < BECS_MAX_ENTITIES); + assert(componentId < ecs->componentTypeCount); - if (!ecs->aliveEntites[entity]) + if (!ecs->aliveEntities[entity]) { return NULL; } @@ -378,7 +433,11 @@ void *BECS_ComponentGet(BECS_ECS *ecs, BECS_Entity entity, BECS_ComponentID comp bool BECS_ComponentHas(BECS_ECS *ecs, BECS_Entity entity, BECS_ComponentID componentId) { - if (!ecs->aliveEntites[entity]) + assert(ecs != NULL); + assert(entity >= 0 && entity < BECS_MAX_ENTITIES); + assert(componentId < ecs->componentTypeCount); + + if (!ecs->aliveEntities[entity]) { return false; } diff --git a/test/main.c b/test/main.c index ad24195..b1bfb75 100644 --- a/test/main.c +++ b/test/main.c @@ -48,6 +48,20 @@ int main(void) { BECS_Entity entity1 = BECS_EntityCreate(&ecs); BECS_Entity entity2 = BECS_EntityCreate(&ecs); + uint32_t i; + for (i = 0; i < BECS_MAX_ENTITIES; i++) + { + BECS_Entity entity = BECS_EntityCreate(&ecs); + if (entity != BECS_NULL_ENTITY) + { + printf("%u\n", entity); + } + else + { + printf("Reached Max Entity Count\n"); + } + } + BECS_ComponentAdd(&ecs, entity1, COMPA); BECS_ComponentAdd(&ecs, entity2, COMPB); @@ -74,5 +88,14 @@ int main(void) { printf("Entity:%u has compB\n", entity2); } + compA *thingA = (compA *)BECS_ComponentGet(&ecs, entity1, COMPA); + compB *thingB = (compB *)BECS_ComponentGet(&ecs, entity1, COMPB); + + BECS_ComponentRemove(&ecs, entity1, COMPA); + BECS_ComponentRemove(&ecs, entity2, COMPB); + + BECS_ComponentRemove(&ecs, entity1, COMPB); + BECS_ComponentRemove(&ecs, entity2, COMPA); + return 0; }