From ed589bbd71b9d0cea9695f298cf44a5c641fd297 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 29 Sep 2018 23:10:31 +0200 Subject: [PATCH] -added absen components list to system -added ECS uda attributes -added InputStruct version switch (gets update() input as structure of arrays) -initial (WIP) EntitiesData update() input structure compile time parsing --- dub.json | 3 + source/ecs/attributes.d | 4 + source/ecs/manager.d | 268 ++++++++++++++++++++++++++++------------ source/ecs/system.d | 1 + tests/tests.d | 41 +++++- 5 files changed, 238 insertions(+), 79 deletions(-) create mode 100644 source/ecs/attributes.d diff --git a/dub.json b/dub.json index bacb5fc..6705634 100755 --- a/dub.json +++ b/dub.json @@ -10,6 +10,9 @@ "dflags-posix-ldc": [ "-defaultlib=phobos2-ldc,druntime-ldc" ], + "versions": [ + "InputStruct" + ], "configurations" : [ { "name" : "library", diff --git a/source/ecs/attributes.d b/source/ecs/attributes.d new file mode 100644 index 0000000..67c09c1 --- /dev/null +++ b/source/ecs/attributes.d @@ -0,0 +1,4 @@ +module ecs.attributes; + +enum optional = "optional"; +enum absen = "absen"; \ No newline at end of file diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 2ba41fa..df77253 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -61,92 +61,120 @@ class EntityManager System system; - static if (!(hasMember!(Sys, "system_id")) || !is(typeof(Sys.system_id) == ushort)) + version (InputStruct) { - static assert(0, "System should have \"__gshared ushort system_id"); - } - - static if (hasMember!(Sys, "update")) - { - alias types = Parameters!(Sys.update); - alias storages = ParameterStorageClassTuple!(Sys.update); - static string genCall()() + static if (!(hasMember!(Sys, "EntitiesData"))) { - string ret; + static assert(0, "System should gave \"EntitiesData\" struct for input components"); + } + + static string genCompList()() + { + string ret = "ushort comp;uint req;uint opt;uint absen;"; + static foreach (member; __traits(allMembers, Sys.EntitiesData)) { - uint i = 0; - uint opt = 0; - static foreach (param; (Parameters!(Sys.update))[1 .. $]) + static if (isFunction!(__traits(getMember, Sys.EntitiesData, member))) + static assert(0, "EntitiesData can't have any function!"); + else static if (isArray!(typeof(__traits(getMember, + Sys.EntitiesData, member)))) + static assert(0, "EntitiesData members should be arrays of elements!"); + else static if (is(typeof(__traits(getMember, + Sys.EntitiesData, member)) == Entity[])) + { + ret ~= "const string entities_name = \"" ~ member ~ "\";"; + } + else { - i++; - if (isPointer!param) { - ret ~= "if(opt_array" ~ opt.to!string ~ " !is null)opt_ptr" - ~ opt.to!string ~ " = &opt_array" ~ opt.to!string ~ "[i];"; - opt++; + bool has_att = false; + foreach (att; __traits(getAttributes, + __traits(getMember, Sys.EntitiesData, member))) + { + if (att == "optional") + { + ret ~= "opt++;"; + has_att = true; + break; + } + else if (att == "absen") + { + ret ~= "absen++;"; + has_att = true; + break; + } + } + if (!has_att) + ret ~= "req++;"; } } } - - /*foreach (i; 1 .. (Parameters!(Sys.update)).length) + + ret ~= "system.m_components = Mallocator.instance.makeArray!ushort(req);"; + ret ~= "system.m_optional_components = Mallocator.instance.makeArray!ushort(opt);"; + ret ~= "opt = 0;req = 0;absen = 0;"; + + static foreach (member; __traits(allMembers, Sys.EntitiesData)) { - ret ~= "*cast(types[" ~ i.to!string ~ "]*)(pointers[" ~ (i - 1) - .to!string ~ "]),"; - }*/ - uint i = 0; - uint req = 0; - uint opt = 0; - ret ~= "s.update(id_array[i],"; - static foreach (param; (Parameters!(Sys.update))[1 .. $]) - { - i++; - if (isPointer!param) + static if (isFunction!(__traits(getMember, Sys.EntitiesData, member))) + static assert(0, "EntitiesData can't have any function!"); + else static if (isArray!(typeof(__traits(getMember, + Sys.EntitiesData, member)))) + static assert(0, "EntitiesData members should be arrays of elements!"); + else static if (is(typeof(__traits(getMember, + Sys.EntitiesData, member)) == Entity[])) { - ret ~= "opt_ptr" ~ (opt++).to!string ~ ","; + //ret ~= "const string entities_name = \"" ~ member ~ "\";"; } else { - ret ~= "array" ~ (req++).to!string ~ "[i],"; - } - } - - - ret ~= ");"; - return ret; - } - - static string genArrays()() - { - string ret; - - uint i = 0; - uint req = 0; - uint opt = 0; - static foreach (param; (Parameters!(Sys.update))[1 .. $]) - { - i++; - if (isPointer!param) - { - ret ~= "PointerTarget!(types[" ~ i.to!string - ~ "])[] opt_array" ~ opt.to!string ~ " = null;"; - ret ~= "if(info.deltas[types[" ~ i.to!string ~ "].component_id] != 0)opt_array" - ~ opt.to!string ~ " - = (cast(types[" ~ i.to!string ~ "])(cast(void*)block + info.deltas[types[" - ~ i.to!string ~ "].component_id]))[0..block.entities_count];"; - ret ~= "types[" ~ i.to!string ~ "] opt_ptr" ~ opt.to!string ~ ";"; - opt++; - } - else - { - ret ~= "types[" ~ i.to!string ~ "][] array" ~ req.to!string ~ " = (cast(types[" - ~ i.to!string ~ "]*)(cast(void*)block + info.deltas[types[" - ~ i.to!string ~ "].component_id]))[0..block.entities_count];"; - req++; + { + bool has_att = false; + foreach (att; __traits(getAttributes, + __traits(getMember, Sys.EntitiesData, member))) + { + if (att == "optional") + { + ret ~= "{comp = components_map.get(\"" ~ (typeof(__traits(getMember, + Sys.EntitiesData, member))) + .stringof ~ "\", ushort.max);\n + if(comp == ushort.max)assert(0,\"Can't register system \\\"" ~ Sys.stringof + ~ "\\\" due to non existing component " ~ typeof(__traits(getMember, + Sys.EntitiesData, member)).stringof ~ ".\"); + system.m_optional_components[opt++] = comp;}"; + has_att = true; + break; + } + else if (att == "absen") + { + ret ~= "{comp = components_map.get(\"" ~ (typeof(__traits(getMember, + Sys.EntitiesData, member))) + .stringof ~ "\", ushort.max);\n + if(comp == ushort.max)assert(0,\"Can't register system \\\"" ~ Sys.stringof + ~ "\\\" due to non existing component " ~ typeof(__traits(getMember, + Sys.EntitiesData, member)).stringof + ~ ".\");system.m_absen_components[absen++] = comp;}"; + has_att = true; + break; + } + } + if (!has_att) + { + ret ~= "{comp = components_map.get(\"" ~ (typeof(__traits(getMember, + Sys.EntitiesData, member))) + .stringof ~ "\", ushort.max);\n + if(comp == ushort.max)assert(0,\"Can't register system \\\"" ~ Sys.stringof + ~ "\\\" due to non existing component " ~ typeof(__traits(getMember, + Sys.EntitiesData, member)).stringof ~ ".\"); + system.m_components[req++] = comp;}"; + } + } } } return ret; } - + } + else + { static string genCompList()() { string ret = "ushort comp;uint req;uint opt;"; @@ -186,6 +214,92 @@ class EntityManager } return ret; } + } + + static if (!(hasMember!(Sys, "system_id")) || !is(typeof(Sys.system_id) == ushort)) + { + static assert(0, "System should have \"__gshared ushort system_id"); + } + + static if (hasMember!(Sys, "update")) + { + alias types = Parameters!(Sys.update); + alias storages = ParameterStorageClassTuple!(Sys.update); + static string genCall()() + { + string ret; + { + uint i = 0; + uint opt = 0; + static foreach (param; (Parameters!(Sys.update))[1 .. $]) + { + i++; + if (isPointer!param) + { + ret ~= "if(opt_array" ~ opt.to!string ~ " !is null)opt_ptr" + ~ opt.to!string ~ " = &opt_array" ~ opt.to!string ~ "[i];"; + opt++; + } + } + } + + /*foreach (i; 1 .. (Parameters!(Sys.update)).length) + { + ret ~= "*cast(types[" ~ i.to!string ~ "]*)(pointers[" ~ (i - 1) + .to!string ~ "]),"; + }*/ + uint i = 0; + uint req = 0; + uint opt = 0; + ret ~= "s.update(id_array[i],"; + static foreach (param; (Parameters!(Sys.update))[1 .. $]) + { + i++; + if (isPointer!param) + { + ret ~= "opt_ptr" ~ (opt++).to!string ~ ","; + } + else + { + ret ~= "array" ~ (req++).to!string ~ "[i],"; + } + } + + ret ~= ");"; + return ret; + } + + static string genArrays()() + { + string ret; + + uint i = 0; + uint req = 0; + uint opt = 0; + static foreach (param; (Parameters!(Sys.update))[1 .. $]) + { + i++; + if (isPointer!param) + { + ret ~= "PointerTarget!(types[" ~ i.to!string + ~ "])[] opt_array" ~ opt.to!string ~ " = null;"; + ret ~= "if(info.deltas[types[" ~ i.to!string ~ "].component_id] != 0)opt_array" ~ opt.to!string + ~ " + = (cast(types[" ~ i.to!string ~ "])(cast(void*)block + info.deltas[types[" + ~ i.to!string ~ "].component_id]))[0..block.entities_count];"; + ret ~= "types[" ~ i.to!string ~ "] opt_ptr" ~ opt.to!string ~ ";"; + opt++; + } + else + { + ret ~= "types[" ~ i.to!string ~ "][] array" ~ req.to!string ~ " = (cast(types[" + ~ i.to!string ~ "]*)(cast(void*)block + info.deltas[types[" + ~ i.to!string ~ "].component_id]))[0..block.entities_count];"; + req++; + } + } + return ret; + } static void callUpdate(ref CallData data, void* entity) { @@ -255,7 +369,12 @@ class EntityManager system.m_priority = priority; //system.m_components = Mallocator.instance.makeArray!uint(types.length - 1); - static if (hasMember!(Sys, "update")) + + version (InputStruct) + { + mixin(genCompList()); + } + else static if (hasMember!(Sys, "update")) { mixin(genCompList()); } @@ -452,7 +571,6 @@ class EntityManager = components[comp].init_data; } - return temp; } @@ -505,7 +623,6 @@ class EntityManager current_delta += entites_in_block * components[id].size; } - foreach (uint i, ref system; systems) { if (system.m_update is null) @@ -644,7 +761,7 @@ class EntityManager EntitiesBlock* new_block = findBlockWithFreeSpace(new_info); void* start = new_block.dataBegin() + new_block.entities_count * EntityID.sizeof; - + Entity* new_entity = cast(Entity*) start; new_entity.id = entity.id; new_entity.updateID(); @@ -759,7 +876,7 @@ class EntityManager //removeEntityNoID(entity, block); void* start = new_block.dataBegin() + new_block.entities_count * EntityID.sizeof; - + Entity* new_entity = cast(Entity*) start; new_entity.id = entity.id; new_entity.updateID(); @@ -797,7 +914,6 @@ class EntityManager } } - new_block.entities_count++; removeEntityNoID(entity, block); } @@ -857,7 +973,6 @@ class EntityManager tmpl.entity_data.ptr + info.tmpl_deltas[comp], components[comp].size); } - if (!block.added_count) blocks_to_update.add(block); @@ -960,7 +1075,6 @@ class EntityManager } } - if (block.entities_count == 0) { if (info.first_block is block) diff --git a/source/ecs/system.d b/source/ecs/system.d index 83bcd7d..1276d86 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -39,6 +39,7 @@ package: void* m_system_pointer; ushort[] m_components; + ushort[] m_absen_components; ushort[] m_optional_components; //void function(ref EntityManager.CallData data, void* entity) update; diff --git a/tests/tests.d b/tests/tests.d index 5fc09f9..11852cb 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -4,6 +4,7 @@ import ecs.entity; import ecs.events; import ecs.manager; import ecs.system; +import ecs.attributes; import core.time; import std.stdio; @@ -124,11 +125,12 @@ int main() } - struct InputData + static struct EntitiesData { TestComp* test; TestComp2* test2; - @("optional") TestComp3* test3; + @optional TestComp3* test3; + @absen TestComp4* test4; } void update(ref Entity entity, ref TestComp test, ref TestComp2 test2)//, TestComp3* test3) //ref TestComp comp) @@ -153,6 +155,11 @@ int main() } + void update(ref EntitiesData data) + { + + } + void handleEvent(TestEvent event, ref TestComp test, ref TestComp2 test2, TestComp3* test3) { @@ -163,6 +170,11 @@ int main() { __gshared ushort system_id; + static struct EntitiesData + { + TestComp* test; + } + void initialize(ref Entity entity, ref TestComp comp) { @@ -175,6 +187,13 @@ int main() //writeln("High priority tekst! "); } + void update(ref EntitiesData data) //ref TestComp comp) + { + assert(cast(size_t)&data.test % TestComp.alignof == 0); + + //writeln("High priority tekst! "); + } + /*void handleEvent(Event event, ref TestComp comp) { @@ -185,6 +204,17 @@ int main() { __gshared ushort system_id; + static struct EntitiesData + { + Entity* entity; + TestComp3* test; + + /*void a() + { + + }*/ + } + void onEnable() { import std.stdio; @@ -211,6 +241,13 @@ int main() gEM.sendSelfEvent!(TestEvent)(entity.id, TestEvent()); } + void update(ref EntitiesData data) //ref TestComp comp) + { + //writeln("TestSystem2 update"); + data.test.gg += 14; + gEM.sendSelfEvent!(TestEvent)(data.entity.id, TestEvent()); + } + /*void handleEvent(Event event, ref TestComp comp) {