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 * <BINARY NAME OF PROPERTY>
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 }