View Javadoc

1   /*
2    * Entreri, an entity-component framework in Java
3    *
4    * Copyright (c) 2013, Michael Ludwig
5    * All rights reserved.
6    *
7    * Redistribution and use in source and binary forms, with or without modification,
8    * are permitted provided that the following conditions are met:
9    *
10   *     Redistributions of source code must retain the above copyright notice,
11   *         this list of conditions and the following disclaimer.
12   *     Redistributions in binary form must reproduce the above copyright notice,
13   *         this list of conditions and the following disclaimer in the
14   *         documentation and/or other materials provided with the distribution.
15   *
16   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
20   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
23   * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26   */
27  package com.lhkbob.entreri;
28  
29  /**
30   * <p/>
31   * Component represents a grouping of reusable and related states that are added to an
32   * {@link Entity}. An Entity's behavior is defined by the union of all components attached
33   * to it, and the system's configured tasks that process the entities. Tasks must be
34   * implemented and used in order to take advantage of a particular component
35   * configuration.
36   * <p/>
37   * An entity can be considered as a collection of aspects represented by component
38   * instances. An entity can have at most one instance of a component type at a time,
39   * although over its lifetime the specific component instance may change.
40   * <p/>
41   * Logically a component definition is a set of named and typed properties, and a
42   * method-based API to get and set the values of each property. Specific types of
43   * component are defined by creating a sub-interface of Component. Using the {@link
44   * com.lhkbob.entreri.property.Named Named}, {@link com.lhkbob.entreri.property.SharedInstance
45   * SharedInstance}, {@link com.lhkbob.entreri.property.Factory Factory} and custom {@link
46   * com.lhkbob.entreri.property.Attribute Attribute} annotations defined by {@link
47   * com.lhkbob.entreri.property.Property Property} implementations, the data properties of
48   * the component type are specified in the sub-interface. A declaration model similar to
49   * the Java Bean model is used and is outlined below:
50   * <p/>
51   * <ol> <li>Non-void, zero-argument methods starting with 'get', 'is', and 'has' declare a
52   * property. The property type is inspected from the return type of the method. The
53   * property name is the method name minus the 'get'/'is'/'has' prefix with its first
54   * letter made lower-case. The {@link com.lhkbob.entreri.property.Named Named} annotation
55   * can be used to override the name.</li> <li>Single-argument methods starting with 'set'
56   * are assumed to be a setter corresponding to a property. The single parameter's type
57   * must equal the type the getter. The {@link com.lhkbob.entreri.property.Named Named}
58   * annotation can be applied to either the setter or the parameter to specify the property
59   * name.</li> <li>Multi-argument methods starting with 'set' are assumed to be a setter
60   * that assigns values to multiple property, one for each argument. Each argument must be
61   * annotated with {@link com.lhkbob.entreri.property.Named Named} to specify the property,
62   * and the argument type must equal the type of the matching property.</li> <li>Setter
63   * methods must return void or return the components type, in which case the proxy will
64   * return itself to allow for method chaining.</li> <li>Getters with void return types or
65   * more than 0 arguments, setters with an invalid return type or no arguments, and any
66   * other method not matching the conventions above will cause the system to throw an
67   * {@link IllegalComponentDefinitionException}.</li> </ol>
68   * <p/>
69   * Internally, the entity system will generate proxy implementations of the component
70   * interfaces that implement the property getters and setters but store all of the values
71   * in {@link com.lhkbob.entreri.property.Property} instances of a compatible type. This
72   * allows iteration over components to have much better cache locality if the component is
73   * defined in terms of primitives or types that have specialized Property implementations
74   * that can pack and unpack an instance. The {@link com.lhkbob.entreri.property.SharedInstance
75   * SharedInstance} annotation can be added to the getter method of a property to specify
76   * that the {@link com.lhkbob.entreri.property.ShareableProperty ShareableProperty} API
77   * should be leveraged by the generated class.
78   * <p/>
79   * Additional attribute annotations can be added to the getter method to influence the
80   * behavior of the {@link com.lhkbob.entreri.property.PropertyFactory PropertyFactory}
81   * used for each property in the component definition. Besides using the Factory
82   * annotation to specify the factory type, a property implementation can be associated
83   * with a type with canonical name <var>C</var> by adding the file
84   * META-INF/entreri/mapping/C to the classpath, where its contents must be:
85   * <pre>
86   *     &lt;BINARY NAME OF PROPERTY&gt;
87   * </pre>
88   * where the value is suitable for passing into {@link Class#forName(String)}.
89   * <p/>
90   * Attribute annotations provided by the default property implementations are outlined
91   * below: <ul> <li>{@link com.lhkbob.entreri.property.BooleanProperty.DefaultBoolean
92   * DefaultBoolean} - set value for boolean properties</li> <li>{@link
93   * com.lhkbob.entreri.property.ByteProperty.DefaultByte DefaultByte} - set value for byte
94   * properties</li> <li>{@link com.lhkbob.entreri.property.ShortProperty.DefaultShort
95   * DefaultShort} - set value for short properties</li> <li>{@link
96   * com.lhkbob.entreri.property.IntProperty.DefaultInt DefaultInt} - set value for int
97   * properties</li> <li>{@link com.lhkbob.entreri.property.LongProperty.DefaultLong
98   * DefaultLong} - set value for long properties</li> <li>{@link
99   * com.lhkbob.entreri.property.FloatProperty.DefaultFloat DefaultFloat} - set value for
100  * float properties</li> <li>{@link com.lhkbob.entreri.property.DoubleProperty.DefaultDouble
101  * DefaultDouble} - set value for double properties</li> <li>{@link
102  * com.lhkbob.entreri.property.CharProperty.DefaultChar DefaultChar} - set value for char
103  * properties</li> <li>{@link com.lhkbob.entreri.property.Clone Clone} - specify clone
104  * policy used with entity or component templates</li> </ul> Note that there are no
105  * annotations that work with general object types. This is because the scope of that
106  * problem is intractable. The default ObjectProperty implementation assumes null values
107  * are allowed and that the default value is null.
108  * <p/>
109  * The generated proxies will implement equals() and hashCode() based on their type and
110  * the id of their owning entity. The {@link ComponentIterator} class creates flyweight
111  * component instances whose identity changes as iteration proceeds; equals() and
112  * hashCode() will behave appropriately. This means that flyweight components should not
113  * be stored in collections that depend on equality or hashes. Flyweight components are
114  * used for performance reasons when iterating over the entities in a system with specific
115  * component configurations because the JVM does not need to load each unique component
116  * instance into the cache.
117  * <p/>
118  * Component implements both {@link Ownable} and {@link Owner}. This can be used to create
119  * hierarchies of both components and entities that share a lifetime. When a component is
120  * removed from an entity, all of its owned objects are disowned. If any of them were
121  * entities or components, they are also removed from the system.
122  *
123  * @author Michael Ludwig
124  */
125 public interface Component extends Owner, Ownable {
126     /**
127      * @return The EntitySystem that created this component
128      */
129     public EntitySystem getEntitySystem();
130 
131     /**
132      * Get the entity that this component is attached to. If the component has been
133      * removed from the entity, or is otherwise not live, this will return null.
134      *
135      * @return The owning entity, or null
136      */
137     public Entity getEntity();
138 
139     /**
140      * <p/>
141      * Get whether or not the component is still attached to an alive entity in an entity
142      * system. This will return false if it or its entity has been removed. If the
143      * component is a flyweight object used in iteration, it can also return false when
144      * iteration has terminated.
145      * <p/>
146      * Using property getters or setters on a dead component produces undefined behavior.
147      *
148      * @return True if the component is still attached to an entity in the entity system,
149      *         or false if it or its entity has been removed
150      */
151     public boolean isAlive();
152 
153     /**
154      * <p/>
155      * Get whether or not this particular instance is a flyweight component object. A
156      * flyweight instance is used by ComponentIterators to efficiently view the underlying
157      * component data iteratively. It is safe to set the owner of a flyweight component or
158      * to set the flyweight as an owner of another object. It will correctly register the
159      * canonical component as the owner.
160      * <p/>
161      * Components returned by {@link Entity#add(Class)}, {@link Entity#get(Class)}, and
162      * its other component returning functions will always return non-flyweight
163      * components. These components are the 'canonical' instances for that component type
164      * and entity.
165      *
166      * @return True if this component is a flyweight instance iterating over a list of
167      *         components
168      */
169     public boolean isFlyweight();
170 
171     /**
172      * <p/>
173      * Get the underlying index of this component used to access its properties. For most
174      * uses, you should not need to use this method.  As an EntitySystem manages and
175      * compacts the component data storage, a component's index can change. The index
176      * should be used to access decorated properties, which will be kept in-sync with any
177      * compactions.
178      * <p/>
179      * Additionally, some component instances may be flyweight objects used for iteration.
180      * In this case, every iteration will update its index and the component object's
181      * identity will change as well. See {@link ComponentIterator} for more information.
182      *
183      * @return The current index of component
184      */
185     public int getIndex();
186 
187     /**
188      * <p/>
189      * Get the current version of the data of this component. When a component's data is
190      * mutated, implementations increment its version so comparing a previously cached
191      * version number can be used to determine when changes have been made.
192      * <p/>
193      * Within a component type for an entity system, version values will be unique across
194      * component instances. Thus, {@code entity.as(T.class).getVersion() != cachedVersion}
195      * will correctly detect changes to the original component instance as well as the
196      * removal and replacement by a new component of type T.
197      *
198      * @return The current version, or a negative number if the data is invalid
199      */
200     public int getVersion();
201 
202     /**
203      * Increment the version of the component accessed by this instance. This will be
204      * automatically called by all exposed setters by the generated proxies, but if
205      * necessary it can be invoked manually as well.
206      *
207      * @see #getVersion()
208      */
209     public void updateVersion();
210 
211     /**
212      * Get the class identifier for this component. This will be the specific
213      * sub-interface of Component that this object is an instance of. getType() should be
214      * used instead of {@link Object#getClass()} because that will return a specific and
215      * most likely generated proxy implementation of the component type.
216      *
217      * @return The component type
218      */
219     public Class<? extends Component> getType();
220 }