diff --git a/.gitignore b/.gitignore index f203f51..de4c133 100644 --- a/.gitignore +++ b/.gitignore @@ -1,17 +1,5 @@ -dub.userprefs -dub.selections.json -.dub -/.vscode -LOC -perf.data -perf.data.old -*.o -*.a -*.obj -*.exe -*.lib -*.so -*.def -*.lib -*.dll -*.exp \ No newline at end of file +* +!source +!tests +!dub.json +!.gitignore \ No newline at end of file diff --git a/dub.json b/dub.json index bacb5fc..52988fd 100755 --- a/dub.json +++ b/dub.json @@ -10,6 +10,9 @@ "dflags-posix-ldc": [ "-defaultlib=phobos2-ldc,druntime-ldc" ], + "dflagss": [ + "-betterC" + ], "configurations" : [ { "name" : "library", diff --git a/source/ecs/attributes.d b/source/ecs/attributes.d index 6b45dae..3a5ec95 100644 --- a/source/ecs/attributes.d +++ b/source/ecs/attributes.d @@ -2,7 +2,7 @@ module ecs.attributes; ///Used to mark optional components for system. enum optional = "optional"; -///Used to mark absent components for system. Enum 'AbsentComponents' should be used instead of it. -enum absent = "absent"; +///Used to mark components excluded from update for system. Enum 'ExcludedComponents' should be used instead of it. +enum excluded = "excluded"; ///Used to mark readonly components for system. "const" can be used insted. enum readonly = "readonly"; \ No newline at end of file diff --git a/source/ecs/core.d b/source/ecs/core.d index 6b27d26..3095dbb 100644 --- a/source/ecs/core.d +++ b/source/ecs/core.d @@ -1,6 +1,7 @@ module ecs.core; public import ecs.manager; +public import ecs.entity; static struct ECS { @@ -25,5 +26,6 @@ static struct ECS mixin template Event() { __gshared ushort event_id; + EntityID entity_id; } } \ No newline at end of file diff --git a/source/ecs/events.d b/source/ecs/events.d index 20c8c0e..ef81b6c 100644 --- a/source/ecs/events.d +++ b/source/ecs/events.d @@ -4,15 +4,19 @@ import ecs.manager; import ecs.block_allocator; import ecs.entity; +import std.experimental.allocator; +import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator; import std.algorithm.comparison : max; -/* -struct Event + +/*struct Event { - uint type; + uint id; + }*/ -mixin template EventManagerCode() +//mixin template EventManagerCode() +struct EventManager { //@disable this(); @@ -22,7 +26,7 @@ mixin template EventManagerCode() manager = m; }*/ - void sendSelfEvent(Ev)(EntityID id, Ev event) + /*void sendSelfEvent(Ev)(EntityID id, Ev event) { ushort size = cast(ushort)(Ev.sizeof); // + EntityID.sizeof + ushort.sizeof); ushort alignment = cast(ushort)(Ev.alignof); @@ -53,8 +57,6 @@ mixin template EventManagerCode() aligned_index = index; alignNum(aligned_index, alignment); - /*if(alignment > EntityID.sizeof + uint.sizeof)aligned_index = alignment; - else aligned_index = uint.sizeof * 4;*/ } EventBlock* block = list.current_block; @@ -66,22 +68,101 @@ mixin template EventManagerCode() *cast(EntityID*)&block.data[index + 2] = id; *cast(Ev*)&block.data[aligned_index] = event; block.index = cast(ushort)(aligned_index + Ev.sizeof); + }*/ + + void initialize(EntityManager m) + { + allocator = BlockAllocator(events_block_size, events_blocks_in_allocation); + manager = m; + } + + void sendEvent(Ev)(EntityID id, Ev event, uint thread_id = 0) + { + uint block_id = current_index+thread_id; + + EventData* data = &events[Ev.event_id]; + EventBlock* block = data.blocks[block_id]; + EntityManager.EventInfo* info = &gEM.events[Ev.event_id]; + event.entity_id = id; + + if(block is null) + { + block = cast(EventBlock*) allocator.getBlock(); + *block = EventBlock(); + data.first_blocks[block_id] = block; + data.blocks[block_id] = block; + } + + if(block.count >= data.max_events) + { + EventBlock* new_block = cast(EventBlock*) allocator.getBlock(); + *new_block = EventBlock(); + block.next = new_block; + block = new_block; + data.blocks[block_id] = block; + } + + /*void* start = cast(void*)block + data.data_offset + block.count * info.size; + Ev* event_ptr = cast(Ev*)start; + *event_ptr = event;*/ + Ev* event_array = cast(Ev*)(cast(void*)block + data.data_offset); + event_array[block.count] = event; + block.count++; + } + + void swapCurrent() + { + uint threads_count = cast(uint)manager.threads.length; + if(current_index == 0)current_index = threads_count; + else current_index = 0; + + foreach(ref event;events) + { + foreach(ref first_block; event.first_blocks[current_index .. current_index + threads_count]) + { + EventBlock* block = first_block; + while(block) + { + EventBlock* to_dispose = block; + block = block.next; + allocator.freeBlock(to_dispose); + } + first_block = null; + } + foreach(ref block; event.blocks[current_index .. current_index + threads_count]) + { + block = null; + } + } } void clearEvents() { - EventList tmp = current_events; + uint threads_count = cast(uint)manager.threads.length; + foreach(ref event;events) + { + foreach(ref first_block; event.first_blocks) + { + EventBlock* block = first_block; + while(block) + { + EventBlock* to_dispose = block; + block = block.next; + allocator.freeBlock(to_dispose); + } + first_block = null; + } + foreach(ref block; event.blocks) + { + block = null; + } + } + /*EventList tmp = current_events; current_events = process_events; process_events = tmp; EventBlock* block = process_events.first_block; - /*if(block) - { - import std.stdio; - writeln(block.data); - }*/ - while (block) { EventBlock* free = block; @@ -89,7 +170,30 @@ mixin template EventManagerCode() allocator.freeBlock(free); } process_events.first_block = null; - process_events.current_block = null; + process_events.current_block = null;*/ + } + + void allocateData(uint threads_count) + { + if(events) + { + foreach(ref event;events) + { + Mallocator.instance.dispose(event.blocks); + Mallocator.instance.dispose(event.first_blocks); + } + Mallocator.instance.dispose(events); + } + events = Mallocator.instance.makeArray!EventData(gEM.events.length); + foreach(i,ref event;events) + { + event.blocks = Mallocator.instance.makeArray!(EventBlock*)(threads_count*2); + event.first_blocks = Mallocator.instance.makeArray!(EventBlock*)(threads_count*2); + event.data_offset = EventBlock.sizeof;//gEM.events[i]. + gEM.alignNum(event.data_offset, gEM.events[i].alignment); + + event.max_events = cast(ushort)((events_block_size - event.data_offset) / gEM.events[i].size); + } } ///Single page size. Must be power of two. @@ -99,7 +203,7 @@ mixin template EventManagerCode() struct EventBlock { - union + /*union { struct { @@ -108,17 +212,31 @@ mixin template EventManagerCode() } ubyte[events_block_size] data; - } + }*/ + EventBlock* next; + ushort count = 0; } - struct EventList + /*struct EventList { EventBlock* first_block; EventBlock* current_block; + }*/ + + struct EventData + { + ushort data_offset; + ushort max_events; + EventBlock*[] blocks; + EventBlock*[] first_blocks; + + //EventBlock*[] current_blocks; } - EventList current_events; - EventList process_events; + /*EventList current_events; + EventList process_events;*/ + uint current_index = 0; + EventData[] events; BlockAllocator/*!(events_block_size, events_blocks_in_allocation)*/ allocator; EntityManager manager; diff --git a/source/ecs/manager.d b/source/ecs/manager.d index fdc2862..1215c5b 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -57,12 +57,12 @@ class EntityManager */ void beginRegister() { - assert(!register_state,"beginRegister() can't be called twice before endRegister();"); + assert(!register_state, "beginRegister() can't be called twice before endRegister();"); register_state = true; - foreach(pass;passes) + foreach (pass; passes) { - foreach(caller;pass.system_callers) + foreach (caller; pass.system_callers) { Mallocator.instance.dispose(caller); } @@ -75,13 +75,13 @@ class EntityManager */ void endRegister() { - assert(register_state,"beginRegister() should be called before endRegister();"); + assert(register_state, "beginRegister() should be called before endRegister();"); register_state = false; - foreach(ref system;systems) + foreach (ref system; systems) { if (system.m_update is null) - continue; + continue; bool added = false; foreach (i, caller; passes[system.m_pass].system_callers) @@ -103,10 +103,45 @@ class EntityManager sys_caller.job_group.caller = sys_caller; passes[system.m_pass].system_callers.add(sys_caller); } - - foreach(info;&entities_infos.byValue) + + foreach (info; &entities_infos.byValue) { - addSystemCaller(*info,system.id); + addSystemCaller(*info, system.id); + } + } + + event_manager.allocateData(cast(uint) threads.length); + + foreach(ref info;events) + { + Mallocator.instance.dispose(info.callers); + } + + ushort[] event_callers = (cast(ushort*)alloca(ushort.sizeof * events.length))[0..events.length]; + foreach(ref caller; event_callers)caller = 0; + + foreach(ref system;systems) + { + foreach(caller;system.m_event_callers) + { + event_callers[caller.id]++; + } + } + + foreach(i,ref info; events) + { + info.callers = Mallocator.instance.makeArray!(EventCaller)(event_callers[i]); + } + + foreach(ref caller; event_callers)caller = 0; + + foreach(ref system;systems) + { + foreach(caller;system.m_event_callers) + { + events[caller.id].callers[event_callers[caller.id]].callback = caller.callback; + events[caller.id].callers[event_callers[caller.id]].system = &system; + event_callers[caller.id]++; } } @@ -119,10 +154,11 @@ class EntityManager this(uint threads_count) { if (threads_count == 0) - threads_count = 0; + threads_count = 1; threads = Mallocator.instance.makeArray!ThreadData(threads_count); id_manager.initialize(); + event_manager.initialize(this); allocator = BlockAllocator(page_size, pages_in_block); @@ -144,7 +180,7 @@ class EntityManager void registerSystem(Sys)(int priority, const(char)[] pass_name) { ushort pass = passes_map.get(pass_name, ushort.max); - assert(pass != ushort.max,"Update pass (Name "~pass_name~") doesn't exist."); + assert(pass != ushort.max, "Update pass (Name " ~ pass_name ~ ") doesn't exist."); registerSystem!(Sys)(priority, pass); } @@ -158,17 +194,18 @@ class EntityManager */ void registerSystem(Sys)(int priority, ushort pass = 0) { - alias STC = ParameterStorageClass; + //alias STC = ParameterStorageClass; - assert(register_state,"asda"); - assert(pass < passes.length,"Update pass (ID "~pass.to!string~") doesn't exist."); + assert(register_state, + "registerSystem must be called between beginRegister() and endRegister()."); + assert(pass < passes.length, "Update pass (ID " ~ pass.to!string ~ ") doesn't exist."); System system; system.m_pass = pass; static if (!(hasMember!(Sys, "system_id")) || !is(typeof(Sys.system_id) == ushort)) { - static assert(0, "Add \"mixin ECS.System;\" in top of system structure;");//"System should have \"__gshared ushort system_id"); + static assert(0, "Add \"mixin ECS.System;\" in top of system structure;"); //"System should have \"__gshared ushort system_id"); } static if (!(hasMember!(Sys, "EntitiesData"))) @@ -176,6 +213,126 @@ class EntityManager static assert(0, "System should gave \"EntitiesData\" struct for input components"); } + //dfmt off + static if(hasMember!(Sys,"EventInput")) + { + static string genEventCompList()() + { + string ret = "Sys.EventInput input;\n"; + string type; + //bool has = true; + foreach (member; __traits(allMembers, Sys.EventInput)) + { + if(mixin("fullyQualifiedName!(ConstOf!(PointerTarget!(typeof(Sys.EventInput."~member~")))) == \"const(ecs.entity.Entity)\"")) + { + ret ~= "input." ~ member ~ " = cast(Entity*) data.block.dataBegin() + data.id;\n"; + continue; + } + + bool has = false; + bool optional = false; + foreach(member2; __traits(allMembers, Sys.EntitiesData)) + { + static if(mixin("isBasicType!(typeof(Sys.EntitiesData."~member2~"))")){} + else static if(mixin("fullyQualifiedName!(ConstOf!(PointerTarget!(typeof(Sys.EventInput."~member~")))) == fullyQualifiedName!(ConstOf!(ForeachType!(typeof(Sys.EntitiesData."~member2~"))))")) + { + has = true; + if(mixin("hasUDA!(Sys.EntitiesData."~member2~",\"optional\")"))optional = true; + break; + } + } + if(!has)assert(0); + + if(optional)ret ~= "input." ~ member ~ " = null;\n"; + else ret ~= "input." ~ member ~ " = cast(typeof(Sys.EventInput." ~ member + ~ "))(cast(void*) data.block + info.deltas[typeof(Sys.EventInput." + ~ member ~ ").component_id] + data.id * typeof(Sys.EventInput." ~ member + ~ ").sizeof);\n"; + } + return ret; + } + + //pragma(msg,genEventCompList()); + //pragma(msg,genEventCompList()); + + static string checkHandler()(string member) + { + string ret; + ret ~= "(Parameters!(Sys."~member~")).length == 2 && "; + ret ~= "((is(Parameters!(Sys."~member~")[0] == Sys.EventInput) && hasStaticMember!(Parameters!(Sys."~member~")[1],\"event_id\")) ||"; + ret ~= " (is(Parameters!(Sys."~member~")[1] == Sys.EventInput) && hasStaticMember!(Parameters!(Sys."~member~")[0],\"event_id\")))"; + return ret; + } + + /*static struct Handler + { + ushort id; + void* callback; + }*/ + + static string catchEventHanlders()() + { + int event_handlers = 0; + string ret; + string event_param; + + static if(__traits(hasMember, Sys, "handleEvent")) + { + foreach(func; __traits(getOverloads, Sys, "handleEvent")) + { + event_handlers++;//pragma(msg,"kupa"); + } + + //ret ~= "Handler[] handlers = (cast(Handler*)alloca("~event_handlers.to!string~" * (Handler).sizeof))[0 .. "~event_handlers.to!string~"];\n"; + ret ~= "system.m_event_callers = Mallocator.instance.makeArray!(System.EventCaller)("~event_handlers.to!string~");"; + event_handlers = 0; + + foreach(j,func; __traits(getOverloads, Sys, "handleEvent")) + { + event_param = "Parameters!(__traits(getOverloads, Sys, \"handleEvent\")["~j.to!string~"])[1]"; + ret ~= "static void callHandler"~event_handlers.to!string~"(ref EventCallData data)\n{\n"; + ret ~= "Sys* s = cast(Sys*) data.system_pointer; + EntityInfo* info = data.block.type_info;"; + ret ~= genEventCompList(); + ret ~= "s.handleEvent(input, *cast("~event_param~"*)data.event);"; + ret ~= "}\n"; + ret ~= "system.m_event_callers["~event_handlers.to!string~"].callback = cast(void*)&callHandler"~event_handlers.to!string~";"; + ret ~= "system.m_event_callers["~event_handlers.to!string~"].id = "~event_param~".event_id;"; + event_handlers++; + } + + /*ret ~= "ushort max_id = 0;"; + ret ~= "foreach(handler;handlers) + { + if(handler.id > max_id)max_id = handler.id; + }"; + ret ~= "system.m_event_callback = Mallocator.instance.makeArray!(System.EventHandler)(max_id);"; + ret ~= "foreach(handler;handlers) + { + system.m_event_callback[handler.id] = handler.callback; + }";*/ + } + + /*static if(__traits(hasMember, Sys, "handleEvent"))//foreach(member; __traits(allMembers,Sys)) + { + + //static foreach() + static if (member == "handleEvent" && mixin("isFunction!(Sys."~member~")")) + { + static if(mixin(checkHandler(member))) + { + event_handlers++; + } + } + }*/ + return ret; + } + + //pragma(msg,catchEventHanlders()); + mixin(catchEventHanlders()); + } + //dfmt on + static string genCompList()() { @@ -199,7 +356,7 @@ class EntityManager uint req; uint opt; - uint absent; + uint excluded; uint read_only; uint modified; foreach (member; __traits(allMembers, Sys.EntitiesData)) @@ -230,9 +387,9 @@ class EntityManager attribs++; //break; } - else if (att == "absent") + else if (att == "excluded") { - absent++; + excluded++; attribs++; //break; } @@ -242,7 +399,7 @@ class EntityManager } } assert(attribs <= 1, - "EntitiesData member can't have both \"@optional\" and \"@absent\"."); + "EntitiesData member can't have both \"@optional\" and \"@excluded\"."); if (!attribs) req++; if (is_read_only) @@ -253,17 +410,17 @@ class EntityManager } } - static if (__traits(hasMember, Sys, "AbsentComponents")) + static if (__traits(hasMember, Sys, "ExcludedComponents")) { - static if (is(Sys.AbsentComponents == enum)) + static if (is(Sys.ExcludedComponents == enum)) { - absent += (Fields!(Sys.AbsentComponents)).length; //static assert(0,"Enum AbsentComponents are not implemented yet."); + excluded += (Fields!(Sys.ExcludedComponents)).length; //static assert(0,"Enum ExcludedComponents are not implemented yet."); } - else static if (__traits(compiles, allSameType!(string, typeof(Sys.AbsentComponents))) - && allSameType!(string, typeof(Sys.AbsentComponents)) - && isExpressions!(Sys.AbsentComponents)) + else static if (__traits(compiles, allSameType!(string, typeof(Sys.ExcludedComponents))) + && allSameType!(string, typeof(Sys.ExcludedComponents)) + && isExpressions!(Sys.ExcludedComponents)) { - absent += Sys.AbsentComponents.length; + excluded += Sys.ExcludedComponents.length; } } @@ -273,39 +430,39 @@ class EntityManager if (opt > 0) ret ~= "system.m_optional_components = Mallocator.instance.makeArray!ushort(" ~ opt.to!string ~ ");"; - if (absent > 0) - ret ~= "system.m_absent_components = Mallocator.instance.makeArray!ushort(" - ~ absent.to!string ~ ");"; + if (excluded > 0) + ret ~= "system.m_excluded_components = Mallocator.instance.makeArray!ushort(" + ~ excluded.to!string ~ ");"; if (read_only > 0) ret ~= "system.m_read_only_components = Mallocator.instance.makeArray!ushort(" ~ read_only.to!string ~ ");"; if (modified > 0) ret ~= "system.m_modified_components = Mallocator.instance.makeArray!ushort(" ~ modified.to!string ~ ");"; - ret ~= "ushort comp;"; //uint opt = 0;uint req = 0;uint absent = 0;"; + ret ~= "ushort comp;"; //uint opt = 0;uint req = 0;uint excluded = 0;"; opt = 0; req = 0; - absent = 0; + excluded = 0; read_only = 0; modified = 0; - static if (__traits(hasMember, Sys, "AbsentComponents")) + static if (__traits(hasMember, Sys, "ExcludedComponents")) { - static if (is(Sys.AbsentComponents == enum)) + static if (is(Sys.ExcludedComponents == enum)) { - //static assert(0,"Enum AbsentComponents are not implemented yet."); - foreach (str; Fields!(Sys.AbsentComponents)) - ret ~= "system.m_absent_components[" ~ (absent++) + //static assert(0,"Enum ExcludedComponents are not implemented yet."); + foreach (str; Fields!(Sys.ExcludedComponents)) + ret ~= "system.m_excluded_components[" ~ (excluded++) .to!string ~ "] = components_map.get(\"" ~ str.stringof ~ "\", ushort.max);"; } - else static if (__traits(compiles, allSameType!(string, typeof(Sys.AbsentComponents))) - && allSameType!(string, typeof(Sys.AbsentComponents)) - && isExpressions!(Sys.AbsentComponents)) + else static if (__traits(compiles, allSameType!(string, typeof(Sys.ExcludedComponents))) + && allSameType!(string, typeof(Sys.ExcludedComponents)) + && isExpressions!(Sys.ExcludedComponents)) { - foreach (str; Sys.AbsentComponents) - ret ~= "system.m_absent_components[" ~ (absent++) + foreach (str; Sys.ExcludedComponents) + ret ~= "system.m_excluded_components[" ~ (excluded++) .to!string ~ "] = components_map.get(\"" ~ str ~ "\", ushort.max);"; } } @@ -349,9 +506,9 @@ class EntityManager has_att = true; //break; } - else if (att == "absent") + else if (att == "excluded") { - ret ~= "system.m_absent_components[" ~ (absent++) + ret ~= "system.m_excluded_components[" ~ (excluded++) .to!string ~ "] = comp;"; has_att = true; //break; @@ -399,7 +556,7 @@ class EntityManager ushort comp; uint req = 0; uint opt = 0; - uint absent = 0; + uint excluded = 0; foreach (member; __traits(allMembers, Sys.EntitiesData)) { if (is(typeof(__traits(getMember, Sys.EntitiesData, @@ -435,9 +592,9 @@ class EntityManager has_att = true; break; } - else if (att == "absent") + else if (att == "excluded") { - absent++; + excluded++; has_att = true; break; } @@ -601,7 +758,7 @@ class EntityManager static if (!(hasMember!(Comp, "component_id")) || !is(typeof(Comp.component_id) == ushort)) { - static assert(0, "Add \"mixin ECS.Component;\" in top of component structure;");//"Component should have \"__gshared ushort component_id"); + static assert(0, "Add \"mixin ECS.Component;\" in top of component structure;"); //"Component should have \"__gshared ushort component_id"); } static if (hasMember!(Comp, "onDestroy") && isFunction!(Comp.onDestroy) @@ -642,7 +799,7 @@ class EntityManager static if (!(hasMember!(Ev, "event_id")) || !is(typeof(Ev.event_id) == ushort)) { - static assert(0, "Add \"mixin ECS.Event;\" in top of event structure;");//"Event should have \"__gshared ushort event_id"); + static assert(0, "Add \"mixin ECS.Event;\" in top of event structure;"); //"Event should have \"__gshared ushort event_id"); } static if (hasMember!(Ev, "onDestroy") && isFunction!(Ev.onDestroy) @@ -979,9 +1136,9 @@ class EntityManager { System* system = &systems[system_id]; - if (system.m_absent_components) + if (system.m_excluded_components) { - foreach (id; system.m_absent_components) + foreach (id; system.m_excluded_components) { foreach (id2; entity.components) { @@ -1581,12 +1738,66 @@ class EntityManager } } + void updateEvents() + { + bool empty = true; + //uint index = event_manager. + while(1) + { + event_manager.swapCurrent(); + //event_manager.clearEvents(); + uint current_index; + if(event_manager.current_index == 0)current_index = cast(uint)threads.length; + else current_index = 0; + foreach(i,event;event_manager.events) + { + foreach(first_block;event.first_blocks[current_index .. current_index + threads.length]) + { + EventManager.EventBlock* block = first_block; + if(block)empty = false; + while(block) + { + EventCallData call_data; + void* event_pointer = cast(void*)block + event.data_offset; + call_data.event = event_pointer; + foreach(j;0..block.count) + { + //void* event_pointer = cast(void*)block + event.data_offset; + EntityID entity_id = *cast(EntityID*)event_pointer; + Entity* entity = id_manager.getEntityPointer(entity_id); + call_data.block = getMetaData(entity); + + static if (EntityID.sizeof == 8) + call_data.id = cast(ushort)((cast(void*)entity - call_data.block.dataBegin()) >> 3); + else + call_data.id = cast(ushort)((cast(void*)entity - call_data.block.dataBegin()) / EntityID.sizeof); + + foreach(caller; events[i].callers) + { + call_data.system_pointer = caller.system.m_system_pointer; + (cast(void function(ref EventCallData))caller.callback)(call_data); + } + event_pointer += events[i].size; + } + block = block.next; + } + } + } + if(empty)break; + empty = true; + //event_manager.clearEvents(); + } + //event_manager.swapCurrent(); + } + export void commit() { + updateEvents(); id_manager.optimize(); updateBlocks(); removeEntities(); changeEntities(); + event_manager.clearEvents(); } /************************************************************************************************************************ @@ -1601,7 +1812,8 @@ class EntityManager foreach (ref system; systems) { if (system.enabled && system.m_begin) - system.m_execute = (cast(bool function(void*)) system.m_begin)(system.m_system_pointer); + system.m_execute = (cast(bool function(void*)) system.m_begin)( + system.m_system_pointer); } } @@ -1619,7 +1831,7 @@ class EntityManager commit(); - //clearEvents(); + //event_manager.clearEvents(); } private void getThreadID() @@ -1630,6 +1842,11 @@ class EntityManager thread_id = 0; } + void sendEvent(Ev)(EntityID id, Ev event) + { + event_manager.sendEvent(id, event, thread_id); + } + /*private */ void generateDependencies() { @@ -1795,10 +2012,25 @@ class EntityManager void function(void* pointer) destroy_callback; } + struct EventCaller + { + System* system; + void* callback; + } + + struct EventCallData + { + EntitiesBlock* block; + void* system_pointer; + void* event; + ushort id; + } + struct EventInfo { ushort size; ushort alignment; + EventCaller[] callers; void function(void* pointer) destroy_callback; } @@ -1951,12 +2183,13 @@ class EntityManager { ~this() { - if(dependencies) + if (dependencies) { Mallocator.instance.dispose(dependencies); Mallocator.instance.dispose(exclusion); } - if(job_group.dependencies)Mallocator.instance.dispose(job_group.dependencies); + if (job_group.dependencies) + Mallocator.instance.dispose(job_group.dependencies); } uint system_id; @@ -2011,8 +2244,8 @@ class EntityManager IDManager id_manager; BlockAllocator /*!(page_size, pages_in_block)*/ allocator; - //EventManager event_manager; - mixin EventManagerCode; + EventManager event_manager; + //mixin EventManagerCode; //Vector!EntityID entities_to_remove; //Vector!(EntitiesBlock*) blocks_to_update; diff --git a/source/ecs/system.d b/source/ecs/system.d index 787c56c..9c61591 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -61,6 +61,12 @@ struct System return m_id; } + struct EventCaller + { + ushort id; + void* callback; + } + package: ///should system be executed in current update? @@ -82,8 +88,8 @@ package: ///required components ushort[] m_components; - ///absent components - ushort[] m_absent_components; + ///excluded components + ushort[] m_excluded_components; ///optional components ushort[] m_optional_components; @@ -93,6 +99,8 @@ package: ushort[] m_read_only_components; ushort[] m_modified_components; + EventCaller[] m_event_callers; + //void function(ref EntityManager.CallData data) m_update; void* m_update; ///workaroud for DMD bug with upper line diff --git a/tests/tests.d b/tests/tests.d index 5366d53..7f9f72b 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -10,253 +10,280 @@ import ecs.core; import core.time; import std.stdio; -int main() +struct TestEvent { + mixin ECS.Event;//__gshared ushort event_id; + int a; +} - struct TestEvent +struct TestEvent2 +{ + mixin ECS.Event;//__gshared ushort event_id; + float a; +} + +static struct TestComp +{ + mixin ECS.Component;//__gshared ushort component_id; + int a = 1; + ulong b = 2; + + static void serializeComponent(SerializeVector output) { - mixin ECS.Event;//__gshared ushort event_id; - int a; + } - struct TestEvent2 + static void deserializeComponent(ubyte[] data) { - mixin ECS.Event;//__gshared ushort event_id; - float a; + + } +} + +static struct TestComp2 +{ + mixin ECS.Component;//__gshared ushort component_id; + int b = 3; + int a = 4; + + static void serializeComponent(ref TestComp comp, SerializeVector output) + { + } - static struct TestComp + static void deserializeComponent(ref TestComp comp, ubyte[] data) { - mixin ECS.Component;//__gshared ushort component_id; - int a = 1; - ulong b = 2; - static void serializeComponent(SerializeVector output) + } +} + +static struct TestComp3 +{ + mixin ECS.Component;//__gshared ushort component_id; + uint gg = 5; //good game + uint bg = 6; //bad game + + void serializeComponent(SerializeVector output) + { + + } + + void deserializeComponent(ubyte[] data) + { + + } +} + +static struct TestComp4 +{ + 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) + { + + } +} + +struct TestSystem +{ + mixin ECS.System!16;//__gshared ushort system_id; + + void onCreate() + { + writeln("On Test System create."); + } + + void onDestroy() + { + writeln("On Test System destroy."); + } + + bool onBegin() + { + //writeln("On Test System begin."); + return true; + } + + void onEnd() + { + //writeln("On Test System end."); + } + + void initialize(ref Entity entity, ref TestComp comp) + { + + } + + static struct EntitiesData + { + size_t length; + TestComp[] test; + TestComp2[] test2; + @readonly @optional const(TestComp3)[] test3; + //@excluded TestComp4[] test4; + } + + 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); + import std.stdio; + + test.a += 1000; + test.b += 2000; + test2.b += 2; + test2.a = 8; + } + + void update(EntitiesData data) + { + foreach(i;0..data.length) { - - } - - static void deserializeComponent(ubyte[] data) - { - + data.test[i].a += 1000; + data.test[i].b += 2000; + data.test2[i].b += 2; + data.test2[i].a = 8; } } - static struct TestComp2 + void handleEvent(TestEvent event, ref TestComp test, ref TestComp2 test2, TestComp3* test3) { - mixin ECS.Component;//__gshared ushort component_id; - int b = 3; - int a = 4; - static void serializeComponent(ref TestComp comp, SerializeVector output) - { + } +} - } +struct TestSystemWithHighPriority +{ + mixin ECS.System!16;//__gshared ushort system_id; - static void deserializeComponent(ref TestComp comp, ubyte[] data) - { - - } + static struct EntitiesData + { + TestComp[] test; } - static struct TestComp3 + void initialize(ref Entity entity, ref TestComp comp) { - mixin ECS.Component;//__gshared ushort component_id; - uint gg = 5; //good game - uint bg = 6; //bad game - - void serializeComponent(SerializeVector output) - { - - } - - void deserializeComponent(ubyte[] data) - { - - } + int o = 1; } - static struct TestComp4 + void update(EntitiesData data) { - 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) - { - - } + } - struct TestSystem + /*void handleEvent(Event event, ref TestComp comp) { - mixin ECS.System!16;//__gshared ushort system_id; - void onCreate() - { - writeln("On Test System create."); - } - - void onDestroy() - { - writeln("On Test System destroy."); - } - - bool onBegin() - { - //writeln("On Test System begin."); - return true; - } - - void onEnd() - { - //writeln("On Test System end."); - } - - void initialize(ref Entity entity, ref TestComp comp) - { - - } - - static struct EntitiesData - { - size_t length; - TestComp[] test; - TestComp2[] test2; - @readonly @optional const(TestComp3)[] test3; - //@absent TestComp4[] test4; - } - - 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); - import std.stdio; - - test.a += 1000; - test.b += 2000; - test2.b += 2; - test2.a = 8; - } - - void update(EntitiesData data) - { - foreach(i;0..data.length) - { - data.test[i].a += 1000; - data.test[i].b += 2000; - data.test2[i].b += 2; - data.test2[i].a = 8; - } - } - - void handleEvent(TestEvent event, ref TestComp test, ref TestComp2 test2, TestComp3* test3) - { - - } - } - - struct TestSystemWithHighPriority - { - mixin ECS.System!16;//__gshared ushort system_id; - - static struct EntitiesData - { - TestComp[] test; - } - - void initialize(ref Entity entity, ref TestComp comp) - { - int o = 1; - } - - void update(EntitiesData data) - { - - } - - /*void handleEvent(Event event, ref TestComp comp) - { - - }*/ - } + }*/ +} import std.meta; - struct TestSystem2 +struct TestSystem2 +{ + mixin ECS.System!16;//__gshared ushort system_id; + + /*enum ExcludedComponents0 { - mixin ECS.System!16;//__gshared ushort system_id; - - enum AbsentComponents0 - { - TestComp, - TestComp4 - } - - alias AbsentComponents = AliasSeq!("TestComp", "TestComp4"); - - string AbsentComponents2; - - static struct EntitiesData - { - short length; - const (Entity)[] entity; - TestComp3[] test; - //@absent TestComp[] testt; - } - - void onEnable() - { - import std.stdio; - - writeln("TestSystem2 enabled"); - } - - void onDisable() - { - import std.stdio; - - writeln("TestSystem2 disabled"); - } - - void initialize(ref Entity entity, ref TestComp comp) - { - - } - - void update(ref EntitiesData data) - { - foreach(i;0..data.test.length) - { - data.test[i].gg += 14; - gEM.sendSelfEvent!(TestEvent)(data.entity[i].id, TestEvent()); - } - } - - void lateUpdate(ref EntitiesData data) - { - foreach(i;0..data.test.length) - { - data.test[i].gg -= 1; - gEM.sendSelfEvent!(TestEvent)(data.entity[i].id, TestEvent()); - } - } - - /*void handleEvent(Event event, ref TestComp comp) - { - - }*/ + TestComp, + TestComp4 } + alias ExcludedComponents = AliasSeq!("TestComp", "TestComp4"); + + string ExcludedComponents2;*/ + + static struct EntitiesData + { + short length; + const (Entity)[] entity; + TestComp3[] test; + //@excluded TestComp[] testt; + } + + static struct EventInput + { + Entity* entity; + TestComp3* test; + //TestComp* tt; + } + + void handleEvent(EventInput input, ref TestEvent event) + { + input.test.bg = event.a; + TestEvent2 event2; + event2.a = event.a + 8; + gEM.sendEvent(input.entity.id, event2); + } + + void handleEvent(EventInput input, ref TestEvent2 event) + { + input.test.gg = cast(uint)event.a; + } + + void onEnable() + { + import std.stdio; + + writeln("TestSystem2 enabled"); + } + + void onDisable() + { + import std.stdio; + + writeln("TestSystem2 disabled"); + } + + void initialize(ref Entity entity, ref TestComp comp) + { + + } + + void update(EntitiesData data) + { + 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);//*/ + /*TestEvent2 event2; + event2.a = data.test[i].gg + 8; + gEM.sendEvent(data.entity[i].id, event2);//*/ + //gEM.sendEvent!(TestEvent)(data.entity[i].id, event); + //gEM.sendSelfEvent!(TestEvent)(data.entity[i].id, TestEvent()); + } + } + + void lateUpdate(ref EntitiesData data) + { + foreach(i;0..data.test.length) + { + data.test[i].gg -= 1; + //gEM.sendSelfEvent!(TestEvent)(data.entity[i].id, TestEvent()); + } + } + + /*void handleEvent(Event event, ref TestComp comp) + { + + }*/ +} + +int main() +{ + void dispatch(EntityManager.JobGroup jobs) { foreach(job;jobs.jobs)