Made a big mess of the codebase

This commit is contained in:
2025-08-28 07:14:13 -05:00
parent 30232d1275
commit af1329710d
44 changed files with 1363 additions and 388 deletions

View File

@@ -0,0 +1,11 @@
# Copyright (c) 2025 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Sources
target_sources(${DUSK_TARGET_NAME}
PRIVATE
ecssystem.c
ecscomponent.c
)

11
archive/dusk/ecs/ecs.h Normal file
View File

@@ -0,0 +1,11 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
typedef int_fast16_t ecsid_t;

View File

@@ -0,0 +1,124 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "ecscomponent.h"
#include "ecssystem.h"
#include "assert/assert.h"
#include "util/memory.h"
void ecsComponentInitialize(ecscomponent_t *cmp) {
assertNotNull(cmp, "Component pointer cannot be NULL.");
assertTrue(
ECS_SYSTEM.componentCount < ECS_SYSTEM_ECS_COMPONENTS_MAX,
"ECS Component count exceeded maximum limit."
);
memoryZero(cmp->data, sizeof(ecscomponent_t));
if(cmp->callbacks.init) cmp->callbacks.init();
cmp->componentFlags |= ECS_COMPONENT_FLAG_INITIALIZED;
ECS_SYSTEM.components[ECS_SYSTEM.componentCount++] = cmp;
}
bool_t ecsComponentIsInitialized(const ecscomponent_t *cmp) {
assertNotNull(cmp, "Component pointer cannot be NULL.");
return (cmp->componentFlags & ECS_COMPONENT_FLAG_INITIALIZED) != 0;
}
bool_t ecsComponentDataHas(const ecscomponent_t *cmp, const ecsid_t id) {
assertTrue(
id >= 0 && id < ECS_ENTITY_COUNT_MAX,
"Invalid entity ID."
);
if(!ecsComponentIsInitialized(cmp)) return false;
return cmp->entityFlags[id] & ECS_COMPONENT_ENTITY_FLAG_USED;
}
void * ecsComponentDataGet(const ecscomponent_t *cmp, const ecsid_t id) {
assertTrue(ecsComponentDataHas(cmp, id), "No data for entity ID.");
return (void *)((uint8_t *)cmp->data + (id * cmp->dataSize));
}
void * ecsComponentDataAdd(ecscomponent_t *cmp, const ecsid_t id) {
if(!ecsComponentIsInitialized(cmp)) ecsComponentInitialize(cmp);
assertTrue(id >= 0 && id < ECS_ENTITY_COUNT_MAX, "Invalid entity ID.");
assertFalse(ecsComponentDataHas(cmp, id), "Entity already has data.");
memoryZero(
(uint8_t *)cmp->data + (id * cmp->dataSize),
cmp->dataSize
);
cmp->entityFlags[id] |= ECS_COMPONENT_ENTITY_FLAG_USED;
if(cmp->callbacks.entityAdd) cmp->callbacks.entityAdd(id);
cmp->entitiesWithData[cmp->entitiesWithDataCount++] = id;
return ecsComponentDataGet(cmp, id);
}
void ecsComponentDataRemove(ecscomponent_t *cmp, const ecsid_t id) {
assertTrue(
ecsComponentIsInitialized(cmp), "Component was never initialized."
);
assertTrue(ecsComponentDataHas(cmp, id), "Entity does not have data.");
cmp->entityFlags[id] = 0;
// Remove entity from the entitiesWithData array by finding its index and
// shifting the rest of the array down. Use memoryCopy to avoid
// unnecessary loops.
uint32_t index = 0;
for(; index < cmp->entitiesWithDataCount; index++) {
if(cmp->entitiesWithData[index] == id) break;
}
assertTrue(
index < cmp->entitiesWithDataCount,
"Entity not found in entitiesWithData?"
);
memoryCopy(
&cmp->entitiesWithData[index],
&cmp->entitiesWithData[index + 1],
sizeof(ecsid_t) * (cmp->entitiesWithDataCount - index - 1)
);
if(cmp->callbacks.entityRemove) cmp->callbacks.entityRemove(id);
}
uint32_t ecsComponentGetAll(const ecscomponent_t *cmp, ecsid_t *out) {
assertTrue(
ecsComponentIsInitialized(cmp),
"Component was never initialized."
);
if(!out) return cmp->entitiesWithDataCount;
memoryCopy(
out,
cmp->entitiesWithData,
sizeof(ecsid_t) * cmp->entitiesWithDataCount
);
return cmp->entitiesWithDataCount;
}
void ecsComponentDispose(ecscomponent_t *cmp) {
assertNotNull(cmp, "Component pointer cannot be NULL.");
assertTrue(
ecsComponentIsInitialized(cmp),
"Component was never initialized."
);
for(uint32_t i = 0; i < cmp->entitiesWithDataCount; i++) {
if(cmp->callbacks.entityRemove)
cmp->callbacks.entityRemove(cmp->entitiesWithData[i]);
}
memoryZero(cmp->entityFlags, sizeof(cmp->entityFlags));
cmp->entitiesWithDataCount = 0;
cmp->componentFlags = 0;
}

