From 7656ad3d85624042885c0d27a8931aa7a947f183 Mon Sep 17 00:00:00 2001 From: David Saltares Date: Mon, 8 Feb 2016 22:18:25 +0000 Subject: [PATCH] Fixes FamilyManager not cleaning up properly after a listener throws --- CHANGELOG.md | 1 + .../badlogic/ashley/core/FamilyManager.java | 27 +++++++------- .../ashley/core/FamilyManagerTests.java | 36 +++++++++++++++++++ 3 files changed, 52 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0107a410..bdb49d64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * ** Bug fix**: `Engine` doesn't use `EntitySystem` `iterator()`. Issue #209. * ** Bug fix**: Fixes `Engine` left unusable, in the updating state, after an uncaught exception in a subsystem. Issue #210. +* ** Bug fix**: Fixes `FamilyManager` not cleaning up properly when a triggering a listener that throws. Issue #210. ### Ashley 1.7.1 diff --git a/ashley/src/com/badlogic/ashley/core/FamilyManager.java b/ashley/src/com/badlogic/ashley/core/FamilyManager.java index abf39fa0..7bda006e 100644 --- a/ashley/src/com/badlogic/ashley/core/FamilyManager.java +++ b/ashley/src/com/badlogic/ashley/core/FamilyManager.java @@ -112,20 +112,23 @@ public void updateFamilyMembership (Entity entity) { notifying = true; Object[] items = entityListeners.begin(); - for (int i = removeListenerBits.nextSetBit(0); i >= 0; i = removeListenerBits.nextSetBit(i + 1)) { - ((EntityListenerData)items[i]).listener.entityRemoved(entity); + try { + for (int i = removeListenerBits.nextSetBit(0); i >= 0; i = removeListenerBits.nextSetBit(i + 1)) { + ((EntityListenerData)items[i]).listener.entityRemoved(entity); + } + + for (int i = addListenerBits.nextSetBit(0); i >= 0; i = addListenerBits.nextSetBit(i + 1)) { + ((EntityListenerData)items[i]).listener.entityAdded(entity); + } } - - for (int i = addListenerBits.nextSetBit(0); i >= 0; i = addListenerBits.nextSetBit(i + 1)) { - ((EntityListenerData)items[i]).listener.entityAdded(entity); + finally { + addListenerBits.clear(); + removeListenerBits.clear(); + bitsPool.free(addListenerBits); + bitsPool.free(removeListenerBits); + entityListeners.end(); + notifying = false; } - - addListenerBits.clear(); - removeListenerBits.clear(); - bitsPool.free(addListenerBits); - bitsPool.free(removeListenerBits); - entityListeners.end(); - notifying = false; } private ImmutableArray registerFamily(Family family) { diff --git a/ashley/tests/com/badlogic/ashley/core/FamilyManagerTests.java b/ashley/tests/com/badlogic/ashley/core/FamilyManagerTests.java index dd9151a4..cf84e0f3 100644 --- a/ashley/tests/com/badlogic/ashley/core/FamilyManagerTests.java +++ b/ashley/tests/com/badlogic/ashley/core/FamilyManagerTests.java @@ -5,6 +5,7 @@ import com.badlogic.ashley.utils.ImmutableArray; import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.GdxRuntimeException; public class FamilyManagerTests { @@ -231,4 +232,39 @@ public void entitiesForFamilyWithRemovalAndFiltering () { assertEquals(2, entitiesWithComponentAOnly.size()); assertEquals(0, entitiesWithComponentB.size()); } + + @Test + public void entityListenerThrows() { + Array entities = new Array(); + ImmutableArray immutableEntities = new ImmutableArray(entities); + FamilyManager manager = new FamilyManager(immutableEntities); + + EntityListener listener = new EntityListener() { + @Override + public void entityAdded (Entity entity) { + throw new GdxRuntimeException("throwing"); + } + + @Override + public void entityRemoved (Entity entity) { + throw new GdxRuntimeException("throwing"); + } + }; + + manager.addEntityListener(Family.all().get(), 0, listener); + + Entity entity = new Entity(); + entities.add(entity); + + boolean thrown = false; + try { + manager.updateFamilyMembership(entity); + } + catch (Exception e) { + thrown = true; + } + + assertTrue(thrown); + assertFalse(manager.notifying()); + } }