From a93df06145d26bf4b43719747ff2dee21d2c100d Mon Sep 17 00:00:00 2001 From: damagefilter Date: Wed, 31 Jul 2013 17:14:50 +0200 Subject: [PATCH] Implementing custom world generation. Adresses #21 Added a custom world provider abstract class that one can implement, in order to realise custom world generation. Custom world generators can be registered at DimensionType. If Canary comes across a Dimensiontype that has a provider attached, it will laod that instead of a normal one. Obviously - this needs testing --- .../java/net/canarymod/api/entity/Entity.java | 140 +++++++++--------- .../canarymod/api/world/ChunkProvider.java | 28 ++-- .../api/world/ChunkProviderCustom.java | 57 +++++++ .../canarymod/api/world/DimensionType.java | 69 ++++++++- .../net/canarymod/api/world/WorldType.java | 4 +- 5 files changed, 211 insertions(+), 87 deletions(-) create mode 100644 src/main/java/net/canarymod/api/world/ChunkProviderCustom.java diff --git a/src/main/java/net/canarymod/api/entity/Entity.java b/src/main/java/net/canarymod/api/entity/Entity.java index a9b9317a..23ecfb8c 100644 --- a/src/main/java/net/canarymod/api/entity/Entity.java +++ b/src/main/java/net/canarymod/api/entity/Entity.java @@ -13,7 +13,7 @@ /** * This defines an entity in the world * Everything that is not a block inherits from Entity in a way. - * + * * @author Chris (damagefilter) * @author Jason (darkdiplomat) */ @@ -21,91 +21,91 @@ public interface Entity { /** * Get X position - * + * * @return x position */ public double getX(); /** * Get Y position - * + * * @return y position */ public double getY(); /** * Get Z position - * + * * @return z position */ public double getZ(); /** * Get X Motion (movement speed) - * + * * @return x motion */ public double getMotionX(); /** * Get Y Motion (movement speed) - * + * * @return y motion */ public double getMotionY(); /** * Get Z Motion (movement speed) - * + * * @return z motion */ public double getMotionZ(); /** * Get this Entities pitch (up or down looking) (Rotation around X axis) - * + * * @return pitch */ public float getPitch(); /** * Get this entities look direction (Rotation around Y axis) - * + * * @return rotation */ public float getRotation(); /** * Returns this entities coordinates in a Vector3D object - * + * * @return {@link Position} */ public Position getPosition(); /** * Get this entities location, including world, dimension, pitch and rotation and coordinates - * + * * @return {@link Location} */ public Location getLocation(); /** * Get the assigned unique ID for this entity - * + * * @return id */ public int getID(); /** * Gets the assigned UUID for this entity - * + * * @return {@link UUID} */ public UUID getUUID(); /** * Set X coordinate - * + * * @param x * the X coordinate to set */ @@ -113,7 +113,7 @@ public interface Entity { /** * Set X coordinate - * + * * @param x * the X coordinate to set */ @@ -121,7 +121,7 @@ public interface Entity { /** * Set Y coordinate - * + * * @param y * the Y coordinate to set */ @@ -129,7 +129,7 @@ public interface Entity { /** * Set Y coordinate - * + * * @param y * the Y coordinate to set */ @@ -137,7 +137,7 @@ public interface Entity { /** * Set Z coordinate - * + * * @param z * the Z coordinate to set */ @@ -145,7 +145,7 @@ public interface Entity { /** * Set Z coordinate - * + * * @param z * the Z coordinate to set */ @@ -153,7 +153,7 @@ public interface Entity { /** * Set X Motion (movement speed) - * + * * @param motionX * the X-wise motion */ @@ -161,7 +161,7 @@ public interface Entity { /** * Set Y Motion (movement speed) - * + * * @param motionY * the Y-wise motion */ @@ -169,7 +169,7 @@ public interface Entity { /** * Set Z Motion (movement speed) - * + * * @param motionZ * the Z-wise motion */ @@ -177,7 +177,7 @@ public interface Entity { /** * Set this entities pitch (up / down looking) - * + * * @param pitch * the Y rotation to set */ @@ -185,7 +185,7 @@ public interface Entity { /** * Set this entities rotation - * + * * @param rotation * the X rotation to set */ @@ -194,7 +194,7 @@ public interface Entity { /** * Get the motion vector of this entity. * This is a convenience for position calculations - * + * * @return {@link Vector3D} */ public Vector3D getMotion(); @@ -202,14 +202,14 @@ public interface Entity { /** * Returns the forward direction of this entity. * Convenience for position calculations - * + * * @return {@link Vector3D} */ public Vector3D getForwardVector(); /** * Translates this entity in its position by the given Vector3D. - * + * * @param factor * the {@link Vector3D} factor */ @@ -219,7 +219,7 @@ public interface Entity { * Move this entity with the forces given. Note that those are not the * coordinates to move to! It does also not translate the entity on a vector. * This simply adds force to this entity - * + * * @param motionX * the X-wise motion * @param motionY @@ -231,7 +231,7 @@ public interface Entity { /** * Teleport this entity to the given coordinates - * + * * @param x * the X coordinate * @param y @@ -243,7 +243,7 @@ public interface Entity { /** * Teleport to this coords in the given dimension - * + * * @param x * the X coordinate * @param y @@ -258,23 +258,23 @@ public interface Entity { /** * Teleport this entity to the given coordinates, with the given pitch and rotation to look at * this.entity.b(x, y, z, rotation, pitch); - * + * * @param x * the X coordinate * @param y * the Y coordinate * @param z * the Z coordinate - * @param rotation - * the X-wise rotation * @param pitch * the Y-wise rotation + * @param rotation + * the X-wise rotation */ - public void teleportTo(double x, double y, double z, float rotation, float pitch); + public void teleportTo(double x, double y, double z, float pitch, float rotation); /** * Teleport to this location in the given world - * + * * @param x * the X coordinate * @param y @@ -292,7 +292,7 @@ public interface Entity { /** * Teleport to the specified location - * + * * @param location * the {@link Location} to teleport to */ @@ -300,7 +300,7 @@ public interface Entity { /** * Teleport this entity to the given position - * + * * @param position * the {@link Position} to teleport to */ @@ -308,7 +308,7 @@ public interface Entity { /** * Set this Entities dimension. (will teleport to the dimension) - * + * * @param dim * the {@link World} */ @@ -316,21 +316,21 @@ public interface Entity { /** * Get this entities world(dimension) - * + * * @return {@link World} */ public World getWorld(); /** * Checks if the player is sprinting - * + * * @return {@code true} if sprinting; {@code false} otherwise */ public boolean isSprinting(); /** * Mark this entity as spriting or not sprinting - * + * * @param sprinting * {@code true} for sprinting; {@code false} otherwise */ @@ -338,14 +338,14 @@ public interface Entity { /** * Returns whether this entity is sneaking - * + * * @return {@code true} if sneaking; {@code false} otherwise */ public boolean isSneaking(); /** * Mark this entity as sneaking or not - * + * * @param sneaking * {@code true} for sneaking; {@code false} otherwise */ @@ -355,7 +355,7 @@ public interface Entity { * Set how many ticks are left until entity catches fire. Note that there's * a base amount of ticks that is always there and if the current fire ticks * are smaller than 20% of the base ticks, the entity will catch fire. - * + * * @param ticks * the fire ticks to set */ @@ -363,56 +363,56 @@ public interface Entity { /** * Get how many ticks are left until entity catches fire. - * + * * @return fire ticks */ public int getFireTicks(); /** * Check if this entity is a living entity - * + * * @return {@code true} if living; {@code false} otherwise */ public boolean isLiving(); /** * Check if this entity is an item entity - * + * * @return {@code true} if {@link EntityItem}; {@code false} otherwise */ public boolean isItem(); /** * Check if this entity is a mob - * + * * @return {@code true} when it is a mob */ public boolean isMob(); /** * Check if this entity is an animal (implements the animal interface) - * + * * @return {@code true} if animal; {@code false} otherwise */ public boolean isAnimal(); /** * Check if this entity is a player entity - * + * * @return {@code true} when it is a player */ public boolean isPlayer(); /** * Checks if this entity is a {@link Golem} - * + * * @return {@code true} if {@link Golem}; {@code false} if not */ public boolean isGolem(); /** * Make this entity drop the given item - * + * * @param itemId * the {@link Item} id to drop * @param amount @@ -423,7 +423,7 @@ public interface Entity { /** * Make this entity drop the given item - * + * * @param item * the {@link Item} to be dropped * @return the resulting {@link EntityItem} @@ -432,35 +432,35 @@ public interface Entity { /** * Get this entity's name, can either be its qualified name or display name if present - * + * * @return name */ public String getName(); /** * Gets the Entity's qualified name (ie: Class Name) - * + * * @return qualified name */ public String getFqName(); /** * Check if this entity can spawn at its current specified position or not - * + * * @return {@code true} if the entity can; {@code false} otherwise */ public boolean canSpawn(); /** * Spawn this entity in the world. - * + * * @return {@code true} if successful; {@code false} if not */ public boolean spawn(); /** * Spawn this entity with a given rider entity - * + * * @param rider * the {@code Entity} rider * @return {@code true} if successful; {@code false} otherwise @@ -469,28 +469,28 @@ public interface Entity { /** * Check if this Entity is riding another entity. - * + * * @return {@code true} if the entity is riding another entity; {@code false} otherwise */ public boolean isRiding(); /** * Checks if the Entity is being ridden by another Entity. - * + * * @return {@code true} if being ridden; {@code false} if not */ public boolean isRidden(); /** * Gets the Entity the Entity is riding - * + * * @return the Entity being ridden by the Entity; {@code null} if not riding */ public Entity getRiding(); /** * Gets the Entity the Entity is being ridden by - * + * * @return the Entity that is riding the Entity; {@code null} if no rider */ public Entity getRider(); @@ -498,7 +498,7 @@ public interface Entity { /** * Set this entities rider. * The given EntityLiving will be attached as rider on this entity. - * + * * @param rider * the {@code Entity} rider */ @@ -511,14 +511,14 @@ public interface Entity { /** * Gets whether this Entity is pending clean up - * + * * @return {@code true} if dead; {@code false} otherwise */ public boolean isDead(); /** * Get's the NBT Tag for this Entity. - * + * * @return {@link CompoundTag} */ public CompoundTag getNBT(); @@ -526,7 +526,7 @@ public interface Entity { /** * Set this NBT Tag for this entity. Any missing values will be overridden * to the defaults. - * + * * @param tag * The tag to set * @see #getNBT() @@ -535,14 +535,14 @@ public interface Entity { /** * Returns whether this entity is invisible - * + * * @return {@code true} if invisible; {@code false} otherwise */ public boolean isInvisible(); /** * Mark this entity as invisible or not - * + * * @param invisible * {@code true} for invisible; {@code false} for visible */ @@ -550,14 +550,14 @@ public interface Entity { /** * Gets the persistent MetaData tag for the Entity - * + * * @return MetaData */ public CompoundTag getMetaData(); /** * Gets the Type of the entity - * + * * @return the {@link EntityType} */ public EntityType getEntityType(); diff --git a/src/main/java/net/canarymod/api/world/ChunkProvider.java b/src/main/java/net/canarymod/api/world/ChunkProvider.java index 7dcf5421..8d3351df 100644 --- a/src/main/java/net/canarymod/api/world/ChunkProvider.java +++ b/src/main/java/net/canarymod/api/world/ChunkProvider.java @@ -7,14 +7,14 @@ * then mapped to dimension types - in order to provide custom world generation.
*

