Properly link flecs library

This commit is contained in:
2023-11-09 11:38:29 +01:00
parent dc585396c3
commit 8edcf9305c
1392 changed files with 390081 additions and 164 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,115 @@
#include <addons.h>
static int dummy_frame_action(
ecs_world_t *world,
const ecs_app_desc_t *desc)
{
return 10;
}
void App_app_w_frame_action(void) {
ecs_world_t *world = ecs_init();
test_int(ecs_app_set_frame_action(dummy_frame_action), 0);
int result = ecs_app_run(world, &(ecs_app_desc_t){ 0 });
test_int(result, 10);
ecs_fini(world);
}
static void Sys(ecs_iter_t *it) {
ecs_quit(it->world);
}
void App_app_w_default_frame_action(void) {
ecs_world_t *world = ecs_init();
ECS_SYSTEM(world, Sys, EcsOnUpdate, 0);
int result = ecs_app_run(world, &(ecs_app_desc_t){ 0 });
test_int(result, 0);
ecs_fini(world);
}
static
void Dummy(ecs_iter_t *it) {
ecs_quit(it->world);
}
void App_app_w_set_threads(void) {
ecs_world_t *world = ecs_init();
ECS_SYSTEM(world, Dummy, EcsOnUpdate, 0);
test_int(ecs_get_stage_count(world), 1);
ecs_set_threads(world, 2);
test_int(ecs_get_stage_count(world), 2);
ecs_app_run(world, &(ecs_app_desc_t) { 0 });
test_int(ecs_get_stage_count(world), 2);
ecs_fini(world);
}
void App_app_w_set_task_threads(void) {
ecs_world_t *world = ecs_init();
ECS_SYSTEM(world, Dummy, EcsOnUpdate, 0);
test_int(ecs_get_stage_count(world), 1);
ecs_set_task_threads(world, 2);
test_int(ecs_get_stage_count(world), 2);
ecs_app_run(world, &(ecs_app_desc_t) { 0 });
test_int(ecs_get_stage_count(world), 2);
ecs_fini(world);
}
void App_app_w_set_target_fps(void) {
ecs_world_t *world = ecs_init();
ECS_SYSTEM(world, Dummy, EcsOnUpdate, 0);
const ecs_world_info_t *info = ecs_get_world_info(world);
test_int(info->target_fps, 0);
ecs_set_target_fps(world, 60);
test_int(info->target_fps, 60);
ecs_app_run(world, &(ecs_app_desc_t) { 0 });
test_int(info->target_fps, 60);
ecs_fini(world);
}
static int sys_invoked = 0;
static void SysCount(ecs_iter_t *it) {
sys_invoked ++;
}
void App_app_w_set_frames(void) {
ecs_world_t *world = ecs_init();
ECS_SYSTEM(world, SysCount, EcsOnUpdate, 0);
ecs_app_run(world, &(ecs_app_desc_t) {
.frames = 100
});
test_int(sys_invoked, 100);
ecs_fini(world);
}

View File

@@ -0,0 +1,134 @@
#include <addons.h>
void Doc_get_set_name(void) {
ecs_world_t *world = ecs_init();
ecs_entity_t e = ecs_new_id(world);
ecs_doc_set_name(world, e, "Human readable name");
test_assert( ecs_has_pair(world, e, ecs_id(EcsDocDescription), EcsName));
test_str( ecs_doc_get_name(world, e), "Human readable name");
ecs_fini(world);
}
void Doc_get_entity_name(void) {
ecs_world_t *world = ecs_init();
ecs_entity_t e = ecs_set_name(world, 0, "Entity name");
test_assert( ecs_has_pair(world, e, ecs_id(EcsIdentifier), EcsName));
test_str( ecs_doc_get_name(world, e), "Entity name");
ecs_fini(world);
}
void Doc_get_set_brief(void) {
ecs_world_t *world = ecs_init();
ECS_TAG(world, MyTag);
ecs_doc_set_brief(world, MyTag, "Brief description");
test_assert( ecs_has_pair(world, MyTag, ecs_id(EcsDocDescription), EcsDocBrief));
test_str( ecs_doc_get_brief(world, MyTag), "Brief description");
ecs_fini(world);
}
void Doc_get_set_detail(void) {
ecs_world_t *world = ecs_init();
ECS_TAG(world, MyTag);
ecs_doc_set_detail(world, MyTag, "Detailed description");
test_assert( ecs_has_pair(world, MyTag, ecs_id(EcsDocDescription), EcsDocDetail));
test_str( ecs_doc_get_detail(world, MyTag), "Detailed description");
ecs_fini(world);
}
void Doc_get_set_link(void) {
ecs_world_t *world = ecs_init();
ECS_TAG(world, MyTag);
ecs_doc_set_link(world, MyTag, "http://www.example.com");
test_assert( ecs_has_pair(world, MyTag, ecs_id(EcsDocDescription), EcsDocLink));
test_str( ecs_doc_get_link(world, MyTag), "http://www.example.com");
ecs_fini(world);
}
void Doc_set_name_nullptr(void) {
ecs_world_t *world = ecs_init();
ecs_entity_t e = ecs_new_id(world);
ecs_doc_set_name(world, e, "foo");
test_assert( ecs_has_pair(world, e, ecs_id(EcsDocDescription), EcsName));
ecs_doc_set_name(world, e, NULL);
test_assert( !ecs_has_pair(world, e, ecs_id(EcsDocDescription), EcsName));
ecs_fini(world);
}
void Doc_set_brief_nullptr(void) {
ecs_world_t *world = ecs_init();
ecs_entity_t e = ecs_new_id(world);
ecs_doc_set_brief(world, e, "foo");
test_assert( ecs_has_pair(world, e, ecs_id(EcsDocDescription), EcsDocBrief));
ecs_doc_set_brief(world, e, NULL);
test_assert( !ecs_has_pair(world, e, ecs_id(EcsDocDescription), EcsDocBrief));
ecs_fini(world);
}
void Doc_set_detail_nullptr(void) {
ecs_world_t *world = ecs_init();
ecs_entity_t e = ecs_new_id(world);
ecs_doc_set_detail(world, e, "foo");
test_assert( ecs_has_pair(world, e, ecs_id(EcsDocDescription), EcsDocDetail));
ecs_doc_set_detail(world, e, NULL);
test_assert( !ecs_has_pair(world, e, ecs_id(EcsDocDescription), EcsDocDetail));
ecs_fini(world);
}
void Doc_set_link_nullptr(void) {
ecs_world_t *world = ecs_init();
ecs_entity_t e = ecs_new_id(world);
ecs_doc_set_link(world, e, "foo");
test_assert( ecs_has_pair(world, e, ecs_id(EcsDocDescription), EcsDocLink));
ecs_doc_set_link(world, e, NULL);
test_assert( !ecs_has_pair(world, e, ecs_id(EcsDocDescription), EcsDocLink));
ecs_fini(world);
}
void Doc_set_color_nullptr(void) {
ecs_world_t *world = ecs_init();
ecs_entity_t e = ecs_new_id(world);
ecs_doc_set_color(world, e, "foo");
test_assert( ecs_has_pair(world, e, ecs_id(EcsDocDescription), EcsDocColor));
ecs_doc_set_color(world, e, NULL);
test_assert( !ecs_has_pair(world, e, ecs_id(EcsDocDescription), EcsDocColor));
ecs_fini(world);
}

View File

