diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index 0dfd8437..81ee66d9 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -11,7 +11,7 @@ Paste in the version information from the SubServers app in question here. To ge Here you can write about what happened that shouldn't have. If you have any errors in your console related to what happened, you should also paste those here. ### How It Happened -Tell us step-by-step how to recreate the problem. This step is vital for us to determine whether or not the problem happens to everyone else too. +Tell us step-by-step how to recreate the problem. This step is vital for us to determine whether the problem happens to everyone else too. ### Additional Information Here you can provide any extra details you may think useful for solving the problem. diff --git a/LICENSE b/LICENSE index 9cb31e6d..ad60f388 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright (C) 2015-2021 ME1312 + Copyright (C) 2015-2022 ME1312 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Library/Metrics.java b/SubServers.Bungee/common/src/net/ME1312/SubServers/Bungee/Library/Metrics.java similarity index 97% rename from SubServers.Sync/src/net/ME1312/SubServers/Sync/Library/Metrics.java rename to SubServers.Bungee/common/src/net/ME1312/SubServers/Bungee/Library/Metrics.java index da084e27..a56ac530 100644 --- a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Library/Metrics.java +++ b/SubServers.Bungee/common/src/net/ME1312/SubServers/Bungee/Library/Metrics.java @@ -1,6 +1,7 @@ -package net.ME1312.SubServers.Sync.Library; +package net.ME1312.SubServers.Bungee.Library; -import net.ME1312.SubServers.Sync.SubAPI; +import net.ME1312.SubServers.Bungee.BungeeAPI; +import net.ME1312.SubServers.Bungee.BungeeCommon; import gnu.trove.map.hash.TIntObjectHashMap; import net.md_5.bungee.api.ProxyServer; @@ -29,6 +30,9 @@ import java.util.logging.Level; import java.util.stream.Collectors; import java.util.zip.GZIPOutputStream; +/** + * SubServers BStats Metrics Implementation + */ public class Metrics { private final Plugin plugin; @@ -79,7 +83,6 @@ public class Metrics { logResponseStatusText); } - /** Loads the bStats configuration. */ private void loadConfig() throws IOException { File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats"); @@ -118,15 +121,6 @@ public class Metrics { } } - /** - * Adds a custom chart. - * - * @param chart The chart to add. - */ - public void addCustomChart(CustomChart chart) { - metricsBase.addCustomChart(chart); - } - private static final AdvancedPie PLAYER_VERSIONS; static { final int[] PROTOCOL_VERSIONS; @@ -169,20 +163,26 @@ public class Metrics { }); } - public void appendAppData() { - addCustomChart(PLAYER_VERSIONS); + /** + * Add subservers platform information as custom charts + */ + public Metrics addPlatformCharts() { + return addCustomChart(new SimplePie("subservers_version", () -> BungeeAPI.getInstance().getWrapperVersion().toString())).addCustomChart(PLAYER_VERSIONS); } - public void appendPluginData() { - addCustomChart(new SimplePie("subservers_version", () -> { - return SubAPI.getInstance().getWrapperVersion().toString(); - })); - addCustomChart(PLAYER_VERSIONS); + /** + * Adds a custom chart. + * + * @param chart The chart to add. + */ + public Metrics addCustomChart(CustomChart chart) { + metricsBase.addCustomChart(chart); + return this; } private void appendPlatformData(JsonObjectBuilder builder) { builder.appendField("playerAmount", plugin.getProxy().getOnlineCount()); - builder.appendField("managedServers", plugin.getProxy().getServers().size()); + builder.appendField("managedServers", ((BungeeCommon) plugin.getProxy()).getServersCopy().size()); builder.appendField("onlineMode", plugin.getProxy().getConfig().isOnlineMode() ? 1 : 0); builder.appendField("bungeecordVersion", plugin.getProxy().getVersion()); builder.appendField("javaVersion", System.getProperty("java.version")); @@ -199,7 +199,7 @@ public class Metrics { public static class MetricsBase { /** The version of the Metrics class. */ - public static final String METRICS_VERSION = "2.2.1"; + public static final String METRICS_VERSION = "3.0.0"; private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, task -> new Thread(task, "bStats-Metrics")); @@ -284,6 +284,7 @@ public class Metrics { this.logResponseStatusText = logResponseStatusText; checkRelocation(); if (enabled) { + // WARNING: Removing the option to opt-out will get your plugin banned from bStats startSubmitting(); } } @@ -420,9 +421,9 @@ public class Metrics { } } - public static class AdvancedBarChart extends CustomChart { + public static class DrilldownPie extends CustomChart { - private final Callable> callable; + private final Callable>> callable; /** * Class constructor. @@ -430,99 +431,33 @@ public class Metrics { * @param chartId The id of the chart. * @param callable The callable which is used to request the chart data. */ - public AdvancedBarChart(String chartId, Callable> callable) { + public DrilldownPie(String chartId, Callable>> callable) { super(chartId); this.callable = callable; } @Override - protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + public JsonObjectBuilder.JsonObject getChartData() throws Exception { JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); - Map map = callable.call(); + Map> map = callable.call(); if (map == null || map.isEmpty()) { // Null = skip the chart return null; } - boolean allSkipped = true; - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue().length == 0) { - // Skip this invalid - continue; + boolean reallyAllSkipped = true; + for (Map.Entry> entryValues : map.entrySet()) { + JsonObjectBuilder valueBuilder = new JsonObjectBuilder(); + boolean allSkipped = true; + for (Map.Entry valueEntry : map.get(entryValues.getKey()).entrySet()) { + valueBuilder.appendField(valueEntry.getKey(), valueEntry.getValue()); + allSkipped = false; } - allSkipped = false; - valuesBuilder.appendField(entry.getKey(), entry.getValue()); - } - if (allSkipped) { - // Null = skip the chart - return null; - } - return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); - } - } - - public static class SimpleBarChart extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public SimpleBarChart(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObjectBuilder.JsonObject getChartData() throws Exception { - JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - for (Map.Entry entry : map.entrySet()) { - valuesBuilder.appendField(entry.getKey(), new int[] {entry.getValue()}); - } - return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); - } - } - - public static class MultiLineChart extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public MultiLineChart(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObjectBuilder.JsonObject getChartData() throws Exception { - JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - boolean allSkipped = true; - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue() == 0) { - // Skip this invalid - continue; + if (!allSkipped) { + reallyAllSkipped = false; + valuesBuilder.appendField(entryValues.getKey(), valueBuilder.build()); } - allSkipped = false; - valuesBuilder.appendField(entry.getKey(), entry.getValue()); } - if (allSkipped) { + if (reallyAllSkipped) { // Null = skip the chart return null; } @@ -570,6 +505,76 @@ public class Metrics { } } + public static class MultiLineChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public MultiLineChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + // Skip this invalid + continue; + } + allSkipped = false; + valuesBuilder.appendField(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class SimpleBarChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SimpleBarChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + for (Map.Entry entry : map.entrySet()) { + valuesBuilder.appendField(entry.getKey(), new int[] {entry.getValue()}); + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + public abstract static class CustomChart { private final String chartId; @@ -604,32 +609,6 @@ public class Metrics { protected abstract JsonObjectBuilder.JsonObject getChartData() throws Exception; } - public static class SingleLineChart extends CustomChart { - - private final Callable callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public SingleLineChart(String chartId, Callable callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObjectBuilder.JsonObject getChartData() throws Exception { - int value = callable.call(); - if (value == 0) { - // Null = skip the chart - return null; - } - return new JsonObjectBuilder().appendField("value", value).build(); - } - } - public static class SimplePie extends CustomChart { private final Callable callable; @@ -656,9 +635,9 @@ public class Metrics { } } - public static class DrilldownPie extends CustomChart { + public static class AdvancedBarChart extends CustomChart { - private final Callable>> callable; + private final Callable> callable; /** * Class constructor. @@ -666,33 +645,29 @@ public class Metrics { * @param chartId The id of the chart. * @param callable The callable which is used to request the chart data. */ - public DrilldownPie(String chartId, Callable>> callable) { + public AdvancedBarChart(String chartId, Callable> callable) { super(chartId); this.callable = callable; } @Override - public JsonObjectBuilder.JsonObject getChartData() throws Exception { + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); - Map> map = callable.call(); + Map map = callable.call(); if (map == null || map.isEmpty()) { // Null = skip the chart return null; } - boolean reallyAllSkipped = true; - for (Map.Entry> entryValues : map.entrySet()) { - JsonObjectBuilder valueBuilder = new JsonObjectBuilder(); - boolean allSkipped = true; - for (Map.Entry valueEntry : map.get(entryValues.getKey()).entrySet()) { - valueBuilder.appendField(valueEntry.getKey(), valueEntry.getValue()); - allSkipped = false; - } - if (!allSkipped) { - reallyAllSkipped = false; - valuesBuilder.appendField(entryValues.getKey(), valueBuilder.build()); + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue().length == 0) { + // Skip this invalid + continue; } + allSkipped = false; + valuesBuilder.appendField(entry.getKey(), entry.getValue()); } - if (reallyAllSkipped) { + if (allSkipped) { // Null = skip the chart return null; } @@ -700,6 +675,32 @@ public class Metrics { } } + public static class SingleLineChart extends CustomChart { + + private final Callable callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SingleLineChart(String chartId, Callable callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + int value = callable.call(); + if (value == 0) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("value", value).build(); + } + } + /** * An extremely simple JSON builder. * @@ -905,4 +906,4 @@ public class Metrics { } } } -} \ No newline at end of file +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Library/SubEvent.java b/SubServers.Bungee/common/src/net/ME1312/SubServers/Bungee/Library/SubEvent.java similarity index 100% rename from SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Library/SubEvent.java rename to SubServers.Bungee/common/src/net/ME1312/SubServers/Bungee/Library/SubEvent.java diff --git a/SubServers.Bungee/pom.xml b/SubServers.Bungee/pom.xml index 2b9caf17..4344035b 100644 --- a/SubServers.Bungee/pom.xml +++ b/SubServers.Bungee/pom.xml @@ -34,7 +34,7 @@ net.ME1312.SubData Server - 22w11a + 22w11c compile diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Library/Compatibility/JNA.java b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Library/Compatibility/JNA.java index dc8f7609..63d05cc1 100644 --- a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Library/Compatibility/JNA.java +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Library/Compatibility/JNA.java @@ -4,12 +4,16 @@ package net.ME1312.SubServers.Bungee.Library.Compatibility; import net.ME1312.SubServers.Bungee.SubAPI; import com.google.common.io.Resources; +import net.md_5.bungee.api.ProxyServer; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.net.URL; import java.net.URLClassLoader; +import java.util.logging.Logger; + +import static java.util.logging.Level.SEVERE; /** * JNA Library Loader Class @@ -29,12 +33,13 @@ public class JNA { public static ClassLoader get() { if (JNA == null) { boolean announced = false; + Logger log = ProxyServer.getInstance().getLogger(); File library = new File(SubAPI.getInstance().getInternals().dir, "SubServers/Cache/Libraries"); File jna = new File(library, "jna-" + JNA_VERSION + ".jar"); jna.getParentFile().mkdirs(); if (!jna.exists()) { announced = true; - System.out.println(">> Downloading JNA Library v" + JNA_VERSION); + log.info(">> Downloading JNA v" + JNA_VERSION); try (FileOutputStream fin = new FileOutputStream(jna)) { Resources.copy(new URL(JNA_DOWNLOAD.replace("$1", "jna")), fin); } catch (Throwable e) { @@ -45,7 +50,7 @@ public class JNA { File platform = new File(library, "jna-platform-" + JNA_VERSION + ".jar"); platform.getParentFile().mkdirs(); if (!platform.exists()) { - if (!announced) System.out.println(">> Downloading JNA Library v" + JNA_VERSION); + if (!announced) log.info(">> Downloading JNA platform v" + JNA_VERSION); announced = true; try (FileOutputStream fin = new FileOutputStream(platform)) { Resources.copy(new URL(JNA_DOWNLOAD.replace("$1", "jna-platform")), fin); @@ -55,16 +60,14 @@ public class JNA { } } if (jna.exists() && platform.exists()) { - if (announced) System.out.println(">> Loading JNA Library"); + if (announced) log.info(">> JNA download complete"); try { JNA = new URLClassLoader(new URL[]{jna.toURI().toURL(), platform.toURI().toURL()}); } catch (Throwable e) { - System.out.println(">> Could not load JNA Library:"); - e.printStackTrace(); + log.log(SEVERE, ">> Couldn't load JNA:", e); } } else { - System.out.println(">> Could not load JNA Library:"); - new FileNotFoundException().printStackTrace(); + log.log(SEVERE, ">> Couldn't load JNA:", new FileNotFoundException()); } } return JNA; diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Library/Metrics.java b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Library/Metrics.java deleted file mode 100644 index 7feff2ed..00000000 --- a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Library/Metrics.java +++ /dev/null @@ -1,917 +0,0 @@ -package net.ME1312.SubServers.Bungee.Library; - -import net.ME1312.SubData.Server.DataServer; -import net.ME1312.SubServers.Bungee.BungeeCommon; -import net.ME1312.SubServers.Bungee.SubAPI; - -import gnu.trove.map.hash.TIntObjectHashMap; -import net.md_5.bungee.api.ProxyServer; -import net.md_5.bungee.api.connection.ProxiedPlayer; -import net.md_5.bungee.api.plugin.Plugin; -import net.md_5.bungee.config.Configuration; -import net.md_5.bungee.config.ConfigurationProvider; -import net.md_5.bungee.config.YamlConfiguration; -import net.md_5.bungee.protocol.ProtocolConstants; - -import javax.net.ssl.HttpsURLConnection; -import java.io.*; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.concurrent.Callable; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import java.util.function.Supplier; -import java.util.logging.Level; -import java.util.stream.Collectors; -import java.util.zip.GZIPOutputStream; - -public class Metrics { - - private final Plugin plugin; - - private final MetricsBase metricsBase; - - private boolean enabled; - - private String serverUUID; - - private boolean logErrors = false; - - private boolean logSentData; - - private boolean logResponseStatusText; - - /** - * Creates a new Metrics instance. - * - * @param plugin Your plugin instance. - * @param serviceId The id of the service. It can be found at What is my plugin id? - */ - public Metrics(Plugin plugin, int serviceId) { - this.plugin = plugin; - try { - loadConfig(); - } catch (IOException e) { - // Failed to load configuration - plugin.getLogger().log(Level.WARNING, "Failed to load bStats config!", e); - metricsBase = null; - return; - } - metricsBase = - new MetricsBase( - "bungeecord", - serverUUID, - serviceId, - enabled, - this::appendPlatformData, - this::appendServiceData, - null, - () -> true, - (message, error) -> this.plugin.getLogger().log(Level.WARNING, message, error), - (message) -> this.plugin.getLogger().log(Level.INFO, message), - logErrors, - logSentData, - logResponseStatusText); - } - - - /** Loads the bStats configuration. */ - private void loadConfig() throws IOException { - File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats"); - bStatsFolder.mkdirs(); - File configFile = new File(bStatsFolder, "config.yml"); - if (!configFile.exists()) { - writeFile( - configFile, - "# bStats (https://bStats.org) collects some basic information for plugin authors, like how", - "# many people use their plugin and their total player count. It's recommended to keep bStats", - "# enabled, but if you're not comfortable with this, you can turn this setting off. There is no", - "# performance penalty associated with having metrics enabled, and data sent to bStats is fully", - "# anonymous.", - "enabled: true", - "serverUuid: \"" + UUID.randomUUID() + "\"", - "logFailedRequests: false", - "logSentData: false", - "logResponseStatusText: false"); - } - Configuration configuration = - ConfigurationProvider.getProvider(YamlConfiguration.class).load(configFile); - // Load configuration - enabled = configuration.getBoolean("enabled", true); - serverUUID = configuration.getString("serverUuid"); - logErrors = configuration.getBoolean("logFailedRequests", false); - logSentData = configuration.getBoolean("logSentData", false); - logResponseStatusText = configuration.getBoolean("logResponseStatusText", false); - } - - private void writeFile(File file, String... lines) throws IOException { - try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file))) { - for (String line : lines) { - bufferedWriter.write(line); - bufferedWriter.newLine(); - } - } - } - - /** - * Adds a custom chart. - * - * @param chart The chart to add. - */ - public void addCustomChart(CustomChart chart) { - metricsBase.addCustomChart(chart); - } - - private static final AdvancedPie PLAYER_VERSIONS; - static { - final int[] PROTOCOL_VERSIONS; - final String[] PROTOCOL_NAMES; - { - TIntObjectHashMap protocols = new TIntObjectHashMap(); - try { - for (Field f : ProtocolConstants.class.getDeclaredFields()) { - int fm = f.getModifiers(); - if (Modifier.isPublic(fm) && Modifier.isStatic(fm) && Modifier.isFinal(fm) && f.getType() == int.class && f.getName().startsWith("MINECRAFT_")) { - protocols.put(f.getInt(null), f.getName().substring(10).replace('_', '.')); - } - } - } catch (Throwable e) { - e.printStackTrace(); - } - PROTOCOL_VERSIONS = protocols.keys(); - PROTOCOL_NAMES = new String[PROTOCOL_VERSIONS.length]; - - Arrays.sort(PROTOCOL_VERSIONS); - for (int i = 0; i < PROTOCOL_VERSIONS.length; ++i) { - PROTOCOL_NAMES[i] = protocols.get(PROTOCOL_VERSIONS[i]); - } - } - - PLAYER_VERSIONS = new AdvancedPie("player_versions", () -> { - int[] players = new int[PROTOCOL_VERSIONS.length]; - for (ProxiedPlayer player : ProxyServer.getInstance().getPlayers()) { - int i = Arrays.binarySearch(PROTOCOL_VERSIONS, player.getPendingConnection().getVersion()); - if (i != -1) { - ++players[i]; - } - } - - HashMap map = new HashMap(); - for (int i = 0; i < PROTOCOL_NAMES.length; ++i) if (players[i] != 0) { - map.put(PROTOCOL_NAMES[i], players[i]); - } - return map; - }); - } - - public void appendAppData() { - addCustomChart(new SingleLineChart("managed_hosts", () -> { - return SubAPI.getInstance().getHosts().size(); - })); - addCustomChart(new SingleLineChart("subdata_connected", () -> { - DataServer subdata = SubAPI.getInstance().getSubDataNetwork(); - return (subdata != null)? subdata.getClients().size() : 0; - })); - addCustomChart(PLAYER_VERSIONS); - } - - public void appendPluginData() { - addCustomChart(new SimplePie("subservers_version", () -> { - return SubAPI.getInstance().getWrapperVersion().toString(); - })); - addCustomChart(PLAYER_VERSIONS); - } - - private void appendPlatformData(JsonObjectBuilder builder) { - builder.appendField("playerAmount", plugin.getProxy().getOnlineCount()); - builder.appendField("managedServers", ((BungeeCommon) plugin.getProxy()).getServersCopy().size()); - builder.appendField("onlineMode", plugin.getProxy().getConfig().isOnlineMode() ? 1 : 0); - builder.appendField("bungeecordVersion", plugin.getProxy().getVersion()); - builder.appendField("javaVersion", System.getProperty("java.version")); - builder.appendField("osName", System.getProperty("os.name")); - builder.appendField("osArch", System.getProperty("os.arch")); - builder.appendField("osVersion", System.getProperty("os.version")); - builder.appendField("coreCount", Runtime.getRuntime().availableProcessors()); - } - - private void appendServiceData(JsonObjectBuilder builder) { - builder.appendField("pluginVersion", plugin.getDescription().getVersion()); - } - - public static class MetricsBase { - - /** The version of the Metrics class. */ - public static final String METRICS_VERSION = "2.2.1"; - - private static final ScheduledExecutorService scheduler = - Executors.newScheduledThreadPool(1, task -> new Thread(task, "bStats-Metrics")); - - private static final String REPORT_URL = "https://bStats.org/api/v2/data/%s"; - - private final String platform; - - private final String serverUuid; - - private final int serviceId; - - private final Consumer appendPlatformDataConsumer; - - private final Consumer appendServiceDataConsumer; - - private final Consumer submitTaskConsumer; - - private final Supplier checkServiceEnabledSupplier; - - private final BiConsumer errorLogger; - - private final Consumer infoLogger; - - private final boolean logErrors; - - private final boolean logSentData; - - private final boolean logResponseStatusText; - - private final Set customCharts = new HashSet<>(); - - private final boolean enabled; - - /** - * Creates a new MetricsBase class instance. - * - * @param platform The platform of the service. - * @param serviceId The id of the service. - * @param serverUuid The server uuid. - * @param enabled Whether or not data sending is enabled. - * @param appendPlatformDataConsumer A consumer that receives a {@code JsonObjectBuilder} and - * appends all platform-specific data. - * @param appendServiceDataConsumer A consumer that receives a {@code JsonObjectBuilder} and - * appends all service-specific data. - * @param submitTaskConsumer A consumer that takes a runnable with the submit task. This can be - * used to delegate the data collection to a another thread to prevent errors caused by - * concurrency. Can be {@code null}. - * @param checkServiceEnabledSupplier A supplier to check if the service is still enabled. - * @param errorLogger A consumer that accepts log message and an error. - * @param infoLogger A consumer that accepts info log messages. - * @param logErrors Whether or not errors should be logged. - * @param logSentData Whether or not the sent data should be logged. - * @param logResponseStatusText Whether or not the response status text should be logged. - */ - public MetricsBase( - String platform, - String serverUuid, - int serviceId, - boolean enabled, - Consumer appendPlatformDataConsumer, - Consumer appendServiceDataConsumer, - Consumer submitTaskConsumer, - Supplier checkServiceEnabledSupplier, - BiConsumer errorLogger, - Consumer infoLogger, - boolean logErrors, - boolean logSentData, - boolean logResponseStatusText) { - this.platform = platform; - this.serverUuid = serverUuid; - this.serviceId = serviceId; - this.enabled = enabled; - this.appendPlatformDataConsumer = appendPlatformDataConsumer; - this.appendServiceDataConsumer = appendServiceDataConsumer; - this.submitTaskConsumer = submitTaskConsumer; - this.checkServiceEnabledSupplier = checkServiceEnabledSupplier; - this.errorLogger = errorLogger; - this.infoLogger = infoLogger; - this.logErrors = logErrors; - this.logSentData = logSentData; - this.logResponseStatusText = logResponseStatusText; - checkRelocation(); - if (enabled) { - startSubmitting(); - } - } - - public void addCustomChart(CustomChart chart) { - this.customCharts.add(chart); - } - - private void startSubmitting() { - final Runnable submitTask = - () -> { - if (!enabled || !checkServiceEnabledSupplier.get()) { - // Submitting data or service is disabled - scheduler.shutdown(); - return; - } - if (submitTaskConsumer != null) { - submitTaskConsumer.accept(this::submitData); - } else { - this.submitData(); - } - }; - // Many servers tend to restart at a fixed time at xx:00 which causes an uneven distribution - // of requests on the - // bStats backend. To circumvent this problem, we introduce some randomness into the initial - // and second delay. - // WARNING: You must not modify and part of this Metrics class, including the submit delay or - // frequency! - // WARNING: Modifying this code will get your plugin banned on bStats. Just don't do it! - long initialDelay = (long) (1000 * 60 * (3 + Math.random() * 3)); - long secondDelay = (long) (1000 * 60 * (Math.random() * 30)); - scheduler.schedule(submitTask, initialDelay, TimeUnit.MILLISECONDS); - scheduler.scheduleAtFixedRate( - submitTask, initialDelay + secondDelay, 1000 * 60 * 30, TimeUnit.MILLISECONDS); - } - - private void submitData() { - final JsonObjectBuilder baseJsonBuilder = new JsonObjectBuilder(); - appendPlatformDataConsumer.accept(baseJsonBuilder); - final JsonObjectBuilder serviceJsonBuilder = new JsonObjectBuilder(); - appendServiceDataConsumer.accept(serviceJsonBuilder); - JsonObjectBuilder.JsonObject[] chartData = - customCharts.stream() - .map(customChart -> customChart.getRequestJsonObject(errorLogger, logErrors)) - .filter(Objects::nonNull) - .toArray(JsonObjectBuilder.JsonObject[]::new); - serviceJsonBuilder.appendField("id", serviceId); - serviceJsonBuilder.appendField("customCharts", chartData); - baseJsonBuilder.appendField("service", serviceJsonBuilder.build()); - baseJsonBuilder.appendField("serverUUID", serverUuid); - baseJsonBuilder.appendField("metricsVersion", METRICS_VERSION); - JsonObjectBuilder.JsonObject data = baseJsonBuilder.build(); - scheduler.execute( - () -> { - try { - // Send the data - sendData(data); - } catch (Exception e) { - // Something went wrong! :( - if (logErrors) { - errorLogger.accept("Could not submit bStats metrics data", e); - } - } - }); - } - - private void sendData(JsonObjectBuilder.JsonObject data) throws Exception { - if (logSentData) { - infoLogger.accept("Sent bStats metrics data: " + data.toString()); - } - String url = String.format(REPORT_URL, platform); - HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection(); - // Compress the data to save bandwidth - byte[] compressedData = compress(data.toString()); - connection.setRequestMethod("POST"); - connection.addRequestProperty("Accept", "application/json"); - connection.addRequestProperty("Connection", "close"); - connection.addRequestProperty("Content-Encoding", "gzip"); - connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length)); - connection.setRequestProperty("Content-Type", "application/json"); - connection.setRequestProperty("User-Agent", "Metrics-Service/1"); - connection.setDoOutput(true); - try (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) { - outputStream.write(compressedData); - } - StringBuilder builder = new StringBuilder(); - try (BufferedReader bufferedReader = - new BufferedReader(new InputStreamReader(connection.getInputStream()))) { - String line; - while ((line = bufferedReader.readLine()) != null) { - builder.append(line); - } - } - if (logResponseStatusText) { - infoLogger.accept("Sent data to bStats and received response: " + builder); - } - } - - /** Checks that the class was properly relocated. */ - private void checkRelocation() { - // You can use the property to disable the check in your test environment - if (System.getProperty("bstats.relocatecheck") == null - || !System.getProperty("bstats.relocatecheck").equals("false")) { - // Maven's Relocate is clever and changes strings, too. So we have to use this little - // "trick" ... :D - final String defaultPackage = - new String(new byte[] {'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's'}); - final String examplePackage = - new String(new byte[] {'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'}); - // We want to make sure no one just copy & pastes the example and uses the wrong package - // names - if (MetricsBase.class.getPackage().getName().startsWith(defaultPackage) - || MetricsBase.class.getPackage().getName().startsWith(examplePackage)) { - throw new IllegalStateException("bStats Metrics class has not been relocated correctly!"); - } - } - } - - /** - * Gzips the given string. - * - * @param str The string to gzip. - * @return The gzipped string. - */ - private static byte[] compress(final String str) throws IOException { - if (str == null) { - return null; - } - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - try (GZIPOutputStream gzip = new GZIPOutputStream(outputStream)) { - gzip.write(str.getBytes(StandardCharsets.UTF_8)); - } - return outputStream.toByteArray(); - } - } - - public static class AdvancedBarChart extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public AdvancedBarChart(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObjectBuilder.JsonObject getChartData() throws Exception { - JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - boolean allSkipped = true; - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue().length == 0) { - // Skip this invalid - continue; - } - allSkipped = false; - valuesBuilder.appendField(entry.getKey(), entry.getValue()); - } - if (allSkipped) { - // Null = skip the chart - return null; - } - return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); - } - } - - public static class SimpleBarChart extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public SimpleBarChart(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObjectBuilder.JsonObject getChartData() throws Exception { - JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - for (Map.Entry entry : map.entrySet()) { - valuesBuilder.appendField(entry.getKey(), new int[] {entry.getValue()}); - } - return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); - } - } - - public static class MultiLineChart extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public MultiLineChart(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObjectBuilder.JsonObject getChartData() throws Exception { - JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - boolean allSkipped = true; - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue() == 0) { - // Skip this invalid - continue; - } - allSkipped = false; - valuesBuilder.appendField(entry.getKey(), entry.getValue()); - } - if (allSkipped) { - // Null = skip the chart - return null; - } - return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); - } - } - - public static class AdvancedPie extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public AdvancedPie(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObjectBuilder.JsonObject getChartData() throws Exception { - JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - boolean allSkipped = true; - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue() == 0) { - // Skip this invalid - continue; - } - allSkipped = false; - valuesBuilder.appendField(entry.getKey(), entry.getValue()); - } - if (allSkipped) { - // Null = skip the chart - return null; - } - return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); - } - } - - public abstract static class CustomChart { - - private final String chartId; - - protected CustomChart(String chartId) { - if (chartId == null) { - throw new IllegalArgumentException("chartId must not be null"); - } - this.chartId = chartId; - } - - public JsonObjectBuilder.JsonObject getRequestJsonObject( - BiConsumer errorLogger, boolean logErrors) { - JsonObjectBuilder builder = new JsonObjectBuilder(); - builder.appendField("chartId", chartId); - try { - JsonObjectBuilder.JsonObject data = getChartData(); - if (data == null) { - // If the data is null we don't send the chart. - return null; - } - builder.appendField("data", data); - } catch (Throwable t) { - if (logErrors) { - errorLogger.accept("Failed to get data for custom chart with id " + chartId, t); - } - return null; - } - return builder.build(); - } - - protected abstract JsonObjectBuilder.JsonObject getChartData() throws Exception; - } - - public static class SingleLineChart extends CustomChart { - - private final Callable callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public SingleLineChart(String chartId, Callable callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObjectBuilder.JsonObject getChartData() throws Exception { - int value = callable.call(); - if (value == 0) { - // Null = skip the chart - return null; - } - return new JsonObjectBuilder().appendField("value", value).build(); - } - } - - public static class SimplePie extends CustomChart { - - private final Callable callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public SimplePie(String chartId, Callable callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObjectBuilder.JsonObject getChartData() throws Exception { - String value = callable.call(); - if (value == null || value.isEmpty()) { - // Null = skip the chart - return null; - } - return new JsonObjectBuilder().appendField("value", value).build(); - } - } - - public static class DrilldownPie extends CustomChart { - - private final Callable>> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public DrilldownPie(String chartId, Callable>> callable) { - super(chartId); - this.callable = callable; - } - - @Override - public JsonObjectBuilder.JsonObject getChartData() throws Exception { - JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); - Map> map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - boolean reallyAllSkipped = true; - for (Map.Entry> entryValues : map.entrySet()) { - JsonObjectBuilder valueBuilder = new JsonObjectBuilder(); - boolean allSkipped = true; - for (Map.Entry valueEntry : map.get(entryValues.getKey()).entrySet()) { - valueBuilder.appendField(valueEntry.getKey(), valueEntry.getValue()); - allSkipped = false; - } - if (!allSkipped) { - reallyAllSkipped = false; - valuesBuilder.appendField(entryValues.getKey(), valueBuilder.build()); - } - } - if (reallyAllSkipped) { - // Null = skip the chart - return null; - } - return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); - } - } - - /** - * An extremely simple JSON builder. - * - *

