diff --git a/TabAPI/pom.xml b/TabAPI/pom.xml index 780eea2..6b11e29 100644 --- a/TabAPI/pom.xml +++ b/TabAPI/pom.xml @@ -1,101 +1,115 @@ - 4.0.0 - org.mcsg.double0negative - tabapi - B 0.1.15 - TabAPI - - - bukkit-repo - http://repo.bukkit.org/content/groups/public - - - comphenix-repo - http://repo.comphenix.net/content/groups/public - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 2.0.2 - - 1.6 - 1.6 - - - - org.apache.maven.plugins - maven-jar-plugin - 2.1 - - - false - - ${project.name} - - - - - - . - true - ${basedir}/src/main/resources - - *.yml - - - - . - ${basedir} - - LICENSE - - - - - - - org.bukkit - bukkit - 1.5.1-R0.2 - - - com.comphenix.protocol - ProtocolLib - 2.4.1 - - + 4.0.0 + org.mcsg.double0negative + tabapi + B 0.1.17 + TabAPI + + + bukkit-repo + http://repo.bukkit.org/content/groups/public + + + + spigot-repo + https://hub.spigotmc.org/nexus/content/groups/public + + + + shadowvolt-repo + http://ci.shadowvolt.com/plugin/repository/everything/ + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.0.2 + + 1.6 + 1.6 + + + + org.apache.maven.plugins + maven-jar-plugin + 2.1 + + + false + + ${project.name} + + + + + + . + true + ${basedir}/src/main/resources + + *.yml + + + + . + ${basedir} + + LICENSE + + + + + + + org.spigotmc + spigot-api + 1.8-R0.1-SNAPSHOT + + + com.comphenix.protocol + ProtocolLib + 3.6.3-SNAPSHOT + + + org.bukkit + bukkit + 1.8-R0.1-SNAPSHOT + jar + + diff --git a/TabAPI/src/main/java/org/mcsg/double0negative/tabapi/Metrics.java b/TabAPI/src/main/java/org/mcsg/double0negative/tabapi/Metrics.java index 0233db3..3b33554 100644 --- a/TabAPI/src/main/java/org/mcsg/double0negative/tabapi/Metrics.java +++ b/TabAPI/src/main/java/org/mcsg/double0negative/tabapi/Metrics.java @@ -1,31 +1,31 @@ package org.mcsg.double0negative.tabapi; /* -* Copyright 2011-2013 Tyler Blair. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and contributors and should not be interpreted as representing official policies, -* either expressed or implied, of anybody else. -*/ + * Copyright 2011-2013 Tyler Blair. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and contributors and should not be interpreted as representing official policies, + * either expressed or implied, of anybody else. + */ import org.bukkit.Bukkit; import org.bukkit.configuration.file.YamlConfiguration; @@ -33,7 +33,6 @@ import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.scheduler.BukkitTask; - import java.io.BufferedReader; import java.io.File; import java.io.IOException; @@ -53,229 +52,244 @@ import java.util.logging.Level; /** -*

The metrics class obtains data about a plugin and submits statistics about it to the metrics backend.

-* Public methods provided by this class:

-* -* Graph createGraph(String name);
-* void addCustomData(BukkitMetrics.Plotter plotter);
-* void start();
-*
-*/ + *

+ * The metrics class obtains data about a plugin and submits statistics about it to the metrics backend.

+ *

+ * Public methods provided by this class:

+ * + * Graph createGraph(String name);
+ * void addCustomData(BukkitMetrics.Plotter plotter);
+ * void start();
+ *
+ */ public class Metrics { /** -* The current revision number -*/ + * The current revision number + */ private final static int REVISION = 6; /** -* The base url of the metrics domain -*/ + * The base url of the metrics domain + */ private static final String BASE_URL = "http://mcstats.org"; /** -* The url used to report a server's status -*/ + * The url used to report a server's status + */ private static final String REPORT_URL = "/report/%s"; /** -* The separator to use for custom data. This MUST NOT change unless you are hosting your own version of metrics and -* want to change it. -*/ + * The separator to use for custom data. This MUST NOT change unless you are hosting your own version of metrics and + * want to change it. + */ private static final String CUSTOM_DATA_SEPARATOR = "~~"; /** -* Interval of time to ping (in minutes) -*/ + * Interval of time to ping (in minutes) + */ private static final int PING_INTERVAL = 10; /** -* The plugin this metrics submits for -*/ + * The plugin this metrics submits for + */ private final Plugin plugin; /** -* All of the custom graphs to submit to metrics -*/ + * All of the custom graphs to submit to metrics + */ private final Set graphs = Collections.synchronizedSet(new HashSet()); /** -* The default graph, used for addCustomData when you don't want a specific graph -*/ + * The default graph, used for addCustomData when you don't want a specific graph + */ private final Graph defaultGraph = new Graph("Default"); /** -* The plugin configuration file -*/ + * The plugin configuration file + */ private final YamlConfiguration configuration; /** -* The plugin configuration file -*/ + * The plugin configuration file + */ private final File configurationFile; /** -* Unique server id -*/ + * Unique server id + */ private final String guid; /** -* Debug mode -*/ + * Debug mode + */ private final boolean debug; /** -* Lock for synchronization -*/ + * Lock for synchronization + */ private final Object optOutLock = new Object(); /** -* The scheduled task -*/ + * The scheduled task + */ private volatile BukkitTask task = null; - public Metrics(final Plugin plugin) throws IOException { - if (plugin == null) { + public Metrics(final Plugin plugin) throws IOException + { + if (plugin == null) + { throw new IllegalArgumentException("Plugin cannot be null"); } - this.plugin = plugin; - // load the config configurationFile = getConfigFile(); configuration = YamlConfiguration.loadConfiguration(configurationFile); - // add some defaults configuration.addDefault("opt-out", false); configuration.addDefault("guid", UUID.randomUUID().toString()); configuration.addDefault("debug", false); - // Do we need to create the file? - if (configuration.get("guid", null) == null) { + if (configuration.get("guid", null) == null) + { configuration.options().header("http://mcstats.org").copyDefaults(true); configuration.save(configurationFile); } - // Load the guid then guid = configuration.getString("guid"); debug = configuration.getBoolean("debug", false); } /** -* Construct and create a Graph that can be used to separate specific plotters to their own graphs on the metrics -* website. Plotters can be added to the graph object returned. -* + * Construct and create a Graph that can be used to separate specific plotters to their own graphs on the metrics + * website. Plotters can be added to the graph object returned. + * * @param name The name of the graph -* @return Graph object created. Will never return NULL under normal circumstances unless bad parameters are given -*/ - public Graph createGraph(final String name) { - if (name == null) { + * @return Graph object created. Will never return NULL under normal circumstances unless bad parameters are given + */ + public Graph createGraph(final String name) + { + if (name == null) + { throw new IllegalArgumentException("Graph name cannot be null"); } - // Construct the graph object final Graph graph = new Graph(name); - // Now we can add our graph graphs.add(graph); - // and return back return graph; } /** -* Add a Graph object to BukkitMetrics that represents data for the plugin that should be sent to the backend -* + * Add a Graph object to BukkitMetrics that represents data for the plugin that should be sent to the backend + * * @param graph The name of the graph -*/ - public void addGraph(final Graph graph) { - if (graph == null) { + */ + public void addGraph(final Graph graph) + { + if (graph == null) + { throw new IllegalArgumentException("Graph cannot be null"); } - graphs.add(graph); } /** -* Adds a custom data plotter to the default graph -* + * Adds a custom data plotter to the default graph + * * @param plotter The plotter to use to plot custom data -*/ - public void addCustomData(final Plotter plotter) { - if (plotter == null) { + */ + public void addCustomData(final Plotter plotter) + { + if (plotter == null) + { throw new IllegalArgumentException("Plotter cannot be null"); } - // Add the plotter to the graph o/ defaultGraph.addPlotter(plotter); - // Ensure the default graph is included in the submitted graphs graphs.add(defaultGraph); } /** -* Start measuring statistics. This will immediately create an async repeating task as the plugin and send the -* initial data to the metrics backend, and then after that it will post in increments of PING_INTERVAL * 1200 -* ticks. -* + * Start measuring statistics. This will immediately create an async repeating task as the plugin and send the + * initial data to the metrics backend, and then after that it will post in increments of PING_INTERVAL * 1200 + * ticks. + * * @return True if statistics measuring is running, otherwise false. -*/ - public boolean start() { - synchronized (optOutLock) { + */ + public boolean start() + { + synchronized (optOutLock) + { // Did we opt out? - if (isOptOut()) { + if (isOptOut()) + { return false; } - // Is metrics already running? - if (task != null) { + if (task != null) + { return true; } - // Begin hitting the server with glorious data task = plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, new Runnable() { - private boolean firstPost = true; - public void run() { - try { + public void run() + { + try + { // This has to be synchronized or it can collide with the disable method. - synchronized (optOutLock) { + synchronized (optOutLock) + { // Disable Task, if it is running and the server owner decided to opt-out - if (isOptOut() && task != null) { + if (isOptOut() && task != null) + { task.cancel(); task = null; // Tell all plotters to stop gathering information. - for (Graph graph : graphs) { + for (Graph graph : graphs) + { graph.onOptOut(); } } } - // We use the inverse of firstPost because if it is the first time we are posting, // it is not a interval ping, so it evaluates to FALSE // Each time thereafter it will evaluate to TRUE, i.e PING! postPlugin(!firstPost); - // After the first post we set firstPost to false // Each post thereafter will be a ping firstPost = false; - } catch (IOException e) { - if (debug) { + } + catch (IOException e) + { + if (debug) + { Bukkit.getLogger().log(Level.INFO, "[Metrics] " + e.getMessage()); } } } }, 0, PING_INTERVAL * 1200); - return true; } } /** -* Has the server owner denied plugin metrics? -* + * Has the server owner denied plugin metrics? + * * @return true if metrics should be opted out of it -*/ - public boolean isOptOut() { - synchronized (optOutLock) { - try { + */ + public boolean isOptOut() + { + synchronized (optOutLock) + { + try + { // Reload the metrics file configuration.load(getConfigFile()); - } catch (IOException ex) { - if (debug) { + } + catch (IOException ex) + { + if (debug) + { Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage()); } return true; - } catch (InvalidConfigurationException ex) { - if (debug) { + } + catch (InvalidConfigurationException ex) + { + if (debug) + { Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage()); } return true; @@ -285,42 +299,48 @@ public boolean isOptOut() { } /** -* Enables metrics for the server by setting "opt-out" to false in the config file and starting the metrics task. -* + * Enables metrics for the server by setting "opt-out" to false in the config file and starting the metrics task. + * * @throws java.io.IOException -*/ - public void enable() throws IOException { + */ + public void enable() throws IOException + { // This has to be synchronized or it can collide with the check in the task. - synchronized (optOutLock) { + synchronized (optOutLock) + { // Check if the server owner has already set opt-out, if not, set it. - if (isOptOut()) { + if (isOptOut()) + { configuration.set("opt-out", false); configuration.save(configurationFile); } - // Enable Task, if it is not running - if (task == null) { + if (task == null) + { start(); } } } /** -* Disables metrics for the server by setting "opt-out" to true in the config file and canceling the metrics task. -* + * Disables metrics for the server by setting "opt-out" to true in the config file and canceling the metrics task. + * * @throws java.io.IOException -*/ - public void disable() throws IOException { + */ + public void disable() throws IOException + { // This has to be synchronized or it can collide with the check in the task. - synchronized (optOutLock) { + synchronized (optOutLock) + { // Check if the server owner has already set opt-out, if not, set it. - if (!isOptOut()) { + if (!isOptOut()) + { configuration.set("opt-out", true); configuration.save(configurationFile); } - // Disable Task, if it is running - if (task != null) { + if (task != null) + { task.cancel(); task = null; } @@ -328,135 +348,129 @@ public void disable() throws IOException { } /** -* Gets the File object of the config file that should be used to store data such as the GUID and opt-out status -* + * Gets the File object of the config file that should be used to store data such as the GUID and opt-out status + * * @return the File object for the config file -*/ - public File getConfigFile() { + */ + public File getConfigFile() + { // I believe the easiest way to get the base folder (e.g craftbukkit set via -P) for plugins to use // is to abuse the plugin object we already have // plugin.getDataFolder() => base/plugins/PluginA/ // pluginsFolder => base/plugins/ // The base is not necessarily relative to the startup directory. File pluginsFolder = plugin.getDataFolder().getParentFile(); - // return => base/plugins/PluginMetrics/config.yml return new File(new File(pluginsFolder, "PluginMetrics"), "config.yml"); } /** -* Generic method that posts a plugin to the metrics website -*/ - private void postPlugin(final boolean isPing) throws IOException { + * Generic method that posts a plugin to the metrics website + */ + private void postPlugin(final boolean isPing) throws IOException + { // Server software specific section PluginDescriptionFile description = plugin.getDescription(); String pluginName = description.getName(); boolean onlineMode = Bukkit.getServer().getOnlineMode(); // TRUE if online mode is enabled String pluginVersion = description.getVersion(); String serverVersion = Bukkit.getVersion(); - int playersOnline = Bukkit.getServer().getOnlinePlayers().length; - + int playersOnline = Bukkit.getServer().getOnlinePlayers().size(); // END server software specific section -- all code below does not use any code outside of this class / Java - // Construct the post data final StringBuilder data = new StringBuilder(); - // The plugin's description file containg all of the plugin data such as name, version, author, etc data.append(encode("guid")).append('=').append(encode(guid)); encodeDataPair(data, "version", pluginVersion); encodeDataPair(data, "server", serverVersion); encodeDataPair(data, "players", Integer.toString(playersOnline)); encodeDataPair(data, "revision", String.valueOf(REVISION)); - // New data as of R6 String osname = System.getProperty("os.name"); String osarch = System.getProperty("os.arch"); String osversion = System.getProperty("os.version"); String java_version = System.getProperty("java.version"); int coreCount = Runtime.getRuntime().availableProcessors(); - // normalize os arch .. amd64 -> x86_64 - if (osarch.equals("amd64")) { + if (osarch.equals("amd64")) + { osarch = "x86_64"; } - encodeDataPair(data, "osname", osname); encodeDataPair(data, "osarch", osarch); encodeDataPair(data, "osversion", osversion); encodeDataPair(data, "cores", Integer.toString(coreCount)); encodeDataPair(data, "online-mode", Boolean.toString(onlineMode)); encodeDataPair(data, "java_version", java_version); - // If we're pinging, append it - if (isPing) { + if (isPing) + { encodeDataPair(data, "ping", "true"); } - // Acquire a lock on the graphs, which lets us make the assumption we also lock everything // inside of the graph (e.g plotters) - synchronized (graphs) { + synchronized (graphs) + { final Iterator iter = graphs.iterator(); - - while (iter.hasNext()) { + while (iter.hasNext()) + { final Graph graph = iter.next(); - - for (Plotter plotter : graph.getPlotters()) { + for (Plotter plotter : graph.getPlotters()) + { // The key name to send to the metrics server // The format is C-GRAPHNAME-PLOTTERNAME where separator - is defined at the top // Legacy (R4) submitters use the format Custom%s, or CustomPLOTTERNAME final String key = String.format("C%s%s%s%s", CUSTOM_DATA_SEPARATOR, graph.getName(), CUSTOM_DATA_SEPARATOR, plotter.getColumnName()); - // The value to send, which for the foreseeable future is just the string // value of plotter.getValue() final String value = Integer.toString(plotter.getValue()); - // Add it to the http post data :) encodeDataPair(data, key, value); } } } - // Create the url URL url = new URL(BASE_URL + String.format(REPORT_URL, encode(pluginName))); - // Connect to the website URLConnection connection; - // Mineshafter creates a socks proxy, so we can safely bypass it // It does not reroute POST requests so we need to go around it - if (isMineshafterPresent()) { + if (isMineshafterPresent()) + { connection = url.openConnection(Proxy.NO_PROXY); - } else { + } + else + { connection = url.openConnection(); } - connection.setDoOutput(true); - // Write the data final OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream()); writer.write(data.toString()); writer.flush(); - // Now read the response final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); final String response = reader.readLine(); - // close resources writer.close(); reader.close(); - - if (response == null || response.startsWith("ERR")) { + if (response == null || response.startsWith("ERR")) + { throw new IOException(response); //Throw the exception - } else { + } + else + { // Is this the first update this hour? - if (response.contains("OK This is your first update this hour")) { - synchronized (graphs) { + if (response.contains("OK This is your first update this hour")) + { + synchronized (graphs) + { final Iterator iter = graphs.iterator(); - - while (iter.hasNext()) { + while (iter.hasNext()) + { final Graph graph = iter.next(); - - for (Plotter plotter : graph.getPlotters()) { + for (Plotter plotter : graph.getPlotters()) + { plotter.reset(); } } @@ -466,186 +480,207 @@ private void postPlugin(final boolean isPing) throws IOException { } /** -* Check if mineshafter is present. If it is, we need to bypass it to send POST requests -* + * Check if mineshafter is present. If it is, we need to bypass it to send POST requests + * * @return true if mineshafter is installed on the server -*/ - private boolean isMineshafterPresent() { - try { + */ + private boolean isMineshafterPresent() + { + try + { Class.forName("mineshafter.MineServer"); return true; - } catch (Exception e) { + } + catch (Exception e) + { return false; } } /** -*

Encode a key/value data pair to be used in a HTTP post request. This INCLUDES a & so the first key/value pair -* MUST be included manually, e.g:

-* -* StringBuffer data = new StringBuffer(); -* data.append(encode("guid")).append('=').append(encode(guid)); -* encodeDataPair(data, "version", description.getVersion()); -* -* + *

+ * Encode a key/value data pair to be used in a HTTP post request. This INCLUDES a & so the first key/value pair + * MUST be included manually, e.g:

+ * + * StringBuffer data = new StringBuffer(); + * data.append(encode("guid")).append('=').append(encode(guid)); + * encodeDataPair(data, "version", description.getVersion()); + * + * * @param buffer the stringbuilder to append the data pair onto -* @param key the key value -* @param value the value -*/ - private static void encodeDataPair(final StringBuilder buffer, final String key, final String value) throws UnsupportedEncodingException { + * @param key the key value + * @param value the value + */ + private static void encodeDataPair(final StringBuilder buffer, final String key, final String value) throws UnsupportedEncodingException + { buffer.append('&').append(encode(key)).append('=').append(encode(value)); } /** -* Encode text as UTF-8 -* + * Encode text as UTF-8 + * * @param text the text to encode -* @return the encoded text, as UTF-8 -*/ - private static String encode(final String text) throws UnsupportedEncodingException { + * @return the encoded text, as UTF-8 + */ + private static String encode(final String text) throws UnsupportedEncodingException + { return URLEncoder.encode(text, "UTF-8"); } /** -* Represents a custom graph on the website -*/ + * Represents a custom graph on the website + */ public static class Graph { /** -* The graph's name, alphanumeric and spaces only :) If it does not comply to the above when submitted, it is -* rejected -*/ + * The graph's name, alphanumeric and spaces only :) If it does not comply to the above when submitted, it is + * rejected + */ private final String name; /** -* The set of plotters that are contained within this graph -*/ + * The set of plotters that are contained within this graph + */ private final Set plotters = new LinkedHashSet(); - private Graph(final String name) { + private Graph(final String name) + { this.name = name; } /** -* Gets the graph's name -* + * Gets the graph's name + * * @return the Graph's name -*/ - public String getName() { + */ + public String getName() + { return name; } /** -* Add a plotter to the graph, which will be used to plot entries -* + * Add a plotter to the graph, which will be used to plot entries + * * @param plotter the plotter to add to the graph -*/ - public void addPlotter(final Plotter plotter) { + */ + public void addPlotter(final Plotter plotter) + { plotters.add(plotter); } /** -* Remove a plotter from the graph -* + * Remove a plotter from the graph + * * @param plotter the plotter to remove from the graph -*/ - public void removePlotter(final Plotter plotter) { + */ + public void removePlotter(final Plotter plotter) + { plotters.remove(plotter); } /** -* Gets an unmodifiable set of the plotter objects in the graph -* + * Gets an unmodifiable set of the plotter objects in the graph + * * @return an unmodifiable {@link java.util.Set} of the plotter objects -*/ - public Set getPlotters() { + */ + public Set getPlotters() + { return Collections.unmodifiableSet(plotters); } @Override - public int hashCode() { + public int hashCode() + { return name.hashCode(); } @Override - public boolean equals(final Object object) { - if (!(object instanceof Graph)) { + public boolean equals(final Object object) + { + if (!(object instanceof Graph)) + { return false; } - final Graph graph = (Graph) object; return graph.name.equals(name); } /** -* Called when the server owner decides to opt-out of BukkitMetrics while the server is running. -*/ - protected void onOptOut() { + * Called when the server owner decides to opt-out of BukkitMetrics while the server is running. + */ + protected void onOptOut() + { } } /** -* Interface used to collect custom data for a plugin -*/ + * Interface used to collect custom data for a plugin + */ public static abstract class Plotter { /** -* The plot's name -*/ + * The plot's name + */ private final String name; /** -* Construct a plotter with the default plot name -*/ - public Plotter() { + * Construct a plotter with the default plot name + */ + public Plotter() + { this("Default"); } /** -* Construct a plotter with a specific plot name -* + * Construct a plotter with a specific plot name + * * @param name the name of the plotter to use, which will show up on the website -*/ - public Plotter(final String name) { + */ + public Plotter(final String name) + { this.name = name; } /** -* Get the current value for the plotted point. Since this function defers to an external function it may or may -* not return immediately thus cannot be guaranteed to be thread friendly or safe. This function can be called -* from any thread so care should be taken when accessing resources that need to be synchronized. -* + * Get the current value for the plotted point. Since this function defers to an external function it may or may + * not return immediately thus cannot be guaranteed to be thread friendly or safe. This function can be called + * from any thread so care should be taken when accessing resources that need to be synchronized. + * * @return the current value for the point to be plotted. -*/ + */ public abstract int getValue(); /** -* Get the column name for the plotted point -* + * Get the column name for the plotted point + * * @return the plotted point's column name -*/ - public String getColumnName() { + */ + public String getColumnName() + { return name; } /** -* Called after the website graphs have been updated -*/ - public void reset() { + * Called after the website graphs have been updated + */ + public void reset() + { } @Override - public int hashCode() { + public int hashCode() + { return getColumnName().hashCode(); } @Override - public boolean equals(final Object object) { - if (!(object instanceof Plotter)) { + public boolean equals(final Object object) + { + if (!(object instanceof Plotter)) + { return false; } - final Plotter plotter = (Plotter) object; return plotter.name.equals(name) && plotter.getValue() == getValue(); } } -} \ No newline at end of file +} diff --git a/TabAPI/src/main/java/org/mcsg/double0negative/tabapi/TabAPI.java b/TabAPI/src/main/java/org/mcsg/double0negative/tabapi/TabAPI.java index 8510c0e..fecf0ce 100644 --- a/TabAPI/src/main/java/org/mcsg/double0negative/tabapi/TabAPI.java +++ b/TabAPI/src/main/java/org/mcsg/double0negative/tabapi/TabAPI.java @@ -1,10 +1,23 @@ package org.mcsg.double0negative.tabapi; +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.ProtocolLibrary; +import com.comphenix.protocol.ProtocolManager; +import com.comphenix.protocol.events.ListenerPriority; +import com.comphenix.protocol.events.PacketAdapter; +import com.comphenix.protocol.events.PacketContainer; +import com.comphenix.protocol.events.PacketEvent; +import com.comphenix.protocol.wrappers.EnumWrappers; +import com.comphenix.protocol.wrappers.EnumWrappers.PlayerInfoAction; +import com.comphenix.protocol.wrappers.PlayerInfoData; +import com.comphenix.protocol.wrappers.WrappedChatComponent; +import com.comphenix.protocol.wrappers.WrappedGameProfile; +import com.google.common.base.Charsets; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; - +import java.util.List; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.command.Command; @@ -14,382 +27,596 @@ import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerKickEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.java.JavaPlugin; -import com.comphenix.protocol.Packets; -import com.comphenix.protocol.ProtocolLibrary; -import com.comphenix.protocol.ProtocolManager; -import com.comphenix.protocol.events.ConnectionSide; -import com.comphenix.protocol.events.ListenerPriority; -import com.comphenix.protocol.events.PacketAdapter; -import com.comphenix.protocol.events.PacketContainer; -import com.comphenix.protocol.events.PacketEvent; - - /** * TabAPI - * - * Provides a simple interface for adding custom text to - * display on the minecraft tab menu on a player/plugin - * basis - * + * + * Provides a simple interface for adding custom text to display on the minecraft tab menu on a player/plugin basis + * * @author Double0negative - * + * * */ +public class TabAPI extends JavaPlugin implements Listener, CommandExecutor { + + private static HashMap playerTab = new HashMap(); + private static HashMap playerTabLast = new HashMap(); + private static HashMap playerTab47 = new HashMap(); + private static HashMap playerTabLast47 = new HashMap(); + private static HashMap> cachedPackets = new HashMap>(); + private static HashMap updateSchedules = new HashMap(); + private static int horizTabSize = 3; + private static int vertTabSize = 20; + private static int horizTabSize47 = 4; + private static int vertTabSize47 = 20; + private static String[] colors = + { + "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "a", "b", "c", "d", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "r", "s", "t", "u", "v", "w", "x", "y", "z" + }; + private static int e = 0; + private static int r = 0; + private static long flickerPrevention = 5L; + public static ProtocolManager protocolManager; + private static boolean shuttingdown = false; + private static TabAPI plugin; + @Override + public void onEnable() + { + TabAPI.plugin = this; + // read initial config if there's any + FileConfiguration config = getConfig(); + config.options().copyDefaults(true); + // add defaults if there are new ones + MemoryConfiguration defaultConfig = new MemoryConfiguration(); + defaultConfig.set("flickerPrevention", flickerPrevention); + config.setDefaults(defaultConfig); + saveConfig(); + // load config settings + reloadConfiguration(); + this.getCommand("tabapi").setExecutor(this); + try + { + new Metrics(this).start(); + } + catch (IOException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + protocolManager = ProtocolLibrary.getProtocolManager(); + Bukkit.getServer().getPluginManager().registerEvents(this, this); + for (Player p : Bukkit.getOnlinePlayers()) + { + Plugin plugin = Bukkit.getPluginManager().getPlugin("TabAPI"); + setPriority(plugin, p, 2); + resetTabList(p); + setPriority(plugin, p, -2); + } + protocolManager.addPacketListener(new PacketAdapter( + this, + ListenerPriority.NORMAL, + PacketType.Play.Server.PLAYER_INFO) { + @Override + public void onPacketSending(PacketEvent event) + { + PacketContainer p = event.getPacket(); + List pinfodata = p.getPlayerInfoDataLists().read(0); + String s = pinfodata.get(0).getProfile().getName(); + if (s.startsWith("$")) + { // this is a packet sent by TabAPI **Work around until I figure out how to make my own + //p.getStrings().write(0, s.substring(1)); // packets bypass this block** + List pinfodataReSend = new ArrayList(); + PlayerInfoData pinfod = pinfodata.get(0); + pinfodataReSend.add(new PlayerInfoData( + pinfod.getProfile().withName(s.substring(1)), + pinfod.getPing(), + pinfod.getGameMode(), + WrappedChatComponent.fromText(pinfod.getProfile().getName().substring(1))) + ); + p.getPlayerInfoDataLists().write(0, pinfodataReSend); + event.setPacket(p); + } + else + { + if (protocolManager.getProtocolVersion(event.getPlayer()) >= 47) + { + // send skins and entity normally in protocol 47 + } + else + { + event.setCancelled(true); + } + } + } + }); + } -public class TabAPI extends JavaPlugin implements Listener, CommandExecutor{ - - - private static HashMapplayerTab = new HashMap(); - private static HashMapplayerTabLast = new HashMap(); - - private static HashMap>cachedPackets = new HashMap>(); - private static HashMapupdateSchedules = new HashMap(); - - private static int horzTabSize = 3; - private static int vertTabSize = 20; - - private static String[] colors = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "a","b", "c", "d", "f", "g", "h", "i", "j","k","l","m","n","o","p","r","s","t","u","v","w","x","y","z"}; - - private static int e = 0; - private static int r = 0; - - private static long flickerPrevention = 5L; - - private static ProtocolManager protocolManager; - - private static boolean shuttingdown = false; - - private static TabAPI plugin; - - public void onEnable(){ - TabAPI.plugin = this; - - // read initial config if there's any - FileConfiguration config = getConfig(); - config.options().copyDefaults(true); - - // add defaults if there are new ones - MemoryConfiguration defaultConfig = new MemoryConfiguration(); - defaultConfig.set("flickerPrevention", flickerPrevention); - config.setDefaults(defaultConfig); - saveConfig(); - - // load config settings - reloadConfiguration(); - - this.getCommand("tabapi").setExecutor(this); - - try { - new Metrics(this).start(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - protocolManager = ProtocolLibrary.getProtocolManager(); - - - Bukkit.getServer().getPluginManager().registerEvents(this, this); - for(Player p: Bukkit.getOnlinePlayers()){ - Plugin plugin = Bukkit.getPluginManager().getPlugin("TabAPI"); - setPriority(plugin, p, 2); - resetTabList(p); - setPriority(plugin, p, -2); - - } - - - protocolManager.addPacketListener(new PacketAdapter(this, - ConnectionSide.SERVER_SIDE, ListenerPriority.NORMAL, Packets.Server.PLAYER_INFO) { - @Override - public void onPacketSending(PacketEvent event) { - switch (event.getPacketID()) { - case Packets.Server.PLAYER_INFO: - PacketContainer p = event.getPacket(); - String s = p.getStrings().read(0); - if(s.startsWith("$")){ // this is a packet sent by TabAPI **Work around until I figure out how to make my own - p.getStrings().write(0,s.substring(1)); // packets bypass this block** - event.setPacket(p); - } - else{ - event.setCancelled(true); - } - break; - } - } - }); + public void reloadConfiguration() + { + reloadConfig(); + flickerPrevention = getConfig().getLong("flickerPrevention"); + } - } - - public void reloadConfiguration() { - reloadConfig(); - flickerPrevention = getConfig().getLong("flickerPrevention"); - } + @Override + public void onDisable() + { + shuttingdown = true; + for (Player p : Bukkit.getOnlinePlayers()) + { + clearTab(p); + } + flushPackets(); + playerTab = null; + playerTabLast = null; + playerTab47 = null; + playerTabLast47 = null; + } - public void onDisable(){ - shuttingdown = true; - for(Player p: Bukkit.getOnlinePlayers()){ - clearTab(p); - } - flushPackets(); - playerTab = null; - playerTabLast = null; - } - @Override - public boolean onCommand(CommandSender sender, Command cmd1, String commandLabel, String[] args){ + public boolean onCommand(CommandSender sender, Command cmd1, String commandLabel, String[] args) + { PluginDescriptionFile pdfFile = this.getDescription(); - Player player = null; - if (sender instanceof Player) { + if (sender instanceof Player) + { player = (Player) sender; - if(args.length == 1 && player.hasPermission("tabapi.reload")){ - reloadConfiguration(); - updateAll(); + if (args.length == 1 && player.hasPermission("tabapi.reload")) + { + reloadConfiguration(); + updateAll(); } - else{ - player.sendMessage(ChatColor.DARK_RED +""+ ChatColor.BOLD +"TabAPI - Double0negative"+ChatColor.RESET+ ChatColor.RED +" Version: "+ pdfFile.getVersion() ); - + else + { + player.sendMessage(ChatColor.DARK_RED + "" + ChatColor.BOLD + "TabAPI - Double0negative, NeT32" + ChatColor.RESET + ChatColor.RED + " Version: " + pdfFile.getVersion()); } } - else{ - sender.sendMessage(ChatColor.DARK_RED +""+ ChatColor.BOLD +"TabAPI - Double0negative"+ChatColor.RESET+ ChatColor.RED +" Version: "+ pdfFile.getVersion() ); + else + { + sender.sendMessage(ChatColor.DARK_RED + "" + ChatColor.BOLD + "TabAPI - Double0negative, NeT32" + ChatColor.RESET + ChatColor.RED + " Version: " + pdfFile.getVersion()); return true; } - return true; - } - private static void addPacket(Player p, String msg, boolean b, int ping){ - PacketContainer message = protocolManager.createPacket(Packets.Server.PLAYER_INFO); - message.getStrings().write(0, ((!shuttingdown)?"$":"")+msg); - message.getBooleans().write(0, b); - message.getIntegers().write(0, ping); - ArrayList packetList = cachedPackets.get(p); - if (packetList == null) { - packetList = new ArrayList(); - cachedPackets.put(p, packetList); - } - packetList.add(message); - } + private static void addPacket(Player p, String msg, int slotId, WrappedGameProfile gameProfile, boolean b, int ping) + { + PacketContainer message = protocolManager.createPacket(PacketType.Play.Server.PLAYER_INFO); + String nameToShow = ((!shuttingdown) ? "$" : "") + msg; + if (protocolManager.getProtocolVersion(p) >= 47) + { + nameToShow = ((!shuttingdown) ? "$" : "") + ChatColor.DARK_GRAY + "" + slotId + ": " + msg.substring(0, Math.min(msg.length(), 10)); + } + PlayerInfoAction action; + if (b) + { + action = PlayerInfoAction.ADD_PLAYER; + } + else + { + action = PlayerInfoAction.REMOVE_PLAYER; + } + message.getPlayerInfoAction().write(0, action); + List pInfoData = new ArrayList(); + if (gameProfile != null) + { + pInfoData.add(new PlayerInfoData( + gameProfile.withName(nameToShow.substring(1)).withId(java.util.UUID.nameUUIDFromBytes(("OfflinePlayer:" + nameToShow.substring(1)).getBytes(Charsets.UTF_8)).toString()), + ping, + EnumWrappers.NativeGameMode.SURVIVAL, + WrappedChatComponent.fromText(nameToShow)) + ); + } + else + { + pInfoData.add(new PlayerInfoData( + new WrappedGameProfile(java.util.UUID.nameUUIDFromBytes(("OfflinePlayer:" + nameToShow.substring(1)).getBytes(Charsets.UTF_8)), nameToShow.substring(1)), + ping, + EnumWrappers.NativeGameMode.SURVIVAL, + WrappedChatComponent.fromText(nameToShow)) + ); + } + message.getPlayerInfoDataLists().write(0, pInfoData); + ArrayList packetList = cachedPackets.get(p); + if (packetList == null) + { + packetList = new ArrayList(); + cachedPackets.put(p, packetList); + } + packetList.add(message); + } + + private static void flushPackets() + { + final Player[] packetPlayers = cachedPackets.keySet().toArray(new Player[0]); + for (Player p : packetPlayers) + { + flushPackets(p, null); + } + } + + private static void flushPackets(final Player p, final Object tabCopy) + { + final PacketContainer[] packets = (PacketContainer[]) cachedPackets.get(p).toArray(new PacketContainer[0]); + // cancel old task (prevents flickering) + Integer taskID = updateSchedules.get(p); + if (taskID != null) + { + Bukkit.getScheduler().cancelTask(taskID); + } + taskID = Bukkit.getScheduler().scheduleSyncDelayedTask(TabAPI.plugin, new Runnable() { + @Override + public void run() + { + if (p.isOnline()) + { + for (PacketContainer packet : packets) + { + try + { + protocolManager.sendServerPacket(p, packet); + } + catch (InvocationTargetException e) + { + e.printStackTrace(); + System.out.println("[TabAPI] Error sending packet to client"); + } + } + } + if (tabCopy != null) + { + if (tabCopy instanceof TabHolder47) + { + playerTabLast47.put(p.getName(), (TabHolder47) tabCopy); // we set this only if we really finally flush it (which is just now) + } + else if (tabCopy instanceof TabHolder) + { + playerTabLast.put(p.getName(), (TabHolder) tabCopy); // we set this only if we really finally flush it (which is just now) + } + } + updateSchedules.remove(p); // we're done, no need to cancel this one on next run + } + }, flickerPrevention); + // let's keep a reference to be able to cancel this (see above) + updateSchedules.put(p, taskID); + cachedPackets.remove(p); + } - private static void flushPackets() { - final Player[] packetPlayers = cachedPackets.keySet().toArray(new Player[0]); - for (Player p : packetPlayers) { - flushPackets(p, null); - } - } + private static TabObject getTab(Player p) + { + TabObject tabo = playerTab.get(p.getName()); + if (tabo == null) + { + tabo = new TabObject(); + playerTab.put(p.getName(), tabo); + } + return tabo; + } - private static void flushPackets(final Player p, final TabHolder tabCopy) { - final PacketContainer[] packets = (PacketContainer[]) cachedPackets.get(p).toArray(new PacketContainer[0]); - - // cancel old task (prevents flickering) - Integer taskID = updateSchedules.get(p); - if (taskID != null) { - Bukkit.getScheduler().cancelTask(taskID); - } - - taskID = Bukkit.getScheduler().scheduleSyncDelayedTask(TabAPI.plugin, new Runnable() { - @Override - public void run() { - if (p.isOnline()) { - - for (PacketContainer packet : packets) { - try { - protocolManager.sendServerPacket(p, packet); - } catch (InvocationTargetException e) { - e.printStackTrace(); - System.out.println("[TabAPI] Error sending packet to client"); - } - } - } - if (tabCopy != null) playerTabLast.put(p.getName(), tabCopy); // we set this only if we really finally flush it (which is just now) - updateSchedules.remove(p); // we're done, no need to cancel this one on next run - } - }, flickerPrevention); - - // let's keep a reference to be able to cancel this (see above) - updateSchedules.put(p, taskID); - - cachedPackets.remove(p); - } - - - private static TabObject getTab(Player p){ - TabObject tabo = playerTab.get(p.getName()); - if(tabo == null){ - tabo = new TabObject(); - playerTab.put(p.getName(), tabo); - } - return tabo; - } - + private static TabObject47 getTab47(Player p) + { + TabObject47 tabo = playerTab47.get(p.getName()); + if (tabo == null) + { + tabo = new TabObject47(); + playerTab47.put(p.getName(), tabo); + } + return tabo; + } - /** - * Priorities - * - * -2 = no longer active, remove - * -1 = background, only show if nothing else is there - * 0 = normal - * 1 = high priority - * 2 = always show, only use if MUST show - * - */ - public static void setPriority(Plugin plugin, Player player, int pri){ - getTab(player).setPriority(plugin, pri); - } + /** + * Priorities + * + * -2 = no longer active, remove -1 = background, only show if nothing else is there 0 = normal 1 = high priority 2 + * = always show, only use if MUST show + * + * @param plugin + * @param player + * @param pri + */ + public static void setPriority(Plugin plugin, Player player, int pri) + { + getTab(player).setPriority(plugin, pri); + } - /** - * Returns the tab list to the vanilla tab list for a player. - * If another plugin holds higher priority, this does notning - * @param p - */ - public static void disableTabForPlayer(Player p){ - playerTab.put(p.getName(), null); - resetTabList(p); - } + /** + * Returns the tab list to the vanilla tab list for a player. If another plugin holds higher priority, this does + * notning + * + * @param p + */ + public static void disableTabForPlayer(Player p) + { + playerTab.put(p.getName(), null); + playerTab47.put(p.getName(), null); + resetTabList(p); + } - /** - * Resets tab to normal tab. - * @param p - */ - public static void resetTabList(Player p){ - int a = 0; int b = 0; + /** + * Resets tab to normal tab. + * + * @param p + */ + public static void resetTabList(Player p) + { + int a = 0; + int b = 0; + for (Player pl : Bukkit.getOnlinePlayers()) + { + setTabString(Bukkit.getPluginManager().getPlugin("TabAPI"), p, a, b, pl.getPlayerListName()); + b++; + if (b > TabAPI.getHorizSize(protocolManager.getProtocolVersion(pl))) + { + b = 0; + a++; + } + } + } - for(Player pl : Bukkit.getOnlinePlayers()){ - setTabString(Bukkit.getPluginManager().getPlugin("TabAPI"), p, a, b, pl.getPlayerListName()); - b++; - if(b > horzTabSize){ - b = 0; - a++; - } - } - } + public static void setTabString(Plugin plugin, Player p, int x, int y, String msg) + { + setTabString(plugin, p, x, y, msg, 0, null); + } - public static void setTabString(Plugin plugin, Player p, int x, int y, String msg){ - setTabString(plugin, p, x, y, msg, 0); - - } - - /** - * Set the tab for a player. - * - * If the plugin the tab is being set from does not have a priority, It will automatically be give a base - * priority of 0 - * - * @param plugin - * @param p - * @param x - * @param y - * @param msg - * @param ping - */ - public static void setTabString(Plugin plugin, Player p, int x, int y, String msg, int ping){ - try{ - TabObject tabo = getTab(p); - tabo.setTab(plugin, x, y,msg,ping); - playerTab.put(p.getName(), tabo); - }catch(Exception e){e.printStackTrace();} + public static void setTabString(Plugin plugin, Player p, int x, int y, String msg, int ping) + { + setTabString(plugin, p, x, y, msg, ping, null); + } - } + /** + * Set the tab for a player. + * + * If the plugin the tab is being set from does not have a priority, It will automatically be give a base priority + * of 0 + * + * @param plugin + * @param p + * @param x + * @param y + * @param msg + * @param ping + * @param gameProfile + */ + public static void setTabString(Plugin plugin, Player p, int x, int y, String msg, int ping, WrappedGameProfile gameProfile) + { + try + { + if (protocolManager.getProtocolVersion(p) >= 47) + { + TabObject47 tabo = getTab47(p); + tabo.setTab(plugin, x, y, msg, ping, gameProfile); + playerTab47.put(p.getName(), tabo); + } + else + { + TabObject tabo = getTab(p); + tabo.setTab(plugin, x, y, msg, ping); + playerTab.put(p.getName(), tabo); + } + } + catch (Exception ex) + { + ex.printStackTrace(); + } + } + /** + * Updates a players tab + * + * A tab will be updated with the tab from the highest priority plugin + * + * @param p + */ + public static void updatePlayer(Player p) + { + if (!p.isOnline()) + { + return; + } + r = 0; + e = 0; + if (protocolManager.getProtocolVersion(p) >= 47) + { + TabObject47 tabo = playerTab47.get(p.getName()); + TabHolder47 tab = tabo.getTab(); + if (tab == null) + { + return; + } + /* need to clear the tab first */ + clearTab(p); + for (int b = 0; b < tab.maxv; b++) + { + for (int a = 0; a < tab.maxh; a++) + { + // fix empty tabs + if (tab.tabs[a][b] == null) + { + tab.tabs[a][b] = nextNull(); + } + String msg = tab.tabs[a][b]; + int ping = tab.tabPings[a][b]; + WrappedGameProfile gameProfile = tab.tabGameProfiles[a][b]; + addPacket(p, (msg == null) ? " " : msg.substring(0, Math.min(msg.length(), 16)), getSlotId(b, a), gameProfile, true, ping); + } + } + flushPackets(p, tab.getCopy()); + } + else + { + TabObject tabo = playerTab.get(p.getName()); + TabHolder tab = tabo.getTab(); + if (tab == null) + { + return; + } + /* need to clear the tab first */ + clearTab(p); + for (int b = 0; b < tab.maxv; b++) + { + for (int a = 0; a < tab.maxh; a++) + { + // fix empty tabs + if (tab.tabs[a][b] == null) + { + tab.tabs[a][b] = nextNull(); + } + String msg = tab.tabs[a][b]; + int ping = tab.tabPings[a][b]; + addPacket(p, (msg == null) ? " " : msg.substring(0, Math.min(msg.length(), 16)), 0, null, true, ping); + } + } + flushPackets(p, tab.getCopy()); + } + } - /** - * Updates a players tab - * - * A tab will be updated with the tab from the highest priority plugin - * - * @param p - */ - public static void updatePlayer(Player p){ - if(!p.isOnline()) return; - r = 0; e = 0; - TabObject tabo = playerTab.get(p.getName()); - TabHolder tab = tabo.getTab(); - if(tab == null) return; - - /* need to clear the tab first */ - clearTab(p); - - for(int b = 0; b < tab.maxv; b++){ - for(int a = 0; a < tab.maxh ; a++){ - // fix empty tabs - if(tab.tabs[a][b] == null) tab.tabs[a][b] = nextNull(); + /** + * Clear a players tab menu + * + * @param p + */ + public static void clearTab(Player p) + { + if (!p.isOnline()) + { + return; + } + if (protocolManager.getProtocolVersion(p) >= 47) + { + TabHolder47 tabold = playerTabLast47.get(p.getName()); + if (tabold != null) + { + for (int b = 0; b < tabold.maxv; b++) + { + for (int a = 0; a < tabold.maxh; a++) + { + String msg = tabold.tabs[a][b]; + WrappedGameProfile gameProfile = tabold.tabGameProfiles[a][b]; + addPacket(p, msg.substring(0, Math.min(msg.length(), 16)), getSlotId(b, a), gameProfile, false, 0); + } + } + } + } + else + { + TabHolder tabold = playerTabLast.get(p.getName()); + if (tabold != null) + { + for (String[] s : tabold.tabs) + { + for (String msg : s) + { + if (msg != null) + { + addPacket(p, msg.substring(0, Math.min(msg.length(), 16)), 0, null, false, 0); + } + } + } + } + } + } - String msg = tab.tabs[a][b]; - int ping = tab.tabPings[a][b]; - - addPacket(p, (msg == null)? " ": msg.substring(0, Math.min(msg.length(), 16)), true, ping); - } - } - flushPackets(p, tab.getCopy()); + public static void updateAll() + { + for (Player p : Bukkit.getOnlinePlayers()) + { + updatePlayer(p); + } + } - } - /** - * Clear a players tab menu - * @param p - */ - public static void clearTab(Player p){ - if(!p.isOnline())return; + /* return the next null filler */ + public static String nextNull() + { + String s = ""; + for (int a = 0; a < r; a++) + { + s = " " + s; + } + s = s + "\u00A7" + colors[e]; + e++; + if (e > 14) + { + e = 0; + r++; + } + return s; + } - TabHolder tabold = playerTabLast.get(p.getName()); + @EventHandler + public void PlayerLeave(PlayerQuitEvent e) + { + //cleanup + playerTab.remove(e.getPlayer().getName()); + playerTabLast.remove(e.getPlayer().getName()); + playerTab47.remove(e.getPlayer().getName()); + playerTabLast47.remove(e.getPlayer().getName()); + } - if(tabold != null){ - for(String [] s: tabold.tabs){ - for(String msg:s){ - if(msg != null){ - addPacket(p, msg.substring(0, Math.min(msg.length(), 16)), false, 0); - } - } - } - } - } + @EventHandler + public void PlayerKick(PlayerKickEvent e) + { + //cleanup + playerTab.remove(e.getPlayer().getName()); + playerTabLast.remove(e.getPlayer().getName()); + playerTab47.remove(e.getPlayer().getName()); + playerTabLast47.remove(e.getPlayer().getName()); + } - public static void updateAll(){ - for(Player p:Bukkit.getOnlinePlayers()){ - updatePlayer(p); - - } - } + @Deprecated + public static int getVertSize() + { + return vertTabSize; + } + @Deprecated + public static int getHorizSize() + { + return horizTabSize; + } - /* return the next null filler */ - public static String nextNull(){ - String s = ""; - for(int a = 0; a < r; a++){ - s = " "+s; - } - s = s + "\u00A7" + colors[e]; - e++; - if(e > 14){ - e = 0; - r++; - } - return s; - } + public static int getVertSize(int protocol) + { + if (protocol >= 47) + { + return vertTabSize47; + } + return vertTabSize; + } - @EventHandler(priority = EventPriority.HIGHEST) - public void PlayerLeave(PlayerQuitEvent e){ - //cleanup - playerTab.remove(e.getPlayer().getName()); - playerTabLast.remove(e.getPlayer().getName()); - } + public static int getHorizSize(int protocol) + { + if (protocol >= 47) + { + return horizTabSize47; + } + return horizTabSize; + } - public static int getVertSize(){ - return vertTabSize; - } - - public static int getHorizSize(){ - return horzTabSize; - } + public static int getSlotId(int x, int y) + { + if (y == 0) + { + return 11 + x; + } + if (y == 1) + { + return 31 + x; + } + if (y == 2) + { + return 51 + x; + } + if (y == 3) + { + return 71 + x; + } + return 0; + } } diff --git a/TabAPI/src/main/java/org/mcsg/double0negative/tabapi/TabHolder.java b/TabAPI/src/main/java/org/mcsg/double0negative/tabapi/TabHolder.java index 7369a3f..f300f4c 100644 --- a/TabAPI/src/main/java/org/mcsg/double0negative/tabapi/TabHolder.java +++ b/TabAPI/src/main/java/org/mcsg/double0negative/tabapi/TabHolder.java @@ -1,60 +1,66 @@ package org.mcsg.double0negative.tabapi; import org.bukkit.plugin.Plugin; + /** - * - * + * + * * Holds tab information such as plugin and tab strings - * - * + * + * * @author Drew * */ -class TabHolder{ - Plugin p; - - String[][]tabs; - int[][]tabPings; - - int maxh = 0, maxv = 0; - - public TabHolder(Plugin p) { - this.p = p; - this.tabs = new String[TabAPI.getHorizSize()][TabAPI.getVertSize()]; - this.tabPings = new int[TabAPI.getHorizSize()][TabAPI.getVertSize()]; - } +class TabHolder { + + Plugin p; + String[][] tabs; + int[][] tabPings; + int maxh = 0, maxv = 0; + + public TabHolder(Plugin p) + { + this.p = p; + this.tabs = new String[TabAPI.getHorizSize()][TabAPI.getVertSize()]; + this.tabPings = new int[TabAPI.getHorizSize()][TabAPI.getVertSize()]; + } + + public TabHolder getCopy() + { + TabHolder newCopy = new TabHolder(p); + newCopy.tabs = copyStringArray(tabs); + newCopy.tabPings = copyIntArray(tabPings); + return newCopy; + } + + /* Util method, copy tab array to new array */ + private static String[][] copyStringArray(String[][] tab) + { + int horzTabSize = TabAPI.getHorizSize(); + int vertTabSize = TabAPI.getVertSize(); + String[][] temp = new String[horzTabSize][vertTabSize]; + for (int b = 0; b < vertTabSize; b++) + { + for (int a = 0; a < horzTabSize; a++) + { + temp[a][b] = tab[a][b]; + } + } + return temp; + } - public TabHolder getCopy() { - TabHolder newCopy = new TabHolder(p); - newCopy.tabs = copyStringArray(tabs); - newCopy.tabPings = copyIntArray(tabPings); - return newCopy; - } - - /* Util method, copy tab array to new array */ - private static String[][] copyStringArray(String[][] tab){ - int horzTabSize = TabAPI.getHorizSize(); - int vertTabSize = TabAPI.getVertSize(); - - String[][] temp = new String[horzTabSize][vertTabSize]; - for(int b = 0; b < vertTabSize; b++){ - for(int a = 0; a < horzTabSize ; a++){ - temp[a][b] = tab[a][b]; - } - } - return temp; - } - - private static int[][] copyIntArray(int[][] tab){ - int horzTabSize = TabAPI.getHorizSize(); - int vertTabSize = TabAPI.getVertSize(); - - int[][] temp = new int[horzTabSize][vertTabSize]; - for(int b = 0; b < vertTabSize; b++){ - for(int a = 0; a < horzTabSize ; a++){ - temp[a][b] = tab[a][b]; - } - } - return temp; - } + private static int[][] copyIntArray(int[][] tab) + { + int horzTabSize = TabAPI.getHorizSize(); + int vertTabSize = TabAPI.getVertSize(); + int[][] temp = new int[horzTabSize][vertTabSize]; + for (int b = 0; b < vertTabSize; b++) + { + for (int a = 0; a < horzTabSize; a++) + { + temp[a][b] = tab[a][b]; + } + } + return temp; + } } diff --git a/TabAPI/src/main/java/org/mcsg/double0negative/tabapi/TabHolder47.java b/TabAPI/src/main/java/org/mcsg/double0negative/tabapi/TabHolder47.java new file mode 100644 index 0000000..6f7747c --- /dev/null +++ b/TabAPI/src/main/java/org/mcsg/double0negative/tabapi/TabHolder47.java @@ -0,0 +1,75 @@ +package org.mcsg.double0negative.tabapi; + +import com.comphenix.protocol.wrappers.WrappedGameProfile; +import org.bukkit.plugin.Plugin; + +/** + * + * @author NeT32 + */ +class TabHolder47 { + + Plugin p; + String[][] tabs; + int[][] tabPings; + WrappedGameProfile[][] tabGameProfiles; + int maxh = 0, maxv = 0; + + public TabHolder47(Plugin p) + { + this.p = p; + this.tabs = new String[TabAPI.getHorizSize(47)][TabAPI.getVertSize(47)]; + this.tabPings = new int[TabAPI.getHorizSize(47)][TabAPI.getVertSize(47)]; + this.tabGameProfiles = new WrappedGameProfile[TabAPI.getHorizSize(47)][TabAPI.getVertSize(47)]; + this.maxh = TabAPI.getHorizSize(47); + this.maxv = TabAPI.getVertSize(47); + for (int b = 0; b < this.maxv; b++) + { + for (int a = 0; a < this.maxh; a++) + { + this.tabs[a][b] = " "; + this.tabPings[a][b] = 9999; + this.tabGameProfiles[a][b] = null; + } + } + } + + public TabHolder47 getCopy() + { + TabHolder47 newCopy = new TabHolder47(p); + newCopy.tabs = copyStringArray(tabs); + newCopy.tabPings = copyIntArray(tabPings); + return newCopy; + } + + /* Util method, copy tab array to new array */ + private static String[][] copyStringArray(String[][] tab) + { + int horzTabSize = TabAPI.getHorizSize(47); + int vertTabSize = TabAPI.getVertSize(47); + String[][] temp = new String[horzTabSize][vertTabSize]; + for (int b = 0; b < vertTabSize; b++) + { + for (int a = 0; a < horzTabSize; a++) + { + temp[a][b] = tab[a][b]; + } + } + return temp; + } + + private static int[][] copyIntArray(int[][] tab) + { + int horzTabSize = TabAPI.getHorizSize(47); + int vertTabSize = TabAPI.getVertSize(47); + int[][] temp = new int[horzTabSize][vertTabSize]; + for (int b = 0; b < vertTabSize; b++) + { + for (int a = 0; a < horzTabSize; a++) + { + temp[a][b] = tab[a][b]; + } + } + return temp; + } +} diff --git a/TabAPI/src/main/java/org/mcsg/double0negative/tabapi/TabObject.java b/TabAPI/src/main/java/org/mcsg/double0negative/tabapi/TabObject.java index ae8bde8..9d312fa 100644 --- a/TabAPI/src/main/java/org/mcsg/double0negative/tabapi/TabObject.java +++ b/TabAPI/src/main/java/org/mcsg/double0negative/tabapi/TabObject.java @@ -1,67 +1,67 @@ package org.mcsg.double0negative.tabapi; import java.util.HashMap; - import org.bukkit.plugin.Plugin; -public class TabObject{ - - - /** - * Holds a list of tab information for a player. - * - * - */ - - - HashMaptabs = new HashMap(); +public class TabObject { - - + /** + * Holds a list of tab information for a player. + * + * + */ + HashMap tabs = new HashMap(); - public void setPriority(Plugin p, int pri){ - //System.out.println("Settings pri for "+p.getName()+": "+pri); - for(int a = -1; a<4;a++){ - if(tabs.get(a) != null && tabs.get(a).p == p){ - tabs.put(a, null); - } - } - if(pri > -2){ - TabHolder t = new TabHolder(p); - tabs.put(pri,t ); - } - } + public void setPriority(Plugin p, int pri) + { + //System.out.println("Settings pri for "+p.getName()+": "+pri); + for (int a = -1; a < 4; a++) + { + if (tabs.get(a) != null && tabs.get(a).p == p) + { + tabs.put(a, null); + } + } + if (pri > -2) + { + TabHolder t = new TabHolder(p); + tabs.put(pri, t); + } + } - public TabHolder getTab(){ - int a = 3; - while(tabs.get(a) == null && a >-3){ - a--; - } - if(a == -2){ - return new TabHolder(null); - } - //System.out.print("Getting tab "+a+" "+tabs.get(a).p.getName()); - return tabs.get(a); - } + public TabHolder getTab() + { + int a = 3; + while (tabs.get(a) == null && a > -3) + { + a--; + } + if (a == -2) + { + return new TabHolder(null); + } + //System.out.print("Getting tab "+a+" "+tabs.get(a).p.getName()); + return tabs.get(a); + } - public void setTab(Plugin plugin, int x, int y, String msg, int ping) { - int a = -1; - while((tabs.get(a)==null || tabs.get(a).p != plugin) && a <3){ - a++; - } - if(a == 3 && (tabs.get(a)==null||tabs.get(a).p != plugin)){ - //System.out.println("Reseting Pri"); - setPriority(plugin, 0); - a = 0; - } + public void setTab(Plugin plugin, int x, int y, String msg, int ping) + { + int a = -1; + while ((tabs.get(a) == null || tabs.get(a).p != plugin) && a < 3) + { + a++; + } + if (a == 3 && (tabs.get(a) == null || tabs.get(a).p != plugin)) + { + //System.out.println("Reseting Pri"); + setPriority(plugin, 0); + a = 0; + } //System.out.println(plugin.getName()+": "+a); - - TabHolder t = tabs.get(a); - - t.tabs[y][x] = msg; - t.tabPings[y][x] = ping; - t.maxh = 3; - t.maxv = Math.max(x+1, t.maxv); - } - + TabHolder t = tabs.get(a); + t.tabs[y][x] = msg; + t.tabPings[y][x] = ping; + t.maxh = 3; + t.maxv = Math.max(x + 1, t.maxv); + } } diff --git a/TabAPI/src/main/java/org/mcsg/double0negative/tabapi/TabObject47.java b/TabAPI/src/main/java/org/mcsg/double0negative/tabapi/TabObject47.java new file mode 100644 index 0000000..25bb478 --- /dev/null +++ b/TabAPI/src/main/java/org/mcsg/double0negative/tabapi/TabObject47.java @@ -0,0 +1,73 @@ +package org.mcsg.double0negative.tabapi; + +import com.comphenix.protocol.wrappers.WrappedGameProfile; +import java.util.HashMap; +import org.bukkit.plugin.Plugin; + +/** + * + * @author NeT32 + */ +public class TabObject47 { + + /** + * Holds a list of tab information for a player. + * + * + */ + HashMap tabs = new HashMap(); + + public void setPriority(Plugin p, int pri) + { + //System.out.println("Settings pri for "+p.getName()+": "+pri); + for (int a = -1; a < 4; a++) + { + if (tabs.get(a) != null && tabs.get(a).p == p) + { + tabs.put(a, null); + } + } + if (pri > -2) + { + TabHolder47 t = new TabHolder47(p); + tabs.put(pri, t); + } + } + + public TabHolder47 getTab() + { + int a = 3; + while (tabs.get(a) == null && a > -3) + { + a--; + } + if (a == -2) + { + return new TabHolder47(null); + } + //System.out.print("Getting tab "+a+" "+tabs.get(a).p.getName()); + return tabs.get(a); + } + + public void setTab(Plugin plugin, int x, int y, String msg, int ping, WrappedGameProfile gameProfile) + { + int a = -1; + while ((tabs.get(a) == null || tabs.get(a).p != plugin) && a < 3) + { + a++; + } + if (a == 3 && (tabs.get(a) == null || tabs.get(a).p != plugin)) + { + //System.out.println("Reseting Pri"); + setPriority(plugin, 0); + a = 0; + } + //System.out.println(plugin.getName()+": "+a); + TabHolder47 t = tabs.get(a); + t.tabs[y][x] = msg; + t.tabPings[y][x] = ping; + t.tabGameProfiles[y][x] = gameProfile; + t.maxh = TabAPI.getHorizSize(47); + t.maxv = Math.max(x + 1, t.maxv); + } +} diff --git a/TabAPI/src/main/resources/plugin.yml b/TabAPI/src/main/resources/plugin.yml index 44dffc5..7b9cce8 100644 --- a/TabAPI/src/main/resources/plugin.yml +++ b/TabAPI/src/main/resources/plugin.yml @@ -1,6 +1,6 @@ name: TabAPI main: org.mcsg.double0negative.tabapi.TabAPI -version: B 0.1.15 +version: B 0.1.17 authors: [Double0negative, MCSG] depend: [ProtocolLib]