/** * Copyright (c) 2026 Dominic Masters * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #include "entitymanager.h" #include "assert/assert.h" #include "util/memory.h" componentdefinition_t COMPONENT_DEFINITIONS[] = { [COMPONENT_TYPE_NULL] = { 0 }, #define X(enm, type, field, iMethod, dMethod) \ [COMPONENT_TYPE_##enm] = { \ .enumName = #enm, \ .name = #field, \ .init = iMethod, \ .dispose = dMethod \ }, #include "componentlist.h" #undef X [COMPONENT_TYPE_COUNT] = { 0 } }; void componentInit( const entityid_t entityId, const componentid_t componentId, const componenttype_t type ) { assertTrue(entityId < ENTITY_COUNT_MAX, "Entity ID OOB"); assertTrue(componentId < ENTITY_COMPONENT_COUNT_MAX, "Component ID OOB"); assertTrue(type < COMPONENT_TYPE_COUNT, "Component type OOB"); assertTrue(type != COMPONENT_TYPE_NULL, "Cannot initialize null component"); componentindex_t index = componentGetIndex(entityId, componentId); component_t *cmp = &ENTITY_MANAGER.components[index]; memoryZero(cmp, sizeof(component_t)); cmp->type = type; if(COMPONENT_DEFINITIONS[type].init) { COMPONENT_DEFINITIONS[type].init(entityId, componentId); } } void * componentGetData( const entityid_t entityId, const componentid_t componentId, const componenttype_t type ) { assertTrue(entityId < ENTITY_COUNT_MAX, "Entity ID OOB"); assertTrue(componentId < ENTITY_COMPONENT_COUNT_MAX, "Component ID OOB"); assertTrue(type < COMPONENT_TYPE_COUNT, "Component type OOB"); assertTrue(type != COMPONENT_TYPE_NULL, "Cannot get data of null component"); componentindex_t index = componentGetIndex(entityId, componentId); component_t *cmp = &ENTITY_MANAGER.components[index]; assertTrue(cmp->type == type, "Component type mismatch"); return &cmp->data; } componentindex_t componentGetIndex( const entityid_t entityId, const componentid_t componentId ) { assertTrue(entityId < ENTITY_COUNT_MAX, "Entity ID OOB"); assertTrue(componentId < ENTITY_COMPONENT_COUNT_MAX, "Component ID OOB"); return (entityId * ENTITY_COMPONENT_COUNT_MAX) + componentId; } entityid_t componentGetEntitiesWithComponent( const componenttype_t type, entityid_t outEntities[ENTITY_COUNT_MAX], componentid_t outComponents[ENTITY_COUNT_MAX] ) { assertTrue(type < COMPONENT_TYPE_COUNT, "Component type OOB"); assertTrue(type != COMPONENT_TYPE_NULL, "Cannot check NULL type"); assertNotNull(outEntities, "Output entities array cannot be null"); assertNotNull(outComponents, "Output components array cannot be null"); entityid_t written = 0; for(entityid_t i = 0; i < ENTITY_COUNT_MAX; i++) { componentid_t used = ENTITY_MANAGER.entitiesWithComponent[ type * ENTITY_COUNT_MAX + i ]; if(used == COMPONENT_ID_INVALID) continue; assertTrue( ENTITY_MANAGER.components[componentGetIndex(i, used)].type == type, "Component type mismatch in entitiesWithComponent lookup" ); assertTrue( (ENTITY_MANAGER.entities[i].state & ENTITY_STATE_ACTIVE) != 0, "Inactive entity in entitiesWithComponent lookup" ); assertTrue( used < ENTITY_COMPONENT_COUNT_MAX, "Component ID OOB in entitiesWithComponent lookup" ); assertTrue( componentGetIndex(i,used) < ENTITY_COUNT_MAX*ENTITY_COMPONENT_COUNT_MAX, "Component index OOB in entitiesWithComponent lookup" ); assertTrue( ENTITY_MANAGER.components[componentGetIndex(i,used)].type == type, "Component type mismatch in entitiesWithComponent lookup" ); outComponents[written] = used; outEntities[written++] = i; } return written; } void componentDispose( const entityid_t entityId, const componentid_t componentId ) { assertTrue(entityId < ENTITY_COUNT_MAX, "Entity ID OOB"); assertTrue(componentId < ENTITY_COMPONENT_COUNT_MAX, "Component ID OOB"); componentindex_t index = componentGetIndex(entityId, componentId); component_t *cmp = &ENTITY_MANAGER.components[index]; if(cmp->type == COMPONENT_TYPE_NULL) return; if(COMPONENT_DEFINITIONS[cmp->type].dispose) { COMPONENT_DEFINITIONS[cmp->type].dispose(entityId, componentId); } cmp->type = COMPONENT_TYPE_NULL; }