While this class is neither feature-rich nor the most performant one, it's sufficient enough - * for its use-case. - */ - public static class JsonObjectBuilder { - - private StringBuilder builder = new StringBuilder(); - - private boolean hasAtLeastOneField = false; - - public JsonObjectBuilder() { - builder.append("{"); - } - - /** - * Appends a null field to the JSON. - * - * @param key The key of the field. - * @return A reference to this object. - */ - public JsonObjectBuilder appendNull(String key) { - appendFieldUnescaped(key, "null"); - return this; - } - - /** - * Appends a string field to the JSON. - * - * @param key The key of the field. - * @param value The value of the field. - * @return A reference to this object. - */ - public JsonObjectBuilder appendField(String key, String value) { - if (value == null) { - throw new IllegalArgumentException("JSON value must not be null"); - } - appendFieldUnescaped(key, "\"" + escape(value) + "\""); - return this; - } - - /** - * Appends an integer field to the JSON. - * - * @param key The key of the field. - * @param value The value of the field. - * @return A reference to this object. - */ - public JsonObjectBuilder appendField(String key, int value) { - appendFieldUnescaped(key, String.valueOf(value)); - return this; - } - - /** - * Appends an object to the JSON. - * - * @param key The key of the field. - * @param object The object. - * @return A reference to this object. - */ - public JsonObjectBuilder appendField(String key, JsonObject object) { - if (object == null) { - throw new IllegalArgumentException("JSON object must not be null"); - } - appendFieldUnescaped(key, object.toString()); - return this; - } - - /** - * Appends a string array to the JSON. - * - * @param key The key of the field. - * @param values The string array. - * @return A reference to this object. - */ - public JsonObjectBuilder appendField(String key, String[] values) { - if (values == null) { - throw new IllegalArgumentException("JSON values must not be null"); - } - String escapedValues = - Arrays.stream(values) - .map(value -> "\"" + escape(value) + "\"") - .collect(Collectors.joining(",")); - appendFieldUnescaped(key, "[" + escapedValues + "]"); - return this; - } - - /** - * Appends an integer array to the JSON. - * - * @param key The key of the field. - * @param values The integer array. - * @return A reference to this object. - */ - public JsonObjectBuilder appendField(String key, int[] values) { - if (values == null) { - throw new IllegalArgumentException("JSON values must not be null"); - } - String escapedValues = - Arrays.stream(values).mapToObj(String::valueOf).collect(Collectors.joining(",")); - appendFieldUnescaped(key, "[" + escapedValues + "]"); - return this; - } - - /** - * Appends an object array to the JSON. - * - * @param key The key of the field. - * @param values The integer array. - * @return A reference to this object. - */ - public JsonObjectBuilder appendField(String key, JsonObject[] values) { - if (values == null) { - throw new IllegalArgumentException("JSON values must not be null"); - } - String escapedValues = - Arrays.stream(values).map(JsonObject::toString).collect(Collectors.joining(",")); - appendFieldUnescaped(key, "[" + escapedValues + "]"); - return this; - } - - /** - * Appends a field to the object. - * - * @param key The key of the field. - * @param escapedValue The escaped value of the field. - */ - private void appendFieldUnescaped(String key, String escapedValue) { - if (builder == null) { - throw new IllegalStateException("JSON has already been built"); - } - if (key == null) { - throw new IllegalArgumentException("JSON key must not be null"); - } - if (hasAtLeastOneField) { - builder.append(","); - } - builder.append("\"").append(escape(key)).append("\":").append(escapedValue); - hasAtLeastOneField = true; - } - - /** - * Builds the JSON string and invalidates this builder. - * - * @return The built JSON string. - */ - public JsonObject build() { - if (builder == null) { - throw new IllegalStateException("JSON has already been built"); - } - JsonObject object = new JsonObject(builder.append("}").toString()); - builder = null; - return object; - } - - /** - * Escapes the given string like stated in https://www.ietf.org/rfc/rfc4627.txt. - * - *

