From e3e4e5ee84a455cac10f39fa830f2869526f550b Mon Sep 17 00:00:00 2001 From: Eric-Paul Ickhorn Date: Wed, 11 Sep 2024 12:16:57 +0200 Subject: [PATCH] Add first, inperformant version of ECS The ECS can't handle many entities in this state; it is really slow. This commit also doesn't contain any tests for its functions. --- modules/ecs/inc-c/voxula/internals/ecs.h | 24 +++++++ .../ecs/inc-c/voxula/internals/ecs/entity.h | 20 ++++++ modules/ecs/inc-c/voxula/internals/ecs/head.h | 69 +++++++++++++++++++ .../ecs/inc-c/voxula/internals/ecs/lookup.h | 33 +++++++++ modules/ecs/src-c/entity.c | 25 +++++++ modules/ecs/src-c/head.c | 21 ++++++ modules/ecs/src-c/lookup.c | 55 +++++++++++++++ modules/ecs/src-c/name-resolver.c | 61 ++++++++++++++++ 8 files changed, 308 insertions(+) create mode 100644 modules/ecs/inc-c/voxula/internals/ecs.h create mode 100644 modules/ecs/inc-c/voxula/internals/ecs/entity.h create mode 100644 modules/ecs/inc-c/voxula/internals/ecs/head.h create mode 100644 modules/ecs/inc-c/voxula/internals/ecs/lookup.h create mode 100644 modules/ecs/src-c/entity.c create mode 100644 modules/ecs/src-c/head.c create mode 100644 modules/ecs/src-c/lookup.c create mode 100644 modules/ecs/src-c/name-resolver.c diff --git a/modules/ecs/inc-c/voxula/internals/ecs.h b/modules/ecs/inc-c/voxula/internals/ecs.h new file mode 100644 index 0000000..ee80d4a --- /dev/null +++ b/modules/ecs/inc-c/voxula/internals/ecs.h @@ -0,0 +1,24 @@ + +#ifndef VOXULA_H +#define VOXULA_H + +#include + +#include + +typedef void vecs_s; +typedef struct vecs_entity vecs_entity_s; + +struct vecs_entity +{ + vecs_s *ecs; + vx_uuid_d uuid; +}; + +vecs_s * vecs_new(); +void vecs_free(vecs_s *ecs); + +vecs_entity_s vecs_summon(vecs_s *ecs); +void vecs_vanish(vecs_entity_s *entity); + +#endif // VOXULA_H diff --git a/modules/ecs/inc-c/voxula/internals/ecs/entity.h b/modules/ecs/inc-c/voxula/internals/ecs/entity.h new file mode 100644 index 0000000..94def4c --- /dev/null +++ b/modules/ecs/inc-c/voxula/internals/ecs/entity.h @@ -0,0 +1,20 @@ + +#ifndef VECS_ENTITY_H +#define VECS_ENTITY_H + +#include + +#include + +typedef struct vecs_entity vecs_entity_s; + +struct vecs_entity +{ + void *head_structure; + vx_uuid_d uuid; +}; + +vecs_entity_s vecs_summon(void *ecs_pointer); +void vecs_vanish(vecs_entity_s *entity); + +#endif // VECS_ENTITY_H diff --git a/modules/ecs/inc-c/voxula/internals/ecs/head.h b/modules/ecs/inc-c/voxula/internals/ecs/head.h new file mode 100644 index 0000000..e586945 --- /dev/null +++ b/modules/ecs/inc-c/voxula/internals/ecs/head.h @@ -0,0 +1,69 @@ + +#ifndef VECS_H +#define VECS_H + +#include + +#include +#include + +typedef struct vecs vecs_s; +typedef struct vecs_shadow vecs_shadow_s; +typedef struct vecs_tag vecs_tag_s; + +typedef struct vecs_tag_name_resolver vecs_tag_name_resolver_s; +typedef struct vecs_tag_name vecs_tag_name_s; + +struct vecs_tag_name +{ + vx_uuid_d uuid; + uint32_t length; + char *string; +}; + +struct vecs_tag_name_resolver +{ + uint32_t names_capacity; + uint32_t num_names; + vecs_tag_name_s *names; + vx_uuid_table_s *uuid_table; + vx_arena_s *string_arena; +}; + +struct vecs_tag +{ + void *pointer; + + vecs_tag_s *next_in_chain; + + vecs_tag_name_s *name; + vecs_tag_s *next_with_same_name; + vecs_tag_s *previous_with_same_name; +}; + +struct vecs_shadow +{ + vx_uuid_d identifier; + + vecs_tag_s *first_tag; +}; + +struct vecs +{ + vx_pool_s *tag_pool; + vx_pool_s *shadow_pool; + vecs_tag_name_resolver_s resolver; + vecs_entity_map_s lookup_map; + vx_uuid_table_s *uuid_table; +}; + +vecs_s * vecs_new(); +void vecs_free(vecs_s *ecs); + +vecs_tag_name_resolver_s vecs_create_tag_name_resolver(); +void vecs_delete_tag_name_resolver(vecs_tag_name_resolver_s *resolver); + +vecs_tag_name_s * vecs_make_tag_name(vecs_tag_name_resolver_s *resolver, const char *name); +vecs_tag_name_s * vecs_search_tag_name(vecs_tag_name_resolver_s *resolver, const char *name); + +#endif // VECS_H diff --git a/modules/ecs/inc-c/voxula/internals/ecs/lookup.h b/modules/ecs/inc-c/voxula/internals/ecs/lookup.h new file mode 100644 index 0000000..e132a46 --- /dev/null +++ b/modules/ecs/inc-c/voxula/internals/ecs/lookup.h @@ -0,0 +1,33 @@ + +#ifndef VOXULA_ENTITY_LOOKUP_H +#define VOXULA_ENTITY_LOOKUP_H + +#include +#include + + +#include + +typedef struct vecs_entity_map vecs_entity_map_s; +typedef struct vecs_entity_entry vecs_entity_entry_s; + +struct vecs_entity_entry +{ + void *shadow; +}; + +struct vecs_entity_map +{ + uint32_t entries_capacity; + uint32_t num_entries; + vecs_entity_entry_s *entries; +}; + +vecs_entity_map_s vecs_create_lookup_map(); +void vecs_delete_lookup_map(vecs_entity_map_s *map); + +void * vecs_lookup_entity(vecs_entity_map_s *map, vx_uuid_d uuid); +void vecs_register_entity(vecs_entity_map_s *map, void *shadow_ptr); +void vecs_unregister_entity(vecs_entity_map_s *map, void *shadow_ptr); + +#endif // VOXULA_ENTITY_LOOKUP_H diff --git a/modules/ecs/src-c/entity.c b/modules/ecs/src-c/entity.c new file mode 100644 index 0000000..c604d0b --- /dev/null +++ b/modules/ecs/src-c/entity.c @@ -0,0 +1,25 @@ +#include +#include + +vecs_entity_s vecs_summon(void *ecs_pointer) +{ + vecs_s *ecs = ecs_pointer; + + vecs_entity_s entity; + entity.head_structure = ecs; + entity.uuid = vx_new_uuid(ecs->uuid_table); + + vecs_shadow_s *shadow = vx_pool(ecs->shadow_pool); + shadow->identifier = entity.uuid; + shadow->first_tag = NULL; + + vecs_register_entity(&ecs->lookup_map, shadow); + return entity; +} + +void vecs_vanish(vecs_entity_s *entity) +{ + vecs_s *ecs = entity->head_structure; + vecs_shadow_s *shadow = vecs_lookup_entity(&ecs->lookup_map, entity->uuid); + vecs_unregister_entity(&ecs->lookup_map, shadow); +} diff --git a/modules/ecs/src-c/head.c b/modules/ecs/src-c/head.c new file mode 100644 index 0000000..26dbff5 --- /dev/null +++ b/modules/ecs/src-c/head.c @@ -0,0 +1,21 @@ +#include +#include +#include + +vecs_s * vecs_new() +{ + vecs_s *ecs = malloc(sizeof(vecs_s)); + ecs->resolver = vecs_create_tag_name_resolver(); + ecs->lookup_map = vecs_create_lookup_map(); + ecs->shadow_pool = vx_new_pool(sizeof(vecs_shadow_s), 8192); + ecs->tag_pool = vx_new_pool(sizeof(vecs_tag_s), 32768); + ecs->uuid_table = vx_new_uuid_table(); + return ecs; +} + +void vecs_free(vecs_s *ecs) +{ + vecs_delete_tag_name_resolver(&ecs->resolver); + vx_free_pool(ecs->shadow_pool); + vx_free_pool(ecs->tag_pool); +} diff --git a/modules/ecs/src-c/lookup.c b/modules/ecs/src-c/lookup.c new file mode 100644 index 0000000..429bab3 --- /dev/null +++ b/modules/ecs/src-c/lookup.c @@ -0,0 +1,55 @@ +#include +#include +#include + +vecs_entity_map_s vecs_create_lookup_map() +{ + vecs_entity_map_s map; + map.num_entries = 0; + map.entries_capacity = 8192; + map.entries = malloc(map.entries_capacity * sizeof(vx_uuid_entry_s)); + return map; +} + +void vecs_delete_lookup_map(vecs_entity_map_s *map) +{ + free(map->entries); +} + +void * vecs_lookup_entity(vecs_entity_map_s *map, vx_uuid_d uuid) +{ + uint32_t entry_index = 0; + while(entry_index < map->num_entries) + { + vecs_shadow_s *shadow = map->entries[entry_index].shadow; + if(shadow->identifier == uuid) + { + return shadow; + } + ++entry_index; + } + return NULL; +} + +void vecs_register_entity(vecs_entity_map_s *map, void *shadow_ptr) +{ + vecs_entity_entry_s *entry = &map->entries[map->num_entries]; + entry->shadow = shadow_ptr; + ++map->num_entries; +} + +void vecs_unregister_entity(vecs_entity_map_s *map, void *shadow_ptr) +{ + vecs_shadow_s *shadow = shadow_ptr; + uint32_t entry_index = 0; + while(entry_index < map->num_entries) + { + vecs_shadow_s *entry = map->entries[entry_index].shadow; + if(entry->identifier == shadow->identifier) + { + map->entries[entry_index] = map->entries[map->num_entries - 1]; + break; + } + ++entry_index; + } +} diff --git a/modules/ecs/src-c/name-resolver.c b/modules/ecs/src-c/name-resolver.c new file mode 100644 index 0000000..f749fbb --- /dev/null +++ b/modules/ecs/src-c/name-resolver.c @@ -0,0 +1,61 @@ +#include +#include +#include + +vecs_tag_name_resolver_s vecs_create_tag_name_resolver() +{ + vecs_tag_name_resolver_s resolver; + resolver.names_capacity = 1024; + resolver.num_names = 0; + resolver.names = malloc(resolver.names_capacity * sizeof(vecs_tag_name_s)); + resolver.string_arena = vx_new_arena(16384); + return resolver; +} + +void vecs_delete_tag_name_resolver(vecs_tag_name_resolver_s *resolver) +{ + vx_free_arena(resolver->string_arena); + free(resolver->names); +} + +vecs_tag_name_s * vecs_force_create_tag_name(vecs_tag_name_resolver_s *resolver, const char *name) +{ + uint32_t len_name = strlen(name); + vecs_tag_name_s *tag_name = &resolver->names[resolver->num_names]; + ++resolver->num_names; + tag_name->length = len_name; + tag_name->string = vx_arena_dupe_string(resolver->string_arena, name); + tag_name->uuid = vx_new_uuid(resolver->uuid_table); + return tag_name; +} + +vecs_tag_name_s * vecs_make_tag_name(vecs_tag_name_resolver_s *resolver, const char *name) +{ + vecs_tag_name_s *tag_name = vecs_search_tag_name(resolver, name); + if(tag_name) + { + return tag_name; + } + return vecs_force_create_tag_name(resolver, name); +} + +vecs_tag_name_s * vecs_search_tag_name(vecs_tag_name_resolver_s *resolver, const char *string) +{ + uint32_t len_string = strlen(string); + uint32_t name_index = 0; + while(name_index < resolver->num_names) + { + vecs_tag_name_s *name = &resolver->names[name_index]; + if(name->length != len_string) + { + ++name_index; + continue; + } + if( ! memcmp(name->string, string, name->length)) + { + return name; + } + ++name_index; + } + return NULL; +}