#include void System_w_FromParent_setup(void) { ecs_log_set_level(-3); } static void Iter(ecs_iter_t *it) { Mass *m_ptr = ecs_field(it, Mass, 1); bool shared = false; if (m_ptr) { shared = !ecs_field_is_self(it, 1); } Position *p = NULL; Velocity *v = NULL; if (it->field_count >= 2) { p = ecs_field(it, Position, 2); } if (it->field_count >= 3) { v = ecs_field(it, Velocity, 3); } probe_iter(it); int i; for (i = 0; i < it->count; i ++) { Mass m = 1; if (m_ptr) { if (shared) { m = *m_ptr; } else { m = m_ptr[i]; } } p[i].x = 10 * m; p[i].y = 20 * m; if (v) { v[i].x = 30 * m; v[i].y = 40 * m; } } } void System_w_FromParent_1_column_from_container(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Mass); ECS_ENTITY(world, e1, Position); ECS_ENTITY(world, e2, Position); ECS_ENTITY(world, e3, Position); ECS_ENTITY(world, e4, Position); ECS_SYSTEM(world, Iter, EcsOnUpdate, Mass(parent), Position); ecs_system_init(world, &(ecs_system_desc_t){ .entity = Iter, .query.filter.instanced = true }); ecs_entity_t parent = ecs_set(world, 0, Mass, {2}); ecs_add_pair(world, e1, EcsChildOf, parent); ecs_add_pair(world, e2, EcsChildOf, parent); ecs_add_pair(world, e3, EcsChildOf, parent); Probe ctx = {0}; ecs_set_ctx(world, &ctx, NULL); ecs_progress(world, 1); test_int(ctx.count, 3); test_int(ctx.invoked, 1); test_int(ctx.system, Iter); test_int(ctx.term_count, 2); 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], ecs_id(Mass)); test_int(ctx.s[0][0], parent); test_int(ctx.c[0][1], ecs_id(Position)); test_int(ctx.s[0][1], 0); const Position *p = ecs_get(world, e1, Position); test_assert(p != NULL); test_int(p->x, 20); test_int(p->y, 40); p = ecs_get(world, e2, Position); test_assert(p != NULL); test_int(p->x, 20); test_int(p->y, 40); p = ecs_get(world, e3, Position); test_assert(p != NULL); test_int(p->x, 20); test_int(p->y, 40); ecs_fini(world); } void System_w_FromParent_2_column_1_from_container(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_COMPONENT(world, Mass); ECS_ENTITY(world, e1, Position, Velocity); ECS_ENTITY(world, e2, Position, Velocity); ECS_ENTITY(world, e3, Position, Velocity); ECS_ENTITY(world, e4, Position, Velocity); ECS_SYSTEM(world, Iter, EcsOnUpdate, Mass(parent), Position, Velocity); ecs_system_init(world, &(ecs_system_desc_t){ .entity = Iter, .query.filter.instanced = true }); ecs_entity_t parent = ecs_set(world, 0, Mass, {2}); ecs_add_pair(world, e1, EcsChildOf, parent); ecs_add_pair(world, e2, EcsChildOf, parent); ecs_add_pair(world, e3, EcsChildOf, parent); Probe ctx = {0}; ecs_set_ctx(world, &ctx, NULL); ecs_progress(world, 1); test_int(ctx.count, 3); test_int(ctx.invoked, 1); test_int(ctx.system, Iter); test_int(ctx.term_count, 3); 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], ecs_id(Mass)); test_int(ctx.s[0][0], parent); test_int(ctx.c[0][1], ecs_id(Position)); test_int(ctx.s[0][1], 0); test_int(ctx.c[0][2], ecs_id(Velocity)); test_int(ctx.s[0][2], 0); const Position *p = ecs_get(world, e1, Position); test_assert(p != NULL); test_int(p->x, 20); test_int(p->y, 40); p = ecs_get(world, e2, Position); test_assert(p != NULL); test_int(p->x, 20); test_int(p->y, 40); p = ecs_get(world, e3, Position); test_assert(p != NULL); test_int(p->x, 20); test_int(p->y, 40); const Velocity *v = ecs_get(world, e1, Velocity); test_assert(v != NULL); test_int(v->x, 60); test_int(v->y, 80); v = ecs_get(world, e2, Velocity); test_assert(v != NULL); test_int(v->x, 60); test_int(v->y, 80); v = ecs_get(world, e3, Velocity); test_assert(v != NULL); test_int(v->x, 60); test_int(v->y, 80); ecs_fini(world); } static void Iter_2_shared(ecs_iter_t *it) { Mass *m_ptr = ecs_field(it, Mass, 1); Rotation *r_ptr = NULL; Position *p = NULL; Velocity *v = NULL; if (it->field_count >= 2) { r_ptr = ecs_field(it, Rotation, 2); } if (it->field_count >= 3) { p = ecs_field(it, Position, 3); } if (it->field_count >= 4) { v = ecs_field(it, Velocity, 4); } probe_iter(it); Mass m = 1; if (m_ptr) { m = *m_ptr; } Rotation r = 0; if (r_ptr) { r = *r_ptr; } int i; for (i = 0; i < it->count; i ++) { if (p) { p[i].x = 10 * m + r; p[i].y = 20 * m + r; } if (v) { v[i].x = 30 * m + r; v[i].y = 40 * m + r; } } } void System_w_FromParent_3_column_2_from_container(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Rotation); ECS_COMPONENT(world, Mass); ECS_ENTITY(world, e1, Position); ECS_ENTITY(world, e2, Position); ECS_ENTITY(world, e3, Position); ECS_ENTITY(world, e4, Position); ECS_SYSTEM(world, Iter_2_shared, EcsOnUpdate, Mass(parent), Rotation(parent), Position); ecs_system_init(world, &(ecs_system_desc_t){ .entity = Iter_2_shared, .query.filter.instanced = true }); ecs_entity_t parent = ecs_set(world, 0, Mass, {2}); ecs_set(world, parent, Rotation, {3}); ecs_add_pair(world, e1, EcsChildOf, parent); ecs_add_pair(world, e2, EcsChildOf, parent); ecs_add_pair(world, e4, EcsChildOf, parent); Probe ctx = {0}; ecs_set_ctx(world, &ctx, NULL); ecs_progress(world, 1); test_int(ctx.count, 3); test_int(ctx.invoked, 1); test_int(ctx.system, Iter_2_shared); test_int(ctx.term_count, 3); test_null(ctx.param); test_int(ctx.e[0], e1); test_int(ctx.e[1], e2); test_int(ctx.e[2], e4); test_int(ctx.c[0][0], ecs_id(Mass)); test_int(ctx.s[0][0], parent); test_int(ctx.c[0][1], ecs_id(Rotation)); test_int(ctx.s[0][1], parent); test_int(ctx.c[0][2], ecs_id(Position)); test_int(ctx.s[0][2], 0); const Position *p = ecs_get(world, e1, Position); test_assert(p != NULL); test_int(p->x, 23); test_int(p->y, 43); p = ecs_get(world, e2, Position); test_assert(p != NULL); test_int(p->x, 23); test_int(p->y, 43); p = ecs_get(world, e4, Position); test_assert(p != NULL); test_int(p->x, 23); test_int(p->y, 43); ecs_fini(world); } void System_w_FromParent_2_column_1_from_container_w_not(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Rotation); ECS_COMPONENT(world, Mass); ECS_ENTITY(world, e1, Position); ECS_ENTITY(world, e2, Position); ECS_ENTITY(world, e3, Position); ECS_ENTITY(world, e4, Position); ECS_ENTITY(world, e5, Position); ECS_SYSTEM(world, Iter, EcsOnUpdate, !Mass(parent), Position); ecs_system_init(world, &(ecs_system_desc_t){ .entity = Iter, .query.filter.instanced = true }); ecs_entity_t parent_1 = ecs_set(world, 0, Mass, {2}); ecs_entity_t parent_2 = ecs_set(world, 0, Rotation, {3}); ecs_add_pair(world, e1, EcsChildOf, parent_2); ecs_add_pair(world, e2, EcsChildOf, parent_2); ecs_add_pair(world, e3, EcsChildOf, parent_2); ecs_add_pair(world, e4, EcsChildOf, parent_1); Probe ctx = {0}; ecs_set_ctx(world, &ctx, NULL); ecs_progress(world, 1); test_int(ctx.count, 4); test_int(ctx.invoked, 2); test_int(ctx.system, Iter); test_int(ctx.term_count, 2); test_null(ctx.param); test_int(ctx.e[0], e5); test_int(ctx.e[1], e1); test_int(ctx.e[2], e2); test_int(ctx.e[3], e3); test_int(ctx.c[0][0], ecs_id(Mass)); test_int(ctx.s[0][0], 0); test_int(ctx.c[0][1], ecs_id(Position)); test_int(ctx.s[0][1], 0); test_int(ctx.c[1][0], ecs_id(Mass)); test_int(ctx.s[1][0], 0); test_int(ctx.c[1][1], ecs_id(Position)); test_int(ctx.s[1][1], 0); const Position *p = ecs_get(world, e1, Position); test_assert(p != NULL); test_int(p->x, 10); test_int(p->y, 20); p = ecs_get(world, e2, Position); test_assert(p != NULL); test_int(p->x, 10); test_int(p->y, 20); p = ecs_get(world, e3, Position); test_assert(p != NULL); test_int(p->x, 10); test_int(p->y, 20); p = ecs_get(world, e5, Position); test_assert(p != NULL); test_int(p->x, 10); test_int(p->y, 20); ecs_fini(world); } void System_w_FromParent_3_column_1_from_comtainer_1_from_container_w_not(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Rotation); ECS_COMPONENT(world, Mass); ECS_ENTITY(world, e1, Position); ECS_ENTITY(world, e2, Position); ECS_ENTITY(world, e3, Position); ECS_ENTITY(world, e4, Position); ECS_ENTITY(world, e5, Position); ECS_ENTITY(world, e6, Position); ECS_SYSTEM(world, Iter_2_shared, EcsOnUpdate, !Mass(parent), Rotation(parent), Position); ecs_system_init(world, &(ecs_system_desc_t){ .entity = Iter_2_shared, .query.filter.instanced = true }); ecs_entity_t parent_1 = ecs_set(world, 0, Mass, {2}); ecs_entity_t parent_2 = ecs_set(world, 0, Rotation, {3}); ecs_entity_t parent_3 = ecs_set(world, 0, Mass, {4}); ecs_set(world, parent_3, Rotation, {5}); ecs_add_pair(world, e1, EcsChildOf, parent_2); ecs_add_pair(world, e2, EcsChildOf, parent_2); ecs_add_pair(world, e3, EcsChildOf, parent_2); ecs_add_pair(world, e4, EcsChildOf, parent_1); ecs_add_pair(world, e5, EcsChildOf, parent_3); Probe ctx = {0}; ecs_set_ctx(world, &ctx, NULL); ecs_progress(world, 1); test_int(ctx.count, 3); test_int(ctx.invoked, 1); test_int(ctx.system, Iter_2_shared); test_int(ctx.term_count, 3); 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], ecs_id(Mass)); test_int(ctx.s[0][0], 0); test_int(ctx.c[0][1], ecs_id(Rotation)); test_int(ctx.s[0][1], parent_2); test_int(ctx.c[0][2], ecs_id(Position)); test_int(ctx.s[0][2], 0); const Position *p = ecs_get(world, e1, Position); test_assert(p != NULL); test_int(p->x, 13); test_int(p->y, 23); p = ecs_get(world, e2, Position); test_assert(p != NULL); test_int(p->x, 13); test_int(p->y, 23); p = ecs_get(world, e3, Position); test_assert(p != NULL); test_int(p->x, 13); test_int(p->y, 23); ecs_fini(world); } void System_w_FromParent_2_column_1_from_container_w_not_prefab(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Rotation); ECS_COMPONENT(world, Mass); ECS_PREFAB(world, Prefab, Rotation); ECS_ENTITY(world, e1, Position); ECS_ENTITY(world, e2, Position); ECS_SYSTEM(world, Iter, EcsOnUpdate, !Mass(parent), Position); ecs_system_init(world, &(ecs_system_desc_t){ .entity = Iter, .query.filter.instanced = true }); ecs_entity_t parent_1 = ecs_set(world, 0, Mass, {2}); ecs_add_pair(world, e1, EcsIsA, Prefab); ecs_add_pair(world, e1, EcsChildOf, parent_1); ecs_set(world, e1, Position, {1, 2}); Probe ctx = {0}; ecs_set_ctx(world, &ctx, NULL); ecs_progress(world, 1); test_int(ctx.count, 1); test_int(ctx.invoked, 1); test_int(ctx.system, Iter); test_int(ctx.term_count, 2); test_null(ctx.param); test_int(ctx.e[0], e2); test_int(ctx.c[0][0], ecs_id(Mass)); test_int(ctx.s[0][0], 0); test_int(ctx.c[0][1], ecs_id(Position)); test_int(ctx.s[0][1], 0); const Position *p = ecs_get(world, e1, Position); test_assert(p != NULL); test_int(p->x, 1); test_int(p->y, 2); p = ecs_get(world, e2, Position); test_assert(p != NULL); test_int(p->x, 10); test_int(p->y, 20); ecs_fini(world); } void System_w_FromParent_2_column_1_from_container_w_or(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_COMPONENT(world, Rotation); ECS_COMPONENT(world, Mass); ECS_ENTITY(world, e1, Position); ECS_ENTITY(world, e2, Position); ECS_ENTITY(world, e3, Position); ECS_ENTITY(world, e4, Position); ECS_ENTITY(world, e5, Position); ECS_ENTITY(world, e6, Position); ECS_SYSTEM(world, Iter, EcsOnUpdate, Mass(parent) || Rotation(parent), Position); ecs_system_init(world, &(ecs_system_desc_t){ .entity = Iter, .query.filter.instanced = true }); ecs_entity_t parent_1 = ecs_set(world, 0, Mass, {2}); ecs_entity_t parent_2 = ecs_set(world, 0, Rotation, {3}); ecs_entity_t parent_3 = ecs_set(world, 0, Rotation, {4}); ecs_set(world, parent_3, Mass, {5}); ecs_entity_t parent_4 = ecs_set(world, 0, Velocity, {10, 20}); ecs_add_pair(world, e1, EcsChildOf, parent_1); ecs_add_pair(world, e2, EcsChildOf, parent_2); ecs_add_pair(world, e3, EcsChildOf, parent_3); ecs_add_pair(world, e4, EcsChildOf, parent_4); Probe ctx = {0}; ecs_set_ctx(world, &ctx, NULL); ecs_progress(world, 1); test_int(ctx.count, 3); test_int(ctx.invoked, 3); test_int(ctx.system, Iter); test_int(ctx.term_count, 2); 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], ecs_id(Mass)); test_int(ctx.s[0][0], parent_1); test_int(ctx.c[0][1], ecs_id(Position)); test_int(ctx.s[0][1], 0); test_int(ctx.c[1][0], ecs_id(Rotation)); test_int(ctx.s[1][0], parent_2); test_int(ctx.c[1][1], ecs_id(Position)); test_int(ctx.s[2][1], 0); test_int(ctx.c[2][0], ecs_id(Mass)); test_int(ctx.s[2][0], parent_3); test_int(ctx.c[2][1], ecs_id(Position)); test_int(ctx.s[2][1], 0); ecs_fini(world); } static void Dummy(ecs_iter_t *it) { Mass *m_ptr = ecs_field(it, Mass, 1); Position *p = ecs_field(it, Position, 2); test_assert(!m_ptr || !ecs_field_is_self(it, 1)); probe_iter(it); Mass m = 1; if (m_ptr) { m = *m_ptr; } int i; for (i = 0; i < it->count; i ++) { p[i].x += m; p[i].y += m; } } void System_w_FromParent_add_component_after_match(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Mass); ECS_ENTITY(world, e1, Position); ECS_ENTITY(world, e2, Position); ECS_ENTITY(world, e3, Position); ECS_ENTITY(world, e4, Position); ECS_SYSTEM(world, Iter, EcsOnUpdate, Mass(parent), Position); ecs_system_init(world, &(ecs_system_desc_t){ .entity = Iter, .query.filter.instanced = true }); ecs_entity_t parent = ecs_new(world, 0); ecs_add_pair(world, e1, EcsChildOf, parent); ecs_add_pair(world, e2, EcsChildOf, parent); ecs_set(world, parent, Mass, {2}); Probe ctx = {0}; ecs_set_ctx(world, &ctx, NULL); ecs_progress(world, 1); test_int(ctx.count, 2); test_int(ctx.invoked, 1); test_int(ctx.system, Iter); test_int(ctx.term_count, 2); test_null(ctx.param); test_int(ctx.e[0], e1); test_int(ctx.e[1], e2); test_int(ctx.c[0][0], ecs_id(Mass)); test_int(ctx.s[0][0], parent); test_int(ctx.c[0][1], ecs_id(Position)); test_int(ctx.s[0][1], 0); const Position *p = ecs_get(world, e1, Position); test_assert(p != NULL); test_int(p->x, 20); test_int(p->y, 40); p = ecs_get(world, e2, Position); test_assert(p != NULL); test_int(p->x, 20); test_int(p->y, 40); ecs_fini(world); } void System_w_FromParent_add_component_after_match_and_rematch(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Mass); ECS_ENTITY(world, e1, Position); ECS_ENTITY(world, e2, Position); ECS_ENTITY(world, e3, Position); ECS_ENTITY(world, e4, Position); ECS_SYSTEM(world, Iter, EcsOnUpdate, Mass(parent), Position); ecs_system_init(world, &(ecs_system_desc_t){ .entity = Iter, .query.filter.instanced = true }); ecs_entity_t parent = ecs_new(world, 0); ecs_add_pair(world, e1, EcsChildOf, parent); ecs_add_pair(world, e2, EcsChildOf, parent); Probe ctx = {0}; ecs_set_ctx(world, &ctx, NULL); /* This will rematch tables, but not match Iter with e1 and e2 because the * parent does not have Mass yet */ ecs_progress(world, 1); test_int(ctx.count, 0); ecs_set(world, parent, Mass, {2}); /* Now a rematch of tables need to happen again, since parent has changed */ ecs_os_zeromem(&ctx); ecs_progress(world, 1); test_int(ctx.count, 2); test_int(ctx.invoked, 1); test_int(ctx.system, Iter); test_int(ctx.term_count, 2); test_null(ctx.param); test_int(ctx.e[0], e1); test_int(ctx.e[1], e2); test_int(ctx.c[0][0], ecs_id(Mass)); test_int(ctx.s[0][0], parent); test_int(ctx.c[0][1], ecs_id(Position)); test_int(ctx.s[0][1], 0); const Position *p = ecs_get(world, e1, Position); test_assert(p != NULL); test_int(p->x, 20); test_int(p->y, 40); p = ecs_get(world, e2, Position); test_assert(p != NULL); test_int(p->x, 20); test_int(p->y, 40); ecs_fini(world); } void System_w_FromParent_add_component_after_match_and_rematch_w_entity_type_expr(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Mass); ECS_ENTITY(world, e3, Position); ECS_ENTITY(world, e4, Position); ECS_SYSTEM(world, Iter, EcsOnUpdate, Mass(parent), Position); ecs_system_init(world, &(ecs_system_desc_t){ .entity = Iter, .query.filter.instanced = true }); ECS_ENTITY(world, Parent, 0); ECS_ENTITY(world, e1, Position, (ChildOf, Parent)); ECS_ENTITY(world, e2, Position, (ChildOf, Parent)); Probe ctx = {0}; ecs_set_ctx(world, &ctx, NULL); /* This will rematch tables, but not match Iter with e1 and e2 because the * Parent does not have Mass yet */ ecs_progress(world, 1); test_int(ctx.count, 0); ecs_set(world, Parent, Mass, {2}); /* Now a rematch of tables need to happen again, since parent has changed */ ecs_os_zeromem(&ctx); ecs_progress(world, 1); test_int(ctx.count, 2); test_int(ctx.invoked, 1); test_int(ctx.system, Iter); test_int(ctx.term_count, 2); test_null(ctx.param); test_int(ctx.e[0], e1); test_int(ctx.e[1], e2); test_int(ctx.c[0][0], ecs_id(Mass)); test_int(ctx.s[0][0], Parent); test_int(ctx.c[0][1], ecs_id(Position)); test_int(ctx.s[0][1], 0); const Position *p = ecs_get(world, e1, Position); test_assert(p != NULL); test_int(p->x, 20); test_int(p->y, 40); p = ecs_get(world, e2, Position); test_assert(p != NULL); test_int(p->x, 20); test_int(p->y, 40); ecs_fini(world); } static void SetMass(ecs_iter_t *it) { ecs_id_t ecs_id(Mass) = ecs_field_id(it, 2); int i; for (i = 0; i < it->count; i ++) { ecs_set(it->world, it->entities[i], Mass, {2}); } } void System_w_FromParent_add_component_after_match_and_rematch_w_entity_type_expr_in_progress(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_COMPONENT(world, Mass); ECS_ENTITY(world, e3, Position); ECS_ENTITY(world, e4, Position); ECS_SYSTEM(world, SetMass, EcsOnUpdate, Velocity, Mass()); ECS_SYSTEM(world, Iter, EcsOnUpdate, Mass(parent), Position); ecs_system_init(world, &(ecs_system_desc_t){ .entity = Iter, .query.filter.instanced = true }); ECS_ENTITY(world, Parent, Velocity); ECS_ENTITY(world, e1, Position, (ChildOf, Parent)); ECS_ENTITY(world, e2, Position, (ChildOf, Parent)); Probe ctx = {0}; ecs_set_ctx(world, &ctx, NULL); ecs_os_zeromem(&ctx); ecs_progress(world, 1); test_int(ctx.count, 2); test_int(ctx.invoked, 1); test_int(ctx.system, Iter); test_int(ctx.term_count, 2); test_null(ctx.param); test_int(ctx.e[0], e1); test_int(ctx.e[1], e2); test_int(ctx.c[0][0], ecs_id(Mass)); test_int(ctx.s[0][0], Parent); test_int(ctx.c[0][1], ecs_id(Position)); test_int(ctx.s[0][1], 0); const Position *p = ecs_get(world, e1, Position); test_assert(p != NULL); test_int(p->x, 20); test_int(p->y, 40); p = ecs_get(world, e2, Position); test_assert(p != NULL); test_int(p->x, 20); test_int(p->y, 40); ecs_fini(world); } void System_w_FromParent_add_component_after_match_unmatch(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Mass); ECS_ENTITY(world, e1, Position); ECS_ENTITY(world, e2, Position); ECS_ENTITY(world, e3, Position); ECS_SYSTEM(world, Iter, EcsOnUpdate, !Mass(parent), Position); ecs_entity_t parent = ecs_new(world, 0); ecs_add_pair(world, e1, EcsChildOf, parent); ecs_add_pair(world, e2, EcsChildOf, parent); ecs_set(world, parent, Mass, {2}); Probe ctx = {0}; ecs_set_ctx(world, &ctx, NULL); ecs_progress(world, 1); test_int(ctx.count, 1); test_int(ctx.invoked, 1); test_int(ctx.system, Iter); test_int(ctx.term_count, 2); test_null(ctx.param); test_int(ctx.e[0], e3); test_int(ctx.c[0][0], ecs_id(Mass)); test_int(ctx.s[0][0], 0); test_int(ctx.c[0][1], ecs_id(Position)); test_int(ctx.s[0][1], 0); const Position *p = ecs_get(world, e3, Position); test_assert(p != NULL); test_int(p->x, 10); test_int(p->y, 20); ecs_fini(world); } void System_w_FromParent_add_component_after_match_unmatch_match(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Mass); ECS_ENTITY(world, e1, Position); ECS_ENTITY(world, e2, Position); ECS_SYSTEM(world, Iter, EcsOnUpdate, Mass(parent), Position); ecs_system_init(world, &(ecs_system_desc_t){ .entity = Iter, .query.filter.instanced = true }); ECS_SYSTEM(world, Dummy, EcsOnUpdate, !Mass(parent), Position); ecs_entity_t parent = ecs_new(world, 0); ecs_add_pair(world, e1, EcsChildOf, parent); ecs_add_pair(world, e2, EcsChildOf, parent); ecs_set(world, parent, Mass, {2}); Probe ctx = {0}; ecs_set_ctx(world, &ctx, NULL); ecs_progress(world, 1); test_int(ctx.count, 2); test_int(ctx.invoked, 1); test_int(ctx.system, Iter); test_int(ctx.term_count, 2); test_null(ctx.param); test_int(ctx.e[0], e1); test_int(ctx.e[1], e2); test_int(ctx.c[0][0], ecs_id(Mass)); test_int(ctx.s[0][0], parent); test_int(ctx.c[0][1], ecs_id(Position)); test_int(ctx.s[0][1], 0); const Position *p = ecs_get(world, e1, Position); test_assert(p != NULL); test_int(p->x, 20); test_int(p->y, 40); p = ecs_get(world, e2, Position); test_assert(p != NULL); test_int(p->x, 20); test_int(p->y, 40); ecs_fini(world); } void System_w_FromParent_add_component_after_match_2_systems(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Mass); ECS_ENTITY(world, e1, Position); ECS_ENTITY(world, e2, Position); ECS_ENTITY(world, e3, Position); ECS_SYSTEM(world, Iter, EcsOnUpdate, Mass(parent), Position); ecs_system_init(world, &(ecs_system_desc_t){ .entity = Iter, .query.filter.instanced = true }); ECS_SYSTEM(world, Dummy, EcsOnUpdate, Mass(parent), Position); ecs_system_init(world, &(ecs_system_desc_t){ .entity = Dummy, .query.filter.instanced = true }); ecs_entity_t parent = ecs_new(world, 0); ecs_add_pair(world, e1, EcsChildOf, parent); ecs_add_pair(world, e2, EcsChildOf, parent); ecs_set(world, parent, Mass, {2}); Probe ctx = {0}; ecs_set_ctx(world, &ctx, NULL); ecs_progress(world, 1); test_int(ctx.count, 4); test_int(ctx.invoked, 2); test_int(ctx.system, Dummy); test_int(ctx.term_count, 2); test_null(ctx.param); test_int(ctx.e[0], e1); test_int(ctx.e[1], e2); test_int(ctx.e[2], e1); test_int(ctx.e[3], e2); test_int(ctx.c[0][0], ecs_id(Mass)); test_int(ctx.s[0][0], parent); test_int(ctx.c[0][1], ecs_id(Position)); test_int(ctx.s[0][1], 0); const Position *p = ecs_get(world, e1, Position); test_assert(p != NULL); test_int(p->x, 22); test_int(p->y, 42); p = ecs_get(world, e2, Position); test_assert(p != NULL); test_int(p->x, 22); test_int(p->y, 42); ecs_fini(world); } static void AddMass(ecs_iter_t *it) { test_assert(it->ctx != NULL); ecs_entity_t ecs_id(Mass) = *(ecs_entity_t*)it->ctx; int i; for (i = 0; i < it->count; i ++) { ecs_set(it->world, it->entities[i], Mass, {2}); } } void System_w_FromParent_add_component_in_progress_after_match(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Mass); ECS_ENTITY(world, Tag, 0); ECS_ENTITY(world, e1, Position); ECS_ENTITY(world, e2, Position); ECS_ENTITY(world, e3, Position); ECS_ENTITY(world, e4, Position); ECS_SYSTEM(world, Iter, EcsOnUpdate, Mass(parent), Position); ecs_system_init(world, &(ecs_system_desc_t){ .entity = Iter, .query.filter.instanced = true }); ECS_OBSERVER(world, AddMass, EcsOnAdd, Tag); ecs_observer_init(world, &(ecs_observer_desc_t){ .entity = AddMass, .ctx = &ecs_id(Mass) }); ecs_entity_t parent = ecs_new(world, 0); ecs_add_pair(world, e1, EcsChildOf, parent); ecs_add_pair(world, e2, EcsChildOf, parent); ecs_add_id(world, parent, Tag); Probe ctx = {0}; ecs_set_ctx(world, &ctx, NULL); ecs_progress(world, 1); test_int(ctx.count, 2); test_int(ctx.invoked, 1); test_int(ctx.system, Iter); test_int(ctx.term_count, 2); test_null(ctx.param); test_int(ctx.e[0], e1); test_int(ctx.e[1], e2); test_int(ctx.c[0][0], ecs_id(Mass)); test_int(ctx.s[0][0], parent); test_int(ctx.c[0][1], ecs_id(Position)); test_int(ctx.s[0][1], 0); const Position *p = ecs_get(world, e1, Position); test_assert(p != NULL); test_int(p->x, 20); test_int(p->y, 40); p = ecs_get(world, e2, Position); test_assert(p != NULL); test_int(p->x, 20); test_int(p->y, 40); ecs_fini(world); } void System_w_FromParent_adopt_after_match(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Mass); ECS_ENTITY(world, e1, Position); ECS_ENTITY(world, e2, Position); ECS_ENTITY(world, e3, Position); ECS_SYSTEM(world, Iter, EcsOnUpdate, Mass(parent), Position); ecs_system_init(world, &(ecs_system_desc_t){ .entity = Iter, .query.filter.instanced = true }); ecs_entity_t parent = ecs_new(world, Mass); ecs_add_pair(world, e1, EcsChildOf, parent); ecs_add_pair(world, e2, EcsChildOf, parent); ecs_set(world, parent, Mass, {2}); Probe ctx = {0}; ecs_set_ctx(world, &ctx, NULL); ecs_progress(world, 1); test_int(ctx.count, 2); test_int(ctx.invoked, 1); test_int(ctx.system, Iter); test_int(ctx.term_count, 2); test_null(ctx.param); test_int(ctx.e[0], e1); test_int(ctx.e[1], e2); test_int(ctx.c[0][0], ecs_id(Mass)); test_int(ctx.s[0][0], parent); test_int(ctx.c[0][1], ecs_id(Position)); test_int(ctx.s[0][1], 0); const Position *p = ecs_get(world, e1, Position); test_assert(p != NULL); test_int(p->x, 20); test_int(p->y, 40); p = ecs_get(world, e2, Position); test_assert(p != NULL); test_int(p->x, 20); test_int(p->y, 40); ecs_fini(world); } void System_w_FromParent_new_child_after_match(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Mass); ECS_ENTITY(world, e3, Position); ECS_SYSTEM(world, Iter, EcsOnUpdate, Mass(parent), Position); ecs_system_init(world, &(ecs_system_desc_t){ .entity = Iter, .query.filter.instanced = true }); ECS_ENTITY(world, parent, Mass); ECS_ENTITY(world, e1, (ChildOf, parent), Position); ECS_ENTITY(world, e2, (ChildOf, parent), Position); ecs_set(world, parent, Mass, {2}); Probe ctx = {0}; ecs_set_ctx(world, &ctx, NULL); ecs_progress(world, 1); test_int(ctx.count, 2); test_int(ctx.invoked, 1); test_int(ctx.system, Iter); test_int(ctx.term_count, 2); test_null(ctx.param); test_int(ctx.e[0], e1); test_int(ctx.e[1], e2); test_int(ctx.c[0][0], ecs_id(Mass)); test_int(ctx.s[0][0], parent); test_int(ctx.c[0][1], ecs_id(Position)); test_int(ctx.s[0][1], 0); const Position *p = ecs_get(world, e1, Position); test_assert(p != NULL); test_int(p->x, 20); test_int(p->y, 40); p = ecs_get(world, e2, Position); test_assert(p != NULL); test_int(p->x, 20); test_int(p->y, 40); ecs_fini(world); } void IterSame(ecs_iter_t *it) { Position *p_parent = ecs_field(it, Position, 1); Position *p = ecs_field(it, Position, 2); test_assert(!ecs_field_is_self(it, 1)); probe_iter(it); int i; for (i = 0; i < it->count; i ++) { p[i].x += p_parent->x; p[i].y += p_parent->y; } } void System_w_FromParent_select_same_from_container(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Mass); ECS_ENTITY(world, e1, Position); ECS_ENTITY(world, e2, Position); ECS_ENTITY(world, e3, Position); ECS_ENTITY(world, e4, Position); ECS_SYSTEM(world, IterSame, EcsOnUpdate, Position(parent), Position); ecs_system_init(world, &(ecs_system_desc_t){ .entity = IterSame, .query.filter.instanced = true }); ecs_entity_t parent = ecs_set(world, 0, Position, {1, 2}); ecs_add_pair(world, e1, EcsChildOf, parent); ecs_add_pair(world, e2, EcsChildOf, parent); ecs_add_pair(world, e3, EcsChildOf, parent); ecs_set(world, e1, Position, {10, 20}); ecs_set(world, e2, Position, {20, 40}); ecs_set(world, e3, Position, {30, 60}); Probe ctx = {0}; ecs_set_ctx(world, &ctx, NULL); ecs_progress(world, 1); test_int(ctx.count, 3); test_int(ctx.invoked, 1); test_int(ctx.system, IterSame); test_int(ctx.term_count, 2); 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], ecs_id(Position)); test_int(ctx.s[0][0], parent); test_int(ctx.c[0][1], ecs_id(Position)); test_int(ctx.s[0][1], 0); const Position *p = ecs_get(world, e1, Position); test_assert(p != NULL); test_int(p->x, 11); test_int(p->y, 22); p = ecs_get(world, e2, Position); test_assert(p != NULL); test_int(p->x, 21); test_int(p->y, 42); p = ecs_get(world, e3, Position); test_assert(p != NULL); test_int(p->x, 31); test_int(p->y, 62); ecs_fini(world); } void System_w_FromParent_realloc_after_match(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Mass); ECS_ENTITY(world, e1, Position); ECS_SYSTEM(world, Iter, EcsOnUpdate, Mass(parent), Position); ecs_entity_t parent = ecs_set(world, 0, Mass, {2}); ecs_add_pair(world, e1, EcsChildOf, parent); Probe ctx = {0}; ecs_set_ctx(world, &ctx, NULL); ecs_progress(world, 1); test_int(ctx.count, 1); test_int(ctx.invoked, 1); test_int(ctx.system, Iter); test_int(ctx.term_count, 2); test_null(ctx.param); test_int(ctx.e[0], e1); test_int(ctx.c[0][0], ecs_id(Mass)); test_int(ctx.s[0][0], parent); test_int(ctx.c[0][1], ecs_id(Position)); test_int(ctx.s[0][1], 0); const Position *p = ecs_get(world, e1, Position); test_assert(p != NULL); test_int(p->x, 20); test_int(p->y, 40); /* Add 1000 entities to table of container, which will trigger realloc */ for (int i = 0; i < 1000; i ++) { ecs_clone(world, 0, parent, false); } /* Change value of parent Mass. This will update the value in the new table. * If the realloc would not be properly handled, the code could either crash * or reference freed memory and use the old value. */ ecs_set(world, parent, Mass, {3}); ecs_os_zeromem(&ctx); ecs_progress(world, 1); test_int(ctx.count, 1); test_int(ctx.invoked, 1); test_int(ctx.system, Iter); test_int(ctx.term_count, 2); test_null(ctx.param); test_int(ctx.e[0], e1); test_int(ctx.c[0][0], ecs_id(Mass)); test_int(ctx.s[0][0], parent); test_int(ctx.c[0][1], ecs_id(Position)); test_int(ctx.s[0][1], 0); p = ecs_get(world, e1, Position); test_assert(p != NULL); test_int(p->x, 30); test_int(p->y, 60); ecs_fini(world); }