1523 lines
36 KiB
C
1523 lines
36 KiB
C
#include <api.h>
|
|
#include <stdlib.h>
|
|
|
|
void World_setup(void) {
|
|
ecs_log_set_level(-3);
|
|
}
|
|
|
|
static
|
|
void Move(ecs_iter_t *it) {
|
|
Position *pos = ecs_field(it, Position, 1);
|
|
Velocity *vel = ecs_field(it, Velocity, 2);
|
|
probe_iter(it);
|
|
|
|
int row;
|
|
for (row = 0; row < it->count; row ++) {
|
|
Position *p = &pos[row];
|
|
Velocity *v = &vel[row];
|
|
p->x += v->x * it->delta_time;
|
|
p->y += v->y * it->delta_time;
|
|
}
|
|
}
|
|
|
|
void World_progress_w_0(void) {
|
|
ecs_world_t *world = ecs_init();
|
|
|
|
ECS_COMPONENT(world, Position);
|
|
ECS_COMPONENT(world, Velocity);
|
|
|
|
ECS_ENTITY(world, e1, Position, Velocity);
|
|
|
|
ECS_SYSTEM(world, Move, EcsOnUpdate, Position, Velocity);
|
|
|
|
Probe ctx = {0};
|
|
ecs_set_ctx(world, &ctx, NULL);
|
|
|
|
ecs_set(world, e1, Position, {0, 0});
|
|
ecs_set(world, e1, Velocity, {1, 2});
|
|
|
|
ecs_progress(world, 0);
|
|
|
|
test_int(ctx.count, 1);
|
|
test_int(ctx.invoked, 1);
|
|
test_int(ctx.system, Move);
|
|
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.c[0][1], ecs_id(Velocity));
|
|
test_int(ctx.s[0][0], 0);
|
|
test_int(ctx.s[0][1], 0);
|
|
|
|
const Position *p = ecs_get(world, e1, Position);
|
|
test_assert(p != NULL);
|
|
test_assert(p->x != 0);
|
|
test_assert(p->y != 0);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_progress_w_t(void) {
|
|
ecs_world_t *world = ecs_init();
|
|
|
|
ECS_COMPONENT(world, Position);
|
|
ECS_COMPONENT(world, Velocity);
|
|
|
|
ECS_ENTITY(world, e1, Position, Velocity);
|
|
|
|
ECS_SYSTEM(world, Move, EcsOnUpdate, Position, Velocity);
|
|
|
|
Probe ctx = {0};
|
|
ecs_set_ctx(world, &ctx, NULL);
|
|
|
|
ecs_set(world, e1, Position, {0, 0});
|
|
ecs_set(world, e1, Velocity, {1, 2});
|
|
|
|
ecs_progress(world, 2);
|
|
|
|
test_int(ctx.count, 1);
|
|
test_int(ctx.invoked, 1);
|
|
test_int(ctx.system, Move);
|
|
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.c[0][1], ecs_id(Velocity));
|
|
test_int(ctx.s[0][0], 0);
|
|
test_int(ctx.s[0][1], 0);
|
|
|
|
const Position *p = ecs_get(world, e1, Position);
|
|
test_assert(p != NULL);
|
|
test_int(p->x, 2);
|
|
test_int(p->y, 4);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_entity_range_offset(void) {
|
|
ecs_world_t *world = ecs_init();
|
|
|
|
ecs_set_entity_range(world, 5000, 0);
|
|
|
|
ecs_entity_t e = ecs_new(world, 0);
|
|
test_int(e, 5000);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_entity_range_offset_out_of_range(void) {
|
|
install_test_abort();
|
|
|
|
ecs_world_t *world = ecs_init();
|
|
|
|
ECS_COMPONENT(world, Position);
|
|
|
|
ecs_enable_range_check(world, true);
|
|
ecs_set_entity_range(world, 2000, 0);
|
|
|
|
test_expect_abort();
|
|
|
|
ecs_add(world, 1500, Position);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_entity_range_limit_out_of_range(void) {
|
|
install_test_abort();
|
|
|
|
ecs_world_t *world = ecs_init();
|
|
|
|
ECS_COMPONENT(world, Position);
|
|
|
|
ecs_enable_range_check(world, true);
|
|
ecs_set_entity_range(world, 0, 2000);
|
|
|
|
test_expect_abort();
|
|
|
|
ecs_add(world, 2500, Position);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_entity_range_out_of_range_check_disabled(void) {
|
|
ecs_world_t *world = ecs_init();
|
|
|
|
ECS_COMPONENT(world, Position);
|
|
|
|
ecs_ensure(world, 4999);
|
|
|
|
ecs_enable_range_check(world, false);
|
|
ecs_set_entity_range(world, 5000, 10000);
|
|
|
|
/* Validate that range is being used when issuing new ids */
|
|
ecs_entity_t e = ecs_new(world, 0);
|
|
test_int(e, 5000);
|
|
|
|
/* Validate that application does not abort when changing out of range */
|
|
ecs_entity_t e2 = ecs_set(world, 4999, Position, {10, 20});
|
|
test_int(e2, 4999);
|
|
test_assert( ecs_has(world, e2, Position));
|
|
|
|
const Position *p = ecs_get(world, e2, Position);
|
|
test_assert(p != NULL);
|
|
test_int(p->x, 10);
|
|
test_int(p->y, 20);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_entity_range_check_after_delete(void) {
|
|
ecs_world_t *world = ecs_init();
|
|
|
|
ECS_COMPONENT(world, Position);
|
|
|
|
ecs_enable_range_check(world, true);
|
|
ecs_set_entity_range(world, 5000, 10000);
|
|
|
|
ecs_entity_t e = ecs_new(world, 0);
|
|
test_assert(e != 0);
|
|
test_assert(e == 5000);
|
|
|
|
ecs_delete(world, e);
|
|
|
|
e = ecs_new(world, 0);
|
|
test_assert(e != 0);
|
|
test_assert((uint32_t)e == 5000);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_entity_range_add_existing_staged(void) {
|
|
ecs_world_t *world = ecs_mini();
|
|
|
|
ECS_COMPONENT(world, Position);
|
|
ECS_COMPONENT(world, Velocity);
|
|
|
|
ecs_entity_t e = ecs_new(world, Position);
|
|
test_assert(e != 0);
|
|
test_assert(e < 1000);
|
|
|
|
ecs_set_entity_range(world, 1000, 1500);
|
|
|
|
ecs_readonly_begin(world);
|
|
ecs_world_t *stage = ecs_get_stage(world, 0);
|
|
ecs_add(stage, e, Velocity);
|
|
ecs_readonly_end(world);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_entity_range_add_in_range_staged(void) {
|
|
ecs_world_t *world = ecs_mini();
|
|
|
|
ECS_COMPONENT(world, Position);
|
|
ECS_COMPONENT(world, Velocity);
|
|
|
|
ecs_set_entity_range(world, 500, 1000);
|
|
|
|
ecs_entity_t e = ecs_new(world, Position);
|
|
test_assert(e == 500);
|
|
|
|
ecs_readonly_begin(world);
|
|
ecs_world_t *stage = ecs_get_stage(world, 0);
|
|
ecs_add(stage, e, Velocity);
|
|
ecs_readonly_end(world);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void AddOutOfRange(ecs_iter_t *it) {
|
|
ecs_id_t ecs_id(Velocity) = ecs_field_id(it, 2);
|
|
|
|
int i;
|
|
for (i = 0; i < it->count; i ++) {
|
|
test_expect_abort();
|
|
ecs_add(it->world, 1001, Velocity);
|
|
}
|
|
}
|
|
|
|
void World_entity_range_add_out_of_range_staged(void) {
|
|
install_test_abort();
|
|
|
|
ecs_world_t *world = ecs_mini();
|
|
|
|
ECS_COMPONENT(world, Position);
|
|
ECS_COMPONENT(world, Velocity);
|
|
|
|
ecs_enable_range_check(world, true);
|
|
ecs_set_entity_range(world, 500, 1000);
|
|
|
|
/* Dummy entity to invoke the system */
|
|
ecs_entity_t e = ecs_new(world, Position);
|
|
test_assert(e == 500);
|
|
|
|
ecs_readonly_begin(world);
|
|
ecs_world_t *stage = ecs_get_stage(world, 0);
|
|
ecs_add(stage, e, Velocity);
|
|
ecs_readonly_end(world);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_get_tick(void) {
|
|
ecs_world_t *world = ecs_init();
|
|
|
|
const ecs_world_info_t *stats = ecs_get_world_info(world);
|
|
test_int(stats->frame_count_total, 0);
|
|
|
|
ecs_progress(world, 1);
|
|
|
|
test_int(stats->frame_count_total, 1);
|
|
|
|
ecs_progress(world, 1);
|
|
|
|
test_int(stats->frame_count_total, 2);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
static int32_t malloc_count;
|
|
|
|
static
|
|
void *test_malloc(ecs_size_t size) {
|
|
malloc_count ++;
|
|
return malloc(size);
|
|
}
|
|
|
|
static
|
|
void *test_calloc(ecs_size_t size) {
|
|
malloc_count ++;
|
|
return calloc(size, 1);
|
|
}
|
|
|
|
static
|
|
void *test_realloc(void *old_ptr, ecs_size_t size) {
|
|
malloc_count ++;
|
|
return realloc(old_ptr, size);
|
|
}
|
|
|
|
void World_dim(void) {
|
|
ecs_os_set_api_defaults();
|
|
ecs_os_api_t os_api = ecs_os_api;
|
|
os_api.malloc_ = test_malloc;
|
|
os_api.calloc_ = test_calloc;
|
|
os_api.realloc_ = test_realloc;
|
|
ecs_os_set_api(&os_api);
|
|
|
|
ecs_world_t *world = ecs_mini();
|
|
|
|
ECS_COMPONENT(world, Position);
|
|
|
|
/* Create single entity so that the table exists. This makes the allocation
|
|
* counts more predictable, as new_w_count won't trigger table creation */
|
|
ecs_new(world, Position);
|
|
|
|
ecs_dim(world, 1100);
|
|
|
|
malloc_count = 0;
|
|
|
|
ecs_bulk_new(world, Position, 500);
|
|
|
|
test_int(malloc_count, 2);
|
|
|
|
malloc_count = 0;
|
|
|
|
ecs_bulk_new(world, Position, 500);
|
|
|
|
test_int(malloc_count, 2);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
static
|
|
void TOnLoad(ecs_iter_t *it) {
|
|
Position *p = ecs_field(it, Position, 1);
|
|
int i;
|
|
for (i = 0; i < it->count; i ++) {
|
|
test_int(p[i].x, 0);
|
|
p[i].x ++;
|
|
}
|
|
}
|
|
|
|
static
|
|
void TPostLoad(ecs_iter_t *it) {
|
|
Position *p = ecs_field(it, Position, 1);
|
|
int i;
|
|
for (i = 0; i < it->count; i ++) {
|
|
test_int(p[i].x, 1);
|
|
p[i].x ++;
|
|
}
|
|
}
|
|
|
|
static
|
|
void TPreUpdate(ecs_iter_t *it) {
|
|
Position *p = ecs_field(it, Position, 1);
|
|
int i;
|
|
for (i = 0; i < it->count; i ++) {
|
|
test_int(p[i].x, 2);
|
|
p[i].x ++;
|
|
}
|
|
}
|
|
|
|
static
|
|
void TOnUpdate(ecs_iter_t *it) {
|
|
Position *p = ecs_field(it, Position, 1);
|
|
int i;
|
|
for (i = 0; i < it->count; i ++) {
|
|
test_int(p[i].x, 3);
|
|
p[i].x ++;
|
|
}
|
|
}
|
|
|
|
static
|
|
void TOnValidate(ecs_iter_t *it) {
|
|
Position *p = ecs_field(it, Position, 1);
|
|
int i;
|
|
for (i = 0; i < it->count; i ++) {
|
|
test_int(p[i].x, 4);
|
|
p[i].x ++;
|
|
}
|
|
}
|
|
|
|
static
|
|
void TPostUpdate(ecs_iter_t *it) {
|
|
Position *p = ecs_field(it, Position, 1);
|
|
int i;
|
|
for (i = 0; i < it->count; i ++) {
|
|
test_int(p[i].x, 5);
|
|
p[i].x ++;
|
|
}
|
|
}
|
|
|
|
static
|
|
void TPreStore(ecs_iter_t *it) {
|
|
Position *p = ecs_field(it, Position, 1);
|
|
int i;
|
|
for (i = 0; i < it->count; i ++) {
|
|
test_int(p[i].x, 6);
|
|
p[i].x ++;
|
|
}
|
|
}
|
|
|
|
static
|
|
void TOnStore(ecs_iter_t *it) {
|
|
Position *p = ecs_field(it, Position, 1);
|
|
int i;
|
|
for (i = 0; i < it->count; i ++) {
|
|
test_int(p[i].x, 7);
|
|
p[i].x ++;
|
|
}
|
|
}
|
|
|
|
static
|
|
void TManual(ecs_iter_t *it) {
|
|
Position *p = ecs_field(it, Position, 1);
|
|
int i;
|
|
for (i = 0; i < it->count; i ++) {
|
|
test_int(p[i].x, 8);
|
|
p[i].x ++;
|
|
}
|
|
}
|
|
|
|
void World_phases(void) {
|
|
ecs_world_t *world = ecs_init();
|
|
|
|
ECS_COMPONENT(world, Position);
|
|
|
|
ECS_SYSTEM(world, TOnLoad, EcsOnLoad, Position);
|
|
ECS_SYSTEM(world, TPostLoad, EcsPostLoad, Position);
|
|
ECS_SYSTEM(world, TPreUpdate, EcsPreUpdate, Position);
|
|
ECS_SYSTEM(world, TOnUpdate, EcsOnUpdate, Position);
|
|
ECS_SYSTEM(world, TOnValidate, EcsOnValidate, Position);
|
|
ECS_SYSTEM(world, TPostUpdate, EcsPostUpdate, Position);
|
|
ECS_SYSTEM(world, TPreStore, EcsPreStore, Position);
|
|
ECS_SYSTEM(world, TOnStore, EcsOnStore, Position);
|
|
ECS_SYSTEM(world, TManual, 0, Position);
|
|
|
|
ecs_entity_t e = ecs_new(world, Position);
|
|
test_assert(e != 0);
|
|
|
|
ecs_set(world, e, Position, {0, 0});
|
|
|
|
ecs_progress(world, 1);
|
|
|
|
const Position *p = ecs_get(world, e, Position);
|
|
test_int(p->x, 8);
|
|
|
|
ecs_run(world, TManual, 0, NULL);
|
|
|
|
test_int(p->x, 9);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_phases_match_in_create(void) {
|
|
ecs_world_t *world = ecs_init();
|
|
|
|
ECS_COMPONENT(world, Position);
|
|
|
|
ecs_entity_t e = ecs_new(world, Position);
|
|
test_assert(e != 0);
|
|
|
|
ecs_set(world, e, Position, {0, 0});
|
|
|
|
ECS_SYSTEM(world, TOnLoad, EcsOnLoad, Position);
|
|
ECS_SYSTEM(world, TPostLoad, EcsPostLoad, Position);
|
|
ECS_SYSTEM(world, TPreUpdate, EcsPreUpdate, Position);
|
|
ECS_SYSTEM(world, TOnUpdate, EcsOnUpdate, Position);
|
|
ECS_SYSTEM(world, TOnValidate, EcsOnValidate, Position);
|
|
ECS_SYSTEM(world, TPostUpdate, EcsPostUpdate, Position);
|
|
ECS_SYSTEM(world, TPreStore, EcsPreStore, Position);
|
|
ECS_SYSTEM(world, TOnStore, EcsOnStore, Position);
|
|
ECS_SYSTEM(world, TManual, 0, Position);
|
|
|
|
ecs_progress(world, 1);
|
|
|
|
const Position *p = ecs_get(world, e, Position);
|
|
test_int(p->x, 8);
|
|
|
|
ecs_run(world, TManual, 0, NULL);
|
|
|
|
test_int(p->x, 9);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
static
|
|
void TMergeOnLoad(ecs_iter_t *it) {
|
|
Position *p = ecs_field(it, Position, 1);
|
|
ecs_id_t ecs_id(Position) = ecs_field_id(it, 1);
|
|
|
|
int i;
|
|
for (i = 0; i < it->count; i ++) {
|
|
test_int(p[i].x, 0);
|
|
ecs_set(it->world, it->entities[i], Position, {p[i].x + 1, 0});
|
|
}
|
|
}
|
|
|
|
static
|
|
void TMergePostLoad(ecs_iter_t *it) {
|
|
Position *p = ecs_field(it, Position, 1);
|
|
ecs_id_t ecs_id(Position) = ecs_field_id(it, 1);
|
|
|
|
int i;
|
|
for (i = 0; i < it->count; i ++) {
|
|
test_int(p[i].x, 1);
|
|
ecs_set(it->world, it->entities[i], Position, {p[i].x + 1, 0});
|
|
}
|
|
}
|
|
|
|
static
|
|
void TMergePreUpdate(ecs_iter_t *it) {
|
|
Position *p = ecs_field(it, Position, 1);
|
|
ecs_id_t ecs_id(Position) = ecs_field_id(it, 1);
|
|
|
|
int i;
|
|
for (i = 0; i < it->count; i ++) {
|
|
test_int(p[i].x, 2);
|
|
ecs_set(it->world, it->entities[i], Position, {p[i].x + 1, 0});
|
|
}
|
|
}
|
|
|
|
static
|
|
void TMergeOnUpdate(ecs_iter_t *it) {
|
|
Position *p = ecs_field(it, Position, 1);
|
|
ecs_id_t ecs_id(Position) = ecs_field_id(it, 1);
|
|
|
|
int i;
|
|
for (i = 0; i < it->count; i ++) {
|
|
test_int(p[i].x, 3);
|
|
ecs_set(it->world, it->entities[i], Position, {p[i].x + 1, 0});
|
|
}
|
|
}
|
|
|
|
static
|
|
void TMergeOnValidate(ecs_iter_t *it) {
|
|
Position *p = ecs_field(it, Position, 1);
|
|
ecs_id_t ecs_id(Position) = ecs_field_id(it, 1);
|
|
|
|
int i;
|
|
for (i = 0; i < it->count; i ++) {
|
|
test_int(p[i].x, 4);
|
|
ecs_set(it->world, it->entities[i], Position, {p[i].x + 1, 0});
|
|
}
|
|
}
|
|
|
|
static
|
|
void TMergePostUpdate(ecs_iter_t *it) {
|
|
Position *p = ecs_field(it, Position, 1);
|
|
ecs_id_t ecs_id(Position) = ecs_field_id(it, 1);
|
|
|
|
int i;
|
|
for (i = 0; i < it->count; i ++) {
|
|
test_int(p[i].x, 5);
|
|
ecs_set(it->world, it->entities[i], Position, {p[i].x + 1, 0});
|
|
}
|
|
}
|
|
|
|
static
|
|
void TMergePreStore(ecs_iter_t *it) {
|
|
Position *p = ecs_field(it, Position, 1);
|
|
ecs_id_t ecs_id(Position) = ecs_field_id(it, 1);
|
|
|
|
int i;
|
|
for (i = 0; i < it->count; i ++) {
|
|
test_int(p[i].x, 6);
|
|
ecs_set(it->world, it->entities[i], Position, {p[i].x + 1, 0});
|
|
}
|
|
}
|
|
|
|
static
|
|
void TMergeOnStore(ecs_iter_t *it) {
|
|
Position *p = ecs_field(it, Position, 1);
|
|
ecs_id_t ecs_id(Position) = ecs_field_id(it, 1);
|
|
|
|
int i;
|
|
for (i = 0; i < it->count; i ++) {
|
|
test_int(p[i].x, 7);
|
|
ecs_set(it->world, it->entities[i], Position, {p[i].x + 1, 0});
|
|
}
|
|
}
|
|
|
|
static
|
|
void TMergeManual(ecs_iter_t *it) {
|
|
Position *p = ecs_field(it, Position, 1);
|
|
ecs_id_t ecs_id(Position) = ecs_field_id(it, 1);
|
|
|
|
int i;
|
|
for (i = 0; i < it->count; i ++) {
|
|
test_int(p[i].x, 8);
|
|
ecs_set(it->world, it->entities[i], Position, {p[i].x + 1, 0});
|
|
}
|
|
}
|
|
|
|
void World_phases_w_merging(void) {
|
|
ecs_world_t *world = ecs_init();
|
|
|
|
ECS_COMPONENT(world, Position);
|
|
|
|
ECS_SYSTEM(world, TMergeOnLoad, EcsOnLoad, Position, [out] Position());
|
|
ECS_SYSTEM(world, TMergePostLoad, EcsPostLoad, Position, [out] Position());
|
|
ECS_SYSTEM(world, TMergePreUpdate, EcsPreUpdate, Position, [out] Position());
|
|
ECS_SYSTEM(world, TMergeOnUpdate, EcsOnUpdate, Position, [out] Position());
|
|
ECS_SYSTEM(world, TMergeOnValidate, EcsOnValidate, Position, [out] Position());
|
|
ECS_SYSTEM(world, TMergePostUpdate, EcsPostUpdate, Position, [out] Position());
|
|
ECS_SYSTEM(world, TMergePreStore, EcsPreStore, Position, [out] Position());
|
|
ECS_SYSTEM(world, TMergeOnStore, EcsOnStore, Position, [out] Position());
|
|
ECS_SYSTEM(world, TMergeManual, 0, Position);
|
|
|
|
ecs_entity_t e = ecs_new(world, Position);
|
|
test_assert(e != 0);
|
|
|
|
ecs_set(world, e, Position, {0, 0});
|
|
|
|
ecs_progress(world, 1);
|
|
|
|
const Position *p = ecs_get(world, e, Position);
|
|
test_int(p->x, 8);
|
|
|
|
ecs_run(world, TMergeManual, 0, NULL);
|
|
|
|
p = ecs_get(world, e, Position);
|
|
test_int(p->x, 9);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
static
|
|
void TimeCheck(ecs_iter_t *it) {
|
|
test_assert(it->delta_time > 0);
|
|
}
|
|
|
|
void World_measure_time(void) {
|
|
ecs_world_t *world = ecs_init();
|
|
|
|
ECS_COMPONENT(world, Position);
|
|
|
|
ECS_SYSTEM(world, TimeCheck, EcsOnLoad, Position);
|
|
|
|
ecs_entity_t e = ecs_new(world, Position);
|
|
test_assert(e != 0);
|
|
|
|
int i = 0;
|
|
for (i = 0; i < 1000; i ++) {
|
|
ecs_progress(world, 0);
|
|
}
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_control_fps(void) {
|
|
test_is_flaky();
|
|
|
|
ecs_world_t *world = ecs_init();
|
|
|
|
ECS_COMPONENT(world, Position);
|
|
|
|
ECS_SYSTEM(world, TimeCheck, EcsOnLoad, Position);
|
|
|
|
ecs_entity_t e = ecs_new(world, Position);
|
|
test_assert(e != 0);
|
|
|
|
double start, now = 0;
|
|
ecs_set_target_fps(world, 20);
|
|
|
|
/* Run a few times to give the code an opportunity to calibrate */
|
|
ecs_progress(world, 0);
|
|
ecs_progress(world, 0);
|
|
ecs_progress(world, 0);
|
|
ecs_progress(world, 0);
|
|
ecs_progress(world, 0);
|
|
|
|
const ecs_world_info_t *stats = ecs_get_world_info(world);
|
|
|
|
/* Run for one second */
|
|
int count = 0;
|
|
do {
|
|
ecs_progress(world, 0);
|
|
if (!count) {
|
|
start = stats->delta_time;
|
|
}
|
|
|
|
now += stats->delta_time;
|
|
count ++;
|
|
} while ((now - start) < 1.0);
|
|
|
|
/* CI can be unpredictable, just make sure it's in the right ballpark */
|
|
test_assert(count >= 15);
|
|
test_assert(count < 25);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
static
|
|
void busy_wait(float wait_time) {
|
|
ecs_time_t start, t;
|
|
ecs_os_get_time(&start);
|
|
|
|
do {
|
|
t = start;
|
|
} while (ecs_time_measure(&t) < wait_time);
|
|
}
|
|
|
|
static
|
|
void BusySystem(ecs_iter_t *it) {
|
|
/* Spend 14msec doing something */
|
|
busy_wait(0.014);
|
|
}
|
|
|
|
void World_control_fps_busy_system(void) {
|
|
test_is_flaky();
|
|
|
|
ecs_world_t *world = ecs_init();
|
|
|
|
ECS_SYSTEM(world, BusySystem, EcsOnUpdate, 0);
|
|
|
|
double start, now = 0;
|
|
ecs_set_target_fps(world, 20);
|
|
|
|
const ecs_world_info_t *stats = ecs_get_world_info(world);
|
|
|
|
/* Run for one second */
|
|
int count = 0;
|
|
do {
|
|
ecs_progress(world, 0);
|
|
if (!count) {
|
|
start = stats->delta_time;
|
|
}
|
|
|
|
now += stats->delta_time;
|
|
count ++;
|
|
} while ((now - start) < 1.0);
|
|
|
|
/* FPS control relies on sleep, which relies on the OS scheduler. Therefore
|
|
* pick a wide enough range to avoid tests failing at random. */
|
|
test_assert(count >= 15);
|
|
test_assert(count < 25);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_control_fps_busy_app(void) {
|
|
test_is_flaky();
|
|
|
|
ecs_world_t *world = ecs_init();
|
|
|
|
double start, now = 0;
|
|
ecs_set_target_fps(world, 20);
|
|
|
|
const ecs_world_info_t *stats = ecs_get_world_info(world);
|
|
|
|
/* Run for one second */
|
|
int count = 0;
|
|
do {
|
|
ecs_progress(world, 0);
|
|
if (!count) {
|
|
start = stats->delta_time;
|
|
}
|
|
|
|
now += stats->delta_time;
|
|
count ++;
|
|
|
|
busy_wait(0.014);
|
|
} while ((now - start) < 1.0);
|
|
|
|
/* FPS control relies on sleep, which relies on the OS scheduler. Therefore
|
|
* pick a wide enough range to avoid tests failing at random. */
|
|
test_assert(count >= 15);
|
|
test_assert(count < 25);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_measure_fps_vs_actual(void) {
|
|
test_is_flaky();
|
|
|
|
ecs_world_t *world = ecs_init();
|
|
|
|
ecs_set_target_fps(world, 60);
|
|
|
|
/* Run 10 times, test if one second has passed */
|
|
ecs_time_t t;
|
|
ecs_os_get_time(&t);
|
|
int32_t i;
|
|
for (i = 0; i < 60; i ++) {
|
|
ecs_progress(world, 0);
|
|
}
|
|
|
|
float elapsed = ecs_time_measure(&t);
|
|
test_assert(elapsed >= 0.9);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_measure_delta_time_vs_actual(void) {
|
|
test_is_flaky();
|
|
|
|
ecs_world_t *world = ecs_init();
|
|
|
|
ecs_set_target_fps(world, 60);
|
|
const ecs_world_info_t *stats = ecs_get_world_info(world);
|
|
|
|
/* Run 10 times, test if one second has passed */
|
|
ecs_time_t t;
|
|
float delta_time = 0;
|
|
ecs_os_get_time(&t);
|
|
int32_t i;
|
|
for (i = 0; i < 60; i ++) {
|
|
ecs_progress(world, 0);
|
|
delta_time += stats->delta_time;
|
|
}
|
|
|
|
float elapsed = ecs_time_measure(&t);
|
|
test_assert(delta_time - elapsed < 0.1);
|
|
test_assert(elapsed >= 0.9);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
static
|
|
void RandomSystem(ecs_iter_t *it) {
|
|
/* wait at most 16msec */
|
|
float rnd_time = ((float)rand() / (float)RAND_MAX) * 0.016;
|
|
busy_wait(rnd_time);
|
|
}
|
|
|
|
void World_control_fps_random_system(void) {
|
|
test_is_flaky();
|
|
|
|
ecs_world_t *world = ecs_init();
|
|
|
|
ECS_SYSTEM(world, RandomSystem, EcsOnUpdate, 0);
|
|
|
|
double start, now = 0;
|
|
ecs_set_target_fps(world, 20);
|
|
|
|
const ecs_world_info_t *stats = ecs_get_world_info(world);
|
|
|
|
/* Run for one second */
|
|
int count = 0;
|
|
do {
|
|
ecs_progress(world, 0);
|
|
if (!count) {
|
|
start = stats->delta_time;
|
|
}
|
|
|
|
now += stats->delta_time;
|
|
count ++;
|
|
} while ((now - start) < 1.0);
|
|
|
|
/* FPS control relies on sleep, which relies on the OS scheduler. Therefore
|
|
* pick a wide enough range to avoid tests failing at random. */
|
|
test_assert(count >= 15);
|
|
test_assert(count < 25);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_control_fps_random_app(void) {
|
|
test_is_flaky();
|
|
|
|
ecs_world_t *world = ecs_init();
|
|
|
|
double start, now = 0;
|
|
ecs_set_target_fps(world, 20);
|
|
|
|
const ecs_world_info_t *stats = ecs_get_world_info(world);
|
|
|
|
/* Run for one second */
|
|
int count = 0;
|
|
do {
|
|
ecs_progress(world, 0);
|
|
if (!count) {
|
|
start = stats->delta_time;
|
|
}
|
|
|
|
now += stats->delta_time;
|
|
count ++;
|
|
|
|
float rnd_time = ((float)rand() / (float)RAND_MAX) * 0.016;
|
|
busy_wait(rnd_time);
|
|
} while ((now - start) < 1.0);
|
|
|
|
/* FPS control relies on sleep, which relies on the OS scheduler. Therefore
|
|
* pick a wide enough range to avoid tests failing at random. */
|
|
test_assert(count >= 15);
|
|
test_assert(count < 25);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_quit(void) {
|
|
ecs_world_t *world = ecs_init();
|
|
|
|
int32_t count = 0;
|
|
|
|
while (ecs_progress(world, 0)) {
|
|
test_int(count, 0);
|
|
ecs_quit(world);
|
|
count ++;
|
|
}
|
|
|
|
test_int(count, 1);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_get_delta_time(void) {
|
|
ecs_world_t *world = ecs_init();
|
|
|
|
const ecs_world_info_t *stats = ecs_get_world_info(world);
|
|
|
|
test_int(stats->delta_time, 0);
|
|
|
|
ecs_progress(world, 1.0);
|
|
|
|
test_flt(stats->delta_time, 1.0);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_get_delta_time_auto(void) {
|
|
ecs_world_t *world = ecs_init();
|
|
|
|
const ecs_world_info_t *stats = ecs_get_world_info(world);
|
|
|
|
test_int(stats->delta_time, 0);
|
|
|
|
ecs_progress(world, 0);
|
|
|
|
test_assert(stats->delta_time != 0);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_recreate_world(void) {
|
|
ecs_world_t *world = ecs_init();
|
|
|
|
test_assert(ecs_fini(world) == 0);
|
|
|
|
world = ecs_init();
|
|
|
|
test_assert(ecs_fini(world) == 0);
|
|
}
|
|
|
|
void World_recreate_world_w_component(void) {
|
|
ecs_world_t *world = ecs_init();
|
|
test_assert(world != NULL);
|
|
|
|
{
|
|
ECS_COMPONENT(world, Position);
|
|
test_assert(ecs_id(Position) != 0);
|
|
}
|
|
|
|
test_assert(ecs_fini(world) == 0);
|
|
|
|
{
|
|
world = ecs_init();
|
|
test_assert(world != NULL);
|
|
|
|
ECS_COMPONENT(world, Position);
|
|
test_assert(ecs_id(Position) != 0);
|
|
|
|
test_assert(ecs_fini(world) == 0);
|
|
}
|
|
}
|
|
|
|
void World_no_threading(void) {
|
|
ecs_os_set_api_defaults();
|
|
ecs_os_api_t os_api = ecs_os_api;
|
|
os_api.mutex_new_ = NULL;
|
|
ecs_os_set_api(&os_api);
|
|
|
|
ecs_world_t *world = ecs_init();
|
|
test_assert(world != NULL);
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_no_time(void) {
|
|
ecs_os_set_api_defaults();
|
|
ecs_os_api_t os_api = ecs_os_api;
|
|
os_api.get_time_ = NULL;
|
|
ecs_os_set_api(&os_api);
|
|
|
|
ecs_world_t *world = ecs_init();
|
|
test_assert(world != NULL);
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_is_entity_enabled(void) {
|
|
ecs_world_t *world = ecs_init();
|
|
|
|
ecs_entity_t e = ecs_new(world, 0);
|
|
|
|
test_assert( ecs_has_id(world, e, EcsDisabled) == false);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
static int zero_time_scale_invoked = 0;
|
|
|
|
void ZeroTimeScale(ecs_iter_t *it) {
|
|
test_assert(it->delta_time == 0.0);
|
|
zero_time_scale_invoked ++;
|
|
}
|
|
|
|
void World_system_time_scale(void) {
|
|
ecs_world_t *world = ecs_init();
|
|
|
|
ECS_TAG(world, Tag);
|
|
|
|
ecs_new_w_id(world, Tag);
|
|
|
|
ecs_set_time_scale(world, 0);
|
|
|
|
ECS_SYSTEM(world, ZeroTimeScale, EcsOnUpdate, Tag);
|
|
|
|
ecs_progress(world, 0);
|
|
ecs_progress(world, 0);
|
|
|
|
const ecs_world_info_t *info = ecs_get_world_info(world);
|
|
test_assert(info->delta_time == 0.0);
|
|
|
|
test_int(zero_time_scale_invoked, 2);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_ensure_empty_root(void) {
|
|
ecs_world_t *world = ecs_init();
|
|
|
|
ecs_query_t *q = ecs_query_new(world, "!(ChildOf, *)");
|
|
ecs_iter_t it = ecs_query_iter(world, q);
|
|
|
|
/* Make sure that the only entity in the root is the flecs module */
|
|
test_assert(ecs_query_next(&it));
|
|
test_int(it.count, 1);
|
|
test_assert(it.entities[0] == EcsFlecs);
|
|
|
|
/* Entity for the query */
|
|
test_assert(ecs_query_next(&it));
|
|
test_int(it.count, 1);
|
|
test_assert(ecs_has_id(world, it.entities[0], EcsQuery));
|
|
|
|
test_assert(!ecs_query_next(&it));
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_register_alias_twice_same_entity(void) {
|
|
ecs_world_t *world = ecs_init();
|
|
|
|
ecs_entity_t e = ecs_new_id(world);
|
|
|
|
ecs_set_alias(world, e, "Foo");
|
|
ecs_set_alias(world, e, "Foo");
|
|
|
|
ecs_entity_t f = ecs_lookup(world, "Foo");
|
|
test_assert(f == e);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_register_alias_twice_different_entity(void) {
|
|
install_test_abort();
|
|
|
|
ecs_world_t *world = ecs_init();
|
|
|
|
ecs_entity_t e = ecs_new_id(world);
|
|
ecs_entity_t f = ecs_new_id(world);
|
|
|
|
ecs_set_alias(world, e, "Foo");
|
|
|
|
test_expect_abort();
|
|
ecs_set_alias(world, f, "Foo");
|
|
}
|
|
|
|
void World_redefine_component(void) {
|
|
ecs_world_t *world = ecs_init();
|
|
|
|
ecs_entity_t c = ecs_component_init(world, &(ecs_component_desc_t){
|
|
.entity = ecs_entity(world, {
|
|
.name = "flecs.core.Component",
|
|
.symbol = "EcsComponent"
|
|
}),
|
|
.type.size = ECS_SIZEOF(EcsComponent),
|
|
.type.alignment = ECS_ALIGNOF(EcsComponent)
|
|
});
|
|
|
|
test_assert(c == ecs_id(EcsComponent));
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_delete_empty_tables_after_mini(void) {
|
|
ecs_world_t *world = ecs_mini();
|
|
|
|
const ecs_world_info_t *info = ecs_get_world_info(world);
|
|
int32_t old_empty_table_count = info->empty_table_count;
|
|
|
|
int32_t deleted;
|
|
deleted = ecs_delete_empty_tables(world, 0, 0, 1, 0, 0); /* Increase to 1 */
|
|
test_int(deleted, 0);
|
|
|
|
deleted = ecs_delete_empty_tables(world, 0, 0, 1, 0, 0); /* Delete */
|
|
test_assert(deleted != 0);
|
|
test_int(info->empty_table_count + deleted, old_empty_table_count);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_delete_empty_tables_after_init(void) {
|
|
ecs_world_t *world = ecs_init();
|
|
|
|
int32_t deleted;
|
|
deleted = ecs_delete_empty_tables(world, 0, 0, 1, 0, 0); /* Increase to 1 */
|
|
test_int(deleted, 0);
|
|
|
|
deleted = ecs_delete_empty_tables(world, 0, 0, 1, 0, 0); /* Delete */
|
|
test_assert(deleted != 0);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_delete_1000_empty_tables(void) {
|
|
ecs_world_t *world = ecs_mini();
|
|
|
|
ECS_TAG(world, Tag);
|
|
ecs_run_aperiodic(world, 0);
|
|
|
|
const ecs_world_info_t *info = ecs_get_world_info(world);
|
|
int32_t old_empty_table_count = info->empty_table_count;
|
|
|
|
ecs_entity_t e = ecs_new(world, Tag);
|
|
for (int i = 0; i < 1000; i ++) {
|
|
ecs_add_id(world, e, ecs_new_id(world));
|
|
}
|
|
|
|
ecs_run_aperiodic(world, 0);
|
|
test_int(info->empty_table_count, old_empty_table_count + 1000);
|
|
|
|
int32_t deleted;
|
|
deleted = ecs_delete_empty_tables(world, 0, 0, 1, 0, 0); /* Increase to 1 */
|
|
test_int(deleted, 0);
|
|
|
|
deleted = ecs_delete_empty_tables(world, 0, 0, 1, 0, 0); /* Delete */
|
|
test_assert(deleted != 0);
|
|
test_assert(deleted >= 1000);
|
|
|
|
test_assert(info->empty_table_count <= old_empty_table_count);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_delete_empty_tables_for_id(void) {
|
|
ecs_world_t *world = ecs_mini();
|
|
|
|
ECS_TAG(world, TagA);
|
|
ECS_TAG(world, TagB);
|
|
ecs_run_aperiodic(world, 0);
|
|
|
|
const ecs_world_info_t *info = ecs_get_world_info(world);
|
|
int32_t old_empty_table_count = info->empty_table_count;
|
|
|
|
ecs_entity_t e1 = ecs_new(world, TagA);
|
|
for (int i = 0; i < 500; i ++) {
|
|
ecs_add_id(world, e1, ecs_new_id(world));
|
|
}
|
|
|
|
ecs_entity_t e2 = ecs_new(world, TagB);
|
|
for (int i = 0; i < 500; i ++) {
|
|
ecs_add_id(world, e2, ecs_new_id(world));
|
|
}
|
|
|
|
ecs_run_aperiodic(world, 0);
|
|
test_int(info->empty_table_count, old_empty_table_count + 1000);
|
|
|
|
int32_t deleted;
|
|
deleted = ecs_delete_empty_tables(world, TagA, 0, 1, 0, 0); /* Increase to 1 */
|
|
test_int(deleted, 0);
|
|
|
|
deleted = ecs_delete_empty_tables(world, TagA, 0, 1, 0, 0); /* Delete */
|
|
test_assert(deleted != 0);
|
|
test_assert(deleted >= 500);
|
|
test_assert(deleted < 1000);
|
|
|
|
test_assert((info->empty_table_count - 500) <= old_empty_table_count);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_use_after_delete_empty(void) {
|
|
ecs_world_t *world = ecs_mini();
|
|
|
|
ECS_TAG(world, TagA);
|
|
ECS_TAG(world, TagB);
|
|
|
|
ecs_entity_t e = ecs_new_id(world);
|
|
ecs_add(world, e, TagA);
|
|
ecs_add(world, e, TagB);
|
|
|
|
ecs_remove(world, e, TagA);
|
|
int32_t deleted;
|
|
deleted = ecs_delete_empty_tables(world, 0, 0, 1, 0, 0);
|
|
test_assert(deleted == 0);
|
|
deleted = ecs_delete_empty_tables(world, 0, 0, 1, 0, 0);
|
|
test_assert(deleted != 0);
|
|
ecs_add(world, e, TagA);
|
|
|
|
test_assert( ecs_has(world, e, TagA));
|
|
test_assert( ecs_has(world, e, TagB));
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_use_after_clear_empty(void) {
|
|
ecs_world_t *world = ecs_mini();
|
|
|
|
ECS_TAG(world, TagA);
|
|
ECS_TAG(world, TagB);
|
|
|
|
ecs_entity_t e = ecs_new_id(world);
|
|
ecs_add(world, e, TagA);
|
|
ecs_add(world, e, TagB);
|
|
|
|
ecs_remove(world, e, TagA);
|
|
int32_t deleted;
|
|
deleted = ecs_delete_empty_tables(world, 0, 1, 0, 0, 0);
|
|
test_assert(deleted == 0);
|
|
deleted = ecs_delete_empty_tables(world, 0, 1, 0, 0, 0);
|
|
test_assert(deleted == 0);
|
|
ecs_add(world, e, TagA);
|
|
|
|
test_assert( ecs_has(world, e, TagA));
|
|
test_assert( ecs_has(world, e, TagB));
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_use_after_delete_empty_w_component(void) {
|
|
ecs_world_t *world = ecs_mini();
|
|
|
|
ECS_COMPONENT(world, Position);
|
|
ECS_COMPONENT(world, Velocity);
|
|
|
|
ecs_entity_t e = ecs_new_id(world);
|
|
ecs_add(world, e, Position);
|
|
ecs_add(world, e, Velocity);
|
|
|
|
test_assert( ecs_has(world, e, Position));
|
|
|
|
ecs_remove(world, e, Velocity);
|
|
test_assert( ecs_has(world, e, Position));
|
|
test_assert( !ecs_has(world, e, Velocity));
|
|
|
|
int32_t deleted;
|
|
deleted = ecs_delete_empty_tables(world, 0, 0, 1, 0, 0);
|
|
test_assert(deleted == 0);
|
|
test_bool(true, ecs_is_alive(world, ecs_id(Position)));
|
|
test_bool(true, ecs_is_alive(world, ecs_id(Velocity)));
|
|
test_assert( ecs_has(world, e, Position));
|
|
|
|
deleted = ecs_delete_empty_tables(world, 0, 0, 1, 0, 0);
|
|
test_assert(deleted != 0);
|
|
test_bool(true, ecs_is_alive(world, ecs_id(Position)));
|
|
test_bool(true, ecs_is_alive(world, ecs_id(Velocity)));
|
|
test_assert( ecs_has(world, e, Position));
|
|
|
|
ecs_add(world, e, Velocity);
|
|
|
|
test_assert( ecs_has(world, e, Position));
|
|
test_assert( ecs_has(world, e, Velocity));
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_use_after_clear_empty_w_component(void) {
|
|
ecs_world_t *world = ecs_mini();
|
|
|
|
ECS_COMPONENT(world, Position);
|
|
ECS_COMPONENT(world, Velocity);
|
|
|
|
ecs_entity_t e = ecs_new_id(world);
|
|
ecs_add(world, e, Position);
|
|
ecs_add(world, e, Velocity);
|
|
|
|
test_assert( ecs_has(world, e, Position));
|
|
|
|
ecs_remove(world, e, Velocity);
|
|
test_assert( ecs_has(world, e, Position));
|
|
test_assert( !ecs_has(world, e, Velocity));
|
|
|
|
int32_t deleted;
|
|
deleted = ecs_delete_empty_tables(world, 0, 1, 0, 0, 0);
|
|
test_assert(deleted == 0);
|
|
test_bool(true, ecs_is_alive(world, ecs_id(Position)));
|
|
test_bool(true, ecs_is_alive(world, ecs_id(Velocity)));
|
|
test_assert( ecs_has(world, e, Position));
|
|
|
|
deleted = ecs_delete_empty_tables(world, 0, 1, 0, 0, 0);
|
|
test_assert(deleted == 0);
|
|
test_bool(true, ecs_is_alive(world, ecs_id(Position)));
|
|
test_bool(true, ecs_is_alive(world, ecs_id(Velocity)));
|
|
test_assert( ecs_has(world, e, Position));
|
|
|
|
ecs_add(world, e, Velocity);
|
|
|
|
test_assert( ecs_has(world, e, Position));
|
|
test_assert( ecs_has(world, e, Velocity));
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_use_after_clear_empty_w_component_w_lifecycle(void) {
|
|
ecs_world_t *world = ecs_mini();
|
|
|
|
ECS_COMPONENT(world, Position);
|
|
ECS_COMPONENT(world, Velocity);
|
|
|
|
ecs_set_hooks(world, Position, {
|
|
.ctor = ecs_default_ctor
|
|
});
|
|
ecs_set_hooks(world, Velocity, {
|
|
.ctor = ecs_default_ctor
|
|
});
|
|
|
|
ecs_entity_t e = ecs_new_id(world);
|
|
ecs_add(world, e, Position);
|
|
ecs_add(world, e, Velocity);
|
|
|
|
test_assert( ecs_has(world, e, Position));
|
|
|
|
ecs_remove(world, e, Velocity);
|
|
test_assert( ecs_has(world, e, Position));
|
|
test_assert( !ecs_has(world, e, Velocity));
|
|
|
|
int32_t deleted;
|
|
deleted = ecs_delete_empty_tables(world, 0, 1, 0, 0, 0);
|
|
test_assert(deleted == 0);
|
|
test_bool(true, ecs_is_alive(world, ecs_id(Position)));
|
|
test_bool(true, ecs_is_alive(world, ecs_id(Velocity)));
|
|
test_assert( ecs_has(world, e, Position));
|
|
|
|
deleted = ecs_delete_empty_tables(world, 0, 1, 0, 0, 0);
|
|
test_assert(deleted == 0);
|
|
test_bool(true, ecs_is_alive(world, ecs_id(Position)));
|
|
test_bool(true, ecs_is_alive(world, ecs_id(Velocity)));
|
|
test_assert( ecs_has(world, e, Position));
|
|
|
|
ecs_add(world, e, Velocity);
|
|
|
|
test_assert( ecs_has(world, e, Position));
|
|
test_assert( ecs_has(world, e, Velocity));
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_use_after_clear_unused(void) {
|
|
ecs_world_t *world = ecs_mini();
|
|
|
|
ECS_TAG(world, TagA);
|
|
ECS_TAG(world, TagB);
|
|
|
|
int32_t deleted;
|
|
deleted = ecs_delete_empty_tables(world, 0, 1, 0, 0, 0);
|
|
test_assert(deleted == 0);
|
|
deleted = ecs_delete_empty_tables(world, 0, 1, 0, 0, 0);
|
|
test_assert(deleted == 0);
|
|
|
|
ecs_entity_t e = ecs_new_id(world);
|
|
ecs_add(world, e, TagA);
|
|
ecs_add(world, e, TagB);
|
|
|
|
test_assert(ecs_has(world, e, TagA));
|
|
test_assert(ecs_has(world, e, TagB));
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
static ECS_COMPONENT_DECLARE(Test);
|
|
|
|
typedef struct Test {
|
|
uint32_t value;
|
|
} Test;
|
|
|
|
static int at_fini_test_invoked = 0;
|
|
|
|
static
|
|
void at_fini_test(
|
|
ecs_world_t* world,
|
|
void* context)
|
|
{
|
|
test_assert(ecs_singleton_get_mut(world, Test) != NULL);
|
|
at_fini_test_invoked = 1;
|
|
}
|
|
|
|
void World_get_mut_in_at_fini(void) {
|
|
ecs_world_t* world = ecs_mini();
|
|
|
|
ECS_COMPONENT_DEFINE(world, Test);
|
|
ecs_singleton_set(world, Test, { 42 });
|
|
|
|
ecs_atfini(world, at_fini_test, NULL);
|
|
|
|
ecs_fini(world);
|
|
|
|
test_int(at_fini_test_invoked, 1);
|
|
}
|
|
|
|
void World_get_type_info(void) {
|
|
ecs_world_t* world = ecs_mini();
|
|
|
|
ECS_COMPONENT(world, Position);
|
|
|
|
const ecs_type_info_t *ti = ecs_get_type_info(world, ecs_id(Position));
|
|
test_assert(ti != NULL);
|
|
test_int(ti->size, ECS_SIZEOF(Position));
|
|
test_int(ti->alignment, ECS_ALIGNOF(Position));
|
|
test_uint(ti->component, ecs_id(Position));
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_get_type_info_after_delete_with(void) {
|
|
ecs_world_t* world = ecs_mini();
|
|
|
|
ECS_COMPONENT(world, Position);
|
|
|
|
ecs_delete_with(world, ecs_id(Position));
|
|
|
|
const ecs_type_info_t *ti = ecs_get_type_info(world, ecs_id(Position));
|
|
test_assert(ti != NULL);
|
|
test_int(ti->size, ECS_SIZEOF(Position));
|
|
test_int(ti->alignment, ECS_ALIGNOF(Position));
|
|
test_uint(ti->component, ecs_id(Position));
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_get_type_info_after_reuse(void) {
|
|
ecs_world_t* world = ecs_mini();
|
|
|
|
ECS_COMPONENT(world, Position);
|
|
|
|
ecs_delete_with(world, ecs_id(Position));
|
|
|
|
ecs_entity_t e = ecs_new(world, Position);
|
|
test_assert(e != 0);
|
|
test_assert( ecs_has(world, e, Position));
|
|
|
|
const ecs_type_info_t *ti = ecs_get_type_info(world, ecs_id(Position));
|
|
test_assert(ti != NULL);
|
|
test_int(ti->size, ECS_SIZEOF(Position));
|
|
test_int(ti->alignment, ECS_ALIGNOF(Position));
|
|
test_uint(ti->component, ecs_id(Position));
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_no_name_prefix_after_init(void) {
|
|
ecs_world_t *world = ecs_mini();
|
|
|
|
const ecs_world_info_t *info = ecs_get_world_info(world);
|
|
test_assert(info->name_prefix == NULL);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_set_get_context(void) {
|
|
ecs_world_t *world = ecs_mini();
|
|
|
|
int ctx;
|
|
ecs_set_ctx(world, &ctx, NULL);
|
|
test_assert(ecs_get_ctx(world) == &ctx);
|
|
test_assert(ecs_get_binding_ctx(world) == NULL);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
void World_set_get_binding_context(void) {
|
|
ecs_world_t *world = ecs_mini();
|
|
|
|
int ctx;
|
|
ecs_set_binding_ctx(world, &ctx, NULL);
|
|
test_assert(ecs_get_ctx(world) == NULL);
|
|
test_assert(ecs_get_binding_ctx(world) == &ctx);
|
|
|
|
ecs_fini(world);
|
|
}
|
|
|
|
static void ctx_free(void *ptr) {
|
|
*(int*)ptr = 10;
|
|
}
|
|
|
|
void World_set_get_context_w_free(void) {
|
|
ecs_world_t *world = ecs_mini();
|
|
|
|
int ctx = 0;
|
|
ecs_set_ctx(world, &ctx, ctx_free);
|
|
test_assert(ecs_get_ctx(world) == &ctx);
|
|
test_assert(ecs_get_binding_ctx(world) == NULL);
|
|
test_int(ctx, 0);
|
|
|
|
ecs_fini(world);
|
|
|
|
test_int(ctx, 10);
|
|
}
|
|
|
|
void World_set_get_binding_context_w_free(void) {
|
|
ecs_world_t *world = ecs_mini();
|
|
|
|
int ctx = 0;
|
|
ecs_set_binding_ctx(world, &ctx, ctx_free);
|
|
test_assert(ecs_get_ctx(world) == NULL);
|
|
test_assert(ecs_get_binding_ctx(world) == &ctx);
|
|
test_int(ctx, 0);
|
|
|
|
ecs_fini(world);
|
|
|
|
test_int(ctx, 10);
|
|
}
|