diff --git a/pom.xml b/pom.xml index bf9f287..8fbe723 100644 --- a/pom.xml +++ b/pom.xml @@ -1,71 +1,76 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - 4.0.0 + 4.0.0 - StaffChat - me.oskar3123 - staffchat - 1.3.1-SNAPSHOT + StaffChat + me.oskar3123 + staffchat + SNAPSHOT - - UTF-8 - + + UTF-8 + - - - spigot-repo - https://hub.spigotmc.org/nexus/content/repositories/snapshots/ - - - bungeecord-repo - https://oss.sonatype.org/content/repositories/snapshots/ - - - placeholderapi - http://repo.extendedclip.com/content/repositories/placeholderapi/ - - + + + spigot-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + bungeecord-repo + https://oss.sonatype.org/content/repositories/snapshots/ + + + placeholderapi + https://repo.extendedclip.com/content/repositories/placeholderapi/ + + - - - org.spigotmc - spigot-api - 1.13.2-R0.1-SNAPSHOT - - - org.bukkit - bukkit - 1.13.2-R0.1-SNAPSHOT - - - net.md-5 - bungeecord-api - 1.13-SNAPSHOT - - - me.clip - placeholderapi - 2.9.2 - provided - - + + + org.spigotmc + spigot-api + 1.18-R0.1-SNAPSHOT + provided + + + net.md-5 + bungeecord-api + 1.18-R0.1-SNAPSHOT + jar + provided + + + net.md-5 + bungeecord-api + 1.18-R0.1-SNAPSHOT + javadoc + provided + + + me.clip + placeholderapi + 2.11.1 + provided + + - - ${project.name}-${project.version} - - - org.apache.maven.plugins - maven-compiler-plugin - 3.1 - - 1.8 - 1.8 - - - - + + ${project.name}-${project.version} + + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + 1.8 + 1.8 + + + + diff --git a/src/main/java/me/oskar3123/staffchat/bungee/BungeeMain.java b/src/main/java/me/oskar3123/staffchat/bungee/BungeeMain.java index 5143caa..936f8a0 100644 --- a/src/main/java/me/oskar3123/staffchat/bungee/BungeeMain.java +++ b/src/main/java/me/oskar3123/staffchat/bungee/BungeeMain.java @@ -1,5 +1,9 @@ package me.oskar3123.staffchat.bungee; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; import me.oskar3123.staffchat.bungee.command.BungeeStaffChatCommand; import me.oskar3123.staffchat.bungee.listener.BungeeChatListener; import net.md_5.bungee.api.plugin.Plugin; @@ -7,123 +11,102 @@ import net.md_5.bungee.config.Configuration; import net.md_5.bungee.config.ConfigurationProvider; import net.md_5.bungee.config.YamlConfiguration; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; +public class BungeeMain extends Plugin { -public class BungeeMain extends Plugin -{ + public final String usePerm = "staffchat.use"; + public final String seePerm = "staffchat.see"; + public final String commandPerm = "staffchat.command"; + public final String reloadPerm = "staffchat.reload"; + public final BungeeChatListener chatListener = new BungeeChatListener(this); + private Configuration config; - public final String usePerm = "staffchat.use"; - public final String seePerm = "staffchat.see"; - public final String commandPerm = "staffchat.command"; - public final String reloadPerm = "staffchat.reload"; - public final BungeeChatListener chatListener = new BungeeChatListener(this); - private Configuration config; - - public void onEnable() - { - new MetricsLite(this); - saveDefaultConfig(); - if (!reloadConfig()) - { - getLogger().severe("Could not load config file, using defaults."); - } - registerCommands(); - registerEvents(); + public void onEnable() { + new MetricsLite(this); + saveDefaultConfig(); + if (!reloadConfig()) { + getLogger().severe("Could not load config file, using defaults."); } + registerCommands(); + registerEvents(); + } - private void registerCommands() - { - getProxy().getPluginManager().registerCommand(this, new BungeeStaffChatCommand(this)); + private void registerCommands() { + getProxy().getPluginManager().registerCommand(this, new BungeeStaffChatCommand(this)); + } + + private void registerEvents() { + getProxy().getPluginManager().registerListener(this, chatListener); + } + + public boolean reloadConfig() { + try { + config = + ConfigurationProvider.getProvider(YamlConfiguration.class) + .load(new File(getDataFolder(), "config.yml")); + loadDefaultValues(); + return true; + } catch (IOException e) { + config = + ConfigurationProvider.getProvider(YamlConfiguration.class) + .load(getResourceAsStream("config.yml")); + loadDefaultValues(); + return false; } + } - private void registerEvents() - { - getProxy().getPluginManager().registerListener(this, chatListener); - } - - public boolean reloadConfig() - { - try - { - config = ConfigurationProvider.getProvider(YamlConfiguration.class).load(new File(getDataFolder(), "config.yml")); - loadDefaultValues(); - return true; - } - catch (IOException e) - { - config = ConfigurationProvider.getProvider(YamlConfiguration.class).load(getResourceAsStream("config.yml")); - loadDefaultValues(); - return false; - } - } - - private void loadDefaultValues() - { - String[] keys = new String[] { - "settings.character", - "settings.format", - "messages.prefix", - "messages.nopermission", - "messages.playeronly", - "messages.reloaded", - "messages.toggled", - "messages.onstring", - "messages.offstring", + private void loadDefaultValues() { + String[] keys = + new String[] { + "settings.character", + "settings.format", + "messages.prefix", + "messages.nopermission", + "messages.playeronly", + "messages.reloaded", + "messages.toggled", + "messages.onstring", + "messages.offstring", }; - Configuration def = ConfigurationProvider.getProvider(YamlConfiguration.class).load(getResourceAsStream("config.yml")); - for (String key : keys) - { - String v = config.getString(key); - if (v == null || v.isEmpty()) - { - config.set(key, def.getString(key)); - } - } - saveConfig(); + Configuration def = + ConfigurationProvider.getProvider(YamlConfiguration.class) + .load(getResourceAsStream("config.yml")); + for (String key : keys) { + String v = config.getString(key); + if (v == null || v.isEmpty()) { + config.set(key, def.getString(key)); + } + } + saveConfig(); + } + + public Configuration getConfig() { + return config; + } + + private void saveDefaultConfig() { + if (!getDataFolder().exists()) { + //noinspection ResultOfMethodCallIgnored + getDataFolder().mkdir(); } - public Configuration getConfig() - { - return config; + File file = new File(getDataFolder(), "config.yml"); + + if (!file.exists()) { + try (InputStream in = getResourceAsStream("config.yml")) { + Files.copy(in, file.toPath()); + } catch (IOException e) { + e.printStackTrace(); + } } + } - private void saveDefaultConfig() - { - if (!getDataFolder().exists()) - { - //noinspection ResultOfMethodCallIgnored - getDataFolder().mkdir(); - } - - File file = new File(getDataFolder(), "config.yml"); - - if (!file.exists()) - { - try (InputStream in = getResourceAsStream("config.yml")) - { - Files.copy(in, file.toPath()); - } - catch (IOException e) - { - e.printStackTrace(); - } - } + public void saveConfig() { + try { + ConfigurationProvider.getProvider(YamlConfiguration.class) + .save(config, new File(getDataFolder(), "config.yml")); + } catch (IOException e) { + e.printStackTrace(); + getLogger().severe("Failed to save config"); } - - public void saveConfig() - { - try - { - ConfigurationProvider.getProvider(YamlConfiguration.class).save(config, new File(getDataFolder(), "config.yml")); - } - catch (IOException e) - { - e.printStackTrace(); - getLogger().severe("Failed to save config"); - } - } - + } } diff --git a/src/main/java/me/oskar3123/staffchat/bungee/MetricsLite.java b/src/main/java/me/oskar3123/staffchat/bungee/MetricsLite.java index 1e6bc74..ccf6dea 100644 --- a/src/main/java/me/oskar3123/staffchat/bungee/MetricsLite.java +++ b/src/main/java/me/oskar3123/staffchat/bungee/MetricsLite.java @@ -2,428 +2,394 @@ 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; -import javax.net.ssl.HttpsURLConnection; -import java.io.*; -import java.lang.reflect.InvocationTargetException; -import java.net.URL; -import java.nio.file.Path; -import java.util.*; -import java.util.concurrent.TimeUnit; -import java.util.logging.Level; -import java.util.zip.GZIPOutputStream; - /** * bStats collects some data for plugin authors. - *

