Commits

Michael Ludwig committed fa669dc

Add versioning to component API.

Comments (0)

Files changed (3)

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

     }
 
     /**
+     * <p>
+     * Get the current version of the data accessed by this ComponentData. When
+     * data is mutated by a ComponentData, implementations increment its
+     * associated component's version so comparing a previously cached version
+     * number can be used to determine when changes have been made.
+     * <p>
+     * If the
+     * 
+     * @return The current version
+     */
+    public final int getVersion() {
+        return owner.getVersion(index);
+    }
+
+    /**
+     * Increment the version of the component accessed by this instance. It is
+     * recommended for component data implementations to call this automatically
+     * from within their exposed mutators, but if necessary it can be invoked
+     * manually as well.
+     * 
+     * @see #getVersion()
+     */
+    public final void updateVersion() {
+        if (isValid()) {
+            owner.incrementVersion(index);
+        }
+    }
+
+    /**
      * Return the Component that this data reads and writes to. If
      * {@link #isValid()} returns false, the returned Component is undefined. It
      * may be the proper component, another component in the system, or null, or

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

     private final List<DeclaredPropertyStore<?>> declaredProperties;
     private final List<DecoratedPropertyStore<?>> decoratedProperties;
 
-    private final BooleanProperty enabledProperty; // this is also contained in decoratedProperties
-    private final IntProperty componentIdProperty; // this is contained in decoratedProperties
+    // this is contained in decoratedProperties
+    private final BooleanProperty enabledProperty;
+    private final IntProperty componentIdProperty;
+    private final IntProperty componentVersionProperty;
     private int idSeq;
 
     /**
 
         // decorate the component data with a boolean property to track enabled status
         enabledProperty = decorate(new BooleanProperty.Factory(true));
-        componentIdProperty = decorate(new IntProperty.Factory(0)); // we'll not assign a default value, since we change the id each time
+        componentIdProperty = decorate(new IntProperty.Factory(0)); // we set a unique id for every component
+        componentVersionProperty = decorate(new IntProperty.Factory(0));
+
         idSeq = 1; // start at 1, just like entity id sequences
     }
 
         return componentIdProperty.get(componentIndex);
     }
 
+    /**
+     * @param componentIndex The component index
+     * @return The component version of the component at the given index
+     */
+    public int getVersion(int componentIndex) {
+        return componentVersionProperty.get(componentIndex);
+    }
+
+    /**
+     * Increment the component's version at the given index.
+     * 
+     * @param componentIndex
+     */
+    public void incrementVersion(int componentIndex) {
+        componentVersionProperty.set(componentVersionProperty.get(componentIndex) + 1,
+                                     componentIndex);
+    }
+
     /*
      * As expandEntityIndex() but expands all related component data and arrays
      * to hold the number of components.

src/main/java/com/lhkbob/entreri/Entity.java

 
     /**
      * <p>
-     * Get the component of type T attached to this entity, but setting the
-     * given data's reference. This will return true if the data instance has
-     * been set to a valid component and that component is enabled. This is a
-     * shortcut for:
+     * Get the component of type T attached to this entity, by setting the given
+     * data's reference. This will return true if the data instance has been set
+     * to a valid component and that component is enabled. This is a shortcut
+     * for:
      * 
      * <pre>
      * Component&lt;T&gt; c = entity.get(TypeId.get(T.class));
      * </p>
      * <p>
      * Note that there is no equivalent {@link #get(TypeId, boolean)} that takes
-     * a ComponentData. This is because the data instance will always be set to
-     * a valid component, even if that component is disabled. It is possible to
-     * identify this case if get() returns false but isValid() returns true.
+     * a ComponentData. This is because the data instance will still be set to a
+     * valid component even when it's disabled. It is possible to identify this
+     * case if get() returns false but isValid() returns true.
      * </p>
      * 
      * @param <T> The component data type
 
     /**
      * <p>
+     * Get the component of type T attached to this entity only if the entity
+     * has a component of type T, it is enabled, and it's version is different
+     * than <tt>priorVersion</tt>. This method is a convenience method to easily
+     * retrieve the component data only if the data has changed.
+     * <p>
+     * If the entity has a component of type T, that is enabled, and has a
+     * version not equal to <tt>priorVersion</tt>, then <tt>data</tt> will be
+     * set to access the component and true will be returned. In any other case,
+     * false is returned. Unlike {@link #get(ComponentData)}, it's not possible
+     * to inspect the data instance to determine why false was returned.
+     * 
+     * @param <T> The component data type
+     * @param data The data instance used to access the component if available
+     * @param priorVersion The previously valid version
+     * @return True if the entity has an enabled component of type T that has
+     *         been modified since <tt>priorVersion</tt>
+     * @throws NullPointerException if data is null
+     * @throws IllegalArgumentException if data was created by another entity
+     *             system
+     */
+    public <T extends ComponentData<T>> boolean getIfModified(T data, int priorVersion) {
+        if (data.owner.getEntitySystem() != getEntitySystem()) {
+            throw new IllegalArgumentException("ComponentData was not created by expected EntitySystem");
+        }
+
+        ComponentRepository<T> ci = data.owner;
+        int componentIndex = ci.getComponentIndex(index);
+
+        if (ci.getVersion(componentIndex) != priorVersion) {
+            return data.setFast(componentIndex) && ci.isEnabled(componentIndex);
+        } else {
+            // note that in this situation, the component data is invalid
+            return false;
+        }
+    }
+
+    /**
+     * <p>
      * Add a new Component with a data type T to this Entity. If the Entity
      * already has component of type T attached, that component is removed and a
      * new one is created. Otherwise, a new instance is created with its default