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];
|
ThreadData* data = &threads[threadID];
|
||||||
uint num = cast(uint) del_ids.length;
|
uint num = cast(uint) del_ids.length;
|
||||||
data.change_entities_list.add(0);
|
data.changeEntitiesList.add(0);
|
||||||
data.change_entities_list.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]);
|
data.changeEntitiesList.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]);
|
||||||
data.change_entities_list.add((cast(ubyte*)&num)[0 .. uint.sizeof]);
|
data.changeEntitiesList.add((cast(ubyte*)&num)[0 .. uint.sizeof]);
|
||||||
data.change_entities_list.add((cast(ubyte*) del_ids.ptr)[0 .. num * 2]);
|
data.changeEntitiesList.add((cast(ubyte*) del_ids.ptr)[0 .. num * 2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void __removeComponents(EntityID entity_id, ushort[] del_ids)
|
private void __removeComponents(EntityID entity_id, ushort[] del_ids)
|
||||||
|
|
@ -2349,13 +2349,13 @@ export struct EntityManager
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadData* data = &threads[threadID];
|
ThreadData* data = &threads[threadID];
|
||||||
data.change_entities_list.add(cast(ubyte) 1u);
|
data.changeEntitiesList.add(cast(ubyte) 1u);
|
||||||
data.change_entities_list.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]);
|
data.changeEntitiesList.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]);
|
||||||
data.change_entities_list.add((cast(ubyte*)&num)[0 .. uint.sizeof]);
|
data.changeEntitiesList.add((cast(ubyte*)&num)[0 .. uint.sizeof]);
|
||||||
data.change_entities_list.add(cast(ubyte[]) new_ids);
|
data.changeEntitiesList.add(cast(ubyte[]) new_ids);
|
||||||
static foreach (i, comp; comps)
|
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);
|
//__addComponents(entity_id, new_ids, pointers);
|
||||||
|
|
@ -2416,7 +2416,7 @@ export struct EntityManager
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new_index == 1)
|
if (new_index == 1)
|
||||||
threads[threadID].blocks_to_update.add(new_block);
|
threads[threadID].blockToUpdate.add(new_block);
|
||||||
|
|
||||||
Entity* new_entity = cast(Entity*) start;
|
Entity* new_entity = cast(Entity*) start;
|
||||||
//add_mutex.lock_nothrow();
|
//add_mutex.lock_nothrow();
|
||||||
|
|
@ -2466,7 +2466,7 @@ export struct EntityManager
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index == 1)
|
if (index == 1)
|
||||||
threads[threadID].blocks_to_update.add(block);
|
threads[threadID].blockToUpdate.add(block);
|
||||||
|
|
||||||
Entity* entity = cast(Entity*) start;
|
Entity* entity = cast(Entity*) start;
|
||||||
//add_mutex.lock_nothrow();
|
//add_mutex.lock_nothrow();
|
||||||
|
|
@ -2557,7 +2557,7 @@ export struct EntityManager
|
||||||
*/
|
*/
|
||||||
export void removeEntity(EntityID id)
|
export void removeEntity(EntityID id)
|
||||||
{
|
{
|
||||||
threads[threadID].entities_to_remove.add(id);
|
threads[threadID].entitesToRemove.add(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void __removeEntity(EntityID id) nothrow @nogc
|
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)));
|
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 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];
|
void*[32] pointers; // = (cast(void**) alloca(num * (void*).sizeof))[0 .. num];
|
||||||
while (index < len)
|
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;
|
index += EntityID.sizeof;
|
||||||
uint num = *cast(uint*)&thread.change_entities_list[index];
|
uint num = *cast(uint*)&thread.changeEntitiesListPrev[index];
|
||||||
index += uint.sizeof;
|
index += uint.sizeof;
|
||||||
ushort[] ids; // = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num];
|
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;
|
index += ushort.sizeof * num;
|
||||||
__removeComponents(id, ids);
|
__removeComponents(id, ids);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
EntityID id = *cast(EntityID*)&thread.change_entities_list[index];
|
EntityID id = *cast(EntityID*)&thread.changeEntitiesListPrev[index];
|
||||||
index += EntityID.sizeof;
|
index += EntityID.sizeof;
|
||||||
uint num = *cast(uint*)&thread.change_entities_list[index];
|
uint num = *cast(uint*)&thread.changeEntitiesListPrev[index];
|
||||||
index += uint.sizeof;
|
index += uint.sizeof;
|
||||||
ushort[] ids; // = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num];
|
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;
|
index += ushort.sizeof * num;
|
||||||
//void*[] pointers = (cast(void**) alloca(num * (void*).sizeof))[0 .. num];
|
//void*[] pointers = (cast(void**) alloca(num * (void*).sizeof))[0 .. num];
|
||||||
foreach (i; 0 .. num)
|
foreach (i; 0 .. num)
|
||||||
{
|
{
|
||||||
pointers[i] = &thread.change_entities_list[index];
|
pointers[i] = &thread.changeEntitiesListPrev[index];
|
||||||
index += components[ids[i]].size;
|
index += components[ids[i]].size;
|
||||||
}
|
}
|
||||||
|
|
||||||
__addComponents(id, ids, pointers[0 .. num]);
|
__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
|
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);
|
(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;
|
EntityInfo* info = block.type_info;
|
||||||
ushort entities_count = block.entities_count;
|
ushort entities_count = block.entities_count;
|
||||||
|
|
@ -2786,30 +2794,35 @@ export struct EntityManager
|
||||||
{
|
{
|
||||||
callAddEntityListeners(info, block, entities_count, block.entities_count);
|
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);
|
__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;
|
bool has_work = false;
|
||||||
while (1)
|
// bool empty = true;
|
||||||
{
|
//while (1)
|
||||||
event_manager.swapCurrent();
|
//{
|
||||||
|
//event_manager.swapCurrent();
|
||||||
uint current_index;
|
uint current_index;
|
||||||
if (event_manager.current_index == 0)
|
if (event_manager.current_index == 0)
|
||||||
current_index = cast(uint) threads.length;
|
current_index = cast(uint) threads.length;
|
||||||
|
|
@ -2821,8 +2834,11 @@ export struct EntityManager
|
||||||
.. current_index + threads.length])
|
.. current_index + threads.length])
|
||||||
{
|
{
|
||||||
EventManager.EventBlock* block = first_block;
|
EventManager.EventBlock* block = first_block;
|
||||||
if (block)
|
if (block)has_work = true;
|
||||||
empty = false;
|
// {
|
||||||
|
// has_work = true;
|
||||||
|
// //empty = false;
|
||||||
|
// }
|
||||||
while (block)
|
while (block)
|
||||||
{
|
{
|
||||||
EventCallData call_data;
|
EventCallData call_data;
|
||||||
|
|
@ -2856,23 +2872,37 @@ export struct EntityManager
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (empty)
|
// if (empty)
|
||||||
break;
|
// break;
|
||||||
empty = true;
|
// empty = true;
|
||||||
|
//}
|
||||||
|
return has_work;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void swapData() nothrow @nogc
|
||||||
|
{
|
||||||
|
event_manager.swapCurrent();
|
||||||
|
foreach(ref ThreadData thread; threads)
|
||||||
|
{
|
||||||
|
thread.swapData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export void commit()
|
export void commit()
|
||||||
{
|
{
|
||||||
id_manager.optimize();
|
bool has_work = true;
|
||||||
updateBlocks();
|
while(has_work)
|
||||||
changeEntities();
|
{
|
||||||
|
swapData();
|
||||||
updateEvents();
|
|
||||||
|
|
||||||
|
has_work = false;
|
||||||
id_manager.optimize();
|
id_manager.optimize();
|
||||||
updateBlocks();
|
has_work |= updateBlocks();
|
||||||
removeEntities();
|
has_work |= changeEntities();
|
||||||
|
has_work |= removeEntities();
|
||||||
|
|
||||||
|
has_work |= updateEvents();
|
||||||
|
}
|
||||||
event_manager.clearEvents();
|
event_manager.clearEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3445,10 +3475,48 @@ export struct EntityManager
|
||||||
|
|
||||||
struct ThreadData
|
struct ThreadData
|
||||||
{
|
{
|
||||||
Vector!EntityID entities_to_remove;
|
ref Vector!EntityID entitesToRemove() @nogc nothrow
|
||||||
//Vector!ubyte change_entities_list;
|
{
|
||||||
SimpleVector change_entities_list;
|
return entities_to_remove[data_index];
|
||||||
Vector!(EntitiesBlock*) blocks_to_update;
|
}
|
||||||
|
|
||||||
|
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
|
export struct UpdatePass
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue