Basic update, multithreading emplate support, fixed

-Added possibility to add entity form template + components to replace template data
-basic tests for new functionality
-small performance improvement for events
-added ComponentRef structure which contain data pointer and component ID
-now events are called before entities removing
This commit is contained in:
Mergul 2020-05-24 21:57:48 +02:00
parent 3d98b0ee5e
commit 15cd57dbcb
6 changed files with 137 additions and 20 deletions

View file

@ -62,6 +62,7 @@ private:
{ {
next_block = cast(void*) Mallocator.alignAlloc( next_block = cast(void*) Mallocator.alignAlloc(
block_size * blocks_in_allocation, block_size); block_size * blocks_in_allocation, block_size);
if(next_block is null)assert(0);
if(pointers is null)pointers = Mallocator.make!BlockPointers; if(pointers is null)pointers = Mallocator.make!BlockPointers;
if(pointers.numberof >= 32) if(pointers.numberof >= 32)

View file

@ -74,6 +74,11 @@ static struct ECS
mixin template Component() mixin template Component()
{ {
__gshared ushort component_id = ushort.max; __gshared ushort component_id = ushort.max;
ComponentRef ref_() @nogc nothrow
{
return ComponentRef(&this,component_id);
}
} }
/************************************************************************************************************************ /************************************************************************************************************************

View file

@ -114,3 +114,14 @@ export struct EntityTemplate
return cast(T*)(entity_data.ptr + info.tmpl_deltas[T.component_id]); 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;
}

View file

@ -40,10 +40,9 @@ package struct EventManager
if(block is null) if(block is null)
{ {
event_block_alloc_mutex.lock(); event_block_alloc_mutex.lock();
scope (exit) block = cast(EventBlock*) allocator.getBlock();
event_block_alloc_mutex.unlock(); event_block_alloc_mutex.unlock();
block = cast(EventBlock*) allocator.getBlock();
*block = EventBlock(); *block = EventBlock();
data.first_blocks[block_id] = block; data.first_blocks[block_id] = block;
data.blocks[block_id] = block; data.blocks[block_id] = block;
@ -52,10 +51,9 @@ package struct EventManager
if(block.count >= data.max_events) if(block.count >= data.max_events)
{ {
event_block_alloc_mutex.lock(); event_block_alloc_mutex.lock();
scope (exit) EventBlock* new_block = cast(EventBlock*) allocator.getBlock();
event_block_alloc_mutex.unlock(); event_block_alloc_mutex.unlock();
EventBlock* new_block = cast(EventBlock*) allocator.getBlock();
*new_block = EventBlock(); *new_block = EventBlock();
block.next = new_block; block.next = new_block;
block = new_block; block = new_block;

View file

@ -2356,12 +2356,7 @@ export struct EntityManager
void addComponents(Components...)(const EntityID entity_id, Components comps) nothrow @nogc void addComponents(Components...)(const EntityID entity_id, Components comps) nothrow @nogc
{ {
const uint num = Components.length; const uint num = Components.length;
//Entity* entity = id_manager.getEntityPointer(entity_id); /*ushort[num] new_ids;
//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;
static foreach (i, comp; Components) static foreach (i, comp; Components)
{ {
@ -2376,9 +2371,39 @@ export struct EntityManager
static foreach (i, comp; comps) static foreach (i, comp; comps)
{ {
data.changeEntitiesList.add((cast(ubyte*)&comp)[0 .. comp.sizeof]); data.changeEntitiesList.add((cast(ubyte*)&comp)[0 .. comp.sizeof]);
} }*/
//__addComponents(entity_id, new_ids, pointers); //__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. tmpl = pointer entity template allocated by EntityManager.
*/ */
export Entity* addEntity(EntityTemplate* tmpl) 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; EntityInfo* info = tmpl.info;
@ -2472,17 +2549,34 @@ export struct EntityManager
void* data_begin = block.dataBegin(); void* data_begin = block.dataBegin();
void* start = data_begin + EntityID.sizeof * id; 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) 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) if (components[comp].create_callback)
{ {
components[comp].create_callback( components[comp].create_callback(
cast(void*) block + info.deltas[comp] + id * components[comp].size); cast(void*) block + info.deltas[comp] + id * components[comp].size);
} }
} }
if (index == 1) if (index == 1)
@ -2916,12 +3010,12 @@ export struct EntityManager
swapData(); swapData();
has_work = false; has_work = false;
has_work |= updateEvents();
id_manager.optimize(); id_manager.optimize();
has_work |= updateBlocks(); has_work |= updateBlocks();
has_work |= changeEntities(); has_work |= changeEntities();
has_work |= removeEntities(); has_work |= removeEntities();
has_work |= updateEvents();
} }
event_manager.clearEvents(); event_manager.clearEvents();
} }

View file

@ -153,6 +153,14 @@ unittest
assert(entity2.getComponent!CFloat); assert(entity2.getComponent!CFloat);
assert(*entity2.getComponent!CInt == 2); assert(*entity2.getComponent!CInt == 2);
assert(*entity2.getComponent!CFloat == 2.0); 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 //allocate templates
@ -1142,7 +1150,7 @@ unittest
entity = gEM.getEntity(id); entity = gEM.getEntity(id);
assert(*entity.getComponent!CLong == 66); assert(*entity.getComponent!CLong == 66);
assert(*entity.getComponent!CInt == 36); assert(*entity.getComponent!CInt == 2);//36);
//test for multiple event blocks //test for multiple event blocks
long result = *entity.getComponent!CLong; long result = *entity.getComponent!CLong;