Skip to content

Commit 7874ea5

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

File tree

5 files changed

+647
-102
lines changed

5 files changed

+647
-102
lines changed

flecs.c

+94-29
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,54 @@ void flecs_emit_propagate_invalidate(
1495114953
}
1495214954
}
1495314955

14956+
void flecs_propagate_entities(
14957+
ecs_world_t *world,
14958+
ecs_iter_t *it,
14959+
ecs_id_record_t *idr,
14960+
ecs_entity_t *entities,
14961+
int32_t count,
14962+
ecs_entity_t src,
14963+
ecs_event_id_record_t **iders,
14964+
int32_t ider_count)
14965+
{
14966+
if (!count) {
14967+
return;
14968+
}
14969+
14970+
ecs_entity_t old_src = it->sources[0];
14971+
ecs_table_t *old_table = it->table;
14972+
ecs_table_t *old_other_table = it->other_table;
14973+
ecs_entity_t *old_entities = it->entities;
14974+
int32_t old_count = it->count;
14975+
int32_t old_offset = it->offset;
14976+
14977+
int32_t i;
14978+
for (i = 0; i < count; i ++) {
14979+
ecs_record_t *record = flecs_entities_get(world, entities[i]);
14980+
if (!record) {
14981+
/* If the event is emitted after a bulk operation, it's possible
14982+
* that it hasn't been populated with entities yet. */
14983+
continue;
14984+
}
14985+
14986+
ecs_id_record_t *idr_t = record->idr;
14987+
if (idr_t) {
14988+
/* Entity is used as target in traversable pairs, propagate */
14989+
ecs_entity_t e = src ? src : entities[i];
14990+
it->sources[0] = e;
14991+
flecs_emit_propagate(
14992+
world, it, idr, idr_t, 0, iders, ider_count);
14993+
}
14994+
}
14995+
14996+
it->table = old_table;
14997+
it->other_table = old_other_table;
14998+
it->entities = old_entities;
14999+
it->count = old_count;
15000+
it->offset = old_offset;
15001+
it->sources[0] = old_src;
15002+
}
15003+
1495415004
static
1495515005
void flecs_override_copy(
1495615006
ecs_world_t *world,
@@ -15512,6 +15562,46 @@ void flecs_emit_forward(
1551215562
rc_idr, elem->src, r->table, tr->index, offset, trav);
1551315563
}
1551415564
}
15565+
15566+
/* Propagate events for new reachable ids downwards */
15567+
if (table->_->traversable_count) {
15568+
int32_t i;
15569+
ecs_entity_t *entities = flecs_table_entities_array(table);
15570+
entities = ECS_ELEM_T(entities, ecs_entity_t, it->offset);
15571+
for (i = 0; i < it->count; i ++) {
15572+
ecs_record_t *r = flecs_entities_get(world, entities[i]);
15573+
if (r->idr) {
15574+
break;
15575+
}
15576+
}
15577+
15578+
if (i != it->count) {
15579+
ecs_reachable_elem_t *elems = ecs_vec_first_t(&rc->ids,
15580+
ecs_reachable_elem_t);
15581+
int32_t count = ecs_vec_count(&rc->ids);
15582+
for (i = 0; i < count; i ++) {
15583+
ecs_reachable_elem_t *elem = &elems[i];
15584+
const ecs_table_record_t *tr = elem->tr;
15585+
ecs_assert(tr != NULL, ECS_INTERNAL_ERROR, NULL);
15586+
ecs_id_record_t *rc_idr = (ecs_id_record_t*)tr->hdr.cache;
15587+
ecs_record_t *r = elem->record;
15588+
15589+
ecs_assert(rc_idr->id == elem->id, ECS_INTERNAL_ERROR, NULL);
15590+
ecs_assert(r != NULL, ECS_INTERNAL_ERROR, NULL);
15591+
ecs_assert(flecs_entities_get(world, elem->src) == r,
15592+
ECS_INTERNAL_ERROR, NULL);
15593+
ecs_dbg_assert(r->table == elem->table, ECS_INTERNAL_ERROR, NULL);
15594+
(void)r;
15595+
15596+
ecs_event_id_record_t *iders[5] = {0};
15597+
int32_t ider_count = flecs_event_observers_get(
15598+
er, rc_idr->id, iders);
15599+
15600+
flecs_propagate_entities(world, it, rc_idr, it->entities,
15601+
it->count, elem->src, iders, ider_count);
15602+
}
15603+
}
15604+
}
1551515605
}
1551615606

1551715607
/* The emit function is responsible for finding and invoking the observers
@@ -15543,7 +15633,7 @@ void flecs_emit(
1554315633
ecs_entity_t event = desc->event;
1554415634
ecs_table_t *table = desc->table, *other_table = desc->other_table;
1554515635
int32_t offset = desc->offset;
15546-
int32_t i, r, count = desc->count;
15636+
int32_t i, count = desc->count;
1554715637
ecs_flags32_t table_flags = table->flags;
1554815638

1554915639
/* Deferring cannot be suspended for observers */
@@ -15842,33 +15932,8 @@ void flecs_emit(
1584215932
* entities that are used as targets of traversable relationships. If the
1584315933
* entity/entities for which the event was generated is used as such a
1584415934
* 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;
15935+
flecs_propagate_entities(
15936+
world, &it, idr, it.entities, count, 0, iders, ider_count);
1587215937
}
1587315938

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

src/observable.c

+95-29
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,
@@ -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

+11-1
Original file line numberDiff line numberDiff line change
@@ -2098,6 +2098,17 @@
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_remove_childof_of_parent",
2107+
"propagate_add_isa_of_parent",
2108+
"propagate_remove_isa_of_parent",
2109+
"propagate_add_childof_of_base",
2110+
"propagate_remove_childof_of_base",
2111+
"emit_for_parent_w_prefab_child_and_instance",
21012112
"observer_w_2_fixed_src",
21022113
"emit_for_recreated_id_after_remove_all",
21032114
"emit_for_recreated_id_after_remove_all_wildcard",
@@ -2120,7 +2131,6 @@
21202131
"wildcard_propagate_w_other_table",
21212132
"add_in_yield_existing",
21222133
"add_in_yield_existing_multi",
2123-
"emit_for_parent_w_prefab_child_and_instance",
21242134
"disable_observer",
21252135
"disable_observer_module",
21262136
"disable_observer_module_nested",

0 commit comments

Comments
 (0)