Skip to content

Commit f479787

Browse files
committed
Add missing event propagation paths
1 parent a496e0d commit f479787

File tree

5 files changed

+723
-104
lines changed

5 files changed

+723
-104
lines changed

flecs.c

+96-30
Original file line numberDiff line numberDiff line change
@@ -14864,7 +14864,9 @@ void flecs_emit_propagate(
1486414864
/* Get traversed relationship */
1486514865
ecs_entity_t trav = ECS_PAIR_FIRST(cur->id);
1486614866
if (propagate_trav && propagate_trav != trav) {
14867-
continue;
14867+
if (propagate_trav != EcsIsA) {
14868+
continue;
14869+
}
1486814870
}
1486914871

1487014872
flecs_emit_propagate_id(
@@ -14951,6 +14953,55 @@ void flecs_emit_propagate_invalidate(
1495114953
}
1495214954
}
1495314955

14956+
static
14957+
void flecs_propagate_entities(
14958+
ecs_world_t *world,
14959+
ecs_iter_t *it,
14960+
ecs_id_record_t *idr,
14961+
ecs_entity_t *entities,
14962+
int32_t count,
14963+
ecs_entity_t src,
14964+
ecs_event_id_record_t **iders,
14965+
int32_t ider_count)
14966+
{
14967+
if (!count) {
14968+
return;
14969+
}
14970+
14971+
ecs_entity_t old_src = it->sources[0];
14972+
ecs_table_t *old_table = it->table;
14973+
ecs_table_t *old_other_table = it->other_table;
14974+
ecs_entity_t *old_entities = it->entities;
14975+
int32_t old_count = it->count;
14976+
int32_t old_offset = it->offset;
14977+
14978+
int32_t i;
14979+
for (i = 0; i < count; i ++) {
14980+
ecs_record_t *record = flecs_entities_get(world, entities[i]);
14981+
if (!record) {
14982+
/* If the event is emitted after a bulk operation, it's possible
14983+
* that it hasn't been populated with entities yet. */
14984+
continue;
14985+
}
14986+
14987+
ecs_id_record_t *idr_t = record->idr;
14988+
if (idr_t) {
14989+
/* Entity is used as target in traversable pairs, propagate */
14990+
ecs_entity_t e = src ? src : entities[i];
14991+
it->sources[0] = e;
14992+
flecs_emit_propagate(
14993+
world, it, idr, idr_t, 0, iders, ider_count);
14994+
}
14995+
}
14996+
14997+
it->table = old_table;
14998+
it->other_table = old_other_table;
14999+
it->entities = old_entities;
15000+
it->count = old_count;
15001+
it->offset = old_offset;
15002+
it->sources[0] = old_src;
15003+
}
15004+
1495415005
static
1495515006
void flecs_override_copy(
1495615007
ecs_world_t *world,
@@ -15316,7 +15367,7 @@ void flecs_emit_forward_table_up(
1531615367
}
1531715368

1531815369
/* Id has the same relationship, traverse to find ids for forwarding */
15319-
if (ECS_PAIR_FIRST(id) == trav) {
15370+
if (ECS_PAIR_FIRST(id) == trav || ECS_PAIR_FIRST(id) == EcsIsA) {
1532015371
ecs_table_t **t = ecs_vec_append_t(&world->allocator, stack,
1532115372
ecs_table_t*);
1532215373
t[0] = tgt_table;
@@ -15512,6 +15563,46 @@ void flecs_emit_forward(
1551215563
rc_idr, elem->src, r->table, tr->index, offset, trav);
1551315564
}
1551415565
}
15566+
15567+
/* Propagate events for new reachable ids downwards */
15568+
if (table->_->traversable_count) {
15569+
int32_t i;
15570+
ecs_entity_t *entities = flecs_table_entities_array(table);
15571+
entities = ECS_ELEM_T(entities, ecs_entity_t, it->offset);
15572+
for (i = 0; i < it->count; i ++) {
15573+
ecs_record_t *r = flecs_entities_get(world, entities[i]);
15574+
if (r->idr) {
15575+
break;
15576+
}
15577+
}
15578+
15579+
if (i != it->count) {
15580+
ecs_reachable_elem_t *elems = ecs_vec_first_t(&rc->ids,
15581+
ecs_reachable_elem_t);
15582+
int32_t count = ecs_vec_count(&rc->ids);
15583+
for (i = 0; i < count; i ++) {
15584+
ecs_reachable_elem_t *elem = &elems[i];
15585+
const ecs_table_record_t *tr = elem->tr;
15586+
ecs_assert(tr != NULL, ECS_INTERNAL_ERROR, NULL);
15587+
ecs_id_record_t *rc_idr = (ecs_id_record_t*)tr->hdr.cache;
15588+
ecs_record_t *r = elem->record;
15589+
15590+
ecs_assert(rc_idr->id == elem->id, ECS_INTERNAL_ERROR, NULL);
15591+
ecs_assert(r != NULL, ECS_INTERNAL_ERROR, NULL);
15592+
ecs_assert(flecs_entities_get(world, elem->src) == r,
15593+
ECS_INTERNAL_ERROR, NULL);
15594+
ecs_dbg_assert(r->table == elem->table, ECS_INTERNAL_ERROR, NULL);
15595+
(void)r;
15596+
15597+
ecs_event_id_record_t *iders[5] = {0};
15598+
int32_t ider_count = flecs_event_observers_get(
15599+
er, rc_idr->id, iders);
15600+
15601+
flecs_propagate_entities(world, it, rc_idr, it->entities,
15602+
it->count, elem->src, iders, ider_count);
15603+
}
15604+
}
15605+
}
1551515606
}
1551615607

1551715608
/* The emit function is responsible for finding and invoking the observers
@@ -15543,7 +15634,7 @@ void flecs_emit(
1554315634
ecs_entity_t event = desc->event;
1554415635
ecs_table_t *table = desc->table, *other_table = desc->other_table;
1554515636
int32_t offset = desc->offset;
15546-
int32_t i, r, count = desc->count;
15637+
int32_t i, count = desc->count;
1554715638
ecs_flags32_t table_flags = table->flags;
1554815639

1554915640
/* Deferring cannot be suspended for observers */
@@ -15842,33 +15933,8 @@ void flecs_emit(
1584215933
* entities that are used as targets of traversable relationships. If the
1584315934
* entity/entities for which the event was generated is used as such a
1584415935
* target, events must be propagated downwards. */
15845-
ecs_entity_t *entities = it.entities;
15846-
it.entities = NULL;
15847-
15848-
for (r = 0; r < count; r ++) {
15849-
ecs_record_t *record = flecs_entities_get(world, entities[r]);
15850-
if (!record) {
15851-
/* If the event is emitted after a bulk operation, it's possible
15852-
* that it hasn't been populated with entities yet. */
15853-
continue;
15854-
}
15855-
15856-
ecs_id_record_t *idr_t = record->idr;
15857-
if (idr_t) {
15858-
/* Entity is used as target in traversable pairs, propagate */
15859-
ecs_entity_t e = entities[r];
15860-
it.sources[0] = e;
15861-
flecs_emit_propagate(
15862-
world, &it, idr, idr_t, 0, iders, ider_count);
15863-
}
15864-
}
15865-
15866-
it.table = table;
15867-
it.other_table = other_table;
15868-
it.entities = entities;
15869-
it.count = count;
15870-
it.offset = offset;
15871-
it.sources[0] = 0;
15936+
flecs_propagate_entities(
15937+
world, &it, idr, it.entities, count, 0, iders, ider_count);
1587215938
}
1587315939

1587415940
can_override = false; /* Don't override twice */

src/observable.c

+96-30
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,9 @@ void flecs_emit_propagate(
346346
/* Get traversed relationship */
347347
ecs_entity_t trav = ECS_PAIR_FIRST(cur->id);
348348
if (propagate_trav && propagate_trav != trav) {
349-
continue;
349+
if (propagate_trav != EcsIsA) {
350+
continue;
351+
}
350352
}
351353

352354
flecs_emit_propagate_id(
@@ -433,6 +435,55 @@ void flecs_emit_propagate_invalidate(
433435
}
434436
}
435437

438+
static
439+
void flecs_propagate_entities(
440+
ecs_world_t *world,
441+
ecs_iter_t *it,
442+
ecs_id_record_t *idr,
443+
ecs_entity_t *entities,
444+
int32_t count,
445+
ecs_entity_t src,
446+
ecs_event_id_record_t **iders,
447+
int32_t ider_count)
448+
{
449+
if (!count) {
450+
return;
451+
}
452+
453+
ecs_entity_t old_src = it->sources[0];
454+
ecs_table_t *old_table = it->table;
455+
ecs_table_t *old_other_table = it->other_table;
456+
ecs_entity_t *old_entities = it->entities;
457+
int32_t old_count = it->count;
458+
int32_t old_offset = it->offset;
459+
460+
int32_t i;
461+
for (i = 0; i < count; i ++) {
462+
ecs_record_t *record = flecs_entities_get(world, entities[i]);
463+
if (!record) {
464+
/* If the event is emitted after a bulk operation, it's possible
465+
* that it hasn't been populated with entities yet. */
466+
continue;
467+
}
468+
469+
ecs_id_record_t *idr_t = record->idr;
470+
if (idr_t) {
471+
/* Entity is used as target in traversable pairs, propagate */
472+
ecs_entity_t e = src ? src : entities[i];
473+
it->sources[0] = e;
474+
flecs_emit_propagate(
475+
world, it, idr, idr_t, 0, iders, ider_count);
476+
}
477+
}
478+
479+
it->table = old_table;
480+
it->other_table = old_other_table;
481+
it->entities = old_entities;
482+
it->count = old_count;
483+
it->offset = old_offset;
484+
it->sources[0] = old_src;
485+
}
486+
436487
static
437488
void flecs_override_copy(
438489
ecs_world_t *world,
@@ -798,7 +849,7 @@ void flecs_emit_forward_table_up(
798849
}
799850

800851
/* Id has the same relationship, traverse to find ids for forwarding */
801-
if (ECS_PAIR_FIRST(id) == trav) {
852+
if (ECS_PAIR_FIRST(id) == trav || ECS_PAIR_FIRST(id) == EcsIsA) {
802853
ecs_table_t **t = ecs_vec_append_t(&world->allocator, stack,
803854
ecs_table_t*);
804855
t[0] = tgt_table;
@@ -994,6 +1045,46 @@ void flecs_emit_forward(
9941045
rc_idr, elem->src, r->table, tr->index, offset, trav);
9951046
}
9961047
}
1048+
1049+
/* Propagate events for new reachable ids downwards */
1050+
if (table->_->traversable_count) {
1051+
int32_t i;
1052+
ecs_entity_t *entities = flecs_table_entities_array(table);
1053+
entities = ECS_ELEM_T(entities, ecs_entity_t, it->offset);
1054+
for (i = 0; i < it->count; i ++) {
1055+
ecs_record_t *r = flecs_entities_get(world, entities[i]);
1056+
if (r->idr) {
1057+
break;
1058+
}
1059+
}
1060+
1061+
if (i != it->count) {
1062+
ecs_reachable_elem_t *elems = ecs_vec_first_t(&rc->ids,
1063+
ecs_reachable_elem_t);
1064+
int32_t count = ecs_vec_count(&rc->ids);
1065+
for (i = 0; i < count; i ++) {
1066+
ecs_reachable_elem_t *elem = &elems[i];
1067+
const ecs_table_record_t *tr = elem->tr;
1068+
ecs_assert(tr != NULL, ECS_INTERNAL_ERROR, NULL);
1069+
ecs_id_record_t *rc_idr = (ecs_id_record_t*)tr->hdr.cache;
1070+
ecs_record_t *r = elem->record;
1071+
1072+
ecs_assert(rc_idr->id == elem->id, ECS_INTERNAL_ERROR, NULL);
1073+
ecs_assert(r != NULL, ECS_INTERNAL_ERROR, NULL);
1074+
ecs_assert(flecs_entities_get(world, elem->src) == r,
1075+
ECS_INTERNAL_ERROR, NULL);
1076+
ecs_dbg_assert(r->table == elem->table, ECS_INTERNAL_ERROR, NULL);
1077+
(void)r;
1078+
1079+
ecs_event_id_record_t *iders[5] = {0};
1080+
int32_t ider_count = flecs_event_observers_get(
1081+
er, rc_idr->id, iders);
1082+
1083+
flecs_propagate_entities(world, it, rc_idr, it->entities,
1084+
it->count, elem->src, iders, ider_count);
1085+
}
1086+
}
1087+
}
9971088
}
9981089

9991090
/* The emit function is responsible for finding and invoking the observers
@@ -1025,7 +1116,7 @@ void flecs_emit(
10251116
ecs_entity_t event = desc->event;
10261117
ecs_table_t *table = desc->table, *other_table = desc->other_table;
10271118
int32_t offset = desc->offset;
1028-
int32_t i, r, count = desc->count;
1119+
int32_t i, count = desc->count;
10291120
ecs_flags32_t table_flags = table->flags;
10301121

10311122
/* Deferring cannot be suspended for observers */
@@ -1324,33 +1415,8 @@ void flecs_emit(
13241415
* entities that are used as targets of traversable relationships. If the
13251416
* entity/entities for which the event was generated is used as such a
13261417
* target, events must be propagated downwards. */
1327-
ecs_entity_t *entities = it.entities;
1328-
it.entities = NULL;
1329-
1330-
for (r = 0; r < count; r ++) {
1331-
ecs_record_t *record = flecs_entities_get(world, entities[r]);
1332-
if (!record) {
1333-
/* If the event is emitted after a bulk operation, it's possible
1334-
* that it hasn't been populated with entities yet. */
1335-
continue;
1336-
}
1337-
1338-
ecs_id_record_t *idr_t = record->idr;
1339-
if (idr_t) {
1340-
/* Entity is used as target in traversable pairs, propagate */
1341-
ecs_entity_t e = entities[r];
1342-
it.sources[0] = e;
1343-
flecs_emit_propagate(
1344-
world, &it, idr, idr_t, 0, iders, ider_count);
1345-
}
1346-
}
1347-
1348-
it.table = table;
1349-
it.other_table = other_table;
1350-
it.entities = entities;
1351-
it.count = count;
1352-
it.offset = offset;
1353-
it.sources[0] = 0;
1418+
flecs_propagate_entities(
1419+
world, &it, idr, it.entities, count, 0, iders, ider_count);
13541420
}
13551421

13561422
can_override = false; /* Don't override twice */

test/api/project.json

+13-1
Original file line numberDiff line numberDiff line change
@@ -2098,6 +2098,19 @@
20982098
"on_add_after_batch_w_exclusive_adds",
20992099
"propagate_match_relationship_w_self_up",
21002100
"propagate_match_relationship_w_up",
2101+
"propagate_isa_of_parent_add",
2102+
"propagate_isa_of_parent_remove",
2103+
"propagate_isa_of_parent_set",
2104+
"propagate_add_childof_of_parent",
2105+
"propagate_add_childof_of_parent_w_siblings",
2106+
"propagate_add_childof_w_parent_w_base",
2107+
"propagate_remove_childof_w_parent_w_base",
2108+
"propagate_remove_childof_of_parent",
2109+
"propagate_add_isa_of_parent",
2110+
"propagate_remove_isa_of_parent",
2111+
"propagate_add_childof_of_base",
2112+
"propagate_remove_childof_of_base",
2113+
"emit_for_parent_w_prefab_child_and_instance",
21012114
"observer_w_2_fixed_src",
21022115
"emit_for_recreated_id_after_remove_all",
21032116
"emit_for_recreated_id_after_remove_all_wildcard",
@@ -2120,7 +2133,6 @@
21202133
"wildcard_propagate_w_other_table",
21212134
"add_in_yield_existing",
21222135
"add_in_yield_existing_multi",
2123-
"emit_for_parent_w_prefab_child_and_instance",
21242136
"disable_observer",
21252137
"disable_observer_module",
21262138
"disable_observer_module_nested",

0 commit comments

Comments
 (0)