From 0608fe6e89d3ff8387317724796fdf7b26409693 Mon Sep 17 00:00:00 2001 From: Mergul Date: Thu, 28 Mar 2019 20:25:08 +0100 Subject: [PATCH] -added new listener callback: onChangeEntity. Callback is called when entity optional components are changed. There is no info about which components are changed (added/removed), but should be in the future).This is probably slowest callback. --- source/ecs/manager.d | 102 ++++++++++++++++++++++++++++++++++++-- source/ecs/system.d | 1 + tests/tests.d | 114 ++++++++++++++++++++++++++++--------------- 3 files changed, 175 insertions(+), 42 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index a5443ce..0e45551 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -95,7 +95,7 @@ class EntityManager { if (system.m_update is null) { - if (system.m_add_entity || system.m_remove_entity) + if (system.m_add_entity || system.m_remove_entity || system.m_change_entity) { foreach (info; &entities_infos.byValue) { @@ -761,6 +761,7 @@ class EntityManager mixin(catchEntityFunc("m_add_entity", "onAddEntity")); mixin(catchEntityFunc("m_remove_entity", "onRemoveEntity")); + mixin(catchEntityFunc("m_change_entity", "onChangeEntity")); system.m_system_pointer = cast(void*) Mallocator.instance.make!Sys; system.m_priority = priority; @@ -1210,10 +1211,9 @@ class EntityManager foreach (i, ref system; systems) { - //if(system.m_add_entity || system.m_remove_entity)info.systems[system.id] = true; if (system.m_update is null) { - if (system.m_add_entity || system.m_remove_entity) + if (system.m_add_entity || system.m_remove_entity || system.m_change_entity) connectListenerToEntityInfo(*info, cast(uint) i); continue; } @@ -1239,13 +1239,21 @@ class EntityManager Mallocator.instance.dispose(info.remove_listeners); info.remove_listeners = null; } + if (info.change_listeners) + { + Mallocator.instance.dispose(info.change_listeners); + info.change_listeners = null; + } //allocate local data ushort[] tmp_add = (cast(ushort*) alloca(systems.length * ushort.sizeof))[0 .. systems.length]; ushort[] tmp_rem = (cast(ushort*) alloca(systems.length * ushort.sizeof))[0 .. systems.length]; + ushort[] tmp_ch = (cast(ushort*) alloca(systems.length * ushort.sizeof))[0 .. systems + .length]; int add_len = 0; int rem_len = 0; + int ch_len = 0; //assign listeners to lists foreach (i; 0 .. systems.length) { @@ -1290,6 +1298,25 @@ class EntityManager //assign listener tmp_rem[j] = cast(ushort) i; } + //onChangeEntity listener + if (system.m_change_entity) + { + //find listener position by priority + int j; + for (j = 0; j < ch_len; j++) + { + if (systems[i].priority > systems[tmp_ch[j]].priority) + break; + } + ch_len++; + //move elements after new listener + for (int k = ch_len; k > j; k--) + { + tmp_ch[k] = tmp_ch[k - 1]; + } + //assign listener + tmp_ch[j] = cast(ushort) i; + } } } @@ -1304,6 +1331,12 @@ class EntityManager info.remove_listeners = Mallocator.instance.makeArray!ushort(rem_len); memcpy(info.remove_listeners.ptr, tmp_rem.ptr, rem_len * ushort.sizeof); } + + if (ch_len) + { + info.change_listeners = Mallocator.instance.makeArray!ushort(ch_len); + memcpy(info.change_listeners.ptr, tmp_ch.ptr, ch_len * ushort.sizeof); + } } export void connectListenerToEntityInfo(ref EntityInfo entity, uint system_id) nothrow @nogc @@ -1486,6 +1519,18 @@ class EntityManager } } + if (new_info.change_listeners) + { + foreach (listener; new_info.change_listeners) + { + if (info.systems[listener]) + { + callChangeEntityListener(&systems[listener], new_info, new_block, + new_block.entities_count, new_block.entities_count + 1, del_ids); + } + } + } + new_block.entities_count++; removeEntityNoID(entity, block); @@ -1660,6 +1705,18 @@ class EntityManager } } + if (new_info.change_listeners) + { + foreach (listener; new_info.change_listeners) + { + if (info.systems[listener]) + { + callChangeEntityListener(&systems[listener], new_info, new_block, + new_block.entities_count, new_block.entities_count + 1, new_ids); + } + } + } + new_block.entities_count++; removeEntityNoID(entity, block); } @@ -2026,6 +2083,43 @@ class EntityManager (cast(void function(ref ListenerCallData) nothrow @nogc) system.m_remove_entity)(data); } + private void callChangeEntityListener(System* system, EntityInfo* info, + EntitiesBlock* block, int begin, int end, ushort[] ch_ids) @nogc nothrow + { + int i = 0; + int j = 0; + bool is_ = false; + while (1) + { + if (ch_ids[i] == system.m_optional_components[j]) + { + is_ = true; + break; + } + else if (ch_ids[i] > system.m_optional_components[j]) + { + j++; + if (j >= system.m_optional_components.length) + break; + } + else + { + i++; + if (i >= ch_ids.length) + break; + } + } + if (!is_) + return; + + ListenerCallData data; + data.system = system; + data.block = block; + data.begin = begin; + data.end = end; + (cast(void function(ref ListenerCallData) nothrow @nogc) system.m_change_entity)(data); + } + private void updateBlocks() { foreach (ref thread; threads) @@ -2393,6 +2487,8 @@ class EntityManager ushort[] add_listeners; ///systems which are listening for removed entities ushort[] remove_listeners; + ///systems which are listening for changed entities (changed in term of contained components) + ushort[] change_listeners; ///pointer to first block/page EntitiesBlock* first_block; diff --git a/source/ecs/system.d b/source/ecs/system.d index d3d2b31..765c380 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -137,6 +137,7 @@ package: void* m_add_entity; void* m_remove_entity; + void* m_change_entity; //void function(ref EntityManager.CallData data) m_initialize; //void function(ref EntityManager.CallData data) m_deinitilize; diff --git a/tests/tests.d b/tests/tests.d index 1206732..50c31b6 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -12,19 +12,19 @@ import std.stdio; struct TestEvent { - mixin ECS.Event;//__gshared ushort event_id; + mixin ECS.Event; //__gshared ushort event_id; int a; } struct TestEvent2 { - mixin ECS.Event;//__gshared ushort event_id; + mixin ECS.Event; //__gshared ushort event_id; float a; } static struct TestComp { - mixin ECS.Component;//__gshared ushort component_id; + mixin ECS.Component; //__gshared ushort component_id; int a = 1; ulong b = 2; @@ -41,7 +41,7 @@ static struct TestComp static struct TestComp2 { - mixin ECS.Component;//__gshared ushort component_id; + mixin ECS.Component; //__gshared ushort component_id; int b = 3; int a = 4; @@ -58,7 +58,7 @@ static struct TestComp2 static struct TestComp3 { - mixin ECS.Component;//__gshared ushort component_id; + mixin ECS.Component; //__gshared ushort component_id; uint gg = 5; //good game uint bg = 6; //bad game @@ -75,7 +75,28 @@ static struct TestComp3 static struct TestComp4 { - mixin ECS.Component;//__gshared ushort component_id; + mixin ECS.Component; //__gshared ushort component_id; + 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 ushort component_id; uint gg = 7; //good game uint bg = 8; //bad game ulong a = 9; @@ -96,7 +117,7 @@ static struct TestComp4 struct ChangeTestSystem { - mixin ECS.System!16;//__gshared ushort system_id; + mixin ECS.System!16; //__gshared ushort system_id; void onCreate() { @@ -110,13 +131,18 @@ struct ChangeTestSystem void onAddEntity(EntitiesData data) { - foreach(i;0..data.length) - writeln("Entity added ID: ",data.entites[i].id.id); + foreach (i; 0 .. data.length) + writeln("Entity added! ID: ", data.entites[i].id.id); } void onRemoveEntity(EntitiesData data) { - writeln("Entity removed ID: ",data.entites[0].id); + writeln("Entity removed! ID: ", data.entites[0].id); + } + + void onChangeEntity(EntitiesData data) + { + writeln("Entity changed! ID: ", data.entites[0].id); } bool onBegin() @@ -140,20 +166,21 @@ struct ChangeTestSystem size_t length; const(Entity)[] entites; TestComp4[] test4; + @optional TestComp5[] test5; } void onUpdate(EntitiesData data) { - foreach(i;0..data.length) + foreach (i; 0 .. data.length) { - + } } } struct TestSystem { - mixin ECS.System!16;//__gshared ushort system_id; + mixin ECS.System!16; //__gshared ushort system_id; void onCreate() { @@ -170,7 +197,7 @@ struct TestSystem //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); @@ -202,7 +229,7 @@ struct TestSystem //@excluded TestComp4[] test4; } - void onUpdate(ref Entity entity, ref TestComp test, ref TestComp2 test2)//, TestComp3* test3) //ref TestComp comp) + 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); @@ -216,7 +243,7 @@ struct TestSystem void onUpdate(EntitiesData data) { - foreach(i;0..data.length) + foreach (i; 0 .. data.length) { data.test[i].a += 1000; data.test[i].b += 2000; @@ -233,7 +260,7 @@ struct TestSystem struct TestSystemWithHighPriority { - mixin ECS.System!16;//__gshared ushort system_id; + mixin ECS.System!16; //__gshared ushort system_id; static struct EntitiesData { @@ -247,7 +274,7 @@ struct TestSystemWithHighPriority void onUpdate(EntitiesData data) { - + } /*void handleEvent(Event event, ref TestComp comp) @@ -282,7 +309,7 @@ struct Sys2 void onAddEntity(EntitiesData data) { - + } } @@ -297,7 +324,7 @@ struct Sys3 void onAddEntity(EntitiesData data) { - + } void onUpdate(EntitiesData data) @@ -306,12 +333,11 @@ struct Sys3 } } - import std.meta; struct TestSystem2 { - mixin ECS.System!16;//__gshared ushort system_id; + mixin ECS.System!16; //__gshared ushort system_id; /*enum ExcludedComponents0 { @@ -326,7 +352,7 @@ struct TestSystem2 static struct EntitiesData { short length; - const (Entity)[] entity; + const(Entity)[] entity; TestComp3[] test; //@excluded TestComp[] testt; } @@ -348,7 +374,7 @@ struct TestSystem2 void handleEvent(EventInput input, ref TestEvent2 event) { - input.test.gg = cast(uint)event.a; + input.test.gg = cast(uint) event.a; } void onEnable() @@ -372,12 +398,12 @@ struct TestSystem2 void onUpdate(EntitiesData data) { - foreach(i;0..data.test.length) + foreach (i; 0 .. data.test.length) { data.test[i].gg += 14; TestEvent event; event.a = data.test[i].gg + 4; - gEM.sendEvent(data.entity[i].id, event);//*/ + gEM.sendEvent(data.entity[i].id, event); //*/ /*TestEvent2 event2; event2.a = data.test[i].gg + 8; gEM.sendEvent(data.entity[i].id, event2);//*/ @@ -385,10 +411,10 @@ struct TestSystem2 //gEM.sendSelfEvent!(TestEvent)(data.entity[i].id, TestEvent()); } } - + void lateUpdate(ref EntitiesData data) { - foreach(i;0..data.test.length) + foreach (i; 0 .. data.test.length) { data.test[i].gg -= 1; //gEM.sendSelfEvent!(TestEvent)(data.entity[i].id, TestEvent()); @@ -406,7 +432,7 @@ int main() void dispatch(EntityManager.JobGroup jobs) nothrow @nogc { - foreach(job;jobs.jobs) + foreach (job; jobs.jobs) { //writeln(job); job.execute(); @@ -417,13 +443,17 @@ int main() { write(entity.id); TestComp* test_comp = entity.getComponent!TestComp; - if(test_comp)write(*test_comp); + if (test_comp) + write(*test_comp); TestComp2* test_comp2 = entity.getComponent!TestComp2; - if(test_comp2)write(*test_comp2); + if (test_comp2) + write(*test_comp2); TestComp3* test_comp3 = entity.getComponent!TestComp3; - if(test_comp3)write(*test_comp3); + if (test_comp3) + write(*test_comp3); TestComp4* test_comp4 = entity.getComponent!TestComp4; - if(test_comp4)write(*test_comp4); + if (test_comp4) + write(*test_comp4); writeln(); //writeln((cast(uint*) pp)[0 .. 14], " ", pp); } @@ -441,6 +471,7 @@ int main() gEM.registerComponent!TestComp4; gEM.registerComponent!TestComp; gEM.registerComponent!TestComp3; + gEM.registerComponent!TestComp5; gEM.registerEvent!TestEvent; gEM.registerEvent!TestEvent2; @@ -450,7 +481,7 @@ int main() time = MonoTime.currTime; - gEM.registerSystem!TestSystemWithHighPriority(100,"fixed"); + gEM.registerSystem!TestSystemWithHighPriority(100, "fixed"); gEM.registerSystem!TestSystem(0); gEM.registerSystem!ChangeTestSystem(0); gEM.registerSystem!Sys1(10); @@ -483,12 +514,13 @@ int main() { entity = gEM.addEntity(tmpl); writeEntityComponents(gEM.getEntity(entity.id)); - EntityManager.EntitiesBlock* block = EntityManager.instance.getMetaData(gEM.getEntity(entity.id)); + EntityManager.EntitiesBlock* block = EntityManager.instance.getMetaData( + gEM.getEntity(entity.id)); EntityManager.EntityInfo* info = block.type_info; writeln(info.add_listeners); //if(info)assert(0); - } - + } + time = MonoTime.currTime; //foreach(i; 0..1_000_000)gEM.addEntity(tmpl); @@ -607,13 +639,17 @@ int main() gEM.removeComponents!(TestComp)(entity.id); gEM.addComponents(entity.id, TestComp()); - gEM.removeComponents!(TestComp4)(entity.id); + gEM.addComponents(entity.id, TestComp5()); gEM.begin(); gEM.update(); gEM.update("fixed"); gEM.end(); + gEM.removeComponents!(TestComp4)(entity.id); + + gEM.commit(); + writeEntityComponents(gEM.getEntity(entity.id)); //import std.stdio; //writeln((cast(uint*)tmpl.info.first_block)[0..48]); @@ -621,4 +657,4 @@ int main() EntityManager.destroy(); return 0; -} \ No newline at end of file +}