From 8e7e5dcb258eff42b9e29e8f3b8a243548ed2837 Mon Sep 17 00:00:00 2001 From: MattBDev Date: Wed, 14 Sep 2016 12:16:22 -0400 Subject: [PATCH] Cleanup Signed-off-by: MattBDev --- .../com/plotsquared/bukkit/BukkitMain.java | 17 +- .../plotsquared/bukkit/chat/ArrayWrapper.java | 158 +- .../plotsquared/bukkit/chat/FancyMessage.java | 1539 ++++++++--------- .../bukkit/chat/JsonRepresentedObject.java | 14 +- .../plotsquared/bukkit/chat/JsonString.java | 52 +- .../plotsquared/bukkit/chat/Reflection.java | 322 ++-- .../bukkit/object/entity/EntityWrapper.java | 13 +- .../bukkit/util/BukkitHybridUtils.java | 8 +- .../bukkit/util/BukkitVersion.java | 13 + .../plotsquared/bukkit/util/NbtFactory.java | 16 +- .../plotsquared/bukkit/util/SendChunk.java | 4 +- .../util/block/BukkitLocalQueue_1_8_3.java | 18 +- .../configuration/MemoryConfiguration.java | 11 - .../configuration/MemorySection.java | 27 +- .../configuration/file/FileConfiguration.java | 31 +- .../configuration/file/YamlConfiguration.java | 37 - .../plot/flag/TeleportDenyFlag.java | 8 +- .../plot/object/comment/CommentInbox.java | 27 +- .../plot/object/comment/InboxOwner.java | 31 - .../plot/object/comment/InboxPublic.java | 33 +- .../plot/object/comment/InboxReport.java | 32 - 21 files changed, 1122 insertions(+), 1289 deletions(-) create mode 100644 Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitVersion.java diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java index 94ea558a0..bd9cda88d 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java @@ -57,6 +57,7 @@ import com.plotsquared.bukkit.util.BukkitSchematicHandler; import com.plotsquared.bukkit.util.BukkitSetupUtils; import com.plotsquared.bukkit.util.BukkitTaskManager; import com.plotsquared.bukkit.util.BukkitUtil; +import com.plotsquared.bukkit.util.BukkitVersion; import com.plotsquared.bukkit.util.Metrics; import com.plotsquared.bukkit.util.SendChunk; import com.plotsquared.bukkit.util.SetGenCB; @@ -356,7 +357,7 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain } @Override - public final ChunkGenerator getDefaultWorldGenerator(String world, String id) { + public ChunkGenerator getDefaultWorldGenerator(String world, String id) { HybridGen result = new HybridGen(); if (!PS.get().setupPlotWorld(world, id, result)) { return null; @@ -374,21 +375,21 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain } catch (NoSuchMethodException ignored) { PS.debug("Not running Spigot. Skipping EntitySpawnListener event."); } - if (PS.get().checkVersion(getServerVersion(), 1, 8, 0)) { + if (PS.get().checkVersion(getServerVersion(), BukkitVersion.v1_8_0)) { try { getServer().getPluginManager().registerEvents(new PlayerEvents_1_8(), this); } catch (Throwable e) { e.printStackTrace(); } } - if (PS.get().checkVersion(getServerVersion(), 1, 8, 3)) { + if (PS.get().checkVersion(getServerVersion(), BukkitVersion.v1_8_3)) { try { getServer().getPluginManager().registerEvents(new PlayerEvents183(), this); } catch (Throwable e) { e.printStackTrace(); } } - if (PS.get().checkVersion(getServerVersion(), 1, 9, 0)) { + if (PS.get().checkVersion(getServerVersion(), BukkitVersion.v1_9_0)) { try { getServer().getPluginManager().registerEvents(new PlayerEvents_1_9(main), this); } catch (Throwable e) { @@ -443,13 +444,13 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain PS.debug(SendChunk.class + " does not support " + StringMan.getString(getServerVersion())); MainUtil.canSendChunk = false; } - if (PS.get().checkVersion(getServerVersion(), 1, 9, 0)) { + if (PS.get().checkVersion(getServerVersion(), BukkitVersion.v1_9_0)) { return QueueProvider.of(BukkitLocalQueue_1_9.class, BukkitLocalQueue.class); } - if (PS.get().checkVersion(getServerVersion(), 1, 8, 3)) { + if (PS.get().checkVersion(getServerVersion(), BukkitVersion.v1_8_3)) { return QueueProvider.of(BukkitLocalQueue_1_8_3.class, BukkitLocalQueue.class); } - if (PS.get().checkVersion(getServerVersion(), 1, 8, 0)) { + if (PS.get().checkVersion(getServerVersion(), BukkitVersion.v1_8_0)) { return QueueProvider.of(BukkitLocalQueue_1_8.class, BukkitLocalQueue.class); } return QueueProvider.of(BukkitLocalQueue_1_7.class, BukkitLocalQueue.class); @@ -505,7 +506,7 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain @Override public UUIDHandlerImplementation initUUIDHandler() { - boolean checkVersion = PS.get().checkVersion(getServerVersion(), 1, 7, 6); + boolean checkVersion = PS.get().checkVersion(getServerVersion(), BukkitVersion.v1_7_6); UUIDWrapper wrapper; if (Settings.UUID.OFFLINE) { if (Settings.UUID.FORCE_LOWERCASE) { diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/chat/ArrayWrapper.java b/Bukkit/src/main/java/com/plotsquared/bukkit/chat/ArrayWrapper.java index 68fc6b723..2dd68fa4e 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/chat/ArrayWrapper.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/chat/ArrayWrapper.java @@ -19,93 +19,93 @@ import java.util.Collection; */ public final class ArrayWrapper { - /** - * Creates an array wrapper with some elements. - * - * @param elements The elements of the array. - */ - public ArrayWrapper(E... elements) { - setArray(elements); - } + /** + * Creates an array wrapper with some elements. + * + * @param elements The elements of the array. + */ + public ArrayWrapper(E... elements) { + setArray(elements); + } - private E[] _array; + private E[] _array; - /** - * Retrieves a reference to the wrapped array instance. - * - * @return The array wrapped by this instance. - */ - public E[] getArray() { - return _array; - } + /** + * Retrieves a reference to the wrapped array instance. + * + * @return The array wrapped by this instance. + */ + public E[] getArray() { + return _array; + } - /** - * Set this wrapper to wrap a new array instance. - * - * @param array The new wrapped array. - */ - public void setArray(E[] array) { - Validate.notNull(array, "The array must not be null."); - _array = array; - } + /** + * Set this wrapper to wrap a new array instance. + * + * @param array The new wrapped array. + */ + public void setArray(E[] array) { + Validate.notNull(array, "The array must not be null."); + _array = array; + } - /** - * Determines if this object has a value equivalent to another object. - * - * @see Arrays#equals(Object[], Object[]) - */ - @SuppressWarnings("rawtypes") - @Override - public boolean equals(Object other) { - if (!(other instanceof ArrayWrapper)) { - return false; - } - return Arrays.equals(_array, ((ArrayWrapper) other)._array); - } + /** + * Determines if this object has a value equivalent to another object. + * + * @see Arrays#equals(Object[], Object[]) + */ + @SuppressWarnings("rawtypes") + @Override + public boolean equals(Object other) { + if (!(other instanceof ArrayWrapper)) { + return false; + } + return Arrays.equals(_array, ((ArrayWrapper) other)._array); + } - /** - * Gets the hash code represented by this objects value. - * - * @return This object's hash code. - * @see Arrays#hashCode(Object[]) - */ - @Override - public int hashCode() { - return Arrays.hashCode(_array); - } + /** + * Gets the hash code represented by this objects value. + * + * @return This object's hash code. + * @see Arrays#hashCode(Object[]) + */ + @Override + public int hashCode() { + return Arrays.hashCode(_array); + } - /** - * Converts an iterable element collection to an array of elements. - * The iteration order of the specified object will be used as the array element order. - * - * @param list The iterable of objects which will be converted to an array. - * @param c The type of the elements of the array. - * @return An array of elements in the specified iterable. - */ - @SuppressWarnings("unchecked") - public static T[] toArray(Iterable list, Class c) { - int size = -1; - if (list instanceof Collection) { - @SuppressWarnings("rawtypes") - Collection coll = (Collection) list; - size = coll.size(); - } + /** + * Converts an iterable element collection to an array of elements. + * The iteration order of the specified object will be used as the array element order. + * + * @param list The iterable of objects which will be converted to an array. + * @param c The type of the elements of the array. + * @return An array of elements in the specified iterable. + */ + @SuppressWarnings("unchecked") + public static T[] toArray(Iterable list, Class c) { + int size = -1; + if (list instanceof Collection) { + @SuppressWarnings("rawtypes") + Collection coll = (Collection) list; + size = coll.size(); + } - if (size < 0) { - size = 0; - // Ugly hack: Count it ourselves - for (@SuppressWarnings("unused") T element : list) { - size++; - } - } + if (size < 0) { + size = 0; + // Ugly hack: Count it ourselves + for (@SuppressWarnings("unused") T element : list) { + size++; + } + } - T[] result = (T[]) Array.newInstance(c, size); - int i = 0; - for (T element : list) { // Assumes iteration order is consistent - result[i++] = element; // Assign array element at index THEN increment counter - } - return result; - } + T[] result = (T[]) Array.newInstance(c, size); + int i = 0; + for (T element : list) { // Assumes iteration order is consistent + result[i++] = element; // Assign array element at index THEN increment counter + } + return result; + } } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/chat/FancyMessage.java b/Bukkit/src/main/java/com/plotsquared/bukkit/chat/FancyMessage.java index 97d112f99..0f1b0d529 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/chat/FancyMessage.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/chat/FancyMessage.java @@ -47,841 +47,840 @@ import java.util.logging.Level; */ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable, ConfigurationSerializable { - static { - ConfigurationSerialization.registerClass(FancyMessage.class); - } + static { + ConfigurationSerialization.registerClass(FancyMessage.class); + } - private List messageParts; - private String jsonString; - private boolean dirty; + private List messageParts; + private String jsonString; + private boolean dirty; - private static Constructor nmsPacketPlayOutChatConstructor; + private static Constructor nmsPacketPlayOutChatConstructor; - @Override - public FancyMessage clone() throws CloneNotSupportedException { - FancyMessage instance = (FancyMessage) super.clone(); - instance.messageParts = new ArrayList<>(messageParts.size()); - for (int i = 0; i < messageParts.size(); i++) { - instance.messageParts.add(i, messageParts.get(i).clone()); - } - instance.dirty = false; - instance.jsonString = null; - return instance; - } + @Override + public FancyMessage clone() throws CloneNotSupportedException { + FancyMessage instance = (FancyMessage) super.clone(); + instance.messageParts = new ArrayList<>(messageParts.size()); + for (int i = 0; i < messageParts.size(); i++) { + instance.messageParts.add(i, messageParts.get(i).clone()); + } + instance.dirty = false; + instance.jsonString = null; + return instance; + } - /** - * Creates a JSON message with text. - * - * @param firstPartText The existing text in the message. - */ - public FancyMessage(final String firstPartText) { - this(rawText(firstPartText)); - } + /** + * Creates a JSON message with text. + * + * @param firstPartText The existing text in the message. + */ + public FancyMessage(final String firstPartText) { + this(rawText(firstPartText)); + } - public FancyMessage(final TextualComponent firstPartText) { - messageParts = new ArrayList<>(); - messageParts.add(new MessagePart(firstPartText)); - jsonString = null; - dirty = false; + private FancyMessage(final TextualComponent firstPartText) { + messageParts = new ArrayList<>(); + messageParts.add(new MessagePart(firstPartText)); + jsonString = null; + dirty = false; + if (nmsPacketPlayOutChatConstructor == null) { + try { + nmsPacketPlayOutChatConstructor = Reflection.getNMSClass("PacketPlayOutChat").getDeclaredConstructor(Reflection.getNMSClass("IChatBaseComponent")); + nmsPacketPlayOutChatConstructor.setAccessible(true); + } catch (NoSuchMethodException e) { + Bukkit.getLogger().log(Level.SEVERE, "Could not find Minecraft method or constructor.", e); + } catch (SecurityException e) { + Bukkit.getLogger().log(Level.WARNING, "Could not access constructor.", e); + } + } + } - if (nmsPacketPlayOutChatConstructor == null) { - try { - nmsPacketPlayOutChatConstructor = Reflection.getNMSClass("PacketPlayOutChat").getDeclaredConstructor(Reflection.getNMSClass("IChatBaseComponent")); - nmsPacketPlayOutChatConstructor.setAccessible(true); - } catch (NoSuchMethodException e) { - Bukkit.getLogger().log(Level.SEVERE, "Could not find Minecraft method or constructor.", e); - } catch (SecurityException e) { - Bukkit.getLogger().log(Level.WARNING, "Could not access constructor.", e); - } - } - } + /** + * Creates a JSON message without text. + */ + public FancyMessage() { + this((TextualComponent) null); + } - /** - * Creates a JSON message without text. - */ - public FancyMessage() { - this((TextualComponent) null); - } + /** + * Sets the text of the current editing component to a value. + * + * @param text The new text of the current editing component. + * @return This builder instance. + */ + public FancyMessage text(String text) { + MessagePart latest = latest(); + latest.text = rawText(text); + dirty = true; + return this; + } - /** - * Sets the text of the current editing component to a value. - * - * @param text The new text of the current editing component. - * @return This builder instance. - */ - public FancyMessage text(String text) { - MessagePart latest = latest(); - latest.text = rawText(text); - dirty = true; - return this; - } + /** + * Sets the text of the current editing component to a value. + * + * @param text The new text of the current editing component. + * @return This builder instance. + */ + public FancyMessage text(TextualComponent text) { + MessagePart latest = latest(); + latest.text = text; + dirty = true; + return this; + } - /** - * Sets the text of the current editing component to a value. - * - * @param text The new text of the current editing component. - * @return This builder instance. - */ - public FancyMessage text(TextualComponent text) { - MessagePart latest = latest(); - latest.text = text; - dirty = true; - return this; - } + /** + * Sets the color of the current editing component to a value. + * + * @param color The new color of the current editing component. + * @return This builder instance. + * @throws IllegalArgumentException If the specified {@code ChatColor} enumeration value is not a color (but a format value). + */ + public FancyMessage color(final ChatColor color) { + if (!color.isColor()) { + throw new IllegalArgumentException(color.name() + " is not a color"); + } + latest().color = color; + dirty = true; + return this; + } - /** - * Sets the color of the current editing component to a value. - * - * @param color The new color of the current editing component. - * @return This builder instance. - * @throws IllegalArgumentException If the specified {@code ChatColor} enumeration value is not a color (but a format value). - */ - public FancyMessage color(final ChatColor color) { - if (!color.isColor()) { - throw new IllegalArgumentException(color.name() + " is not a color"); - } - latest().color = color; - dirty = true; - return this; - } + /** + * Sets the stylization of the current editing component. + * + * @param styles The array of styles to apply to the editing component. + * @return This builder instance. + * @throws IllegalArgumentException If any of the enumeration values in the array do not represent formatters. + */ + public FancyMessage style(ChatColor... styles) { + for (final ChatColor style : styles) { + if (!style.isFormat()) { + throw new IllegalArgumentException(style.name() + " is not a style"); + } + } + latest().styles.addAll(Arrays.asList(styles)); + dirty = true; + return this; + } - /** - * Sets the stylization of the current editing component. - * - * @param styles The array of styles to apply to the editing component. - * @return This builder instance. - * @throws IllegalArgumentException If any of the enumeration values in the array do not represent formatters. - */ - public FancyMessage style(ChatColor... styles) { - for (final ChatColor style : styles) { - if (!style.isFormat()) { - throw new IllegalArgumentException(style.name() + " is not a style"); - } - } - latest().styles.addAll(Arrays.asList(styles)); - dirty = true; - return this; - } + /** + * Set the behavior of the current editing component to instruct the client to open a file on the client side filesystem when the currently edited part of the {@code FancyMessage} is clicked. + * + * @param path The path of the file on the client filesystem. + * @return This builder instance. + */ + public FancyMessage file(final String path) { + onClick("open_file", path); + return this; + } - /** - * Set the behavior of the current editing component to instruct the client to open a file on the client side filesystem when the currently edited part of the {@code FancyMessage} is clicked. - * - * @param path The path of the file on the client filesystem. - * @return This builder instance. - */ - public FancyMessage file(final String path) { - onClick("open_file", path); - return this; - } + /** + * Set the behavior of the current editing component to instruct the client to open a webpage in the client's web browser when the currently edited part of the {@code FancyMessage} is clicked. + * + * @param url The URL of the page to open when the link is clicked. + * @return This builder instance. + */ + public FancyMessage link(final String url) { + onClick("open_url", url); + return this; + } - /** - * Set the behavior of the current editing component to instruct the client to open a webpage in the client's web browser when the currently edited part of the {@code FancyMessage} is clicked. - * - * @param url The URL of the page to open when the link is clicked. - * @return This builder instance. - */ - public FancyMessage link(final String url) { - onClick("open_url", url); - return this; - } + /** + * Set the behavior of the current editing component to instruct the client to replace the chat input box content with the specified string when the currently edited part of the {@code FancyMessage} is clicked. + * The client will not immediately send the command to the server to be executed unless the client player submits the command/chat message, usually with the enter key. + * + * @param command The text to display in the chat bar of the client. + * @return This builder instance. + */ + public FancyMessage suggest(final String command) { + onClick("suggest_command", command); + return this; + } - /** - * Set the behavior of the current editing component to instruct the client to replace the chat input box content with the specified string when the currently edited part of the {@code FancyMessage} is clicked. - * The client will not immediately send the command to the server to be executed unless the client player submits the command/chat message, usually with the enter key. - * - * @param command The text to display in the chat bar of the client. - * @return This builder instance. - */ - public FancyMessage suggest(final String command) { - onClick("suggest_command", command); - return this; - } + /** + * Set the behavior of the current editing component to instruct the client to append the chat input box content with the specified string when the currently edited part of the {@code FancyMessage} is SHIFT-CLICKED. + * The client will not immediately send the command to the server to be executed unless the client player submits the command/chat message, usually with the enter key. + * + * @param command The text to append to the chat bar of the client. + * @return This builder instance. + */ + public FancyMessage insert(final String command) { + latest().insertionData = command; + dirty = true; + return this; + } - /** - * Set the behavior of the current editing component to instruct the client to append the chat input box content with the specified string when the currently edited part of the {@code FancyMessage} is SHIFT-CLICKED. - * The client will not immediately send the command to the server to be executed unless the client player submits the command/chat message, usually with the enter key. - * - * @param command The text to append to the chat bar of the client. - * @return This builder instance. - */ - public FancyMessage insert(final String command) { - latest().insertionData = command; - dirty = true; - return this; - } + /** + * Set the behavior of the current editing component to instruct the client to send the specified string to the server as a chat message when the currently edited part of the {@code FancyMessage} is clicked. + * The client will immediately send the command to the server to be executed when the editing component is clicked. + * + * @param command The text to display in the chat bar of the client. + * @return This builder instance. + */ + public FancyMessage command(final String command) { + onClick("run_command", command); + return this; + } - /** - * Set the behavior of the current editing component to instruct the client to send the specified string to the server as a chat message when the currently edited part of the {@code FancyMessage} is clicked. - * The client will immediately send the command to the server to be executed when the editing component is clicked. - * - * @param command The text to display in the chat bar of the client. - * @return This builder instance. - */ - public FancyMessage command(final String command) { - onClick("run_command", command); - return this; - } + /** + * Set the behavior of the current editing component to display information about an achievement when the client hovers over the text. + *

Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.

+ * + * @param name The name of the achievement to display, excluding the "achievement." prefix. + * @return This builder instance. + */ + public FancyMessage achievementTooltip(final String name) { + onHover("show_achievement", new JsonString("achievement." + name)); + return this; + } - /** - * Set the behavior of the current editing component to display information about an achievement when the client hovers over the text. - *

Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.

- * - * @param name The name of the achievement to display, excluding the "achievement." prefix. - * @return This builder instance. - */ - public FancyMessage achievementTooltip(final String name) { - onHover("show_achievement", new JsonString("achievement." + name)); - return this; - } + /** + * Set the behavior of the current editing component to display information about an achievement when the client hovers over the text. + *

Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.

+ * + * @param which The achievement to display. + * @return This builder instance. + */ + public FancyMessage achievementTooltip(final Achievement which) { + try { + Object achievement = Reflection.getMethod(Reflection.getOBCClass("CraftStatistic"), "getNMSAchievement", Achievement.class).invoke(null, which); + return achievementTooltip((String) Reflection.getField(Reflection.getNMSClass("Achievement"), "name").get(achievement)); + } catch (IllegalAccessException e) { + Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e); + return this; + } catch (IllegalArgumentException e) { + Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e); + return this; + } catch (InvocationTargetException e) { + Bukkit.getLogger().log(Level.WARNING, "A error has occurred during invoking of method.", e); + return this; + } + } - /** - * Set the behavior of the current editing component to display information about an achievement when the client hovers over the text. - *

Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.

- * - * @param which The achievement to display. - * @return This builder instance. - */ - public FancyMessage achievementTooltip(final Achievement which) { - try { - Object achievement = Reflection.getMethod(Reflection.getOBCClass("CraftStatistic"), "getNMSAchievement", Achievement.class).invoke(null, which); - return achievementTooltip((String) Reflection.getField(Reflection.getNMSClass("Achievement"), "name").get(achievement)); - } catch (IllegalAccessException e) { - Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e); - return this; - } catch (IllegalArgumentException e) { - Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e); - return this; - } catch (InvocationTargetException e) { - Bukkit.getLogger().log(Level.WARNING, "A error has occurred during invoking of method.", e); - return this; - } - } + /** + * Set the behavior of the current editing component to display information about a parameterless statistic when the client hovers over the text. + *

Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.

+ * + * @param which The statistic to display. + * @return This builder instance. + * @throws IllegalArgumentException If the statistic requires a parameter which was not supplied. + */ + public FancyMessage statisticTooltip(final Statistic which) { + Type type = which.getType(); + if (type != Type.UNTYPED) { + throw new IllegalArgumentException("That statistic requires an additional " + type + " parameter!"); + } + try { + Object statistic = Reflection.getMethod(Reflection.getOBCClass("CraftStatistic"), "getNMSStatistic", Statistic.class).invoke(null, which); + return achievementTooltip((String) Reflection.getField(Reflection.getNMSClass("Statistic"), "name").get(statistic)); + } catch (IllegalAccessException e) { + Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e); + return this; + } catch (IllegalArgumentException e) { + Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e); + return this; + } catch (InvocationTargetException e) { + Bukkit.getLogger().log(Level.WARNING, "A error has occurred during invoking of method.", e); + return this; + } + } - /** - * Set the behavior of the current editing component to display information about a parameterless statistic when the client hovers over the text. - *

Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.

- * - * @param which The statistic to display. - * @return This builder instance. - * @throws IllegalArgumentException If the statistic requires a parameter which was not supplied. - */ - public FancyMessage statisticTooltip(final Statistic which) { - Type type = which.getType(); - if (type != Type.UNTYPED) { - throw new IllegalArgumentException("That statistic requires an additional " + type + " parameter!"); - } - try { - Object statistic = Reflection.getMethod(Reflection.getOBCClass("CraftStatistic"), "getNMSStatistic", Statistic.class).invoke(null, which); - return achievementTooltip((String) Reflection.getField(Reflection.getNMSClass("Statistic"), "name").get(statistic)); - } catch (IllegalAccessException e) { - Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e); - return this; - } catch (IllegalArgumentException e) { - Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e); - return this; - } catch (InvocationTargetException e) { - Bukkit.getLogger().log(Level.WARNING, "A error has occurred during invoking of method.", e); - return this; - } - } + /** + * Set the behavior of the current editing component to display information about a statistic parameter with a material when the client hovers over the text. + *

Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.

+ * + * @param which The statistic to display. + * @param item The sole material parameter to the statistic. + * @return This builder instance. + * @throws IllegalArgumentException If the statistic requires a parameter which was not supplied, or was supplied a parameter that was not required. + */ + public FancyMessage statisticTooltip(final Statistic which, Material item) { + Type type = which.getType(); + if (type == Type.UNTYPED) { + throw new IllegalArgumentException("That statistic needs no additional parameter!"); + } + if ((type == Type.BLOCK && item.isBlock()) || type == Type.ENTITY) { + throw new IllegalArgumentException("Wrong parameter type for that statistic - needs " + type + "!"); + } + try { + Object statistic = Reflection.getMethod(Reflection.getOBCClass("CraftStatistic"), "getMaterialStatistic", Statistic.class, Material.class).invoke(null, which, item); + return achievementTooltip((String) Reflection.getField(Reflection.getNMSClass("Statistic"), "name").get(statistic)); + } catch (IllegalAccessException e) { + Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e); + return this; + } catch (IllegalArgumentException e) { + Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e); + return this; + } catch (InvocationTargetException e) { + Bukkit.getLogger().log(Level.WARNING, "A error has occurred during invoking of method.", e); + return this; + } + } - /** - * Set the behavior of the current editing component to display information about a statistic parameter with a material when the client hovers over the text. - *

Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.

- * - * @param which The statistic to display. - * @param item The sole material parameter to the statistic. - * @return This builder instance. - * @throws IllegalArgumentException If the statistic requires a parameter which was not supplied, or was supplied a parameter that was not required. - */ - public FancyMessage statisticTooltip(final Statistic which, Material item) { - Type type = which.getType(); - if (type == Type.UNTYPED) { - throw new IllegalArgumentException("That statistic needs no additional parameter!"); - } - if ((type == Type.BLOCK && item.isBlock()) || type == Type.ENTITY) { - throw new IllegalArgumentException("Wrong parameter type for that statistic - needs " + type + "!"); - } - try { - Object statistic = Reflection.getMethod(Reflection.getOBCClass("CraftStatistic"), "getMaterialStatistic", Statistic.class, Material.class).invoke(null, which, item); - return achievementTooltip((String) Reflection.getField(Reflection.getNMSClass("Statistic"), "name").get(statistic)); - } catch (IllegalAccessException e) { - Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e); - return this; - } catch (IllegalArgumentException e) { - Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e); - return this; - } catch (InvocationTargetException e) { - Bukkit.getLogger().log(Level.WARNING, "A error has occurred during invoking of method.", e); - return this; - } - } + /** + * Set the behavior of the current editing component to display information about a statistic parameter with an entity type when the client hovers over the text. + *

Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.

+ * + * @param which The statistic to display. + * @param entity The sole entity type parameter to the statistic. + * @return This builder instance. + * @throws IllegalArgumentException If the statistic requires a parameter which was not supplied, or was supplied a parameter that was not required. + */ + public FancyMessage statisticTooltip(final Statistic which, EntityType entity) { + Type type = which.getType(); + if (type == Type.UNTYPED) { + throw new IllegalArgumentException("That statistic needs no additional parameter!"); + } + if (type != Type.ENTITY) { + throw new IllegalArgumentException("Wrong parameter type for that statistic - needs " + type + "!"); + } + try { + Object statistic = Reflection.getMethod(Reflection.getOBCClass("CraftStatistic"), "getEntityStatistic", Statistic.class, EntityType.class).invoke(null, which, entity); + return achievementTooltip((String) Reflection.getField(Reflection.getNMSClass("Statistic"), "name").get(statistic)); + } catch (IllegalAccessException e) { + Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e); + return this; + } catch (IllegalArgumentException e) { + Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e); + return this; + } catch (InvocationTargetException e) { + Bukkit.getLogger().log(Level.WARNING, "A error has occurred during invoking of method.", e); + return this; + } + } - /** - * Set the behavior of the current editing component to display information about a statistic parameter with an entity type when the client hovers over the text. - *

Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.

- * - * @param which The statistic to display. - * @param entity The sole entity type parameter to the statistic. - * @return This builder instance. - * @throws IllegalArgumentException If the statistic requires a parameter which was not supplied, or was supplied a parameter that was not required. - */ - public FancyMessage statisticTooltip(final Statistic which, EntityType entity) { - Type type = which.getType(); - if (type == Type.UNTYPED) { - throw new IllegalArgumentException("That statistic needs no additional parameter!"); - } - if (type != Type.ENTITY) { - throw new IllegalArgumentException("Wrong parameter type for that statistic - needs " + type + "!"); - } - try { - Object statistic = Reflection.getMethod(Reflection.getOBCClass("CraftStatistic"), "getEntityStatistic", Statistic.class, EntityType.class).invoke(null, which, entity); - return achievementTooltip((String) Reflection.getField(Reflection.getNMSClass("Statistic"), "name").get(statistic)); - } catch (IllegalAccessException e) { - Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e); - return this; - } catch (IllegalArgumentException e) { - Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e); - return this; - } catch (InvocationTargetException e) { - Bukkit.getLogger().log(Level.WARNING, "A error has occurred during invoking of method.", e); - return this; - } - } + /** + * Set the behavior of the current editing component to display information about an item when the client hovers over the text. + *

Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.

+ * + * @param itemJSON A string representing the JSON-serialized NBT data tag of an {@link ItemStack}. + * @return This builder instance. + */ + public FancyMessage itemTooltip(final String itemJSON) { + onHover("show_item", new JsonString(itemJSON)); // Seems a bit hacky, considering we have a JSON object as a parameter + return this; + } - /** - * Set the behavior of the current editing component to display information about an item when the client hovers over the text. - *

Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.

- * - * @param itemJSON A string representing the JSON-serialized NBT data tag of an {@link ItemStack}. - * @return This builder instance. - */ - public FancyMessage itemTooltip(final String itemJSON) { - onHover("show_item", new JsonString(itemJSON)); // Seems a bit hacky, considering we have a JSON object as a parameter - return this; - } + /** + * Set the behavior of the current editing component to display information about an item when the client hovers over the text. + *

Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.

+ * + * @param itemStack The stack for which to display information. + * @return This builder instance. + */ + public FancyMessage itemTooltip(final ItemStack itemStack) { + try { + Object nmsItem = Reflection.getMethod(Reflection.getOBCClass("inventory.CraftItemStack"), "asNMSCopy", ItemStack.class).invoke(null, itemStack); + return itemTooltip(Reflection.getMethod(Reflection.getNMSClass("ItemStack"), "save", Reflection.getNMSClass("NBTTagCompound")).invoke(nmsItem, Reflection.getNMSClass("NBTTagCompound").newInstance()).toString()); + } catch (Exception e) { + e.printStackTrace(); + return this; + } + } - /** - * Set the behavior of the current editing component to display information about an item when the client hovers over the text. - *

Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.

- * - * @param itemStack The stack for which to display information. - * @return This builder instance. - */ - public FancyMessage itemTooltip(final ItemStack itemStack) { - try { - Object nmsItem = Reflection.getMethod(Reflection.getOBCClass("inventory.CraftItemStack"), "asNMSCopy", ItemStack.class).invoke(null, itemStack); - return itemTooltip(Reflection.getMethod(Reflection.getNMSClass("ItemStack"), "save", Reflection.getNMSClass("NBTTagCompound")).invoke(nmsItem, Reflection.getNMSClass("NBTTagCompound").newInstance()).toString()); - } catch (Exception e) { - e.printStackTrace(); - return this; - } - } + /** + * Set the behavior of the current editing component to display raw text when the client hovers over the text. + *

Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.

+ * + * @param text The text, which supports newlines, which will be displayed to the client upon hovering. + * @return This builder instance. + */ + public FancyMessage tooltip(final String text) { + onHover("show_text", new JsonString(text)); + return this; + } - /** - * Set the behavior of the current editing component to display raw text when the client hovers over the text. - *

Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.

- * - * @param text The text, which supports newlines, which will be displayed to the client upon hovering. - * @return This builder instance. - */ - public FancyMessage tooltip(final String text) { - onHover("show_text", new JsonString(text)); - return this; - } + /** + * Set the behavior of the current editing component to display raw text when the client hovers over the text. + *

Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.

+ * + * @param lines The lines of text which will be displayed to the client upon hovering. The iteration order of this object will be the order in which the lines of the tooltip are created. + * @return This builder instance. + */ + public FancyMessage tooltip(final Iterable lines) { + tooltip(com.plotsquared.bukkit.chat.ArrayWrapper.toArray(lines, String.class)); + return this; + } - /** - * Set the behavior of the current editing component to display raw text when the client hovers over the text. - *

Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.

- * - * @param lines The lines of text which will be displayed to the client upon hovering. The iteration order of this object will be the order in which the lines of the tooltip are created. - * @return This builder instance. - */ - public FancyMessage tooltip(final Iterable lines) { - tooltip(com.plotsquared.bukkit.chat.ArrayWrapper.toArray(lines, String.class)); - return this; - } + /** + * Set the behavior of the current editing component to display raw text when the client hovers over the text. + *

Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.

+ * + * @param lines The lines of text which will be displayed to the client upon hovering. + * @return This builder instance. + */ + public FancyMessage tooltip(final String... lines) { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < lines.length; i++) { + builder.append(lines[i]); + if (i != lines.length - 1) { + builder.append('\n'); + } + } + tooltip(builder.toString()); + return this; + } - /** - * Set the behavior of the current editing component to display raw text when the client hovers over the text. - *

Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.

- * - * @param lines The lines of text which will be displayed to the client upon hovering. - * @return This builder instance. - */ - public FancyMessage tooltip(final String... lines) { - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < lines.length; i++) { - builder.append(lines[i]); - if (i != lines.length - 1) { - builder.append('\n'); - } - } - tooltip(builder.toString()); - return this; - } + /** + * Set the behavior of the current editing component to display formatted text when the client hovers over the text. + *

Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.

+ * + * @param text The formatted text which will be displayed to the client upon hovering. + * @return This builder instance. + */ + public FancyMessage formattedTooltip(FancyMessage text) { + for (MessagePart component : text.messageParts) { + if (component.clickActionData != null && component.clickActionName != null) { + throw new IllegalArgumentException("The tooltip text cannot have click data."); + } else if (component.hoverActionData != null && component.hoverActionName != null) { + throw new IllegalArgumentException("The tooltip text cannot have a tooltip."); + } + } + onHover("show_text", text); + return this; + } - /** - * Set the behavior of the current editing component to display formatted text when the client hovers over the text. - *

Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.

- * - * @param text The formatted text which will be displayed to the client upon hovering. - * @return This builder instance. - */ - public FancyMessage formattedTooltip(FancyMessage text) { - for (MessagePart component : text.messageParts) { - if (component.clickActionData != null && component.clickActionName != null) { - throw new IllegalArgumentException("The tooltip text cannot have click data."); - } else if (component.hoverActionData != null && component.hoverActionName != null) { - throw new IllegalArgumentException("The tooltip text cannot have a tooltip."); - } - } - onHover("show_text", text); - return this; - } + /** + * Set the behavior of the current editing component to display the specified lines of formatted text when the client hovers over the text. + *

Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.

+ * + * @param lines The lines of formatted text which will be displayed to the client upon hovering. + * @return This builder instance. + */ + public FancyMessage formattedTooltip(FancyMessage... lines) { + if (lines.length < 1) { + onHover(null, null); // Clear tooltip + return this; + } - /** - * Set the behavior of the current editing component to display the specified lines of formatted text when the client hovers over the text. - *

Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.

- * - * @param lines The lines of formatted text which will be displayed to the client upon hovering. - * @return This builder instance. - */ - public FancyMessage formattedTooltip(FancyMessage... lines) { - if (lines.length < 1) { - onHover(null, null); // Clear tooltip - return this; - } + FancyMessage result = new FancyMessage(); + result.messageParts.clear(); // Remove the one existing text component that exists by default, which destabilizes the object - FancyMessage result = new FancyMessage(); - result.messageParts.clear(); // Remove the one existing text component that exists by default, which destabilizes the object + for (int i = 0; i < lines.length; i++) { + try { + for (MessagePart component : lines[i]) { + if (component.clickActionData != null && component.clickActionName != null) { + throw new IllegalArgumentException("The tooltip text cannot have click data."); + } else if (component.hoverActionData != null && component.hoverActionName != null) { + throw new IllegalArgumentException("The tooltip text cannot have a tooltip."); + } + if (component.hasText()) { + result.messageParts.add(component.clone()); + } + } + if (i != lines.length - 1) { + result.messageParts.add(new MessagePart(rawText("\n"))); + } + } catch (CloneNotSupportedException e) { + Bukkit.getLogger().log(Level.WARNING, "Failed to clone object", e); + return this; + } + } + return formattedTooltip(result.messageParts.isEmpty() ? null : result); // Throws NPE if size is 0, intended + } - for (int i = 0; i < lines.length; i++) { - try { - for (MessagePart component : lines[i]) { - if (component.clickActionData != null && component.clickActionName != null) { - throw new IllegalArgumentException("The tooltip text cannot have click data."); - } else if (component.hoverActionData != null && component.hoverActionName != null) { - throw new IllegalArgumentException("The tooltip text cannot have a tooltip."); - } - if (component.hasText()) { - result.messageParts.add(component.clone()); - } - } - if (i != lines.length - 1) { - result.messageParts.add(new MessagePart(rawText("\n"))); - } - } catch (CloneNotSupportedException e) { - Bukkit.getLogger().log(Level.WARNING, "Failed to clone object", e); - return this; - } - } - return formattedTooltip(result.messageParts.isEmpty() ? null : result); // Throws NPE if size is 0, intended - } + /** + * Set the behavior of the current editing component to display the specified lines of formatted text when the client hovers over the text. + *

Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.

+ * + * @param lines The lines of text which will be displayed to the client upon hovering. The iteration order of this object will be the order in which the lines of the tooltip are created. + * @return This builder instance. + */ + public FancyMessage formattedTooltip(final Iterable lines) { + return formattedTooltip(com.plotsquared.bukkit.chat.ArrayWrapper.toArray(lines, FancyMessage.class)); + } - /** - * Set the behavior of the current editing component to display the specified lines of formatted text when the client hovers over the text. - *

Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.

- * - * @param lines The lines of text which will be displayed to the client upon hovering. The iteration order of this object will be the order in which the lines of the tooltip are created. - * @return This builder instance. - */ - public FancyMessage formattedTooltip(final Iterable lines) { - return formattedTooltip(com.plotsquared.bukkit.chat.ArrayWrapper.toArray(lines, FancyMessage.class)); - } + /** + * If the text is a translatable key, and it has replaceable values, this function can be used to set the replacements that will be used in the message. + * + * @param replacements The replacements, in order, that will be used in the language-specific message. + * @return This builder instance. + */ + public FancyMessage translationReplacements(final String... replacements) { + for (String str : replacements) { + latest().translationReplacements.add(new JsonString(str)); + } + dirty = true; - /** - * If the text is a translatable key, and it has replaceable values, this function can be used to set the replacements that will be used in the message. - * - * @param replacements The replacements, in order, that will be used in the language-specific message. - * @return This builder instance. - */ - public FancyMessage translationReplacements(final String... replacements) { - for (String str : replacements) { - latest().translationReplacements.add(new JsonString(str)); - } - dirty = true; + return this; + } + /* - return this; - } - /* + /** + * If the text is a translatable key, and it has replaceable values, this function can be used to set the replacements that will be used in the message. + * @param replacements The replacements, in order, that will be used in the language-specific message. + * @return This builder instance. + */ /* ------------ + public FancyMessage translationReplacements(final Iterable replacements){ + for(CharSequence str : replacements){ + latest().translationReplacements.add(new JsonString(str)); + } - /** - * If the text is a translatable key, and it has replaceable values, this function can be used to set the replacements that will be used in the message. - * @param replacements The replacements, in order, that will be used in the language-specific message. - * @return This builder instance. - */ /* ------------ - public FancyMessage translationReplacements(final Iterable replacements){ - for(CharSequence str : replacements){ - latest().translationReplacements.add(new JsonString(str)); - } + return this; + } - return this; - } + */ - */ + /** + * If the text is a translatable key, and it has replaceable values, this function can be used to set the replacements that will be used in the message. + * + * @param replacements The replacements, in order, that will be used in the language-specific message. + * @return This builder instance. + */ + public FancyMessage translationReplacements(final FancyMessage... replacements) { + for (FancyMessage str : replacements) { + latest().translationReplacements.add(str); + } - /** - * If the text is a translatable key, and it has replaceable values, this function can be used to set the replacements that will be used in the message. - * - * @param replacements The replacements, in order, that will be used in the language-specific message. - * @return This builder instance. - */ - public FancyMessage translationReplacements(final FancyMessage... replacements) { - for (FancyMessage str : replacements) { - latest().translationReplacements.add(str); - } + dirty = true; - dirty = true; + return this; + } - return this; - } + /** + * If the text is a translatable key, and it has replaceable values, this function can be used to set the replacements that will be used in the message. + * + * @param replacements The replacements, in order, that will be used in the language-specific message. + * @return This builder instance. + */ + public FancyMessage translationReplacements(final Iterable replacements) { + return translationReplacements(com.plotsquared.bukkit.chat.ArrayWrapper.toArray(replacements, FancyMessage.class)); + } - /** - * If the text is a translatable key, and it has replaceable values, this function can be used to set the replacements that will be used in the message. - * - * @param replacements The replacements, in order, that will be used in the language-specific message. - * @return This builder instance. - */ - public FancyMessage translationReplacements(final Iterable replacements) { - return translationReplacements(com.plotsquared.bukkit.chat.ArrayWrapper.toArray(replacements, FancyMessage.class)); - } + /** + * Terminate construction of the current editing component, and begin construction of a new message component. + * After a successful call to this method, all setter methods will refer to a new message component, created as a result of the call to this method. + * + * @param text The text which will populate the new message component. + * @return This builder instance. + */ + public FancyMessage then(final String text) { + return then(rawText(text)); + } - /** - * Terminate construction of the current editing component, and begin construction of a new message component. - * After a successful call to this method, all setter methods will refer to a new message component, created as a result of the call to this method. - * - * @param text The text which will populate the new message component. - * @return This builder instance. - */ - public FancyMessage then(final String text) { - return then(rawText(text)); - } + /** + * Terminate construction of the current editing component, and begin construction of a new message component. + * After a successful call to this method, all setter methods will refer to a new message component, created as a result of the call to this method. + * + * @param text The text which will populate the new message component. + * @return This builder instance. + */ + public FancyMessage then(final TextualComponent text) { + if (!latest().hasText()) { + throw new IllegalStateException("previous message part has no text"); + } + messageParts.add(new MessagePart(text)); + dirty = true; + return this; + } - /** - * Terminate construction of the current editing component, and begin construction of a new message component. - * After a successful call to this method, all setter methods will refer to a new message component, created as a result of the call to this method. - * - * @param text The text which will populate the new message component. - * @return This builder instance. - */ - public FancyMessage then(final TextualComponent text) { - if (!latest().hasText()) { - throw new IllegalStateException("previous message part has no text"); - } - messageParts.add(new MessagePart(text)); - dirty = true; - return this; - } + /** + * Terminate construction of the current editing component, and begin construction of a new message component. + * After a successful call to this method, all setter methods will refer to a new message component, created as a result of the call to this method. + * + * @return This builder instance. + */ + public FancyMessage then() { + if (!latest().hasText()) { + throw new IllegalStateException("previous message part has no text"); + } + messageParts.add(new MessagePart()); + dirty = true; + return this; + } - /** - * Terminate construction of the current editing component, and begin construction of a new message component. - * After a successful call to this method, all setter methods will refer to a new message component, created as a result of the call to this method. - * - * @return This builder instance. - */ - public FancyMessage then() { - if (!latest().hasText()) { - throw new IllegalStateException("previous message part has no text"); - } - messageParts.add(new MessagePart()); - dirty = true; - return this; - } + @Override + public void writeJson(JsonWriter writer) throws IOException { + if (messageParts.size() == 1) { + latest().writeJson(writer); + } else { + writer.beginObject().name("text").value("").name("extra").beginArray(); + for (final MessagePart part : this) { + part.writeJson(writer); + } + writer.endArray().endObject(); + } + } - @Override - public void writeJson(JsonWriter writer) throws IOException { - if (messageParts.size() == 1) { - latest().writeJson(writer); - } else { - writer.beginObject().name("text").value("").name("extra").beginArray(); - for (final MessagePart part : this) { - part.writeJson(writer); - } - writer.endArray().endObject(); - } - } + /** + * Serialize this fancy message, converting it into syntactically-valid JSON using a {@link JsonWriter}. + * This JSON should be compatible with vanilla formatter commands such as {@code /tellraw}. + * + * @return The JSON string representing this object. + */ + public String toJSONString() { + if (!dirty && jsonString != null) { + return jsonString; + } + StringWriter string = new StringWriter(); + JsonWriter json = new JsonWriter(string); + try { + writeJson(json); + json.close(); + } catch (IOException e) { + throw new RuntimeException("invalid message"); + } + jsonString = string.toString(); + dirty = false; + return jsonString; + } - /** - * Serialize this fancy message, converting it into syntactically-valid JSON using a {@link JsonWriter}. - * This JSON should be compatible with vanilla formatter commands such as {@code /tellraw}. - * - * @return The JSON string representing this object. - */ - public String toJSONString() { - if (!dirty && jsonString != null) { - return jsonString; - } - StringWriter string = new StringWriter(); - JsonWriter json = new JsonWriter(string); - try { - writeJson(json); - json.close(); - } catch (IOException e) { - throw new RuntimeException("invalid message"); - } - jsonString = string.toString(); - dirty = false; - return jsonString; - } + /** + * Sends this message to a player. The player will receive the fully-fledged formatted display of this message. + * + * @param player The player who will receive the message. + */ + public void send(Player player) { + send(player, toJSONString()); + } - /** - * Sends this message to a player. The player will receive the fully-fledged formatted display of this message. - * - * @param player The player who will receive the message. - */ - public void send(Player player) { - send(player, toJSONString()); - } + private void send(CommandSender sender, String jsonString) { + if (!(sender instanceof Player)) { + sender.sendMessage(toOldMessageFormat()); + return; + } + Player player = (Player) sender; + try { + Object handle = Reflection.getHandle(player); + Object connection = Reflection.getField(handle.getClass(), "playerConnection").get(handle); + Reflection.getMethod(connection.getClass(), "sendPacket", Reflection.getNMSClass("Packet")).invoke(connection, createChatPacket(jsonString)); + } catch (IllegalArgumentException e) { + Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e); + } catch (IllegalAccessException e) { + Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e); + } catch (InstantiationException e) { + Bukkit.getLogger().log(Level.WARNING, "Underlying class is abstract.", e); + } catch (InvocationTargetException e) { + Bukkit.getLogger().log(Level.WARNING, "A error has occurred during invoking of method.", e); + } catch (NoSuchMethodException e) { + Bukkit.getLogger().log(Level.WARNING, "Could not find method.", e); + } catch (ClassNotFoundException e) { + Bukkit.getLogger().log(Level.WARNING, "Could not find class.", e); + } + } - private void send(CommandSender sender, String jsonString) { - if (!(sender instanceof Player)) { - sender.sendMessage(toOldMessageFormat()); - return; - } - Player player = (Player) sender; - try { - Object handle = Reflection.getHandle(player); - Object connection = Reflection.getField(handle.getClass(), "playerConnection").get(handle); - Reflection.getMethod(connection.getClass(), "sendPacket", Reflection.getNMSClass("Packet")).invoke(connection, createChatPacket(jsonString)); - } catch (IllegalArgumentException e) { - Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e); - } catch (IllegalAccessException e) { - Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e); - } catch (InstantiationException e) { - Bukkit.getLogger().log(Level.WARNING, "Underlying class is abstract.", e); - } catch (InvocationTargetException e) { - Bukkit.getLogger().log(Level.WARNING, "A error has occurred during invoking of method.", e); - } catch (NoSuchMethodException e) { - Bukkit.getLogger().log(Level.WARNING, "Could not find method.", e); - } catch (ClassNotFoundException e) { - Bukkit.getLogger().log(Level.WARNING, "Could not find class.", e); - } - } + // The ChatSerializer's instance of Gson + private static Object nmsChatSerializerGsonInstance; + private static Method fromJsonMethod; - // The ChatSerializer's instance of Gson - private static Object nmsChatSerializerGsonInstance; - private static Method fromJsonMethod; + private Object createChatPacket(String json) throws IllegalArgumentException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, ClassNotFoundException { + if (nmsChatSerializerGsonInstance == null) { + // Find the field and its value, completely bypassing obfuscation + Class chatSerializerClazz; - private Object createChatPacket(String json) throws IllegalArgumentException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, ClassNotFoundException { - if (nmsChatSerializerGsonInstance == null) { - // Find the field and its value, completely bypassing obfuscation - Class chatSerializerClazz; + // Get the three parts of the version string (major version is currently unused) + // vX_Y_RZ + // X = major + // Y = minor + // Z = revision + final String version = Reflection.getVersion(); + String[] split = version.substring(1, version.length() - 1).split("_"); // Remove trailing dot + //int majorVersion = Integer.parseInt(split[0]); + int minorVersion = Integer.parseInt(split[1]); + int revisionVersion = Integer.parseInt(split[2].substring(1)); // Substring to ignore R - // Get the three parts of the version string (major version is currently unused) - // vX_Y_RZ - // X = major - // Y = minor - // Z = revision - final String version = Reflection.getVersion(); - String[] split = version.substring(1, version.length() - 1).split("_"); // Remove trailing dot - //int majorVersion = Integer.parseInt(split[0]); - int minorVersion = Integer.parseInt(split[1]); - int revisionVersion = Integer.parseInt(split[2].substring(1)); // Substring to ignore R + if (minorVersion < 8 || (minorVersion == 8 && revisionVersion == 1)) { + chatSerializerClazz = Reflection.getNMSClass("ChatSerializer"); + } else { + chatSerializerClazz = Reflection.getNMSClass("IChatBaseComponent$ChatSerializer"); + } - if (minorVersion < 8 || (minorVersion == 8 && revisionVersion == 1)) { - chatSerializerClazz = Reflection.getNMSClass("ChatSerializer"); - } else { - chatSerializerClazz = Reflection.getNMSClass("IChatBaseComponent$ChatSerializer"); - } + if (chatSerializerClazz == null) { + throw new ClassNotFoundException("Can't find the ChatSerializer class"); + } - if (chatSerializerClazz == null) { - throw new ClassNotFoundException("Can't find the ChatSerializer class"); - } + for (Field declaredField : chatSerializerClazz.getDeclaredFields()) { + if (Modifier.isFinal(declaredField.getModifiers()) && Modifier.isStatic(declaredField.getModifiers()) && declaredField.getType().getName().endsWith("Gson")) { + // We've found our field + declaredField.setAccessible(true); + nmsChatSerializerGsonInstance = declaredField.get(null); + fromJsonMethod = nmsChatSerializerGsonInstance.getClass().getMethod("fromJson", String.class, Class.class); + break; + } + } + } - for (Field declaredField : chatSerializerClazz.getDeclaredFields()) { - if (Modifier.isFinal(declaredField.getModifiers()) && Modifier.isStatic(declaredField.getModifiers()) && declaredField.getType().getName().endsWith("Gson")) { - // We've found our field - declaredField.setAccessible(true); - nmsChatSerializerGsonInstance = declaredField.get(null); - fromJsonMethod = nmsChatSerializerGsonInstance.getClass().getMethod("fromJson", String.class, Class.class); - break; - } - } - } + // Since the method is so simple, and all the obfuscated methods have the same name, it's easier to reimplement 'IChatBaseComponent a(String)' than to reflectively call it + // Of course, the implementation may change, but fuzzy matches might break with signature changes + Object serializedChatComponent = fromJsonMethod.invoke(nmsChatSerializerGsonInstance, json, Reflection.getNMSClass("IChatBaseComponent")); - // Since the method is so simple, and all the obfuscated methods have the same name, it's easier to reimplement 'IChatBaseComponent a(String)' than to reflectively call it - // Of course, the implementation may change, but fuzzy matches might break with signature changes - Object serializedChatComponent = fromJsonMethod.invoke(nmsChatSerializerGsonInstance, json, Reflection.getNMSClass("IChatBaseComponent")); + return nmsPacketPlayOutChatConstructor.newInstance(serializedChatComponent); + } - return nmsPacketPlayOutChatConstructor.newInstance(serializedChatComponent); - } + /** + * Sends this message to a command sender. + * If the sender is a player, they will receive the fully-fledged formatted display of this message. + * Otherwise, they will receive a version of this message with less formatting. + * + * @param sender The command sender who will receive the message. + * @see #toOldMessageFormat() + */ + public void send(CommandSender sender) { + send(sender, toJSONString()); + } - /** - * Sends this message to a command sender. - * If the sender is a player, they will receive the fully-fledged formatted display of this message. - * Otherwise, they will receive a version of this message with less formatting. - * - * @param sender The command sender who will receive the message. - * @see #toOldMessageFormat() - */ - public void send(CommandSender sender) { - send(sender, toJSONString()); - } + /** + * Sends this message to multiple command senders. + * + * @param senders The command senders who will receive the message. + * @see #send(CommandSender) + */ + public void send(final Iterable senders) { + String string = toJSONString(); + for (final CommandSender sender : senders) { + send(sender, string); + } + } - /** - * Sends this message to multiple command senders. - * - * @param senders The command senders who will receive the message. - * @see #send(CommandSender) - */ - public void send(final Iterable senders) { - String string = toJSONString(); - for (final CommandSender sender : senders) { - send(sender, string); - } - } + /** + * Convert this message to a human-readable string with limited formatting. + * This method is used to send this message to clients without JSON formatting support. + *

+ * Serialization of this message by using this message will include (in this order for each message part): + *

    + *
  1. The color of each message part.
  2. + *
  3. The applicable stylizations for each message part.
  4. + *
  5. The core text of the message part.
  6. + *
+ * The primary omissions are tooltips and clickable actions. Consequently, this method should be used only as a last resort. + *

+ *

+ * Color and formatting can be removed from the returned string by using {@link ChatColor#stripColor(String)}.

+ * + * @return A human-readable string representing limited formatting in addition to the core text of this message. + */ + public String toOldMessageFormat() { + StringBuilder result = new StringBuilder(); + for (MessagePart part : this) { + result.append(part.color == null ? "" : part.color); + for (ChatColor formatSpecifier : part.styles) { + result.append(formatSpecifier); + } + result.append(part.text); + } + return result.toString(); + } - /** - * Convert this message to a human-readable string with limited formatting. - * This method is used to send this message to clients without JSON formatting support. - *

- * Serialization of this message by using this message will include (in this order for each message part): - *

    - *
  1. The color of each message part.
  2. - *
  3. The applicable stylizations for each message part.
  4. - *
  5. The core text of the message part.
  6. - *
- * The primary omissions are tooltips and clickable actions. Consequently, this method should be used only as a last resort. - *

- *

- * Color and formatting can be removed from the returned string by using {@link ChatColor#stripColor(String)}.

- * - * @return A human-readable string representing limited formatting in addition to the core text of this message. - */ - public String toOldMessageFormat() { - StringBuilder result = new StringBuilder(); - for (MessagePart part : this) { - result.append(part.color == null ? "" : part.color); - for (ChatColor formatSpecifier : part.styles) { - result.append(formatSpecifier); - } - result.append(part.text); - } - return result.toString(); - } + private MessagePart latest() { + return messageParts.get(messageParts.size() - 1); + } - private MessagePart latest() { - return messageParts.get(messageParts.size() - 1); - } + private void onClick(final String name, final String data) { + final MessagePart latest = latest(); + latest.clickActionName = name; + latest.clickActionData = data; + dirty = true; + } - private void onClick(final String name, final String data) { - final MessagePart latest = latest(); - latest.clickActionName = name; - latest.clickActionData = data; - dirty = true; - } + private void onHover(final String name, final JsonRepresentedObject data) { + final MessagePart latest = latest(); + latest.hoverActionName = name; + latest.hoverActionData = data; + dirty = true; + } - private void onHover(final String name, final JsonRepresentedObject data) { - final MessagePart latest = latest(); - latest.hoverActionName = name; - latest.hoverActionData = data; - dirty = true; - } - - // Doc copied from interface - public Map serialize() { - HashMap map = new HashMap<>(); - map.put("messageParts", messageParts); + // Doc copied from interface + public Map serialize() { + HashMap map = new HashMap<>(); + map.put("messageParts", messageParts); // map.put("JSON", toJSONString()); - return map; - } + return map; + } - /** - * Deserializes a JSON-represented message from a mapping of key-value pairs. - * This is called by the Bukkit serialization API. - * It is not intended for direct public API consumption. - * - * @param serialized The key-value mapping which represents a fancy message. - */ - @SuppressWarnings("unchecked") - public static FancyMessage deserialize(Map serialized) { - FancyMessage msg = new FancyMessage(); - msg.messageParts = (List) serialized.get("messageParts"); - msg.jsonString = serialized.containsKey("JSON") ? serialized.get("JSON").toString() : null; - msg.dirty = !serialized.containsKey("JSON"); - return msg; - } + /** + * Deserializes a JSON-represented message from a mapping of key-value pairs. + * This is called by the Bukkit serialization API. + * It is not intended for direct public API consumption. + * + * @param serialized The key-value mapping which represents a fancy message. + */ + @SuppressWarnings("unchecked") + public static FancyMessage deserialize(Map serialized) { + FancyMessage msg = new FancyMessage(); + msg.messageParts = (List) serialized.get("messageParts"); + msg.jsonString = serialized.containsKey("JSON") ? serialized.get("JSON").toString() : null; + msg.dirty = !serialized.containsKey("JSON"); + return msg; + } - /** - * Internally called method. Not for API consumption. - */ - public Iterator iterator() { - return messageParts.iterator(); - } + /** + * Internally called method. Not for API consumption. + */ + public Iterator iterator() { + return messageParts.iterator(); + } - private static JsonParser _stringParser = new JsonParser(); + private static JsonParser _stringParser = new JsonParser(); - /** - * Deserializes a fancy message from its JSON representation. This JSON representation is of the format of - * that returned by {@link #toJSONString()}, and is compatible with vanilla inputs. - * - * @param json The JSON string which represents a fancy message. - * @return A {@code FancyMessage} representing the parameterized JSON message. - */ - public static FancyMessage deserialize(String json) { - JsonObject serialized = _stringParser.parse(json).getAsJsonObject(); - JsonArray extra = serialized.getAsJsonArray("extra"); // Get the extra component - FancyMessage returnVal = new FancyMessage(); - returnVal.messageParts.clear(); - for (JsonElement mPrt : extra) { - MessagePart component = new MessagePart(); - JsonObject messagePart = mPrt.getAsJsonObject(); - for (Map.Entry entry : messagePart.entrySet()) { - // Deserialize text - if (TextualComponent.isTextKey(entry.getKey())) { - // The map mimics the YAML serialization, which has a "key" field and one or more "value" fields - Map serializedMapForm = new HashMap<>(); // Must be object due to Bukkit serializer API compliance - serializedMapForm.put("key", entry.getKey()); - if (entry.getValue().isJsonPrimitive()) { - // Assume string - serializedMapForm.put("value", entry.getValue().getAsString()); - } else { - // Composite object, but we assume each element is a string - for (Map.Entry compositeNestedElement : entry.getValue().getAsJsonObject().entrySet()) { - serializedMapForm.put("value." + compositeNestedElement.getKey(), compositeNestedElement.getValue().getAsString()); - } - } - component.text = TextualComponent.deserialize(serializedMapForm); - } else if (MessagePart.stylesToNames.inverse().containsKey(entry.getKey())) { - if (entry.getValue().getAsBoolean()) { - component.styles.add(MessagePart.stylesToNames.inverse().get(entry.getKey())); - } - } else if (entry.getKey().equals("color")) { - component.color = ChatColor.valueOf(entry.getValue().getAsString().toUpperCase()); - } else if (entry.getKey().equals("clickEvent")) { - JsonObject object = entry.getValue().getAsJsonObject(); - component.clickActionName = object.get("action").getAsString(); - component.clickActionData = object.get("value").getAsString(); - } else if (entry.getKey().equals("hoverEvent")) { - JsonObject object = entry.getValue().getAsJsonObject(); - component.hoverActionName = object.get("action").getAsString(); - if (object.get("value").isJsonPrimitive()) { - // Assume string - component.hoverActionData = new JsonString(object.get("value").getAsString()); - } else { - // Assume composite type - // The only composite type we currently store is another FancyMessage - // Therefore, recursion time! - component.hoverActionData = deserialize(object.get("value").toString() /* This should properly serialize the JSON object as a JSON string */); - } - } else if (entry.getKey().equals("insertion")) { - component.insertionData = entry.getValue().getAsString(); - } else if (entry.getKey().equals("with")) { - for (JsonElement object : entry.getValue().getAsJsonArray()) { - if (object.isJsonPrimitive()) { - component.translationReplacements.add(new JsonString(object.getAsString())); - } else { - // Only composite type stored in this array is - again - FancyMessages - // Recurse within this function to parse this as a translation replacement - component.translationReplacements.add(deserialize(object.toString())); - } - } - } - } - returnVal.messageParts.add(component); - } - return returnVal; - } + /** + * Deserializes a fancy message from its JSON representation. This JSON representation is of the format of + * that returned by {@link #toJSONString()}, and is compatible with vanilla inputs. + * + * @param json The JSON string which represents a fancy message. + * @return A {@code FancyMessage} representing the parameterized JSON message. + */ + public static FancyMessage deserialize(String json) { + JsonObject serialized = _stringParser.parse(json).getAsJsonObject(); + JsonArray extra = serialized.getAsJsonArray("extra"); // Get the extra component + FancyMessage returnVal = new FancyMessage(); + returnVal.messageParts.clear(); + for (JsonElement mPrt : extra) { + MessagePart component = new MessagePart(); + JsonObject messagePart = mPrt.getAsJsonObject(); + for (Map.Entry entry : messagePart.entrySet()) { + // Deserialize text + if (TextualComponent.isTextKey(entry.getKey())) { + // The map mimics the YAML serialization, which has a "key" field and one or more "value" fields + Map serializedMapForm = new HashMap<>(); // Must be object due to Bukkit serializer API compliance + serializedMapForm.put("key", entry.getKey()); + if (entry.getValue().isJsonPrimitive()) { + // Assume string + serializedMapForm.put("value", entry.getValue().getAsString()); + } else { + // Composite object, but we assume each element is a string + for (Map.Entry compositeNestedElement : entry.getValue().getAsJsonObject().entrySet()) { + serializedMapForm.put("value." + compositeNestedElement.getKey(), compositeNestedElement.getValue().getAsString()); + } + } + component.text = TextualComponent.deserialize(serializedMapForm); + } else if (MessagePart.stylesToNames.inverse().containsKey(entry.getKey())) { + if (entry.getValue().getAsBoolean()) { + component.styles.add(MessagePart.stylesToNames.inverse().get(entry.getKey())); + } + } else if (entry.getKey().equals("color")) { + component.color = ChatColor.valueOf(entry.getValue().getAsString().toUpperCase()); + } else if (entry.getKey().equals("clickEvent")) { + JsonObject object = entry.getValue().getAsJsonObject(); + component.clickActionName = object.get("action").getAsString(); + component.clickActionData = object.get("value").getAsString(); + } else if (entry.getKey().equals("hoverEvent")) { + JsonObject object = entry.getValue().getAsJsonObject(); + component.hoverActionName = object.get("action").getAsString(); + if (object.get("value").isJsonPrimitive()) { + // Assume string + component.hoverActionData = new JsonString(object.get("value").getAsString()); + } else { + // Assume composite type + // The only composite type we currently store is another FancyMessage + // Therefore, recursion time! + component.hoverActionData = deserialize(object.get("value").toString() /* This should properly serialize the JSON object as a JSON string */); + } + } else if (entry.getKey().equals("insertion")) { + component.insertionData = entry.getValue().getAsString(); + } else if (entry.getKey().equals("with")) { + for (JsonElement object : entry.getValue().getAsJsonArray()) { + if (object.isJsonPrimitive()) { + component.translationReplacements.add(new JsonString(object.getAsString())); + } else { + // Only composite type stored in this array is - again - FancyMessages + // Recurse within this function to parse this as a translation replacement + component.translationReplacements.add(deserialize(object.toString())); + } + } + } + } + returnVal.messageParts.add(component); + } + return returnVal; + } } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/chat/JsonRepresentedObject.java b/Bukkit/src/main/java/com/plotsquared/bukkit/chat/JsonRepresentedObject.java index e76593f29..6092bce60 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/chat/JsonRepresentedObject.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/chat/JsonRepresentedObject.java @@ -9,11 +9,11 @@ import java.io.IOException; */ interface JsonRepresentedObject { - /** - * Writes the JSON representation of this object to the specified writer. - * @param writer The JSON writer which will receive the object. - * @throws IOException If an error occurs writing to the stream. - */ - public void writeJson(JsonWriter writer) throws IOException; - + /** + * Writes the JSON representation of this object to the specified writer. + * @param writer The JSON writer which will receive the object. + * @throws IOException If an error occurs writing to the stream. + */ + public void writeJson(JsonWriter writer) throws IOException; + } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/chat/JsonString.java b/Bukkit/src/main/java/com/plotsquared/bukkit/chat/JsonString.java index e62d98364..1fb197e8b 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/chat/JsonString.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/chat/JsonString.java @@ -1,12 +1,12 @@ package com.plotsquared.bukkit.chat; +import com.google.gson.stream.JsonWriter; +import org.bukkit.configuration.serialization.ConfigurationSerializable; + import java.io.IOException; import java.util.HashMap; import java.util.Map; -import com.google.gson.stream.JsonWriter; -import org.bukkit.configuration.serialization.ConfigurationSerializable; - /** * Represents a JSON string value. * Writes by this object will not write name values nor begin/end objects in the JSON stream. @@ -14,34 +14,34 @@ import org.bukkit.configuration.serialization.ConfigurationSerializable; */ final class JsonString implements JsonRepresentedObject, ConfigurationSerializable { - private String _value; + private String _value; - public JsonString(CharSequence value) { - _value = value == null ? null : value.toString(); - } + public JsonString(CharSequence value) { + _value = value == null ? null : value.toString(); + } - @Override - public void writeJson(JsonWriter writer) throws IOException { - writer.value(getValue()); - } + @Override + public void writeJson(JsonWriter writer) throws IOException { + writer.value(getValue()); + } - public String getValue() { - return _value; - } + public String getValue() { + return _value; + } - public Map serialize() { - HashMap theSingleValue = new HashMap(); - theSingleValue.put("stringValue", _value); - return theSingleValue; - } + public Map serialize() { + HashMap theSingleValue = new HashMap(); + theSingleValue.put("stringValue", _value); + return theSingleValue; + } - public static JsonString deserialize(Map map) { - return new JsonString(map.get("stringValue").toString()); - } + public static JsonString deserialize(Map map) { + return new JsonString(map.get("stringValue").toString()); + } - @Override - public String toString() { - return _value; - } + @Override + public String toString() { + return _value; + } } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/chat/Reflection.java b/Bukkit/src/main/java/com/plotsquared/bukkit/chat/Reflection.java index c5a9fe36c..de315c06e 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/chat/Reflection.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/chat/Reflection.java @@ -15,134 +15,134 @@ import java.util.Map; */ public final class Reflection { - /** - * Stores loaded classes from the {@code net.minecraft.server} package. - */ - private static final Map> _loadedNMSClasses = new HashMap<>(); - /** - * Stores loaded classes from the {@code org.bukkit.craftbukkit} package (and subpackages). - */ - private static final Map> _loadedOBCClasses = new HashMap<>(); - private static final Map, Map> _loadedFields = new HashMap<>(); - /** - * Contains loaded methods in a cache. - * The map maps [types to maps of [method names to maps of [parameter types to method instances]]]. - */ - private static final Map, Map>, Method>>> _loadedMethods = new HashMap<>(); - private static String _versionString; + /** + * Stores loaded classes from the {@code net.minecraft.server} package. + */ + private static final Map> _loadedNMSClasses = new HashMap<>(); + /** + * Stores loaded classes from the {@code org.bukkit.craftbukkit} package (and subpackages). + */ + private static final Map> _loadedOBCClasses = new HashMap<>(); + private static final Map, Map> _loadedFields = new HashMap<>(); + /** + * Contains loaded methods in a cache. + * The map maps [types to maps of [method names to maps of [parameter types to method instances]]]. + */ + private static final Map, Map>, Method>>> _loadedMethods = new HashMap<>(); + private static String _versionString; - private Reflection() { } + private Reflection() { } - /** - * Gets the version string from the package name of the CraftBukkit server implementation. - * This is needed to bypass the JAR package name changing on each update. - * - * @return The version string of the OBC and NMS packages, including the trailing dot. - */ - public synchronized static String getVersion() { - if (_versionString == null) { - if (Bukkit.getServer() == null) { - // The server hasn't started, static initializer call? - return null; - } - String name = Bukkit.getServer().getClass().getPackage().getName(); - _versionString = name.substring(name.lastIndexOf('.') + 1) + "."; - } + /** + * Gets the version string from the package name of the CraftBukkit server implementation. + * This is needed to bypass the JAR package name changing on each update. + * + * @return The version string of the OBC and NMS packages, including the trailing dot. + */ + public synchronized static String getVersion() { + if (_versionString == null) { + if (Bukkit.getServer() == null) { + // The server hasn't started, static initializer call? + return null; + } + String name = Bukkit.getServer().getClass().getPackage().getName(); + _versionString = name.substring(name.lastIndexOf('.') + 1) + "."; + } - return _versionString; - } + return _versionString; + } - /** - * Gets a {@link Class} object representing a type contained within the {@code net.minecraft.server} versioned package. - * The class instances returned by this method are cached, such that no lookup will be done twice (unless multiple threads are accessing this method simultaneously). - * - * @param className The name of the class, excluding the package, within NMS. - * @return The class instance representing the specified NMS class, or {@code null} if it could not be loaded. - */ - public synchronized static Class getNMSClass(String className) { - if (_loadedNMSClasses.containsKey(className)) { - return _loadedNMSClasses.get(className); - } + /** + * Gets a {@link Class} object representing a type contained within the {@code net.minecraft.server} versioned package. + * The class instances returned by this method are cached, such that no lookup will be done twice (unless multiple threads are accessing this method simultaneously). + * + * @param className The name of the class, excluding the package, within NMS. + * @return The class instance representing the specified NMS class, or {@code null} if it could not be loaded. + */ + public synchronized static Class getNMSClass(String className) { + if (_loadedNMSClasses.containsKey(className)) { + return _loadedNMSClasses.get(className); + } - String fullName = "net.minecraft.server." + getVersion() + className; - Class clazz; - try { - clazz = Class.forName(fullName); - } catch (ClassNotFoundException e) { - _loadedNMSClasses.put(className, null); - throw new RuntimeException(e); - } - _loadedNMSClasses.put(className, clazz); - return clazz; - } + String fullName = "net.minecraft.server." + getVersion() + className; + Class clazz; + try { + clazz = Class.forName(fullName); + } catch (ClassNotFoundException e) { + _loadedNMSClasses.put(className, null); + throw new RuntimeException(e); + } + _loadedNMSClasses.put(className, clazz); + return clazz; + } - /** - * Gets a {@link Class} object representing a type contained within the {@code org.bukkit.craftbukkit} versioned package. - * The class instances returned by this method are cached, such that no lookup will be done twice (unless multiple threads are accessing this method simultaneously). - * - * @param className The name of the class, excluding the package, within OBC. This name may contain a subpackage name, such as {@code inventory.CraftItemStack}. - * @return The class instance representing the specified OBC class, or {@code null} if it could not be loaded. - */ - public synchronized static Class getOBCClass(String className) { - if (_loadedOBCClasses.containsKey(className)) { - return _loadedOBCClasses.get(className); - } + /** + * Gets a {@link Class} object representing a type contained within the {@code org.bukkit.craftbukkit} versioned package. + * The class instances returned by this method are cached, such that no lookup will be done twice (unless multiple threads are accessing this method simultaneously). + * + * @param className The name of the class, excluding the package, within OBC. This name may contain a subpackage name, such as {@code inventory.CraftItemStack}. + * @return The class instance representing the specified OBC class, or {@code null} if it could not be loaded. + */ + public synchronized static Class getOBCClass(String className) { + if (_loadedOBCClasses.containsKey(className)) { + return _loadedOBCClasses.get(className); + } - String fullName = "org.bukkit.craftbukkit." + getVersion() + className; - Class clazz; - try { - clazz = Class.forName(fullName); - } catch (ClassNotFoundException e) { - _loadedOBCClasses.put(className, null); - throw new RuntimeException(e); - } - _loadedOBCClasses.put(className, clazz); - return clazz; - } + String fullName = "org.bukkit.craftbukkit." + getVersion() + className; + Class clazz; + try { + clazz = Class.forName(fullName); + } catch (ClassNotFoundException e) { + _loadedOBCClasses.put(className, null); + throw new RuntimeException(e); + } + _loadedOBCClasses.put(className, clazz); + return clazz; + } - /** - * Attempts to get the NMS handle of a CraftBukkit object. - *

- * The only match currently attempted by this method is a retrieval by using a parameterless {@code getHandle()} method implemented by the runtime type of the specified object. - *

- * - * @param obj The object for which to retrieve an NMS handle. - * @return The NMS handle of the specified object, or {@code null} if it could not be retrieved using {@code getHandle()}. - */ - public synchronized static Object getHandle(Object obj) throws InvocationTargetException, IllegalAccessException, IllegalArgumentException { - return getMethod(obj.getClass(), "getHandle").invoke(obj); - } + /** + * Attempts to get the NMS handle of a CraftBukkit object. + *

+ * The only match currently attempted by this method is a retrieval by using a parameterless {@code getHandle()} method implemented by the runtime type of the specified object. + *

+ * + * @param obj The object for which to retrieve an NMS handle. + * @return The NMS handle of the specified object, or {@code null} if it could not be retrieved using {@code getHandle()}. + */ + public synchronized static Object getHandle(Object obj) throws InvocationTargetException, IllegalAccessException, IllegalArgumentException { + return getMethod(obj.getClass(), "getHandle").invoke(obj); + } - /** - * Retrieves a {@link Field} instance declared by the specified class with the specified name. - * Java access modifiers are ignored during this retrieval. No guarantee is made as to whether the field - * returned will be an instance or static field. - *

- * A global caching mechanism within this class is used to store fields. Combined with synchronization, this guarantees that - * no field will be reflectively looked up twice. - *

- *

- * If a field is deemed suitable for return, {@link Field#setAccessible(boolean) setAccessible} will be invoked with an argument of {@code true} before it is returned. - * This ensures that callers do not have to check or worry about Java access modifiers when dealing with the returned instance. - *

- * - * @param clazz The class which contains the field to retrieve. - * @param name The declared name of the field in the class. - * @return A field object with the specified name declared by the specified class. - * @see Class#getDeclaredField(String) - */ - public synchronized static Field getField(Class clazz, String name) { - Map loaded; - if (!_loadedFields.containsKey(clazz)) { - loaded = new HashMap<>(); - _loadedFields.put(clazz, loaded); - } else { - loaded = _loadedFields.get(clazz); - } - if (loaded.containsKey(name)) { - // If the field is loaded (or cached as not existing), return the relevant value, which might be null - return loaded.get(name); - } + /** + * Retrieves a {@link Field} instance declared by the specified class with the specified name. + * Java access modifiers are ignored during this retrieval. No guarantee is made as to whether the field + * returned will be an instance or static field. + *

+ * A global caching mechanism within this class is used to store fields. Combined with synchronization, this guarantees that + * no field will be reflectively looked up twice. + *

+ *

+ * If a field is deemed suitable for return, {@link Field#setAccessible(boolean) setAccessible} will be invoked with an argument of {@code true} before it is returned. + * This ensures that callers do not have to check or worry about Java access modifiers when dealing with the returned instance. + *

+ * + * @param clazz The class which contains the field to retrieve. + * @param name The declared name of the field in the class. + * @return A field object with the specified name declared by the specified class. + * @see Class#getDeclaredField(String) + */ + public synchronized static Field getField(Class clazz, String name) { + Map loaded; + if (!_loadedFields.containsKey(clazz)) { + loaded = new HashMap<>(); + _loadedFields.put(clazz, loaded); + } else { + loaded = _loadedFields.get(clazz); + } + if (loaded.containsKey(name)) { + // If the field is loaded (or cached as not existing), return the relevant value, which might be null + return loaded.get(name); + } try { Field field = clazz.getDeclaredField(name); field.setAccessible(true); @@ -157,50 +157,50 @@ public final class Reflection { } } - /** - * Retrieves a {@link Method} instance declared by the specified class with the specified name and argument types. - * Java access modifiers are ignored during this retrieval. No guarantee is made as to whether the field - * returned will be an instance or static field. - *

- * A global caching mechanism within this class is used to store method. Combined with synchronization, this guarantees that - * no method will be reflectively looked up twice. - *

- * If a method is deemed suitable for return, {@link Method#setAccessible(boolean) setAccessible} will be invoked with an argument of {@code true} before it is returned. - * This ensures that callers do not have to check or worry about Java access modifiers when dealing with the returned instance. - *

- * This method does not search superclasses of the specified type for methods with the specified signature. - * Callers wishing this behavior should use {@link Class#getDeclaredMethod(String, Class...)}. - * - * @param clazz The class which contains the method to retrieve. - * @param name The declared name of the method in the class. - * @param args The formal argument types of the method. - * @return A method object with the specified name declared by the specified class. - */ - public synchronized static Method getMethod(Class clazz, String name, Class... args) { - if (!_loadedMethods.containsKey(clazz)) { - _loadedMethods.put(clazz, new HashMap>, Method>>()); - } + /** + * Retrieves a {@link Method} instance declared by the specified class with the specified name and argument types. + * Java access modifiers are ignored during this retrieval. No guarantee is made as to whether the field + * returned will be an instance or static field. + *

+ * A global caching mechanism within this class is used to store method. Combined with synchronization, this guarantees that + * no method will be reflectively looked up twice. + *

+ * If a method is deemed suitable for return, {@link Method#setAccessible(boolean) setAccessible} will be invoked with an argument of {@code true} before it is returned. + * This ensures that callers do not have to check or worry about Java access modifiers when dealing with the returned instance. + *

+ * This method does not search superclasses of the specified type for methods with the specified signature. + * Callers wishing this behavior should use {@link Class#getDeclaredMethod(String, Class...)}. + * + * @param clazz The class which contains the method to retrieve. + * @param name The declared name of the method in the class. + * @param args The formal argument types of the method. + * @return A method object with the specified name declared by the specified class. + */ + public synchronized static Method getMethod(Class clazz, String name, Class... args) { + if (!_loadedMethods.containsKey(clazz)) { + _loadedMethods.put(clazz, new HashMap>, Method>>()); + } - Map>, Method>> loadedMethodNames = _loadedMethods.get(clazz); - if (!loadedMethodNames.containsKey(name)) { - loadedMethodNames.put(name, new HashMap>, Method>()); - } + Map>, Method>> loadedMethodNames = _loadedMethods.get(clazz); + if (!loadedMethodNames.containsKey(name)) { + loadedMethodNames.put(name, new HashMap>, Method>()); + } - Map>, Method> loadedSignatures = loadedMethodNames.get(name); - ArrayWrapper> wrappedArg = new ArrayWrapper<>(args); - if (loadedSignatures.containsKey(wrappedArg)) { - return loadedSignatures.get(wrappedArg); - } + Map>, Method> loadedSignatures = loadedMethodNames.get(name); + ArrayWrapper> wrappedArg = new ArrayWrapper<>(args); + if (loadedSignatures.containsKey(wrappedArg)) { + return loadedSignatures.get(wrappedArg); + } - for (Method m : clazz.getMethods()) { - if (m.getName().equals(name) && Arrays.equals(args, m.getParameterTypes())) { - m.setAccessible(true); - loadedSignatures.put(wrappedArg, m); - return m; - } - } - loadedSignatures.put(wrappedArg, null); - return null; - } + for (Method m : clazz.getMethods()) { + if (m.getName().equals(name) && Arrays.equals(args, m.getParameterTypes())) { + m.setAccessible(true); + loadedSignatures.put(wrappedArg, m); + return m; + } + } + loadedSignatures.put(wrappedArg, null); + return null; + } } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/object/entity/EntityWrapper.java b/Bukkit/src/main/java/com/plotsquared/bukkit/object/entity/EntityWrapper.java index 22c0230a9..33dc737ab 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/object/entity/EntityWrapper.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/object/entity/EntityWrapper.java @@ -1,6 +1,7 @@ package com.plotsquared.bukkit.object.entity; import com.intellectualcrafters.plot.PS; +import com.plotsquared.bukkit.util.BukkitVersion; import org.bukkit.Art; import org.bukkit.DyeColor; import org.bukkit.Location; @@ -86,7 +87,7 @@ public class EntityWrapper { if (depth == 1) { return; } - if (PS.get().checkVersion(PS.get().IMP.getServerVersion(), 1, 10, 0) || entity instanceof ArmorStand) { + if (PS.get().checkVersion(PS.get().IMP.getServerVersion(), BukkitVersion.v1_10_0) || entity instanceof ArmorStand) { if (!entity.hasGravity()) { this.noGravity = true; } @@ -94,7 +95,7 @@ public class EntityWrapper { switch (entity.getType()) { case ARROW: case BOAT: - if (PS.get().checkVersion(PS.get().IMP.getServerVersion(), 1, 9, 0)) { + if (PS.get().checkVersion(PS.get().IMP.getServerVersion(), BukkitVersion.v1_9_0)) { Boat boat = (Boat) entity; this.dataByte = getOrdinal(TreeSpecies.values(), boat.getWoodType()); } @@ -353,7 +354,7 @@ public class EntityWrapper { void restoreEquipment(LivingEntity entity) { EntityEquipment equipment = entity.getEquipment(); - if (PS.get().checkVersion(PS.get().IMP.getServerVersion(), 1, 9, 0)) { + if (PS.get().checkVersion(PS.get().IMP.getServerVersion(), BukkitVersion.v1_9_0)) { equipment.setItemInMainHand(this.lived.mainHand); equipment.setItemInOffHand(this.lived.offHand); } else { @@ -397,7 +398,7 @@ public class EntityWrapper { } void storeEquipment(EntityEquipment equipment) { - if (PS.get().checkVersion(PS.get().IMP.getServerVersion(), 1, 9, 0)) { + if (PS.get().checkVersion(PS.get().IMP.getServerVersion(), BukkitVersion.v1_9_0)) { this.lived.mainHand = equipment.getItemInMainHand().clone(); this.lived.offHand = equipment.getItemInOffHand().clone(); } else { @@ -487,7 +488,7 @@ public class EntityWrapper { if (this.depth == 1) { return entity; } - if (PS.get().checkVersion(PS.get().IMP.getServerVersion(), 1, 10, 0) || entity instanceof ArmorStand) { + if (PS.get().checkVersion(PS.get().IMP.getServerVersion(), BukkitVersion.v1_10_0) || entity instanceof ArmorStand) { if (this.noGravity) { entity.setGravity(false); } @@ -495,7 +496,7 @@ public class EntityWrapper { switch (entity.getType()) { case ARROW: case BOAT: - if (PS.get().checkVersion(PS.get().IMP.getServerVersion(), 1, 9, 0)) { + if (PS.get().checkVersion(PS.get().IMP.getServerVersion(), BukkitVersion.v1_9_0)) { Boat boat = (Boat) entity; boat.setWoodType(TreeSpecies.values()[dataByte]); } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitHybridUtils.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitHybridUtils.java index c3f2dd26c..1cfa93040 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitHybridUtils.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitHybridUtils.java @@ -12,8 +12,6 @@ import com.intellectualcrafters.plot.util.TaskManager; import com.intellectualcrafters.plot.util.block.GlobalBlockQueue; import com.intellectualcrafters.plot.util.block.LocalBlockQueue; import com.intellectualcrafters.plot.util.expiry.PlotAnalysis; -import java.util.HashSet; -import java.util.Random; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.World; @@ -23,6 +21,9 @@ import org.bukkit.generator.ChunkGenerator.BiomeGrid; import org.bukkit.material.Directional; import org.bukkit.material.MaterialData; +import java.util.HashSet; +import java.util.Random; + public class BukkitHybridUtils extends HybridUtils { @Override @@ -50,7 +51,8 @@ public class BukkitHybridUtils extends HybridUtils { } final BiomeGrid nullBiomeGrid = new BiomeGrid() { @Override - public void setBiome(int a, int b, Biome c) {} + public void setBiome(int a, int b, Biome c) { + } @Override public Biome getBiome(int a, int b) { diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitVersion.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitVersion.java new file mode 100644 index 000000000..bb40266d3 --- /dev/null +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitVersion.java @@ -0,0 +1,13 @@ +package com.plotsquared.bukkit.util; + +public class BukkitVersion { + public static int[] v1_10_2 = {1, 10, 2}; + public static int[] v1_10_0 = {1, 10, 0}; + public static int[] v1_9_4 = {1, 9, 4}; + public static int[] v1_9_0 = {1, 9, 0}; + public static int[] v1_8_3 = {1, 8, 3}; + public static int[] v1_8_0 = {1, 8, 0}; + public static int[] v1_7_6 = {1, 7, 6}; + public static int[] v1_7_0 = {1, 7, 0}; + public static int[] v1_6_0 = {1, 6, 0}; +} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/NbtFactory.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/NbtFactory.java index ea4838bac..8bad6ef4d 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/NbtFactory.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/NbtFactory.java @@ -8,7 +8,6 @@ import com.google.common.collect.MapMaker; import com.google.common.io.ByteSink; import com.google.common.io.ByteSource; import com.google.common.io.Closeables; -import com.google.common.io.Files; import com.google.common.primitives.Primitives; import org.bukkit.Bukkit; import org.bukkit.Material; @@ -20,7 +19,6 @@ import java.io.DataInput; import java.io.DataInputStream; import java.io.DataOutput; import java.io.DataOutputStream; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -161,7 +159,6 @@ public class NbtFactory { /** * Load the content of a file from a stream. * - * Use {@link Files#newInputStreamSupplier(File)} to provide a stream from a file. * @param stream - the stream supplier. * @param option - whether or not to decompress the input stream. * @return The decoded NBT compound. @@ -196,7 +193,6 @@ public class NbtFactory { /** * Save the content of a NBT compound to a stream. * - * Use {@link Files#newOutputStreamSupplier(File)} to provide a stream supplier to a file. * @param source - the NBT compound to save. * @param stream - the stream. * @param option - whether or not to compress the output. @@ -445,8 +441,7 @@ public class NbtFactory { /** * Convert a given NBT element to a primitive wrapper or List/Map equivalent. - *

- * All changes to any mutable objects will be reflected in the underlying NBT element(s). + *

All changes to any mutable objects will be reflected in the underlying NBT element(s). * @param nms - the NBT element. * @return The wrapper equivalent. */ @@ -605,7 +600,7 @@ public class NbtFactory { */ private static class LoadMethodWorldUpdate extends LoadCompoundMethod { - public LoadMethodWorldUpdate(Class streamClass) { + LoadMethodWorldUpdate(Class streamClass) { setMethod(getMethod(Modifier.STATIC, 0, streamClass, null, DataInput.class)); } @@ -622,7 +617,7 @@ public class NbtFactory { private Object readLimiter; - public LoadMethodSkinUpdate(Class streamClass, Class readLimiterClass) { + LoadMethodSkinUpdate(Class streamClass, Class readLimiterClass) { setMethod(getMethod(Modifier.STATIC, 0, streamClass, null, DataInput.class, readLimiterClass)); // Find the unlimited read limiter @@ -645,8 +640,7 @@ public class NbtFactory { /** * Represents a root NBT compound. - *

- * All changes to this map will be reflected in the underlying NBT compound. Values may only be one of the following: + *

All changes to this map will be reflected in the underlying NBT compound. Values may only be one of the following: *

    *
  • Primitive types
  • *
  • {@link String String}
  • @@ -769,8 +763,6 @@ public class NbtFactory { /** * Save the content of a NBT compound to a stream. - *

    - * Use {@link Files#newOutputStreamSupplier(File)} to provide a stream supplier to a file. * @param stream - the output stream. * @param option - whether or not to compress the output. * @throws IOException If anything went wrong. diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/SendChunk.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/SendChunk.java index 9fd272e3d..0ed341469 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/SendChunk.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/SendChunk.java @@ -50,7 +50,7 @@ public class SendChunk { RefClass classChunk = getRefClass("{nms}.Chunk"); this.methodInitLighting = classChunk.getMethod("initLighting"); RefClass classMapChunk = getRefClass("{nms}.PacketPlayOutMapChunk"); - if (PS.get().checkVersion(PS.get().IMP.getServerVersion(), 1, 9, 4)) { + if (PS.get().checkVersion(PS.get().IMP.getServerVersion(), BukkitVersion.v1_9_4)) { //this works for 1.9.4 and 1.10 tempMapChunk = classMapChunk.getConstructor(classChunk.getRealClass(),int.class); } else { @@ -116,7 +116,7 @@ public class SendChunk { chunks.remove(chunk); Object con = this.connection.of(entity).get(); Object packet = null; - if (PS.get().checkVersion(PS.get().IMP.getServerVersion(), 1, 9, 4)) { + if (PS.get().checkVersion(PS.get().IMP.getServerVersion(), BukkitVersion.v1_9_4)) { try { packet = this.mapChunk.create(c,65535); } catch (Exception ignored) {} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/block/BukkitLocalQueue_1_8_3.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/block/BukkitLocalQueue_1_8_3.java index 342d289c8..bf829c074 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/block/BukkitLocalQueue_1_8_3.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/block/BukkitLocalQueue_1_8_3.java @@ -1,5 +1,7 @@ package com.plotsquared.bukkit.util.block; +import static com.intellectualcrafters.plot.util.ReflectionUtils.getRefClass; + import com.intellectualcrafters.plot.object.ChunkLoc; import com.intellectualcrafters.plot.object.ChunkWrapper; import com.intellectualcrafters.plot.object.PseudoRandom; @@ -9,6 +11,11 @@ import com.intellectualcrafters.plot.util.ReflectionUtils; import com.intellectualcrafters.plot.util.TaskManager; import com.intellectualcrafters.plot.util.block.BasicLocalBlockQueue; import com.plotsquared.bukkit.util.SendChunk; +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.Material; +import org.bukkit.World; + import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; @@ -18,13 +25,6 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; -import org.bukkit.Bukkit; -import org.bukkit.Chunk; -import org.bukkit.Material; -import org.bukkit.World; - - -import static com.intellectualcrafters.plot.util.ReflectionUtils.getRefClass; public class BukkitLocalQueue_1_8_3 extends BukkitLocalQueue { @@ -403,11 +403,11 @@ public class BukkitLocalQueue_1_8_3 extends BukkitLocalQueue { } } } -/* + /* if (!(boolean) methodAreNeighborsLoaded.of(c).call(1)) { return false; } -*/ + */ } this.methodInitLighting.of(c).call(); diff --git a/Core/src/main/java/com/intellectualcrafters/configuration/MemoryConfiguration.java b/Core/src/main/java/com/intellectualcrafters/configuration/MemoryConfiguration.java index 4148ac9ce..7d1a5721a 100644 --- a/Core/src/main/java/com/intellectualcrafters/configuration/MemoryConfiguration.java +++ b/Core/src/main/java/com/intellectualcrafters/configuration/MemoryConfiguration.java @@ -29,9 +29,6 @@ public class MemoryConfiguration extends MemorySection implements Configuration @Override public void addDefault(String path, Object value) { - if (path == null) { - throw new NullPointerException("Path may not be null"); - } if (this.defaults == null) { this.defaults = new MemoryConfiguration(); } @@ -41,10 +38,6 @@ public class MemoryConfiguration extends MemorySection implements Configuration @Override public void addDefaults(Map defaults) { - if (defaults == null) { - throw new NullPointerException("Defaults may not be null"); - } - for (Map.Entry entry : defaults.entrySet()) { addDefault(entry.getKey(), entry.getValue()); } @@ -52,10 +45,6 @@ public class MemoryConfiguration extends MemorySection implements Configuration @Override public void addDefaults(Configuration defaults) { - if (defaults == null) { - throw new NullPointerException("Defaults may not be null"); - } - addDefaults(defaults.getValues(true)); } diff --git a/Core/src/main/java/com/intellectualcrafters/configuration/MemorySection.java b/Core/src/main/java/com/intellectualcrafters/configuration/MemorySection.java index d2e0aafa3..86fd77acd 100644 --- a/Core/src/main/java/com/intellectualcrafters/configuration/MemorySection.java +++ b/Core/src/main/java/com/intellectualcrafters/configuration/MemorySection.java @@ -49,13 +49,6 @@ public class MemorySection implements ConfigurationSection { * if parent contains no root Configuration. */ protected MemorySection(ConfigurationSection parent, String path) { - if (parent == null) { - throw new NullPointerException("Parent may not be null"); - } - if (path == null) { - throw new NullPointerException("Path may not be null"); - } - this.path = path; this.parent = parent; this.root = parent.getRoot(); @@ -133,7 +126,7 @@ public class MemorySection implements ConfigurationSection { * @return Full path of the section from its root. */ public static String createPath(ConfigurationSection section, String key) { - return createPath(section, key, (section == null) ? null : section.getRoot()); + return createPath(section, key, section.getRoot()); } /** @@ -149,9 +142,6 @@ public class MemorySection implements ConfigurationSection { * @return Full path of the section from its root. */ public static String createPath(ConfigurationSection section, String key, ConfigurationSection relativeTo) { - if (section == null) { - throw new NullPointerException("Cannot create path without a section"); - } Configuration root = section.getRoot(); if (root == null) { throw new IllegalStateException("Cannot create path without a root"); @@ -253,10 +243,6 @@ public class MemorySection implements ConfigurationSection { @Override public void addDefault(String path, Object value) { - if (path == null) { - throw new NullPointerException("Path cannot be null"); - } - Configuration root = getRoot(); if (root == null) { throw new IllegalStateException("Cannot add default without root"); @@ -283,10 +269,6 @@ public class MemorySection implements ConfigurationSection { @Override public void set(String path, Object value) { - if (path == null) { - throw new NullPointerException("Cannot set to an empty path"); - } - Configuration root = getRoot(); if (root == null) { throw new IllegalStateException("Cannot use section without a root"); @@ -367,9 +349,6 @@ public class MemorySection implements ConfigurationSection { @Override public ConfigurationSection createSection(String path) { - if (path == null) { - throw new NullPointerException("Cannot create section at empty path"); - } Configuration root = getRoot(); if (root == null) { throw new IllegalStateException("Cannot create section without a root"); @@ -787,10 +766,6 @@ public class MemorySection implements ConfigurationSection { } protected Object getDefault(String path) { - if (path == null) { - throw new NullPointerException("Path may not be null"); - } - Configuration root = getRoot(); Configuration defaults = root == null ? null : root.getDefaults(); return (defaults == null) ? null : defaults.get(createPath(this, path)); diff --git a/Core/src/main/java/com/intellectualcrafters/configuration/file/FileConfiguration.java b/Core/src/main/java/com/intellectualcrafters/configuration/file/FileConfiguration.java index ff132d4f5..4989f0084 100644 --- a/Core/src/main/java/com/intellectualcrafters/configuration/file/FileConfiguration.java +++ b/Core/src/main/java/com/intellectualcrafters/configuration/file/FileConfiguration.java @@ -87,9 +87,6 @@ public abstract class FileConfiguration extends MemoryConfiguration { * @throws IllegalArgumentException Thrown when file is null. */ public void load(File file) throws IOException, InvalidConfigurationException { - if (file == null) { - throw new NullPointerException("File cannot be null"); - } FileInputStream stream = new FileInputStream(file); @@ -123,33 +120,7 @@ public abstract class FileConfiguration extends MemoryConfiguration { loadFromString(builder.toString()); } - - /** - * Loads this {@link FileConfiguration} from the specified location. - * - *

    All the values contained within this configuration will be removed, - * leaving only settings and defaults, and the new values will be loaded - * from the given file. - * - *

    If the file cannot be loaded for any reason, an exception will be - * thrown. - * - * @param file File to load from. - * @throws FileNotFoundException Thrown when the given file cannot be - * opened. - * @throws IOException Thrown when the given file cannot be read. - * @throws InvalidConfigurationException Thrown when the given file is not - * a valid Configuration. - * @throws IllegalArgumentException Thrown when file is null. - */ - public void load(String file) throws IOException, InvalidConfigurationException { - if (file == null) { - throw new NullPointerException("File cannot be null"); - } - - load(new File(file)); - } - + /** * Loads this {@link FileConfiguration} from the specified string, as * opposed to from file. diff --git a/Core/src/main/java/com/intellectualcrafters/configuration/file/YamlConfiguration.java b/Core/src/main/java/com/intellectualcrafters/configuration/file/YamlConfiguration.java index 418a9dc75..ae158f938 100644 --- a/Core/src/main/java/com/intellectualcrafters/configuration/file/YamlConfiguration.java +++ b/Core/src/main/java/com/intellectualcrafters/configuration/file/YamlConfiguration.java @@ -11,7 +11,6 @@ import org.yaml.snakeyaml.representer.Representer; import java.io.File; import java.io.IOException; -import java.io.Reader; import java.nio.file.Files; import java.nio.file.StandardCopyOption; import java.util.Map; @@ -38,13 +37,8 @@ public class YamlConfiguration extends FileConfiguration { * * @param file Input file * @return Resulting configuration - * @throws IllegalArgumentException Thrown if file is null */ public static YamlConfiguration loadConfiguration(File file) { - if (file == null) { - throw new NullPointerException("File cannot be null"); - } - YamlConfiguration config = new YamlConfiguration(); try { @@ -70,34 +64,6 @@ public class YamlConfiguration extends FileConfiguration { return config; } - /** - * Creates a new {@link YamlConfiguration}, loading from the given reader. - * - *

    Any errors loading the Configuration will be logged and then ignored. - * If the specified input is not a valid config, a blank config will be - * returned. - * - * @param reader input - * @return resulting configuration - * @throws IllegalArgumentException Thrown if stream is null - */ - public static YamlConfiguration loadConfiguration(Reader reader) { - if (reader == null) { - throw new NullPointerException("Reader cannot be null"); - } - - YamlConfiguration config = new YamlConfiguration(); - - try { - config.load(reader); - } catch (IOException | InvalidConfigurationException ex) { - PS.debug("Cannot load configuration from stream"); - ex.printStackTrace(); - } - - return config; - } - @Override public String saveToString() { yamlOptions.setIndent(options().indent()); @@ -116,9 +82,6 @@ public class YamlConfiguration extends FileConfiguration { @Override public void loadFromString(String contents) throws InvalidConfigurationException { - if (contents == null) { - throw new NullPointerException("Contents cannot be null"); - } Map input; try { diff --git a/Core/src/main/java/com/intellectualcrafters/plot/flag/TeleportDenyFlag.java b/Core/src/main/java/com/intellectualcrafters/plot/flag/TeleportDenyFlag.java index a991968d5..bad35e966 100644 --- a/Core/src/main/java/com/intellectualcrafters/plot/flag/TeleportDenyFlag.java +++ b/Core/src/main/java/com/intellectualcrafters/plot/flag/TeleportDenyFlag.java @@ -19,16 +19,16 @@ public class TeleportDenyFlag extends EnumFlag { result = !plot.getTrusted().contains(player.getUUID()); break; case "members": - result =!plot.getMembers().contains(player.getUUID()); + result = !plot.getMembers().contains(player.getUUID()); break; case "nonmembers": - result =!plot.isAdded(player.getUUID()); + result = !plot.isAdded(player.getUUID()); break; case "nontrusted": - result =!plot.getTrusted().contains(player.getUUID()) && !plot.isOwner(player.getUUID()); + result = !plot.getTrusted().contains(player.getUUID()) && !plot.isOwner(player.getUUID()); break; case "nonowners": - result =!plot.isOwner(player.getUUID()); + result = !plot.isOwner(player.getUUID()); break; default: return true; diff --git a/Core/src/main/java/com/intellectualcrafters/plot/object/comment/CommentInbox.java b/Core/src/main/java/com/intellectualcrafters/plot/object/comment/CommentInbox.java index cd4353299..61d047b47 100644 --- a/Core/src/main/java/com/intellectualcrafters/plot/object/comment/CommentInbox.java +++ b/Core/src/main/java/com/intellectualcrafters/plot/object/comment/CommentInbox.java @@ -4,6 +4,7 @@ import com.intellectualcrafters.plot.database.DBFunc; import com.intellectualcrafters.plot.object.Plot; import com.intellectualcrafters.plot.object.PlotPlayer; import com.intellectualcrafters.plot.object.RunnableVal; +import com.intellectualcrafters.plot.util.Permissions; import java.util.List; @@ -12,11 +13,31 @@ public abstract class CommentInbox { @Override public abstract String toString(); - public abstract boolean canRead(Plot plot, PlotPlayer player); + public boolean canRead(Plot plot, PlotPlayer player) { + if (Permissions.hasPermission(player, "plots.inbox.read." + toString())) { + if (plot.isOwner(player.getUUID()) || Permissions.hasPermission(player, "plots.inbox.read." + toString() + ".other")) { + return true; + } + } + return false; + } - public abstract boolean canWrite(Plot plot, PlotPlayer player); + public boolean canWrite(Plot plot, PlotPlayer player) { + if (plot == null) { + return Permissions.hasPermission(player, "plots.inbox.write." + toString()); + } + return Permissions.hasPermission(player, "plots.inbox.write." + toString()) && (plot.isOwner(player.getUUID()) || Permissions + .hasPermission(player, "plots.inbox.write." + toString() + ".other")); + } - public abstract boolean canModify(Plot plot, PlotPlayer player); + public boolean canModify(Plot plot, PlotPlayer player) { + if (Permissions.hasPermission(player, "plots.inbox.modify." + toString())) { + if (plot.isOwner(player.getUUID()) || Permissions.hasPermission(player, "plots.inbox.modify." + toString() + ".other")) { + return true; + } + } + return false; + } /** * diff --git a/Core/src/main/java/com/intellectualcrafters/plot/object/comment/InboxOwner.java b/Core/src/main/java/com/intellectualcrafters/plot/object/comment/InboxOwner.java index 08c6d7c1c..422bf539b 100644 --- a/Core/src/main/java/com/intellectualcrafters/plot/object/comment/InboxOwner.java +++ b/Core/src/main/java/com/intellectualcrafters/plot/object/comment/InboxOwner.java @@ -3,9 +3,7 @@ package com.intellectualcrafters.plot.object.comment; import com.google.common.base.Optional; import com.intellectualcrafters.plot.database.DBFunc; import com.intellectualcrafters.plot.object.Plot; -import com.intellectualcrafters.plot.object.PlotPlayer; import com.intellectualcrafters.plot.object.RunnableVal; -import com.intellectualcrafters.plot.util.Permissions; import com.intellectualcrafters.plot.util.TaskManager; import java.util.ArrayList; @@ -13,35 +11,6 @@ import java.util.List; public class InboxOwner extends CommentInbox { - @Override - public boolean canRead(Plot plot, PlotPlayer player) { - if (Permissions.hasPermission(player, "plots.inbox.read." + toString())) { - if (plot.isOwner(player.getUUID()) || Permissions.hasPermission(player, "plots.inbox.read." + toString() + ".other")) { - return true; - } - } - return false; - } - - @Override - public boolean canWrite(Plot plot, PlotPlayer player) { - if (plot == null) { - return Permissions.hasPermission(player, "plots.inbox.write." + toString()); - } - return Permissions.hasPermission(player, "plots.inbox.write." + toString()) && (plot.isOwner(player.getUUID()) || Permissions - .hasPermission(player, "plots.inbox.write." + toString() + ".other")); - } - - @Override - public boolean canModify(Plot plot, PlotPlayer player) { - if (Permissions.hasPermission(player, "plots.inbox.modify." + toString())) { - if (plot.isOwner(player.getUUID()) || Permissions.hasPermission(player, "plots.inbox.modify." + toString() + ".other")) { - return true; - } - } - return false; - } - @Override public boolean getComments(final Plot plot, final RunnableVal> whenDone) { Optional> comments = plot.getSettings().getComments(toString()); diff --git a/Core/src/main/java/com/intellectualcrafters/plot/object/comment/InboxPublic.java b/Core/src/main/java/com/intellectualcrafters/plot/object/comment/InboxPublic.java index 0d2fffd70..45de62e44 100644 --- a/Core/src/main/java/com/intellectualcrafters/plot/object/comment/InboxPublic.java +++ b/Core/src/main/java/com/intellectualcrafters/plot/object/comment/InboxPublic.java @@ -3,45 +3,14 @@ package com.intellectualcrafters.plot.object.comment; import com.google.common.base.Optional; import com.intellectualcrafters.plot.database.DBFunc; import com.intellectualcrafters.plot.object.Plot; -import com.intellectualcrafters.plot.object.PlotPlayer; import com.intellectualcrafters.plot.object.RunnableVal; -import com.intellectualcrafters.plot.util.Permissions; import com.intellectualcrafters.plot.util.TaskManager; import java.util.ArrayList; import java.util.List; public class InboxPublic extends CommentInbox { - - @Override - public boolean canRead(Plot plot, PlotPlayer player) { - if (Permissions.hasPermission(player, "plots.inbox.read." + toString())) { - if (plot.isOwner(player.getUUID()) || Permissions.hasPermission(player, "plots.inbox.read." + toString() + ".other")) { - return true; - } - } - return false; - } - - @Override - public boolean canWrite(Plot plot, PlotPlayer player) { - if (plot == null) { - return Permissions.hasPermission(player, "plots.inbox.write." + toString()); - } - return Permissions.hasPermission(player, "plots.inbox.write." + toString()) && (plot.isOwner(player.getUUID()) || Permissions - .hasPermission(player, "plots.inbox.write." + toString() + ".other")); - } - - @Override - public boolean canModify(Plot plot, PlotPlayer player) { - if (Permissions.hasPermission(player, "plots.inbox.modify." + toString())) { - if (plot.isOwner(player.getUUID()) || Permissions.hasPermission(player, "plots.inbox.modify." + toString() + ".other")) { - return true; - } - } - return false; - } - + @Override public boolean getComments(final Plot plot, final RunnableVal> whenDone) { Optional> comments = plot.getSettings().getComments(toString()); diff --git a/Core/src/main/java/com/intellectualcrafters/plot/object/comment/InboxReport.java b/Core/src/main/java/com/intellectualcrafters/plot/object/comment/InboxReport.java index f320e632e..16d4a8f73 100644 --- a/Core/src/main/java/com/intellectualcrafters/plot/object/comment/InboxReport.java +++ b/Core/src/main/java/com/intellectualcrafters/plot/object/comment/InboxReport.java @@ -2,45 +2,13 @@ package com.intellectualcrafters.plot.object.comment; import com.intellectualcrafters.plot.database.DBFunc; import com.intellectualcrafters.plot.object.Plot; -import com.intellectualcrafters.plot.object.PlotPlayer; import com.intellectualcrafters.plot.object.RunnableVal; -import com.intellectualcrafters.plot.util.Permissions; import com.intellectualcrafters.plot.util.TaskManager; import java.util.List; public class InboxReport extends CommentInbox { - @Override - public boolean canRead(Plot plot, PlotPlayer player) { - if (Permissions.hasPermission(player, "plots.inbox.read." + toString())) { - if (plot.isOwner(player.getUUID()) || Permissions - .hasPermission(player, "plots.inbox.read." + toString() + ".other")) { - return true; - } - } - return false; - } - - @Override - public boolean canWrite(Plot plot, PlotPlayer player) { - if (plot == null) { - return Permissions.hasPermission(player, "plots.inbox.write." + toString()); - } - return Permissions.hasPermission(player, "plots.inbox.write." + toString()) && (plot.isOwner(player.getUUID()) || Permissions - .hasPermission(player, "plots.inbox.write." + toString() + ".other")); - } - - @Override - public boolean canModify(Plot plot, PlotPlayer player) { - if (Permissions.hasPermission(player, "plots.inbox.modify." + toString())) { - if (plot.isOwner(player.getUUID()) || Permissions.hasPermission(player, "plots.inbox.modify." + toString() + ".other")) { - return true; - } - } - return false; - } - @Override public boolean getComments(Plot plot, final RunnableVal> whenDone) { DBFunc.getComments(null, toString(), new RunnableVal>() {