diff --git a/source/ecs/core.d b/source/ecs/core.d new file mode 100644 index 0000000..6b27d26 --- /dev/null +++ b/source/ecs/core.d @@ -0,0 +1,29 @@ +module ecs.core; + +public import ecs.manager; + +static struct ECS +{ + mixin template System(uint jobs_count = 32) + { + __gshared ushort system_id; + EntityManager.Job[] _ecs_jobs; + + void __ecsInitialize() + { + import std.experimental.allocator.mallocator; + import std.experimental.allocator; + _ecs_jobs = Mallocator.instance.makeArray!(EntityManager.Job)(jobs_count); + } + } + + mixin template Component() + { + __gshared ushort component_id; + } + + mixin template Event() + { + __gshared ushort event_id; + } +} \ No newline at end of file diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 168b6a1..ec99df1 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -8,6 +8,7 @@ import std.traits; import core.stdc.stdlib; import core.stdc.string; +import core.atomic; import ecs.entity; import ecs.block_allocator; @@ -22,11 +23,10 @@ alias SerializeVector = ecs.vector.Vector!ubyte; class EntityManager { - - export static void initialize() + export static void initialize(uint threads_count) { if (instance is null) - instance = Mallocator.instance.make!EntityManager; + instance = Mallocator.instance.make!EntityManager(threads_count); } export static void destroy() @@ -42,7 +42,7 @@ class EntityManager foreach (ref system; instance.systems) { if (system.m_destroy) - system.m_destroy(system.m_system_pointer); + (cast(void function(void*))system.m_destroy)(system.m_system_pointer); } Mallocator.instance.dispose(instance); @@ -52,8 +52,10 @@ class EntityManager /************************************************************************************************************************ *Default constructor. */ - this() + this(uint threads_count) { + if(threads_count == 0)threads_count = 0; + threads = Mallocator.instance.makeArray!ThreadData(threads_count); //event_manager = EventManager(this); //event_manager.manager = this; } @@ -272,11 +274,11 @@ class EntityManager Sys.EntitiesData, member)) == const(Entity)[])) { ret ~= "input_data." ~ member - ~ " = (cast(Entity*) block.dataBegin())[0 .. block.entities_count];"; + ~ " = (cast(Entity*) block.dataBegin())[offset .. entities_count];"; } else if (member == "length") { - ret ~= "input_data." ~ member ~ " = block.entities_count;"; + ret ~= "input_data." ~ member ~ " = cast(typeof(input_data.length))(entities_count - offset);"; } else { @@ -292,7 +294,7 @@ class EntityManager ~ opt.to!string ~ "]] != 0)input_data." ~ member ~ " = (cast(ForeachType!(typeof(Sys.EntitiesData." ~ member ~ "))*)(cast(void*) block + info.deltas[ data.system.m_optional_components[" - ~ opt.to!string ~ "]]))[0 .. block.entities_count]; + ~ opt.to!string ~ "]]))[offset .. entities_count]; else input_data." ~ member ~ " = null;"; opt++; @@ -310,7 +312,7 @@ class EntityManager { ret ~= "input_data." ~ member ~ " = (cast(ForeachType!(typeof(Sys.EntitiesData." ~ member ~ "))*)(cast(void*) block + info.deltas[ data.system.m_components[" - ~ req.to!string ~ "]]))[0 .. block.entities_count];"; + ~ req.to!string ~ "]]))[offset .. entities_count];"; req++; } } @@ -319,22 +321,47 @@ class EntityManager return ret; } + //pragma(msg,genFillInputData); + static void callUpdate(ref CallData data) { Sys* s = cast(Sys*) data.system.m_system_pointer; Sys.EntitiesData input_data; + EntityInfo* info = data.info; //block.type_info; - EntitiesBlock* block = data.info.first_block; - while (block !is null) + EntitiesBlock* block; + if (data.first_block) + block = data.first_block; + else + block = info.first_block; + + uint offset = data.begin; + uint entities_count; + uint blocks; + if (data.blocks) + blocks = data.blocks; + else + blocks = uint.max; + + while (block !is null && blocks > 0) { - EntityInfo* info = block.type_info; + if (blocks == 1) + { + if (data.end) + entities_count = data.end; + else entities_count = block.entities_count; + } + else + entities_count = block.entities_count; mixin(genFillInputData()); s.update(input_data); block = block.next_block; + offset = 0; + blocks--; } } @@ -368,6 +395,8 @@ class EntityManager system.m_system_pointer = cast(void*) Mallocator.instance.make!Sys; system.m_priority = priority; + (cast(Sys*) system.m_system_pointer).__ecsInitialize(); + system.jobs = (cast(Sys*) system.m_system_pointer)._ecs_jobs; mixin(genCompList()); @@ -383,7 +412,7 @@ class EntityManager /*if (systems[sys_id].m_destroy) systems[sys_id].m_destroy(systems[sys_id].m_system_pointer);*/ if (system.m_create) - system.m_create(system.m_system_pointer); + (cast(void function(void*))system.m_create)(system.m_system_pointer); systems[sys_id] = system; Sys.system_id = sys_id; @@ -396,7 +425,7 @@ class EntityManager systems.add(system); if (system.m_create) - system.m_create(system.m_system_pointer); + (cast(void function(void*))system.m_create)(system.m_system_pointer); systems[$ - 1].enable(); @@ -538,15 +567,16 @@ class EntityManager System* sys = &systems[caller.system_id]; if (sys.enabled) { - if (sys.m_begin) - sys.m_begin(sys.m_system_pointer); + //if (sys.m_begin) + // sys.m_begin(sys.m_system_pointer); foreach (info; caller.infos) { CallData data = CallData(caller.system_id, sys, info); - (cast(SytemFuncType) data.system.m_update)(data); + data.update(); + //(cast(SytemFuncType) data.system.m_update)(data); } - if (sys.m_end) - sys.m_end(sys.m_system_pointer); + //if (sys.m_end) + // sys.m_end(sys.m_system_pointer); } } } @@ -557,22 +587,158 @@ class EntityManager foreach (data; info.callers) { if (data.system.enabled) - (cast(SytemFuncType) data.system.m_update)(data); //caller(call_data,null); + data.update(); + //(cast(SytemFuncType) data.system.m_update)(data); //caller(call_data,null); } } } } + void updateMT() + { + assert(m_dispatch_jobs, + "Can't update with multithreading without JobDispatch function. Please use setJobDispatchFunc()."); + Vector!CallData tmp_datas; + tmp_datas.reserve(8); + + foreach (caller; system_callers) + { + System* sys = &systems[caller.system_id]; + if (sys.enabled) + { + uint entities_count = 0; + foreach (info; caller.infos) + { + uint blocks_count = info.blocksCount(); + if(blocks_count == 0)continue; + if (blocks_count > 1) + entities_count += (blocks_count - 1) * info.max_entities; + entities_count += info.last_block.entities_count; + } + + if (!entities_count) + continue; + + uint jobs_count = cast(uint) sys.jobs.length; + uint entities_per_job = entities_count / jobs_count + 1; + + if (entities_per_job <= 4) + { + jobs_count = entities_count / 4; + if(jobs_count == 0)jobs_count = 1; + entities_per_job = entities_count / jobs_count + 1; + } + + uint job_id = 0; + entities_count = 0; + + void nextJob() + { + CallData[] callers = m_call_data_allocator.getCallData(cast(uint)tmp_datas.length); + callers[0..$] = tmp_datas[0..$]; + tmp_datas.clear(); + sys.jobs[job_id].callers = callers; + job_id++; + } + + foreach (info; caller.infos) + { + uint blocks_count = info.blocksCount(); + EntitiesBlock* first_block = info.first_block; + uint first_elem = 0; + begin: + if (first_block is null || blocks_count == 0) + continue; + + if ((blocks_count - 1) * info.max_entities + entities_count + + info.last_block.entities_count - first_elem >= entities_per_job) + { + int reamaining_entities = (entities_per_job - entities_count - (first_block.entities_count - first_elem)); + if(reamaining_entities >= 0) + { + int full_blocks_count = reamaining_entities / info.max_entities; + EntitiesBlock* block = first_block; + foreach (i; 0 .. full_blocks_count + 1) + block = block.next_block; + + if ( + full_blocks_count * info.max_entities + + entities_count + (first_block.entities_count - first_elem) >= entities_per_job) + { + CallData data = CallData(caller.system_id, sys, info, first_block, + cast(ushort) (full_blocks_count + 1), cast(ushort) first_elem, 0); + tmp_datas.add(data); + first_elem = 0; + blocks_count -= full_blocks_count + 1; + first_block = block; + } + else + { + entities_count += full_blocks_count * info.max_entities + (first_block.entities_count - first_elem);// - first_elem; + uint last_elem = entities_per_job - entities_count;// + first_elem - 1; + CallData data = CallData(caller.system_id, sys, info, first_block, + cast(ushort)(full_blocks_count + 2), + cast(ushort) first_elem, cast(ushort) last_elem); + tmp_datas.add(data); + first_elem = last_elem; + blocks_count -= full_blocks_count + 1; + assert(first_elem <= block.entities_count); + first_block = block; + } + } + else + { + uint last_elem = entities_per_job - entities_count; + CallData data = CallData(caller.system_id, sys, info, first_block, + 1, cast(ushort) first_elem, cast(ushort)(first_elem + last_elem)); + tmp_datas.add(data); + first_elem += last_elem; + assert(first_elem <= first_block.entities_count); + } + nextJob(); + entities_count = 0; + goto begin; + } + else + { + CallData data = CallData(caller.system_id, sys, info, + first_block, cast(ushort) blocks_count, cast(ushort) first_elem); + tmp_datas.add(data); + entities_count += (blocks_count - 1) + * info.max_entities + info.last_block.entities_count - first_elem; + } + } + nextJob(); + + m_dispatch_jobs(sys.jobs[0..job_id]); + } + } + } + + struct Job + { + CallData[] callers; + + void execute() + { + EntityManager.instance.getThreadID(); + foreach (ref caller; callers) + { + caller.update(); + } + } + } + + void setJobDispachFunc(void delegate(Job[]) func) + { + m_dispatch_jobs = func; + } + static void alignNum(ref ushort num, ushort alignment) { num = cast(ushort)((num + alignment - 1) & (-cast(int) alignment)); //num += alignment - (num & (alignment - 1)); } - /*static ushort alignedNum(ushort num, ushort alignment) - { - return cast(ushort)((num + alignment - 1) & (-cast(int) alignment)); - }*/ - extern (C) static int compareUShorts(const void* a, const void* b) { ushort _a = *cast(ushort*) a; @@ -754,7 +920,7 @@ class EntityManager break; } - system_callers[index].infos.add(&entity); + if(index < system_callers.length)system_callers[index].infos.add(&entity); /*for (; index < entity.callers.length; index++) { CallData* caller = &entity.callers[index]; @@ -822,11 +988,12 @@ class EntityManager */ export void removeComponents(EntityID entity_id, ushort[] del_ids) { + ThreadData* data = &threads[thread_id]; uint num = cast(uint) del_ids.length; - change_entities_list.add(0); - change_entities_list.add((cast(ubyte*)&entity_id)[0 .. 8]); - change_entities_list.add((cast(ubyte*)&num)[0 .. 4]); - change_entities_list.add(cast(ubyte[]) del_ids); + data.change_entities_list.add(0); + data.change_entities_list.add((cast(ubyte*)&entity_id)[0 .. 8]); + data.change_entities_list.add((cast(ubyte*)&num)[0 .. 4]); + data.change_entities_list.add(cast(ubyte[]) del_ids); } private void __removeComponents(EntityID entity_id, ushort[] del_ids) @@ -961,34 +1128,42 @@ class EntityManager uint j = 0; uint k = 0; - foreach (ref id; ids) + uint len = 0; + //foreach (ref id; ids) + for(;len= new_ids.length) { - id = info.components[j++]; - continue; + if(j >= info.components.length)break; + *id = info.components[j++]; + //continue; } - if (j >= info.components.length) + else if (j >= info.components.length) { - id = new_ids[k++]; - continue; + *id = new_ids[k++]; + //continue; } - debug if (new_ids[k] == info.components[j]) - assert(0, "Trying to add already existing component!"); - if (new_ids[k] < info.components[j]) + else if(new_ids[k] == info.components[j]) { - id = new_ids[k++]; + *id = info.components[j++]; + k++; + } + /*debug if (new_ids[k] == info.components[j]) + assert(0, "Trying to add already existing component!");*/ + else if (new_ids[k] < info.components[j]) + { + *id = new_ids[k++]; } else - id = info.components[j++]; + *id = info.components[j++]; } + if(len == info.components.length)return; - EntityInfo* new_info = getEntityInfo(ids); + EntityInfo* new_info = getEntityInfo(ids[0..len]); EntitiesBlock* new_block = findBlockWithFreeSpace(new_info); - //removeEntityNoID(entity, block); - void* start = new_block.dataBegin() + new_block.entities_count * EntityID.sizeof; Entity* new_entity = cast(Entity*) start; @@ -1001,10 +1176,10 @@ class EntityManager uint ind = cast(uint)((cast(void*) entity - block.dataBegin()) >> 3); else uint ind = cast(uint)((cast(void*) entity - block.dataBegin()) / EntityID.sizeof()); - foreach (ref id; ids) + foreach (ref id; ids[0..len]) { void* dst = cast(void*) new_block + new_info.deltas[id] + ( - new_block.entities_count + new_block.added_count) * components[id].size; + new_block.entities_count /*+ new_block.added_count*/) * components[id].size; uint size = components[id].size; if (k >= new_ids.length) { @@ -1060,14 +1235,14 @@ class EntityManager { pointers[i] = ∁ }*/ - - change_entities_list.add(1); - change_entities_list.add((cast(ubyte*)&entity_id)[0 .. 8]); - change_entities_list.add((cast(ubyte*)&num)[0 .. 4]); - change_entities_list.add(cast(ubyte[]) new_ids); + ThreadData* data = &threads[thread_id]; + data.change_entities_list.add(1); + data.change_entities_list.add((cast(ubyte*)&entity_id)[0 .. 8]); + data.change_entities_list.add((cast(ubyte*)&num)[0 .. 4]); + data.change_entities_list.add(cast(ubyte[]) new_ids); static foreach (i, comp; comps) { - change_entities_list.add((cast(ubyte*)&comp)[0 .. comp.sizeof]); + data.change_entities_list.add((cast(ubyte*)&comp)[0 .. comp.sizeof]); } //__addComponents(entity_id, new_ids, pointers); @@ -1093,9 +1268,30 @@ class EntityManager */ export ref Entity addEntity(EntityTemplate* tmpl) { - EntitiesBlock* block = findBlockWithFreeSpace(tmpl.info); - uint id = (block.entities_count + block.added_count); EntityInfo* info = tmpl.info; + EntitiesBlock* last_block = info.last_block; + ushort index = 0; + if(last_block)/*index = */ + { + //index = last_block.added_count; + index = last_block.added_count.atomicOp!"+="(1); + } + EntitiesBlock* block = findBlockWithFreeSpace(tmpl.info,index); + if(block != last_block) + { + //index = block.added_count; + /*if(last_block) + { + //last_block.added_count.atomicOp!"-="(1); + last_block.added_count = cast(ushort)(info.max_entities - last_block.entities_count); + }*/ + index = block.added_count.atomicOp!"+="(1); + } + + //index--; + //index = cast(ushort)(block.added_count - 1); + uint id = (block.entities_count + index - 1);//block.added_count); + //EntityInfo* info = tmpl.info; void* data_begin = block.dataBegin(); void* start = data_begin + EntityID.sizeof * id; @@ -1106,23 +1302,45 @@ class EntityManager tmpl.entity_data.ptr + info.tmpl_deltas[comp], components[comp].size); } - if (!block.added_count) + //if (!block.added_count) + //if(block.added_count == 1) + if(index == 1) blocks_to_update.add(block); Entity* entity = cast(Entity*) start; entity.id = id_manager.getNewID(); entity.updateID(); - block.added_count++; + //block.added_count++; + //import core.atomic; + //block.entities_count++; return *entity; } - private EntitiesBlock* findBlockWithFreeSpace(EntityInfo* info) + private EntitiesBlock* findBlockWithFreeSpace(EntityInfo* info, uint new_index = 1) { - EntitiesBlock* previous_block; + //EntitiesBlock* previous_block; EntitiesBlock* block = info.last_block; - while (1) + if(block is null) + { + block = cast(EntitiesBlock*) allocator.getBlock(); //AlignedMallocator.instance.alignedAllocate(page_size, page_size); + *block = EntitiesBlock(info); + block.id = 0; + info.first_block = block; + info.last_block = block; + } + else if(block.entities_count + new_index/*block.added_count*/ > info.max_entities) + { + EntitiesBlock* new_block = cast(EntitiesBlock*) allocator.getBlock(); //AlignedMallocator.instance.alignedAllocate(page_size, page_size); + *new_block = EntitiesBlock(info); + new_block.prev_block = block; + block.next_block = new_block; + new_block.id = cast(ushort)(block.id + 1); + block = new_block; + info.last_block = block; + }//*/ + /*while (1) { if (block is null) { @@ -1143,8 +1361,6 @@ class EntityManager break; // new block certainly has free space } // check if there is enought space - /*if (block.dataDelta() + ( - block.entities_count + block.added_count + 1) * info.size > page_size)*/ if (block.entities_count + block.added_count >= block.type_info.max_entities) { previous_block = block; @@ -1153,7 +1369,7 @@ class EntityManager } break; // block exists and bounds check passed - } + }//*/ return block; } @@ -1166,7 +1382,7 @@ class EntityManager */ export void removeEntity(EntityID id) { - entities_to_remove.add(id); + threads[thread_id].entities_to_remove.add(id); } private void __removeEntity(EntityID id) @@ -1209,7 +1425,7 @@ class EntityManager } } - if(block !is info.last_block || pos != block.entities_count) + if (block !is info.last_block || pos != block.entities_count) { foreach (comp; info.components) { @@ -1236,7 +1452,8 @@ class EntityManager if (block.prev_block) { block.prev_block.next_block = null; - } + block.prev_block.added_count = 0; + } allocator.freeBlock(block); } } @@ -1254,40 +1471,43 @@ class EntityManager private void changeEntites() { - uint index = 0; - uint len = cast(uint) change_entities_list.length; - while (index < len) + foreach(ref thread;threads) { - if (!change_entities_list[index++]) + uint index = 0; + uint len = cast(uint) thread.change_entities_list.length; + while (index < len) { - EntityID id = *cast(EntityID*)&change_entities_list[index]; - index += EntityID.sizeof; - uint num = *cast(uint*)&change_entities_list[index]; - index += uint.sizeof; - ushort[] ids = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num]; - ids[0 .. $] = (cast(ushort*)&change_entities_list[index])[0 .. num]; - index += ushort.sizeof * num; - __removeComponents(id, ids); - } - else - { - EntityID id = *cast(EntityID*)&change_entities_list[index]; - index += EntityID.sizeof; - uint num = *cast(uint*)&change_entities_list[index]; - index += uint.sizeof; - ushort[] ids = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num]; - ids[0 .. $] = (cast(ushort*)&change_entities_list[index])[0 .. num]; - index += ushort.sizeof * num; - void*[] pointers = (cast(void**) alloca(num * (void*).sizeof))[0 .. num]; - foreach (i; 0 .. num) + if (!thread.change_entities_list[index++]) { - pointers[i] = &change_entities_list[index]; - index += components[ids[i]].size; + EntityID id = *cast(EntityID*)&thread.change_entities_list[index]; + index += EntityID.sizeof; + uint num = *cast(uint*)&thread.change_entities_list[index]; + index += uint.sizeof; + ushort[] ids = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num]; + ids[0 .. $] = (cast(ushort*)&thread.change_entities_list[index])[0 .. num]; + index += ushort.sizeof * num; + __removeComponents(id, ids); + } + else + { + EntityID id = *cast(EntityID*)&thread.change_entities_list[index]; + index += EntityID.sizeof; + uint num = *cast(uint*)&thread.change_entities_list[index]; + index += uint.sizeof; + ushort[] ids = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num]; + ids[0 .. $] = (cast(ushort*)&thread.change_entities_list[index])[0 .. num]; + index += ushort.sizeof * num; + void*[] pointers = (cast(void**) alloca(num * (void*).sizeof))[0 .. num]; + foreach (i; 0 .. num) + { + pointers[i] = &thread.change_entities_list[index]; + index += components[ids[i]].size; + } + __addComponents(id, ids, pointers); } - __addComponents(id, ids, pointers); } + thread.change_entities_list.clear(); } - change_entities_list.clear(); } private void updateBlocks() @@ -1295,18 +1515,26 @@ class EntityManager foreach (block; blocks_to_update) { block.entities_count += block.added_count; - block.added_count = 0; + if(block.entities_count > block.type_info.max_entities) + { + block.entities_count = block.type_info.max_entities; + } + //block.added_count = 0; + block.added_count.atomicStore(cast(ushort)0); } blocks_to_update.clear(); } private void removeEntities() { - foreach (id; entities_to_remove) + foreach(i,ref thread;threads) { - __removeEntity(id); + foreach (id; thread.entities_to_remove) + { + __removeEntity(id); + } + thread.entities_to_remove.clear(); } - entities_to_remove.clear(); } /************************************************************************************************************************ @@ -1317,19 +1545,20 @@ class EntityManager updateBlocks(); removeEntities(); changeEntites(); + m_call_data_allocator.clear(); - version (UpdateBySystems) + /*version (UpdateBySystems) { } else + {*/ + foreach (ref system; instance.systems) { - foreach (ref system; instance.systems) - { - if (system.m_begin) - system.m_begin(system.m_system_pointer); - } + if (system.m_begin) + (cast(void function(void*))system.m_begin)(system.m_system_pointer); } + //} } /************************************************************************************************************************ @@ -1337,18 +1566,18 @@ class EntityManager */ export void end() { - version (UpdateBySystems) + /*version (UpdateBySystems) { } else + {*/ + foreach (ref system; instance.systems) { - foreach (ref system; instance.systems) - { - if (system.m_end) - system.m_end(system.m_system_pointer); - } + if (system.m_end) + (cast(void function(void*))system.m_end)(system.m_system_pointer); } + //} updateBlocks(); removeEntities(); @@ -1357,6 +1586,12 @@ class EntityManager //clearEvents(); } + private void getThreadID() + { + if(m_thread_id_func)thread_id = m_thread_id_func(); + else thread_id = 0; + } + /************************************************************************************************************************ *Component info; */ @@ -1387,7 +1622,9 @@ class EntityManager ///Returns number of blocks uint blocksCount() { - return last_block.id; + if(last_block) + return last_block.id + 1; + else return 0; } ///entity components @@ -1438,7 +1675,8 @@ class EntityManager ///number of entities in block ushort entities_count = 0; ///number of new entities in block - ushort added_count = 0; + shared ushort added_count = 0; + //ushort added_count = 0; ///block id ushort id = 0; ///maximum number of entities in block @@ -1452,15 +1690,32 @@ class EntityManager /************************************************************************************************************************ *Structure with data used to calling System calls. + * + *first_block, begin, end, blocks parameters are used + *to call partial info update */ struct CallData { + void update() + { + (cast(SytemFuncType) system.m_update)(this); + } + ///system ID. Used to update system pointer after system reload. uint system_id; ///pointer to used system System* system; ///poiner to Entity type info EntityManager.EntityInfo* info; + + ///pointer to first block into process (if 0 then first block will be used) + EntitiesBlock* first_block; + ///number of blocks to update (if 0 then update all) + ushort blocks; + ///index of first element in first block + ushort begin; + ///index of last element in last block + ushort end; } struct SystemCaller @@ -1470,6 +1725,16 @@ class EntityManager Vector!(EntityInfo*) infos; } + struct ThreadData + { + Vector!EntityID entities_to_remove; + Vector!ubyte change_entities_list; + } + + static uint thread_id; + + ThreadData[] threads; + Vector!(SystemCaller*) system_callers; alias SytemFuncType = void function(ref EntityManager.CallData data); @@ -1489,9 +1754,12 @@ class EntityManager //EventManager event_manager; mixin EventManagerCode; - Vector!EntityID entities_to_remove; + //Vector!EntityID entities_to_remove; Vector!(EntitiesBlock*) blocks_to_update; - Vector!ubyte change_entities_list; + //Vector!ubyte change_entities_list; + + void delegate(Job[] jobs) m_dispatch_jobs; + uint delegate() m_thread_id_func; HashMap!(ushort[], EntityInfo*) entities_infos; HashMap!(const(char)[], ushort) systems_map; @@ -1500,6 +1768,60 @@ class EntityManager Vector!System systems; Vector!ComponentInfo components; Vector!EventInfo events; + + CallDataAllocator m_call_data_allocator; + struct CallDataAllocator + { + struct Block + { + CallData[256] data; + uint allocated = 0; + } + + Vector!(Block*) blocks; + uint id; + + void clear() + { + if(blocks.length > 0) + foreach (block; blocks[0 .. id + 1]) + { + block.allocated = 0; + } + id = 0; + //blocks.clear(); + } + + CallData[] getCallData(uint num) + { + if (blocks.length == 0) + { + Block* new_block = Mallocator.instance.make!Block; + blocks.add(new_block); + } + /*else if(blocks[$-1].allocated + num >= 256) + { + blocks.add(Block()); + }*/ + + Block* block = blocks[id]; + if (block.allocated + num >= 256) + { + id++; + if (id == blocks.length) + { + Block* new_block = Mallocator.instance.make!Block; + blocks.add(new_block); + } + block = blocks[id]; + } + + CallData[] ret = block.data[block.allocated .. block.allocated + num]; + block.allocated += num; + return ret; + } + } + __gshared EntityManager instance = null; } diff --git a/source/ecs/package.d b/source/ecs/package.d index e043ec9..fb40799 100644 --- a/source/ecs/package.d +++ b/source/ecs/package.d @@ -3,5 +3,6 @@ module ecs; public import ecs.manager; public import ecs.entity; public import ecs.system; +public import ecs.core; 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 b13c60a..2ac96fb 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -8,6 +8,7 @@ import ecs.manager; */ struct System { + /************************************************************************************************************************ *Check if system is enabled. */ @@ -22,7 +23,7 @@ struct System export void enable() { if (!m_enabled && m_enable) - m_enable(m_system_pointer); + (cast(void function(void*))m_enable)(m_system_pointer); m_enabled = true; } @@ -32,7 +33,7 @@ struct System export void disable() { if (m_enabled && m_disable) - m_disable(m_system_pointer); + (cast(void function(void*))m_disable)(m_system_pointer); m_enabled = false; } @@ -63,17 +64,28 @@ package: ///optional components ushort[] m_optional_components; + EntityManager.Job[] jobs; + //void function(ref EntityManager.CallData data) m_update; void* m_update; ///workaroud for DMD bug with upper line - void function(void* system_pointer) m_enable; + /*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; + void function(void* system_pointer) m_end;*/ + + void* m_enable; + void* m_disable; + + void* m_create; + void* m_destroy; + + void* m_begin; + void* m_end; //void function(ref EntityManager.CallData data) m_initialize; //void function(ref EntityManager.CallData data) m_deinitilize; diff --git a/source/ecs/vector.d b/source/ecs/vector.d index ef6a238..d67552f 100644 --- a/source/ecs/vector.d +++ b/source/ecs/vector.d @@ -49,9 +49,9 @@ public: export void removeAll() { if (array !is null) { - foreach (ref el; array[0 .. used]) { + /*foreach (ref el; array[0 .. used]) { destroy(el); - } + }*/ freeData(cast(void[]) array); gVectorsDestroyed++; } diff --git a/tests/tests.d b/tests/tests.d index 79a76a6..c9fb25a 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -5,6 +5,7 @@ import ecs.events; import ecs.manager; import ecs.system; import ecs.attributes; +import ecs.core; import core.time; import std.stdio; @@ -14,19 +15,19 @@ int main() struct TestEvent { - __gshared ushort event_id; + mixin ECS.Event;//__gshared ushort event_id; int a; } struct TestEvent2 { - __gshared ushort event_id; + mixin ECS.Event;//__gshared ushort event_id; float a; } static struct TestComp { - __gshared ushort component_id; + mixin ECS.Component;//__gshared ushort component_id; int a = 1; ulong b = 2; @@ -43,7 +44,7 @@ int main() static struct TestComp2 { - __gshared ushort component_id; + mixin ECS.Component;//__gshared ushort component_id; int b = 3; int a = 4; @@ -60,7 +61,7 @@ int main() static struct TestComp3 { - __gshared ushort component_id; + mixin ECS.Component;//__gshared ushort component_id; uint gg = 5; //good game uint bg = 6; //bad game @@ -77,7 +78,7 @@ int main() static struct TestComp4 { - __gshared ushort component_id; + mixin ECS.Component;//__gshared ushort component_id; uint gg = 7; //good game uint bg = 8; //bad game ulong a = 9; @@ -98,7 +99,7 @@ int main() struct TestSystem { - __gshared ushort system_id; + mixin ECS.System!16;//__gshared ushort system_id; void onCreate() { @@ -146,7 +147,7 @@ int main() test2.a = 8; } - void update(ref EntitiesData data) + void update(EntitiesData data) { foreach(i;0..data.length) { @@ -165,7 +166,7 @@ int main() struct TestSystemWithHighPriority { - __gshared ushort system_id; + mixin ECS.System!16;//__gshared ushort system_id; static struct EntitiesData { @@ -177,7 +178,7 @@ int main() } - void update(ref EntitiesData data) + void update(EntitiesData data) { } @@ -192,7 +193,7 @@ import std.meta; struct TestSystem2 { - __gshared ushort system_id; + mixin ECS.System!16;//__gshared ushort system_id; enum AbsentComponents0 { @@ -255,6 +256,15 @@ import std.meta; }*/ } + void dispatch(EntityManager.Job[] jobs) + { + foreach(job;jobs) + { + //writeln(job); + job.execute(); + } + } + void writeEntityComponents(Entity* entity) { write(entity.id); @@ -270,7 +280,8 @@ import std.meta; //writeln((cast(uint*) pp)[0 .. 14], " ", pp); } - EntityManager.initialize(); + EntityManager.initialize(1); + gEM.setJobDispachFunc(&dispatch); assert(gEM !is null); MonoTime time = MonoTime.currTime; @@ -358,40 +369,49 @@ import std.meta; //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)); + Entity entity2; + foreach (i; 0 .. 500_000) { - gEM.addEntity(tmpl); + entity2 = gEM.addEntity(tmpl); gEM.addEntity(tmpl2); } time = MonoTime.currTime; gEM.begin(); + //gEM.updateMT(); gEM.update(); gEM.end(); dur = (MonoTime.currTime - time).total!"usecs"; writeln("Update: ", dur, " usecs"); + writeEntityComponents(gEM.getEntity(entity2.id)); + time = MonoTime.currTime; gEM.begin(); - gEM.update(); + gEM.updateMT(); + //gEM.update(); gEM.end(); dur = (MonoTime.currTime - time).total!"usecs"; writeln("Update: ", dur, " usecs"); + writeEntityComponents(gEM.getEntity(entity2.id)); + time = MonoTime.currTime; gEM.begin(); - gEM.update(); + gEM.updateMT(); + //gEM.update(); gEM.end(); dur = (MonoTime.currTime - time).total!"usecs"; writeln("Update: ", dur, " usecs"); - writeEntityComponents(gEM.getEntity(entity.id)); + writeEntityComponents(gEM.getEntity(entity2.id)); entity = gEM.addEntity(tmpl);