View File

@@ -0,0 +1,111 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "ecs/ecsentity.h"
#define ECS_COMPONENT_ENTITY_FLAG_USED (1 << 0)
#define ECS_COMPONENT_FLAG_INITIALIZED (1 << 0)
typedef struct {
void (*init)();
void (*entityAdd)(const ecsid_t id);
void (*entityRemove)(const ecsid_t id);
} ecscomponentcallbacks_t;
typedef struct {
void *data;
size_t dataSize;
uint8_t entityFlags[ECS_ENTITY_COUNT_MAX];
uint8_t componentFlags;
ecscomponentcallbacks_t callbacks;
ecsid_t entitiesWithData[ECS_ENTITY_COUNT_MAX];
uint32_t entitiesWithDataCount;;
} ecscomponent_t;
/**
* Initializes an ECS Component.
*
* @param dPointer Pointer to the data that the component owns.
* @param cbs Callback functions for the component.
*/
#define ecsComponentInit(dPointer, cbs) \
(ecscomponent_t){ \
.data = dPointer, \
.dataSize = sizeof(*dPointer), \
.entityFlags = 0, \
.componentFlags = 0, \
.callbacks = (cbs) \
}
/**
* Initializes an ECS Component.
*
* @param cmp Pointer to the ecscomponent_t to initialize.
*/
void ecsComponentInitialize(ecscomponent_t *cmp);
/**
* Checks if the component is initialized.
*
* @param cmp Pointer to the ecscomponent_t.
* @return True if the component is initialized, false otherwise.
*/
bool_t ecsComponentIsInitialized(const ecscomponent_t *cmp);
/**
* Checks if the component has data for a specific entity.
*
* @param cmp Pointer to the ecscomponent_t.
* @param id The ID of the entity to check.
* @return True if the component has data for the entity, false otherwise.
*/
bool_t ecsComponentDataHas(const ecscomponent_t *cmp, const ecsid_t id);
/**
* Gets the data for a specific entity in the component.
*
* @param cmp Pointer to the ecscomponent_t.
* @param id The ID of the entity to get data for.
* @return Pointer to the data for the entity.
*/
void * ecsComponentDataGet(const ecscomponent_t *cmp, const ecsid_t id);
/**
* Adds data for a specific entity in the component.
*
* @param cmp Pointer to the ecscomponent_t.
* @param id The ID of the entity to add data for.
*/
void * ecsComponentDataAdd(ecscomponent_t *cmp, const ecsid_t id);
/**
* Removes data for a specific entity in the component.
*
* @param cmp Pointer to the ecscomponent_t.
* @param id The ID of the entity to remove data for.
*/
void ecsComponentDataRemove(ecscomponent_t *cmp, const ecsid_t id);
/**
* Gets all entities that have data in the component. Passing NULL for out will
* just return the count of entities.
*
* @param cmp Pointer to the ecscomponent_t.
* @param out Pointer to an array to store the entity IDs.
* @return The number of entities with data.
*/
uint32_t ecsComponentGetAll(const ecscomponent_t *cmp, ecsid_t *out);
/**
* Disposes the component, freeing any resources it holds.
*
* @param cmp Pointer to the ecscomponent_t to dispose.
*/
void ecsComponentDispose(ecscomponent_t *cmp);