@@ -0,0 +1,70 @@
#include <addons.h>
static bool OnRequest(
const ecs_http_request_t* request,
ecs_http_reply_t *reply,
void *ctx)
{
return true;
}
void Http_teardown(void) {
ecs_set_os_api_impl();
ecs_http_server_t *srv = ecs_http_server_init(&(ecs_http_server_desc_t){
.port = 27750,
.callback = OnRequest
});
test_assert(srv != NULL);
ecs_http_server_fini(srv);
}
void Http_teardown_started(void) {
ecs_set_os_api_impl();
ecs_http_server_t *srv = ecs_http_server_init(&(ecs_http_server_desc_t){
.port = 27751,
.callback = OnRequest
});
test_assert(srv != NULL);
test_int(ecs_http_server_start(srv), 0);
ecs_http_server_fini(srv);
}
void Http_teardown_stopped(void) {
ecs_set_os_api_impl();
ecs_http_server_t *srv = ecs_http_server_init(&(ecs_http_server_desc_t){
.port = 27752,
.callback = OnRequest
});
test_assert(srv != NULL);
test_int(ecs_http_server_start(srv), 0);
ecs_http_server_stop(srv);
ecs_http_server_fini(srv);
}
void Http_stop_start(void) {
ecs_set_os_api_impl();
ecs_http_server_t *srv = ecs_http_server_init(&(ecs_http_server_desc_t){
.port = 27753,
.callback = OnRequest
});
test_assert(srv != NULL);
test_int(ecs_http_server_start(srv), 0);
ecs_http_server_stop(srv);
test_int(ecs_http_server_start(srv), 0);
ecs_http_server_fini(srv);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,412 @@
#include <addons.h>
void Modules_setup(void) {
}
/* -- Begin module code -- */
typedef struct SimpleFooComponent {
float value;
} SimpleFooComponent;
typedef struct NestedComponent {
float value;
} NestedComponent;
static
void Move(ecs_iter_t *it) { }
static
void SimpleFooSystem(ecs_iter_t *it) { }
static
void SimpleFooTrigger(ecs_iter_t *it) { }
static ECS_COMPONENT_DECLARE(NestedComponent);
static ECS_COMPONENT_DECLARE(Position);
static ECS_COMPONENT_DECLARE(Velocity);
static ECS_COMPONENT_DECLARE(SimpleFooComponent);
static ECS_DECLARE(Tag);
static ECS_DECLARE(SimpleFooTag);
static ECS_DECLARE(Entity);
static ECS_DECLARE(SimpleFooEntity);
static ECS_DECLARE(SimpleFooPrefab);
static ECS_DECLARE(SimpleFooPipeline);
static ECS_DECLARE(Simple_underscore);
static ECS_SYSTEM_DECLARE(Move);
static ECS_SYSTEM_DECLARE(SimpleFooSystem);
static ECS_SYSTEM_DECLARE(SimpleFooTrigger);
void NestedModuleImport(
ecs_world_t *world)
{
ECS_MODULE(world, NestedModule);
ecs_set_name_prefix(world, "Nested");
ECS_COMPONENT_DEFINE(world, NestedComponent);
}
void SimpleModuleImport(
ecs_world_t *world)
{
ECS_MODULE(world, SimpleModule);
ECS_IMPORT(world, NestedModule);
ecs_set_name_prefix(world, "Simple");
ECS_COMPONENT_DEFINE(world, Position);
ECS_COMPONENT_DEFINE(world, Velocity);
ECS_COMPONENT_DEFINE(world, SimpleFooComponent);
ECS_TAG_DEFINE(world, Tag);
ECS_ENTITY_DEFINE(world, Entity, 0);
ECS_SYSTEM_DEFINE(world, Move, EcsOnUpdate, Position, Velocity);
ECS_SYSTEM_DEFINE(world, SimpleFooSystem, EcsOnUpdate, Position);
ECS_OBSERVER_DEFINE(world, SimpleFooTrigger, EcsOnAdd, Position);
ECS_TAG_DEFINE(world, SimpleFooTag);
ECS_ENTITY_DEFINE(world, SimpleFooEntity, 0);
ECS_PREFAB_DEFINE(world, SimpleFooPrefab, 0);
ECS_PIPELINE_DEFINE(world, SimpleFooPipeline, flecs.system.System, Tag);
ECS_TAG_DEFINE(world, Simple_underscore);
}
/* -- End module code -- */
void Modules_simple_module(void) {
ecs_world_t *world = ecs_init();
ECS_IMPORT(world, SimpleModule);
ecs_entity_t e = ecs_new(world, Position);
test_assert(e != 0);
test_assert( ecs_has(world, e, Position));
ecs_add(world, e, Velocity);
test_assert( ecs_has(world, e, Velocity));
ecs_fini(world);
}
static
void AddVtoP(ecs_iter_t *it) {
int i;
for (i = 0; i < it->count; i ++) {
ecs_add(it->world, it->entities[i], Velocity);
}
}
void Modules_import_module_from_system(void) {
ecs_world_t *world = ecs_init();
ECS_IMPORT(world, SimpleModule);
ECS_SYSTEM(world, AddVtoP, EcsOnUpdate, simple.module.Position);
ecs_entity_t e = ecs_new(world, Position);
test_assert(e != 0);
test_assert( ecs_has(world, e, Position));
ecs_progress(world, 1);
test_assert( ecs_has(world, e, Velocity));
ecs_fini(world);
}
void Modules_import_again(void) {
ecs_world_t *world = ecs_init();
ecs_entity_t m1 = ECS_IMPORT(world, SimpleModule);
ecs_entity_t m2 = ECS_IMPORT(world, SimpleModule);
test_assert(m1 != 0);
test_assert(m2 != 0);
test_assert(m1 == m2);
ecs_fini(world);
}
void Modules_scoped_component(void) {
ecs_world_t *world = ecs_init();
ECS_IMPORT(world, SimpleModule);
ecs_entity_t e = ecs_lookup_fullpath(world, "simple.module.Position");
test_assert(e != 0);
test_assert(e == ecs_id(Position));
ecs_fini(world);
}
void Modules_scoped_tag(void) {
ecs_world_t *world = ecs_init();
ECS_IMPORT(world, SimpleModule);
ecs_entity_t e = ecs_lookup_fullpath(world, "simple.module.Tag");
test_assert(e != 0);
test_assert(e == Tag);
ecs_fini(world);
}
void Modules_scoped_system(void) {
ecs_world_t *world = ecs_init();
ECS_IMPORT(world, SimpleModule);
ecs_entity_t e = ecs_lookup_fullpath(world, "simple.module.Move");
test_assert(e != 0);
test_assert(e == ecs_id(Move));
ecs_fini(world);
}
void Modules_scoped_entity(void) {
ecs_world_t *world = ecs_init();
ECS_IMPORT(world, SimpleModule);
ecs_entity_t e = ecs_lookup_fullpath(world, "simple.module.Entity");
test_assert(e != 0);
test_assert(e == Entity);
ecs_fini(world);
}
void Modules_name_prefix_component(void) {
ecs_world_t *world = ecs_init();
ECS_IMPORT(world, SimpleModule);
ecs_entity_t e = ecs_lookup_fullpath(world, "simple.module.FooComponent");
test_assert(e != 0);
test_assert(e == ecs_id(SimpleFooComponent));
ecs_fini(world);
}
void Modules_name_prefix_tag(void) {
ecs_world_t *world = ecs_init();
ECS_IMPORT(world, SimpleModule);
ecs_entity_t e = ecs_lookup_fullpath(world, "simple.module.FooTag");
test_assert(e != 0);
test_assert(e == SimpleFooTag);
ecs_fini(world);
}
void Modules_name_prefix_system(void) {
ecs_world_t *world = ecs_init();
ECS_IMPORT(world, SimpleModule);
ecs_entity_t e = ecs_lookup_fullpath(world, "simple.module.FooSystem");
test_assert(e != 0);
test_assert(e == ecs_id(SimpleFooSystem));
ecs_fini(world);
}
void Modules_name_prefix_entity(void) {
ecs_world_t *world = ecs_init();
ECS_IMPORT(world, SimpleModule);
ecs_entity_t e = ecs_lookup_fullpath(world, "simple.module.FooEntity");
test_assert(e != 0);
test_assert(e == SimpleFooEntity);
ecs_fini(world);
}
void Modules_name_prefix_prefab(void) {
ecs_world_t *world = ecs_init();
ECS_IMPORT(world, SimpleModule);
ecs_entity_t e = ecs_lookup_fullpath(world, "simple.module.FooPrefab");
test_assert(e != 0);
test_assert(e == SimpleFooPrefab);
ecs_fini(world);
}
void Modules_name_prefix_pipeline(void) {
ecs_world_t *world = ecs_init();
ECS_IMPORT(world, SimpleModule);
ecs_entity_t e = ecs_lookup_fullpath(world, "simple.module.FooPipeline");
test_assert(e != 0);
test_assert(e == SimpleFooPipeline);
ecs_fini(world);
}
void Modules_name_prefix_trigger(void) {
ecs_world_t *world = ecs_init();
ECS_IMPORT(world, SimpleModule);
ecs_entity_t e = ecs_lookup_fullpath(world, "simple.module.FooTrigger");
test_assert(e != 0);
test_assert(e == ecs_id(SimpleFooTrigger));
ecs_fini(world);
}
void Modules_name_prefix_underscore(void) {
ecs_world_t *world = ecs_init();
ECS_IMPORT(world, SimpleModule);
ecs_entity_t e = ecs_lookup_fullpath(world, "simple.module.underscore");
test_assert(e != 0);
test_assert(e == Simple_underscore);
ecs_fini(world);
}
void Modules_lookup_by_symbol(void) {
ecs_world_t *world = ecs_init();
ECS_IMPORT(world, SimpleModule);
ecs_entity_t e = ecs_lookup_symbol(world, "Position", true, true);
test_assert(e != 0);
test_assert(e == ecs_id(Position));
e = ecs_lookup_symbol(world, "SimpleFooComponent", true, true);
test_assert(e != 0);
test_assert(e == ecs_id(SimpleFooComponent));
ecs_fini(world);
}
void Modules_nested_module(void) {
ecs_world_t *world = ecs_init();
ECS_IMPORT(world, SimpleModule);
ecs_entity_t e = ecs_lookup_fullpath(world, "nested.module.Component");
test_assert(e != 0);
char *path = ecs_get_fullpath(world, e);
test_str(path, "nested.module.Component");
ecs_os_free(path);
ecs_fini(world);
}
void Modules_module_tag_on_namespace(void) {
ecs_world_t *world = ecs_init();
ECS_IMPORT(world, SimpleModule);
ecs_entity_t mid = ecs_lookup_fullpath(world, "simple.module");
test_assert(mid != 0);
test_assert(ecs_has_id(world, mid, EcsModule));
ecs_entity_t nid = ecs_lookup_fullpath(world, "simple");
test_assert(nid != 0);
test_assert(ecs_has_id(world, nid, EcsModule));
ecs_fini(world);
}
void Modules_module_tag_on_namespace_on_add(void) {
ecs_world_t *world = ecs_init();
ecs_entity_t parent = ecs_new_id(world);
test_assert(parent != 0);
ecs_entity_t child = ecs_new_w_pair(world, EcsChildOf, parent);
test_assert(child != 0);
ecs_add_id(world, child, EcsModule);
test_assert( ecs_has_id(world, child, EcsModule));
test_assert( ecs_has_id(world, parent, EcsModule));
ecs_fini(world);
}
void Modules_module_tag_on_namespace_on_add_2_levels(void) {
ecs_world_t *world = ecs_init();
ecs_entity_t root = ecs_new_id(world);
test_assert(root != 0);
ecs_entity_t parent = ecs_new_w_pair(world, EcsChildOf, root);
test_assert(parent != 0);
ecs_entity_t child = ecs_new_w_pair(world, EcsChildOf, parent);
test_assert(child != 0);
ecs_add_id(world, child, EcsModule);
test_assert( ecs_has_id(world, child, EcsModule));
test_assert( ecs_has_id(world, parent, EcsModule));
test_assert( ecs_has_id(world, root, EcsModule));
ecs_fini(world);
}
void Modules_import_2_worlds(void) {
ecs_world_t *world_1 = ecs_init();
ecs_world_t *world_2 = ecs_init();
ECS_IMPORT(world_1, SimpleModule);
ECS_IMPORT(world_2, SimpleModule);
test_assert(ecs_lookup_fullpath(world_1, "simple.module") != 0);
test_assert(ecs_lookup_fullpath(world_2, "simple.module") != 0);
{
ecs_entity_t e = ecs_new(world_1, Position);
test_assert(e != 0);
test_assert( ecs_has(world_1, e, Position));
ecs_add(world_1, e, Velocity);
test_assert( ecs_has(world_1, e, Velocity));
}
{
ecs_entity_t e = ecs_new(world_2, Position);
test_assert(e != 0);
test_assert( ecs_has(world_2, e, Position));
ecs_add(world_2, e, Velocity);
test_assert( ecs_has(world_2, e, Velocity));
}
ecs_fini(world_1);
ecs_fini(world_2);
}
void Modules_import_monitor_2_worlds(void) {
ecs_world_t *world_1 = ecs_init();
ecs_world_t *world_2 = ecs_init();
ECS_IMPORT(world_1, FlecsMonitor);
ECS_IMPORT(world_2, FlecsMonitor);
test_assert(ecs_exists(world_1, ecs_id(FlecsMonitor)));
test_assert(ecs_exists(world_2, ecs_id(FlecsMonitor)));
ecs_fini(world_1);
ecs_fini(world_2);
}
void Modules_import_monitor_after_mini(void) {
ecs_world_t *world = ecs_mini();
ECS_IMPORT(world, FlecsMonitor);
test_assert(ecs_exists(world, ecs_id(FlecsMonitor)));
ecs_fini(world);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,613 @@
#include <addons.h>
void MultiTaskThreadStaging_setup(void) {
ecs_log_set_level(-3);
}
static
void MultiTaskThread_Add_to_current(ecs_iter_t *it) {
IterData *ctx = ecs_get_ctx(it->world);
int i;
for (i = 0; i < it->count; i ++) {
if (ctx->component) {
ecs_add_id(it->world, it->entities[i], ctx->component);
}
if (ctx->component_2) {
ecs_add_id(it->world, it->entities[i], ctx->component_2);
}
ctx->entity_count ++;
}
}
void MultiTaskThreadStaging_2_threads_add_to_current(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_COMPONENT(world, Rotation);
ECS_PREFAB(world, Type, Position, Velocity);
ECS_SYSTEM(world, MultiTaskThread_Add_to_current, EcsOnUpdate, Position);
ecs_system_init(world, &(ecs_system_desc_t){
.entity = MultiTaskThread_Add_to_current,
.multi_threaded = true
});
IterData ctx = {.component = ecs_id(Rotation)};
ecs_set_ctx(world, &ctx, NULL);
ecs_entity_t ids_1[100];
const ecs_entity_t *temp_ids_1 = ecs_bulk_new(world, Position, 100);
memcpy(ids_1, temp_ids_1, sizeof(ecs_entity_t) * 100);
const ecs_entity_t *ids_2 = bulk_new_w_type(world, Type, 100);
ecs_set_task_threads(world, 2);
ecs_progress(world, 1);
int i;
for (i = 0; i < 100; i ++) {
test_assert( ecs_has(world, ids_1[i], Position));
test_assert( ecs_has(world, ids_1[i], Rotation));
test_assert( !ecs_has(world, ids_1[i], Velocity));
}
for (i = 0; i < 100; i ++) {
test_assert( ecs_has(world, ids_2[i], Position));
test_assert( ecs_has(world, ids_2[i], Rotation));
test_assert( ecs_has(world, ids_2[i], Velocity));
}
ecs_fini(world);
}
void MultiTaskThreadStaging_3_threads_add_to_current(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_COMPONENT(world, Rotation);
ECS_PREFAB(world, Type, Position, Velocity);
ECS_SYSTEM(world, MultiTaskThread_Add_to_current, EcsOnUpdate, Position);
ecs_system_init(world, &(ecs_system_desc_t){
.entity = MultiTaskThread_Add_to_current,
.multi_threaded = true
});
IterData ctx = {.component = ecs_id(Rotation)};
ecs_set_ctx(world, &ctx, NULL);
ecs_entity_t ids_1[100];
const ecs_entity_t *temp_ids_1 = ecs_bulk_new(world, Position, 100);
memcpy(ids_1, temp_ids_1, sizeof(ecs_entity_t) * 100);
const ecs_entity_t *ids_2 = bulk_new_w_type(world, Type, 100);
ecs_set_task_threads(world, 3);
ecs_progress(world, 1);
int i;
for (i = 0; i < 100; i ++) {
test_assert( ecs_has(world, ids_1[i], Position));
test_assert( ecs_has(world, ids_1[i], Rotation));
test_assert( !ecs_has(world, ids_1[i], Velocity));
}
for (i = 0; i < 100; i ++) {
test_assert( ecs_has(world, ids_2[i], Position));
test_assert( ecs_has(world, ids_2[i], Rotation));
test_assert( ecs_has(world, ids_2[i], Velocity));
}
ecs_fini(world);
}
void MultiTaskThreadStaging_4_threads_add_to_current(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_COMPONENT(world, Rotation);
ECS_PREFAB(world, Type, Position, Velocity);
ECS_SYSTEM(world, MultiTaskThread_Add_to_current, EcsOnUpdate, Position);
ecs_system_init(world, &(ecs_system_desc_t){
.entity = MultiTaskThread_Add_to_current,
.multi_threaded = true
});
IterData ctx = {.component = ecs_id(Rotation)};
ecs_set_ctx(world, &ctx, NULL);
ecs_entity_t ids_1[100];
const ecs_entity_t *temp_ids_1 = ecs_bulk_new(world, Position, 100);
memcpy(ids_1, temp_ids_1, sizeof(ecs_entity_t) * 100);
const ecs_entity_t *ids_2 = bulk_new_w_type(world, Type, 100);
ecs_set_task_threads(world, 4);
ecs_progress(world, 1);
int i;
for (i = 0; i < 100; i ++) {
test_assert( ecs_has(world, ids_1[i], Position));
test_assert( ecs_has(world, ids_1[i], Rotation));
test_assert( !ecs_has(world, ids_1[i], Velocity));
}
for (i = 0; i < 100; i ++) {
test_assert( ecs_has(world, ids_2[i], Position));
test_assert( ecs_has(world, ids_2[i], Rotation));
test_assert( ecs_has(world, ids_2[i], Velocity));
}
ecs_fini(world);
}
void MultiTaskThreadStaging_5_threads_add_to_current(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_COMPONENT(world, Rotation);
ECS_PREFAB(world, Type, Position, Velocity);
ECS_SYSTEM(world, MultiTaskThread_Add_to_current, EcsOnUpdate, Position);
ecs_system_init(world, &(ecs_system_desc_t){
.entity = MultiTaskThread_Add_to_current,
.multi_threaded = true
});
IterData ctx = {.component = ecs_id(Rotation)};
ecs_set_ctx(world, &ctx, NULL);
ecs_entity_t ids_1[100];
const ecs_entity_t *temp_ids_1 = ecs_bulk_new(world, Position, 100);
memcpy(ids_1, temp_ids_1, sizeof(ecs_entity_t) * 100);
const ecs_entity_t *ids_2 = bulk_new_w_type(world, Type, 100);
ecs_set_task_threads(world, 5);
ecs_progress(world, 1);
int i;
for (i = 0; i < 100; i ++) {
test_assert( ecs_has(world, ids_1[i], Position));
test_assert( ecs_has(world, ids_1[i], Rotation));
test_assert( !ecs_has(world, ids_1[i], Velocity));
}
for (i = 0; i < 100; i ++) {
test_assert( ecs_has(world, ids_2[i], Position));
test_assert( ecs_has(world, ids_2[i], Rotation));
test_assert( ecs_has(world, ids_2[i], Velocity));
}
ecs_fini(world);
}
void MultiTaskThreadStaging_6_threads_add_to_current(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_COMPONENT(world, Rotation);
ECS_PREFAB(world, Type, Position, Velocity);
ECS_SYSTEM(world, MultiTaskThread_Add_to_current, EcsOnUpdate, Position);
ecs_system_init(world, &(ecs_system_desc_t){
.entity = MultiTaskThread_Add_to_current,
.multi_threaded = true
});
IterData ctx = {.component = ecs_id(Rotation)};
ecs_set_ctx(world, &ctx, NULL);
ecs_entity_t ids_1[100];
const ecs_entity_t *temp_ids_1 = ecs_bulk_new(world, Position, 100);
memcpy(ids_1, temp_ids_1, sizeof(ecs_entity_t) * 100);
const ecs_entity_t *ids_2 = bulk_new_w_type(world, Type, 100);
ecs_set_task_threads(world, 6);
ecs_progress(world, 1);
int i;
for (i = 0; i < 100; i ++) {
test_assert( ecs_has(world, ids_1[i], Position));
test_assert( ecs_has(world, ids_1[i], Rotation));
test_assert( !ecs_has(world, ids_1[i], Velocity));
}
for (i = 0; i < 100; i ++) {
test_assert( ecs_has(world, ids_2[i], Position));
test_assert( ecs_has(world, ids_2[i], Rotation));
test_assert( ecs_has(world, ids_2[i], Velocity));
}
ecs_fini(world);
}
static
void InitVelocity(ecs_iter_t *it) {
Velocity *v = ecs_field(it, Velocity, 1);
int i;
for (i = 0; i < it->count; i ++) {
v[i].x = 10;
v[i].y = 20;
}
}
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_add(it->world, it->entities[i], Velocity);
}
}
void MultiTaskThreadStaging_2_threads_on_add(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_OBSERVER(world, InitVelocity, EcsOnAdd, Velocity);
ECS_SYSTEM(world, AddVelocity, EcsOnUpdate, Position, Velocity());
ecs_system_init(world, &(ecs_system_desc_t){
.entity = AddVelocity,
.multi_threaded = true
});
Probe ctx = {0};
ecs_set_ctx(world, &ctx, NULL);
const ecs_entity_t *ids = ecs_bulk_new(world, Position, 10);
test_assert(ids != NULL);
ecs_set_task_threads(world, 2);
ecs_progress(world, 0);
int i;
for (i = 0; i < 10; i ++) {
ecs_entity_t e = ids[i];
test_assert( ecs_has(world, e, Velocity));
const Velocity *v = ecs_get(world, e, Velocity);
test_assert(v != NULL);
test_int(v->x, 10);
test_int(v->y, 20);
}
ecs_fini(world);
}
static
void New_w_count(ecs_iter_t *it) {
ecs_id_t ecs_id(Position) = ecs_field_id(it, 1);
ecs_bulk_new(it->world, Position, 10);
}
void MultiTaskThreadStaging_new_w_count(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_SYSTEM(world, New_w_count, EcsOnUpdate, Position());
ecs_system_init(world, &(ecs_system_desc_t){
.entity = New_w_count,
.multi_threaded = true
});
ecs_set_task_threads(world, 2);
ecs_progress(world, 0);
test_int( ecs_count(world, Position), 10);
ecs_fini(world);
}
void MultiTaskThreadStaging_custom_thread_auto_merge(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ecs_entity_t e1 = ecs_new_id(world);
ecs_entity_t e2 = ecs_new_id(world);
ecs_set_stage_count(world, 2);
ecs_world_t *ctx_1 = ecs_get_stage(world, 0);
ecs_world_t *ctx_2 = ecs_get_stage(world, 1);
ecs_frame_begin(world, 0);
ecs_readonly_begin(world);
/* thread 1 */
ecs_defer_begin(ctx_1);
ecs_set(ctx_1, e1, Position, {10, 20});
test_assert(!ecs_has(world, e1, Position));
test_assert(!ecs_has(ctx_1, e1, Position));
ecs_defer_end(ctx_1);
test_assert(!ecs_has(world, e1, Position));
test_assert(!ecs_has(ctx_1, e1, Position));
/* thread 2 */
ecs_defer_begin(ctx_2);
ecs_set(ctx_2, e2, Position, {20, 30});
test_assert(!ecs_has(world, e2, Position));
test_assert(!ecs_has(ctx_2, e2, Position));
ecs_defer_end(ctx_2);
test_assert(!ecs_has(world, e2, Position));
test_assert(!ecs_has(ctx_2, e2, Position));
ecs_readonly_end(world);
ecs_frame_end(world);
test_assert(ecs_has(world, e1, Position));
test_assert(ecs_has(world, e2, Position));
const Position *p1 = ecs_get(world, e1, Position);
test_int(p1->x, 10);
test_int(p1->y, 20);
const Position *p2 = ecs_get(world, e2, Position);
test_int(p2->x, 20);
test_int(p2->y, 30);
ecs_fini(world);
}
void MultiTaskThreadStaging_custom_thread_manual_merge(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ecs_entity_t e1 = ecs_new_id(world);
ecs_entity_t e2 = ecs_new_id(world);
ecs_set_automerge(world, false);
ecs_set_stage_count(world, 2);
ecs_world_t *ctx_1 = ecs_get_stage(world, 0);
ecs_world_t *ctx_2 = ecs_get_stage(world, 1);
ecs_frame_begin(world, 0);
ecs_readonly_begin(world);
/* thread 1 */
ecs_defer_begin(ctx_1);
ecs_set(ctx_1, e1, Position, {10, 20});
test_assert(!ecs_has(world, e1, Position));
test_assert(!ecs_has(ctx_1, e1, Position));
ecs_defer_end(ctx_1);
test_assert(!ecs_has(world, e1, Position));
test_assert(!ecs_has(ctx_1, e1, Position));
/* thread 2 */
ecs_defer_begin(ctx_2);
ecs_set(ctx_2, e2, Position, {20, 30});
test_assert(!ecs_has(world, e2, Position));
test_assert(!ecs_has(ctx_2, e2, Position));
ecs_defer_end(ctx_2);
test_assert(!ecs_has(world, e2, Position));
test_assert(!ecs_has(ctx_2, e2, Position));
ecs_readonly_end(world);
ecs_frame_end(world);
test_assert(!ecs_has(world, e1, Position));
test_assert(!ecs_has(world, e2, Position));
ecs_merge(world);
test_assert(ecs_has(world, e1, Position));
test_assert(ecs_has(world, e2, Position));
const Position *p1 = ecs_get(world, e1, Position);
test_int(p1->x, 10);
test_int(p1->y, 20);
const Position *p2 = ecs_get(world, e2, Position);
test_int(p2->x, 20);
test_int(p2->y, 30);
ecs_fini(world);
}
void MultiTaskThreadStaging_custom_thread_partial_manual_merge(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ecs_entity_t e1 = ecs_new_id(world);
ecs_entity_t e2 = ecs_new_id(world);
ecs_set_stage_count(world, 2);
ecs_world_t *ctx_1 = ecs_get_stage(world, 0);
ecs_world_t *ctx_2 = ecs_get_stage(world, 1);
/* Only disable automerging for ctx_2 */
ecs_set_automerge(ctx_2, false);
ecs_frame_begin(world, 0);
ecs_readonly_begin(world);
/* thread 1 */
ecs_defer_begin(ctx_1);
ecs_set(ctx_1, e1, Position, {10, 20});
test_assert(!ecs_has(world, e1, Position));
test_assert(!ecs_has(ctx_1, e1, Position));
ecs_defer_end(ctx_1);
test_assert(!ecs_has(world, e1, Position));
test_assert(!ecs_has(ctx_1, e1, Position));
/* thread 2 */
ecs_defer_begin(ctx_2);
ecs_set(ctx_2, e2, Position, {20, 30});
test_assert(!ecs_has(world, e2, Position));
test_assert(!ecs_has(ctx_2, e2, Position));
ecs_defer_end(ctx_2);
test_assert(!ecs_has(world, e2, Position));
test_assert(!ecs_has(ctx_2, e2, Position));
ecs_readonly_end(world);
ecs_frame_end(world);
test_assert(ecs_has(world, e1, Position));
test_assert(!ecs_has(world, e2, Position));
const Position *p1 = ecs_get(world, e1, Position);
test_int(p1->x, 10);
test_int(p1->y, 20);
ecs_merge(ctx_2);
test_assert(ecs_has(world, e1, Position));
test_assert(ecs_has(world, e2, Position));
p1 = ecs_get(world, e1, Position);
test_int(p1->x, 10);
test_int(p1->y, 20);
const Position *p2 = ecs_get(world, e2, Position);
test_int(p2->x, 20);
test_int(p2->y, 30);
ecs_fini(world);
}
void MultiTaskThreadStaging_set_pair_w_new_target_readonly(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ecs_set_task_threads(world, 2);
ecs_entity_t e = ecs_new_id(world);
ecs_world_t *thr_1 = ecs_get_stage(world, 0);
ecs_frame_begin(world, 0);
ecs_readonly_begin(world);
ecs_entity_t tgt = ecs_new_id(thr_1);
ecs_set_pair(thr_1, e, Position, tgt, {10, 20});
ecs_readonly_end(world);
ecs_frame_end(world);
test_assert(ecs_has_pair(world, e, ecs_id(Position), tgt));
const Position *p = ecs_get_pair(world, e, Position, tgt);
test_assert(p != NULL);
test_int(p->x, 10);
test_int(p->y, 20);
ecs_fini(world);
}
void MultiTaskThreadStaging_set_pair_w_new_target_tgt_component_readonly(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ecs_set_task_threads(world, 2);
ecs_entity_t e = ecs_new_id(world);
ecs_world_t *thr_1 = ecs_get_stage(world, 0);
ecs_frame_begin(world, 0);
ecs_readonly_begin(world);
ecs_entity_t tgt = ecs_new_id(thr_1);
ecs_set_pair_second(thr_1, e, tgt, Position, {10, 20});
ecs_readonly_end(world);
ecs_frame_end(world);
test_assert(ecs_has_pair(world, e, tgt, ecs_id(Position)));
const Position *p = ecs_get_pair_second(world, e, tgt, Position);
test_assert(p != NULL);
test_int(p->x, 10);
test_int(p->y, 20);
ecs_fini(world);
}
void MultiTaskThreadStaging_set_pair_w_new_target_defer(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ecs_set_task_threads(world, 2);
ecs_entity_t e = ecs_new_id(world);
ecs_defer_begin(world);
ecs_entity_t tgt = ecs_new_id(world);
ecs_set_pair(world, e, Position, tgt, {10, 20});
ecs_defer_end(world);
test_assert(ecs_has_pair(world, e, ecs_id(Position), tgt));
const Position *p = ecs_get_pair(world, e, Position, tgt);
test_assert(p != NULL);
test_int(p->x, 10);
test_int(p->y, 20);
ecs_fini(world);
}
void MultiTaskThreadStaging_set_pair_w_new_target_tgt_component_defer(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ecs_set_task_threads(world, 2);
ecs_entity_t e = ecs_new_id(world);
ecs_defer_begin(world);
ecs_entity_t tgt = ecs_new_id(world);
ecs_set_pair_second(world, e, tgt, Position, {10, 20});
ecs_defer_end(world);
test_assert(ecs_has_pair(world, e, tgt, ecs_id(Position)));
const Position *p = ecs_get_pair_second(world, e, tgt, Position);
test_assert(p != NULL);
test_int(p->x, 10);
test_int(p->y, 20);
ecs_fini(world);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,613 @@
#include <addons.h>
void MultiThreadStaging_setup(void) {
ecs_log_set_level(-3);
}
static
void Add_to_current(ecs_iter_t *it) {
IterData *ctx = ecs_get_ctx(it->world);
int i;
for (i = 0; i < it->count; i ++) {
if (ctx->component) {
ecs_add_id(it->world, it->entities[i], ctx->component);
}
if (ctx->component_2) {
ecs_add_id(it->world, it->entities[i], ctx->component_2);
}
ctx->entity_count ++;
}
}
void MultiThreadStaging_2_threads_add_to_current(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_COMPONENT(world, Rotation);
ECS_PREFAB(world, Type, Position, Velocity);
ECS_SYSTEM(world, Add_to_current, EcsOnUpdate, Position);
ecs_system_init(world, &(ecs_system_desc_t){
.entity = Add_to_current,
.multi_threaded = true
});
IterData ctx = {.component = ecs_id(Rotation)};
ecs_set_ctx(world, &ctx, NULL);
ecs_entity_t ids_1[100];
const ecs_entity_t *temp_ids_1 = ecs_bulk_new(world, Position, 100);
memcpy(ids_1, temp_ids_1, sizeof(ecs_entity_t) * 100);
const ecs_entity_t *ids_2 = bulk_new_w_type(world, Type, 100);
ecs_set_threads(world, 2);
ecs_progress(world, 1);
int i;
for (i = 0; i < 100; i ++) {
test_assert( ecs_has(world, ids_1[i], Position));
test_assert( ecs_has(world, ids_1[i], Rotation));
test_assert( !ecs_has(world, ids_1[i], Velocity));
}
for (i = 0; i < 100; i ++) {
test_assert( ecs_has(world, ids_2[i], Position));
test_assert( ecs_has(world, ids_2[i], Rotation));
test_assert( ecs_has(world, ids_2[i], Velocity));
}
ecs_fini(world);
}
void MultiThreadStaging_3_threads_add_to_current(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_COMPONENT(world, Rotation);
ECS_PREFAB(world, Type, Position, Velocity);
ECS_SYSTEM(world, Add_to_current, EcsOnUpdate, Position);
ecs_system_init(world, &(ecs_system_desc_t){
.entity = Add_to_current,
.multi_threaded = true
});
IterData ctx = {.component = ecs_id(Rotation)};
ecs_set_ctx(world, &ctx, NULL);
ecs_entity_t ids_1[100];
const ecs_entity_t *temp_ids_1 = ecs_bulk_new(world, Position, 100);
memcpy(ids_1, temp_ids_1, sizeof(ecs_entity_t) * 100);
const ecs_entity_t *ids_2 = bulk_new_w_type(world, Type, 100);
ecs_set_threads(world, 3);
ecs_progress(world, 1);
int i;
for (i = 0; i < 100; i ++) {
test_assert( ecs_has(world, ids_1[i], Position));
test_assert( ecs_has(world, ids_1[i], Rotation));
test_assert( !ecs_has(world, ids_1[i], Velocity));
}
for (i = 0; i < 100; i ++) {
test_assert( ecs_has(world, ids_2[i], Position));
test_assert( ecs_has(world, ids_2[i], Rotation));
test_assert( ecs_has(world, ids_2[i], Velocity));
}
ecs_fini(world);
}
void MultiThreadStaging_4_threads_add_to_current(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_COMPONENT(world, Rotation);
ECS_PREFAB(world, Type, Position, Velocity);
ECS_SYSTEM(world, Add_to_current, EcsOnUpdate, Position);
ecs_system_init(world, &(ecs_system_desc_t){
.entity = Add_to_current,
.multi_threaded = true
});
IterData ctx = {.component = ecs_id(Rotation)};
ecs_set_ctx(world, &ctx, NULL);
ecs_entity_t ids_1[100];
const ecs_entity_t *temp_ids_1 = ecs_bulk_new(world, Position, 100);
memcpy(ids_1, temp_ids_1, sizeof(ecs_entity_t) * 100);
const ecs_entity_t *ids_2 = bulk_new_w_type(world, Type, 100);
ecs_set_threads(world, 4);
ecs_progress(world, 1);
int i;
for (i = 0; i < 100; i ++) {
test_assert( ecs_has(world, ids_1[i], Position));
test_assert( ecs_has(world, ids_1[i], Rotation));
test_assert( !ecs_has(world, ids_1[i], Velocity));
}
for (i = 0; i < 100; i ++) {
test_assert( ecs_has(world, ids_2[i], Position));
test_assert( ecs_has(world, ids_2[i], Rotation));
test_assert( ecs_has(world, ids_2[i], Velocity));
}
ecs_fini(world);
}
void MultiThreadStaging_5_threads_add_to_current(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_COMPONENT(world, Rotation);
ECS_PREFAB(world, Type, Position, Velocity);
ECS_SYSTEM(world, Add_to_current, EcsOnUpdate, Position);
ecs_system_init(world, &(ecs_system_desc_t){
.entity = Add_to_current,
.multi_threaded = true
});
IterData ctx = {.component = ecs_id(Rotation)};
ecs_set_ctx(world, &ctx, NULL);
ecs_entity_t ids_1[100];
const ecs_entity_t *temp_ids_1 = ecs_bulk_new(world, Position, 100);
memcpy(ids_1, temp_ids_1, sizeof(ecs_entity_t) * 100);
const ecs_entity_t *ids_2 = bulk_new_w_type(world, Type, 100);
ecs_set_threads(world, 5);
ecs_progress(world, 1);
int i;
for (i = 0; i < 100; i ++) {
test_assert( ecs_has(world, ids_1[i], Position));
test_assert( ecs_has(world, ids_1[i], Rotation));
test_assert( !ecs_has(world, ids_1[i], Velocity));
}
for (i = 0; i < 100; i ++) {
test_assert( ecs_has(world, ids_2[i], Position));
test_assert( ecs_has(world, ids_2[i], Rotation));
test_assert( ecs_has(world, ids_2[i], Velocity));
}
ecs_fini(world);
}
void MultiThreadStaging_6_threads_add_to_current(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_COMPONENT(world, Rotation);
ECS_PREFAB(world, Type, Position, Velocity);
ECS_SYSTEM(world, Add_to_current, EcsOnUpdate, Position);
ecs_system_init(world, &(ecs_system_desc_t){
.entity = Add_to_current,
.multi_threaded = true
});
IterData ctx = {.component = ecs_id(Rotation)};
ecs_set_ctx(world, &ctx, NULL);
ecs_entity_t ids_1[100];
const ecs_entity_t *temp_ids_1 = ecs_bulk_new(world, Position, 100);
memcpy(ids_1, temp_ids_1, sizeof(ecs_entity_t) * 100);
const ecs_entity_t *ids_2 = bulk_new_w_type(world, Type, 100);
ecs_set_threads(world, 6);
ecs_progress(world, 1);
int i;
for (i = 0; i < 100; i ++) {
test_assert( ecs_has(world, ids_1[i], Position));
test_assert( ecs_has(world, ids_1[i], Rotation));
test_assert( !ecs_has(world, ids_1[i], Velocity));
}
for (i = 0; i < 100; i ++) {
test_assert( ecs_has(world, ids_2[i], Position));
test_assert( ecs_has(world, ids_2[i], Rotation));
test_assert( ecs_has(world, ids_2[i], Velocity));
}
ecs_fini(world);
}
static
void InitVelocity(ecs_iter_t *it) {
Velocity *v = ecs_field(it, Velocity, 1);
int i;
for (i = 0; i < it->count; i ++) {
v[i].x = 10;
v[i].y = 20;
}
}
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_add(it->world, it->entities[i], Velocity);
}
}
void MultiThreadStaging_2_threads_on_add(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_OBSERVER(world, InitVelocity, EcsOnAdd, Velocity);
ECS_SYSTEM(world, AddVelocity, EcsOnUpdate, Position, Velocity());
ecs_system_init(world, &(ecs_system_desc_t){
.entity = AddVelocity,
.multi_threaded = true
});
Probe ctx = {0};
ecs_set_ctx(world, &ctx, NULL);
const ecs_entity_t *ids = ecs_bulk_new(world, Position, 10);
test_assert(ids != NULL);
ecs_set_threads(world, 2);
ecs_progress(world, 0);
int i;
for (i = 0; i < 10; i ++) {
ecs_entity_t e = ids[i];
test_assert( ecs_has(world, e, Velocity));
const Velocity *v = ecs_get(world, e, Velocity);
test_assert(v != NULL);
test_int(v->x, 10);
test_int(v->y, 20);
}
ecs_fini(world);
}
static
void New_w_count(ecs_iter_t *it) {
ecs_id_t ecs_id(Position) = ecs_field_id(it, 1);
ecs_bulk_new(it->world, Position, 10);
}
void MultiThreadStaging_new_w_count(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_SYSTEM(world, New_w_count, EcsOnUpdate, Position());
ecs_system_init(world, &(ecs_system_desc_t){
.entity = New_w_count,
.multi_threaded = true
});
ecs_set_threads(world, 2);
ecs_progress(world, 0);
test_int( ecs_count(world, Position), 10);
ecs_fini(world);
}
void MultiThreadStaging_custom_thread_auto_merge(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ecs_entity_t e1 = ecs_new_id(world);
ecs_entity_t e2 = ecs_new_id(world);
ecs_set_stage_count(world, 2);
ecs_world_t *ctx_1 = ecs_get_stage(world, 0);
ecs_world_t *ctx_2 = ecs_get_stage(world, 1);
ecs_frame_begin(world, 0);
ecs_readonly_begin(world);
/* thread 1 */
ecs_defer_begin(ctx_1);
ecs_set(ctx_1, e1, Position, {10, 20});
test_assert(!ecs_has(world, e1, Position));
test_assert(!ecs_has(ctx_1, e1, Position));
ecs_defer_end(ctx_1);
test_assert(!ecs_has(world, e1, Position));
test_assert(!ecs_has(ctx_1, e1, Position));
/* thread 2 */
ecs_defer_begin(ctx_2);
ecs_set(ctx_2, e2, Position, {20, 30});
test_assert(!ecs_has(world, e2, Position));
test_assert(!ecs_has(ctx_2, e2, Position));
ecs_defer_end(ctx_2);
test_assert(!ecs_has(world, e2, Position));
test_assert(!ecs_has(ctx_2, e2, Position));
ecs_readonly_end(world);
ecs_frame_end(world);
test_assert(ecs_has(world, e1, Position));
test_assert(ecs_has(world, e2, Position));
const Position *p1 = ecs_get(world, e1, Position);
test_int(p1->x, 10);
test_int(p1->y, 20);
const Position *p2 = ecs_get(world, e2, Position);
test_int(p2->x, 20);
test_int(p2->y, 30);
ecs_fini(world);
}
void MultiThreadStaging_custom_thread_manual_merge(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ecs_entity_t e1 = ecs_new_id(world);
ecs_entity_t e2 = ecs_new_id(world);
ecs_set_automerge(world, false);
ecs_set_stage_count(world, 2);
ecs_world_t *ctx_1 = ecs_get_stage(world, 0);
ecs_world_t *ctx_2 = ecs_get_stage(world, 1);
ecs_frame_begin(world, 0);
ecs_readonly_begin(world);
/* thread 1 */
ecs_defer_begin(ctx_1);
ecs_set(ctx_1, e1, Position, {10, 20});
test_assert(!ecs_has(world, e1, Position));
test_assert(!ecs_has(ctx_1, e1, Position));
ecs_defer_end(ctx_1);
test_assert(!ecs_has(world, e1, Position));
test_assert(!ecs_has(ctx_1, e1, Position));
/* thread 2 */
ecs_defer_begin(ctx_2);
ecs_set(ctx_2, e2, Position, {20, 30});
test_assert(!ecs_has(world, e2, Position));
test_assert(!ecs_has(ctx_2, e2, Position));
ecs_defer_end(ctx_2);
test_assert(!ecs_has(world, e2, Position));
test_assert(!ecs_has(ctx_2, e2, Position));
ecs_readonly_end(world);
ecs_frame_end(world);
test_assert(!ecs_has(world, e1, Position));
test_assert(!ecs_has(world, e2, Position));
ecs_merge(world);
test_assert(ecs_has(world, e1, Position));
test_assert(ecs_has(world, e2, Position));
const Position *p1 = ecs_get(world, e1, Position);
test_int(p1->x, 10);
test_int(p1->y, 20);
const Position *p2 = ecs_get(world, e2, Position);
test_int(p2->x, 20);
test_int(p2->y, 30);
ecs_fini(world);
}
void MultiThreadStaging_custom_thread_partial_manual_merge(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ecs_entity_t e1 = ecs_new_id(world);
ecs_entity_t e2 = ecs_new_id(world);
ecs_set_stage_count(world, 2);
ecs_world_t *ctx_1 = ecs_get_stage(world, 0);
ecs_world_t *ctx_2 = ecs_get_stage(world, 1);
/* Only disable automerging for ctx_2 */
ecs_set_automerge(ctx_2, false);
ecs_frame_begin(world, 0);
ecs_readonly_begin(world);
/* thread 1 */
ecs_defer_begin(ctx_1);
ecs_set(ctx_1, e1, Position, {10, 20});
test_assert(!ecs_has(world, e1, Position));
test_assert(!ecs_has(ctx_1, e1, Position));
ecs_defer_end(ctx_1);
test_assert(!ecs_has(world, e1, Position));
test_assert(!ecs_has(ctx_1, e1, Position));
/* thread 2 */
ecs_defer_begin(ctx_2);
ecs_set(ctx_2, e2, Position, {20, 30});
test_assert(!ecs_has(world, e2, Position));
test_assert(!ecs_has(ctx_2, e2, Position));
ecs_defer_end(ctx_2);
test_assert(!ecs_has(world, e2, Position));
test_assert(!ecs_has(ctx_2, e2, Position));
ecs_readonly_end(world);
ecs_frame_end(world);
test_assert(ecs_has(world, e1, Position));
test_assert(!ecs_has(world, e2, Position));
const Position *p1 = ecs_get(world, e1, Position);
test_int(p1->x, 10);
test_int(p1->y, 20);
ecs_merge(ctx_2);
test_assert(ecs_has(world, e1, Position));
test_assert(ecs_has(world, e2, Position));
p1 = ecs_get(world, e1, Position);
test_int(p1->x, 10);
test_int(p1->y, 20);
const Position *p2 = ecs_get(world, e2, Position);
test_int(p2->x, 20);
test_int(p2->y, 30);
ecs_fini(world);
}
void MultiThreadStaging_set_pair_w_new_target_readonly(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ecs_set_threads(world, 2);
ecs_entity_t e = ecs_new_id(world);
ecs_world_t *thr_1 = ecs_get_stage(world, 0);
ecs_frame_begin(world, 0);
ecs_readonly_begin(world);
ecs_entity_t tgt = ecs_new_id(thr_1);
ecs_set_pair(thr_1, e, Position, tgt, {10, 20});
ecs_readonly_end(world);
ecs_frame_end(world);
test_assert(ecs_has_pair(world, e, ecs_id(Position), tgt));
const Position *p = ecs_get_pair(world, e, Position, tgt);
test_assert(p != NULL);
test_int(p->x, 10);
test_int(p->y, 20);
ecs_fini(world);
}
void MultiThreadStaging_set_pair_w_new_target_tgt_component_readonly(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ecs_set_threads(world, 2);
ecs_entity_t e = ecs_new_id(world);
ecs_world_t *thr_1 = ecs_get_stage(world, 0);
ecs_frame_begin(world, 0);
ecs_readonly_begin(world);
ecs_entity_t tgt = ecs_new_id(thr_1);
ecs_set_pair_second(thr_1, e, tgt, Position, {10, 20});
ecs_readonly_end(world);
ecs_frame_end(world);
test_assert(ecs_has_pair(world, e, tgt, ecs_id(Position)));
const Position *p = ecs_get_pair_second(world, e, tgt, Position);
test_assert(p != NULL);
test_int(p->x, 10);
test_int(p->y, 20);
ecs_fini(world);
}
void MultiThreadStaging_set_pair_w_new_target_defer(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ecs_set_threads(world, 2);
ecs_entity_t e = ecs_new_id(world);
ecs_defer_begin(world);
ecs_entity_t tgt = ecs_new_id(world);
ecs_set_pair(world, e, Position, tgt, {10, 20});
ecs_defer_end(world);
test_assert(ecs_has_pair(world, e, ecs_id(Position), tgt));
const Position *p = ecs_get_pair(world, e, Position, tgt);
test_assert(p != NULL);
test_int(p->x, 10);
test_int(p->y, 20);
ecs_fini(world);
}
void MultiThreadStaging_set_pair_w_new_target_tgt_component_defer(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ecs_set_threads(world, 2);
ecs_entity_t e = ecs_new_id(world);
ecs_defer_begin(world);
ecs_entity_t tgt = ecs_new_id(world);
ecs_set_pair_second(world, e, tgt, Position, {10, 20});
ecs_defer_end(world);
test_assert(ecs_has_pair(world, e, tgt, ecs_id(Position)));
const Position *p = ecs_get_pair_second(world, e, tgt, Position);
test_assert(p != NULL);
test_int(p->x, 10);
test_int(p->y, 20);
ecs_fini(world);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,33 @@
#include <addons.h>
void Rest_teardown(void) {
ecs_world_t *world = ecs_init();
ecs_singleton_set(world, EcsRest, {27760});
ecs_fini(world);
test_assert(true); // Ensure teardown was successful
}
void Rest_get(void) {
ecs_world_t *world = ecs_init();
ecs_http_server_t *srv = ecs_rest_server_init(world, NULL);
test_assert(srv != NULL);
ecs_http_reply_t reply = ECS_HTTP_REPLY_INIT;
test_int(0, ecs_http_server_request(srv, "GET",
"/entity/flecs/core/World?label=true", &reply));
test_int(reply.code, 200);
char *reply_str = ecs_strbuf_get(&reply.body);
test_assert(reply_str != NULL);
test_str(reply_str,
"{\"path\":\"flecs.core.World\", \"label\":\"World\", \"ids\":[]}");
ecs_os_free(reply_str);
ecs_rest_server_fini(srv);
ecs_fini(world);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,208 @@
#include <addons.h>
static ecs_entity_t recycled_id(ecs_world_t *world, const char *name) {
ecs_entity_t result = ecs_new_id(world);
ecs_delete(world, result);
ecs_entity_t result_2 = ecs_new_id(world);
test_assert(result_2 != (uint32_t)result);
ecs_set_name(world, result_2, name);
return result_2;
}
void RulesRecycled_recycled_vars(void) {
ecs_world_t *world = ecs_init();
ECS_TAG(world, Tag);
ecs_entity_t src = recycled_id(world, "src");
ecs_entity_t rel = recycled_id(world, "rel");
ecs_add(world, src, Tag);
ecs_add_id(world, src, rel);
ecs_rule_t *r = ecs_rule(world, {
.expr = "$x($y), Tag($y)"
});
test_assert(r != NULL);
int32_t x_var = ecs_rule_find_var(r, "x");
test_assert(x_var != -1);
int32_t y_var = ecs_rule_find_var(r, "y");
test_assert(y_var != -1);
ecs_iter_t it = ecs_rule_iter(world, r);
test_bool(true, ecs_rule_next(&it));
test_uint(0, it.count);
test_uint(Tag, ecs_field_id(&it, 1));
test_uint(Tag, ecs_field_id(&it, 2));
test_uint(src, ecs_field_src(&it, 1));
test_uint(src, ecs_field_src(&it, 2));
test_uint(Tag, ecs_iter_get_var(&it, x_var));
test_uint(src, ecs_iter_get_var(&it, y_var));
test_bool(true, ecs_rule_next(&it));
test_uint(0, it.count);
test_uint(rel, ecs_field_id(&it, 1));
test_uint(Tag, ecs_field_id(&it, 2));
test_uint(src, ecs_field_src(&it, 1));
test_uint(src, ecs_field_src(&it, 2));
test_uint(rel, ecs_iter_get_var(&it, x_var));
test_uint(src, ecs_iter_get_var(&it, y_var));
test_bool(false, ecs_rule_next(&it));
ecs_rule_fini(r);
ecs_fini(world);
}
void RulesRecycled_recycled_pair_vars(void) {
ecs_world_t *world = ecs_init();
ECS_TAG(world, Tag);
ecs_entity_t src = recycled_id(world, "src");
ecs_entity_t rel = recycled_id(world, "rel");
ecs_entity_t tgt = recycled_id(world, "tgt");
ecs_add(world, src, Tag);
ecs_add_pair(world, src, rel, tgt);
ecs_rule_t *r = ecs_rule(world, {
.expr = "$x($y, $z), Tag($y)"
});
test_assert(r != NULL);
int32_t x_var = ecs_rule_find_var(r, "x");
test_assert(x_var != -1);
int32_t y_var = ecs_rule_find_var(r, "y");
test_assert(y_var != -1);
int32_t z_var = ecs_rule_find_var(r, "z");
test_assert(z_var != -1);
ecs_iter_t it = ecs_rule_iter(world, r);
test_bool(true, ecs_rule_next(&it));
test_uint(0, it.count);
test_uint(ecs_pair(ecs_id(EcsIdentifier), EcsName), ecs_field_id(&it, 1));
test_uint(Tag, ecs_field_id(&it, 2));
test_uint(src, ecs_field_src(&it, 1));
test_uint(src, ecs_field_src(&it, 2));
test_uint(ecs_id(EcsIdentifier), ecs_iter_get_var(&it, x_var));
test_uint(src, ecs_iter_get_var(&it, y_var));
test_uint(EcsName, ecs_iter_get_var(&it, z_var));
test_bool(true, ecs_rule_next(&it));
test_uint(0, it.count);
test_uint(ecs_pair(rel, tgt), ecs_field_id(&it, 1));
test_uint(Tag, ecs_field_id(&it, 2));
test_uint(src, ecs_field_src(&it, 1));
test_uint(src, ecs_field_src(&it, 2));
test_uint(rel, ecs_iter_get_var(&it, x_var));
test_uint(src, ecs_iter_get_var(&it, y_var));
test_uint(tgt, ecs_iter_get_var(&it, z_var));
test_bool(false, ecs_rule_next(&it));
ecs_rule_fini(r);
ecs_fini(world);
}
void RulesRecycled_recycled_this_ent_var(void) {
ecs_world_t *world = ecs_init();
ECS_TAG(world, Tag);
ecs_entity_t src = recycled_id(world, "src");
ecs_entity_t rel = recycled_id(world, "rel");
ecs_entity_t tgt = recycled_id(world, "tgt");
ecs_add(world, src, Tag);
ecs_add_pair(world, src, rel, tgt);
ecs_rule_t *r = ecs_rule(world, {
.expr = "$x($y, $this), Tag($y)"
});
test_assert(r != NULL);
int32_t x_var = ecs_rule_find_var(r, "x");
test_assert(x_var != -1);
int32_t y_var = ecs_rule_find_var(r, "y");
test_assert(y_var != -1);
int32_t this_var = ecs_rule_find_var(r, "This");
test_assert(this_var != -1);
ecs_iter_t it = ecs_rule_iter(world, r);
test_bool(true, ecs_rule_next(&it));
test_uint(1, it.count);
test_uint(ecs_pair(ecs_id(EcsIdentifier), EcsName), ecs_field_id(&it, 1));
test_uint(Tag, ecs_field_id(&it, 2));
test_uint(src, ecs_field_src(&it, 1));
test_uint(src, ecs_field_src(&it, 2));
test_uint(ecs_id(EcsIdentifier), ecs_iter_get_var(&it, x_var));
test_uint(src, ecs_iter_get_var(&it, y_var));
test_uint(EcsName, ecs_iter_get_var(&it, this_var));
test_uint(EcsName, it.entities[0]);
test_bool(true, ecs_rule_next(&it));
test_uint(1, it.count);
test_uint(ecs_pair(rel, tgt), ecs_field_id(&it, 1));
test_uint(Tag, ecs_field_id(&it, 2));
test_uint(src, ecs_field_src(&it, 1));
test_uint(src, ecs_field_src(&it, 2));
test_uint(rel, ecs_iter_get_var(&it, x_var));
test_uint(src, ecs_iter_get_var(&it, y_var));
test_uint(tgt, ecs_iter_get_var(&it, this_var));
test_uint(tgt, it.entities[0]);
test_bool(false, ecs_rule_next(&it));
ecs_rule_fini(r);
ecs_fini(world);
}
void RulesRecycled_has_recycled_id_from_pair(void) {
ecs_world_t *world = ecs_init();
ECS_TAG(world, Tag);
ecs_entity_t src = recycled_id(world, "src");
ecs_entity_t rel = recycled_id(world, "rel");
ecs_entity_t tgt = recycled_id(world, "tgt");
ecs_add_pair(world, src, rel, tgt);
ecs_add_id(world, src, tgt);
ecs_add(world, src, Tag);
ecs_rule_t *r = ecs_rule(world, {
.expr = "$x($y, $z), $z($y), Tag($y)"
});
test_assert(r != NULL);
int32_t x_var = ecs_rule_find_var(r, "x");
test_assert(x_var != -1);
int32_t y_var = ecs_rule_find_var(r, "y");
test_assert(y_var != -1);
int32_t z_var = ecs_rule_find_var(r, "z");
test_assert(z_var != -1);
ecs_iter_t it = ecs_rule_iter(world, r);
test_bool(true, ecs_rule_next(&it));
test_uint(0, it.count);
test_uint(ecs_pair(rel, tgt), ecs_field_id(&it, 1));
test_uint(tgt, ecs_field_id(&it, 2));
test_uint(Tag, ecs_field_id(&it, 3));
test_uint(src, ecs_field_src(&it, 1));
test_uint(src, ecs_field_src(&it, 2));
test_uint(src, ecs_field_src(&it, 3));
test_uint(rel, ecs_iter_get_var(&it, x_var));
test_uint(src, ecs_iter_get_var(&it, y_var));
test_uint(tgt, ecs_iter_get_var(&it, z_var));
test_bool(false, ecs_rule_next(&it));
ecs_rule_fini(r);
ecs_fini(world);
}

View File

@@ -0,0 +1,400 @@
#include <addons.h>
void RulesScopes_term_w_not_scope_1_term(void) {
ecs_world_t *world = ecs_init();
ECS_TAG(world, Root);
ECS_TAG(world, TagA);
ecs_entity_t parent_1 = ecs_new(world, Root);
ecs_add(world, parent_1, TagA);
ecs_entity_t parent_2 = ecs_new(world, Root);
ecs_rule_t *r = ecs_rule(world, {
.expr = "Root, !{ TagA }"
});
test_assert(r != NULL);
{
ecs_iter_t it = ecs_rule_iter(world, r);
test_bool(true, ecs_rule_next(&it));
test_uint(1, it.count);
test_uint(Root, ecs_field_id(&it, 1));
test_uint(0, ecs_field_src(&it, 1));
test_bool(true, ecs_field_is_set(&it, 1));
test_uint(parent_2, it.entities[0]);
test_bool(false, ecs_rule_next(&it));
}
ecs_rule_fini(r);
ecs_fini(world);
}
void RulesScopes_term_w_not_scope_2_terms(void) {
ecs_world_t *world = ecs_init();
ECS_TAG(world, Root);
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ecs_entity_t parent_1 = ecs_new(world, Root);
ecs_add(world, parent_1, TagA);
ecs_entity_t parent_2 = ecs_new(world, Root);
ecs_add(world, parent_2, TagB);
ecs_entity_t parent_3 = ecs_new(world, Root);
ecs_add(world, parent_3, TagA);
ecs_add(world, parent_3, TagB);
ecs_rule_t *r = ecs_rule(world, {
.expr = "Root, !{ TagA, TagB }"
});
test_assert(r != NULL);
{
ecs_iter_t it = ecs_rule_iter(world, r);
test_bool(true, ecs_rule_next(&it));
test_uint(1, it.count);
test_uint(Root, ecs_field_id(&it, 1));
test_uint(0, ecs_field_src(&it, 1));
test_bool(true, ecs_field_is_set(&it, 1));
test_uint(parent_1, it.entities[0]);
test_bool(true, ecs_rule_next(&it));
test_uint(1, it.count);
test_uint(Root, ecs_field_id(&it, 1));
test_uint(0, ecs_field_src(&it, 1));
test_bool(true, ecs_field_is_set(&it, 1));
test_uint(parent_2, it.entities[0]);
test_bool(false, ecs_rule_next(&it));
}
ecs_rule_fini(r);
ecs_fini(world);
}
void RulesScopes_term_w_not_scope_1_term_w_not(void) {
ecs_world_t *world = ecs_init();
ECS_TAG(world, Root);
ECS_TAG(world, TagA);
ecs_entity_t parent_1 = ecs_new(world, Root);
ecs_add(world, parent_1, TagA);
ecs_new(world, Root);
ecs_rule_t *r = ecs_rule(world, {
.expr = "Root, !{ !TagA }"
});
test_assert(r != NULL);
{
ecs_iter_t it = ecs_rule_iter(world, r);
test_bool(true, ecs_rule_next(&it));
test_uint(1, it.count);
test_uint(Root, ecs_field_id(&it, 1));
test_uint(0, ecs_field_src(&it, 1));
test_bool(true, ecs_field_is_set(&it, 1));
test_uint(parent_1, it.entities[0]);
test_bool(false, ecs_rule_next(&it));
}
ecs_rule_fini(r);
ecs_fini(world);
}
void RulesScopes_term_w_not_scope_2_terms_w_not(void) {
ecs_world_t *world = ecs_init();
ECS_TAG(world, Root);
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ecs_entity_t parent_1 = ecs_new(world, Root);
ecs_add(world, parent_1, TagA);
ecs_entity_t parent_2 = ecs_new(world, Root);
ecs_add(world, parent_2, TagB);
ecs_entity_t parent_3 = ecs_new(world, Root);
ecs_add(world, parent_3, TagA);
ecs_add(world, parent_3, TagB);
ecs_rule_t *r = ecs_rule(world, {
.expr = "Root, !{ TagA, !TagB }"
});
test_assert(r != NULL);
{
ecs_iter_t it = ecs_rule_iter(world, r);
test_bool(true, ecs_rule_next(&it));
test_uint(1, it.count);
test_uint(Root, ecs_field_id(&it, 1));
test_uint(0, ecs_field_src(&it, 1));
test_bool(true, ecs_field_is_set(&it, 1));
test_uint(parent_2, it.entities[0]);
test_bool(true, ecs_rule_next(&it));
test_uint(1, it.count);
test_uint(Root, ecs_field_id(&it, 1));
test_uint(0, ecs_field_src(&it, 1));
test_bool(true, ecs_field_is_set(&it, 1));
test_uint(parent_3, it.entities[0]);
test_bool(false, ecs_rule_next(&it));
}
ecs_rule_fini(r);
ecs_fini(world);
}
void RulesScopes_term_w_not_scope_1_term_w_var(void) {
ecs_world_t *world = ecs_init();
ECS_TAG(world, Root);
ecs_entity_t parent_1 = ecs_new(world, Root);
ecs_new_w_pair(world, EcsChildOf, parent_1);
ecs_new_w_pair(world, EcsChildOf, parent_1);
ecs_entity_t parent_2 = ecs_new(world, Root);
ecs_new_w_pair(world, EcsChildOf, parent_2);
ecs_entity_t parent_3 = ecs_new(world, Root);
ecs_rule_t *r = ecs_rule(world, {
.expr = "Root, !{ ChildOf($child, $this) }"
});
test_assert(r != NULL);
{
ecs_iter_t it = ecs_rule_iter(world, r);
test_bool(true, ecs_rule_next(&it));
test_uint(1, it.count);
test_uint(Root, ecs_field_id(&it, 1));
test_uint(0, ecs_field_src(&it, 1));
test_bool(true, ecs_field_is_set(&it, 1));
test_uint(parent_3, it.entities[0]);
test_bool(false, ecs_rule_next(&it));
}
ecs_rule_fini(r);
ecs_fini(world);
}
void RulesScopes_term_w_not_scope_2_terms_w_var(void) {
ecs_world_t *world = ecs_init();
ECS_TAG(world, Root);
ECS_COMPONENT(world, Position);
ecs_entity_t parent_0 = ecs_new(world, Root);
{
ecs_entity_t child_1 = ecs_new_w_pair(world, EcsChildOf, parent_0);
ecs_set(world, child_1, Position, {10, 20});
ecs_entity_t child_2 = ecs_new_w_pair(world, EcsChildOf, parent_0);
ecs_set(world, child_2, Position, {10, 20});
}
ecs_entity_t parent_1 = ecs_new(world, Root);
{
ecs_entity_t child_1 = ecs_new_w_pair(world, EcsChildOf, parent_1);
ecs_set(world, child_1, Position, {10, 20});
ecs_new_w_pair(world, EcsChildOf, parent_1);
}
ecs_entity_t parent_2 = ecs_new(world, Root);
{
ecs_new_w_pair(world, EcsChildOf, parent_2);
ecs_new_w_pair(world, EcsChildOf, parent_2);
}
ecs_rule_t *r = ecs_rule(world, {
.expr = "Root, !{ ChildOf($child, $this), Position($child) }"
});
test_assert(r != NULL);
{
ecs_iter_t it = ecs_rule_iter(world, r);
test_bool(true, ecs_rule_next(&it));
test_uint(1, it.count);
test_uint(Root, ecs_field_id(&it, 1));
test_uint(0, ecs_field_src(&it, 1));
test_bool(true, ecs_field_is_set(&it, 1));
test_uint(parent_2, it.entities[0]);
test_bool(false, ecs_rule_next(&it));
}
ecs_rule_fini(r);
ecs_fini(world);
}
void RulesScopes_term_w_not_scope_1_term_w_not_w_var(void) {
ecs_world_t *world = ecs_init();
ECS_TAG(world, Root);
ecs_entity_t parent_0 = ecs_new(world, Root);
{
ecs_new_w_pair(world, EcsChildOf, parent_0);
ecs_new_w_pair(world, EcsChildOf, parent_0);
}
ecs_new(world, Root);
ecs_rule_t *r = ecs_rule(world, {
.expr = "Root, !{ !ChildOf($child, $this) }"
});
test_assert(r != NULL);
{
ecs_iter_t it = ecs_rule_iter(world, r);
test_bool(true, ecs_rule_next(&it));
test_uint(1, it.count);
test_uint(Root, ecs_field_id(&it, 1));
test_uint(0, ecs_field_src(&it, 1));
test_bool(true, ecs_field_is_set(&it, 1));
test_uint(parent_0, it.entities[0]);
test_bool(false, ecs_rule_next(&it));
}
ecs_rule_fini(r);
ecs_fini(world);
}
void RulesScopes_term_w_not_scope_2_terms_w_not_w_var(void) {
ecs_world_t *world = ecs_init();
ECS_TAG(world, Root);
ECS_COMPONENT(world, Position);
ecs_entity_t parent_0 = ecs_new(world, Root);
{
ecs_entity_t child_1 = ecs_new_w_pair(world, EcsChildOf, parent_0);
ecs_set(world, child_1, Position, {10, 20});
ecs_entity_t child_2 = ecs_new_w_pair(world, EcsChildOf, parent_0);
ecs_set(world, child_2, Position, {10, 20});
}
ecs_entity_t parent_1 = ecs_new(world, Root);
{
ecs_entity_t child_1 = ecs_new_w_pair(world, EcsChildOf, parent_1);
ecs_set(world, child_1, Position, {10, 20});
ecs_new_w_pair(world, EcsChildOf, parent_1);
}
ecs_entity_t parent_2 = ecs_new(world, Root);
{
ecs_new_w_pair(world, EcsChildOf, parent_2);
ecs_new_w_pair(world, EcsChildOf, parent_2);
}
ecs_rule_t *r = ecs_rule(world, {
.expr = "Root, !{ ChildOf($child, $this), !Position($child) }"
});
test_assert(r != NULL);
{
ecs_iter_t it = ecs_rule_iter(world, r);
test_bool(true, ecs_rule_next(&it));
test_uint(1, it.count);
test_uint(Root, ecs_field_id(&it, 1));
test_uint(0, ecs_field_src(&it, 1));
test_bool(true, ecs_field_is_set(&it, 1));
test_uint(parent_0, it.entities[0]);
test_bool(false, ecs_rule_next(&it));
}
ecs_rule_fini(r);
ecs_fini(world);
}
void RulesScopes_term_w_not_scope_2_terms_w_or(void) {
ecs_world_t *world = ecs_init();
ECS_TAG(world, Root);
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ecs_entity_t e1 = ecs_new(world, Root);
ecs_add(world, e1, TagA);
ecs_entity_t e2 = ecs_new(world, Root);
ecs_add(world, e2, TagB);
ecs_entity_t e3 = ecs_new(world, Root);
ecs_add(world, e3, TagA);
ecs_add(world, e3, TagB);
ecs_entity_t e4 = ecs_new(world, Root);
ecs_rule_t *r = ecs_rule(world, {
.expr = "Root, !{ TagA || TagB }"
});
test_assert(r != NULL);
{
ecs_iter_t it = ecs_rule_iter(world, r);
test_bool(true, ecs_rule_next(&it));
test_uint(1, it.count);
test_uint(Root, ecs_field_id(&it, 1));
test_uint(0, ecs_field_src(&it, 1));
test_bool(true, ecs_field_is_set(&it, 1));
test_uint(e4, it.entities[0]);
test_bool(false, ecs_rule_next(&it));
}
ecs_rule_fini(r);
ecs_fini(world);
}
void RulesScopes_term_w_not_scope_3_terms_w_or(void) {
ecs_world_t *world = ecs_init();
ECS_TAG(world, Root);
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ECS_TAG(world, TagC);
ecs_entity_t e1 = ecs_new(world, Root);
ecs_add(world, e1, TagA);
ecs_entity_t e2 = ecs_new(world, Root);
ecs_add(world, e2, TagB);
ecs_entity_t e3 = ecs_new(world, Root);
ecs_add(world, e3, TagA);
ecs_add(world, e3, TagB);
ecs_entity_t e4 = ecs_new(world, Root);
ecs_add(world, e4, TagC);
ecs_entity_t e5 = ecs_new(world, Root);
ecs_rule_t *r = ecs_rule(world, {
.expr = "Root, !{ TagA || TagB || TagC }"
});
test_assert(r != NULL);
{
ecs_iter_t it = ecs_rule_iter(world, r);
test_bool(true, ecs_rule_next(&it));
test_uint(1, it.count);
test_uint(Root, ecs_field_id(&it, 1));
test_uint(0, ecs_field_src(&it, 1));
test_bool(true, ecs_field_is_set(&it, 1));
test_uint(e5, it.entities[0]);
test_bool(false, ecs_rule_next(&it));
}
ecs_rule_fini(r);
ecs_fini(world);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,879 @@
#include <addons.h>
void Snapshot_simple_snapshot(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ecs_entity_t e = ecs_set(world, 0, Position, {10, 20});
test_assert(e != 0);
test_assert(ecs_has(world, e, Position));
ecs_snapshot_t *s = ecs_snapshot_take(world);
Position *p = ecs_get_mut(world, e, Position);
test_int(p->x, 10);
test_int(p->y, 20);
p->x ++;
p->y ++;
ecs_snapshot_restore(world, s);
test_assert(ecs_has(world, e, Position));
p = ecs_get_mut(world, e, Position);
test_int(p->x, 10);
test_int(p->y, 20);
ecs_fini(world);
}
void Snapshot_snapshot_after_new(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ecs_entity_t e = ecs_new(world, Position);
test_assert(e != 0);
test_assert(ecs_has(world, e, Position));
ecs_snapshot_t *s = ecs_snapshot_take(world);
ecs_entity_t e2 = ecs_new(world, Position);
test_assert(e2 != 0);
test_assert(ecs_has(world, e2, Position));
ecs_snapshot_restore(world, s);
test_assert(ecs_is_alive(world, e));
test_assert(!ecs_is_alive(world, e2));
test_assert(ecs_has(world, e, Position));
test_assert(ecs_new(world, 0) == e2);
ecs_fini(world);
}
void Snapshot_snapshot_after_delete(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ecs_entity_t e = ecs_set(world, 0, Position, {10, 20});
test_assert(e != 0);
test_assert(ecs_has(world, e, Position));
ecs_snapshot_t *s = ecs_snapshot_take(world);
ecs_delete(world, e);
test_assert(!ecs_is_alive(world, e));
ecs_snapshot_restore(world, s);
test_assert(ecs_is_alive(world, e));
test_assert(ecs_has(world, e, Position));
const Position *p = ecs_get(world, e, Position);
test_int(p->x, 10);
test_int(p->y, 20);
ecs_fini(world);
}
void Snapshot_snapshot_after_new_type(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_entity_t e = ecs_set(world, 0, Position, {10, 20});
test_assert(e != 0);
test_assert(ecs_has(world, e, Position));
ecs_snapshot_t *s = ecs_snapshot_take(world);
ecs_entity_t e2 = ecs_new(world, Position);
ecs_add(world, e2, Velocity);
ecs_snapshot_restore(world, s);
test_assert(ecs_is_alive(world, e));
test_assert(!ecs_is_alive(world, e2));
test_assert(ecs_has(world, e, Position));
ecs_fini(world);
}
void Snapshot_snapshot_after_add(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_entity_t e = ecs_set(world, 0, Position, {10, 20});
test_assert(e != 0);
test_assert(ecs_has(world, e, Position));
ecs_snapshot_t *s = ecs_snapshot_take(world);
ecs_add(world, e, Velocity);
test_assert(ecs_has(world, e, Velocity));
ecs_snapshot_restore(world, s);
test_assert(ecs_has(world, e, Position));
test_assert(!ecs_has(world, e, Velocity));
ecs_fini(world);
}
void Snapshot_snapshot_after_remove(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_entity_t e = ecs_new(world, Position);
test_assert(e != 0);
test_assert(ecs_has(world, e, Position));
ecs_add(world, e, Velocity);
test_assert(ecs_has(world, e, Velocity));
ecs_snapshot_t *s = ecs_snapshot_take(world);
ecs_remove(world, e, Velocity);
test_assert(!ecs_has(world, e, Velocity));
ecs_snapshot_restore(world, s);
test_assert(ecs_has(world, e, Position));
ecs_fini(world);
}
void Snapshot_snapshot_w_include_filter(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_entity_t e1 = ecs_set(world, 0, Position, {10, 20});
test_assert(e1 != 0);
test_assert(ecs_has(world, e1, Position));
ecs_entity_t e2 = ecs_set(world, 0, Position, {15, 25});
test_assert(e2 != 0);
ecs_add(world, e2, Velocity);
test_assert(ecs_has(world, e2, Position));
test_assert(ecs_has(world, e2, Velocity));
ecs_entity_t e3 = ecs_set(world, 0, Velocity, {25, 35});
test_assert(e3 != 0);
test_assert(ecs_has(world, e3, Velocity));
ecs_filter_t f = ECS_FILTER_INIT;
ecs_filter_init(world, &(ecs_filter_desc_t){
.storage = &f,
.terms = {{ ecs_id(Position) }}
});
ecs_iter_t it = ecs_filter_iter(world, &f);
ecs_snapshot_t *s = ecs_snapshot_take_w_iter(&it);
Position *p = ecs_get_mut(world, e1, Position);
test_assert(p != NULL);
test_int(p->x, 10);
test_int(p->y, 20);
p->x ++;
p->y ++;
p = ecs_get_mut(world, e2, Position);
test_assert(p != NULL);
test_int(p->x, 15);
test_int(p->y, 25);
p->x ++;
p->y ++;
Velocity *v = ecs_get_mut(world, e3, Velocity);
test_assert(v != NULL);
test_int(v->x, 25);
test_int(v->y, 35);
v->x ++;
v->y ++;
ecs_snapshot_restore(world, s);
/* Restored */
p = ecs_get_mut(world, e1, Position);
test_assert(p != NULL);
test_int(p->x, 10);
test_int(p->y, 20);
/* Restored */
p = ecs_get_mut(world, e2, Position);
test_assert(p != NULL);
test_int(p->x, 15);
test_int(p->y, 25);
/* Not restored */
v = ecs_get_mut(world, e3, Velocity);
test_assert(v != NULL);
test_int(v->x, 26);
test_int(v->y, 36);
test_assert(ecs_new(world, 0) > e3);
ecs_filter_fini(&f);
ecs_fini(world);
}
void Snapshot_snapshot_w_exclude_filter(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_entity_t e1 = ecs_set(world, 0, Position, {10, 20});
test_assert(e1 != 0);
test_assert(ecs_has(world, e1, Position));
ecs_entity_t e2 = ecs_set(world, 0, Position, {15, 25});
test_assert(e2 != 0);
ecs_add(world, e2, Velocity);
test_assert(ecs_has(world, e2, Position));
test_assert(ecs_has(world, e2, Velocity));
ecs_entity_t e3 = ecs_set(world, 0, Velocity, {25, 35});
test_assert(e3 != 0);
test_assert(ecs_has(world, e3, Velocity));
ecs_filter_t f = ECS_FILTER_INIT;
ecs_filter_init(world, &(ecs_filter_desc_t){
.storage = &f,
.terms = {{ ecs_id(Position), .oper = EcsNot }}
});
ecs_iter_t it = ecs_filter_iter(world, &f);
ecs_snapshot_t *s = ecs_snapshot_take_w_iter(&it);
Position *p = ecs_get_mut(world, e1, Position);
test_assert(p != NULL);
test_int(p->x, 10);
test_int(p->y, 20);
p->x ++;
p->y ++;
p = ecs_get_mut(world, e2, Position);
test_assert(p != NULL);
test_int(p->x, 15);
test_int(p->y, 25);
p->x ++;
p->y ++;
Velocity *v = ecs_get_mut(world, e3, Velocity);
test_assert(v != NULL);
test_int(v->x, 25);
test_int(v->y, 35);
v->x ++;
v->y ++;
ecs_snapshot_restore(world, s);
/* Not restored */
p = ecs_get_mut(world, e1, Position);
test_assert(p != NULL);
test_int(p->x, 11);
test_int(p->y, 21);
/* Not restored */
p = ecs_get_mut(world, e2, Position);
test_assert(p != NULL);
test_int(p->x, 16);
test_int(p->y, 26);
/* Restored */
v = ecs_get_mut(world, e3, Velocity);
test_assert(v != NULL);
test_int(v->x, 25);
test_int(v->y, 35);
test_assert(ecs_new(world, 0) > e3);
ecs_filter_fini(&f);
ecs_fini(world);
}
void Snapshot_snapshot_w_filter_after_new(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_entity_t e1 = ecs_set(world, 0, Position, {1, 2});
test_assert(e1 != 0);
test_assert(ecs_has(world, e1, Position));
ecs_entity_t e2 = ecs_set(world, 0, Velocity, {3, 4});
test_assert(e2 != 0);
test_assert(ecs_has(world, e2, Velocity));
ecs_filter_t f = ECS_FILTER_INIT;
ecs_filter_init(world, &(ecs_filter_desc_t){
.storage = &f,
.terms = {{ ecs_id(Position) }}
});
ecs_iter_t it = ecs_filter_iter(world, &f);
ecs_snapshot_t *s = ecs_snapshot_take_w_iter(&it);
ecs_set(world, e1, Position, {5, 6});
ecs_set(world, e2, Velocity, {7, 8});
ecs_entity_t e3 = ecs_set(world, 0, Position, {33, 44});
test_assert(e3 != 0);
test_assert(ecs_has(world, e3, Position));
ecs_entity_t e4 = ecs_set(world, 0, Velocity, {34, 45});
test_assert(e4 != 0);
test_assert(ecs_has(world, e4, Velocity));
ecs_snapshot_restore(world, s);
test_assert(ecs_has(world, e1, Position));
const Position *p = ecs_get(world, e1, Position);
test_assert(p != NULL);
test_int(p->x, 1);
test_int(p->y, 2);
test_assert(ecs_has(world, e2, Velocity));
const Velocity *v = ecs_get(world, e2, Velocity);
test_assert(v != NULL);
test_int(v->x, 7);
test_int(v->y, 8);
test_assert(ecs_has(world, e3, Position));
p = ecs_get(world, e3, Position);
test_assert(p != NULL);
test_int(p->x, 33);
test_int(p->y, 44);
test_assert(ecs_has(world, e4, Velocity));
v = ecs_get(world, e4, Velocity);
test_assert(p != NULL);
test_int(v->x, 34);
test_int(v->y, 45);
ecs_filter_fini(&f);
ecs_fini(world);
}
void Snapshot_snapshot_w_filter_after_delete(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_entity_t e1 = ecs_set(world, 0, Position, {1, 2});
test_assert(e1 != 0);
test_assert(ecs_has(world, e1, Position));
ecs_entity_t e2 = ecs_set(world, 0, Velocity, {3, 4});
test_assert(e2 != 0);
test_assert(ecs_has(world, e2, Velocity));
ecs_entity_t e3 = ecs_set(world, 0, Position, {1, 2});
test_assert(e3 != 0);
test_assert(ecs_has(world, e3, Position));
ecs_entity_t e4 = ecs_set(world, 0, Velocity, {3, 4});
test_assert(e4 != 0);
test_assert(ecs_has(world, e4, Velocity));
ecs_filter_t f = ECS_FILTER_INIT;
ecs_filter_init(world, &(ecs_filter_desc_t){
.storage = &f,
.terms = {{ ecs_id(Position) }}
});
ecs_iter_t it = ecs_filter_iter(world, &f);
ecs_snapshot_t *s = ecs_snapshot_take_w_iter(&it);
ecs_delete(world, e3);
ecs_delete(world, e4);
test_assert(!ecs_is_alive(world, e3));
test_assert(!ecs_is_alive(world, e4));
ecs_snapshot_restore(world, s);
test_assert(ecs_is_alive(world, e1));
test_assert(ecs_is_alive(world, e2));
test_assert(ecs_is_alive(world, e3));
test_assert(!ecs_is_alive(world, e4));
test_assert(ecs_has(world, e1, Position));
test_assert(ecs_has(world, e2, Velocity));
test_assert(ecs_has(world, e3, Position));
ecs_filter_fini(&f);
ecs_fini(world);
}
void Snapshot_snapshot_free_empty(void) {
ecs_world_t *world = ecs_init();
ecs_snapshot_t *s = ecs_snapshot_take(world);
test_assert(s != NULL);
ecs_snapshot_free(s);
ecs_fini(world);
}
void Snapshot_snapshot_free(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
test_assert( ecs_new(world, Position) != 0);
test_assert( ecs_new(world, Velocity) != 0);
ecs_snapshot_t *s = ecs_snapshot_take(world);
test_assert(s != NULL);
ecs_snapshot_free(s);
ecs_fini(world);
}
void Snapshot_snapshot_free_filtered(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
test_assert( ecs_new(world, Position) != 0);
test_assert( ecs_new(world, Velocity) != 0);
ecs_filter_t f = ECS_FILTER_INIT;
ecs_filter_init(world, &(ecs_filter_desc_t){
.storage = &f,
.terms = {{ ecs_id(Position) }}
});
ecs_iter_t it = ecs_filter_iter(world, &f);
ecs_snapshot_t *s = ecs_snapshot_take_w_iter(&it);
test_assert(s != NULL);
ecs_snapshot_free(s);
ecs_filter_fini(&f);
ecs_fini(world);
}
void Snapshot_snapshot_free_filtered_w_dtor(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_COMPONENT(world, Mass);
ecs_entity_t e1 = ecs_entity_init(world, &(ecs_entity_desc_t){
.name = "e1"
});
ecs_entity_t e2 = ecs_entity_init(world, &(ecs_entity_desc_t){
.name = "e2"
});
ecs_entity_t e3 = ecs_entity_init(world, &(ecs_entity_desc_t){
.name = "e3"
});
ecs_add(world, e1, Position);
ecs_add(world, e2, Position);
ecs_add(world, e3, Position);
ecs_add(world, e1, Velocity);
ecs_add(world, e2, Velocity);
ecs_add(world, e3, Velocity);
ecs_add(world, e3, Mass);
ecs_filter_t f = ECS_FILTER_INIT;
ecs_filter_init(world, &(ecs_filter_desc_t){
.storage = &f,
.terms = {{ ecs_id(Position) }, { ecs_id(Velocity) }}
});
ecs_iter_t it = ecs_filter_iter(world, &f);
ecs_snapshot_t *s = ecs_snapshot_take_w_iter(&it);
test_assert(s != NULL);
ecs_snapshot_free(s);
ecs_filter_fini(&f);
ecs_fini(world);
}
static bool invoked = false;
static
void Dummy(ecs_iter_t *it) {
invoked = true;
}
void Snapshot_snapshot_activate_table_w_filter(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_SYSTEM(world, Dummy, EcsOnUpdate, Position);
ecs_entity_t e = ecs_set(world, 0, Position, {0, 0});
test_assert(e != 0);
ecs_filter_t f = ECS_FILTER_INIT;
ecs_filter_init(world, &(ecs_filter_desc_t){
.storage = &f,
.terms = {{ ecs_id(Position) }}
});
ecs_iter_t it = ecs_filter_iter(world, &f);
ecs_snapshot_t *s = ecs_snapshot_take_w_iter(&it);
ecs_snapshot_restore(world, s);
test_assert(ecs_has(world, e, Position));
ecs_progress(world, 0);
test_bool(invoked, true);
ecs_filter_fini(&f);
ecs_fini(world);
}
void Snapshot_snapshot_copy(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ecs_entity_t e = ecs_set(world, 0, Position, {10, 20});
test_assert(e != 0);
test_assert(ecs_has(world, e, Position));
ecs_snapshot_t *s = ecs_snapshot_take(world);
ecs_iter_t it = ecs_snapshot_iter(s);
ecs_snapshot_t *s_copy = ecs_snapshot_take_w_iter(&it);
ecs_snapshot_free(s);
Position *p = ecs_get_mut(world, e, Position);
test_int(p->x, 10);
test_int(p->y, 20);
p->x ++;
p->y ++;
ecs_snapshot_restore(world, s_copy);
test_assert(ecs_has(world, e, Position));
p = ecs_get_mut(world, e, Position);
test_int(p->x, 10);
test_int(p->y, 20);
ecs_fini(world);
}
void Snapshot_snapshot_get_ref_after_restore(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ecs_entity_t e = ecs_set(world, 0, Position, {10, 20});
test_assert(e != 0);
test_assert(ecs_has(world, e, Position));
ecs_ref_t ref = ecs_ref_init(world, e, Position);
const Position *p = ecs_ref_get(world, &ref, Position);
test_assert(p != NULL);
test_int(p->x, 10);
test_int(p->y, 20);
ecs_snapshot_t *s = ecs_snapshot_take(world);
Position *p_mut = ecs_get_mut(world, e, Position);
test_int(p_mut->x, 10);
test_int(p_mut->y, 20);
p_mut->x ++;
p_mut->y ++;
ecs_snapshot_restore(world, s);
test_assert(ecs_has(world, e, Position));
p = ecs_ref_get(world, &ref, Position);
test_assert(p != NULL);
test_int(p->x, 10);
test_int(p->y, 20);
ecs_fini(world);
}
void Snapshot_new_after_snapshot(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_entity_t e = ecs_set(world, 0, Position, {10, 20});
test_assert(e != 0);
test_assert(ecs_has(world, e, Position));
ecs_snapshot_t *s = ecs_snapshot_take(world);
ecs_snapshot_restore(world, s);
ecs_entity_t e2 = ecs_new(world, Position);
test_assert(e2 != 0);
test_assert(ecs_has(world, e2, Position));
ecs_add(world, e2, Velocity);
test_assert(ecs_has(world, e2, Velocity));
ecs_fini(world);
}
void Snapshot_add_after_snapshot(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_entity_t e = ecs_set(world, 0, Position, {10, 20});
test_assert(e != 0);
test_assert(ecs_has(world, e, Position));
ecs_snapshot_t *s = ecs_snapshot_take(world);
ecs_snapshot_restore(world, s);
ecs_add(world, e, Velocity);
test_assert(ecs_has(world, e, Velocity));
ecs_fini(world);
}
void Snapshot_delete_after_snapshot(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ecs_entity_t e = ecs_set(world, 0, Position, {10, 20});
test_assert(e != 0);
test_assert(ecs_has(world, e, Position));
ecs_snapshot_t *s = ecs_snapshot_take(world);
ecs_snapshot_restore(world, s);
ecs_delete(world, e);
test_assert(!ecs_is_alive(world, e));
ecs_fini(world);
}
void Snapshot_new_empty_after_snapshot(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_entity_t e = ecs_set(world, 0, Position, {10, 20});
test_assert(e != 0);
test_assert(ecs_has(world, e, Position));
ecs_snapshot_t *s = ecs_snapshot_take(world);
ecs_snapshot_restore(world, s);
ecs_entity_t e2 = ecs_new(world, 0);
test_assert(e2 != 0);
ecs_fini(world);
}
void Snapshot_set_after_snapshot(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_entity_t e = ecs_set(world, 0, Position, {10, 20});
test_assert(e != 0);
test_assert(ecs_has(world, e, Position));
ecs_snapshot_t *s = ecs_snapshot_take(world);
ecs_snapshot_restore(world, s);
ecs_entity_t e2 = ecs_new(world, 0);
test_assert(e2 != 0);
ecs_set_name(world, e2, "e2");
test_assert(ecs_has_pair(world, e2, ecs_id(EcsIdentifier), EcsName));
test_str(ecs_get_name(world, e2), "e2");
ecs_fini(world);
}
void Snapshot_restore_recycled(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_entity_t e = ecs_set(world, 0, Position, {10, 20});
test_assert(e != 0);
test_assert(ecs_has(world, e, Position));
ecs_snapshot_t *s = ecs_snapshot_take(world);
ecs_delete(world, e);
ecs_snapshot_restore(world, s);
ecs_entity_t e2 = ecs_new(world, 0);
test_assert(e2 != 0);
test_assert(e != e2);
ecs_fini(world);
}
static
void SetP(ecs_iter_t *it) {
int i;
for (i = 0; i < it->count; i ++) {
ecs_set_name(it->world, 0, "e2");
}
}
void Snapshot_snapshot_w_new_in_onset(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ecs_entity_t e = ecs_set(world, 0, Position, {10, 20});
test_assert(e != 0);
test_assert(ecs_has(world, e, Position));
ECS_OBSERVER(world, SetP, EcsOnSet, Position);
ecs_snapshot_t *s = ecs_snapshot_take(world);
ecs_snapshot_restore(world, s);
ecs_entity_t e2 = ecs_lookup(world, "e2");
test_assert(e2 != 0);
ecs_entity_t e3 = ecs_set_name(world, 0, "e3");
test_assert(e3 != 0);
test_assert(e3 > e2);
test_str(ecs_get_name(world, e3), "e3");
ecs_fini(world);
}
static ecs_entity_t v_entity = 0;
static
void CreateV(ecs_iter_t *it) {
ecs_entity_t ecs_id(Velocity) = ecs_field_id(it, 2);
int i;
for (i = 0; i < it->count; i ++) {
v_entity = ecs_set(it->world, 0, Velocity, {3, 4});
}
}
void Snapshot_snapshot_w_new_in_onset_in_snapshot_table(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_set(world, 0, Position, {10, 20});
ecs_entity_t e2 = ecs_set(world, 0, Velocity, {1, 2});
ECS_OBSERVER(world, CreateV, EcsOnSet, Position, Velocity());
ecs_snapshot_t *s = ecs_snapshot_take(world);
ecs_snapshot_restore(world, s);
const Velocity *v = ecs_get(world, e2, Velocity);
test_assert(v != NULL);
test_int(v->x, 1);
test_int(v->y, 2);
v = ecs_get(world, v_entity, Velocity);
test_assert(v != NULL);
test_int(v->x, 3);
test_int(v->y, 4);
ecs_fini(world);
}
void Snapshot_snapshot_from_stage(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_entity_t e1 = ecs_set(world, 0, Position, {1, 2});
ecs_entity_t e2 = ecs_set(world, 0, Position, {3, 4});
ecs_readonly_begin(world);
ecs_world_t *stage = ecs_get_stage(world, 0);
ecs_snapshot_t *s = ecs_snapshot_take(stage);
ecs_delete(stage, e1);
ecs_delete(stage, e2);
ecs_readonly_end(world);
test_assert(!ecs_is_alive(world, e1));
test_assert(!ecs_is_alive(world, e2));
ecs_snapshot_restore(world, s);
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, 3);
test_int(p->y, 4);
ecs_fini(world);
}

View File

@@ -0,0 +1,314 @@
#include <addons.h>
#define test_delta(prev, cur, field, value)\
test_int(value, (cur)->field - (prev)->field);\
(prev)->field = (cur)->field
void Stats_get_world_stats(void) {
ecs_world_t *world = ecs_init();
ecs_world_stats_t stats = {0};
ecs_world_stats_get(world, &stats);
test_int(stats.t, 1);
ecs_fini(world);
}
void Stats_get_pipeline_stats_before_progress_mini_world(void) {
ecs_world_t *world = ecs_mini();
ECS_IMPORT(world, FlecsPipeline);
ecs_entity_t pipeline = ecs_get_pipeline(world);
test_assert(pipeline != 0);
ecs_pipeline_stats_t stats = {0};
test_bool(ecs_pipeline_stats_get(world, pipeline, &stats), false);
test_assert(ecs_vec_count(&stats.systems) == 0);
test_assert(ecs_map_count(&stats.system_stats) == 0);
ecs_fini(world);
}
void Stats_get_pipeline_stats_before_progress(void) {
ecs_world_t *world = ecs_init();
ecs_entity_t pipeline = ecs_get_pipeline(world);
test_assert(pipeline != 0);
ecs_pipeline_stats_t stats = {0};
test_bool(ecs_pipeline_stats_get(world, pipeline, &stats), true);
test_assert(ecs_vec_count(&stats.systems) == 0);
test_assert(ecs_map_count(&stats.system_stats) != 0); /* Inactive systems */
ecs_pipeline_stats_fini(&stats);
ecs_fini(world);
}
void Stats_get_pipeline_stats_after_progress_no_systems(void) {
ecs_world_t *world = ecs_init();
ecs_entity_t pipeline = ecs_get_pipeline(world);
test_assert(pipeline != 0);
ecs_progress(world, 0);
ecs_pipeline_stats_t stats = {0};
test_bool(ecs_pipeline_stats_get(world, pipeline, &stats), true);
test_int(ecs_vec_count(&stats.systems), 1);
test_int(ecs_vec_get_t(&stats.systems, ecs_entity_t, 0)[0], 0); /* merge */
test_assert(ecs_map_count(&stats.system_stats) != 0); /* Inactive systems */
ecs_pipeline_stats_fini(&stats);
ecs_fini(world);
}
static void FooSys(ecs_iter_t *it) { }
static void BarSys(ecs_iter_t *it) { }
void Stats_get_pipeline_stats_after_progress_1_system(void) {
ecs_world_t *world = ecs_init();
ECS_SYSTEM(world, FooSys, EcsOnUpdate, 0);
ecs_entity_t pipeline = ecs_get_pipeline(world);
test_assert(pipeline != 0);
ecs_progress(world, 0);
ecs_pipeline_stats_t stats = {0};
test_bool(ecs_pipeline_stats_get(world, pipeline, &stats), true);
test_int(ecs_vec_count(&stats.systems), 2);
test_int(ecs_vec_get_t(&stats.systems, ecs_entity_t, 0)[0], ecs_id(FooSys));
test_int(ecs_vec_get_t(&stats.systems, ecs_entity_t, 0)[1], 0); /* merge */
test_assert(ecs_map_count(&stats.system_stats) != 0);
ecs_system_stats_t *sys_stats = ecs_map_get_deref(
&stats.system_stats, ecs_system_stats_t, ecs_id(FooSys));
test_assert(sys_stats != NULL);
test_int(sys_stats->query.t, 1);
test_int(sys_stats->invoke_count.counter.value[1], 1);
ecs_progress(world, 0);
test_bool(ecs_pipeline_stats_get(world, pipeline, &stats), true);
test_int(sys_stats->query.t, 2);
test_int(sys_stats->invoke_count.counter.value[2], 2);
ecs_pipeline_stats_fini(&stats);
ecs_fini(world);
}
void Stats_get_pipeline_stats_after_progress_1_inactive_system(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_SYSTEM(world, FooSys, EcsOnUpdate, Position); // no matching entities
ecs_entity_t pipeline = ecs_get_pipeline(world);
test_assert(pipeline != 0);
ecs_progress(world, 0);
ecs_pipeline_stats_t stats = {0};
test_bool(ecs_pipeline_stats_get(world, pipeline, &stats), true);
test_int(ecs_vec_count(&stats.systems), 1);
test_int(ecs_vec_get_t(&stats.systems, ecs_entity_t, 0)[0], 0); /* merge */
test_assert(ecs_map_count(&stats.system_stats) != 0);
ecs_system_stats_t *sys_stats = ecs_map_get_deref(
&stats.system_stats, ecs_system_stats_t, ecs_id(FooSys));
test_assert(sys_stats != NULL);
test_int(sys_stats->query.t, 1);
test_int(sys_stats->invoke_count.counter.value[1], 0);
ecs_progress(world, 0);
test_bool(ecs_pipeline_stats_get(world, pipeline, &stats), true);
test_int(sys_stats->query.t, 2);
test_int(sys_stats->invoke_count.counter.value[2], 0);
ecs_pipeline_stats_fini(&stats);
ecs_fini(world);
}
void Stats_get_pipeline_stats_after_progress_2_systems(void) {
ecs_world_t *world = ecs_init();
ECS_SYSTEM(world, FooSys, EcsOnUpdate, 0);
ECS_SYSTEM(world, BarSys, EcsOnUpdate, 0);
ecs_entity_t pipeline = ecs_get_pipeline(world);
test_assert(pipeline != 0);
ecs_progress(world, 0);
ecs_pipeline_stats_t stats = {0};
test_bool(ecs_pipeline_stats_get(world, pipeline, &stats), true);
test_int(ecs_vec_count(&stats.systems), 3);
test_int(ecs_vec_get_t(&stats.systems, ecs_entity_t, 0)[0], ecs_id(FooSys));
test_int(ecs_vec_get_t(&stats.systems, ecs_entity_t, 0)[1], ecs_id(BarSys));
test_int(ecs_vec_get_t(&stats.systems, ecs_entity_t, 0)[2], 0); /* merge */
test_assert(ecs_map_count(&stats.system_stats) != 0);
ecs_system_stats_t *sys_foo_stats = ecs_map_get_deref(
&stats.system_stats, ecs_system_stats_t, ecs_id(FooSys));
test_assert(sys_foo_stats != NULL);
test_int(sys_foo_stats->query.t, 1);
test_int(sys_foo_stats->invoke_count.counter.value[1], 1);
ecs_system_stats_t *sys_bar_stats = ecs_map_get_deref(
&stats.system_stats, ecs_system_stats_t, ecs_id(BarSys));
test_assert(sys_bar_stats != NULL);
test_int(sys_bar_stats->query.t, 1);
test_int(sys_bar_stats->invoke_count.counter.value[1], 1);
ecs_progress(world, 0);
ecs_run(world, ecs_id(BarSys), 0, 0);
test_bool(ecs_pipeline_stats_get(world, pipeline, &stats), true);
test_int(sys_foo_stats->query.t, 2);
test_int(sys_foo_stats->invoke_count.counter.value[2], 2);
test_int(sys_bar_stats->query.t, 2);
test_int(sys_bar_stats->invoke_count.counter.value[2], 3);
ecs_pipeline_stats_fini(&stats);
ecs_fini(world);
}
void Stats_get_pipeline_stats_after_progress_2_systems_one_merge(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ecs_new(world, Position); // Make sure systems are active
ECS_SYSTEM(world, FooSys, EcsOnUpdate, [out] Position());
ECS_SYSTEM(world, BarSys, EcsOnUpdate, Position);
ecs_entity_t pipeline = ecs_get_pipeline(world);
test_assert(pipeline != 0);
ecs_progress(world, 0);
ecs_pipeline_stats_t stats = {0};
test_bool(ecs_pipeline_stats_get(world, pipeline, &stats), true);
test_int(ecs_vec_count(&stats.systems), 4);
test_int(ecs_vec_get_t(&stats.systems, ecs_entity_t, 0)[0], ecs_id(FooSys));
test_int(ecs_vec_get_t(&stats.systems, ecs_entity_t, 0)[1], 0); /* merge */
test_int(ecs_vec_get_t(&stats.systems, ecs_entity_t, 0)[2], ecs_id(BarSys));
test_int(ecs_vec_get_t(&stats.systems, ecs_entity_t, 0)[3], 0); /* merge */
test_assert(ecs_map_count(&stats.system_stats) != 0);
ecs_system_stats_t *sys_foo_stats = ecs_map_get_deref(
&stats.system_stats, ecs_system_stats_t, ecs_id(FooSys));
test_assert(sys_foo_stats != NULL);
test_int(sys_foo_stats->query.t, 1);
test_int(sys_foo_stats->invoke_count.counter.value[1], 1);
ecs_system_stats_t *sys_bar_stats = ecs_map_get_deref(
&stats.system_stats, ecs_system_stats_t, ecs_id(BarSys));
test_assert(sys_bar_stats != NULL);
test_int(sys_bar_stats->query.t, 1);
test_int(sys_bar_stats->invoke_count.counter.value[1], 1);
ecs_progress(world, 0);
test_bool(ecs_pipeline_stats_get(world, pipeline, &stats), true);
test_int(sys_foo_stats->query.t, 2);
test_int(sys_foo_stats->invoke_count.counter.value[2], 2);
test_int(sys_bar_stats->query.t, 2);
test_int(sys_bar_stats->invoke_count.counter.value[2], 2);
ecs_pipeline_stats_fini(&stats);
ecs_fini(world);
}
void Stats_get_pipeline_stats_w_task_system(void) {
ecs_world_t *world = ecs_init();
ECS_SYSTEM(world, FooSys, EcsOnUpdate, 0);
ecs_entity_t pipeline = ecs_get_pipeline(world);
test_assert(pipeline != 0);
ecs_pipeline_stats_t stats = {0};
test_bool(ecs_pipeline_stats_get(world, pipeline, &stats), true);
test_assert(ecs_map_count(&stats.system_stats) != 0); /* Inactive systems */
test_int(ecs_vec_count(&stats.systems), 0);
ecs_pipeline_stats_fini(&stats);
ecs_fini(world);
}
void Stats_get_entity_count(void) {
ecs_world_t *world = ecs_init();
ecs_world_stats_t stats = {0};
ecs_world_stats_get(world, &stats);
float count;
float prev = count = stats.entities.count.gauge.avg[stats.t];
test_assert(count != 0);
ecs_entity_t e = ecs_new_id(world);
ecs_world_stats_get(world, &stats);
count = stats.entities.count.gauge.avg[stats.t];
test_int(count - prev, 1);
ecs_delete(world, e);
prev = count;
ecs_world_stats_get(world, &stats);
count = stats.entities.count.gauge.avg[stats.t];
test_int(count - prev, -1);
ecs_fini(world);
}
void Stats_get_not_alive_entity_count(void) {
ecs_world_t *world = ecs_init();
ecs_world_stats_t stats = {0};
ecs_world_stats_get(world, &stats);
float count;
float prev = count = stats.entities.not_alive_count.gauge.avg[stats.t];
test_int(count, 0);
ecs_entity_t e = ecs_new_id(world);
prev = count;
ecs_world_stats_get(world, &stats);
count = stats.entities.not_alive_count.gauge.avg[stats.t];
test_int(count - prev, 0);
ecs_delete(world, e);
prev = count;
ecs_world_stats_get(world, &stats);
count = stats.entities.not_alive_count.gauge.avg[stats.t];
test_int(count - prev, 1);
ecs_fini(world);
}

View File

@@ -0,0 +1,715 @@
#include <addons.h>
static
void Iter(ecs_iter_t *it) {
Position *p = ecs_field(it, Position, 1);
Position *p_parent = ecs_field(it, Position, 2);
test_assert(!p_parent || !ecs_field_is_self(it, 2));
probe_iter(it);
int i;
for (i = 0; i < it->count; i ++) {
p[i].x ++;
p[i].y ++;
if (p_parent) {
p[i].x += p_parent->x;
p[i].y += p_parent->y;
}
}
}
void SystemCascade_cascade_depth_1(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_ENTITY(world, e1, Position);
ECS_ENTITY(world, e2, Position);
ECS_ENTITY(world, e3, Position);
ECS_ENTITY(world, e4, Position);
ECS_SYSTEM(world, Iter, EcsOnUpdate, Position, ?Position(parent|cascade));
ecs_system_init(world, &(ecs_system_desc_t){
.entity = Iter,
.query.filter.instanced = true
});
ecs_set(world, e1, Position, {1, 2});
ecs_set(world, e2, Position, {1, 2});
ecs_set(world, e3, Position, {1, 2});
ecs_set(world, e4, Position, {1, 2});
ecs_add_pair(world, e3, EcsChildOf, e1);
ecs_add_pair(world, e4, EcsChildOf, e2);
Probe ctx = {0};
ecs_set_ctx(world, &ctx, NULL);
ecs_progress(world, 1);
test_int(ctx.count, 4);
test_int(ctx.invoked, 3);
test_int(ctx.system, Iter);
test_int(ctx.term_count, 2);
test_null(ctx.param);
probe_has_entity(&ctx, e1);
probe_has_entity(&ctx, e2);
probe_has_entity(&ctx, e3);
probe_has_entity(&ctx, e4);
test_int(ctx.c[0][0], ecs_id(Position));
test_int(ctx.s[0][0], 0);
const Position *p = ecs_get(world, e1, Position);
test_assert(p != NULL);
test_int(p->x, 2);
test_int(p->y, 3);
p = ecs_get(world, e2, Position);
test_assert(p != NULL);
test_int(p->x, 2);
test_int(p->y, 3);
p = ecs_get(world, e3, Position);
test_assert(p != NULL);
test_int(p->x, 4);
test_int(p->y, 6);
p = ecs_get(world, e4, Position);
test_assert(p != NULL);
test_int(p->x, 4);
test_int(p->y, 6);
ecs_fini(world);
}
void SystemCascade_cascade_depth_2(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_ENTITY(world, e1, Position);
ECS_ENTITY(world, e2, Position);
ECS_ENTITY(world, e3, Position);
ECS_ENTITY(world, e4, Position);
ECS_ENTITY(world, e5, Position);
ECS_ENTITY(world, e6, Position);
ECS_SYSTEM(world, Iter, EcsOnUpdate, Position, ?Position(parent|cascade));
ecs_system_init(world, &(ecs_system_desc_t){
.entity = Iter,
.query.filter.instanced = true
});
ecs_set(world, e1, Position, {1, 2});
ecs_set(world, e2, Position, {1, 2});
ecs_set(world, e3, Position, {1, 2});
ecs_set(world, e4, Position, {1, 2});
ecs_set(world, e5, Position, {1, 2});
ecs_set(world, e6, Position, {1, 2});
ecs_add_pair(world, e3, EcsChildOf, e1); /* depth 1 */
ecs_add_pair(world, e4, EcsChildOf, e2); /* depth 1 */
ecs_add_pair(world, e5, EcsChildOf, e3); /* depth 2 */
ecs_add_pair(world, e6, EcsChildOf, e4); /* depth 2 */
Probe ctx = {0};
ecs_set_ctx(world, &ctx, NULL);
ecs_progress(world, 1);
test_int(ctx.count, 6);
test_int(ctx.invoked, 5);
test_int(ctx.system, Iter);
test_int(ctx.term_count, 2);
test_null(ctx.param);
test_assert((ctx.e[0] == e1 && ctx.e[1] == e2) || (ctx.e[0] == e2 && ctx.e[1] == e1));
test_assert((ctx.e[2] == e3 && ctx.e[3] == e4) || (ctx.e[2] == e4 && ctx.e[3] == e3));
test_assert((ctx.e[4] == e5 && ctx.e[5] == e6) || (ctx.e[4] == e6 && ctx.e[5] == e5));
test_int(ctx.c[0][0], ecs_id(Position));
test_int(ctx.s[0][0], 0);
const Position *p = ecs_get(world, e1, Position);
test_assert(p != NULL);
test_int(p->x, 2);
test_int(p->y, 3);
p = ecs_get(world, e2, Position);
test_assert(p != NULL);
test_int(p->x, 2);
test_int(p->y, 3);
p = ecs_get(world, e3, Position);
test_assert(p != NULL);
test_int(p->x, 4);
test_int(p->y, 6);
p = ecs_get(world, e4, Position);
test_assert(p != NULL);
test_int(p->x, 4);
test_int(p->y, 6);
p = ecs_get(world, e5, Position);
test_assert(p != NULL);
test_int(p->x, 6);
test_int(p->y, 9);
p = ecs_get(world, e6, Position);
test_assert(p != NULL);
test_int(p->x, 6);
test_int(p->y, 9);
ecs_fini(world);
}
void SystemCascade_cascade_depth_2_new_syntax(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_ENTITY(world, e1, Position);
ECS_ENTITY(world, e2, Position);
ECS_ENTITY(world, e3, Position);
ECS_ENTITY(world, e4, Position);
ECS_ENTITY(world, e5, Position);
ECS_ENTITY(world, e6, Position);
ECS_SYSTEM(world, Iter, EcsOnUpdate, Position, ?Position(cascade(ChildOf)));
ecs_system_init(world, &(ecs_system_desc_t){
.entity = Iter,
.query.filter.instanced = true
});
ecs_set(world, e1, Position, {1, 2});
ecs_set(world, e2, Position, {1, 2});
ecs_set(world, e3, Position, {1, 2});
ecs_set(world, e4, Position, {1, 2});
ecs_set(world, e5, Position, {1, 2});
ecs_set(world, e6, Position, {1, 2});
ecs_add_pair(world, e3, EcsChildOf, e1); /* depth 1 */
ecs_add_pair(world, e4, EcsChildOf, e2); /* depth 1 */
ecs_add_pair(world, e5, EcsChildOf, e3); /* depth 2 */
ecs_add_pair(world, e6, EcsChildOf, e4); /* depth 2 */
Probe ctx = {0};
ecs_set_ctx(world, &ctx, NULL);
ecs_progress(world, 1);
test_int(ctx.count, 6);
test_int(ctx.invoked, 5);
test_int(ctx.system, Iter);
test_int(ctx.term_count, 2);
test_null(ctx.param);
test_assert((ctx.e[0] == e1 && ctx.e[1] == e2) || (ctx.e[0] == e2 && ctx.e[1] == e1));
test_assert((ctx.e[2] == e3 && ctx.e[3] == e4) || (ctx.e[2] == e4 && ctx.e[3] == e3));
test_assert((ctx.e[4] == e5 && ctx.e[5] == e6) || (ctx.e[4] == e6 && ctx.e[5] == e5));
test_int(ctx.c[0][0], ecs_id(Position));
test_int(ctx.s[0][0], 0);
const Position *p = ecs_get(world, e1, Position);
test_assert(p != NULL);
test_int(p->x, 2);
test_int(p->y, 3);
p = ecs_get(world, e2, Position);
test_assert(p != NULL);
test_int(p->x, 2);
test_int(p->y, 3);
p = ecs_get(world, e3, Position);
test_assert(p != NULL);
test_int(p->x, 4);
test_int(p->y, 6);
p = ecs_get(world, e4, Position);
test_assert(p != NULL);
test_int(p->x, 4);
test_int(p->y, 6);
p = ecs_get(world, e5, Position);
test_assert(p != NULL);
test_int(p->x, 6);
test_int(p->y, 9);
p = ecs_get(world, e6, Position);
test_assert(p != NULL);
test_int(p->x, 6);
test_int(p->y, 9);
ecs_fini(world);
}
static
void AddParent(ecs_iter_t *it) {
Position *p = ecs_field(it, Position, 1);
Position *p_parent = ecs_field(it, Position, 2);
test_assert(!p_parent || !ecs_field_is_self(it, 2));
probe_iter(it);
int i;
for (i = 0; i < it->count; i ++) {
if (p_parent) {
p[i].x += p_parent->x;
p[i].y += p_parent->y;
}
}
}
void SystemCascade_add_after_match(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_ENTITY(world, e1, Position);
ECS_ENTITY(world, e2, Position);
ECS_ENTITY(world, e3, Position);
ECS_ENTITY(world, e4, Position);
ECS_SYSTEM(world, AddParent, EcsOnUpdate, Position, ?Position(parent|cascade));
ecs_system_init(world, &(ecs_system_desc_t){
.entity = AddParent,
.query.filter.instanced = true
});
ecs_entity_t parent = ecs_new(world, 0);
ecs_set(world, e1, Position, {1, 2});
ecs_set(world, e2, Position, {1, 2});
ecs_set(world, e3, Position, {1, 2});
ecs_set(world, e4, Position, {1, 2});
ecs_add_pair(world, e3, EcsChildOf, parent); /* depth 1 */
ecs_add_pair(world, e4, EcsChildOf, parent); /* depth 1 */
Probe ctx = {0};
ecs_set_ctx(world, &ctx, NULL);
ecs_progress(world, 1);
/* Before adding Position to parent, it wasn't being considered for the
* column(parent|cascade), so tables could have been ordered randomly. Make sure
* that queries can handle changes to depth after all tables are matched */
ecs_set(world, parent, Position, {1, 2});
ecs_os_zeromem(&ctx);
ecs_progress(world, 1);
test_int(ctx.count, 5);
test_int(ctx.invoked, 3);
test_int(ctx.system, AddParent);
test_int(ctx.term_count, 2);
test_null(ctx.param);
test_assert(ctx.e[0] == e1 || ctx.e[1] == e1 || ctx.e[2] == e1);
test_assert(ctx.e[0] == e2 || ctx.e[1] == e2 || ctx.e[2] == e2);
test_assert(ctx.e[0] == parent || ctx.e[1] == parent || ctx.e[2] == parent);
test_assert(ctx.e[3] == e3 || ctx.e[4] == e3);
test_assert(ctx.e[3] == e4 || ctx.e[4] == e4);
test_int(ctx.c[0][0], ecs_id(Position));
test_int(ctx.s[0][0], 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);
p = ecs_get(world, e3, Position);
test_assert(p != NULL);
test_int(p->x, 2);
test_int(p->y, 4);
p = ecs_get(world, e4, Position);
test_assert(p != NULL);
test_int(p->x, 2);
test_int(p->y, 4);
ecs_fini(world);
}
void SystemCascade_adopt_after_match(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_ENTITY(world, e1, Position);
ECS_ENTITY(world, e2, Position);
ECS_ENTITY(world, e3, Position);
ECS_ENTITY(world, e4, Position);
ECS_SYSTEM(world, AddParent, EcsOnUpdate, Position, ?Position(parent|cascade));
ecs_system_init(world, &(ecs_system_desc_t){
.entity = AddParent,
.query.filter.instanced = true
});
ecs_entity_t parent = ecs_set(world, 0, Position, {1, 2});
ecs_set(world, e1, Position, {1, 2});
ecs_set(world, e2, Position, {1, 2});
ecs_set(world, e3, Position, {1, 2});
ecs_set(world, e4, Position, {1, 2});
Probe ctx = {0};
ecs_set_ctx(world, &ctx, NULL);
ecs_progress(world, 1);
ecs_add_pair(world, e3, EcsChildOf, parent);
ecs_add_pair(world, e4, EcsChildOf, parent);
ecs_os_zeromem(&ctx);
ecs_progress(world, 1);
test_int(ctx.count, 5);
test_int(ctx.invoked, 3);
test_int(ctx.system, AddParent);
test_int(ctx.term_count, 2);
test_null(ctx.param);
test_int(ctx.e[0], e1);
test_int(ctx.e[1], e2);
test_int(ctx.e[2], parent);
test_int(ctx.e[3], e3);
test_int(ctx.e[4], e4);
test_int(ctx.c[0][0], ecs_id(Position));
test_int(ctx.s[0][0], 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);
p = ecs_get(world, e3, Position);
test_assert(p != NULL);
test_int(p->x, 2);
test_int(p->y, 4);
p = ecs_get(world, e4, Position);
test_assert(p != NULL);
test_int(p->x, 2);
test_int(p->y, 4);
ecs_fini(world);
}
void SystemCascade_custom_relation_cascade_depth_1(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_ENTITY(world, Rel, Traversable);
ECS_ENTITY(world, e1, Position);
ECS_ENTITY(world, e2, Position);
ECS_ENTITY(world, e3, Position);
ECS_ENTITY(world, e4, Position);
ECS_SYSTEM(world, Iter, EcsOnUpdate, Position, ?Position(cascade(Rel)));
ecs_system_init(world, &(ecs_system_desc_t){
.entity = Iter,
.query.filter.instanced = true
});
ecs_set(world, e1, Position, {1, 2});
ecs_set(world, e2, Position, {1, 2});
ecs_set(world, e3, Position, {1, 2});
ecs_set(world, e4, Position, {1, 2});
ecs_add_pair(world, e3, Rel, e1);
ecs_add_pair(world, e4, Rel, e2);
Probe ctx = {0};
ecs_set_ctx(world, &ctx, NULL);
ecs_progress(world, 1);
test_int(ctx.count, 4);
test_int(ctx.invoked, 3);
test_int(ctx.system, Iter);
test_int(ctx.term_count, 2);
test_null(ctx.param);
probe_has_entity(&ctx, e1);
probe_has_entity(&ctx, e2);
probe_has_entity(&ctx, e3);
probe_has_entity(&ctx, e4);
test_int(ctx.c[0][0], ecs_id(Position));
test_int(ctx.s[0][0], 0);
const Position *p = ecs_get(world, e1, Position);
test_assert(p != NULL);
test_int(p->x, 2);
test_int(p->y, 3);
p = ecs_get(world, e2, Position);
test_assert(p != NULL);
test_int(p->x, 2);
test_int(p->y, 3);
p = ecs_get(world, e3, Position);
test_assert(p != NULL);
test_int(p->x, 4);
test_int(p->y, 6);
p = ecs_get(world, e4, Position);
test_assert(p != NULL);
test_int(p->x, 4);
test_int(p->y, 6);
ecs_fini(world);
}
void SystemCascade_custom_relation_cascade_depth_2(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_ENTITY(world, Rel, Traversable);
ECS_ENTITY(world, e1, Position);
ECS_ENTITY(world, e2, Position);
ECS_ENTITY(world, e3, Position);
ECS_ENTITY(world, e4, Position);
ECS_ENTITY(world, e5, Position);
ECS_ENTITY(world, e6, Position);
ECS_SYSTEM(world, Iter, EcsOnUpdate, Position, ?Position(cascade(Rel)));
ecs_system_init(world, &(ecs_system_desc_t){
.entity = Iter,
.query.filter.instanced = true
});
ecs_set(world, e1, Position, {1, 2});
ecs_set(world, e2, Position, {1, 2});
ecs_set(world, e3, Position, {1, 2});
ecs_set(world, e4, Position, {1, 2});
ecs_set(world, e5, Position, {1, 2});
ecs_set(world, e6, Position, {1, 2});
ecs_add_pair(world, e3, Rel, e1); /* depth 1 */
ecs_add_pair(world, e4, Rel, e2); /* depth 1 */
ecs_add_pair(world, e5, Rel, e3); /* depth 2 */
ecs_add_pair(world, e6, Rel, e4); /* depth 2 */
Probe ctx = {0};
ecs_set_ctx(world, &ctx, NULL);
ecs_progress(world, 1);
test_int(ctx.count, 6);
test_int(ctx.invoked, 5);
test_int(ctx.system, Iter);
test_int(ctx.term_count, 2);
test_null(ctx.param);
test_assert((ctx.e[0] == e1 && ctx.e[1] == e2) || (ctx.e[0] == e2 && ctx.e[1] == e1));
test_assert((ctx.e[2] == e3 && ctx.e[3] == e4) || (ctx.e[2] == e4 && ctx.e[3] == e3));
test_assert((ctx.e[4] == e5 && ctx.e[5] == e6) || (ctx.e[4] == e6 && ctx.e[5] == e5));
test_int(ctx.c[0][0], ecs_id(Position));
test_int(ctx.s[0][0], 0);
const Position *p = ecs_get(world, e1, Position);
test_assert(p != NULL);
test_int(p->x, 2);
test_int(p->y, 3);
p = ecs_get(world, e2, Position);
test_assert(p != NULL);
test_int(p->x, 2);
test_int(p->y, 3);
p = ecs_get(world, e3, Position);
test_assert(p != NULL);
test_int(p->x, 4);
test_int(p->y, 6);
p = ecs_get(world, e4, Position);
test_assert(p != NULL);
test_int(p->x, 4);
test_int(p->y, 6);
p = ecs_get(world, e5, Position);
test_assert(p != NULL);
test_int(p->x, 6);
test_int(p->y, 9);
p = ecs_get(world, e6, Position);
test_assert(p != NULL);
test_int(p->x, 6);
test_int(p->y, 9);
ecs_fini(world);
}
void SystemCascade_custom_relation_add_after_match(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_ENTITY(world, Rel, Traversable);
ECS_ENTITY(world, e1, Position);
ECS_ENTITY(world, e2, Position);
ECS_ENTITY(world, e3, Position);
ECS_ENTITY(world, e4, Position);
ECS_SYSTEM(world, AddParent, EcsOnUpdate, Position, ?Position(cascade(Rel)));
ecs_system_init(world, &(ecs_system_desc_t){
.entity = AddParent,
.query.filter.instanced = true
});
ecs_entity_t parent = ecs_new(world, 0);
ecs_set(world, e1, Position, {1, 2});
ecs_set(world, e2, Position, {1, 2});
ecs_set(world, e3, Position, {1, 2});
ecs_set(world, e4, Position, {1, 2});
ecs_add_pair(world, e3, Rel, parent); /* depth 1 */
ecs_add_pair(world, e4, Rel, parent); /* depth 1 */
Probe ctx = {0};
ecs_set_ctx(world, &ctx, NULL);
ecs_progress(world, 1);
/* Before adding Position to parent, it wasn't being considered for the
* column(parent|cascade), so tables could have been ordered randomly. Make sure
* that queries can handle changes to depth after all tables are matched */
ecs_set(world, parent, Position, {1, 2});
ecs_os_zeromem(&ctx);
ecs_progress(world, 1);
test_int(ctx.count, 5);
test_int(ctx.invoked, 3);
test_int(ctx.system, AddParent);
test_int(ctx.term_count, 2);
test_null(ctx.param);
test_assert(ctx.e[0] == e1 || ctx.e[1] == e1 || ctx.e[2] == e1);
test_assert(ctx.e[0] == e2 || ctx.e[1] == e2 || ctx.e[2] == e2);
test_assert(ctx.e[0] == parent || ctx.e[1] == parent || ctx.e[2] == parent);
test_assert(ctx.e[3] == e3 || ctx.e[4] == e3);
test_assert(ctx.e[3] == e4 || ctx.e[4] == e4);
test_int(ctx.c[0][0], ecs_id(Position));
test_int(ctx.s[0][0], 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);
p = ecs_get(world, e3, Position);
test_assert(p != NULL);
test_int(p->x, 2);
test_int(p->y, 4);
p = ecs_get(world, e4, Position);
test_assert(p != NULL);
test_int(p->x, 2);
test_int(p->y, 4);
ecs_fini(world);
}
void SystemCascade_custom_relation_adopt_after_match(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_ENTITY(world, Rel, Traversable);
ECS_ENTITY(world, e1, Position);
ECS_ENTITY(world, e2, Position);
ECS_ENTITY(world, e3, Position);
ECS_ENTITY(world, e4, Position);
ECS_SYSTEM(world, AddParent, EcsOnUpdate, Position, ?Position(cascade(Rel)));
ecs_system_init(world, &(ecs_system_desc_t){
.entity = AddParent,
.query.filter.instanced = true
});
ecs_entity_t parent = ecs_set(world, 0, Position, {1, 2});
ecs_set(world, e1, Position, {1, 2});
ecs_set(world, e2, Position, {1, 2});
ecs_set(world, e3, Position, {1, 2});
ecs_set(world, e4, Position, {1, 2});
Probe ctx = {0};
ecs_set_ctx(world, &ctx, NULL);
ecs_progress(world, 1);
ecs_add_pair(world, e3, Rel, parent);
ecs_add_pair(world, e4, Rel, parent);
ecs_os_zeromem(&ctx);
ecs_progress(world, 1);
test_int(ctx.count, 5);
test_int(ctx.invoked, 3);
test_int(ctx.system, AddParent);
test_int(ctx.term_count, 2);
test_null(ctx.param);
test_int(ctx.e[0], e1);
test_int(ctx.e[1], e2);
test_int(ctx.e[2], parent);
test_int(ctx.e[3], e3);
test_int(ctx.e[4], e4);
test_int(ctx.c[0][0], ecs_id(Position));
test_int(ctx.s[0][0], 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);
p = ecs_get(world, e3, Position);
test_assert(p != NULL);
test_int(p->x, 2);
test_int(p->y, 4);
p = ecs_get(world, e4, Position);
test_assert(p != NULL);
test_int(p->x, 2);
test_int(p->y, 4);
ecs_fini(world);
}

View File

@@ -0,0 +1,156 @@
#include <addons.h>
void SystemManual_setup(void) {
ecs_log_set_level(-3);
}
static
void Iter(ecs_iter_t *it) {
Position *p = ecs_field(it, Position, 1);
Velocity *v = NULL;
Mass *m = NULL;
if (it->field_count >= 2) {
v = ecs_field(it, Velocity, 2);
}
if (it->field_count >= 3) {
m = ecs_field(it, Mass, 3);
}
probe_iter(it);
int i;
for (i = 0; i < it->count; i ++) {
p[i].x = 10;
p[i].y = 20;
if (v) {
v[i].x = 30;
v[i].y = 40;
}
if (m) {
m[i] = 50;
}
}
}
void SystemManual_1_type_1_component(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_SYSTEM(world, Iter, 0, Position);
ECS_ENTITY(world, e1, Position);
ECS_ENTITY(world, e2, Position);
ECS_ENTITY(world, e3, Position);
Probe ctx = {0};
ecs_set_ctx(world, &ctx, NULL);
ecs_run(world, Iter, 1, NULL);
test_int(ctx.count, 3);
test_int(ctx.invoked, 1);
test_int(ctx.system, Iter);
test_int(ctx.term_count, 1);
test_null(ctx.param);
test_int(ctx.e[0], e1);
test_int(ctx.e[1], e2);
test_int(ctx.e[2], e3);
test_int(ctx.c[0][0], ecs_id(Position));
test_int(ctx.s[0][0], 0);
const Position *p = ecs_get(world, e1, Position);
test_assert(p != NULL);
test_int(p->x, 10);
test_int(p->y, 20);
p = ecs_get(world, e2, Position);
test_assert(p != NULL);
test_int(p->x, 10);
test_int(p->y, 20);
p = ecs_get(world, e3, Position);
test_assert(p != NULL);
test_int(p->x, 10);
test_int(p->y, 20);
ecs_fini(world);
}
static int normal_count;
static
void NormalSystem(ecs_iter_t *it) {
normal_count ++;
}
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_add(it->world, it->entities[i], Velocity);
}
}
void SystemManual_no_automerge(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_SYSTEM(world, AddVelocity, 0, Position, Velocity());
ECS_ENTITY(world, e1, Position);
ecs_set_automerge(world, false);
ecs_readonly_begin(world);
ecs_world_t *stage = ecs_get_stage(world, 0);
ecs_run(stage, AddVelocity, 1, NULL);
test_assert(!ecs_has(stage, e1, Velocity));
ecs_readonly_end(world);
test_assert(!ecs_has(world, e1, Velocity));
ecs_merge(world);
test_assert(ecs_has(world, e1, Velocity));
ecs_fini(world);
}
static int dummy_ran = 0;
void DummySystem(ecs_iter_t *it) {
ecs_entity_t Tag = ecs_field_id(it, 1);
ecs_add_id(it->world, Tag, Tag);
dummy_ran ++;
}
void SystemManual_dont_run_w_unmatching_entity_query(void) {
ecs_world_t *world = ecs_init();
ECS_TAG(world, Tag);
ECS_SYSTEM(world, DummySystem, 0, !Tag($));
ecs_run(world, DummySystem, 0, NULL);
test_int(dummy_ran, 1);
dummy_ran = 0;
ecs_run(world, DummySystem, 0, NULL);
test_int(dummy_ran, 0);
ecs_fini(world);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,107 @@
#include <addons.h>
static
void Iter(ecs_iter_t *it) {
Position *p = ecs_field(it, Position, 1);
probe_iter(it);
int i;
for (i = 0; i < it->count; i ++) {
p[i].x = 10;
p[i].y = 20;
}
}
void System_w_Empty_2_column_1_from_id(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_SYSTEM(world, Iter, EcsOnUpdate, Position, Velocity());
Probe ctx = {0};
ecs_set_ctx(world, &ctx, NULL);
ecs_entity_t e = ecs_new(world, Position);
ecs_progress(world, 1);
test_int(ctx.count, 1);
test_int(ctx.invoked, 1);
test_int(ctx.system, Iter);
test_int(ctx.term_count, 2);
test_null(ctx.param);
test_int(ctx.e[0], e);
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], 0);
ecs_fini(world);
}
void System_w_Empty_3_column_2_from_id(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_COMPONENT(world, Rotation);
ECS_SYSTEM(world, Iter, EcsOnUpdate, Position, Velocity(), Rotation());
Probe ctx = {0};
ecs_set_ctx(world, &ctx, NULL);
ecs_entity_t e = ecs_new(world, Position);
ecs_progress(world, 1);
test_int(ctx.count, 1);
test_int(ctx.invoked, 1);
test_int(ctx.system, Iter);
test_int(ctx.term_count, 3);
test_null(ctx.param);
test_int(ctx.e[0], e);
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], 0);
test_int(ctx.c[0][2], ecs_id(Rotation));
test_int(ctx.s[0][2], 0);
ecs_fini(world);
}
static
void CheckColumnType(ecs_iter_t *it) {
ecs_id_t ecs_id(Position) = ecs_field_id(it, 2);
test_assert(ecs_id(Position) == ecs_field_id(it, 1));
probe_iter(it);
}
void System_w_Empty_column_type(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_COMPONENT(world, Rotation);
ECS_SYSTEM(world, CheckColumnType, EcsOnUpdate, Position, Position());
Probe ctx = {0};
ecs_set_ctx(world, &ctx, NULL);
ecs_new(world, Position);
ecs_progress(world, 1);
test_int(ctx.count, 1);
ecs_fini(world);
}

