/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.pepsoft.worldpainter.objects;
import java.io.File;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import javax.vecmath.Point3i;
import org.pepsoft.minecraft.Entity;
import org.pepsoft.minecraft.Material;
import org.pepsoft.minecraft.TileEntity;
/**
* A three dimensional object, consisting of Minecraft blocks, which can be
* placed in a map.
*
* @author pepijn
*/
public interface WPObject extends Serializable, Cloneable {
/**
* Get the name of the object.
*
* @return The name of the object.
*/
String getName();
/**
* Set the name of the object.
*
* @param name The new name of the object.
*/
void setName(String name);
/**
* Get the dimensions of the object.
*
* @return The dimensions of the object.
*/
Point3i getDimensions();
/**
* Get the offset to apply to this object when placing it. In other words
* these are the reverse of the coordinates of the "anchor" block of this
* object.
*
* <p>This is a convenience method which must return the same as invoking
* <code>getAttribute(ATTRIBUTE_OFFSET)</code>. See
* {@link #getAttribute(AttributeKey)} and {@link #ATTRIBUTE_OFFSET}.
*
* @return The offset to apply to this object when placing it.
*/
Point3i getOffset();
/**
* Get the material to place at the specified relative coordinates. Should
* only be invoked for coordinates for which {@link #getMask(int, int, int)}
* returns <code>true</code>.
*
* @param x The relative X coordinate.
* @param y The relative Y coordinate.
* @param z The relative Z coordinate.
* @return The material to place at the specified relative coordinates.
*/
Material getMaterial(int x, int y, int z);
/**
* Determine whether a block should be placed at the specified relative
* coordinates.
*
* @param x The relative X coordinate.
* @param y The relative Y coordinate.
* @param z The relative Z coordinate.
* @return <code>true</code> if a block should be placed at the specified
* relative coordinates.
*/
boolean getMask(int x, int y, int z);
/**
* Get any entities contained in the object. The entities' coordinates
* should be relative to the object, not absolute.
*
* @return Any entities contained in the object. May be <code>null</code>.
*/
List<Entity> getEntities();
/**
* Get any tile entities contained in the object. The entities' coordinates
* should be relative to the object, not absolute.
*
* @return Any tile entities contained in the object. May be
* <code>null</code>.
*/
List<TileEntity> getTileEntities();
/**
* Get a live view of the object metadata.
*
* @return A live view of the object metadata. May be <code>null</code>.
*/
Map<String, Serializable> getAttributes();
/**
* Convencience method for getting the value of an attribute stored in the
* external metadata, if any. Should return the value of the attribute if it
* is present, or a default value (which may be <code>null</code>) if it is
* not.
*
* @param <T> The type of the attribute.
* @param key The key of the attribute.
* @return The value of the specified attribute, or the specified default
* value if the attribute is not set.
*/
<T extends Serializable> T getAttribute(AttributeKey<T> key);
/**
* Store external metadata about the object.
*
* @param attributes The external metadata to store.
*/
void setAttributes(Map<String, Serializable> attributes);
/**
* Convenience method for setting the value of an attribute stored in the
* external metadata, if any. Setting the value to <code>null</code> will
* delete the attribute from the store. If the store becomes empty it is
* deleted entirely.
*
* @param <T> The type of the attribute.
* @param key The key of the attribute to set or delete.
* @param value The value of the attribute to set, or <code>null</code> to
* delete it.
*/
<T extends Serializable> void setAttribute(AttributeKey<T> key, T value);
/**
* Create a clone of the object. The block data is immutable so may be
* shared, but all mutable settings are copied so they can be changed
* independently.
*
* @return A clone of the object.
*/
WPObject clone();
// Standard attribute values
int COLLISION_MODE_ALL = 1;
int COLLISION_MODE_SOLID = 2;
int COLLISION_MODE_NONE = 3;
int LEAF_DECAY_NO_CHANGE = 1;
int LEAF_DECAY_ON = 2;
int LEAF_DECAY_OFF = 3;
// Standard attribute keys
AttributeKey<File> ATTRIBUTE_FILE = new AttributeKey<>("WPObject.file");
AttributeKey<Point3i> ATTRIBUTE_OFFSET = new AttributeKey<>("WPObject.offset", new Point3i());
AttributeKey<Boolean> ATTRIBUTE_RANDOM_ROTATION = new AttributeKey<>("WPObject.randomRotation", true);
AttributeKey<Boolean> ATTRIBUTE_NEEDS_FOUNDATION = new AttributeKey<>("WPObject.needsFoundation", true);
AttributeKey<Boolean> ATTRIBUTE_SPAWN_IN_WATER = new AttributeKey<>("WPObject.spawnInWater", false);
AttributeKey<Boolean> ATTRIBUTE_SPAWN_IN_LAVA = new AttributeKey<>("WPObject.spawnInLava", false);
AttributeKey<Boolean> ATTRIBUTE_SPAWN_ON_LAND = new AttributeKey<>("WPObject.spawnOnLand", true);
AttributeKey<Boolean> ATTRIBUTE_SPAWN_ON_WATER = new AttributeKey<>("WPObject.spawnOnWater", false);
AttributeKey<Boolean> ATTRIBUTE_SPAWN_ON_LAVA = new AttributeKey<>("WPObject.spawnOnLava", false);
AttributeKey<Integer> ATTRIBUTE_FREQUENCY = new AttributeKey<>("WPObject.frequency", 100);
/**
* Collision mode. Possible values:
*
* <p><table><tr><th>Value</th><th>Meaning</th></tr>
* <tr><td>{@link #COLLISION_MODE_ALL}</td><td>Will collide with (and therefore not render) any above ground block other than air</td></tr>
* <tr><td><strong>{@link #COLLISION_MODE_SOLID}</strong></td><td>Will collide with (and therefore not render) any above ground <em>solid</em> block (i.e. not air, grass, water, flowers, leaves, etc.). Default value</td></tr>
* <tr><td>{@link #COLLISION_MODE_NONE}</td><td>Will not collide with <em>any</em> above ground block (and therefore intersect any other object already there!)</td></tr></table>
*/
AttributeKey<Integer> ATTRIBUTE_COLLISION_MODE = new AttributeKey<>("WPObject.collisionMode", COLLISION_MODE_SOLID); // See COLLISION_MODE_* constants
/**
* Underground rendering mode. Possible values:
*
* <p><table><tr><th>Value</th><th>Meaning</th></tr>
* <tr><td><strong>{@link #COLLISION_MODE_ALL}</strong></td><td>Every underground block belonging to the object will be rendered (including air blocks), regardless of what is already there. Default value</td></tr>
* <tr><td>{@link #COLLISION_MODE_SOLID}</td><td>Every <em>solid</em> (i.e. not air, grass, water, flowers, leaves, etc.) underground block belonging to the object will be rendered regardless of what is already there. Non-solid blocks will be rendered only if the existing block is air</td></tr>
* <tr><td>{@link #COLLISION_MODE_NONE}</td><td>Underground blocks belonging to the object will only be rendered if the existing block is air</td></tr></table>
*/
AttributeKey<Integer> ATTRIBUTE_UNDERGROUND_MODE = new AttributeKey<>("WPObject.undergroundMode", COLLISION_MODE_ALL); // See COLLISION_MODE_* constants
/**
* Whether to change leaf blocks so that they do or do not decay. Possible values:
*
* <p><table><tr><th>Value</th><th>Meaning</th></tr>
* <tr><td><strong>{@link #LEAF_DECAY_NO_CHANGE}</strong></td><td>Leaf blocks are copied unchanged from the custom object. Default value</td></tr>
* <tr><td>{@link #LEAF_DECAY_ON}</td><td>All leaf blocks are set to decay regardless of their setting in the custom object</td></tr>
* <tr><td>{@link #LEAF_DECAY_OFF}</td><td>All leaf blocks are set to <em>not</em> decay regardless of their setting in the custom object</td></tr></table>
*/
AttributeKey<Integer> ATTRIBUTE_LEAF_DECAY_MODE = new AttributeKey<>("WPObject.leafDecay", LEAF_DECAY_NO_CHANGE); // See LEAF_DECAY_* constants
/**
* When set, describes a block ID (index 0) and data (index 1) combination
* which will be replaced with air blocks when this object is rendered.
* Mainly meant to be able to create voids underground using schematics,
* which is otherwise not possible since there is no way to tell whether an
* air block from a schematic is supposed to be placed or not.
*/
AttributeKey<int[]> ATTRIBUTE_REPLACE_WITH_AIR = new AttributeKey<>("WPObject.replaceWithAir");
/**
* When set, the blocks on the lowest level of the object will be copied
* downwards until they meet a solid block, if they end up being placed
* floating in the air. This allows objects to have "legs", "roots" or a
* "foundation" which will be extended by WorldPainter to meet the ground.
*/
AttributeKey<Boolean> ATTRIBUTE_EXTEND_FOUNDATION = new AttributeKey<>("WPObject.extendFoundation", false);
/**
* A utility class for getting a typed attribute value with a default
* conveniently.
*
* @param <T> The value type of the attribute.
*/
final class AttributeKey<T extends Serializable> {
public AttributeKey(String key) {
this(key, null);
}
public AttributeKey(String key, T defaultValue) {
if (key == null) {
throw new NullPointerException("key");
}
this.key = key;
this.defaultValue = defaultValue;
}
@SuppressWarnings("unchecked") // Responsibility of client
public T get(Map<String, Serializable> values) {
return ((values != null) && values.containsKey(key)) ? (T) values.get(key) : defaultValue;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AttributeKey<?> that = (AttributeKey<?>) o;
if (!key.equals(that.key)) return false;
return true;
}
@Override
public int hashCode() {
return key.hashCode();
}
public final String key;
public final T defaultValue;
}
}