Commits

Michael Ludwig committed 8cf6a81

Finish implementing tests, and clean up controller API

  • Participants
  • Parent commits 13a96c8

Comments (0)

Files changed (39)

src/main/java/com/googlecode/entreri/AbstractController.java

-/*
- * Entreri, an entity-component framework in Java
- *
- * Copyright (c) 2011, Michael Ludwig
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- *     Redistributions of source code must retain the above copyright notice,
- *         this list of conditions and the following disclaimer.
- *     Redistributions in binary form must reproduce the above copyright notice,
- *         this list of conditions and the following disclaimer in the
- *         documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.googlecode.entreri;
-
-/**
- * AbstractController implements Controller by performing no action on each of
- * Controller's process or event hooks. Subclasses can override just the methods
- * they are interested in implementing.
- * 
- * @author Michael Ludwig
- */
-public abstract class AbstractController implements Controller {
-
-    @Override
-    public void preProcess(EntitySystem system, float dt) {
-        // do nothing in base class
-    }
-
-    @Override
-    public void process(EntitySystem system, float dt) {
-        // do nothing in base class
-    }
-
-    @Override
-    public void postProcess(EntitySystem system, float dt) {
-        // do nothing in base class
-    }
-
-    @Override
-    public void addedToSystem(EntitySystem system) {
-        // do nothing in base class
-    }
-
-    @Override
-    public void removedFromSystem(EntitySystem system) {
-        // do nothing in base class
-    }
-
-    @Override
-    public void onEntityAdd(Entity e) {
-        // do nothing in base class
-    }
-
-    @Override
-    public void onEntityRemove(Entity e) {
-        // do nothing in base class
-    }
-
-    @Override
-    public void onComponentAdd(ComponentData c) {
-        // do nothing in base class
-    }
-
-    @Override
-    public void onComponentRemove(ComponentData c) {
-        // do nothing in base class
-    }
-}

src/main/java/com/googlecode/entreri/ComponentData.java

     public final boolean isValid() {
         // we have to check the index of the ComponentData because the ComponentRepository
         // does not make sure the data's indices stay within bounds of the repository arrays
-        return index != 0 && index < owner.getSizeEstimate() && owner.getId(index) == id;
+        if (index != 0 && index < owner.getMaxComponentIndex()) {
+            return owner.getId(index) == id && owner.getEntityIndex(index) != 0;
+        }
+        return false;
     }
 
     /**
      *             entity system
      */
     public final boolean set(Component<T> component) {
-        // we check repository since it is guaranteed type safe
-        if (component.getRepository() == owner)
-            throw new IllegalArgumentException("Component not created by expected EntitySystem");
-        
-        return setFast(component.index);
+        if (component == null) {
+            return setFast(0);
+        } else {
+            // we check repository since it is guaranteed type safe
+            if (component.getRepository() != owner)
+                throw new IllegalArgumentException("Component not created by expected EntitySystem");
+            
+            return setFast(component.index);
+        }
     }
 
     /**

src/main/java/com/googlecode/entreri/ComponentIterator.java

             // putting one data into the required array
             required = Arrays.copyOf(required, required.length + 1);
 
-            if (data.owner.getSizeEstimate() < primary.owner.getSizeEstimate()) {
+            if (data.owner.getMaxComponentIndex() < primary.owner.getMaxComponentIndex()) {
                 // new primary
                 required[required.length - 1] = primary;
                 primary = data;
         boolean found;
         int entity;
         int component;
-        int count = primary.owner.getSizeEstimate();
-        while(index < count) {
+        int count = primary.owner.getMaxComponentIndex();
+        while(index < count - 1) {
+            index++; // always increment one
+
             found = true;
             entity = primary.owner.getEntityIndex(index);
             if (entity != 0) {
                     return true;
                 }
             }
-            
-            index++;
         }
         
         return false;

src/main/java/com/googlecode/entreri/ComponentRepository.java

     public TypeId<T> getTypeId() {
         return type;
     }
-    
+
     /**
-     * @return An estimate on the number of components in the index, will not be
-     *         less than the true size
+     * @return The upper bound (exclusive) for component index values
      */
