BY_ID = Maps.newHashMap();
+
+ private Art(int id, int width, int height) {
+ this.id = id;
+ this.width = width;
+ this.height = height;
+ }
+
+ /**
+ * Gets the width of the painting, in blocks
+ *
+ * @return The width of the painting, in blocks
+ */
+ public int getBlockWidth() {
+ return width;
+ }
+
+ /**
+ * Gets the height of the painting, in blocks
+ *
+ * @return The height of the painting, in blocks
+ */
+ public int getBlockHeight() {
+ return height;
+ }
+
+ /**
+ * Get the ID of this painting.
+ *
+ * @return The ID of this painting
+ * @deprecated Magic value
+ */
+ @Deprecated
+ public int getId() {
+ return id;
+ }
+
+ /**
+ * Get a painting by its numeric ID
+ *
+ * @param id The ID
+ * @return The painting
+ * @deprecated Magic value
+ */
+ @Deprecated
+ public static Art getById(int id) {
+ return BY_ID.get(id);
+ }
+
+ /**
+ * Get a painting by its unique name
+ *
+ * This ignores underscores and capitalization
+ *
+ * @param name The name
+ * @return The painting
+ */
+ public static Art getByName(String name) {
+ Validate.notNull(name, "Name cannot be null");
+
+ return BY_NAME.get(name.toLowerCase().replaceAll("_", ""));
+ }
+
+ static {
+ for (Art art : values()) {
+ BY_ID.put(art.id, art);
+ BY_NAME.put(art.toString().toLowerCase().replaceAll("_", ""), art);
+ }
+ }
+}
diff --git a/PaperSpigot-API/src/main/java/org/bukkit/AxisAlignedBB.java b/PaperSpigot-API/src/main/java/org/bukkit/AxisAlignedBB.java
new file mode 100644
index 0000000..3b2c6b4
--- /dev/null
+++ b/PaperSpigot-API/src/main/java/org/bukkit/AxisAlignedBB.java
@@ -0,0 +1,111 @@
+package org.bukkit;
+
+/**
+ * A static representation of the bounding box of some Entity or Block
+ */
+public class AxisAlignedBB {
+
+ private final double minX;
+ private final double minY;
+ private final double minZ;
+ private final double maxX;
+ private final double maxY;
+ private final double maxZ;
+
+ public AxisAlignedBB(double minX, double minY, double minZ,
+ double maxX, double maxY, double maxZ) {
+ this.minX = minX;
+ this.minY = minY;
+ this.minZ = minZ;
+ this.maxX = maxX;
+ this.maxY = maxY;
+ this.maxZ = maxZ;
+ }
+
+ /**
+ * Gets the minimum x-coordinate of this bounding box.
+ *
+ * @return minimum x-coordinate
+ */
+ public double getMinX() {
+ return minX;
+ }
+
+ /**
+ * Gets the minimum y-coordinate of this bounding box.
+ *
+ * @return minimum y-coordinate
+ */
+ public double getMinY() {
+ return minY;
+ }
+
+ /**
+ * Gets the minimum z-coordinate of this bounding box.
+ *
+ * @return minimum z-coordinate
+ */
+ public double getMinZ() {
+ return minZ;
+ }
+
+ /**
+ * Gets the maximum x-coordinate of this bounding box.
+ *
+ * @return maximum x-coordinate
+ */
+ public double getMaxX() {
+ return maxX;
+ }
+
+ /**
+ * Gets the maximum y-coordinate of this bounding box.
+ *
+ * @return maximum y-coordinate
+ */
+ public double getMaxY() {
+ return maxY;
+ }
+
+ /**
+ * Gets the minimum z-coordinate of this bounding box.
+ *
+ * @return maximum z-coordinate
+ */
+ public double getMaxZ() {
+ return maxZ;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 3;
+ hash = 19 * hash + (int) (Double.doubleToLongBits(this.minX) ^ (Double.doubleToLongBits(this.minX) >>> 32));
+ hash = 19 * hash + (int) (Double.doubleToLongBits(this.minY) ^ (Double.doubleToLongBits(this.minY) >>> 32));
+ hash = 19 * hash + (int) (Double.doubleToLongBits(this.minZ) ^ (Double.doubleToLongBits(this.minZ) >>> 32));
+ hash = 19 * hash + (int) (Double.doubleToLongBits(this.maxX) ^ (Double.doubleToLongBits(this.maxX) >>> 32));
+ hash = 19 * hash + (int) (Double.doubleToLongBits(this.maxY) ^ (Double.doubleToLongBits(this.maxY) >>> 32));
+ hash = 19 * hash + (int) (Double.doubleToLongBits(this.maxZ) ^ (Double.doubleToLongBits(this.maxZ) >>> 32));
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ } else if (!(other instanceof AxisAlignedBB)) {
+ return false;
+ }
+ AxisAlignedBB aabb = (AxisAlignedBB) other;
+ return Double.compare(aabb.minX, minX) == 0
+ && Double.compare(aabb.minY, minY) == 0
+ && Double.compare(aabb.minZ, minZ) == 0
+ && Double.compare(aabb.maxX, maxX) == 0
+ && Double.compare(aabb.maxY, maxY) == 0
+ && Double.compare(aabb.maxZ, maxZ) == 0;
+ }
+
+ @Override
+ public String toString() {
+ return "AxisAlignedBB[" + minX + ", " + minY + ", " + minZ + " -> " + maxX + ", " + maxY + ", " + maxZ + "]";
+ }
+}
diff --git a/PaperSpigot-API/src/main/java/org/bukkit/BanEntry.java b/PaperSpigot-API/src/main/java/org/bukkit/BanEntry.java
new file mode 100644
index 0000000..986120e
--- /dev/null
+++ b/PaperSpigot-API/src/main/java/org/bukkit/BanEntry.java
@@ -0,0 +1,127 @@
+package org.bukkit;
+
+import java.util.Date;
+
+/**
+ * A single entry from a ban list. This may represent either a player ban or
+ * an IP ban.
+ *
+ * Ban entries include the following properties:
+ *
+ *
+ * Property |
+ * Description |
+ *
+ * Target Name / IP Address |
+ * The target name or IP address |
+ *
+ * Creation Date |
+ * The creation date of the ban |
+ *
+ * Source |
+ * The source of the ban, such as a player, console, plugin, etc |
+ *
+ * Expiration Date |
+ * The expiration date of the ban |
+ *
+ * Reason |
+ * The reason for the ban |
+ *
+ *
+ *
+ * Unsaved information is not automatically written to the implementation's
+ * ban list, instead, the {@link #save()} method must be called to write the
+ * changes to the ban list. If this ban entry has expired (such as from an
+ * unban) and is no longer found in the list, the {@link #save()} call will
+ * re-add it to the list, therefore banning the victim specified.
+ *
+ * Likewise, changes to the associated {@link BanList} or other entries may or
+ * may not be reflected in this entry.
+ */
+public interface BanEntry {
+
+ /**
+ * Gets the target involved. This may be in the form of an IP or a player
+ * name.
+ *
+ * @return the target name or IP address
+ */
+ public String getTarget();
+
+ /**
+ * Gets the date this ban entry was created.
+ *
+ * @return the creation date
+ */
+ public Date getCreated();
+
+ /**
+ * Sets the date this ban entry was created.
+ *
+ * @param created the new created date, cannot be null
+ * @see #save() saving changes
+ */
+ public void setCreated(Date created);
+
+ /**
+ * Gets the source of this ban.
+ *
+ * Note: A source is considered any String, although this is generally a
+ * player name.
+ *
+ * @return the source of the ban
+ */
+ public String getSource();
+
+ /**
+ * Sets the source of this ban.
+ *
+ * Note: A source is considered any String, although this is generally a
+ * player name.
+ *
+ * @param source the new source where null values become empty strings
+ * @see #save() saving changes
+ */
+ public void setSource(String source);
+
+ /**
+ * Gets the date this ban expires on, or null for no defined end date.
+ *
+ * @return the expiration date
+ */
+ public Date getExpiration();
+
+ /**
+ * Sets the date this ban expires on. Null values are considered
+ * "infinite" bans.
+ *
+ * @param expiration the new expiration date, or null to indicate an
+ * eternity
+ * @see #save() saving changes
+ */
+ public void setExpiration(Date expiration);
+
+ /**
+ * Gets the reason for this ban.
+ *
+ * @return the ban reason, or null if not set
+ */
+ public String getReason();
+
+ /**
+ * Sets the reason for this ban. Reasons must not be null.
+ *
+ * @param reason the new reason, null values assume the implementation
+ * default
+ * @see #save() saving changes
+ */
+ public void setReason(String reason);
+
+ /**
+ * Saves the ban entry, overwriting any previous data in the ban list.
+ *
+ * Saving the ban entry of an unbanned player will cause the player to be
+ * banned once again.
+ */
+ public void save();
+}
diff --git a/PaperSpigot-API/src/main/java/org/bukkit/BanList.java b/PaperSpigot-API/src/main/java/org/bukkit/BanList.java
new file mode 100644
index 0000000..c21b858
--- /dev/null
+++ b/PaperSpigot-API/src/main/java/org/bukkit/BanList.java
@@ -0,0 +1,72 @@
+package org.bukkit;
+
+import java.util.Date;
+import java.util.Set;
+
+/**
+ * A ban list, containing bans of some {@link Type}.
+ */
+public interface BanList {
+
+ /**
+ * Represents a ban-type that a {@link BanList} may track.
+ */
+ public enum Type {
+ /**
+ * Banned player names
+ */
+ NAME,
+ /**
+ * Banned player IP addresses
+ */
+ IP,
+ ;
+ }
+
+ /**
+ * Gets a {@link BanEntry} by target.
+ *
+ * @param target entry parameter to search for
+ * @return the corresponding entry, or null if none found
+ */
+ public BanEntry getBanEntry(String target);
+
+ /**
+ * Adds a ban to the this list. If a previous ban exists, this will
+ * update the previous entry.
+ *
+ * @param target the target of the ban
+ * @param reason reason for the ban, null indicates implementation default
+ * @param expires date for the ban's expiration (unban), or null to imply
+ * forever
+ * @param source source of the ban, null indicates implementation default
+ * @return the entry for the newly created ban, or the entry for the
+ * (updated) previous ban
+ */
+ public BanEntry addBan(String target, String reason, Date expires, String source);
+
+ /**
+ * Gets a set containing every {@link BanEntry} in this list.
+ *
+ * @return an immutable set containing every entry tracked by this list
+ */
+ public Set getBanEntries();
+
+ /**
+ * Gets if a {@link BanEntry} exists for the target, indicating an active
+ * ban status.
+ *
+ * @param target the target to find
+ * @return true if a {@link BanEntry} exists for the name, indicating an
+ * active ban status, false otherwise
+ */
+ public boolean isBanned(String target);
+
+ /**
+ * Removes the specified target from this list, therefore indicating a
+ * "not banned" status.
+ *
+ * @param target the target to remove from this list
+ */
+ public void pardon(String target);
+}
diff --git a/PaperSpigot-API/src/main/java/org/bukkit/BlockChangeDelegate.java b/PaperSpigot-API/src/main/java/org/bukkit/BlockChangeDelegate.java
new file mode 100644
index 0000000..e6b9f0e
--- /dev/null
+++ b/PaperSpigot-API/src/main/java/org/bukkit/BlockChangeDelegate.java
@@ -0,0 +1,104 @@
+package org.bukkit;
+
+/**
+ * A delegate for handling block changes. This serves as a direct interface
+ * between generation algorithms in the server implementation and utilizing
+ * code.
+ */
+public interface BlockChangeDelegate {
+
+ /**
+ * Set a block type at the specified coordinates without doing all world
+ * updates and notifications.
+ *
+ * It is safe to have this call World.setTypeId, but it may be slower than
+ * World.setRawTypeId.
+ *
+ * @param x X coordinate
+ * @param y Y coordinate
+ * @param z Z coordinate
+ * @param typeId New block ID
+ * @return true if the block was set successfully
+ * @deprecated Magic value
+ */
+ @Deprecated
+ public boolean setRawTypeId(int x, int y, int z, int typeId);
+
+ /**
+ * Set a block type and data at the specified coordinates without doing
+ * all world updates and notifications.
+ *
+ * It is safe to have this call World.setTypeId, but it may be slower than
+ * World.setRawTypeId.
+ *
+ * @param x X coordinate
+ * @param y Y coordinate
+ * @param z Z coordinate
+ * @param typeId New block ID
+ * @param data Block data
+ * @return true if the block was set successfully
+ * @deprecated Magic value
+ */
+ @Deprecated
+ public boolean setRawTypeIdAndData(int x, int y, int z, int typeId, int data);
+
+ /**
+ * Set a block type at the specified coordinates.
+ *
+ * This method cannot call World.setRawTypeId, a full update is needed.
+ *
+ * @param x X coordinate
+ * @param y Y coordinate
+ * @param z Z coordinate
+ * @param typeId New block ID
+ * @return true if the block was set successfully
+ * @deprecated Magic value
+ */
+ @Deprecated
+ public boolean setTypeId(int x, int y, int z, int typeId);
+
+ /**
+ * Set a block type and data at the specified coordinates.
+ *
+ * This method cannot call World.setRawTypeId, a full update is needed.
+ *
+ * @param x X coordinate
+ * @param y Y coordinate
+ * @param z Z coordinate
+ * @param typeId New block ID
+ * @param data Block data
+ * @return true if the block was set successfully
+ * @deprecated Magic value
+ */
+ @Deprecated
+ public boolean setTypeIdAndData(int x, int y, int z, int typeId, int data);
+
+ /**
+ * Get the block type at the location.
+ *
+ * @param x X coordinate
+ * @param y Y coordinate
+ * @param z Z coordinate
+ * @return The block ID
+ * @deprecated Magic value
+ */
+ @Deprecated
+ public int getTypeId(int x, int y, int z);
+
+ /**
+ * Gets the height of the world.
+ *
+ * @return Height of the world
+ */
+ public int getHeight();
+
+ /**
+ * Checks if the specified block is empty (air) or not.
+ *
+ * @param x X coordinate
+ * @param y Y coordinate
+ * @param z Z coordinate
+ * @return True if the block is considered empty.
+ */
+ public boolean isEmpty(int x, int y, int z);
+}
diff --git a/PaperSpigot-API/src/main/java/org/bukkit/Bukkit.java b/PaperSpigot-API/src/main/java/org/bukkit/Bukkit.java
new file mode 100644
index 0000000..dcadc5c
--- /dev/null
+++ b/PaperSpigot-API/src/main/java/org/bukkit/Bukkit.java
@@ -0,0 +1,776 @@
+package org.bukkit;
+
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.logging.Logger;
+
+import co.aikar.timings.Timings;
+import org.bukkit.Warning.WarningState;
+import org.bukkit.command.CommandException;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.ConsoleCommandSender;
+import org.bukkit.command.PluginCommand;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.Player;
+import org.bukkit.event.inventory.InventoryType;
+import org.bukkit.help.HelpMap;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.InventoryHolder;
+import org.bukkit.inventory.ItemFactory;
+import org.bukkit.inventory.Recipe;
+import org.bukkit.map.MapView;
+import org.bukkit.metadata.MetadataStore;
+import org.bukkit.plugin.PluginManager;
+import org.bukkit.plugin.ServicesManager;
+import org.bukkit.plugin.messaging.Messenger;
+import org.bukkit.scheduler.BukkitScheduler;
+import org.bukkit.scoreboard.ScoreboardManager;
+import org.bukkit.util.CachedServerIcon;
+
+import com.avaje.ebean.config.ServerConfig;
+
+/**
+ * Represents the Bukkit core, for version and Server singleton handling
+ */
+public final class Bukkit {
+ private static Server server;
+
+ /**
+ * Static class cannot be initialized.
+ */
+ private Bukkit() {}
+
+ /**
+ * Gets the current {@link Server} singleton
+ *
+ * @return Server instance being ran
+ */
+ public static Server getServer() {
+ return server;
+ }
+
+ /**
+ * Attempts to set the {@link Server} singleton.
+ *
+ * This cannot be done if the Server is already set.
+ *
+ * @param server Server instance
+ */
+ public static void setServer(Server server) {
+ if (Bukkit.server != null) {
+ throw new UnsupportedOperationException("Cannot redefine singleton Server");
+ }
+
+ Bukkit.server = server;
+ server.getLogger().info("This server is running " + getName() + " version " + getVersion() + " (Implementing API version " + getBukkitVersion() + ")");
+ }
+
+ /**
+ * @see Server#getName()
+ */
+ public static String getName() {
+ return server.getName();
+ }
+
+ /**
+ * @see Server#getVersion()
+ */
+ public static String getVersion() {
+ return server.getVersion();
+ }
+
+ /**
+ * @see Server#getBukkitVersion()
+ */
+ public static String getBukkitVersion() {
+ return server.getBukkitVersion();
+ }
+
+ /**
+ * This method exists for legacy reasons to provide backwards
+ * compatibility. It will not exist at runtime and should not be used
+ * under any circumstances.
+ *
+ * @Deprecated
+ * @see Server#_INVALID_getOnlinePlayers()
+ */
+ @Deprecated
+ public static Player[] _INVALID_getOnlinePlayers() {
+ return server._INVALID_getOnlinePlayers();
+ }
+
+ /**
+ * @see Server#getOnlinePlayers()
+ */
+ public static Collection extends Player> getOnlinePlayers() {
+ return server.getOnlinePlayers();
+ }
+
+ /**
+ * @see Server#getMaxPlayers()
+ */
+ public static int getMaxPlayers() {
+ return server.getMaxPlayers();
+ }
+
+ /**
+ * @see Server#getPort()
+ */
+ public static int getPort() {
+ return server.getPort();
+ }
+
+ /**
+ * @see Server#getViewDistance()
+ */
+ public static int getViewDistance() {
+ return server.getViewDistance();
+ }
+
+ /**
+ * @see Server#getIp()
+ */
+ public static String getIp() {
+ return server.getIp();
+ }
+
+ /**
+ * @see Server#getServerName()
+ */
+ public static String getServerName() {
+ return server.getServerName();
+ }
+
+ /**
+ * @see Server#getServerId()
+ */
+ public static String getServerId() {
+ return server.getServerId();
+ }
+
+ /**
+ * @see Server#getWorldType()
+ */
+ public static String getWorldType() {
+ return server.getWorldType();
+ }
+
+ /**
+ * @see Server#getGenerateStructures()
+ */
+ public static boolean getGenerateStructures() {
+ return server.getGenerateStructures();
+ }
+
+ /**
+ * @see Server#getAllowNether()
+ */
+ public static boolean getAllowNether() {
+ return server.getAllowNether();
+ }
+
+ /**
+ * @see Server#hasWhitelist()
+ */
+ public static boolean hasWhitelist() {
+ return server.hasWhitelist();
+ }
+
+ /**
+ * @see Server#broadcastMessage(String message)
+ */
+ public static int broadcastMessage(String message) {
+ return server.broadcastMessage(message);
+ }
+
+ /**
+ * @see Server#getUpdateFolder()
+ */
+ public static String getUpdateFolder() {
+ return server.getUpdateFolder();
+ }
+
+ /**
+ * @see Server#getPlayer(String name)
+ */
+ public static Player getPlayer(String name) {
+ return server.getPlayer(name);
+ }
+
+ /**
+ * @see Server#matchPlayer(String name)
+ */
+ public static List matchPlayer(String name) {
+ return server.matchPlayer(name);
+ }
+
+ /**
+ * @see Server#getPlayer(java.util.UUID)
+ */
+ public static Player getPlayer(UUID id) {
+ return server.getPlayer(id);
+ }
+
+ /**
+ * @see Server#getPluginManager()
+ */
+ public static PluginManager getPluginManager() {
+ return server.getPluginManager();
+ }
+
+ /**
+ * @see Server#getScheduler()
+ */
+ public static BukkitScheduler getScheduler() {
+ return server.getScheduler();
+ }
+
+ /**
+ * @see Server#getServicesManager()
+ */
+ public static ServicesManager getServicesManager() {
+ return server.getServicesManager();
+ }
+
+ /**
+ * @see Server#getWorlds()
+ */
+ public static List getWorlds() {
+ return server.getWorlds();
+ }
+
+ /**
+ * @see Server#createWorld(WorldCreator options)
+ */
+ public static World createWorld(WorldCreator options) {
+ return server.createWorld(options);
+ }
+
+ /**
+ * @see Server#unloadWorld(String name, boolean save)
+ */
+ public static boolean unloadWorld(String name, boolean save) {
+ return server.unloadWorld(name, save);
+ }
+
+ /**
+ * @see Server#unloadWorld(World world, boolean save)
+ */
+ public static boolean unloadWorld(World world, boolean save) {
+ return server.unloadWorld(world, save);
+ }
+
+ /**
+ * @see Server#getWorld(String name)
+ */
+ public static World getWorld(String name) {
+ return server.getWorld(name);
+ }
+
+ /**
+ * @see Server#getWorld(UUID uid)
+ */
+ public static World getWorld(UUID uid) {
+ return server.getWorld(uid);
+ }
+
+ /**
+ * @see Server#getMap(short id)
+ * @deprecated Magic value
+ */
+ @Deprecated
+ public static MapView getMap(short id) {
+ return server.getMap(id);
+ }
+
+ /**
+ * @see Server#createMap(World world)
+ */
+ public static MapView createMap(World world) {
+ return server.createMap(world);
+ }
+
+ /**
+ * @see Server#reload()
+ */
+ public static void reload() {
+ server.reload();
+ }
+
+ /**
+ * @see Server#getLogger()
+ */
+ public static Logger getLogger() {
+ return server.getLogger();
+ }
+
+ /**
+ * @see Server#getPluginCommand(String name)
+ */
+ public static PluginCommand getPluginCommand(String name) {
+ return server.getPluginCommand(name);
+ }
+
+ /**
+ * @see Server#savePlayers()
+ */
+ public static void savePlayers() {
+ server.savePlayers();
+ }
+
+ /**
+ * @see Server#dispatchCommand(CommandSender sender, String commandLine)
+ */
+ public static boolean dispatchCommand(CommandSender sender, String commandLine) throws CommandException {
+ return server.dispatchCommand(sender, commandLine);
+ }
+
+ /**
+ * @see Server#configureDbConfig(ServerConfig config)
+ */
+ public static void configureDbConfig(ServerConfig config) {
+ server.configureDbConfig(config);
+ }
+
+ /**
+ * @see Server#addRecipe(Recipe recipe)
+ */
+ public static boolean addRecipe(Recipe recipe) {
+ return server.addRecipe(recipe);
+ }
+
+ /**
+ * @see Server#getRecipesFor(ItemStack result)
+ */
+ public static List getRecipesFor(ItemStack result) {
+ return server.getRecipesFor(result);
+ }
+
+ /**
+ * @see Server#recipeIterator()
+ */
+ public static Iterator recipeIterator() {
+ return server.recipeIterator();
+ }
+
+ /**
+ * @see Server#clearRecipes()
+ */
+ public static void clearRecipes() {
+ server.clearRecipes();
+ }
+
+ /**
+ * @see Server#resetRecipes()
+ */
+ public static void resetRecipes() {
+ server.resetRecipes();
+ }
+
+ /**
+ * @see Server#getCommandAliases()
+ */
+ public static Map getCommandAliases() {
+ return server.getCommandAliases();
+ }
+
+ /**
+ * @see Server#getSpawnRadius()
+ */
+ public static int getSpawnRadius() {
+ return server.getSpawnRadius();
+ }
+
+ /**
+ * @see Server#setSpawnRadius(int value)
+ */
+ public static void setSpawnRadius(int value) {
+ server.setSpawnRadius(value);
+ }
+
+ /**
+ * @see Server#getOnlineMode()
+ */
+ public static boolean getOnlineMode() {
+ return server.getOnlineMode();
+ }
+
+ /**
+ * @see Server#getAllowFlight()
+ */
+ public static boolean getAllowFlight() {
+ return server.getAllowFlight();
+ }
+
+ /**
+ * @see Server#isHardcore()
+ */
+ public static boolean isHardcore() {
+ return server.isHardcore();
+ }
+
+ /**
+ * @see Server#shutdown()
+ */
+ public static void shutdown() {
+ server.shutdown();
+ }
+
+ /**
+ * @see Server#broadcast(String message, String permission)
+ */
+ public static int broadcast(String message, String permission) {
+ return server.broadcast(message, permission);
+ }
+
+ /**
+ * @see Server#getOfflinePlayer(String name)
+ */
+ @Deprecated
+ public static OfflinePlayer getOfflinePlayer(String name) {
+ return server.getOfflinePlayer(name);
+ }
+
+ /**
+ * @see Server#getOfflinePlayer(java.util.UUID)
+ */
+ public static OfflinePlayer getOfflinePlayer(UUID id) {
+ return server.getOfflinePlayer(id);
+ }
+
+ /**
+ * @see Server#getPlayerExact(String name)
+ */
+ public static Player getPlayerExact(String name) {
+ return server.getPlayerExact(name);
+ }
+
+ /**
+ * @see Server#getIPBans()
+ */
+ public static Set getIPBans() {
+ return server.getIPBans();
+ }
+
+ /**
+ * @see Server#banIP(String address)
+ */
+ public static void banIP(String address) {
+ server.banIP(address);
+ }
+
+ /**
+ * @see Server#unbanIP(String address)
+ */
+ public static void unbanIP(String address) {
+ server.unbanIP(address);
+ }
+
+ /**
+ * @see Server#getBannedPlayers()
+ */
+ public static Set getBannedPlayers() {
+ return server.getBannedPlayers();
+ }
+
+ /**
+ * @see Server#getBanList(BanList.Type)
+ */
+ public static BanList getBanList(BanList.Type type){
+ return server.getBanList(type);
+ }
+
+ /**
+ * @see Server#setWhitelist(boolean value)
+ */
+ public static void setWhitelist(boolean value) {
+ server.setWhitelist(value);
+ }
+
+ /**
+ * @see Server#getWhitelistedPlayers()
+ */
+ public static Set getWhitelistedPlayers() {
+ return server.getWhitelistedPlayers();
+ }
+
+ /**
+ * @see Server#reloadWhitelist()
+ */
+ public static void reloadWhitelist() {
+ server.reloadWhitelist();
+ }
+
+ /**
+ * @see Server#getConsoleSender()
+ */
+ public static ConsoleCommandSender getConsoleSender() {
+ return server.getConsoleSender();
+ }
+
+ /**
+ * @see Server#getOperators()
+ */
+ public static Set getOperators() {
+ return server.getOperators();
+ }
+
+ /**
+ * @see Server#getEntityMetadata()
+ */
+ public static MetadataStore getEntityMetadata() {
+ return server.getEntityMetadata();
+ }
+
+ /**
+ * @see Server#getPlayerMetadata()
+ */
+ public static MetadataStore getPlayerMetadata() {
+ return server.getPlayerMetadata();
+ }
+
+ /**
+ * @see Server#getWorldMetadata()
+ */
+ public static MetadataStore getWorldMetadata() {
+ return server.getWorldMetadata();
+ }
+
+ /**
+ * @see Server#getWorldContainer()
+ */
+ public static File getWorldContainer() {
+ return server.getWorldContainer();
+ }
+
+ /**
+ * @see Server#getMessenger()
+ */
+ public static Messenger getMessenger() {
+ return server.getMessenger();
+ }
+
+ /**
+ * @see Server#getAllowEnd()
+ */
+ public static boolean getAllowEnd() {
+ return server.getAllowEnd();
+ }
+
+ /**
+ * @see Server#getUpdateFolderFile()
+ */
+ public static File getUpdateFolderFile() {
+ return server.getUpdateFolderFile();
+ }
+
+ /**
+ * @see Server#getConnectionThrottle()
+ */
+ public static long getConnectionThrottle() {
+ return server.getConnectionThrottle();
+ }
+
+ /**
+ * @see Server#getTicksPerAnimalSpawns()
+ */
+ public static int getTicksPerAnimalSpawns() {
+ return server.getTicksPerAnimalSpawns();
+ }
+
+ /**
+ * @see Server#getTicksPerMonsterSpawns()
+ */
+ public static int getTicksPerMonsterSpawns() {
+ return server.getTicksPerMonsterSpawns();
+ }
+
+ /**
+ * @see Server#useExactLoginLocation()
+ */
+ public static boolean useExactLoginLocation() {
+ return server.useExactLoginLocation();
+ }
+
+ /**
+ * @see Server#getDefaultGameMode()
+ */
+ public static GameMode getDefaultGameMode() {
+ return server.getDefaultGameMode();
+ }
+
+ /**
+ * @see Server#setDefaultGameMode(GameMode mode)
+ */
+ public static void setDefaultGameMode(GameMode mode) {
+ server.setDefaultGameMode(mode);
+ }
+
+ /**
+ * @see Server#getOfflinePlayers()
+ */
+ public static OfflinePlayer[] getOfflinePlayers() {
+ return server.getOfflinePlayers();
+ }
+
+ /**
+ * @see Server#createInventory(InventoryHolder owner, InventoryType type)
+ */
+ public static Inventory createInventory(InventoryHolder owner, InventoryType type) {
+ return server.createInventory(owner, type);
+ }
+
+ /**
+ * @see Server#createInventory(InventoryHolder owner, InventoryType type, String title)
+ */
+ public static Inventory createInventory(InventoryHolder owner, InventoryType type, String title) {
+ return server.createInventory(owner, type, title);
+ }
+
+ /**
+ * @see Server#createInventory(InventoryHolder owner, int size)
+ */
+ public static Inventory createInventory(InventoryHolder owner, int size) throws IllegalArgumentException {
+ return server.createInventory(owner, size);
+ }
+
+ /**
+ * @see Server#createInventory(InventoryHolder owner, int size, String
+ * title)
+ */
+ public static Inventory createInventory(InventoryHolder owner, int size, String title) throws IllegalArgumentException {
+ return server.createInventory(owner, size, title);
+ }
+
+ /**
+ * @see Server#getHelpMap()
+ */
+ public static HelpMap getHelpMap() {
+ return server.getHelpMap();
+ }
+
+ /**
+ * @see Server#getMonsterSpawnLimit()
+ */
+ public static int getMonsterSpawnLimit() {
+ return server.getMonsterSpawnLimit();
+ }
+
+ /**
+ * @see Server#getAnimalSpawnLimit()
+ */
+ public static int getAnimalSpawnLimit() {
+ return server.getAnimalSpawnLimit();
+ }
+
+ /**
+ * @see Server#getWaterAnimalSpawnLimit()
+ */
+ public static int getWaterAnimalSpawnLimit() {
+ return server.getWaterAnimalSpawnLimit();
+ }
+
+ /**
+ * @see Server#getAmbientSpawnLimit()
+ */
+ public static int getAmbientSpawnLimit() {
+ return server.getAmbientSpawnLimit();
+ }
+
+ /**
+ * @see Server#isPrimaryThread()
+ */
+ public static boolean isPrimaryThread() {
+ return server.isPrimaryThread();
+ }
+
+ /**
+ * @see Server#getMotd()
+ */
+ public static String getMotd() {
+ return server.getMotd();
+ }
+
+ /**
+ * @see Server#getShutdownMessage()
+ */
+ public static String getShutdownMessage() {
+ return server.getShutdownMessage();
+ }
+
+ /**
+ * @see Server#getWarningState()
+ */
+ public static WarningState getWarningState() {
+ return server.getWarningState();
+ }
+
+ /**
+ * @see Server#getItemFactory()
+ */
+ public static ItemFactory getItemFactory() {
+ return server.getItemFactory();
+ }
+
+ /**
+ * @see Server#getScoreboardManager()
+ */
+ public static ScoreboardManager getScoreboardManager() {
+ return server.getScoreboardManager();
+ }
+
+ /**
+ * @see Server#getServerIcon()
+ */
+ public static CachedServerIcon getServerIcon() {
+ return server.getServerIcon();
+ }
+
+ /**
+ * @see Server#loadServerIcon(File)
+ */
+ public static CachedServerIcon loadServerIcon(File file) throws IllegalArgumentException, Exception {
+ return server.loadServerIcon(file);
+ }
+
+ /**
+ * @see Server#loadServerIcon(BufferedImage)
+ */
+ public static CachedServerIcon loadServerIcon(BufferedImage image) throws IllegalArgumentException, Exception {
+ return server.loadServerIcon(image);
+ }
+
+ /**
+ * @see Server#setIdleTimeout(int)
+ */
+ public static void setIdleTimeout(int threshold) {
+ server.setIdleTimeout(threshold);
+ }
+
+ /**
+ * @see Server#getIdleTimeout()
+ */
+ public static int getIdleTimeout() {
+ return server.getIdleTimeout();
+ }
+
+ /**
+ * @see Server#getUnsafe()
+ */
+ @Deprecated
+ public static UnsafeValues getUnsafe() {
+ return server.getUnsafe();
+ }
+
+ public static Server.Spigot spigot()
+ {
+ return server.spigot();
+ }
+}
diff --git a/PaperSpigot-API/src/main/java/org/bukkit/ChatColor.java b/PaperSpigot-API/src/main/java/org/bukkit/ChatColor.java
new file mode 100644
index 0000000..0bbc9fa
--- /dev/null
+++ b/PaperSpigot-API/src/main/java/org/bukkit/ChatColor.java
@@ -0,0 +1,253 @@
+package org.bukkit;
+
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import org.apache.commons.lang.Validate;
+
+import com.google.common.collect.Maps;
+
+/**
+ * All supported color values for chat
+ */
+public enum ChatColor {
+ /**
+ * Represents black
+ */
+ BLACK('0', 0x00),
+ /**
+ * Represents dark blue
+ */
+ DARK_BLUE('1', 0x1),
+ /**
+ * Represents dark green
+ */
+ DARK_GREEN('2', 0x2),
+ /**
+ * Represents dark blue (aqua)
+ */
+ DARK_AQUA('3', 0x3),
+ /**
+ * Represents dark red
+ */
+ DARK_RED('4', 0x4),
+ /**
+ * Represents dark purple
+ */
+ DARK_PURPLE('5', 0x5),
+ /**
+ * Represents gold
+ */
+ GOLD('6', 0x6),
+ /**
+ * Represents gray
+ */
+ GRAY('7', 0x7),
+ /**
+ * Represents dark gray
+ */
+ DARK_GRAY('8', 0x8),
+ /**
+ * Represents blue
+ */
+ BLUE('9', 0x9),
+ /**
+ * Represents green
+ */
+ GREEN('a', 0xA),
+ /**
+ * Represents aqua
+ */
+ AQUA('b', 0xB),
+ /**
+ * Represents red
+ */
+ RED('c', 0xC),
+ /**
+ * Represents light purple
+ */
+ LIGHT_PURPLE('d', 0xD),
+ /**
+ * Represents yellow
+ */
+ YELLOW('e', 0xE),
+ /**
+ * Represents white
+ */
+ WHITE('f', 0xF),
+ /**
+ * Represents magical characters that change around randomly
+ */
+ MAGIC('k', 0x10, true),
+ /**
+ * Makes the text bold.
+ */
+ BOLD('l', 0x11, true),
+ /**
+ * Makes a line appear through the text.
+ */
+ STRIKETHROUGH('m', 0x12, true),
+ /**
+ * Makes the text appear underlined.
+ */
+ UNDERLINE('n', 0x13, true),
+ /**
+ * Makes the text italic.
+ */
+ ITALIC('o', 0x14, true),
+ /**
+ * Resets all previous chat colors or formats.
+ */
+ RESET('r', 0x15);
+
+ /**
+ * The special character which prefixes all chat colour codes. Use this if
+ * you need to dynamically convert colour codes from your custom format.
+ */
+ public static final char COLOR_CHAR = '\u00A7';
+ private static final Pattern STRIP_COLOR_PATTERN = Pattern.compile("(?i)" + String.valueOf(COLOR_CHAR) + "[0-9A-FK-OR]");
+
+ private final int intCode;
+ private final char code;
+ private final boolean isFormat;
+ private final String toString;
+ private final static Map BY_ID = Maps.newHashMap();
+ private final static Map BY_CHAR = Maps.newHashMap();
+
+ private ChatColor(char code, int intCode) {
+ this(code, intCode, false);
+ }
+
+ private ChatColor(char code, int intCode, boolean isFormat) {
+ this.code = code;
+ this.intCode = intCode;
+ this.isFormat = isFormat;
+ this.toString = new String(new char[] {COLOR_CHAR, code});
+ }
+
+ /**
+ * Gets the char value associated with this color
+ *
+ * @return A char value of this color code
+ */
+ public char getChar() {
+ return code;
+ }
+
+ @Override
+ public String toString() {
+ return toString;
+ }
+
+ /**
+ * Checks if this code is a format code as opposed to a color code.
+ */
+ public boolean isFormat() {
+ return isFormat;
+ }
+
+ /**
+ * Checks if this code is a color code as opposed to a format code.
+ */
+ public boolean isColor() {
+ return !isFormat && this != RESET;
+ }
+
+ /**
+ * Gets the color represented by the specified color code
+ *
+ * @param code Code to check
+ * @return Associative {@link org.bukkit.ChatColor} with the given code,
+ * or null if it doesn't exist
+ */
+ public static ChatColor getByChar(char code) {
+ return BY_CHAR.get(code);
+ }
+
+ /**
+ * Gets the color represented by the specified color code
+ *
+ * @param code Code to check
+ * @return Associative {@link org.bukkit.ChatColor} with the given code,
+ * or null if it doesn't exist
+ */
+ public static ChatColor getByChar(String code) {
+ Validate.notNull(code, "Code cannot be null");
+ Validate.isTrue(code.length() > 0, "Code must have at least one char");
+
+ return BY_CHAR.get(code.charAt(0));
+ }
+
+ /**
+ * Strips the given message of all color codes
+ *
+ * @param input String to strip of color
+ * @return A copy of the input string, without any coloring
+ */
+ public static String stripColor(final String input) {
+ if (input == null) {
+ return null;
+ }
+
+ return STRIP_COLOR_PATTERN.matcher(input).replaceAll("");
+ }
+
+ /**
+ * Translates a string using an alternate color code character into a
+ * string that uses the internal ChatColor.COLOR_CODE color code
+ * character. The alternate color code character will only be replaced if
+ * it is immediately followed by 0-9, A-F, a-f, K-O, k-o, R or r.
+ *
+ * @param altColorChar The alternate color code character to replace. Ex: &
+ * @param textToTranslate Text containing the alternate color code character.
+ * @return Text containing the ChatColor.COLOR_CODE color code character.
+ */
+ public static String translateAlternateColorCodes(char altColorChar, String textToTranslate) {
+ char[] b = textToTranslate.toCharArray();
+ for (int i = 0; i < b.length - 1; i++) {
+ if (b[i] == altColorChar && "0123456789AaBbCcDdEeFfKkLlMmNnOoRr".indexOf(b[i+1]) > -1) {
+ b[i] = ChatColor.COLOR_CHAR;
+ b[i+1] = Character.toLowerCase(b[i+1]);
+ }
+ }
+ return new String(b);
+ }
+
+ /**
+ * Gets the ChatColors used at the end of the given input string.
+ *
+ * @param input Input string to retrieve the colors from.
+ * @return Any remaining ChatColors to pass onto the next line.
+ */
+ public static String getLastColors(String input) {
+ String result = "";
+ int length = input.length();
+
+ // Search backwards from the end as it is faster
+ for (int index = length - 1; index > -1; index--) {
+ char section = input.charAt(index);
+ if (section == COLOR_CHAR && index < length - 1) {
+ char c = input.charAt(index + 1);
+ ChatColor color = getByChar(c);
+
+ if (color != null) {
+ result = color.toString() + result;
+
+ // Once we find a color or reset we can stop searching
+ if (color.isColor() || color.equals(RESET)) {
+ break;
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ static {
+ for (ChatColor color : values()) {
+ BY_ID.put(color.intCode, color);
+ BY_CHAR.put(color.code, color);
+ }
+ }
+}
diff --git a/PaperSpigot-API/src/main/java/org/bukkit/Chunk.java b/PaperSpigot-API/src/main/java/org/bukkit/Chunk.java
new file mode 100644
index 0000000..0510151
--- /dev/null
+++ b/PaperSpigot-API/src/main/java/org/bukkit/Chunk.java
@@ -0,0 +1,124 @@
+package org.bukkit;
+
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockState;
+import org.bukkit.entity.Entity;
+
+/**
+ * Represents a chunk of blocks
+ */
+public interface Chunk {
+
+ /**
+ * Gets the X-coordinate of this chunk
+ *
+ * @return X-coordinate
+ */
+ int getX();
+
+ /**
+ * Gets the Z-coordinate of this chunk
+ *
+ * @return Z-coordinate
+ */
+ int getZ();
+
+ /**
+ * Gets the world containing this chunk
+ *
+ * @return Parent World
+ */
+ World getWorld();
+
+ /**
+ * Gets a block from this chunk
+ *
+ * @param x 0-15
+ * @param y 0-127
+ * @param z 0-15
+ * @return the Block
+ */
+ Block getBlock(int x, int y, int z);
+
+ /**
+ * Capture thread-safe read-only snapshot of chunk data
+ *
+ * @return ChunkSnapshot
+ */
+ ChunkSnapshot getChunkSnapshot();
+
+ /**
+ * Capture thread-safe read-only snapshot of chunk data
+ *
+ * @param includeMaxblocky - if true, snapshot includes per-coordinate
+ * maximum Y values
+ * @param includeBiome - if true, snapshot includes per-coordinate biome
+ * type
+ * @param includeBiomeTempRain - if true, snapshot includes per-coordinate
+ * raw biome temperature and rainfall
+ * @return ChunkSnapshot
+ */
+ ChunkSnapshot getChunkSnapshot(boolean includeMaxblocky, boolean includeBiome, boolean includeBiomeTempRain);
+
+ /**
+ * Get a list of all entities in the chunk.
+ *
+ * @return The entities.
+ */
+ Entity[] getEntities();
+
+ /**
+ * Get a list of all tile entities in the chunk.
+ *
+ * @return The tile entities.
+ */
+ BlockState[] getTileEntities();
+
+ /**
+ * Checks if the chunk is loaded.
+ *
+ * @return True if it is loaded.
+ */
+ boolean isLoaded();
+
+ /**
+ * Loads the chunk.
+ *
+ * @param generate Whether or not to generate a chunk if it doesn't
+ * already exist
+ * @return true if the chunk has loaded successfully, otherwise false
+ */
+ boolean load(boolean generate);
+
+ /**
+ * Loads the chunk.
+ *
+ * @return true if the chunk has loaded successfully, otherwise false
+ */
+ boolean load();
+
+ /**
+ * Unloads and optionally saves the Chunk
+ *
+ * @param save Controls whether the chunk is saved
+ * @param safe Controls whether to unload the chunk when players are
+ * nearby
+ * @return true if the chunk has unloaded successfully, otherwise false
+ */
+ boolean unload(boolean save, boolean safe);
+
+ /**
+ * Unloads and optionally saves the Chunk
+ *
+ * @param save Controls whether the chunk is saved
+ * @return true if the chunk has unloaded successfully, otherwise false
+ */
+ boolean unload(boolean save);
+
+ /**
+ * Unloads and optionally saves the Chunk
+ *
+ * @return true if the chunk has unloaded successfully, otherwise false
+ */
+ boolean unload();
+}
diff --git a/PaperSpigot-API/src/main/java/org/bukkit/ChunkSnapshot.java b/PaperSpigot-API/src/main/java/org/bukkit/ChunkSnapshot.java
new file mode 100644
index 0000000..83fccc8
--- /dev/null
+++ b/PaperSpigot-API/src/main/java/org/bukkit/ChunkSnapshot.java
@@ -0,0 +1,129 @@
+package org.bukkit;
+
+import org.bukkit.block.Biome;
+
+/**
+ * Represents a static, thread-safe snapshot of chunk of blocks.
+ *
+ * Purpose is to allow clean, efficient copy of a chunk data to be made, and
+ * then handed off for processing in another thread (e.g. map rendering)
+ */
+public interface ChunkSnapshot {
+
+ /**
+ * Gets the X-coordinate of this chunk
+ *
+ * @return X-coordinate
+ */
+ int getX();
+
+ /**
+ * Gets the Z-coordinate of this chunk
+ *
+ * @return Z-coordinate
+ */
+ int getZ();
+
+ /**
+ * Gets name of the world containing this chunk
+ *
+ * @return Parent World Name
+ */
+ String getWorldName();
+
+ /**
+ * Get block type for block at corresponding coordinate in the chunk
+ *
+ * @param x 0-15
+ * @param y 0-127
+ * @param z 0-15
+ * @return 0-255
+ * @deprecated Magic value
+ */
+ @Deprecated
+ int getBlockTypeId(int x, int y, int z);
+
+ /**
+ * Get block data for block at corresponding coordinate in the chunk
+ *
+ * @param x 0-15
+ * @param y 0-127
+ * @param z 0-15
+ * @return 0-15
+ * @deprecated Magic value
+ */
+ @Deprecated
+ int getBlockData(int x, int y, int z);
+
+ /**
+ * Get sky light level for block at corresponding coordinate in the chunk
+ *
+ * @param x 0-15
+ * @param y 0-127
+ * @param z 0-15
+ * @return 0-15
+ */
+ int getBlockSkyLight(int x, int y, int z);
+
+ /**
+ * Get light level emitted by block at corresponding coordinate in the
+ * chunk
+ *
+ * @param x 0-15
+ * @param y 0-127
+ * @param z 0-15
+ * @return 0-15
+ */
+ int getBlockEmittedLight(int x, int y, int z);
+
+ /**
+ * Gets the highest non-air coordinate at the given coordinates
+ *
+ * @param x X-coordinate of the blocks
+ * @param z Z-coordinate of the blocks
+ * @return Y-coordinate of the highest non-air block
+ */
+ int getHighestBlockYAt(int x, int z);
+
+ /**
+ * Get biome at given coordinates
+ *
+ * @param x X-coordinate
+ * @param z Z-coordinate
+ * @return Biome at given coordinate
+ */
+ Biome getBiome(int x, int z);
+
+ /**
+ * Get raw biome temperature (0.0-1.0) at given coordinate
+ *
+ * @param x X-coordinate
+ * @param z Z-coordinate
+ * @return temperature at given coordinate
+ */
+ double getRawBiomeTemperature(int x, int z);
+
+ /**
+ * Get raw biome rainfall (0.0-1.0) at given coordinate
+ *
+ * @param x X-coordinate
+ * @param z Z-coordinate
+ * @return rainfall at given coordinate
+ */
+ double getRawBiomeRainfall(int x, int z);
+
+ /**
+ * Get world full time when chunk snapshot was captured
+ *
+ * @return time in ticks
+ */
+ long getCaptureFullTime();
+
+ /**
+ * Test if section is empty
+ *
+ * @param sy - section Y coordinate (block Y / 16)
+ * @return true if empty, false if not
+ */
+ boolean isSectionEmpty(int sy);
+}
diff --git a/PaperSpigot-API/src/main/java/org/bukkit/CoalType.java b/PaperSpigot-API/src/main/java/org/bukkit/CoalType.java
new file mode 100644
index 0000000..4fcccd2
--- /dev/null
+++ b/PaperSpigot-API/src/main/java/org/bukkit/CoalType.java
@@ -0,0 +1,50 @@
+package org.bukkit;
+
+import java.util.Map;
+
+import com.google.common.collect.Maps;
+
+/**
+ * Represents the two types of coal
+ */
+public enum CoalType {
+ COAL(0x0),
+ CHARCOAL(0x1);
+
+ private final byte data;
+ private final static Map BY_DATA = Maps.newHashMap();
+
+ private CoalType(final int data) {
+ this.data = (byte) data;
+ }
+
+ /**
+ * Gets the associated data value representing this type of coal
+ *
+ * @return A byte containing the data value of this coal type
+ * @deprecated Magic value
+ */
+ @Deprecated
+ public byte getData() {
+ return data;
+ }
+
+ /**
+ * Gets the type of coal with the given data value
+ *
+ * @param data Data value to fetch
+ * @return The {@link CoalType} representing the given value, or null if
+ * it doesn't exist
+ * @deprecated Magic value
+ */
+ @Deprecated
+ public static CoalType getByData(final byte data) {
+ return BY_DATA.get(data);
+ }
+
+ static {
+ for (CoalType type : values()) {
+ BY_DATA.put(type.data, type);
+ }
+ }
+}
diff --git a/PaperSpigot-API/src/main/java/org/bukkit/Color.java b/PaperSpigot-API/src/main/java/org/bukkit/Color.java
new file mode 100644
index 0000000..76ff651
--- /dev/null
+++ b/PaperSpigot-API/src/main/java/org/bukkit/Color.java
@@ -0,0 +1,344 @@
+package org.bukkit;
+
+import java.util.Map;
+
+import org.apache.commons.lang.Validate;
+import org.bukkit.configuration.serialization.ConfigurationSerializable;
+import org.bukkit.configuration.serialization.SerializableAs;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * A container for a color palette. This class is immutable; the set methods
+ * return a new color. The color names listed as fields are HTML4 standards,
+ * but subject to change.
+ */
+@SerializableAs("Color")
+public final class Color implements ConfigurationSerializable {
+ private static final int BIT_MASK = 0xff;
+
+ /**
+ * White, or (0xFF,0xFF,0xFF) in (R,G,B)
+ */
+ public static final Color WHITE = fromRGB(0xFFFFFF);
+
+ /**
+ * Silver, or (0xC0,0xC0,0xC0) in (R,G,B)
+ */
+ public static final Color SILVER = fromRGB(0xC0C0C0);
+
+ /**
+ * Gray, or (0x80,0x80,0x80) in (R,G,B)
+ */
+ public static final Color GRAY = fromRGB(0x808080);
+
+ /**
+ * Black, or (0x00,0x00,0x00) in (R,G,B)
+ */
+ public static final Color BLACK = fromRGB(0x000000);
+
+ /**
+ * Red, or (0xFF,0x00,0x00) in (R,G,B)
+ */
+ public static final Color RED = fromRGB(0xFF0000);
+
+ /**
+ * Maroon, or (0x80,0x00,0x00) in (R,G,B)
+ */
+ public static final Color MAROON = fromRGB(0x800000);
+
+ /**
+ * Yellow, or (0xFF,0xFF,0x00) in (R,G,B)
+ */
+ public static final Color YELLOW = fromRGB(0xFFFF00);
+
+ /**
+ * Olive, or (0x80,0x80,0x00) in (R,G,B)
+ */
+ public static final Color OLIVE = fromRGB(0x808000);
+
+ /**
+ * Lime, or (0x00,0xFF,0x00) in (R,G,B)
+ */
+ public static final Color LIME = fromRGB(0x00FF00);
+
+ /**
+ * Green, or (0x00,0x80,0x00) in (R,G,B)
+ */
+ public static final Color GREEN = fromRGB(0x008000);
+
+ /**
+ * Aqua, or (0x00,0xFF,0xFF) in (R,G,B)
+ */
+ public static final Color AQUA = fromRGB(0x00FFFF);
+
+ /**
+ * Teal, or (0x00,0x80,0x80) in (R,G,B)
+ */
+ public static final Color TEAL = fromRGB(0x008080);
+
+ /**
+ * Blue, or (0x00,0x00,0xFF) in (R,G,B)
+ */
+ public static final Color BLUE = fromRGB(0x0000FF);
+
+ /**
+ * Navy, or (0x00,0x00,0x80) in (R,G,B)
+ */
+ public static final Color NAVY = fromRGB(0x000080);
+
+ /**
+ * Fuchsia, or (0xFF,0x00,0xFF) in (R,G,B)
+ */
+ public static final Color FUCHSIA = fromRGB(0xFF00FF);
+
+ /**
+ * Purple, or (0x80,0x00,0x80) in (R,G,B)
+ */
+ public static final Color PURPLE = fromRGB(0x800080);
+
+ /**
+ * Orange, or (0xFF,0xA5,0x00) in (R,G,B)
+ */
+ public static final Color ORANGE = fromRGB(0xFFA500);
+
+ private final byte red;
+ private final byte green;
+ private final byte blue;
+
+ /**
+ * Creates a new Color object from a red, green, and blue
+ *
+ * @param red integer from 0-255
+ * @param green integer from 0-255
+ * @param blue integer from 0-255
+ * @return a new Color object for the red, green, blue
+ * @throws IllegalArgumentException if any value is strictly >255 or <0
+ */
+ public static Color fromRGB(int red, int green, int blue) throws IllegalArgumentException {
+ return new Color(red, green, blue);
+ }
+
+ /**
+ * Creates a new Color object from a blue, green, and red
+ *
+ * @param blue integer from 0-255
+ * @param green integer from 0-255
+ * @param red integer from 0-255
+ * @return a new Color object for the red, green, blue
+ * @throws IllegalArgumentException if any value is strictly >255 or <0
+ */
+ public static Color fromBGR(int blue, int green, int red) throws IllegalArgumentException {
+ return new Color(red, green, blue);
+ }
+
+ /**
+ * Creates a new color object from an integer that contains the red,
+ * green, and blue bytes in the lowest order 24 bits.
+ *
+ * @param rgb the integer storing the red, green, and blue values
+ * @return a new color object for specified values
+ * @throws IllegalArgumentException if any data is in the highest order 8
+ * bits
+ */
+ public static Color fromRGB(int rgb) throws IllegalArgumentException {
+ Validate.isTrue((rgb >> 24) == 0, "Extrenuous data in: ", rgb);
+ return fromRGB(rgb >> 16 & BIT_MASK, rgb >> 8 & BIT_MASK, rgb >> 0 & BIT_MASK);
+ }
+
+ /**
+ * Creates a new color object from an integer that contains the blue,
+ * green, and red bytes in the lowest order 24 bits.
+ *
+ * @param bgr the integer storing the blue, green, and red values
+ * @return a new color object for specified values
+ * @throws IllegalArgumentException if any data is in the highest order 8
+ * bits
+ */
+ public static Color fromBGR(int bgr) throws IllegalArgumentException {
+ Validate.isTrue((bgr >> 24) == 0, "Extrenuous data in: ", bgr);
+ return fromBGR(bgr >> 16 & BIT_MASK, bgr >> 8 & BIT_MASK, bgr >> 0 & BIT_MASK);
+ }
+
+ private Color(int red, int green, int blue) {
+ Validate.isTrue(red >= 0 && red <= BIT_MASK, "Red is not between 0-255: ", red);
+ Validate.isTrue(green >= 0 && green <= BIT_MASK, "Green is not between 0-255: ", green);
+ Validate.isTrue(blue >= 0 && blue <= BIT_MASK, "Blue is not between 0-255: ", blue);
+
+ this.red = (byte) red;
+ this.green = (byte) green;
+ this.blue = (byte) blue;
+ }
+
+ /**
+ * Gets the red component
+ *
+ * @return red component, from 0 to 255
+ */
+ public int getRed() {
+ return BIT_MASK & red;
+ }
+
+ /**
+ * Creates a new Color object with specified component
+ *
+ * @param red the red component, from 0 to 255
+ * @return a new color object with the red component
+ */
+ public Color setRed(int red) {
+ return fromRGB(red, getGreen(), getBlue());
+ }
+
+ /**
+ * Gets the green component
+ *
+ * @return green component, from 0 to 255
+ */
+ public int getGreen() {
+ return BIT_MASK & green;
+ }
+
+ /**
+ * Creates a new Color object with specified component
+ *
+ * @param green the red component, from 0 to 255
+ * @return a new color object with the red component
+ */
+ public Color setGreen(int green) {
+ return fromRGB(getRed(), green, getBlue());
+ }
+
+ /**
+ * Gets the blue component
+ *
+ * @return blue component, from 0 to 255
+ */
+ public int getBlue() {
+ return BIT_MASK & blue;
+ }
+
+ /**
+ * Creates a new Color object with specified component
+ *
+ * @param blue the red component, from 0 to 255
+ * @return a new color object with the red component
+ */
+ public Color setBlue(int blue) {
+ return fromRGB(getRed(), getGreen(), blue);
+ }
+
+ /**
+ *
+ * @return An integer representation of this color, as 0xRRGGBB
+ */
+ public int asRGB() {
+ return getRed() << 16 | getGreen() << 8 | getBlue() << 0;
+ }
+
+ /**
+ *
+ * @return An integer representation of this color, as 0xBBGGRR
+ */
+ public int asBGR() {
+ return getBlue() << 16 | getGreen() << 8 | getRed() << 0;
+ }
+
+ /**
+ * Creates a new color with its RGB components changed as if it was dyed
+ * with the colors passed in, replicating vanilla workbench dyeing
+ *
+ * @param colors The DyeColors to dye with
+ * @return A new color with the changed rgb components
+ */
+ // TODO: Javadoc what this method does, not what it mimics. API != Implementation
+ public Color mixDyes(DyeColor... colors) {
+ Validate.noNullElements(colors, "Colors cannot be null");
+
+ Color[] toPass = new Color[colors.length];
+ for (int i = 0; i < colors.length; i++) {
+ toPass[i] = colors[i].getColor();
+ }
+
+ return mixColors(toPass);
+ }
+
+ /**
+ * Creates a new color with its RGB components changed as if it was dyed
+ * with the colors passed in, replicating vanilla workbench dyeing
+ *
+ * @param colors The colors to dye with
+ * @return A new color with the changed rgb components
+ */
+ // TODO: Javadoc what this method does, not what it mimics. API != Implementation
+ public Color mixColors(Color... colors) {
+ Validate.noNullElements(colors, "Colors cannot be null");
+
+ int totalRed = this.getRed();
+ int totalGreen = this.getGreen();
+ int totalBlue = this.getBlue();
+ int totalMax = Math.max(Math.max(totalRed, totalGreen), totalBlue);
+ for (Color color : colors) {
+ totalRed += color.getRed();
+ totalGreen += color.getGreen();
+ totalBlue += color.getBlue();
+ totalMax += Math.max(Math.max(color.getRed(), color.getGreen()), color.getBlue());
+ }
+
+ float averageRed = totalRed / (colors.length + 1);
+ float averageGreen = totalGreen / (colors.length + 1);
+ float averageBlue = totalBlue / (colors.length + 1);
+ float averageMax = totalMax / (colors.length + 1);
+
+ float maximumOfAverages = Math.max(Math.max(averageRed, averageGreen), averageBlue);
+ float gainFactor = averageMax / maximumOfAverages;
+
+ return Color.fromRGB((int) (averageRed * gainFactor), (int) (averageGreen * gainFactor), (int) (averageBlue * gainFactor));
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Color)) {
+ return false;
+ }
+ final Color that = (Color) o;
+ return this.blue == that.blue && this.green == that.green && this.red == that.red;
+ }
+
+ @Override
+ public int hashCode() {
+ return asRGB() ^ Color.class.hashCode();
+ }
+
+ public Map serialize() {
+ return ImmutableMap.of(
+ "RED", getRed(),
+ "BLUE", getBlue(),
+ "GREEN", getGreen()
+ );
+ }
+
+ @SuppressWarnings("javadoc")
+ public static Color deserialize(Map map) {
+ return fromRGB(
+ asInt("RED", map),
+ asInt("GREEN", map),
+ asInt("BLUE", map)
+ );
+ }
+
+ private static int asInt(String string, Map map) {
+ Object value = map.get(string);
+ if (value == null) {
+ throw new IllegalArgumentException(string + " not in map " + map);
+ }
+ if (!(value instanceof Number)) {
+ throw new IllegalArgumentException(string + '(' + value + ") is not a number");
+ }
+ return ((Number) value).intValue();
+ }
+
+ @Override
+ public String toString() {
+ return "Color:[rgb0x" + Integer.toHexString(getRed()).toUpperCase() + Integer.toHexString(getGreen()).toUpperCase() + Integer.toHexString(getBlue()).toUpperCase() + "]";
+ }
+}
diff --git a/PaperSpigot-API/src/main/java/org/bukkit/CropState.java b/PaperSpigot-API/src/main/java/org/bukkit/CropState.java
new file mode 100644
index 0000000..ef0faf9
--- /dev/null
+++ b/PaperSpigot-API/src/main/java/org/bukkit/CropState.java
@@ -0,0 +1,81 @@
+package org.bukkit;
+
+import java.util.Map;
+
+import com.google.common.collect.Maps;
+
+/**
+ * Represents the different growth states of crops
+ */
+public enum CropState {
+
+ /**
+ * State when first seeded
+ */
+ SEEDED(0x0),
+ /**
+ * First growth stage
+ */
+ GERMINATED(0x1),
+ /**
+ * Second growth stage
+ */
+ VERY_SMALL(0x2),
+ /**
+ * Third growth stage
+ */
+ SMALL(0x3),
+ /**
+ * Fourth growth stage
+ */
+ MEDIUM(0x4),
+ /**
+ * Fifth growth stage
+ */
+ TALL(0x5),
+ /**
+ * Almost ripe stage
+ */
+ VERY_TALL(0x6),
+ /**
+ * Ripe stage
+ */
+ RIPE(0x7);
+
+ private final byte data;
+ private final static Map BY_DATA = Maps.newHashMap();
+
+ private CropState(final int data) {
+ this.data = (byte) data;
+ }
+
+ /**
+ * Gets the associated data value representing this growth state
+ *
+ * @return A byte containing the data value of this growth state
+ * @deprecated Magic value
+ */
+ @Deprecated
+ public byte getData() {
+ return data;
+ }
+
+ /**
+ * Gets the CropState with the given data value
+ *
+ * @param data Data value to fetch
+ * @return The {@link CropState} representing the given value, or null if
+ * it doesn't exist
+ * @deprecated Magic value
+ */
+ @Deprecated
+ public static CropState getByData(final byte data) {
+ return BY_DATA.get(data);
+ }
+
+ static {
+ for (CropState cropState : values()) {
+ BY_DATA.put(cropState.getData(), cropState);
+ }
+ }
+}
diff --git a/PaperSpigot-API/src/main/java/org/bukkit/Difficulty.java b/PaperSpigot-API/src/main/java/org/bukkit/Difficulty.java
new file mode 100644
index 0000000..a8a5a78
--- /dev/null
+++ b/PaperSpigot-API/src/main/java/org/bukkit/Difficulty.java
@@ -0,0 +1,72 @@
+package org.bukkit;
+
+import java.util.Map;
+
+import com.google.common.collect.Maps;
+
+/**
+ * Represents the various difficulty levels that are available.
+ */
+public enum Difficulty {
+ /**
+ * Players regain health over time, hostile mobs don't spawn, the hunger
+ * bar does not deplete.
+ */
+ PEACEFUL(0),
+
+ /**
+ * Hostile mobs spawn, enemies deal less damage than on normal difficulty,
+ * the hunger bar does deplete and starving deals up to 5 hearts of
+ * damage. (Default value)
+ */
+ EASY(1),
+
+ /**
+ * Hostile mobs spawn, enemies deal normal amounts of damage, the hunger
+ * bar does deplete and starving deals up to 9.5 hearts of damage.
+ */
+ NORMAL(2),
+
+ /**
+ * Hostile mobs spawn, enemies deal greater damage than on normal
+ * difficulty, the hunger bar does deplete and starving can kill players.
+ */
+ HARD(3);
+
+ private final int value;
+ private final static Map BY_ID = Maps.newHashMap();
+
+ private Difficulty(final int value) {
+ this.value = value;
+ }
+
+ /**
+ * Gets the difficulty value associated with this Difficulty.
+ *
+ * @return An integer value of this difficulty
+ * @deprecated Magic value
+ */
+ @Deprecated
+ public int getValue() {
+ return value;
+ }
+
+ /**
+ * Gets the Difficulty represented by the specified value
+ *
+ * @param value Value to check
+ * @return Associative {@link Difficulty} with the given value, or null if
+ * it doesn't exist
+ * @deprecated Magic value
+ */
+ @Deprecated
+ public static Difficulty getByValue(final int value) {
+ return BY_ID.get(value);
+ }
+
+ static {
+ for (Difficulty diff : values()) {
+ BY_ID.put(diff.value, diff);
+ }
+ }
+}
diff --git a/PaperSpigot-API/src/main/java/org/bukkit/DyeColor.java b/PaperSpigot-API/src/main/java/org/bukkit/DyeColor.java
new file mode 100644
index 0000000..214806e
--- /dev/null
+++ b/PaperSpigot-API/src/main/java/org/bukkit/DyeColor.java
@@ -0,0 +1,239 @@
+package org.bukkit;
+
+import java.util.Map;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * All supported color values for dyes and cloth
+ */
+public enum DyeColor {
+
+ /**
+ * Represents white dye.
+ */
+ WHITE(0x0, 0xF, Color.WHITE, Color.fromRGB(0xF0F0F0)),
+ /**
+ * Represents orange dye.
+ */
+ ORANGE(0x1, 0xE, Color.fromRGB(0xD87F33), Color.fromRGB(0xEB8844)),
+ /**
+ * Represents magenta dye.
+ */
+ MAGENTA(0x2, 0xD, Color.fromRGB(0xB24CD8), Color.fromRGB(0xC354CD)),
+ /**
+ * Represents light blue dye.
+ */
+ LIGHT_BLUE(0x3, 0xC, Color.fromRGB(0x6699D8), Color.fromRGB(0x6689D3)),
+ /**
+ * Represents yellow dye.
+ */
+ YELLOW(0x4, 0xB, Color.fromRGB(0xE5E533), Color.fromRGB(0xDECF2A)),
+ /**
+ * Represents lime dye.
+ */
+ LIME(0x5, 0xA, Color.fromRGB(0x7FCC19), Color.fromRGB(0x41CD34)),
+ /**
+ * Represents pink dye.
+ */
+ PINK(0x6, 0x9, Color.fromRGB(0xF27FA5), Color.fromRGB(0xD88198)),
+ /**
+ * Represents gray dye.
+ */
+ GRAY(0x7, 0x8, Color.fromRGB(0x4C4C4C), Color.fromRGB(0x434343)),
+ /**
+ * Represents silver dye.
+ */
+ SILVER(0x8, 0x7, Color.fromRGB(0x999999), Color.fromRGB(0xABABAB)),
+ /**
+ * Represents cyan dye.
+ */
+ CYAN(0x9, 0x6, Color.fromRGB(0x4C7F99), Color.fromRGB(0x287697)),
+ /**
+ * Represents purple dye.
+ */
+ PURPLE(0xA, 0x5, Color.fromRGB(0x7F3FB2), Color.fromRGB(0x7B2FBE)),
+ /**
+ * Represents blue dye.
+ */
+ BLUE(0xB, 0x4, Color.fromRGB(0x334CB2), Color.fromRGB(0x253192)),
+ /**
+ * Represents brown dye.
+ */
+ BROWN(0xC, 0x3, Color.fromRGB(0x664C33), Color.fromRGB(0x51301A)),
+ /**
+ * Represents green dye.
+ */
+ GREEN(0xD, 0x2, Color.fromRGB(0x667F33), Color.fromRGB(0x3B511A)),
+ /**
+ * Represents red dye.
+ */
+ RED(0xE, 0x1, Color.fromRGB(0x993333), Color.fromRGB(0xB3312C)),
+ /**
+ * Represents black dye.
+ */
+ BLACK(0xF, 0x0, Color.fromRGB(0x191919), Color.fromRGB(0x1E1B1B));
+
+ private final byte woolData;
+ private final byte dyeData;
+ private final Color color;
+ private final Color firework;
+ private final static DyeColor[] BY_WOOL_DATA;
+ private final static DyeColor[] BY_DYE_DATA;
+ private final static Map BY_COLOR;
+ private final static Map BY_FIREWORK;
+
+ private DyeColor(final int woolData, final int dyeData, Color color, Color firework) {
+ this.woolData = (byte) woolData;
+ this.dyeData = (byte) dyeData;
+ this.color = color;
+ this.firework = firework;
+ }
+
+ /**
+ * Gets the associated (wool) data value representing this color.
+ *
+ * @return A byte containing the (wool) data value of this color
+ * @deprecated The name is misleading. It would imply {@link
+ * Material#INK_SACK} but uses {@link Material#WOOL}
+ * @see #getWoolData()
+ * @see #getDyeData()
+ */
+ @Deprecated
+ public byte getData() {
+ return getWoolData();
+ }
+
+ /**
+ * Gets the associated wool data value representing this color.
+ *
+ * @return A byte containing the wool data value of this color
+ * @see #getDyeData()
+ * @deprecated Magic value
+ */
+ @Deprecated
+ public byte getWoolData() {
+ return woolData;
+ }
+
+ /**
+ * Gets the associated dye data value representing this color.
+ *
+ * @return A byte containing the dye data value of this color
+ * @see #getWoolData()
+ * @deprecated Magic value
+ */
+ @Deprecated
+ public byte getDyeData() {
+ return dyeData;
+ }
+
+ /**
+ * Gets the color that this dye represents.
+ *
+ * @return The {@link Color} that this dye represents
+ */
+ public Color getColor() {
+ return color;
+ }
+
+ /**
+ * Gets the firework color that this dye represents.
+ *
+ * @return The {@link Color} that this dye represents
+ */
+ public Color getFireworkColor() {
+ return firework;
+ }
+
+ /**
+ * Gets the DyeColor with the given (wool) data value.
+ *
+ * @param data (wool) data value to fetch
+ * @return The {@link DyeColor} representing the given value, or null if
+ * it doesn't exist
+ * @deprecated The name is misleading. It would imply {@link
+ * Material#INK_SACK} but uses {@link Material#WOOL}
+ * @see #getByDyeData(byte)
+ * @see #getByWoolData(byte)
+ */
+ @Deprecated
+ public static DyeColor getByData(final byte data) {
+ return getByWoolData(data);
+ }
+
+ /**
+ * Gets the DyeColor with the given wool data value.
+ *
+ * @param data Wool data value to fetch
+ * @return The {@link DyeColor} representing the given value, or null if
+ * it doesn't exist
+ * @see #getByDyeData(byte)
+ * @deprecated Magic value
+ */
+ @Deprecated
+ public static DyeColor getByWoolData(final byte data) {
+ int i = 0xff & data;
+ if (i >= BY_WOOL_DATA.length) {
+ return null;
+ }
+ return BY_WOOL_DATA[i];
+ }
+
+ /**
+ * Gets the DyeColor with the given dye data value.
+ *
+ * @param data Dye data value to fetch
+ * @return The {@link DyeColor} representing the given value, or null if
+ * it doesn't exist
+ * @see #getByWoolData(byte)
+ * @deprecated Magic value
+ */
+ @Deprecated
+ public static DyeColor getByDyeData(final byte data) {
+ int i = 0xff & data;
+ if (i >= BY_DYE_DATA.length) {
+ return null;
+ }
+ return BY_DYE_DATA[i];
+ }
+
+ /**
+ * Gets the DyeColor with the given color value.
+ *
+ * @param color Color value to get the dye by
+ * @return The {@link DyeColor} representing the given value, or null if
+ * it doesn't exist
+ */
+ public static DyeColor getByColor(final Color color) {
+ return BY_COLOR.get(color);
+ }
+
+ /**
+ * Gets the DyeColor with the given firework color value.
+ *
+ * @param color Color value to get dye by
+ * @return The {@link DyeColor} representing the given value, or null if
+ * it doesn't exist
+ */
+ public static DyeColor getByFireworkColor(final Color color) {
+ return BY_FIREWORK.get(color);
+ }
+
+ static {
+ BY_WOOL_DATA = values();
+ BY_DYE_DATA = values();
+ ImmutableMap.Builder byColor = ImmutableMap.builder();
+ ImmutableMap.Builder byFirework = ImmutableMap.builder();
+
+ for (DyeColor color : values()) {
+ BY_WOOL_DATA[color.woolData & 0xff] = color;
+ BY_DYE_DATA[color.dyeData & 0xff] = color;
+ byColor.put(color.getColor(), color);
+ byFirework.put(color.getFireworkColor(), color);
+ }
+
+ BY_COLOR = byColor.build();
+ BY_FIREWORK = byFirework.build();
+ }
+}
diff --git a/PaperSpigot-API/src/main/java/org/bukkit/Effect.java b/PaperSpigot-API/src/main/java/org/bukkit/Effect.java
new file mode 100644
index 0000000..37f29e2
--- /dev/null
+++ b/PaperSpigot-API/src/main/java/org/bukkit/Effect.java
@@ -0,0 +1,337 @@
+package org.bukkit;
+
+import java.util.Map;
+
+import com.google.common.collect.Maps;
+
+import org.bukkit.block.BlockFace;
+import org.bukkit.material.MaterialData;
+import org.bukkit.potion.Potion;
+
+/**
+ * A list of effects that the server is able to send to players.
+ */
+public enum Effect {
+ /**
+ * An alternate click sound.
+ */
+ CLICK2(1000, Type.SOUND),
+ /**
+ * A click sound.
+ */
+ CLICK1(1001, Type.SOUND),
+ /**
+ * Sound of a bow firing.
+ */
+ BOW_FIRE(1002, Type.SOUND),
+ /**
+ * Sound of a door opening/closing.
+ */
+ DOOR_TOGGLE(1003, Type.SOUND),
+ /**
+ * Sound of fire being extinguished.
+ */
+ EXTINGUISH(1004, Type.SOUND),
+ /**
+ * A song from a record. Needs the record item ID as additional info
+ */
+ RECORD_PLAY(1005, Type.SOUND, Material.class),
+ /**
+ * Sound of ghast shrieking.
+ */
+ GHAST_SHRIEK(1007, Type.SOUND),
+ /**
+ * Sound of ghast firing.
+ */
+ GHAST_SHOOT(1008, Type.SOUND),
+ /**
+ * Sound of blaze firing.
+ */
+ BLAZE_SHOOT(1009, Type.SOUND),
+ /**
+ * Sound of zombies chewing on wooden doors.
+ */
+ ZOMBIE_CHEW_WOODEN_DOOR(1010, Type.SOUND),
+ /**
+ * Sound of zombies chewing on iron doors.
+ */
+ ZOMBIE_CHEW_IRON_DOOR(1011, Type.SOUND),
+ /**
+ * Sound of zombies destroying a door.
+ */
+ ZOMBIE_DESTROY_DOOR(1012, Type.SOUND),
+ /**
+ * A visual smoke effect. Needs direction as additional info.
+ */
+ SMOKE(2000, Type.VISUAL, BlockFace.class),
+ /**
+ * Sound of a block breaking. Needs block ID as additional info.
+ */
+ STEP_SOUND(2001, Type.SOUND, Material.class),
+ /**
+ * Visual effect of a splash potion breaking. Needs potion data value as
+ * additional info.
+ */
+ POTION_BREAK(2002, Type.VISUAL, Potion.class),
+ /**
+ * An ender eye signal; a visual effect.
+ */
+ ENDER_SIGNAL(2003, Type.VISUAL),
+ /**
+ * The flames seen on a mobspawner; a visual effect.
+ */
+ MOBSPAWNER_FLAMES(2004, Type.VISUAL),
+ /**
+ * The spark that comes off a fireworks
+ */
+ FIREWORKS_SPARK("fireworksSpark", Type.PARTICLE),
+ /**
+ * Critical hit particles
+ */
+ CRIT("crit", Type.PARTICLE),
+ /**
+ * Blue critical hit particles
+ */
+ MAGIC_CRIT("magicCrit", Type.PARTICLE),
+ /**
+ * Multicolored potion effect particles
+ */
+ POTION_SWIRL("mobSpell", Type.PARTICLE),
+ /**
+ * Multicolored potion effect particles that are slightly transparent
+ */
+ POTION_SWIRL_TRANSPARENT("mobSpellAmbient", Type.PARTICLE),
+ /**
+ * A puff of white potion swirls
+ */
+ SPELL("spell", Type.PARTICLE),
+ /**
+ * A puff of white stars
+ */
+ INSTANT_SPELL("instantSpell", Type.PARTICLE),
+ /**
+ * A puff of purple particles
+ */
+ WITCH_MAGIC("witchMagic", Type.PARTICLE),
+ /**
+ * The note that appears above note blocks
+ */
+ NOTE("note", Type.PARTICLE),
+ /**
+ * The particles shown at nether portals
+ */
+ PORTAL("portal", Type.PARTICLE),
+ /**
+ * The symbols that fly towards the enchantment table
+ */
+ FLYING_GLYPH("enchantmenttable", Type.PARTICLE),
+ /**
+ * Fire particles
+ */
+ FLAME("flame", Type.PARTICLE),
+ /**
+ * The particles that pop out of lava
+ */
+ LAVA_POP("lava", Type.PARTICLE),
+ /**
+ * A small gray square
+ */
+ FOOTSTEP("footstep", Type.PARTICLE),
+ /**
+ * Water particles
+ */
+ SPLASH("splash", Type.PARTICLE),
+ /**
+ * Smoke particles
+ */
+ PARTICLE_SMOKE("smoke", Type.PARTICLE),
+ /**
+ * The biggest explosion particle effect
+ */
+ EXPLOSION_HUGE("hugeexplosion", Type.PARTICLE),
+ /**
+ * A larger version of the explode particle
+ */
+ EXPLOSION_LARGE("largeexplode", Type.PARTICLE),
+ /**
+ * Explosion particles
+ */
+ EXPLOSION("explode", Type.PARTICLE),
+ /**
+ * Small gray particles
+ */
+ VOID_FOG("depthsuspend", Type.PARTICLE),
+ /**
+ * Small gray particles
+ */
+ SMALL_SMOKE("townaura", Type.PARTICLE),
+ /**
+ * A puff of white smoke
+ */
+ CLOUD("cloud", Type.PARTICLE),
+ /**
+ * Multicolored dust particles
+ */
+ COLOURED_DUST("reddust", Type.PARTICLE),
+ /**
+ * Snowball breaking
+ */
+ SNOWBALL_BREAK("snowballpoof", Type.PARTICLE),
+ /**
+ * The water drip particle that appears on blocks under water
+ */
+ WATERDRIP("dripWater", Type.PARTICLE),
+ /**
+ * The lava drip particle that appears on blocks under lava
+ */
+ LAVADRIP("dripLava", Type.PARTICLE),
+ /**
+ * White particles
+ */
+ SNOW_SHOVEL("snowshovel", Type.PARTICLE),
+ /**
+ * The particle shown when a slime jumps
+ */
+ SLIME("slime", Type.PARTICLE),
+ /**
+ * The particle that appears when breading animals
+ */
+ HEART("heart", Type.PARTICLE),
+ /**
+ * The particle that appears when hitting a villager
+ */
+ VILLAGER_THUNDERCLOUD("angryVillager", Type.PARTICLE),
+ /**
+ * The particle that appears when trading with a villager
+ */
+ HAPPY_VILLAGER("happyVillager", Type.PARTICLE),
+ /**
+ * The smoke particles that appears on blazes, minecarts
+ * with furnaces and fire
+ */
+ LARGE_SMOKE("largesmoke", Type.PARTICLE),
+ /**
+ * The particles generated when a tool breaks.
+ * This particle requires a Material so that the client can select the correct texture.
+ */
+ ITEM_BREAK("iconcrack", Type.PARTICLE, Material.class),
+ /**
+ * The particles generated while breaking a block.
+ * This particle requires a Material and data value so that the client can select the correct texture.
+ */
+ TILE_BREAK("blockcrack", Type.PARTICLE, MaterialData.class),
+ /**
+ * The particles generated while sprinting a block
+ * This particle requires a Material and data value so that the client can select the correct texture.
+ */
+ TILE_DUST("blockdust", Type.PARTICLE, MaterialData.class);
+
+ private final int id;
+ private final Type type;
+ private final Class> data;
+ private static final Map BY_ID = Maps.newHashMap();
+ private static final Map BY_NAME = Maps.newHashMap();
+ private final String particleName;
+
+ private Effect(int id, Type type) {
+ this(id,type,null);
+ }
+
+ private Effect(int id, Type type, Class> data) {
+ this.id = id;
+ this.type = type;
+ this.data = data;
+ particleName = null;
+ }
+
+ private Effect(String particleName, Type type, Class> data) {
+ this.particleName = particleName;
+ this.type = type;
+ id = 0;
+ this.data = data;
+ }
+
+ private Effect(String particleName, Type type) {
+ this.particleName = particleName;
+ this.type = type;
+ id = 0;
+ this.data = null;
+ }
+
+ /**
+ * Gets the ID for this effect.
+ *
+ * @return if this Effect isn't of type PARTICLE it returns ID of this effect
+ * @deprecated Magic value
+ */
+ @Deprecated
+ public int getId() {
+ return this.id;
+ }
+
+ /**
+ * Returns the effect's name. This returns null if the effect is not a particle
+ *
+ * @return The effect's name
+ */
+ public String getName() {
+ return particleName;
+ }
+
+ /**
+ * @return The type of the effect.
+ */
+ public Type getType() {
+ return this.type;
+ }
+
+ /**
+ * @return if this Effect isn't of type PARTICLE it returns the class which represents data for this effect, or null if none
+ */
+ public Class> getData() {
+ return this.data;
+ }
+
+ /**
+ * Gets the Effect associated with the given ID.
+ *
+ * @param id ID of the Effect to return
+ * @return Effect with the given ID
+ * @deprecated Magic value
+ */
+ @Deprecated
+ public static Effect getById(int id) {
+ return BY_ID.get(id);
+ }
+
+ static {
+ for (Effect effect : values()) {
+ if (effect.type != Type.PARTICLE) {
+ BY_ID.put(effect.id, effect);
+ }
+ }
+ }
+
+ /**
+ * Gets the Effect associated with the given name.
+ *
+ * @param name name of the Effect to return
+ * @return Effect with the given name
+ */
+ public static Effect getByName(String name) {
+ return BY_NAME.get(name);
+ }
+
+ static {
+ for (Effect effect : values()) {
+ if (effect.type == Type.PARTICLE) {
+ BY_NAME.put(effect.particleName, effect);
+ }
+ }
+ }
+
+ /**
+ * Represents the type of an effect.
+ */
+ public enum Type {SOUND, VISUAL, PARTICLE}
+}
diff --git a/PaperSpigot-API/src/main/java/org/bukkit/EntityEffect.java b/PaperSpigot-API/src/main/java/org/bukkit/EntityEffect.java
new file mode 100644
index 0000000..ec7d1e3
--- /dev/null
+++ b/PaperSpigot-API/src/main/java/org/bukkit/EntityEffect.java
@@ -0,0 +1,136 @@
+package org.bukkit;
+
+import java.util.Map;
+
+import com.google.common.collect.Maps;
+
+/**
+ * A list of all Effects that can happen to entities.
+ */
+public enum EntityEffect {
+
+ /**
+ * When mobs get hurt.
+ */
+ HURT(2),
+
+ /**
+ * When a mob dies.
+ *
+ * This will cause client-glitches!
+ */
+ DEATH(3),
+
+ /**
+ * The smoke when taming a wolf fails.
+ *
+ * Without client-mods this will be ignored if the entity is not a wolf.
+ */
+ WOLF_SMOKE(6),
+
+ /**
+ * The hearts when taming a wolf succeeds.
+ *
+ * Without client-mods this will be ignored if the entity is not a wolf.
+ */
+ WOLF_HEARTS(7),
+
+ /**
+ * When a wolf shakes (after being wet).
+ *
+ * Without client-mods this will be ignored if the entity is not a wolf.
+ */
+ WOLF_SHAKE(8),
+
+ /**
+ * When a sheep eats a LONG_GRASS block.
+ */
+ SHEEP_EAT(10),
+
+ /**
+ * When an Iron Golem gives a rose.
+ *
+ * This will not play an effect if the entity is not an iron golem.
+ */
+ IRON_GOLEM_ROSE(11),
+
+ /**
+ * Hearts from a villager.
+ *
+ * This will not play an effect if the entity is not a villager.
+ */
+ VILLAGER_HEART(12),
+
+ /**
+ * When a villager is angry.
+ *
+ * This will not play an effect if the entity is not a villager.
+ */
+ VILLAGER_ANGRY(13),
+
+ /**
+ * Happy particles from a villager.
+ *
+ * This will not play an effect if the entity is not a villager.
+ */
+ VILLAGER_HAPPY(14),
+
+ /**
+ * Magic particles from a witch.
+ *
+ * This will not play an effect if the entity is not a witch.
+ */
+ WITCH_MAGIC(15),
+
+ /**
+ * When a zombie transforms into a villager by shaking violently.
+ *
+ * This will not play an effect if the entity is not a zombie.
+ */
+ ZOMBIE_TRANSFORM(16),
+
+ /**
+ * When a firework explodes.
+ *
+ * This will not play an effect if the entity is not a firework.
+ */
+ FIREWORK_EXPLODE(17);
+
+ private final byte data;
+ private final static Map BY_DATA = Maps.newHashMap();
+
+ EntityEffect(final int data) {
+ this.data = (byte) data;
+ }
+
+ /**
+ * Gets the data value of this EntityEffect
+ *
+ * @return The data value
+ * @deprecated Magic value
+ */
+ @Deprecated
+ public byte getData() {
+ return data;
+ }
+
+ /**
+ * Gets the EntityEffect with the given data value
+ *
+ * @param data Data value to fetch
+ * @return The {@link EntityEffect} representing the given value, or null
+ * if it doesn't exist
+ * @deprecated Magic value
+ */
+ @Deprecated
+ public static EntityEffect getByData(final byte data) {
+ return BY_DATA.get(data);
+ }
+
+
+ static {
+ for (EntityEffect entityEffect : values()) {
+ BY_DATA.put(entityEffect.data, entityEffect);
+ }
+ }
+}
diff --git a/PaperSpigot-API/src/main/java/org/bukkit/FireworkEffect.java b/PaperSpigot-API/src/main/java/org/bukkit/FireworkEffect.java
new file mode 100644
index 0000000..6f2d096
--- /dev/null
+++ b/PaperSpigot-API/src/main/java/org/bukkit/FireworkEffect.java
@@ -0,0 +1,421 @@
+package org.bukkit;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang.Validate;
+import org.bukkit.configuration.serialization.ConfigurationSerializable;
+import org.bukkit.configuration.serialization.SerializableAs;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Represents a single firework effect.
+ */
+@SerializableAs("Firework")
+public final class FireworkEffect implements ConfigurationSerializable {
+
+ /**
+ * The type or shape of the effect.
+ */
+ public enum Type {
+ /**
+ * A small ball effect.
+ */
+ BALL,
+ /**
+ * A large ball effect.
+ */
+ BALL_LARGE,
+ /**
+ * A star-shaped effect.
+ */
+ STAR,
+ /**
+ * A burst effect.
+ */
+ BURST,
+ /**
+ * A creeper-face effect.
+ */
+ CREEPER,
+ ;
+ }
+
+ /**
+ * Construct a firework effect.
+ *
+ * @return A utility object for building a firework effect
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * This is a builder for FireworkEffects.
+ *
+ * @see FireworkEffect#builder()
+ */
+ public static final class Builder {
+ boolean flicker = false;
+ boolean trail = false;
+ final ImmutableList.Builder colors = ImmutableList.builder();
+ ImmutableList.Builder fadeColors = null;
+ Type type = Type.BALL;
+
+ Builder() {}
+
+ /**
+ * Specify the type of the firework effect.
+ *
+ * @param type The effect type
+ * @return This object, for chaining
+ * @throws IllegalArgumentException If type is null
+ */
+ public Builder with(Type type) throws IllegalArgumentException {
+ Validate.notNull(type, "Cannot have null type");
+ this.type = type;
+ return this;
+ }
+
+ /**
+ * Add a flicker to the firework effect.
+ *
+ * @return This object, for chaining
+ */
+ public Builder withFlicker() {
+ flicker = true;
+ return this;
+ }
+
+ /**
+ * Set whether the firework effect should flicker.
+ *
+ * @param flicker true if it should flicker, false if not
+ * @return This object, for chaining
+ */
+ public Builder flicker(boolean flicker) {
+ this.flicker = flicker;
+ return this;
+ }
+
+ /**
+ * Add a trail to the firework effect.
+ *
+ * @return This object, for chaining
+ */
+ public Builder withTrail() {
+ trail = true;
+ return this;
+ }
+
+ /**
+ * Set whether the firework effect should have a trail.
+ *
+ * @param trail true if it should have a trail, false for no trail
+ * @return This object, for chaining
+ */
+ public Builder trail(boolean trail) {
+ this.trail = trail;
+ return this;
+ }
+
+ /**
+ * Add a primary color to the firework effect.
+ *
+ * @param color The color to add
+ * @return This object, for chaining
+ * @throws IllegalArgumentException If color is null
+ */
+ public Builder withColor(Color color) throws IllegalArgumentException {
+ Validate.notNull(color, "Cannot have null color");
+
+ colors.add(color);
+
+ return this;
+ }
+
+ /**
+ * Add several primary colors to the firework effect.
+ *
+ * @param colors The colors to add
+ * @return This object, for chaining
+ * @throws IllegalArgumentException If colors is null
+ * @throws IllegalArgumentException If any color is null (may be
+ * thrown after changes have occurred)
+ */
+ public Builder withColor(Color...colors) throws IllegalArgumentException {
+ Validate.notNull(colors, "Cannot have null colors");
+ if (colors.length == 0) {
+ return this;
+ }
+
+ ImmutableList.Builder list = this.colors;
+ for (Color color : colors) {
+ Validate.notNull(color, "Color cannot be null");
+ list.add(color);
+ }
+
+ return this;
+ }
+
+ /**
+ * Add several primary colors to the firework effect.
+ *
+ * @param colors An iterable object whose iterator yields the desired
+ * colors
+ * @return This object, for chaining
+ * @throws IllegalArgumentException If colors is null
+ * @throws IllegalArgumentException If any color is null (may be
+ * thrown after changes have occurred)
+ */
+ public Builder withColor(Iterable> colors) throws IllegalArgumentException {
+ Validate.notNull(colors, "Cannot have null colors");
+
+ ImmutableList.Builder list = this.colors;
+ for (Object color : colors) {
+ if (!(color instanceof Color)) {
+ throw new IllegalArgumentException(color + " is not a Color in " + colors);
+ }
+ list.add((Color) color);
+ }
+
+ return this;
+ }
+
+ /**
+ * Add a fade color to the firework effect.
+ *
+ * @param color The color to add
+ * @return This object, for chaining
+ * @throws IllegalArgumentException If colors is null
+ * @throws IllegalArgumentException If any color is null (may be
+ * thrown after changes have occurred)
+ */
+ public Builder withFade(Color color) throws IllegalArgumentException {
+ Validate.notNull(color, "Cannot have null color");
+
+ if (fadeColors == null) {
+ fadeColors = ImmutableList.builder();
+ }
+
+ fadeColors.add(color);
+
+ return this;
+ }
+
+ /**
+ * Add several fade colors to the firework effect.
+ *
+ * @param colors The colors to add
+ * @return This object, for chaining
+ * @throws IllegalArgumentException If colors is null
+ * @throws IllegalArgumentException If any color is null (may be
+ * thrown after changes have occurred)
+ */
+ public Builder withFade(Color...colors) throws IllegalArgumentException {
+ Validate.notNull(colors, "Cannot have null colors");
+ if (colors.length == 0) {
+ return this;
+ }
+
+ ImmutableList.Builder list = this.fadeColors;
+ if (list == null) {
+ list = this.fadeColors = ImmutableList.builder();
+ }
+
+ for (Color color : colors) {
+ Validate.notNull(color, "Color cannot be null");
+ list.add(color);
+ }
+
+ return this;
+ }
+
+ /**
+ * Add several fade colors to the firework effect.
+ *
+ * @param colors An iterable object whose iterator yields the desired
+ * colors
+ * @return This object, for chaining
+ * @throws IllegalArgumentException If colors is null
+ * @throws IllegalArgumentException If any color is null (may be
+ * thrown after changes have occurred)
+ */
+ public Builder withFade(Iterable> colors) throws IllegalArgumentException {
+ Validate.notNull(colors, "Cannot have null colors");
+
+ ImmutableList.Builder list = this.fadeColors;
+ if (list == null) {
+ list = this.fadeColors = ImmutableList.builder();
+ }
+
+ for (Object color : colors) {
+ if (!(color instanceof Color)) {
+ throw new IllegalArgumentException(color + " is not a Color in " + colors);
+ }
+ list.add((Color) color);
+ }
+
+ return this;
+ }
+
+ /**
+ * Create a {@link FireworkEffect} from the current contents of this
+ * builder.
+ *
+ * To successfully build, you must have specified at least one color.
+ *
+ * @return The representative firework effect
+ */
+ public FireworkEffect build() {
+ return new FireworkEffect(
+ flicker,
+ trail,
+ colors.build(),
+ fadeColors == null ? ImmutableList.of() : fadeColors.build(),
+ type
+ );
+ }
+ }
+
+ private static final String FLICKER = "flicker";
+ private static final String TRAIL = "trail";
+ private static final String COLORS = "colors";
+ private static final String FADE_COLORS = "fade-colors";
+ private static final String TYPE = "type";
+
+ private final boolean flicker;
+ private final boolean trail;
+ private final ImmutableList colors;
+ private final ImmutableList fadeColors;
+ private final Type type;
+ private String string = null;
+
+ FireworkEffect(boolean flicker, boolean trail, ImmutableList colors, ImmutableList fadeColors, Type type) {
+ if (colors.isEmpty()) {
+ throw new IllegalStateException("Cannot make FireworkEffect without any color");
+ }
+ this.flicker = flicker;
+ this.trail = trail;
+ this.colors = colors;
+ this.fadeColors = fadeColors;
+ this.type = type;
+ }
+
+ /**
+ * Get whether the firework effect flickers.
+ *
+ * @return true if it flickers, false if not
+ */
+ public boolean hasFlicker() {
+ return flicker;
+ }
+
+ /**
+ * Get whether the firework effect has a trail.
+ *
+ * @return true if it has a trail, false if not
+ */
+ public boolean hasTrail() {
+ return trail;
+ }
+
+ /**
+ * Get the primary colors of the firework effect.
+ *
+ * @return An immutable list of the primary colors
+ */
+ public List getColors() {
+ return colors;
+ }
+
+ /**
+ * Get the fade colors of the firework effect.
+ *
+ * @return An immutable list of the fade colors
+ */
+ public List getFadeColors() {
+ return fadeColors;
+ }
+
+ /**
+ * Get the type of the firework effect.
+ *
+ * @return The effect type
+ */
+ public Type getType() {
+ return type;
+ }
+
+ /**
+ * @see ConfigurationSerializable
+ */
+ public static ConfigurationSerializable deserialize(Map map) {
+ Type type = Type.valueOf((String) map.get(TYPE));
+ if (type == null) {
+ throw new IllegalArgumentException(map.get(TYPE) + " is not a valid Type");
+ }
+
+ return builder()
+ .flicker((Boolean) map.get(FLICKER))
+ .trail((Boolean) map.get(TRAIL))
+ .withColor((Iterable>) map.get(COLORS))
+ .withFade((Iterable>) map.get(FADE_COLORS))
+ .with(type)
+ .build();
+ }
+
+ public Map serialize() {
+ return ImmutableMap.of(
+ FLICKER, flicker,
+ TRAIL, trail,
+ COLORS, colors,
+ FADE_COLORS, fadeColors,
+ TYPE, type.name()
+ );
+ }
+
+ @Override
+ public String toString() {
+ final String string = this.string;
+ if (string == null) {
+ return this.string = "FireworkEffect:" + serialize();
+ }
+ return string;
+ }
+
+ @Override
+ public int hashCode() {
+ /**
+ * TRUE and FALSE as per boolean.hashCode()
+ */
+ final int PRIME = 31, TRUE = 1231, FALSE = 1237;
+ int hash = 1;
+ hash = hash * PRIME + (flicker ? TRUE : FALSE);
+ hash = hash * PRIME + (trail ? TRUE : FALSE);
+ hash = hash * PRIME + type.hashCode();
+ hash = hash * PRIME + colors.hashCode();
+ hash = hash * PRIME + fadeColors.hashCode();
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (!(obj instanceof FireworkEffect)) {
+ return false;
+ }
+
+ FireworkEffect that = (FireworkEffect) obj;
+ return this.flicker == that.flicker
+ && this.trail == that.trail
+ && this.type == that.type
+ && this.colors.equals(that.colors)
+ && this.fadeColors.equals(that.fadeColors);
+ }
+}
diff --git a/PaperSpigot-API/src/main/java/org/bukkit/GameMode.java b/PaperSpigot-API/src/main/java/org/bukkit/GameMode.java
new file mode 100644
index 0000000..f85ed0b
--- /dev/null
+++ b/PaperSpigot-API/src/main/java/org/bukkit/GameMode.java
@@ -0,0 +1,66 @@
+package org.bukkit;
+
+import java.util.Map;
+
+import org.bukkit.entity.HumanEntity;
+
+import com.google.common.collect.Maps;
+
+/**
+ * Represents the various type of game modes that {@link HumanEntity}s may
+ * have
+ */
+public enum GameMode {
+ /**
+ * Creative mode may fly, build instantly, become invulnerable and create
+ * free items.
+ */
+ CREATIVE(1),
+
+ /**
+ * Survival mode is the "normal" gameplay type, with no special features.
+ */
+ SURVIVAL(0),
+
+ /**
+ * Adventure mode cannot break blocks without the correct tools.
+ */
+ ADVENTURE(2);
+
+ private final int value;
+ private final static Map BY_ID = Maps.newHashMap();
+
+ private GameMode(final int value) {
+ this.value = value;
+ }
+
+ /**
+ * Gets the mode value associated with this GameMode
+ *
+ * @return An integer value of this gamemode
+ * @deprecated Magic value
+ */
+ @Deprecated
+ public int getValue() {
+ return value;
+ }
+
+ /**
+ * Gets the GameMode represented by the specified value
+ *
+ * @param value Value to check
+ * @return Associative {@link GameMode} with the given value, or null if
+ * it doesn't exist
+ * @deprecated Magic value
+ */
+ @Deprecated
+ public static GameMode getByValue(final int value) {
+ return BY_ID.get(value);
+ }
+
+ static {
+ for (GameMode mode : values()) {
+ BY_ID.put(mode.getValue(), mode);
+ }
+ }
+}
diff --git a/PaperSpigot-API/src/main/java/org/bukkit/GrassSpecies.java b/PaperSpigot-API/src/main/java/org/bukkit/GrassSpecies.java
new file mode 100644
index 0000000..1111515
--- /dev/null
+++ b/PaperSpigot-API/src/main/java/org/bukkit/GrassSpecies.java
@@ -0,0 +1,61 @@
+package org.bukkit;
+
+import java.util.Map;
+
+import com.google.common.collect.Maps;
+
+/**
+ * Represents the different types of grass.
+ */
+public enum GrassSpecies {
+
+ /**
+ * Represents the dead looking grass.
+ */
+ DEAD(0x0),
+ /**
+ * Represents the normal grass species.
+ */
+ NORMAL(0x1),
+ /**
+ * Represents the fern-looking grass species.
+ */
+ FERN_LIKE(0x2);
+
+ private final byte data;
+ private final static Map BY_DATA = Maps.newHashMap();
+
+ private GrassSpecies(final int data) {
+ this.data = (byte) data;
+ }
+
+ /**
+ * Gets the associated data value representing this species
+ *
+ * @return A byte containing the data value of this grass species
+ * @deprecated Magic value
+ */
+ @Deprecated
+ public byte getData() {
+ return data;
+ }
+
+ /**
+ * Gets the GrassSpecies with the given data value
+ *
+ * @param data Data value to fetch
+ * @return The {@link GrassSpecies} representing the given value, or null
+ * if it doesn't exist
+ * @deprecated Magic value
+ */
+ @Deprecated
+ public static GrassSpecies getByData(final byte data) {
+ return BY_DATA.get(data);
+ }
+
+ static {
+ for (GrassSpecies grassSpecies : values()) {
+ BY_DATA.put(grassSpecies.getData(), grassSpecies);
+ }
+ }
+}
diff --git a/PaperSpigot-API/src/main/java/org/bukkit/Instrument.java b/PaperSpigot-API/src/main/java/org/bukkit/Instrument.java
new file mode 100644
index 0000000..891a2b1
--- /dev/null
+++ b/PaperSpigot-API/src/main/java/org/bukkit/Instrument.java
@@ -0,0 +1,67 @@
+package org.bukkit;
+
+import java.util.Map;
+
+import com.google.common.collect.Maps;
+
+public enum Instrument {
+
+ /**
+ * Piano is the standard instrument for a note block.
+ */
+ PIANO(0x0),
+ /**
+ * Bass drum is normally played when a note block is on top of a
+ * stone-like block
+ */
+ BASS_DRUM(0x1),
+ /**
+ * Snare drum is normally played when a note block is on top of a sandy
+ * block.
+ */
+ SNARE_DRUM(0x2),
+ /**
+ * Sticks are normally played when a note block is on top of a glass
+ * block.
+ */
+ STICKS(0x3),
+ /**
+ * Bass guitar is normally played when a note block is on top of a wooden
+ * block.
+ */
+ BASS_GUITAR(0x4);
+
+ private final byte type;
+ private final static Map BY_DATA = Maps.newHashMap();
+
+ private Instrument(final int type) {
+ this.type = (byte) type;
+ }
+
+ /**
+ * @return The type ID of this instrument.
+ * @deprecated Magic value
+ */
+ @Deprecated
+ public byte getType() {
+ return this.type;
+ }
+
+ /**
+ * Get an instrument by its type ID.
+ *
+ * @param type The type ID
+ * @return The instrument
+ * @deprecated Magic value
+ */
+ @Deprecated
+ public static Instrument getByType(final byte type) {
+ return BY_DATA.get(type);
+ }
+
+ static {
+ for (Instrument instrument : Instrument.values()) {
+ BY_DATA.put(instrument.getType(), instrument);
+ }
+ }
+}
diff --git a/PaperSpigot-API/src/main/java/org/bukkit/Location.java b/PaperSpigot-API/src/main/java/org/bukkit/Location.java
new file mode 100644
index 0000000..5c18507
--- /dev/null
+++ b/PaperSpigot-API/src/main/java/org/bukkit/Location.java
@@ -0,0 +1,560 @@
+package org.bukkit;
+
+import org.bukkit.block.Block;
+import org.bukkit.util.NumberConversions;
+import org.bukkit.util.Vector;
+
+/**
+ * Represents a 3-dimensional position in a world
+ */
+public class Location implements Cloneable {
+ private World world;
+ private double x;
+ private double y;
+ private double z;
+ private float pitch;
+ private float yaw;
+
+ /**
+ * Constructs a new Location with the given coordinates
+ *
+ * @param world The world in which this location resides
+ * @param x The x-coordinate of this new location
+ * @param y The y-coordinate of this new location
+ * @param z The z-coordinate of this new location
+ */
+ public Location(final World world, final double x, final double y, final double z) {
+ this(world, x, y, z, 0, 0);
+ }
+
+ /**
+ * Constructs a new Location with the given coordinates and direction
+ *
+ * @param world The world in which this location resides
+ * @param x The x-coordinate of this new location
+ * @param y The y-coordinate of this new location
+ * @param z The z-coordinate of this new location
+ * @param yaw The absolute rotation on the x-plane, in degrees
+ * @param pitch The absolute rotation on the y-plane, in degrees
+ */
+ public Location(final World world, final double x, final double y, final double z, final float yaw, final float pitch) {
+ this.world = world;
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.pitch = pitch;
+ this.yaw = yaw;
+ }
+
+ /**
+ * Sets the world that this location resides in
+ *
+ * @param world New world that this location resides in
+ */
+ public void setWorld(World world) {
+ this.world = world;
+ }
+
+ /**
+ * Gets the world that this location resides in
+ *
+ * @return World that contains this location
+ */
+ public World getWorld() {
+ return world;
+ }
+
+ /**
+ * Gets the chunk at the represented location
+ *
+ * @return Chunk at the represented location
+ */
+ public Chunk getChunk() {
+ return world.getChunkAt(this);
+ }
+
+ /**
+ * Gets the block at the represented location
+ *
+ * @return Block at the represented location
+ */
+ public Block getBlock() {
+ return world.getBlockAt(this);
+ }
+
+ /**
+ * Sets the x-coordinate of this location
+ *
+ * @param x X-coordinate
+ */
+ public void setX(double x) {
+ this.x = x;
+ }
+
+ /**
+ * Gets the x-coordinate of this location
+ *
+ * @return x-coordinate
+ */
+ public double getX() {
+ return x;
+ }
+
+ /**
+ * Gets the floored value of the X component, indicating the block that
+ * this location is contained with.
+ *
+ * @return block X
+ */
+ public int getBlockX() {
+ return locToBlock(x);
+ }
+
+ /**
+ * Sets the y-coordinate of this location
+ *
+ * @param y y-coordinate
+ */
+ public void setY(double y) {
+ this.y = y;
+ }
+
+ /**
+ * Gets the y-coordinate of this location
+ *
+ * @return y-coordinate
+ */
+ public double getY() {
+ return y;
+ }
+
+ /**
+ * Gets the floored value of the Y component, indicating the block that
+ * this location is contained with.
+ *
+ * @return block y
+ */
+ public int getBlockY() {
+ return locToBlock(y);
+ }
+
+ /**
+ * Sets the z-coordinate of this location
+ *
+ * @param z z-coordinate
+ */
+ public void setZ(double z) {
+ this.z = z;
+ }
+
+ /**
+ * Gets the z-coordinate of this location
+ *
+ * @return z-coordinate
+ */
+ public double getZ() {
+ return z;
+ }
+
+ /**
+ * Gets the floored value of the Z component, indicating the block that
+ * this location is contained with.
+ *
+ * @return block z
+ */
+ public int getBlockZ() {
+ return locToBlock(z);
+ }
+
+ /**
+ * Sets the yaw of this location, measured in degrees.
+ *
+ * - A yaw of 0 or 360 represents the positive z direction.
+ *
- A yaw of 180 represents the negative z direction.
+ *
- A yaw of 90 represents the negative x direction.
+ *
- A yaw of 270 represents the positive x direction.
+ *
+ * Increasing yaw values are the equivalent of turning to your
+ * right-facing, increasing the scale of the next respective axis, and
+ * decreasing the scale of the previous axis.
+ *
+ * @param yaw new rotation's yaw
+ */
+ public void setYaw(float yaw) {
+ this.yaw = yaw;
+ }
+
+ /**
+ * Gets the yaw of this location, measured in degrees.
+ *
+ * - A yaw of 0 or 360 represents the positive z direction.
+ *
- A yaw of 180 represents the negative z direction.
+ *
- A yaw of 90 represents the negative x direction.
+ *
- A yaw of 270 represents the positive x direction.
+ *
+ * Increasing yaw values are the equivalent of turning to your
+ * right-facing, increasing the scale of the next respective axis, and
+ * decreasing the scale of the previous axis.
+ *
+ * @return the rotation's yaw
+ */
+ public float getYaw() {
+ return yaw;
+ }
+
+ /**
+ * Sets the pitch of this location, measured in degrees.
+ *
+ * - A pitch of 0 represents level forward facing.
+ *
- A pitch of 90 represents downward facing, or negative y
+ * direction.
+ *
- A pitch of -90 represents upward facing, or positive y direction.
+ *
+ * Increasing pitch values the equivalent of looking down.
+ *
+ * @param pitch new incline's pitch
+ */
+ public void setPitch(float pitch) {
+ this.pitch = pitch;
+ }
+
+ /**
+ * Gets the pitch of this location, measured in degrees.
+ *
+ * - A pitch of 0 represents level forward facing.
+ *
- A pitch of 90 represents downward facing, or negative y
+ * direction.
+ *
- A pitch of -90 represents upward facing, or positive y direction.
+ *