// A very simple library for constructing the basis of EXTREMELY simple ecs // systems. Made mostly for fun #ifndef __HALOO3D_ECS_H #define __HALOO3D_ECS_H #include #include #include #ifndef HECS_MAXENTITIES #define HECS_MAXENTITIES 1024 #endif typedef uint64_t hecs_cidt; typedef int hecs_eidt; #define HECS_MAXCTYPES 63 // One minus the thing typedef struct { hecs_cidt e_components[HECS_MAXENTITIES]; void *components[HECS_MAXCTYPES]; int numcomponents; hecs_eidt entitytop; } haloo_ecs; static void haloo_ecs_init(haloo_ecs *ecs) { memset(ecs, 0, sizeof(haloo_ecs)); } // Add an entity with given components to ecs system. static hecs_eidt haloo_ecs_newentity(haloo_ecs *ecs, hecs_cidt basecomponents) { for (int i = 0; i < HECS_MAXENTITIES; i++) { hecs_eidt id = ecs->entitytop++; if (ecs->e_components[id] == 0) { // Utilize the very last bit to indicate that the entity is active ecs->e_components[id] = (1ULL << HECS_MAXCTYPES) | basecomponents; return id; } } return -1; } static int haloo_ecs_match(haloo_ecs *ecs, hecs_eidt eid, hecs_cidt comps) { hecs_cidt realcomps = (1ULL << HECS_MAXCTYPES) | comps; return (ecs->e_components[eid] & realcomps) == realcomps; } static void haloo_ecs_removeentity(haloo_ecs *ecs, int eid) { if (eid >= 0 && eid < HECS_MAXENTITIES) ecs->e_components[eid] = 0; } // Add a new component to ecs. Create the type or storage with // HECS_NEWCOMPONENT(type, name) static int haloo_ecs_newcomponent(haloo_ecs *ecs, void *component) { int id = ecs->numcomponents++; ecs->components[id] = component; return id; } // Convert component id into flag for use with system identification #define HECS_CIDF(id) (1ULL << id) // Shortcut to both create the storage and add it to the given ecs. // Automatically stores the name as __type. Stores the id for the component in // type_id. For convenience, another variable of type_f is created for the flag // version of the component id #define HECS_ADDNEWCOMPONENT(type, ecs) \ type __##type[HECS_MAXENTITIES]; \ hecs_cidt type##_id = haloo_ecs_newcomponent(ecs, __##type); \ hecs_cidt type##_f = HECS_CIDF(type##_id); // Set component values on a given entity, also sets the flag indicating this // component is now registered with the given entity. You should follow this // statement immediately with the values for your component. // Example: HECS_SETCOMPONENT(mytype, &ecs, playerid) { .x = 1, .y = 2 } #define HECS_SETCOMPONENT(type, ecs, eid) \ (ecs)->e_components[eid] |= type##_f; \ __##type[eid] = (type) // Retrieve a component for a single entity from the entity system, // casting it to the given type #define HECS_ENTITYCOMPONENT(type, eid, cid, ecs) \ (((type)ecs->components[cid]) + eid) // Run a function against ecs using the given limiting components. Note that // components MUST be passed in the EXACT order the function expects them! #define HECS_RUNSYS(ecs, eid, func, ...) \ { \ const hecs_cidt _hecstemp[] = {__VA_ARGS__}; \ const int _hecsnumargs = sizeof(_hecstemp) / sizeof(hecs_cidt); \ hecs_cidt _hecsflags = 0; \ /*eprintf("MADE ARGS: %d\n", _hecsnumargs);*/ \ for (int _hecsi = 0; _hecsi < _hecsnumargs; _hecsi++) { \ _hecsflags |= HECS_CIDF(_hecstemp[_hecsi]); \ } \ if (haloo_ecs_match(ecs, eid, _hecsflags)) { \ func(ecs, eid, __VA_ARGS__); \ } \ } #endif