Skip to content
Browse files

Prefabs - refactoring, inheritance, serialization and unit tests for …

…all that.
  • Loading branch information...
1 parent 4cb4b03 commit 6068ec950c2a90b6f3561ec3f0a100f27d8b1feb @t3hk0d3 t3hk0d3 committed Mar 4, 2012
View
1 build.gradle
@@ -31,6 +31,7 @@ repositories {
dependencies{
groovy group: 'org.codehaus.groovy', name: 'groovy', version: '1.8.2'
compile group: 'com.google.guava', name: 'guava', version: '11.0.1'
+ compile group: 'com.google.code.gson', name: 'gson', version: '2.1'
compile fileTree(dir: 'libs', include: '*.jar', exclude: 'mockito-all-1.9.0.jar')
testCompile 'junit:junit:4.10'
testCompile group: 'org.mockito', name: 'mockito-all', version: '1.9.0'
View
BIN libs/gson-2.1.jar
Binary file not shown.
View
2 src/org/terasology/components/CharacterMovementComponent.java
@@ -39,6 +39,8 @@
public void store(StorageWriter writer) {
//To change body of implemented methods use File | Settings | File Templates.
+
+
}
public void retrieve(StorageReader reader) {
View
24 src/org/terasology/components/LocationComponent.java
@@ -38,4 +38,28 @@ public void retrieve(StorageReader reader) {
scale = reader.readFloat("scale", 1.0f);
parent = reader.read("parent", EntityRef.class, parent);
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ LocationComponent component = (LocationComponent) o;
+
+ if (Float.compare(component.scale, scale) != 0) return false;
+ if (parent != null ? !parent.equals(component.parent) : component.parent != null) return false;
+ if (position != null ? !position.equals(component.position) : component.position != null) return false;
+ if (rotation != null ? !rotation.equals(component.rotation) : component.rotation != null) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = position != null ? position.hashCode() : 0;
+ result = 31 * result + (rotation != null ? rotation.hashCode() : 0);
+ result = 31 * result + (scale != +0.0f ? Float.floatToIntBits(scale) : 0);
+ result = 31 * result + (parent != null ? parent.hashCode() : 0);
+ return result;
+ }
}
View
24 src/org/terasology/entitySystem/AbstractComponent.java
@@ -1,15 +1,29 @@
package org.terasology.entitySystem;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+
/**
* @author Immortius <immortius@gmail.com>
*/
public abstract class AbstractComponent implements Component {
+
public String getName() {
- int index = getClass().getSimpleName().lastIndexOf("Component");
- if (index != -1) {
- return getClass().getSimpleName().substring(0, index).toLowerCase();
+ String className = getClass().getSimpleName().toLowerCase();
+
+ if (className.endsWith("component")) {
+ return className.substring(0, className.lastIndexOf("component"));
+ }
+
+ return className;
+ }
+
+ public Component clone() {
+ try {
+ return (Component) super.clone();
+ } catch (CloneNotSupportedException e) {
+ // this shouldn't happen
+ throw new InternalError();
}
- return getClass().getSimpleName().toLowerCase();
}
-
}
View
48 src/org/terasology/entitySystem/AbstractPrefab.java
@@ -0,0 +1,48 @@
+package org.terasology.entitySystem;
+
+import com.google.common.base.Objects;
+
+/**
+ * @todo javadoc
+ */
+public abstract class AbstractPrefab implements Prefab {
+
+ private String name;
+
+ protected AbstractPrefab(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Prefab clone() {
+ try {
+ return (Prefab) super.clone();
+ } catch (CloneNotSupportedException e) {
+ // this shouldn't happen
+ throw new InternalError();
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o instanceof Prefab) {
+ return Objects.equal(name, ((Prefab) o).getName());
+ }
+
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(name);
+ }
+
+ @Override
+ public String toString() {
+ return "Prefab(" + name + "){ components: " + this.listOwnComponents() + ", parents: " + this.getParents() + " }";
+ }
+}
View
4 src/org/terasology/entitySystem/Component.java
@@ -8,6 +8,8 @@
*
* @author Immortius <immortius@gmail.com>
*/
-public interface Component extends Persistable {
+public interface Component extends Persistable, Cloneable {
public String getName();
+
+ public Component clone();
}
View
118 ...rg/terasology/entitySystem/PrefabRef.java → src/org/terasology/entitySystem/Prefab.java
@@ -1,56 +1,62 @@
-package org.terasology.entitySystem;
-
-/**
- * An entity prefab describes the recipe for creating an entity.
- * Like an entity it groups a collection of components.
- * @author Immortius <immortius@gmail.com>
- */
-public interface PrefabRef {
- /**
- * @return The identifier for this prefab
- */
- String getName();
-
- /**
- *
- * @param newName
- * @throws IllegalArgumentException If the new name is already in use
- */
- void rename(String newName);
-
- /**
- *
- * @param componentClass
- * @param <T>
- * @return The requested component, or null if the entity doesn't have a component of this class
- */
- <T extends Component> T getComponent(Class<T> componentClass);
-
- /**
- * Adds a component to this entity. If the entity already has a component of the same class it is replaced.
- * @param component
- */
- <T extends Component> T addComponent(T component);
-
- /**
- * @param componentClass
- */
- void removeComponent(Class<? extends Component> componentClass);
-
- /**
- * @param component
- */
- void saveComponent(Component component);
-
- /**
- * Iterates over all the components
- * @return
- */
- Iterable<Component> iterateComponents();
-
- /**
- * Removes this prefab from the prefab manager
- */
- void destroy();
-
-}
+package org.terasology.entitySystem;
+
+/**
+ * An entity prefab describes the recipe for creating an entity.
+ * Like an entity it groups a collection of components.
+ *
+ * @author Immortius <immortius@gmail.com>
+ */
+public interface Prefab extends Cloneable{
+
+ /**
+ * @return The identifier for this prefab
+ */
+ public String getName();
+
+ /**
+ *
+ * @param componentClass
+ * @param <T>
+ * @return The requested component, or null if the entity doesn't have a component of this class
+ */
+ public <T extends Component> T getComponent(Class<T> componentClass);
+
+ /**
+ * Adds a component to this entity. If the entity already has a component of the same class it is replaced.
+ * @param component
+ */
+ public <T extends Component> T setComponent(T component);
+
+ /**
+ * @param componentClass
+ */
+ public void removeComponent(Class<? extends Component> componentClass);
+
+ /**
+ * Iterates over all the components
+ * @return
+ */
+ public Iterable<Component> listComponents();
+
+ /**
+ * Iterate only over OWN components, excluding inheritance.
+ * Required for proper serializing
+ *
+ * @return
+ */
+ public Iterable<Component> listOwnComponents();
+
+ /**
+ * Return parents prefabs
+ *
+ * @return
+ */
+ public Iterable<Prefab> getParents();
+
+ public void addParent(Prefab parent);
+
+ public void removeParent(Prefab parent);
+
+ public Prefab clone();
+
+}
View
42 src/org/terasology/entitySystem/PrefabManager.java
@@ -1,33 +1,29 @@
package org.terasology.entitySystem;
/**
+ *
+ * @todo Write javadoc
* @author Immortius <immortius@gmail.com>
*/
public interface PrefabManager {
- /**
- * @param name
- * @return A new PrefabRef
- * @throws IllegalArgumentException when name is already in use
- */
- PrefabRef create(String name);
+ public Prefab createPrefab(String name);
- PrefabRef get(String name);
+ public Prefab getPrefab(String name);
- boolean exists(String name);
-
- /**
- * @param oldName
- * @param name
- * @return A new PrefabRef with the new name
- * @throws IllegalArgumentException if either the oldName isn't in use or the new name is already in use
- */
- PrefabRef rename(String oldName, String name);
-
- void destroy(String name);
-
- <T extends Component> T getComponent(String name, Class<T> componentClass);
- void addComponent(String name, Component component);
- <T extends Component> void removeComponent(String name, Class<T> componentClass);
- void saveComponent(String name, Component component);
+ public boolean exists(String name);
+
+ public Prefab registerPrefab(Prefab prefab);
+
+ public Iterable<Prefab> listPrefabs();
+
+ public void removePrefab(String name);
+
+ public <T extends Component> T getComponent(String name, Class<T> componentClass);
+
+ public <T extends Component> T setComponent(String name, T component);
+
+
+ public <T extends Component> void removeComponent(String name, Class<T> componentClass);
+
}
View
197 src/org/terasology/entitySystem/persist/JsonPersister.java
@@ -0,0 +1,197 @@
+package org.terasology.entitySystem.persist;
+
+
+import com.google.gson.*;
+import org.terasology.entitySystem.Component;
+import org.terasology.entitySystem.Prefab;
+import org.terasology.entitySystem.PrefabManager;
+import org.terasology.entitySystem.pojo.PojoPrefabManager;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Writer;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
+import java.util.Map;
+
+public class JsonPersister implements PrefabPersister {
+
+ private Gson gson;
+
+ protected PrefabManager prefabManager;
+
+ public JsonPersister() {
+ this.initialize();
+ }
+
+ private void initialize() {
+ GsonBuilder builder = new GsonBuilder();
+
+ builder.registerTypeAdapter(Prefab.class, new PrefabAdapter());
+ builder.registerTypeAdapter(PrefabManager.class, new PrefabManagerAdapter());
+ builder.registerTypeAdapter(Component.class, new ComponentAdapter());
+
+ this.gson = builder.create();
+ }
+
+
+ public Prefab loadPrefab(Reader reader, PrefabManager manager) throws IOException {
+ prefabManager = manager;
+ Prefab prefab = gson.fromJson(reader, Prefab.class);
+ prefabManager = null;
+
+ return prefab;
+ }
+
+ public PrefabManager loadPrefabs(Reader reader) throws IOException {
+ PrefabManager manager = gson.fromJson(reader, PrefabManager.class);
+ prefabManager = null;
+
+ return manager;
+ }
+
+ public void savePrefab(Writer writer, Prefab prefab) throws IOException {
+ gson.toJson(prefab, Prefab.class, writer);
+
+ writer.flush();
+ }
+
+ public void savePrefabs(Writer writer, PrefabManager manager) throws IOException {
+ gson.toJson(manager, PrefabManager.class, writer);
+
+ writer.flush();
+ }
+
+ protected class PrefabAdapter implements JsonDeserializer<Prefab>, JsonSerializer<Prefab> {
+
+ public Prefab deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
+ JsonObject object = json.getAsJsonObject();
+
+ String prefabName = object.get("name").getAsString();
+
+ Prefab prefab = prefabManager.createPrefab(prefabName);
+
+ JsonArray parents = object.get("parents").getAsJsonArray();
+
+ for (JsonElement parentElement : parents) {
+ prefab.addParent(prefabManager.createPrefab(parentElement.getAsString()));
+ }
+
+ JsonObject components = object.get("components").getAsJsonObject();
+ for (Map.Entry<String, JsonElement> entry : components.entrySet()) {
+ prefab.setComponent(gson.fromJson(entry.getValue(), Component.class));
+ }
+
+ return prefab;
+ }
+
+ public JsonElement serialize(Prefab src, Type typeOfSrc, JsonSerializationContext context) {
+ JsonObject object = new JsonObject();
+ {
+
+ object.addProperty("name", src.getName());
+
+ JsonArray parents = new JsonArray();
+ {
+ for (Prefab parent : src.getParents()) {
+ parents.add(new JsonPrimitive(parent.getName()));
+ }
+ }
+ object.add("parents", parents);
+
+ JsonObject components = new JsonObject();
+ {
+ for (Component component : src.listOwnComponents()) {
+ components.add(component.getName(), gson.toJsonTree(component, Component.class));
+ }
+ }
+ object.add("components", components);
+ }
+ return object;
+ }
+ }
+
+ protected class PrefabManagerAdapter implements JsonDeserializer<PrefabManager>, JsonSerializer<PrefabManager> {
+
+ public PrefabManager deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
+ JsonObject object = json.getAsJsonObject();
+
+ prefabManager = new PojoPrefabManager();
+
+ JsonArray prefabs = object.get("prefabs").getAsJsonArray();
+ for (JsonElement prefabElement : prefabs) {
+ gson.fromJson(prefabElement, Prefab.class);
+ }
+
+ return prefabManager;
+ }
+
+ public JsonElement serialize(PrefabManager src, Type typeOfSrc, JsonSerializationContext context) {
+ JsonObject object = new JsonObject();
+ {
+ JsonArray prefabs = new JsonArray();
+ {
+ for (Prefab prefab : src.listPrefabs()) {
+ prefabs.add(gson.toJsonTree(prefab, Prefab.class));
+ }
+ }
+ object.add("prefabs", prefabs);
+ }
+ return object;
+ }
+ }
+
+ protected class ComponentAdapter implements JsonDeserializer<Component>, JsonSerializer<Component> {
+
+ public Component deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
+ JsonObject object = json.getAsJsonObject();
+
+ try {
+ Class<?> componentClass = Class.forName(object.get("class").getAsString());
+
+ if (!Component.class.isAssignableFrom(componentClass)) {
+ throw new IllegalStateException("Wrong class specified - not Component!");
+ }
+
+ Component instance = (Component) componentClass.newInstance();
+
+ for (Map.Entry<String, JsonElement> element : object.entrySet()) {
+ if ("class".equals(element.getKey())) {
+ continue;
+ }
+
+ Field field = componentClass.getDeclaredField(element.getKey());
+ field.set(instance, gson.fromJson(element.getValue(), field.getType()));
+ }
+
+ return instance;
+ } catch (Throwable e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public JsonElement serialize(Component src, Type typeOfSrc, JsonSerializationContext context) {
+ JsonObject object = new JsonObject();
+ {
+ object.addProperty("class", src.getClass().getName());
+
+ for (Field field : src.getClass().getDeclaredFields()) {
+ if (Modifier.isTransient(field.getModifiers())) { // skip transient fields
+ continue;
+ }
+
+ field.setAccessible(true);
+
+ try {
+ object.add(field.getName(), gson.toJsonTree(field.get(src)));
+ } catch (IllegalAccessException e) {
+ // @todo add proper logging
+ throw new IllegalStateException("Can't obtain field '" + field.getName() + "' from '" + object.getClass().getName() + "'");
+ }
+ }
+ }
+ return object;
+ }
+ }
+}
View
26 src/org/terasology/entitySystem/persist/PersisterFactory.java
@@ -0,0 +1,26 @@
+package org.terasology.entitySystem.persist;
+
+import com.google.gson.Gson;
+import org.terasology.entitySystem.Prefab;
+import org.terasology.entitySystem.PrefabManager;
+import org.terasology.entitySystem.pojo.PojoPrefab;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Writer;
+
+public abstract class PersisterFactory {
+
+ /**
+ * Do nothing, just avoid factory from being instanced
+ */
+
+ public static PersisterFactory getFactory() {
+ return null;
+ }
+
+ public static PrefabPersister createPrefabPersister() {
+ return new JsonPersister();
+ }
+
+}
View
19 src/org/terasology/entitySystem/persist/PrefabPersister.java
@@ -0,0 +1,19 @@
+package org.terasology.entitySystem.persist;
+
+import org.terasology.entitySystem.Prefab;
+import org.terasology.entitySystem.PrefabManager;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Writer;
+
+public interface PrefabPersister {
+
+ public Prefab loadPrefab(Reader reader, PrefabManager manager) throws IOException;
+
+ public PrefabManager loadPrefabs(Reader reader) throws IOException;
+
+ public void savePrefab(Writer writer, Prefab prefab) throws IOException;
+
+ public void savePrefabs(Writer writer, PrefabManager manager) throws IOException;
+}
View
128 src/org/terasology/entitySystem/pojo/PojoPrefab.java
@@ -0,0 +1,128 @@
+package org.terasology.entitySystem.pojo;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.terasology.entitySystem.AbstractPrefab;
+import org.terasology.entitySystem.Component;
+import org.terasology.entitySystem.Prefab;
+
+import java.util.*;
+
+/**
+ * @author Immortius <immortius@gmail.com>
+ */
+public class PojoPrefab extends AbstractPrefab implements Prefab {
+
+ private Map<Class<? extends Component>, Component> components;
+
+ private List<Prefab> parents;
+
+ private transient Map<Class<? extends Component>, Component> componentCache;
+
+ protected PojoPrefab(String name) {
+ this(name, Maps.<Class<? extends Component>, Component>newHashMap(), Lists.<Prefab>newLinkedList());
+ }
+
+ protected PojoPrefab(String name, Map<Class<? extends Component>, Component> components, List<Prefab> parents) {
+ super(name);
+
+ this.components = components;
+ this.parents = parents;
+ }
+
+ public <T extends Component> T getComponent(Class<T> componentClass) {
+ checkComponentCache();
+
+ return componentClass.cast(componentCache.get(componentClass));
+ }
+
+ public <T extends Component> T setComponent(T component) {
+ // Update data
+ this.components.put(component.getClass(), component);
+
+ if (componentCache != null) {
+ this.componentCache.put(component.getClass(), component);
+ }
+
+ return component;
+ }
+
+ public void removeComponent(Class<? extends Component> componentClass) {
+ components.remove(componentClass);
+ this.invalidateComponentCache();
+ }
+
+ public Iterable<Component> listComponents() {
+ checkComponentCache();
+
+ return Collections.unmodifiableCollection(componentCache.values());
+ }
+
+ public Iterable<Component> listOwnComponents() {
+ return Collections.unmodifiableCollection(components.values());
+ }
+
+ public void addParent(Prefab parent) {
+ if (this.parents.contains(parent)) {
+ // @todo should we throw IllegalArgumentException instead?
+ return;
+ }
+
+ this.parents.add(parent);
+ this.invalidateComponentCache();
+ }
+
+ public Iterable<Prefab> getParents() {
+ return Collections.unmodifiableCollection(parents);
+ }
+
+ public void removeParent(Prefab parent) {
+ this.parents.remove(parent);
+ invalidateComponentCache();
+ }
+
+ private void checkComponentCache() {
+ if (components == null) {
+ throw new IllegalStateException("Prefab is destroyed!");
+ }
+
+ if (componentCache == null) {
+ this.buildComponentCache();
+ }
+ }
+
+ private void invalidateComponentCache() {
+ componentCache = null;
+ }
+
+ private void buildComponentCache() {
+ // save old cache, will find changes from it
+ Map<Class<? extends Component>, Component> oldCache = componentCache;
+
+ componentCache = Maps.newHashMap();
+
+ // 1) Fill inherited components
+ for (Prefab ref : this.getParents()) {
+ for (Component component : ref.listComponents()) {
+ componentCache.put(component.getClass(), component.clone());
+ }
+ }
+
+ // 2) Find delta changes
+ if (oldCache != null) {
+ for (Component component : oldCache.values()) {
+ if (!component.equals(componentCache.get(component.getClass()))) {
+ components.put(component.getClass(), component);
+ }
+ }
+ }
+
+ // 3) Fill own components
+ for (Component component : components.values()) {
+ componentCache.put(component.getClass(), component);
+ }
+
+ // 4) PROFIT!
+ }
+
+}
View
82 src/org/terasology/entitySystem/pojo/PojoPrefabManager.java
@@ -2,68 +2,88 @@
import com.google.common.collect.Maps;
import org.terasology.entitySystem.Component;
-import org.terasology.entitySystem.PrefabRef;
+import org.terasology.entitySystem.Prefab;
import org.terasology.entitySystem.PrefabManager;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.util.Collections;
import java.util.Map;
+import java.util.Observable;
+import java.util.Observer;
/**
* @author Immortius <immortius@gmail.com>
*/
public class PojoPrefabManager implements PrefabManager {
- Map<String, Map<Class<? extends Component>, Component>> prefabTable = Maps.newHashMap();
-
- public PrefabRef create(String name) {
- if (prefabTable.containsKey(name)) {
- throw new IllegalArgumentException("Prefab name already in use: " + name);
+ protected final static String OBSERVER_EVENT_DESTROYED = "destroyed";
+ protected final static String OBSERVER_EVENT_RENAMED = "rename";
+
+ Map<String, Prefab> prefabTable = Maps.newHashMap();
+
+ public Prefab createPrefab(String name) {
+ if (exists(name)) {
+ return getPrefab(name);
}
- Map<Class<? extends Component>, Component> map = Maps.newHashMap();
- prefabTable.put(name, map);
- return new PojoPrefabRef(this, name, map);
+
+ return this.registerPrefab(new PojoPrefab(name));
}
- public PrefabRef get(String name) {
- if (prefabTable.containsKey(name)) {
- return new PojoPrefabRef(this, name, prefabTable.get(name));
- }
- return null;
+ public Prefab getPrefab(String name) {
+ return exists(name) ? prefabTable.get(name) : null;
}
public boolean exists(String name) {
return prefabTable.containsKey(name);
}
- public PrefabRef rename(String oldName, String name) {
- if (prefabTable.containsKey(name)) {
- throw new IllegalArgumentException("Prefab name already in use: " + name);
- }
- Map<Class<? extends Component>, Component> map = prefabTable.get(oldName);
- if (map == null) {
- throw new IllegalArgumentException("No prefab exists with name: " + oldName);
+ public Prefab registerPrefab(Prefab prefab) {
+ if (prefabTable.containsKey(prefab.getName())) {
+ throw new IllegalArgumentException("Prefab '" + prefab.getName() + "' already registered!");
}
- prefabTable.put(name, map);
- prefabTable.remove(oldName);
- return new PojoPrefabRef(this, name, map);
+
+ prefabTable.put(prefab.getName(), prefab);
+
+ return prefab;
+ }
+
+ public Iterable<Prefab> listPrefabs() {
+ return Collections.unmodifiableCollection(prefabTable.values());
}
- public void destroy(String name) {
+ public void removePrefab(String name) {
prefabTable.remove(name);
}
public <T extends Component> T getComponent(String name, Class<T> componentClass) {
- return null; //To change body of implemented methods use File | Settings | File Templates.
+ if (!exists(name)) {
+ return null;
+ }
+
+ return getPrefab(name).getComponent(componentClass);
}
- public void addComponent(String name, Component component) {
- //To change body of implemented methods use File | Settings | File Templates.
+ public <T extends Component> T setComponent(String name, T component) {
+ if (!exists(name)) {
+ throw new IllegalArgumentException("No prefab exists with name: " + name);
+ }
+
+ return getPrefab(name).setComponent(component);
}
public <T extends Component> void removeComponent(String name, Class<T> componentClass) {
- //To change body of implemented methods use File | Settings | File Templates.
+ if (!exists(name)) {
+ throw new IllegalArgumentException("No prefab exists with name: " + name);
+ }
+
+ getPrefab(name).removeComponent(componentClass);
}
- public void saveComponent(String name, Component component) {
- //To change body of implemented methods use File | Settings | File Templates.
+ protected class PrefabObserver implements Observer {
+
+ public void update(Observable o, Object arg) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
}
}
View
75 src/org/terasology/entitySystem/pojo/PojoPrefabRef.java
@@ -1,75 +0,0 @@
-package org.terasology.entitySystem.pojo;
-
-import com.google.common.base.Objects;
-import org.terasology.entitySystem.Component;
-import org.terasology.entitySystem.PrefabRef;
-import org.terasology.entitySystem.PrefabManager;
-
-import java.util.Map;
-
-/**
- * @author Immortius <immortius@gmail.com>
- */
-public class PojoPrefabRef implements PrefabRef {
- private PrefabManager manager;
- private String name;
- private Map<Class<? extends Component>, Component> componentMap;
-
- PojoPrefabRef(PrefabManager manager, String name, Map<Class<? extends Component>, Component> componentMap) {
- this.manager = manager;
- this.name = name;
- this.componentMap = componentMap;
- }
-
- public String getName() {
- return name;
- }
-
- public void rename(String newName) {
- manager.rename(name, newName);
- name = newName;
- }
-
- public <T extends Component> T getComponent(Class<T> componentClass) {
- return componentClass.cast(componentMap.get(componentClass));
- }
-
- public <T extends Component> T addComponent(T component) {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void removeComponent(Class<? extends Component> componentClass) {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void saveComponent(Component component) {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public Iterable<Component> iterateComponents() {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void destroy() {
- manager.destroy(name);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o instanceof PojoPrefabRef) {
- return Objects.equal(name, ((PojoPrefabRef)o).name);
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(name);
- }
-
- @Override
- public String toString() {
- return "Prefab:" + name;
- }
-}
View
62 tests/org/terasology/entitySystem/PojoPrefabManagerTest.java
@@ -2,9 +2,12 @@
import org.junit.Before;
import org.junit.Test;
+import org.terasology.components.LocationComponent;
import org.terasology.entitySystem.pojo.PojoPrefabManager;
import org.terasology.entitySystem.stubs.StringComponent;
+import javax.vecmath.Vector3f;
+
import static org.junit.Assert.*;
/**
@@ -22,64 +25,63 @@ public void setup() {
@Test
public void retrieveNonExistentPrefab() {
- assertNull(prefabManager.get(PrefabName));
+ assertNull(prefabManager.getPrefab(PrefabName));
}
@Test
public void createPrefab() {
- PrefabRef ref = prefabManager.create(PrefabName);
+ Prefab ref = prefabManager.createPrefab(PrefabName);
assertNotNull(ref);
assertEquals(PrefabName, ref.getName());
assertTrue(prefabManager.exists(PrefabName));
}
@Test
public void retrievePrefab() {
- prefabManager.create(PrefabName);
- PrefabRef ref = prefabManager.get(PrefabName);
+ prefabManager.createPrefab(PrefabName);
+ Prefab ref = prefabManager.getPrefab(PrefabName);
assertNotNull(ref);
assertEquals(PrefabName, ref.getName());
}
- @Test(expected = IllegalArgumentException.class)
+ @Test
public void errorIfCreatePrefabWithUsedName() {
- prefabManager.create(PrefabName);
- prefabManager.create(PrefabName);
+ assertEquals(prefabManager.createPrefab(PrefabName), prefabManager.createPrefab(PrefabName));
}
@Test
- public void renamePrefab() {
- PrefabRef ref = prefabManager.create(PrefabName);
- ref.rename("NewName");
-
- assertEquals("NewName", ref.getName());
- assertNotNull(prefabManager.get("NewName"));
- assertNull(prefabManager.get(PrefabName));
- assertTrue(prefabManager.exists("NewName"));
- assertFalse(prefabManager.exists(PrefabName));
- }
-
- @Test
- public void destroyPrefab() {
- PrefabRef ref = prefabManager.create(PrefabName);
- ref.destroy();
- assertFalse(prefabManager.exists(PrefabName));
- }
-
- @Test
public void prefabRefEquals() {
- prefabManager.create(PrefabName);
- assertEquals(prefabManager.get(PrefabName), prefabManager.get(PrefabName));
+ prefabManager.createPrefab(PrefabName);
+
+ assertEquals(prefabManager.getPrefab(PrefabName), prefabManager.getPrefab(PrefabName));
}
@Test
public void addAndRetrieveComponent() {
- PrefabRef prefab = prefabManager.create(PrefabName);
- StringComponent comp = prefab.addComponent(new StringComponent());
+ Prefab prefab = prefabManager.createPrefab(PrefabName);
+ StringComponent comp = prefab.setComponent(new StringComponent());
assertNotNull(comp);
assertEquals(comp, prefab.getComponent(StringComponent.class));
}
+ @Test
+ public void testPrefabInheritance() {
+ Prefab parentPrefab = prefabManager.createPrefab("parentPrefab");
+
+ LocationComponent testComponent = new LocationComponent();
+ parentPrefab.setComponent(testComponent);
+
+
+ Prefab prefab = prefabManager.createPrefab(PrefabName);
+ prefab.addParent(parentPrefab);
+
+ assertEquals(testComponent, prefab.getComponent(testComponent.getClass()));
+
+ prefab.getComponent(testComponent.getClass()).position.set(1, 1, 1);
+
+ assertNotSame(testComponent, prefab.getComponent(testComponent.getClass()));
+ }
+
}
View
113 tests/org/terasology/entitySystem/PrefabPersisterTests.java
@@ -0,0 +1,113 @@
+package org.terasology.entitySystem;
+
+import org.junit.Test;
+import org.terasology.components.LocationComponent;
+import org.terasology.entitySystem.persist.PersisterFactory;
+import org.terasology.entitySystem.persist.PrefabPersister;
+import org.terasology.entitySystem.pojo.PojoPrefabManager;
+import org.terasology.entitySystem.stubs.StringComponent;
+
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class PrefabPersisterTests {
+
+ private PrefabManager manager = new PojoPrefabManager();
+ private Prefab prefab;
+
+ public PrefabPersisterTests() {
+ this.initializeData();
+ }
+
+ private void initializeData() {
+ prefab = manager.createPrefab("prefab");
+
+ StringComponent component = new StringComponent();
+ component.value = "test";
+
+ prefab.setComponent(component);
+
+ LocationComponent loc = new LocationComponent();
+
+ loc.position.set(1, 1, 1);
+
+
+
+ Prefab parentPrefab = manager.createPrefab("parentPrefab");
+
+ parentPrefab.setComponent(loc);
+
+ prefab.addParent(parentPrefab);
+ }
+
+ @Test
+ public void testPrefabManagerSerializationDeserialization() throws Exception {
+
+ PrefabPersister persister = PersisterFactory.createPrefabPersister();
+
+ StringWriter writer = new StringWriter();
+
+ persister.savePrefabs(writer, manager);
+
+ String firstPass = writer.getBuffer().toString();
+
+ StringReader reader = new StringReader(writer.getBuffer().toString());
+ PrefabManager deserializedMananger = persister.loadPrefabs(reader);
+
+ // Comparing collections
+ Iterator<Prefab> one = manager.listPrefabs().iterator();
+ Iterator<Prefab> two = deserializedMananger.listPrefabs().iterator();
+
+ while (one.hasNext() || two.hasNext()) {
+ // To ensure both collections is same size
+ assertTrue(one.hasNext() && two.hasNext());
+ // To ensure both collections elements are equals and in same order
+ assertEquals(one.next(), two.next());
+ }
+
+ writer = new StringWriter();
+
+ persister.savePrefabs(writer, deserializedMananger);
+
+ String secondPass = writer.getBuffer().toString();
+
+ assertEquals(firstPass, secondPass);
+ }
+
+ @Test
+ public void testPrefabSerializationDeserialization() throws Exception {
+
+ PrefabPersister persister = PersisterFactory.createPrefabPersister();
+
+ StringWriter writer = new StringWriter();
+
+ /** First serialization pass **/
+ persister.savePrefab(writer, prefab);
+ String firstPass = writer.getBuffer().toString();
+
+ /** Clear space for deserialized prefab **/
+ manager.removePrefab(prefab.getName());
+
+ /** Deserialization **/
+ StringReader reader = new StringReader(writer.getBuffer().toString());
+ Prefab deserializedPrefab = persister.loadPrefab(reader, manager);
+
+ writer = new StringWriter();
+
+ /** Second serialization pass (using deserialized object) **/
+ persister.savePrefab(writer, deserializedPrefab);
+ String secondPass = writer.getBuffer().toString();
+
+ /** Checks first and second pass results **/
+ assertEquals(firstPass, secondPass);
+
+ /** Check serialization results **/
+ assertEquals(prefab, deserializedPrefab);
+ }
+}
View
1 tests/org/terasology/entitySystem/stubs/IntegerComponent.java
@@ -1,7 +1,6 @@
package org.terasology.entitySystem.stubs;
import org.terasology.entitySystem.AbstractComponent;
-import org.terasology.entitySystem.Component;
import org.terasology.persistence.interfaces.StorageReader;
import org.terasology.persistence.interfaces.StorageWriter;

0 comments on commit 6068ec9

Please sign in to comment.
Something went wrong with that request. Please try again.