421 lines
9.2 KiB
C
421 lines
9.2 KiB
C
#include <api.h>
|
|
|
|
void Deinit(ecs_iter_t *it) {
|
|
Position *p = ecs_field(it, Position, 1);
|
|
|
|
Velocity *v = NULL;
|
|
if (it->field_count >= 2) {
|
|
v = ecs_field(it, Velocity, 2);
|
|
}
|
|
|
|
probe_iter(it);
|
|
|
|
/* Write to validate columns point to valid memory */
|
|
int i;
|
|
for (i = 0; i < it->count; i ++) {
|
|
p[i].x = 0;
|
|
p[i].y = 0;
|
|
|
|
if (v) {
|
|
v[i].x = 0;
|
|
v[i].y = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
static
|
|
void Remove_from_current(ecs_iter_t *it) {
|
|
IterData *ctx = ecs_get_ctx(it->world);
|
|
|
|
int i;
|
|
for (i = 0; i < it->count; i ++) {
|
|
ecs_entity_t e = it->entities[i];
|
|
|
|
if (ctx->component) {
|
|
ecs_remove_id(it->world, e, ctx->component);
|
|
}
|
|
|
|
if (ctx->component_2) {
|
|
ecs_remove_id(it->world, e, ctx->component_2);
|
|
}
|
|
|
|
ctx->entity_count ++;
|
|
}
|
|
}
|
|
|
|
void TriggerOnRemove_remove(void) {
|
|
ecs_world_t *world = ecs_mini();
|
|
|
|
ECS_COMPONENT(world, Position);
|
|
ECS_OBSERVER(world, Deinit, EcsOnRemove, Position);
|
|
|
|
Probe ctx = {0};
|
|
ecs_set_ctx(world, &ctx, NULL);
|
|
|
|
ecs_entity_t e = ecs_new(world, Position);
|
|
test_assert(e != 0);
|
|
|
|
test_int(ctx.count, 0);
|
|
|
|
ecs_remove(world, e, Position);
|
|
|
|
test_int(ctx.count, 1);
|
|
test_int(ctx.term_count, 1);
|
|
test_null(ctx.param);
|
|
|
|
test_int(ctx.e[0], e);
|
|
test_int(ctx.c[0][0], ecs_id(Position));
|
|
test_int(ctx.s[0][0], 0);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void TriggerOnRemove_remove_no_match(void) {
|
|
ecs_world_t *world = ecs_mini();
|
|
|
|
ECS_COMPONENT(world, Position);
|
|
ECS_COMPONENT(world, Velocity);
|
|
ECS_OBSERVER(world, Deinit, EcsOnRemove, Position);
|
|
|
|
Probe ctx = {0};
|
|
ecs_set_ctx(world, &ctx, NULL);
|
|
|
|
ecs_entity_t e = ecs_new(world, Position);
|
|
test_assert(e != 0);
|
|
|
|
test_int(ctx.count, 0);
|
|
|
|
ecs_remove(world, e, Velocity);
|
|
|
|
test_int(ctx.count, 0);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void TriggerOnRemove_delete(void) {
|
|
ecs_world_t *world = ecs_mini();
|
|
|
|
ECS_COMPONENT(world, Position);
|
|
ECS_OBSERVER(world, Deinit, EcsOnRemove, Position);
|
|
|
|
Probe ctx = {0};
|
|
ecs_set_ctx(world, &ctx, NULL);
|
|
|
|
ecs_entity_t e = ecs_new(world, Position);
|
|
test_assert(e != 0);
|
|
|
|
test_int(ctx.count, 0);
|
|
|
|
ecs_delete(world, e);
|
|
|
|
test_int(ctx.count, 1);
|
|
test_int(ctx.term_count, 1);
|
|
test_null(ctx.param);
|
|
|
|
test_int(ctx.e[0], e);
|
|
test_int(ctx.c[0][0], ecs_id(Position));
|
|
test_int(ctx.s[0][0], 0);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void TriggerOnRemove_delete_no_match(void) {
|
|
ecs_world_t *world = ecs_mini();
|
|
|
|
ECS_COMPONENT(world, Position);
|
|
ECS_COMPONENT(world, Velocity);
|
|
ECS_OBSERVER(world, Deinit, EcsOnRemove, Position);
|
|
|
|
Probe ctx = {0};
|
|
ecs_set_ctx(world, &ctx, NULL);
|
|
|
|
ecs_entity_t e = ecs_new(world, Velocity);
|
|
test_assert(e != 0);
|
|
|
|
test_int(ctx.count, 0);
|
|
|
|
ecs_delete(world, e);
|
|
|
|
test_int(ctx.count, 0);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
static Position old_position = {0};
|
|
|
|
static
|
|
void RemovePosition(ecs_iter_t *it) {
|
|
Position *p = ecs_field(it, Position, 1);
|
|
|
|
test_assert(it->count == 1);
|
|
|
|
old_position = p[0];
|
|
}
|
|
|
|
void TriggerOnRemove_remove_watched(void) {
|
|
ecs_world_t *world = ecs_mini();
|
|
|
|
ECS_COMPONENT(world, Position);
|
|
|
|
ECS_OBSERVER(world, RemovePosition, EcsOnRemove, Position);
|
|
|
|
ecs_entity_t e = ecs_set(world, 0, Position, {10, 20});
|
|
test_assert(e != 0);
|
|
|
|
/* Make parent entity watched */
|
|
ecs_new_w_pair(world, EcsChildOf, e);
|
|
|
|
ecs_remove(world, e, Position);
|
|
|
|
test_int(old_position.x, 10);
|
|
test_int(old_position.y, 20);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
|
|
void TriggerOnRemove_delete_watched(void) {
|
|
ecs_world_t *world = ecs_mini();
|
|
|
|
ECS_COMPONENT(world, Position);
|
|
|
|
ECS_OBSERVER(world, RemovePosition, EcsOnRemove, Position);
|
|
|
|
ecs_entity_t e = ecs_set(world, 0, Position, {10, 20});
|
|
test_assert(e != 0);
|
|
|
|
/* Make parent entity watched */
|
|
ecs_new_w_pair(world, EcsChildOf, e);
|
|
|
|
ecs_delete(world, e);
|
|
|
|
test_int(old_position.x, 10);
|
|
test_int(old_position.y, 20);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
static bool dummy_called = false;
|
|
|
|
static
|
|
void Dummy(ecs_iter_t *it) {
|
|
dummy_called = true;
|
|
}
|
|
|
|
void TriggerOnRemove_on_remove_in_on_update(void) {
|
|
ecs_world_t *world = ecs_init();
|
|
|
|
ECS_COMPONENT(world, Position);
|
|
ECS_COMPONENT(world, Velocity);
|
|
|
|
ECS_SYSTEM(world, Remove_from_current, EcsOnUpdate, Position);
|
|
ECS_OBSERVER(world, Dummy, EcsOnRemove, Velocity);
|
|
|
|
IterData ctx = {.component = ecs_id(Velocity)};
|
|
ecs_set_ctx(world, &ctx, NULL);
|
|
|
|
ECS_ENTITY(world, e1, Position, Velocity);
|
|
ECS_ENTITY(world, e2, Position, Velocity);
|
|
ECS_ENTITY(world, e3, Position, Velocity);
|
|
|
|
ecs_progress(world, 1);
|
|
|
|
test_assert( ecs_has(world, e1, Position));
|
|
test_assert( ecs_has(world, e2, Position));
|
|
test_assert( ecs_has(world, e3, Position));
|
|
|
|
test_assert( !ecs_has(world, e1, Velocity));
|
|
test_assert( !ecs_has(world, e2, Velocity));
|
|
test_assert( !ecs_has(world, e3, Velocity));
|
|
|
|
test_assert(dummy_called);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
static int dummy_dtor_invoked = 0;
|
|
|
|
typedef struct DummyComp {
|
|
int value;
|
|
} DummyComp;
|
|
|
|
static
|
|
void RemoveDummyComp(ecs_iter_t *it) {
|
|
int i;
|
|
for (i = 0; i < it->count; i ++) {
|
|
test_assert(ecs_is_valid(it->world, it->entities[i]));
|
|
test_assert(ecs_is_alive(it->world, it->entities[i]));
|
|
}
|
|
|
|
dummy_dtor_invoked ++;
|
|
}
|
|
|
|
void TriggerOnRemove_valid_entity_after_delete(void) {
|
|
ecs_world_t *world = ecs_mini();
|
|
|
|
ECS_COMPONENT(world, DummyComp);
|
|
ECS_OBSERVER(world, RemoveDummyComp, EcsOnRemove, DummyComp);
|
|
|
|
ecs_entity_t e = ecs_new(world, DummyComp);
|
|
test_assert(e != 0);
|
|
|
|
ecs_delete(world, e);
|
|
test_assert(!ecs_is_valid(world, e));
|
|
test_assert(!ecs_is_alive(world, e));
|
|
|
|
test_int(dummy_dtor_invoked, 1);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void TriggerOnRemove_remove_after_delete_trigger(void) {
|
|
ecs_world_t *world = ecs_mini();
|
|
|
|
ECS_COMPONENT(world, Position);
|
|
|
|
ecs_entity_t trigger = ecs_observer_init(world, &(ecs_observer_desc_t){
|
|
.filter.terms[0].id = ecs_id(Position),
|
|
.events = {EcsOnRemove},
|
|
.callback = Dummy
|
|
});
|
|
|
|
ecs_entity_t e1 = ecs_new(world, Position);
|
|
test_assert(e1 != 0);
|
|
test_assert(ecs_has(world, e1, Position));
|
|
test_int(dummy_called, 0);
|
|
|
|
ecs_remove(world, e1, Position);
|
|
test_int(dummy_called, 1);
|
|
|
|
dummy_called = 0;
|
|
|
|
ecs_delete(world, trigger);
|
|
test_int(dummy_called, 0);
|
|
|
|
ecs_entity_t e2 = ecs_new(world, Position);
|
|
test_assert(e2 != 0);
|
|
test_assert(ecs_has(world, e2, Position));
|
|
test_int(dummy_called, 0);
|
|
|
|
ecs_remove(world, e2, Position);
|
|
test_int(dummy_called, 0);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void TriggerOnRemove_remove_after_delete_wildcard_id_trigger(void) {
|
|
ecs_world_t *world = ecs_mini();
|
|
|
|
ECS_COMPONENT(world, Position);
|
|
|
|
ecs_entity_t trigger = ecs_observer_init(world, &(ecs_observer_desc_t){
|
|
.filter.terms[0].id = EcsWildcard,
|
|
.events = {EcsOnRemove},
|
|
.callback = Dummy
|
|
});
|
|
|
|
ecs_entity_t e1 = ecs_new(world, Position);
|
|
test_assert(e1 != 0);
|
|
test_assert(ecs_has(world, e1, Position));
|
|
test_int(dummy_called, 0);
|
|
|
|
ecs_remove(world, e1, Position);
|
|
test_int(dummy_called, 1);
|
|
|
|
dummy_called = 0;
|
|
|
|
ecs_delete(world, trigger);
|
|
|
|
test_int(dummy_called, 1);
|
|
|
|
dummy_called = 0;
|
|
|
|
ecs_entity_t e2 = ecs_new(world, Position);
|
|
test_assert(e2 != 0);
|
|
test_assert(ecs_has(world, e2, Position));
|
|
test_int(dummy_called, 0);
|
|
|
|
ecs_remove(world, e2, Position);
|
|
test_int(dummy_called, 0);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
typedef struct on_remove_has_tag_t {
|
|
ecs_entity_t ent;
|
|
ecs_entity_t tag;
|
|
} on_remove_has_tag_t;
|
|
|
|
static
|
|
void OnRemoveHasTag(ecs_iter_t *it) {
|
|
on_remove_has_tag_t *ctx = it->ctx;
|
|
test_assert(ctx != NULL);
|
|
|
|
test_int(it->count, 1);
|
|
test_assert(it->entities[0] == ctx->ent);
|
|
test_assert(ecs_field_id(it, 1) == ctx->tag);
|
|
test_bool(ecs_has_id(it->world, ctx->ent, ctx->tag), true);
|
|
|
|
dummy_called = true;
|
|
}
|
|
|
|
void TriggerOnRemove_has_removed_tag_trigger_1_tag(void) {
|
|
ecs_world_t *world = ecs_mini();
|
|
|
|
ECS_TAG(world, Tag);
|
|
|
|
ecs_entity_t e = ecs_new(world, Tag);
|
|
test_assert(e != 0);
|
|
test_assert(ecs_has(world, e, Tag));
|
|
|
|
on_remove_has_tag_t ctx = {
|
|
.ent = e,
|
|
.tag = Tag
|
|
};
|
|
|
|
ecs_observer_init(world, &(ecs_observer_desc_t){
|
|
.filter.terms[0].id = Tag,
|
|
.events = {EcsOnRemove},
|
|
.callback = OnRemoveHasTag,
|
|
.ctx = &ctx
|
|
});
|
|
|
|
ecs_remove(world, e, Tag);
|
|
|
|
test_int(dummy_called, 1);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void TriggerOnRemove_has_removed_tag_trigger_2_tags(void) {
|
|
ecs_world_t *world = ecs_mini();
|
|
|
|
ECS_TAG(world, TagA);
|
|
ECS_TAG(world, TagB);
|
|
|
|
ecs_entity_t e = ecs_new(world, TagA);
|
|
test_assert(e != 0);
|
|
test_assert(ecs_has(world, e, TagA));
|
|
|
|
ecs_add(world, e, TagB);
|
|
test_assert(ecs_has(world, e, TagB));
|
|
|
|
on_remove_has_tag_t ctx = {
|
|
.ent = e,
|
|
.tag = TagA
|
|
};
|
|
|
|
ecs_observer_init(world, &(ecs_observer_desc_t){
|
|
.filter.terms[0].id = TagA,
|
|
.events = {EcsOnRemove},
|
|
.callback = OnRemoveHasTag,
|
|
.ctx = &ctx
|
|
});
|
|
|
|
ecs_remove(world, e, TagA);
|
|
|
|
test_int(dummy_called, 1);
|
|
|
|
ecs_fini(world);
|
|
}
|