Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trigger OnRemove yield_existing observer when it is deleted #1357

Merged
merged 1 commit into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 34 additions & 3 deletions distr/flecs.c
Original file line number Diff line number Diff line change
Expand Up @@ -14571,7 +14571,8 @@ void flecs_multi_observer_builtin_run(ecs_iter_t *it) {
static
void flecs_observer_yield_existing(
ecs_world_t *world,
ecs_observer_t *o)
ecs_observer_t *o,
bool yield_on_remove)
{
ecs_run_action_t run = o->run;
if (!run) {
Expand All @@ -14586,6 +14587,19 @@ void flecs_observer_yield_existing(
* the event, if the event is iterable. */
int i, count = o->event_count;
for (i = 0; i < count; i ++) {
ecs_entity_t event = o->events[i];

/* We only yield for OnRemove events if the observer is deleted. */
if (event == EcsOnRemove) {
if (!yield_on_remove) {
continue;
}
} else {
if (yield_on_remove) {
continue;
}
}

ecs_iter_t it = ecs_query_iter(world, o->query);
it.system = o->entity;
it.ctx = o;
Expand Down Expand Up @@ -14919,6 +14933,8 @@ ecs_observer_t* flecs_observer_init(
impl->term_index = desc->term_index_;
impl->flags = desc->flags_;

bool yield_on_create = false;

/* Check if observer is monitor. Monitors are created as multi observers
* since they require pre/post checking of the filter to test if the
* entity is entering/leaving the monitor. */
Expand All @@ -14937,8 +14953,19 @@ ecs_observer_t* flecs_observer_init(
o->events[1] = EcsOnRemove;
o->event_count ++;
impl->flags |= EcsObserverIsMonitor;
if (desc->yield_existing) {
impl->flags |= EcsObserverYieldOnDelete;
yield_on_create = true;
}
} else {
o->events[i] = event;
if (desc->yield_existing) {
if (event == EcsOnRemove) {
impl->flags |= EcsObserverYieldOnDelete;
} else {
yield_on_create = true;
}
}
}

o->event_count ++;
Expand Down Expand Up @@ -14972,8 +14999,8 @@ ecs_observer_t* flecs_observer_init(
}
}

if (desc->yield_existing) {
flecs_observer_yield_existing(world, o);
if (yield_on_create) {
flecs_observer_yield_existing(world, o, false);
}

return o;
Expand Down Expand Up @@ -15098,6 +15125,10 @@ void flecs_observer_fini(
ecs_world_t *world = o->query->world;
ecs_observer_impl_t *impl = flecs_observer_impl(o);

if (impl->flags & EcsObserverYieldOnDelete) {
flecs_observer_yield_existing(world, o, true);
}

if (impl->flags & EcsObserverIsMulti) {
ecs_observer_t **children = ecs_vec_first(&impl->children);
int32_t i, children_count = ecs_vec_count(&impl->children);
Expand Down
3 changes: 2 additions & 1 deletion distr/flecs.h
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,8 @@ extern "C" {
#define EcsObserverIsMonitor (1u << 2u) /* Is observer a monitor */
#define EcsObserverIsDisabled (1u << 3u) /* Is observer entity disabled */
#define EcsObserverIsParentDisabled (1u << 4u) /* Is module parent of observer disabled */
#define EcsObserverBypassQuery (1u << 5u)
#define EcsObserverBypassQuery (1u << 5u) /* Don't evaluate query for multi-component observer*/
#define EcsObserverYieldOnDelete (1u << 6u) /* Yield matching entities when deleting observer */

////////////////////////////////////////////////////////////////////////////////
//// Table flags (used by ecs_table_t::flags)
Expand Down
3 changes: 2 additions & 1 deletion include/flecs/private/api_flags.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,8 @@ extern "C" {
#define EcsObserverIsMonitor (1u << 2u) /* Is observer a monitor */
#define EcsObserverIsDisabled (1u << 3u) /* Is observer entity disabled */
#define EcsObserverIsParentDisabled (1u << 4u) /* Is module parent of observer disabled */
#define EcsObserverBypassQuery (1u << 5u)
#define EcsObserverBypassQuery (1u << 5u) /* Don't evaluate query for multi-component observer*/
#define EcsObserverYieldOnDelete (1u << 6u) /* Yield matching entities when deleting observer */

////////////////////////////////////////////////////////////////////////////////
//// Table flags (used by ecs_table_t::flags)
Expand Down
37 changes: 34 additions & 3 deletions src/observer.c
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,8 @@ void flecs_multi_observer_builtin_run(ecs_iter_t *it) {
static
void flecs_observer_yield_existing(
ecs_world_t *world,
ecs_observer_t *o)
ecs_observer_t *o,
bool yield_on_remove)
{
ecs_run_action_t run = o->run;
if (!run) {
Expand All @@ -614,6 +615,19 @@ void flecs_observer_yield_existing(
* the event, if the event is iterable. */
int i, count = o->event_count;
for (i = 0; i < count; i ++) {
ecs_entity_t event = o->events[i];

/* We only yield for OnRemove events if the observer is deleted. */
if (event == EcsOnRemove) {
if (!yield_on_remove) {
continue;
}
} else {
if (yield_on_remove) {
continue;
}
}

ecs_iter_t it = ecs_query_iter(world, o->query);
it.system = o->entity;
it.ctx = o;
Expand Down Expand Up @@ -947,6 +961,8 @@ ecs_observer_t* flecs_observer_init(
impl->term_index = desc->term_index_;
impl->flags = desc->flags_;

bool yield_on_create = false;

/* Check if observer is monitor. Monitors are created as multi observers
* since they require pre/post checking of the filter to test if the
* entity is entering/leaving the monitor. */
Expand All @@ -965,8 +981,19 @@ ecs_observer_t* flecs_observer_init(
o->events[1] = EcsOnRemove;
o->event_count ++;
impl->flags |= EcsObserverIsMonitor;
if (desc->yield_existing) {
impl->flags |= EcsObserverYieldOnDelete;
yield_on_create = true;
}
} else {
o->events[i] = event;
if (desc->yield_existing) {
if (event == EcsOnRemove) {
impl->flags |= EcsObserverYieldOnDelete;
} else {
yield_on_create = true;
}
}
}

o->event_count ++;
Expand Down Expand Up @@ -1000,8 +1027,8 @@ ecs_observer_t* flecs_observer_init(
}
}

if (desc->yield_existing) {
flecs_observer_yield_existing(world, o);
if (yield_on_create) {
flecs_observer_yield_existing(world, o, false);
}

return o;
Expand Down Expand Up @@ -1126,6 +1153,10 @@ void flecs_observer_fini(
ecs_world_t *world = o->query->world;
ecs_observer_impl_t *impl = flecs_observer_impl(o);

if (impl->flags & EcsObserverYieldOnDelete) {
flecs_observer_yield_existing(world, o, true);
}

if (impl->flags & EcsObserverIsMulti) {
ecs_observer_t **children = ecs_vec_first(&impl->children);
int32_t i, children_count = ecs_vec_count(&impl->children);
Expand Down
50 changes: 25 additions & 25 deletions test/core/include/core/bake_config.h
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
/*
)
(.)
.|.
| |
_.--| |--._
.-'; ;`-'& ; `&.
\ & ; & &_/
|"""---...---"""|
\ | | | | | | | /
`---.|.|.|.---'
* This file is generated by bake.lang.c for your convenience. Headers of
* dependencies will automatically show up in this file. Include bake_config.h
* in your main project file. Do not edit! */
#ifndef CORE_BAKE_CONFIG_H
#define CORE_BAKE_CONFIG_H
/* Headers of public dependencies */
#include <flecs.h>
#include <bake_test.h>
#endif
/*
)
(.)
.|.
| |
_.--| |--._
.-'; ;`-'& ; `&.
\ & ; & &_/
|"""---...---"""|
\ | | | | | | | /
`---.|.|.|.---'

* This file is generated by bake.lang.c for your convenience. Headers of
* dependencies will automatically show up in this file. Include bake_config.h
* in your main project file. Do not edit! */

#ifndef CORE_BAKE_CONFIG_H
#define CORE_BAKE_CONFIG_H

/* Headers of public dependencies */
#include <flecs.h>
#include <bake_test.h>

#endif

16 changes: 13 additions & 3 deletions test/core/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -1499,6 +1499,13 @@
"on_add_yield_existing_wildcard",
"on_add_yield_existing_wildcard_multi",
"on_add_yield_existing_wildcard_multi_w_wildcard_pivot",
"on_remove_yield_existing",
"on_remove_yield_existing_2_tables",
"on_remove_yield_existing_2_terms",
"on_remove_yield_existing_wildcard",
"on_remove_yield_existing_wildcard_multi",
"on_remove_yield_existing_wildcard_multi_w_wildcard_pivot",
"on_add_remove_yield_existing",
"observer_superset_wildcard",
"observer_superset_wildcard_add_isa",
"observer_superset_wildcard_add_isa_at_offset",
Expand Down Expand Up @@ -1557,8 +1564,10 @@
"notify_after_defer_batched_2_entities_in_table_w_tgt",
"multi_observer_table_fill_w_singleton",
"wildcard_propagate_w_other_table",
"add_in_yield_existing",
"add_in_yield_existing_multi",
"add_in_on_add_yield_existing",
"add_in_on_add_yield_existing_multi",
"add_in_on_remove_yield_existing",
"add_in_on_remove_yield_existing_multi",
"disable_observer",
"disable_observer_module",
"disable_observer_module_nested",
Expand Down Expand Up @@ -1725,7 +1734,8 @@
"monitor_w_wildcard",
"monitor_at_fini",
"monitor_other_table",
"monitor_component"
"monitor_component",
"yield_existing"
]
}, {
"id": "Prefab",
Expand Down
56 changes: 56 additions & 0 deletions test/core/src/Monitor.c
Original file line number Diff line number Diff line change
Expand Up @@ -733,3 +733,59 @@ void Monitor_monitor_component(void) {
test_int(ctx.invoked, 4);
test_assert(ctx.result == expect);
}

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

ECS_TAG(world, Tag);

/* Create entities before trigger */
ecs_entity_t e1 = ecs_new_w(world, Tag);
ecs_entity_t e2 = ecs_new_w(world, Tag);
ecs_entity_t e3 = ecs_new_w(world, Tag);

test_assert(e1 != 0);
test_assert(e2 != 0);
test_assert(e3 != 0);

Probe ctx = {0};
ecs_entity_t t = ecs_observer_init(world, &(ecs_observer_desc_t){
.query.terms = {{ Tag }},
.events = {EcsMonitor},
.callback = Monitor,
.ctx = &ctx,
.yield_existing = true
});

test_int(ctx.invoked, 1);
test_int(ctx.count, 3);
test_int(ctx.system, t);
test_int(ctx.event, EcsOnAdd);
test_int(ctx.event_id, Tag);
test_int(ctx.term_count, 1);
test_null(ctx.param);

test_int(ctx.e[0], e1);
test_int(ctx.e[1], e2);
test_int(ctx.e[2], e3);
test_int(ctx.c[0][0], Tag);

ecs_os_zeromem(&ctx);

ecs_delete(world, t);

test_int(ctx.invoked, 1);
test_int(ctx.count, 3);
test_int(ctx.system, t);
test_int(ctx.event, EcsOnRemove);
test_int(ctx.event_id, Tag);
test_int(ctx.term_count, 1);
test_null(ctx.param);

test_int(ctx.e[0], e1);
test_int(ctx.e[1], e2);
test_int(ctx.e[2], e3);
test_int(ctx.c[0][0], Tag);

ecs_fini(world);
}
Loading