Skip to content

Commit

Permalink
Fix issue with tag observers that specify both OnAdd and OnSet events
Browse files Browse the repository at this point in the history
  • Loading branch information
SanderMertens committed Feb 24, 2024
1 parent c85eb03 commit ff99497
Show file tree
Hide file tree
Showing 5 changed files with 241 additions and 31 deletions.
25 changes: 23 additions & 2 deletions flecs.c
Original file line number Diff line number Diff line change
Expand Up @@ -16648,12 +16648,33 @@ int flecs_uni_observer_init(
if (ecs_id_is_tag(world, term->id)) {
/* If id is a tag, downgrade OnSet/UnSet to OnAdd/OnRemove. */
int32_t e, count = observer->event_count;
bool has_on_add = false;
bool has_on_remove = false;
for (e = 0; e < count; e ++) {
if (observer->events[e] == EcsOnAdd) {
has_on_add = true;
}
if (observer->events[e] == EcsOnRemove) {
has_on_remove = true;
}
}

for (e = 0; e < count; e ++) {
if (observer->events[e] == EcsOnSet) {
observer->events[e] = EcsOnAdd;
if (has_on_add) {
/* Already registered */
observer->events[e] = 0;
} else {
observer->events[e] = EcsOnAdd;
}
} else
if (observer->events[e] == EcsUnSet) {
observer->events[e] = EcsOnRemove;
if (has_on_remove) {
/* Already registered */
observer->events[e] = 0;
} else {
observer->events[e] = EcsOnRemove;
}
}
}
}
Expand Down
25 changes: 23 additions & 2 deletions src/observer.c
Original file line number Diff line number Diff line change
Expand Up @@ -684,12 +684,33 @@ int flecs_uni_observer_init(
if (ecs_id_is_tag(world, term->id)) {
/* If id is a tag, downgrade OnSet/UnSet to OnAdd/OnRemove. */
int32_t e, count = observer->event_count;
bool has_on_add = false;
bool has_on_remove = false;
for (e = 0; e < count; e ++) {
if (observer->events[e] == EcsOnAdd) {
has_on_add = true;
}
if (observer->events[e] == EcsOnRemove) {
has_on_remove = true;
}
}

for (e = 0; e < count; e ++) {
if (observer->events[e] == EcsOnSet) {
observer->events[e] = EcsOnAdd;
if (has_on_add) {
/* Already registered */
observer->events[e] = 0;
} else {
observer->events[e] = EcsOnAdd;
}
} else
if (observer->events[e] == EcsUnSet) {
observer->events[e] = EcsOnRemove;
if (has_on_remove) {
/* Already registered */
observer->events[e] = 0;
} else {
observer->events[e] = EcsOnRemove;
}
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions test/api/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -2129,6 +2129,10 @@
"disable_multi_observer_module",
"disable_multi_observer_module_nested",
"disable_multi_observer_and_module",
"tag_w_on_set_and_on_add",
"tag_w_on_set_and_on_add_reverse",
"tag_w_un_set_and_on_remove",
"tag_w_un_set_and_on_remove_reverse",
"cache_test_1",
"cache_test_2",
"cache_test_3",
Expand Down
196 changes: 170 additions & 26 deletions test/api/src/Observer.c
Original file line number Diff line number Diff line change
Expand Up @@ -4355,6 +4355,150 @@ void Observer_disable_multi_observer_and_module(void) {
ecs_fini(ecs);
}

void Observer_tag_w_on_set_and_on_add(void) {
ecs_world_t *world = ecs_mini();

ecs_entity_t tag = ecs_new_id(world);
ecs_entity_t e1 = ecs_new_id(world);

Probe ctx = {0};

ecs_entity_t o = ecs_observer(world, {
.filter.terms = {{ tag }},
.events = {EcsOnAdd, EcsOnSet},
.callback = Observer,
.ctx = &ctx
});

ecs_add_id(world, e1, tag);

test_int(ctx.invoked, 1);
test_int(ctx.count, 1);
test_int(ctx.e[0], e1);
test_int(ctx.s[0][0], 0);
test_int(ctx.c[0][0], tag);
test_int(ctx.event, EcsOnAdd);

ecs_delete(world, o);
ecs_os_zeromem(&ctx);

ecs_entity_t e2 = ecs_new_id(world);
ecs_add_id(world, e2, tag);
test_int(ctx.invoked, 0);

ecs_fini(world);
}

void Observer_tag_w_on_set_and_on_add_reverse(void) {
ecs_world_t *world = ecs_mini();

ecs_entity_t tag = ecs_new_id(world);
ecs_entity_t e1 = ecs_new_id(world);

Probe ctx = {0};

ecs_entity_t o = ecs_observer(world, {
.filter.terms = {{ tag }},
.events = {EcsOnSet, EcsOnAdd},
.callback = Observer,
.ctx = &ctx
});

ecs_add_id(world, e1, tag);

test_int(ctx.invoked, 1);
test_int(ctx.count, 1);
test_int(ctx.e[0], e1);
test_int(ctx.s[0][0], 0);
test_int(ctx.c[0][0], tag);
test_int(ctx.event, EcsOnAdd);

ecs_delete(world, o);
ecs_os_zeromem(&ctx);

ecs_entity_t e2 = ecs_new_id(world);
ecs_add_id(world, e2, tag);
test_int(ctx.invoked, 0);

ecs_fini(world);
}

void Observer_tag_w_un_set_and_on_remove(void) {
ecs_world_t *world = ecs_mini();

ecs_entity_t tag = ecs_new_id(world);
ecs_entity_t e1 = ecs_new_id(world);

Probe ctx = {0};

ecs_entity_t o = ecs_observer(world, {
.filter.terms = {{ tag }},
.events = {EcsOnRemove, EcsUnSet},
.callback = Observer,
.ctx = &ctx
});

ecs_add_id(world, e1, tag);
test_int(ctx.invoked, 0);

ecs_remove_id(world, e1, tag);

test_int(ctx.invoked, 1);
test_int(ctx.count, 1);
test_int(ctx.e[0], e1);
test_int(ctx.s[0][0], 0);
test_int(ctx.c[0][0], tag);
test_int(ctx.event, EcsOnRemove);

ecs_delete(world, o);
ecs_os_zeromem(&ctx);

ecs_entity_t e2 = ecs_new_id(world);
ecs_add_id(world, e2, tag);
ecs_remove_id(world, e1, tag);
test_int(ctx.invoked, 0);

ecs_fini(world);
}

void Observer_tag_w_un_set_and_on_remove_reverse(void) {
ecs_world_t *world = ecs_mini();

ecs_entity_t tag = ecs_new_id(world);
ecs_entity_t e1 = ecs_new_id(world);

Probe ctx = {0};

ecs_entity_t o = ecs_observer(world, {
.filter.terms = {{ tag }},
.events = {EcsUnSet, EcsOnRemove},
.callback = Observer,
.ctx = &ctx
});

ecs_add_id(world, e1, tag);
test_int(ctx.invoked, 0);

ecs_remove_id(world, e1, tag);

test_int(ctx.invoked, 1);
test_int(ctx.count, 1);
test_int(ctx.e[0], e1);
test_int(ctx.s[0][0], 0);
test_int(ctx.c[0][0], tag);
test_int(ctx.event, EcsOnRemove);

ecs_delete(world, o);
ecs_os_zeromem(&ctx);

ecs_entity_t e2 = ecs_new_id(world);
ecs_add_id(world, e2, tag);
ecs_remove_id(world, e1, tag);
test_int(ctx.invoked, 0);

ecs_fini(world);
}

void Observer_cache_test_1(void) {
ecs_world_t *world = ecs_mini();

Expand Down Expand Up @@ -5109,6 +5253,32 @@ void Observer_cache_test_15(void) {
ecs_fini(world);
}

static
void Observer_w_run_aperiodic(ecs_iter_t *it) {
test_int(it->count, 1);
ecs_run_aperiodic(it->world, 0);
}

void Observer_cache_test_16(void) {
ecs_world_t* ecs = ecs_init();

ECS_TAG(ecs, Foo);

ECS_OBSERVER(ecs, Observer_w_run_aperiodic, EcsOnAdd, Foo);

ecs_entity_t p1 = ecs_new_id(ecs);
ecs_entity_t e1 = ecs_new_w_pair(ecs, EcsIsA, p1);

ecs_run_aperiodic(ecs, 0);

ecs_entity_t e2 = ecs_new_id(ecs);
ecs_add_pair(ecs, e2, EcsIsA, p1);
ecs_add_pair(ecs, e2, EcsChildOf, e1);
ecs_add(ecs, e1, Foo);

ecs_fini(ecs);
}

static int Observer_a_invoked = 0;
static int Observer_b_invoked = 0;

Expand Down Expand Up @@ -5413,29 +5583,3 @@ void Observer_emit_for_parent_w_prefab_child_and_instance(void) {

ecs_fini(ecs);
}

static
void Observer_w_run_aperiodic(ecs_iter_t *it) {
test_int(it->count, 1);
ecs_run_aperiodic(it->world, 0);
}

void Observer_cache_test_16(void) {
ecs_world_t* ecs = ecs_init();

ECS_TAG(ecs, Foo);

ECS_OBSERVER(ecs, Observer_w_run_aperiodic, EcsOnAdd, Foo);

ecs_entity_t p1 = ecs_new_id(ecs);
ecs_entity_t e1 = ecs_new_w_pair(ecs, EcsIsA, p1);

ecs_run_aperiodic(ecs, 0);

ecs_entity_t e2 = ecs_new_id(ecs);
ecs_add_pair(ecs, e2, EcsIsA, p1);
ecs_add_pair(ecs, e2, EcsChildOf, e1);
ecs_add(ecs, e1, Foo);

ecs_fini(ecs);
}
22 changes: 21 additions & 1 deletion test/api/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -2058,6 +2058,10 @@ void Observer_disable_multi_observer(void);
void Observer_disable_multi_observer_module(void);
void Observer_disable_multi_observer_module_nested(void);
void Observer_disable_multi_observer_and_module(void);
void Observer_tag_w_on_set_and_on_add(void);
void Observer_tag_w_on_set_and_on_add_reverse(void);
void Observer_tag_w_un_set_and_on_remove(void);
void Observer_tag_w_un_set_and_on_remove_reverse(void);
void Observer_cache_test_1(void);
void Observer_cache_test_2(void);
void Observer_cache_test_3(void);
Expand Down Expand Up @@ -10709,6 +10713,22 @@ bake_test_case Observer_testcases[] = {
"disable_multi_observer_and_module",
Observer_disable_multi_observer_and_module
},
{
"tag_w_on_set_and_on_add",
Observer_tag_w_on_set_and_on_add
},
{
"tag_w_on_set_and_on_add_reverse",
Observer_tag_w_on_set_and_on_add_reverse
},
{
"tag_w_un_set_and_on_remove",
Observer_tag_w_un_set_and_on_remove
},
{
"tag_w_un_set_and_on_remove_reverse",
Observer_tag_w_un_set_and_on_remove_reverse
},
{
"cache_test_1",
Observer_cache_test_1
Expand Down Expand Up @@ -13415,7 +13435,7 @@ static bake_test_suite suites[] = {
"Observer",
NULL,
NULL,
124,
128,
Observer_testcases
},
{
Expand Down

0 comments on commit ff99497

Please sign in to comment.