From d6b53425dd73abe8bb3f08a8c259e8418e39756f Mon Sep 17 00:00:00 2001 From: Mergul Date: Fri, 6 Mar 2020 13:52:21 +0100 Subject: [PATCH] -added EmptySystem supprort (called once per frame, sholud be once per jobs) -EntitiesData can contain "thread_id" which is filled with ID of current thread --- source/ecs/manager.d | 243 ++++++++++++++++++++++++++----------------- source/ecs/system.d | 2 + tests/tests.d | 148 +++++++++++++++----------- 3 files changed, 237 insertions(+), 156 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 27eaa40..f3c5db8 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -164,6 +164,11 @@ export struct EntityManager foreach (ref system; systems) { + if (system.m_empty == true) + { + addSystemCaller(system.id); + continue; + } if (system.m_update is null) { if (system.m_add_entity || system.m_remove_entity || system.m_change_entity) @@ -357,46 +362,8 @@ export struct EntityManager { static void callEventHandler(Type)(ref EventCallData data) { - //Sys.EventInput input; Sys* data_system = cast(Sys*) data.system_pointer; - /*EntityInfo* info = data.block.type_info; - alias EventFields = Fields!(Sys.EventInput); - foreach (ref event_field; input.tupleof) - { - alias EventFieldType = Unqual!(typeof(*event_field)); - enum bool is_entity = is(EventFieldType == ecs.entity.Entity); - - static if (is_entity) - { - event_field = cast(Entity*) data.block.dataBegin() + data.id; - continue; - } - else - { - enum long index_in_entities_data = getIndexOfTypeInEntitiesData!(Sys.EntitiesData, - EventFieldType); - static assert(index_in_entities_data != -1, - "Component present in EventInput has to be present in EntitiesData!"); // Type present in EventInput has to be present in EntitiesData - - enum bool is_optional = hasUDA!(Sys.EntitiesData.tupleof[index_in_entities_data], - "optional"); - static if (is_optional) - { - if(info.deltas[EventFieldType.component_id] != 0)event_field = cast(EventFieldType*)(cast(void*) data.block - + info.deltas[EventFieldType.component_id] - + data.id * EventFieldType.sizeof); - else event_field = null; - } - else - { - event_field = cast(EventFieldType*)(cast(void*) data.block - + info.deltas[EventFieldType.component_id] - + data.id * EventFieldType.sizeof); - } - } - - }//*/ Type* event = cast(Type*) data.event; data_system.handleEvent(gEM.getEntity(event.entity_id), *event); } @@ -542,8 +509,8 @@ export struct EntityManager foreach (member; __traits(allMembers, Sys.EntitiesData)) { alias MemberType = typeof(__traits(getMember, Sys.EntitiesData, member)); - if (member == "length" || member == "thread_id" || is(MemberType == Entity[]) - || is(MemberType == const(Entity)[])) + if (member == "length" || member == "thread_id" + || is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) { if (is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) components_info.entites_array = member; @@ -648,7 +615,7 @@ export struct EntityManager static assert(MemberType.sizeof > 1, "EntitiesData 'length' member can't be byte or ubyte."); } - else static if(member == "thread_id") + else static if (member == "thread_id") { static assert(isIntegral!(MemberType), "EntitiesData 'thread_id' member must be integral type."); @@ -710,11 +677,11 @@ export struct EntityManager { input_data.length = cast(typeof(input_data.length))(entities_count - offset); } - - static if (hasMember!(Sys.EntitiesData, "thread_id")) + + /*static if (hasMember!(Sys.EntitiesData, "thread_id")) { input_data.thread_id = cast(typeof(input_data.thread_id))threadID(); - } + }//*/ static foreach (iii, comp_info; components_info.req) { @@ -774,52 +741,86 @@ export struct EntityManager static if (OnUpdateOverloadNum != -1) { - static void callUpdate(ref CallData data) + static if (components_info.req.length != 0 || components_info.optional.length != 0) { - Sys* s = cast(Sys*) data.system.m_system_pointer; - - Sys.EntitiesData input_data; - EntityInfo* info = data.info; //block.type_info; - System* system = data.system; - - EntitiesBlock* block; - if (data.first_block) - block = data.first_block; - else - block = info.first_block; - - uint offset = data.begin; - uint entities_count; - uint blocks; - if (data.blocks) - blocks = data.blocks; - else - blocks = uint.max; - - while (block !is null && blocks > 0) + static void callUpdate(ref CallData data) { - if (blocks == 1) + Sys* s = cast(Sys*) data.system.m_system_pointer; + + Sys.EntitiesData input_data; + EntityInfo* info = data.info; //block.type_info; + System* system = data.system; + + EntitiesBlock* block; + if (data.first_block) + block = data.first_block; + else + block = info.first_block; + + uint offset = data.begin; + uint entities_count; + uint blocks; + if (data.blocks) + blocks = data.blocks; + else + blocks = uint.max; + + while (block !is null && blocks > 0) { - if (data.end) - entities_count = data.end; + if (blocks == 1) + { + if (data.end) + entities_count = data.end; + else + entities_count = block.entities_count; + } else entities_count = block.entities_count; + + assert(entities_count <= block.entities_count + && offset <= block.entities_count); + + fillInputData(input_data, info, block, offset, entities_count, system); + + static if (hasMember!(Sys.EntitiesData, "thread_id")) + { + input_data.thread_id = cast(typeof(input_data.thread_id)) data + .thread_id; + } + + //s.onUpdate(input_data); + (cast(typeof(&__traits(getOverloads, s, + "onUpdate")[OnUpdateOverloadNum])) data.update_delegate)(input_data); + + block = block.next_block; + offset = 0; + blocks--; } - else - entities_count = block.entities_count; + } + } + else + { + static void callUpdate(ref CallData data) + { + Sys* s = cast(Sys*) data.system.m_system_pointer; - assert(entities_count <= block.entities_count && offset <= block.entities_count); + Sys.EntitiesData input_data; - fillInputData(input_data, info, block, offset, entities_count, system); + /*static if (hasMember!(Sys.EntitiesData, "length")) + { + input_data.length = 0; + }//*/ + + static if (hasMember!(Sys.EntitiesData, "thread_id")) + { + input_data.thread_id = cast(typeof(input_data.thread_id)) data.thread_id; + } - //s.onUpdate(input_data); (cast(typeof(&__traits(getOverloads, s, "onUpdate")[OnUpdateOverloadNum])) data.update_delegate)(input_data); - - block = block.next_block; - offset = 0; - blocks--; } + + system.m_empty = true; } system.m_update = &callUpdate; @@ -1097,11 +1098,18 @@ export struct EntityManager System* sys = &systems[caller.system_id]; if (sys.enabled && sys.execute) { - foreach (info; caller.infos) + if (sys.m_empty) { - CallData data = CallData(caller.system_id, sys, info, sys.m_update_delegate); + CallData data = CallData(caller.system_id, sys, null, sys.m_update_delegate); data.update(); } + else + foreach (info; caller.infos) + { + CallData data = CallData(caller.system_id, sys, info, + sys.m_update_delegate); + data.update(); + } } } } @@ -1130,6 +1138,26 @@ export struct EntityManager System* sys = &systems[caller.system_id]; if (sys.enabled && sys.execute) { + uint job_id = 0; + void nextJob() + { + CallData[] callers = m_call_data_allocator.getCallData( + cast(uint) tmp_datas.length); + //callers[0 .. $] = tmp_datas[0 .. $]; + memcpy(callers.ptr, &tmp_datas[0], CallData.sizeof * tmp_datas.length); + tmp_datas.clear(); + sys.jobs[job_id].callers = callers; + job_id++; + } + + if (sys.m_empty) + { + tmp_datas.add(CallData(caller.system_id, sys, null, sys.m_update_delegate)); + nextJob(); + caller.job_group.jobs = sys.jobs[0 .. 1]; + (cast(void delegate(JobGroup) nothrow @nogc) m_dispatch_jobs)(caller.job_group); + continue; + } uint entities_count = 0; foreach (info; caller.infos) { @@ -1155,20 +1183,8 @@ export struct EntityManager entities_per_job = entities_count / jobs_count + 1; } - uint job_id = 0; entities_count = 0; - void nextJob() - { - CallData[] callers = m_call_data_allocator.getCallData( - cast(uint) tmp_datas.length); - //callers[0 .. $] = tmp_datas[0 .. $]; - memcpy(callers.ptr, &tmp_datas[0], CallData.sizeof * tmp_datas.length); - tmp_datas.clear(); - sys.jobs[job_id].callers = callers; - job_id++; - } - foreach (info; caller.infos) { uint blocks_count = info.nonEmptyBlocksCount(); @@ -1596,6 +1612,41 @@ export struct EntityManager entity.systems[system_id] = true; } + export void addSystemCaller(uint system_id) nothrow @nogc + { + System* system = &systems[system_id]; + + uint index = 0; + for (; index < passes[system.m_pass].system_callers.length; index++) + { + if (passes[system.m_pass].system_callers[index].system_id == system_id) + return; + } + + bool added = false; + foreach (i, caller; passes[system.m_pass].system_callers) + { + if (systems[caller.system_id].priority > system.priority) + { + SystemCaller* sys_caller = Mallocator.make!SystemCaller; + sys_caller.system_id = system.id; + sys_caller.job_group.caller = sys_caller; + system.m_any_system_caller = sys_caller; + passes[system.m_pass].system_callers.add(sys_caller, i); + added = true; + break; + } + } + if (!added) + { + SystemCaller* sys_caller = Mallocator.make!SystemCaller; + sys_caller.system_id = system.id; + sys_caller.job_group.caller = sys_caller; + system.m_any_system_caller = sys_caller; + passes[system.m_pass].system_callers.add(sys_caller); + } + } + export void addSystemCaller(ref EntityInfo info, uint system_id) nothrow @nogc { System* system = &systems[system_id]; @@ -2402,7 +2453,10 @@ export struct EntityManager foreach (caller; events[i].callers) { - if(call_data.block.type_info.systems[caller.system.m_id] == false)continue; + if ( + call_data.block.type_info.systems[caller.system.m_id] + == false) + continue; call_data.system_pointer = caller.system.m_system_pointer; (cast(void function( ref EventCallData) nothrow @nogc) caller.callback)( @@ -2887,6 +2941,8 @@ export struct EntityManager ushort begin; ///index of last element in last block ushort end; + ///current thread index + uint thread_id; } struct ListenerCallData @@ -2906,6 +2962,7 @@ export struct EntityManager //EntityManager.instance.getThreadID(); foreach (ref caller; callers) { + caller.thread_id = EntityManager.instance.threadID(); caller.update(); } } diff --git a/source/ecs/system.d b/source/ecs/system.d index c63a2b2..54b3555 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -94,6 +94,8 @@ package: bool m_execute = true; ///system id ushort m_id; + ///is system empty? Empty systems don't update entities, and is called once per update + bool m_empty = false; ///should system update and catch events? bool m_enabled = false; diff --git a/tests/tests.d b/tests/tests.d index 3ff9d00..d75eb47 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -10,9 +10,9 @@ import ecs.system; import ecs.attributes; import ecs.core; -version(WebAssembly) +version (WebAssembly) { - extern(C) int printf(scope const char* format, ...) @nogc nothrow @system; + extern (C) int printf(scope const char* format, ...) @nogc nothrow @system; alias int time_t; alias int clockid_t; @@ -20,62 +20,65 @@ version(WebAssembly) struct timespec { - time_t tv_sec; - int tv_nsec; + time_t tv_sec; + int tv_nsec; } - extern(C) int clock_gettime(clockid_t, timespec*) @nogc nothrow @system; + extern (C) int clock_gettime(clockid_t, timespec*) @nogc nothrow @system; struct Time - { - + { - static long getUSecTime() - { + 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; - } - } + return spec.tv_sec * 1000_000 + spec.tv_nsec / 1000; //time / 1000_000; + } + } - extern(C) void _start() {} + extern (C) void _start() + { + } } -else version(Windows) +else version (Windows) { import core.stdc.stdio : printf; import core.sys.windows.windows; + struct Time - { - static long getUSecTime() - { - LARGE_INTEGER time, freq; - QueryPerformanceFrequency(&freq); + { + static long getUSecTime() + { + LARGE_INTEGER time, freq; + QueryPerformanceFrequency(&freq); QueryPerformanceCounter(&time); - return time.QuadPart / (freq.QuadPart / 1000_000); - } - } + return time.QuadPart / (freq.QuadPart / 1000_000); + } + } } -else version(Posix) +else version (Posix) { import core.stdc.stdio : printf; import core.sys.posix.time; + struct Time - { - static long getUSecTime() - { + { + 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; - } - } + return spec.tv_sec * 1000_000 + spec.tv_nsec / 1000; //time / 1000_000; + } + } } struct TestEvent @@ -209,20 +212,20 @@ struct ChangeTestSystem { //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); + 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); + 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); + printf("Entity changed! ID: %u\n", cast(uint) data.entites[0].id.id); } bool onBegin() @@ -409,6 +412,21 @@ struct Sys3 } } +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 @@ -422,7 +440,7 @@ struct TestSystem2 }*/ //alias ExcludedComponents = AliasSeq!("TestComp", "TestComp4"); -/* + /* string ExcludedComponents2;*/ static struct EntitiesData @@ -507,15 +525,15 @@ struct ExternalUpdateCallTest void update(TestSystem2.EntitiesData data) { - if(print_count > 0) + if (print_count > 0) { print_count--; - printf("ExternalUpdateCallTest %u %u\n", data.test[0].gg, cast(uint)data.length); + printf("ExternalUpdateCallTest %u %u\n", data.test[0].gg, cast(uint) data.length); } } } -version(unittest) +version (unittest) { void main() { @@ -523,7 +541,7 @@ version(unittest) } } else: -extern(C) int main() + extern (C) int main() { void dispatch(EntityManager.JobGroup jobs) nothrow @nogc @@ -542,28 +560,30 @@ extern(C) int main() void writeEntityComponents(Entity* entity) { - - printf("EntityID(%u, %u)",cast(uint)entity.id.id,cast(uint)entity.id.counter); + + 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); + 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); + 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); + 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("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); - + //gEM.setJobDispachFunc(&dispatch); gEM.setMultithreadingCallbacks(&dispatch, &getID); //assert(gEM !is null); @@ -588,7 +608,7 @@ extern(C) int main() time = MonoTime.currTime;*/ - printf("Components register: %f usecs\n",cast(float)(Time.getUSecTime() - time)); + printf("Components register: %f usecs\n", cast(float)(Time.getUSecTime() - time)); time = Time.getUSecTime(); gEM.registerSystem!TestSystemWithHighPriority(100, "fixed"); @@ -597,6 +617,7 @@ extern(C) int main() gEM.registerSystem!Sys1(10); gEM.registerSystem!Sys2(-100); gEM.registerSystem!Sys3(-2); + gEM.registerSystem!EmptySystem(2); //gEM.registerSystem!TestSystemWithHighPriority(100); //gEM.registerSystem!TestSystem2(0); gEM.endRegister(); @@ -605,7 +626,7 @@ extern(C) int main() //writeln("Systems register: ", dur, " usecs"); time = MonoTime.currTime;*/ - printf("Systems register: %f usecs\n",cast(float)(Time.getUSecTime() - time)); + printf("Systems register: %f usecs\n", cast(float)(Time.getUSecTime() - time)); time = Time.getUSecTime(); //ushort[3] ids = [TestComp2.component_id, TestComp.component_id, TestComp4.component_id]; @@ -620,7 +641,7 @@ extern(C) int main() //dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Template allocating: ", dur, " usecs"); - printf("Template allocating: %f usecs\n",cast(float)(Time.getUSecTime() - time)); + printf("Template allocating: %f usecs\n", cast(float)(Time.getUSecTime() - time)); time = Time.getUSecTime(); EntityID entity; @@ -644,7 +665,7 @@ extern(C) int main() import ecs.std; - EntityID[] idss = Mallocator.makeArray!EntityID(5000);//[5000] + EntityID[] idss = Mallocator.makeArray!EntityID(5000); //[5000] //scope(exit)Mallocator.dispose(idss); foreach (i; 0 .. 200) @@ -660,7 +681,7 @@ extern(C) int main() //dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Entities adding: ", dur, " usecs"); - printf("Entities adding: %f usecs\n",cast(float)(Time.getUSecTime() - time)); + printf("Entities adding: %f usecs\n", cast(float)(Time.getUSecTime() - time)); time = Time.getUSecTime(); uint blocks = 0; @@ -674,7 +695,7 @@ extern(C) int main() } } //writeln("Entities blocks: ", blocks); - printf("Entities blocks: %u\n",blocks); + printf("Entities blocks: %u\n", blocks); //foreach(j; 0..1_000)gEM.addEntity(tmpl); @@ -696,8 +717,8 @@ extern(C) int main() foreach (i; 0 .. 500_000) { entity2 = gEM.addEntity(tmpl).id; - entities[i*2] = entity2; - entities[i*2+1] = gEM.addEntity(tmpl2).id; + entities[i * 2] = entity2; + entities[i * 2 + 1] = gEM.addEntity(tmpl2).id; } gEM.commit(); @@ -705,13 +726,14 @@ extern(C) int main() //writeln("Entities adding2: ", dur, " usecs"); //time = MonoTime.currTime; - printf("Entities adding2: %f usecs\n",cast(float)(Time.getUSecTime() - time)); + printf("Entities adding2: %f usecs\n", cast(float)(Time.getUSecTime() - time)); time = Time.getUSecTime(); foreach (i; 0 .. 1_000_000) { - EntityManager.instance.addComponents(entities[i],TestComp5()); - if((i & 0x00FFFF) == 0)gEM.commit(); + EntityManager.instance.addComponents(entities[i], TestComp5()); + if ((i & 0x00FFFF) == 0) + gEM.commit(); } gEM.commit(); @@ -719,7 +741,7 @@ extern(C) int main() //writeln("Components adding: ", dur, " usecs"); //time = MonoTime.currTime; - printf("Components adding: %f usecs\n",cast(float)(Time.getUSecTime() - time)); + printf("Components adding: %f usecs\n", cast(float)(Time.getUSecTime() - time)); time = Time.getUSecTime(); foreach (i; 0 .. 1_000_000) @@ -731,7 +753,7 @@ extern(C) int main() gEM.commit(); //dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Components removing: ", dur, " usecs"); - printf("Components removing: %f usecs\n",cast(float)(Time.getUSecTime() - time)); + printf("Components removing: %f usecs\n", cast(float)(Time.getUSecTime() - time)); time = Time.getUSecTime(); Mallocator.dispose(entities); @@ -746,7 +768,7 @@ extern(C) int main() //dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Update: ", dur, " usecs"); - printf("Update: %f usecs\n",cast(float)(Time.getUSecTime() - time)); + printf("Update: %f usecs\n", cast(float)(Time.getUSecTime() - time)); writeEntityComponents(gEM.getEntity(entity2)); @@ -760,7 +782,7 @@ extern(C) int main() //dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Update: ", dur, " usecs"); - printf("Update: %f usecs\n",cast(float)(Time.getUSecTime() - time)); + printf("Update: %f usecs\n", cast(float)(Time.getUSecTime() - time)); writeEntityComponents(gEM.getEntity(entity2)); @@ -774,7 +796,7 @@ extern(C) int main() //dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Update: ", dur, " usecs"); - printf("Update: %f usecs\n",cast(float)(Time.getUSecTime() - time)); + printf("Update: %f usecs\n", cast(float)(Time.getUSecTime() - time)); writeEntityComponents(gEM.getEntity(entity2)); @@ -794,7 +816,7 @@ extern(C) int main() writeEntityComponents(gEM.addEntityCopy(entity)); EntityTemplate* copy_tempalte = gEM.allocateTemplate(entity); writeEntityComponents(gEM.addEntity(copy_tempalte)); - EntityTemplate* copy_default_tempalte = gEM.allocateTemplate(entity,true); + EntityTemplate* copy_default_tempalte = gEM.allocateTemplate(entity, true); writeEntityComponents(gEM.addEntity(copy_default_tempalte)); gEM.addComponents(entity, TestComp4()); @@ -838,7 +860,7 @@ extern(C) int main() Mallocator.dispose(idss); - printf("end\n");//*/ + printf("end\n"); //*/ return 0; }