- * Check out https://bStats.org/ to learn more about bStats! + * + *

Check out https://bStats.org/ to learn more about bStats! */ @SuppressWarnings("all") -public class MetricsLite -{ +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<>(); + // 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!"); - } + 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; } - // 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; + // We are not allowed to send data about this server :( + if (!enabled) { + return; + } - public MetricsLite(Plugin plugin) - { - this.plugin = plugin; + 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); + } + } + } + } - try - { - loadConfig(); - } - catch (IOException e) - { - // Failed to load configuration - plugin.getLogger().log(Level.WARNING, "Failed to load bStats config!", e); - return; - } + /** + * 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); + } - // We are not allowed to send data about this server :( - if (!enabled) - { - return; - } + /** + * 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"); + } - Class usedMetricsClass = getFirstBStatsClass(); - if (usedMetricsClass == null) - { - // Failed to get first metrics class - return; + 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); } - 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); + } 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; } + } - /** - * 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); + /** + * 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; } - - /** - * 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 :) + try (FileReader fileReader = new FileReader(file); + BufferedReader bufferedReader = new BufferedReader(fileReader); ) { + return bufferedReader.readLine(); } + } - /** - * 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(); + /** + * 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(); } - - /** - * 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; + try (FileWriter fileWriter = new FileWriter(file); + BufferedWriter bufferedWriter = new BufferedWriter(fileWriter)) { + for (String line : lines) { + bufferedWriter.write(line); + bufferedWriter.newLine(); + } } - - 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(); - } - } - } - -} \ No newline at end of file + } +} diff --git a/src/main/java/me/oskar3123/staffchat/bungee/command/BungeeStaffChatCommand.java b/src/main/java/me/oskar3123/staffchat/bungee/command/BungeeStaffChatCommand.java index f0a2742..a9a1399 100644 --- a/src/main/java/me/oskar3123/staffchat/bungee/command/BungeeStaffChatCommand.java +++ b/src/main/java/me/oskar3123/staffchat/bungee/command/BungeeStaffChatCommand.java @@ -8,107 +8,95 @@ import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.plugin.Command; import net.md_5.bungee.config.Configuration; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; -public class BungeeStaffChatCommand extends Command -{ +public class BungeeStaffChatCommand extends Command { - private BungeeMain plugin; - private Configuration config; + private final BungeeMain plugin; + private Configuration config; - public BungeeStaffChatCommand(BungeeMain plugin) - { - super("staffchat"); - this.plugin = plugin; - config = plugin.getConfig(); + public BungeeStaffChatCommand(@NotNull BungeeMain plugin) { + super("staffchat"); + this.plugin = plugin; + config = plugin.getConfig(); + } + + public void execute(@NotNull CommandSender sender, @NotNull String[] args) { + BaseComponent[] noPerm = + txt(config.getString("messages.prefix") + config.getString("messages.nopermission")); + if (!sender.hasPermission(plugin.commandPerm)) { + sender.sendMessage(noPerm); + return; } - - public void execute(CommandSender sender, String[] args) - { - BaseComponent[] noPerm = txt(config.getString("messages.prefix") + config.getString("messages.nopermission")); - if (!sender.hasPermission(plugin.commandPerm)) - { - sender.sendMessage(noPerm); - return; - } - if (args.length < 1) - { - help(sender, getName()); - return; - } - if (args[0].equalsIgnoreCase("reload")) - { - if (sender.hasPermission(plugin.reloadPerm)) - { - reload(sender); - } - else - { - sender.sendMessage(noPerm); - } - return; - } - else if (args[0].equalsIgnoreCase("toggle")) - { - if (sender.hasPermission(plugin.usePerm)) - { - toggle(sender); - } - else - { - sender.sendMessage(noPerm); - } - return; - } - help(sender, getName()); + if (args.length < 1) { + help(sender, getName()); + return; } - - private void playerOnly(CommandSender sender) - { - sender.sendMessage(txt(config.getString("messages.prefix") + config.getString("messages.playeronly"))); + if (args[0].equalsIgnoreCase("reload")) { + if (sender.hasPermission(plugin.reloadPerm)) { + reload(sender); + } else { + sender.sendMessage(noPerm); + } + return; + } else if (args[0].equalsIgnoreCase("toggle")) { + if (sender.hasPermission(plugin.usePerm)) { + toggle(sender); + } else { + sender.sendMessage(noPerm); + } + return; } + help(sender, getName()); + } - private void help(CommandSender sender, String label) - { - String prefix = config.getString("messages.prefix"); - sender.sendMessage(txt(prefix + "Version " + plugin.getDescription().getVersion() + ", made by oskar3123")); - if (sender.hasPermission(plugin.usePerm)) - { - sender.sendMessage(txt(prefix + "Message prefix: " + config.getString("settings.character"))); - sender.sendMessage(txt(prefix + "/" + label + " toggle - Toggles auto staffchat")); - } - if (sender.hasPermission(plugin.reloadPerm)) - { - sender.sendMessage(txt(prefix + "/" + label + " reload - Reloads the config file")); - } + private void playerOnly(@NotNull CommandSender sender) { + sender.sendMessage( + txt(config.getString("messages.prefix") + config.getString("messages.playeronly"))); + } + + private void help(@NotNull CommandSender sender, String label) { + String prefix = config.getString("messages.prefix"); + sender.sendMessage( + txt(prefix + "Version " + plugin.getDescription().getVersion() + ", made by oskar3123")); + if (sender.hasPermission(plugin.usePerm)) { + sender.sendMessage(txt(prefix + "Message prefix: " + config.getString("settings.character"))); + sender.sendMessage(txt(prefix + "/" + label + " toggle - Toggles auto staffchat")); } - - private void reload(CommandSender sender) - { - plugin.reloadConfig(); - config = plugin.getConfig(); - sender.sendMessage(txt(config.getString("messages.prefix") + config.getString("messages.reloaded"))); + if (sender.hasPermission(plugin.reloadPerm)) { + sender.sendMessage(txt(prefix + "/" + label + " reload - Reloads the config file")); } + } - private void toggle(CommandSender sender) - { - if (!(sender instanceof ProxiedPlayer)) - { - playerOnly(sender); - return; - } - boolean toggled = plugin.chatListener.togglePlayer(((ProxiedPlayer) sender).getUniqueId()); - String state = toggled ? config.getString("messages.onstring") : config.getString("messages.offstring"); - sender.sendMessage(txt(config.getString("messages.prefix") + String.format(config.getString("messages.toggled"), state))); + private void reload(@NotNull CommandSender sender) { + plugin.reloadConfig(); + config = plugin.getConfig(); + sender.sendMessage( + txt(config.getString("messages.prefix") + config.getString("messages.reloaded"))); + } + + private void toggle(@NotNull CommandSender sender) { + if (!(sender instanceof ProxiedPlayer)) { + playerOnly(sender); + return; } + boolean toggled = plugin.chatListener.togglePlayer(((ProxiedPlayer) sender).getUniqueId()); + String state = + toggled ? config.getString("messages.onstring") : config.getString("messages.offstring"); + sender.sendMessage( + txt( + config.getString("messages.prefix") + + String.format(config.getString("messages.toggled", ""), state))); + } - private String clr(String string) - { - return ChatColor.translateAlternateColorCodes('&', string); - } - - private BaseComponent[] txt(String text) - { - return TextComponent.fromLegacyText(clr(text)); - } + @Contract("_ -> new") + private @NotNull String clr(@NotNull String string) { + return ChatColor.translateAlternateColorCodes('&', string); + } + @Contract("_ -> new") + private @NotNull BaseComponent[] txt(@NotNull String text) { + return TextComponent.fromLegacyText(clr(text)); + } } diff --git a/src/main/java/me/oskar3123/staffchat/bungee/event/BungeeStaffChatEvent.java b/src/main/java/me/oskar3123/staffchat/bungee/event/BungeeStaffChatEvent.java index b293ba1..3c6cbce 100644 --- a/src/main/java/me/oskar3123/staffchat/bungee/event/BungeeStaffChatEvent.java +++ b/src/main/java/me/oskar3123/staffchat/bungee/event/BungeeStaffChatEvent.java @@ -1,59 +1,53 @@ package me.oskar3123.staffchat.bungee.event; +import java.util.Objects; import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.plugin.Cancellable; import net.md_5.bungee.api.plugin.Event; +import org.jetbrains.annotations.NotNull; -public class BungeeStaffChatEvent extends Event implements Cancellable -{ +public class BungeeStaffChatEvent extends Event implements Cancellable { - private final ProxiedPlayer player; - private boolean cancelled = false; - private String format; - private String message; + private final ProxiedPlayer player; - public BungeeStaffChatEvent(ProxiedPlayer player, String format, String message) - { - this.player = player; - this.format = format; - this.message = message; - } + private boolean cancelled = false; + private String format; + private String message; - public String getFormat() - { - return format; - } + public BungeeStaffChatEvent( + @NotNull ProxiedPlayer player, @NotNull String format, @NotNull String message) { + this.player = player; + this.format = format; + this.message = message; + } - public void setFormat(String format) - { - this.format = format; - } + public @NotNull String getFormat() { + return format; + } - public String getMessage() - { - return message; - } + public void setFormat(@NotNull String format) { + this.format = Objects.requireNonNull(format); + } - public void setMessage(String message) - { - this.message = message; - } + public @NotNull String getMessage() { + return message; + } - public ProxiedPlayer getPlayer() - { - return player; - } + public void setMessage(@NotNull String message) { + this.message = Objects.requireNonNull(message); + } - @Override - public boolean isCancelled() - { - return cancelled; - } + public @NotNull ProxiedPlayer getPlayer() { + return player; + } - @Override - public void setCancelled(boolean cancelled) - { - this.cancelled = cancelled; - } + @Override + public boolean isCancelled() { + return cancelled; + } + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } } diff --git a/src/main/java/me/oskar3123/staffchat/bungee/listener/BungeeChatListener.java b/src/main/java/me/oskar3123/staffchat/bungee/listener/BungeeChatListener.java index 4330741..9af0360 100644 --- a/src/main/java/me/oskar3123/staffchat/bungee/listener/BungeeChatListener.java +++ b/src/main/java/me/oskar3123/staffchat/bungee/listener/BungeeChatListener.java @@ -1,5 +1,9 @@ package me.oskar3123.staffchat.bungee.listener; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; import me.oskar3123.staffchat.bungee.BungeeMain; import me.oskar3123.staffchat.bungee.event.BungeeStaffChatEvent; import me.oskar3123.staffchat.util.StringUtils; @@ -11,91 +15,78 @@ import net.md_5.bungee.api.event.ChatEvent; import net.md_5.bungee.api.plugin.Listener; import net.md_5.bungee.config.Configuration; import net.md_5.bungee.event.EventHandler; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; +public class BungeeChatListener implements Listener { -public class BungeeChatListener implements Listener -{ + private final BungeeMain plugin; + private final Set toggledPlayers = new HashSet<>(); - private BungeeMain plugin; - private Set toggledPlayers = new HashSet<>(); + public BungeeChatListener(@NotNull BungeeMain plugin) { + this.plugin = plugin; + } - public BungeeChatListener(BungeeMain plugin) - { - this.plugin = plugin; + @EventHandler + public void chat(@NotNull ChatEvent event) { + if (event.getMessage().startsWith("/")) { + return; + } + if (!(event.getSender() instanceof ProxiedPlayer)) { + return; } - @EventHandler - public void chat(ChatEvent event) - { - if (event.getMessage().startsWith("/")) - { - return; - } - if (!(event.getSender() instanceof ProxiedPlayer)) - { - return; - } - - ProxiedPlayer player = (ProxiedPlayer) event.getSender(); - if (!player.hasPermission(plugin.usePerm)) - { - return; - } - - Configuration config = plugin.getConfig(); - String character = config.getString("settings.character"); - boolean isToggled = toggledPlayers.contains(player.getUniqueId()); - if (!event.getMessage().startsWith(character) && !isToggled) - { - return; - } - - String format = config.getString("settings.format"); - String message = event.getMessage().substring(isToggled ? 0 : character.length()).trim(); - - BungeeStaffChatEvent chatEvent = new BungeeStaffChatEvent(player, format, message); - plugin.getProxy().getPluginManager().callEvent(chatEvent); - if (chatEvent.isCancelled()) - { - return; - } - format = chatEvent.getFormat(); - message = chatEvent.getMessage(); - - format = format.replaceAll("\\{NAME\\}", StringUtils.sanitize(player.getName())); - format = format.replaceAll("\\{MESSAGE\\}", StringUtils.sanitize(message)); - final BaseComponent[] messageComponents = txt(format); - - plugin.getProxy().getPlayers().stream() - .filter(p -> p.hasPermission(plugin.seePerm)) - .forEach(p -> p.sendMessage(messageComponents)); - plugin.getLogger().info(ChatColor.stripColor(clr(format))); - - event.setCancelled(true); + ProxiedPlayer player = (ProxiedPlayer) event.getSender(); + if (!player.hasPermission(plugin.usePerm)) { + return; } - private String clr(String string) - { - return ChatColor.translateAlternateColorCodes('&', string); + Configuration config = plugin.getConfig(); + String character = Objects.requireNonNull(config.getString("settings.character", "@")); + boolean isToggled = toggledPlayers.contains(player.getUniqueId()); + if (!event.getMessage().startsWith(character) && !isToggled) { + return; } - private BaseComponent[] txt(String text) - { - return TextComponent.fromLegacyText(clr(text)); - } + String format = Objects.requireNonNull(config.getString("settings.format", "")); + String message = event.getMessage().substring(isToggled ? 0 : character.length()).trim(); - public boolean togglePlayer(UUID player) - { - if (toggledPlayers.contains(player)) - { - toggledPlayers.remove(player); - return false; - } - toggledPlayers.add(player); - return true; + BungeeStaffChatEvent chatEvent = new BungeeStaffChatEvent(player, format, message); + plugin.getProxy().getPluginManager().callEvent(chatEvent); + if (chatEvent.isCancelled()) { + return; } + format = chatEvent.getFormat(); + message = chatEvent.getMessage(); + format = format.replaceAll("\\{NAME}", StringUtils.sanitize(player.getName())); + format = format.replaceAll("\\{MESSAGE}", StringUtils.sanitize(message)); + final BaseComponent[] messageComponents = txt(format); + + plugin.getProxy().getPlayers().stream() + .filter(p -> p.hasPermission(plugin.seePerm)) + .forEach(p -> p.sendMessage(messageComponents)); + plugin.getLogger().info(ChatColor.stripColor(clr(format))); + + event.setCancelled(true); + } + + @Contract("_ -> new") + private @NotNull String clr(@NotNull String string) { + return ChatColor.translateAlternateColorCodes('&', string); + } + + @Contract("_ -> new") + private @NotNull BaseComponent[] txt(@NotNull String text) { + return TextComponent.fromLegacyText(clr(text)); + } + + public boolean togglePlayer(@NotNull UUID player) { + if (toggledPlayers.contains(player)) { + toggledPlayers.remove(player); + return false; + } + toggledPlayers.add(player); + return true; + } } diff --git a/src/main/java/me/oskar3123/staffchat/spigot/Main.java b/src/main/java/me/oskar3123/staffchat/spigot/Main.java index 23bbaca..dc82487 100644 --- a/src/main/java/me/oskar3123/staffchat/spigot/Main.java +++ b/src/main/java/me/oskar3123/staffchat/spigot/Main.java @@ -1,5 +1,6 @@ package me.oskar3123.staffchat.spigot; +import java.util.Optional; import me.clip.placeholderapi.PlaceholderAPI; import me.oskar3123.staffchat.spigot.command.StaffChatCommand; import me.oskar3123.staffchat.spigot.listener.ChatListener; @@ -7,55 +8,47 @@ import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; -public class Main extends JavaPlugin -{ +public class Main extends JavaPlugin { - public final String usePerm = "staffchat.use"; - public final String seePerm = "staffchat.see"; - public final String commandPerm = "staffchat.command"; - public final String reloadPerm = "staffchat.reload"; - public final ChatListener chatListener = new ChatListener(this); + public final String usePerm = "staffchat.use"; + public final String seePerm = "staffchat.see"; + public final String commandPerm = "staffchat.command"; + public final String reloadPerm = "staffchat.reload"; + public final ChatListener chatListener = new ChatListener(this); - public void onEnable() - { - getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord"); - getServer().getMessenger().registerIncomingPluginChannel(this, "BungeeCord", chatListener); - new MetricsLite(this); - saveDefaultConfig(); - registerCommands(); - registerEvents(); + public void onEnable() { + getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord"); + getServer().getMessenger().registerIncomingPluginChannel(this, "BungeeCord", chatListener); + new MetricsLite(this); + saveDefaultConfig(); + registerCommands(); + registerEvents(); + } + + @Override + public void saveDefaultConfig() { + super.saveDefaultConfig(); + getConfig().options().copyDefaults(true); + saveConfig(); + } + + private void registerCommands() { + Optional.ofNullable(getCommand("staffchat")) + .ifPresent(command -> command.setExecutor(new StaffChatCommand(this))); + } + + private void registerEvents() { + Bukkit.getPluginManager().registerEvents(this.chatListener, this); + } + + private boolean isPlaceholderApiEnabled() { + return Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI"); + } + + public String replacePlaceholders(Player player, String string) { + if (!isPlaceholderApiEnabled()) { + return string; } - - @Override - public void saveDefaultConfig() - { - super.saveDefaultConfig(); - getConfig().options().copyDefaults(true); - saveConfig(); - } - - private void registerCommands() - { - getCommand("staffchat").setExecutor(new StaffChatCommand(this)); - } - - private void registerEvents() - { - Bukkit.getPluginManager().registerEvents(this.chatListener, this); - } - - private boolean isPlaceholderApiEnabled() - { - return Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI"); - } - - public String replacePlaceholders(Player player, String string) - { - if (!isPlaceholderApiEnabled()) - { - return string; - } - return PlaceholderAPI.setPlaceholders(player, string); - } - + return PlaceholderAPI.setPlaceholders(player, string); + } } diff --git a/src/main/java/me/oskar3123/staffchat/spigot/MetricsLite.java b/src/main/java/me/oskar3123/staffchat/spigot/MetricsLite.java index 483165d..48e8bbf 100644 --- a/src/main/java/me/oskar3123/staffchat/spigot/MetricsLite.java +++ b/src/main/java/me/oskar3123/staffchat/spigot/MetricsLite.java @@ -1,13 +1,7 @@ package me.oskar3123.staffchat.spigot; -import org.bukkit.Bukkit; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.plugin.ServicePriority; -import org.bukkit.plugin.java.JavaPlugin; -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; - -import javax.net.ssl.HttpsURLConnection; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.File; @@ -19,317 +13,304 @@ 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! + * + *

Check out https://bStats.org/ to learn more about bStats! */ @SuppressWarnings("all") -public class MetricsLite -{ +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; + // 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!"); - } + 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) { + } } - // 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(); - } + // 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 :) + /** + * 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!"); } - - /** - * 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(); + if (Bukkit.isPrimaryThread()) { + throw new IllegalAccessException("This method must not be called from the main thread!"); } + HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection(); - /** - * 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() - { + // 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! + } + }); + } + }, + 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) { + } } - /** - * Gets the plugin specific data. - * This method is called using Reflection. - * - * @return The plugin specific data. - */ - public JSONObject getPluginData() - { - JSONObject data = new JSONObject(); + data.add("plugins", pluginData); - String pluginName = plugin.getDescription().getName(); - String pluginVersion = plugin.getDescription().getVersion(); - - data.put("pluginName", pluginName); // Append the name of the plugin - data.put("pluginVersion", pluginVersion); // Append the version of the plugin - JSONArray customCharts = new JSONArray(); - data.put("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.put("serverUUID", serverUUID); - - data.put("playerAmount", playerAmount); - data.put("onlineMode", onlineMode); - data.put("bukkitVersion", bukkitVersion); - - data.put("javaVersion", javaVersion); - data.put("osName", osName); - data.put("osArch", osArch); - data.put("osVersion", osVersion); - data.put("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(service.getMethod("getPluginData").invoke(Bukkit.getServicesManager().load(service))); - } - catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) - { - } - } - - data.put("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); + // 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); + } } - catch (Exception e) - { - // Something went wrong! :( - if (logFailedRequests) - { - plugin.getLogger().log(Level.WARNING, "Could not submit plugin stats of " + plugin.getName(), e); - } - } - } - }).start(); - } - -} \ No newline at end of file + } + }) + .start(); + } +} diff --git a/src/main/java/me/oskar3123/staffchat/spigot/command/StaffChatCommand.java b/src/main/java/me/oskar3123/staffchat/spigot/command/StaffChatCommand.java index 5a0d4ad..cf4d2f2 100644 --- a/src/main/java/me/oskar3123/staffchat/spigot/command/StaffChatCommand.java +++ b/src/main/java/me/oskar3123/staffchat/spigot/command/StaffChatCommand.java @@ -1,5 +1,6 @@ package me.oskar3123.staffchat.spigot.command; +import java.util.Objects; import me.oskar3123.staffchat.spigot.Main; import org.bukkit.ChatColor; import org.bukkit.command.Command; @@ -7,103 +8,96 @@ import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.entity.Player; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; -public class StaffChatCommand implements CommandExecutor -{ +public class StaffChatCommand implements CommandExecutor { - private Main plugin; - private FileConfiguration config; + private final Main plugin; + private FileConfiguration config; - public StaffChatCommand(Main plugin) - { - this.plugin = plugin; - config = plugin.getConfig(); + public StaffChatCommand(@NotNull Main plugin) { + this.plugin = plugin; + config = plugin.getConfig(); + } + + @Override + public boolean onCommand( + @NotNull CommandSender sender, + @NotNull Command command, + @NotNull String label, + @NotNull String[] args) { + String noPerm = + clr(config.getString("messages.prefix") + config.getString("messages.nopermission")); + if (!sender.hasPermission(plugin.commandPerm)) { + sender.sendMessage(noPerm); + return true; } - - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) - { - String noPerm = clr(config.getString("messages.prefix") + config.getString("messages.nopermission")); - if (!sender.hasPermission(plugin.commandPerm)) - { - sender.sendMessage(noPerm); - return true; - } - if (args.length < 1) - { - help(sender, label); - return true; - } - if (args[0].equalsIgnoreCase("reload")) - { - if (sender.hasPermission(plugin.reloadPerm)) - { - reload(sender); - } - else - { - sender.sendMessage(noPerm); - } - return true; - } - else if (args[0].equalsIgnoreCase("toggle")) - { - if (sender.hasPermission(plugin.usePerm)) - { - toggle(sender); - } - else - { - sender.sendMessage(noPerm); - } - return true; - } - help(sender, label); - return true; + if (args.length < 1) { + help(sender, label); + return true; } - - private void playerOnly(CommandSender sender) - { - sender.sendMessage(clr(config.getString("messages.prefix") + config.getString("messages.playeronly"))); + if (args[0].equalsIgnoreCase("reload")) { + if (sender.hasPermission(plugin.reloadPerm)) { + reload(sender); + } else { + sender.sendMessage(noPerm); + } + return true; + } else if (args[0].equalsIgnoreCase("toggle")) { + if (sender.hasPermission(plugin.usePerm)) { + toggle(sender); + } else { + sender.sendMessage(noPerm); + } + return true; } + help(sender, label); + return true; + } - private void help(CommandSender sender, String label) - { - String prefix = clr(config.getString("messages.prefix")); - sender.sendMessage(prefix + "Version " + plugin.getDescription().getVersion() + ", made by oskar3123"); - if (sender.hasPermission(plugin.usePerm)) - { - sender.sendMessage(prefix + "Message prefix: " + config.getString("settings.character")); - sender.sendMessage(prefix + "/" + label + " toggle - Toggles auto staffchat"); - } - if (sender.hasPermission(plugin.reloadPerm)) - { - sender.sendMessage(prefix + "/" + label + " reload - Reloads the config file"); - } + private void playerOnly(@NotNull CommandSender sender) { + sender.sendMessage( + clr(config.getString("messages.prefix") + config.getString("messages.playeronly"))); + } + + private void help(@NotNull CommandSender sender, String label) { + String prefix = clr(Objects.requireNonNull(config.getString("messages.prefix", ""))); + sender.sendMessage( + prefix + "Version " + plugin.getDescription().getVersion() + ", made by oskar3123"); + if (sender.hasPermission(plugin.usePerm)) { + sender.sendMessage(prefix + "Message prefix: " + config.getString("settings.character")); + sender.sendMessage(prefix + "/" + label + " toggle - Toggles auto staffchat"); } - - private void reload(CommandSender sender) - { - plugin.reloadConfig(); - config = plugin.getConfig(); - sender.sendMessage(clr(config.getString("messages.prefix") + config.getString("messages.reloaded"))); + if (sender.hasPermission(plugin.reloadPerm)) { + sender.sendMessage(prefix + "/" + label + " reload - Reloads the config file"); } + } - private void toggle(CommandSender sender) - { - if (!(sender instanceof Player)) - { - playerOnly(sender); - return; - } - boolean toggled = plugin.chatListener.togglePlayer(((Player) sender).getUniqueId()); - String state = toggled ? config.getString("messages.onstring") : config.getString("messages.offstring"); - sender.sendMessage(clr(config.getString("messages.prefix") + String.format(config.getString("messages.toggled"), state))); - } - - private String clr(String string) - { - return ChatColor.translateAlternateColorCodes('&', string); + private void reload(@NotNull CommandSender sender) { + plugin.reloadConfig(); + config = plugin.getConfig(); + sender.sendMessage( + clr(config.getString("messages.prefix") + config.getString("messages.reloaded"))); + } + + private void toggle(@NotNull CommandSender sender) { + if (!(sender instanceof Player)) { + playerOnly(sender); + return; } + boolean toggled = plugin.chatListener.togglePlayer(((Player) sender).getUniqueId()); + String state = + toggled ? config.getString("messages.onstring") : config.getString("messages.offstring"); + sender.sendMessage( + clr( + config.getString("messages.prefix") + + String.format( + Objects.requireNonNull(config.getString("messages.toggled", "")), state))); + } + @Contract("_ -> new") + private @NotNull String clr(@NotNull String string) { + return ChatColor.translateAlternateColorCodes('&', string); + } } diff --git a/src/main/java/me/oskar3123/staffchat/spigot/event/StaffChatEvent.java b/src/main/java/me/oskar3123/staffchat/spigot/event/StaffChatEvent.java index 5955e85..f15af12 100644 --- a/src/main/java/me/oskar3123/staffchat/spigot/event/StaffChatEvent.java +++ b/src/main/java/me/oskar3123/staffchat/spigot/event/StaffChatEvent.java @@ -1,73 +1,72 @@ package me.oskar3123.staffchat.spigot.event; +import java.util.Objects; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; -public class StaffChatEvent extends Event implements Cancellable -{ +public class StaffChatEvent extends Event implements Cancellable { - private static HandlerList handlerList = new HandlerList(); - private final Player player; - private boolean cancelled = false; - private String format; - private String message; + private static final HandlerList HANDLER_LIST = new HandlerList(); - public StaffChatEvent(boolean async, Player player, String format, String message) - { - super(async); - this.player = player; - this.format = format; - this.message = message; - } + private final Player player; - public static HandlerList getHandlerList() - { - return handlerList; - } + private boolean cancelled = false; + private String format; + private String message; - public String getFormat() - { - return format; - } + public StaffChatEvent( + boolean async, @NotNull Player player, @NotNull String format, @NotNull String message) { + super(async); + this.player = player; + this.format = format; + this.message = message; + } - public void setFormat(String format) - { - this.format = format; - } + /** + * Required by BungeeCord + * + * @return the handler list + */ + @SuppressWarnings("unused") + public static @NotNull HandlerList getHandlerList() { + return HANDLER_LIST; + } - public Player getPlayer() - { - return player; - } + public @NotNull String getFormat() { + return format; + } - public String getMessage() - { - return message; - } + public void setFormat(String format) { + this.format = Objects.requireNonNull(format); + } - public void setMessage(String message) - { - this.message = message; - } + public @NotNull String getMessage() { + return message; + } - @Override - public HandlerList getHandlers() - { - return handlerList; - } + public void setMessage(String message) { + this.message = Objects.requireNonNull(message); + } - @Override - public boolean isCancelled() - { - return cancelled; - } + public @NotNull Player getPlayer() { + return player; + } - @Override - public void setCancelled(boolean cancelled) - { - this.cancelled = cancelled; - } + @Override + public @NotNull HandlerList getHandlers() { + return HANDLER_LIST; + } + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } } diff --git a/src/main/java/me/oskar3123/staffchat/spigot/listener/ChatListener.java b/src/main/java/me/oskar3123/staffchat/spigot/listener/ChatListener.java index 85f8cb4..c3862de 100644 --- a/src/main/java/me/oskar3123/staffchat/spigot/listener/ChatListener.java +++ b/src/main/java/me/oskar3123/staffchat/spigot/listener/ChatListener.java @@ -3,6 +3,15 @@ package me.oskar3123.staffchat.spigot.listener; import com.google.common.io.ByteArrayDataInput; import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; import me.oskar3123.staffchat.spigot.Main; import me.oskar3123.staffchat.spigot.event.StaffChatEvent; import me.oskar3123.staffchat.util.StringUtils; @@ -14,142 +23,119 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.plugin.messaging.PluginMessageListener; +import org.jetbrains.annotations.NotNull; -import java.io.*; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; +public class ChatListener implements Listener, PluginMessageListener { -public class ChatListener implements Listener, PluginMessageListener -{ + private final Main plugin; + private final Set toggledPlayers = new HashSet<>(); - private Main plugin; - private Set toggledPlayers = new HashSet<>(); + public ChatListener(@NotNull Main plugin) { + this.plugin = plugin; + } - public ChatListener(Main plugin) - { - this.plugin = plugin; + @EventHandler + public void chat(@NotNull AsyncPlayerChatEvent event) { + if (!event.getPlayer().hasPermission(plugin.usePerm)) { + return; } - @EventHandler - public void chat(AsyncPlayerChatEvent event) - { - if (!event.getPlayer().hasPermission(plugin.usePerm)) - { - return; - } - - FileConfiguration config = plugin.getConfig(); - String character = config.getString("settings.character"); - boolean isToggled = toggledPlayers.contains(event.getPlayer().getUniqueId()); - if (!event.getMessage().startsWith(character) && !isToggled) - { - return; - } - - String format = config.getString("settings.format"); - String message = event.getMessage().substring(isToggled ? 0 : character.length()).trim(); - if (config.getBoolean("settings.replaceplaceholdersinmessage")) - { - message = plugin.replacePlaceholders(event.getPlayer(), message); - } - - StaffChatEvent chatEvent = new StaffChatEvent(event.isAsynchronous(), event.getPlayer(), format, message); - Bukkit.getServer().getPluginManager().callEvent(chatEvent); - if (chatEvent.isCancelled()) - { - return; - } - format = chatEvent.getFormat(); - message = chatEvent.getMessage(); - - format = plugin.replacePlaceholders(event.getPlayer(), format); - format = format.replaceAll("\\{NAME\\}", StringUtils.sanitize(event.getPlayer().getName())); - format = ChatColor.translateAlternateColorCodes('&', format); - format = format.replaceAll("\\{MESSAGE\\}", StringUtils.sanitize(message)); - final String finalMessage = format; - - if (plugin.getConfig().getBoolean("settings.sendmessagestoallservers")) - { - sendForwardPluginMessage(event.getPlayer(), finalMessage); - } - sendStaffChatMessage(finalMessage); - - event.setCancelled(true); + FileConfiguration config = plugin.getConfig(); + String character = Objects.requireNonNull(config.getString("settings.character", "@")); + boolean isToggled = toggledPlayers.contains(event.getPlayer().getUniqueId()); + if (!event.getMessage().startsWith(character) && !isToggled) { + return; } - @Override - public void onPluginMessageReceived(String channel, Player player, byte[] message) - { - if (!channel.equals("BungeeCord")) { - return; - } - ByteArrayDataInput in = ByteStreams.newDataInput(message); - String subChannel = in.readUTF(); - if (!subChannel.equals("StaffChat")) - { - return; - } - short len = in.readShort(); - byte[] msgbytes = new byte[len]; - in.readFully(msgbytes); - - DataInputStream msgin = new DataInputStream(new ByteArrayInputStream(msgbytes)); - String actualMessage; - try - { - actualMessage = msgin.readUTF(); - } - catch (IOException e) - { - e.printStackTrace(); - plugin.getLogger().severe("Failed to read plugin message from bungeecord"); - return; - } - sendStaffChatMessage(actualMessage); + String format = Objects.requireNonNull(config.getString("settings.format", "")); + String message = event.getMessage().substring(isToggled ? 0 : character.length()).trim(); + if (config.getBoolean("settings.replaceplaceholdersinmessage")) { + message = plugin.replacePlaceholders(event.getPlayer(), message); } - private void sendStaffChatMessage(final String message) - { - Bukkit.getOnlinePlayers().stream() - .filter(p -> p.hasPermission(plugin.seePerm)) - .forEach(p -> p.sendMessage(message)); - plugin.getLogger().info(ChatColor.stripColor(message)); + StaffChatEvent chatEvent = + new StaffChatEvent(event.isAsynchronous(), event.getPlayer(), format, message); + Bukkit.getServer().getPluginManager().callEvent(chatEvent); + if (chatEvent.isCancelled()) { + return; } + format = chatEvent.getFormat(); + message = chatEvent.getMessage(); - private void sendForwardPluginMessage(Player player, final String finalMessage) - { - ByteArrayDataOutput out = ByteStreams.newDataOutput(); - out.writeUTF("Forward"); - out.writeUTF("ONLINE"); - out.writeUTF("StaffChat"); - ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); - DataOutputStream dataStream = new DataOutputStream(byteStream); - try - { - dataStream.writeUTF(finalMessage); - } - catch (IOException e) - { - e.printStackTrace(); - plugin.getLogger().severe("Failed to send plugin message to bungeecord"); - return; - } - byte[] data = byteStream.toByteArray(); - out.writeShort(data.length); - out.write(data); - player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray()); + format = plugin.replacePlaceholders(event.getPlayer(), format); + format = format.replaceAll("\\{NAME}", StringUtils.sanitize(event.getPlayer().getName())); + format = ChatColor.translateAlternateColorCodes('&', format); + format = format.replaceAll("\\{MESSAGE}", StringUtils.sanitize(message)); + final String finalMessage = format; + + if (plugin.getConfig().getBoolean("settings.sendmessagestoallservers")) { + sendForwardPluginMessage(event.getPlayer(), finalMessage); } + sendStaffChatMessage(finalMessage); - public boolean togglePlayer(UUID player) - { - if (toggledPlayers.contains(player)) - { - toggledPlayers.remove(player); - return false; - } - toggledPlayers.add(player); - return true; + event.setCancelled(true); + } + + @Override + public void onPluginMessageReceived( + @NotNull String channel, @NotNull Player player, byte[] message) { + if (!channel.equals("BungeeCord")) { + return; } + ByteArrayDataInput in = ByteStreams.newDataInput(message); + String subChannel = in.readUTF(); + if (!subChannel.equals("StaffChat")) { + return; + } + short len = in.readShort(); + byte[] msgbytes = new byte[len]; + in.readFully(msgbytes); + DataInputStream msgin = new DataInputStream(new ByteArrayInputStream(msgbytes)); + String actualMessage; + try { + actualMessage = msgin.readUTF(); + } catch (IOException e) { + e.printStackTrace(); + plugin.getLogger().severe("Failed to read plugin message from bungeecord"); + return; + } + sendStaffChatMessage(actualMessage); + } + + private void sendStaffChatMessage(@NotNull String message) { + Bukkit.getOnlinePlayers().stream() + .filter(p -> p.hasPermission(plugin.seePerm)) + .forEach(p -> p.sendMessage(message)); + plugin.getLogger().info(ChatColor.stripColor(message)); + } + + private void sendForwardPluginMessage(@NotNull Player player, @NotNull String message) { + ByteArrayDataOutput out = ByteStreams.newDataOutput(); + out.writeUTF("Forward"); + out.writeUTF("ONLINE"); + out.writeUTF("StaffChat"); + ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); + DataOutputStream dataStream = new DataOutputStream(byteStream); + try { + dataStream.writeUTF(message); + } catch (IOException e) { + e.printStackTrace(); + plugin.getLogger().severe("Failed to send plugin message to bungeecord"); + return; + } + byte[] data = byteStream.toByteArray(); + out.writeShort(data.length); + out.write(data); + player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray()); + } + + public boolean togglePlayer(@NotNull UUID player) { + if (toggledPlayers.contains(player)) { + toggledPlayers.remove(player); + return false; + } + toggledPlayers.add(player); + return true; + } } diff --git a/src/main/java/me/oskar3123/staffchat/util/StringUtils.java b/src/main/java/me/oskar3123/staffchat/util/StringUtils.java index 6ee0783..2c9095a 100644 --- a/src/main/java/me/oskar3123/staffchat/util/StringUtils.java +++ b/src/main/java/me/oskar3123/staffchat/util/StringUtils.java @@ -1,13 +1,10 @@ package me.oskar3123.staffchat.util; -public class StringUtils -{ - - public static String sanitize(String string) - { - string = string.replaceAll("\\\\", "\\\\\\\\"); - string = string.replaceAll("\\$", "\\\\\\$"); - return string; - } +public class StringUtils { + public static String sanitize(String string) { + string = string.replaceAll("\\\\", "\\\\\\\\"); + string = string.replaceAll("\\$", "\\\\\\$"); + return string; + } } diff --git a/src/main/resources/bungee.yml b/src/main/resources/bungee.yml index 2873305..87682a5 100644 --- a/src/main/resources/bungee.yml +++ b/src/main/resources/bungee.yml @@ -1,4 +1,4 @@ name: StaffChat -authors: [oskar3123] +author: oskar3123 main: me.oskar3123.staffchat.bungee.BungeeMain -version: 1.3.0 +version: SNAPSHOT diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 785d220..7fca06b 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,9 +1,9 @@ name: StaffChat -authors: [oskar3123] +authors: [ oskar3123 ] main: me.oskar3123.staffchat.spigot.Main api-version: 1.13 -version: 1.3.1 -softdepend: [PlaceholderAPI] +version: SNAPSHOT +softdepend: [ PlaceholderAPI ] commands: staffchat: usage: /