module tests.tests; /* import std.experimental.allocator; import std.experimental.allocator.mallocator;*/ import bubel.ecs.entity; import bubel.ecs.events; import bubel.ecs.manager; import bubel.ecs.system; import bubel.ecs.attributes; import bubel.ecs.core; version (WebAssembly) { extern (C) int printf(scope const char* format, ...) @nogc nothrow @system; alias int time_t; alias int clockid_t; enum CLOCK_REALTIME = 0; struct timespec { time_t tv_sec; int tv_nsec; } extern (C) int clock_gettime(clockid_t, timespec*) @nogc nothrow @system; struct Time { static long getUSecTime() { time_t time; timespec spec; clock_gettime(CLOCK_REALTIME, &spec); //time = spec.tv_sec; return spec.tv_sec * 1000_000 + spec.tv_nsec / 1000; //time / 1000_000; } } extern (C) void _start() { } } else version (Windows) { import core.stdc.stdio : printf; import core.sys.windows.windows; struct Time { static long getUSecTime() { LARGE_INTEGER time, freq; QueryPerformanceFrequency(&freq); QueryPerformanceCounter(&time); return time.QuadPart / (freq.QuadPart / 1000_000); } } } else version (Posix) { import core.stdc.stdio : printf; import core.sys.posix.time; struct Time { static long getUSecTime() { time_t time; timespec spec; clock_gettime(CLOCK_REALTIME, &spec); //time = spec.tv_sec; return spec.tv_sec * 1000_000 + spec.tv_nsec / 1000; //time / 1000_000; } } } struct TestEvent { mixin ECS.Event; //__gshared ushort event_id; int a; } struct TestEvent2 { mixin ECS.Event; //__gshared ushort event_id; float a; } static struct CPosition { mixin ECS.Component; float x; float y; } static struct TestComp { mixin ECS.Component; //__gshared becsID!ushort; int a = 1; ulong b = 2; static void serializeComponent(SerializeVector output) { } static void deserializeComponent(ubyte[] data) { } } static struct TestComp2 { mixin ECS.Component; //__gshared becsID!ushort; int b = 3; int a = 4; static void serializeComponent(ref TestComp comp, SerializeVector output) { } static void deserializeComponent(ref TestComp comp, ubyte[] data) { } } static struct TestComp3 { mixin ECS.Component; //__gshared becsID!ushort; uint gg = 5; //good game uint bg = 6; //bad game void serializeComponent(SerializeVector output) { } void deserializeComponent(ubyte[] data) { } } static struct TestComp4 { mixin ECS.Component; //__gshared becsID!ushort; uint gg = 7; //good game uint bg = 8; //bad game ulong a = 9; ulong b = 10; ulong c = 11; ulong g = 12; static void serializeComponent(ref TestComp comp, SerializeVector output) { } static void deserializeComponent(ref TestComp comp, ubyte[] data) { } } static struct TestComp5 { mixin ECS.Component; //__gshared becsID!ushort; uint gg = 7; //good game uint bg = 8; //bad game ulong a = 9; ulong b = 10; ulong c = 11; ulong g = 12; static void serializeComponent(ref TestComp comp, SerializeVector output) { } static void deserializeComponent(ref TestComp comp, ubyte[] data) { } } struct EverySystem { mixin ECS.System; struct EntitiesData { uint length; Entity[] entity; CPosition[] pos; } void onUpdate(EntitiesData data) { foreach(i;0..data.length) { data.pos[i].x++; data.pos[i].y++; } } void iterate(EntitiesData data) { foreach(i;0..data.length) { data.pos[i].x++; data.pos[i].y++; } } void free(EntitiesData data) { foreach(i;0..data.length) { gEntityManager.removeEntity(data.entity[i].id); } } void addOne(EntitiesData data) { foreach(i;0..data.length) { gEntityManager.addComponents(data.entity[i].id, TestComp2()); } } } struct ChangeTestSystem { mixin ECS.System!16; //__gshared ushort system_id; void onCreate() { //writeln("On Change Test System create."); printf("On Change Test System create.\n"); } void onCreate(int i) { //writeln("On Change Test System create."); printf("On Change Test System create.\n"); } void onDestroy() { //writeln("On Change Test System destroy."); printf("On Change Test System destroy.\n"); } void onAddEntity(EntitiesData data) { //printf("Entity added! ID: "); foreach (i; 0 .. data.length) printf("Entity added! ID: %u\n", cast(uint) data.entites[i].id.id); ////writeln("Entity added! ID: ", data.entites[i].id); } void onRemoveEntity(EntitiesData data) { ////writeln("Entity removed! ID: ", data.entites[0].id); printf("Entity removed! ID: %u\n", cast(uint) data.entites[0].id.id); } void onChangeEntity(EntitiesData data) { ////writeln("Entity changed! ID: ", data.entites[0].id); printf("Entity changed! ID: %u\n", cast(uint) data.entites[0].id.id); } bool onBegin() { // writeln("On Test System begin."); return true; } void onEnd() { // writeln("On Test System end."); } void initialize(ref Entity entity, ref TestComp comp) { } static struct EntitiesData { size_t length; const(Entity)[] entites; TestComp4[] test4; @optional TestComp5[] test5; } void onUpdate(EntitiesData data) { /*foreach (i; 0 .. data.length) { }*/ } } struct TestSystem { mixin ECS.System!16; //__gshared ushort system_id; uint print = 1; void onCreate() { //writeln("On Test System create."); printf("On Change Test System create.\n"); } void onDestroy() { //writeln("On Test System destroy."); printf("On Change Test System destroy.\n"); } void onAddEntity(EntitiesData data) { //foreach(i;0..data.length) ////writeln("Entity added ID: ",data.entites[i].id.id); } /* void onRemoveEntity(EntitiesData data) { ////writeln("Entity destroyed ID: ",data.entites[0].id); }*/ bool onBegin() { if(print)printf("On Test System begin.\n"); return true; } void onEnd() { if(print)printf("On Test System end.\n"); print = 0; } void initialize(ref Entity entity, ref TestComp comp) { } static struct EntitiesData { size_t length; const(Entity)[] entites; TestComp[] test; TestComp2[] test2; @readonly @optional const(TestComp3)[] test3; //@excluded TestComp4[] test4; } void onUpdate(ref Entity entity, ref TestComp test, ref TestComp2 test2) //, TestComp3* test3) //ref TestComp comp) { //assert(cast(size_t)&test % TestComp.alignof == 0); //assert(cast(size_t)&test2 % TestComp2.alignof == 0); test.a += 1000; test.b += 2000; test2.b += 2; test2.a = 8; } void onUpdate(EntitiesData data) { foreach (i; 0 .. data.length) { data.test[i].a += 1000; data.test[i].b += 2000; data.test2[i].b += 2; data.test2[i].a = 8; } } void handleEvent(TestEvent event, ref TestComp test, ref TestComp2 test2, TestComp3* test3) { } } struct TestSystemWithHighPriority { mixin ECS.System!16; //__gshared ushort system_id; static struct EntitiesData { TestComp[] test; } void initialize(ref Entity entity, ref TestComp comp) { } void onUpdate(EntitiesData data) { } } struct Sys1 { mixin ECS.System; struct EntitiesData { TestComp[] comp; } void onAddEntity(EntitiesData data) { } } struct Sys2 { mixin ECS.System; struct EntitiesData { TestComp[] comp; } void onAddEntity(EntitiesData data) { } } struct Sys3 { mixin ECS.System; struct EntitiesData { TestComp[] comp; } void onAddEntity(EntitiesData data) { } void onUpdate(EntitiesData data) { } } struct EmptyEventSystem { mixin ECS.System; bool handled = false; struct EntitiesData { uint thread_id; } void handleEvent(Entity* entity, TestEvent event) { if (!handled) { printf("EmptyEventSystem.handleEvent() called!\n"); handled = true; } assert(0, "this shouldn't be called!"); } } struct EventSystem { mixin ECS.System; bool handled = false; struct EntitiesData { uint thread_id; TestComp[] comp; } void handleEvent(Entity* entity, TestEvent event) { if (!handled) { printf("EventSystem.handleEvent() called!\n"); handled = true; } } /*void onUpdate(EntitiesData) { }*/ } struct EmptySystem { mixin ECS.System; struct EntitiesData { uint thread_id; } void onUpdate(EntitiesData data) { printf("EmptySystem.onUpdate() - this should be called once per update\n"); } } import std.meta; struct TestSystem2 { mixin ECS.System!16; //__gshared ushort system_id; /*enum ExcludedComponents { TestComp, TestComp4 }*/ //alias ExcludedComponents = AliasSeq!("TestComp", "TestComp4"); /* string ExcludedComponents2;*/ static struct EntitiesData { short length; const(Entity)[] entity; TestComp3[] test; //@excluded TestComp[] testt; } static struct EventInput { Entity* entity; TestComp3* test; //TestComp* tt; } void handleEvent(Entity* entity, TestEvent event) { TestComp3* test = entity.getComponent!TestComp3; test.bg = event.a; TestEvent2 event2; event2.a = event.a + 8; gEntityManager.sendEvent(entity.id, event2); } void handleEvent(Entity* entity, TestEvent2 event) { TestComp3* test = entity.getComponent!TestComp3; test.gg = cast(uint) event.a; } void onEnable() { //writeln("TestSystem2 enabled"); printf("TestSystem2 enabled\n"); } void onDisable() { //writeln("TestSystem2 disabled"); printf("TestSystem2 disabled\n"); } void initialize(ref Entity entity, ref TestComp comp) { } void onUpdate(EntitiesData data) { foreach (i; 0 .. data.test.length) { data.test[i].gg += 14; TestEvent event; event.a = data.test[i].gg + 4; gEntityManager.sendEvent(data.entity[i].id, event); //*/ /*TestEvent2 event2; event2.a = data.test[i].gg + 8; gEntityManager.sendEvent(data.entity[i].id, event2);//*/ //gEntityManager.sendEvent!(TestEvent)(data.entity[i].id, event); //gEntityManager.sendSelfEvent!(TestEvent)(data.entity[i].id, TestEvent()); } } void lateUpdate(ref EntitiesData data) { foreach (i; 0 .. data.test.length) { data.test[i].gg -= 1; //gEntityManager.sendSelfEvent!(TestEvent)(data.entity[i].id, TestEvent()); } } } struct ExternalUpdateCallTest { int print_count = 3; void update(TestSystem2.EntitiesData data) { if (print_count > 0) { print_count--; printf("ExternalUpdateCallTest %u %u\n", data.test[0].gg, cast(uint) data.length); } } } version (unittest) { void main() { } } else: extern (C) int main() { void dispatch(EntityManager.JobGroup jobs) nothrow @nogc { foreach (job; jobs.jobs) { ////writeln(job); job.execute(); } } uint getID() nothrow @nogc { return 0; } void writeEntityComponents(Entity* entity) { printf("EntityID(%u, %u)", cast(uint) entity.id.id, cast(uint) entity.id.counter); //write(entity.id); TestComp* test_comp = entity.getComponent!TestComp; if (test_comp) printf("TestComp(%u, %u)", cast(uint) test_comp.a, cast(uint) test_comp.b); //write(*test_comp); TestComp2* test_comp2 = entity.getComponent!TestComp2; if (test_comp2) printf("TestComp2(%u, %u)", cast(uint) test_comp2.b, cast(uint) test_comp2.a); //write(*test_comp2); TestComp3* test_comp3 = entity.getComponent!TestComp3; if (test_comp3) printf("TestComp3(%u, %u)", cast(uint) test_comp3.gg, cast(uint) test_comp3.bg); //write(*test_comp3); TestComp4* test_comp4 = entity.getComponent!TestComp4; if (test_comp4) printf("TestComp4(%u, %u, %u, %u, %u, %u)", test_comp4.gg, test_comp4.bg, cast(uint) test_comp4.a, cast(uint) test_comp4.b, cast(uint) test_comp4.c, cast(uint) test_comp4.g); //write(*test_comp4); printf("\n"); //writeln(); ////writeln((cast(uint*) pp)[0 .. 14], " ", pp); } EntityManager.initialize(1); //gEntityManager.setJobDispachFunc(&dispatch); gEntityManager.setMultithreadingCallbacks(&dispatch, &getID); //assert(gEntityManager !is null); gEntityManager.beginRegister(); gEntityManager.registerPass("fixed"); //MonoTime time = MonoTime.currTime; long time = Time.getUSecTime(); gEntityManager.registerComponent!TestComp2; gEntityManager.registerComponent!TestComp4; gEntityManager.registerComponent!TestComp; gEntityManager.registerComponent!TestComp3; gEntityManager.registerComponent!TestComp5; gEntityManager.registerComponent!CPosition; gEntityManager.registerEvent!TestEvent; gEntityManager.registerEvent!TestEvent2; /*ulong dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Components register: ", dur, " usecs"); time = MonoTime.currTime;*/ printf("Components register: %f usecs\n", cast(float)(Time.getUSecTime() - time)); time = Time.getUSecTime(); gEntityManager.registerSystem!TestSystemWithHighPriority(100, "fixed"); gEntityManager.registerSystem!TestSystem(0); gEntityManager.registerSystem!ChangeTestSystem(0); gEntityManager.registerSystem!Sys1(10); gEntityManager.registerSystem!Sys2(-100); gEntityManager.registerSystem!Sys3(-2); gEntityManager.registerSystem!EmptySystem(2); gEntityManager.registerSystem!EmptyEventSystem(2); gEntityManager.registerSystem!EventSystem(2); gEntityManager.registerSystem!EverySystem(0); //gEntityManager.registerSystem!TestSystemWithHighPriority(100); //gEntityManager.registerSystem!TestSystem2(0); gEntityManager.endRegister(); /*dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Systems register: ", dur, " usecs"); time = MonoTime.currTime;*/ printf("Systems register: %f usecs\n", cast(float)(Time.getUSecTime() - time)); time = Time.getUSecTime(); //ushort[3] ids = [becsID!TestComp2, becsID!TestComp, becsID!TestComp4]; ushort[2] ids = [becsID!TestComp2, becsID!TestComp]; EntityTemplate* tmpl = gEntityManager.allocateTemplate(ids); //ushort[3] ids2 = [becsID!TestComp3, becsID!TestComp, becsID!TestComp4]; ushort[2] ids2 = [becsID!TestComp3, becsID!TestComp]; EntityTemplate* tmpl2 = gEntityManager.allocateTemplate(ids2); ////writeln(tmpl.info.components[]); //*cast(EntityID*) tmpl.entity_data.ptr = EntityID(1, 1); //dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Template allocating: ", dur, " usecs"); printf("Template allocating: %f usecs\n", cast(float)(Time.getUSecTime() - time)); time = Time.getUSecTime(); ushort[1] empty_ids = [becsID!CPosition]; EntityTemplate* tmpl_empty = gEntityManager.allocateTemplate(empty_ids); gEntityManager.commit(); time = Time.getUSecTime(); foreach(i;0..4_000_000)gEntityManager.addEntity(tmpl_empty); gEntityManager.commit(); foreach(i;0..4_000_000)gEntityManager.addEntity(tmpl_empty); gEntityManager.commit(); foreach(i;0..2_000_000)gEntityManager.addEntity(tmpl_empty); gEntityManager.commit(); printf("Adding 1M entities: %f usecs\n", cast(float)(Time.getUSecTime() - time)); gEntityManager.commit(); time = Time.getUSecTime(); gEntityManager.callEntitiesFunction!EverySystem(&gEntityManager.getSystem!EverySystem().iterate); printf("Iterate 1M entities: %f usecs\n", cast(float)(Time.getUSecTime() - time)); gEntityManager.begin(); time = Time.getUSecTime(); gEntityManager.update(); printf("Iterate 1M entities (update): %f usecs\n", cast(float)(Time.getUSecTime() - time)); gEntityManager.end(); time = Time.getUSecTime(); gEntityManager.callEntitiesFunction!EverySystem(&gEntityManager.getSystem!EverySystem().free); gEntityManager.commit(); printf("Deleting 1M entities: %f usecs\n", cast(float)(Time.getUSecTime() - time)); time = Time.getUSecTime(); foreach(i;0..4_000_000)gEntityManager.addEntity(tmpl_empty); gEntityManager.commit(); foreach(i;0..4_000_000)gEntityManager.addEntity(tmpl_empty); gEntityManager.commit(); foreach(i;0..2_000_000)gEntityManager.addEntity(tmpl_empty); gEntityManager.commit(); printf("Adding 1M entities (prealloc): %f usecs\n", cast(float)(Time.getUSecTime() - time)); gEntityManager.commit(); time = Time.getUSecTime(); gEntityManager.callEntitiesFunction!EverySystem(&gEntityManager.getSystem!EverySystem().addOne); gEntityManager.commit(); printf("Adding 1M component: %f usecs\n", cast(float)(Time.getUSecTime() - time)); gEntityManager.commit(); gEntityManager.callEntitiesFunction!EverySystem(&gEntityManager.getSystem!EverySystem().free); gEntityManager.commit(); time = Time.getUSecTime(); EntityID entity; { entity = gEntityManager.addEntity(tmpl).id; writeEntityComponents(gEntityManager.getEntity(entity)); EntityManager.EntitiesBlock* block = gEntityManager.getMetaData( gEntityManager.getEntity(entity)); EntityManager.EntityInfo* info = block.type_info; //writeln(info.add_listeners); //if(info)assert(0); } //time = MonoTime.currTime; time = Time.getUSecTime(); //foreach(i; 0..1_000_000)gEntityManager.addEntity(tmpl); //foreach(i; 0..1_000_000)gEntityManager.removeEntity(gEntityManager.addEntity(tmpl).id); import bubel.ecs.std; EntityID[] idss = Mallocator.makeArray!EntityID(5000); //[5000] //scope(exit)Mallocator.dispose(idss); foreach (i; 0 .. 200) { gEntityManager.begin(); foreach (j; 0 .. 5_000) idss[j] = gEntityManager.addEntity(tmpl).id; foreach (j; 0 .. 5_000) gEntityManager.removeEntity(idss[j]); gEntityManager.end(); } gEntityManager.commit(); //dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Entities adding: ", dur, " usecs"); printf("Entities adding: %f usecs\n", cast(float)(Time.getUSecTime() - time)); Mallocator.dispose(idss); time = Time.getUSecTime(); uint blocks = 0; foreach (info; &gEntityManager.entities_infos.byValue) { EntityManager.EntitiesBlock* block = info.first_block; while (block !is null) { block = block.next_block; blocks++; } } //writeln("Entities blocks: ", blocks); printf("Entities blocks: %u\n", blocks); //foreach(j; 0..1_000)gEntityManager.addEntity(tmpl); gEntityManager.beginRegister(); gEntityManager.registerSystem!TestSystem2(0); gEntityManager.endRegister(); //gEntityManager.generateDependencies(); //assert(*(cast(EntityID*)(cast(void*)tmpl.info.first_block+24)) == EntityID(1,1)); //assert(*(cast(EntityID*)(cast(void*)tmpl.info.first_block+48)) == EntityID(1,1)); EntityID entity2; //time = MonoTime.currTime; time = Time.getUSecTime(); EntityID[] entities = Mallocator.makeArray!EntityID(1_000_000); foreach (i; 0 .. 500_000) { entity2 = gEntityManager.addEntity(tmpl).id; entities[i * 2] = entity2; entities[i * 2 + 1] = gEntityManager.addEntity(tmpl2).id; } gEntityManager.commit(); //dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Entities adding2: ", dur, " usecs"); //time = MonoTime.currTime; printf("Entities adding2: %f usecs\n", cast(float)(Time.getUSecTime() - time)); time = Time.getUSecTime(); foreach (i; 0 .. 1_000_000) { gEntityManager.addComponents(entities[i], TestComp5()); if ((i & 0x00FFFF) == 0) gEntityManager.commit(); } gEntityManager.commit(); //dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Components adding: ", dur, " usecs"); //time = MonoTime.currTime; printf("Components adding: %f usecs\n", cast(float)(Time.getUSecTime() - time)); time = Time.getUSecTime(); foreach (i; 0 .. 1_000_000) { gEntityManager.removeComponents!TestComp5(entities[i]); //if((i & 0x00FFFF) == 0)gEntityManager.commit(); } gEntityManager.commit(); //dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Components removing: ", dur, " usecs"); printf("Components removing: %f usecs\n", cast(float)(Time.getUSecTime() - time)); time = Time.getUSecTime(); Mallocator.dispose(entities); //time = MonoTime.currTime; time = Time.getUSecTime(); gEntityManager.begin(); //gEntityManager.updateMT(); gEntityManager.update(); gEntityManager.end(); //dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Update: ", dur, " usecs"); printf("Update: %f usecs\n", cast(float)(Time.getUSecTime() - time)); writeEntityComponents(gEntityManager.getEntity(entity2)); //time = MonoTime.currTime; time = Time.getUSecTime(); gEntityManager.begin(); gEntityManager.updateMT(); //gEntityManager.update(); gEntityManager.end(); //dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Update: ", dur, " usecs"); printf("Update: %f usecs\n", cast(float)(Time.getUSecTime() - time)); writeEntityComponents(gEntityManager.getEntity(entity2)); //time = MonoTime.currTime; time = Time.getUSecTime(); gEntityManager.begin(); gEntityManager.updateMT(); //gEntityManager.update(); gEntityManager.end(); //dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Update: ", dur, " usecs"); printf("Update: %f usecs\n", cast(float)(Time.getUSecTime() - time)); writeEntityComponents(gEntityManager.getEntity(entity2)); entity = gEntityManager.addEntity(tmpl).id; gEntityManager.begin(); gEntityManager.update(); gEntityManager.end(); //Entity* pp;// = gEntityManager.getEntity(entity.id); ////writeln((cast(uint*) pp)[0 .. 14], " ", pp); writeEntityComponents(gEntityManager.getEntity(entity)); //writeln("Entity, its copy, and template, and default filled tempalte"); gEntityManager.addEntity(tmpl); writeEntityComponents(gEntityManager.getEntity(entity)); writeEntityComponents(gEntityManager.addEntityCopy(entity)); EntityTemplate* copy_tempalte = gEntityManager.allocateTemplate(entity); writeEntityComponents(gEntityManager.addEntity(copy_tempalte)); EntityTemplate* copy_default_tempalte = gEntityManager.allocateTemplate(entity, true); writeEntityComponents(gEntityManager.addEntity(copy_default_tempalte)); gEntityManager.addComponents(entity, TestComp4()); gEntityManager.addComponents(entity, TestComp3()); gEntityManager.begin(); gEntityManager.update(); gEntityManager.end(); writeEntityComponents(gEntityManager.getEntity(entity)); gEntityManager.removeComponents!(TestComp)(entity); gEntityManager.addComponents(entity, TestComp()); gEntityManager.addComponents(entity, TestComp5()); gEntityManager.begin(); gEntityManager.update(); gEntityManager.update("fixed"); gEntityManager.end(); gEntityManager.removeComponents!(TestComp4)(entity); gEntityManager.commit(); System* sys = gEntityManager.getSystem(becsID!TestSystem2); ExternalUpdateCallTest external_update_test; gEntityManager.callEntitiesFunction!TestSystem2(&external_update_test.update); printf("pre end\n"); writeEntityComponents(gEntityManager.getEntity(entity)); //import std.stdio; ////writeln((cast(uint*)tmpl.info.first_block)[0..48]); gEntityManager.freeTemplate(tmpl_empty); gEntityManager.freeTemplate(tmpl); gEntityManager.freeTemplate(tmpl2); gEntityManager.freeTemplate(copy_tempalte); gEntityManager.freeTemplate(copy_default_tempalte); EntityManager.destroy(); printf("end\n"); //*/ return 0; }