diff --git a/source/ecs/entity_allocator.d b/source/ecs/entity_allocator.d index ae6cc61..a23ad7d 100644 --- a/source/ecs/entity_allocator.d +++ b/source/ecs/entity_allocator.d @@ -2,8 +2,8 @@ module ecs.entity_allocator; import ecs.manager; -import std.experimental.allocator.mallocator : Mallocator, AlignedMallocator; import std.experimental.allocator; +import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator; struct EntityAllocator { diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 777f635..5809dba 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -27,8 +27,19 @@ class EntityManager instance = Mallocator.instance.make!EntityManager; } - static void destory() + static void destroy() { + + foreach(ref system;instance.systems) + { + system.disable(); + } + + foreach(ref system;instance.systems) + { + if(system.m_destroy)system.m_destroy(system.m_system_pointer); + } + Mallocator.instance.dispose(instance); instance = null; } @@ -36,16 +47,34 @@ class EntityManager void registerSystem(Sys)(int priority) { alias types = Parameters!(Sys.update); + alias storages = ParameterStorageClassTuple!(Sys.update); + + alias STC = ParameterStorageClass; System system; static string genCall()() { string ret = "s.update(*cast(Entity*)data_pointer,"; - foreach (i; 1 .. (Parameters!(Sys.update)).length) + /*foreach (i; 1 .. (Parameters!(Sys.update)).length) { - ret ~= "*cast(types[" ~ i.to!string ~ "]*)(data_pointer + data.deltas[" ~ (i - 1) - .to!string ~ "]),"; + ret ~= "*cast(types[" ~ i.to!string ~ "]*)(pointers[" ~ (i - 1) + .to!string ~ "]),"; + }*/ + uint i = 0; + uint req = 0; + uint opt = 0; + static foreach(param;(Parameters!(Sys.update))[1..$]) + { + i++; + if(isPointer!param) + { + ret ~= "cast(types[" ~ i.to!string ~ "])(optional_pointers[" ~ (opt++).to!string ~ "]),"; + } + else + { + ret ~= "*cast(types[" ~ i.to!string ~ "]*)(pointers[" ~ (req++).to!string ~ "]),"; + } } ret ~= ");"; return ret; @@ -53,16 +82,53 @@ class EntityManager static string genCompList()() { - string ret = "uint comp;"; + string ret = "ushort comp;uint req;uint opt;"; foreach (i; 1 .. (Parameters!(Sys.update)).length) { - ret ~= "comp = components_map.get(types[" ~ i.to!string ~ "].stringof, ushort.max);\n - if(comp == ushort.max)assert(0,\"Can't register system \\\"" ~ Sys.stringof - ~ "\\\" due to non existing component \\\"\"~types[" ~ i.to!string ~ "].stringof~\"\\\".\"); - system.m_components[" ~ (i - 1) - .to!string ~ "] = comp;"; - + ret ~= " + static if(isPointer!(types[" ~ i.to!string ~ "]))opt++; + else static if(storages[" ~ i.to!string ~ "] == STC.ref_)req++;\n + else static assert(0,\"Can't register system \\\"" ~ Sys.stringof + ~ "\\\". Unsupported parameter type \\\"\"~types[" ~ i.to!string ~ "].stringof~\"\\\".\");"; } + ret ~= "system.m_components = Mallocator.instance.makeArray!ushort(req);"; + ret ~= "system.m_optional_components = Mallocator.instance.makeArray!ushort(opt);"; + ret ~= "opt = 0;req = 0;"; + foreach (i; 1 .. (Parameters!(Sys.update)).length) + { + ret ~= " + static if(isPointer!(types[" ~ i.to!string ~ "])) + { + comp = components_map.get(PointerTarget!(types[" ~ i.to!string ~ "]).stringof, ushort.max);\n + if(comp == ushort.max)assert(0,\"Can't register system \\\"" ~ Sys.stringof + ~ "\\\" due to non existing component \\\"\"~types[" ~ i.to!string ~ "].stringof~\"\\\".\"); + system.m_optional_components[opt++] = comp; + } + else static if(storages[" ~ i.to!string ~ "] == STC.ref_) + { + comp = components_map.get(types[" ~ i.to!string ~ "].stringof, ushort.max);\n + if(comp == ushort.max)assert(0,\"Can't register system \\\"" ~ Sys.stringof + ~ "\\\" due to non existing component \\\"\"~types[" ~ i.to!string ~ "].stringof~\"\\\".\"); + system.m_components[req++] = comp; + }"; + } + return ret; + } + + static string catchFunc()(string member, string func) + { + string ret = + "static if (hasMember!(Sys, \""~func~"\")) + { + static void call"~func~"(void* system_pointer) + { + + Sys* s = cast(Sys*) system_pointer; + s."~func~"(); + } + + system."~member~" = &call"~func~"; + }"; return ret; } @@ -74,14 +140,30 @@ class EntityManager { Sys* s = cast(Sys*) data.system.m_system_pointer; + void*[] pointers = (cast(void**)alloca(data.system.m_components.length * (void*).sizeof))[0 .. data.system.m_components.length]; + void*[] optional_pointers = (cast(void**)alloca(data.system.m_optional_components.length * (void*).sizeof))[0 .. data.system.m_optional_components.length]; + EntitiesBlock* block = data.info.first_block; while (block !is null) { + uint size = block.type_data.size; void* data_pointer = block.dataBegin(); + foreach(i, ref pointer;pointers) + { + pointer = data_pointer + data.deltas[i]; + } + foreach(i, ref pointer;optional_pointers) + { + uint ind = cast(uint)(i + pointers.length); + if(data.deltas[ind] != uint.max)pointer = data_pointer + data.deltas[ind]; + else pointer = null; + } foreach (i; 0 .. block.entities_count) { mixin(genCall()); - data_pointer += data.info.size; + data_pointer += size;//data.info.size; + foreach(ref pointer;pointers)pointer += size; + foreach(ref pointer;optional_pointers)if(pointer != null)pointer += size; } block = block.next_block; } @@ -92,37 +174,23 @@ class EntityManager system.m_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; - } + mixin(catchFunc("m_enable","onEnable")); + mixin(catchFunc("m_disable","onDisable")); + mixin(catchFunc("m_create","onCreate")); + mixin(catchFunc("m_destroy","onDestroy")); + mixin(catchFunc("m_begin","onBegin")); + mixin(catchFunc("m_end","onEnd")); system.m_system_pointer = cast(void*) Mallocator.instance.make!Sys; system.m_priority = priority; - system.m_components = Mallocator.instance.makeArray!uint(types.length - 1); + //system.m_components = Mallocator.instance.makeArray!uint(types.length - 1); mixin(genCompList()); systems.add(system); + + if(system.m_create)system.m_create(system.m_system_pointer); + systems[$ - 1].enable(); foreach (info; &entities_infos.byValue) @@ -151,7 +219,6 @@ class EntityManager { (cast(Comp*) pointer).onDestroy(); } - info.destroy_callback = &callDestroy; } @@ -162,7 +229,7 @@ class EntityManager components.add(info); Comp.component_id = cast(ushort)(components.length - 1); - components_map.add(Comp.stringof, cast(uint)(components.length - 1)); + components_map.add(Comp.stringof, cast(ushort)(components.length - 1)); } void update() @@ -283,38 +350,48 @@ class EntityManager { System* system = &systems[system_id]; CallData call_data = CallData(system_id, system, &entity, null); - ushort[] deltas = (cast(ushort*) alloca(system.m_components.length * ushort.sizeof))[0 - .. system.m_components.length]; - foreach (i, id; system.m_components) + uint num = cast(uint)(system.m_components.length + system.m_optional_components.length); + ushort[] deltas = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num]; + uint delta_id = 0; + + ushort[] cmp_array = system.m_components; + add_deltas: + foreach (id; cmp_array) { - deltas[i] = ushort.max; + deltas[delta_id] = ushort.max; foreach (i2, id2; entity.components) { if (id2 == id) { - deltas[i] = entity.deltas[id2]; + deltas[delta_id] = entity.deltas[id2]; break; } } - if (deltas[i] == ushort.max) + if (deltas[delta_id] == ushort.max) { deltas = null; break; } + delta_id++; } - if (deltas) + if(deltas is null)return; + if(cmp_array.ptr == system.m_components.ptr) { - call_data.deltas = Mallocator.instance.makeArray(deltas); //Mallocator.instance.makeArray!ushort(system.m_components.length); - - uint index = 0; - for (; index < entity.callers.length; index++) - { - CallData* caller = &entity.callers[index]; - if (caller.system.priority >= call_data.system.priority) - break; - } - entity.callers.add(call_data, index); + cmp_array = system.m_optional_components; + goto add_deltas; } + + + call_data.deltas = Mallocator.instance.makeArray(deltas); //Mallocator.instance.makeArray!ushort(system.m_components.length); + + uint index = 0; + for (; index < entity.callers.length; index++) + { + CallData* caller = &entity.callers[index]; + if (caller.system.priority >= call_data.system.priority) + break; + } + entity.callers.add(call_data, index); } Entity* getEntity(EntityID id) @@ -640,11 +717,18 @@ class EntityManager void begin() { - + foreach(ref system;instance.systems) + { + if(system.m_begin)system.m_begin(system.m_system_pointer); + } } void end() { + foreach(ref system;instance.systems) + { + if(system.m_end)system.m_end(system.m_system_pointer); + } removeEntites(); } @@ -737,7 +821,7 @@ class EntityManager Vector!EntityID entities_to_remove; HashMap!(ushort[], EntityInfo*) entities_infos; - HashMap!(string, uint) components_map; + HashMap!(string, ushort) components_map; Vector!System systems; Vector!ComponentInfo components; __gshared EntityManager instance; diff --git a/source/ecs/system.d b/source/ecs/system.d index 4e5fd21..95136dc 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -38,11 +38,18 @@ package: ///pointer to system implementation void* m_system_pointer; - uint[] m_components; + ushort[] m_components; + ushort[] m_optional_components; //void function(ref EntityManager.CallData data, void* entity) update; void* m_update; ///workaroud for DMD bug with upper line void function(void* system_pointer) m_enable; void function(void* system_pointer) m_disable; + + void function(void* system_pointer) m_create; + void function(void* system_pointer) m_destroy; + + void function(void* system_pointer) m_begin; + void function(void* system_pointer) m_end; } diff --git a/tests/tests.d b/tests/tests.d index 9a815b0..739562c 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -81,12 +81,32 @@ int main() struct TestSystem { + void onCreate() + { + writeln("On Test System create."); + } + + void onDestroy() + { + writeln("On Test System destroy."); + } + + void onBegin() + { + writeln("On Test System begin."); + } + + void onEnd() + { + writeln("On Test System end."); + } + void initialize(ref Entity entity, ref TestComp comp) { } - void update(ref Entity entity, ref TestComp test, ref TestComp2 test2) //ref TestComp comp) + void update(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); @@ -100,6 +120,7 @@ int main() test2.a = 8; //writeln("Jakis tekst! ",test2.b); //writeln("Low priority tekst! "); + if(test3)test3.gg = 200; } void handleEvent(Event event, ref TestComp comp) @@ -247,7 +268,9 @@ int main() Entity entity = gEM.addEntity(tmpl); + gEM.begin(); gEM.update(); + gEM.end(); Entity* pp = gEM.getEntity(entity.id); writeln((cast(uint*) pp)[0 .. 14], " ", pp); @@ -257,19 +280,25 @@ int main() gEM.addComponents(entity.id, TestComp3()); pp = gEM.getEntity(entity.id); + gEM.begin(); gEM.update(); + gEM.end(); writeln((cast(uint*) pp)[0 .. 14], " ", pp); gEM.removeComponents!(TestComp)(entity.id); pp = gEM.getEntity(entity.id); + gEM.begin(); gEM.update(); + gEM.end(); writeln((cast(uint*) pp)[0 .. 14], " ", pp); //import std.stdio; //writeln((cast(uint*)tmpl.info.first_block)[0..48]); gEM.freeTemplate(tmpl); + EntityManager.destroy(); + return 0; }