View File

@@ -0,0 +1,141 @@
#include <addons.h>
static
void Iter(ecs_iter_t *it) {
Mass *m_ptr = ecs_field(it, Mass, 1);
Position *p = NULL;
Velocity *v = NULL;
if (it->field_count >= 2) {
p = ecs_field(it, Position, 2);
}
if (it->field_count >= 3) {
v = ecs_field(it, Velocity, 3);
}
test_assert(!m_ptr || !ecs_field_is_self(it, 1));
probe_iter(it);
Mass m = 1;
if (m_ptr) {
m = *m_ptr;
}
int i;
for (i = 0; i < it->count; i ++) {
p[i].x = 10 * m;
p[i].y = 20 * m;
if (v) {
v[i].x = 30 * m;
v[i].y = 40 * m;
}
}
}
void System_w_FromEntity_2_column_1_from_entity(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Mass);
ECS_ENTITY(world, e1, Mass);
ECS_ENTITY(world, e2, Position);
ECS_SYSTEM(world, Iter, EcsOnUpdate, Mass(e1), Position);
ecs_set(world, e1, Mass, {5});
Probe ctx = {0};
ecs_set_ctx(world, &ctx, NULL);
ecs_progress(world, 1);
test_int(ctx.count, 1);
test_int(ctx.invoked, 1);
test_int(ctx.system, Iter);
test_int(ctx.term_count, 2);
test_null(ctx.param);
test_int(ctx.e[0], e2);
test_int(ctx.c[0][0], ecs_id(Mass));
test_int(ctx.s[0][0], e1);
test_int(ctx.c[0][1], ecs_id(Position));
test_int(ctx.s[0][1], 0);
const Position *p = ecs_get(world, e2, Position);
test_assert(p != NULL);
test_int(p->x, 50);
test_int(p->y, 100);
ecs_fini(world);
}
static bool dummy_invoked = 0;
static ecs_entity_t dummy_component = 0;
static ecs_entity_t dummy_source = 0;
static
void dummy_reset(void) {
dummy_invoked = false;
dummy_component = 0;
dummy_source = 0;
}
static
void Dummy(ecs_iter_t *it) {
dummy_invoked = 1;
dummy_component = ecs_field_id(it, 1);
dummy_source = ecs_field_src(it, 1);
}
void System_w_FromEntity_task_from_entity(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_ENTITY(world, e1, Position);
ECS_SYSTEM(world, Dummy, EcsOnUpdate, Position(e1));
ecs_progress(world, 1);
test_bool(dummy_invoked, true);
test_assert(dummy_component == ecs_id(Position));
test_assert(dummy_source == e1);
dummy_reset();
ecs_remove(world, e1, Position);
ecs_progress(world, 1);
test_bool(dummy_invoked, false);
ecs_fini(world);
}
void System_w_FromEntity_task_not_from_entity(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_ENTITY(world, e1, Position);
ECS_SYSTEM(world, Dummy, EcsOnUpdate, !Position(e1));
ecs_progress(world, 1);
test_bool(dummy_invoked, false);
ecs_remove(world, e1, Position);
ecs_progress(world, 1);
test_bool(dummy_invoked, true);
test_assert(dummy_component == ecs_id(Position));
test_assert(dummy_source == e1);
ecs_fini(world);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,196 @@
#include <addons.h>
void InitVelocity(ecs_iter_t *it) {
Velocity *v = ecs_field(it, Velocity, 1);
int i;
for (i = 0; i < it->count; i ++) {
v[i].x = 10;
v[i].y = 20;
}
}
void InitMass(ecs_iter_t *it) {
Mass *m = ecs_field(it, Mass, 1);
int i;
for (i = 0; i < it->count; i ++) {
m[i] = 3;
}
}
void Iter(ecs_iter_t *it) {
Position *p = ecs_field(it, Position, 1);
Velocity *v = NULL;
Mass *m = NULL;
if (it->field_count >= 2) {
v = ecs_field(it, Velocity, 2);
test_assert(!ecs_field_is_self(it, 2));
}
if (it->field_count >= 3) {
m = ecs_field(it, Mass, 3);
test_assert(!m || !ecs_field_is_self(it, 3));
}
probe_iter(it);
int i;
for (i = 0; i < it->count; i ++) {
p[i].x += v->x;
p[i].y += v->y;
if (m) {
p[i].x += *m;
p[i].y += *m;
}
}
}
void System_w_FromSystem_2_column_1_from_system(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_OBSERVER(world, InitVelocity, EcsOnAdd, Velocity);
ECS_SYSTEM(world, Iter, EcsOnUpdate, Position, Velocity(Iter));
test_assert( ecs_has(world, Iter, Velocity));
const Velocity *v = ecs_get(world, Iter, Velocity);
test_assert(v != NULL);
test_int(v->x, 10);
test_int(v->y, 20);
Probe ctx = {0};
ecs_set_ctx(world, &ctx, NULL);
ecs_entity_t e = ecs_set(world, 0, Position, {0, 0});
ecs_progress(world, 1);
test_int(ctx.count, 1);
test_int(ctx.invoked, 1);
test_int(ctx.system, Iter);
test_int(ctx.term_count, 2);
test_null(ctx.param);
test_int(ctx.e[0], e);
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], Iter);
const Position *p = ecs_get(world, e, Position);
test_assert(p != NULL);
test_int(p->x, 10);
test_int(p->y, 20);
ecs_progress(world, 1);
test_int(p->x, 20);
test_int(p->y, 40);
ecs_fini(world);
}
void System_w_FromSystem_3_column_2_from_system(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_COMPONENT(world, Mass);
ECS_OBSERVER(world, InitVelocity, EcsOnAdd, Velocity);
ECS_OBSERVER(world, InitMass, EcsOnAdd, Mass);
ECS_SYSTEM(world, Iter, EcsOnUpdate, Position, Velocity(Iter), Mass(Iter));
test_assert( ecs_has(world, Iter, Velocity));
const Velocity *v = ecs_get(world, Iter, Velocity);
test_assert(v != NULL);
test_int(v->x, 10);
test_int(v->y, 20);
test_assert( ecs_has(world, Iter, Mass));
const Mass *m = ecs_get(world, Iter, Mass);
test_assert(m != NULL);
test_int(*m, 3);
Probe ctx = {0};
ecs_set_ctx(world, &ctx, NULL);
ecs_entity_t e = ecs_set(world, 0, Position, {0, 0});
ecs_progress(world, 1);
test_int(ctx.count, 1);
test_int(ctx.invoked, 1);
test_int(ctx.system, Iter);
test_int(ctx.term_count, 3);
test_null(ctx.param);
test_int(ctx.e[0], e);
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], Iter);
test_int(ctx.c[0][2], ecs_id(Mass));
test_int(ctx.s[0][2], Iter);
const Position *p = ecs_get(world, e, Position);
test_assert(p != NULL);
test_int(p->x, 13);
test_int(p->y, 23);
ecs_progress(world, 1);
test_int(p->x, 26);
test_int(p->y, 46);
ecs_fini(world);
}
void Iter_reactive(ecs_iter_t *it) {
Position *p = ecs_field(it, Position, 1);
Velocity *v = it->param;
Mass *m = NULL;
if (it->field_count >= 2) {
v = ecs_field(it, Velocity, 2);
test_assert(!ecs_field_is_self(it, 2));
}
probe_iter(it);
int i;
for (i = 0; i < it->count; i ++) {
p[i].x = v->x;
p[i].y = v->y;
if (m) {
p[i].x = *m;
p[i].y = *m;
}
}
}
void Dummy_1(ecs_iter_t *it) { }
void Dummy_2(ecs_iter_t *it) { }
void System_w_FromSystem_auto_add_tag(void) {
ecs_world_t *world = ecs_init();
ECS_TAG(world, Foo);
ECS_COMPONENT(world, Position);
ECS_SYSTEM(world, Dummy_1, EcsOnUpdate, Position, Foo(Dummy_1));
ECS_SYSTEM(world, Dummy_2, 0, Position, Foo(Dummy_2));
test_assert( ecs_has_id(world, Dummy_1, Foo));
test_assert( ecs_has_id(world, Dummy_2, Foo));
ecs_fini(world);
}

