diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 82a091c..4fcf742 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -7,6 +7,7 @@ import std.algorithm : max; import std.conv : to; import core.stdc.string; +import core.stdc.stdlib; import ecs.system; import ecs.entity; @@ -34,6 +35,8 @@ class EntityManager { alias types = Parameters!(Sys.update); + System system; + static string genCall()() { string ret = "s.update("; @@ -57,46 +60,67 @@ class EntityManager return ret; } - static void callUpdate(ref CallData data, void* entity) - { - static if (hasMember!(Sys, "update")) - { - Sys* s = cast(Sys*) data.system.system_pointer; - - EntitiesBlock* block = data.info.first_block; - while (block !is null) - { - void* data_pointer = block.dataBegin(); - foreach (i; 0 .. block.entities_count) - { - mixin(genCall()); - data_pointer += data.info.size; - } - block = block.next_block; - } - - } - } - - System system; static if (hasMember!(Sys, "update")) { + static void callUpdate(ref CallData data, void* entity) + { + static if (hasMember!(Sys, "update")) + { + Sys* s = cast(Sys*) data.system.system_pointer; + + EntitiesBlock* block = data.info.first_block; + while (block !is null) + { + void* data_pointer = block.dataBegin(); + foreach (i; 0 .. block.entities_count) + { + mixin(genCall()); + data_pointer += data.info.size; + } + block = block.next_block; + } + + } + } + system.update = &callUpdate; } + + static if (hasMember!(Sys, "onEnable")) + { + static void callEnable(void* system_pointer) + { + + Sys* s = cast(Sys*) system_pointer; + s.onEnable(); + } + + system.m_enable = &callEnable; + } + + static if (hasMember!(Sys, "onDisable")) + { + static void callDisable(void* system_pointer) + { + + Sys* s = cast(Sys*) system_pointer; + s.onDisable(); + } + + system.m_disable = &callDisable; + } + system.system_pointer = cast(void*) Mallocator.instance.make!Sys; system.components = Mallocator.instance.makeArray!uint(types.length); mixin(genCompList()); - if (systems is null) + systems.add(system); + systems[$ - 1].enable(); + + foreach (info; &entities_infos.byValue) { - systems = Mallocator.instance.makeArray!System(1); - systems[0] = system; - } - else - { - Mallocator.instance.expandArray(systems, 1); - systems[$ - 1] = system; + addEntityCaller(*info, systems[$ - 1]); } } @@ -107,17 +131,7 @@ class EntityManager info.size = size; info.aligment = Comp.alignof; //8; - if (components is null) - { - components = Mallocator.instance.makeArray!ComponentInfo(1); - components[0] = info; - } - else - { - Mallocator.instance.expandArray(components, 1); - components[$ - 1] = info; - } - + components.add(info); components_map.add(Comp.stringof, cast(uint)(components.length - 1)); } @@ -127,7 +141,8 @@ class EntityManager { foreach (data; info.callers) { - data.system.update(data, null); //caller(call_data,null); + if (data.system.enabled) + (cast(SytemFuncType) data.system.update)(data, null); //caller(call_data,null); } } } @@ -163,20 +178,7 @@ class EntityManager { if (system.update is null) continue; - CallData call_data = CallData(&system, info, null); - call_data.deltas = Mallocator.instance.makeArray!ushort(system.components.length); - foreach (i, id; system.components) - { - foreach (i2, id2; info.components) - { - if (id2 == id) - { - call_data.deltas[i] = info.deltas[i2]; - break; - } - } - } - info.callers.add(call_data); + addEntityCaller(*info, system); } entities_infos.add(info.components, info); @@ -188,6 +190,35 @@ class EntityManager return temp; } + void addEntityCaller(ref EntityInfo entity, ref System system) + { + CallData call_data = CallData(&system, &entity, null); + ushort[] deltas = (cast(ushort*) alloca(system.components.length * ushort.sizeof))[0 + .. system.components.length]; + foreach (i, id; system.components) + { + deltas[i] = ushort.max; + foreach (i2, id2; entity.components) + { + if (id2 == id) + { + deltas[i] = entity.deltas[i2]; + break; + } + } + if (deltas[i] == ushort.max) + { + deltas = null; + break; + } + } + if (deltas) + { + call_data.deltas = Mallocator.instance.makeArray(deltas); //Mallocator.instance.makeArray!ushort(system.components.length); + entity.callers.add(call_data); + } + } + void freeTemplate(EntityTemplate* template_) { Mallocator.instance.dispose(template_.entity_data); @@ -204,7 +235,8 @@ class EntityManager { if (block is null) { - block = cast(EntitiesBlock*) AlignedMallocator.instance.alignedAllocate(page_size, page_size); + block = cast(EntitiesBlock*) AlignedMallocator.instance.alignedAllocate(page_size, + page_size); *block = EntitiesBlock(tmpl.info); if (previous_block is null) { @@ -231,19 +263,12 @@ class EntityManager void* start = block.dataBegin() + block.entities_count * tmpl.info.size; memcpy(start, tmpl.entity_data.ptr, tmpl.info.size); - Entity* entity = cast(Entity*)start; + Entity* entity = cast(Entity*) start; entity.id = id_manager.getNewID(); entity.updateID(); block.entities_count++; } - struct CallData - { - System* system; - EntityInfo* info; - ushort[] deltas; - } - struct ComponentInfo { ushort size; @@ -283,17 +308,24 @@ class EntityManager ///there is a loooot of data (4kB, pure magic) } - enum page_size = 4096; - enum pages_in_block = 128; + struct CallData + { + System* system; + EntityManager.EntityInfo* info; + ushort[] deltas; + } alias SytemFuncType = void function(ref EntityManager.CallData data, void* entity); + enum page_size = 4096; + enum pages_in_block = 128; + IDManager id_manager; HashMap!(ushort[], EntityInfo*) entities_infos; HashMap!(string, uint) components_map; - System[] systems; - ComponentInfo[] components; + Vector!System systems; + Vector!ComponentInfo components; __gshared EntityManager instance; } diff --git a/source/ecs/package.d b/source/ecs/package.d new file mode 100644 index 0000000..e043ec9 --- /dev/null +++ b/source/ecs/package.d @@ -0,0 +1,7 @@ +module ecs; + +public import ecs.manager; +public import ecs.entity; +public import ecs.system; +import ecs.id_manager; +import ecs.events; \ No newline at end of file diff --git a/source/ecs/system.d b/source/ecs/system.d index a319902..9734c92 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -6,7 +6,7 @@ import ecs.manager; struct System { ///should system update and catch events? - bool enabled = true; + bool m_enabled = false; ///system priority int prority; ///pointer to system implementation @@ -14,5 +14,26 @@ struct System uint[] components; - void function(ref EntityManager.CallData data, void* entity) update; + bool enabled() + { + return m_enabled; + } + + void enable() + { + if(!m_enabled && m_enable)m_enable(system_pointer); + m_enabled = true; + } + + void disable() + { + if(m_enabled && m_disable)m_disable(system_pointer); + m_enabled = false; + } + + //void function(ref EntityManager.CallData data, void* entity) update; + void* update; ///workaroud for DMD bug with upper line + + void function(void* system_pointer) m_enable; + void function(void* system_pointer) m_disable; } diff --git a/tests/tests.d b/tests/tests.d index bec6983..9a48aa9 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -77,6 +77,18 @@ int main() struct TestSystem2 { + void onEnable() + { + import std.stdio; + writeln("TestSystem2 enabled"); + } + + void onDisable() + { + import std.stdio; + writeln("TestSystem2 disabled"); + } + void initialize(ref TestComp comp) { @@ -102,15 +114,15 @@ int main() gEM.registerComponent!TestComp; ulong dur = (MonoTime.currTime - time).total!"usecs"; - writeln("Components register time: ",dur," usecs"); + writeln("Components register: ",dur," usecs"); time = MonoTime.currTime; gEM.registerSystem!TestSystem(0); - gEM.registerSystem!TestSystem2(0); + //gEM.registerSystem!TestSystem2(0); dur = (MonoTime.currTime - time).total!"usecs"; - writeln("System register time: ",dur," usecs"); + writeln("Systems register: ",dur," usecs"); time = MonoTime.currTime; @@ -119,7 +131,7 @@ int main() *cast(EntityID*)tmpl.entity_data.ptr = EntityID(1,1); dur = (MonoTime.currTime - time).total!"usecs"; - writeln("Template allocating time: ",dur," usecs"); + writeln("Template allocating: ",dur," usecs"); time = MonoTime.currTime; @@ -128,6 +140,8 @@ int main() dur = (MonoTime.currTime - time).total!"usecs"; writeln("Entities adding: ",dur," usecs"); + gEM.registerSystem!TestSystem2(0); + //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)); @@ -136,10 +150,10 @@ int main() gEM.update(); dur = (MonoTime.currTime - time).total!"usecs"; - writeln("Update time: ",dur," usecs"); + writeln("Update: ",dur," usecs"); - import std.stdio; - writeln((cast(uint*)tmpl.info.first_block)[0..48]); + //import std.stdio; + //writeln((cast(uint*)tmpl.info.first_block)[0..48]); gEM.freeTemplate(tmpl); return 0; } \ No newline at end of file