From 16ca7b0e559a8753d1fada37fe74c4cd1a1b6e53 Mon Sep 17 00:00:00 2001 From: Eldalar Date: Sun, 7 Jul 2019 13:00:34 +0200 Subject: [PATCH] Fixes a bug when >1 entities are added and removed to/from 1 family The bug would occur under the following circumstances: * 2 Entities (1 and 2) belong to one family * Both of those entities had an optional component added to them in the same frame And it would lead to only one of the 2 entities to be updated This lead to the following situation: toRemove = { 1, 2 } entities = { 1(old), 2(old), 1(new), 2(new) } after one pass it would then lead to this situation: toRemove = { 2 } entities = { 2(new), 2(old), 1(new), 1(old) } And on the second pass to: toRemove = {} entities = { 1(new), 2(old), 2(new), 1(old) } Afterwards deleting the wrong entity with the ID 2. The fix buffers the swaps in a vector and executes them all at once, preventing the changes from interfering with the forward scan. Using reference instead of copy in iteration through moves --- src/engine/entity/include/halley/entity/family.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/engine/entity/include/halley/entity/family.h b/src/engine/entity/include/halley/entity/family.h index 6c60a3076..2db5a694e 100644 --- a/src/engine/entity/include/halley/entity/family.h +++ b/src/engine/entity/include/halley/entity/family.h @@ -169,6 +169,8 @@ namespace Halley { // Move all entities to be removed to the back of the vector { int n = int(entities.size()); + std::vector> moves; + moves.reserve( removeCount ); // Note: it's important to scan it forward. Scanning backwards would improve performance for short-lived entities, // but it causes an issue where an entity is removed and added to the same family in one frame. for (int i = 0; i < n; i++) { @@ -177,7 +179,7 @@ namespace Halley { if (iter != toRemove.end() && id == *iter) { toRemove.erase(iter); if (i != n - 1) { - std::swap(entities[i], entities[n - 1]); + moves.emplace_back( std::make_pair( i, n - 1 ) ); i--; } n--; @@ -186,6 +188,9 @@ namespace Halley { } } } + for (const std::pair& move : moves) { + std::swap(entities[move.first], entities[move.second]); + } Ensures(size_t(n) + removeCount == entities.size()); }