View File

@@ -0,0 +1,150 @@
#include <addons.h>
void Task(ecs_iter_t *it) {
probe_iter(it);
}
void Tasks_no_components(void) {
ecs_world_t *world = ecs_init();
ECS_SYSTEM(world, Task, EcsOnUpdate, 0);
Probe ctx = {0};
ecs_set_ctx(world, &ctx, NULL);
ecs_progress(world, 1);
test_int(ctx.count, 0);
test_int(ctx.invoked, 1);
test_int(ctx.term_count, 0);
ecs_fini(world);
}
void Tasks_one_tag(void) {
ecs_world_t *world = ecs_init();
ECS_TAG(world, Foo);
ECS_SYSTEM(world, Task, EcsOnUpdate, Foo(Task));
Probe ctx = {0};
ecs_set_ctx(world, &ctx, NULL);
ecs_progress(world, 1);
test_int(ctx.count, 0);
test_int(ctx.invoked, 1);
test_int(ctx.term_count, 1);
test_int(ctx.c[0][0], Foo);
ecs_fini(world);
}
void Tasks_from_system(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_SYSTEM(world, Task, EcsOnUpdate, Position(Task));
Probe ctx = {0};
ecs_set_ctx(world, &ctx, NULL);
ecs_progress(world, 1);
test_int(ctx.count, 0);
test_int(ctx.invoked, 1);
test_int(ctx.term_count, 1);
test_int(ctx.c[0][0], ecs_id(Position));
ecs_fini(world);
}
static int phase_counter = 0;
static
void OnLoadTask(ecs_iter_t *it) {
test_assert(it->entities == NULL);
test_int(it->count, 0);
test_int(phase_counter, 0);
phase_counter ++;
}
static
void PostLoadTask(ecs_iter_t *it) {
test_assert(it->entities == NULL);
test_int(it->count, 0);
test_int(phase_counter, 1);
phase_counter ++;
}
static
void PreUpdateTask(ecs_iter_t *it) {
test_assert(it->entities == NULL);
test_int(it->count, 0);
test_int(phase_counter, 2);
phase_counter ++;
}
static
void OnUpdateTask(ecs_iter_t *it) {
test_assert(it->entities == NULL);
test_int(it->count, 0);
test_int(phase_counter, 3);
phase_counter ++;
}
static
void OnValidateTask(ecs_iter_t *it) {
test_assert(it->entities == NULL);
test_int(it->count, 0);
test_int(phase_counter, 4);
phase_counter ++;
}
static
void PostUpdateTask(ecs_iter_t *it) {
test_assert(it->entities == NULL);
test_int(it->count, 0);
test_int(phase_counter, 5);
phase_counter ++;
}
static
void PreStoreTask(ecs_iter_t *it) {
test_assert(it->entities == NULL);
test_int(it->count, 0);
test_int(phase_counter, 6);
phase_counter ++;
}
static
void OnStoreTask(ecs_iter_t *it) {
test_assert(it->entities == NULL);
test_int(it->count, 0);
test_int(phase_counter, 7);
phase_counter ++;
}
void Tasks_tasks_in_phases(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_SYSTEM(world, OnLoadTask, EcsOnLoad, Position());
ECS_SYSTEM(world, PostLoadTask, EcsPostLoad, Position());
ECS_SYSTEM(world, PreUpdateTask, EcsPreUpdate, Position());
ECS_SYSTEM(world, OnUpdateTask, EcsOnUpdate, Position());
ECS_SYSTEM(world, OnValidateTask, EcsOnValidate, Position());
ECS_SYSTEM(world, PostUpdateTask, EcsPostUpdate, Position());
ECS_SYSTEM(world, PreStoreTask, EcsPreStore, Position());
ECS_SYSTEM(world, OnStoreTask, EcsOnStore, Position());
ecs_progress(world, 1);
test_int(phase_counter, 8);
ecs_fini(world);
}

