Fixed ECS bug related to adding/removing entities inside onAdd/onRemove entity callback
Now whole committing process is called in specific order: - UpdateBlocks - ChangeEntities - RemoveEntities - HandleEvents Whole process is repeated until there will be no more changes to commit
This commit is contained in:
parent
d89df28f85
commit
43f8755a39
1 changed files with 123 additions and 55 deletions
|
|
@ -2074,10 +2074,10 @@ export struct EntityManager
|
|||
{
|
||||
ThreadData* data = &threads[threadID];
|
||||
uint num = cast(uint) del_ids.length;
|
||||
data.change_entities_list.add(0);
|
||||
data.change_entities_list.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]);
|
||||
data.change_entities_list.add((cast(ubyte*)&num)[0 .. uint.sizeof]);
|
||||
data.change_entities_list.add((cast(ubyte*) del_ids.ptr)[0 .. num * 2]);
|
||||
data.changeEntitiesList.add(0);
|
||||
data.changeEntitiesList.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]);
|
||||
data.changeEntitiesList.add((cast(ubyte*)&num)[0 .. uint.sizeof]);
|
||||
data.changeEntitiesList.add((cast(ubyte*) del_ids.ptr)[0 .. num * 2]);
|
||||
}
|
||||
|
||||
private void __removeComponents(EntityID entity_id, ushort[] del_ids)
|
||||
|
|
@ -2349,13 +2349,13 @@ export struct EntityManager
|
|||
}
|
||||
|
||||
ThreadData* data = &threads[threadID];
|
||||
data.change_entities_list.add(cast(ubyte) 1u);
|
||||
data.change_entities_list.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]);
|
||||
data.change_entities_list.add((cast(ubyte*)&num)[0 .. uint.sizeof]);
|
||||
data.change_entities_list.add(cast(ubyte[]) new_ids);
|
||||
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]);
|
||||
data.changeEntitiesList.add(cast(ubyte[]) new_ids);
|
||||
static foreach (i, comp; comps)
|
||||
{
|
||||
data.change_entities_list.add((cast(ubyte*)&comp)[0 .. comp.sizeof]);
|
||||
data.changeEntitiesList.add((cast(ubyte*)&comp)[0 .. comp.sizeof]);
|
||||
}
|
||||
|
||||
//__addComponents(entity_id, new_ids, pointers);
|
||||
|
|
@ -2416,7 +2416,7 @@ export struct EntityManager
|
|||
}
|
||||
|
||||
if (new_index == 1)
|
||||
threads[threadID].blocks_to_update.add(new_block);
|
||||
threads[threadID].blockToUpdate.add(new_block);
|
||||
|
||||
Entity* new_entity = cast(Entity*) start;
|
||||
//add_mutex.lock_nothrow();
|
||||
|
|
@ -2466,7 +2466,7 @@ export struct EntityManager
|
|||
}
|
||||
|
||||
if (index == 1)
|
||||
threads[threadID].blocks_to_update.add(block);
|
||||
threads[threadID].blockToUpdate.add(block);
|
||||
|
||||
Entity* entity = cast(Entity*) start;
|
||||
//add_mutex.lock_nothrow();
|
||||
|
|
@ -2557,7 +2557,7 @@ export struct EntityManager
|
|||
*/
|
||||
export void removeEntity(EntityID id)
|
||||
{
|
||||
threads[threadID].entities_to_remove.add(id);
|
||||
threads[threadID].entitesToRemove.add(id);
|
||||
}
|
||||
|
||||
private void __removeEntity(EntityID id) nothrow @nogc
|
||||
|
|
@ -2646,47 +2646,51 @@ export struct EntityManager
|
|||
return cast(EntitiesBlock*)(cast(size_t) pointer & (~cast(size_t)(m_page_size - 1)));
|
||||
}
|
||||
|
||||
private void changeEntities()
|
||||
private bool changeEntities()
|
||||
{
|
||||
foreach (ref thread; threads)
|
||||
bool has_work = false;
|
||||
//foreach (ref ThreadData thread; threads)thread.swapToChange();
|
||||
foreach (ref ThreadData thread; threads)
|
||||
{
|
||||
uint index = 0;
|
||||
uint len = cast(uint) thread.change_entities_list.length;
|
||||
uint len = cast(uint) thread.changeEntitiesListPrev.length;
|
||||
if(len)has_work = true;
|
||||
void*[32] pointers; // = (cast(void**) alloca(num * (void*).sizeof))[0 .. num];
|
||||
while (index < len)
|
||||
{
|
||||
if (!thread.change_entities_list[index++])
|
||||
if (!thread.changeEntitiesListPrev[index++])
|
||||
{
|
||||
EntityID id = *cast(EntityID*)&thread.change_entities_list[index];
|
||||
EntityID id = *cast(EntityID*)&thread.changeEntitiesListPrev[index];
|
||||
index += EntityID.sizeof;
|
||||
uint num = *cast(uint*)&thread.change_entities_list[index];
|
||||
uint num = *cast(uint*)&thread.changeEntitiesListPrev[index];
|
||||
index += uint.sizeof;
|
||||
ushort[] ids; // = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num];
|
||||
ids = (cast(ushort*)&thread.change_entities_list[index])[0 .. num];
|
||||
ids = (cast(ushort*)&thread.changeEntitiesListPrev[index])[0 .. num];
|
||||
index += ushort.sizeof * num;
|
||||
__removeComponents(id, ids);
|
||||
}
|
||||
else
|
||||
{
|
||||
EntityID id = *cast(EntityID*)&thread.change_entities_list[index];
|
||||
EntityID id = *cast(EntityID*)&thread.changeEntitiesListPrev[index];
|
||||
index += EntityID.sizeof;
|
||||
uint num = *cast(uint*)&thread.change_entities_list[index];
|
||||
uint num = *cast(uint*)&thread.changeEntitiesListPrev[index];
|
||||
index += uint.sizeof;
|
||||
ushort[] ids; // = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num];
|
||||
ids = (cast(ushort*)&thread.change_entities_list[index])[0 .. num];
|
||||
ids = (cast(ushort*)&thread.changeEntitiesListPrev[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];
|
||||
pointers[i] = &thread.changeEntitiesListPrev[index];
|
||||
index += components[ids[i]].size;
|
||||
}
|
||||
|
||||
__addComponents(id, ids, pointers[0 .. num]);
|
||||
}
|
||||
}
|
||||
thread.change_entities_list.clear();
|
||||
thread.changeEntitiesListPrev.clear();
|
||||
}
|
||||
return has_work;
|
||||
}
|
||||
|
||||
private void callAddEntityListeners(EntityInfo* info, EntitiesBlock* block, int begin, int end) @nogc nothrow
|
||||
|
|
@ -2767,11 +2771,15 @@ export struct EntityManager
|
|||
(cast(void function(ref ListenerCallData) nothrow @nogc) system.m_change_entity)(data);
|
||||
}
|
||||
|
||||
private void updateBlocks()
|
||||
private bool updateBlocks()
|
||||
{
|
||||
foreach (ref thread; threads)
|
||||
bool has_work = false;
|
||||
//foreach (ref ThreadData thread; threads)thread.swapToUpdate();
|
||||
foreach (ref ThreadData thread; threads)
|
||||
{
|
||||
foreach (block; thread.blocks_to_update)
|
||||
//thread.swapToUpdate();
|
||||
if(thread.blockToUpdatePrev.length)has_work = true;
|
||||
foreach (block; thread.blockToUpdatePrev)
|
||||
{
|
||||
EntityInfo* info = block.type_info;
|
||||
ushort entities_count = block.entities_count;
|
||||
|
|
@ -2786,30 +2794,35 @@ export struct EntityManager
|
|||
{
|
||||
callAddEntityListeners(info, block, entities_count, block.entities_count);
|
||||
}
|
||||
|
||||
}
|
||||
thread.blocks_to_update.clear();
|
||||
thread.blockToUpdatePrev.clear();
|
||||
}
|
||||
return has_work;
|
||||
}
|
||||
|
||||
private void removeEntities() nothrow @nogc
|
||||
private bool removeEntities() nothrow @nogc
|
||||
{
|
||||
foreach (i, ref thread; threads)
|
||||
bool has_work = false;
|
||||
//foreach (ref ThreadData thread; threads)thread.swapToRemove();
|
||||
foreach (ref ThreadData thread; threads)
|
||||
{
|
||||
foreach (id; thread.entities_to_remove)
|
||||
if(thread.entitiesToRemovePrev.length)has_work = true;
|
||||
foreach (id; thread.entitiesToRemovePrev)
|
||||
{
|
||||
__removeEntity(id);
|
||||
}
|
||||
thread.entities_to_remove.clear();
|
||||
thread.entitiesToRemovePrev.clear();
|
||||
}
|
||||
return has_work;
|
||||
}
|
||||
|
||||
private void updateEvents() nothrow @nogc
|
||||
private bool updateEvents() nothrow @nogc
|
||||
{
|
||||
bool empty = true;
|
||||
while (1)
|
||||
{
|
||||
event_manager.swapCurrent();
|
||||
bool has_work = false;
|
||||
// bool empty = true;
|
||||
//while (1)
|
||||
//{
|
||||
//event_manager.swapCurrent();
|
||||
uint current_index;
|
||||
if (event_manager.current_index == 0)
|
||||
current_index = cast(uint) threads.length;
|
||||
|
|
@ -2821,8 +2834,11 @@ export struct EntityManager
|
|||
.. current_index + threads.length])
|
||||
{
|
||||
EventManager.EventBlock* block = first_block;
|
||||
if (block)
|
||||
empty = false;
|
||||
if (block)has_work = true;
|
||||
// {
|
||||
// has_work = true;
|
||||
// //empty = false;
|
||||
// }
|
||||
while (block)
|
||||
{
|
||||
EventCallData call_data;
|
||||
|
|
@ -2856,23 +2872,37 @@ export struct EntityManager
|
|||
}
|
||||
}
|
||||
}
|
||||
if (empty)
|
||||
break;
|
||||
empty = true;
|
||||
// if (empty)
|
||||
// break;
|
||||
// empty = true;
|
||||
//}
|
||||
return has_work;
|
||||
}
|
||||
|
||||
private void swapData() nothrow @nogc
|
||||
{
|
||||
event_manager.swapCurrent();
|
||||
foreach(ref ThreadData thread; threads)
|
||||
{
|
||||
thread.swapData();
|
||||
}
|
||||
}
|
||||
|
||||
export void commit()
|
||||
{
|
||||
id_manager.optimize();
|
||||
updateBlocks();
|
||||
changeEntities();
|
||||
|
||||
updateEvents();
|
||||
bool has_work = true;
|
||||
while(has_work)
|
||||
{
|
||||
swapData();
|
||||
|
||||
has_work = false;
|
||||
id_manager.optimize();
|
||||
updateBlocks();
|
||||
removeEntities();
|
||||
has_work |= updateBlocks();
|
||||
has_work |= changeEntities();
|
||||
has_work |= removeEntities();
|
||||
|
||||
has_work |= updateEvents();
|
||||
}
|
||||
event_manager.clearEvents();
|
||||
}
|
||||
|
||||
|
|
@ -3445,10 +3475,48 @@ export struct EntityManager
|
|||
|
||||
struct ThreadData
|
||||
{
|
||||
Vector!EntityID entities_to_remove;
|
||||
//Vector!ubyte change_entities_list;
|
||||
SimpleVector change_entities_list;
|
||||
Vector!(EntitiesBlock*) blocks_to_update;
|
||||
ref Vector!EntityID entitesToRemove() @nogc nothrow
|
||||
{
|
||||
return entities_to_remove[data_index];
|
||||
}
|
||||
|
||||
ref SimpleVector changeEntitiesList() @nogc nothrow
|
||||
{
|
||||
return change_entities_list[data_index];
|
||||
}
|
||||
|
||||
ref Vector!(EntitiesBlock*) blockToUpdate() @nogc nothrow
|
||||
{
|
||||
return blocks_to_update[data_index];
|
||||
}
|
||||
|
||||
ref Vector!EntityID entitiesToRemovePrev() @nogc nothrow
|
||||
{
|
||||
return entities_to_remove[1 - data_index];
|
||||
}
|
||||
|
||||
ref SimpleVector changeEntitiesListPrev() @nogc nothrow
|
||||
{
|
||||
return change_entities_list[1 - data_index];
|
||||
}
|
||||
|
||||
ref Vector!(EntitiesBlock*) blockToUpdatePrev() @nogc nothrow
|
||||
{
|
||||
return blocks_to_update[1 - data_index];
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void swapData() @nogc nothrow
|
||||
{
|
||||
data_index = cast(ubyte)(1 - data_index);
|
||||
}
|
||||
|
||||
Vector!EntityID[2] entities_to_remove;
|
||||
SimpleVector[2] change_entities_list;
|
||||
Vector!(EntitiesBlock*)[2] blocks_to_update;
|
||||
|
||||
ubyte data_index = 0;
|
||||
}
|
||||
|
||||
export struct UpdatePass
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue