diff --git a/README.md b/README.md index a51766e6..1905b8d5 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ -Bukkit +Spigot-API ====== A Minecraft Server API. -Website: [http://bukkit.org](http://bukkit.org) -Bugs/Suggestions: [http://leaky.bukkit.org](http://leaky.bukkit.org) -Contributing Guidelines: [CONTRIBUTING.md](https://github.com/Bukkit/Bukkit/blob/master/CONTRIBUTING.md) +Website: [http://spigotmc.org](http://spigotmc.org) +Bugs/Suggestions: [http://www.spigotmc.org/forums/bugs-feature-requests.8/](http://www.spigotmc.org/forums/bugs-feature-requests.8/) +Contributing Guidelines: [CONTRIBUTING.md](https://github.com/SpigotMC/Spigot-API/blob/master/CONTRIBUTING.md) Compilation ----------- diff --git a/pom.xml b/pom.xml index 4c5937ab..0c9f2433 100644 --- a/pom.xml +++ b/pom.xml @@ -1,42 +1,21 @@ 4.0.0 - org.bukkit - bukkit + org.spigotmc + spigot-api 1.7.10-R0.1-SNAPSHOT - Bukkit - http://www.bukkit.org + Spigot-API + http://www.spigotmc.org UTF-8 - - scm:git:git@github.com:Bukkit/Bukkit.git - scm:git:git://github.com/Bukkit/Bukkit.git - https://github.com/Bukkit/Bukkit/tree/master/ - - - - jenkins - http://ci.bukkit.org - - - - - jd.bukkit.org - file:///home/javadocs/public_html/ - - - repobo-rel - repo.bukkit.org Releases - http://repo.bukkit.org/content/repositories/releases/ - - - repobo-snap - repo.bukkit.org Snapshots - http://repo.bukkit.org/content/repositories/snapshots/ - - + + org.spigotmc + spigot-parent + dev-SNAPSHOT + ../pom.xml + @@ -97,21 +76,21 @@ org.yaml snakeyaml - 1.9 + 1.12 jar compile com.googlecode.json-simple json-simple - 1.1 + 1.1.1 jar compile org.avaje ebean - 2.7.3 + 2.8.1 jar compile @@ -125,7 +104,7 @@ commons-lang commons-lang - 2.3 + 2.6 diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java index 1eaf92d7..34f44af4 100644 --- a/src/main/java/org/bukkit/Bukkit.java +++ b/src/main/java/org/bukkit/Bukkit.java @@ -197,7 +197,6 @@ public static String getUpdateFolder() { /** * @see Server#getPlayer(String name) */ - @Deprecated public static Player getPlayer(String name) { return server.getPlayer(name); } @@ -205,7 +204,6 @@ public static Player getPlayer(String name) { /** * @see Server#matchPlayer(String name) */ - @Deprecated public static List matchPlayer(String name) { return server.matchPlayer(name); } @@ -301,6 +299,7 @@ public static MapView createMap(World world) { */ public static void reload() { server.reload(); + org.spigotmc.CustomTimingsHandler.reload(); // Spigot } /** @@ -447,7 +446,6 @@ public static OfflinePlayer getOfflinePlayer(UUID id) { /** * @see Server#getPlayerExact(String name) */ - @Deprecated public static Player getPlayerExact(String name) { return server.getPlayerExact(name); } diff --git a/src/main/java/org/bukkit/Effect.java b/src/main/java/org/bukkit/Effect.java index 2474a2d9..37f29e2e 100644 --- a/src/main/java/org/bukkit/Effect.java +++ b/src/main/java/org/bukkit/Effect.java @@ -5,6 +5,7 @@ import com.google.common.collect.Maps; import org.bukkit.block.BlockFace; +import org.bukkit.material.MaterialData; import org.bukkit.potion.Potion; /** @@ -79,27 +80,188 @@ public enum Effect { /** * The flames seen on a mobspawner; a visual effect. */ - MOBSPAWNER_FLAMES(2004, Type.VISUAL); + 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; - Effect(int id, Type type) { + private Effect(int id, Type type) { this(id,type,null); } - Effect(int id, Type type, Class data) { + 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 ID of this effect + * @return if this Effect isn't of type PARTICLE it returns ID of this effect * @deprecated Magic value */ @Deprecated @@ -107,6 +269,15 @@ 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. */ @@ -115,8 +286,7 @@ public Type getType() { } /** - * @return The class which represents data for this effect, or null if - * none + * @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; @@ -136,12 +306,32 @@ public static Effect getById(int id) { static { for (Effect effect : values()) { - BY_ID.put(effect.id, effect); + 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} + public enum Type {SOUND, VISUAL, PARTICLE} } diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java index e14e9f1d..14c8a8a7 100644 --- a/src/main/java/org/bukkit/Server.java +++ b/src/main/java/org/bukkit/Server.java @@ -308,23 +308,17 @@ public interface Server extends PluginMessageRecipient { *

* This method may not return objects for offline players. * - * @deprecated Use {@link #getPlayer(UUID)} as player names are no longer - * guaranteed to be unique * @param name the name to look up * @return a player if one was found, null otherwise */ - @Deprecated public Player getPlayer(String name); /** * Gets the player with the exact given name, case insensitive. * - * @deprecated Use {@link #getPlayer(UUID)} as player names are no longer - * guaranteed to be unique * @param name Exact name of the player to retrieve * @return a player object if one was found, null otherwise */ - @Deprecated public Player getPlayerExact(String name); /** @@ -334,12 +328,9 @@ public interface Server extends PluginMessageRecipient { * This list is not sorted in any particular order. If an exact match is * found, the returned list will only contain a single result. * - * @deprecated Use {@link #getPlayer(UUID)} as player names are no longer - * guaranteed to be unique * @param name the (partial) name to match * @return list of all possible players */ - @Deprecated public List matchPlayer(String name); /** diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java index 9bf2c41b..ab731747 100644 --- a/src/main/java/org/bukkit/World.java +++ b/src/main/java/org/bukkit/World.java @@ -1155,6 +1155,80 @@ public interface World extends PluginMessageRecipient, Metadatable { */ public boolean isGameRule(String rule); + // Spigot start + public class Spigot + { + + /** + * Plays an effect to all players within a default radius around a given + * location. + * + * @param location the {@link Location} around which players must be to + * see the effect + * @param effect the {@link Effect} + * @throws IllegalArgumentException if the location or effect is null. + * It also throws when the effect requires a material or a material data + */ + public void playEffect(Location location, Effect effect) + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + /** + * Plays an effect to all players within a default radius around a given + * location. The effect will use the provided material (and material + * data if required). The particle's position on the client will be the + * given location, adjusted on each axis by a normal distribution with + * mean 0 and standard deviation given in the offset parameters, each + * particle has independently calculated offsets. The effect will have + * the given speed and particle count if the effect is a particle. Some + * effect will create multiple particles. + * + * @param location the {@link Location} around which players must be to + * see the effect + * @param effect effect the {@link Effect} + * @param id the item/block/data id for the effect + * @param data the data value of the block/item for the effect + * @param offsetX the amount to be randomly offset by in the X axis + * @param offsetY the amount to be randomly offset by in the Y axis + * @param offsetZ the amount to be randomly offset by in the Z axis + * @param speed the speed of the particles + * @param particleCount the number of particles + * @param radius the radius around the location + */ + public void playEffect(Location location, Effect effect, int id, int data, float offsetX, float offsetY, float offsetZ, float speed, int particleCount, int radius) + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + /** + * Strikes lightning at the given {@link Location} and possibly without sound + * + * @param loc The location to strike lightning + * @param isSilent Whether this strike makes no sound + * @return The lightning entity. + */ + public LightningStrike strikeLightning(Location loc, boolean isSilent) + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + /** + * Strikes lightning at the given {@link Location} without doing damage and possibly without sound + * + * @param loc The location to strike lightning + * @param isSilent Whether this strike makes no sound + * @return The lightning entity. + */ + public LightningStrike strikeLightningEffect(Location loc, boolean isSilent) + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + } + + Spigot spigot(); + // Spigot end + /** * Represents various map environment types that a world may be */ diff --git a/src/main/java/org/bukkit/command/Command.java b/src/main/java/org/bukkit/command/Command.java index 87c33d9c..31e4f667 100644 --- a/src/main/java/org/bukkit/command/Command.java +++ b/src/main/java/org/bukkit/command/Command.java @@ -31,6 +31,7 @@ public abstract class Command { protected String usageMessage; private String permission; private String permissionMessage; + public org.spigotmc.CustomTimingsHandler timings; // Spigot protected Command(String name) { this(name, "", "/" + name, new ArrayList()); @@ -44,6 +45,7 @@ protected Command(String name, String description, String usageMessage, List(aliases); + this.timings = new org.spigotmc.CustomTimingsHandler("** Command: " + name); // Spigot } /** @@ -200,6 +202,7 @@ public String getLabel() { public boolean setLabel(String name) { this.nextLabel = name; if (!isRegistered()) { + this.timings = new org.spigotmc.CustomTimingsHandler("** Command: " + name); // Spigot this.label = name; return true; } diff --git a/src/main/java/org/bukkit/command/SimpleCommandMap.java b/src/main/java/org/bukkit/command/SimpleCommandMap.java index d75380c8..f15b95da 100644 --- a/src/main/java/org/bukkit/command/SimpleCommandMap.java +++ b/src/main/java/org/bukkit/command/SimpleCommandMap.java @@ -176,11 +176,15 @@ public boolean dispatch(CommandSender sender, String commandLine) throws Command } try { + target.timings.startTiming(); // Spigot // Note: we don't return the result of target.execute as thats success / failure, we return handled (true) or not handled (false) target.execute(sender, sentCommandLabel, Arrays_copyOfRange(args, 1, args.length)); + target.timings.stopTiming(); // Spigot } catch (CommandException ex) { + target.timings.stopTiming(); // Spigot throw ex; } catch (Throwable ex) { + target.timings.stopTiming(); // Spigot throw new CommandException("Unhandled exception executing '" + commandLine + "' in " + target, ex); } diff --git a/src/main/java/org/bukkit/command/defaults/DeopCommand.java b/src/main/java/org/bukkit/command/defaults/DeopCommand.java index 1b71d493..be85334a 100644 --- a/src/main/java/org/bukkit/command/defaults/DeopCommand.java +++ b/src/main/java/org/bukkit/command/defaults/DeopCommand.java @@ -49,7 +49,7 @@ public List tabComplete(CommandSender sender, String alias, String[] arg if (args.length == 1) { List completions = new ArrayList(); - for (OfflinePlayer player : Bukkit.getOfflinePlayers()) { + for (OfflinePlayer player : Bukkit.getOperators()) { // Spigot - only deop ops! String playerName = player.getName(); if (player.isOp() && StringUtil.startsWithIgnoreCase(playerName, args[0])) { completions.add(playerName); diff --git a/src/main/java/org/bukkit/command/defaults/PluginsCommand.java b/src/main/java/org/bukkit/command/defaults/PluginsCommand.java index b888da13..e21d1679 100644 --- a/src/main/java/org/bukkit/command/defaults/PluginsCommand.java +++ b/src/main/java/org/bukkit/command/defaults/PluginsCommand.java @@ -40,4 +40,12 @@ private String getPluginList() { return "(" + plugins.length + "): " + pluginList.toString(); } + + // Spigot Start + @Override + public java.util.List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException + { + return java.util.Collections.emptyList(); + } + // Spigot End } diff --git a/src/main/java/org/bukkit/command/defaults/ReloadCommand.java b/src/main/java/org/bukkit/command/defaults/ReloadCommand.java index fb3c90fb..a08ae804 100644 --- a/src/main/java/org/bukkit/command/defaults/ReloadCommand.java +++ b/src/main/java/org/bukkit/command/defaults/ReloadCommand.java @@ -25,4 +25,12 @@ public boolean execute(CommandSender sender, String currentAlias, String[] args) return true; } + + // Spigot Start + @Override + public java.util.List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException + { + return java.util.Collections.emptyList(); + } + // Spigot End } diff --git a/src/main/java/org/bukkit/command/defaults/TellCommand.java b/src/main/java/org/bukkit/command/defaults/TellCommand.java index 287f49f8..fc49207a 100644 --- a/src/main/java/org/bukkit/command/defaults/TellCommand.java +++ b/src/main/java/org/bukkit/command/defaults/TellCommand.java @@ -45,4 +45,16 @@ public boolean execute(CommandSender sender, String currentAlias, String[] args) return true; } + + // Spigot Start + @Override + public java.util.List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException + { + if ( args.length == 0 ) + { + return super.tabComplete( sender, alias, args ); + } + return java.util.Collections.emptyList(); + } + // Spigot End } diff --git a/src/main/java/org/bukkit/command/defaults/TestForCommand.java b/src/main/java/org/bukkit/command/defaults/TestForCommand.java index c9ac1cea..a687fef3 100644 --- a/src/main/java/org/bukkit/command/defaults/TestForCommand.java +++ b/src/main/java/org/bukkit/command/defaults/TestForCommand.java @@ -23,4 +23,16 @@ public boolean execute(CommandSender sender, String currentAlias, String[] args) sender.sendMessage(ChatColor.RED + "/testfor is only usable by commandblocks with analog output."); return true; } + + // Spigot Start + @Override + public java.util.List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException + { + if ( args.length == 0 ) + { + return super.tabComplete( sender, alias, args ); + } + return java.util.Collections.emptyList(); + } + // Spigot End } diff --git a/src/main/java/org/bukkit/command/defaults/TimingsCommand.java b/src/main/java/org/bukkit/command/defaults/TimingsCommand.java index 05cfcb01..22926d63 100644 --- a/src/main/java/org/bukkit/command/defaults/TimingsCommand.java +++ b/src/main/java/org/bukkit/command/defaults/TimingsCommand.java @@ -19,23 +19,97 @@ import com.google.common.collect.ImmutableList; +// Spigot start +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.util.logging.Level; + +import org.bukkit.command.RemoteConsoleCommandSender; +import org.bukkit.plugin.SimplePluginManager; +import org.spigotmc.CustomTimingsHandler; +// Spigot end + public class TimingsCommand extends BukkitCommand { - private static final List TIMINGS_SUBCOMMANDS = ImmutableList.of("merged", "reset", "separate"); + private static final List TIMINGS_SUBCOMMANDS = ImmutableList.of("report", "reset", "on", "off", "paste"); // Spigot + public static long timingStart = 0; // Spigot public TimingsCommand(String name) { super(name); - this.description = "Records timings for all plugin events"; - this.usageMessage = "/timings "; + this.description = "Manages Spigot Timings data to see performance of the server."; // Spigot + this.usageMessage = "/timings "; // Spigot this.setPermission("bukkit.command.timings"); } + // Spigot start - redesigned Timings Command + public void executeSpigotTimings(CommandSender sender, String[] args) { + if ( "on".equals( args[0] ) ) + { + ( (SimplePluginManager) Bukkit.getPluginManager() ).useTimings( true ); + CustomTimingsHandler.reload(); + sender.sendMessage( "Enabled Timings & Reset" ); + return; + } else if ( "off".equals( args[0] ) ) + { + ( (SimplePluginManager) Bukkit.getPluginManager() ).useTimings( false ); + sender.sendMessage( "Disabled Timings" ); + return; + } + + if ( !Bukkit.getPluginManager().useTimings() ) + { + sender.sendMessage( "Please enable timings by typing /timings on" ); + return; + } + + boolean paste = "paste".equals( args[0] ); + if ("reset".equals(args[0])) { + CustomTimingsHandler.reload(); + sender.sendMessage("Timings reset"); + } else if ("merged".equals(args[0]) || "report".equals(args[0]) || paste) { + long sampleTime = System.nanoTime() - timingStart; + int index = 0; + File timingFolder = new File("timings"); + timingFolder.mkdirs(); + File timings = new File(timingFolder, "timings.txt"); + ByteArrayOutputStream bout = ( paste ) ? new ByteArrayOutputStream() : null; + while (timings.exists()) timings = new File(timingFolder, "timings" + (++index) + ".txt"); + PrintStream fileTimings = null; + try { + fileTimings = ( paste ) ? new PrintStream( bout ) : new PrintStream( timings ); + + CustomTimingsHandler.printTimings(fileTimings); + fileTimings.println( "Sample time " + sampleTime + " (" + sampleTime / 1E9 + "s)" ); + + if ( paste ) + { + new PasteThread( sender, bout ).start(); + return; + } + + sender.sendMessage("Timings written to " + timings.getPath()); + sender.sendMessage( "Paste contents of file into form at http://www.spigotmc.org/go/timings to read results." ); + + } catch (IOException e) { + } finally { + if (fileTimings != null) { + fileTimings.close(); + } + } + } + } + // Spigot end + @Override public boolean execute(CommandSender sender, String currentAlias, String[] args) { if (!testPermission(sender)) return true; - if (args.length != 1) { + if (args.length < 1) { // Spigot sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); return false; } + if (true) { executeSpigotTimings(sender, args); return true; } // Spigot if (!sender.getServer().getPluginManager().useTimings()) { sender.sendMessage("Please enable timings by setting \"settings.plugin-profiling\" to true in bukkit.yml"); return true; @@ -118,4 +192,55 @@ public List tabComplete(CommandSender sender, String alias, String[] arg } return ImmutableList.of(); } + + // Spigot start + private static class PasteThread extends Thread + { + + private final CommandSender sender; + private final ByteArrayOutputStream bout; + + public PasteThread(CommandSender sender, ByteArrayOutputStream bout) + { + super( "Timings paste thread" ); + this.sender = sender; + this.bout = bout; + } + + @Override + public synchronized void start() { + if (sender instanceof RemoteConsoleCommandSender) { + run(); + } else { + super.start(); + } + } + + @Override + public void run() + { + try + { + HttpURLConnection con = (HttpURLConnection) new URL( "http://paste.ubuntu.com/" ).openConnection(); + con.setDoOutput( true ); + con.setRequestMethod( "POST" ); + con.setInstanceFollowRedirects( false ); + + OutputStream out = con.getOutputStream(); + out.write( "poster=Spigot&syntax=text&content=".getBytes( "UTF-8" ) ); + out.write( URLEncoder.encode( bout.toString( "UTF-8" ), "UTF-8" ).getBytes( "UTF-8" ) ); + out.close(); + con.getInputStream().close(); + + String location = con.getHeaderField( "Location" ); + String pasteID = location.substring( "http://paste.ubuntu.com/".length(), location.length() - 1 ); + sender.sendMessage( ChatColor.GREEN + "View timings results can be viewed at http://www.spigotmc.org/go/timings?url=" + pasteID ); + } catch ( IOException ex ) + { + sender.sendMessage( ChatColor.RED + "Error pasting timings, check your console for more information" ); + Bukkit.getServer().getLogger().log( Level.WARNING, "Could not paste timings", ex ); + } + } + } + // Spigot end } diff --git a/src/main/java/org/bukkit/command/defaults/WhitelistCommand.java b/src/main/java/org/bukkit/command/defaults/WhitelistCommand.java index b3fa4f82..6559b33b 100644 --- a/src/main/java/org/bukkit/command/defaults/WhitelistCommand.java +++ b/src/main/java/org/bukkit/command/defaults/WhitelistCommand.java @@ -104,7 +104,7 @@ public List tabComplete(CommandSender sender, String alias, String[] arg } else if (args.length == 2) { if (args[0].equalsIgnoreCase("add")) { List completions = new ArrayList(); - for (OfflinePlayer player : Bukkit.getOfflinePlayers()) { + for (OfflinePlayer player : Bukkit.getOnlinePlayers()) { // Spigot - well maybe sometimes you haven't turned the whitelist on just yet. String name = player.getName(); if (StringUtil.startsWithIgnoreCase(name, args[1]) && !player.isWhitelisted()) { completions.add(name); diff --git a/src/main/java/org/bukkit/conversations/BooleanPrompt.java b/src/main/java/org/bukkit/conversations/BooleanPrompt.java index 3f2c97f4..81ef78cd 100644 --- a/src/main/java/org/bukkit/conversations/BooleanPrompt.java +++ b/src/main/java/org/bukkit/conversations/BooleanPrompt.java @@ -15,12 +15,13 @@ public BooleanPrompt() { @Override protected boolean isInputValid(ConversationContext context, String input) { - String[] accepted = {"true", "false", "on", "off", "yes", "no"}; + String[] accepted = {"true", "false", "on", "off", "yes", "no" /* Spigot: */, "y", "n", "1", "0", "right", "wrong", "correct", "incorrect", "valid", "invalid"}; // Spigot return ArrayUtils.contains(accepted, input.toLowerCase()); } @Override protected Prompt acceptValidatedInput(ConversationContext context, String input) { + if (input.equalsIgnoreCase("y") || input.equals("1") || input.equalsIgnoreCase("right") || input.equalsIgnoreCase("correct") || input.equalsIgnoreCase("valid")) input = "true"; // Spigot return acceptValidatedInput(context, BooleanUtils.toBoolean(input)); } diff --git a/src/main/java/org/bukkit/conversations/Conversation.java b/src/main/java/org/bukkit/conversations/Conversation.java index d4c1f6d3..46912c8f 100644 --- a/src/main/java/org/bukkit/conversations/Conversation.java +++ b/src/main/java/org/bukkit/conversations/Conversation.java @@ -209,6 +209,7 @@ public ConversationState getState() { * @param input The user's chat text. */ public void acceptInput(String input) { + try { // Spigot if (currentPrompt != null) { // Echo the user's input @@ -228,6 +229,12 @@ public void acceptInput(String input) { currentPrompt = currentPrompt.acceptInput(context, input); outputNextPrompt(); } + // Spigot Start + } catch ( Throwable t ) + { + org.bukkit.Bukkit.getLogger().log( java.util.logging.Level.SEVERE, "Error handling conversation prompt", t ); + } + // Spigot End } /** diff --git a/src/main/java/org/bukkit/conversations/ConversationContext.java b/src/main/java/org/bukkit/conversations/ConversationContext.java index 4f33ff46..7390a771 100644 --- a/src/main/java/org/bukkit/conversations/ConversationContext.java +++ b/src/main/java/org/bukkit/conversations/ConversationContext.java @@ -45,6 +45,14 @@ public Conversable getForWhom() { return forWhom; } + /** + * Gets the entire sessionData map. + * @return The full sessionData map. + */ + public Map getAllSessionData() { + return sessionData; + } + /** * Gets session data shared between all {@link Prompt} invocations. Use * this as a way to pass data through each Prompt as the conversation diff --git a/src/main/java/org/bukkit/entity/Arrow.java b/src/main/java/org/bukkit/entity/Arrow.java index e49eef07..e7a32f79 100644 --- a/src/main/java/org/bukkit/entity/Arrow.java +++ b/src/main/java/org/bukkit/entity/Arrow.java @@ -39,4 +39,20 @@ public interface Arrow extends Projectile { * @param critical whether or not it should be critical */ public void setCritical(boolean critical); + + public class Spigot extends Entity.Spigot + { + + public double getDamage() + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + public void setDamage(double damage) + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + } + + Spigot spigot(); } diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java index 396ea208..294e80b4 100644 --- a/src/main/java/org/bukkit/entity/Entity.java +++ b/src/main/java/org/bukkit/entity/Entity.java @@ -291,4 +291,22 @@ public interface Entity extends Metadatable { * @return The current vehicle. */ public Entity getVehicle(); + + // Spigot Start + public class Spigot + { + + /** + * Returns whether this entity is invulnerable. + * + * @return True if the entity is invulnerable. + */ + public boolean isInvulnerable() + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + } + + Spigot spigot(); + // Spigot End } diff --git a/src/main/java/org/bukkit/entity/LightningStrike.java b/src/main/java/org/bukkit/entity/LightningStrike.java index c8b5154e..1ed4ac98 100644 --- a/src/main/java/org/bukkit/entity/LightningStrike.java +++ b/src/main/java/org/bukkit/entity/LightningStrike.java @@ -12,4 +12,21 @@ public interface LightningStrike extends Weather { */ public boolean isEffect(); + + public class Spigot extends Entity.Spigot + { + + /* + * Returns whether the strike is silent. + * + * @return whether the strike is silent. + */ + public boolean isSilent() + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + } + + Spigot spigot(); } diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java index fe8a0bd7..b2ad5b7f 100644 --- a/src/main/java/org/bukkit/entity/Player.java +++ b/src/main/java/org/bukkit/entity/Player.java @@ -333,10 +333,8 @@ public interface Player extends HumanEntity, Conversable, CommandSender, Offline /** * Forces an update of the player's entire inventory. * - * @deprecated This method should not be relied upon as it is a temporary - * work-around for a larger, more complicated issue. */ - @Deprecated + //@Deprecated // Spigot - undeprecate public void updateInventory(); /** @@ -1035,4 +1033,77 @@ public interface Player extends HumanEntity, Conversable, CommandSender, Offline * @see Player#setHealthScaled(boolean) */ public double getHealthScale(); + + // Spigot start + public class Spigot extends Entity.Spigot + { + + /** + * Gets the connection address of this player, regardless of whether it + * has been spoofed or not. + * + * @return the player's connection address + */ + public InetSocketAddress getRawAddress() + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + public void playEffect(Location location, Effect effect, int id, int data, float offsetX, float offsetY, float offsetZ, float speed, int particleCount, int radius) + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + /** + * Gets whether the player collides with entities + * + * @return the player's collision toggle state + */ + public boolean getCollidesWithEntities() + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + /** + * Sets whether the player collides with entities + * + * @param collides whether the player should collide with entities or + * not. + */ + public void setCollidesWithEntities(boolean collides) + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + /** + * Respawns the player if dead. + */ + public void respawn() + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + /** + * Gets player locale language. + * + * @return the player's client language settings + */ + public String getLocale() + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + /** + * Gets all players hidden with {@link hidePlayer(org.bukkit.entity.Player)}. + * + * @return a Set with all hidden players + */ + public java.util.Set getHiddenPlayers() + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + } + + Spigot spigot(); + // Spigot end } diff --git a/src/main/java/org/bukkit/event/entity/CreatureSpawnEvent.java b/src/main/java/org/bukkit/event/entity/CreatureSpawnEvent.java index 288e98bd..88831574 100644 --- a/src/main/java/org/bukkit/event/entity/CreatureSpawnEvent.java +++ b/src/main/java/org/bukkit/event/entity/CreatureSpawnEvent.java @@ -4,17 +4,13 @@ import org.bukkit.entity.CreatureType; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; -import org.bukkit.event.Cancellable; -import org.bukkit.event.HandlerList; /** * Called when a creature is spawned into a world. *

* If a Creature Spawn event is cancelled, the creature will not spawn. */ -public class CreatureSpawnEvent extends EntityEvent implements Cancellable { - private static final HandlerList handlers = new HandlerList(); - private boolean canceled; +public class CreatureSpawnEvent extends EntitySpawnEvent { private final SpawnReason spawnReason; public CreatureSpawnEvent(final LivingEntity spawnee, final SpawnReason spawnReason) { @@ -28,28 +24,11 @@ public CreatureSpawnEvent(Entity spawnee, CreatureType type, Location loc, Spawn spawnReason = reason; } - public boolean isCancelled() { - return canceled; - } - - public void setCancelled(boolean cancel) { - canceled = cancel; - } - @Override public LivingEntity getEntity() { return (LivingEntity) entity; } - /** - * Gets the location at which the creature is spawning. - * - * @return The location at which the creature is spawning - */ - public Location getLocation() { - return getEntity().getLocation(); - } - /** * Gets the type of creature being spawned. * @@ -72,15 +51,6 @@ public SpawnReason getSpawnReason() { return spawnReason; } - @Override - public HandlerList getHandlers() { - return handlers; - } - - public static HandlerList getHandlerList() { - return handlers; - } - /** * An enum to specify the type of spawning */ diff --git a/src/main/java/org/bukkit/event/entity/EntitySpawnEvent.java b/src/main/java/org/bukkit/event/entity/EntitySpawnEvent.java new file mode 100644 index 00000000..5dcf98f3 --- /dev/null +++ b/src/main/java/org/bukkit/event/entity/EntitySpawnEvent.java @@ -0,0 +1,45 @@ +package org.bukkit.event.entity; + +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.event.HandlerList; + +/** + * Called when an entity is spawned into a world. + *

+ * If an Entity Spawn event is cancelled, the entity will not spawn. + */ +public class EntitySpawnEvent extends EntityEvent implements org.bukkit.event.Cancellable { + private static final HandlerList handlers = new HandlerList(); + private boolean canceled; + + public EntitySpawnEvent(final Entity spawnee) { + super(spawnee); + } + + public boolean isCancelled() { + return canceled; + } + + public void setCancelled(boolean cancel) { + canceled = cancel; + } + + /** + * Gets the location at which the entity is spawning. + * + * @return The location at which the entity is spawning + */ + public Location getLocation() { + return getEntity().getLocation(); + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/src/main/java/org/bukkit/event/entity/ItemSpawnEvent.java b/src/main/java/org/bukkit/event/entity/ItemSpawnEvent.java index bafd934a..776f8e72 100644 --- a/src/main/java/org/bukkit/event/entity/ItemSpawnEvent.java +++ b/src/main/java/org/bukkit/event/entity/ItemSpawnEvent.java @@ -1,51 +1,23 @@ package org.bukkit.event.entity; -import org.bukkit.entity.Item; import org.bukkit.Location; -import org.bukkit.event.Cancellable; -import org.bukkit.event.HandlerList; +import org.bukkit.entity.Item; /** * Called when an item is spawned into a world */ -public class ItemSpawnEvent extends EntityEvent implements Cancellable { - private static final HandlerList handlers = new HandlerList(); - private final Location location; - private boolean canceled; - - public ItemSpawnEvent(final Item spawnee, final Location loc) { +public class ItemSpawnEvent extends EntitySpawnEvent { + public ItemSpawnEvent(final Item spawnee) { super(spawnee); - this.location = loc; } - public boolean isCancelled() { - return canceled; - } - - public void setCancelled(boolean cancel) { - canceled = cancel; + @Deprecated + public ItemSpawnEvent(final Item spawnee, final Location loc) { + this(spawnee); } @Override public Item getEntity() { return (Item) entity; } - - /** - * Gets the location at which the item is spawning. - * - * @return The location at which the item is spawning - */ - public Location getLocation() { - return location; - } - - @Override - public HandlerList getHandlers() { - return handlers; - } - - public static HandlerList getHandlerList() { - return handlers; - } } diff --git a/src/main/java/org/bukkit/event/entity/SpawnerSpawnEvent.java b/src/main/java/org/bukkit/event/entity/SpawnerSpawnEvent.java new file mode 100644 index 00000000..1acb3c40 --- /dev/null +++ b/src/main/java/org/bukkit/event/entity/SpawnerSpawnEvent.java @@ -0,0 +1,22 @@ +package org.bukkit.event.entity; + +import org.bukkit.block.CreatureSpawner; +import org.bukkit.entity.Entity; + +/** + * Called when an entity is spawned into a world by a spawner. + *

+ * If a Spawner Spawn event is cancelled, the entity will not spawn. + */ +public class SpawnerSpawnEvent extends EntitySpawnEvent { + private final CreatureSpawner spawner; + + public SpawnerSpawnEvent(final Entity spawnee, final CreatureSpawner spawner) { + super(spawnee); + this.spawner = spawner; + } + + public CreatureSpawner getSpawner() { + return spawner; + } +} diff --git a/src/main/java/org/bukkit/event/inventory/InventoryClickEvent.java b/src/main/java/org/bukkit/event/inventory/InventoryClickEvent.java index 28198b8b..3313d915 100644 --- a/src/main/java/org/bukkit/event/inventory/InventoryClickEvent.java +++ b/src/main/java/org/bukkit/event/inventory/InventoryClickEvent.java @@ -47,6 +47,7 @@ public class InventoryClickEvent extends InventoryInteractEvent { private static final HandlerList handlers = new HandlerList(); private final ClickType click; private final InventoryAction action; + private final Inventory clickedInventory; private SlotType slot_type; private int whichSlot; private int rawSlot; @@ -62,6 +63,13 @@ public InventoryClickEvent(InventoryView view, SlotType type, int slot, ClickTyp super(view); this.slot_type = type; this.rawSlot = slot; + if (slot < 0) { + this.clickedInventory = null; + } else if (view.getTopInventory() != null && slot < view.getTopInventory().getSize()) { + this.clickedInventory = view.getTopInventory(); + } else { + this.clickedInventory = view.getBottomInventory(); + } this.whichSlot = view.convertSlot(slot); this.click = click; this.action = action; @@ -72,6 +80,14 @@ public InventoryClickEvent(InventoryView view, SlotType type, int slot, ClickTyp this.hotbarKey = key; } + /** + * Gets the inventory that was clicked, or null if outside of window + * @return The clicked inventory + */ + public Inventory getClickedInventory() { + return clickedInventory; + } + /** * Gets the type of slot that was clicked. * diff --git a/src/main/java/org/bukkit/event/player/PlayerItemDamageEvent.java b/src/main/java/org/bukkit/event/player/PlayerItemDamageEvent.java new file mode 100644 index 00000000..38a72ab8 --- /dev/null +++ b/src/main/java/org/bukkit/event/player/PlayerItemDamageEvent.java @@ -0,0 +1,54 @@ +package org.bukkit.event.player; + +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.inventory.ItemStack; + +public class PlayerItemDamageEvent extends PlayerEvent implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); + private final ItemStack item; + private int damage; + private boolean cancelled = false; + + public PlayerItemDamageEvent(Player player, ItemStack what, int damage) { + super(player); + this.item = what; + this.damage = damage; + } + + public ItemStack getItem() { + return item; + } + + /** + * Gets the amount of durability damage this item will be taking. + * + * @return durability change + */ + public int getDamage() { + return damage; + } + + public void setDamage(int damage) { + this.damage = damage; + } + + public boolean isCancelled() { + return cancelled; + } + + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/src/main/java/org/bukkit/event/player/PlayerLoginEvent.java b/src/main/java/org/bukkit/event/player/PlayerLoginEvent.java index b74b7b89..081e994a 100644 --- a/src/main/java/org/bukkit/event/player/PlayerLoginEvent.java +++ b/src/main/java/org/bukkit/event/player/PlayerLoginEvent.java @@ -14,6 +14,7 @@ public class PlayerLoginEvent extends PlayerEvent { private final String hostname; private Result result = Result.ALLOWED; private String message = ""; + private final InetAddress realAddress; // Spigot /** * @deprecated Address should be provided in other constructor @@ -40,10 +41,17 @@ public PlayerLoginEvent(final Player player, final String hostname) { * @param address The address the player used to connect, provided for * timing issues */ - public PlayerLoginEvent(final Player player, final String hostname, final InetAddress address) { + public PlayerLoginEvent(final Player player, final String hostname, final InetAddress address, final InetAddress realAddress) { // Spigot super(player); this.hostname = hostname; this.address = address; + // Spigot start + this.realAddress = realAddress; + } + + public PlayerLoginEvent(final Player player, final String hostname, final InetAddress address) { + this(player, hostname, address, address); + // Spigot end } /** @@ -52,7 +60,7 @@ public PlayerLoginEvent(final Player player, final String hostname, final InetAd */ @Deprecated public PlayerLoginEvent(final Player player, final Result result, final String message) { - this(player, "", null, result, message); + this(player, "", null, result, message, null); // Spigot } /** @@ -65,12 +73,23 @@ public PlayerLoginEvent(final Player player, final Result result, final String m * @param result The result status for this event * @param message The message to be displayed if result denies login */ - public PlayerLoginEvent(final Player player, String hostname, final InetAddress address, final Result result, final String message) { - this(player, hostname, address); + public PlayerLoginEvent(final Player player, String hostname, final InetAddress address, final Result result, final String message, final InetAddress realAddress) { // Spigot + this(player, hostname, address, realAddress); // Spigot this.result = result; this.message = message; } + // Spigot start + /** + * Gets the connection address of this player, regardless of whether it has been spoofed or not. + * + * @return the player's connection address + */ + public InetAddress getRealAddress() { + return realAddress; + } + // Spigot end + /** * Gets the current result of the login, as an enum * diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java index d2fe422c..1d519080 100644 --- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java +++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java @@ -295,6 +295,7 @@ public Plugin[] loadPlugins(File directory) { } } + org.bukkit.command.defaults.TimingsCommand.timingStart = System.nanoTime(); // Spigot return result.toArray(new Plugin[result.size()]); } diff --git a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java index b178c0d1..a845e818 100644 --- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java +++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java @@ -39,6 +39,7 @@ import org.bukkit.plugin.RegisteredListener; import org.bukkit.plugin.TimedRegisteredListener; import org.bukkit.plugin.UnknownDependencyException; +import org.spigotmc.CustomTimingsHandler; // Spigot import org.yaml.snakeyaml.error.YAMLException; /** @@ -47,8 +48,9 @@ public final class JavaPluginLoader implements PluginLoader { final Server server; private final Pattern[] fileFilters = new Pattern[] { Pattern.compile("\\.jar$"), }; - private final Map> classes = new HashMap>(); + private final Map> classes = new java.util.concurrent.ConcurrentHashMap>(); // Spigot private final Map loaders = new LinkedHashMap(); + public static final CustomTimingsHandler pluginParentTimer = new CustomTimingsHandler("** Plugins"); // Spigot /** * This class was not meant to be constructed explicitly @@ -283,13 +285,16 @@ public Map, Set> createRegisteredList } } + final CustomTimingsHandler timings = new CustomTimingsHandler("Plugin: " + plugin.getDescription().getFullName() + " Event: " + listener.getClass().getName() + "::" + method.getName()+"("+eventClass.getSimpleName()+")", pluginParentTimer); // Spigot EventExecutor executor = new EventExecutor() { public void execute(Listener listener, Event event) throws EventException { try { if (!eventClass.isAssignableFrom(event.getClass())) { return; } + timings.startTiming(); // Spigot method.invoke(listener, event); + timings.stopTiming(); // Spigot } catch (InvocationTargetException ex) { throw new EventException(ex.getCause()); } catch (Throwable t) { @@ -297,7 +302,7 @@ public void execute(Listener listener, Event event) throws EventException { } } }; - if (useTimings) { + if (false) { // Spigot - RL handles useTimings check now eventSet.add(new TimedRegisteredListener(listener, executor, eh.priority(), plugin, eh.ignoreCancelled())); } else { eventSet.add(new RegisteredListener(listener, executor, eh.priority(), plugin, eh.ignoreCancelled())); diff --git a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java index 13f86338..4cffa137 100644 --- a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java +++ b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java @@ -17,7 +17,7 @@ */ final class PluginClassLoader extends URLClassLoader { private final JavaPluginLoader loader; - private final Map> classes = new HashMap>(); + private final Map> classes = new java.util.concurrent.ConcurrentHashMap>(); // Spigot private final PluginDescriptionFile description; private final File dataFolder; private final File file; @@ -25,6 +25,30 @@ final class PluginClassLoader extends URLClassLoader { private JavaPlugin pluginInit; private IllegalStateException pluginState; + // Spigot Start + static + { + try + { + java.lang.reflect.Method method = ClassLoader.class.getDeclaredMethod( "registerAsParallelCapable" ); + if ( method != null ) + { + boolean oldAccessible = method.isAccessible(); + method.setAccessible( true ); + method.invoke( null ); + method.setAccessible( oldAccessible ); + org.bukkit.Bukkit.getLogger().log( java.util.logging.Level.INFO, "Set PluginClassLoader as parallel capable" ); + } + } catch ( NoSuchMethodException ex ) + { + // Ignore + } catch ( Exception ex ) + { + org.bukkit.Bukkit.getLogger().log( java.util.logging.Level.WARNING, "Error setting PluginClassLoader as parallel capable", ex ); + } + } + // Spigot End + PluginClassLoader(final JavaPluginLoader loader, final ClassLoader parent, final PluginDescriptionFile description, final File dataFolder, final File file) throws InvalidPluginException, MalformedURLException { super(new URL[] {file.toURI().toURL()}, parent); Validate.notNull(loader, "Loader cannot be null"); diff --git a/src/main/java/org/bukkit/plugin/messaging/StandardMessenger.java b/src/main/java/org/bukkit/plugin/messaging/StandardMessenger.java index a906f8dd..4c171e88 100644 --- a/src/main/java/org/bukkit/plugin/messaging/StandardMessenger.java +++ b/src/main/java/org/bukkit/plugin/messaging/StandardMessenger.java @@ -421,7 +421,15 @@ public void dispatchIncomingMessage(Player source, String channel, byte[] messag Set registrations = getIncomingChannelRegistrations(channel); for (PluginMessageListenerRegistration registration : registrations) { - registration.getListener().onPluginMessageReceived(channel, source, message); + // Spigot Start + try + { + registration.getListener().onPluginMessageReceived( channel, source, message ); + } catch ( Throwable t ) + { + org.bukkit.Bukkit.getLogger().log( java.util.logging.Level.WARNING, "Could not pass incoming plugin message to " + registration.getPlugin(), t ); + } + // Spigot End } } diff --git a/src/main/java/org/bukkit/scoreboard/Score.java b/src/main/java/org/bukkit/scoreboard/Score.java index 4c103468..2410cbd1 100644 --- a/src/main/java/org/bukkit/scoreboard/Score.java +++ b/src/main/java/org/bukkit/scoreboard/Score.java @@ -51,6 +51,17 @@ public interface Score { */ void setScore(int score) throws IllegalStateException; + // Spigot start + /** + * Shows if this score has been set at any point in time. + * + * @return if this score has been set before + * @throws IllegalStateException if the associated objective has been + * unregistered + */ + boolean isScoreSet() throws IllegalStateException; + // Spigot end + /** * Gets the scoreboard for the associated objective. * diff --git a/src/main/java/org/bukkit/scoreboard/Team.java b/src/main/java/org/bukkit/scoreboard/Team.java index 50c6f762..b90b9c3a 100644 --- a/src/main/java/org/bukkit/scoreboard/Team.java +++ b/src/main/java/org/bukkit/scoreboard/Team.java @@ -118,6 +118,15 @@ public interface Team { */ Set getPlayers() throws IllegalStateException; + // Spigot start + /** + * Same as the player method, but with an arbitrary string. + * + * @see #getPlayers() + */ + Set getEntries() throws IllegalStateException; + // Spigot End + /** * Gets the size of the team * @@ -145,6 +154,15 @@ public interface Team { */ void addPlayer(OfflinePlayer player) throws IllegalStateException, IllegalArgumentException; + // Spigot start + /** + * Same as the player method, but with an arbitrary string. + * + * @see #addPlayer(org.bukkit.OfflinePlayer) + */ + void addEntry(String entry) throws IllegalStateException, IllegalArgumentException; + // Spigot end + /** * Removes the player from this team. * @@ -155,6 +173,15 @@ public interface Team { */ boolean removePlayer(OfflinePlayer player) throws IllegalStateException, IllegalArgumentException; + // Spigot start + /** + * Same as the player method, but with an arbitrary string. + * + * @see #removePlayer(org.bukkit.OfflinePlayer) + */ + boolean removeEntry(String entry) throws IllegalStateException, IllegalArgumentException; + // Spigot end + /** * Unregisters this team from the Scoreboard * @@ -171,4 +198,13 @@ public interface Team { * @throws IllegalStateException if this team has been unregistered */ boolean hasPlayer(OfflinePlayer player) throws IllegalArgumentException, IllegalStateException; + + // Spigot start + /** + * Same as the player method, but with an arbitrary string. + * + * @see #hasPlayer(org.bukkit.OfflinePlayer) + */ + boolean hasEntry(String entry) throws IllegalArgumentException,IllegalStateException; + // Spigot end } diff --git a/src/main/java/org/spigotmc/CustomTimingsHandler.java b/src/main/java/org/spigotmc/CustomTimingsHandler.java new file mode 100644 index 00000000..ab5299fd --- /dev/null +++ b/src/main/java/org/spigotmc/CustomTimingsHandler.java @@ -0,0 +1,168 @@ +package org.spigotmc; + +import org.bukkit.command.defaults.TimingsCommand; +import org.bukkit.event.HandlerList; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.RegisteredListener; +import org.bukkit.plugin.TimedRegisteredListener; +import java.io.PrintStream; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; + +import org.bukkit.Bukkit; +import org.bukkit.World; + +/** + * Provides custom timing sections for /timings merged. + */ +public class CustomTimingsHandler +{ + + private static Queue HANDLERS = new ConcurrentLinkedQueue(); + /*========================================================================*/ + private final String name; + private final CustomTimingsHandler parent; + private long count = 0; + private long start = 0; + private long timingDepth = 0; + private long totalTime = 0; + private long curTickTotal = 0; + private long violations = 0; + + public CustomTimingsHandler(String name) + { + this( name, null ); + } + + public CustomTimingsHandler(String name, CustomTimingsHandler parent) + { + this.name = name; + this.parent = parent; + HANDLERS.add( this ); + } + + /** + * Prints the timings and extra data to the given stream. + * + * @param printStream + */ + public static void printTimings(PrintStream printStream) + { + printStream.println( "Minecraft" ); + for ( CustomTimingsHandler timings : HANDLERS ) + { + long time = timings.totalTime; + long count = timings.count; + if ( count == 0 ) + { + continue; + } + long avg = time / count; + + printStream.println( " " + timings.name + " Time: " + time + " Count: " + count + " Avg: " + avg + " Violations: " + timings.violations ); + } + printStream.println( "# Version " + Bukkit.getVersion() ); + int entities = 0; + int livingEntities = 0; + int loadedChunks = 0; + for ( World world : Bukkit.getWorlds() ) + { + entities += world.getEntities().size(); + livingEntities += world.getLivingEntities().size(); + loadedChunks += world.getLoadedChunks().size(); + } + printStream.println( "# Entities " + entities ); + printStream.println( "# LivingEntities " + livingEntities ); + printStream.println( "# LoadedChunks " + loadedChunks ); + } + + /** + * Resets all timings. + */ + public static void reload() + { + if ( Bukkit.getPluginManager().useTimings() ) + { + for ( CustomTimingsHandler timings : HANDLERS ) + { + timings.reset(); + } + } + TimingsCommand.timingStart = System.nanoTime(); + } + + /** + * Ticked every tick by CraftBukkit to count the number of times a timer + * caused TPS loss. + */ + public static void tick() + { + if ( Bukkit.getPluginManager().useTimings() ) + { + for ( CustomTimingsHandler timings : HANDLERS ) + { + if ( timings.curTickTotal > 50000000 ) + { + timings.violations += Math.ceil( timings.curTickTotal / 50000000 ); + } + timings.curTickTotal = 0; + timings.timingDepth = 0; // incase reset messes this up + } + } + } + + /** + * Starts timing to track a section of code. + */ + public void startTiming() + { + // If second condtion fails we are already timing + if ( Bukkit.getPluginManager().useTimings() && ++timingDepth == 1 ) + { + start = System.nanoTime(); + if ( parent != null && ++parent.timingDepth == 1 ) + { + parent.start = start; + } + } + } + + /** + * Stops timing a section of code. + */ + public void stopTiming() + { + if ( Bukkit.getPluginManager().useTimings() ) + { + if ( --timingDepth != 0 || start == 0 ) + { + return; + } + long diff = System.nanoTime() - start; + totalTime += diff; + curTickTotal += diff; + count++; + start = 0; + if ( parent != null ) + { + parent.stopTiming(); + } + } + } + + /** + * Reset this timer, setting all values to zero. + */ + public void reset() + { + count = 0; + violations = 0; + curTickTotal = 0; + totalTime = 0; + start = 0; + timingDepth = 0; + } +} diff --git a/src/main/java/org/spigotmc/event/entity/EntityDismountEvent.java b/src/main/java/org/spigotmc/event/entity/EntityDismountEvent.java new file mode 100644 index 00000000..24d4942a --- /dev/null +++ b/src/main/java/org/spigotmc/event/entity/EntityDismountEvent.java @@ -0,0 +1,39 @@ +package org.spigotmc.event.entity; + +import org.bukkit.entity.Entity; +import org.bukkit.event.HandlerList; +import org.bukkit.event.entity.EntityEvent; + +/** + * Called when an entity stops riding another entity. + * + */ +public class EntityDismountEvent extends EntityEvent +{ + + private static final HandlerList handlers = new HandlerList(); + private boolean cancelled; + private final Entity dismounted; + + public EntityDismountEvent(Entity what, Entity dismounted) + { + super( what ); + this.dismounted = dismounted; + } + + public Entity getDismounted() + { + return dismounted; + } + + @Override + public HandlerList getHandlers() + { + return handlers; + } + + public static HandlerList getHandlerList() + { + return handlers; + } +} diff --git a/src/main/java/org/spigotmc/event/entity/EntityMountEvent.java b/src/main/java/org/spigotmc/event/entity/EntityMountEvent.java new file mode 100644 index 00000000..16aa2a7e --- /dev/null +++ b/src/main/java/org/spigotmc/event/entity/EntityMountEvent.java @@ -0,0 +1,52 @@ +package org.spigotmc.event.entity; + +import org.bukkit.entity.Entity; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.entity.EntityEvent; + +/** + * Called when an entity attempts to ride another entity. + * + */ +public class EntityMountEvent extends EntityEvent implements Cancellable +{ + + private static final HandlerList handlers = new HandlerList(); + private boolean cancelled; + private final Entity mount; + + public EntityMountEvent(Entity what, Entity mount) + { + super( what ); + this.mount = mount; + } + + public Entity getMount() + { + return mount; + } + + @Override + public boolean isCancelled() + { + return cancelled; + } + + @Override + public void setCancelled(boolean cancel) + { + this.cancelled = cancel; + } + + @Override + public HandlerList getHandlers() + { + return handlers; + } + + public static HandlerList getHandlerList() + { + return handlers; + } +} diff --git a/src/main/java/org/spigotmc/event/player/PlayerSpawnLocationEvent.java b/src/main/java/org/spigotmc/event/player/PlayerSpawnLocationEvent.java new file mode 100644 index 00000000..dd3f58ca --- /dev/null +++ b/src/main/java/org/spigotmc/event/player/PlayerSpawnLocationEvent.java @@ -0,0 +1,50 @@ +package org.spigotmc.event.player; + +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; + +/** + * Called when player is about to spawn in a world after joining the server. + */ +public class PlayerSpawnLocationEvent extends PlayerEvent { + private static final HandlerList handlers = new HandlerList(); + private Location spawnLocation; + + public PlayerSpawnLocationEvent(final Player who, Location spawnLocation) { + super(who); + this.spawnLocation = spawnLocation; + } + + + /** + * Gets player's spawn location. + * If the player {@link Player#hasPlayedBefore()}, it's going to default to the location inside player.dat file. + * For new players, the default spawn location is spawn of the main Bukkit world. + * + * @return the spawn location + */ + public Location getSpawnLocation() { + return spawnLocation; + } + + /** + * Sets player's spawn location. + * + * @param location the spawn location + */ + public void setSpawnLocation(Location location) { + this.spawnLocation = location; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/src/test/java/org/bukkit/EffectTest.java b/src/test/java/org/bukkit/EffectTest.java index 08aa71d3..5217aecb 100644 --- a/src/test/java/org/bukkit/EffectTest.java +++ b/src/test/java/org/bukkit/EffectTest.java @@ -9,7 +9,11 @@ public class EffectTest { @Test public void getById() { for (Effect effect : Effect.values()) { - assertThat(Effect.getById(effect.getId()), is(effect)); + if (effect.getType() != Effect.Type.PARTICLE) { + assertThat(Effect.getById(effect.getId()), is(effect)); + } else { + assertThat(Effect.getByName(effect.getName()), is(effect)); + } } } }