Custom World Generation

This is the interface everything related to world generation boils down to. * A world will use this to create its terrain and call the provideChunk methid. - * + * * @author Chris (damagefilter) */ public interface ChunkProvider { /** * Check if this chunk provider is allowed to save chunks - * + * * @return true if chunks can be saved, false otherwise * @PluginDev You do not need to implement this */ @@ -23,17 +23,18 @@ public interface ChunkProvider { /** * Check if a chunk at the given coords exist * The x/z must be chunk coordinates, that means right-shifted by 4 - * + * * @param x * @param z * @return + * @PluginDev You do not need to implement this */ public boolean chunkExists(int x, int z); /** * Load chunk at that x-z coordinate * The x/z must be chunk coordinates, that means right-shifted by 4 - * + * * @param x * @param z * @return Chunk that has been loaded @@ -44,7 +45,7 @@ public interface ChunkProvider { * Is called after the large-scale generation is done to populate the world with details. * For instance glowstone blocks * The x/z must be chunk coordinates, that means right-shifted by 4 - * + * * @param provider * @param x * @param z @@ -55,15 +56,16 @@ public interface ChunkProvider { * Return a String that displays the statistics for this ChunkProvider. * This will be shown in the servers GUI for instance.
* The default NMS method returns the size of the Chunk Cache and the number of dropped chunks - * + * * @return + * @PluginDev You do not need to implement this (But you can) */ public String getStatistics(); /** * Reload the given chunk. * The x/z must be chunk coordinates, that means right-shifted by 4 - * + * * @return true when successful, false otherwise * @PluginDev You do not need to implement this */ @@ -72,17 +74,17 @@ public interface ChunkProvider { /** * Drop the chunk at the given coordinates * The x/z must be chunk coordinates, that means right-shifted by 4 - * + * * @return true when successful, false otherwise * @PluginDev You do not need to implement this */ public void dropChunk(int x, int z); /** - * Provides an Chunk. If that chunk didn't exist in any case it will + * Provides a Chunk. If that chunk didn't exist in any case it will * generate a new one. * The x/z must be chunk coordinates, that means right-shifted by 4 - * + * * @param x * @param z * @return @@ -91,7 +93,7 @@ public interface ChunkProvider { /** * Save up to two chunks or if saveAll is true, save all chunks. - * + * * @param saveAll * @return true on success, false otherwise * @PluginDev You do not need to implement this @@ -101,7 +103,7 @@ public interface ChunkProvider { /** * Regenerate the whole chunk at the given x/z coordinate. * The x/z must be chunk coordinates, that means right-shifted by 4 - * + * * @param x * @param z * @return @@ -111,7 +113,7 @@ public interface ChunkProvider { /** * Check if a chunk at the specified coordinates is loaded * The x/z must be chunk coordinates, that means right-shifted by 4 - * + * * @param x * @param z * @return diff --git a/src/main/java/net/canarymod/api/world/ChunkProviderCustom.java b/src/main/java/net/canarymod/api/world/ChunkProviderCustom.java new file mode 100644 index 00000000..2015fd0c --- /dev/null +++ b/src/main/java/net/canarymod/api/world/ChunkProviderCustom.java @@ -0,0 +1,57 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package net.canarymod.api.world; + +/** + * A ChunkProvider that is used to implement custom world generation. + * + * Note that implementations of this class must not have constructors with arguments. + * + * + * @author Chris(damagefilter) + */ +public abstract class ChunkProviderCustom { + protected World world; + + /** + * Will be called when a new chunk needs to be generated. + * The x/z are Chunk coordinates. (right-shifted by 4) + * + * @param x + * @param z + * @return + */ + public abstract Chunk provideChunk(int x, int z); + + + /** + * Is called after the large-scale generation is done to populate the world with details. + * For instance glowstone blocks + * The x/z are chunk coordinates, that means right-shifted by 4 + * + * @param x + * @param z + */ + public abstract void populate(int x, int z); + + /** + * Is called after populate(), in order to create or re-create structures. + * That means: Houses, Strongholds, temples and the likes + * @param x + * @param z + */ + public abstract void createStructures(int x, int z); + + /** + * Set the world used for this generator. + * Canary will call this before the generation process starts, + * to make sure the world exists. + * @param world + */ + public void setWorld(World world) { + this.world = world; + } + +} diff --git a/src/main/java/net/canarymod/api/world/DimensionType.java b/src/main/java/net/canarymod/api/world/DimensionType.java index 51f68e20..f70a28c9 100644 --- a/src/main/java/net/canarymod/api/world/DimensionType.java +++ b/src/main/java/net/canarymod/api/world/DimensionType.java @@ -1,11 +1,13 @@ package net.canarymod.api.world; import java.util.HashMap; +import java.util.logging.Level; +import java.util.logging.Logger; import net.canarymod.Canary; /** * Dynamic worldType list - * + * * @author Chris */ public class DimensionType { @@ -13,7 +15,7 @@ public class DimensionType { // *** STATIC STUFF *** private static HashMap typeList = new HashMap(5); // 3 std dims and 2 extras - public static void addType(String name, int id) { + public static void registerType(String name, int id) { if (typeList.containsKey(name)) { Canary.logWarning("Tried to add existing world type, aborting! WorldType: " + name); return; @@ -26,6 +28,19 @@ public static void addType(String name, int id) { } } + public static void registerType(String name, int id, Class cpc) { + if (typeList.containsKey(name)) { + Canary.logWarning("Tried to add existing world type, aborting! WorldType: " + name); + return; + } + if (validateId(id)) { + typeList.put(name, new DimensionType(name, id, cpc)); + } else { + Canary.logWarning("WorldType ID is not unique! Id: " + id + ", Type: " + name + " - Creating unique ID from hashCode!"); + typeList.put(name, new DimensionType(name, name.hashCode(), cpc)); + } + } + public static DimensionType fromName(String name) { return typeList.get(name); } @@ -52,6 +67,12 @@ private static boolean validateId(int id) { return true; } + /** + * Check if a type with the given name exists. + * This is case sensitive + * @param name + * @return + */ public static boolean typeExists(String name) { return typeList.containsKey(name); } @@ -60,6 +81,7 @@ public static boolean typeExists(String name) { private int id; private String name; + private Class cpc = null; // Make sure no-one can just instantiate a new world type private DimensionType(String name, int id) { @@ -67,14 +89,55 @@ private DimensionType(String name, int id) { this.name = name; } + private DimensionType(String name, int id, Class cpc) { + this.id = id; + this.name = name; + this.cpc = cpc; + } + + /** + * Get the ID of this dimension type. With this ID the DimensionType can be identified. + * @return + */ public int getId() { return id; } + /** + * Get the name of this dimension type + * @return + */ public String getName() { return name; } + /** + * Checks if this dimension type has a custom chunk provider attached + * @return + */ + public boolean hasChunkProvider() { + return cpc != null; + } + + /** + * Get the ChunkProviderCustom that is attached to this Dimensiontype. + * Note that this returns null if the DimensionType has no provider attached + * @return + */ + public ChunkProviderCustom getChunkProvider() { + try { + return cpc.newInstance(); + } + catch (InstantiationException ex) { + Canary.logSevere(ex.getMessage()); + } + catch (IllegalAccessException ex) { + Canary.logSevere(ex.getMessage()); + } + return null; + } + + @Override public boolean equals(Object ob) { if (!(ob instanceof DimensionType)) { return false; @@ -84,10 +147,12 @@ public boolean equals(Object ob) { return o.name.equals(name) && o.id == id; } + @Override public int hashCode() { return name.hashCode() + id; } + @Override public String toString() { return name + ":" + id; } diff --git a/src/main/java/net/canarymod/api/world/WorldType.java b/src/main/java/net/canarymod/api/world/WorldType.java index 8ebd0d8b..08033d75 100644 --- a/src/main/java/net/canarymod/api/world/WorldType.java +++ b/src/main/java/net/canarymod/api/world/WorldType.java @@ -21,7 +21,7 @@ private WorldType(String string) { /** * Register a new WorldType. - * + * * @param name * @return */ @@ -41,7 +41,7 @@ public String toString() { /** * get a worldType from string. * This may return null if the requested WorldType does not exist! - * + * * @param string * @return */