View File

@@ -0,0 +1,758 @@
#include <addons.h>
static bool system_a_invoked;
static bool system_b_invoked;
static bool system_c_invoked;
static
void SystemA(ecs_iter_t *it) {
test_int(it->delta_time, 1.0);
test_int(it->delta_system_time, 3.0);
system_a_invoked = true;
}
static
void SystemB(ecs_iter_t *it) {
test_int(it->delta_time, 1.0);
test_int(it->delta_system_time, 3.0);
system_b_invoked = true;
}
void Timer_timeout(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_SYSTEM(world, SystemA, EcsOnUpdate, Position);
ecs_new(world, Position);
ecs_entity_t timer = ecs_set_timeout(world, SystemA, 3.0);
test_assert(timer != 0);
test_assert(timer == SystemA);
test_bool(system_a_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, true);
system_a_invoked = false;
/* Make sure this was a one-shot timer */
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
ecs_fini(world);
}
void Timer_interval(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_SYSTEM(world, SystemA, EcsOnUpdate, Position);
ecs_new(world, Position);
ecs_entity_t timer = ecs_set_interval(world, SystemA, 3.0);
test_assert(timer != 0);
test_assert(timer == SystemA);
test_bool(system_a_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, true);
system_a_invoked = false;
/* Make sure this was not a one-shot timer */
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, true);
ecs_fini(world);
}
void Timer_shared_timeout(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_SYSTEM(world, SystemA, EcsOnUpdate, Position);
ECS_SYSTEM(world, SystemB, EcsOnUpdate, Position);
ecs_new(world, Position);
ecs_entity_t timer = ecs_set_timeout(world, 0, 3.0);
test_assert(timer != 0);
ecs_set_tick_source(world, SystemA, timer);
ecs_set_tick_source(world, SystemB, timer);
test_bool(system_a_invoked, false);
test_bool(system_b_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
test_bool(system_b_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
test_bool(system_b_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, true);
test_bool(system_b_invoked, true);
system_a_invoked = false;
system_b_invoked = false;
/* Make sure this was a one-shot timer */
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
test_bool(system_b_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
test_bool(system_b_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
test_bool(system_b_invoked, false);
ecs_fini(world);
}
void Timer_shared_interval(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_SYSTEM(world, SystemA, EcsOnUpdate, Position);
ECS_SYSTEM(world, SystemB, EcsOnUpdate, Position);
ecs_new(world, Position);
ecs_entity_t timer = ecs_set_interval(world, 0, 3.0);
test_assert(timer != 0);
ecs_set_tick_source(world, SystemA, timer);
ecs_set_tick_source(world, SystemB, timer);
test_bool(system_a_invoked, false);
test_bool(system_b_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
test_bool(system_b_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
test_bool(system_b_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, true);
test_bool(system_b_invoked, true);
system_a_invoked = false;
system_b_invoked = false;
/* Make sure this was a one-shot timer */
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
test_bool(system_b_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
test_bool(system_b_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, true);
test_bool(system_b_invoked, true);
ecs_fini(world);
}
void Timer_start_stop_one_shot(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_SYSTEM(world, SystemA, EcsOnUpdate, Position);
ecs_new(world, Position);
ecs_entity_t timer = ecs_set_timeout(world, SystemA, 3.0);
test_assert(timer != 0);
test_assert(timer == SystemA);
test_bool(system_a_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
/* Stop timer */
ecs_stop_timer(world, timer);
/* Timer is stopped, should not trigger system */
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
/* Start timer, this should reset timer */
ecs_start_timer(world, timer);
/* Make sure this was a one-shot timer */
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
ecs_progress(world, 1.0);
/* System should have been triggered */
test_bool(system_a_invoked, true);
ecs_fini(world);
}
void Timer_start_stop_interval(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_SYSTEM(world, SystemA, EcsOnUpdate, Position);
ecs_new(world, Position);
ecs_entity_t timer = ecs_set_interval(world, SystemA, 3.0);
test_assert(timer != 0);
test_assert(timer == SystemA);
test_bool(system_a_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
/* Stop timer */
ecs_stop_timer(world, timer);
/* Timer is stopped, should not trigger system */
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
/* Start timer, this should reset timer */
ecs_start_timer(world, timer);
/* Make sure this was a one-shot timer */
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
ecs_progress(world, 1.0);
/* System should have been triggered */
test_bool(system_a_invoked, true);
system_a_invoked = false;
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
ecs_progress(world, 1.0);
/* Ensure that timer still triggers repeatedly */
test_bool(system_a_invoked, true);
ecs_fini(world);
}
void Timer_rate_filter(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_SYSTEM(world, SystemA, EcsOnUpdate, Position);
ecs_new(world, Position);
ecs_entity_t filter = ecs_set_rate(world, SystemA, 3, 0);
test_assert(filter != 0);
test_assert(filter == SystemA);
test_bool(system_a_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, true);
system_a_invoked = false;
/* Make sure this was a one-shot timer */
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, false);
ecs_progress(world, 1.0);
test_bool(system_a_invoked, true);
ecs_fini(world);
}
static
void SystemC(ecs_iter_t *it) {
test_int(it->delta_time, 1.0);
test_int(it->delta_system_time, 6.0);
system_c_invoked = true;
}
void Timer_rate_filter_w_rate_filter_src(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_SYSTEM(world, SystemC, EcsOnUpdate, Position);
ecs_new(world, Position);
ecs_entity_t filter_a = ecs_set_rate(world, 0, 2, 0);
test_assert(filter_a != 0);
ecs_entity_t filter_b = ecs_set_rate(world, SystemC, 3, filter_a);
test_assert(filter_b != 0);
test_assert(filter_b == SystemC);
test_bool(system_c_invoked, false);
int i;
for (i = 0; i < 5; i ++) {
ecs_progress(world, 1.0);
test_bool(system_c_invoked, false);
}
ecs_progress(world, 1.0);
test_bool(system_c_invoked, true);
system_c_invoked = false;
/* Make sure rate filter triggers repeatedly */
for (i = 0; i < 5; i ++) {
ecs_progress(world, 1.0);
test_bool(system_c_invoked, false);
}
ecs_progress(world, 1.0);
test_bool(system_c_invoked, true);
ecs_fini(world);
}
void Timer_rate_filter_w_timer_src(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_SYSTEM(world, SystemC, EcsOnUpdate, Position);
ECS_ENTITY(world, E1, Position);
ecs_entity_t timer = ecs_set_interval(world, 0, 2.0);
test_assert(timer != 0);
ecs_entity_t filter = ecs_set_rate(world, SystemC, 3, timer);
test_assert(filter != 0);
test_assert(filter == SystemC);
test_bool(system_c_invoked, false);
int i;
for (i = 0; i < 5; i ++) {
ecs_progress(world, 1.0);
test_bool(system_c_invoked, false);
}
ecs_progress(world, 1.0);
test_bool(system_c_invoked, true);
system_c_invoked = false;
/* Make sure rate filter triggers repeatedly */
for (i = 0; i < 5; i ++) {
ecs_progress(world, 1.0);
test_bool(system_c_invoked, false);
}
ecs_progress(world, 1.0);
test_bool(system_c_invoked, true);
ecs_fini(world);
}
void Timer_rate_filter_with_empty_src(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_SYSTEM(world, SystemC, EcsOnUpdate, Position);
ecs_new(world, Position);
// Not actually a tick source
ecs_entity_t filter_a = ecs_new_id(world);
test_assert(filter_a != 0);
ecs_entity_t filter_b = ecs_set_rate(world, SystemC, 6, filter_a);
test_assert(filter_b != 0);
test_assert(filter_b == SystemC);
test_bool(system_c_invoked, false);
int i;
for (i = 0; i < 5; i ++) {
ecs_progress(world, 1.0);
test_bool(system_c_invoked, false);
}
ecs_progress(world, 1.0);
test_bool(system_c_invoked, true);
system_c_invoked = false;
/* Make sure rate filter triggers repeatedly */
for (i = 0; i < 5; i ++) {
ecs_progress(world, 1.0);
test_bool(system_c_invoked, false);
}
ecs_progress(world, 1.0);
test_bool(system_c_invoked, true);
ecs_fini(world);
}
void Timer_one_shot_timer_entity(void) {
ecs_world_t *world = ecs_init();
ecs_entity_t timer = ecs_set_timeout(world, 0, 1.0);
int i;
for (i = 0; i < 3; i ++) {
ecs_progress(world, 0.3);
const EcsTickSource *src = ecs_get(world, timer, EcsTickSource);
test_assert(src != NULL);
test_bool(src->tick, false);
}
ecs_progress(world, 0.3);
const EcsTickSource *src = ecs_get(world, timer, EcsTickSource);
test_assert(src != NULL);
test_bool(src->tick, true);
/* Ensure timer doesn't tick again */
for (i = 0; i < 12; i ++) {
ecs_progress(world, 0.3);
test_bool(src->tick, false);
}
ecs_fini(world);
}
void Timer_interval_timer_entity(void) {
ecs_world_t *world = ecs_init();
ecs_entity_t timer = ecs_set_interval(world, 0, 1.0);
int i;
for (i = 0; i < 3; i ++) {
ecs_progress(world, 0.3);
const EcsTickSource *src = ecs_get(world, timer, EcsTickSource);
test_assert(src != NULL);
test_bool(src->tick, false);
}
ecs_progress(world, 0.3);
const EcsTickSource *src = ecs_get(world, timer, EcsTickSource);
test_assert(src != NULL);
test_bool(src->tick, true);
for (i = 0; i < 2; i ++) {
ecs_progress(world, 0.3);
test_bool(src->tick, false);
}
/* Timer should tick again */
ecs_progress(world, 0.3);
test_bool(src->tick, true);
ecs_fini(world);
}
void Timer_rate_entity(void) {
ecs_world_t *world = ecs_init();
/* Specify 0 for source. This applies the rate to the frame ticks */
ecs_entity_t rate = ecs_set_rate(world, 0, 4, 0);
int i;
for (i = 0; i < 3; i ++) {
ecs_progress(world, 0);
const EcsTickSource *src = ecs_get(world, rate, EcsTickSource);
test_assert(src != NULL);
test_bool(src->tick, false);
}
ecs_progress(world, 0);
const EcsTickSource *src = ecs_get(world, rate, EcsTickSource);
test_assert(src != NULL);
test_bool(src->tick, true);
for (i = 0; i < 3; i ++) {
ecs_progress(world, 0);
const EcsTickSource *src = ecs_get(world, rate, EcsTickSource);
test_assert(src != NULL);
test_bool(src->tick, false);
}
/* Filter should tick again */
ecs_progress(world, 0);
test_bool(src->tick, true);
ecs_fini(world);
}
void Timer_nested_rate_entity(void) {
ecs_world_t *world = ecs_init();
/* Nested rate filter */
ecs_entity_t parent = ecs_set_rate(world, 0, 2, 0);
ecs_entity_t rate = ecs_set_rate(world, 0, 2, parent);
int i;
for (i = 0; i < 3; i ++) {
ecs_progress(world, 0);
const EcsTickSource *src = ecs_get(world, rate, EcsTickSource);
test_assert(src != NULL);
test_bool(src->tick, false);
}
ecs_progress(world, 0);
const EcsTickSource *src = ecs_get(world, rate, EcsTickSource);
test_assert(src != NULL);
test_bool(src->tick, true);
for (i = 0; i < 3; i ++) {
ecs_progress(world, 0);
const EcsTickSource *src = ecs_get(world, rate, EcsTickSource);
test_assert(src != NULL);
test_bool(src->tick, false);
}
/* Filter should tick again */
ecs_progress(world, 0);
test_bool(src->tick, true);
ecs_fini(world);
}
void Timer_nested_rate_entity_empty_src(void) {
ecs_world_t *world = ecs_init();
/* Rate filter with source that is not a tick source */
ecs_entity_t parent = ecs_new(world, 0);
ecs_entity_t rate = ecs_set_rate(world, 0, 4, parent);
int i;
for (i = 0; i < 3; i ++) {
ecs_progress(world, 0);
const EcsTickSource *src = ecs_get(world, rate, EcsTickSource);
test_assert(src != NULL);
test_bool(src->tick, false);
}
ecs_progress(world, 0);
const EcsTickSource *src = ecs_get(world, rate, EcsTickSource);
test_assert(src != NULL);
test_bool(src->tick, true);
for (i = 0; i < 3; i ++) {
ecs_progress(world, 0);
const EcsTickSource *src = ecs_get(world, rate, EcsTickSource);
test_assert(src != NULL);
test_bool(src->tick, false);
}
/* Filter should tick again */
ecs_progress(world, 0);
test_bool(src->tick, true);
ecs_fini(world);
}
void Timer_naked_tick_entity(void) {
ecs_world_t *world = ecs_init();
ecs_entity_t tick = ecs_set(world, 0, EcsTickSource, {0});
int i;
for (i = 0; i < 10; i ++) {
ecs_progress(world, 0);
const EcsTickSource *src = ecs_get(world, tick, EcsTickSource);
test_assert(src != NULL);
/* Tick should always be true, no filter is applied */
test_bool(src->tick, true);
}
ecs_fini(world);
}
void Timer_stop_timer_w_rate(void) {
ecs_world_t *world = ecs_init();
ecs_entity_t timer = ecs_set_interval(world, 0, 1.0);
ecs_entity_t rate = ecs_set_rate(world, 0, 3.0, timer);
for (int i = 0; i < 5; i ++) {
ecs_progress(world, 0.5);
const EcsTickSource *src = ecs_get(world, rate, EcsTickSource);
test_assert(src != NULL);
test_bool(src->tick, false);
}
ecs_progress(world, 0.5);
{
const EcsTickSource *src = ecs_get(world, rate, EcsTickSource);
test_assert(src != NULL);
test_bool(src->tick, true);
}
ecs_stop_timer(world, timer);
for (int i = 0; i < 5; i ++) {
ecs_progress(world, 0.5);
const EcsTickSource *src = ecs_get(world, rate, EcsTickSource);
test_assert(src != NULL);
test_bool(src->tick, false);
}
ecs_progress(world, 0.5);
{
const EcsTickSource *src = ecs_get(world, rate, EcsTickSource);
test_assert(src != NULL);
test_bool(src->tick, false);
}
ecs_start_timer(world, timer);
for (int i = 0; i < 5; i ++) {
ecs_progress(world, 0.5);
const EcsTickSource *src = ecs_get(world, rate, EcsTickSource);
test_assert(src != NULL);
test_bool(src->tick, false);
}
ecs_progress(world, 0.5);
{
const EcsTickSource *src = ecs_get(world, rate, EcsTickSource);
test_assert(src != NULL);
test_bool(src->tick, true);
}
ecs_fini(world);
}
void Timer_stop_timer_w_rate_same_src(void) {
ecs_world_t *world = ecs_init();
ecs_entity_t timer = ecs_set_interval(world, 0, 1.0);
ecs_entity_t rate = ecs_set_rate(world, timer, 3.0, timer);
test_assert(rate == timer);
for (int i = 0; i < 5; i ++) {
ecs_progress(world, 0.5);
const EcsTickSource *src = ecs_get(world, rate, EcsTickSource);
test_assert(src != NULL);
test_bool(src->tick, false);
}
ecs_progress(world, 0.5);
{
const EcsTickSource *src = ecs_get(world, rate, EcsTickSource);
test_assert(src != NULL);
test_bool(src->tick, true);
}
ecs_stop_timer(world, timer);
for (int i = 0; i < 5; i ++) {
ecs_progress(world, 0.5);
const EcsTickSource *src = ecs_get(world, rate, EcsTickSource);
test_assert(src != NULL);
test_bool(src->tick, false);
}
ecs_progress(world, 0.5);
{
const EcsTickSource *src = ecs_get(world, rate, EcsTickSource);
test_assert(src != NULL);
test_bool(src->tick, false);
}
ecs_start_timer(world, timer);
for (int i = 0; i < 5; i ++) {
ecs_progress(world, 0.5);
const EcsTickSource *src = ecs_get(world, rate, EcsTickSource);
test_assert(src != NULL);
test_bool(src->tick, false);
}
ecs_progress(world, 0.5);
{
const EcsTickSource *src = ecs_get(world, rate, EcsTickSource);
test_assert(src != NULL);
test_bool(src->tick, true);
}
ecs_fini(world);
}
void Timer_randomize_timers(void) {
ecs_world_t *world = ecs_init();
ecs_entity_t timer_a = ecs_set_interval(world, 0, 1.0);
{
const EcsTimer *t = ecs_get(world, timer_a, EcsTimer);
test_assert(t != NULL);
test_assert(t->time == 0);
}
ecs_randomize_timers(world);
{
const EcsTimer *t = ecs_get(world, timer_a, EcsTimer);
test_assert(t != NULL);
test_assert(t->time != 0);
}
ecs_entity_t timer_b = ecs_set_interval(world, 0, 1.0);
{
const EcsTimer *t = ecs_get(world, timer_b, EcsTimer);
test_assert(t != NULL);
test_assert(t->time != 0);
}
ecs_fini(world);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,319 @@
#include <addons.h>
#include <stdio.h>
void probe_system_w_ctx(
ecs_iter_t *it,
Probe *ctx)
{
if (!ctx) {
return;
}
ctx->param = it->param;
ctx->system = it->system;
ctx->event = it->event;
ctx->event_id = it->event_id;
ctx->offset = 0;
ctx->term_count = it->field_count;
ctx->term_index = it->term_index;
int i;
for (i = 0; i < ctx->term_count; i ++) {
ctx->c[ctx->invoked][i] = it->ids[i];
ctx->s[ctx->invoked][i] = ecs_field_src(it, i + 1);
ecs_id_t e = ecs_field_id(it, i + 1);
test_assert(e != 0);
}
for (i = 0; i < it->count; i ++) {
if (i + ctx->count < 256) {
ctx->e[i + ctx->count] = it->entities[i];
} else {
/* can't store more than that, tests shouldn't rely on
* getting back more than 256 results */
}
}
ctx->count += it->count;
ctx->invoked ++;
}
void probe_iter(
ecs_iter_t *it)
{
Probe *ctx = ecs_get_ctx(it->world);
if (!ctx) {
ctx = it->ctx;
}
probe_system_w_ctx(it, ctx);
}
void probe_has_entity(Probe *probe, ecs_entity_t e) {
int i;
for (i = 0; i < probe->count; i ++) {
if (probe->e[i] == e) {
break;
}
}
test_assert(i != probe->count);
}
void install_test_abort(void) {
ecs_os_set_api_defaults();
ecs_os_api_t os_api = ecs_os_api;
os_api.abort_ = test_abort;
ecs_os_set_api(&os_api);
ecs_log_set_level(-5);
}
const ecs_entity_t* bulk_new_w_type(
ecs_world_t *world, ecs_entity_t type_ent, int32_t count)
{
const ecs_type_t *type = ecs_get_type(world, type_ent);
test_assert(type != NULL);
ecs_id_t *ids = type->array;
int i = 0;
while ((ecs_id_get_flags(world, ids[i]) & EcsIdDontInherit)) {
i ++;
}
const ecs_entity_t *result = ecs_bulk_new_w_id(world, ids[i], count);
for (; i < type->count; i ++) {
for (int e = 0; e < count; e ++) {
if (ecs_id_get_flags(world, ids[i]) & EcsIdDontInherit) {
continue;
}
ecs_add_id(world, result[e], ids[i]);
}
}
return result;
}
int32_t find_entity(
ecs_world_t *world,
test_iter_result_t *expect,
ecs_entity_t e)
{
int i;
for (i = 0; i < ITER_MAX_ENTITIES; i ++) {
if (expect->entities[i] == e) {
while (expect->matched[i]) {
i ++;
if (!if_test_assert(e == expect->entities[i])) {
return -1;
}
}
if (expect->entity_names[i]) {
if (!if_test_str(ecs_get_name(world, e), expect->entity_names[i])) {
return -1;
}
}
return i;
}
}
for (i = 0; i < ITER_MAX_ENTITIES; i ++) {
if (!expect->entity_names[i]) {
break;
}
if (!strcmp(ecs_get_name(world, e), expect->entity_names[i])) {
while (expect->matched[i]) {
i ++;
// If this fails, the entity is encountered more times than
// expected.
if (!if_test_str(ecs_get_name(world, e),
expect->entity_names[i]))
{
return -1;
}
}
return i;
}
}
return -1;
}
bool test_iter(
ecs_iter_t *it,
ecs_iter_next_action_t next,
test_iter_result_t *expect)
{
int32_t entity_index = -1;
while (next(it)) {
int i;
for (i = 0; (i < it->count) || (i < 1); i ++) {
ecs_entity_t e = 0;
int t;
if (it->count) {
e = it->entities[i];
entity_index = find_entity(it->world, expect, e);
// Matched unexpected entity
test_assert(entity_index != -1);
expect->matched[entity_index] = true;
// Test data
for (t = 0; t < it->field_count; t++) {
size_t size = ecs_field_size(it, t + 1);
if (!size) {
continue;
}
void *expect_ptr = expect->term_columns[t];
if (!expect_ptr) {
continue;
}
expect_ptr = ECS_OFFSET(expect_ptr, size * entity_index);
void *component_ptr = ecs_field_w_size(it, size, t + 1);
if (!if_test_assert(component_ptr != NULL)) {
return false;
}
component_ptr = ECS_OFFSET(component_ptr, size * i);
if (!if_test_assert(memcpy(component_ptr, expect_ptr, size))) {
return false;
}
}
} else {
entity_index ++;
}
// Test ids
ecs_id_t *ids = expect->term_ids[entity_index];
if (!ids[0]) {
ids = expect->term_ids[0];
}
for (t = 0; t < it->field_count; t++) {
if (!ids[t]) {
break;
}
if (!if_test_assert(ecs_field_id(it, t + 1) == ids[t])) {
return false;
}
}
if (!if_test_assert(ids[t] == 0)) {
return false;
}
// Test ids by expr
char **ids_expect = expect->term_ids_expr[entity_index];
if (!ids_expect) {
ids_expect = expect->term_ids_expr[0];
}
for (t = 0; t < it->field_count; t++) {
if (!ids_expect[t]) {
break;
}
char *id_found = ecs_id_str(it->world, ecs_field_id(it, t + 1));
if (!if_test_str(id_found, ids_expect[t])) {
printf(" - term %d\n", t);
if (e) {
printf(" - matched entity %u (%s, [%s])\n",
(uint32_t)e,
ecs_get_name(it->world, e),
ecs_type_str(it->world, ecs_get_type(it->world, e)));
if (expect->entities[i]) {
printf(" - expected entity %u (%s)\n",
(uint32_t)expect->entities[i],
ecs_get_name(it->world, expect->entities[i]));
} else if (expect->entity_names[i]) {
printf(" - expected entity %s\n",
expect->entity_names[i]);
}
}
printf(" - @ result index %d\n", entity_index);
return false;
}
ecs_os_free(id_found);
}
if (!if_test_assert(ids_expect[t] == NULL)) {
return false;
}
// Test variables
int v;
for (v = 0; v < ITER_MAX_VARIABLES; v++) {
int32_t id = expect->variables[v].id;
if (!id) {
break;
}
ecs_entity_t e = expect->variables[v].entities[entity_index];
if (!e) {
e = expect->variables[v].entities[0];
}
if (e) {
ecs_entity_t var = ecs_iter_get_var(it, id);
if (!if_test_assert(e == var)) {
return false;
}
}
const char *name = expect->variables[v].entity_names[entity_index];
if (!name) {
name = expect->variables[v].entity_names[0];
}
if (name) {
ecs_entity_t var = ecs_iter_get_var(it, id);
if (!if_test_str(name, ecs_get_name(it->world, var))) {
printf(" - variable id %d\n", id);
printf(" - index %d\n", entity_index);
return false;
}
}
/* If a variable id is set, either an entity or entity name must
* be set. */
if (!if_test_assert(e || name)) {
return false;
}
}
}
expect->table_count_actual ++;
}
for (int i = 0; i < ITER_MAX_ENTITIES; i ++) {
if (expect->entities[i] || expect->entity_names[i]) {
if (!if_test_assert(expect->matched[i])) {
printf(" - entity %u (%s) at index %d not matched\n",
(uint32_t)expect->entities[i], expect->entity_names[i], i);
return false;
}
}
}
if (expect->table_count_expect) {
if (!if_test_assert(expect->table_count_actual == expect->table_count_expect)) {
return false;
}
}
return true;
}