diff --git a/source/ecs/manager.d b/source/ecs/manager.d index b5636b3..6d01d6d 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -1056,7 +1056,7 @@ export class EntityManager m_dispatch_jobs = func; } - static void alignNum(ref ushort num, ushort alignment) nothrow @nogc + static void alignNum(ref ushort num, ushort alignment) nothrow @nogc pure { num = cast(ushort)((num + alignment - 1) & (-cast(int) alignment)); //num += alignment - (num & (alignment - 1)); } @@ -1459,10 +1459,7 @@ export class EntityManager new_entity.id = entity.id; new_entity.updateID(); - static if (EntityID.sizeof == 8) - uint ind = cast(uint)((cast(void*) entity - block.dataBegin()) >> 3); - else - uint ind = cast(uint)((cast(void*) entity - block.dataBegin()) / EntityID.sizeof()); + uint ind = block.entityIndex(entity); if (info.remove_listeners) { @@ -1636,10 +1633,7 @@ export class EntityManager uint j = 0; uint k = 0; - static if (EntityID.sizeof == 8) - uint ind = cast(uint)((cast(void*) entity - block.dataBegin()) >> 3); - else - uint ind = cast(uint)((cast(void*) entity - block.dataBegin()) / EntityID.sizeof()); + uint ind = block.entityIndex(entity); if (info.remove_listeners) { @@ -1761,12 +1755,66 @@ export class EntityManager } /************************************************************************************************************************ - *Add entity to system. + *Add copy of entity to system and returns pointer to it. Added copy has same data as copied entity. Returen pointer is + *valid only before one from commit(), begin() or end() will be called. To save entity to further use you should save ID + *instead of pointer. * *Params: *tmpl = pointer entity template allocated by EntityManager. */ - export ref Entity addEntity(EntityTemplate* tmpl) + export Entity* addEntityCopy(EntityID id) + { + Entity* entity = getEntity(id); + EntitiesBlock* block = getMetaData(entity); + EntityInfo* info = block.type_info; + + ushort index = block.entityIndex(entity); + + ushort new_index = 0; + EntitiesBlock* new_block; + do + { + new_block = findBlockWithFreeSpaceMT(info); + new_index = new_block.added_count.atomicOp!"+="(1); + } + while (new_block.entities_count + new_index > info.max_entities); + + ushort new_id = cast(ushort)(new_block.entities_count + new_index - 1); + const void* data_begin = new_block.dataBegin(); + const void* start = data_begin + EntityID.sizeof * new_id; + + foreach (i, comp; info.components) + { + memcpy(cast(void*) new_block + info.deltas[comp] + components[comp].size * new_id, + cast(void*) block + info.deltas[comp] + components[comp].size * index, components[comp].size); + + if (components[comp].create_callback) + { + components[comp].create_callback( + cast(void*) block + info.deltas[comp] + new_id * components[comp].size); + } + } + + if (new_index == 1) + threads[thread_id].blocks_to_update.add(new_block); + + Entity* new_entity = cast(Entity*) start; + //add_mutex.lock_nothrow(); + new_entity.id = id_manager.getNewID(); + //add_mutex.unlock_nothrow(); + new_entity.updateID(); + + return new_entity; + } + + /************************************************************************************************************************ + *Add entity to system. Returen pointer is valid only before one from commit(), begin() or end() will be called. To save entity to further + *use you should save ID instead of pointer. + * + *Params: + *tmpl = pointer entity template allocated by EntityManager. + */ + export Entity* addEntity(EntityTemplate* tmpl) { EntityInfo* info = tmpl.info; @@ -1806,7 +1854,7 @@ export class EntityManager //add_mutex.unlock_nothrow(); entity.updateID(); - return *entity; + return entity; } /************************************************************************************************************************ @@ -1903,11 +1951,7 @@ export class EntityManager EntityInfo* info = block.type_info; if (info.remove_listeners) { - void* data_begin = block.dataBegin(); - static if (EntityID.sizeof == 8) - uint pos = cast(uint)((cast(void*) entity - data_begin) >> 3); - else - uint pos = cast(uint)((cast(void*) entity - data_begin) / EntityID.sizeof()); + uint pos = block.entityIndex(entity); callRemoveEntityListeners(info, block, pos, pos + 1); } @@ -1920,16 +1964,11 @@ export class EntityManager private void removeEntityNoID(Entity* entity, EntitiesBlock* block, bool call_destructors = false) nothrow @nogc { - //pos is Entity number in block - void* data_begin = block.dataBegin(); EntityInfo* info = block.type_info; info.last_block.entities_count--; - static if (EntityID.sizeof == 8) - uint pos = cast(uint)((cast(void*) entity - data_begin) >> 3); - else - uint pos = cast(uint)((cast(void*) entity - data_begin) / EntityID.sizeof()); + uint pos = block.entityIndex(entity); if (call_destructors) { @@ -2173,14 +2212,7 @@ export class EntityManager 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); + call_data.id = call_data.block.entityIndex(entity); foreach (caller; events[i].callers) { @@ -2580,7 +2612,7 @@ export class EntityManager struct EntitiesBlock { ///return distance (in bytes) from begin of block to data - export uint dataDelta() nothrow @nogc + export uint dataDelta() nothrow @nogc pure { ushort dif = EntitiesBlock.sizeof; alignNum(dif, type_info.alignment); @@ -2588,12 +2620,20 @@ export class EntityManager } ///return pointer to first element in block - export void* dataBegin() nothrow @nogc + export void* dataBegin() nothrow @nogc pure { ushort dif = EntitiesBlock.sizeof; return cast(void*)&this + dif; } + export ushort entityIndex(Entity* entity) nothrow @nogc pure + { + static if (EntityID.sizeof == 8) + return cast(ushort)((cast(void*) entity - dataBegin()) >> 3); + else + return cast(ushort)((cast(void*) entity - dataBegin()) / EntityID.sizeof()); + } + ///pointer to Entity type info EntityInfo* type_info = null; ///number of entities in block diff --git a/tests/tests.d b/tests/tests.d index 3cf3697..1b7e47b 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -526,13 +526,13 @@ int main() dur = (MonoTime.currTime - time).total!"usecs"; writeln("Template allocating: ", dur, " usecs"); - Entity entity; + EntityID entity; { - entity = gEM.addEntity(tmpl); - writeEntityComponents(gEM.getEntity(entity.id)); + entity = gEM.addEntity(tmpl).id; + writeEntityComponents(gEM.getEntity(entity)); EntityManager.EntitiesBlock* block = EntityManager.instance.getMetaData( - gEM.getEntity(entity.id)); + gEM.getEntity(entity)); EntityManager.EntityInfo* info = block.type_info; writeln(info.add_listeners); //if(info)assert(0); @@ -586,15 +586,15 @@ int main() //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; + EntityID entity2; time = MonoTime.currTime; EntityID[] entities = Mallocator.instance.makeArray!EntityID(1_000_000); foreach (i; 0 .. 500_000) { - entity2 = gEM.addEntity(tmpl); - entities[i*2] = entity2.id; + entity2 = gEM.addEntity(tmpl).id; + entities[i*2] = entity2; entities[i*2+1] = gEM.addEntity(tmpl2).id; } @@ -638,7 +638,7 @@ int main() dur = (MonoTime.currTime - time).total!"usecs"; writeln("Update: ", dur, " usecs"); - writeEntityComponents(gEM.getEntity(entity2.id)); + writeEntityComponents(gEM.getEntity(entity2)); time = MonoTime.currTime; @@ -650,7 +650,7 @@ int main() dur = (MonoTime.currTime - time).total!"usecs"; writeln("Update: ", dur, " usecs"); - writeEntityComponents(gEM.getEntity(entity2.id)); + writeEntityComponents(gEM.getEntity(entity2)); time = MonoTime.currTime; @@ -662,9 +662,9 @@ int main() dur = (MonoTime.currTime - time).total!"usecs"; writeln("Update: ", dur, " usecs"); - writeEntityComponents(gEM.getEntity(entity2.id)); + writeEntityComponents(gEM.getEntity(entity2)); - entity = gEM.addEntity(tmpl); + entity = gEM.addEntity(tmpl).id; gEM.begin(); gEM.update(); @@ -672,40 +672,39 @@ int main() //Entity* pp;// = gEM.getEntity(entity.id); //writeln((cast(uint*) pp)[0 .. 14], " ", pp); - writeEntityComponents(gEM.getEntity(entity.id)); + writeEntityComponents(gEM.getEntity(entity)); gEM.addEntity(tmpl); + gEM.addEntityCopy(entity); - gEM.addComponents(entity.id, TestComp4()); - gEM.addComponents(entity.id, TestComp3()); + gEM.addComponents(entity, TestComp4()); + gEM.addComponents(entity, TestComp3()); gEM.begin(); gEM.update(); gEM.end(); - writeEntityComponents(gEM.getEntity(entity.id)); + writeEntityComponents(gEM.getEntity(entity)); - gEM.removeComponents!(TestComp)(entity.id); - gEM.addComponents(entity.id, TestComp()); - gEM.addComponents(entity.id, TestComp5()); + gEM.removeComponents!(TestComp)(entity); + gEM.addComponents(entity, TestComp()); + gEM.addComponents(entity, TestComp5()); gEM.begin(); gEM.update(); gEM.update("fixed"); gEM.end(); - gEM.removeComponents!(TestComp4)(entity.id); + gEM.removeComponents!(TestComp4)(entity); gEM.commit();//*/ - writeEntityComponents(gEM.getEntity(entity.id)); + writeEntityComponents(gEM.getEntity(entity)); //import std.stdio; //writeln((cast(uint*)tmpl.info.first_block)[0..48]); gEM.freeTemplate(tmpl); gEM.freeTemplate(tmpl2); EntityManager.destroy(); - - return 0; }