-    public int getSizeEstimate() {
-        return componentInsert + 1;
+    public int getMaxComponentIndex() {
+        return componentInsert;
     }
     
     /**
      *         if the component is not attached
      */
     public int getEntityIndex(int componentIndex) {
+        if (componentIndex >= componentIndexToEntityIndex.length) {
+            System.out.println("problem!");
+        }
         return componentIndexToEntityIndex[componentIndex];
     }
 
     public Component<T> addComponent(int entityIndex, Component<T> fromTemplate) {
         if (fromTemplate.getEntitySystem() != getEntitySystem())
             throw new IllegalArgumentException("Component not owned by expected EntitySystem");
-        if (fromTemplate.getTypeId().equals(type))
+        if (!fromTemplate.getTypeId().equals(type))
             throw new IllegalArgumentException("Component not of expected type, expected: " + type + ", but was: " + type);
         if (!fromTemplate.isLive())
             throw new IllegalStateException("Template component is not live");
         componentIndexToEntityIndex = newComponentRepository;
         
         // Possibly compact the component data
-        if (componentInsert < .6f * components.length) {
+        /*if (componentInsert < .6f * components.length) {
             int newSize = (int) (1.2f * componentInsert) + 1;
             components = Arrays.copyOf(components, newSize);
             componentIndexToEntityIndex = Arrays.copyOf(componentIndexToEntityIndex, newSize);
             resizePropertyStores(declaredProperties, newSize);
             resizePropertyStores(decoratedProperties, newSize);
-        }
+        }*/
         
         // Repair entityIndexToComponentRepository - and possible shrink the index
         // based on the number of packed entities
-        if (numEntities < .6f * entityIndexToComponentRepository.length)
+        /*if (numEntities < .6f * entityIndexToComponentRepository.length)
             entityIndexToComponentRepository = new int[(int) (1.2f * numEntities) + 1];
         else
-            Arrays.fill(entityIndexToComponentRepository, 0);
+            Arrays.fill(entityIndexToComponentRepository, 0);*/
         
         for (int i = 1; i < componentInsert; i++)
             entityIndexToComponentRepository[componentIndexToEntityIndex[i]] = i;
         final PropertyFactory<P> creator;
         IndexedDataStore swap; // may be null
         
-        
         public PropertyStore(PropertyFactory<P> creator, String key) {
             this.creator = creator;
             this.key = key;

src/main/java/com/googlecode/entreri/Controller.java

      * @param system The entity system to process
      * @param dt The elapsed time since the last processing
      */
-    public void preProcess(EntitySystem system, float dt);
+    public void preProcess(float dt);
 
     /**
      * Invoke controller specific operations to process the EntitySystem. All
      * @param system The entity system to process
      * @param dt The elapsed time since the last processing
      */
-    public void process(EntitySystem system, float dt);
+    public void process(float dt);
 
     /**
      * Invoked at the end of a processing phase after all controllers in a
      * @param system The entity system to process
      * @param dt The elapsed time since the last processing
      */
-    public void postProcess(EntitySystem system, float dt);
+    public void postProcess(float dt);
     
-    public void addedToSystem(EntitySystem system);
+    public void init(EntitySystem system);
     
-    public void removedFromSystem(EntitySystem system);
+    public void destroy();
     
     public void onEntityAdd(Entity e);
     
     
     public void onComponentRemove(Component<?> c);
     
-    // FIXME: TODO:
-    // Final solution: This is an interface, with a DefaultController or abstract, etc.
-    // that implements all of the methods as no-ops, except for init and destroy
-    // Part of the API is getEntitySystem(), which is used to validate by the controller-manager.
-    // rename addedToSystem, etc. to init(System) and destroy().
-    // I will keep the phases, since I can imagine a health controller that subtracts
-    // health during processing, and on post process removes everything that is dead
-    // TODO: I think I will add some Scheduler interface or type that is used to
-    // control the ordering and execution of controllers during a process request,
-    // theoretically this could do MTing, or dependency ordering. ATM it will do
-    // by-add ordering.
-
+    public EntitySystem getEntitySystem();
 }

src/main/java/com/googlecode/entreri/ControllerManager.java

         controllers.add(controller);
         
         if (!removed)
-            controller.addedToSystem(system);
+            controller.init(system);
     }
 
     /**
             throw new NullPointerException("Controller cannot be null");
         boolean removed = controllers.remove(controller);
         if (removed)
-            controller.removedFromSystem(system);
+            controller.destroy();
     }
     
     /**
     
     private void firePreProcess(float dt) {
         for (int i = 0; i < controllers.size(); i++)
-            controllers.get(i).preProcess(system, dt);
+            controllers.get(i).preProcess(dt);
     }
     
     private void fireProcess(float dt) {
         for (int i = 0; i < controllers.size(); i++)
-            controllers.get(i).process(system, dt);
+            controllers.get(i).process(dt);
     }
     
     private void firePostProcess(float dt) {
         for (int i = 0; i < controllers.size(); i++)
-            controllers.get(i).postProcess(system, dt);
+            controllers.get(i).postProcess(dt);
     }
 }

src/main/java/com/googlecode/entreri/EntitySystem.java

  * 
  * @author Michael Ludwig
  */
-public final class EntitySystem {
+public final class EntitySystem implements Iterable<Entity> {
     private ComponentRepository<?>[] componentIndices;
     
     private Entity[] entities;
         return new EntityIterator();
     }
 
-    /*
-     * Internal method that prepares the bulk iterators by finding the type
-     * with the smallest number of entities and using it as the primary iterator.
-     */
-//    @SuppressWarnings({ "rawtypes", "unchecked" })
-//    private Iterator<IndexedComponentMap> bulkIterator(boolean fast, TypeId<?>... ids) {
-//        if (ids == null)
-//            throw new NullPointerException("TypedIds cannot be null");
-//        if (ids.length < 1)
-//            throw new IllegalArgumentException("Must have at least one TypeId");
-//        
-//        TypeId[] rawIds = ids;
-//        
-//        int minIndex = -1;
-//        int minSize = Integer.MAX_VALUE;
-//        
-//        ComponentRepository index;
-//        ComponentRepository[] rawIndices = new ComponentRepository[ids.length];
-//        
-//        for (int i = 0; i < ids.length; i++) {
-//            if (ids[i] == null)
-//                throw new NullPointerException("TypeId in id set cannot be null");
-//            
-//            index = getIndex(rawIds[i]);
-//            if (index.getSizeEstimate() < minSize) {
-//                minIndex = i;
-//                minSize = index.getSizeEstimate();
-//            }
-//            
-//            rawIndices[i] = index;
-//        }
-//
-//        if (fast)
-//            return new FastBulkComponentIterator(rawIndices, minIndex);
-//        else
-//            return new BulkComponentIterator(rawIndices, minIndex);
-//    }
-
     /**
      * <p>
      * Compact the entity and component data so that iteration is more
         ComponentRepository index = getIndex(typeId);
         index.addComponent(entityIndex, c);
     }
-    
-//    @SuppressWarnings({ "unchecked", "rawtypes" })
-//    private class BulkComponentIterator implements Iterator<IndexedComponentMap> {
-//        private final ComponentRepository[] indices;
-//        private final int minIndex;
-//        private final Iterator<ComponentData> minComponentIterator;
-//        private final ComponentData[] result;
-//        
-//        private final IndexedComponentMap map;
-//        
-//        private boolean hasAdvanced;
-//        private boolean resultValid;
-//        
-//        public BulkComponentIterator(ComponentRepository[] indices, int minIndex) {
-//            this.indices = indices;
-//            this.minIndex = minIndex;
-//            
-//            minComponentIterator = indices[minIndex].iterator();
-//            result = new ComponentData[indices.length];
-//            map = new IndexedComponentMap(result);
-//            
-//            hasAdvanced = false;
-//            resultValid = false;
-//        }
-//        
-//        @Override
-//        public boolean hasNext() {
-//            if (!hasAdvanced)
-//                advance();
-//            return resultValid;
-//        }
-//
-//        @Override
-//        public IndexedComponentMap next() {
-//            if (!hasNext())
-//                throw new NoSuchElementException();
-//            hasAdvanced = false;
-//            return map;
-//        }
-//
-//        @Override
-//        public void remove() {
-//            throw new UnsupportedOperationException();
-//        }
-//        
-//        private void advance() {
-//            ComponentData c;
-//            boolean foundAll;
-//            int entityIndex;
-//            
-//            hasAdvanced = true;
-//            resultValid = false;
-//            while(minComponentIterator.hasNext()) {
-//                foundAll = true;
-//                c = minComponentIterator.next();
-//                entityIndex = indices[minIndex].getEntityIndex(c.index);
-//                
-//                result[minIndex] = c;
-//                
-//                // now look for every other component
-//                for (int i = 0; i < result.length; i++) {
-//                    if (i == minIndex)
-//                        continue;
-//                    
-//                    c = indices[i].getComponent(entityIndex);
-//                    if (c == null) {
-//                        foundAll = false;
-//                        break;
-//                    } else {
-//                        result[i] = c;
-//                    }
-//                }
-//                
-//                if (foundAll) {
-//                    resultValid = true;
-//                    break;
-//                }
-//            }
-//        }
-//    }
-//    
-//    @SuppressWarnings({ "unchecked", "rawtypes" })
-//    private class FastBulkComponentIterator implements Iterator<IndexedComponentMap> {
-//        private final ComponentRepository[] indices;
-//        private final int minIndex;
-//        private final Iterator<ComponentData> minComponentIterator;
-//        private final ComponentData[] result;
-//        private final IndexedComponentMap map;
-//        
-//        private boolean hasAdvanced;
-//        private boolean resultValid;
-//        
-//        public FastBulkComponentIterator(ComponentRepository[] indices, int minIndex) {
-//            this.indices = indices;
-//            this.minIndex = minIndex;
-//            
-//            minComponentIterator = indices[minIndex].fastIterator();
-//            result = new ComponentData[indices.length];
-//            map = new IndexedComponentMap(result);
-//            
-//            hasAdvanced = false;
-//            resultValid = false;
-//            
-//            // now create local instances for the components
-//            for (int i = 0; i < indices.length; i++) {
-//                if (i == minIndex)
-//                    continue;
-//                result[i] = indices[i].newInstance(0);
-//            }
-//        }
-//        
-//        @Override
-//        public boolean hasNext() {
-//            if (!hasAdvanced)
-//                advance();
-//            return resultValid;
-//        }
-//
-//        @Override
-//        public IndexedComponentMap next() {
-//            if (!hasNext())
-//                throw new NoSuchElementException();
-//            hasAdvanced = false;
-//            return map;
-//        }
-//
-//        @Override
-//        public void remove() {
-//            throw new UnsupportedOperationException();
-//        }
-//        
-//        private void advance() {
-//            ComponentData c;
-//            boolean foundAll;
-//            int entityIndex;
-//            int ci;
-//            
-//            hasAdvanced = true;
-//            resultValid = false;
-//            while(minComponentIterator.hasNext()) {
-//                foundAll = true;
-//                c = minComponentIterator.next();
-//                entityIndex = indices[minIndex].getEntityIndex(c.index);
-//                
-//                // we use the fastIterator()'s returned instance for the min component,
-//                // so we have to assign it here
-//                result[minIndex] = c;
-//                
-//                // now look for every other component
-//                for (int i = 0; i < result.length; i++) {
-//                    if (i == minIndex)
-//                        continue;
-//                    
-//                    ci = indices[i].getComponentRepository(entityIndex);
-//                    if (ci == 0) {
-//                        foundAll = false;
-//                        break;
-//                    } else {
-//                        result[i].index = ci;
-//                    }
-//                }
-//                
-//                if (foundAll) {
-//                    resultValid = true;
-//                    break;
-//                }
-//            }
-//        }
-//    }
-    
+
     private class ComponentRepositoryIterator implements Iterator<ComponentRepository<?>> {
         private int index;
         private boolean advanced;

src/main/java/com/googlecode/entreri/SimpleController.java

+/*
+ * Entreri, an entity-component framework in Java
+ *
+ * Copyright (c) 2011, Michael Ludwig
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ *     Redistributions of source code must retain the above copyright notice,
+ *         this list of conditions and the following disclaimer.
+ *     Redistributions in binary form must reproduce the above copyright notice,
+ *         this list of conditions and the following disclaimer in the
+ *         documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.googlecode.entreri;
+
+/**
+ * SimpleController implements Controller by performing no action on each of
+ * Controller's process or event hooks. Subclasses can override just the methods
+ * they are interested in implementing.
+ * 
+ * @author Michael Ludwig
+ */
+public class SimpleController implements Controller {
+    private EntitySystem system;
+    
+    @Override
+    public void preProcess(float dt) {
+        // do nothing in base class
+    }
+
+    @Override
+    public void process(float dt) {
+        // do nothing in base class
+    }
+
+    @Override
+    public void postProcess(float dt) {
+        // do nothing in base class
+    }
+
+    @Override
+    public void init(EntitySystem system) {
+        if (this.system != null)
+            throw new IllegalStateException("Controller is already used in another EntitySystem");
+        this.system = system;
+    }
+    
+    @Override
+    public void destroy() {
+        system = null; 
+    }
+
+    @Override
+    public void onEntityAdd(Entity e) {
+        // do nothing in base class
+    }
+
+    @Override
+    public void onEntityRemove(Entity e) {
+        // do nothing in base class
+    }
+
+    @Override
+    public void onComponentAdd(Component<?> c) {
+        // do nothing in base class
+    }
+
+    @Override
+    public void onComponentRemove(Component<?> c) {
+        // do nothing in base class
+    }
+
+    @Override
+    public EntitySystem getEntitySystem() {
+        return system;
+    }
+}

src/main/java/com/googlecode/entreri/TypeId.java

  * @author Michael Ludwig
  * @param <T> The identified type
  */
-// FIXME: I need an API for assigning the ComponentDataFactory to use
-// Is this a per type basis? Can I override it? Or should it only be possible
-// via an annotation configuration?
-// - I think that is probably best since we need this to be a consistent global
-//   state
-// - That being said, it's probably possible to declare a customizable default type
-//   that could be used instead of the reflection impl.
-// - Perhaps the factory can be specified before the TypeId is loaded?
-
-// What is the downside to allowing it to change in the future?
-//  - technically different property factories and properties,
-//    it wouldn't work on another system.
-// - However, we could say that they can be configured to the scope of a system,
-//   since we're already locking a CD to a system.
-//   Then it can fail if it's already been coerced into using a different factory.
-// - This makes me think that the system should be have newInstance(TypeId) instead
-//   of TypeId.newInstance(system).
-//   - This makes for a better design since it re-inforces the ownership
 public class TypeId<T extends ComponentData<T>> {
     // Use a ConcurrentHashMap to perform reads. It is still synchronized completely to do
     // an insert to make sure a type doesn't try to use two different id values.

src/main/java/com/googlecode/entreri/property/BooleanProperty.java

      *             would access illegal indices
      */
     public void set(boolean val, int componentIndex, int offset) {
-        store.array[componentIndex * store.elementSize] = val;
+        store.array[componentIndex * store.elementSize + offset] = val;
     }
     
     @Override

src/main/java/com/googlecode/entreri/property/ByteProperty.java

      *             would access illegal indices
      */
     public void set(byte val, int componentIndex, int offset) {
-        store.array[componentIndex * store.elementSize] = val;
+        store.array[componentIndex * store.elementSize + offset] = val;
     }
     
     @Override

src/main/java/com/googlecode/entreri/property/CharProperty.java

      *             would access illegal indices
      */
     public void set(char val, int componentIndex, int offset) {
-        store.array[componentIndex * store.elementSize] = val;
+        store.array[componentIndex * store.elementSize + offset] = val;
     }
     
     @Override

src/main/java/com/googlecode/entreri/property/DoubleProperty.java

      *             would access illegal indices
      */
     public void set(double val, int componentIndex, int offset) {
-        store.array[componentIndex * store.elementSize] = val;
+        store.array[componentIndex * store.elementSize + offset] = val;
     }
     
     @Override

src/main/java/com/googlecode/entreri/property/FloatProperty.java

      *             would access illegal indices
      */
     public void set(float val, int componentIndex, int offset) {
-        store.array[componentIndex * store.elementSize] = val;
+        store.array[componentIndex * store.elementSize + offset] = val;
     }
     
     @Override

src/main/java/com/googlecode/entreri/property/IntProperty.java

      *             would access illegal indices
      */
     public void set(int val, int componentIndex, int offset) {
-        store.array[componentIndex * store.elementSize] = val;
+        store.array[componentIndex * store.elementSize + offset] = val;
     }
     
     @Override

src/main/java/com/googlecode/entreri/property/LongProperty.java

      *             would access illegal indices
      */
     public void set(long val, int componentIndex, int offset) {
-        store.array[componentIndex * store.elementSize] = val;
+        store.array[componentIndex * store.elementSize + offset] = val;
     }
     
     @Override

src/main/java/com/googlecode/entreri/property/ObjectProperty.java

      *             would access illegal indices
      */
     public void set(T val, int componentIndex, int offset) {
-        store.array[componentIndex * store.elementSize] = val;
+        store.array[componentIndex * store.elementSize + offset] = val;
     }
     
     @Override

src/main/java/com/googlecode/entreri/property/ReflectionComponentDataFactory.java

         // validate field now
         if (f == null)
             throw new IllegalArgumentException("Key is not in Map returned by getPropertyFactories(): " + key);
-        if (f.getType().isAssignableFrom(property.getClass()))
+        if (!f.getType().isAssignableFrom(property.getClass()))
             throw new IllegalArgumentException("Property was not created by correct PropertyFactory for key: " + key);
         
         try {
         Factory factoryAnnot = field.getAnnotation(Factory.class);
         if (factoryAnnot != null) {
             // verify that the PropertyFactory actually creates the right type
-            try {
-                Method create = factoryAnnot.value().getMethod("create");
-                if (!type.isAssignableFrom(create.getReturnType()))
-                    throw new IllegalComponentDefinitionException(forCType, "@Factory for " + factoryAnnot.value() + " creates incorrect Property type for property type: " + type);
-            } catch (Exception e) {
-                // should not happen
-                throw new RuntimeException("Unable to inspect PropertyFactory create() method", e);
-            }
-            
+                try {
+                    Method create = factoryAnnot.value().getMethod("create");
+                    if (!type.isAssignableFrom(create.getReturnType()))
+                        throw new IllegalComponentDefinitionException(forCType, "@Factory for " + factoryAnnot.value() + " creates incorrect Property type for property type: " + type);
+                } catch (SecurityException e) {
+                    // should not happen
+                    throw new RuntimeException("Unable to inspect factory's create method", e);
+                } catch (NoSuchMethodException e) {
+                    // should not happen
+                    throw new RuntimeException("Unable to inspect factory's create method", e);
+                }
+                
             try {
                 return factoryAnnot.value().newInstance();
             } catch (Exception e) {

src/main/java/com/googlecode/entreri/property/ShortProperty.java

      *             would access illegal indices
      */
     public void set(short val, int componentIndex, int offset) {
-        store.array[componentIndex * store.elementSize] = val;
+        store.array[componentIndex * store.elementSize + offset] = val;
     }
     
     @Override

src/test/java/com/googlecode/entreri/ComponentDataTest.java

+package com.googlecode.entreri;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+
+import com.googlecode.entreri.component.IntComponent;
+
+public class ComponentDataTest {
+    @Test
+    public void testInvalidComponentRemove() {
+        EntitySystem system = new EntitySystem();
+        Entity e = system.addEntity();
+        
+        Component<IntComponent> c = e.add(TypeId.get(IntComponent.class));
+        IntComponent cd = c.getData();
+        
+        Assert.assertTrue(cd.isValid()); // sanity check
+        e.remove(TypeId.get(IntComponent.class));
+        Assert.assertFalse(cd.isValid());
+    }
+    
+    @Test
+    public void testInvalidEntityRemove() {
+        EntitySystem system = new EntitySystem();
+        Entity e = system.addEntity();
+        
+        Component<IntComponent> c = e.add(TypeId.get(IntComponent.class));
+        IntComponent cd = c.getData();
+        
+        Assert.assertTrue(cd.isValid()); // sanity check
+        system.removeEntity(e);
+        Assert.assertFalse(cd.isValid());
+    }
+    
+    @Test
+    public void testInvalidCompact() {
+        EntitySystem system = new EntitySystem();
+        Entity e1 = system.addEntity();
+        Entity e2 = system.addEntity();
+        Entity e3 = system.addEntity();
+        
+        e1.add(TypeId.get(IntComponent.class)); // removed
+        e2.add(TypeId.get(IntComponent.class)); // will shift over 
+        e3.add(TypeId.get(IntComponent.class)); // will shift over 
+        IntComponent cd = e2.get(TypeId.get(IntComponent.class)).getData();
+        
+        Assert.assertTrue(cd.isValid()); // sanity check
+        
+        e1.remove(TypeId.get(IntComponent.class));
+        system.compact(); // since e1's component was moved, this shifts e2
+        
+        Assert.assertFalse(cd.isValid());
+    }
+    
+    @Test
+    public void testIsValid() {
+        EntitySystem system = new EntitySystem();
+        Entity e = system.addEntity();
+        
+        Component<IntComponent> c = e.add(TypeId.get(IntComponent.class));
+        IntComponent cd = c.getData();
+        
+        Assert.assertTrue(cd.isValid()); // sanity check
+    }
+    
+    @Test
+    public void testIsValidNoopCompact() {
+        EntitySystem system = new EntitySystem();
+        Entity e1 = system.addEntity();
+        Entity e2 = system.addEntity();
+        
+        e1.add(TypeId.get(IntComponent.class));
+        e2.add(TypeId.get(IntComponent.class));
+        IntComponent cd = e2.get(TypeId.get(IntComponent.class)).getData();
+        
+        Assert.assertTrue(cd.isValid()); // sanity check
+        system.compact(); // no changes
+        Assert.assertTrue(cd.isValid());
+    }
+    
+    @Test
+    public void testSetValid() {
+        EntitySystem system = new EntitySystem();
+        Entity e = system.addEntity();
+        
+        Component<IntComponent> c = e.add(TypeId.get(IntComponent.class)); 
+        
+        IntComponent cd = system.createDataInstance(TypeId.get(IntComponent.class));
+        Assert.assertFalse(cd.isValid());
+        Assert.assertTrue(cd.set(c));
+        Assert.assertTrue(cd.isValid());
+    }
+    
+    @Test
+    public void testSetInvalid() {
+        EntitySystem system = new EntitySystem();
+        Entity e = system.addEntity();
+        
+        Component<IntComponent> c = e.add(TypeId.get(IntComponent.class));
+        IntComponent cd = system.createDataInstance(TypeId.get(IntComponent.class));
+        
+        e.remove(TypeId.get(IntComponent.class));
+        
+        Assert.assertFalse(cd.set(c));
+        Assert.assertFalse(cd.isValid());
+        Assert.assertFalse(cd.set(null));
+        Assert.assertFalse(cd.isValid());
+        
+        cd.set(e.add(TypeId.get(IntComponent.class)));
+        Assert.assertTrue(cd.isValid());
+    }
+}

src/test/java/com/googlecode/entreri/ComponentRepositoryTest.java

+package com.googlecode.entreri;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.googlecode.entreri.component.IntComponent;
+import com.googlecode.entreri.component.MultiPropertyComponent;
+import com.googlecode.entreri.property.FloatProperty;
+import com.googlecode.entreri.property.FloatPropertyFactory;
+
+public class ComponentRepositoryTest {
+    @Test
+    public void testFactorySetValue() {
+        EntitySystem system = new EntitySystem();
+        MultiPropertyComponent c = system.addEntity().add(TypeId.get(MultiPropertyComponent.class)).getData();
+        Assert.assertEquals(FloatPropertyFactory.DEFAULT, c.getFactoryFloat(), .0001f);
+    }
+    
+    @Test
+    public void testDecorateProperty() {
+        EntitySystem system = new EntitySystem();
+        Entity e = system.addEntity();
+        IntComponent c = e.add(TypeId.get(IntComponent.class)).getData();
+        
+        FloatProperty decorated = system.decorate(TypeId.get(IntComponent.class), new FloatPropertyFactory());
+        decorated.getIndexedData()[c.getIndex()] = 1f;
+        
+        int count = 0;
+        for (Entity entity: system) {
+            Assert.assertTrue(entity.get(c));
+            count++;
+            
+            Assert.assertEquals(1f, decorated.getIndexedData()[c.getIndex()], .0001f);
+        }
+        Assert.assertEquals(1, count);
+    }
+    
+    @Test
+    public void testDecoratePropertyAddComponent() {
+        EntitySystem system = new EntitySystem();
+        Entity e = system.addEntity();
+        IntComponent c = e.add(TypeId.get(IntComponent.class)).getData();
+        
+        FloatProperty decorated = system.decorate(TypeId.get(IntComponent.class), new FloatPropertyFactory());
+        decorated.getIndexedData()[c.getIndex()] = 1f;
+        
+        Entity e2 = system.addEntity();
+        IntComponent c2 = e2.add(TypeId.get(IntComponent.class)).getData();
+        decorated.getIndexedData()[c2.getIndex()] = 2f;
+        
+        int count = 0;
+        for (Entity entity: system) {
+            IntComponent c3 = entity.get(TypeId.get(IntComponent.class)).getData();
+            count++;
+            
+            if (c3.getIndex() == c.getIndex())
+                Assert.assertEquals(1f, decorated.getIndexedData()[c3.getIndex()], .0001f);
+            else
+                Assert.assertEquals(2f, decorated.getIndexedData()[c3.getIndex()], .0001f);
+        }
+        Assert.assertEquals(2, count);
+    }
+    
+    @Test
+    public void testUndecorateValidProperty() {
+        EntitySystem system = new EntitySystem();
+        
+        FloatProperty decorated = system.decorate(TypeId.get(IntComponent.class), new FloatPropertyFactory());
+        system.undecorate(TypeId.get(IntComponent.class), decorated);
+    }
+    
+    @Test
+    public void testUndecorateInvalidProperty() {
+        FloatProperty prop = new FloatProperty(2);
+        EntitySystem system = new EntitySystem();
+        system.undecorate(TypeId.get(IntComponent.class), prop);
+        // should not fail
+    }
+}

src/test/java/com/googlecode/entreri/ComponentTest.java

-/*
- * Entreri, an entity-component framework in Java
- *
- * Copyright (c) 2011, Michael Ludwig
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- *     Redistributions of source code must retain the above copyright notice,
- *         this list of conditions and the following disclaimer.
- *     Redistributions in binary form must reproduce the above copyright notice,
- *         this list of conditions and the following disclaimer in the
- *         documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.googlecode.entreri;
-
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-import com.googlecode.entreri.component.BadConstructorComponent;
-import com.googlecode.entreri.component.BadParametersComponent;
-import com.googlecode.entreri.component.ExtraFieldComponent;
-import com.googlecode.entreri.component.FloatComponent;
-import com.googlecode.entreri.component.IntComponent;
-import com.googlecode.entreri.component.InvalidHierarchyComponent;
-import com.googlecode.entreri.component.MultiPropertyComponent;
-import com.googlecode.entreri.component.ObjectComponent;
-import com.googlecode.entreri.component.PublicConstructorComponent;
-import com.googlecode.entreri.component.PublicPropertyComponent;
-import com.googlecode.entreri.component.UnmanagedFieldComponent;
-import com.googlecode.entreri.property.FloatProperty;
-import com.googlecode.entreri.property.FloatPropertyFactory;
-import com.googlecode.entreri.property.MultiParameterProperty;
-import com.googlecode.entreri.property.NoParameterProperty;
-import com.googlecode.entreri.property.Property;
-import com.googlecode.entreri.property.PropertyFactory;
-import com.googlecode.entreri.property.ReflectionComponentDataFactory;
-
-public class ComponentTest {
-    @Test
-    public void testGetTypedId() {
-        doGetTypedIdTest(FloatComponent.class);
-        doGetTypedIdTest(IntComponent.class);
-        doGetTypedIdTest(ObjectComponent.class);
-        doGetTypedIdTest(MultiPropertyComponent.class);
-        doGetTypedIdTest(UnmanagedFieldComponent.class);
-    }
-    
-    private void doGetTypedIdTest(Class<? extends ComponentData> type) {
-        ComponentData.getTypedId(type);
-    }
-    
-    @Test
-    public void testInvalidComponentDefinition() {
-        doInvalidComponentDefinitionTest(BadConstructorComponent.class);
-        doInvalidComponentDefinitionTest(BadParametersComponent.class);
-        doInvalidComponentDefinitionTest(ExtraFieldComponent.class);
-        doInvalidComponentDefinitionTest(InvalidHierarchyComponent.class);
-        doInvalidComponentDefinitionTest(PublicConstructorComponent.class);
-        doInvalidComponentDefinitionTest(PublicPropertyComponent.class);
-    }
-    
-    private void doInvalidComponentDefinitionTest(Class<? extends ComponentData> type) {
-        try {
-            ComponentData.getTypedId(type);
-            Assert.fail("Expected IllegalComponentDefinitionException");
-        } catch(IllegalComponentDefinitionException e) {
-            // expected
-        }
-    }
-    
-    @Test
-    public void testFactorySetValue() {
-        EntitySystem system = new EntitySystem();
-        MultiPropertyComponent c = system.addEntity().add(ComponentData.getTypedId(MultiPropertyComponent.class));
-        Assert.assertEquals(FloatPropertyFactory.DEFAULT, c.getFactoryFloat(), .0001f);
-    }
-    
-    @Test
-    public void testPropertyLookup() {
-        ReflectionComponentDataFactory<MultiPropertyComponent> builder = ComponentData.getBuilder(ComponentData.getTypedId(MultiPropertyComponent.class));
-        Collection<Property> props = new HashSet<Property>();
-        for (PropertyFactory<?> factory: builder.getPropertyFactories().values()) {
-            props.add(factory.create());
-        }
-        
-        Set<Class<? extends Property>> propTypeSet = new HashSet<Class<? extends Property>>();
-        for (Property p: props) {
-            propTypeSet.add(p.getClass());
-        }
-        
-        Assert.assertEquals(3, propTypeSet.size());
-        Assert.assertTrue(propTypeSet.contains(MultiParameterProperty.class));
-        Assert.assertTrue(propTypeSet.contains(NoParameterProperty.class));
-        Assert.assertTrue(propTypeSet.contains(FloatProperty.class));
-    }
-    
-    @Test
-    public void testUnmanagedField() {
-        TypeId<UnmanagedFieldComponent> id = ComponentData.getTypedId(UnmanagedFieldComponent.class);
-        
-        EntitySystem system = new EntitySystem();
-        for (int i = 0; i < 4; i++) {
-            system.addEntity().add(id).setFloat(i);
-        }
-        
-        int i = 0;
-        Iterator<UnmanagedFieldComponent> it = system.iterator(id);
-        while(it.hasNext()) {
-            float f = it.next().getFloat();
-            Assert.assertEquals(i, f, .0001f);
-            i++;
-        }
-        
-        it = system.fastIterator(id);
-        while(it.hasNext()) {
-            float f = it.next().getFloat();
-            Assert.assertEquals(0, f, .0001f);
-        }
-    }
-    
-    @Test
-    public void testDecorateProperty() {
-        EntitySystem system = new EntitySystem();
-        Entity e = system.addEntity();
-        IntComponent c = e.add(ComponentData.getTypedId(IntComponent.class));
-        
-        FloatProperty decorated = system.decorate(ComponentData.getTypedId(IntComponent.class), new FloatPropertyFactory());
-        
-        decorated.getIndexedData()[c.getIndex()] = 1f;
-        
-        int count = 0;
-        Iterator<IntComponent> it = system.fastIterator(ComponentData.getTypedId(IntComponent.class));
-        while(it.hasNext()) {
-            c = it.next();
-            count++;
-            
-            Assert.assertEquals(1f, decorated.getIndexedData()[c.getIndex()], .0001f);
-        }
-        Assert.assertEquals(1, count);
-    }
-    
-    @Test
-    public void testDecoratePropertyAddComponent() {
-        EntitySystem system = new EntitySystem();
-        Entity e = system.addEntity();
-        IntComponent c = e.add(ComponentData.getTypedId(IntComponent.class));
-        
-        FloatProperty decorated = system.decorate(ComponentData.getTypedId(IntComponent.class), new FloatPropertyFactory());
-        decorated.getIndexedData()[c.getIndex()] = 1f;
-        
-        Entity e2 = system.addEntity();
-        IntComponent c2 = e2.add(ComponentData.getTypedId(IntComponent.class));
-        decorated.getIndexedData()[c2.getIndex()] = 2f;
-        
-        int count = 0;
-        Iterator<IntComponent> it = system.fastIterator(ComponentData.getTypedId(IntComponent.class));
-        while(it.hasNext()) {
-            IntComponent c3 = it.next();
-            count++;
-            
-            if (c3.getIndex() == c.getIndex())
-                Assert.assertEquals(1f, decorated.getIndexedData()[c3.getIndex()], .0001f);
-            else
-                Assert.assertEquals(2f, decorated.getIndexedData()[c3.getIndex()], .0001f);
-        }
-        Assert.assertEquals(2, count);
-    }
-    
-    @Test
-    public void testUndecorateValidProperty() {
-        EntitySystem system = new EntitySystem();
-        
-        FloatProperty decorated = system.decorate(ComponentData.getTypedId(IntComponent.class), new FloatPropertyFactory());
-        system.undecorate(ComponentData.getTypedId(IntComponent.class), decorated);
-    }
-    
-    @Test
-    public void testUndecorateInvalidProperty() {
-        FloatProperty prop = new FloatProperty(2);
-        EntitySystem system = new EntitySystem();
-        system.undecorate(ComponentData.getTypedId(IntComponent.class), prop);
-        // should not fail
-    }
-    
-    @Test
-    public void testEquals() {
-        EntitySystem system = new EntitySystem();
-        Entity e = system.addEntity();
-        IntComponent c = e.add(ComponentData.getTypedId(IntComponent.class));
-        
-        int count = 0;
-        Iterator<IntComponent> it = system.fastIterator(ComponentData.getTypedId(IntComponent.class));
-        while(it.hasNext()) {
-            IntComponent c2 = it.next();
-            count++;
-            Assert.assertEquals(c, c2);
-        }
-        Assert.assertEquals(1, count);
-    }
-}

src/test/java/com/googlecode/entreri/ControllerManagerTest.java

         system.getControllerManager().addController(ctrl);
         
         Entity e = system.addEntity();
-        IntComponent i = e.add(ComponentData.getTypedId(IntComponent.class));
+        Component<IntComponent> i = e.add(TypeId.get(IntComponent.class));
         
         Assert.assertEquals(i, ctrl.lastAddedComponent);
-        e.remove(ComponentData.getTypedId(IntComponent.class));
+        e.remove(TypeId.get(IntComponent.class));
         Assert.assertTrue(i == ctrl.lastRemovedComponent);
     }
     
         private Entity lastAddedEntity;
         private Entity lastRemovedEntity;
         
-        private ComponentData lastAddedComponent;
-        private ComponentData lastRemovedComponent;
+        private Component<?> lastAddedComponent;
+        private Component<?> lastRemovedComponent;
+        
+        private EntitySystem system;
         
         @Override
-        public void preProcess(EntitySystem system, float dt) {
+        public EntitySystem getEntitySystem() {
+            return system;
+        }
+        
+        @Override
+        public void preProcess(float dt) {
             preprocessed = true;
             this.dt = dt;
         }
 
         @Override
-        public void process(EntitySystem system, float dt) {
+        public void process(float dt) {
             processed = true;
             this.dt = dt;
         }
 
         @Override
-        public void postProcess(EntitySystem system, float dt) {
+        public void postProcess(float dt) {
             postprocessed = true;
             this.dt = dt;
         }
 
         @Override
-        public void addedToSystem(EntitySystem system) {
+        public void init(EntitySystem system) {
             added = true;
         }
 
         @Override
-        public void removedFromSystem(EntitySystem system) {
+        public void destroy() {
             removed = true;
         }
 
         }
 
         @Override
-        public void onComponentAdd(ComponentData c) {
+        public void onComponentAdd(Component<?> c) {
             lastAddedComponent = c;
         }
 
         @Override
-        public void onComponentRemove(ComponentData c) {
+        public void onComponentRemove(Component<?> c) {
             lastRemovedComponent = c;
         }
     }

src/test/java/com/googlecode/entreri/EntityTest.java

 import org.junit.Assert;
 import org.junit.Test;
 
-import com.googlecode.entreri.ComponentData;
-import com.googlecode.entreri.Entity;
-import com.googlecode.entreri.EntitySystem;
 import com.googlecode.entreri.component.FloatComponent;
-import com.googlecode.entreri.component.InitParamsComponent;
 import com.googlecode.entreri.component.IntComponent;
+import com.googlecode.entreri.component.ObjectComponent;
 
 public class EntityTest {
     @Test
     }
     
     @Test
-    public void testValidInitParams() {
-        TypeId<InitParamsComponent> id = ComponentData.getTypedId(InitParamsComponent.class);
+    public void testAddRemoveComponent() {
         EntitySystem system = new EntitySystem();
         Entity e = system.addEntity();
         
-        // First test a simple add
-        Object val = new Object();
-        InitParamsComponent c = e.add(id, 4f, val);
-        Assert.assertEquals(4f, c.getFloat(), .0001f);
-        Assert.assertEquals(val, c.getObject());
+        Component<IntComponent> c = e.add(TypeId.get(IntComponent.class));
+        
+        c.getData().setInt(0, 1);
+        Assert.assertEquals(1, c.getData().getInt(0));
+        
+        Assert.assertEquals(c, e.get(TypeId.get(IntComponent.class)));
+        Assert.assertEquals(1, e.get(TypeId.get(IntComponent.class)).getData().getInt(0));
+        
+        Assert.assertTrue(e.remove(TypeId.get(IntComponent.class)));
+        
+        Assert.assertNull(e.get(TypeId.get(IntComponent.class)));
+        Assert.assertNull(e.get(TypeId.get(FloatComponent.class)));
+        
+        Assert.assertFalse(c.isLive());
+        Assert.assertFalse(e.get(system.createDataInstance(TypeId.get(IntComponent.class))));
     }
     
     @Test
-    public void testBadInitParams() {
-        // empty args when expected some
-        doTestBadInitParams(ComponentData.getTypedId(InitParamsComponent.class), new Object[0], new Object[] {4f, new Object()});
-        // not enough args when expected some
-        doTestBadInitParams(ComponentData.getTypedId(InitParamsComponent.class), new Object[] {5f}, new Object[] {4f, new Object()});
-        // swapped type list
-        doTestBadInitParams(ComponentData.getTypedId(InitParamsComponent.class), new Object[] {new Object(), 5f}, new Object[] {4f, new Object()});
-        // bad type list
-        doTestBadInitParams(ComponentData.getTypedId(InitParamsComponent.class), new Object[] {"", 2}, new Object[] {4f, new Object()});
-        // parameters when none are expected
-        doTestBadInitParams(ComponentData.getTypedId(FloatComponent.class), new Object[] { 4f, 3f }, new Object[0]);
-    }
-    
-    private void doTestBadInitParams(TypeId<? extends ComponentData> id, Object[] use, Object[] valid) {
+    public void testReAddComponent() {
         EntitySystem system = new EntitySystem();
         Entity e = system.addEntity();
         
-        try {
-            e.add(id, use);
-            Assert.fail();
-        } catch(IllegalArgumentException iae) {
-            // expected
-        }
+        Component<IntComponent> c = e.add(TypeId.get(IntComponent.class));
+        Component<IntComponent> c2 = e.add(TypeId.get(IntComponent.class));
         
-        // verify that this still works
-        ComponentData c = e.add(id, valid);
-        Iterator<? extends ComponentData> it = system.iterator(id);
-        while(it.hasNext()) {
-            Assert.assertEquals(c, it.next());
-            break;
-        }
-        Assert.assertFalse(it.hasNext());
+        Assert.assertNotSame(c, c2);
+        Assert.assertFalse(c.isLive());
+        Assert.assertTrue(c2.isLive());
+        Assert.assertSame(c2, e.get(TypeId.get(IntComponent.class)));
     }
     
     @Test
-    public void testComponent() {
+    public void testGetComponent() {
         EntitySystem system = new EntitySystem();
         Entity e = system.addEntity();
         
-        IntComponent c = e.add(ComponentData.getTypedId(IntComponent.class));
-        
-        c.setInt(0, 1);
-        Assert.assertEquals(1, c.getInt(0));
-        
-        Assert.assertEquals(c, e.get(ComponentData.getTypedId(IntComponent.class)));
-        Assert.assertEquals(1, e.get(ComponentData.getTypedId(IntComponent.class)).getInt(0));
-        
-        e.remove(ComponentData.getTypedId(IntComponent.class));
-        
-        Assert.assertNull(e.get(ComponentData.getTypedId(IntComponent.class)));
-        Assert.assertNull(e.get(ComponentData.getTypedId(FloatComponent.class)));
-    }
-    
-    @Test
-    public void testGetComponentFastEntity() {
-        EntitySystem system = new EntitySystem();
-        Entity e = system.addEntity();
-        
-        IntComponent c = e.add(ComponentData.getTypedId(IntComponent.class));
-        c.setInt(0, 2);
+        Component<IntComponent> c = e.add(TypeId.get(IntComponent.class));
+        c.getData().setInt(0, 2);
         
         int count = 0;
-        Iterator<Entity> it = system.fastIterator();
-        while(it.hasNext()) {
-            Entity e2 = it.next();
-            Assert.assertEquals(2, e2.get(ComponentData.getTypedId(IntComponent.class)).getInt(0));
+        for (Entity e2: system) {
+            Assert.assertSame(e, e2);
+            Assert.assertSame(c, e2.get(TypeId.get(IntComponent.class)));
+            Assert.assertEquals(2, e2.get(TypeId.get(IntComponent.class)).getData().getInt(0));
             count++;
         }
         
     }
     
     @Test
-    public void testAddComponentFastEntity() {
+    public void testDisabledComponent() {
         EntitySystem system = new EntitySystem();
         Entity e = system.addEntity();
         
-        Iterator<Entity> it = system.fastIterator();
-        while(it.hasNext()) {
-            IntComponent c = it.next().add(ComponentData.getTypedId(IntComponent.class));
-            c.setInt(0, 3);
-        }
+        Component<IntComponent> c = e.add(TypeId.get(IntComponent.class));
+        c.setEnabled(false);
         
-        Assert.assertEquals(3, e.get(ComponentData.getTypedId(IntComponent.class)).getInt(0));
+        Assert.assertNull(e.get(TypeId.get(IntComponent.class)));
+        Assert.assertSame(c, e.get(TypeId.get(IntComponent.class), true));
+        
+        // test removing a disabled component
+        Assert.assertTrue(e.remove(TypeId.get(IntComponent.class)));
     }
     
     @Test
-    public void testRemoveComponentFastEntity() {
+    public void testGetComponentData() {
         EntitySystem system = new EntitySystem();
-        Entity e = system.addEntity();
-        e.add(ComponentData.getTypedId(IntComponent.class));
-
         
-        Iterator<Entity> it = system.fastIterator();
-        while(it.hasNext()) {
-            Entity e2 = it.next();
-            Assert.assertNotNull(e2.get(ComponentData.getTypedId(IntComponent.class)));
-            e2.remove(ComponentData.getTypedId(IntComponent.class));
-        }
+        Entity e1 = system.addEntity();
+        Entity e2 = system.addEntity();
         
-        Assert.assertNull(e.get(ComponentData.getTypedId(IntComponent.class)));
+        IntComponent data = system.createDataInstance(TypeId.get(IntComponent.class));
+        
+        Assert.assertTrue(data.set(e1.add(TypeId.get(IntComponent.class))));
+        data.setInt(0, 1);
+        
+        Assert.assertTrue(data.set(e2.add(TypeId.get(IntComponent.class))));
+        data.setInt(0, 2);
+        
+        Assert.assertTrue(e1.get(data));
+        Assert.assertEquals(1, data.getInt(0));
+        Assert.assertTrue(e2.get(data));
+        Assert.assertEquals(2, data.getInt(0));
+        
+        // now test disabled'ness
+        e1.get(TypeId.get(IntComponent.class)).setEnabled(false);
+        Assert.assertFalse(e1.get(data));
+        Assert.assertTrue(data.isValid());
+        Assert.assertFalse(data.isEnabled());
     }
     
     @Test
     public void testIterateComponents() {
         EntitySystem system = new EntitySystem();
         Entity e = system.addEntity();
-        e.add(ComponentData.getTypedId(IntComponent.class));
-        e.add(ComponentData.getTypedId(FloatComponent.class));
+        Component<IntComponent> ic = e.add(TypeId.get(IntComponent.class));
+        Component<FloatComponent> fc = e.add(TypeId.get(FloatComponent.class));
+        
+        e.add(TypeId.get(ObjectComponent.class)).setEnabled(false);
         
         boolean intFound = false;
-        for(ComponentData c: e) {
-            if (intFound) {
-                Assert.assertTrue(c instanceof FloatComponent);
+        boolean floatFound = false;
+        for(Component<?> c: e) {
+            if (ic == c) {
+                Assert.assertFalse(intFound);
+                intFound = true;
+            } else if (fc == c) {
+                Assert.assertFalse(floatFound);
+                floatFound = true;
             } else {
-                Assert.assertTrue(c instanceof IntComponent || c instanceof FloatComponent);
-                if (c instanceof IntComponent)
-                    intFound = true;
+                Assert.fail();
             }
         }
         
         Assert.assertTrue(intFound);
+        Assert.assertTrue(floatFound);
+    }
+    
+    @Test
+    public void testIterateDisabledComponents() {
+        EntitySystem system = new EntitySystem();
+        Entity e = system.addEntity();
+        Component<IntComponent> ic = e.add(TypeId.get(IntComponent.class));
+        Component<FloatComponent> fc = e.add(TypeId.get(FloatComponent.class));
+        
+        Component<ObjectComponent> oc = e.add(TypeId.get(ObjectComponent.class));
+        oc.setEnabled(false);
+        
+        boolean intFound = false;
+        boolean floatFound = false;
+        boolean objFound = false;
+        Iterator<Component<?>> it = e.iterator(true);
+        while(it.hasNext()) {
+            Component<?> c = it.next();
+            if (ic == c) {
+                Assert.assertFalse(intFound);
+                intFound = true;
+            } else if (fc == c) {
+                Assert.assertFalse(floatFound);
+                floatFound = true;
+            } else if (oc == c) {
+                Assert.assertFalse(objFound);
+                objFound = true;
+            } else {
+                Assert.fail();
+            }
+        }
+        
+        Assert.assertTrue(intFound);
+        Assert.assertTrue(floatFound);
+        Assert.assertTrue(objFound);
     }
     
     @Test
     public void testIterateRemoveComponent() {
         EntitySystem system = new EntitySystem();
         Entity e = system.addEntity();
-        e.add(ComponentData.getTypedId(IntComponent.class));
-        e.add(ComponentData.getTypedId(FloatComponent.class));
+        Component<IntComponent> ic = e.add(TypeId.get(IntComponent.class));
+        Component<FloatComponent> fc = e.add(TypeId.get(FloatComponent.class));
         
-        Iterator<ComponentData> it = e.iterator();
+        Iterator<Component<?>> it = e.iterator();
         while(it.hasNext()) {
-            ComponentData c = it.next();
-            if (c instanceof IntComponent) {
+            Component<?> c = it.next();
+            if (c.getTypeId() == TypeId.get(IntComponent.class)) {
+                Assert.assertSame(ic, c);
                 it.remove();
                 
                 Assert.assertNull(c.getEntity());
-                Assert.assertEquals(0, c.getIndex());
+                Assert.assertEquals(0, c.index);
+            } else {
+                Assert.assertSame(fc, c);
             }
         }
         
-        Assert.assertNull(e.get(ComponentData.getTypedId(IntComponent.class)));
-        Assert.assertNotNull(e.get(ComponentData.getTypedId(FloatComponent.class)));
+        Assert.assertNull(e.get(TypeId.get(IntComponent.class)));
+        Assert.assertNotNull(e.get(TypeId.get(FloatComponent.class)));
+        Assert.assertFalse(ic.isLive());
+        Assert.assertFalse(e.get(system.createDataInstance(TypeId.get(IntComponent.class))));
     }
 }

src/test/java/com/googlecode/entreri/IteratorTest.java

 import org.junit.Before;
 import org.junit.Test;
 
-import com.googlecode.entreri.ComponentData;
-import com.googlecode.entreri.Entity;
-import com.googlecode.entreri.EntitySystem;
-import com.googlecode.entreri.IndexedComponentMap;
-import com.googlecode.entreri.TypeId;
 import com.googlecode.entreri.component.FloatComponent;
 import com.googlecode.entreri.component.ObjectComponent;
 
 public class IteratorTest {
-    private static final int ENTITY_COUNT = 10000;
+    private static final int ENTITY_COUNT = 5;
     
     private EntitySystem system;
     private List<Integer> entityIds;
     private TypeId<ObjectComponent> objId;
     private TypeId<FloatComponent> floatId;
     
+    private ObjectComponent objData;
+    private FloatComponent floatData;
+    
     @Before
     public void setup() {
-        objId = ComponentData.getTypedId(ObjectComponent.class);
-        floatId = ComponentData.getTypedId(FloatComponent.class);
-        
+        objId = TypeId.get(ObjectComponent.class);
+        floatId = TypeId.get(FloatComponent.class);
         
         entityIds = new ArrayList<Integer>();
         entityObjValues = new ArrayList<Object>();
         
         system = new EntitySystem();
         
+        objData = system.createDataInstance(objId);
+        floatData = system.createDataInstance(floatId);
+        
         for (int i = 0; i < ENTITY_COUNT; i++) {
             Entity e = system.addEntity();
             
             double c = Math.random();
             if (c > .8) {
                 // both components to add
-                ObjectComponent o = e.add(objId);
+                objData.set(e.add(objId));
                 Object v = new Object();
                 entityObjValues.add(v);
                 entityCombinedObjValues.add(v);
-                o.setObject(0, v);
+                objData.setObject(0, v);
                 
-                FloatComponent f = e.add(floatId);
+                floatData.set(e.add(floatId));
                 Float fv = (float) (Math.random() * 1000);
                 entityFloatValues.add(fv);
                 entityCombinedFloatValues.add(fv);
-                f.setFloat(0, fv);
+                floatData.setFloat(0, fv);
                 
                 countWithBoth++;
                 countWithObj++;
                 countWithFloat++;
             } else if (c > .4) {
                 // just float component
-                FloatComponent f = e.add(floatId);
+                floatData.set(e.add(floatId));
                 Float fv = (float) (Math.random() * 1000);
                 entityFloatValues.add(fv);
-                f.setFloat(0, fv);
+                floatData.setFloat(0, fv);
                 
                 countWithFloat++;
             } else {
                 // just object component
-                ObjectComponent o = e.add(objId);
+                objData.set(e.add(objId));
                 Object v = new Object();
                 entityObjValues.add(v);
-                o.setObject(0, v);
+                objData.setObject(0, v);
                 
                 countWithObj++;
             }
         Assert.assertEquals(entityIds.size(), i);
     }
     
-    private void doTestObjectComponentIterator(Iterator<ObjectComponent> it) {
+    // assumes it has objData in it
+    private void doTestObjectComponentIterator(ComponentIterator it) {
         int i = 0;
-        while(it.hasNext()) {
-            Assert.assertEquals(entityObjValues.get(i), it.next().getObject(0));
+        while(it.next()) {
+            Assert.assertEquals(entityObjValues.get(i), objData.getObject(0));
             i++;
         }
         
         Assert.assertEquals(countWithObj, i);
     }
     
-    private void doTestFloatComponentIterator(Iterator<FloatComponent> it) {
+    // assumes it has floatData in it
+    private void doTestFloatComponentIterator(ComponentIterator it) {
         int i = 0;
-        while(it.hasNext()) {
-            Assert.assertEquals(entityFloatValues.get(i).floatValue(), it.next().getFloat(0), .0001f);
+        while(it.next()) {
+            Assert.assertEquals(entityFloatValues.get(i).floatValue(), floatData.getFloat(0), .0001f);
             i++;
         }
         
         Assert.assertEquals(countWithFloat, i);
     }
     
-    private void doTestBulkComponentIterator(Iterator<IndexedComponentMap> it) {
+    // assumes it has floatData and objData as required
+    private void doTestBulkComponentIterator(ComponentIterator it) {
         int i = 0;
-        while(it.hasNext()) {
-            IndexedComponentMap map = it.next();
-            Assert.assertEquals(entityCombinedObjValues.get(i), map.get(objId, 0).getObject(0));
-            Assert.assertEquals(entityCombinedObjValues.get(i), map.get(objId).getObject(0));
-            Assert.assertEquals(entityCombinedFloatValues.get(i).floatValue(), map.get(floatId, 1).getFloat(0), .0001f);
-            Assert.assertEquals(entityCombinedFloatValues.get(i).floatValue(), map.get(floatId).getFloat(0), .0001f);
+        while(it.next()) {
+            Assert.assertEquals(entityCombinedObjValues.get(i), objData.getObject(0));
+            Assert.assertEquals(entityCombinedFloatValues.get(i).floatValue(), floatData.getFloat(0), .0001f);
             i++;
         }
         
         // this invalidates all of the value lists, but that is okay
     }
     
-    private void doIteratorObjectComponentRemove(Iterator<ObjectComponent> it) {
-        int i = 0;
-        Iterator<Object> vs = entityObjValues.iterator();
-        while(it.hasNext()) {
-            it.next();
-            vs.next();
-            if (i > countWithObj / 2) {
-                it.remove();
-                vs.remove();
-                countWithObj--;
-            }
-            
-            i++;
-        }
-        
-        // this invalidates the combined value lists, but that is okay
-    }
-