Skip to content

Commit

Permalink
Fix observer crash when matching a wildcard id on base entity
Browse files Browse the repository at this point in the history
  • Loading branch information
SanderMertens committed Jan 17, 2023
1 parent 337d189 commit 2b0a2d8
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 18 deletions.
24 changes: 18 additions & 6 deletions flecs.c
Original file line number Diff line number Diff line change
Expand Up @@ -45195,13 +45195,19 @@ bool flecs_filter_match_table(
}

for (i = 0; i < count; i ++) {
ecs_term_t *term = &terms[i];
ecs_oper_kind_t oper = term->oper;
if (i == skip_term) {
continue;
if (oper == EcsOr) {
is_or = true;
or_result = true;
}
if (oper != EcsAndFrom && oper != EcsOrFrom && oper != EcsNotFrom) {
continue;
}
}

ecs_term_t *term = &terms[i];
ecs_term_id_t *src = &term->src;
ecs_oper_kind_t oper = term->oper;
const ecs_table_t *match_table = table;
int32_t t_i = term->field_index;

Expand Down Expand Up @@ -46153,6 +46159,7 @@ bool flecs_type_can_inherit_id(
const ecs_id_record_t *idr,
ecs_id_t id)
{
ecs_assert(idr != NULL, ECS_INTERNAL_ERROR, NULL);
if (idr->flags & EcsIdDontInherit) {
return false;
}
Expand Down Expand Up @@ -46289,7 +46296,7 @@ int32_t flecs_search_relation_w_idr(

flags = flags ? flags : (EcsSelf|EcsUp);

if (!idr && !offset) {
if (!idr) {
idr = flecs_query_id_record_get(world, id);
if (!idr) {
return -1;
Expand Down Expand Up @@ -46873,9 +46880,10 @@ bool flecs_multi_observer_invoke(ecs_iter_t *it) {

user_it.columns[0] = 0;
user_it.columns[pivot_term] = column;
user_it.sources[pivot_term] = it->sources[0];

if (flecs_filter_match_table(world, &o->filter, table, user_it.ids,
user_it.columns, user_it.sources, NULL, NULL, false, -1,
user_it.columns, user_it.sources, NULL, NULL, false, pivot_term,
user_it.flags))
{
/* Monitor observers only invoke when the filter matches for the first
Expand All @@ -46897,10 +46905,14 @@ bool flecs_multi_observer_invoke(ecs_iter_t *it) {
user_it.columns, user_it.sources, NULL, NULL, false, -1,
user_it.flags | EcsFilterPopulate);
}

flecs_iter_populate_data(world, &user_it, it->table, it->offset,
it->count, user_it.ptrs, user_it.sizes);

if (it->ptrs) {
user_it.ptrs[pivot_term] = it->ptrs[0];
user_it.sizes[pivot_term] = it->sizes[0];
}
user_it.ids[pivot_term] = it->event_id;
user_it.system = o->filter.entity;
user_it.term_index = pivot_term;
Expand Down
9 changes: 6 additions & 3 deletions flecs.h
Original file line number Diff line number Diff line change
Expand Up @@ -17439,10 +17439,13 @@ namespace flecs
*/
template <typename T>
struct ref {
ref(world_t *world, entity_t entity, flecs::id_t id = 0)
: m_world( world )
, m_ref()
ref(world_t *world, entity_t entity, flecs::id_t id = 0)
: m_ref()
{
// the world we were called with may be a stage; convert it to a world
// here if that is the case
m_world = world ? const_cast<flecs::world_t *>(ecs_get_world(world))
: nullptr;
if (!id) {
id = _::cpp_type<T>::id(world);
}
Expand Down
12 changes: 9 additions & 3 deletions src/filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -1713,13 +1713,19 @@ bool flecs_filter_match_table(
}

for (i = 0; i < count; i ++) {
ecs_term_t *term = &terms[i];
ecs_oper_kind_t oper = term->oper;
if (i == skip_term) {
continue;
if (oper == EcsOr) {
is_or = true;
or_result = true;
}
if (oper != EcsAndFrom && oper != EcsOrFrom && oper != EcsNotFrom) {
continue;
}
}

ecs_term_t *term = &terms[i];
ecs_term_id_t *src = &term->src;
ecs_oper_kind_t oper = term->oper;
const ecs_table_t *match_table = table;
int32_t t_i = term->field_index;

Expand Down
9 changes: 7 additions & 2 deletions src/observer.c
Original file line number Diff line number Diff line change
Expand Up @@ -436,9 +436,10 @@ bool flecs_multi_observer_invoke(ecs_iter_t *it) {

user_it.columns[0] = 0;
user_it.columns[pivot_term] = column;
user_it.sources[pivot_term] = it->sources[0];

if (flecs_filter_match_table(world, &o->filter, table, user_it.ids,
user_it.columns, user_it.sources, NULL, NULL, false, -1,
user_it.columns, user_it.sources, NULL, NULL, false, pivot_term,
user_it.flags))
{
/* Monitor observers only invoke when the filter matches for the first
Expand All @@ -460,10 +461,14 @@ bool flecs_multi_observer_invoke(ecs_iter_t *it) {
user_it.columns, user_it.sources, NULL, NULL, false, -1,
user_it.flags | EcsFilterPopulate);
}

flecs_iter_populate_data(world, &user_it, it->table, it->offset,
it->count, user_it.ptrs, user_it.sizes);

if (it->ptrs) {
user_it.ptrs[pivot_term] = it->ptrs[0];
user_it.sizes[pivot_term] = it->sizes[0];
}
user_it.ids[pivot_term] = it->event_id;
user_it.system = o->filter.entity;
user_it.term_index = pivot_term;
Expand Down
3 changes: 2 additions & 1 deletion src/search.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ bool flecs_type_can_inherit_id(
const ecs_id_record_t *idr,
ecs_id_t id)
{
ecs_assert(idr != NULL, ECS_INTERNAL_ERROR, NULL);
if (idr->flags & EcsIdDontInherit) {
return false;
}
Expand Down Expand Up @@ -204,7 +205,7 @@ int32_t flecs_search_relation_w_idr(

flags = flags ? flags : (EcsSelf|EcsUp);

if (!idr && !offset) {
if (!idr) {
idr = flecs_query_id_record_get(world, id);
if (!idr) {
return -1;
Expand Down
2 changes: 2 additions & 0 deletions test/api/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -1816,6 +1816,8 @@
"on_add_2_pairs_w_multi_observer",
"on_set_2_pairs_w_uni_observer",
"on_set_2_pairs_w_multi_observer",
"on_remove_target_from_base_at_offset",
"on_remove_target_component_from_base_at_offset",
"cache_test_1",
"cache_test_2",
"cache_test_3",
Expand Down
92 changes: 92 additions & 0 deletions test/api/src/Observer.c
Original file line number Diff line number Diff line change
Expand Up @@ -3728,6 +3728,98 @@ void Observer_on_set_2_pairs_w_multi_observer() {
ecs_fini(world);
}

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

ecs_entity_t R = ecs_new_id(world);
ecs_entity_t T1 = ecs_new_id(world);
ecs_entity_t T2 = ecs_new_id(world);
ecs_entity_t C = ecs_new_id(world);

Probe ctx = { 0 };
ecs_entity_t o = ecs_observer(world, {
.filter.terms = {
{ .id = ecs_pair(R, EcsWildcard), .src.flags = EcsUp },
{ .id = C },
},
.events = { EcsOnRemove },
.callback = Observer,
.ctx = &ctx
});

ecs_entity_t base = ecs_new_id(world);
ecs_add_pair(world, base, R, T1);
ecs_add_pair(world, base, R, T2);

ecs_entity_t e = ecs_new_id(world);
ecs_add_pair(world, e, EcsIsA, base);
ecs_add_id(world, e, C);

test_int(ctx.invoked, 0);
ecs_delete(world, T2);
test_int(ctx.invoked, 1);
test_int(ctx.count, 1);
test_int(ctx.system, o);
test_int(ctx.term_count, 2);
test_int(ctx.event_id, ecs_pair(R, T2));
test_int(ctx.event, EcsOnRemove);

ecs_fini(world);
}

static void Observer_base_component(ecs_iter_t *it) {
probe_system_w_ctx(it, it->ctx);

Position *p = ecs_field(it, Position, 1);
test_assert(p != NULL);
test_int(p->x, 30);
test_int(p->y, 40);
}

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

ECS_COMPONENT(world, Position);
ecs_entity_t T1 = ecs_new_id(world);
ecs_entity_t T2 = ecs_new_id(world);
ecs_entity_t C = ecs_new_id(world);

Probe ctx = { 0 };
ecs_entity_t o = ecs_observer(world, {
.filter.terms = {
{ .id = ecs_pair(ecs_id(Position), EcsWildcard), .src.flags = EcsUp },
{ .id = C },
},
.events = { EcsOnRemove },
.callback = Observer_base_component,
.ctx = &ctx
});

ecs_entity_t base = ecs_new_id(world);
ecs_set_pair(world, base, Position, T1, {10, 20});
ecs_set_pair(world, base, Position, T2, {30, 40});

ecs_entity_t e = ecs_new_id(world);
ecs_add_pair(world, e, EcsIsA, base);
ecs_add_id(world, e, C);

test_int(ctx.invoked, 0);
ecs_delete(world, T2);
test_int(ctx.invoked, 1);
test_int(ctx.count, 1);
test_int(ctx.system, o);
test_int(ctx.term_count, 2);
test_int(ctx.e[0], e);
test_int(ctx.s[0][0], base);
test_int(ctx.s[0][1], 0);
test_int(ctx.event_id, ecs_pair(ecs_id(Position), T2));
test_int(ctx.event, EcsOnRemove);

ecs_delete(world, o);

ecs_fini(world);
}

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

Expand Down
4 changes: 2 additions & 2 deletions test/api/src/Stresstests.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ static
void create_delete_entity_random_components_staged(
int32_t threads)
{
test_quarantine("---");
test_quarantine("16 Jan 2023");
return;

ecs_world_t *world = ecs_init();
Expand Down Expand Up @@ -139,7 +139,7 @@ static
void set_entity_random_components(
int32_t threads)
{
test_quarantine("---");
test_quarantine("16 Jan 2023");
return;

ecs_world_t *world = ecs_init();
Expand Down
12 changes: 11 additions & 1 deletion test/api/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1747,6 +1747,8 @@ void Observer_on_add_2_pairs_w_uni_observer(void);
void Observer_on_add_2_pairs_w_multi_observer(void);
void Observer_on_set_2_pairs_w_uni_observer(void);
void Observer_on_set_2_pairs_w_multi_observer(void);
void Observer_on_remove_target_from_base_at_offset(void);
void Observer_on_remove_target_component_from_base_at_offset(void);
void Observer_cache_test_1(void);
void Observer_cache_test_2(void);
void Observer_cache_test_3(void);
Expand Down Expand Up @@ -9108,6 +9110,14 @@ bake_test_case Observer_testcases[] = {
"on_set_2_pairs_w_multi_observer",
Observer_on_set_2_pairs_w_multi_observer
},
{
"on_remove_target_from_base_at_offset",
Observer_on_remove_target_from_base_at_offset
},
{
"on_remove_target_component_from_base_at_offset",
Observer_on_remove_target_component_from_base_at_offset
},
{
"cache_test_1",
Observer_cache_test_1
Expand Down Expand Up @@ -11607,7 +11617,7 @@ static bake_test_suite suites[] = {
"Observer",
NULL,
NULL,
102,
104,
Observer_testcases
},
{
Expand Down

0 comments on commit 2b0a2d8

Please sign in to comment.