diff --git a/source/bubel/ecs/block_allocator.d b/source/bubel/ecs/block_allocator.d index 740b762..5a2d02c 100644 --- a/source/bubel/ecs/block_allocator.d +++ b/source/bubel/ecs/block_allocator.d @@ -62,6 +62,7 @@ private: { next_block = cast(void*) Mallocator.alignAlloc( block_size * blocks_in_allocation, block_size); + if(next_block is null)assert(0); if(pointers is null)pointers = Mallocator.make!BlockPointers; if(pointers.numberof >= 32) diff --git a/source/bubel/ecs/core.d b/source/bubel/ecs/core.d index 0487665..4a90928 100644 --- a/source/bubel/ecs/core.d +++ b/source/bubel/ecs/core.d @@ -74,6 +74,11 @@ static struct ECS mixin template Component() { __gshared ushort component_id = ushort.max; + + ComponentRef ref_() @nogc nothrow + { + return ComponentRef(&this,component_id); + } } /************************************************************************************************************************ diff --git a/source/bubel/ecs/entity.d b/source/bubel/ecs/entity.d index 1e98ff2..f24ddf3 100644 --- a/source/bubel/ecs/entity.d +++ b/source/bubel/ecs/entity.d @@ -114,3 +114,14 @@ export struct EntityTemplate return cast(T*)(entity_data.ptr + info.tmpl_deltas[T.component_id]); } } + +/************************************************************************************************************************ +ComponentRef contain component ID and pointer to it. It used to add component data to entity. +*/ +export struct ComponentRef +{ + ///pointer to component + void* ptr; + ///component index + ushort component_id; +} diff --git a/source/bubel/ecs/events.d b/source/bubel/ecs/events.d index 772d5b5..25b864d 100644 --- a/source/bubel/ecs/events.d +++ b/source/bubel/ecs/events.d @@ -40,10 +40,9 @@ package struct EventManager if(block is null) { event_block_alloc_mutex.lock(); - scope (exit) - event_block_alloc_mutex.unlock(); - block = cast(EventBlock*) allocator.getBlock(); + event_block_alloc_mutex.unlock(); + *block = EventBlock(); data.first_blocks[block_id] = block; data.blocks[block_id] = block; @@ -52,10 +51,9 @@ package struct EventManager if(block.count >= data.max_events) { event_block_alloc_mutex.lock(); - scope (exit) - event_block_alloc_mutex.unlock(); - EventBlock* new_block = cast(EventBlock*) allocator.getBlock(); + event_block_alloc_mutex.unlock(); + *new_block = EventBlock(); block.next = new_block; block = new_block; diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index d5892bb..3ac16e8 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -2356,12 +2356,7 @@ export struct EntityManager void addComponents(Components...)(const EntityID entity_id, Components comps) nothrow @nogc { const uint num = Components.length; - //Entity* entity = id_manager.getEntityPointer(entity_id); - //EntitiesBlock* block = getMetaData(entity); - //EntityInfo* info = block.type_info; - /*ushort[] ids = (cast(ushort*) alloca(ushort.sizeof * (info.components.length + num)))[0 - .. info.components.length + num];*/ - ushort[num] new_ids; + /*ushort[num] new_ids; static foreach (i, comp; Components) { @@ -2376,9 +2371,39 @@ export struct EntityManager static foreach (i, comp; comps) { data.changeEntitiesList.add((cast(ubyte*)&comp)[0 .. comp.sizeof]); - } + }*/ //__addComponents(entity_id, new_ids, pointers); + + ComponentRef[num] _comps; + static foreach(i, comp; comps) + { + _comps[i] = comp.ref_; + } + addComponents(entity_id, _comps); + + } + + export void addComponents(const EntityID entity_id, ComponentRef[] comps) nothrow @nogc + { + uint num = cast(uint)comps.length; + ThreadData* data = &threads[threadID]; + data.changeEntitiesList.add(cast(ubyte) 1u); + data.changeEntitiesList.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]); + data.changeEntitiesList.add((cast(ubyte*)&num)[0 .. uint.sizeof]); + foreach(ref_; comps) + { + data.changeEntitiesList.add((cast(ubyte*)&ref_.component_id)[0 .. ushort.sizeof]); + } + foreach(ref_; comps) + { + data.changeEntitiesList.add((cast(ubyte*)ref_.ptr)[0 .. components[ref_.component_id].size]); + } + /*data.changeEntitiesList.add(cast(ubyte[]) new_ids); + static foreach (i, comp; comps) + { + data.changeEntitiesList.add((cast(ubyte*)&comp)[0 .. comp.sizeof]); + }*/ } /************************************************************************************************************************ @@ -2455,6 +2480,58 @@ export struct EntityManager tmpl = pointer entity template allocated by EntityManager. */ export Entity* addEntity(EntityTemplate* tmpl) + { + /*EntityInfo* info = tmpl.info; + + ushort index = 0; + EntitiesBlock* block; + do + { + block = findBlockWithFreeSpaceMT(info); + index = block.added_count.atomicOp!"+="(1); + } + while (block.entities_count + index > info.max_entities); + + uint id = (block.entities_count + index - 1); //block.added_count); + + void* data_begin = block.dataBegin(); + void* start = data_begin + EntityID.sizeof * id; + + foreach (comp; info.components) + { + memcpy(cast(void*) block + info.deltas[comp] + components[comp].size * id, + tmpl.entity_data.ptr + info.tmpl_deltas[comp], components[comp].size); + + if (components[comp].create_callback) + { + components[comp].create_callback( + cast(void*) block + info.deltas[comp] + id * components[comp].size); + } + + } + + if (index == 1) + threads[threadID].blockToUpdate.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;*/ + return addEntity(tmpl, null); + } + + /************************************************************************************************************************ + 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. + replacement = list of components references to used. Memory form list replace data from template inside new entity. Should be used only for data which vary between most entities (like 3D position etc.) + */ + export Entity* addEntity(EntityTemplate* tmpl, ComponentRef[] replacement) { EntityInfo* info = tmpl.info; @@ -2472,17 +2549,34 @@ export struct EntityManager void* data_begin = block.dataBegin(); void* start = data_begin + EntityID.sizeof * id; + foreach (comp; info.components) + { + uint size = components[comp].size; + memcpy(cast(void*) block + info.deltas[comp] + size * id, + tmpl.entity_data.ptr + info.tmpl_deltas[comp], size); + } + + foreach(comp; replacement) + { + if(comp.component_id < info.deltas.length) + { + ushort delta = info.deltas[comp.component_id]; + if(delta != ushort.max) + { + uint size = components[comp.component_id].size; + memcpy(cast(void*) block + delta + size * id, + comp.ptr, size); + } + } + } + foreach (i, comp; info.components) { - memcpy(cast(void*) block + info.deltas[comp] + components[comp].size * id, - tmpl.entity_data.ptr + info.tmpl_deltas[comp], components[comp].size); - if (components[comp].create_callback) { components[comp].create_callback( cast(void*) block + info.deltas[comp] + id * components[comp].size); } - } if (index == 1) @@ -2916,12 +3010,12 @@ export struct EntityManager swapData(); has_work = false; + has_work |= updateEvents(); + id_manager.optimize(); has_work |= updateBlocks(); has_work |= changeEntities(); has_work |= removeEntities(); - - has_work |= updateEvents(); } event_manager.clearEvents(); } diff --git a/tests/basic.d b/tests/basic.d index 3bf2814..ab9acec 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -153,6 +153,14 @@ unittest assert(entity2.getComponent!CFloat); assert(*entity2.getComponent!CInt == 2); assert(*entity2.getComponent!CFloat == 2.0); + + CInt cint = CInt(10); + CLong clong; + Entity* entity3 = gEM.addEntity(tmpl_, [cint.ref_, clong.ref_].staticArray); + assert(entity3.getComponent!CInt); + assert(entity3.getComponent!CFloat); + assert(*entity3.getComponent!CInt == 10); + assert(*entity3.getComponent!CFloat == 2.0); } //allocate templates @@ -1142,7 +1150,7 @@ unittest entity = gEM.getEntity(id); assert(*entity.getComponent!CLong == 66); - assert(*entity.getComponent!CInt == 36); + assert(*entity.getComponent!CInt == 2);//36); //test for multiple event blocks long result = *entity.getComponent!CLong;