package com.badlogic.ashley.core; import com.badlogic.ashley.utils.ImmutableArray; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Bits; import com.badlogic.gdx.utils.ObjectMap; import com.badlogic.gdx.utils.Pool; import com.badlogic.gdx.utils.SnapshotArray; class FamilyManager { ImmutableArray<Entity> entities; private ObjectMap<Family, Array<Entity>> families = new ObjectMap<Family, Array<Entity>>(); private ObjectMap<Family, ImmutableArray<Entity>> immutableFamilies = new ObjectMap<Family, ImmutableArray<Entity>>(); private SnapshotArray<EntityListenerData> entityListeners = new SnapshotArray<EntityListenerData>(true, 16); private ObjectMap<Family, Bits> entityListenerMasks = new ObjectMap<Family, Bits>(); private BitsPool bitsPool = new BitsPool(); private boolean notifying = false; public FamilyManager(ImmutableArray<Entity> entities) { this.entities = entities; } public ImmutableArray<Entity> getEntitiesFor(Family family) { return registerFamily(family); } public boolean notifying() { return notifying; } public void addEntityListener (Family family, int priority, EntityListener listener) { registerFamily(family); int insertionIndex = 0; while (insertionIndex < entityListeners.size) { if (entityListeners.get(insertionIndex).priority <= priority) { insertionIndex++; } else { break; } } // Shift up bitmasks by one step for (Bits mask : entityListenerMasks.values()) { for (int k = mask.length(); k > insertionIndex; k--) { if (mask.get(k - 1)) { mask.set(k); } else { mask.clear(k); } } mask.clear(insertionIndex); } entityListenerMasks.get(family).set(insertionIndex); EntityListenerData entityListenerData = new EntityListenerData(); entityListenerData.listener = listener; entityListenerData.priority = priority; entityListeners.insert(insertionIndex, entityListenerData); } public void removeEntityListener (EntityListener listener) { for (int i = 0; i < entityListeners.size; i++) { EntityListenerData entityListenerData = entityListeners.get(i); if (entityListenerData.listener == listener) { // Shift down bitmasks by one step for (Bits mask : entityListenerMasks.values()) { for (int k = i, n = mask.length(); k < n; k++) { if (mask.get(k + 1)) { mask.set(k); } else { mask.clear(k); } } } entityListeners.removeIndex(i--); } } } public void updateFamilyMembership (Entity entity) { // Find families that the entity was added to/removed from, and fill // the bitmasks with corresponding listener bits. Bits addListenerBits = bitsPool.obtain(); Bits removeListenerBits = bitsPool.obtain(); for (Family family : entityListenerMasks.keys()) { final int familyIndex = family.getIndex(); final Bits entityFamilyBits = entity.getFamilyBits(); boolean belongsToFamily = entityFamilyBits.get(familyIndex); boolean matches = family.matches(entity) && !entity.removing; if (belongsToFamily != matches) { final Bits listenersMask = entityListenerMasks.get(family); final Array<Entity> familyEntities = families.get(family); if (matches) { addListenerBits.or(listenersMask); familyEntities.add(entity); entityFamilyBits.set(familyIndex); } else { removeListenerBits.or(listenersMask); familyEntities.removeValue(entity, true); entityFamilyBits.clear(familyIndex); } } } // Notify listeners; set bits match indices of listeners notifying = true; Object[] items = entityListeners.begin(); 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); } } finally { addListenerBits.clear(); removeListenerBits.clear(); bitsPool.free(addListenerBits); bitsPool.free(removeListenerBits); entityListeners.end(); notifying = false; } } private ImmutableArray<Entity> registerFamily(Family family) { ImmutableArray<Entity> entitiesInFamily = immutableFamilies.get(family); if (entitiesInFamily == null) { Array<Entity> familyEntities = new Array<Entity>(false, 16); entitiesInFamily = new ImmutableArray<Entity>(familyEntities); families.put(family, familyEntities); immutableFamilies.put(family, entitiesInFamily); entityListenerMasks.put(family, new Bits()); for (Entity entity : entities){ updateFamilyMembership(entity); } } return entitiesInFamily; } private static class EntityListenerData { public EntityListener listener; public int priority; } private static class BitsPool extends Pool<Bits> { @Override protected Bits newObject () { return new Bits(); } } }