diff --git a/include/arc/std/entity.h b/include/arc/std/entity.h index 02ca6a1..011b49b 100644 --- a/include/arc/std/entity.h +++ b/include/arc/std/entity.h @@ -5,6 +5,8 @@ extern "C" { #endif +#include "arc/std/array.h" +#include "arc/std/bool.h" #include /** @@ -17,6 +19,14 @@ typedef struct ARC_EntitySystem ARC_EntitySystem; */ typedef uint32_t ARC_Entity; +/** + * @brief an entity component system type +*/ +typedef enum ARC_EntityFlags { + ARC_ENTITY_DEAD = 0, + ARC_ENTITY_ALIVE = 1 +} ARC_EntityFlags; + /** * @brief an entity component system type */ @@ -35,15 +45,51 @@ void ARC_EntitySystem_Create(ARC_EntitySystem **entitySystem); /** * @brief destroys an ARC_EntitySystem * - * @param[in] vector ARC_EntitySystem to free + * @param[in] entitySystem ARC_EntitySystem to free */ void ARC_EntitySystem_Destroy(ARC_EntitySystem *entitySystem); -void ARC_EntitySystem_RegisterComponent(ARC_EntitySystem *entitySystem, uint32_t componentSize); +/** + * @brief registers space for a component and an id for the compenent within the entity system + * + * @note this function will set arc_errno if the components run out of space + * + * @param[in] entitySystem the entity system to register the component to + * @param[in] componentSize the size of the component to register + * + * @return an id for for the component +*/ +uint32_t ARC_EntitySystem_RegisterComponent(ARC_EntitySystem *entitySystem, uint32_t componentSize); -//void ARC_EntitySystem_RunSystem(ARC_EntitySystem *entitySystem, ARC_Component component); +/** + * @brief +*/ +ARC_Entity ARC_EntitySystem_InitEntity(ARC_EntitySystem *entitySystem); -void ARC_EntitySystem_Run(ARC_EntitySystem *entitySystem); +/** + * @brief +*/ +void ARC_EntitySystem_ReleaseEntity(ARC_EntitySystem *entitySystem, ARC_Entity entity); + +/** + * @brief +*/ +void ARC_EntitySystem_AddComponent(ARC_EntitySystem *entitySystem, ARC_Entity entity, ARC_EntityComponent component, void *data); + +/** + * @brief +*/ +ARC_Bool ARC_EntitySystem_HasComponent(ARC_EntitySystem *entitySystem, ARC_Entity entity, ARC_EntityComponent component); + +/** + * @brief +*/ +void *ARC_EntitySystem_GetComponentData(ARC_EntitySystem *entitySystem, ARC_Entity entity, ARC_EntityComponent component); + +/** + * @brief +*/ +ARC_Array ARC_EntitySystem_QueryComponentsData(ARC_EntitySystem *entitySystem, uint32_t components); #ifdef __cplusplus } diff --git a/src/std/entity.c b/src/std/entity.c index c65c308..ebe1414 100644 --- a/src/std/entity.c +++ b/src/std/entity.c @@ -1,31 +1,174 @@ #include "arc/std/entity.h" +#include "arc/std/array.h" +#include "arc/std/errno.h" #include "arc/std/bool.h" -#include "arc/std/vector.h" +#include "arc/std/vector/inline.h" #include +#include //TODO: might want to change how vector holds data for speed struct ARC_EntitySystem { - ARC_Vector *flagVector; - ARC_Vector *maskVector; + //entity data + ARC_VectorInline *flagVector; + ARC_VectorInline *maskVector; - void *data; + //component data + ARC_VectorInline *offsetVector; + ARC_VectorInline *sizeVector; + + //stored component data + ARC_VectorInline *data; + + //TODO: this would probs be better to use a queue + ARC_VectorInline *freeEntities; }; ARC_Bool ARC_EntitySystem_VectorCompareDataFn(void *dataA, void *dataB){ return (ARC_Bool)(*(uint32_t *)dataA == *(uint32_t *)dataB); } -void ARC_EntitySystem_VectorDestroyDataFn(void *data){ - free((uint32_t *)data); -} - void ARC_EntitySystem_Create(ARC_EntitySystem **entitySystem){ *entitySystem = (ARC_EntitySystem *)malloc(sizeof(ARC_EntitySystem)); - ARC_Vector_CompareDataFn compareDataFn = ARC_EntitySystem_VectorCompareDataFn; - ARC_Vector_DestroyDataFn destroyDataFn = ARC_EntitySystem_VectorDestroyDataFn; + //ARC_Vector_CompareDataFn compareDataFn = ARC_EntitySystem_VectorCompareDataFn; + //ARC_Vector_DestroyDataFn destroyDataFn = ARC_EntitySystem_VectorDestroyDataFn; - ARC_Vector_Create(&((*entitySystem)->flagVector), &compareDataFn, &destroyDataFn); - ARC_Vector_Create(&((*entitySystem)->maskVector), &compareDataFn, &destroyDataFn); + ARC_VectorInline_Create(&((*entitySystem)->flagVector) , sizeof(uint8_t) , NULL, NULL); + ARC_VectorInline_Create(&((*entitySystem)->maskVector) , sizeof(uint32_t), NULL, NULL); + ARC_VectorInline_Create(&((*entitySystem)->offsetVector), sizeof(uint32_t), NULL, NULL); + ARC_VectorInline_Create(&((*entitySystem)->sizeVector) , sizeof(uint32_t), NULL, NULL); + //can't create the data vector because no components have been registered + (*entitySystem)->data = NULL; + + //TODO: this would probs be better to use a queue + ARC_VectorInline_Create(&((*entitySystem)->freeEntities), sizeof(ARC_Entity), NULL, NULL); +} + +void ARC_EntitySystem_Destroy(ARC_EntitySystem *entitySystem){ + if(entitySystem->data != NULL){ + ARC_VectorInline_Destroy(entitySystem->data); + } + + ARC_VectorInline_Destroy(entitySystem->sizeVector); + ARC_VectorInline_Destroy(entitySystem->offsetVector); + ARC_VectorInline_Destroy(entitySystem->maskVector); + ARC_VectorInline_Destroy(entitySystem->flagVector); + + free(entitySystem); +} + +uint32_t ARC_EntitySystem_RegisterComponent(ARC_EntitySystem *entitySystem, uint32_t componentSize){ + //error if componentSize is zero, it must have been an error because a component is a type, and types have size + if(componentSize == 0){ + arc_errno = ARC_ERRNO_NULL; + ARC_DEBUG_LOG_ERROR("ARC_EntitySystem_RegisterComponent(entitySystem, componentSize), cannot add a component that does not have a size"); + return ~(uint32_t)0; + } + + //if data exists, free it to recreate it with the new size + if(entitySystem->data != NULL){ + ARC_VectorInline_Destroy(entitySystem->data); + } + + //get the total component size + uint32_t offsetEndIndex = ARC_VectorInline_GetSize(entitySystem->offsetVector); + uint32_t totalSize = *(uint32_t *)ARC_VectorInline_Get(entitySystem->offsetVector, offsetEndIndex); + + //if the new component size would overflow, throw an error + if(totalSize > (~(uint32_t)0) - componentSize){ + arc_errno = ARC_ERRNO_NULL; + ARC_DEBUG_LOG_ERROR("ARC_EntitySystem_RegisterComponent(entitySystem, componentSize), cannot add a component because combined size with all the other components is bigger than a uint32_t max val"); + return ~(uint32_t)0; + } + + //add the component size to the total size and the offset vector array + ARC_VectorInline_Add(entitySystem->offsetVector, &totalSize); + ARC_VectorInline_Add(entitySystem->sizeVector , &componentSize); + totalSize += componentSize; + + //create the resized data vector that can now house the registered component + ARC_VectorInline_Create(&(entitySystem->data), totalSize, NULL, NULL); + + //get the id (last index) in the offset vector + return ARC_VectorInline_GetSize(entitySystem->offsetVector) - 1; +} + +ARC_Entity ARC_EntitySystem_InitEntity(ARC_EntitySystem *entitySystem){ + //check if there is a free id to use + if(ARC_VectorInline_GetSize(entitySystem->freeEntities) != 0){ + //get the next free entity and remove the used id from the free entities + ARC_Entity entity = *(ARC_Entity *)ARC_VectorInline_Get(entitySystem->freeEntities, 0); + ARC_VectorInline_RemoveIndex(entitySystem->freeEntities, 0); + + //set the flag to make the current entity alive + uint8_t *flagData = (uint8_t *)ARC_VectorInline_Get(entitySystem->flagVector, (uint32_t)entity); + *flagData = (uint8_t)ARC_ENTITY_ALIVE; + + //reset the mask data to clear all the components + uint8_t *maskData = (uint8_t *)ARC_VectorInline_Get(entitySystem->maskVector, (uint32_t)entity); + *maskData = 0; + + //return the entity + return entity; + } + + //get the next free entity + ARC_Entity entity = (ARC_Entity)ARC_VectorInline_GetSize(entitySystem->data); + //TODO: check if this works + ARC_VectorInline_Add(entitySystem->data, NULL); + + //set the flag to make the current entity alive + uint8_t *flagData = (uint8_t *)ARC_VectorInline_Get(entitySystem->flagVector, (uint32_t)entity); + *flagData = (uint8_t)ARC_ENTITY_ALIVE; + + //reset the mask data to clear all the components + uint8_t *maskData = (uint8_t *)ARC_VectorInline_Get(entitySystem->maskVector, (uint32_t)entity); + *maskData = 0; + + //return the entity + return entity; +} + +void ARC_EntitySystem_ReleaseEntity(ARC_EntitySystem *entitySystem, ARC_Entity entity){ + //set the flag to make the current entity dead + uint8_t *flagData = (uint8_t *)ARC_VectorInline_Get(entitySystem->flagVector, (uint32_t)entity); + *flagData = (uint8_t)ARC_ENTITY_DEAD; + + //add the entity to the free entities vector + ARC_VectorInline_Add(entitySystem->freeEntities, &entity); +} + +void ARC_EntitySystem_AddComponent(ARC_EntitySystem *entitySystem, ARC_Entity entity, ARC_EntityComponent component, void *data){ + //get the component data to set + uint32_t componentSize = *(uint32_t *)ARC_VectorInline_Get(entitySystem->sizeVector, (uint32_t)component); + void *componentData = ARC_EntitySystem_GetComponentData(entitySystem, entity, component); + + //set the component in the entity mask + uint32_t *maskData = (uint32_t *)ARC_VectorInline_Get(entitySystem->maskVector, (uint32_t)entity); + *maskData |= 1 << (uint32_t)component; + + //copy the data into the component + memcpy(componentData, data, componentSize); +} + +ARC_Bool ARC_EntitySystem_HasComponent(ARC_EntitySystem *entitySystem, ARC_Entity entity, ARC_EntityComponent component){ + //get the mask, then check if it holds a component + uint32_t *maskData = (uint32_t *)ARC_VectorInline_Get(entitySystem->maskVector, (uint32_t)entity); + return (ARC_Bool)((*maskData & (1 << (uint32_t)component)) != 0); +} + +void *ARC_EntitySystem_GetComponentData(ARC_EntitySystem *entitySystem, ARC_Entity entity, ARC_EntityComponent component){ + //get the entity row, then offset that for the component to get the component data + void *data = ARC_VectorInline_Get(entitySystem->data, (uint32_t)entity); + return data + *(int32_t *)ARC_VectorInline_Get(entitySystem->offsetVector, (uint32_t)component); +} + + +ARC_Array ARC_EntitySystem_QueryComponentsData(ARC_EntitySystem *entitySystem, uint32_t components){ + ARC_Array componentsData = { 0, NULL }; + + componentsData.size = ARC_VectorInline_GetSize(entitySystem->data) - ARC_VectorInline_GetSize(entitySystem->freeEntities); + + return componentsData; }