diff --git a/README.md b/README.md index 12493a4..72a00cb 100644 --- a/README.md +++ b/README.md @@ -24,14 +24,14 @@ This plugin is licensed with the MIT License, for more information see the [LICE ## Building -To build this yourself just clone the repository and run `build` with the Gradle Wrapper +To build this yourself just clone the repository and run the `shadowJar` task with the Gradle Wrapper ### Windows ```bat git clone git@github.com:oskar3123/StaffChat.git cd StaffChat -gradlew.bat build +gradlew.bat shadowJar ``` ### *nix (Linux, FreeBSD, macOS, ...) @@ -39,7 +39,7 @@ gradlew.bat build ```bash git clone git@github.com:oskar3123/StaffChat.git cd StaffChat -./gradlew build +./gradlew shadowJar ``` ## Event API (For developers) diff --git a/build.gradle.kts b/build.gradle.kts index 9cb254f..133152c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,4 +1,5 @@ plugins { + id("com.github.johnrengelman.shadow").version("8.1.1") id("java") } @@ -37,10 +38,17 @@ dependencies { compileOnly("me.clip:placeholderapi:2.11.1") compileOnly("com.discordsrv:discordsrv:1.25.1") + implementation("org.bstats:bstats-bukkit:3.0.2") + implementation("org.bstats:bstats-bungeecord:3.0.2") + testImplementation(platform("org.junit:junit-bom:5.10.0")) testImplementation("org.junit.jupiter:junit-jupiter:5.10.0") } +tasks.shadowJar { + relocate("org.bstats", "me.oskar3123.staffchat.bstats") +} + tasks.test { useJUnitPlatform() } diff --git a/src/main/java/me/oskar3123/staffchat/bungee/BungeeMain.java b/src/main/java/me/oskar3123/staffchat/bungee/BungeeMain.java index 936f8a0..2f07a34 100644 --- a/src/main/java/me/oskar3123/staffchat/bungee/BungeeMain.java +++ b/src/main/java/me/oskar3123/staffchat/bungee/BungeeMain.java @@ -10,9 +10,12 @@ 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 org.bstats.bungeecord.Metrics; public class BungeeMain extends Plugin { + private static final int BSTATS_PLUGIN_ID = 836; + public final String usePerm = "staffchat.use"; public final String seePerm = "staffchat.see"; public final String commandPerm = "staffchat.command"; @@ -21,7 +24,7 @@ public class BungeeMain extends Plugin { private Configuration config; public void onEnable() { - new MetricsLite(this); + new Metrics(this, BSTATS_PLUGIN_ID); saveDefaultConfig(); if (!reloadConfig()) { getLogger().severe("Could not load config file, using defaults."); diff --git a/src/main/java/me/oskar3123/staffchat/bungee/MetricsLite.java b/src/main/java/me/oskar3123/staffchat/bungee/MetricsLite.java deleted file mode 100644 index ccf6dea..0000000 --- a/src/main/java/me/oskar3123/staffchat/bungee/MetricsLite.java +++ /dev/null @@ -1,395 +0,0 @@ -package me.oskar3123.staffchat.bungee; - -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.net.URL; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; -import java.util.Timer; -import java.util.TimerTask; -import java.util.UUID; -import java.util.concurrent.TimeUnit; -import java.util.logging.Level; -import java.util.zip.GZIPOutputStream; -import javax.net.ssl.HttpsURLConnection; -import net.md_5.bungee.api.plugin.Plugin; -import net.md_5.bungee.api.scheduler.TaskScheduler; -import net.md_5.bungee.config.Configuration; -import net.md_5.bungee.config.ConfigurationProvider; -import net.md_5.bungee.config.YamlConfiguration; - -/** - * bStats collects some data for plugin authors. - * - *

Check out https://bStats.org/ to learn more about bStats! - */ -@SuppressWarnings("all") -public class MetricsLite { - - // The version of this bStats class - public static final int B_STATS_VERSION = 1; - // The url to which the data is sent - private static final String URL = "https://bStats.org/submitData/bungeecord"; - // A list with all known metrics class objects including this one - private static final List knownMetricsInstances = new ArrayList<>(); - - static { - // 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 nobody just copy & pastes the example and use the wrong package names - if (MetricsLite.class.getPackage().getName().equals(defaultPackage) - || MetricsLite.class.getPackage().getName().equals(examplePackage)) { - throw new IllegalStateException("bStats Metrics class has not been relocated correctly!"); - } - } - - // The plugin - private final Plugin plugin; - // Is bStats enabled on this server? - private boolean enabled; - // The uuid of the server - private String serverUUID; - // Should failed requests be logged? - private boolean logFailedRequests = false; - - public MetricsLite(Plugin plugin) { - this.plugin = plugin; - - try { - loadConfig(); - } catch (IOException e) { - // Failed to load configuration - plugin.getLogger().log(Level.WARNING, "Failed to load bStats config!", e); - return; - } - - // We are not allowed to send data about this server :( - if (!enabled) { - return; - } - - Class usedMetricsClass = getFirstBStatsClass(); - if (usedMetricsClass == null) { - // Failed to get first metrics class - return; - } - if (usedMetricsClass == getClass()) { - // We are the first! :) - linkMetrics(this); - startSubmitting(); - } else { - // We aren't the first so we link to the first metrics class - try { - usedMetricsClass.getMethod("linkMetrics", Object.class).invoke(null, this); - } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { - if (logFailedRequests) { - plugin - .getLogger() - .log( - Level.WARNING, - "Failed to link to first metrics class " + usedMetricsClass.getName() + "!", - e); - } - } - } - } - - /** - * Links an other metrics class with this class. This method is called using Reflection. - * - * @param metrics An object of the metrics class to link. - */ - public static void linkMetrics(Object metrics) { - knownMetricsInstances.add(metrics); - } - - /** - * Sends the data to the bStats server. - * - * @param data The data to send. - * @throws Exception If the request failed. - */ - private static void sendData(JsonObject data) throws Exception { - if (data == null) { - throw new IllegalArgumentException("Data cannot be null"); - } - - HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection(); - - // Compress the data to save bandwidth - byte[] compressedData = compress(data.toString()); - - // Add headers - connection.setRequestMethod("POST"); - connection.addRequestProperty("Accept", "application/json"); - connection.addRequestProperty("Connection", "close"); - connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request - connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length)); - connection.setRequestProperty( - "Content-Type", "application/json"); // We send our data in JSON format - connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION); - - // Send data - connection.setDoOutput(true); - DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream()); - outputStream.write(compressedData); - outputStream.flush(); - outputStream.close(); - - connection.getInputStream().close(); // We don't care about the response - Just send our data :) - } - - /** - * Gzips the given String. - * - * @param str The string to gzip. - * @return The gzipped String. - * @throws IOException If the compression failed. - */ - private static byte[] compress(final String str) throws IOException { - if (str == null) { - return null; - } - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - GZIPOutputStream gzip = new GZIPOutputStream(outputStream); - gzip.write(str.getBytes("UTF-8")); - gzip.close(); - return outputStream.toByteArray(); - } - - /** - * Gets the plugin specific data. This method is called using Reflection. - * - * @return The plugin specific data. - */ - public JsonObject getPluginData() { - JsonObject data = new JsonObject(); - - String pluginName = plugin.getDescription().getName(); - String pluginVersion = plugin.getDescription().getVersion(); - - data.addProperty("pluginName", pluginName); - data.addProperty("pluginVersion", pluginVersion); - - JsonArray customCharts = new JsonArray(); - data.add("customCharts", customCharts); - - return data; - } - - private void startSubmitting() { - // We use a timer cause want to be independent from the server tps - final Timer timer = new Timer(true); - timer.scheduleAtFixedRate( - new TimerTask() { - @Override - public void run() { - // The data collection (e.g. for custom graphs) is done sync - // Don't be afraid! The connection to the bStats server is still async, only the stats - // collection is sync ;) - TaskScheduler scheduler = plugin.getProxy().getScheduler(); - scheduler.schedule( - plugin, - new Runnable() { - @Override - public void run() { - submitData(); - } - }, - 0L, - TimeUnit.SECONDS); - } - }, - 1000 * 60 * 2, - 1000 * 60 * 30); - // Submit the data every 30 minutes, first time after 2 minutes to give other plugins enough - // time to start - // WARNING: Changing the frequency has no effect but your plugin WILL be blocked/deleted! - // WARNING: Just don't do it! - } - - /** - * Gets the server specific data. - * - * @return The server specific data. - */ - private JsonObject getServerData() { - // Minecraft specific data - int playerAmount = plugin.getProxy().getOnlineCount(); - playerAmount = playerAmount > 500 ? 500 : playerAmount; - int onlineMode = plugin.getProxy().getConfig().isOnlineMode() ? 1 : 0; - String bungeecordVersion = plugin.getProxy().getVersion(); - int managedServers = plugin.getProxy().getServers().size(); - - // OS/Java specific data - String javaVersion = System.getProperty("java.version"); - String osName = System.getProperty("os.name"); - String osArch = System.getProperty("os.arch"); - String osVersion = System.getProperty("os.version"); - int coreCount = Runtime.getRuntime().availableProcessors(); - - JsonObject data = new JsonObject(); - - data.addProperty("serverUUID", serverUUID); - - data.addProperty("playerAmount", playerAmount); - data.addProperty("managedServers", managedServers); - data.addProperty("onlineMode", onlineMode); - data.addProperty("bungeecordVersion", bungeecordVersion); - - data.addProperty("javaVersion", javaVersion); - data.addProperty("osName", osName); - data.addProperty("osArch", osArch); - data.addProperty("osVersion", osVersion); - data.addProperty("coreCount", coreCount); - - return data; - } - - /** Collects the data and sends it afterwards. */ - private void submitData() { - final JsonObject data = getServerData(); - - final JsonArray pluginData = new JsonArray(); - // Search for all other bStats Metrics classes to get their plugin data - for (Object metrics : knownMetricsInstances) { - try { - Object plugin = metrics.getClass().getMethod("getPluginData").invoke(metrics); - if (plugin instanceof JsonObject) { - pluginData.add((JsonObject) plugin); - } - } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { - } - } - - data.add("plugins", pluginData); - - // Create a new thread for the connection to the bStats server - new Thread( - new Runnable() { - @Override - public void run() { - try { - // Send the data - sendData(data); - } catch (Exception e) { - // Something went wrong! :( - if (logFailedRequests) { - plugin.getLogger().log(Level.WARNING, "Could not submit plugin stats!", e); - } - } - } - }) - .start(); - } - - /** - * Loads the bStats configuration. - * - * @throws IOException If something did not work :( - */ - private void loadConfig() throws IOException { - Path configPath = plugin.getDataFolder().toPath().getParent().resolve("bStats"); - configPath.toFile().mkdirs(); - File configFile = new File(configPath.toFile(), "config.yml"); - if (!configFile.exists()) { - writeFile( - configFile, - "#bStats collects some data for plugin authors like how many servers are using their plugins.", - "#To honor their work, you should not disable it.", - "#This has nearly no effect on the server performance!", - "#Check out https://bStats.org/ to learn more :)", - "enabled: true", - "serverUuid: \"" + UUID.randomUUID().toString() + "\"", - "logFailedRequests: false"); - } - - Configuration configuration = - ConfigurationProvider.getProvider(YamlConfiguration.class).load(configFile); - - // Load configuration - enabled = configuration.getBoolean("enabled", true); - serverUUID = configuration.getString("serverUuid"); - logFailedRequests = configuration.getBoolean("logFailedRequests", false); - } - - /** - * Gets the first bStat Metrics class. - * - * @return The first bStats metrics class. - */ - private Class getFirstBStatsClass() { - Path configPath = plugin.getDataFolder().toPath().getParent().resolve("bStats"); - configPath.toFile().mkdirs(); - File tempFile = new File(configPath.toFile(), "temp.txt"); - - try { - String className = readFile(tempFile); - if (className != null) { - try { - // Let's check if a class with the given name exists. - return Class.forName(className); - } catch (ClassNotFoundException ignored) { - } - } - writeFile(tempFile, getClass().getName()); - return getClass(); - } catch (IOException e) { - if (logFailedRequests) { - plugin.getLogger().log(Level.WARNING, "Failed to get first bStats class!", e); - } - return null; - } - } - - /** - * Reads the first line of the file. - * - * @param file The file to read. Cannot be null. - * @return The first line of the file or null if the file does not exist or is empty. - * @throws IOException If something did not work :( - */ - private String readFile(File file) throws IOException { - if (!file.exists()) { - return null; - } - try (FileReader fileReader = new FileReader(file); - BufferedReader bufferedReader = new BufferedReader(fileReader); ) { - return bufferedReader.readLine(); - } - } - - /** - * Writes a String to a file. It also adds a note for the user, - * - * @param file The file to write to. Cannot be null. - * @param lines The lines to write. - * @throws IOException If something did not work :( - */ - private void writeFile(File file, String... lines) throws IOException { - if (!file.exists()) { - file.createNewFile(); - } - try (FileWriter fileWriter = new FileWriter(file); - BufferedWriter bufferedWriter = new BufferedWriter(fileWriter)) { - for (String line : lines) { - bufferedWriter.write(line); - bufferedWriter.newLine(); - } - } - } -} diff --git a/src/main/java/me/oskar3123/staffchat/spigot/Main.java b/src/main/java/me/oskar3123/staffchat/spigot/Main.java index 1dfb350..5bdf936 100644 --- a/src/main/java/me/oskar3123/staffchat/spigot/Main.java +++ b/src/main/java/me/oskar3123/staffchat/spigot/Main.java @@ -8,6 +8,7 @@ import me.oskar3123.staffchat.spigot.handler.StaffChatHandler; import me.oskar3123.staffchat.spigot.listener.ChatListener; import me.oskar3123.staffchat.spigot.listener.DiscordSrvListener; import me.oskar3123.staffchat.spigot.listener.StaffChatPml; +import org.bstats.bukkit.Metrics; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; @@ -15,6 +16,8 @@ import org.jetbrains.annotations.NotNull; public class Main extends JavaPlugin { + private static final int BSTATS_PLUGIN_ID = 835; + public final String usePerm = "staffchat.use"; public final String seePerm = "staffchat.see"; public final String commandPerm = "staffchat.command"; @@ -26,7 +29,7 @@ public class Main extends JavaPlugin { public void onEnable() { getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord"); getServer().getMessenger().registerIncomingPluginChannel(this, "BungeeCord", staffChatPml); - new MetricsLite(this); + new Metrics(this, BSTATS_PLUGIN_ID); saveDefaultConfig(); registerCommands(); registerEvents(); diff --git a/src/main/java/me/oskar3123/staffchat/spigot/MetricsLite.java b/src/main/java/me/oskar3123/staffchat/spigot/MetricsLite.java deleted file mode 100644 index 48e8bbf..0000000 --- a/src/main/java/me/oskar3123/staffchat/spigot/MetricsLite.java +++ /dev/null @@ -1,316 +0,0 @@ -package me.oskar3123.staffchat.spigot; - -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.net.URL; -import java.util.Timer; -import java.util.TimerTask; -import java.util.UUID; -import java.util.logging.Level; -import java.util.zip.GZIPOutputStream; -import javax.net.ssl.HttpsURLConnection; -import org.bukkit.Bukkit; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.plugin.ServicePriority; -import org.bukkit.plugin.java.JavaPlugin; - -/** - * bStats collects some data for plugin authors. - * - *

Check out https://bStats.org/ to learn more about bStats! - */ -@SuppressWarnings("all") -public class MetricsLite { - - // The version of this bStats class - public static final int B_STATS_VERSION = 1; - // The url to which the data is sent - private static final String URL = "https://bStats.org/submitData/bukkit"; - // Should failed requests be logged? - private static boolean logFailedRequests; - // The uuid of the server - private static String serverUUID; - - static { - // 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 nobody just copy & pastes the example and use the wrong package names - if (MetricsLite.class.getPackage().getName().equals(defaultPackage) - || MetricsLite.class.getPackage().getName().equals(examplePackage)) { - throw new IllegalStateException("bStats Metrics class has not been relocated correctly!"); - } - } - - // The plugin - private final JavaPlugin plugin; - - /** - * Class constructor. - * - * @param plugin The plugin which stats should be submitted. - */ - public MetricsLite(JavaPlugin plugin) { - if (plugin == null) { - throw new IllegalArgumentException("Plugin cannot be null!"); - } - this.plugin = plugin; - - // Get the config file - File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats"); - File configFile = new File(bStatsFolder, "config.yml"); - YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); - - // Check if the config file exists - if (!config.isSet("serverUuid")) { - - // Add default values - config.addDefault("enabled", true); - // Every server gets it's unique random id. - config.addDefault("serverUuid", UUID.randomUUID().toString()); - // Should failed request be logged? - config.addDefault("logFailedRequests", false); - - // Inform the server owners about bStats - config - .options() - .header( - "bStats collects some data for plugin authors like how many servers are using their plugins.\n" - + "To honor their work, you should not disable it.\n" - + "This has nearly no effect on the server performance!\n" - + "Check out https://bStats.org/ to learn more :)") - .copyDefaults(true); - try { - config.save(configFile); - } catch (IOException ignored) { - } - } - - // Load the data - serverUUID = config.getString("serverUuid"); - logFailedRequests = config.getBoolean("logFailedRequests", false); - if (config.getBoolean("enabled", true)) { - boolean found = false; - // Search for all other bStats Metrics classes to see if we are the first one - for (Class service : Bukkit.getServicesManager().getKnownServices()) { - try { - service.getField("B_STATS_VERSION"); // Our identifier :) - found = true; // We aren't the first - break; - } catch (NoSuchFieldException ignored) { - } - } - // Register our service - Bukkit.getServicesManager().register(MetricsLite.class, this, plugin, ServicePriority.Normal); - if (!found) { - // We are the first! - startSubmitting(); - } - } - } - - /** - * Sends the data to the bStats server. - * - * @param data The data to send. - * @throws Exception If the request failed. - */ - private static void sendData(JsonObject data) throws Exception { - if (data == null) { - throw new IllegalArgumentException("Data cannot be null!"); - } - if (Bukkit.isPrimaryThread()) { - throw new IllegalAccessException("This method must not be called from the main thread!"); - } - HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection(); - - // Compress the data to save bandwidth - byte[] compressedData = compress(data.toString()); - - // Add headers - connection.setRequestMethod("POST"); - connection.addRequestProperty("Accept", "application/json"); - connection.addRequestProperty("Connection", "close"); - connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request - connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length)); - connection.setRequestProperty( - "Content-Type", "application/json"); // We send our data in JSON format - connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION); - - // Send data - connection.setDoOutput(true); - DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream()); - outputStream.write(compressedData); - outputStream.flush(); - outputStream.close(); - - connection.getInputStream().close(); // We don't care about the response - Just send our data :) - } - - /** - * Gzips the given String. - * - * @param str The string to gzip. - * @return The gzipped String. - * @throws IOException If the compression failed. - */ - private static byte[] compress(final String str) throws IOException { - if (str == null) { - return null; - } - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - GZIPOutputStream gzip = new GZIPOutputStream(outputStream); - gzip.write(str.getBytes("UTF-8")); - gzip.close(); - return outputStream.toByteArray(); - } - - /** Starts the Scheduler which submits our data every 30 minutes. */ - private void startSubmitting() { - final Timer timer = - new Timer(true); // We use a timer cause the Bukkit scheduler is affected by server lags - timer.scheduleAtFixedRate( - new TimerTask() { - @Override - public void run() { - if (!plugin.isEnabled()) { // Plugin was disabled - timer.cancel(); - return; - } - // Nevertheless we want our code to run in the Bukkit main thread, so we have to use the - // Bukkit scheduler - // Don't be afraid! The connection to the bStats server is still async, only the stats - // collection is sync ;) - Bukkit.getScheduler() - .runTask( - plugin, - new Runnable() { - @Override - public void run() { - submitData(); - } - }); - } - }, - 1000 * 60 * 5, - 1000 * 60 * 30); - // Submit the data every 30 minutes, first time after 5 minutes to give other plugins enough - // time to start - // WARNING: Changing the frequency has no effect but your plugin WILL be blocked/deleted! - // WARNING: Just don't do it! - } - - /** - * Gets the plugin specific data. This method is called using Reflection. - * - * @return The plugin specific data. - */ - public JsonObject getPluginData() { - JsonObject data = new JsonObject(); - - String pluginName = plugin.getDescription().getName(); - String pluginVersion = plugin.getDescription().getVersion(); - - data.addProperty("pluginName", pluginName); // Append the name of the plugin - data.addProperty("pluginVersion", pluginVersion); // Append the version of the plugin - - JsonArray customCharts = new JsonArray(); - data.add("customCharts", customCharts); - - return data; - } - - /** - * Gets the server specific data. - * - * @return The server specific data. - */ - private JsonObject getServerData() { - // Minecraft specific data - int playerAmount = Bukkit.getOnlinePlayers().size(); - int onlineMode = Bukkit.getOnlineMode() ? 1 : 0; - String bukkitVersion = Bukkit.getVersion(); - bukkitVersion = - bukkitVersion.substring(bukkitVersion.indexOf("MC: ") + 4, bukkitVersion.length() - 1); - - // OS/Java specific data - String javaVersion = System.getProperty("java.version"); - String osName = System.getProperty("os.name"); - String osArch = System.getProperty("os.arch"); - String osVersion = System.getProperty("os.version"); - int coreCount = Runtime.getRuntime().availableProcessors(); - - JsonObject data = new JsonObject(); - - data.addProperty("serverUUID", serverUUID); - - data.addProperty("playerAmount", playerAmount); - data.addProperty("onlineMode", onlineMode); - data.addProperty("bukkitVersion", bukkitVersion); - - data.addProperty("javaVersion", javaVersion); - data.addProperty("osName", osName); - data.addProperty("osArch", osArch); - data.addProperty("osVersion", osVersion); - data.addProperty("coreCount", coreCount); - - return data; - } - - /** Collects the data and sends it afterwards. */ - private void submitData() { - final JsonObject data = getServerData(); - - JsonArray pluginData = new JsonArray(); - // Search for all other bStats Metrics classes to get their plugin data - for (Class service : Bukkit.getServicesManager().getKnownServices()) { - try { - service.getField("B_STATS_VERSION"); // Our identifier :) - } catch (NoSuchFieldException ignored) { - continue; // Continue "searching" - } - // Found one! - try { - pluginData.add( - (JsonObject) - service - .getMethod("getPluginData") - .invoke(Bukkit.getServicesManager().load(service))); - } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { - } - } - - data.add("plugins", pluginData); - - // Create a new thread for the connection to the bStats server - new Thread( - new Runnable() { - @Override - public void run() { - try { - // Send the data - sendData(data); - } catch (Exception e) { - // Something went wrong! :( - if (logFailedRequests) { - plugin - .getLogger() - .log( - Level.WARNING, - "Could not submit plugin stats of " + plugin.getName(), - e); - } - } - } - }) - .start(); - } -}