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.
+ * 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]