#include void Observer_2_terms_on_add(void) { flecs::world ecs; int32_t count = 0; ecs.observer() .event(flecs::OnAdd) .each([&](Position& p, Velocity& v) { count ++; }); auto e = ecs.entity(); test_int(count, 0); e.set({10, 20}); test_int(count, 0); e.set({1, 2}); test_int(count, 1); } void Observer_2_terms_on_remove(void) { flecs::world ecs; int32_t count = 0; ecs.observer() .event(flecs::OnRemove) .each([&](Position& p, Velocity& v) { count ++; test_int(p.x, 10); test_int(p.y, 20); test_int(v.x, 1); test_int(v.y, 2); }); auto e = ecs.entity(); test_int(count, 0); e.set({10, 20}); test_int(count, 0); e.set({1, 2}); test_int(count, 0); e.remove(); test_int(count, 1); e.remove(); test_int(count, 1); } void Observer_2_terms_on_set(void) { flecs::world ecs; int32_t count = 0; ecs.observer() .event(flecs::OnSet) .each([&](Position& p, Velocity& v) { count ++; test_int(p.x, 10); test_int(p.y, 20); test_int(v.x, 1); test_int(v.y, 2); }); auto e = ecs.entity(); test_int(count, 0); e.set({10, 20}); test_int(count, 0); e.set({1, 2}); test_int(count, 1); } void Observer_2_terms_un_set(void) { flecs::world ecs; int32_t count = 0; ecs.observer() .event(flecs::UnSet) .each([&](Position& p, Velocity& v) { count ++; test_int(p.x, 10); test_int(p.y, 20); test_int(v.x, 1); test_int(v.y, 2); }); auto e = ecs.entity(); test_int(count, 0); e.set({10, 20}); test_int(count, 0); e.set({1, 2}); test_int(count, 0); e.remove(); test_int(count, 1); e.remove(); test_int(count, 1); } void Observer_10_terms(void) { flecs::world ecs; int count = 0; auto e = ecs.entity(); ecs.observer<>() .event(flecs::OnAdd) .term() .term() .term() .term() .term() .term() .term() .term() .term() .term() .iter([&](flecs::iter& it) { test_int(it.count(), 1); test_assert(it.entity(0) == e); test_int(it.field_count(), 10); count ++; }); e.add() .add() .add() .add() .add() .add() .add() .add() .add() .add(); test_int(count, 1); } void Observer_20_terms(void) { flecs::world ecs; int count = 0; auto e = ecs.entity(); ecs.observer<>() .event(flecs::OnAdd) .term() .term() .term() .term() .term() .term() .term() .term() .term() .term() .term() .term() .term() .term() .term() .term() .term() .term() .term() .term() .iter([&](flecs::iter& it) { test_int(it.count(), 1); test_assert(it.entity(0) == e); test_int(it.field_count(), 20); count ++; }); e.add() .add() .add() .add() .add() .add() .add() .add() .add() .add() .add() .add() .add() .add() .add() .add() .add() .add() .add() .add(); test_int(count, 1); } void Observer_2_entities_iter(void) { flecs::world ecs; auto e1 = ecs.entity(); auto e2 = ecs.entity(); int32_t count = 0; flecs::entity last; ecs.observer() .event(flecs::OnSet) .iter([&](flecs::iter& it, const Position *p) { for (auto i : it) { count ++; if (it.entity(i) == e1) { test_int(p[i].x, 10); test_int(p[i].y, 20); } else if (it.entity(i) == e2) { test_int(p[i].x, 30); test_int(p[i].y, 40); } else { test_assert(false); } last = it.entity(i); } }); e1.set({ 10, 20 }); test_int(count, 1); test_assert(last == e1); e2.set({ 30, 40 }); test_int(count, 2); test_assert(last == e2); } void Observer_2_entities_table_column(void) { flecs::world ecs; auto e1 = ecs.entity(); auto e2 = ecs.entity(); int32_t count = 0; flecs::entity last; ecs.observer() .event(flecs::OnSet) .iter([&](flecs::iter& it) { auto p = it.range().get(); for (auto i : it) { count ++; if (it.entity(i) == e1) { test_int(p[i].x, 10); test_int(p[i].y, 20); } else if (it.entity(i) == e2) { test_int(p[i].x, 30); test_int(p[i].y, 40); } else { test_assert(false); } last = it.entity(i); } }); e1.set({ 10, 20 }); test_int(count, 1); test_assert(last == e1); e2.set({ 30, 40 }); test_int(count, 2); test_assert(last == e2); } void Observer_2_entities_each(void) { flecs::world ecs; auto e1 = ecs.entity(); auto e2 = ecs.entity(); int32_t count = 0; flecs::entity last; ecs.observer() .event(flecs::OnSet) .each([&](flecs::entity e, const Position& p) { count ++; if (e == e1) { test_int(p.x, 10); test_int(p.y, 20); } else if (e == e2) { test_int(p.x, 30); test_int(p.y, 40); } else { test_assert(false); } last = e; }); e1.set({ 10, 20 }); test_int(count, 1); test_assert(last == e1); e2.set({ 30, 40 }); test_int(count, 2); test_assert(last == e2); } void Observer_create_w_no_template_args(void) { flecs::world ecs; auto e1 = ecs.entity(); int32_t count = 0; ecs.observer() .term() .event(flecs::OnAdd) .each([&](flecs::entity e) { test_assert(e == e1); count ++; }); e1.set({10, 20}); test_int(count, 1); } void Observer_yield_existing(void) { flecs::world world; struct TagA { }; struct TagB { }; auto e1 = world.entity().add(); auto e2 = world.entity().add(); auto e3 = world.entity().add().add(); int32_t count = 0; world.observer() .event(flecs::OnAdd) .yield_existing() .each([&](flecs::entity e, TagA) { if (e == e1) count ++; if (e == e2) count += 2; if (e == e3) count += 3; }); test_int(count, 6); } void Observer_yield_existing_2_terms(void) { flecs::world world; struct TagA { }; struct TagB { }; auto e1 = world.entity().add().add(); auto e2 = world.entity().add().add(); auto e3 = world.entity().add().add().add(); world.entity().add(); world.entity().add(); int32_t count = 0; world.observer() .event(flecs::OnAdd) .yield_existing() .each([&](flecs::entity e, TagA, TagB) { if (e == e1) count ++; if (e == e2) count += 2; if (e == e3) count += 3; }); test_int(count, 6); } void Observer_default_ctor(void) { flecs::world world; struct TagA { }; flecs::observer o; test_assert(o == 0); int32_t count = 0; o = world.observer() .event(flecs::OnAdd) .each([&](flecs::entity e, TagA) { count ++; }); world.entity().add(); test_int(count, 1); } void Observer_entity_ctor(void) { flecs::world world; struct TagA { }; flecs::observer o = world.observer() .event(flecs::OnAdd) .each([&](flecs::entity e, TagA) { }); flecs::entity oe = o; flecs::observer eo = world.observer(oe); test_assert(eo == o); } void Observer_on_add(void) { flecs::world world; int invoked = 0; world.observer() .event(flecs::OnAdd) .each([&](flecs::entity e, Position& p) { invoked ++; }); world.entity() .add(); test_int(invoked, 1); } void Observer_on_remove(void) { flecs::world world; int invoked = 0; world.observer() .event(flecs::OnRemove) .each([&](flecs::entity e, Position& p) { invoked ++; }); auto e = world.entity() .add(); test_int(invoked, 0); e.remove(); test_int(invoked, 1); } struct MyTag { }; void Observer_on_add_tag_action(void) { flecs::world world; int invoked = 0; world.observer() .event(flecs::OnAdd) .iter([&](flecs::iter it, MyTag*) { invoked ++; }); world.entity() .add(); test_int(invoked, 1); } void Observer_on_add_tag_iter(void) { flecs::world world; int invoked = 0; world.observer() .event(flecs::OnAdd) .iter([&](flecs::iter it, MyTag*) { invoked ++; }); world.entity() .add(); test_int(invoked, 1); } void Observer_on_add_tag_each(void) { flecs::world world; int invoked = 0; world.observer() .event(flecs::OnAdd) .each([&](flecs::entity e, MyTag) { invoked ++; }); world.entity() .add(); test_int(invoked, 1); } void Observer_on_add_expr(void) { flecs::world world; int invoked = 0; world.component(); world.observer<>().expr("Tag") .event(flecs::OnAdd) .each([&](flecs::entity e) { invoked ++; }); auto e = world.entity().add(); test_int(invoked, 1); e.remove(); test_int(invoked, 1); } void Observer_observer_w_filter_term(void) { flecs::world world; flecs::entity TagA = world.entity(); flecs::entity TagB = world.entity(); int invoked = 0; world.observer() .term(TagA) .term(TagB).filter() .event(flecs::OnAdd) .each([&](flecs::entity e) { invoked ++; }); flecs::entity e = world.entity(); test_int(invoked, 0); e.add(TagB); test_int(invoked, 0); e.add(TagA); test_int(invoked, 1); e.remove(TagB); test_int(invoked, 1); e.add(TagB); test_int(invoked, 1); e.clear(); test_int(invoked, 1); e.add(TagA); test_int(invoked, 1); } void Observer_run_callback(void) { flecs::world ecs; int32_t count = 0; ecs.observer() .event(flecs::OnAdd) .run([](flecs::iter_t *it) { while (ecs_iter_next(it)) { it->callback(it); } }) .each([&](Position& p) { count ++; }); auto e = ecs.entity(); test_int(count, 0); e.set({10, 20}); test_int(count, 1); } void Observer_get_query(void) { flecs::world world; world.entity().set({0, 0}); world.entity().set({1, 0}); world.entity().set({2, 0}); int32_t count = 0; auto sys = world.observer() .event(flecs::OnSet) .each([&](flecs::entity e, const Position& p) { // Not used }); auto q = sys.query(); q.iter([&](flecs::iter &it) { auto pos = it.field(1); for (auto i : it) { test_int(i, pos[i].x); count ++; } }); test_int(count, 3); } void Observer_on_set_w_set(void) { flecs::world world; int32_t count = 0; world.observer() .event(flecs::OnSet) .each([&](flecs::entity e, Position& p) { count ++; }); flecs::entity e = world.entity(); test_int(count, 0); e.set({10, 20}); test_int(count, 1); } void Observer_on_set_w_defer_set(void) { flecs::world world; int32_t count = 0; world.observer() .event(flecs::OnSet) .each([&](flecs::entity e, Position& p) { count ++; }); flecs::entity e = world.entity(); test_int(count, 0); world.defer_begin(); e.set({10, 20}); test_int(count, 0); world.defer_end(); test_int(count, 1); } #include void Observer_on_add_singleton(void) { flecs::world world; int32_t count = 0; world.observer() .term_at(1).singleton() .event(flecs::OnSet) .each([&](Position& p) { test_int(p.x, 10); test_int(p.y, 20); count ++; }); world.set({10, 20}); test_int(count, 1); } void Observer_on_add_pair_singleton(void) { flecs::world world; int32_t count = 0; flecs::entity tgt = world.entity(); world.observer() .term_at(1).second(tgt).singleton() .event(flecs::OnSet) .each([&](Position& p) { test_int(p.x, 10); test_int(p.y, 20); count ++; }); world.set(tgt, {10, 20}); test_int(count, 1); } void Observer_on_add_pair_wildcard_singleton(void) { flecs::world world; int32_t count = 0; flecs::entity tgt_1 = world.entity(); flecs::entity tgt_2 = world.entity(); world.observer() .term_at(1).second(flecs::Wildcard).singleton() .event(flecs::OnSet) .each([&](Position& p) { test_int(p.x, 10); test_int(p.y, 20); count ++; }); world.set(tgt_1, {10, 20}); test_int(count, 1); world.set(tgt_2, {10, 20}); test_int(count, 2); } void Observer_on_add_with_pair_singleton(void) { flecs::world world; int32_t count = 0; flecs::entity tgt = world.entity(); world.observer() .with(tgt).singleton() .event(flecs::OnSet) .each([&](flecs::entity) { count ++; }); world.set(tgt, {10, 20}); test_int(count, 1); } void Observer_add_in_yield_existing(void) { flecs::world world; flecs::entity e1 = world.entity().set({}); flecs::entity e2 = world.entity().set({}); flecs::entity e3 = world.entity().set({}); world.observer() .with() .event(flecs::OnAdd) .yield_existing() .each([](flecs::entity e) { e.add(); }); test_assert(e1.has()); test_assert(e1.has()); test_assert(e2.has()); test_assert(e2.has()); test_assert(e3.has()); test_assert(e3.has()); } void Observer_add_in_yield_existing_multi(void) { flecs::world world; flecs::entity e1 = world.entity().set({}).set({}); flecs::entity e2 = world.entity().set({}).set({}); flecs::entity e3 = world.entity().set({}).set({}); world.observer() .with() .with() .event(flecs::OnAdd) .yield_existing() .each([](flecs::entity e) { e.add(); }); test_assert(e1.has()); test_assert(e1.has()); test_assert(e1.has()); test_assert(e2.has()); test_assert(e2.has()); test_assert(e2.has()); test_assert(e3.has()); test_assert(e3.has()); test_assert(e3.has()); } void Observer_name_from_root(void) { flecs::world ecs; flecs::entity sys = ecs.observer("::ns::MySystem") .event(flecs::OnSet) .each([](Position& p) { }); test_str(sys.name(), "MySystem"); flecs::entity ns = ecs.entity("::ns"); test_assert(ns == sys.parent()); }