diff --git a/.gitignore b/.gitignore index 3a4254f..280be93 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,5 @@ !source/** !tests/** !README.md -!dub.json +!./dub.json !.gitignore \ No newline at end of file diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 87491ea..8ca576c 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -84,6 +84,12 @@ class EntityManager assert(register_state, "beginRegister() should be called before endRegister();"); register_state = false; + foreach(ref info; &entities_infos.byValue) + { + if(info.systems)Mallocator.instance.dispose(info.systems); + info.systems = Mallocator.instance.makeArray!bool(systems.length); + } + foreach (ref system; systems) { if (system.m_update is null) @@ -151,6 +157,11 @@ class EntityManager } } + foreach(info; &entities_infos.byValue) + { + generateListeners(info); + } + generateDependencies(); } @@ -681,7 +692,6 @@ class EntityManager static "~RetType.stringof~" call" ~ func ~ "(void* system_pointer) { - Sys* s = cast(Sys*) system_pointer; "~ret_str~"s." ~ func ~ "(); } @@ -693,6 +703,32 @@ class EntityManager //dfmt on } + static string catchEntityFunc(RetType = void)(string member, string func) + { + //dfmt off + + static if(is(RetType == void))string ret_str = ""; + else string ret_str = "return "; + string ret = "static if (hasMember!(Sys, \"" ~ func ~ "\") && + Parameters!(Sys."~func~").length == 1 && + is(Parameters!(Sys."~func~")[0] == Sys.EntitiesData) && + is(ReturnType!(Sys."~func~") == "~RetType.stringof~")) + { + static "~RetType.stringof~" call" ~ func + ~ "(void* system_pointer) + { + Sys* s = cast(Sys*) system_pointer; + Sys.EntitiesData data; + "~ret_str~"s." ~ func ~ "(data); + } + + system." + ~ member ~ " = &call" ~ func ~ "; + }"; + return ret; + //dfmt on + } + mixin(catchFunc("m_enable", "onEnable")); mixin(catchFunc("m_disable", "onDisable")); mixin(catchFunc("m_create", "onCreate")); @@ -700,6 +736,9 @@ class EntityManager mixin(catchFunc!(bool)("m_begin", "onBegin")); mixin(catchFunc("m_end", "onEnd")); + mixin(catchEntityFunc("m_entity_added","onAdd")); + mixin(catchEntityFunc("m_entity_removed","onRemove")); + system.m_system_pointer = cast(void*) Mallocator.instance.make!Sys; system.m_priority = priority; (cast(Sys*) system.m_system_pointer).__ecsInitialize(); @@ -1145,6 +1184,8 @@ class EntityManager current_delta += entites_in_block * components[id].size; } + info.systems = Mallocator.instance.makeArray!bool(systems.length); + foreach (i, ref system; systems) { if (system.m_update is null) @@ -1153,10 +1194,52 @@ class EntityManager } entities_infos.add(info.components, info); + + generateListeners(info); } return info; } + void generateListeners(EntityInfo* info) + { + if(info.add_listeners) + { + Mallocator.instance.dispose(info.add_listeners); + info.add_listeners = null; + } + if(info.remove_listeners) + { + Mallocator.instance.dispose(info.remove_listeners); + info.remove_listeners = null; + } + + 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]; + int add_len = 0; + int rem_len = 0; + foreach(i;0..systems.length) + { + if(info.systems[i]) + { + System* system = &systems[i]; + if(system.m_entity_added)tmp_add[add_len++] = cast(ushort)i; + if(system.m_entity_removed)tmp_rem[rem_len++] = cast(ushort)i; + } + } + + if(add_len) + { + info.add_listeners = Mallocator.instance.makeArray!ushort(add_len); + memcpy(info.add_listeners.ptr,tmp_add.ptr,add_len*ushort.sizeof); + } + + if(rem_len) + { + info.remove_listeners = Mallocator.instance.makeArray!ushort(rem_len); + memcpy(info.remove_listeners.ptr,tmp_add.ptr,rem_len*ushort.sizeof); + } + } + export void addSystemCaller(ref EntityInfo entity, uint system_id) nothrow @nogc { System* system = &systems[system_id]; @@ -1193,6 +1276,8 @@ class EntityManager if (index < passes[system.m_pass].system_callers.length) passes[system.m_pass].system_callers[index].infos.add(&entity); + + entity.systems[system_id] = true; } /************************************************************************************************************************ @@ -2084,6 +2169,13 @@ class EntityManager ///max number of entities in block ushort max_entities; + ///array of systems which will update this entity + bool[] systems; + ///systems which are listening for added entities + ushort[] add_listeners; + ///systems which are listening for removed entities + ushort[] remove_listeners; + ///pointer to first block/page EntitiesBlock* first_block; ///pointer to last block diff --git a/source/ecs/system.d b/source/ecs/system.d index ba2168e..747f85c 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -9,12 +9,15 @@ import ecs.manager; /************************************************************************************************************************ *System contain data required to proper glue EntityManager with Systems. *System callbacks: +*
-void update(EntitesData); *
-void onEnable() *
-void onDisable(); *
-bool onBegin(); *
-void onEnd(); *
-void onCreate() *
-void onDestroy(); +*
-void onAdd(EntitesData); +*
-void onRemove(EntitiesData); */ struct System { @@ -132,6 +135,9 @@ package: void* m_begin; void* m_end; + void* m_entity_added; + void* m_entity_removed; + //void function(ref EntityManager.CallData data) m_initialize; //void function(ref EntityManager.CallData data) m_deinitilize; void* m_initialize; diff --git a/tests/tests.d b/tests/tests.d index 1d48f4b..dade72a 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -108,6 +108,21 @@ struct TestSystem writeln("On Test System destroy."); } + void onAdd(EntitiesData data) + { + writeln("Entity added ID: ",data.entites[0].id); + } + + /*void onAdd() + { + + }*/ + + void onRemove(EntitiesData data) + { + writeln("Entity destroyed ID: ",data.entites[0].id); + } + bool onBegin() { //writeln("On Test System begin."); @@ -127,6 +142,7 @@ struct TestSystem static struct EntitiesData { size_t length; + const(Entity)[] entites; TestComp[] test; TestComp2[] test2; @readonly @optional const(TestComp3)[] test3;