diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index a8954e0..0982531 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -2154,6 +2154,8 @@ export struct EntityManager return;*/ EntitiesBlock* new_block = findBlockWithFreeSpace(new_info); + updateEntityInfoBlocks(new_info); + assert(new_block.added_count == 0); void* start = new_block.dataBegin() + new_block.entities_count * EntityID.sizeof; @@ -2183,6 +2185,10 @@ export struct EntityManager cast(void*) block + info.deltas[comp] + ind * comp_size, comp_size); } + new_block.entities_count++; + if (new_block != new_info.update_block) + new_info.update_block = new_block; + if (new_info.add_listeners) { foreach (listener; new_info.add_listeners) @@ -2190,7 +2196,7 @@ export struct EntityManager if (!info.systems[listener]) { callAddEntityListener(&systems[listener], new_info, new_block, - new_block.entities_count, new_block.entities_count + 1); + new_block.entities_count - 1, new_block.entities_count); } } } @@ -2202,13 +2208,11 @@ export struct EntityManager if (info.systems[listener]) { callChangeEntityListener(&systems[listener], new_info, new_block, - new_block.entities_count, new_block.entities_count + 1, del_ids); + new_block.entities_count - 1, new_block.entities_count, del_ids); } } } - new_block.entities_count++; - removeEntityNoID(entity, block); } @@ -2291,12 +2295,14 @@ export struct EntityManager //EntityInfo* new_info = getEntityInfo(ids[0 .. len]); EntitiesBlock* new_block = findBlockWithFreeSpace(new_info); + updateEntityInfoBlocks(new_info); + assert(new_block.added_count == 0); void* start = new_block.dataBegin() + new_block.entities_count * EntityID.sizeof; Entity* new_entity = cast(Entity*) start; new_entity.id = entity.id; - id_manager.update(*new_entity); //new_entity.updateID(); + id_manager.update(*new_entity); uint j = 0; uint k = 0; @@ -2342,6 +2348,10 @@ export struct EntityManager } } + new_block.entities_count++; + if (new_block != new_info.update_block) + new_info.update_block = new_block; + if (new_info.add_listeners) { foreach (listener; new_info.add_listeners) @@ -2349,7 +2359,7 @@ export struct EntityManager if (!info.systems[listener]) { callAddEntityListener(&systems[listener], new_info, new_block, - new_block.entities_count, new_block.entities_count + 1); + new_block.entities_count - 1, new_block.entities_count); } } } @@ -2361,12 +2371,11 @@ export struct EntityManager if (info.systems[listener]) { callChangeEntityListener(&systems[listener], new_info, new_block, - new_block.entities_count, new_block.entities_count + 1, new_ids); + new_block.entities_count - 1, new_block.entities_count, new_ids); } } } - new_block.entities_count++; removeEntityNoID(entity, block); } @@ -2487,14 +2496,12 @@ export struct EntityManager } } - if (new_index == 1) - threads[threadID].blockToUpdate.add(new_block); + if (new_index == 1 && info.update_block == block) + threads[threadID].infosToUpdate.add(info); Entity* new_entity = cast(Entity*) start; - //add_mutex.lock_nothrow(); new_entity.id = id_manager.getNewID(); - //add_mutex.unlock_nothrow(); - id_manager.update(*new_entity); //new_entity.updateID(); + id_manager.update(*new_entity); return new_entity; } @@ -2538,12 +2545,10 @@ export struct EntityManager } if (index == 1) - threads[threadID].blockToUpdate.add(block); + threads[threadID].infosToUpdate.add(block); Entity* entity = cast(Entity*) start; - //add_mutex.lock_nothrow(); entity.id = id_manager.getNewID(); - //add_mutex.unlock_nothrow(); id_manager.update(*entity); //entity.updateID(); return entity;*/ @@ -2589,7 +2594,7 @@ export struct EntityManager if (comp.component_id < info.deltas.length) { ushort delta = info.deltas[comp.component_id]; - if (delta != ushort.max) + if (delta != 0) { uint size = components[comp.component_id].size; if (size != 0) @@ -2607,14 +2612,12 @@ export struct EntityManager } } - if (index == 1) - threads[threadID].blockToUpdate.add(block); + if (index == 1 && info.update_block == block) + threads[threadID].infosToUpdate.add(info); Entity* entity = cast(Entity*) start; - //add_mutex.lock_nothrow(); entity.id = id_manager.getNewID(); - //add_mutex.unlock_nothrow(); - id_manager.update(*entity); //entity.updateID(); + id_manager.update(*entity); return entity; } @@ -2633,6 +2636,7 @@ export struct EntityManager block.id = 0; info.first_block = block; info.last_block = block; + info.update_block = block; } else if (block.entities_count >= info.max_entities) { @@ -2643,6 +2647,12 @@ export struct EntityManager new_block.id = cast(ushort)(block.id + 1); block = new_block; info.last_block = block; + ///make sure that update_block point to unfilled block + if (info.update_block.entities_count == info.max_entities) + { + assert(!info.update_block.added_count); + info.update_block = block; + } } return block; } @@ -2668,8 +2678,9 @@ export struct EntityManager block.id = 0; info.first_block = block; info.last_block = block; + info.update_block = block; } - else if (block.entities_count + block.added_count > info.max_entities) + else if (block.entities_count + block.added_count >= info.max_entities) { EntitiesBlock* last_block = info.last_block; @@ -2687,6 +2698,12 @@ export struct EntityManager new_block.id = cast(ushort)(block.id + 1); block = new_block; info.last_block = block; + ///make sure that update_block point to unfilled block + if (info.update_block.entities_count == info.max_entities) + { + assert(!info.update_block.added_count); + info.update_block = block; + } } return block; } @@ -2730,8 +2747,10 @@ export struct EntityManager { EntityInfo* info = block.type_info; - if (info.last_block.added_count) - updateBlock(info.last_block); + updateEntityInfoBlocks(info); + + assert(info.last_block.added_count == 0); + assert(info.last_block.entities_count > 0); info.last_block.entities_count--; @@ -2764,12 +2783,13 @@ export struct EntityManager block = info.last_block; entity.id = *cast(EntityID*)(block.dataBegin() + block.entities_count * EntityID.sizeof); - id_manager.update(*entity); //entity.updateID(); + id_manager.update(*entity); } block = info.last_block; if (block.entities_count == 0) { + assert(info.update_block is block); info.last_block = block.prev_block; if (info.first_block is block) { @@ -2778,7 +2798,9 @@ export struct EntityManager if (block.prev_block) { block.prev_block.next_block = null; - block.prev_block.added_count = 0; + info.update_block = block.prev_block; + assert(block.prev_block.added_count == 0); + //block.prev_block.added_count.atomicStore(cast(ushort)0); } allocator.freeBlock(block); } @@ -2852,7 +2874,7 @@ export struct EntityManager } } - private void callAddEntityListener(System* system, EntityInfo* info, + private static void callAddEntityListener(System* system, EntityInfo* info, EntitiesBlock* block, int begin, int end) @nogc nothrow { ListenerCallData data; @@ -2873,8 +2895,8 @@ export struct EntityManager } } - private void callRemoveEntityListener(System* system, EntityInfo* info, - EntitiesBlock* block, int begin, int end) @nogc nothrow + private static void callRemoveEntityListener(System* system, + EntityInfo* info, EntitiesBlock* block, int begin, int end) @nogc nothrow { ListenerCallData data; data.system = system; @@ -2921,9 +2943,34 @@ export struct EntityManager (cast(void function(ref ListenerCallData) nothrow @nogc) system.m_change_entity)(data); } + private void updateEntityInfoBlocks(EntityInfo* info) nothrow @nogc + { + while (info.last_block.added_count) + { + EntitiesBlock* block = info.update_block; + assert(block !is null); + if (block.entities_count == info.max_entities) + { + assert(!block.added_count); + block = block.next_block; + } + assert(!block.prev_block || !block.prev_block.added_count); + info.update_block = info.last_block; + + while (block) + { + assert(block.added_count.atomicLoad() > 0); + updateBlock(block); + block = block.next_block; + } + } + assert(info.last_block is info.update_block); + } + private void updateBlock(EntitiesBlock* block) @nogc nothrow { - if(block.added_count == 0)return; + //if(block.added_count == 0)return; + assert(block.added_count != 0); EntityInfo* info = block.type_info; ushort entities_count = block.entities_count; block.entities_count += block.added_count; @@ -2942,17 +2989,15 @@ export struct EntityManager private bool updateBlocks() { bool has_work = false; - //foreach (ref ThreadData thread; threads)thread.swapToUpdate(); foreach (ref ThreadData thread; threads) { - //thread.swapToUpdate(); - if (thread.blockToUpdatePrev.length) + if (thread.infosToUpdatePrev.length) has_work = true; - foreach (block; thread.blockToUpdatePrev) + foreach (info; thread.infosToUpdatePrev) { - updateBlock(block); + updateEntityInfoBlocks(info); } - thread.blockToUpdatePrev.clear(); + thread.infosToUpdatePrev.clear(); } return has_work; } @@ -3055,6 +3100,9 @@ export struct EntityManager swapData(); has_work = false; + // has_work |= updateBlocks(); + // has_work |= changeEntities(); + // has_work |= removeEntities(); has_work |= updateEvents(); //id_manager.optimize(); @@ -3477,7 +3525,7 @@ export struct EntityManager EntityInfo*[] comp_rem_info; ///alignment of whole entity - ushort alignment; //unused in linear-layout + ushort alignment; //unused in linear-layout TODO: to remove ///size of entity (with alignment respect) ushort size; ///max number of entities in block @@ -3496,6 +3544,8 @@ export struct EntityManager EntitiesBlock* first_block; ///pointer to last block EntitiesBlock* last_block; + ///pointer to last updated block + EntitiesBlock* update_block; } /************************************************************************************************************************ @@ -3642,9 +3692,9 @@ export struct EntityManager return change_entities_list[data_index]; } - ref Vector!(EntitiesBlock*) blockToUpdate() @nogc nothrow return + ref Vector!(EntityInfo*) infosToUpdate() @nogc nothrow return { - return blocks_to_update[data_index]; + return infos_to_update[data_index]; } ref Vector!EntityID entitiesToRemovePrev() @nogc nothrow return @@ -3657,9 +3707,9 @@ export struct EntityManager return change_entities_list[1 - data_index]; } - ref Vector!(EntitiesBlock*) blockToUpdatePrev() @nogc nothrow return + ref Vector!(EntityInfo*) infosToUpdatePrev() @nogc nothrow return { - return blocks_to_update[1 - data_index]; + return infos_to_update[1 - data_index]; } private: @@ -3671,7 +3721,7 @@ export struct EntityManager Vector!EntityID[2] entities_to_remove; SimpleVector[2] change_entities_list; - Vector!(EntitiesBlock*)[2] blocks_to_update; + Vector!(EntityInfo*)[2] infos_to_update; ubyte data_index = 0; }