[ecs] Adjust subpool range type to return start,end

I found I needed the subrange start as well as the end, but I liked that
the subpools themselves used only the end of the range, so switching to
just a unint32_t for the value and adding a function to return a tuple
made sense. I had kept the struct because I thought I might want to
store additional information (eg, the entity "owning" the subpool), but
found that I didn't need such information as the systems using subpools
that way would have access to the entity by other means.

Interestingly, the change found a bug in subpool creation: I really
don't know why things worked before, but they work better now :)
This commit is contained in:
Bill Currie 2022-12-20 17:56:08 +09:00
parent 34930ba195
commit 3a2877dd9a
4 changed files with 52 additions and 24 deletions

View file

@ -63,13 +63,14 @@ typedef struct ecs_pool_s {
typedef struct DARRAY_TYPE(component_t) componentset_t;
typedef struct ecs_range_s {
uint32_t start;
uint32_t end;
} ecs_range_t;
typedef struct ecs_subpool_s {
ecs_range_t *ranges;
uint32_t *rangeids;
uint32_t *sorted;
uint32_t *ranges;
uint32_t next;
uint32_t available;
uint32_t num_ranges;
@ -98,6 +99,10 @@ typedef struct ecs_system_s {
uint32_t base;
} ecs_system_t;
#include "QF/ecs/entity.h"
#define ECSINLINE GNU89INLINE inline
ecs_registry_t *ECS_NewRegistry (void);
void ECS_DelRegistry (ecs_registry_t *registry);
uint32_t ECS_RegisterComponents (ecs_registry_t *registry,
@ -120,11 +125,31 @@ void ECS_RemoveEntities (ecs_registry_t *registry, uint32_t component);
uint32_t ECS_NewSubpoolRange (ecs_registry_t *registry, uint32_t component);
void ECS_DelSubpoolRange (ecs_registry_t *registry, uint32_t component,
uint32_t id);
ECSINLINE ecs_range_t ECS_GetSubpoolRange (ecs_registry_t *registry,
uint32_t component, uint32_t id);
#undef ECSINLINE
#ifndef IMPLEMENT_ECS_Funcs
#define ECSINLINE GNU89INLINE inline
#else
#define ECSINLINE VISIBLE
#endif
ECSINLINE
ecs_range_t
ECS_GetSubpoolRange (ecs_registry_t *registry, uint32_t component, uint32_t id)
{
ecs_subpool_t *subpool = &registry->subpools[component];
uint32_t ind = subpool->sorted[Ent_Index (id)];
ecs_range_t range = {
.start = ind ? subpool->ranges[ind - 1] : 0,
.end = subpool->ranges[ind],
};
return range;
}
#undef ECSINLINE
///@}
#include "QF/ecs/entity.h"
#endif//__QF_ecs_h

View file

@ -67,11 +67,11 @@ Ent_AddComponent (uint32_t ent, uint32_t comp, ecs_registry_t *registry)
uint32_t rangeind = subpool->sorted[Ent_Index (rangeid)];
printf ("ent:%d rangeid:%d rangeind:%d\n", ent, rangeid, rangeind);
while (rind-- > rangeind) {
if (subpool->ranges[rind].end == ind) {
subpool->ranges[rind].end++;
if (subpool->ranges[rind] == ind) {
subpool->ranges[rind]++;
continue;
}
uint32_t end = subpool->ranges[rind].end++;
uint32_t end = subpool->ranges[rind]++;
Component_MoveElements (c, pool->data, ind, end, 1);
swap_inds (&pool->sparse[Ent_Index (pool->dense[end])],
&pool->sparse[Ent_Index (pool->dense[ind])]);
@ -87,24 +87,24 @@ static int
range_cmp (const void *_key, const void *_range, void *_subpool)
{
const uint32_t *key = _key;
const ecs_range_t *range = _range;
const uint32_t *range = _range;
ecs_subpool_t *subpool = _subpool;
if (*key >= range->end) {
if (*key >= *range) {
return -1;
}
if (range - subpool->ranges > 0) {
return *key >= range[-1].end ? 0 : -1;
return *key >= range[-1] ? 0 : -1;
}
return 0;
}
static ecs_range_t *
static uint32_t *
find_range (ecs_subpool_t *subpool, uint32_t ind)
{
return bsearch_r (&ind, subpool->ranges,
subpool->num_ranges - subpool->available,
sizeof (ecs_range_t), range_cmp, subpool);
sizeof (uint32_t), range_cmp, subpool);
}
VISIBLE void
@ -120,9 +120,9 @@ Ent_RemoveComponent (uint32_t ent, uint32_t comp, ecs_registry_t *registry)
Component_DestroyElements (c, pool->data, ind, 1);
if (subpool->num_ranges - subpool->available) {
uint32_t range_count = subpool->num_ranges - subpool->available;
ecs_range_t *range = find_range (subpool, ind);
uint32_t *range = find_range (subpool, ind);
while (range - subpool->ranges < range_count) {
uint32_t end = --range->end;
uint32_t end = --*range;
range++;
pool->sparse[Ent_Index (pool->dense[end])] = ind;
pool->dense[ind] = pool->dense[end];

View file

@ -64,11 +64,9 @@ ECS_NewSubpoolRange (ecs_registry_t *registry, uint32_t component)
}
uint32_t end = 0;
if (num_ranges) {
end = subpool->ranges[num_ranges - 1].end;
end = subpool->ranges[num_ranges - 1];
}
subpool->ranges[Ent_Index (id)] = (ecs_range_t) {
.end = end,
};
subpool->ranges[subpool->sorted[Ent_Index (id)]] = end;
return id;
}

View file

@ -52,13 +52,13 @@ static int
check_subpool_ranges (ecs_subpool_t *subpool, uint32_t *expect)
{
uint32_t count = subpool->num_ranges - subpool->available;
ecs_range_t *range = subpool->ranges;
uint32_t *range = subpool->ranges;
while (count--) {
ecs_range_t *r = range++;
uint32_t e = *expect++;
printf ("%d: %d %d\n", (int)(r - subpool->ranges), r->end, e);
if (r->end != e++) {
uint32_t *r = range++;
uint32_t e = *expect++;
printf ("%d: %d %d\n", (int)(r - subpool->ranges), *r, e);
if (*r != e++) {
return 1;
}
}
@ -109,9 +109,9 @@ main (void)
return 1;
}
for (uint32_t i = 0; i < reg->subpools[base + test_obj].num_ranges; i++) {
if (reg->subpools[base + test_obj].ranges[i].end != 0) {
if (reg->subpools[base + test_obj].ranges[i] != 0) {
printf ("end %d not 0 count: %d\n", i,
reg->subpools[base + test_obj].ranges[i].end);
reg->subpools[base + test_obj].ranges[i]);
return 1;
}
}
@ -234,6 +234,11 @@ main (void)
sp2 = ECS_NewSubpoolRange (reg, base + test_obj);
printf ("sp2: %d\n", sp2);
if (check_subpool_ranges (&reg->subpools[base + test_obj],
(uint32_t[]) { 2, 4, 4 })) {
printf ("oops\n");
return 1;
}
Ent_SetComponent (entc, base + test_subpool, reg, &sp2);
Ent_SetComponent (entf, base + test_subpool, reg, &sp2);
Ent_SetComponent (entg, base + test_subpool, reg, &sp2);