View File

@@ -0,0 +1,18 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "ecs.h"
#define ECS_ENTITY_FLAG_USED (1 << 0)
#define ECS_ENTITY_COUNT_MAX 2048
typedef struct ecsentity_s {
ecsid_t id;
uint8_t flags;
} ecsentity_t;

View File

@@ -0,0 +1,66 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "ecssystem.h"
#include "util/memory.h"
#include "assert/assert.h"
ecssystem_t ECS_SYSTEM;
void ecsSystemInit() {
memoryZero(&ECS_SYSTEM, sizeof(ecssystem_t));
// Fill ECS ids
for(uint32_t i = 0; i < ECS_ENTITY_COUNT_MAX; i++) {
ECS_SYSTEM.entities[i].id = i;
}
// Fill the available array.
for(uint32_t i = 0; i < ECS_ENTITY_COUNT_MAX; i++) {
ECS_SYSTEM.available[i] = &ECS_SYSTEM.entities[i];
}
ECS_SYSTEM.availableCount = ECS_ENTITY_COUNT_MAX;
}
ecsid_t ecsEntityAdd() {
assertTrue(ECS_SYSTEM.availableCount > 0, "No available entities to create");
// Pop off the last available entity.
ecsentity_t *entity = ECS_SYSTEM.available[--ECS_SYSTEM.availableCount];
assertTrue((entity->flags & ECS_ENTITY_FLAG_USED) == 0, "Entity is used.");
assertTrue(entity->id >= 0, "Entity is invalid.");
assertTrue(entity->id < ECS_ENTITY_COUNT_MAX, "Entity ID out of bounds");
entity->flags |= ECS_ENTITY_FLAG_USED;
return entity->id;
}
void ecsEntityRemove(const ecsid_t id) {
assertTrue(id < ECS_ENTITY_COUNT_MAX, "Invalid entity ID");
ecsentity_t *entity = &ECS_SYSTEM.entities[id];
assertTrue(entity->id >= 0, "Entity is invalid.");
assertTrue((entity->flags & ECS_ENTITY_FLAG_USED) != 0, "Entity is not used.");
// Mark the entity as available.
ECS_SYSTEM.available[ECS_SYSTEM.availableCount++] = entity;
assertTrue(
ECS_SYSTEM.availableCount <= ECS_ENTITY_COUNT_MAX,
"Available count exceeded maximum limit"
);
}
void ecsSystemDispose() {
for(uint32_t i = 0; i < ECS_SYSTEM.componentCount; i++) {
ecscomponent_t *cmp = ECS_SYSTEM.components[i];
ecsComponentDispose(cmp);
assertTrue(cmp->entitiesWithDataCount == 0, "Component still has data.");
}
memoryZero(&ECS_SYSTEM, sizeof(ecssystem_t));
}

View File

@@ -0,0 +1,50 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "ecsentity.h"
#include "ecscomponent.h"
#define ECS_SYSTEM_ECS_COMPONENTS_MAX 64
typedef struct {
ecsentity_t entities[ECS_ENTITY_COUNT_MAX];
ecsentity_t *available[ECS_ENTITY_COUNT_MAX];
uint32_t availableCount;
ecscomponent_t *components[ECS_SYSTEM_ECS_COMPONENTS_MAX];
uint32_t componentCount;
} ecssystem_t;
extern ecssystem_t ECS_SYSTEM;
/**
* Initialize the ECS system.
*/
void ecsSystemInit();
/**
* Create a new entity in the ECS. This locks an id and gives it to the caller,
* who will be responsible for managing the entity's lifecycle.
*
* @return The ID of the newly created entity.
*/
ecsid_t ecsEntityAdd();
/**
* Disposes an entity in the ECS. This will free the entity's ID and make it
* available for reuse.
*
* @param id The ID of the entity to destroy.
*/
void ecsEntityRemove(const ecsid_t id);
/**
* Dispose the ECS system, freeing all resources.
*/
void ecsSystemDispose();