#include static ecs_id_t NamePair; void Prefab_setup(void) { NamePair = ecs_pair(ecs_id(EcsIdentifier), EcsName); } static void Iter(ecs_iter_t *it) { Mass *m_ptr = ecs_field(it, Mass, 1); bool shared = !ecs_field_is_self(it, 1); Position *p = ecs_field(it, Position, 2); Velocity *v = NULL; 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 Prefab_new_w_prefab(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_PREFAB(world, Prefab, Position); ecs_set(world, Prefab, Position, {10, 20}); ecs_entity_t e1 = ecs_new_w_pair(world, EcsIsA, Prefab); test_assert(e1 != 0); test_assert( ecs_has(world, e1, Position)); test_assert( ecs_has_pair(world, e1, EcsIsA, Prefab)); /* These components should never be inherited from prefabs */ test_assert( !ecs_has_id(world, e1, EcsPrefab)); test_assert( !ecs_has_id(world, e1, NamePair)); test_assert( !ecs_get_id(world, e1, NamePair)); ecs_add(world, e1, Velocity); test_assert( ecs_has(world, e1, Position)); test_assert( ecs_has(world, e1, Velocity)); test_assert( ecs_has_pair(world, e1, EcsIsA, Prefab)); test_assert( !ecs_has_id(world, e1, EcsPrefab)); test_assert( !ecs_has_id(world, e1, NamePair)); test_assert( !ecs_get_id(world, e1, NamePair)); ecs_entity_t e2 = ecs_new_w_pair(world, EcsIsA, Prefab); test_assert( ecs_has(world, e2, Position)); test_assert( ecs_has_pair(world, e2, EcsIsA, Prefab)); test_assert( !ecs_has_id(world, e2, EcsPrefab)); test_assert( !ecs_has_id(world, e2, NamePair)); test_assert( !ecs_get_id(world, e2, NamePair)); ecs_add(world, e2, Velocity); test_assert( ecs_has(world, e2, Position)); test_assert( ecs_has(world, e2, Velocity)); test_assert( ecs_has_pair(world, e2, EcsIsA, Prefab)); test_assert( !ecs_has_id(world, e2, EcsPrefab)); test_assert( !ecs_has_id(world, e2, NamePair)); test_assert( !ecs_get_id(world, e2, NamePair)); const Position *p_1 = ecs_get(world, e1, Position); const Position *p_2 = ecs_get(world, e2, Position); test_assert(p_1 != NULL); test_assert(p_2 != NULL); test_assert(p_1 == p_2); test_int(p_1->x, 10); test_int(p_1->y, 20); const Velocity *v_1 = ecs_get(world, e1, Velocity); const Velocity *v_2 = ecs_get(world, e2, Velocity); test_assert(v_1 != NULL); test_assert(v_2 != NULL); test_assert(v_1 != v_2); ecs_fini(world); } void Prefab_new_w_count_prefab(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_PREFAB(world, Prefab, Position); ecs_set(world, Prefab, Position, {10, 20}); const ecs_entity_t *ids = ecs_bulk_new_w_id(world, ecs_pair(EcsIsA, Prefab), 10); test_assert(ids != NULL); ecs_entity_t i; const Position *p_prev = NULL; for (i = 0; i < 10; i ++) { ecs_entity_t e = ids[i]; const Position *p = ecs_get(world, e, Position); test_assert(p != NULL); if (p_prev) test_ptr(p, p_prev); test_int(p->x, 10); test_int(p->y, 20); p_prev = p; } ecs_fini(world); } void Prefab_new_w_type_w_prefab(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_PREFAB(world, Prefab, Position, OVERRIDE | Velocity); ecs_set(world, Prefab, Position, {10, 20}); ecs_entity_t e1 = ecs_new_w_pair(world, EcsIsA, Prefab); test_assert(e1 != 0); test_assert( ecs_has(world, e1, Position)); test_assert( ecs_has_pair(world, e1, EcsIsA, Prefab)); /* These components should never be inherited from prefabs */ test_assert( !ecs_has_id(world, e1, EcsPrefab)); test_assert( !ecs_has_id(world, e1, NamePair)); ecs_entity_t e2 = ecs_new_w_pair(world, EcsIsA, Prefab); test_assert( ecs_has(world, e2, Position)); test_assert( ecs_has_pair(world, e2, EcsIsA, Prefab)); test_assert( !ecs_has_id(world, e2, EcsPrefab)); test_assert( !ecs_has_id(world, e2, NamePair)); const Position *p_1 = ecs_get(world, e1, Position); const Position *p_2 = ecs_get(world, e2, Position); const Position *p_prefab = ecs_get(world, Prefab, Position); test_assert(p_1 != NULL); test_assert(p_2 != NULL); test_assert(p_1 == p_2); test_assert(p_1 == p_prefab); test_int(p_1->x, 10); test_int(p_1->y, 20); const Velocity *v_1 = ecs_get(world, e1, Velocity); const Velocity *v_2 = ecs_get(world, e2, Velocity); test_assert(v_1 != NULL); test_assert(v_2 != NULL); test_assert(v_1 != v_2); ecs_fini(world); } void Prefab_add_prefab(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_PREFAB(world, Prefab, Position); ecs_set(world, Prefab, Position, {10, 20}); ecs_entity_t e1 = ecs_new(world, Velocity); test_assert(e1 != 0); ecs_add_pair(world, e1, EcsIsA, Prefab); test_assert( ecs_has(world, e1, Position)); test_assert( ecs_has_pair(world, e1, EcsIsA, Prefab)); /* These components should never be inherited from prefabs */ test_assert( !ecs_has_id(world, e1, EcsPrefab)); test_assert( !ecs_has_id(world, e1, NamePair)); ecs_entity_t e2 = ecs_new(world, Velocity); test_assert(e2 != 0); ecs_add_pair(world, e2, EcsIsA, Prefab); test_assert( ecs_has(world, e2, Position)); test_assert( ecs_has_pair(world, e2, EcsIsA, Prefab)); test_assert( !ecs_has_id(world, e2, EcsPrefab)); test_assert( !ecs_has_id(world, e2, NamePair)); const Position *p_1 = ecs_get(world, e1, Position); const Position *p_2 = ecs_get(world, e2, Position); const Position *p_prefab = ecs_get(world, Prefab, Position); test_assert(p_1 != NULL); test_assert(p_2 != NULL); test_assert(p_1 == p_2); test_assert(p_prefab == p_1); test_int(p_1->x, 10); test_int(p_1->y, 20); const Velocity *v_1 = ecs_get(world, e1, Velocity); const Velocity *v_2 = ecs_get(world, e2, Velocity); test_assert(v_1 != NULL); test_assert(v_2 != NULL); test_assert(v_1 != v_2); ecs_fini(world); } void Prefab_remove_prefab_after_new(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_PREFAB(world, Prefab, Position); ecs_set(world, Prefab, Position, {10, 20}); ecs_entity_t e1 = ecs_new_w_pair(world, EcsIsA, Prefab); test_assert(e1 != 0); test_assert( ecs_has(world, e1, Position)); test_assert( ecs_has_pair(world, e1, EcsIsA, Prefab)); /* These components should never be inherited from prefabs */ test_assert( !ecs_has_id(world, e1, EcsPrefab)); test_assert( !ecs_has_id(world, e1, NamePair)); test_assert( !ecs_get_id(world, e1, NamePair)); ecs_remove_pair(world, e1, EcsIsA, Prefab); test_assert( !ecs_has(world, e1, Position)); test_assert( !ecs_has_pair(world, e1, EcsIsA, Prefab)); /* These components should never be inherited from prefabs */ test_assert( !ecs_has_id(world, e1, EcsPrefab)); test_assert( !ecs_has_id(world, e1, NamePair)); test_assert( !ecs_get_id(world, e1, NamePair)); ecs_fini(world); } void Prefab_remove_prefab_after_add(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_PREFAB(world, Prefab, Position); ecs_set(world, Prefab, Position, {10, 20}); ecs_entity_t e1 = ecs_new(world, 0); test_assert(e1 != 0); ecs_add_pair(world, e1, EcsIsA, Prefab); test_assert( ecs_has(world, e1, Position)); test_assert( ecs_has_pair(world, e1, EcsIsA, Prefab)); /* These components should never be inherited from prefabs */ test_assert( !ecs_has_id(world, e1, EcsPrefab)); test_assert( !ecs_has_id(world, e1, NamePair)); test_assert( !ecs_get_id(world, e1, NamePair)); ecs_remove_pair(world, e1, EcsIsA, Prefab); test_assert( !ecs_has(world, e1, Position)); test_assert( !ecs_has_pair(world, e1, EcsIsA, Prefab)); /* These components should never be inherited from prefabs */ test_assert( !ecs_has_id(world, e1, EcsPrefab)); test_assert( !ecs_has_id(world, e1, NamePair)); test_assert( !ecs_get_id(world, e1, NamePair)); ecs_fini(world); } void Prefab_override_component(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_PREFAB(world, Prefab, Position); ecs_set(world, Prefab, Position, {10, 20}); ecs_entity_t e1 = ecs_new_w_pair(world, EcsIsA, Prefab); test_assert(e1 != 0); test_assert( ecs_has(world, e1, Position)); test_assert( ecs_has_pair(world, e1, EcsIsA, Prefab)); /* These components should never be inherited from prefabs */ test_assert( !ecs_has_id(world, e1, EcsPrefab)); test_assert( !ecs_has_id(world, e1, NamePair)); test_assert( !ecs_get_id(world, e1, NamePair)); const Position *p = ecs_get(world, e1, Position); test_assert(p != NULL); test_int(p->x, 10); test_int(p->y, 20); ecs_set(world, e1, Position, {20, 30}); p = ecs_get(world, e1, Position); test_int(p->x, 20); test_int(p->y, 30); const Position *p_prefab = ecs_get(world, Prefab, Position); test_assert(p != p_prefab); test_int(p_prefab->x, 10); test_int(p_prefab->y, 20); ecs_fini(world); } void Prefab_override_remove_component(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_PREFAB(world, Prefab, Position); ecs_set(world, Prefab, Position, {10, 20}); ecs_entity_t e1 = ecs_new_w_pair(world, EcsIsA, Prefab); test_assert(e1 != 0); test_assert( ecs_has(world, e1, Position)); test_assert( ecs_has_pair(world, e1, EcsIsA, Prefab)); /* These components should never be inherited from prefabs */ test_assert( !ecs_has_id(world, e1, EcsPrefab)); test_assert( !ecs_has_id(world, e1, NamePair)); test_assert( !ecs_get_id(world, e1, NamePair)); const Position *p = ecs_get(world, e1, Position); test_assert(p != NULL); test_int(p->x, 10); test_int(p->y, 20); ecs_set(world, e1, Position, {20, 30}); p = ecs_get(world, e1, Position); test_int(p->x, 20); test_int(p->y, 30); const Position *p_prefab = ecs_get(world, Prefab, Position); test_assert(p_prefab != NULL); test_assert(p != p_prefab); test_int(p_prefab->x, 10); test_int(p_prefab->y, 20); ecs_remove(world, e1, Position); p = ecs_get(world, e1, Position); test_assert(p != NULL); test_assert(p == p_prefab); test_int(p->x, 10); test_int(p->y, 20); ecs_fini(world); } void Prefab_override_2_of_3_components_1_self(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_COMPONENT(world, Mass); ECS_COMPONENT(world, Rotation); ECS_PREFAB(world, Prefab, Position, Velocity, Mass); ecs_set(world, Prefab, Position, {10, 20}); ecs_set(world, Prefab, Velocity, {30, 40}); ecs_set(world, Prefab, Mass, {50}); ecs_entity_t e1 = ecs_new_w_pair(world, EcsIsA, Prefab); test_assert(e1 != 0); ecs_set(world, e1, Rotation, {60}); test_assert( ecs_has(world, e1, Position)); test_assert( ecs_has(world, e1, Velocity)); test_assert( ecs_has(world, e1, Mass)); test_assert( ecs_has(world, e1, Rotation)); test_assert( ecs_has_pair(world, e1, EcsIsA, Prefab)); /* These components should never be inherited from prefabs */ test_assert( !ecs_has_id(world, e1, EcsPrefab)); test_assert( !ecs_has_id(world, e1, NamePair)); test_assert( !ecs_get_id(world, e1, NamePair)); const Position *p = ecs_get(world, e1, Position); test_assert(p != NULL); test_int(p->x, 10); test_int(p->y, 20); ecs_set(world, e1, Position, {20, 30}); p = ecs_get(world, e1, Position); test_int(p->x, 20); test_int(p->y, 30); const Position *p_prefab = ecs_get(world, Prefab, Position); test_assert(p != p_prefab); test_int(p_prefab->x, 10); test_int(p_prefab->y, 20); const Velocity *v = ecs_get(world, e1, Velocity); test_assert(v != NULL); test_int(v->x, 30); test_int(v->y, 40); ecs_set(world, e1, Velocity, {40, 50}); v = ecs_get(world, e1, Velocity); test_int(v->x, 40); test_int(v->y, 50); const Velocity *v_prefab = ecs_get(world, Prefab, Velocity); test_assert(v != v_prefab); test_int(v_prefab->x, 30); test_int(v_prefab->y, 40); const Mass *m = ecs_get(world, e1, Mass); test_assert(m != NULL); test_int(*m, 50); const Mass *m_prefab = ecs_get(world, Prefab, Mass); test_assert(m_prefab != NULL); test_ptr(m_prefab, m); const Rotation *r = ecs_get(world, e1, Rotation); test_assert(r != NULL); test_int(*r, 60); ecs_fini(world); } void Prefab_new_type_w_1_override(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_PREFAB(world, Prefab, Position, Velocity, OVERRIDE | Position); ecs_set(world, Prefab, Position, {10, 20}); ecs_set(world, Prefab, Velocity, {30, 40}); ecs_entity_t e1 = ecs_new_w_pair(world, EcsIsA, Prefab); test_assert(e1 != 0); test_assert( ecs_has(world, e1, Position)); test_assert( ecs_has(world, e1, Velocity)); test_assert( ecs_has_pair(world, e1, EcsIsA, Prefab)); /* These components should never be inherited from prefabs */ test_assert( !ecs_has_id(world, e1, EcsPrefab)); test_assert( !ecs_has_id(world, e1, NamePair)); test_assert( !ecs_get_id(world, e1, NamePair)); const Position *p = ecs_get(world, e1, Position); test_assert(p != NULL); test_int(p->x, 10); test_int(p->y, 20); const Position *p_prefab = ecs_get(world, Prefab, Position); test_assert(p_prefab != NULL); test_assert(p != p_prefab); test_int(p_prefab->x, 10); test_int(p_prefab->y, 20); const Velocity *v = ecs_get(world, e1, Velocity); test_assert(v != NULL); test_int(v->x, 30); test_int(v->y, 40); const Velocity *v_prefab = ecs_get(world, Prefab, Velocity); test_assert(v_prefab != NULL); test_assert(v == v_prefab); test_int(v_prefab->x, 30); test_int(v_prefab->y, 40); ecs_fini(world); } void Prefab_new_type_w_2_overrides(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_PREFAB(world, Prefab, Position, Velocity, OVERRIDE | Position, OVERRIDE | Velocity); ecs_set(world, Prefab, Position, {10, 20}); ecs_set(world, Prefab, Velocity, {30, 40}); ecs_entity_t e1 = ecs_new_w_pair(world, EcsIsA, Prefab); test_assert(e1 != 0); test_assert( ecs_has(world, e1, Position)); test_assert( ecs_has(world, e1, Velocity)); test_assert( ecs_has_pair(world, e1, EcsIsA, Prefab)); /* These components should never be inherited from prefabs */ test_assert( !ecs_has_id(world, e1, EcsPrefab)); test_assert( !ecs_has_id(world, e1, NamePair)); test_assert( !ecs_get_id(world, e1, NamePair)); const Position *p = ecs_get(world, e1, Position); test_assert(p != NULL); test_int(p->x, 10); test_int(p->y, 20); const Position *p_prefab = ecs_get(world, Prefab, Position); test_assert(p_prefab != NULL); test_assert(p != p_prefab); test_int(p_prefab->x, 10); test_int(p_prefab->y, 20); const Velocity *v = ecs_get(world, e1, Velocity); test_assert(v != NULL); test_int(v->x, 30); test_int(v->y, 40); const Velocity *v_prefab = ecs_get(world, Prefab, Velocity); test_assert(v_prefab != NULL); test_assert(v != v_prefab); test_int(v_prefab->x, 30); test_int(v_prefab->y, 40); ecs_fini(world); } void Prefab_get_ptr_prefab(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_PREFAB(world, Prefab, Position); ecs_set(world, Prefab, Position, {10, 20}); ecs_entity_t e1 = ecs_new_w_pair(world, EcsIsA, Prefab); test_assert(e1 != 0); test_assert( ecs_has_pair(world, e1, EcsIsA, Prefab)); test_assert( ecs_get_id(world, e1, Prefab) == NULL); ecs_fini(world); } static void Prefab_w_shared(ecs_iter_t *it) { Velocity *v = NULL; if (it->field_count >= 2) { v = ecs_field(it, Velocity, 2); if (v) { test_assert(!ecs_field_is_self(it, 2)); } } Mass *m = NULL; if (it->field_count >= 3) { m = ecs_field(it, Mass, 3); } probe_iter(it); Position *pos = ecs_field(it, Position, 1); for (int i = 0; i < it->count; i ++) { Position *p = &pos[i]; p->x += v->x; p->y += v->y; if (m) { p->x += *m; p->y += *m; } } } void Prefab_iterate_w_prefab_shared(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_PREFAB(world, Prefab, Velocity); ECS_SYSTEM(world, Prefab_w_shared, EcsOnUpdate, Position, Velocity(up|self)); ecs_set(world, Prefab, Velocity, {1, 2}); ECS_ENTITY(world, e1, (IsA, Prefab), Position); test_assert(e1 != 0); ecs_set(world, e1, Position, {0, 0}); 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, Prefab_w_shared); test_int(ctx.term_count, 2); test_null(ctx.param); test_int(ctx.e[0], e1); test_int(ctx.c[0][0], ecs_id(Position)); test_int(ctx.s[0][0], 0); test_int(ctx.c[0][1], ecs_id(Velocity)); test_int(ctx.s[0][1], Prefab); const Position *p = ecs_get(world, e1, Position); test_assert(p != NULL); test_int(p->x, 1); test_int(p->y, 2); ecs_fini(world); } void Prefab_match_entity_prefab_w_system_optional(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_COMPONENT(world, Mass); ECS_PREFAB(world, Prefab, Velocity, Mass); ECS_SYSTEM(world, Prefab_w_shared, EcsOnUpdate, Position, Velocity(self|up), ?Mass(self|up)); ecs_set(world, Prefab, Velocity, {1, 2}); ecs_set(world, Prefab, Mass, {3}); ECS_ENTITY(world, e1, (IsA, Prefab), Position); test_assert(e1 != 0); ecs_set(world, e1, Position, {0, 0}); 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, Prefab_w_shared); test_int(ctx.term_count, 3); test_null(ctx.param); test_int(ctx.e[0], e1); test_int(ctx.c[0][0], ecs_id(Position)); test_int(ctx.s[0][0], 0); test_int(ctx.c[0][1], ecs_id(Velocity)); test_int(ctx.s[0][1], Prefab); test_int(ctx.c[0][2], ecs_id(Mass)); test_int(ctx.s[0][2], Prefab); const Position *p = ecs_get(world, e1, Position); test_assert(p != NULL); test_int(p->x, 4); test_int(p->y, 5); ecs_fini(world); } void Prefab_prefab_in_system_expr(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_COMPONENT(world, Mass); ECS_PREFAB(world, Prefab1, Velocity); ECS_PREFAB(world, Prefab2, Velocity); ECS_SYSTEM(world, Prefab_w_shared, EcsOnUpdate, Position, Velocity(self|up), Mass, (IsA, Prefab1)); ecs_system_init(world, &(ecs_system_desc_t){ .entity = Prefab_w_shared, .query.filter.instanced = true }); ecs_set(world, Prefab1, Velocity, {1, 2}); ecs_set(world, Prefab2, Velocity, {1, 2}); ecs_entity_t e1 = ecs_new_w_pair(world, EcsIsA, Prefab1); ecs_entity_t e2 = ecs_new_w_pair(world, EcsIsA, Prefab1); ecs_entity_t e3 = ecs_new_w_pair(world, EcsIsA, Prefab2); test_assert(e1 != 0); test_assert(e2 != 0); test_assert(e3 != 0); ecs_set(world, e1, Position, {0, 0}); ecs_set(world, e2, Position, {0, 0}); ecs_set(world, e3, Position, {0, 0}); ecs_set(world, e1, Mass, {0}); ecs_set(world, e2, Mass, {0}); ecs_set(world, e3, Mass, {0}); 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, Prefab_w_shared); test_int(ctx.term_count, 4); test_null(ctx.param); test_int(ctx.e[0], e1); test_int(ctx.e[1], e2); test_int(ctx.c[0][0], ecs_id(Position)); test_int(ctx.s[0][0], 0); test_int(ctx.c[0][1], ecs_id(Velocity)); test_int(ctx.s[0][1], Prefab1); test_int(ctx.c[0][2], ecs_id(Mass)); test_int(ctx.s[0][2], 0); test_int(ctx.c[0][3], ecs_pair(EcsIsA, Prefab1)); test_int(ctx.s[0][3], 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, 1); test_int(p->y, 2); ecs_fini(world); } static void Dummy(ecs_iter_t *it) { probe_iter(it); } void Prefab_dont_match_prefab(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_PREFAB(world, Prefab, Position); ECS_SYSTEM(world, Dummy, EcsOnUpdate, Position); Probe ctx = {0}; ecs_set_ctx(world, &ctx, NULL); ecs_progress(world, 1); test_int(ctx.count, 0); test_int(ctx.invoked, 0); ecs_fini(world); } void Prefab_new_w_count_w_override(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_PREFAB(world, Prefab, Position, Velocity, OVERRIDE | Velocity); ecs_set(world, Prefab, Position, {10, 20}); ecs_set(world, Prefab, Velocity, {30, 40}); const ecs_entity_t *ids = ecs_bulk_new_w_id( world, ecs_pair(EcsIsA, Prefab), 100); test_assert(ids != NULL); const Position *prefab_p = ecs_get(world, Prefab, Position); const Velocity *prefab_v = ecs_get(world, Prefab, Velocity); int i; for (i = 0; i < 100; i ++) { ecs_entity_t e = ids[i]; test_assert( ecs_has(world, e, Position)); test_assert( ecs_has(world, e, Velocity)); test_assert( ecs_has_pair(world, e, EcsIsA, Prefab)); const Position *p = ecs_get(world, e, Position); test_assert(p != NULL); test_assert(p == prefab_p); test_int(p->x, 10); test_int(p->y, 20); const Velocity *v = ecs_get(world, e, Velocity); test_assert(v != NULL); test_assert(v != prefab_v); test_int(v->x, 30); test_int(v->y, 40); } ecs_fini(world); } void Prefab_override_2_components_different_size(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_COMPONENT(world, Color); ECS_PREFAB(world, Prefab, Position, Velocity, Color, OVERRIDE | Velocity, OVERRIDE | Color); ecs_set(world, Prefab, Position, {10, 20}); ecs_set(world, Prefab, Velocity, {30, 40}); ecs_set(world, Prefab, Color, {1, 2, 3, 4}); const ecs_entity_t *ids = ecs_bulk_new_w_id(world, ecs_pair(EcsIsA, Prefab), 100); test_assert(ids != NULL); const Position *prefab_p = ecs_get(world, Prefab, Position); const Velocity *prefab_v = ecs_get(world, Prefab, Velocity); const Color *prefab_c = ecs_get(world, Prefab, Color); test_assert(prefab_p != NULL); test_assert(prefab_v != NULL); test_assert(prefab_c != NULL); int i; for (i = 0; i < 100; i ++) { ecs_entity_t e = ids[i]; test_assert( ecs_has(world, e, Position)); test_assert( ecs_has(world, e, Velocity)); test_assert( ecs_has_pair(world, e, EcsIsA, Prefab)); const Position *p = ecs_get(world, e, Position); test_assert(p != NULL); test_int(p->x, 10); test_int(p->y, 20); test_assert(p == prefab_p); const Velocity *v = ecs_get(world, e, Velocity); test_assert(v != NULL); test_int(v->x, 30); test_int(v->y, 40); test_assert(v != prefab_v); const Color *c = ecs_get(world, e, Color); test_assert(c != NULL); test_int(c->r, 1); test_int(c->g, 2); test_int(c->b, 3); test_int(c->a, 4); test_assert(c != prefab_c); } ecs_fini(world); } void Prefab_ignore_prefab_parent_component(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_ENTITY(world, parent, Prefab, Position); ECS_ENTITY(world, child, Prefab, (ChildOf, parent), Velocity); test_assert( ecs_has_pair(world, child, EcsChildOf, parent)); test_assert( !ecs_has(world, child, Position)); test_assert( ecs_has(world, child, Velocity)); ecs_fini(world); } static void Move(ecs_iter_t *it) { Position *p = ecs_field(it, Position, 1); Velocity *v = ecs_field(it, Velocity, 2); int i; for (i = 0; i < it->count; i ++) { p[i].x += v[i].y; p[i].y += v[i].y; } } static void AddVelocity(ecs_iter_t *it) { ecs_id_t ecs_id(Velocity) = ecs_field_id(it, 2); int i; for (i = 0; i < it->count; i ++) { ecs_set(it->world, it->entities[i], Velocity, {1, 1}); } } void Prefab_match_table_created_in_progress(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_COMPONENT(world, Mass); ECS_PREFAB(world, Prefab, Mass); ecs_set(world, Prefab, Mass, {10}); ECS_ENTITY(world, e, (IsA, Prefab), Position); ECS_SYSTEM(world, AddVelocity, EcsOnUpdate, Position, [out] !Velocity); ECS_SYSTEM(world, Move, EcsOnUpdate, Position, Velocity, Mass(self|up)); ecs_set(world, e, Position, {0, 0}); test_assert( ecs_has(world, e, Position)); test_assert( !ecs_has(world, e, Velocity)); test_assert( ecs_has(world, e, Mass)); ecs_progress(world, 1); test_assert( ecs_has(world, e, Velocity)); const Position *p = ecs_get(world, e, Position); test_assert(p != NULL); test_int(p->x, 1); test_int(p->y, 1); ecs_progress(world, 1); p = ecs_get(world, e, Position); test_assert(p != NULL); test_int(p->x, 2); test_int(p->y, 2); ecs_fini(world); } void Prefab_prefab_w_1_child(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_PREFAB(world, Parent, Position); ecs_set(world, Parent, Position, {1, 2}); ECS_PREFAB(world, Child, (ChildOf, Parent), Position); ecs_set(world, Child, Position, {2, 3}); ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, Parent); test_assert(e != 0); test_assert( ecs_has(world, e, Position)); const Position *p_e = ecs_get(world, e, Position); test_assert(p_e != NULL); test_int(p_e->x, 1); test_int(p_e->y, 2); ecs_entity_t e_child = ecs_lookup_child(world, e, "Child"); test_assert(e_child != 0); test_assert(ecs_has(world, e_child, Position)); test_assert(ecs_has_pair(world, e_child, EcsChildOf, e)); const Position *p_child = ecs_get(world, e_child, Position); test_assert(p_child != NULL); test_int(p_child->x, 2); test_int(p_child->y, 3); ecs_entity_t e2 = ecs_new_w_pair(world, EcsIsA, Parent); test_assert(e2 != 0); test_assert( ecs_has(world, e, Position)); test_assert( ecs_get(world, e2, Position) == p_e); ecs_entity_t e_child2 = ecs_lookup_child(world, e2, "Child"); test_assert(e_child2 != 0); test_assert(ecs_has(world, e_child2, Position)); test_assert(ecs_has_pair(world, e_child2, EcsChildOf, e2)); test_assert( ecs_get(world, e_child2, Position) != p_child); p_child = ecs_get(world, e_child2, Position); test_assert(p_child != NULL); test_int(p_child->x, 2); test_int(p_child->y, 3); ecs_fini(world); } void Prefab_prefab_w_2_children(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_ENTITY(world, Parent, Prefab, Position); ecs_set(world, Parent, Position, {1, 2}); ECS_ENTITY(world, Child1, Prefab, (ChildOf, Parent), Position); ecs_set(world, Child1, Position, {2, 3}); ECS_ENTITY(world, Child2, Prefab, (ChildOf, Parent), Position); ecs_set(world, Child2, Position, {3, 4}); ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, Parent); test_assert(e != 0); test_assert( ecs_has(world, e, Position)); const Position *p = ecs_get(world, e, Position); test_assert(p != NULL); test_int(p->x, 1); test_int(p->y, 2); ecs_entity_t e_child = ecs_lookup_child(world, e, "Child1"); test_assert(e_child != 0); test_assert(ecs_has(world, e_child, Position)); test_assert(ecs_has_pair(world, e_child, EcsChildOf, e)); p = ecs_get(world, e_child, Position); test_assert(p != NULL); test_int(p->x, 2); test_int(p->y, 3); e_child = ecs_lookup_child(world, e, "Child2"); test_assert(e_child != 0); test_assert(ecs_has(world, e_child, Position)); test_assert(ecs_has_pair(world, e_child, EcsChildOf, e)); p = ecs_get(world, e_child, Position); test_assert(p != NULL); test_int(p->x, 3); test_int(p->y, 4); ecs_fini(world); } void Prefab_prefab_w_grandchild(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Rotation); ECS_ENTITY(world, Parent, Prefab, Position); ecs_set(world, Parent, Position, {1, 2}); ECS_ENTITY(world, Child, Prefab, (ChildOf, Parent), Position); ecs_set(world, Child, Position, {2, 3}); ECS_ENTITY(world, GrandChild, Prefab, (ChildOf, Parent.Child), Position, Rotation); ecs_set(world, GrandChild, Position, {3, 4}); ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, Parent); test_assert(e != 0); test_assert( ecs_has(world, e, Position)); const Position *p = ecs_get(world, e, Position); test_assert(p != NULL); test_int(p->x, 1); test_int(p->y, 2); ecs_entity_t e_child = ecs_lookup_child(world, e, "Child"); test_assert(e_child != 0); test_assert(ecs_has(world, e_child, Position)); test_assert(ecs_has_pair(world, e_child, EcsChildOf, e)); p = ecs_get(world, e_child, Position); test_assert(p != NULL); test_int(p->x, 2); test_int(p->y, 3); ecs_entity_t e_grandchild = ecs_lookup_child(world, e_child, "GrandChild"); test_assert(e_grandchild != 0); test_assert(ecs_has(world, e_grandchild, Position)); test_assert(ecs_has_pair(world, e_grandchild, EcsChildOf, e_child)); p = ecs_get(world, e_grandchild, Position); test_assert(p != NULL); test_int(p->x, 3); test_int(p->y, 4); ecs_fini(world); } void Prefab_prefab_tree_1_2_1(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Rotation); ECS_ENTITY(world, parent, Prefab, Position); ecs_set(world, parent, Position, {1, 2}); ECS_ENTITY(world, child_1, Prefab, (ChildOf, parent), Position); ecs_set(world, child_1, Position, {2, 3}); ECS_ENTITY(world, child_2, Prefab, (ChildOf, parent), Position); ecs_set(world, child_2, Position, {4, 5}); ECS_ENTITY(world, grandchild, Prefab, (ChildOf, parent.child_2), Position); ecs_set(world, grandchild, Position, {6, 7}); test_assert(ecs_has_pair(world, child_1, EcsChildOf, parent)); test_assert(ecs_has_pair(world, child_2, EcsChildOf, parent)); test_assert(ecs_has_pair(world, grandchild, EcsChildOf, child_2)); ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, parent); test_assert(e != 0); test_assert( ecs_has(world, e, Position)); const Position *p = ecs_get(world, e, Position); test_assert(p != NULL); test_int(p->x, 1); test_int(p->y, 2); ecs_entity_t e_child = ecs_lookup_child(world, e, "child_1"); test_assert(e_child != 0); test_assert(ecs_has(world, e_child, Position)); test_assert(ecs_has_pair(world, e_child, EcsChildOf, e)); p = ecs_get(world, e_child, Position); test_assert(p != NULL); test_int(p->x, 2); test_int(p->y, 3); e_child = ecs_lookup_child(world, e, "child_2"); test_assert(e_child != 0); test_assert(ecs_has(world, e_child, Position)); test_assert(ecs_has_pair(world, e_child, EcsChildOf, e)); p = ecs_get(world, e_child, Position); test_assert(p != NULL); test_int(p->x, 4); test_int(p->y, 5); ecs_entity_t e_grandchild = ecs_lookup_child(world, e_child, "grandchild"); test_assert(e_grandchild != 0); test_assert(ecs_has(world, e_grandchild, Position)); test_assert(ecs_has_pair(world, e_grandchild, EcsChildOf, e_child)); p = ecs_get(world, e_grandchild, Position); test_assert(p != NULL); test_int(p->x, 6); test_int(p->y, 7); ecs_fini(world); } void Prefab_prefab_w_base_w_child(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_ENTITY(world, Base, Prefab, Velocity); ecs_set(world, Base, Velocity, {3, 4}); ECS_ENTITY(world, Parent, Prefab, (IsA, Base), Position); ecs_set(world, Parent, Position, {1, 2}); ECS_ENTITY(world, Child, Prefab, (ChildOf, Parent), Position); ecs_set(world, Child, Position, {2, 3}); ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, Parent); test_assert(e != 0); test_assert( ecs_has(world, e, Position)); test_assert( ecs_has(world, e, Velocity)); const Position *p_e = ecs_get(world, e, Position); test_assert(p_e != NULL); test_int(p_e->x, 1); test_int(p_e->y, 2); const Velocity *v_e = ecs_get(world, e, Velocity); test_assert(v_e != NULL); test_int(v_e->x, 3); test_int(v_e->y, 4); ecs_entity_t e_child = ecs_lookup_child(world, e, "Child"); test_assert(e_child != 0); test_assert(ecs_has(world, e_child, Position)); test_assert(!ecs_has(world, e_child, Velocity)); test_assert(ecs_has_pair(world, e_child, EcsChildOf, e)); const Position *p_child = ecs_get(world, e_child, Position); test_assert(p_child != NULL); test_int(p_child->x, 2); test_int(p_child->y, 3); ecs_fini(world); } void Prefab_prefab_w_child_w_base(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_ENTITY(world, Base, Prefab, Velocity); ecs_set(world, Base, Velocity, {3, 4}); ECS_ENTITY(world, Parent, Prefab, Position); ecs_set(world, Parent, Position, {1, 2}); ECS_ENTITY(world, Child, Prefab, (ChildOf, Parent), (IsA, Base), Position); ecs_set(world, Child, Position, {2, 3}); ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, Parent); test_assert(e != 0); test_assert( ecs_has(world, e, Position)); const Position *p_e = ecs_get(world, e, Position); test_assert(p_e != NULL); test_int(p_e->x, 1); test_int(p_e->y, 2); ecs_entity_t e_child = ecs_lookup_child(world, e, "Child"); test_assert(e_child != 0); test_assert(ecs_has(world, e_child, Position)); test_assert(ecs_has(world, e_child, Velocity)); test_assert(ecs_has_pair(world, e_child, EcsChildOf, e)); const Position *p_child = ecs_get(world, e_child, Position); test_assert(p_child != NULL); test_int(p_child->x, 2); test_int(p_child->y, 3); const Velocity *v_child = ecs_get(world, e_child, Velocity); test_assert(v_child != NULL); test_int(v_child->x, 3); test_int(v_child->y, 4); ecs_fini(world); } void Prefab_prefab_w_child_w_base_w_children(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_ENTITY(world, Base, Prefab, Velocity); ecs_set(world, Base, Velocity, {3, 4}); ECS_ENTITY(world, BaseChild, Prefab, (ChildOf, Base), Position); ecs_set(world, BaseChild, Position, {4, 5}); ECS_ENTITY(world, Parent, Prefab, Position); ecs_set(world, Parent, Position, {1, 2}); ECS_ENTITY(world, Child, Prefab, (ChildOf, Parent), (IsA, Base), Position); ecs_set(world, Child, Position, {2, 3}); ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, Parent); test_assert(e != 0); test_assert( ecs_has(world, e, Position)); const Position *p_e = ecs_get(world, e, Position); test_assert(p_e != NULL); test_int(p_e->x, 1); test_int(p_e->y, 2); ecs_entity_t e_child = ecs_lookup_child(world, e, "Child"); test_assert(e_child != 0); test_assert(ecs_has(world, e_child, Position)); test_assert(ecs_has(world, e_child, Velocity)); test_assert(ecs_has_pair(world, e_child, EcsChildOf, e)); const Position *p_child = ecs_get(world, e_child, Position); test_assert(p_child != NULL); test_int(p_child->x, 2); test_int(p_child->y, 3); const Velocity *v_child = ecs_get(world, e_child, Velocity); test_assert(v_child != NULL); test_int(v_child->x, 3); test_int(v_child->y, 4); ecs_entity_t e_base_child = ecs_lookup_child(world, e_child, "BaseChild"); test_assert(e_base_child != 0); test_assert(ecs_has(world, e_base_child, Position)); test_assert(!ecs_has(world, e_base_child, Velocity)); test_assert(ecs_has_pair(world, e_base_child, EcsChildOf, e_child)); const Position *p_base_child = ecs_get(world, e_base_child, Position); test_assert(p_base_child != NULL); test_assert(p_base_child != p_child); test_int(p_base_child->x, 4); test_int(p_base_child->y, 5); ecs_fini(world); } void Prefab_prefab_w_child_new_w_count(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_ENTITY(world, Parent, Prefab, Position); ecs_set(world, Parent, Position, {1, 2}); ECS_ENTITY(world, Child, Prefab, (ChildOf, Parent), Position); ecs_set(world, Child, Position, {2, 3}); const ecs_entity_t *ids = ecs_bulk_new_w_id(world, ecs_pair(EcsIsA, Parent), 3); test_assert(ids != NULL); int i; for (i = 0; i < 3; i ++) { ecs_entity_t e = ids[i]; test_assert( ecs_has(world, e, Position)); const Position *p_e = ecs_get(world, e, Position); test_assert(p_e != NULL); test_int(p_e->x, 1); test_int(p_e->y, 2); ecs_entity_t e_child = ecs_lookup_child(world, e, "Child"); test_assert(e_child != 0); test_assert(ecs_has(world, e_child, Position)); test_assert(ecs_has_pair(world, e_child, EcsChildOf, e)); const Position *p_child = ecs_get(world, e_child, Position); test_assert(p_child != NULL); test_int(p_child->x, 2); test_int(p_child->y, 3); } ecs_fini(world); } void Prefab_prefab_auto_override_child_component(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_ENTITY(world, Parent, Prefab, Position); ecs_set(world, Parent, Position, {1, 2}); ECS_ENTITY(world, ChildPrefab, Prefab, Position, Velocity); ecs_set(world, ChildPrefab, Position, {2, 3}); ecs_set(world, ChildPrefab, Velocity, {4, 5}); ECS_ENTITY(world, Child, Prefab, (ChildOf, Parent), (IsA, ChildPrefab), Velocity); ecs_entity_t e1 = ecs_new_w_pair(world, EcsIsA, Parent); test_assert(e1 != 0); test_assert( ecs_has(world, e1, Position)); ecs_entity_t e2 = ecs_new_w_pair(world, EcsIsA, Parent); test_assert(e2 != 0); test_assert( ecs_has(world, e2, Position)); const Position *p1 = ecs_get(world, e1, Position); test_assert(p1 != NULL); test_int(p1->x, 1); test_int(p1->y, 2); const Position *p2 = ecs_get(world, e2, Position); test_assert(p2 != NULL); test_int(p2->x, 1); test_int(p2->y, 2); test_assert(p1 == p2); ecs_entity_t child_1 = ecs_lookup_child(world, e1, "Child"); test_assert(child_1 != 0); test_assert( ecs_has(world, child_1, Position)); test_assert( ecs_has(world, child_1, Velocity)); ecs_entity_t child_2 = ecs_lookup_child(world, e2, "Child"); test_assert(child_2 != 0); test_assert( ecs_has(world, child_2, Position)); test_assert( ecs_has(world, child_2, Velocity)); const Position *child_p1 = ecs_get(world, child_1, Position); test_assert(child_p1 != NULL); test_int(child_p1->x, 2); test_int(child_p1->y, 3); const Position *child_p2 = ecs_get(world, child_2, Position); test_assert(child_p2 != NULL); test_int(child_p2->x, 2); test_int(child_p2->y, 3); test_assert(child_p1 == child_p2); const Velocity *child_v1 = ecs_get(world, child_1, Velocity); test_assert(child_v1 != NULL); test_int(child_v1->x, 4); test_int(child_v1->y, 5); const Velocity *child_v2 = ecs_get(world, child_2, Velocity); test_assert(child_v2 != NULL); test_int(child_v2->x, 4); test_int(child_v2->y, 5); test_assert(child_v1 != child_v2); ecs_fini(world); } static int invoked; void PrefabReactiveTest(ecs_iter_t *it) { invoked ++; } void Prefab_ignore_on_add(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_OBSERVER(world, PrefabReactiveTest, EcsOnAdd, Position); ECS_PREFAB(world, Prefab, Position); test_int(invoked, 0); ecs_fini(world); } void Prefab_ignore_on_remove(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_OBSERVER(world, PrefabReactiveTest, EcsOnRemove, Position); ECS_PREFAB(world, Prefab, Position); test_int(invoked, 0); ecs_remove(world, Prefab, Position); test_int(invoked, 0); ecs_fini(world); } void Prefab_ignore_on_set(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_OBSERVER(world, PrefabReactiveTest, EcsOnSet, Position); ECS_PREFAB(world, Prefab, Position); test_int(invoked, 0); ecs_set(world, Prefab, Position, {0, 0}); test_int(invoked, 0); ecs_fini(world); } void Prefab_on_set_on_instance(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_OBSERVER(world, PrefabReactiveTest, EcsOnSet, Position(self|up)); ECS_PREFAB(world, Prefab, Position); test_int(invoked, 0); ecs_set(world, Prefab, Position, {1, 2}); test_int(invoked, 0); ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, Prefab); test_assert(e != 0); test_assert( ecs_has(world, e, Position)); test_int(invoked, 1); const Position *p = ecs_get(world, e, Position); test_assert(p != NULL); test_int(p->x, 1); test_int(p->y, 2); ecs_fini(world); } void InstantiateInProgress(ecs_iter_t *it) { ecs_id_t Prefab = ecs_field_id(it, 2); ecs_entity_t *ids = ecs_get_ctx(it->world); int i; for (i = 0; i < it->count; i ++) { ids[i] = ecs_new_w_pair(it->world, EcsIsA, Prefab); } } void Prefab_instantiate_in_progress(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_PREFAB(world, Prefab, Velocity); ecs_set(world, Prefab, Velocity, {1, 2}); ECS_SYSTEM(world, InstantiateInProgress, EcsOnUpdate, Position, Prefab()); const ecs_entity_t *dummy_ids = ecs_bulk_new(world, Position, 10); test_assert(dummy_ids != NULL); ecs_entity_t ids[10]; ecs_set_ctx(world, ids, NULL); ecs_progress(world, 1); test_int(ecs_count_id(world, ecs_pair(EcsIsA, Prefab)), 10); const Velocity *v_prefab = ecs_get(world, Prefab, Velocity); int i; for (i = 0; i < 10; i ++) { const Velocity *v = ecs_get(world, ids[i], Velocity); test_assert(v == v_prefab); } ecs_fini(world); } void NewInProgress(ecs_iter_t *it) { ecs_id_t Prefab = ecs_field_id(it, 2); ecs_entity_t *ids = ecs_get_ctx(it->world); int i; for (i = 0; i < it->count; i ++) { ids[i] = ecs_new_w_pair(it->world, EcsIsA, Prefab); } } void Prefab_copy_from_prefab_in_progress(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_PREFAB(world, Prefab, Velocity, OVERRIDE | Velocity); ecs_set(world, Prefab, Velocity, {1, 2}); ECS_SYSTEM(world, NewInProgress, EcsOnUpdate, Position, Prefab()); ecs_entity_t ids[10]; ecs_set_ctx(world, ids, NULL); const ecs_entity_t *dummy_ids = ecs_bulk_new(world, Position, 10); test_assert(dummy_ids != NULL); /* Create one prefab instance so table is already created (case where table * is not created is tested in copy_from_prefab_first_instance_in_progress*/ ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, Prefab); test_assert(e != 0); ecs_progress(world, 1); test_int(ecs_count_id(world, ecs_pair(EcsIsA, Prefab)), 11); int i; for (i = 0; i < 10; i ++) { const Velocity *v = ecs_get(world, ids[i], Velocity); test_int(v->x, 1); test_int(v->y, 2); } ecs_fini(world); } void Prefab_copy_from_prefab_first_instance_in_progress(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_PREFAB(world, Prefab, Velocity, OVERRIDE | Velocity); ecs_set(world, Prefab, Velocity, {1, 2}); ECS_SYSTEM(world, NewInProgress, EcsOnUpdate, Position, Prefab()); ecs_entity_t ids[10]; ecs_set_ctx(world, ids, NULL); const ecs_entity_t *dummy_ids = ecs_bulk_new(world, Position, 10); test_assert(dummy_ids != NULL); ecs_progress(world, 1); test_int(ecs_count_id(world, ecs_pair(EcsIsA, Prefab)), 10); int i; for (i = 0; i < 10; i ++) { const Velocity *v = ecs_get(world, ids[i], Velocity); test_int(v->x, 1); test_int(v->y, 2); } ecs_fini(world); } void Prefab_ref_after_realloc(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_COMPONENT(world, Mass); ECS_PREFAB(world, Prefab, Mass); ecs_set(world, Prefab, Mass, {2}); ECS_ENTITY(world, e1, Position, Mass); ecs_set(world, e1, Mass, {3}); ECS_ENTITY(world, e2, Position, (IsA, Prefab)); ECS_SYSTEM(world, Iter, EcsOnUpdate, Mass(self|up), Position); /* Trigger a realloc of the table in which the prefab is stored. This should * cause systems with refs to re-resolve their cached ref ptrs */ for (int i = 0; i < 1000; i ++) { ecs_clone(world, 0, Prefab, false); } ecs_progress(world, 1); const Position *p = ecs_get(world, e1, Position); test_assert(p != NULL); test_int(p->x, 30); test_int(p->y, 60); p = ecs_get(world, e2, Position); test_assert(p != NULL); test_int(p->x, 20); test_int(p->y, 40); ecs_fini(world); } void Prefab_revalidate_ref_w_mixed_table_refs(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_COMPONENT(world, Mass); ECS_PREFAB(world, Prefab, Mass); ecs_set(world, Prefab, Mass, {1}); ECS_ENTITY(world, e1, Position, (IsA, Prefab)); ECS_ENTITY(world, e2, Position, Mass); ecs_set(world, e2, Mass, {3}); ECS_SYSTEM(world, Iter, EcsOnUpdate, Mass(self|up), Position); /* Trigger a realloc of the table in which the prefab is stored. This should * cause systems with refs to re-resolve their cached ref ptrs */ for (int i = 0; i < 1000; i ++) { ecs_clone(world, 0, Prefab, false); } ecs_set(world, Prefab, Mass, {2}); ecs_progress(world, 1); const Position *p = ecs_get(world, e2, Position); test_assert(p != NULL); test_int(p->x, 30); test_int(p->y, 60); p = ecs_get(world, e1, Position); test_assert(p != NULL); test_int(p->x, 20); test_int(p->y, 40); ecs_fini(world); } void Prefab_no_overwrite_on_2nd_add(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_COMPONENT(world, Mass); ECS_PREFAB(world, Prefab, Mass); ecs_set(world, Prefab, Mass, {1}); ECS_ENTITY(world, e1, Position, (IsA, Prefab)); ecs_add(world, e1, Mass); test_int( *ecs_get(world, e1, Mass), 1); ecs_set(world, e1, Mass, {2}); test_int( *ecs_get(world, e1, Mass), 2); ecs_add(world, e1, Mass); test_int( *ecs_get(world, e1, Mass), 2); ecs_fini(world); } void AddPrefab(ecs_iter_t *it) { ecs_id_t Prefab = ecs_field_id(it, 2); int i; for (i = 0; i < it->count; i ++) { ecs_add_pair(it->world, it->entities[i], EcsIsA, Prefab); } } void Prefab_no_overwrite_on_2nd_add_in_progress(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_COMPONENT(world, Mass); ECS_PREFAB(world, Prefab, Mass); ecs_set(world, Prefab, Mass, {1}); ECS_SYSTEM(world, AddPrefab, EcsOnUpdate, Position, Prefab()); ECS_ENTITY(world, e1, Position, (IsA, Prefab)); ecs_add(world, e1, Mass); test_int( *ecs_get(world, e1, Mass), 1); ecs_set(world, e1, Mass, {2}); test_int( *ecs_get(world, e1, Mass), 2); ecs_progress(world, 1); test_int( *ecs_get(world, e1, Mass), 2); ecs_fini(world); } void Prefab_no_instantiate_on_2nd_add(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_COMPONENT(world, Mass); ECS_PREFAB(world, Prefab, Position); ecs_set(world, Prefab, Position, {1, 2}); ECS_PREFAB(world, ChildPrefab, (ChildOf, Prefab), Velocity); ecs_set(world, ChildPrefab, Velocity, {3, 4}); ECS_SYSTEM(world, AddPrefab, EcsOnUpdate, Position, Prefab()); ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, Prefab); test_assert( ecs_has_pair(world, e, EcsIsA, Prefab)); const Position *p = ecs_get(world, e, Position); test_assert(p != NULL); test_int(p->x, 1); test_int(p->y, 2); ecs_entity_t e_child = ecs_lookup_child(world, e, "ChildPrefab"); test_assert(e_child != 0); const Velocity *v = ecs_get(world, e_child, Velocity); test_assert(v != NULL); test_int(v->x, 3); test_int(v->y, 4); ecs_set(world, e_child, Velocity, {4, 5}); v = ecs_get(world, e_child, Velocity); test_assert(v != NULL); test_int(v->x, 4); test_int(v->y, 5); ecs_add_pair(world, e, EcsIsA, Prefab); ecs_entity_t e_child_2 = ecs_lookup_child(world, e, "ChildPrefab"); test_assert(e_child == e_child_2); v = ecs_get(world, e_child, Velocity); test_assert(v != NULL); test_int(v->x, 4); test_int(v->y, 5); ecs_fini(world); } void Prefab_no_instantiate_on_2nd_add_in_progress(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_COMPONENT(world, Mass); ECS_PREFAB(world, Prefab, Position); ecs_set(world, Prefab, Position, {1, 2}); ECS_PREFAB(world, ChildPrefab, (ChildOf, Prefab), Velocity); ecs_set(world, ChildPrefab, Velocity, {3, 4}); ECS_SYSTEM(world, AddPrefab, EcsOnUpdate, Position, Prefab()); ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, Prefab); test_assert( ecs_has_pair(world, e, EcsIsA, Prefab)); const Position *p = ecs_get(world, e, Position); test_assert(p != NULL); test_int(p->x, 1); test_int(p->y, 2); ecs_entity_t e_child = ecs_lookup_child(world, e, "ChildPrefab"); test_assert(e_child != 0); const Velocity *v = ecs_get(world, e_child, Velocity); test_assert(v != NULL); test_int(v->x, 3); test_int(v->y, 4); ecs_set(world, e_child, Velocity, {4, 5}); v = ecs_get(world, e_child, Velocity); test_assert(v != NULL); test_int(v->x, 4); test_int(v->y, 5); ecs_progress(world, 1); ecs_entity_t e_child_2 = ecs_lookup_child(world, e, "ChildPrefab"); test_assert(e_child == e_child_2); v = ecs_get(world, e_child, Velocity); test_assert(v != NULL); test_int(v->x, 4); test_int(v->y, 5); ecs_fini(world); } void NewPrefab_w_count(ecs_iter_t *it) { ecs_entity_t *ids = ecs_get_ctx(it->world); ecs_id_t Prefab = ecs_field_id(it, 1); const ecs_entity_t *new_ids = ecs_bulk_new_w_id(it->world, ecs_pair(EcsIsA, Prefab), 3); test_assert(new_ids != NULL); memcpy(ids, new_ids, sizeof(ecs_entity_t) * 3); } void Prefab_nested_prefab_in_progress_w_count(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_COMPONENT(world, Mass); ECS_PREFAB(world, Prefab, Position); ecs_set(world, Prefab, Position, {1, 2}); ECS_PREFAB(world, ChildPrefab, (ChildOf, Prefab), Velocity); ecs_set(world, ChildPrefab, Velocity, {3, 4}); ECS_SYSTEM(world, NewPrefab_w_count, EcsOnUpdate, Prefab()); ecs_entity_t ids[3] = {0}; ecs_set_ctx(world, ids, NULL); ecs_progress(world, 1); int i; for (i = 0; i < 3; i ++) { ecs_has_pair(world, ids[i], EcsIsA, Prefab); const Position *p = ecs_get(world, ids[i], Position); test_assert(p != NULL); test_int(p->x, 1); test_int(p->y, 2); ecs_entity_t child = ecs_lookup_child(world, ids[i], "ChildPrefab"); test_assert(child != 0); const Velocity *v = ecs_get(world, child, Velocity); test_assert(v != NULL); test_int(v->x, 3); test_int(v->y, 4); } ecs_fini(world); } static int on_set_velocity_invoked; static void OnSetVelocity(ecs_iter_t *it) { Velocity *v = ecs_field(it, Velocity, 1); ecs_id_t ecs_id(Velocity) = ecs_field_id(it, 1); on_set_velocity_invoked ++; int i; for (i = 0; i < it->count; i ++) { ecs_add(it->world, it->entities[i], Velocity); if (ecs_field_is_self(it, 1)) { v[i].x ++; v[i].y ++; } } } void Prefab_nested_prefab_in_progress_w_count_set_after_override(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_COMPONENT(world, Mass); ECS_PREFAB(world, Prefab, Position); ecs_set(world, Prefab, Position, {1, 2}); ECS_PREFAB(world, ChildPrefab, (ChildOf, Prefab), Velocity); ecs_set(world, ChildPrefab, Velocity, {3, 4}); ECS_SYSTEM(world, NewPrefab_w_count, EcsOnUpdate, Prefab()); ECS_OBSERVER(world, OnSetVelocity, EcsOnSet, Velocity); test_int(on_set_velocity_invoked, 0); ecs_entity_t ids[3] = {0}; ecs_set_ctx(world, ids, NULL); ecs_progress(world, 1); test_assert(ids != NULL); test_int(on_set_velocity_invoked, 3); int i; for (i = 0; i < 3; i ++) { ecs_has_pair(world, ids[i], EcsIsA, Prefab); const Position *p = ecs_get(world, ids[i], Position); test_assert(p != NULL); test_int(p->x, 1); test_int(p->y, 2); ecs_entity_t child = ecs_lookup_child(world, ids[i], "ChildPrefab"); test_assert(child != 0); const Velocity *v = ecs_get(world, child, Velocity); test_assert(v != NULL); test_int(v->x, 3 + 1); test_int(v->y, 4 + 1); } ecs_fini(world); } void AddPrefabInProgress(ecs_iter_t *it) { ecs_id_t Prefab = ecs_field_id(it, 2); ecs_id_t ecs_id(Velocity) = ecs_field_id(it, 3); int i; for (i = 0; i < it->count; i ++) { ecs_add_pair(it->world, it->entities[i], EcsIsA, Prefab); test_assert( ecs_has_id(it->world, it->entities[i], Prefab)); test_assert( ecs_has(it->world, it->entities[i], Velocity)); const Velocity *v = ecs_get(it->world, it->entities[i], Velocity); test_assert(v != NULL); test_int(v->x, 1); test_int(v->y, 2); test_assert( ecs_get(it->world, Prefab, Velocity) == v); } } void Prefab_get_ptr_from_prefab_from_new_table_in_progress(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_PREFAB(world, Prefab, Velocity); ecs_set(world, Prefab, Velocity, {1, 2}); ECS_SYSTEM(world, AddPrefabInProgress, EcsOnUpdate, Position, Prefab(), Velocity()); ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, Prefab); ecs_progress(world, 1); test_assert( ecs_has_pair(world, e, EcsIsA, Prefab)); test_assert( ecs_has(world, e, Velocity)); const Velocity *v = ecs_get(world, e, Velocity); test_assert(v != NULL); test_int(v->x, 1); test_int(v->y, 2); test_assert( ecs_get(world, Prefab, Velocity) == v); ecs_fini(world); } void TestBase(ecs_iter_t *it) { Position *p = ecs_field(it, Position, 1); Velocity *v = ecs_field(it, Velocity, 2); test_assert(!ecs_field_is_self(it, 2)); test_assert(p != NULL); test_assert(v != NULL); test_int(it->count, 1); } void Prefab_match_base(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_PREFAB(world, Base, Velocity); ecs_set(world, Base, Velocity, {1, 2}); ECS_PREFAB(world, Child, (IsA, Base)); ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, Child); ecs_add(world, e, Position); ECS_SYSTEM(world, TestBase, EcsOnUpdate, Position, Velocity(self|up)); ecs_progress(world, 1); ecs_fini(world); } static void AddMass(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_add(it->world, it->entities[i], Mass); } } void Prefab_match_base_after_add_in_prev_phase(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_COMPONENT(world, Mass); ECS_PREFAB(world, Base, Velocity); ecs_set(world, Base, Velocity, {1, 2}); ECS_PREFAB(world, Child, (IsA, Base)); ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, Child); ecs_add(world, e, Position); ECS_SYSTEM(world, AddMass, EcsPreUpdate, Position, !Mass); ECS_SYSTEM(world, TestBase, EcsOnUpdate, Position, Velocity(self|up)); ecs_progress(world, 1); ecs_fini(world); } void Prefab_override_watched_prefab(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); /* Create a system that listens for Position */ ECS_SYSTEM(world, Dummy, EcsOnUpdate, Position(self|up)); /* Create a prefab with Position */ ECS_PREFAB(world, Prefab, Position); /* Create an instance of Prefab, this will cause Prefab to be watched since * it will be matched as reference with the system */ ECS_ENTITY(world, Entity1, (IsA, Prefab)); /* Another instance of Prefab is created, prefab data is resolved to check * if components need to be overridden. Index will be negative, so code * needs to flip sign on the index, or this will fail. */ ECS_ENTITY(world, Entity2, (IsA, Prefab), Position); const Position *p1 = ecs_get(world, Prefab, Position); const Position *p2 = ecs_get(world, Entity1, Position); const Position *p3 = ecs_get(world, Entity2, Position); test_assert(p1 == p2); test_assert(p2 != p3); ecs_fini(world); } void Prefab_rematch_twice(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_COMPONENT(world, Mass); ECS_SYSTEM(world, Dummy, EcsOnUpdate, Position(self|up), Velocity(self|up), Mass(self|up)); ECS_PREFAB(world, Prefab, Position); ECS_ENTITY(world, Entity, (IsA, Prefab)); Probe ctx = {0}; ecs_set_ctx(world, &ctx, NULL); ecs_progress(world, 1); test_int(ctx.count, 0); ctx.count = 0; ecs_add(world, Prefab, Velocity); ecs_progress(world, 1); test_int(ctx.count, 0); ctx.count = 0; ecs_add(world, Prefab, Mass); ecs_progress(world, 1); test_int(ctx.count, 1); ecs_fini(world); } static void AddPosition(ecs_iter_t *it) { ecs_id_t ecs_id(Position) = ecs_field_id(it, 1); ecs_entity_t *base = ecs_get_ctx(it->world); ecs_add(it->world, *base, Position); } void Prefab_add_to_empty_base_in_system(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ecs_entity_t base = ecs_new(world, 0); ecs_entity_t e1 = ecs_new(world, Position); ecs_add_pair(world, e1, EcsIsA, base); ECS_SYSTEM(world, AddPosition, EcsOnUpdate, Position()); ecs_set_ctx(world, &base, NULL); ecs_progress(world, 1); test_assert( ecs_has(world, base, Position)); ecs_fini(world); } void Prefab_inherit_disabled(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ecs_entity_t e1 = ecs_new(world, Position); ecs_entity_t e2 = ecs_new(world, Velocity); ecs_add_id(world, e2, EcsDisabled); ecs_add_pair(world, e1, EcsIsA, e2); test_assert( ecs_has(world, e1, Position)); test_assert( ecs_has(world, e1, Velocity)); test_assert( ecs_has_id(world, e1, EcsDisabled)); test_assert( ecs_has_pair(world, e1, EcsIsA, e2)); test_assert( !ecs_has(world, e2, Position)); test_assert( ecs_has(world, e2, Velocity)); test_assert( ecs_has_id(world, e2, EcsDisabled)); ecs_fini(world); } static bool has_cloned = false; static void CloneInOnAdd(ecs_iter_t *it) { Position *p = ecs_field(it, Position, 1); int i; for (i = 0; i < it->count; i ++) { bool has_cloned_test = has_cloned; /* Prevent recursive OnAdd calls */ has_cloned = true; p[i].x = 10; p[i].y = 20; if (!has_cloned_test) { ecs_entity_t e = it->entities[i]; ecs_entity_t clone = ecs_clone(it->world, 0, e, true); ecs_add_pair(it->world, e, EcsIsA, clone); } } } void Prefab_clone_after_inherit_in_on_add(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_OBSERVER(world, CloneInOnAdd, EcsOnAdd, Position); ecs_entity_t e = ecs_new(world, Position); test_assert(e != 0); const Position *p = ecs_get(world, e, Position); test_int(p->x, 10); test_int(p->y, 20); test_assert(has_cloned == true); ecs_fini(world); } void Prefab_override_from_nested(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_PREFAB(world, BasePrefab, Position); ecs_set(world, BasePrefab, Position, {10, 20}); ECS_PREFAB(world, SubPrefab, (IsA, BasePrefab), Velocity, OVERRIDE | Position, OVERRIDE | Velocity); ecs_set(world, SubPrefab, Velocity, {30, 40}); ecs_entity_t e1 = ecs_new_w_pair(world, EcsIsA, SubPrefab); test_assert(e1 != 0); test_assert( ecs_owns(world, e1, Position)); test_assert( ecs_owns(world, e1, Velocity)); test_assert( ecs_owns(world, e1, Position)); test_assert( ecs_owns(world, e1, Velocity)); test_assert( ecs_has_pair(world, e1, EcsIsA, SubPrefab)); test_assert( ecs_has_pair(world, e1, EcsIsA, BasePrefab)); const Position *p = ecs_get(world, e1, Position); test_assert(p != NULL); test_int(p->x, 10); test_int(p->y, 20); const Velocity *v = ecs_get(world, e1, Velocity); test_assert(v != NULL); test_int(v->x, 30); test_int(v->y, 40); ecs_fini(world); } static void OnAddEntity(ecs_iter_t *it) { ecs_entity_t *e = ecs_field(it, ecs_entity_t, 1); int i; for (i = 0; i < it->count; i ++) { e[i] = it->entities[i]; } } void Prefab_create_multiple_nested_w_on_set(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_COMPONENT(world, Mass); ECS_COMPONENT(world, ecs_entity_t); ECS_PREFAB(world, Prefab, Position); ecs_set(world, Prefab, Position, {1, 2}); ECS_PREFAB(world, Child, (ChildOf, Prefab), Velocity, ecs_entity_t); ecs_set(world, Child, Velocity, {3, 4}); ECS_OBSERVER(world, OnAddEntity, EcsOnSet, ecs_entity_t); ECS_OBSERVER(world, OnSetVelocity, EcsOnSet, Velocity); test_int(on_set_velocity_invoked, 0); /* Create two entities with separate calls */ ecs_entity_t e1 = ecs_new_w_pair(world, EcsIsA, Prefab); ecs_entity_t e2 = ecs_new_w_pair(world, EcsIsA, Prefab); test_int(on_set_velocity_invoked, 2); test_assert( ecs_has(world, e1, Position)); test_assert( ecs_has(world, e2, Position)); ecs_entity_t child1 = ecs_lookup_child(world, e1, "Child"); test_assert(child1 != 0); ecs_entity_t child2 = ecs_lookup_child(world, e2, "Child"); test_assert(child2 != 0); test_assert(child1 != child2); const ecs_entity_t *self1 = ecs_get(world, child1, ecs_entity_t); test_assert(self1 != NULL); test_assert(*self1 == child1); const ecs_entity_t *self2 = ecs_get(world, child2, ecs_entity_t); test_assert(self2 != NULL); test_assert(self1 != self2); test_assert(*self2 == child2); test_assert( ecs_has(world, child1, Velocity)); test_assert( ecs_has(world, child2, Velocity)); test_assert( ecs_owns(world, child1, Velocity)); test_assert( ecs_owns(world, child2, Velocity)); const Velocity *v1 = ecs_get(world, child1, Velocity); test_assert(v1 != NULL); test_int(v1->x, 4); test_int(v1->y, 5); const Velocity *v2 = ecs_get(world, child2, Velocity); test_assert(v2 != NULL); test_assert(v1 != v2); test_int(v2->x, 4); test_int(v2->y, 5); ecs_fini(world); } static ecs_entity_t new_instance_1, new_instance_2; static void CreateInstances(ecs_iter_t *it) { ecs_id_t Prefab = ecs_field_id(it, 1); new_instance_1 = ecs_new_w_pair(it->world, EcsIsA, Prefab); new_instance_2 = ecs_new_w_pair(it->world, EcsIsA, Prefab); } void Prefab_create_multiple_nested_w_on_set_in_progress(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_COMPONENT(world, Mass); ECS_COMPONENT(world, ecs_entity_t); ECS_PREFAB(world, Prefab, Position); ecs_set(world, Prefab, Position, {1, 2}); ECS_PREFAB(world, ChildPrefab, Velocity); ecs_set(world, ChildPrefab, Velocity, {3, 4}); ECS_PREFAB(world, Child, (ChildOf, Prefab), (IsA, ChildPrefab), ecs_entity_t); ECS_SYSTEM(world, CreateInstances, EcsOnUpdate, Prefab()); ECS_OBSERVER(world, OnAddEntity, EcsOnSet, ecs_entity_t); ECS_OBSERVER(world, OnSetVelocity, EcsOnSet, Velocity(self|up)); ecs_progress(world, 1); test_int(on_set_velocity_invoked, 2); ecs_entity_t e1 = new_instance_1; ecs_entity_t e2 = new_instance_2; test_assert( ecs_has(world, e1, Position)); test_assert( ecs_has(world, e2, Position)); ecs_entity_t child1 = ecs_lookup_child(world, e1, "Child"); test_assert(child1 != 0); ecs_entity_t child2 = ecs_lookup_child(world, e2, "Child"); test_assert(child2 != 0); test_assert(child1 != child2); const ecs_entity_t *self1 = ecs_get(world, child1, ecs_entity_t); test_assert(self1 != NULL); test_assert(*self1 == child1); const ecs_entity_t *self2 = ecs_get(world, child2, ecs_entity_t); test_assert(self2 != NULL); test_assert(self1 != self2); test_assert(*self2 == child2); test_assert( ecs_has(world, child1, Velocity)); test_assert( ecs_has(world, child2, Velocity)); test_assert( ecs_owns(world, child1, Velocity)); test_assert( ecs_owns(world, child2, Velocity)); const Velocity *v1 = ecs_get(world, child1, Velocity); test_assert(v1 != NULL); test_int(v1->x, 3); test_int(v1->y, 4); const Velocity *v2 = ecs_get(world, child2, Velocity); test_assert(v2 != NULL); test_assert(v1 != v2); test_int(v2->x, 3); test_int(v2->y, 4); ecs_fini(world); } void Prefab_single_on_set_on_child_w_override(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_COMPONENT(world, Mass); ECS_COMPONENT(world, ecs_entity_t); ECS_PREFAB(world, Prefab, Position); ecs_set(world, Prefab, Position, {1, 2}); ECS_PREFAB(world, ChildPrefab, Velocity); ecs_set(world, ChildPrefab, Velocity, {3, 4}); ECS_PREFAB(world, Child, (ChildOf, Prefab), (IsA, ChildPrefab), Velocity); ECS_OBSERVER(world, OnSetVelocity, EcsOnSet, Velocity); test_int(on_set_velocity_invoked, 0); ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, Prefab); /* Make sure OnSet is invoked only once, even though Child overrides a * component from a ChildPrefab. Velocity is already overridden for Child, * and while it would technically not be incorrect to issue an OnSet for the * override, we don't want to spam the application with redundant triggers. */ test_int(on_set_velocity_invoked, 1); test_assert( ecs_has(world, e, Position)); ecs_entity_t child = ecs_lookup_child(world, e, "Child"); test_assert(child != 0); test_assert( ecs_has(world, child, Velocity)); test_assert( ecs_owns(world, child, Velocity)); const Velocity *v = ecs_get(world, child, Velocity); test_assert(v != NULL); test_int(v->x, 4); test_int(v->y, 5); ecs_fini(world); } void Prefab_auto_override(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_PREFAB(world, Prefab, Position, Velocity, OVERRIDE | Position); ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, Prefab); test_assert(ecs_has(world, e, Position)); test_assert(ecs_owns(world, e, Position)); test_assert(ecs_has(world, e, Velocity)); test_assert(!ecs_owns(world, e, Velocity)); ecs_fini(world); } void Prefab_auto_override_2(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_PREFAB(world, Prefab, Position, Velocity, OVERRIDE | Position, OVERRIDE | Velocity); ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, Prefab); test_assert(ecs_has(world, e, Position)); test_assert(ecs_owns(world, e, Position)); test_assert(ecs_has(world, e, Velocity)); test_assert(ecs_owns(world, e, Velocity)); ecs_fini(world); } void Prefab_auto_override_nested(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_PREFAB(world, Prefab, Position, Velocity, OVERRIDE | Position); ECS_PREFAB(world, Prefab_2, (IsA, Prefab)); ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, Prefab_2); test_assert(ecs_has(world, e, Position)); test_assert(ecs_owns(world, e, Position)); test_assert(ecs_has(world, e, Velocity)); test_assert(!ecs_owns(world, e, Velocity)); ecs_fini(world); } void Prefab_auto_override_pair(void) { ecs_world_t *world = ecs_init(); ECS_TAG(world, TgtA); ECS_TAG(world, TgtB); ECS_TAG(world, Rel); ecs_entity_t base = ecs_new_id(world); ecs_add_id(world, base, ECS_OVERRIDE | ecs_pair(Rel, TgtA)); test_assert(!ecs_has_pair(world, base, Rel, TgtA)); test_assert(!ecs_has_pair(world, base, Rel, TgtB)); test_assert(ecs_has_id(world, base, ECS_OVERRIDE | ecs_pair(Rel, TgtA))); ecs_add_pair(world, base, Rel, TgtA); ecs_add_pair(world, base, Rel, TgtB); test_assert(ecs_has_pair(world, base, Rel, TgtA)); test_assert(ecs_has_pair(world, base, Rel, TgtB)); test_assert(ecs_has_id(world, base, ECS_OVERRIDE | ecs_pair(Rel, TgtA))); ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, base); test_assert(ecs_has_pair(world, inst, Rel, TgtA)); test_assert(ecs_has_pair(world, inst, Rel, TgtB)); test_assert(ecs_owns_pair(world, inst, Rel, TgtA)); test_assert(!ecs_owns_pair(world, inst, Rel, TgtB)); ecs_fini(world); } void Prefab_auto_override_pair_w_component(void) { ecs_world_t *world = ecs_init(); ECS_TAG(world, TgtA); ECS_TAG(world, TgtB); ECS_COMPONENT(world, Position); ecs_entity_t base = ecs_new_id(world); ecs_add_id(world, base, ECS_OVERRIDE | ecs_pair(ecs_id(Position), TgtA)); test_assert(ecs_get_pair(world, base, Position, TgtA) == NULL); ecs_set_pair(world, base, Position, TgtA, {10, 20}); ecs_set_pair(world, base, Position, TgtB, {20, 30}); const Position *pa = ecs_get_pair(world, base, Position, TgtA); const Position *pb = ecs_get_pair(world, base, Position, TgtB); test_assert(pa != NULL); test_assert(pb != NULL); test_int(pa->x, 10); test_int(pa->y, 20); test_int(pb->x, 20); test_int(pb->y, 30); ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, base); const Position *pia = ecs_get_pair(world, inst, Position, TgtA); const Position *pib = ecs_get_pair(world, inst, Position, TgtB); test_assert(pia != pa); test_assert(pib == pb); test_int(pia->x, 10); test_int(pia->y, 20); test_assert(ecs_owns_pair(world, inst, ecs_id(Position), TgtA)); test_assert(!ecs_owns_pair(world, inst, ecs_id(Position), TgtB)); ecs_fini(world); } void Prefab_auto_override_2_pairs(void) { ecs_world_t *world = ecs_init(); ECS_TAG(world, TgtA); ECS_TAG(world, TgtB); ECS_TAG(world, Rel); ecs_entity_t base = ecs_new_id(world); ecs_add_id(world, base, ECS_OVERRIDE | ecs_pair(Rel, TgtA)); ecs_add_id(world, base, ECS_OVERRIDE | ecs_pair(Rel, TgtB)); test_assert(!ecs_has_pair(world, base, Rel, TgtA)); test_assert(!ecs_has_pair(world, base, Rel, TgtB)); test_assert(ecs_has_id(world, base, ECS_OVERRIDE | ecs_pair(Rel, TgtA))); test_assert(ecs_has_id(world, base, ECS_OVERRIDE | ecs_pair(Rel, TgtB))); ecs_add_pair(world, base, Rel, TgtA); ecs_add_pair(world, base, Rel, TgtB); test_assert(ecs_has_pair(world, base, Rel, TgtA)); test_assert(ecs_has_pair(world, base, Rel, TgtB)); test_assert(ecs_has_id(world, base, ECS_OVERRIDE | ecs_pair(Rel, TgtA))); test_assert(ecs_has_id(world, base, ECS_OVERRIDE | ecs_pair(Rel, TgtB))); ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, base); test_assert(ecs_has_pair(world, inst, Rel, TgtA)); test_assert(ecs_has_pair(world, inst, Rel, TgtB)); test_assert(ecs_owns_pair(world, inst, Rel, TgtA)); test_assert(ecs_owns_pair(world, inst, Rel, TgtB)); ecs_fini(world); } void Prefab_auto_override_2_pairs_w_component(void) { ecs_world_t *world = ecs_init(); ECS_TAG(world, TgtA); ECS_TAG(world, TgtB); ECS_COMPONENT(world, Position); ecs_entity_t base = ecs_new_id(world); ecs_add_id(world, base, ECS_OVERRIDE | ecs_pair(ecs_id(Position), TgtA)); ecs_add_id(world, base, ECS_OVERRIDE | ecs_pair(ecs_id(Position), TgtB)); test_assert(ecs_get_pair(world, base, Position, TgtA) == NULL); test_assert(ecs_get_pair(world, base, Position, TgtB) == NULL); ecs_set_pair(world, base, Position, TgtA, {10, 20}); ecs_set_pair(world, base, Position, TgtB, {20, 30}); const Position *pa = ecs_get_pair(world, base, Position, TgtA); const Position *pb = ecs_get_pair(world, base, Position, TgtB); test_assert(pa != NULL); test_assert(pb != NULL); test_int(pa->x, 10); test_int(pa->y, 20); test_int(pb->x, 20); test_int(pb->y, 30); ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, base); const Position *pia = ecs_get_pair(world, inst, Position, TgtA); const Position *pib = ecs_get_pair(world, inst, Position, TgtB); test_assert(pia != pa); test_assert(pib != pb); test_int(pia->x, 10); test_int(pia->y, 20); test_int(pib->x, 20); test_int(pib->y, 30); test_assert(ecs_owns_pair(world, inst, ecs_id(Position), TgtA)); test_assert(ecs_owns_pair(world, inst, ecs_id(Position), TgtB)); ecs_fini(world); } void Prefab_auto_override_2_pairs_same_obj(void) { ecs_world_t *world = ecs_init(); ECS_TAG(world, Tgt); ECS_TAG(world, RelA); ECS_TAG(world, RelB); ecs_entity_t base = ecs_new_id(world); ecs_add_id(world, base, ECS_OVERRIDE | ecs_pair(RelA, Tgt)); ecs_add_id(world, base, ECS_OVERRIDE | ecs_pair(RelB, Tgt)); test_assert(!ecs_has_pair(world, base, RelA, Tgt)); test_assert(!ecs_has_pair(world, base, RelB, Tgt)); test_assert(ecs_has_id(world, base, ECS_OVERRIDE | ecs_pair(RelA, Tgt))); test_assert(ecs_has_id(world, base, ECS_OVERRIDE | ecs_pair(RelB, Tgt))); ecs_add_pair(world, base, RelA, Tgt); ecs_add_pair(world, base, RelB, Tgt); test_assert(ecs_has_pair(world, base, RelA, Tgt)); test_assert(ecs_has_pair(world, base, RelB, Tgt)); test_assert(ecs_has_id(world, base, ECS_OVERRIDE | ecs_pair(RelA, Tgt))); test_assert(ecs_has_id(world, base, ECS_OVERRIDE | ecs_pair(RelB, Tgt))); ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, base); test_assert(ecs_has_pair(world, inst, RelA, Tgt)); test_assert(ecs_has_pair(world, inst, RelB, Tgt)); test_assert(ecs_owns_pair(world, inst, RelA, Tgt)); test_assert(ecs_owns_pair(world, inst, RelB, Tgt)); ecs_fini(world); } void Prefab_prefab_instanceof_hierarchy(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_PREFAB(world, Base, Position); ECS_PREFAB(world, BaseChild, Position, (ChildOf, Base)); ECS_PREFAB(world, ThePrefab, (IsA, Base)); /* Ensure that child has not been instantiated by making * sure there are no matching entities for Position up to this point */ ecs_query_t *q = ecs_query_new(world, "Position(self|up)"); ecs_iter_t qit = ecs_query_iter(world, q); test_assert(!ecs_query_next(&qit)); /* Instantiate the prefab */ ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, ThePrefab); test_assert(e != 0); ecs_entity_t child = ecs_lookup_child(world, e, "BaseChild"); test_assert(child != 0); qit = ecs_query_iter(world, q); test_assert(ecs_query_next(&qit) == true); test_int(qit.count, 1); test_assert(ecs_query_next(&qit) == true); test_int(qit.count, 1); test_assert(ecs_query_next(&qit) == false); ecs_fini(world); } void Prefab_override_tag(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_TAG(world, Tag); ecs_entity_t base = ecs_new(world, Tag); ecs_set(world, base, Position, {10, 20}); ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, base); test_assert(ecs_has(world, e, Position)); test_assert(ecs_has(world, e, Tag)); ecs_add(world, e, Tag); test_assert(ecs_has(world, e, Tag)); test_assert(ecs_owns(world, e, Tag)); ecs_fini(world); } void Prefab_empty_prefab(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ecs_entity_t base = ecs_new(world, 0); ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, base); ecs_add(world, e, Position); test_assert(ecs_has(world, e, Position)); test_assert(ecs_has_pair(world, e, EcsIsA, base)); ecs_fini(world); } void Prefab_instanceof_0(void) { install_test_abort(); ecs_world_t *world = ecs_mini(); test_expect_abort(); /* Not allowed */ ecs_new_w_pair(world, EcsIsA, 0); ecs_fini(world); } void Prefab_instantiate_empty_child_table(void) { ecs_world_t *world = ecs_init(); ECS_PREFAB(world, Prefab, 0); /* Forces creation of child table without children */ ecs_table_t *table = ecs_table_add_id(world, 0, ecs_childof(Prefab)); test_assert(table != NULL); /* Main goal of this test is to ensure this doesn't crash */ ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, Prefab); test_assert(e != 0); test_assert(ecs_has_pair(world, e, EcsIsA, Prefab)); /* This shouldn't crash either */ ecs_delete(world, Prefab); test_assert(!ecs_is_alive(world, Prefab)); ecs_fini(world); } void Prefab_instantiate_emptied_child_table(void) { ecs_world_t *world = ecs_init(); ECS_PREFAB(world, Prefab, 0); /* Create & remove prefab child */ ecs_entity_t child = ecs_new_w_pair(world, EcsChildOf, Prefab); test_assert(child != 0); /* Deleting the child will leave an initialized but empty table */ ecs_delete(world, child); test_assert(!ecs_is_alive(world, child)); /* Main goal of this test is to ensure this doesn't crash */ ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, Prefab); test_assert(e != 0); test_assert(ecs_has_pair(world, e, EcsIsA, Prefab)); /* This shouldn't crash either */ ecs_delete(world, Prefab); test_assert(!ecs_is_alive(world, Prefab)); ecs_fini(world); } void Prefab_override_2_prefabs(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ECS_PREFAB(world, PrefabA, Position); ECS_PREFAB(world, PrefabB, Velocity); ecs_set(world, PrefabA, Position, {10, 20}); ecs_set(world, PrefabB, Velocity, {1, 2}); ecs_entity_t e = ecs_new(world, 0); ecs_add_pair(world, e, EcsIsA, PrefabA); ecs_add_pair(world, e, EcsIsA, PrefabB); ecs_add(world, e, Position); ecs_add(world, e, Velocity); test_assert(ecs_owns(world, e, Position)); test_assert(ecs_owns(world, e, Velocity)); const Position *p = ecs_get(world, e, Position); test_int(p->x, 10); test_int(p->y, 20); const Velocity *v = ecs_get(world, e, Velocity); test_int(v->x, 1); test_int(v->y, 2); ecs_fini(world); } void Prefab_rematch_after_add_instanceof_to_parent(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ecs_query_t *q = ecs_query_new(world, "Position(parent)"); test_assert(q != NULL); ecs_entity_t base = ecs_set(world, 0, Position, {10, 20}); ecs_entity_t parent = ecs_new(world, 0); ecs_entity_t child = ecs_new_w_pair(world, EcsChildOf, parent); test_assert(base != 0); test_assert(parent != 0); test_assert(child != 0); ecs_add_pair(world, parent, EcsIsA, base); ecs_iter_t it = ecs_query_iter(world, q); test_bool(ecs_query_next(&it), true); test_int(it.count, 1); test_int(it.entities[0], child); Position *p = ecs_field(&it, Position, 1); test_assert(p != NULL); test_int(p->x, 10); test_int(p->y, 20); test_bool(ecs_query_next(&it), false); ecs_fini(world); } void Prefab_child_of_instance(void) { install_test_abort(); ecs_world_t *world = ecs_init(); ecs_entity_t base = ecs_new_w_id(world, EcsPrefab); ecs_entity_t e = ecs_new_id(world); ecs_add_pair(world, e, EcsChildOf, base); test_expect_abort(); /* Should trigger an assert */ ecs_add_pair(world, e, EcsIsA, base); ecs_fini(world); } void Prefab_rematch_after_prefab_delete(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ecs_entity_t base = ecs_set(world, 0, Position, {10, 20}); ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, base); ecs_query_t *q = ecs_query_new(world, "Position(up)"); ecs_iter_t it = ecs_query_iter(world, q); test_assert(ecs_query_next(&it)); test_int(it.count, 1); test_int(it.entities[0], e); Position *p = ecs_field(&it, Position, 1); test_assert(p != NULL); test_int(p->x, 10); test_int(p->y, 20); test_assert(!ecs_query_next(&it)); ecs_delete(world, base); it = ecs_query_iter(world, q); test_assert(!ecs_query_next(&it)); ecs_fini(world); } void Prefab_add_tag_w_low_id_to_instance(void) { ecs_world_t *world = ecs_init(); ecs_entity_t Tag = ecs_new_low_id(world); ECS_COMPONENT(world, Position); ecs_entity_t base = ecs_set(world, 0, Position, {10, 20}); ecs_add_id(world, base, Tag); ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, base); ecs_add(world, e, Position); ecs_add_id(world, e, Tag); test_assert(ecs_has_id(world, e, Tag)); ecs_fini(world); } void Prefab_get_type_after_base_add(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ecs_entity_t base = ecs_new(world, Position); test_assert(base != 0); test_assert( ecs_get_type(world, base) != NULL); ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, base); test_assert(e != 0); test_assert( ecs_get_type(world, base) != NULL); ecs_fini(world); } void Prefab_get_type_after_recycled_base_add(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ecs_entity_t base = ecs_new(world, 0); test_assert(base != 0); test_assert( ecs_get_type(world, base) == NULL); ecs_delete(world, base); test_assert( !ecs_is_alive(world, base)); base = ecs_new(world, Position); test_assert(base != 0); test_assert(ecs_entity_t_lo(base) != base); // Ensure recycled test_assert( ecs_get_type(world, base) != NULL); ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, base); test_assert(e != 0); test_assert( ecs_get_type(world, base) != NULL); ecs_fini(world); } void Prefab_new_w_recycled_base(void) { ecs_world_t *world = ecs_init(); ecs_entity_t base = ecs_new(world, 0); test_assert(base != 0); ecs_delete(world, base); test_assert( !ecs_is_alive(world, base)); base = ecs_new(world, 0); test_assert(base != 0); test_assert(ecs_entity_t_lo(base) != base); // Ensure recycled ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, base); test_assert(e != 0); test_assert( ecs_has_pair(world, e, EcsIsA, base)); ecs_fini(world); } void Prefab_add_recycled_base(void) { ecs_world_t *world = ecs_init(); ecs_entity_t base = ecs_new(world, 0); test_assert(base != 0); ecs_delete(world, base); test_assert( !ecs_is_alive(world, base)); base = ecs_new(world, 0); test_assert(base != 0); test_assert(ecs_entity_t_lo(base) != base); // Ensure recycled ecs_entity_t e = ecs_new(world, 0); test_assert(e != 0); ecs_add_pair(world, e, EcsIsA, base); test_assert( ecs_has_pair(world, e, EcsIsA, base)); ecs_fini(world); } void Prefab_remove_recycled_base(void) { ecs_world_t *world = ecs_init(); ecs_entity_t base = ecs_new(world, 0); test_assert(base != 0); ecs_delete(world, base); test_assert( !ecs_is_alive(world, base)); base = ecs_new(world, 0); test_assert(base != 0); test_assert(ecs_entity_t_lo(base) != base); // Ensure recycled ecs_entity_t e = ecs_new(world, 0); test_assert(e != 0); ecs_add_pair(world, e, EcsIsA, base); test_assert( ecs_has_pair(world, e, EcsIsA, base)); ecs_remove_pair(world, e, EcsIsA, base); test_assert( !ecs_has_pair(world, e, EcsIsA, base)); ecs_fini(world); } void Prefab_get_from_recycled_base(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ecs_entity_t base = ecs_new(world, 0); test_assert(base != 0); ecs_delete(world, base); test_assert( !ecs_is_alive(world, base)); base = ecs_set(world, 0, Position, {10, 20}); test_assert(base != 0); test_assert(ecs_entity_t_lo(base) != base); // Ensure recycled test_assert( ecs_get_type(world, base) != NULL); ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, base); test_assert(e != 0); test_assert( ecs_has_pair(world, e, EcsIsA, base)); test_assert( ecs_has(world, e, Position)); test_assert( !ecs_owns(world, e, Position)); const Position *p = ecs_get(world, e, Position); test_assert(p != NULL); test_int(p->x, 10); test_int(p->y, 20); test_assert(p == ecs_get(world, base, Position)); ecs_fini(world); } void Prefab_override_from_recycled_base(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ecs_entity_t base = ecs_new(world, 0); test_assert(base != 0); ecs_delete(world, base); test_assert( !ecs_is_alive(world, base)); base = ecs_set(world, 0, Position, {10, 20}); test_assert(base != 0); test_assert(ecs_entity_t_lo(base) != base); // Ensure recycled ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, base); test_assert(e != 0); test_assert( ecs_has_pair(world, e, EcsIsA, base)); test_assert( ecs_has(world, e, Position)); test_assert( !ecs_owns(world, e, Position)); ecs_add(world, e, Position); test_assert( ecs_has(world, e, Position)); test_assert( ecs_owns(world, e, Position)); const Position *p = ecs_get(world, e, Position); test_assert(p != NULL); test_int(p->x, 10); test_int(p->y, 20); ecs_fini(world); } void Prefab_remove_override_from_recycled_base(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ecs_entity_t base = ecs_new(world, 0); test_assert(base != 0); ecs_delete(world, base); test_assert( !ecs_is_alive(world, base)); base = ecs_set(world, 0, Position, {10, 20}); test_assert(base != 0); test_assert(ecs_entity_t_lo(base) != base); // Ensure recycled ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, base); test_assert(e != 0); test_assert( ecs_has_pair(world, e, EcsIsA, base)); test_assert( ecs_has(world, e, Position)); test_assert( !ecs_owns(world, e, Position)); ecs_add(world, e, Position); test_assert( ecs_has(world, e, Position)); test_assert( ecs_owns(world, e, Position)); ecs_remove(world, e, Position); test_assert( ecs_has(world, e, Position)); test_assert( !ecs_owns(world, e, Position)); ecs_fini(world); } void Prefab_instantiate_tree_from_recycled_base(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ecs_entity_t base = ecs_new_w_id(world, EcsPrefab); test_assert(base != 0); ecs_delete(world, base); test_assert( !ecs_is_alive(world, base)); base = ecs_set(world, 0, Position, {10, 20}); test_assert(base != 0); ecs_add_id(world, base, EcsPrefab); ecs_entity_t base_child = ecs_new_w_pair(world, EcsChildOf, base); test_assert(base_child != 0); ecs_set_name(world, base_child, "Child"); ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, base); test_assert(e != 0); test_assert( ecs_has_pair(world, e, EcsIsA, base)); test_assert( ecs_has(world, e, Position)); test_assert( !ecs_owns(world, e, Position)); const Position *p = ecs_get(world, e, Position); test_assert(p != NULL); test_int(p->x, 10); test_int(p->y, 20); test_assert(p == ecs_get(world, base, Position)); ecs_entity_t instance_child = ecs_lookup_child(world, e, "Child"); test_assert(instance_child != 0); test_assert( ecs_has_pair(world, instance_child, EcsChildOf, e)); ecs_fini(world); } void Prefab_rematch_after_add_to_recycled_base(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_TAG(world, Tag); ecs_query_t *q = ecs_query_new(world, "Tag, Position(up)"); ecs_entity_t base = ecs_new(world, 0); test_assert(base != 0); ecs_delete(world, base); test_assert( !ecs_is_alive(world, base)); base = ecs_new(world, 0); test_assert(base != 0); ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, base); test_assert(e != 0); test_assert( ecs_has_pair(world, e, EcsIsA, base)); ecs_add(world, e, Tag); ecs_iter_t it = ecs_query_iter(world, q); test_bool(ecs_query_next(&it), false); ecs_set(world, base, Position, {10, 20}); ecs_progress(world, 0); it = ecs_query_iter(world, q); test_bool(ecs_query_next(&it), true); test_int(it.count, 1); const Position *p = ecs_field(&it, Position, 2); test_assert(p != NULL); test_int(p->x, 10); test_int(p->y, 20); test_assert(ecs_field_src(&it, 2) == base); test_bool(ecs_query_next(&it), false); ecs_fini(world); } void Prefab_get_tag_from_2nd_base(void) { ecs_world_t *world = ecs_init(); ECS_TAG(world, Tag); ecs_entity_t base_1 = ecs_new_id(world); ecs_entity_t base_2 = ecs_new_w_id(world, Tag); ecs_entity_t e = ecs_new_id(world); ecs_add_pair(world, e, EcsIsA, base_1); ecs_add_pair(world, e, EcsIsA, base_2); test_assert(ecs_has_pair(world, e, EcsIsA, base_1)); test_assert(ecs_has_pair(world, e, EcsIsA, base_2)); test_assert(ecs_has_id(world, e, Tag)); ecs_fini(world); } void Prefab_get_component_from_2nd_base(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ecs_entity_t base_1 = ecs_new_id(world); ecs_entity_t base_2 = ecs_new(world, Position); ecs_entity_t e = ecs_new_id(world); ecs_add_pair(world, e, EcsIsA, base_1); ecs_add_pair(world, e, EcsIsA, base_2); test_assert(ecs_has_pair(world, e, EcsIsA, base_1)); test_assert(ecs_has_pair(world, e, EcsIsA, base_2)); test_assert(ecs_has(world, e, Position)); const Position *p = ecs_get(world, e, Position); test_assert(p != NULL); test_assert(p == ecs_get(world, base_2, Position)); ecs_fini(world); } void Prefab_get_component_from_1st_base(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ecs_entity_t base_1 = ecs_new(world, Position); ecs_entity_t base_2 = ecs_new(world, Position); ecs_entity_t e = ecs_new_id(world); ecs_add_pair(world, e, EcsIsA, base_1); ecs_add_pair(world, e, EcsIsA, base_2); test_assert(ecs_has_pair(world, e, EcsIsA, base_1)); test_assert(ecs_has_pair(world, e, EcsIsA, base_2)); test_assert(ecs_has(world, e, Position)); const Position *p = ecs_get(world, e, Position); test_assert(p != NULL); test_assert(p == ecs_get(world, base_1, Position)); ecs_fini(world); } void Prefab_get_component_from_2nd_base_of_base(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ecs_entity_t base_1 = ecs_new_id(world); ecs_entity_t base_2 = ecs_new(world, Position); ecs_entity_t base_3 = ecs_new_id(world); ecs_add_pair(world, base_3, EcsIsA, base_1); ecs_add_pair(world, base_3, EcsIsA, base_2); ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, base_3); test_assert(ecs_has_pair(world, e, EcsIsA, base_1)); test_assert(ecs_has_pair(world, e, EcsIsA, base_2)); test_assert(ecs_has(world, e, Position)); const Position *p = ecs_get(world, e, Position); test_assert(p != NULL); test_assert(p == ecs_get(world, base_2, Position)); ecs_fini(world); } void Prefab_get_component_from_1st_base_of_base(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ecs_entity_t base_1 = ecs_new(world, Position); ecs_entity_t base_2 = ecs_new(world, Position); ecs_entity_t base_3 = ecs_new_id(world); ecs_add_pair(world, base_3, EcsIsA, base_1); ecs_add_pair(world, base_3, EcsIsA, base_2); ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, base_3); test_assert(ecs_has_pair(world, e, EcsIsA, base_1)); test_assert(ecs_has_pair(world, e, EcsIsA, base_2)); test_assert(ecs_has(world, e, Position)); const Position *p = ecs_get(world, e, Position); test_assert(p != NULL); test_assert(p == ecs_get(world, base_1, Position)); ecs_fini(world); } void Prefab_get_component_from_2nd_base_prefab_base(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_PREFAB(world, base_1, 0); ECS_PREFAB(world, base_2, Position); ecs_entity_t e = ecs_new_id(world); ecs_add_pair(world, e, EcsIsA, base_1); ecs_add_pair(world, e, EcsIsA, base_2); test_assert(ecs_has_pair(world, e, EcsIsA, base_1)); test_assert(ecs_has_pair(world, e, EcsIsA, base_2)); test_assert(ecs_has(world, e, Position)); const Position *p = ecs_get(world, e, Position); test_assert(p != NULL); test_assert(p == ecs_get(world, base_2, Position)); ecs_fini(world); } void Prefab_get_component_from_1st_base_prefab_base(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_PREFAB(world, base_1, Position); ECS_PREFAB(world, base_2, Position); ecs_entity_t e = ecs_new_id(world); ecs_add_pair(world, e, EcsIsA, base_1); ecs_add_pair(world, e, EcsIsA, base_2); test_assert(ecs_has_pair(world, e, EcsIsA, base_1)); test_assert(ecs_has_pair(world, e, EcsIsA, base_2)); test_assert(ecs_has(world, e, Position)); const Position *p = ecs_get(world, e, Position); test_assert(p != NULL); test_assert(p == ecs_get(world, base_1, Position)); ecs_fini(world); } void Prefab_get_component_from_2nd_base_of_base_prefab_base(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_PREFAB(world, base_1, 0); ECS_PREFAB(world, base_2, Position); ECS_PREFAB(world, base_3, (IsA, base_1), (IsA, base_2)); ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, base_3); test_assert(ecs_has_pair(world, e, EcsIsA, base_1)); test_assert(ecs_has_pair(world, e, EcsIsA, base_2)); test_assert(ecs_has(world, e, Position)); const Position *p = ecs_get(world, e, Position); test_assert(p != NULL); test_assert(p == ecs_get(world, base_2, Position)); ecs_fini(world); } void Prefab_get_component_from_1st_base_of_base_prefab_base(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_PREFAB(world, base_1, Position); ECS_PREFAB(world, base_2, Position); ECS_PREFAB(world, base_3, (IsA, base_1), (IsA, base_2)); ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, base_3); test_assert(ecs_has_pair(world, e, EcsIsA, base_1)); test_assert(ecs_has_pair(world, e, EcsIsA, base_2)); test_assert(ecs_has(world, e, Position)); const Position *p = ecs_get(world, e, Position); test_assert(p != NULL); test_assert(p == ecs_get(world, base_1, Position)); ecs_fini(world); } void Prefab_fail_on_override_final(void) { install_test_abort(); ecs_world_t *world = ecs_init(); ecs_entity_t base = ecs_new_w_id(world, EcsFinal); test_expect_abort(); ecs_new_w_pair(world, EcsIsA, base); ecs_fini(world); } static int child_count(ecs_world_t *world, ecs_entity_t e) { int32_t count = 0; ecs_iter_t it = ecs_term_iter(world, &(ecs_term_t){ ecs_pair(EcsChildOf, e )}); while (ecs_term_next(&it)) { count += it.count; } return count; } void Prefab_instantiate_tree_once(void) { ecs_world_t *world = ecs_init(); ECS_PREFAB(world, Cannon, 0); ECS_PREFAB(world, Turret, 0); ECS_PREFAB(world, CannonA, (IsA, Cannon), (ChildOf, Turret)); ECS_PREFAB(world, CannonB, (IsA, Cannon), (ChildOf, Turret)); ECS_PREFAB(world, SpaceShip, 0); ECS_PREFAB(world, TurretA, (IsA, Turret), (ChildOf, SpaceShip)); ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, SpaceShip); test_assert(inst != 0); test_int(1, child_count(world, inst)); ecs_entity_t turret_a = ecs_lookup_child(world, inst, "TurretA"); test_assert(turret_a != 0); test_int(2, child_count(world, turret_a)); ecs_fini(world); } void Prefab_nested_prefab_w_named_children(void) { ecs_world_t *world = ecs_init(); ECS_PREFAB(world, Cannon, 0); ECS_PREFAB(world, Turret, 0); ecs_set_scope(world, Turret); ECS_ENTITY(world, CannonA, (IsA, Cannon)); ecs_set_scope(world, 0); ECS_PREFAB(world, SpaceShip, 0); ecs_set_scope(world, SpaceShip); ECS_PREFAB(world, TurretA, (IsA, Turret)); ecs_set_scope(world, 0); test_assert( ecs_has_pair(world, CannonA, EcsChildOf, Turret)); test_assert( ecs_has_pair(world, CannonA, EcsIsA, Cannon)); test_str("CannonA", ecs_get_name(world, CannonA)); test_assert( ecs_has_pair(world, TurretA, EcsChildOf, SpaceShip)); test_assert( ecs_has_pair(world, TurretA, EcsIsA, Turret)); test_str("TurretA", ecs_get_name(world, TurretA)); ecs_fini(world); } void Prefab_dont_copy_children_for_non_prefab_base(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_ENTITY(world, Base, Position); ECS_ENTITY(world, Child, (ChildOf, Base)); ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, Base); test_assert(e != 0); test_assert(ecs_get(world, e, Position) != NULL); test_assert(ecs_lookup_child(world, e, "Child") == 0); ecs_fini(world); } void Prefab_get_component_pair_from_base(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_TAG(world, Obj); ecs_entity_t base = ecs_set_pair(world, 0, Position, Obj, {10, 20}); test_assert(ecs_has_pair(world, base, ecs_id(Position), Obj)); ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, base); test_assert(ecs_has_pair(world, inst, ecs_id(Position), Obj)); const Position *p = ecs_get_pair(world, inst, Position, Obj); test_assert(p != NULL); test_int(p->x, 10); test_int(p->y, 20); test_assert(p == ecs_get_pair(world, base, Position, Obj)); ecs_fini(world); } void Prefab_get_component_pair_from_prefab_base(void) { ecs_world_t *world = ecs_init(); ECS_COMPONENT(world, Position); ECS_TAG(world, Obj); ecs_entity_t base = ecs_new_w_id(world, EcsPrefab); ecs_set_pair(world, base, Position, Obj, {10, 20}); test_assert(ecs_has_pair(world, base, ecs_id(Position), Obj)); ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, base); test_assert(ecs_has_pair(world, inst, ecs_id(Position), Obj)); const Position *p = ecs_get_pair(world, inst, Position, Obj); test_assert(p != NULL); test_int(p->x, 10); test_int(p->y, 20); test_assert(p == ecs_get_pair(world, base, Position, Obj)); ecs_fini(world); } void Prefab_override_dont_inherit(void) { ecs_world_t *world = ecs_mini(); ECS_COMPONENT(world, Position); ecs_add_id(world, ecs_id(Position), EcsDontInherit); ecs_set_hooks(world, Position, { .ctor = ecs_default_ctor }); ecs_entity_t base = ecs_set(world, 0, Position, {10, 20}); ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, base); test_assert( !ecs_has(world, inst, Position)); ecs_add(world, inst, Position); test_assert( ecs_has(world, inst, Position)); const Position *p = ecs_get(world, inst, Position); test_int(p->x, 0); test_int(p->y, 0); ecs_fini(world); } void Prefab_prefab_w_switch(void) { ecs_world_t *world = ecs_mini(); ECS_ENTITY(world, Movement, Union); ECS_TAG(world, Walking); ECS_TAG(world, Running); ecs_entity_t p = ecs_new_w_pair(world, Movement, Running); test_assert( ecs_has_pair(world, p, Movement, Running)); ecs_entity_t i = ecs_new_w_pair(world, EcsIsA, p); test_assert( ecs_has_pair(world, i, Movement, Running)); test_assert( !ecs_has_pair(world, i, Movement, Walking)); ecs_fini(world); } void Prefab_prefab_child_w_dont_inherit_component(void) { ecs_world_t *world = ecs_mini(); ECS_ENTITY(world, TagA, DontInherit); ECS_TAG(world, TagB); ecs_entity_t base = ecs_new_prefab(world, "Base"); ecs_entity_t base_child = ecs_new_prefab(world, "Base.Child"); ecs_add(world, base_child, TagA); ecs_add(world, base_child, TagB); test_assert(base != 0); test_assert(base_child != 0); ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, base); test_assert(inst != 0); ecs_entity_t inst_child = ecs_lookup_child(world, inst, "Child"); test_assert(inst_child != 0); test_assert(!ecs_has(world, inst_child, TagA)); test_assert(ecs_has(world, inst_child, TagB)); ecs_fini(world); } void Prefab_prefab_child_override(void) { ecs_world_t *world = ecs_mini(); ECS_TAG(world, Foo); ECS_TAG(world, Bar); ecs_entity_t turret = ecs_new_prefab(world, "Turret"); ecs_entity_t turret_head = ecs_new_prefab(world, "Turret.Head"); ecs_add(world, turret_head, Foo); ecs_entity_t railgun = ecs_new_prefab(world, "Railgun"); ecs_add_pair(world, railgun, EcsIsA, turret); ecs_entity_t railgun_head = ecs_new_prefab(world, "Railgun.Head"); ecs_add(world, railgun_head, Bar); ecs_entity_t inst = ecs_new_entity(world, "inst"); ecs_add_pair(world, inst, EcsIsA, railgun); ecs_entity_t head = ecs_lookup_child(world, inst, "Head"); test_assert(head != 0); test_assert(ecs_has(world, head, Foo)); test_assert(ecs_has(world, head, Bar)); ecs_fini(world); } void Prefab_prefab_child_override_w_exclusive_pair(void) { ecs_world_t *world = ecs_mini(); ECS_ENTITY(world, Rel, Exclusive); ECS_TAG(world, ObjA); ECS_TAG(world, ObjB); ecs_entity_t turret = ecs_new_prefab(world, "Turret"); ecs_entity_t turret_head = ecs_new_prefab(world, "Turret.Head"); ecs_add_pair(world, turret_head, Rel, ObjA); test_assert(ecs_has_pair(world, turret_head, Rel, ObjA)); ecs_entity_t railgun = ecs_new_prefab(world, "Railgun"); ecs_add_pair(world, railgun, EcsIsA, turret); ecs_entity_t railgun_head = ecs_new_prefab(world, "Railgun.Head"); ecs_add_pair(world, railgun_head, Rel, ObjB); test_assert(!ecs_has_pair(world, railgun_head, Rel, ObjA)); test_assert(ecs_has_pair(world, railgun_head, Rel, ObjB)); ecs_entity_t inst = ecs_new_entity(world, "inst"); ecs_add_pair(world, inst, EcsIsA, railgun); ecs_entity_t head = ecs_lookup_child(world, inst, "Head"); test_assert(head != 0); test_assert(!ecs_has_pair(world, head, Rel, ObjA)); test_assert(ecs_has_pair(world, head, Rel, ObjB)); ecs_fini(world); } void Prefab_prefab_1_slot(void) { ecs_world_t *world = ecs_mini(); ecs_entity_t base = ecs_new_prefab(world, "Base"); ecs_entity_t base_slot = ecs_new_prefab(world, "Base.Slot"); ecs_add_pair(world, base_slot, EcsSlotOf, base); test_assert(ecs_has_pair(world, base_slot, EcsChildOf, base)); test_assert(ecs_has_pair(world, base_slot, EcsSlotOf, base)); ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, base); test_assert(inst != 0); ecs_entity_t inst_slot = ecs_get_target(world, inst, base_slot, 0); test_assert(inst_slot != 0); test_str(ecs_get_name(world, inst_slot), "Slot"); test_assert(!ecs_has_pair(world, inst_slot, EcsSlotOf, EcsWildcard)); test_assert(ecs_has_pair(world, inst_slot, EcsChildOf, inst)); ecs_fini(world); } void Prefab_prefab_2_slots(void) { ecs_world_t *world = ecs_mini(); ecs_entity_t base = ecs_new_prefab(world, "Base"); ecs_entity_t base_slot_a = ecs_new_prefab(world, "Base.SlotA"); ecs_entity_t base_slot_b = ecs_new_prefab(world, "Base.SlotB"); ecs_add_pair(world, base_slot_a, EcsSlotOf, base); ecs_add_pair(world, base_slot_b, EcsSlotOf, base); test_assert(ecs_has_pair(world, base_slot_a, EcsChildOf, base)); test_assert(ecs_has_pair(world, base_slot_a, EcsSlotOf, base)); test_assert(ecs_has_pair(world, base_slot_b, EcsChildOf, base)); test_assert(ecs_has_pair(world, base_slot_b, EcsSlotOf, base)); ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, base); test_assert(inst != 0); ecs_entity_t inst_slot_a = ecs_get_target(world, inst, base_slot_a, 0); test_assert(inst_slot_a != 0); test_str(ecs_get_name(world, inst_slot_a), "SlotA"); test_assert(!ecs_has_pair(world, inst_slot_a, EcsSlotOf, EcsWildcard)); test_assert(ecs_has_pair(world, inst_slot_a, EcsChildOf, inst)); ecs_entity_t inst_slot_b = ecs_get_target(world, inst, base_slot_b, 0); test_assert(inst_slot_b != 0); test_str(ecs_get_name(world, inst_slot_b), "SlotB"); test_assert(!ecs_has_pair(world, inst_slot_b, EcsSlotOf, EcsWildcard)); test_assert(ecs_has_pair(world, inst_slot_b, EcsChildOf, inst)); ecs_fini(world); } void Prefab_prefab_w_nested_slot(void) { ecs_world_t *world = ecs_mini(); ecs_entity_t base = ecs_new_prefab(world, "Base"); ecs_entity_t base_slot = ecs_new_prefab(world, "Base.Slot"); ecs_entity_t base_slot_slot = ecs_new_prefab(world, "Base.Slot.Slot"); ecs_add_pair(world, base_slot, EcsSlotOf, base); ecs_add_pair(world, base_slot_slot, EcsSlotOf, base); test_assert(ecs_has_pair(world, base_slot, EcsChildOf, base)); test_assert(ecs_has_pair(world, base_slot, EcsSlotOf, base)); test_assert(ecs_has_pair(world, base_slot_slot, EcsChildOf, base_slot)); test_assert(ecs_has_pair(world, base_slot_slot, EcsSlotOf, base)); ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, base); test_assert(inst != 0); ecs_entity_t inst_slot = ecs_get_target(world, inst, base_slot, 0); test_assert(inst_slot != 0); test_str(ecs_get_name(world, inst_slot), "Slot"); test_assert(!ecs_has_pair(world, inst_slot, EcsSlotOf, EcsWildcard)); test_assert(ecs_has_pair(world, inst_slot, EcsChildOf, inst)); ecs_entity_t inst_slot_slot = ecs_get_target(world, inst, base_slot_slot, 0); test_assert(inst_slot_slot != 0); test_assert(inst_slot_slot != inst_slot); test_str(ecs_get_name(world, inst_slot_slot), "Slot"); test_assert(!ecs_has_pair(world, inst_slot_slot, EcsSlotOf, EcsWildcard)); test_assert(ecs_has_pair(world, inst_slot_slot, EcsChildOf, inst_slot)); ecs_fini(world); } void Prefab_prefab_w_mixed_slots(void) { ecs_world_t *world = ecs_mini(); ecs_entity_t base = ecs_new_prefab(world, "Base"); ecs_entity_t base_slot = ecs_new_prefab(world, "Base.Slot"); ecs_entity_t base_slot_slot = ecs_new_prefab(world, "Base.Slot.Slot"); ecs_add_pair(world, base_slot, EcsSlotOf, base); ecs_add_pair(world, base_slot_slot, EcsSlotOf, base_slot); test_assert(ecs_has_pair(world, base_slot, EcsChildOf, base)); test_assert(ecs_has_pair(world, base_slot, EcsSlotOf, base)); test_assert(ecs_has_pair(world, base_slot_slot, EcsChildOf, base_slot)); test_assert(ecs_has_pair(world, base_slot_slot, EcsSlotOf, base_slot)); ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, base); test_assert(inst != 0); ecs_entity_t inst_slot = ecs_get_target(world, inst, base_slot, 0); test_assert(inst_slot != 0); test_str(ecs_get_name(world, inst_slot), "Slot"); test_assert(!ecs_has_pair(world, inst_slot, EcsSlotOf, EcsWildcard)); test_assert(ecs_has_pair(world, inst_slot, EcsChildOf, inst)); ecs_entity_t inst_slot_slot = ecs_get_target(world, inst, base_slot_slot, 0); test_assert(inst_slot_slot == 0); inst_slot_slot = ecs_get_target(world, inst_slot, base_slot_slot, 0); test_assert(inst_slot_slot != 0); test_assert(inst_slot_slot != inst_slot); test_str(ecs_get_name(world, inst_slot_slot), "Slot"); test_assert(!ecs_has_pair(world, inst_slot_slot, EcsSlotOf, EcsWildcard)); test_assert(ecs_has_pair(world, inst_slot_slot, EcsChildOf, inst_slot)); ecs_fini(world); } void Prefab_prefab_variant_w_slot(void) { ecs_world_t *world = ecs_mini(); ecs_entity_t base = ecs_new_prefab(world, "Base"); ecs_entity_t variant = ecs_new_prefab(world, "Variant"); ecs_entity_t variant_slot = ecs_new_prefab(world, "Variant.Slot"); ecs_add_pair(world, variant, EcsIsA, base); ecs_add_pair(world, variant_slot, EcsSlotOf, variant); test_assert(ecs_has_pair(world, variant_slot, EcsChildOf, variant)); test_assert(ecs_has_pair(world, variant_slot, EcsSlotOf, variant)); ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, variant); test_assert(inst != 0); ecs_entity_t inst_slot = ecs_get_target(world, inst, variant_slot, 0); test_assert(inst_slot != 0); test_str(ecs_get_name(world, inst_slot), "Slot"); test_assert(!ecs_has_pair(world, inst_slot, EcsSlotOf, EcsWildcard)); test_assert(ecs_has_pair(world, inst_slot, EcsChildOf, inst)); ecs_fini(world); } void Prefab_prefab_variant_w_base_slot(void) { ecs_world_t *world = ecs_mini(); ecs_entity_t base = ecs_new_prefab(world, "Base"); ecs_entity_t base_slot = ecs_new_prefab(world, "Base.Slot"); ecs_add_pair(world, base_slot, EcsSlotOf, base); test_assert(ecs_has_pair(world, base_slot, EcsChildOf, base)); test_assert(ecs_has_pair(world, base_slot, EcsSlotOf, base)); ecs_entity_t variant = ecs_new_prefab(world, "Variant"); ecs_add_pair(world, variant, EcsIsA, base); ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, variant); test_assert(inst != 0); ecs_entity_t inst_slot = ecs_get_target(world, inst, base_slot, 0); test_assert(inst_slot != 0); test_str(ecs_get_name(world, inst_slot), "Slot"); test_assert(!ecs_has_pair(world, inst_slot, EcsSlotOf, EcsWildcard)); test_assert(ecs_has_pair(world, inst_slot, EcsChildOf, inst)); ecs_fini(world); } void Prefab_prefab_variant_w_mixed_slots(void) { ecs_world_t *world = ecs_mini(); ecs_entity_t base = ecs_new_prefab(world, "Base"); ecs_entity_t base_slot = ecs_new_prefab(world, "Base.BaseSlot"); ecs_add_pair(world, base_slot, EcsSlotOf, base); test_assert(ecs_has_pair(world, base_slot, EcsChildOf, base)); test_assert(ecs_has_pair(world, base_slot, EcsSlotOf, base)); ecs_entity_t variant = ecs_new_prefab(world, "Variant"); ecs_add_pair(world, variant, EcsIsA, base); ecs_entity_t variant_slot = ecs_new_prefab(world, "Variant.VariantSlot"); ecs_add_pair(world, variant, EcsIsA, base); ecs_add_pair(world, variant_slot, EcsSlotOf, variant); test_assert(ecs_has_pair(world, variant_slot, EcsChildOf, variant)); test_assert(ecs_has_pair(world, variant_slot, EcsSlotOf, variant)); ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, variant); test_assert(inst != 0); ecs_entity_t inst_base_slot = ecs_get_target(world, inst, base_slot, 0); test_assert(inst_base_slot != 0); test_str(ecs_get_name(world, inst_base_slot), "BaseSlot"); test_assert(!ecs_has_pair(world, inst_base_slot, EcsSlotOf, EcsWildcard)); test_assert(ecs_has_pair(world, inst_base_slot, EcsChildOf, inst)); ecs_entity_t inst_variant_slot = ecs_get_target(world, inst, variant_slot, 0); test_assert(inst_variant_slot != 0); test_assert(inst_variant_slot != inst_base_slot); test_str(ecs_get_name(world, inst_variant_slot), "VariantSlot"); test_assert(!ecs_has_pair(world, inst_variant_slot, EcsSlotOf, EcsWildcard)); test_assert(ecs_has_pair(world, inst_variant_slot, EcsChildOf, inst)); ecs_fini(world); } void Prefab_override_slot(void) { ecs_world_t *world = ecs_mini(); ecs_entity_t base = ecs_new_prefab(world, "Base"); ecs_entity_t base_slot = ecs_new_prefab(world, "Base.Slot"); ecs_add_pair(world, base_slot, EcsSlotOf, base); test_assert(ecs_has_pair(world, base_slot, EcsChildOf, base)); test_assert(ecs_has_pair(world, base_slot, EcsSlotOf, base)); ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, base); test_assert(inst != 0); ecs_entity_t inst_slot = ecs_get_target(world, inst, base_slot, 0); test_assert(inst_slot != 0); test_str(ecs_get_name(world, inst_slot), "Slot"); test_assert(!ecs_has_pair(world, inst_slot, EcsSlotOf, EcsWildcard)); test_assert(ecs_has_pair(world, inst_slot, EcsChildOf, inst)); ecs_entity_t slot_override = ecs_new_id(world); ecs_add_pair(world, inst, base_slot, slot_override); test_assert(ecs_has_pair(world, inst, base_slot, slot_override)); test_assert(!ecs_has_pair(world, inst, base_slot, inst_slot)); ecs_fini(world); } void Prefab_2_instances_w_slots_same_table(void) { ecs_world_t *world = ecs_mini(); ecs_entity_t base = ecs_new_prefab(world, "Base"); ecs_entity_t base_slot = ecs_new_prefab(world, "Base.Slot"); ecs_add_pair(world, base_slot, EcsSlotOf, base); test_assert(ecs_has_pair(world, base_slot, EcsChildOf, base)); test_assert(ecs_has_pair(world, base_slot, EcsSlotOf, base)); ecs_entity_t inst_1 = ecs_new_w_pair(world, EcsIsA, base); test_assert(inst_1 != 0); ecs_entity_t inst_2 = ecs_new_w_pair(world, EcsIsA, base); test_assert(inst_2 != 0); ecs_entity_t slot_1 = ecs_get_target(world, inst_1, base_slot, 0); test_assert(slot_1 != 0); ecs_entity_t slot_2 = ecs_get_target(world, inst_2, base_slot, 0); test_assert(slot_2 != 0); test_assert(slot_1 != slot_2); /* Make sure slots don't fragment */ test_assert(ecs_get_table(world, inst_1) == ecs_get_table(world, inst_2)); ecs_fini(world); } void Prefab_slot_has_union(void) { ecs_world_t *world = ecs_mini(); ecs_entity_t base = ecs_new_prefab(world, "Base"); ecs_entity_t base_slot = ecs_new_prefab(world, "Base.Slot"); ecs_add_pair(world, base_slot, EcsSlotOf, base); test_assert(ecs_has_pair(world, base_slot, EcsChildOf, base)); test_assert(ecs_has_pair(world, base_slot, EcsSlotOf, base)); ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, base); test_assert(inst != 0); ecs_entity_t inst_slot = ecs_get_target(world, inst, base_slot, 0); test_assert(inst_slot != 0); test_assert(base_slot != 0); test_assert( ecs_has_id(world, base_slot, EcsUnion)); test_assert( !ecs_has_id(world, inst_slot, EcsUnion)); ecs_fini(world); } void Prefab_slot_override(void) { ecs_world_t *world = ecs_mini(); ecs_entity_t turret = ecs_new_prefab(world, "Turret"); ecs_entity_t turret_base = ecs_new_prefab(world, "Turret.Base"); ecs_add_pair(world, turret_base, EcsSlotOf, turret); ecs_entity_t turret_head = ecs_new_prefab(world, "Turret.Head"); ecs_add_pair(world, turret_head, EcsSlotOf, turret); ecs_entity_t railgun = ecs_new_prefab(world, "Railgun"); ecs_add_pair(world, railgun, EcsIsA, turret); ecs_entity_t railgun_head = ecs_new_prefab(world, "Railgun.Head"); test_assert(ecs_has_pair(world, railgun_head, EcsSlotOf, turret)); ecs_add_pair(world, railgun_head, EcsSlotOf, railgun); test_assert(ecs_has_pair(world, railgun_head, EcsSlotOf, railgun)); test_assert(!ecs_has_pair(world, railgun_head, EcsSlotOf, turret)); ecs_entity_t railgun_beam = ecs_new_prefab(world, "Railgun.Beam"); ecs_add_pair(world, railgun_beam, EcsSlotOf, railgun); ecs_entity_t inst = ecs_new_entity(world, "inst"); ecs_add_pair(world, inst, EcsIsA, railgun); ecs_entity_t head = ecs_get_target(world, inst, turret_head, 0); ecs_entity_t head_r = ecs_get_target(world, inst, railgun_head, 0); ecs_entity_t base = ecs_get_target(world, inst, turret_base, 0); ecs_entity_t beam = ecs_get_target(world, inst, railgun_beam, 0); test_assert(head == 0); test_assert(head_r != 0); test_assert(base != 0); test_assert(beam != 0); char *path = ecs_get_fullpath(world, head_r); test_str(path, "inst.Head"); ecs_os_free(path); path = ecs_get_fullpath(world, base); test_str(path, "inst.Base"); ecs_os_free(path); path = ecs_get_fullpath(world, beam); test_str(path, "inst.Beam"); ecs_os_free(path); ecs_fini(world); } void Prefab_base_slot_override(void) { ecs_world_t *world = ecs_mini(); ecs_entity_t turret = ecs_new_prefab(world, "Turret"); ecs_entity_t turret_base = ecs_new_prefab(world, "Turret.Base"); ecs_add_pair(world, turret_base, EcsSlotOf, turret); ecs_entity_t turret_head = ecs_new_prefab(world, "Turret.Head"); ecs_add_pair(world, turret_head, EcsSlotOf, turret); ecs_entity_t railgun = ecs_new_prefab(world, "Railgun"); ecs_add_pair(world, railgun, EcsIsA, turret); ecs_entity_t railgun_head = ecs_new_prefab(world, "Railgun.Head"); test_assert(ecs_has_pair(world, railgun_head, EcsSlotOf, turret)); ecs_entity_t railgun_beam = ecs_new_prefab(world, "Railgun.Beam"); ecs_add_pair(world, railgun_beam, EcsSlotOf, railgun); ecs_entity_t inst = ecs_new_entity(world, "inst"); ecs_add_pair(world, inst, EcsIsA, railgun); ecs_entity_t head = ecs_get_target(world, inst, turret_head, 0); ecs_entity_t head_r = ecs_get_target(world, inst, railgun_head, 0); ecs_entity_t base = ecs_get_target(world, inst, turret_base, 0); ecs_entity_t beam = ecs_get_target(world, inst, railgun_beam, 0); test_assert(head != 0); test_assert(head_r == 0); test_assert(base != 0); test_assert(beam != 0); char *path = ecs_get_fullpath(world, head); test_str(path, "inst.Head"); ecs_os_free(path); path = ecs_get_fullpath(world, base); test_str(path, "inst.Base"); ecs_os_free(path); path = ecs_get_fullpath(world, beam); test_str(path, "inst.Beam"); ecs_os_free(path); ecs_fini(world); } void Prefab_prefab_child_w_union(void) { ecs_world_t *world = ecs_mini(); ECS_ENTITY(world, Rel, Union); ECS_TAG(world, TgtA); ECS_TAG(world, TgtB); ECS_TAG(world, TgtC); ecs_entity_t base = ecs_new_prefab(world, "Base"); ecs_entity_t base_child_a = ecs_new_prefab(world, "Base.ChildA"); ecs_entity_t base_child_b = ecs_new_prefab(world, "Base.ChildB"); ecs_entity_t base_child_c = ecs_new_prefab(world, "Base.ChildC"); ecs_add_pair(world, base_child_a, Rel, TgtA); ecs_add_pair(world, base_child_b, Rel, TgtB); ecs_add_pair(world, base_child_c, Rel, TgtC); ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, base); test_assert(inst != 0); ecs_entity_t child_a = ecs_lookup_child(world, inst, "ChildA"); ecs_entity_t child_b = ecs_lookup_child(world, inst, "ChildB"); ecs_entity_t child_c = ecs_lookup_child(world, inst, "ChildC"); test_assert(child_a != 0); test_assert(child_b != 0); test_assert(child_c != 0); test_assert(ecs_has_pair(world, child_a, Rel, TgtA)); test_assert(ecs_has_pair(world, child_b, Rel, TgtB)); test_assert(ecs_has_pair(world, child_c, Rel, TgtC)); ecs_fini(world); } void Prefab_override_twice_w_add(void) { ecs_world_t *world = ecs_mini(); ECS_COMPONENT(world, Position); ecs_entity_t base = ecs_new_id(world); ecs_set(world, base, Position, {10}); ecs_override(world, base, Position); ecs_entity_t e1 = ecs_new_w_pair(world, EcsIsA, base); ecs_set(world, e1, Position, { 20 }); ecs_entity_t e2 = ecs_new_w_pair(world, EcsIsA, base); ecs_add(world, e2, Position); const Position *ptr = ecs_get(world, e1, Position); test_assert(ptr != NULL); test_int(ptr->x, 20); ptr = ecs_get(world, e2, Position); test_assert(ptr != NULL); test_int(ptr->x, 10); ecs_fini(world); } void Prefab_override_twice_w_set(void) { ecs_world_t *world = ecs_mini(); ECS_COMPONENT(world, Position); ecs_entity_t base = ecs_new_id(world); ecs_set(world, base, Position, {10}); ecs_override(world, base, Position); ecs_entity_t e1 = ecs_new_w_pair(world, EcsIsA, base); ecs_set(world, e1, Position, { 20 }); ecs_entity_t e2 = ecs_new_w_pair(world, EcsIsA, base); ecs_set(world, e2, Position, {30}); const Position *ptr = ecs_get(world, e1, Position); test_assert(ptr != NULL); test_int(ptr->x, 20); ptr = ecs_get(world, e2, Position); test_assert(ptr != NULL); test_int(ptr->x, 30); ecs_fini(world); } static int position_copy_invoked = 0; static ECS_COPY(Position, dst, src, { dst->x = src->x; dst->y = src->y; position_copy_invoked ++; }) void Prefab_auto_override_copy_once(void) { ecs_world_t *world = ecs_mini(); ECS_COMPONENT(world, Position); ecs_set_hooks(world, Position, { .copy = ecs_copy(Position) }); ecs_entity_t base = ecs_new_id(world); ecs_set(world, base, Position, {10, 20}); ecs_override(world, base, Position); test_int(position_copy_invoked, 1); position_copy_invoked = 0; ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, base); const Position *ptr = ecs_get(world, inst, Position); test_assert(ptr != NULL); test_int(ptr->x, 10); test_int(ptr->y, 20); test_int(position_copy_invoked, 1); ecs_fini(world); } void Prefab_always_override(void) { ecs_world_t *world = ecs_mini(); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ecs_add_id(world, ecs_id(Position), EcsAlwaysOverride); ecs_entity_t b = ecs_new_id(world); ecs_set(world, b, Position, {10, 20}); ecs_set(world, b, Velocity, {1, 2}); ecs_entity_t i = ecs_new_w_pair(world, EcsIsA, b); test_assert(ecs_has(world, i, Position)); test_assert(ecs_has(world, i, Velocity)); test_assert(ecs_owns(world, i, Position)); test_assert(!ecs_owns(world, i, Velocity)); { const Position *ptr = ecs_get(world, i, Position); test_assert(ptr != NULL); test_int(ptr->x, 10); test_int(ptr->y, 20); } { const Velocity *ptr = ecs_get(world, i, Velocity); test_assert(ptr != NULL); test_int(ptr->x, 1); test_int(ptr->y, 2); } ecs_fini(world); } void Prefab_always_override_pair(void) { ecs_world_t *world = ecs_mini(); ECS_TAG(world, RelA); ECS_TAG(world, RelB); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); ecs_add_id(world, RelA, EcsAlwaysOverride); ecs_entity_t b = ecs_new_id(world); ecs_set_pair_second(world, b, RelA, Position, {10, 20}); ecs_set_pair_second(world, b, RelB, Velocity, {1, 2}); ecs_entity_t i = ecs_new_w_pair(world, EcsIsA, b); test_assert(ecs_has_pair(world, i, RelA, ecs_id(Position))); test_assert(ecs_has_pair(world, i, RelB, ecs_id(Velocity))); test_assert(ecs_owns_pair(world, i, RelA, ecs_id(Position))); test_assert(!ecs_owns_pair(world, i, RelB, ecs_id(Velocity))); { const Position *ptr = ecs_get_pair_second(world, i, RelA, Position); test_assert(ptr != NULL); test_int(ptr->x, 10); test_int(ptr->y, 20); } { const Velocity *ptr = ecs_get_pair_second(world, i, RelB, Velocity); test_assert(ptr != NULL); test_int(ptr->x, 1); test_int(ptr->y, 2); } ecs_fini(world); } void Prefab_child_of_prefab_is_prefab(void) { ecs_world_t *world = ecs_mini(); ecs_entity_t base = ecs_new_w_id(world, EcsPrefab); ecs_entity_t inst = ecs_new_w_pair(world, EcsChildOf, base); test_assert(ecs_has_id(world, inst, EcsPrefab)); ecs_entity_t inst_child = ecs_new_w_pair(world, EcsChildOf, inst); test_assert(ecs_has_id(world, inst_child, EcsPrefab)); ecs_fini(world); } void Prefab_override_exclusive(void) { ecs_world_t* ecs = ecs_mini(); ECS_ENTITY(ecs, Rel, Exclusive); ecs_entity_t t1 = ecs_new_id(ecs); ecs_entity_t t2 = ecs_new_id(ecs); ecs_entity_t e = ecs_new_id(ecs); ecs_add_pair(ecs, e, Rel, t1); ecs_entity_t p = ecs_new_id(ecs); ecs_override_pair(ecs, p, Rel, t2); ecs_add_pair(ecs, e, EcsIsA, p); test_assert(ecs_has_pair(ecs, e, Rel, t2)); test_assert(!ecs_has_pair(ecs, e, Rel, t1)); ecs_fini(ecs); } void Prefab_override_exclusive_2_lvls(void) { ecs_world_t* ecs = ecs_mini(); ECS_ENTITY(ecs, Rel, Exclusive); ecs_entity_t t1 = ecs_new_id(ecs); ecs_entity_t t2 = ecs_new_id(ecs); ecs_entity_t t3 = ecs_new_id(ecs); ecs_entity_t e = ecs_new_id(ecs); ecs_add_pair(ecs, e, Rel, t1); ecs_entity_t p = ecs_new_id(ecs); ecs_override_pair(ecs, p, Rel, t2); ecs_entity_t p2 = ecs_new_id(ecs); ecs_override_pair(ecs, p2, Rel, t3); ecs_add_pair(ecs, p2, EcsIsA, p); ecs_add_pair(ecs, e, EcsIsA, p2); test_assert(ecs_has_pair(ecs, e, Rel, t2)); test_assert(!ecs_has_pair(ecs, e, Rel, t1)); test_assert(!ecs_has_pair(ecs, e, Rel, t3)); ecs_fini(ecs); } static ecs_entity_t make_prefabs(ecs_world_t *ecs) { ecs_entity_t root = ecs_new_w_id(ecs, EcsPrefab); ecs_entity_t parent = ecs_new_w_pair(ecs, EcsChildOf, root); ecs_new_w_pair(ecs, EcsChildOf, parent); return root; } void Prefab_hierarchy_w_recycled_id(void) { ecs_world_t* ecs = ecs_mini(); { ecs_entity_t p = make_prefabs(ecs); test_assert(p != 0); ecs_entity_t i = ecs_new_w_pair(ecs, EcsIsA, p); test_assert(i != 0); ecs_delete(ecs, i); } { ecs_entity_t p = make_prefabs(ecs); test_assert(p != 0); ecs_entity_t i = ecs_new_w_pair(ecs, EcsIsA, p); test_assert(i != 0); } ecs_fini(ecs); }