diff --git a/modules/API/src/main/java/com/comphenix/protocol/AsynchronousManager.java b/modules/API/src/main/java/com/comphenix/protocol/AsynchronousManager.java index 907590b2..3d3cc260 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/AsynchronousManager.java +++ b/modules/API/src/main/java/com/comphenix/protocol/AsynchronousManager.java @@ -152,4 +152,4 @@ public interface AsynchronousManager { * @return Set of every asynchronous packet listener. */ public abstract Set getAsyncHandlers(); -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/PacketType.java b/modules/API/src/main/java/com/comphenix/protocol/PacketType.java index 2e4cccc7..7fbf7303 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/PacketType.java +++ b/modules/API/src/main/java/com/comphenix/protocol/PacketType.java @@ -1082,4 +1082,4 @@ public class PacketType implements Serializable, Comparable { else return clazz.getSimpleName() + "[" + currentId + ", legacy: " + legacyId + "]"; } -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/ProtocolConfig.java b/modules/API/src/main/java/com/comphenix/protocol/ProtocolConfig.java index 63374007..f0854da4 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/ProtocolConfig.java +++ b/modules/API/src/main/java/com/comphenix/protocol/ProtocolConfig.java @@ -1,500 +1,500 @@ -/** - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2012 Kristian S. Stangeland - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ -package com.comphenix.protocol; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import org.bukkit.configuration.Configuration; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.plugin.Plugin; - -import com.comphenix.protocol.injector.PlayerInjectHooks; -import com.google.common.base.Charsets; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; -import com.google.common.io.Files; - -/** - * Represents the configuration of ProtocolLib. - * - * @author Kristian - */ -public class ProtocolConfig { - private static final String LAST_UPDATE_FILE = "lastupdate"; - - private static final String SECTION_GLOBAL = "global"; - private static final String SECTION_AUTOUPDATER = "auto updater"; - - private static final String METRICS_ENABLED = "metrics"; - - private static final String IGNORE_VERSION_CHECK = "ignore version check"; - private static final String BACKGROUND_COMPILER_ENABLED = "background compiler"; - - private static final String DEBUG_MODE_ENABLED = "debug"; - private static final String DETAILED_ERROR = "detailed error"; - private static final String INJECTION_METHOD = "injection method"; - - private static final String SCRIPT_ENGINE_NAME = "script engine"; - private static final String SUPPRESSED_REPORTS = "suppressed reports"; - - private static final String UPDATER_NOTIFY = "notify"; - private static final String UPDATER_DOWNLAD = "download"; - private static final String UPDATER_DELAY = "delay"; - - // Defaults - private static final long DEFAULT_UPDATER_DELAY = 43200; - - private Plugin plugin; - private Configuration config; - private boolean loadingSections; - - private ConfigurationSection global; - private ConfigurationSection updater; - - // Last update time - private long lastUpdateTime; - private boolean configChanged; - private boolean valuesChanged; - - // Modifications - private int modCount; - - public ProtocolConfig(Plugin plugin) { - this.plugin = plugin; - reloadConfig(); - } - - /** - * Reload configuration file. - */ - public void reloadConfig() { - // Reset - configChanged = false; - valuesChanged = false; - modCount++; - - this.config = plugin.getConfig(); - this.lastUpdateTime = loadLastUpdate(); - loadSections(!loadingSections); - } - - /** - * Load the last update time stamp from the file system. - * - * @return Last update time stamp. - */ - private long loadLastUpdate() { - File dataFile = getLastUpdateFile(); - - if (dataFile.exists()) { - try { - return Long.parseLong(Files.toString(dataFile, Charsets.UTF_8)); - } catch (NumberFormatException e) { - plugin.getLogger().warning("Cannot parse " + dataFile + " as a number."); - } catch (IOException e) { - plugin.getLogger().warning("Cannot read " + dataFile); - } - } - // Default last update - return 0; - } - - /** - * Store the given time stamp. - * - * @param value - time stamp to store. - */ - private void saveLastUpdate(long value) { - File dataFile = getLastUpdateFile(); - - // The data folder must exist - dataFile.getParentFile().mkdirs(); - - if (dataFile.exists()) - dataFile.delete(); - - try { - Files.write(Long.toString(value), dataFile, Charsets.UTF_8); - } catch (IOException e) { - throw new RuntimeException("Cannot write " + dataFile, e); - } - } - - /** - * Retrieve the file that is used to store the update time stamp. - * - * @return File storing the update time stamp. - */ - private File getLastUpdateFile() { - return new File(plugin.getDataFolder(), LAST_UPDATE_FILE); - } - - /** - * Load data sections. - * - * @param copyDefaults - whether or not to copy configuration defaults. - */ - private void loadSections(boolean copyDefaults) { - if (config != null) { - global = config.getConfigurationSection(SECTION_GLOBAL); - } - if (global != null) { - updater = global.getConfigurationSection(SECTION_AUTOUPDATER); - } - - // Automatically copy defaults - if (copyDefaults && (!getFile().exists() || global == null || updater == null)) { - loadingSections = true; - - if (config != null) - config.options().copyDefaults(true); - plugin.saveDefaultConfig(); - plugin.reloadConfig(); - loadingSections = false; - - // Inform the user - plugin.getLogger().info("Created default configuration."); - } - } - - /** - * Set a particular configuration key value pair. - * - * @param section - the configuration root. - * @param path - the path to the key. - * @param value - the value to set. - */ - private void setConfig(ConfigurationSection section, String path, Object value) { - configChanged = true; - section.set(path, value); - } - - @SuppressWarnings("unchecked") - private T getGlobalValue(String path, T def) { - try { - return (T) global.get(path, def); - } catch (Throwable ex) { - return def; - } - } - - @SuppressWarnings("unchecked") - private T getUpdaterValue(String path, T def) { - try { - return (T) updater.get(path, def); - } catch (Throwable ex) { - return def; - } - } - - /** - * Retrieve a reference to the configuration file. - * - * @return Configuration file on disk. - */ - public File getFile() { - return new File(plugin.getDataFolder(), "config.yml"); - } - - /** - * Determine if detailed error reporting is enabled. Default FALSE. - * - * @return TRUE if it is enabled, FALSE otherwise. - */ - public boolean isDetailedErrorReporting() { - return getGlobalValue(DETAILED_ERROR, false); - } - - /** - * Set whether or not detailed error reporting is enabled. - * - * @param value - TRUE if it is enabled, FALSE otherwise. - */ - public void setDetailedErrorReporting(boolean value) { - global.set(DETAILED_ERROR, value); - } - - /** - * Retrieve whether or not ProtocolLib should determine if a new version has been released. - * - * @return TRUE if it should do this automatically, FALSE otherwise. - */ - public boolean isAutoNotify() { - return getUpdaterValue(UPDATER_NOTIFY, true); - } - - /** - * Set whether or not ProtocolLib should determine if a new version has been released. - * - * @param value - TRUE to do this automatically, FALSE otherwise. - */ - public void setAutoNotify(boolean value) { - setConfig(updater, UPDATER_NOTIFY, value); - modCount++; - } - - /** - * Retrieve whether or not ProtocolLib should automatically download the new version. - * - * @return TRUE if it should, FALSE otherwise. - */ - public boolean isAutoDownload() { - return updater != null && getUpdaterValue(UPDATER_DOWNLAD, false); - } - - /** - * Set whether or not ProtocolLib should automatically download the new version. - * - * @param value - TRUE if it should. FALSE otherwise. - */ - public void setAutoDownload(boolean value) { - setConfig(updater, UPDATER_DOWNLAD, value); - modCount++; - } - - /** - * Determine whether or not debug mode is enabled. - *

- * This grants access to the filter command. - * - * @return TRUE if it is, FALSE otherwise. - */ - public boolean isDebug() { - return getGlobalValue(DEBUG_MODE_ENABLED, false); - } - - /** - * Set whether or not debug mode is enabled. - * - * @param value - TRUE if it is enabled, FALSE otherwise. - */ - public void setDebug(boolean value) { - setConfig(global, DEBUG_MODE_ENABLED, value); - modCount++; - } - - /** - * Retrieve an immutable list of every suppressed report type. - * - * @return Every suppressed report type. - */ - public ImmutableList getSuppressedReports() { - return ImmutableList.copyOf(getGlobalValue(SUPPRESSED_REPORTS, new ArrayList())); - } - - /** - * Set the list of suppressed report types, - * - * @param reports - suppressed report types. - */ - public void setSuppressedReports(List reports) { - global.set(SUPPRESSED_REPORTS, Lists.newArrayList(reports)); - modCount++; - } - - /** - * Retrieve the amount of time to wait until checking for a new update. - * - * @return The amount of time to wait. - */ - public long getAutoDelay() { - // Note that the delay must be greater than 59 seconds - return Math.max(getUpdaterValue(UPDATER_DELAY, 0), DEFAULT_UPDATER_DELAY); - } - - /** - * Set the amount of time to wait until checking for a new update. - *

- * This time must be greater than 59 seconds. - * - * @param delaySeconds - the amount of time to wait. - */ - public void setAutoDelay(long delaySeconds) { - // Silently fix the delay - if (delaySeconds < DEFAULT_UPDATER_DELAY) - delaySeconds = DEFAULT_UPDATER_DELAY; - setConfig(updater, UPDATER_DELAY, delaySeconds); - modCount++; - } - - /** - * The version of Minecraft to ignore the built-in safety feature. - * - * @return The version to ignore ProtocolLib's satefy. - */ - public String getIgnoreVersionCheck() { - return getGlobalValue(IGNORE_VERSION_CHECK, ""); - } - - /** - * Sets under which version of Minecraft the version safety feature will be ignored. - *

- * This is useful if a server operator has tested and verified that a version of ProtocolLib works, but doesn't want or can't upgrade to a newer version. - * - * @param ignoreVersion - the version of Minecraft where the satefy will be disabled. - */ - public void setIgnoreVersionCheck(String ignoreVersion) { - setConfig(global, IGNORE_VERSION_CHECK, ignoreVersion); - modCount++; - } - - /** - * Retrieve whether or not metrics is enabled. - * - * @return TRUE if metrics is enabled, FALSE otherwise. - */ - public boolean isMetricsEnabled() { - return getGlobalValue(METRICS_ENABLED, true); - } - - /** - * Set whether or not metrics is enabled. - *

- * This setting will take effect next time ProtocolLib is started. - * - * @param enabled - whether or not metrics is enabled. - */ - public void setMetricsEnabled(boolean enabled) { - setConfig(global, METRICS_ENABLED, enabled); - modCount++; - } - - /** - * Retrieve whether or not the background compiler for structure modifiers is enabled or not. - * - * @return TRUE if it is enabled, FALSE otherwise. - */ - public boolean isBackgroundCompilerEnabled() { - return getGlobalValue(BACKGROUND_COMPILER_ENABLED, true); - } - - /** - * Set whether or not the background compiler for structure modifiers is enabled or not. - *

- * This setting will take effect next time ProtocolLib is started. - * - * @param enabled - TRUE if is enabled/running, FALSE otherwise. - */ - public void setBackgroundCompilerEnabled(boolean enabled) { - setConfig(global, BACKGROUND_COMPILER_ENABLED, enabled); - modCount++; - } - - /** - * Retrieve the last time we updated, in seconds since 1970.01.01 00:00. - * - * @return Last update time. - */ - public long getAutoLastTime() { - return lastUpdateTime; - } - - /** - * Set the last time we updated, in seconds since 1970.01.01 00:00. - *

- * Note that this is not considered to modify the configuration, so the modification count will not be incremented. - * - * @param lastTimeSeconds - new last update time. - */ - public void setAutoLastTime(long lastTimeSeconds) { - this.valuesChanged = true; - this.lastUpdateTime = lastTimeSeconds; - } - - /** - * Retrieve the unique name of the script engine to use for filtering. - * - * @return Script engine to use. - */ - public String getScriptEngineName() { - return getGlobalValue(SCRIPT_ENGINE_NAME, "JavaScript"); - } - - /** - * Set the unique name of the script engine to use for filtering. - *

- * This setting will take effect next time ProtocolLib is started. - * - * @param name - name of the script engine to use. - */ - public void setScriptEngineName(String name) { - setConfig(global, SCRIPT_ENGINE_NAME, name); - modCount++; - } - - /** - * Retrieve the default injection method. - * - * @return Default method. - */ - public PlayerInjectHooks getDefaultMethod() { - return PlayerInjectHooks.NETWORK_SERVER_OBJECT; - } - - /** - * Retrieve the injection method that has been set in the configuration, or use a default value. - * - * @return Injection method to use. - * @throws IllegalArgumentException If the configuration option is malformed. - */ - public PlayerInjectHooks getInjectionMethod() throws IllegalArgumentException { - String text = global.getString(INJECTION_METHOD); - - // Default hook if nothing has been set - PlayerInjectHooks hook = getDefaultMethod(); - - if (text != null) - hook = PlayerInjectHooks.valueOf(text.toUpperCase().replace(" ", "_")); - return hook; - } - - /** - * Set the starting injection method to use. - * - * @return Injection method. - */ - public void setInjectionMethod(PlayerInjectHooks hook) { - setConfig(global, INJECTION_METHOD, hook.name()); - modCount++; - } - - /** - * Retrieve the number of modifications made to this configuration. - * - * @return The number of modifications. - */ - public int getModificationCount() { - return modCount; - } - - /** - * Save the current configuration file. - */ - public void saveAll() { - if (valuesChanged) - saveLastUpdate(lastUpdateTime); - if (configChanged) - plugin.saveConfig(); - - // And we're done - valuesChanged = false; - configChanged = false; - } -} \ No newline at end of file +/** + * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. + * Copyright (C) 2012 Kristian S. Stangeland + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ +package com.comphenix.protocol; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.bukkit.configuration.Configuration; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.plugin.Plugin; + +import com.comphenix.protocol.injector.PlayerInjectHooks; +import com.google.common.base.Charsets; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import com.google.common.io.Files; + +/** + * Represents the configuration of ProtocolLib. + * + * @author Kristian + */ +public class ProtocolConfig { + private static final String LAST_UPDATE_FILE = "lastupdate"; + + private static final String SECTION_GLOBAL = "global"; + private static final String SECTION_AUTOUPDATER = "auto updater"; + + private static final String METRICS_ENABLED = "metrics"; + + private static final String IGNORE_VERSION_CHECK = "ignore version check"; + private static final String BACKGROUND_COMPILER_ENABLED = "background compiler"; + + private static final String DEBUG_MODE_ENABLED = "debug"; + private static final String DETAILED_ERROR = "detailed error"; + private static final String INJECTION_METHOD = "injection method"; + + private static final String SCRIPT_ENGINE_NAME = "script engine"; + private static final String SUPPRESSED_REPORTS = "suppressed reports"; + + private static final String UPDATER_NOTIFY = "notify"; + private static final String UPDATER_DOWNLAD = "download"; + private static final String UPDATER_DELAY = "delay"; + + // Defaults + private static final long DEFAULT_UPDATER_DELAY = 43200; + + private Plugin plugin; + private Configuration config; + private boolean loadingSections; + + private ConfigurationSection global; + private ConfigurationSection updater; + + // Last update time + private long lastUpdateTime; + private boolean configChanged; + private boolean valuesChanged; + + // Modifications + private int modCount; + + public ProtocolConfig(Plugin plugin) { + this.plugin = plugin; + reloadConfig(); + } + + /** + * Reload configuration file. + */ + public void reloadConfig() { + // Reset + configChanged = false; + valuesChanged = false; + modCount++; + + this.config = plugin.getConfig(); + this.lastUpdateTime = loadLastUpdate(); + loadSections(!loadingSections); + } + + /** + * Load the last update time stamp from the file system. + * + * @return Last update time stamp. + */ + private long loadLastUpdate() { + File dataFile = getLastUpdateFile(); + + if (dataFile.exists()) { + try { + return Long.parseLong(Files.toString(dataFile, Charsets.UTF_8)); + } catch (NumberFormatException e) { + plugin.getLogger().warning("Cannot parse " + dataFile + " as a number."); + } catch (IOException e) { + plugin.getLogger().warning("Cannot read " + dataFile); + } + } + // Default last update + return 0; + } + + /** + * Store the given time stamp. + * + * @param value - time stamp to store. + */ + private void saveLastUpdate(long value) { + File dataFile = getLastUpdateFile(); + + // The data folder must exist + dataFile.getParentFile().mkdirs(); + + if (dataFile.exists()) + dataFile.delete(); + + try { + Files.write(Long.toString(value), dataFile, Charsets.UTF_8); + } catch (IOException e) { + throw new RuntimeException("Cannot write " + dataFile, e); + } + } + + /** + * Retrieve the file that is used to store the update time stamp. + * + * @return File storing the update time stamp. + */ + private File getLastUpdateFile() { + return new File(plugin.getDataFolder(), LAST_UPDATE_FILE); + } + + /** + * Load data sections. + * + * @param copyDefaults - whether or not to copy configuration defaults. + */ + private void loadSections(boolean copyDefaults) { + if (config != null) { + global = config.getConfigurationSection(SECTION_GLOBAL); + } + if (global != null) { + updater = global.getConfigurationSection(SECTION_AUTOUPDATER); + } + + // Automatically copy defaults + if (copyDefaults && (!getFile().exists() || global == null || updater == null)) { + loadingSections = true; + + if (config != null) + config.options().copyDefaults(true); + plugin.saveDefaultConfig(); + plugin.reloadConfig(); + loadingSections = false; + + // Inform the user + plugin.getLogger().info("Created default configuration."); + } + } + + /** + * Set a particular configuration key value pair. + * + * @param section - the configuration root. + * @param path - the path to the key. + * @param value - the value to set. + */ + private void setConfig(ConfigurationSection section, String path, Object value) { + configChanged = true; + section.set(path, value); + } + + @SuppressWarnings("unchecked") + private T getGlobalValue(String path, T def) { + try { + return (T) global.get(path, def); + } catch (Throwable ex) { + return def; + } + } + + @SuppressWarnings("unchecked") + private T getUpdaterValue(String path, T def) { + try { + return (T) updater.get(path, def); + } catch (Throwable ex) { + return def; + } + } + + /** + * Retrieve a reference to the configuration file. + * + * @return Configuration file on disk. + */ + public File getFile() { + return new File(plugin.getDataFolder(), "config.yml"); + } + + /** + * Determine if detailed error reporting is enabled. Default FALSE. + * + * @return TRUE if it is enabled, FALSE otherwise. + */ + public boolean isDetailedErrorReporting() { + return getGlobalValue(DETAILED_ERROR, false); + } + + /** + * Set whether or not detailed error reporting is enabled. + * + * @param value - TRUE if it is enabled, FALSE otherwise. + */ + public void setDetailedErrorReporting(boolean value) { + global.set(DETAILED_ERROR, value); + } + + /** + * Retrieve whether or not ProtocolLib should determine if a new version has been released. + * + * @return TRUE if it should do this automatically, FALSE otherwise. + */ + public boolean isAutoNotify() { + return getUpdaterValue(UPDATER_NOTIFY, true); + } + + /** + * Set whether or not ProtocolLib should determine if a new version has been released. + * + * @param value - TRUE to do this automatically, FALSE otherwise. + */ + public void setAutoNotify(boolean value) { + setConfig(updater, UPDATER_NOTIFY, value); + modCount++; + } + + /** + * Retrieve whether or not ProtocolLib should automatically download the new version. + * + * @return TRUE if it should, FALSE otherwise. + */ + public boolean isAutoDownload() { + return updater != null && getUpdaterValue(UPDATER_DOWNLAD, false); + } + + /** + * Set whether or not ProtocolLib should automatically download the new version. + * + * @param value - TRUE if it should. FALSE otherwise. + */ + public void setAutoDownload(boolean value) { + setConfig(updater, UPDATER_DOWNLAD, value); + modCount++; + } + + /** + * Determine whether or not debug mode is enabled. + *

+ * This grants access to the filter command. + * + * @return TRUE if it is, FALSE otherwise. + */ + public boolean isDebug() { + return getGlobalValue(DEBUG_MODE_ENABLED, false); + } + + /** + * Set whether or not debug mode is enabled. + * + * @param value - TRUE if it is enabled, FALSE otherwise. + */ + public void setDebug(boolean value) { + setConfig(global, DEBUG_MODE_ENABLED, value); + modCount++; + } + + /** + * Retrieve an immutable list of every suppressed report type. + * + * @return Every suppressed report type. + */ + public ImmutableList getSuppressedReports() { + return ImmutableList.copyOf(getGlobalValue(SUPPRESSED_REPORTS, new ArrayList())); + } + + /** + * Set the list of suppressed report types, + * + * @param reports - suppressed report types. + */ + public void setSuppressedReports(List reports) { + global.set(SUPPRESSED_REPORTS, Lists.newArrayList(reports)); + modCount++; + } + + /** + * Retrieve the amount of time to wait until checking for a new update. + * + * @return The amount of time to wait. + */ + public long getAutoDelay() { + // Note that the delay must be greater than 59 seconds + return Math.max(getUpdaterValue(UPDATER_DELAY, 0), DEFAULT_UPDATER_DELAY); + } + + /** + * Set the amount of time to wait until checking for a new update. + *

+ * This time must be greater than 59 seconds. + * + * @param delaySeconds - the amount of time to wait. + */ + public void setAutoDelay(long delaySeconds) { + // Silently fix the delay + if (delaySeconds < DEFAULT_UPDATER_DELAY) + delaySeconds = DEFAULT_UPDATER_DELAY; + setConfig(updater, UPDATER_DELAY, delaySeconds); + modCount++; + } + + /** + * The version of Minecraft to ignore the built-in safety feature. + * + * @return The version to ignore ProtocolLib's satefy. + */ + public String getIgnoreVersionCheck() { + return getGlobalValue(IGNORE_VERSION_CHECK, ""); + } + + /** + * Sets under which version of Minecraft the version safety feature will be ignored. + *

+ * This is useful if a server operator has tested and verified that a version of ProtocolLib works, but doesn't want or can't upgrade to a newer version. + * + * @param ignoreVersion - the version of Minecraft where the satefy will be disabled. + */ + public void setIgnoreVersionCheck(String ignoreVersion) { + setConfig(global, IGNORE_VERSION_CHECK, ignoreVersion); + modCount++; + } + + /** + * Retrieve whether or not metrics is enabled. + * + * @return TRUE if metrics is enabled, FALSE otherwise. + */ + public boolean isMetricsEnabled() { + return getGlobalValue(METRICS_ENABLED, true); + } + + /** + * Set whether or not metrics is enabled. + *

+ * This setting will take effect next time ProtocolLib is started. + * + * @param enabled - whether or not metrics is enabled. + */ + public void setMetricsEnabled(boolean enabled) { + setConfig(global, METRICS_ENABLED, enabled); + modCount++; + } + + /** + * Retrieve whether or not the background compiler for structure modifiers is enabled or not. + * + * @return TRUE if it is enabled, FALSE otherwise. + */ + public boolean isBackgroundCompilerEnabled() { + return getGlobalValue(BACKGROUND_COMPILER_ENABLED, true); + } + + /** + * Set whether or not the background compiler for structure modifiers is enabled or not. + *

+ * This setting will take effect next time ProtocolLib is started. + * + * @param enabled - TRUE if is enabled/running, FALSE otherwise. + */ + public void setBackgroundCompilerEnabled(boolean enabled) { + setConfig(global, BACKGROUND_COMPILER_ENABLED, enabled); + modCount++; + } + + /** + * Retrieve the last time we updated, in seconds since 1970.01.01 00:00. + * + * @return Last update time. + */ + public long getAutoLastTime() { + return lastUpdateTime; + } + + /** + * Set the last time we updated, in seconds since 1970.01.01 00:00. + *

+ * Note that this is not considered to modify the configuration, so the modification count will not be incremented. + * + * @param lastTimeSeconds - new last update time. + */ + public void setAutoLastTime(long lastTimeSeconds) { + this.valuesChanged = true; + this.lastUpdateTime = lastTimeSeconds; + } + + /** + * Retrieve the unique name of the script engine to use for filtering. + * + * @return Script engine to use. + */ + public String getScriptEngineName() { + return getGlobalValue(SCRIPT_ENGINE_NAME, "JavaScript"); + } + + /** + * Set the unique name of the script engine to use for filtering. + *

+ * This setting will take effect next time ProtocolLib is started. + * + * @param name - name of the script engine to use. + */ + public void setScriptEngineName(String name) { + setConfig(global, SCRIPT_ENGINE_NAME, name); + modCount++; + } + + /** + * Retrieve the default injection method. + * + * @return Default method. + */ + public PlayerInjectHooks getDefaultMethod() { + return PlayerInjectHooks.NETWORK_SERVER_OBJECT; + } + + /** + * Retrieve the injection method that has been set in the configuration, or use a default value. + * + * @return Injection method to use. + * @throws IllegalArgumentException If the configuration option is malformed. + */ + public PlayerInjectHooks getInjectionMethod() throws IllegalArgumentException { + String text = global.getString(INJECTION_METHOD); + + // Default hook if nothing has been set + PlayerInjectHooks hook = getDefaultMethod(); + + if (text != null) + hook = PlayerInjectHooks.valueOf(text.toUpperCase().replace(" ", "_")); + return hook; + } + + /** + * Set the starting injection method to use. + * + * @return Injection method. + */ + public void setInjectionMethod(PlayerInjectHooks hook) { + setConfig(global, INJECTION_METHOD, hook.name()); + modCount++; + } + + /** + * Retrieve the number of modifications made to this configuration. + * + * @return The number of modifications. + */ + public int getModificationCount() { + return modCount; + } + + /** + * Save the current configuration file. + */ + public void saveAll() { + if (valuesChanged) + saveLastUpdate(lastUpdateTime); + if (configChanged) + plugin.saveConfig(); + + // And we're done + valuesChanged = false; + configChanged = false; + } +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/ProtocolLibrary.java b/modules/API/src/main/java/com/comphenix/protocol/ProtocolLibrary.java index d080d56c..f19a6d1c 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/ProtocolLibrary.java +++ b/modules/API/src/main/java/com/comphenix/protocol/ProtocolLibrary.java @@ -1,144 +1,144 @@ -/** - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2016 dmulloy2 - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ -package com.comphenix.protocol; - -import java.util.Arrays; -import java.util.List; - -import org.apache.commons.lang.Validate; -import org.bukkit.plugin.Plugin; - -import com.comphenix.protocol.error.BasicErrorReporter; -import com.comphenix.protocol.error.ErrorReporter; -import com.google.common.util.concurrent.ListeningScheduledExecutorService; - -/** - * The main entry point for ProtocolLib. - * @author dmulloy2 - */ -public class ProtocolLibrary { - /** - * The minimum version ProtocolLib has been tested with. - */ - public static final String MINIMUM_MINECRAFT_VERSION = "1.9"; - - /** - * The maximum version ProtocolLib has been tested with. - */ - public static final String MAXIMUM_MINECRAFT_VERSION = "1.9.4"; - - /** - * The date (with ISO 8601 or YYYY-MM-DD) when the most recent version (1.9.4) was released. - */ - public static final String MINECRAFT_LAST_RELEASE_DATE = "2016-05-10"; - - /** - * Plugins that are currently incompatible with ProtocolLib. - */ - public static final List INCOMPATIBLE = Arrays.asList("TagAPI"); - - private static Plugin plugin; - private static ProtocolConfig config; - private static ProtocolManager manager; - private static ErrorReporter reporter = new BasicErrorReporter(); - - private static ListeningScheduledExecutorService executorAsync; - private static ListeningScheduledExecutorService executorSync; - - private static boolean updatesDisabled; - private static boolean initialized; - - protected static void init(Plugin plugin, ProtocolConfig config, ProtocolManager manager, ErrorReporter reporter, - ListeningScheduledExecutorService executorAsync, ListeningScheduledExecutorService executorSync) { - Validate.isTrue(!initialized, "ProtocolLib has already been initialized."); - ProtocolLibrary.plugin = plugin; - ProtocolLibrary.config = config; - ProtocolLibrary.manager = manager; - ProtocolLibrary.reporter = reporter; - ProtocolLibrary.executorAsync = executorAsync; - ProtocolLibrary.executorSync = executorSync; - ProtocolLogger.init(plugin); - initialized = true; - } - - /** - * Gets the ProtocolLib plugin instance. - * @return The plugin instance - */ - public static Plugin getPlugin() { - return plugin; - } - - /** - * Gets ProtocolLib's configuration - * @return The config - */ - public static ProtocolConfig getConfig() { - return config; - } - - /** - * Retrieves the packet protocol manager. - * @return Packet protocol manager - */ - public static ProtocolManager getProtocolManager() { - return manager; - } - - /** - * Retrieve the current error reporter. - * @return Current error reporter. - */ - public static ErrorReporter getErrorReporter() { - return reporter; - } - - /** - * Retrieve an executor service for performing asynchronous tasks on the behalf of ProtocolLib. - *

- * Note that this service is NULL if ProtocolLib has not been initialized yet. - * @return The executor service, or NULL. - */ - public static ListeningScheduledExecutorService getExecutorAsync() { - return executorAsync; - } - - /** - * Retrieve an executor service for performing synchronous tasks (main thread) on the behalf of ProtocolLib. - *

- * Note that this service is NULL if ProtocolLib has not been initialized yet. - * @return The executor service, or NULL. - */ - public static ListeningScheduledExecutorService getExecutorSync() { - return executorSync; - } - - /** - * Disables the ProtocolLib update checker. - */ - public static void disableUpdates() { - updatesDisabled = true; - } - - /** - * Whether or not updates are currently disabled. - * @return True if it is, false if not - */ - public static boolean updatesDisabled() { - return updatesDisabled; - } -} \ No newline at end of file +/** + * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. + * Copyright (C) 2016 dmulloy2 + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ +package com.comphenix.protocol; + +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.lang.Validate; +import org.bukkit.plugin.Plugin; + +import com.comphenix.protocol.error.BasicErrorReporter; +import com.comphenix.protocol.error.ErrorReporter; +import com.google.common.util.concurrent.ListeningScheduledExecutorService; + +/** + * The main entry point for ProtocolLib. + * @author dmulloy2 + */ +public class ProtocolLibrary { + /** + * The minimum version ProtocolLib has been tested with. + */ + public static final String MINIMUM_MINECRAFT_VERSION = "1.9"; + + /** + * The maximum version ProtocolLib has been tested with. + */ + public static final String MAXIMUM_MINECRAFT_VERSION = "1.9.4"; + + /** + * The date (with ISO 8601 or YYYY-MM-DD) when the most recent version (1.9.4) was released. + */ + public static final String MINECRAFT_LAST_RELEASE_DATE = "2016-05-10"; + + /** + * Plugins that are currently incompatible with ProtocolLib. + */ + public static final List INCOMPATIBLE = Arrays.asList("TagAPI"); + + private static Plugin plugin; + private static ProtocolConfig config; + private static ProtocolManager manager; + private static ErrorReporter reporter = new BasicErrorReporter(); + + private static ListeningScheduledExecutorService executorAsync; + private static ListeningScheduledExecutorService executorSync; + + private static boolean updatesDisabled; + private static boolean initialized; + + protected static void init(Plugin plugin, ProtocolConfig config, ProtocolManager manager, ErrorReporter reporter, + ListeningScheduledExecutorService executorAsync, ListeningScheduledExecutorService executorSync) { + Validate.isTrue(!initialized, "ProtocolLib has already been initialized."); + ProtocolLibrary.plugin = plugin; + ProtocolLibrary.config = config; + ProtocolLibrary.manager = manager; + ProtocolLibrary.reporter = reporter; + ProtocolLibrary.executorAsync = executorAsync; + ProtocolLibrary.executorSync = executorSync; + ProtocolLogger.init(plugin); + initialized = true; + } + + /** + * Gets the ProtocolLib plugin instance. + * @return The plugin instance + */ + public static Plugin getPlugin() { + return plugin; + } + + /** + * Gets ProtocolLib's configuration + * @return The config + */ + public static ProtocolConfig getConfig() { + return config; + } + + /** + * Retrieves the packet protocol manager. + * @return Packet protocol manager + */ + public static ProtocolManager getProtocolManager() { + return manager; + } + + /** + * Retrieve the current error reporter. + * @return Current error reporter. + */ + public static ErrorReporter getErrorReporter() { + return reporter; + } + + /** + * Retrieve an executor service for performing asynchronous tasks on the behalf of ProtocolLib. + *

+ * Note that this service is NULL if ProtocolLib has not been initialized yet. + * @return The executor service, or NULL. + */ + public static ListeningScheduledExecutorService getExecutorAsync() { + return executorAsync; + } + + /** + * Retrieve an executor service for performing synchronous tasks (main thread) on the behalf of ProtocolLib. + *

+ * Note that this service is NULL if ProtocolLib has not been initialized yet. + * @return The executor service, or NULL. + */ + public static ListeningScheduledExecutorService getExecutorSync() { + return executorSync; + } + + /** + * Disables the ProtocolLib update checker. + */ + public static void disableUpdates() { + updatesDisabled = true; + } + + /** + * Whether or not updates are currently disabled. + * @return True if it is, false if not + */ + public static boolean updatesDisabled() { + return updatesDisabled; + } +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/ProtocolLogger.java b/modules/API/src/main/java/com/comphenix/protocol/ProtocolLogger.java index 032e0d65..c3f7b3f7 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/ProtocolLogger.java +++ b/modules/API/src/main/java/com/comphenix/protocol/ProtocolLogger.java @@ -1,81 +1,81 @@ -/** - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2016 dmulloy2 - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ -package com.comphenix.protocol; - -import java.text.MessageFormat; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.bukkit.plugin.Plugin; - -/** - * @author dmulloy2 - */ -public class ProtocolLogger { - private static Logger logger; - - protected static void init(Plugin plugin) { - ProtocolLogger.logger = plugin.getLogger(); - } - - private static boolean isDebugEnabled() { - try { - return ProtocolLibrary.getConfig().isDebug(); - } catch (Throwable ex) { - return true; // For testing - } - } - - /** - * Logs a message to console with a given level. - * @param level Logging level - * @param message Message to log - * @param args Arguments to format in - */ - public static void log(Level level, String message, Object... args) { - logger.log(level, MessageFormat.format(message, args)); - } - - /** - * Logs a method to console with the INFO level. - * @param message Message to log - * @param args Arguments to format in - */ - public static void log(String message, Object... args) { - log(Level.INFO, message, args); - } - - /** - * Logs a message to console with a given level and exception. - * @param level Logging level - * @param message Message to log - * @param ex Exception to log - */ - public static void log(Level level, String message, Throwable ex) { - logger.log(level, message, ex); - } - - public static void debug(String message, Object... args) { - if (isDebugEnabled()) { - if (logger != null) { - log("[Debug] " + message, args); - } else { - System.out.println("[Debug] " + MessageFormat.format(message, args)); - } - } - } -} \ No newline at end of file +/** + * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. + * Copyright (C) 2016 dmulloy2 + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ +package com.comphenix.protocol; + +import java.text.MessageFormat; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.bukkit.plugin.Plugin; + +/** + * @author dmulloy2 + */ +public class ProtocolLogger { + private static Logger logger; + + protected static void init(Plugin plugin) { + ProtocolLogger.logger = plugin.getLogger(); + } + + private static boolean isDebugEnabled() { + try { + return ProtocolLibrary.getConfig().isDebug(); + } catch (Throwable ex) { + return true; // For testing + } + } + + /** + * Logs a message to console with a given level. + * @param level Logging level + * @param message Message to log + * @param args Arguments to format in + */ + public static void log(Level level, String message, Object... args) { + logger.log(level, MessageFormat.format(message, args)); + } + + /** + * Logs a method to console with the INFO level. + * @param message Message to log + * @param args Arguments to format in + */ + public static void log(String message, Object... args) { + log(Level.INFO, message, args); + } + + /** + * Logs a message to console with a given level and exception. + * @param level Logging level + * @param message Message to log + * @param ex Exception to log + */ + public static void log(Level level, String message, Throwable ex) { + logger.log(level, message, ex); + } + + public static void debug(String message, Object... args) { + if (isDebugEnabled()) { + if (logger != null) { + log("[Debug] " + message, args); + } else { + System.out.println("[Debug] " + MessageFormat.format(message, args)); + } + } + } +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/ProtocolManager.java b/modules/API/src/main/java/com/comphenix/protocol/ProtocolManager.java index 0283e0d7..1ff9c6bd 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/ProtocolManager.java +++ b/modules/API/src/main/java/com/comphenix/protocol/ProtocolManager.java @@ -282,4 +282,4 @@ public interface ProtocolManager extends PacketStream { public AsynchronousManager getAsynchronousManager(); public void verifyWhitelist(PacketListener listener, ListeningWhitelist whitelist); -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/collections/ExpireHashMap.java b/modules/API/src/main/java/com/comphenix/protocol/collections/ExpireHashMap.java index 04e83313..54e98e3f 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/collections/ExpireHashMap.java +++ b/modules/API/src/main/java/com/comphenix/protocol/collections/ExpireHashMap.java @@ -243,4 +243,4 @@ public class ExpireHashMap { return valueView.toString(); } } - \ No newline at end of file + diff --git a/modules/API/src/main/java/com/comphenix/protocol/error/ErrorReporter.java b/modules/API/src/main/java/com/comphenix/protocol/error/ErrorReporter.java index ac647395..607e980f 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/error/ErrorReporter.java +++ b/modules/API/src/main/java/com/comphenix/protocol/error/ErrorReporter.java @@ -87,4 +87,4 @@ public interface ErrorReporter { * @param reportBuilder - an error report builder that will be used to get the report. */ public abstract void reportDetailed(Object sender, ReportBuilder reportBuilder); -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/events/PacketContainer.java b/modules/API/src/main/java/com/comphenix/protocol/events/PacketContainer.java index fdf1d308..06035825 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/events/PacketContainer.java +++ b/modules/API/src/main/java/com/comphenix/protocol/events/PacketContainer.java @@ -1261,4 +1261,4 @@ public class PacketContainer implements Serializable { public String toString() { return "PacketContainer[type=" + type + ", structureModifier=" + structureModifier + "]"; } -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/events/PacketEvent.java b/modules/API/src/main/java/com/comphenix/protocol/events/PacketEvent.java index 7bf4b9fe..644b119e 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/events/PacketEvent.java +++ b/modules/API/src/main/java/com/comphenix/protocol/events/PacketEvent.java @@ -453,4 +453,4 @@ public class PacketEvent extends EventObject implements Cancellable { public String toString() { return "PacketEvent[player=" + getPlayer() + ", packet=" + packet + "]"; } -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/injector/PlayerInjectHooks.java b/modules/API/src/main/java/com/comphenix/protocol/injector/PlayerInjectHooks.java index 1308c264..57bd15db 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/injector/PlayerInjectHooks.java +++ b/modules/API/src/main/java/com/comphenix/protocol/injector/PlayerInjectHooks.java @@ -1,31 +1,31 @@ -package com.comphenix.protocol.injector; - -/** - * Sets the inject hook type. Different types allow for maximum compatibility. - * @author Kristian - */ -public enum PlayerInjectHooks { - /** - * The injection hook that does nothing. Set when every other inject hook fails. - */ - NONE, - - /** - * Override the network handler object itself. Only works in 1.3. - *

- * Cannot intercept MapChunk packets. - */ - NETWORK_MANAGER_OBJECT, - - /** - * Override the packet queue lists in NetworkHandler. - *

- * Cannot intercept MapChunk packets. - */ - NETWORK_HANDLER_FIELDS, - - /** - * Override the server handler object. Versatile, but a tad slower. - */ - NETWORK_SERVER_OBJECT; -} \ No newline at end of file +package com.comphenix.protocol.injector; + +/** + * Sets the inject hook type. Different types allow for maximum compatibility. + * @author Kristian + */ +public enum PlayerInjectHooks { + /** + * The injection hook that does nothing. Set when every other inject hook fails. + */ + NONE, + + /** + * Override the network handler object itself. Only works in 1.3. + *

+ * Cannot intercept MapChunk packets. + */ + NETWORK_MANAGER_OBJECT, + + /** + * Override the packet queue lists in NetworkHandler. + *

+ * Cannot intercept MapChunk packets. + */ + NETWORK_HANDLER_FIELDS, + + /** + * Override the server handler object. Versatile, but a tad slower. + */ + NETWORK_SERVER_OBJECT; +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/injector/StructureCache.java b/modules/API/src/main/java/com/comphenix/protocol/injector/StructureCache.java index a926f0ea..a22e0509 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/injector/StructureCache.java +++ b/modules/API/src/main/java/com/comphenix/protocol/injector/StructureCache.java @@ -172,4 +172,4 @@ public class StructureCache { } return result; } -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/injector/netty/NettyByteBufAdapter.java b/modules/API/src/main/java/com/comphenix/protocol/injector/netty/NettyByteBufAdapter.java index d31734e2..fbfa6932 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/injector/netty/NettyByteBufAdapter.java +++ b/modules/API/src/main/java/com/comphenix/protocol/injector/netty/NettyByteBufAdapter.java @@ -389,4 +389,4 @@ public class NettyByteBufAdapter extends AbstractByteBuf { public ByteBuf retain() { return this; } -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/injector/netty/NettyProtocolRegistry.java b/modules/API/src/main/java/com/comphenix/protocol/injector/netty/NettyProtocolRegistry.java index 55a339ba..5b0baf6b 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/injector/netty/NettyProtocolRegistry.java +++ b/modules/API/src/main/java/com/comphenix/protocol/injector/netty/NettyProtocolRegistry.java @@ -1,111 +1,111 @@ -/** - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2015 dmulloy2 - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ -package com.comphenix.protocol.injector.netty; - -import java.util.Map; -import java.util.Map.Entry; - -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.ProtocolLogger; -import com.comphenix.protocol.PacketType.Protocol; -import com.comphenix.protocol.PacketType.Sender; -import com.comphenix.protocol.injector.netty.ProtocolRegistry; -import com.comphenix.protocol.injector.packet.MapContainer; -import com.comphenix.protocol.reflect.StructureModifier; -import com.google.common.collect.Maps; - -/** - * @author dmulloy2 - */ - -public class NettyProtocolRegistry extends ProtocolRegistry { - - public NettyProtocolRegistry() { - super(); - } - - @Override - protected synchronized void initialize() { - ProtocolLogger.debug("NettyProtocolRegistry#initialize()"); // Debug for issue #202 - - Object[] protocols = enumProtocol.getEnumConstants(); - - // ID to Packet class maps - Map>> serverMaps = Maps.newLinkedHashMap(); - Map>> clientMaps = Maps.newLinkedHashMap(); - - Register result = new Register(); - StructureModifier modifier = null; - - // Iterate through the protocols - for (Object protocol : protocols) { - if (modifier == null) - modifier = new StructureModifier(protocol.getClass().getSuperclass(), false); - StructureModifier>>> maps = modifier.withTarget(protocol).withType(Map.class); - for (Entry>> entry : maps.read(0).entrySet()) { - String direction = entry.getKey().toString(); - if (direction.contains("CLIENTBOUND")) { // Sent by Server - serverMaps.put(protocol, entry.getValue()); - } else if (direction.contains("SERVERBOUND")) { // Sent by Client - clientMaps.put(protocol, entry.getValue()); - } - } - } - - // Maps we have to occasionally check have changed - for (Map> map : serverMaps.values()) { - result.containers.add(new MapContainer(map)); - } - - for (Map> map : clientMaps.values()) { - result.containers.add(new MapContainer(map)); - } - - for (int i = 0; i < protocols.length; i++) { - Object protocol = protocols[i]; - Enum enumProtocol = (Enum) protocol; - Protocol equivalent = Protocol.fromVanilla(enumProtocol); - - // Associate known types - if (serverMaps.containsKey(protocol)) - associatePackets(result, serverMaps.get(protocol), equivalent, Sender.SERVER); - if (clientMaps.containsKey(protocol)) - associatePackets(result, clientMaps.get(protocol), equivalent, Sender.CLIENT); - } - - // Exchange (thread safe, as we have only one writer) - this.register = result; - } - - @Override - protected void associatePackets(Register register, Map> lookup, Protocol protocol, Sender sender) { - for (Entry> entry : lookup.entrySet()) { - PacketType type = PacketType.fromCurrent(protocol, sender, entry.getKey(), entry.getValue()); - - try { - register.typeToClass.put(type, entry.getValue()); - - if (sender == Sender.SERVER) - register.serverPackets.add(type); - if (sender == Sender.CLIENT) - register.clientPackets.add(type); - } catch (IllegalArgumentException ex) { - // Sometimes this happens with fake packets, just ignore it - } - } - } -} +/** + * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. + * Copyright (C) 2015 dmulloy2 + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ +package com.comphenix.protocol.injector.netty; + +import java.util.Map; +import java.util.Map.Entry; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.ProtocolLogger; +import com.comphenix.protocol.PacketType.Protocol; +import com.comphenix.protocol.PacketType.Sender; +import com.comphenix.protocol.injector.netty.ProtocolRegistry; +import com.comphenix.protocol.injector.packet.MapContainer; +import com.comphenix.protocol.reflect.StructureModifier; +import com.google.common.collect.Maps; + +/** + * @author dmulloy2 + */ + +public class NettyProtocolRegistry extends ProtocolRegistry { + + public NettyProtocolRegistry() { + super(); + } + + @Override + protected synchronized void initialize() { + ProtocolLogger.debug("NettyProtocolRegistry#initialize()"); // Debug for issue #202 + + Object[] protocols = enumProtocol.getEnumConstants(); + + // ID to Packet class maps + Map>> serverMaps = Maps.newLinkedHashMap(); + Map>> clientMaps = Maps.newLinkedHashMap(); + + Register result = new Register(); + StructureModifier modifier = null; + + // Iterate through the protocols + for (Object protocol : protocols) { + if (modifier == null) + modifier = new StructureModifier(protocol.getClass().getSuperclass(), false); + StructureModifier>>> maps = modifier.withTarget(protocol).withType(Map.class); + for (Entry>> entry : maps.read(0).entrySet()) { + String direction = entry.getKey().toString(); + if (direction.contains("CLIENTBOUND")) { // Sent by Server + serverMaps.put(protocol, entry.getValue()); + } else if (direction.contains("SERVERBOUND")) { // Sent by Client + clientMaps.put(protocol, entry.getValue()); + } + } + } + + // Maps we have to occasionally check have changed + for (Map> map : serverMaps.values()) { + result.containers.add(new MapContainer(map)); + } + + for (Map> map : clientMaps.values()) { + result.containers.add(new MapContainer(map)); + } + + for (int i = 0; i < protocols.length; i++) { + Object protocol = protocols[i]; + Enum enumProtocol = (Enum) protocol; + Protocol equivalent = Protocol.fromVanilla(enumProtocol); + + // Associate known types + if (serverMaps.containsKey(protocol)) + associatePackets(result, serverMaps.get(protocol), equivalent, Sender.SERVER); + if (clientMaps.containsKey(protocol)) + associatePackets(result, clientMaps.get(protocol), equivalent, Sender.CLIENT); + } + + // Exchange (thread safe, as we have only one writer) + this.register = result; + } + + @Override + protected void associatePackets(Register register, Map> lookup, Protocol protocol, Sender sender) { + for (Entry> entry : lookup.entrySet()) { + PacketType type = PacketType.fromCurrent(protocol, sender, entry.getKey(), entry.getValue()); + + try { + register.typeToClass.put(type, entry.getValue()); + + if (sender == Sender.SERVER) + register.serverPackets.add(type); + if (sender == Sender.CLIENT) + register.clientPackets.add(type); + } catch (IllegalArgumentException ex) { + // Sometimes this happens with fake packets, just ignore it + } + } + } +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/injector/netty/ProtocolRegistry.java b/modules/API/src/main/java/com/comphenix/protocol/injector/netty/ProtocolRegistry.java index 278cb6d1..1b3da48c 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/injector/netty/ProtocolRegistry.java +++ b/modules/API/src/main/java/com/comphenix/protocol/injector/netty/ProtocolRegistry.java @@ -122,4 +122,4 @@ public abstract class ProtocolRegistry { count += map.size(); return count; } -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/injector/netty/WirePacket.java b/modules/API/src/main/java/com/comphenix/protocol/injector/netty/WirePacket.java index 34f2102f..adb8fc29 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/injector/netty/WirePacket.java +++ b/modules/API/src/main/java/com/comphenix/protocol/injector/netty/WirePacket.java @@ -1,55 +1,55 @@ -/** - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2015 dmulloy2 - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ -package com.comphenix.protocol.injector.netty; - -import io.netty.buffer.ByteBuf; - -/** - * @author dmulloy2 - */ - -public class WirePacket { - private final int id; - private final byte[] bytes; - - public WirePacket(int id, byte[] bytes) { - this.id = id; - this.bytes = bytes; - } - - public int getId() { - return id; - } - - public byte[] getBytes() { - return bytes; - } - - public void writeId(ByteBuf output) { - int i = id; - while ((i & -128) != 0) { - output.writeByte(i & 127 | 128); - i >>>= 7; - } - - output.writeByte(i); - } - - public void writeBytes(ByteBuf output) { - output.writeBytes(bytes); - } -} \ No newline at end of file +/** + * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. + * Copyright (C) 2015 dmulloy2 + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ +package com.comphenix.protocol.injector.netty; + +import io.netty.buffer.ByteBuf; + +/** + * @author dmulloy2 + */ + +public class WirePacket { + private final int id; + private final byte[] bytes; + + public WirePacket(int id, byte[] bytes) { + this.id = id; + this.bytes = bytes; + } + + public int getId() { + return id; + } + + public byte[] getBytes() { + return bytes; + } + + public void writeId(ByteBuf output) { + int i = id; + while ((i & -128) != 0) { + output.writeByte(i & 127 | 128); + i >>>= 7; + } + + output.writeByte(i); + } + + public void writeBytes(ByteBuf output) { + output.writeBytes(bytes); + } +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/injector/packet/MapContainer.java b/modules/API/src/main/java/com/comphenix/protocol/injector/packet/MapContainer.java index ee006f71..2cdbc357 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/injector/packet/MapContainer.java +++ b/modules/API/src/main/java/com/comphenix/protocol/injector/packet/MapContainer.java @@ -64,4 +64,4 @@ public class MapContainer { throw new RuntimeException("Unable to retrieve modCount.", e); } } -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/injector/packet/PacketRegistry.java b/modules/API/src/main/java/com/comphenix/protocol/injector/packet/PacketRegistry.java index 333a1320..fbe6b556 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/injector/packet/PacketRegistry.java +++ b/modules/API/src/main/java/com/comphenix/protocol/injector/packet/PacketRegistry.java @@ -1,322 +1,322 @@ -/* - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2012 Kristian S. Stangeland - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -package com.comphenix.protocol.injector.packet; - -import java.util.Collections; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.PacketType.Sender; -import com.comphenix.protocol.error.ReportType; -import com.comphenix.protocol.injector.netty.NettyProtocolRegistry; -import com.comphenix.protocol.injector.netty.ProtocolRegistry; -import com.comphenix.protocol.reflect.FieldAccessException; -import com.google.common.base.Function; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; - -/** - * Static packet registry in Minecraft. - * @author Kristian - */ -@SuppressWarnings("rawtypes") -public class PacketRegistry { - public static final ReportType REPORT_CANNOT_CORRECT_TROVE_MAP = new ReportType("Unable to correct no entry value."); - - public static final ReportType REPORT_INSUFFICIENT_SERVER_PACKETS = new ReportType("Too few server packets detected: %s"); - public static final ReportType REPORT_INSUFFICIENT_CLIENT_PACKETS = new ReportType("Too few client packets detected: %s"); - - // The Netty packet registry - private static volatile ProtocolRegistry NETTY; - - // Cached for Netty - private static volatile Set LEGACY_SERVER_PACKETS; - private static volatile Set LEGACY_CLIENT_PACKETS; - private static volatile Map LEGACY_PREVIOUS_PACKETS; - - // Whether or not the registry has been initialized - private static volatile boolean INITIALIZED = false; - - /** - * Initializes the packet registry. - */ - private static void initialize() { - if (INITIALIZED) { - if (NETTY == null) { - throw new IllegalStateException("Failed to initialize packet registry."); - } - return; - } - - NETTY = new NettyProtocolRegistry(); - INITIALIZED = true; - } - - /** - * Determine if the given packet type is supported on the current server. - * @param type - the type to check. - * @return TRUE if it is, FALSE otherwise. - */ - public static boolean isSupported(PacketType type) { - initialize(); - return NETTY.getPacketTypeLookup().containsKey(type); - } - - /** - * Retrieve a map of every packet class to every ID. - *

- * Deprecated: Use {@link #getPacketToType()} instead. - * @return A map of packet classes and their corresponding ID. - */ - @Deprecated - public static Map getPacketToID() { - initialize(); - - @SuppressWarnings("unchecked") - Map result = (Map) Maps.transformValues( - NETTY.getPacketClassLookup(), - new Function() { - @Override - public Integer apply(PacketType type) { - return type.getLegacyId(); - }; - }); - return result; - } - - /** - * Retrieve a map of every packet class to the respective packet type. - * @return A map of packet classes and their corresponding packet type. - */ - public static Map getPacketToType() { - initialize(); - - @SuppressWarnings("unchecked") - Map result = (Map) NETTY.getPacketClassLookup(); - return result; - } - - /** - * Retrieve the injected proxy classes handlig each packet ID. - *

- * This is not supported in 1.7.2 and later. - * @return Injected classes. - */ - @Deprecated - public static Map getOverwrittenPackets() { - initialize(); - throw new IllegalStateException("Not supported on Netty."); - } - - /** - * Retrieve the vanilla classes handling each packet ID. - * @return Vanilla classes. - */ - @Deprecated - public static Map getPreviousPackets() { - initialize(); - - // Construct it first - if (LEGACY_PREVIOUS_PACKETS == null) { - Map map = Maps.newHashMap(); - - for (Entry> entry : NETTY.getPacketTypeLookup().entrySet()) { - map.put(entry.getKey().getLegacyId(), entry.getValue()); - } - LEGACY_PREVIOUS_PACKETS = Collections.unmodifiableMap(map); - } - return LEGACY_PREVIOUS_PACKETS; - } - - /** - * Retrieve every known and supported server packet. - *

- * Deprecated: Use {@link #getServerPacketTypes()} instead. - * @return An immutable set of every known server packet. - * @throws FieldAccessException If we're unable to retrieve the server packet data from Minecraft. - */ - @Deprecated - public static Set getServerPackets() throws FieldAccessException { - initialize(); - - if (LEGACY_SERVER_PACKETS == null) { - LEGACY_SERVER_PACKETS = toLegacy(NETTY.getServerPackets()); - } - return LEGACY_SERVER_PACKETS; - } - - /** - * Retrieve every known and supported server packet type. - * @return Every server packet type. - */ - public static Set getServerPacketTypes() { - initialize(); - - NETTY.synchronize(); - return NETTY.getServerPackets(); - } - - /** - * Retrieve every known and supported client packet. - *

- * Deprecated: Use {@link #getClientPacketTypes()} instead. - * @return An immutable set of every known client packet. - * @throws FieldAccessException If we're unable to retrieve the client packet data from Minecraft. - */ - @Deprecated - public static Set getClientPackets() throws FieldAccessException { - initialize(); - - if (LEGACY_CLIENT_PACKETS == null) { - LEGACY_CLIENT_PACKETS = toLegacy(NETTY.getClientPackets()); - } - return LEGACY_CLIENT_PACKETS; - } - - /** - * Retrieve every known and supported server packet type. - * @return Every server packet type. - */ - public static Set getClientPacketTypes() { - initialize(); - - NETTY.synchronize(); - return NETTY.getClientPackets(); - } - - /** - * Convert a set of packet types to a set of integers based on the legacy packet ID. - * @param types - packet type. - * @return Set of integers. - */ - public static Set toLegacy(Set types) { - Set result = Sets.newHashSet(); - - for (PacketType type : types) - result.add(type.getLegacyId()); - return Collections.unmodifiableSet(result); - } - - /** - * Convert a set of legacy packet IDs to packet types. - * @param ids - legacy packet IDs. - * @return Set of packet types. - */ - public static Set toPacketTypes(Set ids) { - return toPacketTypes(ids, null); - } - - /** - * Convert a set of legacy packet IDs to packet types. - * @param ids - legacy packet IDs. - * @param preference - the sender preference, if any. - * @return Set of packet types. - */ - public static Set toPacketTypes(Set ids, Sender preference) { - Set result = Sets.newHashSet(); - - for (int id : ids) - result.add(PacketType.fromLegacy(id, preference)); - return Collections.unmodifiableSet(result); - } - - /** - * Retrieves the correct packet class from a given packet ID. - *

- * Deprecated: Use {@link #getPacketClassFromType(PacketType)} instead. - * @param packetID - the packet ID. - * @return The associated class. - */ - @Deprecated - public static Class getPacketClassFromID(int packetID) { - initialize(); - return NETTY.getPacketTypeLookup().get(PacketType.findLegacy(packetID)); - } - - /** - * Retrieves the correct packet class from a given type. - * @param type - the packet type. - * @return The associated class. - */ - public static Class getPacketClassFromType(PacketType type) { - return getPacketClassFromType(type, false); - } - - /** - * Retrieves the correct packet class from a given type. - *

- * Note that forceVanillla will be ignored on MC 1.7.2 and later. - * @param type - the packet type. - * @param forceVanilla - whether or not to look for vanilla classes, not injected classes. - * @return The associated class. - */ - public static Class getPacketClassFromType(PacketType type, boolean forceVanilla) { - initialize(); - return NETTY.getPacketTypeLookup().get(type); - } - - /** - * Retrieves the correct packet class from a given packet ID. - *

- * This method has been deprecated. - * @param packetID - the packet ID. - * @param forceVanilla - whether or not to look for vanilla classes, not injected classes. - * @return The associated class. - */ - @Deprecated - public static Class getPacketClassFromID(int packetID, boolean forceVanilla) { - initialize(); - return getPacketClassFromID(packetID); - } - - /** - * Retrieve the packet ID of a given packet. - *

- * Deprecated: Use {@link #getPacketType(Class)}. - * @param packet - the type of packet to check. - * @return The legacy ID of the given packet. - * @throws IllegalArgumentException If this is not a valid packet. - */ - @Deprecated - public static int getPacketID(Class packet) { - initialize(); - return NETTY.getPacketClassLookup().get(packet).getLegacyId(); - } - - /** - * Retrieve the packet type of a given packet. - * @param packet - the class of the packet. - * @return The packet type, or NULL if not found. - */ - public static PacketType getPacketType(Class packet) { - return getPacketType(packet, null); - } - - /** - * Retrieve the packet type of a given packet. - * @param packet - the class of the packet. - * @param sender - the sender of the packet, or NULL. - * @return The packet type, or NULL if not found. - */ - public static PacketType getPacketType(Class packet, Sender sender) { - initialize(); - return NETTY.getPacketClassLookup().get(packet); - } -} \ No newline at end of file +/* + * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. + * Copyright (C) 2012 Kristian S. Stangeland + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +package com.comphenix.protocol.injector.packet; + +import java.util.Collections; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.PacketType.Sender; +import com.comphenix.protocol.error.ReportType; +import com.comphenix.protocol.injector.netty.NettyProtocolRegistry; +import com.comphenix.protocol.injector.netty.ProtocolRegistry; +import com.comphenix.protocol.reflect.FieldAccessException; +import com.google.common.base.Function; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; + +/** + * Static packet registry in Minecraft. + * @author Kristian + */ +@SuppressWarnings("rawtypes") +public class PacketRegistry { + public static final ReportType REPORT_CANNOT_CORRECT_TROVE_MAP = new ReportType("Unable to correct no entry value."); + + public static final ReportType REPORT_INSUFFICIENT_SERVER_PACKETS = new ReportType("Too few server packets detected: %s"); + public static final ReportType REPORT_INSUFFICIENT_CLIENT_PACKETS = new ReportType("Too few client packets detected: %s"); + + // The Netty packet registry + private static volatile ProtocolRegistry NETTY; + + // Cached for Netty + private static volatile Set LEGACY_SERVER_PACKETS; + private static volatile Set LEGACY_CLIENT_PACKETS; + private static volatile Map LEGACY_PREVIOUS_PACKETS; + + // Whether or not the registry has been initialized + private static volatile boolean INITIALIZED = false; + + /** + * Initializes the packet registry. + */ + private static void initialize() { + if (INITIALIZED) { + if (NETTY == null) { + throw new IllegalStateException("Failed to initialize packet registry."); + } + return; + } + + NETTY = new NettyProtocolRegistry(); + INITIALIZED = true; + } + + /** + * Determine if the given packet type is supported on the current server. + * @param type - the type to check. + * @return TRUE if it is, FALSE otherwise. + */ + public static boolean isSupported(PacketType type) { + initialize(); + return NETTY.getPacketTypeLookup().containsKey(type); + } + + /** + * Retrieve a map of every packet class to every ID. + *

+ * Deprecated: Use {@link #getPacketToType()} instead. + * @return A map of packet classes and their corresponding ID. + */ + @Deprecated + public static Map getPacketToID() { + initialize(); + + @SuppressWarnings("unchecked") + Map result = (Map) Maps.transformValues( + NETTY.getPacketClassLookup(), + new Function() { + @Override + public Integer apply(PacketType type) { + return type.getLegacyId(); + }; + }); + return result; + } + + /** + * Retrieve a map of every packet class to the respective packet type. + * @return A map of packet classes and their corresponding packet type. + */ + public static Map getPacketToType() { + initialize(); + + @SuppressWarnings("unchecked") + Map result = (Map) NETTY.getPacketClassLookup(); + return result; + } + + /** + * Retrieve the injected proxy classes handlig each packet ID. + *

+ * This is not supported in 1.7.2 and later. + * @return Injected classes. + */ + @Deprecated + public static Map getOverwrittenPackets() { + initialize(); + throw new IllegalStateException("Not supported on Netty."); + } + + /** + * Retrieve the vanilla classes handling each packet ID. + * @return Vanilla classes. + */ + @Deprecated + public static Map getPreviousPackets() { + initialize(); + + // Construct it first + if (LEGACY_PREVIOUS_PACKETS == null) { + Map map = Maps.newHashMap(); + + for (Entry> entry : NETTY.getPacketTypeLookup().entrySet()) { + map.put(entry.getKey().getLegacyId(), entry.getValue()); + } + LEGACY_PREVIOUS_PACKETS = Collections.unmodifiableMap(map); + } + return LEGACY_PREVIOUS_PACKETS; + } + + /** + * Retrieve every known and supported server packet. + *

+ * Deprecated: Use {@link #getServerPacketTypes()} instead. + * @return An immutable set of every known server packet. + * @throws FieldAccessException If we're unable to retrieve the server packet data from Minecraft. + */ + @Deprecated + public static Set getServerPackets() throws FieldAccessException { + initialize(); + + if (LEGACY_SERVER_PACKETS == null) { + LEGACY_SERVER_PACKETS = toLegacy(NETTY.getServerPackets()); + } + return LEGACY_SERVER_PACKETS; + } + + /** + * Retrieve every known and supported server packet type. + * @return Every server packet type. + */ + public static Set getServerPacketTypes() { + initialize(); + + NETTY.synchronize(); + return NETTY.getServerPackets(); + } + + /** + * Retrieve every known and supported client packet. + *

+ * Deprecated: Use {@link #getClientPacketTypes()} instead. + * @return An immutable set of every known client packet. + * @throws FieldAccessException If we're unable to retrieve the client packet data from Minecraft. + */ + @Deprecated + public static Set getClientPackets() throws FieldAccessException { + initialize(); + + if (LEGACY_CLIENT_PACKETS == null) { + LEGACY_CLIENT_PACKETS = toLegacy(NETTY.getClientPackets()); + } + return LEGACY_CLIENT_PACKETS; + } + + /** + * Retrieve every known and supported server packet type. + * @return Every server packet type. + */ + public static Set getClientPacketTypes() { + initialize(); + + NETTY.synchronize(); + return NETTY.getClientPackets(); + } + + /** + * Convert a set of packet types to a set of integers based on the legacy packet ID. + * @param types - packet type. + * @return Set of integers. + */ + public static Set toLegacy(Set types) { + Set result = Sets.newHashSet(); + + for (PacketType type : types) + result.add(type.getLegacyId()); + return Collections.unmodifiableSet(result); + } + + /** + * Convert a set of legacy packet IDs to packet types. + * @param ids - legacy packet IDs. + * @return Set of packet types. + */ + public static Set toPacketTypes(Set ids) { + return toPacketTypes(ids, null); + } + + /** + * Convert a set of legacy packet IDs to packet types. + * @param ids - legacy packet IDs. + * @param preference - the sender preference, if any. + * @return Set of packet types. + */ + public static Set toPacketTypes(Set ids, Sender preference) { + Set result = Sets.newHashSet(); + + for (int id : ids) + result.add(PacketType.fromLegacy(id, preference)); + return Collections.unmodifiableSet(result); + } + + /** + * Retrieves the correct packet class from a given packet ID. + *

+ * Deprecated: Use {@link #getPacketClassFromType(PacketType)} instead. + * @param packetID - the packet ID. + * @return The associated class. + */ + @Deprecated + public static Class getPacketClassFromID(int packetID) { + initialize(); + return NETTY.getPacketTypeLookup().get(PacketType.findLegacy(packetID)); + } + + /** + * Retrieves the correct packet class from a given type. + * @param type - the packet type. + * @return The associated class. + */ + public static Class getPacketClassFromType(PacketType type) { + return getPacketClassFromType(type, false); + } + + /** + * Retrieves the correct packet class from a given type. + *

+ * Note that forceVanillla will be ignored on MC 1.7.2 and later. + * @param type - the packet type. + * @param forceVanilla - whether or not to look for vanilla classes, not injected classes. + * @return The associated class. + */ + public static Class getPacketClassFromType(PacketType type, boolean forceVanilla) { + initialize(); + return NETTY.getPacketTypeLookup().get(type); + } + + /** + * Retrieves the correct packet class from a given packet ID. + *

+ * This method has been deprecated. + * @param packetID - the packet ID. + * @param forceVanilla - whether or not to look for vanilla classes, not injected classes. + * @return The associated class. + */ + @Deprecated + public static Class getPacketClassFromID(int packetID, boolean forceVanilla) { + initialize(); + return getPacketClassFromID(packetID); + } + + /** + * Retrieve the packet ID of a given packet. + *

+ * Deprecated: Use {@link #getPacketType(Class)}. + * @param packet - the type of packet to check. + * @return The legacy ID of the given packet. + * @throws IllegalArgumentException If this is not a valid packet. + */ + @Deprecated + public static int getPacketID(Class packet) { + initialize(); + return NETTY.getPacketClassLookup().get(packet).getLegacyId(); + } + + /** + * Retrieve the packet type of a given packet. + * @param packet - the class of the packet. + * @return The packet type, or NULL if not found. + */ + public static PacketType getPacketType(Class packet) { + return getPacketType(packet, null); + } + + /** + * Retrieve the packet type of a given packet. + * @param packet - the class of the packet. + * @param sender - the sender of the packet, or NULL. + * @return The packet type, or NULL if not found. + */ + public static PacketType getPacketType(Class packet, Sender sender) { + initialize(); + return NETTY.getPacketClassLookup().get(packet); + } +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/package-info.java b/modules/API/src/main/java/com/comphenix/protocol/package-info.java index d2628ab2..fc2651b4 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/package-info.java +++ b/modules/API/src/main/java/com/comphenix/protocol/package-info.java @@ -11,4 +11,4 @@ * } * */ -package com.comphenix.protocol; \ No newline at end of file +package com.comphenix.protocol; diff --git a/modules/API/src/main/java/com/comphenix/protocol/reflect/StructureModifier.java b/modules/API/src/main/java/com/comphenix/protocol/reflect/StructureModifier.java index 51fe1c3f..2744fbe5 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/reflect/StructureModifier.java +++ b/modules/API/src/main/java/com/comphenix/protocol/reflect/StructureModifier.java @@ -682,4 +682,4 @@ public class StructureModifier { public String toString() { return "StructureModifier[fieldType=" + fieldType + ", data=" + data + "]"; } -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/reflect/accessors/DefaultConstrutorAccessor.java b/modules/API/src/main/java/com/comphenix/protocol/reflect/accessors/DefaultConstrutorAccessor.java index e27bca80..c9471ce9 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/reflect/accessors/DefaultConstrutorAccessor.java +++ b/modules/API/src/main/java/com/comphenix/protocol/reflect/accessors/DefaultConstrutorAccessor.java @@ -51,4 +51,4 @@ final class DefaultConstrutorAccessor implements ConstructorAccessor { public String toString() { return "DefaultConstrutorAccessor [constructor=" + constructor + "]"; } -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/reflect/accessors/DefaultFieldAccessor.java b/modules/API/src/main/java/com/comphenix/protocol/reflect/accessors/DefaultFieldAccessor.java index 3a654cd0..a0488e95 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/reflect/accessors/DefaultFieldAccessor.java +++ b/modules/API/src/main/java/com/comphenix/protocol/reflect/accessors/DefaultFieldAccessor.java @@ -57,4 +57,4 @@ final class DefaultFieldAccessor implements FieldAccessor { public String toString() { return "DefaultFieldAccessor [field=" + field + "]"; } -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/reflect/accessors/DefaultMethodAccessor.java b/modules/API/src/main/java/com/comphenix/protocol/reflect/accessors/DefaultMethodAccessor.java index c43d1777..4c5d1e7d 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/reflect/accessors/DefaultMethodAccessor.java +++ b/modules/API/src/main/java/com/comphenix/protocol/reflect/accessors/DefaultMethodAccessor.java @@ -49,4 +49,4 @@ final class DefaultMethodAccessor implements MethodAccessor { public String toString() { return "DefaultMethodAccessor [method=" + method + "]"; } -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/reflect/accessors/FieldAccessor.java b/modules/API/src/main/java/com/comphenix/protocol/reflect/accessors/FieldAccessor.java index b7148c2c..bdd9a43c 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/reflect/accessors/FieldAccessor.java +++ b/modules/API/src/main/java/com/comphenix/protocol/reflect/accessors/FieldAccessor.java @@ -27,4 +27,4 @@ public interface FieldAccessor { * @return The field. */ public Field getField(); -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/reflect/accessors/MethodAccessor.java b/modules/API/src/main/java/com/comphenix/protocol/reflect/accessors/MethodAccessor.java index 83b4400a..04979927 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/reflect/accessors/MethodAccessor.java +++ b/modules/API/src/main/java/com/comphenix/protocol/reflect/accessors/MethodAccessor.java @@ -20,4 +20,4 @@ public interface MethodAccessor { * @return The method. */ public Method getMethod(); -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/reflect/cloning/BukkitCloner.java b/modules/API/src/main/java/com/comphenix/protocol/reflect/cloning/BukkitCloner.java index 1544e280..431f3d7f 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/reflect/cloning/BukkitCloner.java +++ b/modules/API/src/main/java/com/comphenix/protocol/reflect/cloning/BukkitCloner.java @@ -117,4 +117,4 @@ public class BukkitCloner implements Cloner { throw new IllegalArgumentException("Cannot clone objects of type " + source.getClass()); } } -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/reflect/cloning/OptionalCloner.java b/modules/API/src/main/java/com/comphenix/protocol/reflect/cloning/OptionalCloner.java index 7f583109..ac346c38 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/reflect/cloning/OptionalCloner.java +++ b/modules/API/src/main/java/com/comphenix/protocol/reflect/cloning/OptionalCloner.java @@ -1,39 +1,39 @@ -/** - * (c) 2016 dmulloy2 - */ -package com.comphenix.protocol.reflect.cloning; - -import com.google.common.base.Optional; - -/** - * A cloner that can clone Optional objects - * @author dmulloy2 - */ - -public class OptionalCloner implements Cloner { - protected Cloner wrapped; - - public OptionalCloner(Cloner wrapped) { - this.wrapped = wrapped; - } - - @Override - public boolean canClone(Object source) { - return source instanceof Optional; - } - - @Override - public Object clone(Object source) { - Optional optional = (Optional) source; - if (!optional.isPresent()) { - return Optional.absent(); - } - - // Clone the inner value - return Optional.of(wrapped.clone(optional.get())); - } - - public Cloner getWrapped() { - return wrapped; - } -} \ No newline at end of file +/** + * (c) 2016 dmulloy2 + */ +package com.comphenix.protocol.reflect.cloning; + +import com.google.common.base.Optional; + +/** + * A cloner that can clone Optional objects + * @author dmulloy2 + */ + +public class OptionalCloner implements Cloner { + protected Cloner wrapped; + + public OptionalCloner(Cloner wrapped) { + this.wrapped = wrapped; + } + + @Override + public boolean canClone(Object source) { + return source instanceof Optional; + } + + @Override + public Object clone(Object source) { + Optional optional = (Optional) source; + if (!optional.isPresent()) { + return Optional.absent(); + } + + // Clone the inner value + return Optional.of(wrapped.clone(optional.get())); + } + + public Cloner getWrapped() { + return wrapped; + } +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/reflect/fuzzy/ClassRegexMatcher.java b/modules/API/src/main/java/com/comphenix/protocol/reflect/fuzzy/ClassRegexMatcher.java index f08d5057..a0d88640 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/reflect/fuzzy/ClassRegexMatcher.java +++ b/modules/API/src/main/java/com/comphenix/protocol/reflect/fuzzy/ClassRegexMatcher.java @@ -55,4 +55,4 @@ class ClassRegexMatcher extends AbstractFuzzyMatcher> { } return false; } -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/reflect/fuzzy/ClassSetMatcher.java b/modules/API/src/main/java/com/comphenix/protocol/reflect/fuzzy/ClassSetMatcher.java index f67a3634..b85afb8a 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/reflect/fuzzy/ClassSetMatcher.java +++ b/modules/API/src/main/java/com/comphenix/protocol/reflect/fuzzy/ClassSetMatcher.java @@ -54,4 +54,4 @@ class ClassSetMatcher extends AbstractFuzzyMatcher> { } return true; } -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/reflect/instances/CollectionGenerator.java b/modules/API/src/main/java/com/comphenix/protocol/reflect/instances/CollectionGenerator.java index 1e350ad7..1ebade33 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/reflect/instances/CollectionGenerator.java +++ b/modules/API/src/main/java/com/comphenix/protocol/reflect/instances/CollectionGenerator.java @@ -65,4 +65,4 @@ public class CollectionGenerator implements InstanceProvider { // Cannot provide an instance return null; } -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/reflect/instances/InstanceProvider.java b/modules/API/src/main/java/com/comphenix/protocol/reflect/instances/InstanceProvider.java index 0c71ed92..0746d246 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/reflect/instances/InstanceProvider.java +++ b/modules/API/src/main/java/com/comphenix/protocol/reflect/instances/InstanceProvider.java @@ -32,4 +32,4 @@ public interface InstanceProvider { * @throws NotConstructableException Thrown to indicate that this type cannot or should never be constructed. */ public abstract Object create(@Nullable Class type); -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/reflect/instances/PrimitiveGenerator.java b/modules/API/src/main/java/com/comphenix/protocol/reflect/instances/PrimitiveGenerator.java index aaaf19ca..c00c6c0a 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/reflect/instances/PrimitiveGenerator.java +++ b/modules/API/src/main/java/com/comphenix/protocol/reflect/instances/PrimitiveGenerator.java @@ -77,4 +77,4 @@ public class PrimitiveGenerator implements InstanceProvider { // Cannot handle this type return null; } -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/timing/HistogramStream.java b/modules/API/src/main/java/com/comphenix/protocol/timing/HistogramStream.java index 61d325a3..b7f463f6 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/timing/HistogramStream.java +++ b/modules/API/src/main/java/com/comphenix/protocol/timing/HistogramStream.java @@ -122,4 +122,4 @@ public class HistogramStream extends OnlineComputation { public int getCount() { return count; } -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/timing/OnlineComputation.java b/modules/API/src/main/java/com/comphenix/protocol/timing/OnlineComputation.java index 39b641f5..09b9f908 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/timing/OnlineComputation.java +++ b/modules/API/src/main/java/com/comphenix/protocol/timing/OnlineComputation.java @@ -46,4 +46,4 @@ public abstract class OnlineComputation { } }; } -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/timing/StatisticsStream.java b/modules/API/src/main/java/com/comphenix/protocol/timing/StatisticsStream.java index 1c6fc73e..10a7181b 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/timing/StatisticsStream.java +++ b/modules/API/src/main/java/com/comphenix/protocol/timing/StatisticsStream.java @@ -152,4 +152,4 @@ public class StatisticsStream extends OnlineComputation { getMean(), getStandardDeviation(), getMinimum(), getMaximum(), getCount()); } -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/utility/Closer.java b/modules/API/src/main/java/com/comphenix/protocol/utility/Closer.java index 290e0bee..c2ef6cdb 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/utility/Closer.java +++ b/modules/API/src/main/java/com/comphenix/protocol/utility/Closer.java @@ -1,57 +1,57 @@ -/** - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2015 dmulloy2 - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ -package com.comphenix.protocol.utility; - -import java.io.Closeable; -import java.util.ArrayList; -import java.util.List; - -/** - * @author dmulloy2 - */ - -// TODO Switch to AutoCloseable w/ Java 7 -public class Closer implements Closeable { - private final List list; - - private Closer() { - this.list = new ArrayList(); - } - - public static Closer create() { - return new Closer(); - } - - public C register(C close) { - list.add(close); - return close; - } - - @Override - public void close() { - for (Closeable close : list) { - closeQuietly(close); - } - } - - public static void closeQuietly(Closeable close) { - try { - close.close(); - } catch (Throwable ex) { } - } - -} +/** + * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. + * Copyright (C) 2015 dmulloy2 + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ +package com.comphenix.protocol.utility; + +import java.io.Closeable; +import java.util.ArrayList; +import java.util.List; + +/** + * @author dmulloy2 + */ + +// TODO Switch to AutoCloseable w/ Java 7 +public class Closer implements Closeable { + private final List list; + + private Closer() { + this.list = new ArrayList(); + } + + public static Closer create() { + return new Closer(); + } + + public C register(C close) { + list.add(close); + return close; + } + + @Override + public void close() { + for (Closeable close : list) { + closeQuietly(close); + } + } + + public static void closeQuietly(Closeable close) { + try { + close.close(); + } catch (Throwable ex) { } + } + +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/utility/Constants.java b/modules/API/src/main/java/com/comphenix/protocol/utility/Constants.java index 38d1e9d7..0120719e 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/utility/Constants.java +++ b/modules/API/src/main/java/com/comphenix/protocol/utility/Constants.java @@ -1,27 +1,27 @@ -/** - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2015 dmulloy2 - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ -package com.comphenix.protocol.utility; - -/** - * @author dmulloy2 - */ - -public final class Constants { - public static final String PACKAGE_VERSION = "v1_9_R2"; - public static final String NMS = "net.minecraft.server." + PACKAGE_VERSION; - public static final String OBC = "org.bukkit.craftbukkit." + PACKAGE_VERSION; -} \ No newline at end of file +/** + * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. + * Copyright (C) 2015 dmulloy2 + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ +package com.comphenix.protocol.utility; + +/** + * @author dmulloy2 + */ + +public final class Constants { + public static final String PACKAGE_VERSION = "v1_9_R2"; + public static final String NMS = "net.minecraft.server." + PACKAGE_VERSION; + public static final String OBC = "org.bukkit.craftbukkit." + PACKAGE_VERSION; +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java b/modules/API/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java index 658f6120..8d0b9c38 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java +++ b/modules/API/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java @@ -2103,4 +2103,4 @@ public class MinecraftReflection { throw new RuntimeException("Cannot construct packet serializer.", e); } } -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/utility/StreamSerializer.java b/modules/API/src/main/java/com/comphenix/protocol/utility/StreamSerializer.java index 91d8ebd0..d7b62ac5 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/utility/StreamSerializer.java +++ b/modules/API/src/main/java/com/comphenix/protocol/utility/StreamSerializer.java @@ -468,4 +468,4 @@ public class StreamSerializer { else return null; } -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/utility/Util.java b/modules/API/src/main/java/com/comphenix/protocol/utility/Util.java index ff921a87..f6ef046d 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/utility/Util.java +++ b/modules/API/src/main/java/com/comphenix/protocol/utility/Util.java @@ -1,63 +1,63 @@ -/** - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2015 dmulloy2 - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ -package com.comphenix.protocol.utility; - -import java.util.ArrayList; -import java.util.List; - -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; - -/** - * General utility class - * @author dmulloy2 - */ -public class Util { - - /** - * Gets a list of currently online Players. - * @return The list - */ - @SuppressWarnings("unchecked") - public static List getOnlinePlayers() { - return (List) Bukkit.getOnlinePlayers(); - } - - /** - * Converts a variable argument array into a List. - * @param elements Array to convert - * @return The list - */ - @SafeVarargs - public static List asList(E... elements) { - List list = new ArrayList(elements.length); - for (E element : elements) { - list.add(element); - } - - return list; - } - - /** - * Whether or not this server is running Spigot. This works by checking - * the server version for the String "Spigot" - * @return True if it is, false if not. - */ - public static boolean isUsingSpigot() { - return Bukkit.getServer().getVersion().contains("Spigot"); - } -} \ No newline at end of file +/** + * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. + * Copyright (C) 2015 dmulloy2 + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ +package com.comphenix.protocol.utility; + +import java.util.ArrayList; +import java.util.List; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +/** + * General utility class + * @author dmulloy2 + */ +public class Util { + + /** + * Gets a list of currently online Players. + * @return The list + */ + @SuppressWarnings("unchecked") + public static List getOnlinePlayers() { + return (List) Bukkit.getOnlinePlayers(); + } + + /** + * Converts a variable argument array into a List. + * @param elements Array to convert + * @return The list + */ + @SafeVarargs + public static List asList(E... elements) { + List list = new ArrayList(elements.length); + for (E element : elements) { + list.add(element); + } + + return list; + } + + /** + * Whether or not this server is running Spigot. This works by checking + * the server version for the String "Spigot" + * @return True if it is, false if not. + */ + public static boolean isUsingSpigot() { + return Bukkit.getServer().getVersion().contains("Spigot"); + } +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/wrappers/BlockPosition.java b/modules/API/src/main/java/com/comphenix/protocol/wrappers/BlockPosition.java index 323853b1..c1a667a2 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/wrappers/BlockPosition.java +++ b/modules/API/src/main/java/com/comphenix/protocol/wrappers/BlockPosition.java @@ -1,244 +1,244 @@ -/** - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2015 dmulloy2 - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ -package com.comphenix.protocol.wrappers; - -import java.lang.reflect.Constructor; - -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.util.Vector; - -import com.comphenix.protocol.reflect.EquivalentConverter; -import com.comphenix.protocol.reflect.FieldAccessException; -import com.comphenix.protocol.reflect.StructureModifier; -import com.comphenix.protocol.utility.MinecraftReflection; -import com.google.common.base.Objects; - -/** - * Copies a immutable net.minecraft.server.BlockPosition, which represents a integer 3D vector. - * - * @author dmulloy2 - */ -public class BlockPosition { - - /** - * Represents the null (0, 0, 0) origin. - */ - public static BlockPosition ORIGIN = new BlockPosition(0, 0, 0); - - private static Constructor blockPositionConstructor; - - // Use protected members, like Bukkit - protected final int x; - protected final int y; - protected final int z; - - // Used to access a BlockPosition, in case it's names are changed - private static StructureModifier intModifier; - - /** - * Construct an immutable 3D vector. - * @param x - x coordinate - * @param y - y coordinate - * @param z - z coordinate - */ - public BlockPosition(int x, int y, int z) { - this.x = x; - this.y = y; - this.z = z; - } - - /** - * Construct an immutable integer 3D vector from a mutable Bukkit vector. - * @param vector - the mutable real Bukkit vector to copy. - */ - public BlockPosition(Vector vector) { - if (vector == null) - throw new IllegalArgumentException("Vector cannot be NULL."); - this.x = vector.getBlockX(); - this.y = vector.getBlockY(); - this.z = vector.getBlockZ(); - } - - /** - * Convert this instance to an equivalent real 3D vector. - * @return Real 3D vector. - */ - public Vector toVector() { - return new Vector(x, y, z); - } - - /** - * Convert this instance to an equivalent Location. - * @param world World for the location - * @return Location - */ - public Location toLocation(World world) { - return new Location(world, x, y, z); - } - - /** - * Retrieve the x-coordinate. - * @return X coordinate. - */ - public int getX() { - return x; - } - - /** - * Retrieve the y-coordinate. - * @return Y coordinate. - */ - public int getY() { - return y; - } - - /** - * Retrieve the z-coordinate. - * @return Z coordinate. - */ - public int getZ() { - return z; - } - - /** - * Adds the current position and a given position together, producing a result position. - * @param other - the other position. - * @return The new result position. - */ - public BlockPosition add(BlockPosition other) { - if (other == null) - throw new IllegalArgumentException("other cannot be NULL"); - return new BlockPosition(x + other.x, y + other.y, z + other.z); - } - - /** - * Adds the current position and a given position together, producing a result position. - * @param other - the other position. - * @return The new result position. - */ - public BlockPosition subtract(BlockPosition other) { - if (other == null) - throw new IllegalArgumentException("other cannot be NULL"); - return new BlockPosition(x - other.x, y - other.y, z - other.z); - } - - /** - * Multiply each dimension in the current position by the given factor. - * @param factor - multiplier. - * @return The new result. - */ - public BlockPosition multiply(int factor) { - return new BlockPosition(x * factor, y * factor, z * factor); - } - - /** - * Divide each dimension in the current position by the given divisor. - * @param divisor - the divisor. - * @return The new result. - */ - public BlockPosition divide(int divisor) { - if (divisor == 0) - throw new IllegalArgumentException("Cannot divide by null."); - return new BlockPosition(x / divisor, y / divisor, z / divisor); - } - - /** - * Used to convert between NMS ChunkPosition and the wrapper instance. - * @return A new converter. - */ - public static EquivalentConverter getConverter() { - return new EquivalentConverter() { - @Override - public Object getGeneric(Class genericType, BlockPosition specific) { - if (blockPositionConstructor == null) { - try { - blockPositionConstructor = MinecraftReflection.getBlockPositionClass(). - getConstructor(int.class, int.class, int.class); - } catch (Exception e) { - throw new RuntimeException("Cannot find block position constructor.", e); - } - } - - // Construct the underlying BlockPosition - try { - Object result = blockPositionConstructor.newInstance(specific.x, specific.y, specific.z); - return result; - } catch (Exception e) { - throw new RuntimeException("Cannot construct BlockPosition.", e); - } - } - - @Override - public BlockPosition getSpecific(Object generic) { - if (MinecraftReflection.isBlockPosition(generic)) { - // Use a structure modifier - intModifier = new StructureModifier(generic.getClass(), null, false).withType(int.class); - - // Damn it all - if (intModifier.size() < 3) { - throw new IllegalStateException("Cannot read class " + generic.getClass() + " for its integer fields."); - } - - if (intModifier.size() >= 3) { - try { - StructureModifier instance = intModifier.withTarget(generic); - BlockPosition result = new BlockPosition(instance.read(0), instance.read(1), instance.read(2)); - return result; - } catch (FieldAccessException e) { - // This is an exeptional work-around, so we don't want to burden the caller with the messy details - throw new RuntimeException("Field access error.", e); - } - } - } - - // Otherwise, return NULL - return null; - } - - // Thanks Java Generics! - @Override - public Class getSpecificType() { - return BlockPosition.class; - } - }; - } - - @Override - public boolean equals(Object obj) { - // Fast checks - if (this == obj) return true; - if (obj == null) return false; - - // Only compare objects of similar type - if (obj instanceof BlockPosition) { - BlockPosition other = (BlockPosition) obj; - return x == other.x && y == other.y && z == other.z; - } - return false; - } - - @Override - public int hashCode() { - return Objects.hashCode(x, y, z); - } - - @Override - public String toString() { - return "BlockPosition [x=" + x + ", y=" + y + ", z=" + z + "]"; - } -} +/** + * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. + * Copyright (C) 2015 dmulloy2 + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ +package com.comphenix.protocol.wrappers; + +import java.lang.reflect.Constructor; + +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.util.Vector; + +import com.comphenix.protocol.reflect.EquivalentConverter; +import com.comphenix.protocol.reflect.FieldAccessException; +import com.comphenix.protocol.reflect.StructureModifier; +import com.comphenix.protocol.utility.MinecraftReflection; +import com.google.common.base.Objects; + +/** + * Copies a immutable net.minecraft.server.BlockPosition, which represents a integer 3D vector. + * + * @author dmulloy2 + */ +public class BlockPosition { + + /** + * Represents the null (0, 0, 0) origin. + */ + public static BlockPosition ORIGIN = new BlockPosition(0, 0, 0); + + private static Constructor blockPositionConstructor; + + // Use protected members, like Bukkit + protected final int x; + protected final int y; + protected final int z; + + // Used to access a BlockPosition, in case it's names are changed + private static StructureModifier intModifier; + + /** + * Construct an immutable 3D vector. + * @param x - x coordinate + * @param y - y coordinate + * @param z - z coordinate + */ + public BlockPosition(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + /** + * Construct an immutable integer 3D vector from a mutable Bukkit vector. + * @param vector - the mutable real Bukkit vector to copy. + */ + public BlockPosition(Vector vector) { + if (vector == null) + throw new IllegalArgumentException("Vector cannot be NULL."); + this.x = vector.getBlockX(); + this.y = vector.getBlockY(); + this.z = vector.getBlockZ(); + } + + /** + * Convert this instance to an equivalent real 3D vector. + * @return Real 3D vector. + */ + public Vector toVector() { + return new Vector(x, y, z); + } + + /** + * Convert this instance to an equivalent Location. + * @param world World for the location + * @return Location + */ + public Location toLocation(World world) { + return new Location(world, x, y, z); + } + + /** + * Retrieve the x-coordinate. + * @return X coordinate. + */ + public int getX() { + return x; + } + + /** + * Retrieve the y-coordinate. + * @return Y coordinate. + */ + public int getY() { + return y; + } + + /** + * Retrieve the z-coordinate. + * @return Z coordinate. + */ + public int getZ() { + return z; + } + + /** + * Adds the current position and a given position together, producing a result position. + * @param other - the other position. + * @return The new result position. + */ + public BlockPosition add(BlockPosition other) { + if (other == null) + throw new IllegalArgumentException("other cannot be NULL"); + return new BlockPosition(x + other.x, y + other.y, z + other.z); + } + + /** + * Adds the current position and a given position together, producing a result position. + * @param other - the other position. + * @return The new result position. + */ + public BlockPosition subtract(BlockPosition other) { + if (other == null) + throw new IllegalArgumentException("other cannot be NULL"); + return new BlockPosition(x - other.x, y - other.y, z - other.z); + } + + /** + * Multiply each dimension in the current position by the given factor. + * @param factor - multiplier. + * @return The new result. + */ + public BlockPosition multiply(int factor) { + return new BlockPosition(x * factor, y * factor, z * factor); + } + + /** + * Divide each dimension in the current position by the given divisor. + * @param divisor - the divisor. + * @return The new result. + */ + public BlockPosition divide(int divisor) { + if (divisor == 0) + throw new IllegalArgumentException("Cannot divide by null."); + return new BlockPosition(x / divisor, y / divisor, z / divisor); + } + + /** + * Used to convert between NMS ChunkPosition and the wrapper instance. + * @return A new converter. + */ + public static EquivalentConverter getConverter() { + return new EquivalentConverter() { + @Override + public Object getGeneric(Class genericType, BlockPosition specific) { + if (blockPositionConstructor == null) { + try { + blockPositionConstructor = MinecraftReflection.getBlockPositionClass(). + getConstructor(int.class, int.class, int.class); + } catch (Exception e) { + throw new RuntimeException("Cannot find block position constructor.", e); + } + } + + // Construct the underlying BlockPosition + try { + Object result = blockPositionConstructor.newInstance(specific.x, specific.y, specific.z); + return result; + } catch (Exception e) { + throw new RuntimeException("Cannot construct BlockPosition.", e); + } + } + + @Override + public BlockPosition getSpecific(Object generic) { + if (MinecraftReflection.isBlockPosition(generic)) { + // Use a structure modifier + intModifier = new StructureModifier(generic.getClass(), null, false).withType(int.class); + + // Damn it all + if (intModifier.size() < 3) { + throw new IllegalStateException("Cannot read class " + generic.getClass() + " for its integer fields."); + } + + if (intModifier.size() >= 3) { + try { + StructureModifier instance = intModifier.withTarget(generic); + BlockPosition result = new BlockPosition(instance.read(0), instance.read(1), instance.read(2)); + return result; + } catch (FieldAccessException e) { + // This is an exeptional work-around, so we don't want to burden the caller with the messy details + throw new RuntimeException("Field access error.", e); + } + } + } + + // Otherwise, return NULL + return null; + } + + // Thanks Java Generics! + @Override + public Class getSpecificType() { + return BlockPosition.class; + } + }; + } + + @Override + public boolean equals(Object obj) { + // Fast checks + if (this == obj) return true; + if (obj == null) return false; + + // Only compare objects of similar type + if (obj instanceof BlockPosition) { + BlockPosition other = (BlockPosition) obj; + return x == other.x && y == other.y && z == other.z; + } + return false; + } + + @Override + public int hashCode() { + return Objects.hashCode(x, y, z); + } + + @Override + public String toString() { + return "BlockPosition [x=" + x + ", y=" + y + ", z=" + z + "]"; + } +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/wrappers/ComponentConverter.java b/modules/API/src/main/java/com/comphenix/protocol/wrappers/ComponentConverter.java index 9a824472..1af399b8 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/wrappers/ComponentConverter.java +++ b/modules/API/src/main/java/com/comphenix/protocol/wrappers/ComponentConverter.java @@ -1,51 +1,51 @@ -/** - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2015 dmulloy2 - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ -package com.comphenix.protocol.wrappers; - -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.chat.ComponentSerializer; - -/** - * Utility class for converting between the BungeeCord Chat API and ProtocolLib's wrapper - *

- * Note: The BungeeCord Chat API is not included in CraftBukkit. - * @author dmulloy2 - */ - -public final class ComponentConverter { - - private ComponentConverter() { - } - - /** - * Converts a {@link WrappedChatComponent} into an array of {@link BaseComponent}s - * @param wrapper ProtocolLib wrapper - * @return BaseComponent array - */ - public static BaseComponent[] fromWrapper(WrappedChatComponent wrapper) { - return ComponentSerializer.parse(wrapper.getJson()); - } - - /** - * Converts an array of {@link BaseComponent}s into a ProtocolLib wrapper - * @param components BaseComponent array - * @return ProtocolLib wrapper - */ - public static WrappedChatComponent fromBaseComponent(BaseComponent... components) { - return WrappedChatComponent.fromJson(ComponentSerializer.toString(components)); - } -} \ No newline at end of file +/** + * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. + * Copyright (C) 2015 dmulloy2 + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ +package com.comphenix.protocol.wrappers; + +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.chat.ComponentSerializer; + +/** + * Utility class for converting between the BungeeCord Chat API and ProtocolLib's wrapper + *

+ * Note: The BungeeCord Chat API is not included in CraftBukkit. + * @author dmulloy2 + */ + +public final class ComponentConverter { + + private ComponentConverter() { + } + + /** + * Converts a {@link WrappedChatComponent} into an array of {@link BaseComponent}s + * @param wrapper ProtocolLib wrapper + * @return BaseComponent array + */ + public static BaseComponent[] fromWrapper(WrappedChatComponent wrapper) { + return ComponentSerializer.parse(wrapper.getJson()); + } + + /** + * Converts an array of {@link BaseComponent}s into a ProtocolLib wrapper + * @param components BaseComponent array + * @return ProtocolLib wrapper + */ + public static WrappedChatComponent fromBaseComponent(BaseComponent... components) { + return WrappedChatComponent.fromJson(ComponentSerializer.toString(components)); + } +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/wrappers/MinecraftKey.java b/modules/API/src/main/java/com/comphenix/protocol/wrappers/MinecraftKey.java index c758d806..10cb1362 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/wrappers/MinecraftKey.java +++ b/modules/API/src/main/java/com/comphenix/protocol/wrappers/MinecraftKey.java @@ -1,142 +1,142 @@ -/** - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2016 dmulloy2 - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ -package com.comphenix.protocol.wrappers; - -import java.lang.reflect.Constructor; - -import com.comphenix.protocol.reflect.EquivalentConverter; -import com.comphenix.protocol.reflect.StructureModifier; -import com.comphenix.protocol.utility.MinecraftReflection; - -/** - * Represents a MinecraftKey in 1.9. - *

- * Keys are in the format {@code prefix:key} - * - * @author dmulloy2 - */ - -public class MinecraftKey { - private final String prefix; - private final String key; - - /** - * Constructs a new key with a given prefix and key. - * - * @param prefix The prefix, usually minecraft. - * @param key The key, the part we care about - */ - public MinecraftKey(String prefix, String key) { - this.prefix = prefix; - this.key = key; - } - - /** - * Constructs a new key with minecraft prefix and a key. - * @param key The key - */ - public MinecraftKey(String key) { - this("minecraft", key); - } - - /** - * Creates a MinecraftKey wrapper from a Minecraft handle. - * @param handle The handle - * @return The resulting key - */ - public static MinecraftKey fromHandle(Object handle) { - StructureModifier modifier = new StructureModifier(handle.getClass()).withTarget(handle).withType(String.class); - return new MinecraftKey(modifier.read(0), modifier.read(1)); - } - - /** - * Creates a MinecraftKey wrapper from an Enum constant. The resulting key - * is lower case, with underscores replaced by periods. - * @param value The value - * @return The resulting key - */ - public static MinecraftKey fromEnum(Enum value) { - return new MinecraftKey(value.name().toLowerCase().replace("_", ".")); - } - - /** - * Gets the prefix of this MinecraftKey. It is minecraft by default. - * @return The prefix - */ - public String getPrefix() { - return prefix; - } - - /** - * Gets the key of this MinecraftKey. It is generally the important part. - * @return The key - */ - public String getKey() { - return key; - } - - /** - * Gets the full key of this MinecraftKey. It is in the format of - * {@code prefix:key} - * @return The full key - */ - public String getFullKey() { - return prefix + ":" + key; - } - - /** - * Returns this key back into Enum format, upper case with periods replaced - * by underscores. - * @return The enum format - */ - public String getEnumFormat() { - return key.toUpperCase().replace(".", "_"); - } - - private static Constructor constructor = null; - - public static EquivalentConverter getConverter() { - return new EquivalentConverter() { - @Override - public MinecraftKey getSpecific(Object generic) { - return MinecraftKey.fromHandle(generic); - } - - @Override - public Object getGeneric(Class genericType, MinecraftKey specific) { - if (constructor == null) { - try { - constructor = MinecraftReflection.getMinecraftKeyClass().getConstructor(String.class, String.class); - } catch (ReflectiveOperationException e) { - throw new RuntimeException("Failed to obtain MinecraftKey constructor", e); - } - } - - try { - return constructor.newInstance(specific.getPrefix(), specific.getKey()); - } catch (ReflectiveOperationException e) { - throw new RuntimeException("Failed to create new MinecraftKey", e); - } - } - - @Override - public Class getSpecificType() { - return MinecraftKey.class; - } - }; - } -} \ No newline at end of file +/** + * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. + * Copyright (C) 2016 dmulloy2 + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ +package com.comphenix.protocol.wrappers; + +import java.lang.reflect.Constructor; + +import com.comphenix.protocol.reflect.EquivalentConverter; +import com.comphenix.protocol.reflect.StructureModifier; +import com.comphenix.protocol.utility.MinecraftReflection; + +/** + * Represents a MinecraftKey in 1.9. + *

+ * Keys are in the format {@code prefix:key} + * + * @author dmulloy2 + */ + +public class MinecraftKey { + private final String prefix; + private final String key; + + /** + * Constructs a new key with a given prefix and key. + * + * @param prefix The prefix, usually minecraft. + * @param key The key, the part we care about + */ + public MinecraftKey(String prefix, String key) { + this.prefix = prefix; + this.key = key; + } + + /** + * Constructs a new key with minecraft prefix and a key. + * @param key The key + */ + public MinecraftKey(String key) { + this("minecraft", key); + } + + /** + * Creates a MinecraftKey wrapper from a Minecraft handle. + * @param handle The handle + * @return The resulting key + */ + public static MinecraftKey fromHandle(Object handle) { + StructureModifier modifier = new StructureModifier(handle.getClass()).withTarget(handle).withType(String.class); + return new MinecraftKey(modifier.read(0), modifier.read(1)); + } + + /** + * Creates a MinecraftKey wrapper from an Enum constant. The resulting key + * is lower case, with underscores replaced by periods. + * @param value The value + * @return The resulting key + */ + public static MinecraftKey fromEnum(Enum value) { + return new MinecraftKey(value.name().toLowerCase().replace("_", ".")); + } + + /** + * Gets the prefix of this MinecraftKey. It is minecraft by default. + * @return The prefix + */ + public String getPrefix() { + return prefix; + } + + /** + * Gets the key of this MinecraftKey. It is generally the important part. + * @return The key + */ + public String getKey() { + return key; + } + + /** + * Gets the full key of this MinecraftKey. It is in the format of + * {@code prefix:key} + * @return The full key + */ + public String getFullKey() { + return prefix + ":" + key; + } + + /** + * Returns this key back into Enum format, upper case with periods replaced + * by underscores. + * @return The enum format + */ + public String getEnumFormat() { + return key.toUpperCase().replace(".", "_"); + } + + private static Constructor constructor = null; + + public static EquivalentConverter getConverter() { + return new EquivalentConverter() { + @Override + public MinecraftKey getSpecific(Object generic) { + return MinecraftKey.fromHandle(generic); + } + + @Override + public Object getGeneric(Class genericType, MinecraftKey specific) { + if (constructor == null) { + try { + constructor = MinecraftReflection.getMinecraftKeyClass().getConstructor(String.class, String.class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("Failed to obtain MinecraftKey constructor", e); + } + } + + try { + return constructor.newInstance(specific.getPrefix(), specific.getKey()); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("Failed to create new MinecraftKey", e); + } + } + + @Override + public Class getSpecificType() { + return MinecraftKey.class; + } + }; + } +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/wrappers/MultiBlockChangeInfo.java b/modules/API/src/main/java/com/comphenix/protocol/wrappers/MultiBlockChangeInfo.java index 6d87f584..6eb8050c 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/wrappers/MultiBlockChangeInfo.java +++ b/modules/API/src/main/java/com/comphenix/protocol/wrappers/MultiBlockChangeInfo.java @@ -1,268 +1,268 @@ -/** - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2015 dmulloy2 - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ -package com.comphenix.protocol.wrappers; - -import java.lang.reflect.Array; -import java.lang.reflect.Constructor; - -import org.bukkit.Location; -import org.bukkit.World; - -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.reflect.EquivalentConverter; -import com.comphenix.protocol.reflect.StructureModifier; -import com.comphenix.protocol.utility.MinecraftReflection; - -/** - * Represents a single block change. - * - * @author dmulloy2 - */ - -public class MultiBlockChangeInfo { - private static Constructor constructor; - private static Class nmsClass = MinecraftReflection.getMultiBlockChangeInfoClass(); - - private short location; - private WrappedBlockData data; - private ChunkCoordIntPair chunk; - - public MultiBlockChangeInfo(short location, WrappedBlockData data, ChunkCoordIntPair chunk) { - this.location = location; - this.data = data; - this.chunk = chunk; - } - - public MultiBlockChangeInfo(Location location, WrappedBlockData data) { - this.data = data; - this.chunk = new ChunkCoordIntPair(location.getBlockX() >> 4, location.getBlockZ() >> 4); - this.setLocation(location); - } - - /** - * Returns this block change's absolute Location in a given World. - * - * @param world World for the location - * @return This block change's absolute Location - */ - public Location getLocation(World world) { - return new Location(world, getAbsoluteX(), getY(), getAbsoluteZ()); - } - - /** - * Sets this block change's absolute Location. - * - * @param location This block change's new location - */ - public void setLocation(Location location) { - setLocation(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - } - - /** - * Sets this block change's absolute coordinates. - * - * @param x X coordinate - * @param y Y coordinate - * @param z Z coordinate - */ - public void setLocation(int x, int y, int z) { - x = x & 15; - z = z & 15; - - this.location = (short) (x << 12 | z << 8 | y); - } - - /** - * Gets this block change's relative x coordinate. - * - * @return Relative X coordinate - */ - public int getX() { - return location >> 12 & 15; - } - - /** - * Gets this block change's absolute x coordinate. - * - * @return Absolute X coordinate - */ - public int getAbsoluteX() { - return (chunk.getChunkX() << 4) + getX(); - } - - /** - * Sets this block change's absolute x coordinate. - * - * @param x New x coordinate - */ - public void setX(int x) { - setLocation(x, getY(), getZ()); - } - - /** - * Gets this block change's y coordinate. - * - * @return Y coordinate - */ - public int getY() { - return location & 255; - } - - /** - * Sets this block change's y coordinate - * - * @param y New y coordinate - */ - public void setY(int y) { - setLocation(getX(), y, getZ()); - } - - /** - * Gets this block change's relative z coordinate. - * - * @return Relative Z coordinate - */ - public int getZ() { - return location >> 8 & 15; - } - - /** - * Gets this block change's absolute z coordinate. - * - * @return Absolute Z coordinate - */ - public int getAbsoluteZ() { - return (chunk.getChunkZ() << 4) + getZ(); - } - - /** - * Sets this block change's relative z coordinate. - * - * @param z New z coordinate - */ - public void setZ(int z) { - setLocation(getX(), getY(), z); - } - - /** - * Gets this block change's block data. - * - * @return The block data - */ - public WrappedBlockData getData() { - return data; - } - - /** - * Sets this block change's block data. - * - * @param data New block data - */ - public void setData(WrappedBlockData data) { - this.data = data; - } - - /** - * Gets the chunk this block change occured in. - * - * @return The chunk - */ - public ChunkCoordIntPair getChunk() { - return chunk; - } - - public static EquivalentConverter getConverter(final ChunkCoordIntPair chunk) { - return new EquivalentConverter() { - - @Override - public MultiBlockChangeInfo getSpecific(Object generic) { - StructureModifier modifier = new StructureModifier(generic.getClass(), null, false).withTarget(generic); - - StructureModifier shorts = modifier.withType(short.class); - short location = shorts.read(0); - - StructureModifier dataModifier = modifier.withType(MinecraftReflection.getIBlockDataClass(), - BukkitConverters.getWrappedBlockDataConverter()); - WrappedBlockData data = dataModifier.read(0); - - return new MultiBlockChangeInfo(location, data, chunk); - } - - @Override - public Object getGeneric(Class genericType, MultiBlockChangeInfo specific) { - try { - if (constructor == null) { - constructor = nmsClass.getConstructor( - PacketType.Play.Server.MULTI_BLOCK_CHANGE.getPacketClass(), - short.class, - MinecraftReflection.getIBlockDataClass() - ); - } - - return constructor.newInstance( - null, - specific.location, - BukkitConverters.getWrappedBlockDataConverter().getGeneric(MinecraftReflection.getIBlockDataClass(), specific.data) - ); - } catch (Throwable ex) { - throw new RuntimeException("Failed to construct MultiBlockChangeInfo instance.", ex); - } - } - - @Override - public Class getSpecificType() { - return MultiBlockChangeInfo.class; - } - }; - } - - public static EquivalentConverter getArrayConverter(final ChunkCoordIntPair chunk) { - return new EquivalentConverter() { - private final EquivalentConverter converter = MultiBlockChangeInfo.getConverter(chunk); - - @Override - public MultiBlockChangeInfo[] getSpecific(Object generic) { - Object[] array = (Object[]) generic; - MultiBlockChangeInfo[] result = new MultiBlockChangeInfo[array.length]; - - // Unwrap every item - for (int i = 0; i < result.length; i++) { - result[i] = converter.getSpecific(array[i]); - } - - return result; - } - - @Override - public Object getGeneric(Class genericType, MultiBlockChangeInfo[] specific) { - Object[] result = (Object[]) Array.newInstance(nmsClass, specific.length); - - // Wrap every item - for (int i = 0; i < result.length; i++) { - result[i] = converter.getGeneric(nmsClass, specific[i]); - } - - return result; - } - - @Override - public Class getSpecificType() { - return MultiBlockChangeInfo[].class; - } - }; - } -} \ No newline at end of file +/** + * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. + * Copyright (C) 2015 dmulloy2 + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ +package com.comphenix.protocol.wrappers; + +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; + +import org.bukkit.Location; +import org.bukkit.World; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.reflect.EquivalentConverter; +import com.comphenix.protocol.reflect.StructureModifier; +import com.comphenix.protocol.utility.MinecraftReflection; + +/** + * Represents a single block change. + * + * @author dmulloy2 + */ + +public class MultiBlockChangeInfo { + private static Constructor constructor; + private static Class nmsClass = MinecraftReflection.getMultiBlockChangeInfoClass(); + + private short location; + private WrappedBlockData data; + private ChunkCoordIntPair chunk; + + public MultiBlockChangeInfo(short location, WrappedBlockData data, ChunkCoordIntPair chunk) { + this.location = location; + this.data = data; + this.chunk = chunk; + } + + public MultiBlockChangeInfo(Location location, WrappedBlockData data) { + this.data = data; + this.chunk = new ChunkCoordIntPair(location.getBlockX() >> 4, location.getBlockZ() >> 4); + this.setLocation(location); + } + + /** + * Returns this block change's absolute Location in a given World. + * + * @param world World for the location + * @return This block change's absolute Location + */ + public Location getLocation(World world) { + return new Location(world, getAbsoluteX(), getY(), getAbsoluteZ()); + } + + /** + * Sets this block change's absolute Location. + * + * @param location This block change's new location + */ + public void setLocation(Location location) { + setLocation(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + } + + /** + * Sets this block change's absolute coordinates. + * + * @param x X coordinate + * @param y Y coordinate + * @param z Z coordinate + */ + public void setLocation(int x, int y, int z) { + x = x & 15; + z = z & 15; + + this.location = (short) (x << 12 | z << 8 | y); + } + + /** + * Gets this block change's relative x coordinate. + * + * @return Relative X coordinate + */ + public int getX() { + return location >> 12 & 15; + } + + /** + * Gets this block change's absolute x coordinate. + * + * @return Absolute X coordinate + */ + public int getAbsoluteX() { + return (chunk.getChunkX() << 4) + getX(); + } + + /** + * Sets this block change's absolute x coordinate. + * + * @param x New x coordinate + */ + public void setX(int x) { + setLocation(x, getY(), getZ()); + } + + /** + * Gets this block change's y coordinate. + * + * @return Y coordinate + */ + public int getY() { + return location & 255; + } + + /** + * Sets this block change's y coordinate + * + * @param y New y coordinate + */ + public void setY(int y) { + setLocation(getX(), y, getZ()); + } + + /** + * Gets this block change's relative z coordinate. + * + * @return Relative Z coordinate + */ + public int getZ() { + return location >> 8 & 15; + } + + /** + * Gets this block change's absolute z coordinate. + * + * @return Absolute Z coordinate + */ + public int getAbsoluteZ() { + return (chunk.getChunkZ() << 4) + getZ(); + } + + /** + * Sets this block change's relative z coordinate. + * + * @param z New z coordinate + */ + public void setZ(int z) { + setLocation(getX(), getY(), z); + } + + /** + * Gets this block change's block data. + * + * @return The block data + */ + public WrappedBlockData getData() { + return data; + } + + /** + * Sets this block change's block data. + * + * @param data New block data + */ + public void setData(WrappedBlockData data) { + this.data = data; + } + + /** + * Gets the chunk this block change occured in. + * + * @return The chunk + */ + public ChunkCoordIntPair getChunk() { + return chunk; + } + + public static EquivalentConverter getConverter(final ChunkCoordIntPair chunk) { + return new EquivalentConverter() { + + @Override + public MultiBlockChangeInfo getSpecific(Object generic) { + StructureModifier modifier = new StructureModifier(generic.getClass(), null, false).withTarget(generic); + + StructureModifier shorts = modifier.withType(short.class); + short location = shorts.read(0); + + StructureModifier dataModifier = modifier.withType(MinecraftReflection.getIBlockDataClass(), + BukkitConverters.getWrappedBlockDataConverter()); + WrappedBlockData data = dataModifier.read(0); + + return new MultiBlockChangeInfo(location, data, chunk); + } + + @Override + public Object getGeneric(Class genericType, MultiBlockChangeInfo specific) { + try { + if (constructor == null) { + constructor = nmsClass.getConstructor( + PacketType.Play.Server.MULTI_BLOCK_CHANGE.getPacketClass(), + short.class, + MinecraftReflection.getIBlockDataClass() + ); + } + + return constructor.newInstance( + null, + specific.location, + BukkitConverters.getWrappedBlockDataConverter().getGeneric(MinecraftReflection.getIBlockDataClass(), specific.data) + ); + } catch (Throwable ex) { + throw new RuntimeException("Failed to construct MultiBlockChangeInfo instance.", ex); + } + } + + @Override + public Class getSpecificType() { + return MultiBlockChangeInfo.class; + } + }; + } + + public static EquivalentConverter getArrayConverter(final ChunkCoordIntPair chunk) { + return new EquivalentConverter() { + private final EquivalentConverter converter = MultiBlockChangeInfo.getConverter(chunk); + + @Override + public MultiBlockChangeInfo[] getSpecific(Object generic) { + Object[] array = (Object[]) generic; + MultiBlockChangeInfo[] result = new MultiBlockChangeInfo[array.length]; + + // Unwrap every item + for (int i = 0; i < result.length; i++) { + result[i] = converter.getSpecific(array[i]); + } + + return result; + } + + @Override + public Object getGeneric(Class genericType, MultiBlockChangeInfo[] specific) { + Object[] result = (Object[]) Array.newInstance(nmsClass, specific.length); + + // Wrap every item + for (int i = 0; i < result.length; i++) { + result[i] = converter.getGeneric(nmsClass, specific[i]); + } + + return result; + } + + @Override + public Class getSpecificType() { + return MultiBlockChangeInfo[].class; + } + }; + } +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/wrappers/PlayerInfoData.java b/modules/API/src/main/java/com/comphenix/protocol/wrappers/PlayerInfoData.java index b82468b8..77a6e390 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/wrappers/PlayerInfoData.java +++ b/modules/API/src/main/java/com/comphenix/protocol/wrappers/PlayerInfoData.java @@ -1,189 +1,189 @@ -/** - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2015 dmulloy2 - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ -package com.comphenix.protocol.wrappers; - -import java.lang.reflect.Constructor; - -import com.comphenix.protocol.reflect.EquivalentConverter; -import com.comphenix.protocol.reflect.StructureModifier; -import com.comphenix.protocol.utility.MinecraftReflection; -import com.comphenix.protocol.wrappers.EnumWrappers.NativeGameMode; -import com.google.common.base.Objects; - -/** - * Represents an immutable PlayerInfoData in the PLAYER_INFO packet. - * @author dmulloy2 - */ -public class PlayerInfoData { - private static Constructor constructor; - - private final int latency; - private final NativeGameMode gameMode; - private final WrappedGameProfile profile; - private final WrappedChatComponent displayName; - - // This is the same order as the NMS class, minus the packet (which isn't a field) - public PlayerInfoData(WrappedGameProfile profile, int latency, NativeGameMode gameMode, WrappedChatComponent displayName) { - this.profile = profile; - this.latency = latency; - this.gameMode = gameMode; - this.displayName = displayName; - } - - /** - * Gets the GameProfile of the player represented by this data. - * @return The GameProfile - */ - public WrappedGameProfile getProfile() { - return profile; - } - - /** - * @deprecated Replaced by {@link #getLatency()} - */ - @Deprecated - public int getPing() { - return latency; - } - - /** - * Gets the latency between the client and the server. - * @return The latency - */ - public int getLatency() { - return latency; - } - - /** - * Gets the GameMode of the player represented by this data. - * @return The GameMode - */ - public NativeGameMode getGameMode() { - return gameMode; - } - - /** - * Gets the display name of the player represented by this data. - * @return The display name - */ - public WrappedChatComponent getDisplayName() { - return displayName; - } - - /** - * Used to convert between NMS PlayerInfoData and the wrapper instance. - * @return A new converter. - */ - public static EquivalentConverter getConverter() { - return new EquivalentConverter() { - @Override - public Object getGeneric(Class genericType, PlayerInfoData specific) { - if (constructor == null) { - try { - // public PlayerInfoData(Packet, GameProfile, int, GameMode, ChatComponent) - constructor = MinecraftReflection.getPlayerInfoDataClass().getConstructor( - MinecraftReflection.getMinecraftClass("PacketPlayOutPlayerInfo"), - MinecraftReflection.getGameProfileClass(), - int.class, - EnumWrappers.getGameModeClass(), - MinecraftReflection.getIChatBaseComponentClass() - ); - } catch (Exception e) { - throw new RuntimeException("Cannot find PlayerInfoData constructor.", e); - } - } - - // Attempt to construct the underlying PlayerInfoData - - try { - // public PlayerInfoData(null, GameProfile, ping, GameMode, ChatComponent) - // The packet isn't a field, so it can be null - Object result = constructor.newInstance( - null, - specific.profile.handle, - specific.latency, - EnumWrappers.getGameModeConverter().getGeneric(EnumWrappers.getGameModeClass(), specific.gameMode), - specific.displayName != null ? specific.displayName.handle : null - ); - return result; - } catch (Exception e) { - throw new RuntimeException("Failed to construct PlayerInfoData.", e); - } - } - - @Override - public PlayerInfoData getSpecific(Object generic) { - if (MinecraftReflection.isPlayerInfoData(generic)) { - StructureModifier modifier = new StructureModifier(generic.getClass(), null, false) - .withTarget(generic); - - StructureModifier gameProfiles = modifier.withType( - MinecraftReflection.getGameProfileClass(), BukkitConverters.getWrappedGameProfileConverter()); - WrappedGameProfile gameProfile = gameProfiles.read(0); - - StructureModifier ints = modifier.withType(int.class); - int latency = ints.read(0); - - StructureModifier gameModes = modifier.withType( - EnumWrappers.getGameModeClass(), EnumWrappers.getGameModeConverter()); - NativeGameMode gameMode = gameModes.read(0); - - StructureModifier displayNames = modifier.withType( - MinecraftReflection.getIChatBaseComponentClass(), BukkitConverters.getWrappedChatComponentConverter()); - WrappedChatComponent displayName = displayNames.read(0); - - return new PlayerInfoData(gameProfile, latency, gameMode, displayName); - } - - // Otherwise, return null - return null; - } - - // Thanks Java Generics! - @Override - public Class getSpecificType() { - return PlayerInfoData.class; - } - }; - } - - @Override - public boolean equals(Object obj) { - // Fast checks - if (this == obj) return true; - if (obj == null) return false; - - // Only compare objects of similar type - if (obj instanceof PlayerInfoData) { - PlayerInfoData other = (PlayerInfoData) obj; - return profile.equals(other.profile) && latency == other.latency && gameMode == other.gameMode - && displayName.equals(other.displayName); - } - return false; - } - - @Override - public int hashCode() { - return Objects.hashCode(latency, gameMode, profile, displayName); - } - - @Override - public String toString() { - return String.format("PlayerInfoData[latency=%s, gameMode=%s, profile=%s, displayName=%s", - latency, gameMode, profile, displayName); - } -} +/** + * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. + * Copyright (C) 2015 dmulloy2 + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ +package com.comphenix.protocol.wrappers; + +import java.lang.reflect.Constructor; + +import com.comphenix.protocol.reflect.EquivalentConverter; +import com.comphenix.protocol.reflect.StructureModifier; +import com.comphenix.protocol.utility.MinecraftReflection; +import com.comphenix.protocol.wrappers.EnumWrappers.NativeGameMode; +import com.google.common.base.Objects; + +/** + * Represents an immutable PlayerInfoData in the PLAYER_INFO packet. + * @author dmulloy2 + */ +public class PlayerInfoData { + private static Constructor constructor; + + private final int latency; + private final NativeGameMode gameMode; + private final WrappedGameProfile profile; + private final WrappedChatComponent displayName; + + // This is the same order as the NMS class, minus the packet (which isn't a field) + public PlayerInfoData(WrappedGameProfile profile, int latency, NativeGameMode gameMode, WrappedChatComponent displayName) { + this.profile = profile; + this.latency = latency; + this.gameMode = gameMode; + this.displayName = displayName; + } + + /** + * Gets the GameProfile of the player represented by this data. + * @return The GameProfile + */ + public WrappedGameProfile getProfile() { + return profile; + } + + /** + * @deprecated Replaced by {@link #getLatency()} + */ + @Deprecated + public int getPing() { + return latency; + } + + /** + * Gets the latency between the client and the server. + * @return The latency + */ + public int getLatency() { + return latency; + } + + /** + * Gets the GameMode of the player represented by this data. + * @return The GameMode + */ + public NativeGameMode getGameMode() { + return gameMode; + } + + /** + * Gets the display name of the player represented by this data. + * @return The display name + */ + public WrappedChatComponent getDisplayName() { + return displayName; + } + + /** + * Used to convert between NMS PlayerInfoData and the wrapper instance. + * @return A new converter. + */ + public static EquivalentConverter getConverter() { + return new EquivalentConverter() { + @Override + public Object getGeneric(Class genericType, PlayerInfoData specific) { + if (constructor == null) { + try { + // public PlayerInfoData(Packet, GameProfile, int, GameMode, ChatComponent) + constructor = MinecraftReflection.getPlayerInfoDataClass().getConstructor( + MinecraftReflection.getMinecraftClass("PacketPlayOutPlayerInfo"), + MinecraftReflection.getGameProfileClass(), + int.class, + EnumWrappers.getGameModeClass(), + MinecraftReflection.getIChatBaseComponentClass() + ); + } catch (Exception e) { + throw new RuntimeException("Cannot find PlayerInfoData constructor.", e); + } + } + + // Attempt to construct the underlying PlayerInfoData + + try { + // public PlayerInfoData(null, GameProfile, ping, GameMode, ChatComponent) + // The packet isn't a field, so it can be null + Object result = constructor.newInstance( + null, + specific.profile.handle, + specific.latency, + EnumWrappers.getGameModeConverter().getGeneric(EnumWrappers.getGameModeClass(), specific.gameMode), + specific.displayName != null ? specific.displayName.handle : null + ); + return result; + } catch (Exception e) { + throw new RuntimeException("Failed to construct PlayerInfoData.", e); + } + } + + @Override + public PlayerInfoData getSpecific(Object generic) { + if (MinecraftReflection.isPlayerInfoData(generic)) { + StructureModifier modifier = new StructureModifier(generic.getClass(), null, false) + .withTarget(generic); + + StructureModifier gameProfiles = modifier.withType( + MinecraftReflection.getGameProfileClass(), BukkitConverters.getWrappedGameProfileConverter()); + WrappedGameProfile gameProfile = gameProfiles.read(0); + + StructureModifier ints = modifier.withType(int.class); + int latency = ints.read(0); + + StructureModifier gameModes = modifier.withType( + EnumWrappers.getGameModeClass(), EnumWrappers.getGameModeConverter()); + NativeGameMode gameMode = gameModes.read(0); + + StructureModifier displayNames = modifier.withType( + MinecraftReflection.getIChatBaseComponentClass(), BukkitConverters.getWrappedChatComponentConverter()); + WrappedChatComponent displayName = displayNames.read(0); + + return new PlayerInfoData(gameProfile, latency, gameMode, displayName); + } + + // Otherwise, return null + return null; + } + + // Thanks Java Generics! + @Override + public Class getSpecificType() { + return PlayerInfoData.class; + } + }; + } + + @Override + public boolean equals(Object obj) { + // Fast checks + if (this == obj) return true; + if (obj == null) return false; + + // Only compare objects of similar type + if (obj instanceof PlayerInfoData) { + PlayerInfoData other = (PlayerInfoData) obj; + return profile.equals(other.profile) && latency == other.latency && gameMode == other.gameMode + && displayName.equals(other.displayName); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hashCode(latency, gameMode, profile, displayName); + } + + @Override + public String toString() { + return String.format("PlayerInfoData[latency=%s, gameMode=%s, profile=%s, displayName=%s", + latency, gameMode, profile, displayName); + } +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/wrappers/WrappedBlockData.java b/modules/API/src/main/java/com/comphenix/protocol/wrappers/WrappedBlockData.java index 87e8a5a1..ed08cb30 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/wrappers/WrappedBlockData.java +++ b/modules/API/src/main/java/com/comphenix/protocol/wrappers/WrappedBlockData.java @@ -1,166 +1,166 @@ -/** - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2015 dmulloy2 - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ -package com.comphenix.protocol.wrappers; - -import java.lang.reflect.Modifier; - -import org.bukkit.Material; - -import com.comphenix.protocol.reflect.FuzzyReflection; -import com.comphenix.protocol.reflect.accessors.Accessors; -import com.comphenix.protocol.reflect.accessors.MethodAccessor; -import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract; -import com.comphenix.protocol.utility.MinecraftReflection; - -/** - * Represents a wrapper around IBlockData. - * - * @author dmulloy2 - */ - -public class WrappedBlockData extends AbstractWrapper { - private static final Class MAGIC_NUMBERS = MinecraftReflection.getCraftBukkitClass("util.CraftMagicNumbers"); - private static final Class IBLOCK_DATA = MinecraftReflection.getIBlockDataClass(); - private static final Class BLOCK = MinecraftReflection.getBlockClass(); - - private static MethodAccessor FROM_LEGACY_DATA = null; - private static MethodAccessor TO_LEGACY_DATA = null; - private static MethodAccessor GET_NMS_BLOCK = null; - private static MethodAccessor GET_BLOCK = null; - - static { - FuzzyReflection fuzzy = FuzzyReflection.fromClass(BLOCK); - FuzzyMethodContract contract = FuzzyMethodContract.newBuilder() - .banModifier(Modifier.STATIC) - .parameterExactArray(int.class) - .returnTypeExact(IBLOCK_DATA) - .build(); - FROM_LEGACY_DATA = Accessors.getMethodAccessor(fuzzy.getMethod(contract)); - - contract = FuzzyMethodContract.newBuilder() - .banModifier(Modifier.STATIC) - .parameterExactArray(IBLOCK_DATA) - .returnTypeExact(int.class) - .build(); - TO_LEGACY_DATA = Accessors.getMethodAccessor(fuzzy.getMethod(contract, "toLegacyData")); - - fuzzy = FuzzyReflection.fromClass(MAGIC_NUMBERS); - GET_NMS_BLOCK = Accessors.getMethodAccessor(fuzzy.getMethodByParameters("getBlock", BLOCK, - new Class[] { Material.class })); - - fuzzy = FuzzyReflection.fromClass(IBLOCK_DATA); - GET_BLOCK = Accessors.getMethodAccessor(fuzzy.getMethodByParameters("getBlock", BLOCK, - new Class[0])); - } - - public WrappedBlockData(Object handle) { - super(IBLOCK_DATA); - setHandle(handle); - } - - /** - * Retrieves the type of this BlockData. - * @return The type of this BlockData. - */ - public Material getType() { - Object block = GET_BLOCK.invoke(handle); - return BukkitConverters.getBlockConverter().getSpecific(block); - } - - /** - * Retrieves the type id of this BlockData. - * @return The type id of this BlockData. - * @deprecated ID's are deprecated - */ - @Deprecated - public int getTypeId() { - Object block = GET_BLOCK.invoke(handle); - return BukkitConverters.getBlockIDConverter().getSpecific(block); - } - - /** - * Retrieves the data of this BlockData. - * @return The data of this BlockData. - */ - public int getData() { - Object block = GET_BLOCK.invoke(handle); - return (Integer) TO_LEGACY_DATA.invoke(block, handle); - } - - /** - * Sets the type of this BlockData. - * @param type New type - */ - public void setType(Material type) { - setTypeAndData(type, 0); - } - - /** - * Sets the data of this BlockData. - * @param data New data - */ - public void setData(int data) { - setTypeAndData(getType(), data); - } - - /** - * Sets the type and data of this BlockData. - * @param type New type - * @param data New data - */ - public void setTypeAndData(Material type, int data) { - Object nmsBlock = GET_NMS_BLOCK.invoke(null, type); - Object blockData = FROM_LEGACY_DATA.invoke(nmsBlock, data); - setHandle(blockData); - } - - /** - * Creates a new BlockData instance with the given type and no data. - * @param type Block type - * @return New BlockData - */ - public static WrappedBlockData createData(Material type) { - return createData(type, 0); - } - - /** - * Creates a new BlockData instance with the given type and data. - * @param type Block type - * @param data Block data - * @return New BlockData - */ - public static WrappedBlockData createData(Material type, int data) { - Object nmsBlock = GET_NMS_BLOCK.invoke(null, type); - Object blockData = FROM_LEGACY_DATA.invoke(nmsBlock, data); - return new WrappedBlockData(blockData); - } - - @Override - public String toString() { - return "WrappedBlockData[handle=" + handle + "]"; - } - - @Override - public boolean equals(Object o) { - if (o instanceof WrappedBlockData) { - WrappedBlockData that = (WrappedBlockData) o; - return this.getType() == that.getType(); - } - - return false; - } -} \ No newline at end of file +/** + * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. + * Copyright (C) 2015 dmulloy2 + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ +package com.comphenix.protocol.wrappers; + +import java.lang.reflect.Modifier; + +import org.bukkit.Material; + +import com.comphenix.protocol.reflect.FuzzyReflection; +import com.comphenix.protocol.reflect.accessors.Accessors; +import com.comphenix.protocol.reflect.accessors.MethodAccessor; +import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract; +import com.comphenix.protocol.utility.MinecraftReflection; + +/** + * Represents a wrapper around IBlockData. + * + * @author dmulloy2 + */ + +public class WrappedBlockData extends AbstractWrapper { + private static final Class MAGIC_NUMBERS = MinecraftReflection.getCraftBukkitClass("util.CraftMagicNumbers"); + private static final Class IBLOCK_DATA = MinecraftReflection.getIBlockDataClass(); + private static final Class BLOCK = MinecraftReflection.getBlockClass(); + + private static MethodAccessor FROM_LEGACY_DATA = null; + private static MethodAccessor TO_LEGACY_DATA = null; + private static MethodAccessor GET_NMS_BLOCK = null; + private static MethodAccessor GET_BLOCK = null; + + static { + FuzzyReflection fuzzy = FuzzyReflection.fromClass(BLOCK); + FuzzyMethodContract contract = FuzzyMethodContract.newBuilder() + .banModifier(Modifier.STATIC) + .parameterExactArray(int.class) + .returnTypeExact(IBLOCK_DATA) + .build(); + FROM_LEGACY_DATA = Accessors.getMethodAccessor(fuzzy.getMethod(contract)); + + contract = FuzzyMethodContract.newBuilder() + .banModifier(Modifier.STATIC) + .parameterExactArray(IBLOCK_DATA) + .returnTypeExact(int.class) + .build(); + TO_LEGACY_DATA = Accessors.getMethodAccessor(fuzzy.getMethod(contract, "toLegacyData")); + + fuzzy = FuzzyReflection.fromClass(MAGIC_NUMBERS); + GET_NMS_BLOCK = Accessors.getMethodAccessor(fuzzy.getMethodByParameters("getBlock", BLOCK, + new Class[] { Material.class })); + + fuzzy = FuzzyReflection.fromClass(IBLOCK_DATA); + GET_BLOCK = Accessors.getMethodAccessor(fuzzy.getMethodByParameters("getBlock", BLOCK, + new Class[0])); + } + + public WrappedBlockData(Object handle) { + super(IBLOCK_DATA); + setHandle(handle); + } + + /** + * Retrieves the type of this BlockData. + * @return The type of this BlockData. + */ + public Material getType() { + Object block = GET_BLOCK.invoke(handle); + return BukkitConverters.getBlockConverter().getSpecific(block); + } + + /** + * Retrieves the type id of this BlockData. + * @return The type id of this BlockData. + * @deprecated ID's are deprecated + */ + @Deprecated + public int getTypeId() { + Object block = GET_BLOCK.invoke(handle); + return BukkitConverters.getBlockIDConverter().getSpecific(block); + } + + /** + * Retrieves the data of this BlockData. + * @return The data of this BlockData. + */ + public int getData() { + Object block = GET_BLOCK.invoke(handle); + return (Integer) TO_LEGACY_DATA.invoke(block, handle); + } + + /** + * Sets the type of this BlockData. + * @param type New type + */ + public void setType(Material type) { + setTypeAndData(type, 0); + } + + /** + * Sets the data of this BlockData. + * @param data New data + */ + public void setData(int data) { + setTypeAndData(getType(), data); + } + + /** + * Sets the type and data of this BlockData. + * @param type New type + * @param data New data + */ + public void setTypeAndData(Material type, int data) { + Object nmsBlock = GET_NMS_BLOCK.invoke(null, type); + Object blockData = FROM_LEGACY_DATA.invoke(nmsBlock, data); + setHandle(blockData); + } + + /** + * Creates a new BlockData instance with the given type and no data. + * @param type Block type + * @return New BlockData + */ + public static WrappedBlockData createData(Material type) { + return createData(type, 0); + } + + /** + * Creates a new BlockData instance with the given type and data. + * @param type Block type + * @param data Block data + * @return New BlockData + */ + public static WrappedBlockData createData(Material type, int data) { + Object nmsBlock = GET_NMS_BLOCK.invoke(null, type); + Object blockData = FROM_LEGACY_DATA.invoke(nmsBlock, data); + return new WrappedBlockData(blockData); + } + + @Override + public String toString() { + return "WrappedBlockData[handle=" + handle + "]"; + } + + @Override + public boolean equals(Object o) { + if (o instanceof WrappedBlockData) { + WrappedBlockData that = (WrappedBlockData) o; + return this.getType() == that.getType(); + } + + return false; + } +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/wrappers/WrappedChatComponent.java b/modules/API/src/main/java/com/comphenix/protocol/wrappers/WrappedChatComponent.java index 66ab83bb..ccb02e14 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/wrappers/WrappedChatComponent.java +++ b/modules/API/src/main/java/com/comphenix/protocol/wrappers/WrappedChatComponent.java @@ -158,4 +158,4 @@ public class WrappedChatComponent extends AbstractWrapper { public String toString() { return "WrappedChatComponent[json=" + getJson() + "]"; } -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/wrappers/WrappedGameProfile.java b/modules/API/src/main/java/com/comphenix/protocol/wrappers/WrappedGameProfile.java index 2f2960fb..ec6ca5e1 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/wrappers/WrappedGameProfile.java +++ b/modules/API/src/main/java/com/comphenix/protocol/wrappers/WrappedGameProfile.java @@ -333,4 +333,4 @@ public class WrappedGameProfile extends AbstractWrapper { return false; } -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/wrappers/WrappedWatchableObject.java b/modules/API/src/main/java/com/comphenix/protocol/wrappers/WrappedWatchableObject.java index c6b778b8..7a854a45 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/wrappers/WrappedWatchableObject.java +++ b/modules/API/src/main/java/com/comphenix/protocol/wrappers/WrappedWatchableObject.java @@ -1,232 +1,232 @@ -/** - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2016 dmulloy2 - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ -package com.comphenix.protocol.wrappers; - -import org.bukkit.inventory.ItemStack; - -import com.comphenix.protocol.reflect.StructureModifier; -import com.comphenix.protocol.reflect.accessors.Accessors; -import com.comphenix.protocol.reflect.accessors.ConstructorAccessor; -import com.comphenix.protocol.utility.MinecraftReflection; -import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject; - -/** - * Represents a DataWatcher Item in 1.9. - * @author dmulloy2 - */ - -public class WrappedWatchableObject extends AbstractWrapper { - private static final Class HANDLE_TYPE = MinecraftReflection.getDataWatcherItemClass(); - private static ConstructorAccessor constructor; - - private final StructureModifier modifier; - - /** - * Constructs a wrapped watchable object around an existing NMS data watcher item. - * @param handle Data watcher item - */ - public WrappedWatchableObject(Object handle) { - super(HANDLE_TYPE); - setHandle(handle); - this.modifier = new StructureModifier(handleType).withTarget(handle); - } - - /** - * Constructs a wrapped watchable object with a given watcher object and initial value. - * @param watcherObject Watcher object - * @param value Initial value - */ - public WrappedWatchableObject(WrappedDataWatcherObject watcherObject, Object value) { - this(newHandle(watcherObject, value)); - } - - private static Object newHandle(WrappedDataWatcherObject watcherObject, Object value) { - if (constructor == null) { - constructor = Accessors.getConstructorAccessor(HANDLE_TYPE.getConstructors()[0]); - } - - return constructor.invoke(watcherObject.getHandle(), value); - } - - // ---- Getter methods - - /** - * Gets this Item's watcher object, which contains the index and serializer. - * @return The watcher object - */ - public WrappedDataWatcherObject getWatcherObject() { - return new WrappedDataWatcherObject(modifier.read(0)); - } - - /** - * Gets this Item's index from the watcher object - * @return The index - */ - public int getIndex() { - return getWatcherObject().getIndex(); - } - - /** - * Gets the wrapped value of this data watcher item. - * @return The wrapped value - */ - public Object getValue() { - return getWrapped(getRawValue()); - } - - /** - * Gets the raw value of this data watcher item. - * @return Raw value - */ - public Object getRawValue() { - return modifier.readSafely(1); - } - - /** - * Retrieve the wrapped object value, if needed. - * - * @param value - the raw NMS object to wrap. - * @return The wrapped object. - */ - @SuppressWarnings("rawtypes") - static Object getWrapped(Object value) { - // Handle the special cases - if (MinecraftReflection.isItemStack(value)) { - return BukkitConverters.getItemStackConverter().getSpecific(value); - } else if (MinecraftReflection.isChunkCoordinates(value)) { - return new WrappedChunkCoordinate((Comparable) value); - } else { - return value; - } - } - - /** - * Retrieve the wrapped type, if needed. - * - * @param wrapped - the wrapped class type. - * @return The wrapped class type. - */ - static Class getWrappedType(Class unwrapped) { - if (unwrapped.equals(MinecraftReflection.getChunkPositionClass())) - return ChunkPosition.class; - else if (unwrapped.equals(MinecraftReflection.getBlockPositionClass())) - return BlockPosition.class; - else if (unwrapped.equals(MinecraftReflection.getChunkCoordinatesClass())) - return WrappedChunkCoordinate.class; - else if (unwrapped.equals(MinecraftReflection.getItemStackClass())) - return ItemStack.class; - else - return unwrapped; - } - - /** - * Sets the value of this item. - * @param value New value - * @param updateClient Whether or not to update the client - */ - public void setValue(Object value, boolean updateClient) { - modifier.write(1, getUnwrapped(value)); - - if (updateClient) { - setDirtyState(true); - } - } - - /** - * Sets the value of this item. - * @param value New value - */ - public void setValue(Object value) { - setValue(value, false); - } - - /** - * Retrieve the raw NMS value. - * - * @param wrapped - the wrapped position. - * @return The raw NMS object. - */ - static Object getUnwrapped(Object wrapped) { - // Convert special cases - if (wrapped instanceof ChunkPosition) - return ChunkPosition.getConverter().getGeneric(MinecraftReflection.getChunkPositionClass(), (ChunkPosition) wrapped); - else if (wrapped instanceof BlockPosition) - return BlockPosition.getConverter().getGeneric(MinecraftReflection.getBlockPositionClass(), (BlockPosition) wrapped); - else if (wrapped instanceof WrappedChunkCoordinate) - return ((WrappedChunkCoordinate) wrapped).getHandle(); - else if (wrapped instanceof ItemStack) - return BukkitConverters.getItemStackConverter().getGeneric(MinecraftReflection.getItemStackClass(), (ItemStack) wrapped); - else - return wrapped; - } - - /** - * Retrieve the unwrapped type, if needed. - * - * @param wrapped - the unwrapped class type. - * @return The unwrapped class type. - */ - static Class getUnwrappedType(Class wrapped) { - if (wrapped.equals(ChunkPosition.class)) - return MinecraftReflection.getChunkPositionClass(); - else if (wrapped.equals(BlockPosition.class)) - return MinecraftReflection.getBlockPositionClass(); - else if (wrapped.equals(WrappedChunkCoordinate.class)) - return MinecraftReflection.getChunkCoordinatesClass(); - else if (ItemStack.class.isAssignableFrom(wrapped)) - return MinecraftReflection.getItemStackClass(); - else - return wrapped; - } - - /** - * Whether or not the value must be synchronized with the client. - * @return True if it must, false if not - */ - public boolean getDirtyState() { - return (boolean) modifier.read(2); - } - - /** - * Sets this item's dirty state - * @param dirty New state - */ - public void setDirtyState(boolean dirty) { - modifier.write(2, dirty); - } - - @Override - public boolean equals(Object obj) { - if (obj == this) return true; - if (obj == null) return false; - - if (obj instanceof WrappedWatchableObject) { - // watcher object, value, dirty state - WrappedWatchableObject other = (WrappedWatchableObject) obj; - return getWatcherObject().equals(other.getWatcherObject()) - && getRawValue().equals(other.getRawValue()) - && getDirtyState() == other.getDirtyState(); - } - - return false; - } - - @Override - public String toString() { - return "DataWatcherItem[object=" + getWatcherObject() + ", value=" + getValue() + ", dirty=" + getDirtyState() + "]"; - } -} \ No newline at end of file +/** + * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. + * Copyright (C) 2016 dmulloy2 + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ +package com.comphenix.protocol.wrappers; + +import org.bukkit.inventory.ItemStack; + +import com.comphenix.protocol.reflect.StructureModifier; +import com.comphenix.protocol.reflect.accessors.Accessors; +import com.comphenix.protocol.reflect.accessors.ConstructorAccessor; +import com.comphenix.protocol.utility.MinecraftReflection; +import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject; + +/** + * Represents a DataWatcher Item in 1.9. + * @author dmulloy2 + */ + +public class WrappedWatchableObject extends AbstractWrapper { + private static final Class HANDLE_TYPE = MinecraftReflection.getDataWatcherItemClass(); + private static ConstructorAccessor constructor; + + private final StructureModifier modifier; + + /** + * Constructs a wrapped watchable object around an existing NMS data watcher item. + * @param handle Data watcher item + */ + public WrappedWatchableObject(Object handle) { + super(HANDLE_TYPE); + setHandle(handle); + this.modifier = new StructureModifier(handleType).withTarget(handle); + } + + /** + * Constructs a wrapped watchable object with a given watcher object and initial value. + * @param watcherObject Watcher object + * @param value Initial value + */ + public WrappedWatchableObject(WrappedDataWatcherObject watcherObject, Object value) { + this(newHandle(watcherObject, value)); + } + + private static Object newHandle(WrappedDataWatcherObject watcherObject, Object value) { + if (constructor == null) { + constructor = Accessors.getConstructorAccessor(HANDLE_TYPE.getConstructors()[0]); + } + + return constructor.invoke(watcherObject.getHandle(), value); + } + + // ---- Getter methods + + /** + * Gets this Item's watcher object, which contains the index and serializer. + * @return The watcher object + */ + public WrappedDataWatcherObject getWatcherObject() { + return new WrappedDataWatcherObject(modifier.read(0)); + } + + /** + * Gets this Item's index from the watcher object + * @return The index + */ + public int getIndex() { + return getWatcherObject().getIndex(); + } + + /** + * Gets the wrapped value of this data watcher item. + * @return The wrapped value + */ + public Object getValue() { + return getWrapped(getRawValue()); + } + + /** + * Gets the raw value of this data watcher item. + * @return Raw value + */ + public Object getRawValue() { + return modifier.readSafely(1); + } + + /** + * Retrieve the wrapped object value, if needed. + * + * @param value - the raw NMS object to wrap. + * @return The wrapped object. + */ + @SuppressWarnings("rawtypes") + static Object getWrapped(Object value) { + // Handle the special cases + if (MinecraftReflection.isItemStack(value)) { + return BukkitConverters.getItemStackConverter().getSpecific(value); + } else if (MinecraftReflection.isChunkCoordinates(value)) { + return new WrappedChunkCoordinate((Comparable) value); + } else { + return value; + } + } + + /** + * Retrieve the wrapped type, if needed. + * + * @param wrapped - the wrapped class type. + * @return The wrapped class type. + */ + static Class getWrappedType(Class unwrapped) { + if (unwrapped.equals(MinecraftReflection.getChunkPositionClass())) + return ChunkPosition.class; + else if (unwrapped.equals(MinecraftReflection.getBlockPositionClass())) + return BlockPosition.class; + else if (unwrapped.equals(MinecraftReflection.getChunkCoordinatesClass())) + return WrappedChunkCoordinate.class; + else if (unwrapped.equals(MinecraftReflection.getItemStackClass())) + return ItemStack.class; + else + return unwrapped; + } + + /** + * Sets the value of this item. + * @param value New value + * @param updateClient Whether or not to update the client + */ + public void setValue(Object value, boolean updateClient) { + modifier.write(1, getUnwrapped(value)); + + if (updateClient) { + setDirtyState(true); + } + } + + /** + * Sets the value of this item. + * @param value New value + */ + public void setValue(Object value) { + setValue(value, false); + } + + /** + * Retrieve the raw NMS value. + * + * @param wrapped - the wrapped position. + * @return The raw NMS object. + */ + static Object getUnwrapped(Object wrapped) { + // Convert special cases + if (wrapped instanceof ChunkPosition) + return ChunkPosition.getConverter().getGeneric(MinecraftReflection.getChunkPositionClass(), (ChunkPosition) wrapped); + else if (wrapped instanceof BlockPosition) + return BlockPosition.getConverter().getGeneric(MinecraftReflection.getBlockPositionClass(), (BlockPosition) wrapped); + else if (wrapped instanceof WrappedChunkCoordinate) + return ((WrappedChunkCoordinate) wrapped).getHandle(); + else if (wrapped instanceof ItemStack) + return BukkitConverters.getItemStackConverter().getGeneric(MinecraftReflection.getItemStackClass(), (ItemStack) wrapped); + else + return wrapped; + } + + /** + * Retrieve the unwrapped type, if needed. + * + * @param wrapped - the unwrapped class type. + * @return The unwrapped class type. + */ + static Class getUnwrappedType(Class wrapped) { + if (wrapped.equals(ChunkPosition.class)) + return MinecraftReflection.getChunkPositionClass(); + else if (wrapped.equals(BlockPosition.class)) + return MinecraftReflection.getBlockPositionClass(); + else if (wrapped.equals(WrappedChunkCoordinate.class)) + return MinecraftReflection.getChunkCoordinatesClass(); + else if (ItemStack.class.isAssignableFrom(wrapped)) + return MinecraftReflection.getItemStackClass(); + else + return wrapped; + } + + /** + * Whether or not the value must be synchronized with the client. + * @return True if it must, false if not + */ + public boolean getDirtyState() { + return (boolean) modifier.read(2); + } + + /** + * Sets this item's dirty state + * @param dirty New state + */ + public void setDirtyState(boolean dirty) { + modifier.write(2, dirty); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) return true; + if (obj == null) return false; + + if (obj instanceof WrappedWatchableObject) { + // watcher object, value, dirty state + WrappedWatchableObject other = (WrappedWatchableObject) obj; + return getWatcherObject().equals(other.getWatcherObject()) + && getRawValue().equals(other.getRawValue()) + && getDirtyState() == other.getDirtyState(); + } + + return false; + } + + @Override + public String toString() { + return "DataWatcherItem[object=" + getWatcherObject() + ", value=" + getValue() + ", dirty=" + getDirtyState() + "]"; + } +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/wrappers/collection/BiFunction.java b/modules/API/src/main/java/com/comphenix/protocol/wrappers/collection/BiFunction.java index 77fd51c5..f026fbc9 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/wrappers/collection/BiFunction.java +++ b/modules/API/src/main/java/com/comphenix/protocol/wrappers/collection/BiFunction.java @@ -9,4 +9,4 @@ package com.comphenix.protocol.wrappers.collection; */ public interface BiFunction { public TResult apply(T1 arg1, T2 arg2); -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/wrappers/nbt/NbtBase.java b/modules/API/src/main/java/com/comphenix/protocol/wrappers/nbt/NbtBase.java index 36b6df2a..8b7b1bde 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/wrappers/nbt/NbtBase.java +++ b/modules/API/src/main/java/com/comphenix/protocol/wrappers/nbt/NbtBase.java @@ -84,4 +84,4 @@ public interface NbtBase { * @return The cloned tag. */ public abstract NbtBase deepClone(); -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/wrappers/nbt/NbtCompound.java b/modules/API/src/main/java/com/comphenix/protocol/wrappers/nbt/NbtCompound.java index 29c96678..988c7237 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/wrappers/nbt/NbtCompound.java +++ b/modules/API/src/main/java/com/comphenix/protocol/wrappers/nbt/NbtCompound.java @@ -350,4 +350,4 @@ public interface NbtCompound extends NbtBase>>, Iterable< */ @Override public abstract Iterator> iterator(); -} \ No newline at end of file +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/wrappers/nbt/NbtList.java b/modules/API/src/main/java/com/comphenix/protocol/wrappers/nbt/NbtList.java index f7e5be7c..eeb8e24c 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/wrappers/nbt/NbtList.java +++ b/modules/API/src/main/java/com/comphenix/protocol/wrappers/nbt/NbtList.java @@ -137,4 +137,4 @@ public interface NbtList extends NbtBase>>, Iterable< */ @Override public abstract Iterator iterator(); -} \ No newline at end of file +} diff --git a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolLib.java b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolLib.java index 4effdad8..7eaa1594 100644 --- a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolLib.java +++ b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolLib.java @@ -678,4 +678,4 @@ public class ProtocolLib extends JavaPlugin { public Statistics getStatistics() { return statistics; } -} \ No newline at end of file +} diff --git a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/ListenerInvoker.java b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/ListenerInvoker.java index f3992b21..ae773556 100644 --- a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/ListenerInvoker.java +++ b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/ListenerInvoker.java @@ -91,4 +91,4 @@ public interface ListenerInvoker { */ @Deprecated public abstract Class getPacketClassFromID(int packetID, boolean forceVanilla); -} \ No newline at end of file +} diff --git a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/ChannelInjector.java b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/ChannelInjector.java index dc82bbf0..6cdffad3 100644 --- a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/ChannelInjector.java +++ b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/ChannelInjector.java @@ -1,935 +1,935 @@ -/** - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2015 dmulloy2 - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ -package com.comphenix.protocol.injector.netty; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandler; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; -import io.netty.channel.ChannelPipeline; -import io.netty.channel.ChannelPromise; -import io.netty.channel.socket.SocketChannel; -import io.netty.handler.codec.ByteToMessageDecoder; -import io.netty.handler.codec.MessageToByteEncoder; -import io.netty.util.concurrent.GenericFutureListener; -import io.netty.util.internal.TypeParameterMatcher; - -import java.lang.reflect.InvocationTargetException; -import java.net.Socket; -import java.net.SocketAddress; -import java.util.ArrayDeque; -import java.util.Deque; -import java.util.List; -import java.util.ListIterator; -import java.util.Map.Entry; -import java.util.NoSuchElementException; -import java.util.concurrent.Callable; -import java.util.concurrent.ConcurrentMap; - -import net.sf.cglib.proxy.Factory; - -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; - -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.PacketType.Protocol; -import com.comphenix.protocol.ProtocolLibrary; -import com.comphenix.protocol.error.Report; -import com.comphenix.protocol.error.ReportType; -import com.comphenix.protocol.events.ConnectionSide; -import com.comphenix.protocol.events.NetworkMarker; -import com.comphenix.protocol.events.PacketEvent; -import com.comphenix.protocol.injector.NetworkProcessor; -import com.comphenix.protocol.injector.netty.WirePacket; -import com.comphenix.protocol.injector.server.SocketInjector; -import com.comphenix.protocol.reflect.FuzzyReflection; -import com.comphenix.protocol.reflect.VolatileField; -import com.comphenix.protocol.reflect.accessors.Accessors; -import com.comphenix.protocol.reflect.accessors.FieldAccessor; -import com.comphenix.protocol.reflect.accessors.MethodAccessor; -import com.comphenix.protocol.utility.MinecraftFields; -import com.comphenix.protocol.utility.MinecraftMethods; -import com.comphenix.protocol.utility.MinecraftProtocolVersion; -import com.comphenix.protocol.utility.MinecraftReflection; -import com.comphenix.protocol.wrappers.WrappedGameProfile; -import com.google.common.base.Preconditions; -import com.google.common.collect.MapMaker; - -/** - * Represents a channel injector. - * @author Kristian - */ -public class ChannelInjector extends ByteToMessageDecoder implements Injector { - public static final ReportType REPORT_CANNOT_INTERCEPT_SERVER_PACKET = new ReportType("Unable to intercept a written server packet."); - public static final ReportType REPORT_CANNOT_INTERCEPT_CLIENT_PACKET = new ReportType("Unable to intercept a read client packet."); - public static final ReportType REPORT_CANNOT_EXECUTE_IN_CHANNEL_THREAD = new ReportType("Cannot execute code in channel thread."); - public static final ReportType REPORT_CANNOT_FIND_GET_VERSION = new ReportType("Cannot find getVersion() in NetworkMananger"); - public static final ReportType REPORT_CANNOT_SEND_PACKET = new ReportType("Unable to send packet %s to %s"); - - /** - * Indicates that a packet has bypassed packet listeners. - */ - private static final PacketEvent BYPASSED_PACKET = new PacketEvent(ChannelInjector.class); - - // The login packet - private static Class PACKET_LOGIN_CLIENT = null; - private static FieldAccessor LOGIN_GAME_PROFILE = null; - - // Saved accessors - private static MethodAccessor DECODE_BUFFER; - private static MethodAccessor ENCODE_BUFFER; - private static FieldAccessor ENCODER_TYPE_MATCHER; - - // For retrieving the protocol - private static FieldAccessor PROTOCOL_ACCESSOR; - - // For retrieving the protocol version - private static MethodAccessor PROTOCOL_VERSION; - - // The factory that created this injector - private InjectionFactory factory; - - // The player, or temporary player - private Player player; - private Player updated; - private String playerName; - - // The player connection - private Object playerConnection; - - // The current network manager and channel - private final Object networkManager; - private final Channel originalChannel; - private VolatileField channelField; - - // Known network markers - private ConcurrentMap packetMarker = new MapMaker().weakKeys().makeMap(); - - /** - * Indicate that this packet has been processed by event listeners. - *

- * This must never be set outside the channel pipeline's thread. - */ - private PacketEvent currentEvent; - - /** - * A packet event that should be processed by the write method. - */ - private PacketEvent finalEvent; - - /** - * A flag set by the main thread to indiciate that a packet should not be processed. - */ - private final ThreadLocal scheduleProcessPackets = new ThreadLocal() { - @Override - protected Boolean initialValue() { - return true; - }; - }; - - // Other handlers - private ByteToMessageDecoder vanillaDecoder; - private MessageToByteEncoder vanillaEncoder; - - private Deque finishQueue = new ArrayDeque(); - - // The channel listener - private ChannelListener channelListener; - - // Processing network markers - private NetworkProcessor processor; - - // Closed - private boolean injected; - private boolean closed; - - /** - * Construct a new channel injector. - * @param player - the current player, or temporary player. - * @param networkManager - its network manager. - * @param channel - its channel. - * @param channelListener - a listener. - * @param factory - the factory that created this injector - */ - public ChannelInjector(Player player, Object networkManager, Channel channel, ChannelListener channelListener, InjectionFactory factory) { - this.player = Preconditions.checkNotNull(player, "player cannot be NULL"); - this.networkManager = Preconditions.checkNotNull(networkManager, "networkMananger cannot be NULL"); - this.originalChannel = Preconditions.checkNotNull(channel, "channel cannot be NULL"); - this.channelListener = Preconditions.checkNotNull(channelListener, "channelListener cannot be NULL"); - this.factory = Preconditions.checkNotNull(factory, "factory cannot be NULL"); - this.processor = new NetworkProcessor(ProtocolLibrary.getErrorReporter()); - - // Get the channel field - this.channelField = new VolatileField(FuzzyReflection.fromObject(networkManager, true).getFieldByType("channel", Channel.class), - networkManager, true); - } - - /** - * Get the version of the current protocol. - * @return The version. - */ - @Override - public int getProtocolVersion() { - MethodAccessor accessor = PROTOCOL_VERSION; - if (accessor == null) { - try { - accessor = Accessors.getMethodAccessor(networkManager.getClass(), "getVersion"); - } catch (Throwable ex) { - } - } - - if (accessor != null) { - return (Integer) accessor.invoke(networkManager); - } else { - return MinecraftProtocolVersion.getCurrentVersion(); - } - } - - @Override - @SuppressWarnings("unchecked") - public boolean inject() { - synchronized (networkManager) { - if (closed) - return false; - if (originalChannel instanceof Factory) - return false; - if (!originalChannel.isActive()) - return false; - - // Main thread? We should synchronize with the channel thread, otherwise we might see a - // pipeline with only some of the handlers removed - if (Bukkit.isPrimaryThread()) { - // Just like in the close() method, we'll avoid blocking the main thread - executeInChannelThread(new Runnable() { - @Override - public void run() { - inject(); - } - }); - return false; // We don't know - } - - // Don't inject the same channel twice - if (findChannelHandler(originalChannel, ChannelInjector.class) != null) { - return false; - } - - // Get the vanilla decoder, so we don't have to replicate the work - vanillaDecoder = (ByteToMessageDecoder) originalChannel.pipeline().get("decoder"); - vanillaEncoder = (MessageToByteEncoder) originalChannel.pipeline().get("encoder"); - - if (vanillaDecoder == null) - throw new IllegalArgumentException("Unable to find vanilla decoder in " + originalChannel.pipeline() ); - if (vanillaEncoder == null) - throw new IllegalArgumentException("Unable to find vanilla encoder in " + originalChannel.pipeline() ); - patchEncoder(vanillaEncoder); - - if (DECODE_BUFFER == null) - DECODE_BUFFER = Accessors.getMethodAccessor(vanillaDecoder.getClass(), - "decode", ChannelHandlerContext.class, ByteBuf.class, List.class); - if (ENCODE_BUFFER == null) - ENCODE_BUFFER = Accessors.getMethodAccessor(vanillaEncoder.getClass(), - "encode", ChannelHandlerContext.class, Object.class, ByteBuf.class); - - // Intercept sent packets - MessageToByteEncoder protocolEncoder = new MessageToByteEncoder() { - @Override - protected void encode(ChannelHandlerContext ctx, Object packet, ByteBuf output) throws Exception { - if (packet instanceof WirePacket) { - // Special case for wire format - ChannelInjector.this.encodeWirePacket((WirePacket) packet, output); - } else { - ChannelInjector.this.encode(ctx, packet, output); - } - } - - @Override - public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) throws Exception { - super.write(ctx, packet, promise); - ChannelInjector.this.finalWrite(ctx, packet, promise); - } - }; - - // Intercept recieved packets - ChannelInboundHandlerAdapter finishHandler = new ChannelInboundHandlerAdapter() { - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - // Execute context first - ctx.fireChannelRead(msg); - ChannelInjector.this.finishRead(ctx, msg); - } - }; - - // Insert our handlers - note that we effectively replace the vanilla encoder/decoder - originalChannel.pipeline().addBefore("decoder", "protocol_lib_decoder", this); - originalChannel.pipeline().addBefore("protocol_lib_decoder", "protocol_lib_finish", finishHandler); - originalChannel.pipeline().addAfter("encoder", "protocol_lib_encoder", protocolEncoder); - - // Intercept all write methods - channelField.setValue(new ChannelProxy(originalChannel, MinecraftReflection.getPacketClass()) { - // Compatibility with Spigot 1.8 - private final PipelineProxy pipelineProxy = new PipelineProxy(originalChannel.pipeline(), this) { - @Override - public ChannelPipeline addBefore(String baseName, String name, ChannelHandler handler) { - // Correct the position of the decoder - if ("decoder".equals(baseName)) { - if (super.get("protocol_lib_decoder") != null && guessCompression(handler)) { - super.addBefore("protocol_lib_decoder", name, handler); - return this; - } - } - - return super.addBefore(baseName, name, handler); - } - }; - - @Override - public ChannelPipeline pipeline() { - return pipelineProxy; - } - - @Override - protected Callable onMessageScheduled(final Callable callable, FieldAccessor packetAccessor) { - final PacketEvent event = handleScheduled(callable, packetAccessor); - - // Handle cancelled events - if (event != null && event.isCancelled()) - return null; - - return new Callable() { - @Override - public T call() throws Exception { - T result = null; - - // This field must only be updated in the pipeline thread - currentEvent = event; - result = callable.call(); - currentEvent = null; - return result; - } - }; - } - - @Override - protected Runnable onMessageScheduled(final Runnable runnable, FieldAccessor packetAccessor) { - final PacketEvent event = handleScheduled(runnable, packetAccessor); - - // Handle cancelled events - if (event != null && event.isCancelled()) - return null; - - return new Runnable() { - @Override - public void run() { - currentEvent = event; - runnable.run(); - currentEvent = null; - } - }; - } - - protected PacketEvent handleScheduled(Object instance, FieldAccessor accessor) { - // Let the filters handle this packet - Object original = accessor.get(instance); - - // See if we've been instructed not to process packets - if (!scheduleProcessPackets.get()) { - NetworkMarker marker = getMarker(original); - - if (marker != null) { - PacketEvent result = new PacketEvent(ChannelInjector.class); - result.setNetworkMarker(marker); - return result; - } else { - return BYPASSED_PACKET; - } - } - PacketEvent event = processSending(original); - - if (event != null && !event.isCancelled()) { - Object changed = event.getPacket().getHandle(); - - // Change packet to be scheduled - if (original != changed) - accessor.set(instance, changed); - }; - return event != null ? event : BYPASSED_PACKET; - } - }); - - injected = true; - return true; - } - } - - /** - * Determine if the given object is a compressor or decompressor. - * @param handler - object to test. - * @return TRUE if it is, FALSE if not or unknown. - */ - private boolean guessCompression(ChannelHandler handler) { - String className = handler != null ? handler.getClass().getCanonicalName() : ""; - return className.contains("Compressor") || className.contains("Decompressor"); - } - - /** - * Process a given message on the packet listeners. - * @param message - the message/packet. - * @return The resulting message/packet. - */ - private PacketEvent processSending(Object message) { - return channelListener.onPacketSending(ChannelInjector.this, message, getMarker(message)); - } - - /** - * This method patches the encoder so that it skips already created packets. - * @param encoder - the encoder to patch. - */ - private void patchEncoder(MessageToByteEncoder encoder) { - if (ENCODER_TYPE_MATCHER == null) { - ENCODER_TYPE_MATCHER = Accessors.getFieldAccessor(encoder.getClass(), "matcher", true); - } - ENCODER_TYPE_MATCHER.set(encoder, TypeParameterMatcher.get(MinecraftReflection.getPacketClass())); - } - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { - if (channelListener.isDebug()) - cause.printStackTrace(); - super.exceptionCaught(ctx, cause); - } - - protected void encodeWirePacket(WirePacket packet, ByteBuf output) throws Exception { - packet.writeId(output); - packet.writeBytes(output); - } - - /** - * Encode a packet to a byte buffer, taking over for the standard Minecraft encoder. - * @param ctx - the current context. - * @param packet - the packet to encode to a byte array. - * @param output - the output byte array. - * @throws Exception If anything went wrong. - */ - protected void encode(ChannelHandlerContext ctx, Object packet, ByteBuf output) throws Exception { - NetworkMarker marker = null; - PacketEvent event = currentEvent; - - try { - // Skip every kind of non-filtered packet - if (!scheduleProcessPackets.get()) { - return; - } - - // This packet has not been seen by the main thread - if (event == null) { - Class clazz = packet.getClass(); - - // Schedule the transmission on the main thread instead - if (channelListener.hasMainThreadListener(clazz)) { - // Delay the packet - scheduleMainThread(packet); - packet = null; - - } else { - event = processSending(packet); - - // Handle the output - if (event != null) { - packet = !event.isCancelled() ? event.getPacket().getHandle() : null; - } - } - } - if (event != null) { - // Retrieve marker without accidentally constructing it - marker = NetworkMarker.getNetworkMarker(event); - } - - // Process output handler - if (packet != null && event != null && NetworkMarker.hasOutputHandlers(marker)) { - ByteBuf packetBuffer = ctx.alloc().buffer(); - ENCODE_BUFFER.invoke(vanillaEncoder, ctx, packet, packetBuffer); - - // Let each handler prepare the actual output - byte[] data = processor.processOutput(event, marker, getBytes(packetBuffer)); - - // Write the result - output.writeBytes(data); - packet = null; - - // Sent listeners? - finalEvent = event; - return; - } - } catch (Exception e) { - channelListener.getReporter().reportDetailed(this, - Report.newBuilder(REPORT_CANNOT_INTERCEPT_SERVER_PACKET).callerParam(packet).error(e).build()); - } finally { - // Attempt to handle the packet nevertheless - if (packet != null) { - ENCODE_BUFFER.invoke(vanillaEncoder, ctx, packet, output); - finalEvent = event; - } - } - } - - /** - * Invoked when a packet has been written to the channel. - * @param ctx - current context. - * @param packet - the packet that has been written. - * @param promise - a promise. - */ - protected void finalWrite(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) { - PacketEvent event = finalEvent; - - if (event != null) { - // Necessary to prevent infinite loops - finalEvent = null; - currentEvent = null; - - processor.invokePostEvent(event, NetworkMarker.getNetworkMarker(event)); - } - } - - private void scheduleMainThread(final Object packetCopy) { - // Don't use BukkitExecutors for this - it has a bit of overhead - Bukkit.getScheduler().scheduleSyncDelayedTask(factory.getPlugin(), new Runnable() { - @Override - public void run() { - invokeSendPacket(packetCopy); - } - }); - } - - @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuffer, List packets) throws Exception { - byteBuffer.markReaderIndex(); - DECODE_BUFFER.invoke(vanillaDecoder, ctx, byteBuffer, packets); - - try { - // Reset queue - finishQueue.clear(); - - for (ListIterator it = packets.listIterator(); it.hasNext(); ) { - Object input = it.next(); - Class packetClass = input.getClass(); - NetworkMarker marker = null; - - // Special case! - handleLogin(packetClass, input); - - if (channelListener.includeBuffer(packetClass)) { - byteBuffer.resetReaderIndex(); - marker = new NettyNetworkMarker(ConnectionSide.CLIENT_SIDE, getBytes(byteBuffer)); - } - - PacketEvent output = channelListener.onPacketReceiving(this, input, marker); - - // Handle packet changes - if (output != null) { - if (output.isCancelled()) { - it.remove(); - continue; - } else if (output.getPacket().getHandle() != input) { - it.set(output.getPacket().getHandle()); - } - - finishQueue.addLast(output); - } - } - } catch (Exception e) { - channelListener.getReporter().reportDetailed(this, - Report.newBuilder(REPORT_CANNOT_INTERCEPT_CLIENT_PACKET).callerParam(byteBuffer).error(e).build()); - } - } - - /** - * Invoked after our decoder. - * @param ctx - current context. - * @param msg - the current packet. - */ - protected void finishRead(ChannelHandlerContext ctx, Object msg) { - // Assume same order - PacketEvent event = finishQueue.pollFirst(); - - if (event != null) { - NetworkMarker marker = NetworkMarker.getNetworkMarker(event); - - if (marker != null) { - processor.invokePostEvent(event, marker); - } - } - } - - /** - * Invoked when we may need to handle the login packet. - * @param packetClass - the packet class. - * @param packet - the packet. - */ - protected void handleLogin(Class packetClass, Object packet) { - try { - Class loginClass = PACKET_LOGIN_CLIENT; - FieldAccessor loginClient = LOGIN_GAME_PROFILE; - - // Initialize packet class and login - if (loginClass == null) { - loginClass = PacketType.Login.Client.START.getPacketClass(); - PACKET_LOGIN_CLIENT = loginClass; - } - if (loginClient == null) { - loginClient = Accessors.getFieldAccessor(PACKET_LOGIN_CLIENT, MinecraftReflection.getGameProfileClass(), true); - LOGIN_GAME_PROFILE = loginClient; - } - - // See if we are dealing with the login packet - if (loginClass.equals(packetClass)) { - // GameProfile profile = (GameProfile) loginClient.get(packet); - WrappedGameProfile profile = WrappedGameProfile.fromHandle(loginClient.get(packet)); - - // Save the channel injector - factory.cacheInjector(profile.getName(), this); - } - } catch (IllegalArgumentException ex) { // Thrown by FuzzyReflection#getFields() - System.err.println(String.format("[ProtocolLib] Encountered NPE in handleLogin(%s, %s)", packetClass, packet)); - System.err.println("PACKET_LOGIN_CLIENT = " + PACKET_LOGIN_CLIENT); - System.err.println("LOGIN_GAME_PROFILE = " + LOGIN_GAME_PROFILE); - System.err.println("GameProfile class = " + MinecraftReflection.getGameProfileClass()); - System.err.println("Provide this information in a new or existing issue"); - throw ex; - } - } - - @Override - public void channelActive(ChannelHandlerContext ctx) throws Exception { - super.channelActive(ctx); - - // See NetworkManager.channelActive(ChannelHandlerContext) for why - if (channelField != null) { - channelField.refreshValue(); - } - } - - /** - * Retrieve every byte in the given byte buffer. - * @param buffer - the buffer. - * @return The bytes. - */ - private byte[] getBytes(ByteBuf buffer) { - byte[] data = new byte[buffer.readableBytes()]; - - buffer.readBytes(data); - return data; - } - - /** - * Disconnect the current player. - * @param message - the disconnect message, if possible. - */ - private void disconnect(String message) { - // If we're logging in, we can only close the channel - if (playerConnection == null || player instanceof Factory) { - originalChannel.disconnect(); - } else { - // Call the disconnect method - try { - MinecraftMethods.getDisconnectMethod(playerConnection.getClass()). - invoke(playerConnection, message); - } catch (Exception e) { - throw new IllegalArgumentException("Unable to invoke disconnect method.", e); - } - } - } - - @Override - public void sendServerPacket(Object packet, NetworkMarker marker, boolean filtered) { - saveMarker(packet, marker); - - try { - scheduleProcessPackets.set(filtered); - invokeSendPacket(packet); - } finally { - scheduleProcessPackets.set(true); - } - } - - /** - * Invoke the sendPacket method in Minecraft. - * @param packet - the packet to send. - */ - private void invokeSendPacket(Object packet) { - // Attempt to send the packet with NetworkMarker.handle(), or the PlayerConnection if its active - try { - if (player instanceof Factory) { - MinecraftMethods.getNetworkManagerHandleMethod().invoke(networkManager, packet, new GenericFutureListener[0]); - } else { - MinecraftMethods.getSendPacketMethod().invoke(getPlayerConnection(), packet); - } - } catch (Throwable ex) { - ProtocolLibrary.getErrorReporter().reportWarning(factory.getPlugin(), - Report.newBuilder(REPORT_CANNOT_SEND_PACKET).messageParam(packet, playerName).error(ex).build()); - } - } - - @Override - public void recieveClientPacket(final Object packet) { - // TODO: Ensure the packet listeners are executed in the channel thread. - - // Execute this in the channel thread - Runnable action = new Runnable() { - @Override - public void run() { - try { - MinecraftMethods.getNetworkManagerReadPacketMethod().invoke(networkManager, null, packet); - } catch (Exception e) { - // Inform the user - ProtocolLibrary.getErrorReporter().reportMinimal(factory.getPlugin(), "recieveClientPacket", e); - } - } - }; - - // Execute in the worker thread - if (originalChannel.eventLoop().inEventLoop()) { - action.run(); - } else { - originalChannel.eventLoop().execute(action); - } - } - - @Override - public Protocol getCurrentProtocol() { - if (PROTOCOL_ACCESSOR == null) { - PROTOCOL_ACCESSOR = Accessors.getFieldAccessor( - networkManager.getClass(), MinecraftReflection.getEnumProtocolClass(), true); - } - return Protocol.fromVanilla((Enum) PROTOCOL_ACCESSOR.get(networkManager)); - } - - /** - * Retrieve the player connection of the current player. - * @return The player connection. - */ - private Object getPlayerConnection() { - if (playerConnection == null) { - playerConnection = MinecraftFields.getPlayerConnection(player); - } - return playerConnection; - } - - @Override - public NetworkMarker getMarker(Object packet) { - return packetMarker.get(packet); - } - - @Override - public void saveMarker(Object packet, NetworkMarker marker) { - if (marker != null) { - packetMarker.put(packet, marker); - } - } - - @Override - public Player getPlayer() { - if (player == null && playerName != null) { - return Bukkit.getPlayer(playerName); - } - - return player; - } - - /** - * Set the player instance. - * @param player - current instance. - */ - @Override - public void setPlayer(Player player) { - this.player = player; - this.playerName = player.getName(); - } - - /** - * Set the updated player instance. - * @param updated - updated instance. - */ - @Override - public void setUpdatedPlayer(Player updated) { - this.updated = updated; - this.playerName = updated.getName(); - } - - @Override - public boolean isInjected() { - return injected; - } - - /** - * Determine if this channel has been closed and cleaned up. - * @return TRUE if it has, FALSE otherwise. - */ - @Override - public boolean isClosed() { - return closed; - } - - @Override - public void close() { - if (!closed) { - closed = true; - - if (injected) { - channelField.revertValue(); - - // Calling remove() in the main thread will block the main thread, which may lead - // to a deadlock: - // http://pastebin.com/L3SBVKzp - // - // ProtocolLib executes this close() method through a PlayerQuitEvent in the main thread, - // which has implicitly aquired a lock on SimplePluginManager (see SimplePluginManager.callEvent(Event)). - // Unfortunately, the remove() method will schedule the removal on one of the Netty worker threads if - // it's called from a different thread, blocking until the removal has been confirmed. - // - // This is bad enough (Rule #1: Don't block the main thread), but the real trouble starts if the same - // worker thread happens to be handling a server ping connection when this removal task is scheduled. - // In that case, it may attempt to invoke an asynchronous ServerPingEvent (see PacketStatusListener) - // using SimplePluginManager.callEvent(). But, since this has already been locked by the main thread, - // we end up with a deadlock. The main thread is waiting for the worker thread to process the task, and - // the worker thread is waiting for the main thread to finish executing PlayerQuitEvent. - // - // TL;DR: Concurrency is hard. - executeInChannelThread(new Runnable() { - @Override - public void run() { - String[] handlers = new String[] { - "protocol_lib_decoder", "protocol_lib_finish", "protocol_lib_encoder" - }; - - for (String handler : handlers) { - try { - originalChannel.pipeline().remove(handler); - } catch (NoSuchElementException e) { - // Ignore - } - } - } - }); - - // Clear cache - factory.invalidate(player); - - // Clear player instances - // Should help fix memory leaks - this.player = null; - this.updated = null; - } - } - } - - /** - * Execute a specific command in the channel thread. - *

- * Exceptions are printed through the standard error reporter mechanism. - * @param command - the command to execute. - */ - private void executeInChannelThread(final Runnable command) { - originalChannel.eventLoop().execute(new Runnable() { - @Override - public void run() { - try { - command.run(); - } catch (Exception e) { - ProtocolLibrary.getErrorReporter().reportDetailed(ChannelInjector.this, - Report.newBuilder(REPORT_CANNOT_EXECUTE_IN_CHANNEL_THREAD).error(e).build()); - } - } - }); - } - - /** - * Find the first channel handler that is assignable to a given type. - * @param channel - the channel. - * @param clazz - the type. - * @return The first handler, or NULL. - */ - public static ChannelHandler findChannelHandler(Channel channel, Class clazz) { - for (Entry entry : channel.pipeline()) { - if (clazz.isAssignableFrom(entry.getValue().getClass())) { - return entry.getValue(); - } - } - return null; - } - - /** - * Represents a socket injector that foreards to the current channel injector. - * @author Kristian - */ - public static class ChannelSocketInjector implements SocketInjector { - private final ChannelInjector injector; - - public ChannelSocketInjector(ChannelInjector injector) { - this.injector = Preconditions.checkNotNull(injector, "injector cannot be NULL"); - } - - @Override - public Socket getSocket() throws IllegalAccessException { - return SocketAdapter.adapt((SocketChannel) injector.originalChannel); - } - - @Override - public SocketAddress getAddress() throws IllegalAccessException { - return injector.originalChannel.remoteAddress(); - } - - @Override - public void disconnect(String message) throws InvocationTargetException { - injector.disconnect(message); - } - - @Override - public void sendServerPacket(Object packet, NetworkMarker marker, boolean filtered) throws InvocationTargetException { - injector.sendServerPacket(packet, marker, filtered); - } - - @Override - public Player getPlayer() { - return injector.getPlayer(); - } - - @Override - public Player getUpdatedPlayer() { - return injector.updated; - } - - @Override - public void transferState(SocketInjector delegate) { - // Do nothing - } - - @Override - public void setUpdatedPlayer(Player updatedPlayer) { - injector.setPlayer(updatedPlayer); - } - - public ChannelInjector getChannelInjector() { - return injector; - } - } - - public Channel getChannel() { - return originalChannel; - } -} \ No newline at end of file +/** + * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. + * Copyright (C) 2015 dmulloy2 + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ +package com.comphenix.protocol.injector.netty; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.ChannelPromise; +import io.netty.channel.socket.SocketChannel; +import io.netty.handler.codec.ByteToMessageDecoder; +import io.netty.handler.codec.MessageToByteEncoder; +import io.netty.util.concurrent.GenericFutureListener; +import io.netty.util.internal.TypeParameterMatcher; + +import java.lang.reflect.InvocationTargetException; +import java.net.Socket; +import java.net.SocketAddress; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.List; +import java.util.ListIterator; +import java.util.Map.Entry; +import java.util.NoSuchElementException; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentMap; + +import net.sf.cglib.proxy.Factory; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.PacketType.Protocol; +import com.comphenix.protocol.ProtocolLibrary; +import com.comphenix.protocol.error.Report; +import com.comphenix.protocol.error.ReportType; +import com.comphenix.protocol.events.ConnectionSide; +import com.comphenix.protocol.events.NetworkMarker; +import com.comphenix.protocol.events.PacketEvent; +import com.comphenix.protocol.injector.NetworkProcessor; +import com.comphenix.protocol.injector.netty.WirePacket; +import com.comphenix.protocol.injector.server.SocketInjector; +import com.comphenix.protocol.reflect.FuzzyReflection; +import com.comphenix.protocol.reflect.VolatileField; +import com.comphenix.protocol.reflect.accessors.Accessors; +import com.comphenix.protocol.reflect.accessors.FieldAccessor; +import com.comphenix.protocol.reflect.accessors.MethodAccessor; +import com.comphenix.protocol.utility.MinecraftFields; +import com.comphenix.protocol.utility.MinecraftMethods; +import com.comphenix.protocol.utility.MinecraftProtocolVersion; +import com.comphenix.protocol.utility.MinecraftReflection; +import com.comphenix.protocol.wrappers.WrappedGameProfile; +import com.google.common.base.Preconditions; +import com.google.common.collect.MapMaker; + +/** + * Represents a channel injector. + * @author Kristian + */ +public class ChannelInjector extends ByteToMessageDecoder implements Injector { + public static final ReportType REPORT_CANNOT_INTERCEPT_SERVER_PACKET = new ReportType("Unable to intercept a written server packet."); + public static final ReportType REPORT_CANNOT_INTERCEPT_CLIENT_PACKET = new ReportType("Unable to intercept a read client packet."); + public static final ReportType REPORT_CANNOT_EXECUTE_IN_CHANNEL_THREAD = new ReportType("Cannot execute code in channel thread."); + public static final ReportType REPORT_CANNOT_FIND_GET_VERSION = new ReportType("Cannot find getVersion() in NetworkMananger"); + public static final ReportType REPORT_CANNOT_SEND_PACKET = new ReportType("Unable to send packet %s to %s"); + + /** + * Indicates that a packet has bypassed packet listeners. + */ + private static final PacketEvent BYPASSED_PACKET = new PacketEvent(ChannelInjector.class); + + // The login packet + private static Class PACKET_LOGIN_CLIENT = null; + private static FieldAccessor LOGIN_GAME_PROFILE = null; + + // Saved accessors + private static MethodAccessor DECODE_BUFFER; + private static MethodAccessor ENCODE_BUFFER; + private static FieldAccessor ENCODER_TYPE_MATCHER; + + // For retrieving the protocol + private static FieldAccessor PROTOCOL_ACCESSOR; + + // For retrieving the protocol version + private static MethodAccessor PROTOCOL_VERSION; + + // The factory that created this injector + private InjectionFactory factory; + + // The player, or temporary player + private Player player; + private Player updated; + private String playerName; + + // The player connection + private Object playerConnection; + + // The current network manager and channel + private final Object networkManager; + private final Channel originalChannel; + private VolatileField channelField; + + // Known network markers + private ConcurrentMap packetMarker = new MapMaker().weakKeys().makeMap(); + + /** + * Indicate that this packet has been processed by event listeners. + *

+ * This must never be set outside the channel pipeline's thread. + */ + private PacketEvent currentEvent; + + /** + * A packet event that should be processed by the write method. + */ + private PacketEvent finalEvent; + + /** + * A flag set by the main thread to indiciate that a packet should not be processed. + */ + private final ThreadLocal scheduleProcessPackets = new ThreadLocal() { + @Override + protected Boolean initialValue() { + return true; + }; + }; + + // Other handlers + private ByteToMessageDecoder vanillaDecoder; + private MessageToByteEncoder vanillaEncoder; + + private Deque finishQueue = new ArrayDeque(); + + // The channel listener + private ChannelListener channelListener; + + // Processing network markers + private NetworkProcessor processor; + + // Closed + private boolean injected; + private boolean closed; + + /** + * Construct a new channel injector. + * @param player - the current player, or temporary player. + * @param networkManager - its network manager. + * @param channel - its channel. + * @param channelListener - a listener. + * @param factory - the factory that created this injector + */ + public ChannelInjector(Player player, Object networkManager, Channel channel, ChannelListener channelListener, InjectionFactory factory) { + this.player = Preconditions.checkNotNull(player, "player cannot be NULL"); + this.networkManager = Preconditions.checkNotNull(networkManager, "networkMananger cannot be NULL"); + this.originalChannel = Preconditions.checkNotNull(channel, "channel cannot be NULL"); + this.channelListener = Preconditions.checkNotNull(channelListener, "channelListener cannot be NULL"); + this.factory = Preconditions.checkNotNull(factory, "factory cannot be NULL"); + this.processor = new NetworkProcessor(ProtocolLibrary.getErrorReporter()); + + // Get the channel field + this.channelField = new VolatileField(FuzzyReflection.fromObject(networkManager, true).getFieldByType("channel", Channel.class), + networkManager, true); + } + + /** + * Get the version of the current protocol. + * @return The version. + */ + @Override + public int getProtocolVersion() { + MethodAccessor accessor = PROTOCOL_VERSION; + if (accessor == null) { + try { + accessor = Accessors.getMethodAccessor(networkManager.getClass(), "getVersion"); + } catch (Throwable ex) { + } + } + + if (accessor != null) { + return (Integer) accessor.invoke(networkManager); + } else { + return MinecraftProtocolVersion.getCurrentVersion(); + } + } + + @Override + @SuppressWarnings("unchecked") + public boolean inject() { + synchronized (networkManager) { + if (closed) + return false; + if (originalChannel instanceof Factory) + return false; + if (!originalChannel.isActive()) + return false; + + // Main thread? We should synchronize with the channel thread, otherwise we might see a + // pipeline with only some of the handlers removed + if (Bukkit.isPrimaryThread()) { + // Just like in the close() method, we'll avoid blocking the main thread + executeInChannelThread(new Runnable() { + @Override + public void run() { + inject(); + } + }); + return false; // We don't know + } + + // Don't inject the same channel twice + if (findChannelHandler(originalChannel, ChannelInjector.class) != null) { + return false; + } + + // Get the vanilla decoder, so we don't have to replicate the work + vanillaDecoder = (ByteToMessageDecoder) originalChannel.pipeline().get("decoder"); + vanillaEncoder = (MessageToByteEncoder) originalChannel.pipeline().get("encoder"); + + if (vanillaDecoder == null) + throw new IllegalArgumentException("Unable to find vanilla decoder in " + originalChannel.pipeline() ); + if (vanillaEncoder == null) + throw new IllegalArgumentException("Unable to find vanilla encoder in " + originalChannel.pipeline() ); + patchEncoder(vanillaEncoder); + + if (DECODE_BUFFER == null) + DECODE_BUFFER = Accessors.getMethodAccessor(vanillaDecoder.getClass(), + "decode", ChannelHandlerContext.class, ByteBuf.class, List.class); + if (ENCODE_BUFFER == null) + ENCODE_BUFFER = Accessors.getMethodAccessor(vanillaEncoder.getClass(), + "encode", ChannelHandlerContext.class, Object.class, ByteBuf.class); + + // Intercept sent packets + MessageToByteEncoder protocolEncoder = new MessageToByteEncoder() { + @Override + protected void encode(ChannelHandlerContext ctx, Object packet, ByteBuf output) throws Exception { + if (packet instanceof WirePacket) { + // Special case for wire format + ChannelInjector.this.encodeWirePacket((WirePacket) packet, output); + } else { + ChannelInjector.this.encode(ctx, packet, output); + } + } + + @Override + public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) throws Exception { + super.write(ctx, packet, promise); + ChannelInjector.this.finalWrite(ctx, packet, promise); + } + }; + + // Intercept recieved packets + ChannelInboundHandlerAdapter finishHandler = new ChannelInboundHandlerAdapter() { + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + // Execute context first + ctx.fireChannelRead(msg); + ChannelInjector.this.finishRead(ctx, msg); + } + }; + + // Insert our handlers - note that we effectively replace the vanilla encoder/decoder + originalChannel.pipeline().addBefore("decoder", "protocol_lib_decoder", this); + originalChannel.pipeline().addBefore("protocol_lib_decoder", "protocol_lib_finish", finishHandler); + originalChannel.pipeline().addAfter("encoder", "protocol_lib_encoder", protocolEncoder); + + // Intercept all write methods + channelField.setValue(new ChannelProxy(originalChannel, MinecraftReflection.getPacketClass()) { + // Compatibility with Spigot 1.8 + private final PipelineProxy pipelineProxy = new PipelineProxy(originalChannel.pipeline(), this) { + @Override + public ChannelPipeline addBefore(String baseName, String name, ChannelHandler handler) { + // Correct the position of the decoder + if ("decoder".equals(baseName)) { + if (super.get("protocol_lib_decoder") != null && guessCompression(handler)) { + super.addBefore("protocol_lib_decoder", name, handler); + return this; + } + } + + return super.addBefore(baseName, name, handler); + } + }; + + @Override + public ChannelPipeline pipeline() { + return pipelineProxy; + } + + @Override + protected Callable onMessageScheduled(final Callable callable, FieldAccessor packetAccessor) { + final PacketEvent event = handleScheduled(callable, packetAccessor); + + // Handle cancelled events + if (event != null && event.isCancelled()) + return null; + + return new Callable() { + @Override + public T call() throws Exception { + T result = null; + + // This field must only be updated in the pipeline thread + currentEvent = event; + result = callable.call(); + currentEvent = null; + return result; + } + }; + } + + @Override + protected Runnable onMessageScheduled(final Runnable runnable, FieldAccessor packetAccessor) { + final PacketEvent event = handleScheduled(runnable, packetAccessor); + + // Handle cancelled events + if (event != null && event.isCancelled()) + return null; + + return new Runnable() { + @Override + public void run() { + currentEvent = event; + runnable.run(); + currentEvent = null; + } + }; + } + + protected PacketEvent handleScheduled(Object instance, FieldAccessor accessor) { + // Let the filters handle this packet + Object original = accessor.get(instance); + + // See if we've been instructed not to process packets + if (!scheduleProcessPackets.get()) { + NetworkMarker marker = getMarker(original); + + if (marker != null) { + PacketEvent result = new PacketEvent(ChannelInjector.class); + result.setNetworkMarker(marker); + return result; + } else { + return BYPASSED_PACKET; + } + } + PacketEvent event = processSending(original); + + if (event != null && !event.isCancelled()) { + Object changed = event.getPacket().getHandle(); + + // Change packet to be scheduled + if (original != changed) + accessor.set(instance, changed); + }; + return event != null ? event : BYPASSED_PACKET; + } + }); + + injected = true; + return true; + } + } + + /** + * Determine if the given object is a compressor or decompressor. + * @param handler - object to test. + * @return TRUE if it is, FALSE if not or unknown. + */ + private boolean guessCompression(ChannelHandler handler) { + String className = handler != null ? handler.getClass().getCanonicalName() : ""; + return className.contains("Compressor") || className.contains("Decompressor"); + } + + /** + * Process a given message on the packet listeners. + * @param message - the message/packet. + * @return The resulting message/packet. + */ + private PacketEvent processSending(Object message) { + return channelListener.onPacketSending(ChannelInjector.this, message, getMarker(message)); + } + + /** + * This method patches the encoder so that it skips already created packets. + * @param encoder - the encoder to patch. + */ + private void patchEncoder(MessageToByteEncoder encoder) { + if (ENCODER_TYPE_MATCHER == null) { + ENCODER_TYPE_MATCHER = Accessors.getFieldAccessor(encoder.getClass(), "matcher", true); + } + ENCODER_TYPE_MATCHER.set(encoder, TypeParameterMatcher.get(MinecraftReflection.getPacketClass())); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + if (channelListener.isDebug()) + cause.printStackTrace(); + super.exceptionCaught(ctx, cause); + } + + protected void encodeWirePacket(WirePacket packet, ByteBuf output) throws Exception { + packet.writeId(output); + packet.writeBytes(output); + } + + /** + * Encode a packet to a byte buffer, taking over for the standard Minecraft encoder. + * @param ctx - the current context. + * @param packet - the packet to encode to a byte array. + * @param output - the output byte array. + * @throws Exception If anything went wrong. + */ + protected void encode(ChannelHandlerContext ctx, Object packet, ByteBuf output) throws Exception { + NetworkMarker marker = null; + PacketEvent event = currentEvent; + + try { + // Skip every kind of non-filtered packet + if (!scheduleProcessPackets.get()) { + return; + } + + // This packet has not been seen by the main thread + if (event == null) { + Class clazz = packet.getClass(); + + // Schedule the transmission on the main thread instead + if (channelListener.hasMainThreadListener(clazz)) { + // Delay the packet + scheduleMainThread(packet); + packet = null; + + } else { + event = processSending(packet); + + // Handle the output + if (event != null) { + packet = !event.isCancelled() ? event.getPacket().getHandle() : null; + } + } + } + if (event != null) { + // Retrieve marker without accidentally constructing it + marker = NetworkMarker.getNetworkMarker(event); + } + + // Process output handler + if (packet != null && event != null && NetworkMarker.hasOutputHandlers(marker)) { + ByteBuf packetBuffer = ctx.alloc().buffer(); + ENCODE_BUFFER.invoke(vanillaEncoder, ctx, packet, packetBuffer); + + // Let each handler prepare the actual output + byte[] data = processor.processOutput(event, marker, getBytes(packetBuffer)); + + // Write the result + output.writeBytes(data); + packet = null; + + // Sent listeners? + finalEvent = event; + return; + } + } catch (Exception e) { + channelListener.getReporter().reportDetailed(this, + Report.newBuilder(REPORT_CANNOT_INTERCEPT_SERVER_PACKET).callerParam(packet).error(e).build()); + } finally { + // Attempt to handle the packet nevertheless + if (packet != null) { + ENCODE_BUFFER.invoke(vanillaEncoder, ctx, packet, output); + finalEvent = event; + } + } + } + + /** + * Invoked when a packet has been written to the channel. + * @param ctx - current context. + * @param packet - the packet that has been written. + * @param promise - a promise. + */ + protected void finalWrite(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) { + PacketEvent event = finalEvent; + + if (event != null) { + // Necessary to prevent infinite loops + finalEvent = null; + currentEvent = null; + + processor.invokePostEvent(event, NetworkMarker.getNetworkMarker(event)); + } + } + + private void scheduleMainThread(final Object packetCopy) { + // Don't use BukkitExecutors for this - it has a bit of overhead + Bukkit.getScheduler().scheduleSyncDelayedTask(factory.getPlugin(), new Runnable() { + @Override + public void run() { + invokeSendPacket(packetCopy); + } + }); + } + + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuffer, List packets) throws Exception { + byteBuffer.markReaderIndex(); + DECODE_BUFFER.invoke(vanillaDecoder, ctx, byteBuffer, packets); + + try { + // Reset queue + finishQueue.clear(); + + for (ListIterator it = packets.listIterator(); it.hasNext(); ) { + Object input = it.next(); + Class packetClass = input.getClass(); + NetworkMarker marker = null; + + // Special case! + handleLogin(packetClass, input); + + if (channelListener.includeBuffer(packetClass)) { + byteBuffer.resetReaderIndex(); + marker = new NettyNetworkMarker(ConnectionSide.CLIENT_SIDE, getBytes(byteBuffer)); + } + + PacketEvent output = channelListener.onPacketReceiving(this, input, marker); + + // Handle packet changes + if (output != null) { + if (output.isCancelled()) { + it.remove(); + continue; + } else if (output.getPacket().getHandle() != input) { + it.set(output.getPacket().getHandle()); + } + + finishQueue.addLast(output); + } + } + } catch (Exception e) { + channelListener.getReporter().reportDetailed(this, + Report.newBuilder(REPORT_CANNOT_INTERCEPT_CLIENT_PACKET).callerParam(byteBuffer).error(e).build()); + } + } + + /** + * Invoked after our decoder. + * @param ctx - current context. + * @param msg - the current packet. + */ + protected void finishRead(ChannelHandlerContext ctx, Object msg) { + // Assume same order + PacketEvent event = finishQueue.pollFirst(); + + if (event != null) { + NetworkMarker marker = NetworkMarker.getNetworkMarker(event); + + if (marker != null) { + processor.invokePostEvent(event, marker); + } + } + } + + /** + * Invoked when we may need to handle the login packet. + * @param packetClass - the packet class. + * @param packet - the packet. + */ + protected void handleLogin(Class packetClass, Object packet) { + try { + Class loginClass = PACKET_LOGIN_CLIENT; + FieldAccessor loginClient = LOGIN_GAME_PROFILE; + + // Initialize packet class and login + if (loginClass == null) { + loginClass = PacketType.Login.Client.START.getPacketClass(); + PACKET_LOGIN_CLIENT = loginClass; + } + if (loginClient == null) { + loginClient = Accessors.getFieldAccessor(PACKET_LOGIN_CLIENT, MinecraftReflection.getGameProfileClass(), true); + LOGIN_GAME_PROFILE = loginClient; + } + + // See if we are dealing with the login packet + if (loginClass.equals(packetClass)) { + // GameProfile profile = (GameProfile) loginClient.get(packet); + WrappedGameProfile profile = WrappedGameProfile.fromHandle(loginClient.get(packet)); + + // Save the channel injector + factory.cacheInjector(profile.getName(), this); + } + } catch (IllegalArgumentException ex) { // Thrown by FuzzyReflection#getFields() + System.err.println(String.format("[ProtocolLib] Encountered NPE in handleLogin(%s, %s)", packetClass, packet)); + System.err.println("PACKET_LOGIN_CLIENT = " + PACKET_LOGIN_CLIENT); + System.err.println("LOGIN_GAME_PROFILE = " + LOGIN_GAME_PROFILE); + System.err.println("GameProfile class = " + MinecraftReflection.getGameProfileClass()); + System.err.println("Provide this information in a new or existing issue"); + throw ex; + } + } + + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + super.channelActive(ctx); + + // See NetworkManager.channelActive(ChannelHandlerContext) for why + if (channelField != null) { + channelField.refreshValue(); + } + } + + /** + * Retrieve every byte in the given byte buffer. + * @param buffer - the buffer. + * @return The bytes. + */ + private byte[] getBytes(ByteBuf buffer) { + byte[] data = new byte[buffer.readableBytes()]; + + buffer.readBytes(data); + return data; + } + + /** + * Disconnect the current player. + * @param message - the disconnect message, if possible. + */ + private void disconnect(String message) { + // If we're logging in, we can only close the channel + if (playerConnection == null || player instanceof Factory) { + originalChannel.disconnect(); + } else { + // Call the disconnect method + try { + MinecraftMethods.getDisconnectMethod(playerConnection.getClass()). + invoke(playerConnection, message); + } catch (Exception e) { + throw new IllegalArgumentException("Unable to invoke disconnect method.", e); + } + } + } + + @Override + public void sendServerPacket(Object packet, NetworkMarker marker, boolean filtered) { + saveMarker(packet, marker); + + try { + scheduleProcessPackets.set(filtered); + invokeSendPacket(packet); + } finally { + scheduleProcessPackets.set(true); + } + } + + /** + * Invoke the sendPacket method in Minecraft. + * @param packet - the packet to send. + */ + private void invokeSendPacket(Object packet) { + // Attempt to send the packet with NetworkMarker.handle(), or the PlayerConnection if its active + try { + if (player instanceof Factory) { + MinecraftMethods.getNetworkManagerHandleMethod().invoke(networkManager, packet, new GenericFutureListener[0]); + } else { + MinecraftMethods.getSendPacketMethod().invoke(getPlayerConnection(), packet); + } + } catch (Throwable ex) { + ProtocolLibrary.getErrorReporter().reportWarning(factory.getPlugin(), + Report.newBuilder(REPORT_CANNOT_SEND_PACKET).messageParam(packet, playerName).error(ex).build()); + } + } + + @Override + public void recieveClientPacket(final Object packet) { + // TODO: Ensure the packet listeners are executed in the channel thread. + + // Execute this in the channel thread + Runnable action = new Runnable() { + @Override + public void run() { + try { + MinecraftMethods.getNetworkManagerReadPacketMethod().invoke(networkManager, null, packet); + } catch (Exception e) { + // Inform the user + ProtocolLibrary.getErrorReporter().reportMinimal(factory.getPlugin(), "recieveClientPacket", e); + } + } + }; + + // Execute in the worker thread + if (originalChannel.eventLoop().inEventLoop()) { + action.run(); + } else { + originalChannel.eventLoop().execute(action); + } + } + + @Override + public Protocol getCurrentProtocol() { + if (PROTOCOL_ACCESSOR == null) { + PROTOCOL_ACCESSOR = Accessors.getFieldAccessor( + networkManager.getClass(), MinecraftReflection.getEnumProtocolClass(), true); + } + return Protocol.fromVanilla((Enum) PROTOCOL_ACCESSOR.get(networkManager)); + } + + /** + * Retrieve the player connection of the current player. + * @return The player connection. + */ + private Object getPlayerConnection() { + if (playerConnection == null) { + playerConnection = MinecraftFields.getPlayerConnection(player); + } + return playerConnection; + } + + @Override + public NetworkMarker getMarker(Object packet) { + return packetMarker.get(packet); + } + + @Override + public void saveMarker(Object packet, NetworkMarker marker) { + if (marker != null) { + packetMarker.put(packet, marker); + } + } + + @Override + public Player getPlayer() { + if (player == null && playerName != null) { + return Bukkit.getPlayer(playerName); + } + + return player; + } + + /** + * Set the player instance. + * @param player - current instance. + */ + @Override + public void setPlayer(Player player) { + this.player = player; + this.playerName = player.getName(); + } + + /** + * Set the updated player instance. + * @param updated - updated instance. + */ + @Override + public void setUpdatedPlayer(Player updated) { + this.updated = updated; + this.playerName = updated.getName(); + } + + @Override + public boolean isInjected() { + return injected; + } + + /** + * Determine if this channel has been closed and cleaned up. + * @return TRUE if it has, FALSE otherwise. + */ + @Override + public boolean isClosed() { + return closed; + } + + @Override + public void close() { + if (!closed) { + closed = true; + + if (injected) { + channelField.revertValue(); + + // Calling remove() in the main thread will block the main thread, which may lead + // to a deadlock: + // http://pastebin.com/L3SBVKzp + // + // ProtocolLib executes this close() method through a PlayerQuitEvent in the main thread, + // which has implicitly aquired a lock on SimplePluginManager (see SimplePluginManager.callEvent(Event)). + // Unfortunately, the remove() method will schedule the removal on one of the Netty worker threads if + // it's called from a different thread, blocking until the removal has been confirmed. + // + // This is bad enough (Rule #1: Don't block the main thread), but the real trouble starts if the same + // worker thread happens to be handling a server ping connection when this removal task is scheduled. + // In that case, it may attempt to invoke an asynchronous ServerPingEvent (see PacketStatusListener) + // using SimplePluginManager.callEvent(). But, since this has already been locked by the main thread, + // we end up with a deadlock. The main thread is waiting for the worker thread to process the task, and + // the worker thread is waiting for the main thread to finish executing PlayerQuitEvent. + // + // TL;DR: Concurrency is hard. + executeInChannelThread(new Runnable() { + @Override + public void run() { + String[] handlers = new String[] { + "protocol_lib_decoder", "protocol_lib_finish", "protocol_lib_encoder" + }; + + for (String handler : handlers) { + try { + originalChannel.pipeline().remove(handler); + } catch (NoSuchElementException e) { + // Ignore + } + } + } + }); + + // Clear cache + factory.invalidate(player); + + // Clear player instances + // Should help fix memory leaks + this.player = null; + this.updated = null; + } + } + } + + /** + * Execute a specific command in the channel thread. + *

+ * Exceptions are printed through the standard error reporter mechanism. + * @param command - the command to execute. + */ + private void executeInChannelThread(final Runnable command) { + originalChannel.eventLoop().execute(new Runnable() { + @Override + public void run() { + try { + command.run(); + } catch (Exception e) { + ProtocolLibrary.getErrorReporter().reportDetailed(ChannelInjector.this, + Report.newBuilder(REPORT_CANNOT_EXECUTE_IN_CHANNEL_THREAD).error(e).build()); + } + } + }); + } + + /** + * Find the first channel handler that is assignable to a given type. + * @param channel - the channel. + * @param clazz - the type. + * @return The first handler, or NULL. + */ + public static ChannelHandler findChannelHandler(Channel channel, Class clazz) { + for (Entry entry : channel.pipeline()) { + if (clazz.isAssignableFrom(entry.getValue().getClass())) { + return entry.getValue(); + } + } + return null; + } + + /** + * Represents a socket injector that foreards to the current channel injector. + * @author Kristian + */ + public static class ChannelSocketInjector implements SocketInjector { + private final ChannelInjector injector; + + public ChannelSocketInjector(ChannelInjector injector) { + this.injector = Preconditions.checkNotNull(injector, "injector cannot be NULL"); + } + + @Override + public Socket getSocket() throws IllegalAccessException { + return SocketAdapter.adapt((SocketChannel) injector.originalChannel); + } + + @Override + public SocketAddress getAddress() throws IllegalAccessException { + return injector.originalChannel.remoteAddress(); + } + + @Override + public void disconnect(String message) throws InvocationTargetException { + injector.disconnect(message); + } + + @Override + public void sendServerPacket(Object packet, NetworkMarker marker, boolean filtered) throws InvocationTargetException { + injector.sendServerPacket(packet, marker, filtered); + } + + @Override + public Player getPlayer() { + return injector.getPlayer(); + } + + @Override + public Player getUpdatedPlayer() { + return injector.updated; + } + + @Override + public void transferState(SocketInjector delegate) { + // Do nothing + } + + @Override + public void setUpdatedPlayer(Player updatedPlayer) { + injector.setPlayer(updatedPlayer); + } + + public ChannelInjector getChannelInjector() { + return injector; + } + } + + public Channel getChannel() { + return originalChannel; + } +} diff --git a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/ChannelListener.java b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/ChannelListener.java index aaf724e6..ababc785 100644 --- a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/ChannelListener.java +++ b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/ChannelListener.java @@ -63,4 +63,4 @@ public interface ChannelListener { * @return TRUE if it is, FALSE otherwise. */ boolean isDebug(); -} \ No newline at end of file +} diff --git a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/Injector.java b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/Injector.java index c247397a..2ada4a94 100644 --- a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/Injector.java +++ b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/Injector.java @@ -94,4 +94,4 @@ public interface Injector { * @param player - the more up-to-date player. */ public abstract void setUpdatedPlayer(Player player); -} \ No newline at end of file +} diff --git a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/PipelineProxy.java b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/PipelineProxy.java index 22dd22c6..e49288e9 100644 --- a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/PipelineProxy.java +++ b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/PipelineProxy.java @@ -1,371 +1,371 @@ -/** - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2015 dmulloy2 - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ -package com.comphenix.protocol.injector.netty; - -import io.netty.channel.Channel; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelHandler; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelPipeline; -import io.netty.channel.ChannelPromise; -import io.netty.util.concurrent.EventExecutorGroup; - -import java.net.SocketAddress; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -/** - * A pipeline proxy. - * @author Kristian - */ -public class PipelineProxy implements ChannelPipeline { - protected final ChannelPipeline pipeline; - protected final Channel channel; - - public PipelineProxy(ChannelPipeline pipeline, Channel channel) { - this.pipeline = pipeline; - this.channel = channel; - } - - @Override - public ChannelPipeline addAfter(EventExecutorGroup arg0, String arg1, String arg2, ChannelHandler arg3) { - pipeline.addAfter(arg0, arg1, arg2, arg3); - return this; - } - - @Override - public ChannelPipeline addAfter(String arg0, String arg1, ChannelHandler arg2) { - pipeline.addAfter(arg0, arg1, arg2); - return this; - } - - @Override - public ChannelPipeline addBefore(EventExecutorGroup arg0, String arg1, String arg2, ChannelHandler arg3) { - pipeline.addBefore(arg0, arg1, arg2, arg3); - return this; - } - - @Override - public ChannelPipeline addBefore(String arg0, String arg1, ChannelHandler arg2) { - pipeline.addBefore(arg0, arg1, arg2); - return this; - } - - @Override - public ChannelPipeline addFirst(ChannelHandler... arg0) { - pipeline.addFirst(arg0); - return this; - } - - @Override - public ChannelPipeline addFirst(EventExecutorGroup arg0, ChannelHandler... arg1) { - pipeline.addFirst(arg0, arg1); - return this; - } - - @Override - public ChannelPipeline addFirst(EventExecutorGroup arg0, String arg1, ChannelHandler arg2) { - pipeline.addFirst(arg0, arg1, arg2); - return this; - } - - @Override - public ChannelPipeline addFirst(String arg0, ChannelHandler arg1) { - pipeline.addFirst(arg0, arg1); - return this; - } - - @Override - public ChannelPipeline addLast(ChannelHandler... arg0) { - pipeline.addLast(arg0); - return this; - } - - @Override - public ChannelPipeline addLast(EventExecutorGroup arg0, ChannelHandler... arg1) { - pipeline.addLast(arg0, arg1); - return this; - } - - @Override - public ChannelPipeline addLast(EventExecutorGroup arg0, String arg1, ChannelHandler arg2) { - pipeline.addLast(arg0, arg1, arg2); - return this; - } - - @Override - public ChannelPipeline addLast(String arg0, ChannelHandler arg1) { - pipeline.addLast(arg0, arg1); - return this; - } - - @Override - public ChannelFuture bind(SocketAddress arg0, ChannelPromise arg1) { - return pipeline.bind(arg0, arg1); - } - - @Override - public ChannelFuture bind(SocketAddress arg0) { - return pipeline.bind(arg0); - } - - @Override - public Channel channel() { - return channel; - } - - @Override - public ChannelFuture close() { - return pipeline.close(); - } - - @Override - public ChannelFuture close(ChannelPromise arg0) { - return pipeline.close(arg0); - } - - @Override - public ChannelFuture connect(SocketAddress arg0, ChannelPromise arg1) { - return pipeline.connect(arg0, arg1); - } - - @Override - public ChannelFuture connect(SocketAddress arg0, SocketAddress arg1, ChannelPromise arg2) { - return pipeline.connect(arg0, arg1, arg2); - } - - @Override - public ChannelFuture connect(SocketAddress arg0, SocketAddress arg1) { - return pipeline.connect(arg0, arg1); - } - - @Override - public ChannelFuture connect(SocketAddress arg0) { - return pipeline.connect(arg0); - } - - @Override - public ChannelHandlerContext context(ChannelHandler arg0) { - return pipeline.context(arg0); - } - - @Override - public ChannelHandlerContext context(Class arg0) { - return pipeline.context(arg0); - } - - @Override - public ChannelHandlerContext context(String arg0) { - return pipeline.context(arg0); - } - - // We have to call the depreciated methods to properly implement the proxy - @Override - public ChannelFuture deregister() { - return pipeline.deregister(); - } - - @Override - public ChannelFuture deregister(ChannelPromise arg0) { - return pipeline.deregister(arg0); - } - - @Override - public ChannelPipeline fireChannelUnregistered() { - pipeline.fireChannelUnregistered(); - return this; - } - - @Override - public ChannelFuture disconnect() { - return pipeline.disconnect(); - } - - @Override - public ChannelFuture disconnect(ChannelPromise arg0) { - return pipeline.disconnect(arg0); - } - - @Override - public ChannelPipeline fireChannelActive() { - pipeline.fireChannelActive(); - return this; - } - - @Override - public ChannelPipeline fireChannelInactive() { - pipeline.fireChannelInactive(); - return this; - } - - @Override - public ChannelPipeline fireChannelRead(Object arg0) { - pipeline.fireChannelRead(arg0); - return this; - } - - @Override - public ChannelPipeline fireChannelReadComplete() { - pipeline.fireChannelReadComplete(); - return this; - } - - @Override - public ChannelPipeline fireChannelRegistered() { - pipeline.fireChannelRegistered(); - return this; - } - - @Override - public ChannelPipeline fireChannelWritabilityChanged() { - pipeline.fireChannelWritabilityChanged(); - return this; - } - - @Override - public ChannelPipeline fireExceptionCaught(Throwable arg0) { - pipeline.fireExceptionCaught(arg0); - return this; - } - - @Override - public ChannelPipeline fireUserEventTriggered(Object arg0) { - pipeline.fireUserEventTriggered(arg0); - return this; - } - - @Override - public ChannelHandler first() { - return pipeline.first(); - } - - @Override - public ChannelHandlerContext firstContext() { - return pipeline.firstContext(); - } - - @Override - public ChannelPipeline flush() { - pipeline.flush(); - return this; - } - - @Override - public T get(Class arg0) { - return pipeline.get(arg0); - } - - @Override - public ChannelHandler get(String arg0) { - return pipeline.get(arg0); - } - - @Override - public Iterator> iterator() { - return pipeline.iterator(); - } - - @Override - public ChannelHandler last() { - return pipeline.last(); - } - - @Override - public ChannelHandlerContext lastContext() { - return pipeline.lastContext(); - } - - @Override - public List names() { - return pipeline.names(); - } - - @Override - public ChannelPipeline read() { - pipeline.read(); - return this; - } - - @Override - public ChannelPipeline remove(ChannelHandler arg0) { - pipeline.remove(arg0); - return this; - } - - @Override - public T remove(Class arg0) { - return pipeline.remove(arg0); - } - - @Override - public ChannelHandler remove(String arg0) { - return pipeline.remove(arg0); - } - - @Override - public ChannelHandler removeFirst() { - return pipeline.removeFirst(); - } - - @Override - public ChannelHandler removeLast() { - return pipeline.removeLast(); - } - - @Override - public ChannelPipeline replace(ChannelHandler arg0, String arg1, ChannelHandler arg2) { - pipeline.replace(arg0, arg1, arg2); - return this; - } - - @Override - public T replace(Class arg0, String arg1, ChannelHandler arg2) { - return pipeline.replace(arg0, arg1, arg2); - } - - @Override - public ChannelHandler replace(String arg0, String arg1, ChannelHandler arg2) { - return pipeline.replace(arg0, arg1, arg2); - } - - @Override - public Map toMap() { - return pipeline.toMap(); - } - - @Override - public ChannelFuture write(Object arg0, ChannelPromise arg1) { - return pipeline.write(arg0, arg1); - } - - @Override - public ChannelFuture write(Object arg0) { - return pipeline.write(arg0); - } - - @Override - public ChannelFuture writeAndFlush(Object arg0, ChannelPromise arg1) { - return pipeline.writeAndFlush(arg0, arg1); - } - - @Override - public ChannelFuture writeAndFlush(Object arg0) { - return pipeline.writeAndFlush(arg0); - } -} \ No newline at end of file +/** + * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. + * Copyright (C) 2015 dmulloy2 + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ +package com.comphenix.protocol.injector.netty; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.ChannelPromise; +import io.netty.util.concurrent.EventExecutorGroup; + +import java.net.SocketAddress; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +/** + * A pipeline proxy. + * @author Kristian + */ +public class PipelineProxy implements ChannelPipeline { + protected final ChannelPipeline pipeline; + protected final Channel channel; + + public PipelineProxy(ChannelPipeline pipeline, Channel channel) { + this.pipeline = pipeline; + this.channel = channel; + } + + @Override + public ChannelPipeline addAfter(EventExecutorGroup arg0, String arg1, String arg2, ChannelHandler arg3) { + pipeline.addAfter(arg0, arg1, arg2, arg3); + return this; + } + + @Override + public ChannelPipeline addAfter(String arg0, String arg1, ChannelHandler arg2) { + pipeline.addAfter(arg0, arg1, arg2); + return this; + } + + @Override + public ChannelPipeline addBefore(EventExecutorGroup arg0, String arg1, String arg2, ChannelHandler arg3) { + pipeline.addBefore(arg0, arg1, arg2, arg3); + return this; + } + + @Override + public ChannelPipeline addBefore(String arg0, String arg1, ChannelHandler arg2) { + pipeline.addBefore(arg0, arg1, arg2); + return this; + } + + @Override + public ChannelPipeline addFirst(ChannelHandler... arg0) { + pipeline.addFirst(arg0); + return this; + } + + @Override + public ChannelPipeline addFirst(EventExecutorGroup arg0, ChannelHandler... arg1) { + pipeline.addFirst(arg0, arg1); + return this; + } + + @Override + public ChannelPipeline addFirst(EventExecutorGroup arg0, String arg1, ChannelHandler arg2) { + pipeline.addFirst(arg0, arg1, arg2); + return this; + } + + @Override + public ChannelPipeline addFirst(String arg0, ChannelHandler arg1) { + pipeline.addFirst(arg0, arg1); + return this; + } + + @Override + public ChannelPipeline addLast(ChannelHandler... arg0) { + pipeline.addLast(arg0); + return this; + } + + @Override + public ChannelPipeline addLast(EventExecutorGroup arg0, ChannelHandler... arg1) { + pipeline.addLast(arg0, arg1); + return this; + } + + @Override + public ChannelPipeline addLast(EventExecutorGroup arg0, String arg1, ChannelHandler arg2) { + pipeline.addLast(arg0, arg1, arg2); + return this; + } + + @Override + public ChannelPipeline addLast(String arg0, ChannelHandler arg1) { + pipeline.addLast(arg0, arg1); + return this; + } + + @Override + public ChannelFuture bind(SocketAddress arg0, ChannelPromise arg1) { + return pipeline.bind(arg0, arg1); + } + + @Override + public ChannelFuture bind(SocketAddress arg0) { + return pipeline.bind(arg0); + } + + @Override + public Channel channel() { + return channel; + } + + @Override + public ChannelFuture close() { + return pipeline.close(); + } + + @Override + public ChannelFuture close(ChannelPromise arg0) { + return pipeline.close(arg0); + } + + @Override + public ChannelFuture connect(SocketAddress arg0, ChannelPromise arg1) { + return pipeline.connect(arg0, arg1); + } + + @Override + public ChannelFuture connect(SocketAddress arg0, SocketAddress arg1, ChannelPromise arg2) { + return pipeline.connect(arg0, arg1, arg2); + } + + @Override + public ChannelFuture connect(SocketAddress arg0, SocketAddress arg1) { + return pipeline.connect(arg0, arg1); + } + + @Override + public ChannelFuture connect(SocketAddress arg0) { + return pipeline.connect(arg0); + } + + @Override + public ChannelHandlerContext context(ChannelHandler arg0) { + return pipeline.context(arg0); + } + + @Override + public ChannelHandlerContext context(Class arg0) { + return pipeline.context(arg0); + } + + @Override + public ChannelHandlerContext context(String arg0) { + return pipeline.context(arg0); + } + + // We have to call the depreciated methods to properly implement the proxy + @Override + public ChannelFuture deregister() { + return pipeline.deregister(); + } + + @Override + public ChannelFuture deregister(ChannelPromise arg0) { + return pipeline.deregister(arg0); + } + + @Override + public ChannelPipeline fireChannelUnregistered() { + pipeline.fireChannelUnregistered(); + return this; + } + + @Override + public ChannelFuture disconnect() { + return pipeline.disconnect(); + } + + @Override + public ChannelFuture disconnect(ChannelPromise arg0) { + return pipeline.disconnect(arg0); + } + + @Override + public ChannelPipeline fireChannelActive() { + pipeline.fireChannelActive(); + return this; + } + + @Override + public ChannelPipeline fireChannelInactive() { + pipeline.fireChannelInactive(); + return this; + } + + @Override + public ChannelPipeline fireChannelRead(Object arg0) { + pipeline.fireChannelRead(arg0); + return this; + } + + @Override + public ChannelPipeline fireChannelReadComplete() { + pipeline.fireChannelReadComplete(); + return this; + } + + @Override + public ChannelPipeline fireChannelRegistered() { + pipeline.fireChannelRegistered(); + return this; + } + + @Override + public ChannelPipeline fireChannelWritabilityChanged() { + pipeline.fireChannelWritabilityChanged(); + return this; + } + + @Override + public ChannelPipeline fireExceptionCaught(Throwable arg0) { + pipeline.fireExceptionCaught(arg0); + return this; + } + + @Override + public ChannelPipeline fireUserEventTriggered(Object arg0) { + pipeline.fireUserEventTriggered(arg0); + return this; + } + + @Override + public ChannelHandler first() { + return pipeline.first(); + } + + @Override + public ChannelHandlerContext firstContext() { + return pipeline.firstContext(); + } + + @Override + public ChannelPipeline flush() { + pipeline.flush(); + return this; + } + + @Override + public T get(Class arg0) { + return pipeline.get(arg0); + } + + @Override + public ChannelHandler get(String arg0) { + return pipeline.get(arg0); + } + + @Override + public Iterator> iterator() { + return pipeline.iterator(); + } + + @Override + public ChannelHandler last() { + return pipeline.last(); + } + + @Override + public ChannelHandlerContext lastContext() { + return pipeline.lastContext(); + } + + @Override + public List names() { + return pipeline.names(); + } + + @Override + public ChannelPipeline read() { + pipeline.read(); + return this; + } + + @Override + public ChannelPipeline remove(ChannelHandler arg0) { + pipeline.remove(arg0); + return this; + } + + @Override + public T remove(Class arg0) { + return pipeline.remove(arg0); + } + + @Override + public ChannelHandler remove(String arg0) { + return pipeline.remove(arg0); + } + + @Override + public ChannelHandler removeFirst() { + return pipeline.removeFirst(); + } + + @Override + public ChannelHandler removeLast() { + return pipeline.removeLast(); + } + + @Override + public ChannelPipeline replace(ChannelHandler arg0, String arg1, ChannelHandler arg2) { + pipeline.replace(arg0, arg1, arg2); + return this; + } + + @Override + public T replace(Class arg0, String arg1, ChannelHandler arg2) { + return pipeline.replace(arg0, arg1, arg2); + } + + @Override + public ChannelHandler replace(String arg0, String arg1, ChannelHandler arg2) { + return pipeline.replace(arg0, arg1, arg2); + } + + @Override + public Map toMap() { + return pipeline.toMap(); + } + + @Override + public ChannelFuture write(Object arg0, ChannelPromise arg1) { + return pipeline.write(arg0, arg1); + } + + @Override + public ChannelFuture write(Object arg0) { + return pipeline.write(arg0); + } + + @Override + public ChannelFuture writeAndFlush(Object arg0, ChannelPromise arg1) { + return pipeline.writeAndFlush(arg0, arg1); + } + + @Override + public ChannelFuture writeAndFlush(Object arg0) { + return pipeline.writeAndFlush(arg0); + } +} diff --git a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/packet/LegacyNetworkMarker.java b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/packet/LegacyNetworkMarker.java index f126215d..a9c41387 100644 --- a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/packet/LegacyNetworkMarker.java +++ b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/packet/LegacyNetworkMarker.java @@ -62,4 +62,4 @@ public class LegacyNetworkMarker extends NetworkMarker { throw new RuntimeException("Cannot add header.", e); } } -} \ No newline at end of file +} diff --git a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/packet/PacketInjector.java b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/packet/PacketInjector.java index a3a60e45..5546a525 100644 --- a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/packet/PacketInjector.java +++ b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/packet/PacketInjector.java @@ -76,4 +76,4 @@ public interface PacketInjector { * Perform any necessary cleanup before unloading ProtocolLib. */ public abstract void cleanupAll(); -} \ No newline at end of file +} diff --git a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjectionHandler.java b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjectionHandler.java index 43ebed3b..cc053d60 100644 --- a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjectionHandler.java +++ b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjectionHandler.java @@ -202,4 +202,4 @@ public interface PlayerInjectionHandler { public abstract boolean hasMainThreadListener(PacketType type); public abstract Channel getChannel(Player player); -} \ No newline at end of file +} diff --git a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/ReplacedArrayList.java b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/ReplacedArrayList.java index 8fe8b3e3..9caa56f4 100644 --- a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/ReplacedArrayList.java +++ b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/ReplacedArrayList.java @@ -367,4 +367,4 @@ class ReplacedArrayList extends ArrayList { revertAll(); super.finalize(); } -} \ No newline at end of file +} diff --git a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/server/AbstractInputStreamLookup.java b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/server/AbstractInputStreamLookup.java index 6e60cbba..e5518418 100644 --- a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/server/AbstractInputStreamLookup.java +++ b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/server/AbstractInputStreamLookup.java @@ -80,4 +80,4 @@ public abstract class AbstractInputStreamLookup { * Invoked when the injection should be undone. */ public abstract void cleanupAll(); -} \ No newline at end of file +} diff --git a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/server/InjectorContainer.java b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/server/InjectorContainer.java index 7a642a09..560b0176 100644 --- a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/server/InjectorContainer.java +++ b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/server/InjectorContainer.java @@ -18,4 +18,4 @@ class InjectorContainer { throw new IllegalArgumentException("Injector cannot be NULL."); this.injector = injector; } -} \ No newline at end of file +} diff --git a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/server/QueuedSendPacket.java b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/server/QueuedSendPacket.java index 0e7a479b..aa2090ca 100644 --- a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/server/QueuedSendPacket.java +++ b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/server/QueuedSendPacket.java @@ -40,4 +40,4 @@ class QueuedSendPacket { public boolean isFiltered() { return filtered; } -} \ No newline at end of file +} diff --git a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/server/SocketInjector.java b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/server/SocketInjector.java index 9060d884..3c08a0de 100644 --- a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/server/SocketInjector.java +++ b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/server/SocketInjector.java @@ -68,4 +68,4 @@ public interface SocketInjector { * @param updatedPlayer - the real Bukkit player. */ public abstract void setUpdatedPlayer(Player updatedPlayer); -} \ No newline at end of file +} diff --git a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/spigot/AbstractPacketInjector.java b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/spigot/AbstractPacketInjector.java index 925423d7..df279dfe 100644 --- a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/spigot/AbstractPacketInjector.java +++ b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/spigot/AbstractPacketInjector.java @@ -51,4 +51,4 @@ public abstract class AbstractPacketInjector implements PacketInjector { public void cleanupAll() { reveivedFilters.clear(); } -} \ No newline at end of file +} diff --git a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/spigot/AbstractPlayerHandler.java b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/spigot/AbstractPlayerHandler.java index 34c54671..81f8616d 100644 --- a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/spigot/AbstractPlayerHandler.java +++ b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/spigot/AbstractPlayerHandler.java @@ -80,4 +80,4 @@ public abstract class AbstractPlayerHandler implements PlayerInjectionHandler { public void checkListener(Set listeners) { // Yes, really } -} \ No newline at end of file +} diff --git a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/metrics/Metrics.java b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/metrics/Metrics.java index e22d5f75..9127cd52 100644 --- a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/metrics/Metrics.java +++ b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/metrics/Metrics.java @@ -750,4 +750,4 @@ public class Metrics { return plotter.name.equals(name) && plotter.getValue() == getValue(); } } -} \ No newline at end of file +} diff --git a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/updater/BukkitUpdater.java b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/updater/BukkitUpdater.java index 4a835906..39fabfeb 100644 --- a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/updater/BukkitUpdater.java +++ b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/updater/BukkitUpdater.java @@ -1,417 +1,417 @@ -/* - * Updater for Bukkit. - * - * This class provides the means to safely and easily update a plugin, or check to see if it is updated using dev.bukkit.org - */ - -// Somewhat modified by aadnk. -package com.comphenix.protocol.updater; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLConnection; -import java.util.Enumeration; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.plugin.Plugin; -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; -import org.json.simple.JSONValue; - -import com.comphenix.protocol.ProtocolLibrary; -import com.comphenix.protocol.error.Report; - -/** - * Check dev.bukkit.org to find updates for a given plugin, and download the updates if needed. - *

- * VERY, VERY IMPORTANT: Because there are no standards for adding auto-update toggles in your plugin's config, this system provides NO CHECK WITH YOUR CONFIG to make sure the user has allowed auto-updating. - *
- * It is a BUKKIT POLICY that you include a boolean value in your config that prevents the auto-updater from running AT ALL. - *
- * If you fail to include this option in your config, your plugin will be REJECTED when you attempt to submit it to dev.bukkit.org. - *

- * An example of a good configuration option would be something similar to 'auto-update: true' - if this value is set to false you may NOT run the auto-updater. - *
- * If you are unsure about these rules, please read the plugin submission guidelines: http://goo.gl/8iU5l - * - * @author Gravity - * @version 2.0 - */ - -public class BukkitUpdater extends Updater { - private URL url; // Connecting to RSS - private File file; // The plugin's file - private Thread thread; // Updater thread - - private int id = -1; // Project's Curse ID - private String apiKey = null; // BukkitDev ServerMods API key - private static final String TITLE_VALUE = "name"; // Gets remote file's title - private static final String LINK_VALUE = "downloadUrl"; // Gets remote file's download link - private static final String TYPE_VALUE = "releaseType"; // Gets remote file's release type - private static final String VERSION_VALUE = "gameVersion"; // Gets remote file's build version - private static final Object FILE_NAME = "fileName"; // Gets remote file's name - private static final String QUERY = "/servermods/files?projectIds="; // Path to GET - private static final String HOST = "https://api.curseforge.com"; // Slugs will be appended to this to get to the project's RSS feed - - // private static final String[] NO_UPDATE_TAG = { "-DEV", "-PRE", "-SNAPSHOT" }; // If the version number contains one of these, don't update. - private static final int BYTE_SIZE = 1024; // Used for downloading files - - private YamlConfiguration config; // Config file - private String updateFolder;// The folder that downloads will be placed in - - /** - * Initialize the updater. - *

- * Call {@link #start()} to actually start looking (and downloading) updates. - * - * @param plugin The plugin that is checking for an update. - * @param id The dev.bukkit.org id of the project - * @param file The file that the plugin is running from, get this by doing this.getFile() from within your main class. - * @param type Specify the type of update this will be. See {@link UpdateType} - * @param announce True if the program should announce the progress of new updates in console - */ - public BukkitUpdater(Plugin plugin, int id, File file, UpdateType type, boolean announce) { - super(plugin, type, announce); - - this.file = file; - this.id = id; - this.updateFolder = plugin.getServer().getUpdateFolder(); - - File dataFolder = plugin.getDataFolder(); - if (dataFolder != null) { - final File pluginFile = plugin.getDataFolder().getParentFile(); - final File updaterFile = new File(pluginFile, "Updater"); - final File updaterConfigFile = new File(updaterFile, "config.yml"); - - if (!updaterFile.exists()) { - updaterFile.mkdir(); - } - if (!updaterConfigFile.exists()) { - try { - updaterConfigFile.createNewFile(); - } catch (final IOException e) { - plugin.getLogger().severe("The updater could not create a configuration in " + updaterFile.getAbsolutePath()); - e.printStackTrace(); - } - } - this.config = YamlConfiguration.loadConfiguration(updaterConfigFile); - - this.config.options().header("This configuration file affects all plugins using the Updater system (version 2+ - http://forums.bukkit.org/threads/96681/ )" + '\n' - + "If you wish to use your API key, read http://wiki.bukkit.org/ServerMods_API and place it below." + '\n' - + "Some updating systems will not adhere to the disabled value, but these may be turned off in their plugin's configuration."); - this.config.addDefault("api-key", "PUT_API_KEY_HERE"); - this.config.addDefault("disable", false); - - if (this.config.get("api-key", null) == null) { - this.config.options().copyDefaults(true); - try { - this.config.save(updaterConfigFile); - } catch (final IOException e) { - plugin.getLogger().severe("The updater could not save the configuration in " + updaterFile.getAbsolutePath()); - e.printStackTrace(); - } - } - - if (this.config.getBoolean("disable")) { - this.result = UpdateResult.DISABLED; - return; - } - - String key = this.config.getString("api-key"); - if (key.equalsIgnoreCase("PUT_API_KEY_HERE") || key.equals("")) { - key = null; - } - - this.apiKey = key; - } - - try { - this.url = new URL(BukkitUpdater.HOST + BukkitUpdater.QUERY + id); - } catch (final MalformedURLException e) { - plugin.getLogger().severe("The project ID provided for updating, " + id + " is invalid."); - this.result = UpdateResult.FAIL_BADID; - e.printStackTrace(); - } - } - - // aadnk - decouple the thread start and the constructor. - /** - * Begin looking for updates. - * @param type - the update type. - */ - public void start(UpdateType type) { - waitForThread(); - - this.type = type; - this.thread = new Thread(new UpdateRunnable()); - this.thread.start(); - } - - /** - * Save an update from dev.bukkit.org into the server's update folder. - */ - private void saveFile(File folder, String file, String u) { - if (!folder.exists()) { - folder.mkdir(); - } - BufferedInputStream in = null; - FileOutputStream fout = null; - try { - // Download the file - final URL url = new URL(u); - final int fileLength = url.openConnection().getContentLength(); - in = new BufferedInputStream(url.openStream()); - fout = new FileOutputStream(folder.getAbsolutePath() + "/" + file); - - final byte[] data = new byte[BukkitUpdater.BYTE_SIZE]; - int count; - if (this.announce) { - this.plugin.getLogger().info("About to download a new update: " + this.versionName); - } - long downloaded = 0; - while ((count = in.read(data, 0, BukkitUpdater.BYTE_SIZE)) != -1) { - downloaded += count; - fout.write(data, 0, count); - final int percent = (int) ((downloaded * 100) / fileLength); - if (this.announce && ((percent % 10) == 0)) { - this.plugin.getLogger().info("Downloading update: " + percent + "% of " + fileLength + " bytes."); - } - } - //Just a quick check to make sure we didn't leave any files from last time... - for (final File xFile : new File(this.plugin.getDataFolder().getParent(), this.updateFolder).listFiles()) { - if (xFile.getName().endsWith(".zip")) { - xFile.delete(); - } - } - // Check to see if it's a zip file, if it is, unzip it. - final File dFile = new File(folder.getAbsolutePath() + "/" + file); - if (dFile.getName().endsWith(".zip")) { - // Unzip - this.unzip(dFile.getCanonicalPath()); - } - if (this.announce) { - this.plugin.getLogger().info("Finished updating."); - } - } catch (final Exception ex) { - this.plugin.getLogger().warning("The auto-updater tried to download a new update, but was unsuccessful."); - this.result = BukkitUpdater.UpdateResult.FAIL_DOWNLOAD; - } finally { - try { - if (in != null) { - in.close(); - } - if (fout != null) { - fout.close(); - } - } catch (final Exception ex) { - } - } - } - - /** - * Part of Zip-File-Extractor, modified by Gravity for use with Bukkit - */ - private void unzip(String file) { - try { - final File fSourceZip = new File(file); - final String zipPath = file.substring(0, file.length() - 4); - ZipFile zipFile = new ZipFile(fSourceZip); - Enumeration e = zipFile.entries(); - while (e.hasMoreElements()) { - ZipEntry entry = e.nextElement(); - File destinationFilePath = new File(zipPath, entry.getName()); - destinationFilePath.getParentFile().mkdirs(); - if (entry.isDirectory()) { - continue; - } else { - final BufferedInputStream bis = new BufferedInputStream(zipFile.getInputStream(entry)); - int b; - final byte buffer[] = new byte[BukkitUpdater.BYTE_SIZE]; - final FileOutputStream fos = new FileOutputStream(destinationFilePath); - final BufferedOutputStream bos = new BufferedOutputStream(fos, BukkitUpdater.BYTE_SIZE); - while ((b = bis.read(buffer, 0, BukkitUpdater.BYTE_SIZE)) != -1) { - bos.write(buffer, 0, b); - } - bos.flush(); - bos.close(); - bis.close(); - final String name = destinationFilePath.getName(); - if (name.endsWith(".jar") && this.pluginFile(name)) { - destinationFilePath.renameTo(new File(this.plugin.getDataFolder().getParent(), this.updateFolder + "/" + name)); - } - } - entry = null; - destinationFilePath = null; - } - e = null; - zipFile.close(); - zipFile = null; - - // Move any plugin data folders that were included to the right place, Bukkit won't do this for us. - for (final File dFile : new File(zipPath).listFiles()) { - if (dFile.isDirectory()) { - if (this.pluginFile(dFile.getName())) { - final File oFile = new File(this.plugin.getDataFolder().getParent(), dFile.getName()); // Get current dir - final File[] contents = oFile.listFiles(); // List of existing files in the current dir - for (final File cFile : dFile.listFiles()) // Loop through all the files in the new dir - { - boolean found = false; - for (final File xFile : contents) // Loop through contents to see if it exists - { - if (xFile.getName().equals(cFile.getName())) { - found = true; - break; - } - } - if (!found) { - // Move the new file into the current dir - cFile.renameTo(new File(oFile.getCanonicalFile() + "/" + cFile.getName())); - } else { - // This file already exists, so we don't need it anymore. - cFile.delete(); - } - } - } - } - dFile.delete(); - } - new File(zipPath).delete(); - fSourceZip.delete(); - } catch (final IOException ex) { - this.plugin.getLogger().warning("The auto-updater tried to unzip a new update file, but was unsuccessful."); - this.result = BukkitUpdater.UpdateResult.FAIL_DOWNLOAD; - ex.printStackTrace(); - } - new File(file).delete(); - } - - /** - * Check if the name of a jar is one of the plugins currently installed, used for extracting the correct files out of a zip. - */ - private boolean pluginFile(String name) { - for (final File file : new File("plugins").listFiles()) { - if (file.getName().equals(name)) { - return true; - } - } - return false; - } - - /** - * Evaluate whether the version number is marked showing that it should not be updated by this program - */ - /* private boolean hasTag(String version) { - for (final String string : BukkitUpdater.NO_UPDATE_TAG) { - if (version.contains(string)) { - return true; - } - } - return false; - } */ - - public boolean read() { - try { - final URLConnection conn = this.url.openConnection(); - conn.setConnectTimeout(5000); - - if (this.apiKey != null) { - conn.addRequestProperty("X-API-Key", this.apiKey); - } - conn.addRequestProperty("User-Agent", "Updater (by Gravity)"); - conn.setDoOutput(true); - - final BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); - final String response = reader.readLine(); - - final JSONArray array = (JSONArray) JSONValue.parse(response); - - if (array.size() == 0) { - this.plugin.getLogger().warning("The updater could not find any files for the project id " + this.id); - this.result = UpdateResult.FAIL_BADID; - return false; - } - - final JSONObject jsonObject = (JSONObject) array.get(array.size() - 1); - this.versionFileName = (String) jsonObject.get(BukkitUpdater.FILE_NAME); - this.versionName = (String) jsonObject.get(BukkitUpdater.TITLE_VALUE); - this.versionLink = (String) jsonObject.get(BukkitUpdater.LINK_VALUE); - this.versionType = (String) jsonObject.get(BukkitUpdater.TYPE_VALUE); - this.versionGameVersion = (String) jsonObject.get(BukkitUpdater.VERSION_VALUE); - - return true; - } catch (final IOException e) { - if (e.getMessage().contains("HTTP response code: 403")) { - this.plugin.getLogger().warning("dev.bukkit.org rejected the API key provided in plugins/Updater/config.yml"); - this.plugin.getLogger().warning("Please double-check your configuration to ensure it is correct."); - this.result = UpdateResult.FAIL_APIKEY; - } else { - this.plugin.getLogger().warning("The updater could not contact dev.bukkit.org for updating."); - this.plugin.getLogger().warning("If you have not recently modified your configuration and this is the first time you are seeing this message, the site may be experiencing temporary downtime."); - this.result = UpdateResult.FAIL_DBO; - } - e.printStackTrace(); - return false; - } - } - - // aadnk - added listeners - private class UpdateRunnable implements Runnable { - @Override - public void run() { - try { - if (BukkitUpdater.this.url != null) { - // Obtain the results of the project's file feed - if (BukkitUpdater.this.read()) { - if (BukkitUpdater.this.versionCheck(BukkitUpdater.this.versionName)) { - performUpdate(); - } - } - } - } catch (Exception e) { - // Any generic error will be handled here - ProtocolLibrary.getErrorReporter().reportDetailed( - BukkitUpdater.this, Report.newBuilder(REPORT_CANNOT_UPDATE_PLUGIN).error(e).callerParam(this)); - - } finally { - // Invoke the listeners on the main thread - for (Runnable listener : listeners) { - plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, listener); - } - } - } - - private void performUpdate() { - if ((BukkitUpdater.this.versionLink != null) && (BukkitUpdater.this.type != UpdateType.NO_DOWNLOAD)) { - final File pluginFolder = plugin.getDataFolder().getParentFile(); - File destinationFolder = new File(pluginFolder, updateFolder); - String name = BukkitUpdater.this.file.getName(); - - // If it's a zip file, it shouldn't be downloaded as the plugin's name - if (BukkitUpdater.this.versionLink.endsWith(".zip")) { - name = versionFileName; - } - BukkitUpdater.this.saveFile( - destinationFolder, - name, - BukkitUpdater.this.versionLink - ); - } else { - BukkitUpdater.this.result = UpdateResult.UPDATE_AVAILABLE; - } - } - } - - @Override - public String getRemoteVersion() { - return getLatestName(); - } -} \ No newline at end of file +/* + * Updater for Bukkit. + * + * This class provides the means to safely and easily update a plugin, or check to see if it is updated using dev.bukkit.org + */ + +// Somewhat modified by aadnk. +package com.comphenix.protocol.updater; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.util.Enumeration; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.plugin.Plugin; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; + +import com.comphenix.protocol.ProtocolLibrary; +import com.comphenix.protocol.error.Report; + +/** + * Check dev.bukkit.org to find updates for a given plugin, and download the updates if needed. + *

+ * VERY, VERY IMPORTANT: Because there are no standards for adding auto-update toggles in your plugin's config, this system provides NO CHECK WITH YOUR CONFIG to make sure the user has allowed auto-updating. + *
+ * It is a BUKKIT POLICY that you include a boolean value in your config that prevents the auto-updater from running AT ALL. + *
+ * If you fail to include this option in your config, your plugin will be REJECTED when you attempt to submit it to dev.bukkit.org. + *

+ * An example of a good configuration option would be something similar to 'auto-update: true' - if this value is set to false you may NOT run the auto-updater. + *
+ * If you are unsure about these rules, please read the plugin submission guidelines: http://goo.gl/8iU5l + * + * @author Gravity + * @version 2.0 + */ + +public class BukkitUpdater extends Updater { + private URL url; // Connecting to RSS + private File file; // The plugin's file + private Thread thread; // Updater thread + + private int id = -1; // Project's Curse ID + private String apiKey = null; // BukkitDev ServerMods API key + private static final String TITLE_VALUE = "name"; // Gets remote file's title + private static final String LINK_VALUE = "downloadUrl"; // Gets remote file's download link + private static final String TYPE_VALUE = "releaseType"; // Gets remote file's release type + private static final String VERSION_VALUE = "gameVersion"; // Gets remote file's build version + private static final Object FILE_NAME = "fileName"; // Gets remote file's name + private static final String QUERY = "/servermods/files?projectIds="; // Path to GET + private static final String HOST = "https://api.curseforge.com"; // Slugs will be appended to this to get to the project's RSS feed + + // private static final String[] NO_UPDATE_TAG = { "-DEV", "-PRE", "-SNAPSHOT" }; // If the version number contains one of these, don't update. + private static final int BYTE_SIZE = 1024; // Used for downloading files + + private YamlConfiguration config; // Config file + private String updateFolder;// The folder that downloads will be placed in + + /** + * Initialize the updater. + *

+ * Call {@link #start()} to actually start looking (and downloading) updates. + * + * @param plugin The plugin that is checking for an update. + * @param id The dev.bukkit.org id of the project + * @param file The file that the plugin is running from, get this by doing this.getFile() from within your main class. + * @param type Specify the type of update this will be. See {@link UpdateType} + * @param announce True if the program should announce the progress of new updates in console + */ + public BukkitUpdater(Plugin plugin, int id, File file, UpdateType type, boolean announce) { + super(plugin, type, announce); + + this.file = file; + this.id = id; + this.updateFolder = plugin.getServer().getUpdateFolder(); + + File dataFolder = plugin.getDataFolder(); + if (dataFolder != null) { + final File pluginFile = plugin.getDataFolder().getParentFile(); + final File updaterFile = new File(pluginFile, "Updater"); + final File updaterConfigFile = new File(updaterFile, "config.yml"); + + if (!updaterFile.exists()) { + updaterFile.mkdir(); + } + if (!updaterConfigFile.exists()) { + try { + updaterConfigFile.createNewFile(); + } catch (final IOException e) { + plugin.getLogger().severe("The updater could not create a configuration in " + updaterFile.getAbsolutePath()); + e.printStackTrace(); + } + } + this.config = YamlConfiguration.loadConfiguration(updaterConfigFile); + + this.config.options().header("This configuration file affects all plugins using the Updater system (version 2+ - http://forums.bukkit.org/threads/96681/ )" + '\n' + + "If you wish to use your API key, read http://wiki.bukkit.org/ServerMods_API and place it below." + '\n' + + "Some updating systems will not adhere to the disabled value, but these may be turned off in their plugin's configuration."); + this.config.addDefault("api-key", "PUT_API_KEY_HERE"); + this.config.addDefault("disable", false); + + if (this.config.get("api-key", null) == null) { + this.config.options().copyDefaults(true); + try { + this.config.save(updaterConfigFile); + } catch (final IOException e) { + plugin.getLogger().severe("The updater could not save the configuration in " + updaterFile.getAbsolutePath()); + e.printStackTrace(); + } + } + + if (this.config.getBoolean("disable")) { + this.result = UpdateResult.DISABLED; + return; + } + + String key = this.config.getString("api-key"); + if (key.equalsIgnoreCase("PUT_API_KEY_HERE") || key.equals("")) { + key = null; + } + + this.apiKey = key; + } + + try { + this.url = new URL(BukkitUpdater.HOST + BukkitUpdater.QUERY + id); + } catch (final MalformedURLException e) { + plugin.getLogger().severe("The project ID provided for updating, " + id + " is invalid."); + this.result = UpdateResult.FAIL_BADID; + e.printStackTrace(); + } + } + + // aadnk - decouple the thread start and the constructor. + /** + * Begin looking for updates. + * @param type - the update type. + */ + public void start(UpdateType type) { + waitForThread(); + + this.type = type; + this.thread = new Thread(new UpdateRunnable()); + this.thread.start(); + } + + /** + * Save an update from dev.bukkit.org into the server's update folder. + */ + private void saveFile(File folder, String file, String u) { + if (!folder.exists()) { + folder.mkdir(); + } + BufferedInputStream in = null; + FileOutputStream fout = null; + try { + // Download the file + final URL url = new URL(u); + final int fileLength = url.openConnection().getContentLength(); + in = new BufferedInputStream(url.openStream()); + fout = new FileOutputStream(folder.getAbsolutePath() + "/" + file); + + final byte[] data = new byte[BukkitUpdater.BYTE_SIZE]; + int count; + if (this.announce) { + this.plugin.getLogger().info("About to download a new update: " + this.versionName); + } + long downloaded = 0; + while ((count = in.read(data, 0, BukkitUpdater.BYTE_SIZE)) != -1) { + downloaded += count; + fout.write(data, 0, count); + final int percent = (int) ((downloaded * 100) / fileLength); + if (this.announce && ((percent % 10) == 0)) { + this.plugin.getLogger().info("Downloading update: " + percent + "% of " + fileLength + " bytes."); + } + } + //Just a quick check to make sure we didn't leave any files from last time... + for (final File xFile : new File(this.plugin.getDataFolder().getParent(), this.updateFolder).listFiles()) { + if (xFile.getName().endsWith(".zip")) { + xFile.delete(); + } + } + // Check to see if it's a zip file, if it is, unzip it. + final File dFile = new File(folder.getAbsolutePath() + "/" + file); + if (dFile.getName().endsWith(".zip")) { + // Unzip + this.unzip(dFile.getCanonicalPath()); + } + if (this.announce) { + this.plugin.getLogger().info("Finished updating."); + } + } catch (final Exception ex) { + this.plugin.getLogger().warning("The auto-updater tried to download a new update, but was unsuccessful."); + this.result = BukkitUpdater.UpdateResult.FAIL_DOWNLOAD; + } finally { + try { + if (in != null) { + in.close(); + } + if (fout != null) { + fout.close(); + } + } catch (final Exception ex) { + } + } + } + + /** + * Part of Zip-File-Extractor, modified by Gravity for use with Bukkit + */ + private void unzip(String file) { + try { + final File fSourceZip = new File(file); + final String zipPath = file.substring(0, file.length() - 4); + ZipFile zipFile = new ZipFile(fSourceZip); + Enumeration e = zipFile.entries(); + while (e.hasMoreElements()) { + ZipEntry entry = e.nextElement(); + File destinationFilePath = new File(zipPath, entry.getName()); + destinationFilePath.getParentFile().mkdirs(); + if (entry.isDirectory()) { + continue; + } else { + final BufferedInputStream bis = new BufferedInputStream(zipFile.getInputStream(entry)); + int b; + final byte buffer[] = new byte[BukkitUpdater.BYTE_SIZE]; + final FileOutputStream fos = new FileOutputStream(destinationFilePath); + final BufferedOutputStream bos = new BufferedOutputStream(fos, BukkitUpdater.BYTE_SIZE); + while ((b = bis.read(buffer, 0, BukkitUpdater.BYTE_SIZE)) != -1) { + bos.write(buffer, 0, b); + } + bos.flush(); + bos.close(); + bis.close(); + final String name = destinationFilePath.getName(); + if (name.endsWith(".jar") && this.pluginFile(name)) { + destinationFilePath.renameTo(new File(this.plugin.getDataFolder().getParent(), this.updateFolder + "/" + name)); + } + } + entry = null; + destinationFilePath = null; + } + e = null; + zipFile.close(); + zipFile = null; + + // Move any plugin data folders that were included to the right place, Bukkit won't do this for us. + for (final File dFile : new File(zipPath).listFiles()) { + if (dFile.isDirectory()) { + if (this.pluginFile(dFile.getName())) { + final File oFile = new File(this.plugin.getDataFolder().getParent(), dFile.getName()); // Get current dir + final File[] contents = oFile.listFiles(); // List of existing files in the current dir + for (final File cFile : dFile.listFiles()) // Loop through all the files in the new dir + { + boolean found = false; + for (final File xFile : contents) // Loop through contents to see if it exists + { + if (xFile.getName().equals(cFile.getName())) { + found = true; + break; + } + } + if (!found) { + // Move the new file into the current dir + cFile.renameTo(new File(oFile.getCanonicalFile() + "/" + cFile.getName())); + } else { + // This file already exists, so we don't need it anymore. + cFile.delete(); + } + } + } + } + dFile.delete(); + } + new File(zipPath).delete(); + fSourceZip.delete(); + } catch (final IOException ex) { + this.plugin.getLogger().warning("The auto-updater tried to unzip a new update file, but was unsuccessful."); + this.result = BukkitUpdater.UpdateResult.FAIL_DOWNLOAD; + ex.printStackTrace(); + } + new File(file).delete(); + } + + /** + * Check if the name of a jar is one of the plugins currently installed, used for extracting the correct files out of a zip. + */ + private boolean pluginFile(String name) { + for (final File file : new File("plugins").listFiles()) { + if (file.getName().equals(name)) { + return true; + } + } + return false; + } + + /** + * Evaluate whether the version number is marked showing that it should not be updated by this program + */ + /* private boolean hasTag(String version) { + for (final String string : BukkitUpdater.NO_UPDATE_TAG) { + if (version.contains(string)) { + return true; + } + } + return false; + } */ + + public boolean read() { + try { + final URLConnection conn = this.url.openConnection(); + conn.setConnectTimeout(5000); + + if (this.apiKey != null) { + conn.addRequestProperty("X-API-Key", this.apiKey); + } + conn.addRequestProperty("User-Agent", "Updater (by Gravity)"); + conn.setDoOutput(true); + + final BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); + final String response = reader.readLine(); + + final JSONArray array = (JSONArray) JSONValue.parse(response); + + if (array.size() == 0) { + this.plugin.getLogger().warning("The updater could not find any files for the project id " + this.id); + this.result = UpdateResult.FAIL_BADID; + return false; + } + + final JSONObject jsonObject = (JSONObject) array.get(array.size() - 1); + this.versionFileName = (String) jsonObject.get(BukkitUpdater.FILE_NAME); + this.versionName = (String) jsonObject.get(BukkitUpdater.TITLE_VALUE); + this.versionLink = (String) jsonObject.get(BukkitUpdater.LINK_VALUE); + this.versionType = (String) jsonObject.get(BukkitUpdater.TYPE_VALUE); + this.versionGameVersion = (String) jsonObject.get(BukkitUpdater.VERSION_VALUE); + + return true; + } catch (final IOException e) { + if (e.getMessage().contains("HTTP response code: 403")) { + this.plugin.getLogger().warning("dev.bukkit.org rejected the API key provided in plugins/Updater/config.yml"); + this.plugin.getLogger().warning("Please double-check your configuration to ensure it is correct."); + this.result = UpdateResult.FAIL_APIKEY; + } else { + this.plugin.getLogger().warning("The updater could not contact dev.bukkit.org for updating."); + this.plugin.getLogger().warning("If you have not recently modified your configuration and this is the first time you are seeing this message, the site may be experiencing temporary downtime."); + this.result = UpdateResult.FAIL_DBO; + } + e.printStackTrace(); + return false; + } + } + + // aadnk - added listeners + private class UpdateRunnable implements Runnable { + @Override + public void run() { + try { + if (BukkitUpdater.this.url != null) { + // Obtain the results of the project's file feed + if (BukkitUpdater.this.read()) { + if (BukkitUpdater.this.versionCheck(BukkitUpdater.this.versionName)) { + performUpdate(); + } + } + } + } catch (Exception e) { + // Any generic error will be handled here + ProtocolLibrary.getErrorReporter().reportDetailed( + BukkitUpdater.this, Report.newBuilder(REPORT_CANNOT_UPDATE_PLUGIN).error(e).callerParam(this)); + + } finally { + // Invoke the listeners on the main thread + for (Runnable listener : listeners) { + plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, listener); + } + } + } + + private void performUpdate() { + if ((BukkitUpdater.this.versionLink != null) && (BukkitUpdater.this.type != UpdateType.NO_DOWNLOAD)) { + final File pluginFolder = plugin.getDataFolder().getParentFile(); + File destinationFolder = new File(pluginFolder, updateFolder); + String name = BukkitUpdater.this.file.getName(); + + // If it's a zip file, it shouldn't be downloaded as the plugin's name + if (BukkitUpdater.this.versionLink.endsWith(".zip")) { + name = versionFileName; + } + BukkitUpdater.this.saveFile( + destinationFolder, + name, + BukkitUpdater.this.versionLink + ); + } else { + BukkitUpdater.this.result = UpdateResult.UPDATE_AVAILABLE; + } + } + } + + @Override + public String getRemoteVersion() { + return getLatestName(); + } +} diff --git a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/updater/SpigotUpdater.java b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/updater/SpigotUpdater.java index 19c24f38..708efdd6 100644 --- a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/updater/SpigotUpdater.java +++ b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/updater/SpigotUpdater.java @@ -1,120 +1,120 @@ -/** - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2015 dmulloy2 - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ -package com.comphenix.protocol.updater; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.logging.Level; - -import org.bukkit.plugin.Plugin; - -import com.comphenix.protocol.ProtocolLibrary; -import com.comphenix.protocol.error.Report; -import com.comphenix.protocol.utility.Closer; -import com.google.common.base.Charsets; - -/** - * Adapted version of the Bukkit updater for use with Spigot resources - * @author dmulloy2 - */ - -public final class SpigotUpdater extends Updater { - private String remoteVersion; - - public SpigotUpdater(Plugin plugin, UpdateType type, boolean announce) { - super(plugin, type, announce); - } - - @Override - public void start(UpdateType type) { - waitForThread(); - - this.type = type; - this.thread = new Thread(new SpigotUpdateRunnable()); - this.thread.start(); - } - - @Override - public String getResult() { - waitForThread(); - return String.format(result.toString(), remoteVersion, plugin.getDescription().getVersion(), RESOURCE_URL); - } - - private class SpigotUpdateRunnable implements Runnable { - - @Override - public void run() { - try { - String version = getSpigotVersion(); - remoteVersion = version; - - if (versionCheck(version)) { - result = UpdateResult.SPIGOT_UPDATE_AVAILABLE; - } else { - result = UpdateResult.NO_UPDATE; - } - } catch (Throwable ex) { - if (ProtocolLibrary.getConfig().isDebug()) { - ProtocolLibrary.getErrorReporter().reportDetailed( - SpigotUpdater.this, Report.newBuilder(REPORT_CANNOT_UPDATE_PLUGIN).error(ex).callerParam(this)); - } else { - plugin.getLogger().log(Level.WARNING, "Failed to check for updates: " + ex); - } - - ProtocolLibrary.disableUpdates(); - } finally { - // Invoke the listeners on the main thread - for (Runnable listener : listeners) { - plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, listener); - } - } - } - } - - private static final String PROTOCOL = "https://"; - private static final String RESOURCE_URL = PROTOCOL + "www.spigotmc.org/resources/protocollib.1997/"; - private static final String API_URL = PROTOCOL + "www.spigotmc.org/api/general.php"; - private static final String ACTION = "POST"; - - private static final int ID = 1997; - private static final byte[] API_KEY = ("key=98BE0FE67F88AB82B4C197FAF1DC3B69206EFDCC4D3B80FC83A00037510B99B4&resource=" + ID).getBytes(Charsets.UTF_8); - - public String getSpigotVersion() throws IOException { - Closer closer = Closer.create(); - - try { - HttpURLConnection con = (HttpURLConnection) new URL(API_URL).openConnection(); - con.setDoOutput(true); - con.setRequestMethod(ACTION); - con.getOutputStream().write(API_KEY); - - InputStreamReader isr = closer.register(new InputStreamReader(con.getInputStream())); - BufferedReader br = closer.register(new BufferedReader(isr)); - return br.readLine(); - } finally { - closer.close(); - } - } - - @Override - public String getRemoteVersion() { - return remoteVersion; - } -} \ No newline at end of file +/** + * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. + * Copyright (C) 2015 dmulloy2 + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ +package com.comphenix.protocol.updater; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.logging.Level; + +import org.bukkit.plugin.Plugin; + +import com.comphenix.protocol.ProtocolLibrary; +import com.comphenix.protocol.error.Report; +import com.comphenix.protocol.utility.Closer; +import com.google.common.base.Charsets; + +/** + * Adapted version of the Bukkit updater for use with Spigot resources + * @author dmulloy2 + */ + +public final class SpigotUpdater extends Updater { + private String remoteVersion; + + public SpigotUpdater(Plugin plugin, UpdateType type, boolean announce) { + super(plugin, type, announce); + } + + @Override + public void start(UpdateType type) { + waitForThread(); + + this.type = type; + this.thread = new Thread(new SpigotUpdateRunnable()); + this.thread.start(); + } + + @Override + public String getResult() { + waitForThread(); + return String.format(result.toString(), remoteVersion, plugin.getDescription().getVersion(), RESOURCE_URL); + } + + private class SpigotUpdateRunnable implements Runnable { + + @Override + public void run() { + try { + String version = getSpigotVersion(); + remoteVersion = version; + + if (versionCheck(version)) { + result = UpdateResult.SPIGOT_UPDATE_AVAILABLE; + } else { + result = UpdateResult.NO_UPDATE; + } + } catch (Throwable ex) { + if (ProtocolLibrary.getConfig().isDebug()) { + ProtocolLibrary.getErrorReporter().reportDetailed( + SpigotUpdater.this, Report.newBuilder(REPORT_CANNOT_UPDATE_PLUGIN).error(ex).callerParam(this)); + } else { + plugin.getLogger().log(Level.WARNING, "Failed to check for updates: " + ex); + } + + ProtocolLibrary.disableUpdates(); + } finally { + // Invoke the listeners on the main thread + for (Runnable listener : listeners) { + plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, listener); + } + } + } + } + + private static final String PROTOCOL = "https://"; + private static final String RESOURCE_URL = PROTOCOL + "www.spigotmc.org/resources/protocollib.1997/"; + private static final String API_URL = PROTOCOL + "www.spigotmc.org/api/general.php"; + private static final String ACTION = "POST"; + + private static final int ID = 1997; + private static final byte[] API_KEY = ("key=98BE0FE67F88AB82B4C197FAF1DC3B69206EFDCC4D3B80FC83A00037510B99B4&resource=" + ID).getBytes(Charsets.UTF_8); + + public String getSpigotVersion() throws IOException { + Closer closer = Closer.create(); + + try { + HttpURLConnection con = (HttpURLConnection) new URL(API_URL).openConnection(); + con.setDoOutput(true); + con.setRequestMethod(ACTION); + con.getOutputStream().write(API_KEY); + + InputStreamReader isr = closer.register(new InputStreamReader(con.getInputStream())); + BufferedReader br = closer.register(new BufferedReader(isr)); + return br.readLine(); + } finally { + closer.close(); + } + } + + @Override + public String getRemoteVersion() { + return remoteVersion; + } +} diff --git a/modules/ProtocolLib/src/test/java/com/comphenix/integration/protocol/SimpleMinecraftClient.java b/modules/ProtocolLib/src/test/java/com/comphenix/integration/protocol/SimpleMinecraftClient.java index 6a6b2acb..c187fcdc 100644 --- a/modules/ProtocolLib/src/test/java/com/comphenix/integration/protocol/SimpleMinecraftClient.java +++ b/modules/ProtocolLib/src/test/java/com/comphenix/integration/protocol/SimpleMinecraftClient.java @@ -217,4 +217,4 @@ public class SimpleMinecraftClient { } } } -} \ No newline at end of file +} diff --git a/modules/ProtocolLib/src/test/java/com/comphenix/protocol/PacketTypeTest.java b/modules/ProtocolLib/src/test/java/com/comphenix/protocol/PacketTypeTest.java index ed780d6a..d70a4c0d 100644 --- a/modules/ProtocolLib/src/test/java/com/comphenix/protocol/PacketTypeTest.java +++ b/modules/ProtocolLib/src/test/java/com/comphenix/protocol/PacketTypeTest.java @@ -53,4 +53,4 @@ public class PacketTypeTest { assertFalse("There are packets that aren\'t accounted for!", missing); } -} \ No newline at end of file +} diff --git a/modules/ProtocolLib/src/test/java/com/comphenix/protocol/updater/UpdaterTest.java b/modules/ProtocolLib/src/test/java/com/comphenix/protocol/updater/UpdaterTest.java index 8f15a1e6..52efb9f7 100644 --- a/modules/ProtocolLib/src/test/java/com/comphenix/protocol/updater/UpdaterTest.java +++ b/modules/ProtocolLib/src/test/java/com/comphenix/protocol/updater/UpdaterTest.java @@ -65,4 +65,4 @@ public class UpdaterTest { System.out.println("Determined remote Bukkit Dev version: " + remote); System.out.println("Update available: " + updater.versionCheck(remote)); } -} \ No newline at end of file +} diff --git a/modules/ProtocolLib/src/test/java/com/comphenix/protocol/utility/MinecraftReflectionTest.java b/modules/ProtocolLib/src/test/java/com/comphenix/protocol/utility/MinecraftReflectionTest.java index 39e19837..c739c018 100644 --- a/modules/ProtocolLib/src/test/java/com/comphenix/protocol/utility/MinecraftReflectionTest.java +++ b/modules/ProtocolLib/src/test/java/com/comphenix/protocol/utility/MinecraftReflectionTest.java @@ -143,4 +143,4 @@ public class MinecraftReflectionTest { public void testGameProfile() { assertEquals(GameProfile.class, MinecraftReflection.getGameProfileClass()); } -} \ No newline at end of file +} diff --git a/modules/ProtocolLib/src/test/java/com/comphenix/protocol/utility/StreamSerializerTest.java b/modules/ProtocolLib/src/test/java/com/comphenix/protocol/utility/StreamSerializerTest.java index 0addfde6..a746b48e 100644 --- a/modules/ProtocolLib/src/test/java/com/comphenix/protocol/utility/StreamSerializerTest.java +++ b/modules/ProtocolLib/src/test/java/com/comphenix/protocol/utility/StreamSerializerTest.java @@ -97,4 +97,4 @@ public class StreamSerializerTest { assertEquals(initial, deserialized); } -} \ No newline at end of file +} diff --git a/modules/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/MultiBlockChangeTest.java b/modules/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/MultiBlockChangeTest.java index 95720fbc..5cd40c9a 100644 --- a/modules/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/MultiBlockChangeTest.java +++ b/modules/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/MultiBlockChangeTest.java @@ -1,70 +1,70 @@ -/** - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2015 dmulloy2 - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ -package com.comphenix.protocol.wrappers; - -import static org.junit.Assert.assertEquals; - -import org.bukkit.Location; -import org.bukkit.Material; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PowerMockIgnore; - -import com.comphenix.protocol.BukkitInitialization; -import com.comphenix.protocol.reflect.EquivalentConverter; -import com.comphenix.protocol.utility.MinecraftReflection; - -/** - * @author dmulloy2 - */ -@RunWith(org.powermock.modules.junit4.PowerMockRunner.class) -@PowerMockIgnore({ "org.apache.log4j.*", "org.apache.logging.*", "org.bukkit.craftbukkit.libs.jline.*" }) -public class MultiBlockChangeTest { - - @BeforeClass - public static void initializeBukkit() throws IllegalAccessException { - BukkitInitialization.initializeItemMeta(); - } - - @Test - public void test() { - int x = 42; - int y = 64; - int z = 70; - - Location loc = new Location(null, x, y, z); - ChunkCoordIntPair chunk = new ChunkCoordIntPair(x >> 4, z >> 4); - WrappedBlockData blockData = WrappedBlockData.createData(Material.STONE); - MultiBlockChangeInfo info = new MultiBlockChangeInfo(loc, blockData); - - // Make sure the location is correct - assertEquals(loc, info.getLocation(null)); - - MultiBlockChangeInfo[] array = { info, info }; - - EquivalentConverter converter = MultiBlockChangeInfo.getArrayConverter(chunk); - Object generic = converter.getGeneric(MinecraftReflection.getMultiBlockChangeInfoArrayClass(), array); - MultiBlockChangeInfo[] back = converter.getSpecific(generic); - - // Make sure our conversions are correct - assertEquals(info.getX(), back[0].getX()); - assertEquals(info.getY(), back[0].getY()); - assertEquals(info.getZ(), back[0].getZ()); - assertEquals(info.getData(), back[0].getData()); - } -} \ No newline at end of file +/** + * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. + * Copyright (C) 2015 dmulloy2 + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ +package com.comphenix.protocol.wrappers; + +import static org.junit.Assert.assertEquals; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PowerMockIgnore; + +import com.comphenix.protocol.BukkitInitialization; +import com.comphenix.protocol.reflect.EquivalentConverter; +import com.comphenix.protocol.utility.MinecraftReflection; + +/** + * @author dmulloy2 + */ +@RunWith(org.powermock.modules.junit4.PowerMockRunner.class) +@PowerMockIgnore({ "org.apache.log4j.*", "org.apache.logging.*", "org.bukkit.craftbukkit.libs.jline.*" }) +public class MultiBlockChangeTest { + + @BeforeClass + public static void initializeBukkit() throws IllegalAccessException { + BukkitInitialization.initializeItemMeta(); + } + + @Test + public void test() { + int x = 42; + int y = 64; + int z = 70; + + Location loc = new Location(null, x, y, z); + ChunkCoordIntPair chunk = new ChunkCoordIntPair(x >> 4, z >> 4); + WrappedBlockData blockData = WrappedBlockData.createData(Material.STONE); + MultiBlockChangeInfo info = new MultiBlockChangeInfo(loc, blockData); + + // Make sure the location is correct + assertEquals(loc, info.getLocation(null)); + + MultiBlockChangeInfo[] array = { info, info }; + + EquivalentConverter converter = MultiBlockChangeInfo.getArrayConverter(chunk); + Object generic = converter.getGeneric(MinecraftReflection.getMultiBlockChangeInfoArrayClass(), array); + MultiBlockChangeInfo[] back = converter.getSpecific(generic); + + // Make sure our conversions are correct + assertEquals(info.getX(), back[0].getX()); + assertEquals(info.getY(), back[0].getY()); + assertEquals(info.getZ(), back[0].getZ()); + assertEquals(info.getData(), back[0].getData()); + } +} diff --git a/modules/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/PlayerInfoDataTest.java b/modules/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/PlayerInfoDataTest.java index d86fedb2..58c80658 100644 --- a/modules/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/PlayerInfoDataTest.java +++ b/modules/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/PlayerInfoDataTest.java @@ -1,51 +1,51 @@ -/** - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2015 dmulloy2 - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ -package com.comphenix.protocol.wrappers; - -import static org.junit.Assert.assertEquals; - -import java.util.UUID; - -import org.junit.BeforeClass; -import org.junit.Test; - -import com.comphenix.protocol.BukkitInitialization; -import com.comphenix.protocol.utility.MinecraftReflection; -import com.comphenix.protocol.wrappers.EnumWrappers.NativeGameMode; - -/** - * @author dmulloy2 - */ -public class PlayerInfoDataTest { - - @BeforeClass - public static void initializeBukkit() { - BukkitInitialization.initializePackage(); - } - - @Test - public void test() { - WrappedGameProfile profile = new WrappedGameProfile(UUID.randomUUID(), "Name"); - WrappedChatComponent displayName = WrappedChatComponent.fromText("Name's Name"); - - PlayerInfoData data = new PlayerInfoData(profile, 42, NativeGameMode.CREATIVE, displayName); - Object generic = PlayerInfoData.getConverter().getGeneric(MinecraftReflection.getPlayerInfoDataClass(), data); - PlayerInfoData back = PlayerInfoData.getConverter().getSpecific(generic); - - assertEquals(data, back); - } -} \ No newline at end of file +/** + * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. + * Copyright (C) 2015 dmulloy2 + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ +package com.comphenix.protocol.wrappers; + +import static org.junit.Assert.assertEquals; + +import java.util.UUID; + +import org.junit.BeforeClass; +import org.junit.Test; + +import com.comphenix.protocol.BukkitInitialization; +import com.comphenix.protocol.utility.MinecraftReflection; +import com.comphenix.protocol.wrappers.EnumWrappers.NativeGameMode; + +/** + * @author dmulloy2 + */ +public class PlayerInfoDataTest { + + @BeforeClass + public static void initializeBukkit() { + BukkitInitialization.initializePackage(); + } + + @Test + public void test() { + WrappedGameProfile profile = new WrappedGameProfile(UUID.randomUUID(), "Name"); + WrappedChatComponent displayName = WrappedChatComponent.fromText("Name's Name"); + + PlayerInfoData data = new PlayerInfoData(profile, 42, NativeGameMode.CREATIVE, displayName); + Object generic = PlayerInfoData.getConverter().getGeneric(MinecraftReflection.getPlayerInfoDataClass(), data); + PlayerInfoData back = PlayerInfoData.getConverter().getSpecific(generic); + + assertEquals(data, back); + } +} diff --git a/modules/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedBlockDataTest.java b/modules/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedBlockDataTest.java index df54aaee..a6384360 100644 --- a/modules/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedBlockDataTest.java +++ b/modules/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedBlockDataTest.java @@ -1,56 +1,56 @@ -/** - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2015 dmulloy2 - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ -package com.comphenix.protocol.wrappers; - -import static org.junit.Assert.assertEquals; - -import org.bukkit.DyeColor; -import org.bukkit.Material; -import org.junit.BeforeClass; -import org.junit.Test; - -import com.comphenix.protocol.BukkitInitialization; -import com.comphenix.protocol.utility.MinecraftReflection; - -/** - * @author dmulloy2 - */ - -public class WrappedBlockDataTest { - - @BeforeClass - public static void initializeBukkit() throws IllegalAccessException { - BukkitInitialization.initializeItemMeta(); - } - - @Test - public void test() { - Material type = Material.WOOL; - int data = DyeColor.BLUE.getWoolData(); - - WrappedBlockData wrapper = WrappedBlockData.createData(type, data); - - assertEquals(wrapper.getType(), type); - assertEquals(wrapper.getData(), data); - - Object generic = BukkitConverters.getWrappedBlockDataConverter().getGeneric(MinecraftReflection.getIBlockDataClass(), wrapper); - WrappedBlockData back = BukkitConverters.getWrappedBlockDataConverter().getSpecific(generic); - - assertEquals(wrapper.getType(), back.getType()); - assertEquals(wrapper.getData(), back.getData()); - } -} \ No newline at end of file +/** + * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. + * Copyright (C) 2015 dmulloy2 + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ +package com.comphenix.protocol.wrappers; + +import static org.junit.Assert.assertEquals; + +import org.bukkit.DyeColor; +import org.bukkit.Material; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.comphenix.protocol.BukkitInitialization; +import com.comphenix.protocol.utility.MinecraftReflection; + +/** + * @author dmulloy2 + */ + +public class WrappedBlockDataTest { + + @BeforeClass + public static void initializeBukkit() throws IllegalAccessException { + BukkitInitialization.initializeItemMeta(); + } + + @Test + public void test() { + Material type = Material.WOOL; + int data = DyeColor.BLUE.getWoolData(); + + WrappedBlockData wrapper = WrappedBlockData.createData(type, data); + + assertEquals(wrapper.getType(), type); + assertEquals(wrapper.getData(), data); + + Object generic = BukkitConverters.getWrappedBlockDataConverter().getGeneric(MinecraftReflection.getIBlockDataClass(), wrapper); + WrappedBlockData back = BukkitConverters.getWrappedBlockDataConverter().getSpecific(generic); + + assertEquals(wrapper.getType(), back.getType()); + assertEquals(wrapper.getData(), back.getData()); + } +} diff --git a/modules/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedDataWatcherTest.java b/modules/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedDataWatcherTest.java index cf9ac97d..0ba729d1 100644 --- a/modules/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedDataWatcherTest.java +++ b/modules/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedDataWatcherTest.java @@ -1,102 +1,102 @@ -/** - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2016 dmulloy2 - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ -package com.comphenix.protocol.wrappers; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import java.util.UUID; - -import net.minecraft.server.v1_9_R2.EntityLightning; -import net.minecraft.server.v1_9_R2.ItemStack; - -import org.bukkit.craftbukkit.v1_9_R2.entity.CraftLightningStrike; -import org.bukkit.entity.Entity; -import org.junit.BeforeClass; -import org.junit.Test; - -import com.comphenix.protocol.BukkitInitialization; -import com.comphenix.protocol.wrappers.WrappedDataWatcher.Registry; -import com.comphenix.protocol.wrappers.WrappedDataWatcher.Serializer; -import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject; - -/** - * @author dmulloy2 - */ - -public class WrappedDataWatcherTest { - - @BeforeClass - public static void prepare() { - BukkitInitialization.initializePackage(); - } - - @Test - public void testBytes() { - // Create a fake lightning strike and get its watcher - EntityLightning lightning = new EntityLightning(null, 0, 0, 0, true); - Entity entity = new CraftLightningStrike(null, lightning); - WrappedDataWatcher wrapper = WrappedDataWatcher.getEntityWatcher(entity); - - WrappedWatchableObject watchable = wrapper.getWatchableObject(0); - WrappedDataWatcherObject object = watchable.getWatcherObject(); - - // Make sure the serializers work - assertEquals(object.getSerializer(), Registry.get(Byte.class)); - - // Make sure we can set existing objects - wrapper.setObject(0, (byte) 21); - assertTrue(wrapper.getByte(0) == 21); - } - - @Test - public void testStrings() { - WrappedDataWatcher wrapper = new WrappedDataWatcher(); - - // Make sure we can create watcher objects - Serializer serializer = Registry.get(String.class); - WrappedDataWatcherObject object = new WrappedDataWatcherObject(3, serializer); - wrapper.setObject(object, "Test"); - - assertEquals(wrapper.getString(3), "Test"); - } - - @Test - public void testFloats() { - WrappedDataWatcher wrapper = new WrappedDataWatcher(); - - // Make sure we can add new entries - Serializer serializer = Registry.get(Float.class); - WrappedDataWatcherObject object = new WrappedDataWatcherObject(10, serializer); - wrapper.setObject(object, 21.0F); - - assertTrue(wrapper.hasIndex(10)); - } - - @Test - public void testSerializers() { - Serializer blockPos = Registry.get(net.minecraft.server.v1_9_R2.BlockPosition.class, false); - Serializer optionalBlockPos = Registry.get(net.minecraft.server.v1_9_R2.BlockPosition.class, true); - assertNotSame(blockPos, optionalBlockPos); - - assertNull(Registry.get(ItemStack.class, false)); - assertNotNull(Registry.get(UUID.class, true)); - } -} \ No newline at end of file +/** + * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. + * Copyright (C) 2016 dmulloy2 + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ +package com.comphenix.protocol.wrappers; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.UUID; + +import net.minecraft.server.v1_9_R2.EntityLightning; +import net.minecraft.server.v1_9_R2.ItemStack; + +import org.bukkit.craftbukkit.v1_9_R2.entity.CraftLightningStrike; +import org.bukkit.entity.Entity; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.comphenix.protocol.BukkitInitialization; +import com.comphenix.protocol.wrappers.WrappedDataWatcher.Registry; +import com.comphenix.protocol.wrappers.WrappedDataWatcher.Serializer; +import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject; + +/** + * @author dmulloy2 + */ + +public class WrappedDataWatcherTest { + + @BeforeClass + public static void prepare() { + BukkitInitialization.initializePackage(); + } + + @Test + public void testBytes() { + // Create a fake lightning strike and get its watcher + EntityLightning lightning = new EntityLightning(null, 0, 0, 0, true); + Entity entity = new CraftLightningStrike(null, lightning); + WrappedDataWatcher wrapper = WrappedDataWatcher.getEntityWatcher(entity); + + WrappedWatchableObject watchable = wrapper.getWatchableObject(0); + WrappedDataWatcherObject object = watchable.getWatcherObject(); + + // Make sure the serializers work + assertEquals(object.getSerializer(), Registry.get(Byte.class)); + + // Make sure we can set existing objects + wrapper.setObject(0, (byte) 21); + assertTrue(wrapper.getByte(0) == 21); + } + + @Test + public void testStrings() { + WrappedDataWatcher wrapper = new WrappedDataWatcher(); + + // Make sure we can create watcher objects + Serializer serializer = Registry.get(String.class); + WrappedDataWatcherObject object = new WrappedDataWatcherObject(3, serializer); + wrapper.setObject(object, "Test"); + + assertEquals(wrapper.getString(3), "Test"); + } + + @Test + public void testFloats() { + WrappedDataWatcher wrapper = new WrappedDataWatcher(); + + // Make sure we can add new entries + Serializer serializer = Registry.get(Float.class); + WrappedDataWatcherObject object = new WrappedDataWatcherObject(10, serializer); + wrapper.setObject(object, 21.0F); + + assertTrue(wrapper.hasIndex(10)); + } + + @Test + public void testSerializers() { + Serializer blockPos = Registry.get(net.minecraft.server.v1_9_R2.BlockPosition.class, false); + Serializer optionalBlockPos = Registry.get(net.minecraft.server.v1_9_R2.BlockPosition.class, true); + assertNotSame(blockPos, optionalBlockPos); + + assertNull(Registry.get(ItemStack.class, false)); + assertNotNull(Registry.get(UUID.class, true)); + } +} diff --git a/modules/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedGameProfileTest.java b/modules/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedGameProfileTest.java index 76ec9ea0..766f0a0e 100644 --- a/modules/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedGameProfileTest.java +++ b/modules/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedGameProfileTest.java @@ -81,4 +81,4 @@ public class WrappedGameProfileTest { assertEquals(property.getValue(), value); assertEquals(property.getSignature(), signature); } -} \ No newline at end of file +} diff --git a/modules/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedServerPingTest.java b/modules/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedServerPingTest.java index 3301c199..b2c02657 100644 --- a/modules/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedServerPingTest.java +++ b/modules/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedServerPingTest.java @@ -52,4 +52,4 @@ public class WrappedServerPingTest { } } } -} \ No newline at end of file +} diff --git a/modules/TinyProtocol/src/main/java/com/comphenix/tinyprotocol/ExamplePlugin.java b/modules/TinyProtocol/src/main/java/com/comphenix/tinyprotocol/ExamplePlugin.java index a8eb7f7a..bd6bc0d1 100644 --- a/modules/TinyProtocol/src/main/java/com/comphenix/tinyprotocol/ExamplePlugin.java +++ b/modules/TinyProtocol/src/main/java/com/comphenix/tinyprotocol/ExamplePlugin.java @@ -114,4 +114,4 @@ public class ExamplePlugin extends JavaPlugin { throw new RuntimeException("Cannot send packet.", e); } } -} \ No newline at end of file +} diff --git a/modules/TinyProtocol/src/main/java/com/comphenix/tinyprotocol/Reflection.java b/modules/TinyProtocol/src/main/java/com/comphenix/tinyprotocol/Reflection.java index d08980fe..7cadf5af 100644 --- a/modules/TinyProtocol/src/main/java/com/comphenix/tinyprotocol/Reflection.java +++ b/modules/TinyProtocol/src/main/java/com/comphenix/tinyprotocol/Reflection.java @@ -400,4 +400,4 @@ public final class Reflection { matcher.appendTail(output); return output.toString(); } -} \ No newline at end of file +} diff --git a/modules/TinyProtocol/src/main/java/com/comphenix/tinyprotocol/TinyProtocol.java b/modules/TinyProtocol/src/main/java/com/comphenix/tinyprotocol/TinyProtocol.java index 3ef458f9..0f17a55b 100644 --- a/modules/TinyProtocol/src/main/java/com/comphenix/tinyprotocol/TinyProtocol.java +++ b/modules/TinyProtocol/src/main/java/com/comphenix/tinyprotocol/TinyProtocol.java @@ -521,4 +521,4 @@ public abstract class TinyProtocol { } } } -} \ No newline at end of file +}