Skip to content

Commit

Permalink
Prevent event from being propagated along incorrect relationship edge
Browse files Browse the repository at this point in the history
  • Loading branch information
SanderMertens committed Oct 3, 2023
1 parent c549506 commit 0ed5507
Show file tree
Hide file tree
Showing 9 changed files with 224 additions and 125 deletions.
150 changes: 88 additions & 62 deletions flecs.c
Original file line number Diff line number Diff line change
Expand Up @@ -2411,9 +2411,6 @@ void flecs_table_hashmap_init(
ecs_world_t *world,
ecs_hashmap_t *hm);

void flecs_dump_backtrace(
FILE *stream);

void flecs_colorize_buf(
char *msg,
bool enable_colors,
Expand Down Expand Up @@ -14151,6 +14148,85 @@ void flecs_emit_propagate(
ecs_iter_t *it,
ecs_id_record_t *idr,
ecs_id_record_t *tgt_idr,
ecs_entity_t trav,
ecs_event_id_record_t **iders,
int32_t ider_count);

static
void flecs_emit_propagate_id(
ecs_world_t *world,
ecs_iter_t *it,
ecs_id_record_t *idr,
ecs_id_record_t *cur,
ecs_entity_t trav,
ecs_event_id_record_t **iders,
int32_t ider_count)
{
ecs_table_cache_iter_t idt;
if (!flecs_table_cache_all_iter(&cur->cache, &idt)) {
return;
}

const ecs_table_record_t *tr;
while ((tr = flecs_table_cache_next(&idt, ecs_table_record_t))) {
ecs_table_t *table = tr->hdr.table;
if (!ecs_table_count(table)) {
continue;
}

bool owned = flecs_id_record_get_table(idr, table) != NULL;

int32_t e, entity_count = ecs_table_count(table);
it->table = table;
it->other_table = NULL;
it->offset = 0;
it->count = entity_count;
if (entity_count) {
it->entities = ecs_vec_first(&table->data.entities);
}

/* Treat as new event as this could invoke observers again for
* different tables. */
int32_t evtx = ++ world->event_id;

int32_t ider_i;
for (ider_i = 0; ider_i < ider_count; ider_i ++) {
ecs_event_id_record_t *ider = iders[ider_i];
flecs_observers_invoke(world, &ider->up, it, table, trav, evtx);

if (!owned) {
/* Owned takes precedence */
flecs_observers_invoke(
world, &ider->self_up, it, table, trav, evtx);
}
}

if (!table->_->traversable_count) {
continue;
}

ecs_record_t **records = ecs_vec_first(&table->data.records);
for (e = 0; e < entity_count; e ++) {
ecs_record_t *r = records[e];
ecs_assert(r != NULL, ECS_INTERNAL_ERROR, NULL);
ecs_id_record_t *idr_t = r->idr;
if (idr_t) {
/* Only notify for entities that are used in pairs with
* traversable relationships */
flecs_emit_propagate(world, it, idr, idr_t, trav,
iders, ider_count);
}
}
}
}

static
void flecs_emit_propagate(
ecs_world_t *world,
ecs_iter_t *it,
ecs_id_record_t *idr,
ecs_id_record_t *tgt_idr,
ecs_entity_t propagate_trav,
ecs_event_id_record_t **iders,
int32_t ider_count)
{
Expand All @@ -14168,65 +14244,14 @@ void flecs_emit_propagate(
while ((cur = cur->trav.next)) {
cur->reachable.generation ++; /* Invalidate cache */

ecs_table_cache_iter_t idt;
if (!flecs_table_cache_all_iter(&cur->cache, &idt)) {
continue;
}

/* Get traversed relationship */
ecs_entity_t trav = ECS_PAIR_FIRST(cur->id);

const ecs_table_record_t *tr;
while ((tr = flecs_table_cache_next(&idt, ecs_table_record_t))) {
ecs_table_t *table = tr->hdr.table;
if (!ecs_table_count(table)) {
continue;
}

bool owned = flecs_id_record_get_table(idr, table) != NULL;

int32_t e, entity_count = ecs_table_count(table);
it->table = table;
it->other_table = NULL;
it->offset = 0;
it->count = entity_count;
if (entity_count) {
it->entities = ecs_vec_first(&table->data.entities);
}

/* Treat as new event as this could invoke observers again for
* different tables. */
int32_t evtx = ++ world->event_id;

int32_t ider_i;
for (ider_i = 0; ider_i < ider_count; ider_i ++) {
ecs_event_id_record_t *ider = iders[ider_i];
flecs_observers_invoke(world, &ider->up, it, table, trav, evtx);

if (!owned) {
/* Owned takes precedence */
flecs_observers_invoke(
world, &ider->self_up, it, table, trav, evtx);
}
}

if (!table->_->traversable_count) {
continue;
}

ecs_record_t **records = ecs_vec_first(&table->data.records);
for (e = 0; e < entity_count; e ++) {
ecs_record_t *r = records[e];
ecs_assert(r != NULL, ECS_INTERNAL_ERROR, NULL);
ecs_id_record_t *idr_t = r->idr;
if (idr_t) {
/* Only notify for entities that are used in pairs with
* traversable relationships */
flecs_emit_propagate(world, it, idr, idr_t,
iders, ider_count);
}
}
if (propagate_trav && propagate_trav != trav) {
continue;
}

flecs_emit_propagate_id(
world, it, idr, cur, trav, iders, ider_count);
}

ecs_log_pop_3();
Expand Down Expand Up @@ -15218,7 +15243,8 @@ void flecs_emit(
/* Entity is used as target in traversable pairs, propagate */
ecs_entity_t e = entities[r];
it.sources[0] = e;
flecs_emit_propagate(world, &it, idr, idr_t, iders, ider_count);
flecs_emit_propagate(
world, &it, idr, idr_t, 0, iders, ider_count);
}
}

Expand Down Expand Up @@ -16398,7 +16424,7 @@ void ecs_os_fini(void) {
#define ECS_BT_BUF_SIZE 100

void flecs_dump_backtrace(
FILE *stream)
void *stream)
{
int nptrs;
void *buffer[ECS_BT_BUF_SIZE];
Expand All @@ -16419,7 +16445,7 @@ void flecs_dump_backtrace(
}
#else
void flecs_dump_backtrace(
FILE *stream)
void *stream)
{
(void)stream;
}
Expand Down
4 changes: 4 additions & 0 deletions flecs.h
Original file line number Diff line number Diff line change
Expand Up @@ -3471,6 +3471,10 @@ FLECS_DBG_API
int32_t flecs_table_observed_count(
const ecs_table_t *table);

FLECS_DBG_API
void flecs_dump_backtrace(
void *stream);

/** Calculate offset from address */
#ifdef __cplusplus
#define ECS_OFFSET(o, offset) reinterpret_cast<void*>((reinterpret_cast<uintptr_t>(o)) + (static_cast<uintptr_t>(offset)))
Expand Down
4 changes: 4 additions & 0 deletions include/flecs/private/api_support.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ FLECS_DBG_API
int32_t flecs_table_observed_count(
const ecs_table_t *table);

FLECS_DBG_API
void flecs_dump_backtrace(
void *stream);

/** Calculate offset from address */
#ifdef __cplusplus
#define ECS_OFFSET(o, offset) reinterpret_cast<void*>((reinterpret_cast<uintptr_t>(o)) + (static_cast<uintptr_t>(offset)))
Expand Down
143 changes: 86 additions & 57 deletions src/observable.c
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,85 @@ void flecs_emit_propagate(
ecs_iter_t *it,
ecs_id_record_t *idr,
ecs_id_record_t *tgt_idr,
ecs_entity_t trav,
ecs_event_id_record_t **iders,
int32_t ider_count);

static
void flecs_emit_propagate_id(
ecs_world_t *world,
ecs_iter_t *it,
ecs_id_record_t *idr,
ecs_id_record_t *cur,
ecs_entity_t trav,
ecs_event_id_record_t **iders,
int32_t ider_count)
{
ecs_table_cache_iter_t idt;
if (!flecs_table_cache_all_iter(&cur->cache, &idt)) {
return;
}

const ecs_table_record_t *tr;
while ((tr = flecs_table_cache_next(&idt, ecs_table_record_t))) {
ecs_table_t *table = tr->hdr.table;
if (!ecs_table_count(table)) {
continue;
}

bool owned = flecs_id_record_get_table(idr, table) != NULL;

int32_t e, entity_count = ecs_table_count(table);
it->table = table;
it->other_table = NULL;
it->offset = 0;
it->count = entity_count;
if (entity_count) {
it->entities = ecs_vec_first(&table->data.entities);
}

/* Treat as new event as this could invoke observers again for
* different tables. */
int32_t evtx = ++ world->event_id;

int32_t ider_i;
for (ider_i = 0; ider_i < ider_count; ider_i ++) {
ecs_event_id_record_t *ider = iders[ider_i];
flecs_observers_invoke(world, &ider->up, it, table, trav, evtx);

if (!owned) {
/* Owned takes precedence */
flecs_observers_invoke(
world, &ider->self_up, it, table, trav, evtx);
}
}

if (!table->_->traversable_count) {
continue;
}

ecs_record_t **records = ecs_vec_first(&table->data.records);
for (e = 0; e < entity_count; e ++) {
ecs_record_t *r = records[e];
ecs_assert(r != NULL, ECS_INTERNAL_ERROR, NULL);
ecs_id_record_t *idr_t = r->idr;
if (idr_t) {
/* Only notify for entities that are used in pairs with
* traversable relationships */
flecs_emit_propagate(world, it, idr, idr_t, trav,
iders, ider_count);
}
}
}
}

static
void flecs_emit_propagate(
ecs_world_t *world,
ecs_iter_t *it,
ecs_id_record_t *idr,
ecs_id_record_t *tgt_idr,
ecs_entity_t propagate_trav,
ecs_event_id_record_t **iders,
int32_t ider_count)
{
Expand All @@ -257,65 +336,14 @@ void flecs_emit_propagate(
while ((cur = cur->trav.next)) {
cur->reachable.generation ++; /* Invalidate cache */

ecs_table_cache_iter_t idt;
if (!flecs_table_cache_all_iter(&cur->cache, &idt)) {
continue;
}

/* Get traversed relationship */
ecs_entity_t trav = ECS_PAIR_FIRST(cur->id);

const ecs_table_record_t *tr;
while ((tr = flecs_table_cache_next(&idt, ecs_table_record_t))) {
ecs_table_t *table = tr->hdr.table;
if (!ecs_table_count(table)) {
continue;
}

bool owned = flecs_id_record_get_table(idr, table) != NULL;

int32_t e, entity_count = ecs_table_count(table);
it->table = table;
it->other_table = NULL;
it->offset = 0;
it->count = entity_count;
if (entity_count) {
it->entities = ecs_vec_first(&table->data.entities);
}

/* Treat as new event as this could invoke observers again for
* different tables. */
int32_t evtx = ++ world->event_id;

int32_t ider_i;
for (ider_i = 0; ider_i < ider_count; ider_i ++) {
ecs_event_id_record_t *ider = iders[ider_i];
flecs_observers_invoke(world, &ider->up, it, table, trav, evtx);

if (!owned) {
/* Owned takes precedence */
flecs_observers_invoke(
world, &ider->self_up, it, table, trav, evtx);
}
}

if (!table->_->traversable_count) {
continue;
}

ecs_record_t **records = ecs_vec_first(&table->data.records);
for (e = 0; e < entity_count; e ++) {
ecs_record_t *r = records[e];
ecs_assert(r != NULL, ECS_INTERNAL_ERROR, NULL);
ecs_id_record_t *idr_t = r->idr;
if (idr_t) {
/* Only notify for entities that are used in pairs with
* traversable relationships */
flecs_emit_propagate(world, it, idr, idr_t,
iders, ider_count);
}
}
if (propagate_trav && propagate_trav != trav) {
continue;
}

flecs_emit_propagate_id(
world, it, idr, cur, trav, iders, ider_count);
}

ecs_log_pop_3();
Expand Down Expand Up @@ -1307,7 +1335,8 @@ void flecs_emit(
/* Entity is used as target in traversable pairs, propagate */
ecs_entity_t e = entities[r];
it.sources[0] = e;
flecs_emit_propagate(world, &it, idr, idr_t, iders, ider_count);
flecs_emit_propagate(
world, &it, idr, idr_t, 0, iders, ider_count);
}
}

Expand Down
Loading

0 comments on commit 0ed5507

Please sign in to comment.