This method escapes only the necessary characters '"', '\'. and '\u0000' - '\u001F'. - * Compact escapes are not used (e.g., '\n' is escaped as "\u000a" and not as "\n"). - * - * @param value The value to escape. - * @return The escaped value. - */ - private static String escape(String value) { - final StringBuilder builder = new StringBuilder(); - for (int i = 0; i < value.length(); i++) { - char c = value.charAt(i); - if (c == '"') { - builder.append("\\\""); - } else if (c == '\\') { - builder.append("\\\\"); - } else if (c <= '\u000F') { - builder.append("\\u000").append(Integer.toHexString(c)); - } else if (c <= '\u001F') { - builder.append("\\u00").append(Integer.toHexString(c)); - } else { - builder.append(c); - } - } - return builder.toString(); - } - - /** - * A super simple representation of a JSON object. - * - *

This class only exists to make methods of the {@link JsonObjectBuilder} type-safe and not - * allow a raw string inputs for methods like {@link JsonObjectBuilder#appendField(String, - * JsonObject)}. - */ - public static class JsonObject { - - private final String value; - - private JsonObject(String value) { - this.value = value; - } - - @Override - public String toString() { - return value; - } - } - } -} \ No newline at end of file diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/SubProxy.java b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/SubProxy.java index a6614bc2..f1266a3e 100644 --- a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/SubProxy.java +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/SubProxy.java @@ -731,7 +731,14 @@ public final class SubProxy extends BungeeCommon implements Listener { if (getReconnectHandler() != null && getReconnectHandler().getClass().equals(SmartFallback.class)) setReconnectHandler(new SmartFallback(config.get().getMap("Settings").getMap("Smart-Fallback", new ObjectMap<>()))); // Re-initialize Smart Fallback - if (plugin != null) new Metrics(plugin, 1406).appendAppData(); + if (plugin != null) Try.none.run(() -> new Metrics(plugin, 1406) + .addCustomChart(new Metrics.SingleLineChart("managed_hosts", () -> { + return hosts.size(); + })).addCustomChart(new Metrics.SingleLineChart("subdata_connected", () -> { + final SubDataServer subdata = this.subdata; + return (subdata != null)? subdata.getClients().size() : 0; + })).addCustomChart(Util.reflect(Metrics.class.getDeclaredField("PLAYER_VERSIONS"), null)) + ); new Timer("SubServers.Bungee::Routine_Update_Check").schedule(new TimerTask() { @SuppressWarnings("unchecked") @Override diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubAddHostEvent.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubAddHostEvent.java index b986a61e..423cbf61 100644 --- a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubAddHostEvent.java +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubAddHostEvent.java @@ -22,6 +22,7 @@ public class SubAddHostEvent extends Event implements SubEvent { * @param host Host to be added */ public SubAddHostEvent(UUID player, String host) { + super(true); Util.nullpo(host); this.player = player; this.host = host; diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubAddProxyEvent.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubAddProxyEvent.java index 64d7987a..fedb4ec4 100644 --- a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubAddProxyEvent.java +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubAddProxyEvent.java @@ -18,6 +18,7 @@ public class SubAddProxyEvent extends Event implements SubEvent { * @param proxy Host Being Added */ public SubAddProxyEvent(String proxy) { + super(true); Util.nullpo(proxy); this.proxy = proxy; } diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubAddServerEvent.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubAddServerEvent.java index 9826bde9..3950892e 100644 --- a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubAddServerEvent.java +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubAddServerEvent.java @@ -23,6 +23,7 @@ public class SubAddServerEvent extends Event implements SubEvent { * @param server Server Starting */ public SubAddServerEvent(UUID player, String host, String server) { + super(true); Util.nullpo(server); this.player = player; this.host = host; diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubCreateEvent.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubCreateEvent.java index 75c2a6b5..587fd434 100644 --- a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubCreateEvent.java +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubCreateEvent.java @@ -36,6 +36,7 @@ public class SubCreateEvent extends Event implements SubEvent { * @param port Server Port Number */ public SubCreateEvent(UUID player, String host, String name, String template, Version version, int port, boolean update) { + super(true); Util.nullpo(host, name, template, port); this.player = player; this.update = update; diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubCreatedEvent.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubCreatedEvent.java index 46264b8e..e91b8f24 100644 --- a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubCreatedEvent.java +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubCreatedEvent.java @@ -37,6 +37,7 @@ public class SubCreatedEvent extends Event implements SubEvent { * @param port Server Port Number */ public SubCreatedEvent(UUID player, String host, String name, String template, Version version, int port, boolean update, boolean success) { + super(true); Util.nullpo(host, name, template, port); this.player = player; this.success = success; diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubEditServerEvent.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubEditServerEvent.java index 1b684131..8bc2cc12 100644 --- a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubEditServerEvent.java +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubEditServerEvent.java @@ -28,6 +28,7 @@ public class SubEditServerEvent extends Event implements SubEvent { * @param edit Edit to make */ public SubEditServerEvent(UUID player, String server, Pair edit) { + super(true); Util.nullpo(server, edit); ObjectMap section = new ObjectMap(); section.set(".", edit.value()); diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubNetworkConnectEvent.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubNetworkConnectEvent.java index a347a971..211bfb8e 100644 --- a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubNetworkConnectEvent.java +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubNetworkConnectEvent.java @@ -17,6 +17,7 @@ public class SubNetworkConnectEvent extends Event implements SubEvent { * SubData Network Connect Event */ public SubNetworkConnectEvent(DataClient network) { + super(true); Util.nullpo(network); this.network = network; } diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubNetworkDisconnectEvent.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubNetworkDisconnectEvent.java index e646329a..33709789 100644 --- a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubNetworkDisconnectEvent.java +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubNetworkDisconnectEvent.java @@ -19,6 +19,7 @@ public class SubNetworkDisconnectEvent extends Event implements SubEvent { * SubData Network Disconnect Event */ public SubNetworkDisconnectEvent(DataClient network, DisconnectReason reason) { + super(true); Util.nullpo(network, reason); this.network = network; this.reason = reason; diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubRemoveHostEvent.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubRemoveHostEvent.java index 8df67b1a..0618e6d1 100644 --- a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubRemoveHostEvent.java +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubRemoveHostEvent.java @@ -22,6 +22,7 @@ public class SubRemoveHostEvent extends Event implements SubEvent { * @param host Server Starting */ public SubRemoveHostEvent(UUID player, String host) { + super(true); Util.nullpo(host); this.player = player; this.host = host; diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubRemoveProxyEvent.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubRemoveProxyEvent.java index 9e4fc5da..579b1a89 100644 --- a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubRemoveProxyEvent.java +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubRemoveProxyEvent.java @@ -18,6 +18,7 @@ public class SubRemoveProxyEvent extends Event implements SubEvent { * @param proxy Host Being Added */ public SubRemoveProxyEvent(String proxy) { + super(true); Util.nullpo(proxy); this.proxy = proxy; } diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubRemoveServerEvent.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubRemoveServerEvent.java index 8c87a537..4c80f8cf 100644 --- a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubRemoveServerEvent.java +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubRemoveServerEvent.java @@ -23,6 +23,7 @@ public class SubRemoveServerEvent extends Event implements SubEvent { * @param server Server Starting */ public SubRemoveServerEvent(UUID player, String host, String server) { + super(true); Util.nullpo(server); this.player = player; this.host = host; diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubSendCommandEvent.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubSendCommandEvent.java index ec895b47..7fd7b094 100644 --- a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubSendCommandEvent.java +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubSendCommandEvent.java @@ -26,6 +26,7 @@ public class SubSendCommandEvent extends Event implements SubEvent { * @param target Player that will send */ public SubSendCommandEvent(UUID player, String server, String command, UUID target) { + super(true); Util.nullpo(server, command); this.player = player; this.server = server; diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubStartEvent.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubStartEvent.java index 2450a397..0640b60f 100644 --- a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubStartEvent.java +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubStartEvent.java @@ -23,6 +23,7 @@ public class SubStartEvent extends Event implements SubEvent { * @param server Server Starting */ public SubStartEvent(UUID player, String server) { + super(true); Util.nullpo(server); this.player = player; this.server = server; diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubStartedEvent.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubStartedEvent.java index f76a021e..f1f12e9a 100644 --- a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubStartedEvent.java +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubStartedEvent.java @@ -19,6 +19,7 @@ public class SubStartedEvent extends Event implements SubEvent { * @param server Server that Started */ public SubStartedEvent(String server) { + super(true); Util.nullpo(server); this.server = server; } diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubStopEvent.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubStopEvent.java index 72427639..7a22a629 100644 --- a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubStopEvent.java +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubStopEvent.java @@ -25,6 +25,7 @@ public class SubStopEvent extends Event implements SubEvent { * @param force If it was a Forced Shutdown */ public SubStopEvent(UUID player, String server, boolean force) { + super(true); Util.nullpo(server, force); this.player = player; this.server = server; diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubStoppedEvent.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubStoppedEvent.java index f59235cb..88d4dbe9 100644 --- a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubStoppedEvent.java +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Event/SubStoppedEvent.java @@ -18,6 +18,7 @@ public class SubStoppedEvent extends Event implements SubEvent { * @param server Server that Stopped */ public SubStoppedEvent(String server) { + super(true); Util.nullpo(server); this.server = server; } diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Graphic/DefaultUIRenderer.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Graphic/DefaultUIRenderer.java index 58a87731..47806f81 100644 --- a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Graphic/DefaultUIRenderer.java +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Graphic/DefaultUIRenderer.java @@ -102,7 +102,7 @@ public class DefaultUIRenderer extends UIRenderer { public void hostMenu(final int page) { setDownloading(ChatColor.stripColor(plugin.api.getLang("SubServers", "Interface.Host-Menu.Title"))); - plugin.api.getHosts(hosts -> plugin.api.getGroups(groups -> { + plugin.api.getHosts(hosts -> plugin.api.getGroups(groups -> Bukkit.getScheduler().runTask(plugin, () -> { setDownloading(null); lastVisitedObjects[0] = null; lastPage = page; @@ -229,12 +229,12 @@ public class DefaultUIRenderer extends UIRenderer { Bukkit.getPlayer(player).openInventory(inv); open = true; - })); + }))); } public void hostAdmin(final String name) { setDownloading(ChatColor.stripColor(plugin.api.getLang("SubServers", "Interface.Host-Admin.Title").replace("$str$", name))); - plugin.api.getHost(name, host -> { + plugin.api.getHost(name, host -> Bukkit.getScheduler().runTask(plugin, () -> { windowHistory.add(() -> hostAdmin(name)); if (host == null) { if (hasHistory()) back(); @@ -342,7 +342,7 @@ public class DefaultUIRenderer extends UIRenderer { Bukkit.getPlayer(this.player).openInventory(inv); open = true; } - }); + })); } public void hostCreator(final CreatorOptions options) { @@ -350,7 +350,7 @@ public class DefaultUIRenderer extends UIRenderer { if (!options.init()) windowHistory.add(() -> hostCreator(options)); lastVisitedObjects[0] = options; - plugin.api.getHost(options.getHost(), host -> { + plugin.api.getHost(options.getHost(), host -> Bukkit.getScheduler().runTask(plugin, () -> { if (host == null || !host.isAvailable() || !host.isEnabled()) { lastVisitedObjects[0] = null; if (hasHistory()) back(); @@ -469,14 +469,14 @@ public class DefaultUIRenderer extends UIRenderer { Bukkit.getPlayer(player).openInventory(inv); open = true; } - }); + })); } public void hostCreatorTemplates(final int page, final CreatorOptions options) { setDownloading(ChatColor.stripColor(plugin.api.getLang("SubServers", "Interface.Host-Creator.Edit-Template.Title").replace("$str$", options.getHost()))); options.init(); lastVisitedObjects[0] = options; - plugin.api.getHost(options.getHost(), host -> { + plugin.api.getHost(options.getHost(), host -> Bukkit.getScheduler().runTask(plugin, () -> { if (host == null || !host.isAvailable() || !host.isEnabled()) { lastVisitedObjects[0] = null; if (hasHistory()) back(); @@ -582,12 +582,12 @@ public class DefaultUIRenderer extends UIRenderer { Bukkit.getPlayer(player).openInventory(inv); open = true; } - }); + })); } public void hostPlugin(final int page, final String name) { setDownloading(ChatColor.stripColor(plugin.api.getLang("SubServers", "Interface.Host-Plugin.Title").replace("$str$", name))); - plugin.api.getHost(name, host -> { + plugin.api.getHost(name, host -> Bukkit.getScheduler().runTask(plugin, () -> { windowHistory.add(() -> hostPlugin(page, name)); if (host == null) { if (hasHistory()) back(); @@ -690,12 +690,12 @@ public class DefaultUIRenderer extends UIRenderer { Bukkit.getPlayer(player).openInventory(inv); open = true; } - }); + })); } public void groupMenu(final int page) { setDownloading(ChatColor.stripColor(plugin.api.getLang("SubServers", "Interface.Group-Menu.Title"))); - plugin.api.getServers(servers -> { + plugin.api.getServers(servers -> Bukkit.getScheduler().runTask(plugin, () -> { setDownloading(null); lastVisitedObjects[0] = null; lastPage = page; @@ -822,14 +822,14 @@ public class DefaultUIRenderer extends UIRenderer { Bukkit.getPlayer(player).openInventory(inv); open = true; - }); + })); } public void serverMenu(final int page, final String host, final String group) { setDownloading(ChatColor.stripColor((host == null)?((group == null)?plugin.api.getLang("SubServers", "Interface.Server-Menu.Title"):((group.length() == 0)?plugin.api.getLang("SubServers", "Interface.Group-SubServer.Title-Ungrouped"):plugin.api.getLang("SubServers", "Interface.Group-SubServer.Title").replace("$str$", group))):plugin.api.getLang("SubServers", "Interface.Host-SubServer.Title").replace("$str$", host))); Value hostname = new Container(host); Value> servercontainer = new Container>(new LinkedList()); - Runnable renderer = () -> { + Runnable renderer = () -> Bukkit.getScheduler().runTask(plugin, () -> { setDownloading(null); lastPage = page; @@ -987,7 +987,7 @@ public class DefaultUIRenderer extends UIRenderer { Bukkit.getPlayer(player).openInventory(inv); open = true; - }; + }); if (host != null && host.length() > 0) { plugin.api.getHost(host, object -> { @@ -1018,7 +1018,7 @@ public class DefaultUIRenderer extends UIRenderer { public void serverAdmin(final String name) { setDownloading(ChatColor.stripColor(plugin.api.getLang("SubServers", "Interface.Server-Admin.Title").replace("$str$", name))); - BiConsumer renderer = (server, host) -> { + BiConsumer renderer = (server, host) -> Bukkit.getScheduler().runTask(plugin, () -> { setDownloading(null); lastVisitedObjects[0] = server; ItemStack block; @@ -1226,7 +1226,7 @@ public class DefaultUIRenderer extends UIRenderer { player.openInventory(inv); open = true; - }; + }); plugin.api.getServer(name, server -> { windowHistory.add(() -> serverAdmin(name)); @@ -1250,7 +1250,7 @@ public class DefaultUIRenderer extends UIRenderer { public void serverPlugin(final int page, final String name) { setDownloading(ChatColor.stripColor(plugin.api.getLang("SubServers", "Interface.SubServer-Plugin.Title").replace("$str$", name))); - plugin.api.getServer(name, server -> { + plugin.api.getServer(name, server -> Bukkit.getScheduler().runTask(plugin, () -> { windowHistory.add(() -> serverPlugin(page, name)); if (server == null) { if (hasHistory()) back(); @@ -1353,6 +1353,6 @@ public class DefaultUIRenderer extends UIRenderer { Bukkit.getPlayer(player).openInventory(inv); open = true; } - }); + })); } } \ No newline at end of file diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Library/Metrics.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Library/Metrics.java index 418ad18b..f8743855 100644 --- a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Library/Metrics.java +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Library/Metrics.java @@ -1,5 +1,7 @@ package net.ME1312.SubServers.Client.Bukkit.Library; +import net.ME1312.SubServers.Client.Bukkit.SubAPI; + import org.bukkit.Bukkit; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; @@ -23,6 +25,9 @@ import java.util.logging.Level; import java.util.stream.Collectors; import java.util.zip.GZIPOutputStream; +/** + * SubServers BStats Metrics Implementation + */ public class Metrics { private final Plugin plugin; @@ -86,13 +91,21 @@ public class Metrics { logResponseStatusText); } + /** + * Add subservers platform information as custom charts + */ + public Metrics addPlatformCharts() { + return addCustomChart(new SimplePie("subservers_version", () -> SubAPI.getInstance().getPluginVersion().toString())); + } + /** * Adds a custom chart. * * @param chart The chart to add. */ - public void addCustomChart(CustomChart chart) { + public Metrics addCustomChart(CustomChart chart) { metricsBase.addCustomChart(chart); + return this; } private void appendPlatformData(JsonObjectBuilder builder) { @@ -129,7 +142,7 @@ public class Metrics { public static class MetricsBase { /** The version of the Metrics class. */ - public static final String METRICS_VERSION = "2.2.1"; + public static final String METRICS_VERSION = "3.0.0"; private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, task -> new Thread(task, "bStats-Metrics")); @@ -214,6 +227,7 @@ public class Metrics { this.logResponseStatusText = logResponseStatusText; checkRelocation(); if (enabled) { + // WARNING: Removing the option to opt-out will get your plugin banned from bStats startSubmitting(); } } @@ -350,9 +364,9 @@ public class Metrics { } } - public static class AdvancedBarChart extends CustomChart { + public static class DrilldownPie extends CustomChart { - private final Callable> callable; + private final Callable>> callable; /** * Class constructor. @@ -360,99 +374,33 @@ public class Metrics { * @param chartId The id of the chart. * @param callable The callable which is used to request the chart data. */ - public AdvancedBarChart(String chartId, Callable> callable) { + public DrilldownPie(String chartId, Callable>> callable) { super(chartId); this.callable = callable; } @Override - protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + public JsonObjectBuilder.JsonObject getChartData() throws Exception { JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); - Map map = callable.call(); + Map> map = callable.call(); if (map == null || map.isEmpty()) { // Null = skip the chart return null; } - boolean allSkipped = true; - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue().length == 0) { - // Skip this invalid - continue; + boolean reallyAllSkipped = true; + for (Map.Entry> entryValues : map.entrySet()) { + JsonObjectBuilder valueBuilder = new JsonObjectBuilder(); + boolean allSkipped = true; + for (Map.Entry valueEntry : map.get(entryValues.getKey()).entrySet()) { + valueBuilder.appendField(valueEntry.getKey(), valueEntry.getValue()); + allSkipped = false; } - allSkipped = false; - valuesBuilder.appendField(entry.getKey(), entry.getValue()); - } - if (allSkipped) { - // Null = skip the chart - return null; - } - return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); - } - } - - public static class SimpleBarChart extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public SimpleBarChart(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObjectBuilder.JsonObject getChartData() throws Exception { - JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - for (Map.Entry entry : map.entrySet()) { - valuesBuilder.appendField(entry.getKey(), new int[] {entry.getValue()}); - } - return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); - } - } - - public static class MultiLineChart extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public MultiLineChart(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObjectBuilder.JsonObject getChartData() throws Exception { - JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - boolean allSkipped = true; - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue() == 0) { - // Skip this invalid - continue; + if (!allSkipped) { + reallyAllSkipped = false; + valuesBuilder.appendField(entryValues.getKey(), valueBuilder.build()); } - allSkipped = false; - valuesBuilder.appendField(entry.getKey(), entry.getValue()); } - if (allSkipped) { + if (reallyAllSkipped) { // Null = skip the chart return null; } @@ -500,6 +448,76 @@ public class Metrics { } } + public static class MultiLineChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public MultiLineChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + // Skip this invalid + continue; + } + allSkipped = false; + valuesBuilder.appendField(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class SimpleBarChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SimpleBarChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + for (Map.Entry entry : map.entrySet()) { + valuesBuilder.appendField(entry.getKey(), new int[] {entry.getValue()}); + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + public abstract static class CustomChart { private final String chartId; @@ -534,32 +552,6 @@ public class Metrics { protected abstract JsonObjectBuilder.JsonObject getChartData() throws Exception; } - public static class SingleLineChart extends CustomChart { - - private final Callable callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public SingleLineChart(String chartId, Callable callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObjectBuilder.JsonObject getChartData() throws Exception { - int value = callable.call(); - if (value == 0) { - // Null = skip the chart - return null; - } - return new JsonObjectBuilder().appendField("value", value).build(); - } - } - public static class SimplePie extends CustomChart { private final Callable callable; @@ -586,9 +578,9 @@ public class Metrics { } } - public static class DrilldownPie extends CustomChart { + public static class AdvancedBarChart extends CustomChart { - private final Callable>> callable; + private final Callable> callable; /** * Class constructor. @@ -596,33 +588,29 @@ public class Metrics { * @param chartId The id of the chart. * @param callable The callable which is used to request the chart data. */ - public DrilldownPie(String chartId, Callable>> callable) { + public AdvancedBarChart(String chartId, Callable> callable) { super(chartId); this.callable = callable; } @Override - public JsonObjectBuilder.JsonObject getChartData() throws Exception { + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); - Map> map = callable.call(); + Map map = callable.call(); if (map == null || map.isEmpty()) { // Null = skip the chart return null; } - boolean reallyAllSkipped = true; - for (Map.Entry> entryValues : map.entrySet()) { - JsonObjectBuilder valueBuilder = new JsonObjectBuilder(); - boolean allSkipped = true; - for (Map.Entry valueEntry : map.get(entryValues.getKey()).entrySet()) { - valueBuilder.appendField(valueEntry.getKey(), valueEntry.getValue()); - allSkipped = false; - } - if (!allSkipped) { - reallyAllSkipped = false; - valuesBuilder.appendField(entryValues.getKey(), valueBuilder.build()); + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue().length == 0) { + // Skip this invalid + continue; } + allSkipped = false; + valuesBuilder.appendField(entry.getKey(), entry.getValue()); } - if (reallyAllSkipped) { + if (allSkipped) { // Null = skip the chart return null; } @@ -630,6 +618,32 @@ public class Metrics { } } + public static class SingleLineChart extends CustomChart { + + private final Callable callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SingleLineChart(String chartId, Callable callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + int value = callable.call(); + if (value == 0) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("value", value).build(); + } + } + /** * An extremely simple JSON builder. * diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Library/Placeholders.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Library/Placeholders.java index da8983aa..808f4840 100644 --- a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Library/Placeholders.java +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Library/Placeholders.java @@ -591,9 +591,9 @@ public final class Placeholders { } public final class Cache { - private Map proxies = Collections.emptyMap(); - private Map hosts = Collections.emptyMap(); - private Map servers = Collections.emptyMap(); + private Map proxies = new TreeMap<>(); + private Map hosts = new TreeMap<>(); + private Map servers = new TreeMap<>(); private Proxy master = null; private Listener events = new Events(); diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Library/SignState.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Library/SignState.java new file mode 100644 index 00000000..fb0cb922 --- /dev/null +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Library/SignState.java @@ -0,0 +1,42 @@ +package net.ME1312.SubServers.Client.Bukkit.Library; + +import net.ME1312.SubServers.Client.Common.Network.API.Server; +import net.ME1312.SubServers.Client.Common.Network.API.SubServer; + +public enum SignState { + UNKNOWN(0, "Signs.Text.Unknown"), + OFFLINE(1, "Signs.Text.Offline"), + STARTING(3, "Signs.Text.Starting"), + ONLINE(4, "Signs.Text.Online"), + STOPPING(2, "Signs.Text.Stopping"), + ; + public final byte priority; + public final String text; + + SignState(int priority, String text) { + this.priority = (byte) priority; + this.text = text; + } + + public static SignState determine(SubServer server) { + if (!server.isRunning()) { + return SignState.OFFLINE; + } else if (server.isStopping()) { + return SignState.STOPPING; + } else if (server.isOnline()) { + return SignState.ONLINE; + } else { + return SignState.STARTING; + } + } + + public static SignState determine(Server server) { + if (server instanceof SubServer) { + return determine((SubServer) server); + } else if (server.getSubData()[0] == null) { + return SignState.UNKNOWN; + } else { + return SignState.ONLINE; + } + } +} diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Network/SubProtocol.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Network/SubProtocol.java index ada66dfb..9a815c94 100644 --- a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Network/SubProtocol.java +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Network/SubProtocol.java @@ -115,9 +115,7 @@ public class SubProtocol extends SubDataProtocol { return instance; } - @SuppressWarnings("deprecation") private Logger getLogger(int channel) { - SubPlugin plugin = SubAPI.getInstance().getInternals(); Logger log = Logger.getAnonymousLogger(); log.setUseParentHandlers(false); log.addHandler(new Handler() { @@ -127,11 +125,7 @@ public class SubProtocol extends SubDataProtocol { @Override public void publish(LogRecord record) { if (open) { - if (plugin.isEnabled()) { - Bukkit.getScheduler().runTask(plugin, () -> Bukkit.getLogger().log(record.getLevel(), prefix + " > " + record.getMessage(), record.getParameters())); - } else { - Bukkit.getLogger().log(record.getLevel(), prefix + " > " + record.getMessage(), record.getParameters()); - } + Bukkit.getLogger().log(record.getLevel(), prefix + " > " + record.getMessage(), record.getParameters()); } } @@ -193,7 +187,7 @@ public class SubProtocol extends SubDataProtocol { public SubDataClient open(Logger logger, InetAddress address, int port) throws IOException { SubPlugin plugin = SubAPI.getInstance().getInternals(); return open(event -> { - if (plugin.isEnabled()) Bukkit.getScheduler().runTask(plugin, event); + if (plugin.isEnabled()) Bukkit.getScheduler().runTaskAsynchronously(plugin, event); else event.run(); }, logger, address, port); } diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/SubCommand.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/SubCommand.java index 37b3fb46..88290df2 100644 --- a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/SubCommand.java +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/SubCommand.java @@ -63,7 +63,7 @@ public final class SubCommand extends Command { if (sender.hasPermission("subservers.command")) { if (args.length > 0) { if (args[0].equalsIgnoreCase("help") || args[0].equalsIgnoreCase("?")) { - sender.sendMessage(printHelp(sender, label)); + sender.sendMessage(printHelp(label)); } else if (args[0].equalsIgnoreCase("version") || args[0].equalsIgnoreCase("ver")) { sender.sendMessage(plugin.api.getLang("SubServers", "Command.Version").replace("$str$", "SubServers.Client.Bukkit")); sender.sendMessage(ChatColor.WHITE + " " + Platform.getSystemName() + ' ' + Platform.getSystemVersion() + ((Platform.getSystemBuild() != null)?" (" + Platform.getSystemBuild() + ')':"") + ((!Platform.getSystemArchitecture().equals("unknown"))?" [" + Platform.getSystemArchitecture() + ']':"") + ChatColor.RESET + ','); @@ -838,7 +838,7 @@ public final class SubCommand extends Command { if (plugin.gui != null && sender instanceof Player && sender.hasPermission("subservers.interface")) { plugin.gui.getRenderer((Player) sender).newUI(); } else { - sender.sendMessage(printHelp(sender, label)); + sender.sendMessage(printHelp(label)); } } } else if (args.length > 0 && (args[0].equalsIgnoreCase("tp") || args[0].equalsIgnoreCase("teleport"))) { @@ -1118,7 +1118,7 @@ public final class SubCommand extends Command { } } - private String[] printHelp(CommandSender sender, String label) { + private String[] printHelp(String label) { return new String[]{ plugin.api.getLang("SubServers", "Command.Help.Header"), plugin.api.getLang("SubServers", "Command.Help.Help").replace("$str$", label.toLowerCase() + " help"), diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/SubPlugin.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/SubPlugin.java index a1ea4c04..dd36ba84 100644 --- a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/SubPlugin.java +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/SubPlugin.java @@ -52,6 +52,7 @@ public final class SubPlugin extends JavaPlugin { public SubProtocol subprotocol; public UIHandler gui = null; + public SubSigns signs = null; public final Version version; public final SubAPI api = new SubAPI(this); public final Placeholders phi = new Placeholders(this); @@ -130,7 +131,7 @@ public final class SubPlugin extends JavaPlugin { gui = new DefaultUIHandler(this); if (api.access.value > NO_COMMANDS.value && !config.get().getMap("Settings").getBoolean("API-Only-Mode", false)) { - Bukkit.getPluginManager().registerEvents(new SubSigns(this, new File(dir, "signs.dat")), this); + signs = new SubSigns(this, new File(dir, "signs.dat")); CommandMap cmd = Util.reflect(Bukkit.getServer().getClass().getDeclaredField("commandMap"), Bukkit.getServer()); cmd.register("subservers", new SubCommand(this, "subservers")); @@ -176,9 +177,9 @@ public final class SubPlugin extends JavaPlugin { if (notifyPlugins) { List listeners = api.reloadListeners; if (listeners.size() > 0) { - for (Object obj : listeners) { + for (Runnable listener : listeners) { try { - ((Runnable) obj).run(); + listener.run(); } catch (Throwable e) { new InvocationTargetException(e, "Problem reloading plugin").printStackTrace(); } @@ -206,10 +207,10 @@ public final class SubPlugin extends JavaPlugin { } catch (IOException e) { Bukkit.getLogger().info("SubData > Connection was unsuccessful, retrying in " + reconnect + " seconds"); - Bukkit.getScheduler().runTaskLater(SubPlugin.this, this, reconnect * 20); + Bukkit.getScheduler().runTaskLater(SubPlugin.this, this, reconnect * 20L); } } - }, (disconnect == null)?0:reconnect * 20); + }, (disconnect == null)?0:reconnect * 20L); } } @@ -230,7 +231,7 @@ public final class SubPlugin extends JavaPlugin { } subdata.clear(); subdata.put(0, null); - SubSigns.save(); + if (signs != null) signs.save(); } catch (IOException | InterruptedException e) { e.printStackTrace(); } diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/SubSigns.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/SubSigns.java index 19c4dc03..1621dfcb 100644 --- a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/SubSigns.java +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/SubSigns.java @@ -7,6 +7,7 @@ import net.ME1312.SubServers.Client.Bukkit.Event.SubStartedEvent; import net.ME1312.SubServers.Client.Bukkit.Event.SubStopEvent; import net.ME1312.SubServers.Client.Bukkit.Event.SubStoppedEvent; import net.ME1312.SubServers.Client.Bukkit.Library.Compatibility.OfflineBlock; +import net.ME1312.SubServers.Client.Bukkit.Library.SignState; import net.ME1312.SubServers.Client.Common.Network.API.Host; import net.ME1312.SubServers.Client.Common.Network.API.Server; import net.ME1312.SubServers.Client.Common.Network.API.SubServer; @@ -37,20 +38,21 @@ import java.util.function.Supplier; * SubServers Signs Class */ public class SubSigns implements Listener { - private static final HashMap data = new HashMap(); - private static final HashMap locations = new HashMap(); - private static HashMap> signs = new HashMap>(); - private static File file; + private final HashMap data = new HashMap(); + private final HashMap locations = new HashMap(); + private HashMap> signs = new HashMap>(); + private final File file; private final SubPlugin plugin; private boolean active = false; SubSigns(SubPlugin plugin, File file) throws IOException { this.plugin = plugin; - SubSigns.file = file; - load(); + this.file = file; + this.load(); + Bukkit.getPluginManager().registerEvents(this, plugin); } - public static void save() throws IOException { + public void save() throws IOException { if (!data.isEmpty() || (file.exists() && !file.delete())) { FileOutputStream raw = new FileOutputStream(file, false); EscapedOutputStream escaped = new EscapedOutputStream(raw, '\u001B', '\u0003'); @@ -130,11 +132,11 @@ public class SubSigns implements Listener { Supplier translator = translate(name); Location location = e.getBlock().getLocation(); - HashMap> signs = new HashMap>(SubSigns.signs); + HashMap> signs = new HashMap>(this.signs); signs.put(location, translator); - SubSigns.data.put(new OfflineBlock(location), name); - SubSigns.signs = signs; - SubSigns.locations.put(name.toLowerCase(), location); + this.data.put(new OfflineBlock(location), name); + this.signs = signs; + this.locations.put(name.toLowerCase(), location); listen(); refresh(e.getBlock(), translator); @@ -178,6 +180,30 @@ public class SubSigns implements Listener { } } + @EventHandler(priority = EventPriority.MONITOR) + public void refresh(SubStartEvent e) { + refresh(e.getServer()); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void refresh(SubStartedEvent e) { + refresh(e.getServer()); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void refresh(SubStopEvent e) { + refresh(e.getServer()); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void refresh(SubStoppedEvent e) { + refresh(e.getServer()); + } + + private void refresh(String name) { + refresh(plugin.phi.cache.getSubServer(name)); + } + private void refresh(SubServer server) { if (server != null && plugin.lang != null) { Location location = locations.get(server.getName().toLowerCase()); @@ -195,95 +221,60 @@ public class SubSigns implements Listener { } } - private enum Text { - UNKNOWN(0, "Signs.Text.Unknown"), - OFFLINE(1, "Signs.Text.Offline"), - STARTING(3, "Signs.Text.Starting"), - ONLINE(4, "Signs.Text.Online"), - STOPPING(2, "Signs.Text.Stopping"), - ; - private final byte priority; - private final String text; - Text(int priority, String text) { - this.priority = (byte) priority; - this.text = text; - } - - private static Text determine(SubServer server) { - if (!server.isRunning()) { - return Text.OFFLINE; - } else if (server.isStopping()) { - return Text.STOPPING; - } else if (server.isOnline()) { - return Text.ONLINE; - } else { - return Text.STARTING; - } - } - - private static Text determine(Server server) { - if (server instanceof SubServer) { - return determine((SubServer) server); - } else if (server.getSubData()[0] == null) { - return Text.UNKNOWN; - } else { - return Text.ONLINE; - } - } - } - @SuppressWarnings("unchecked") private void refresh(Block block, Supplier translator) { - if (block.getState() instanceof Sign) { - Object object = translator.get(); - String name; - int players = 0; + Bukkit.getScheduler().runTask(plugin, () -> { + if (block.getState() instanceof Sign) { + Object object = translator.get(); + String name; + int players = 0; - Sign sign = (Sign) block.getState(); - Text state = Text.UNKNOWN; + Sign sign = (Sign) block.getState(); + SignState state = SignState.UNKNOWN; - if (object instanceof Server) { - Server server = (Server) object; - state = Text.determine(server); - name = server.getDisplayName(); - players = server.getRemotePlayers().size(); + if (object instanceof Server) { + Server server = (Server) object; + state = SignState.determine(server); + name = server.getDisplayName(); + players = server.getRemotePlayers().size(); - } else if (object instanceof Pair) { - Pair> group = (Pair>) object; - name = group.key(); + } else if (object instanceof Pair) { + Pair> group = (Pair>) object; + name = group.key(); - Text incoming; - for (Server server : group.value()) { - players += server.getRemotePlayers().size(); - incoming = Text.determine(server); - if (incoming.priority > state.priority) - state = incoming; + SignState incoming; + for (Server server : group.value()) { + players += server.getRemotePlayers().size(); + incoming = SignState.determine(server); + if (incoming.priority > state.priority) + state = incoming; + } + } else if (object instanceof Host) { + Host host = (Host) object; + name = host.getDisplayName(); + + SignState incoming; + for (SubServer server : host.getSubServers().values()) { + players += server.getRemotePlayers().size(); + incoming = SignState.determine(server); + if (incoming.priority > state.priority) + state = incoming; + } + } else if (object instanceof String) { + name = (String) object; + } else { + return; } - } else if (object instanceof Host) { - Host host = (Host) object; - name = host.getDisplayName(); - Text incoming; - for (SubServer server : host.getSubServers().values()) { - players += server.getRemotePlayers().size(); - incoming = Text.determine(server); - if (incoming.priority > state.priority) - state = incoming; + String[] text = plugin.phi.replace(null, plugin.api.getLang("SubServers", state.text).replace("$str$", name).replace("$int$", NumberFormat.getInstance().format(players))).split("\n", 4); + for (int i = 0; i < 4; ++i) if (i < text.length) { + sign.setLine(i, text[i]); + } else { + sign.setLine(i, ""); } - } else if (object instanceof String) { - name = (String) object; - } else { - return; + sign.update(); } - - String[] text = plugin.phi.replace(null, plugin.api.getLang("SubServers", state.text).replace("$str$", name).replace("$int$", NumberFormat.getInstance().format(players))).split("\n", 4); - for (int i = 0; i < 4; ++i) if (i < text.length) { - sign.setLine(i, text[i]); - } else { - sign.setLine(i, ""); - } - Bukkit.getScheduler().runTask(plugin, sign::update); - } + }); } @SuppressWarnings("unchecked") @@ -307,12 +298,12 @@ public class SubSigns implements Listener { return; } - Text incoming, state = Text.UNKNOWN; + SignState incoming, state = SignState.UNKNOWN; List selected = new ArrayList<>(); for (Server server : servers) { - incoming = Text.determine(server); - if (incoming != Text.STOPPING) { - if (incoming == Text.OFFLINE) { + incoming = SignState.determine(server); + if (incoming != SignState.STOPPING) { + if (incoming == SignState.OFFLINE) { SubServer subserver = (SubServer) server; if (!subserver.isEnabled() || !subserver.isAvailable() || subserver.getCurrentIncompatibilities().size() != 0) continue; } @@ -329,7 +320,7 @@ public class SubSigns implements Listener { if (selected.size() > 0) { Server server = selected.get(new Random().nextInt(selected.size())); - if (state == Text.OFFLINE) { + if (state == SignState.OFFLINE) { ((SubServer) server).start(); } else { player.sendMessage(plugin.api.getLang("SubServers", "Command.Teleport").replace("$name$", player.getName()).replace("$str$", server.getDisplayName())); @@ -350,9 +341,9 @@ public class SubSigns implements Listener { String name = data.remove(new OfflineBlock(location)); if (name != null) locations.remove(name.toLowerCase()); - HashMap> signs = new HashMap>(SubSigns.signs); + HashMap> signs = new HashMap>(this.signs); signs.remove(location); - SubSigns.signs = signs; + this.signs = signs; player.sendMessage(plugin.api.getLang("SubServers", "Signs.Delete")); } else { @@ -360,24 +351,4 @@ public class SubSigns implements Listener { } } } - - @EventHandler(priority = EventPriority.MONITOR) - public void start(SubStartEvent e) { - refresh(plugin.phi.cache.getSubServer(e.getServer())); - } - - @EventHandler(priority = EventPriority.MONITOR) - public void started(SubStartedEvent e) { - refresh(plugin.phi.cache.getSubServer(e.getServer())); - } - - @EventHandler(priority = EventPriority.MONITOR) - public void stopping(SubStopEvent e) { - refresh(plugin.phi.cache.getSubServer(e.getServer())); - } - - @EventHandler(priority = EventPriority.MONITOR) - public void stopped(SubStoppedEvent e) { - refresh(plugin.phi.cache.getSubServer(e.getServer())); - } } diff --git a/SubServers.Client/Common/pom.xml b/SubServers.Client/Common/pom.xml index 6ab8c5db..4bd6d7f6 100644 --- a/SubServers.Client/Common/pom.xml +++ b/SubServers.Client/Common/pom.xml @@ -24,7 +24,7 @@ net.ME1312.SubData Client - 22w11a + 22w11c compile diff --git a/SubServers.Client/Sponge/src/net/ME1312/SubServers/Client/Sponge/Library/Metrics.java b/SubServers.Client/Sponge/src/net/ME1312/SubServers/Client/Sponge/Library/Metrics.java index f2b7809b..6f6777f2 100644 --- a/SubServers.Client/Sponge/src/net/ME1312/SubServers/Client/Sponge/Library/Metrics.java +++ b/SubServers.Client/Sponge/src/net/ME1312/SubServers/Client/Sponge/Library/Metrics.java @@ -22,9 +22,7 @@ import java.util.*; import java.util.zip.GZIPOutputStream; /** - * bStats collects some data for plugin authors. - * - * Check out https://bStats.org/ to learn more about bStats! + * SubServers BStats Metrics Implementation */ public class Metrics { diff --git a/SubServers.Client/Sponge/src/net/ME1312/SubServers/Client/Sponge/SubPlugin.java b/SubServers.Client/Sponge/src/net/ME1312/SubServers/Client/Sponge/SubPlugin.java index 7beb1f25..4a845426 100644 --- a/SubServers.Client/Sponge/src/net/ME1312/SubServers/Client/Sponge/SubPlugin.java +++ b/SubServers.Client/Sponge/src/net/ME1312/SubServers/Client/Sponge/SubPlugin.java @@ -178,9 +178,9 @@ public final class SubPlugin { if (notifyPlugins) { List listeners = api.reloadListeners; if (listeners.size() > 0) { - for (Object obj : listeners) { + for (Runnable listener : listeners) { try { - ((Runnable) obj).run(); + listener.run(); } catch (Throwable e) { new InvocationTargetException(e, "Problem reloading plugin").printStackTrace(); } diff --git a/SubServers.Console/pom.xml b/SubServers.Console/pom.xml index 22155f11..bee123e2 100644 --- a/SubServers.Console/pom.xml +++ b/SubServers.Console/pom.xml @@ -33,6 +33,12 @@ 1.8-SNAPSHOT provided + + net.ME1312.SubServers + SubServers.Bungee.Common + ${project.version} + provided + net.ME1312.SubServers SubServers.Bungee diff --git a/SubServers.Console/src/net/ME1312/SubServers/Console/ConsolePlugin.java b/SubServers.Console/src/net/ME1312/SubServers/Console/ConsolePlugin.java index 18b0f577..71381393 100644 --- a/SubServers.Console/src/net/ME1312/SubServers/Console/ConsolePlugin.java +++ b/SubServers.Console/src/net/ME1312/SubServers/Console/ConsolePlugin.java @@ -37,7 +37,7 @@ public final class ConsolePlugin extends Plugin implements Listener { getProxy().getPluginManager().registerCommand(this, new ConsoleCommand.AUTO_POPOUT(this, "apopout")); getProxy().getPluginManager().registerCommand(this, new ConsoleCommand.AUTO_POPOUT(this, "autopopout")); - new Metrics(this, 3853).appendPluginData(); + new Metrics(this, 3853).addPlatformCharts(); try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); diff --git a/SubServers.Host/src/net/ME1312/SubServers/Host/Library/Compatibility/JNA.java b/SubServers.Host/src/net/ME1312/SubServers/Host/Library/Compatibility/JNA.java index 472f2238..71459e46 100644 --- a/SubServers.Host/src/net/ME1312/SubServers/Host/Library/Compatibility/JNA.java +++ b/SubServers.Host/src/net/ME1312/SubServers/Host/Library/Compatibility/JNA.java @@ -34,7 +34,7 @@ public class JNA { File jna = new File(library, "jna-" + JNA_VERSION + ".jar"); jna.getParentFile().mkdirs(); if (!jna.exists()) { - log.info.println("Downloading JNA Library v" + JNA_VERSION); + log.info.println("Downloading JNA v" + JNA_VERSION); announced = true; try (InputStream in = new URL(JNA_DOWNLOAD.replace("$1", "jna")).openStream()) { Files.copy(in, jna.toPath(), StandardCopyOption.REPLACE_EXISTING); @@ -46,7 +46,7 @@ public class JNA { File platform = new File(library, "jna-platform-" + JNA_VERSION + ".jar"); platform.getParentFile().mkdirs(); if (!platform.exists()) { - if (!announced) log.info.println("Downloading JNA Library v" + JNA_VERSION); + if (!announced) log.info.println("Downloading JNA platform v" + JNA_VERSION); announced = true; try (InputStream in = new URL(JNA_DOWNLOAD.replace("$1", "jna-platform")).openStream()) { Files.copy(in, platform.toPath(), StandardCopyOption.REPLACE_EXISTING); @@ -56,15 +56,15 @@ public class JNA { } } if (jna.exists() && platform.exists()) { - if (announced) log.info.println("Loading JNA Library"); + if (announced) log.info.println("JNA download complete"); try { JNA = new URLClassLoader(new URL[]{jna.toURI().toURL(), platform.toURI().toURL()}); } catch (Throwable e) { - log.error.println("Could not load JNA Library:"); + log.error.println("Couldn't load JNA:"); log.error.println(e); } } else { - log.error.println("Could not load JNA Library:"); + log.error.println("Couldn't load JNA:"); log.error.println(new FileNotFoundException()); } } diff --git a/SubServers.Host/src/net/ME1312/SubServers/Host/Library/Metrics.java b/SubServers.Host/src/net/ME1312/SubServers/Host/Library/Metrics.java index e26ec845..5fdd422e 100644 --- a/SubServers.Host/src/net/ME1312/SubServers/Host/Library/Metrics.java +++ b/SubServers.Host/src/net/ME1312/SubServers/Host/Library/Metrics.java @@ -20,9 +20,7 @@ import java.util.regex.Pattern; import java.util.zip.GZIPOutputStream; /** - * bStats collects some data for plugin authors. - * - * Check out https://bStats.org/ to learn more about bStats! + * SubServers BStats Metrics Implementation */ public class Metrics { diff --git a/SubServers.Host/src/net/ME1312/SubServers/Host/Network/Packet/PacketInExReload.java b/SubServers.Host/src/net/ME1312/SubServers/Host/Network/Packet/PacketInExReload.java index 49db1d2e..77690eb4 100644 --- a/SubServers.Host/src/net/ME1312/SubServers/Host/Network/Packet/PacketInExReload.java +++ b/SubServers.Host/src/net/ME1312/SubServers/Host/Network/Packet/PacketInExReload.java @@ -28,7 +28,7 @@ public class PacketInExReload implements PacketObjectIn { @Override public void receive(SubDataSender client, ObjectMap data) { Logger log = Try.all.get(() -> Util.reflect(SubDataClient.class.getDeclaredField("log"), client.getConnection()), null); - if (data != null && data.contains(0x0000)) log.warning("Received request for a plugin reload: " + data.getString(0x0000)); + if (data != null && data.contains(0x0000)) log.warning("Received request for an app reload: " + data.getString(0x0000)); // else log.warning("Received request for a plugin reload"); new Thread(() -> { try { diff --git a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubAddHostEvent.java b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubAddHostEvent.java index 5071d5b6..3b6aaeda 100644 --- a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubAddHostEvent.java +++ b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubAddHostEvent.java @@ -1,7 +1,7 @@ package net.ME1312.SubServers.Sync.Event; import net.ME1312.Galaxi.Library.Util; -import net.ME1312.SubServers.Sync.Library.SubEvent; +import net.ME1312.SubServers.Bungee.Library.SubEvent; import net.md_5.bungee.api.plugin.Event; diff --git a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubAddProxyEvent.java b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubAddProxyEvent.java index 30231c8b..f46f8a1a 100644 --- a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubAddProxyEvent.java +++ b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubAddProxyEvent.java @@ -1,7 +1,7 @@ package net.ME1312.SubServers.Sync.Event; import net.ME1312.Galaxi.Library.Util; -import net.ME1312.SubServers.Sync.Library.SubEvent; +import net.ME1312.SubServers.Bungee.Library.SubEvent; import net.md_5.bungee.api.plugin.Event; diff --git a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubAddServerEvent.java b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubAddServerEvent.java index b2a2af4f..6fa76467 100644 --- a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubAddServerEvent.java +++ b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubAddServerEvent.java @@ -1,7 +1,7 @@ package net.ME1312.SubServers.Sync.Event; import net.ME1312.Galaxi.Library.Util; -import net.ME1312.SubServers.Sync.Library.SubEvent; +import net.ME1312.SubServers.Bungee.Library.SubEvent; import net.md_5.bungee.api.plugin.Event; diff --git a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubCreateEvent.java b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubCreateEvent.java index 252e68c7..9cbfa9c8 100644 --- a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubCreateEvent.java +++ b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubCreateEvent.java @@ -2,8 +2,8 @@ package net.ME1312.SubServers.Sync.Event; import net.ME1312.Galaxi.Library.Util; import net.ME1312.Galaxi.Library.Version.Version; +import net.ME1312.SubServers.Bungee.Library.SubEvent; import net.ME1312.SubServers.Client.Common.Network.API.SubServer; -import net.ME1312.SubServers.Sync.Library.SubEvent; import net.ME1312.SubServers.Sync.SubAPI; import net.md_5.bungee.api.plugin.Event; diff --git a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubCreatedEvent.java b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubCreatedEvent.java index b60af5d5..cc837bca 100644 --- a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubCreatedEvent.java +++ b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubCreatedEvent.java @@ -2,8 +2,8 @@ package net.ME1312.SubServers.Sync.Event; import net.ME1312.Galaxi.Library.Util; import net.ME1312.Galaxi.Library.Version.Version; +import net.ME1312.SubServers.Bungee.Library.SubEvent; import net.ME1312.SubServers.Client.Common.Network.API.SubServer; -import net.ME1312.SubServers.Sync.Library.SubEvent; import net.ME1312.SubServers.Sync.SubAPI; import net.md_5.bungee.api.plugin.Event; diff --git a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubEditServerEvent.java b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubEditServerEvent.java index 97f8e03a..a52f159b 100644 --- a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubEditServerEvent.java +++ b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubEditServerEvent.java @@ -5,7 +5,7 @@ import net.ME1312.Galaxi.Library.Container.Pair; import net.ME1312.Galaxi.Library.Map.ObjectMap; import net.ME1312.Galaxi.Library.Map.ObjectMapValue; import net.ME1312.Galaxi.Library.Util; -import net.ME1312.SubServers.Sync.Library.SubEvent; +import net.ME1312.SubServers.Bungee.Library.SubEvent; import net.md_5.bungee.api.plugin.Event; diff --git a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubNetworkConnectEvent.java b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubNetworkConnectEvent.java index efbf9c0a..110161d5 100644 --- a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubNetworkConnectEvent.java +++ b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubNetworkConnectEvent.java @@ -2,7 +2,7 @@ package net.ME1312.SubServers.Sync.Event; import net.ME1312.Galaxi.Library.Util; import net.ME1312.SubData.Client.DataClient; -import net.ME1312.SubServers.Sync.Library.SubEvent; +import net.ME1312.SubServers.Bungee.Library.SubEvent; import net.md_5.bungee.api.plugin.Event; diff --git a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubNetworkDisconnectEvent.java b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubNetworkDisconnectEvent.java index aa991748..56172406 100644 --- a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubNetworkDisconnectEvent.java +++ b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubNetworkDisconnectEvent.java @@ -3,7 +3,7 @@ package net.ME1312.SubServers.Sync.Event; import net.ME1312.Galaxi.Library.Util; import net.ME1312.SubData.Client.DataClient; import net.ME1312.SubData.Client.Library.DisconnectReason; -import net.ME1312.SubServers.Sync.Library.SubEvent; +import net.ME1312.SubServers.Bungee.Library.SubEvent; import net.md_5.bungee.api.plugin.Event; diff --git a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubRemoveHostEvent.java b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubRemoveHostEvent.java index 26839f1e..40c7e365 100644 --- a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubRemoveHostEvent.java +++ b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubRemoveHostEvent.java @@ -1,7 +1,7 @@ package net.ME1312.SubServers.Sync.Event; import net.ME1312.Galaxi.Library.Util; -import net.ME1312.SubServers.Sync.Library.SubEvent; +import net.ME1312.SubServers.Bungee.Library.SubEvent; import net.md_5.bungee.api.plugin.Event; diff --git a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubRemoveProxyEvent.java b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubRemoveProxyEvent.java index 210d0fa5..f9d21737 100644 --- a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubRemoveProxyEvent.java +++ b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubRemoveProxyEvent.java @@ -1,7 +1,7 @@ package net.ME1312.SubServers.Sync.Event; import net.ME1312.Galaxi.Library.Util; -import net.ME1312.SubServers.Sync.Library.SubEvent; +import net.ME1312.SubServers.Bungee.Library.SubEvent; import net.md_5.bungee.api.plugin.Event; diff --git a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubRemoveServerEvent.java b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubRemoveServerEvent.java index 25e1ad9f..6ff8042f 100644 --- a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubRemoveServerEvent.java +++ b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubRemoveServerEvent.java @@ -1,7 +1,7 @@ package net.ME1312.SubServers.Sync.Event; import net.ME1312.Galaxi.Library.Util; -import net.ME1312.SubServers.Sync.Library.SubEvent; +import net.ME1312.SubServers.Bungee.Library.SubEvent; import net.md_5.bungee.api.plugin.Event; diff --git a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubSendCommandEvent.java b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubSendCommandEvent.java index 7e4465d7..06a458f7 100644 --- a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubSendCommandEvent.java +++ b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubSendCommandEvent.java @@ -1,7 +1,7 @@ package net.ME1312.SubServers.Sync.Event; import net.ME1312.Galaxi.Library.Util; -import net.ME1312.SubServers.Sync.Library.SubEvent; +import net.ME1312.SubServers.Bungee.Library.SubEvent; import net.md_5.bungee.api.plugin.Event; diff --git a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubStartEvent.java b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubStartEvent.java index 9c5d4644..23108405 100644 --- a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubStartEvent.java +++ b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubStartEvent.java @@ -1,7 +1,7 @@ package net.ME1312.SubServers.Sync.Event; import net.ME1312.Galaxi.Library.Util; -import net.ME1312.SubServers.Sync.Library.SubEvent; +import net.ME1312.SubServers.Bungee.Library.SubEvent; import net.md_5.bungee.api.plugin.Event; diff --git a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubStartedEvent.java b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubStartedEvent.java index 1e75babd..de28c6b0 100644 --- a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubStartedEvent.java +++ b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubStartedEvent.java @@ -1,7 +1,7 @@ package net.ME1312.SubServers.Sync.Event; import net.ME1312.Galaxi.Library.Util; -import net.ME1312.SubServers.Sync.Library.SubEvent; +import net.ME1312.SubServers.Bungee.Library.SubEvent; import net.md_5.bungee.api.plugin.Event; diff --git a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubStopEvent.java b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubStopEvent.java index 153d23f3..b5641c5d 100644 --- a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubStopEvent.java +++ b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubStopEvent.java @@ -1,7 +1,7 @@ package net.ME1312.SubServers.Sync.Event; import net.ME1312.Galaxi.Library.Util; -import net.ME1312.SubServers.Sync.Library.SubEvent; +import net.ME1312.SubServers.Bungee.Library.SubEvent; import net.md_5.bungee.api.plugin.Event; diff --git a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubStoppedEvent.java b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubStoppedEvent.java index f4a9b86d..599de0f2 100644 --- a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubStoppedEvent.java +++ b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Event/SubStoppedEvent.java @@ -1,7 +1,7 @@ package net.ME1312.SubServers.Sync.Event; import net.ME1312.Galaxi.Library.Util; -import net.ME1312.SubServers.Sync.Library.SubEvent; +import net.ME1312.SubServers.Bungee.Library.SubEvent; import net.md_5.bungee.api.plugin.Event; diff --git a/SubServers.Sync/src/net/ME1312/SubServers/Sync/ExProxy.java b/SubServers.Sync/src/net/ME1312/SubServers/Sync/ExProxy.java index baa4673b..f81fe8f2 100644 --- a/SubServers.Sync/src/net/ME1312/SubServers/Sync/ExProxy.java +++ b/SubServers.Sync/src/net/ME1312/SubServers/Sync/ExProxy.java @@ -17,13 +17,13 @@ import net.ME1312.SubServers.Bungee.BungeeCommon; import net.ME1312.SubServers.Bungee.Library.Compatibility.Logger; import net.ME1312.SubServers.Bungee.Library.Fallback.FallbackState; import net.ME1312.SubServers.Bungee.Library.Fallback.SmartFallback; +import net.ME1312.SubServers.Bungee.Library.Metrics; import net.ME1312.SubServers.Client.Common.Network.Packet.PacketDisconnectPlayer; import net.ME1312.SubServers.Sync.Event.SubAddServerEvent; import net.ME1312.SubServers.Sync.Event.SubRemoveServerEvent; import net.ME1312.SubServers.Sync.Event.SubStartEvent; import net.ME1312.SubServers.Sync.Event.SubStoppedEvent; import net.ME1312.SubServers.Sync.Library.ConfigUpdater; -import net.ME1312.SubServers.Sync.Library.Metrics; import net.ME1312.SubServers.Sync.Network.Packet.PacketExSyncPlayer; import net.ME1312.SubServers.Sync.Network.SubProtocol; import net.ME1312.SubServers.Sync.Server.CachedPlayer; @@ -267,7 +267,8 @@ public final class ExProxy extends BungeeCommon implements Listener { if (getReconnectHandler() != null && getReconnectHandler().getClass().equals(SmartFallback.class)) setReconnectHandler(new SmartFallback(config.get().getMap("Settings").getMap("Smart-Fallback", new ObjectMap<>()))); // Re-initialize Smart Fallback - if (plugin != null) new Metrics(plugin, 1461).appendAppData(); + + if (plugin != null) Try.none.run(() -> new Metrics(plugin, 1461).addCustomChart(Util.reflect(Metrics.class.getDeclaredField("PLAYER_VERSIONS"), null))); new Timer("SubServers.Sync::Routine_Update_Check").schedule(new TimerTask() { @SuppressWarnings("unchecked") @Override diff --git a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Library/SubEvent.java b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Library/SubEvent.java deleted file mode 100644 index 68b06e25..00000000 --- a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Library/SubEvent.java +++ /dev/null @@ -1,7 +0,0 @@ -package net.ME1312.SubServers.Sync.Library; - -/** - * SubEvent Layout Class - */ -public interface SubEvent { -} diff --git a/SubServers.Sync/velocity/pom.xml b/SubServers.Sync/velocity/pom.xml index 3a42d158..13f8c891 100644 --- a/SubServers.Sync/velocity/pom.xml +++ b/SubServers.Sync/velocity/pom.xml @@ -22,7 +22,7 @@ org.apache.logging.log4j log4j-core - 2.16.0 + 2.17.2 provided diff --git a/SubServers.Sync/velocity/src/net/ME1312/SubServers/Velocity/ExProxy.java b/SubServers.Sync/velocity/src/net/ME1312/SubServers/Velocity/ExProxy.java index f943b8a4..f6ae17ef 100644 --- a/SubServers.Sync/velocity/src/net/ME1312/SubServers/Velocity/ExProxy.java +++ b/SubServers.Sync/velocity/src/net/ME1312/SubServers/Velocity/ExProxy.java @@ -230,7 +230,7 @@ public class ExProxy { if (config.get().getMap("Settings").getMap("Smart-Fallback", new ObjectMap<>()).getBoolean("Enabled", true)) proxy.getEventManager().register(this, new SmartFallback(config.get().getMap("Settings").getMap("Smart-Fallback", new ObjectMap<>()))); - metrics.make(this, 11953).appendAppData(); + Try.none.run(() -> metrics.make(this, 11953).addCustomChart(Util.reflect(Metrics.class.getDeclaredField("PLAYER_VERSIONS"), null))); new Timer("SubServers.Sync::Routine_Update_Check").schedule(new TimerTask() { @SuppressWarnings("unchecked") @Override diff --git a/SubServers.Sync/velocity/src/net/ME1312/SubServers/Velocity/Library/Metrics.java b/SubServers.Sync/velocity/src/net/ME1312/SubServers/Velocity/Library/Metrics.java index 60a93b67..3c63b22e 100644 --- a/SubServers.Sync/velocity/src/net/ME1312/SubServers/Velocity/Library/Metrics.java +++ b/SubServers.Sync/velocity/src/net/ME1312/SubServers/Velocity/Library/Metrics.java @@ -29,6 +29,9 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.zip.GZIPOutputStream; +/** + * SubServers BStats Metrics Implementation + */ public class Metrics { /** A factory to create new Metrics classes. */ @@ -116,17 +119,6 @@ public class Metrics { } } - /** - * Adds a custom chart. - * - * @param chart The chart to add. - */ - public void addCustomChart(CustomChart chart) { - if (metricsBase != null) { - metricsBase.addCustomChart(chart); - } - } - private static final AdvancedPie PLAYER_VERSIONS; static { final ProtocolVersion[] PROTOCOLS = ProtocolVersion.SUPPORTED_VERSIONS.toArray(new ProtocolVersion[0]); @@ -149,15 +141,23 @@ public class Metrics { }); } - public void appendAppData() { - addCustomChart(PLAYER_VERSIONS); + /** + * Add subservers platform information as custom charts + */ + public Metrics addPlatformCharts() { + return addCustomChart(new SimplePie("subservers_version", () -> SubAPI.getInstance().getPluginVersion().toString())).addCustomChart(PLAYER_VERSIONS); } - public void appendPluginData() { - addCustomChart(new SimplePie("subservers_version", () -> { - return SubAPI.getInstance().getPluginVersion().toString(); - })); - addCustomChart(PLAYER_VERSIONS); + /** + * Adds a custom chart. + * + * @param chart The chart to add. + */ + public Metrics addCustomChart(CustomChart chart) { + if (metricsBase != null) { + metricsBase.addCustomChart(chart); + } + return this; } private void appendPlatformData(JsonObjectBuilder builder) { @@ -182,7 +182,7 @@ public class Metrics { public static class MetricsBase { /** The version of the Metrics class. */ - public static final String METRICS_VERSION = "2.2.1"; + public static final String METRICS_VERSION = "3.0.0"; private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, task -> new Thread(task, "bStats-Metrics")); @@ -267,6 +267,7 @@ public class Metrics { this.logResponseStatusText = logResponseStatusText; checkRelocation(); if (enabled) { + // WARNING: Removing the option to opt-out will get your plugin banned from bStats startSubmitting(); } } @@ -403,9 +404,9 @@ public class Metrics { } } - public static class AdvancedBarChart extends CustomChart { + public static class DrilldownPie extends CustomChart { - private final Callable> callable; + private final Callable>> callable; /** * Class constructor. @@ -413,99 +414,33 @@ public class Metrics { * @param chartId The id of the chart. * @param callable The callable which is used to request the chart data. */ - public AdvancedBarChart(String chartId, Callable> callable) { + public DrilldownPie(String chartId, Callable>> callable) { super(chartId); this.callable = callable; } @Override - protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + public JsonObjectBuilder.JsonObject getChartData() throws Exception { JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); - Map map = callable.call(); + Map> map = callable.call(); if (map == null || map.isEmpty()) { // Null = skip the chart return null; } - boolean allSkipped = true; - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue().length == 0) { - // Skip this invalid - continue; + boolean reallyAllSkipped = true; + for (Map.Entry> entryValues : map.entrySet()) { + JsonObjectBuilder valueBuilder = new JsonObjectBuilder(); + boolean allSkipped = true; + for (Map.Entry valueEntry : map.get(entryValues.getKey()).entrySet()) { + valueBuilder.appendField(valueEntry.getKey(), valueEntry.getValue()); + allSkipped = false; } - allSkipped = false; - valuesBuilder.appendField(entry.getKey(), entry.getValue()); - } - if (allSkipped) { - // Null = skip the chart - return null; - } - return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); - } - } - - public static class SimpleBarChart extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public SimpleBarChart(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObjectBuilder.JsonObject getChartData() throws Exception { - JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - for (Map.Entry entry : map.entrySet()) { - valuesBuilder.appendField(entry.getKey(), new int[] {entry.getValue()}); - } - return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); - } - } - - public static class MultiLineChart extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public MultiLineChart(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObjectBuilder.JsonObject getChartData() throws Exception { - JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - boolean allSkipped = true; - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue() == 0) { - // Skip this invalid - continue; + if (!allSkipped) { + reallyAllSkipped = false; + valuesBuilder.appendField(entryValues.getKey(), valueBuilder.build()); } - allSkipped = false; - valuesBuilder.appendField(entry.getKey(), entry.getValue()); } - if (allSkipped) { + if (reallyAllSkipped) { // Null = skip the chart return null; } @@ -553,6 +488,76 @@ public class Metrics { } } + public static class MultiLineChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public MultiLineChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + // Skip this invalid + continue; + } + allSkipped = false; + valuesBuilder.appendField(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class SimpleBarChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SimpleBarChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + for (Map.Entry entry : map.entrySet()) { + valuesBuilder.appendField(entry.getKey(), new int[] {entry.getValue()}); + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + public abstract static class CustomChart { private final String chartId; @@ -587,32 +592,6 @@ public class Metrics { protected abstract JsonObjectBuilder.JsonObject getChartData() throws Exception; } - public static class SingleLineChart extends CustomChart { - - private final Callable callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public SingleLineChart(String chartId, Callable callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObjectBuilder.JsonObject getChartData() throws Exception { - int value = callable.call(); - if (value == 0) { - // Null = skip the chart - return null; - } - return new JsonObjectBuilder().appendField("value", value).build(); - } - } - public static class SimplePie extends CustomChart { private final Callable callable; @@ -639,9 +618,9 @@ public class Metrics { } } - public static class DrilldownPie extends CustomChart { + public static class AdvancedBarChart extends CustomChart { - private final Callable>> callable; + private final Callable> callable; /** * Class constructor. @@ -649,33 +628,29 @@ public class Metrics { * @param chartId The id of the chart. * @param callable The callable which is used to request the chart data. */ - public DrilldownPie(String chartId, Callable>> callable) { + public AdvancedBarChart(String chartId, Callable> callable) { super(chartId); this.callable = callable; } @Override - public JsonObjectBuilder.JsonObject getChartData() throws Exception { + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); - Map> map = callable.call(); + Map map = callable.call(); if (map == null || map.isEmpty()) { // Null = skip the chart return null; } - boolean reallyAllSkipped = true; - for (Map.Entry> entryValues : map.entrySet()) { - JsonObjectBuilder valueBuilder = new JsonObjectBuilder(); - boolean allSkipped = true; - for (Map.Entry valueEntry : map.get(entryValues.getKey()).entrySet()) { - valueBuilder.appendField(valueEntry.getKey(), valueEntry.getValue()); - allSkipped = false; - } - if (!allSkipped) { - reallyAllSkipped = false; - valuesBuilder.appendField(entryValues.getKey(), valueBuilder.build()); + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue().length == 0) { + // Skip this invalid + continue; } + allSkipped = false; + valuesBuilder.appendField(entry.getKey(), entry.getValue()); } - if (reallyAllSkipped) { + if (allSkipped) { // Null = skip the chart return null; } @@ -683,6 +658,32 @@ public class Metrics { } } + public static class SingleLineChart extends CustomChart { + + private final Callable callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SingleLineChart(String chartId, Callable callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + int value = callable.call(); + if (value == 0) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("value", value).build(); + } + } + /** * An extremely simple JSON builder. *