diff --git a/Bukkit/build.gradle b/Bukkit/build.gradle index ef26dbb05..f9998521f 100644 --- a/Bukkit/build.gradle +++ b/Bukkit/build.gradle @@ -13,7 +13,6 @@ dependencies { implementation 'com.onarandombox.multiversecore:Multiverse-Core:3.0.0-SNAPSHOT' implementation 'org.spigotmc:spigot-api:1.14-pre5-SNAPSHOT' compile(group: 'com.sk89q.worldedit', name: 'worldedit-bukkit', version: '7.0.0-SNAPSHOT') - compile(group: 'org.bstats', name: 'bstats-bukkit', version: '1.4') compile("net.milkbowl.vault:VaultAPI:1.7") { exclude module: 'bukkit' } @@ -37,7 +36,6 @@ jar.enabled = false shadowJar { dependencies { include(dependency(':Core')) - include(dependency('org.bstats:bstats-bukkit:1.4')) // update notification stuff include(dependency('com.github.Sauilitired:Jenkins4J:2.0-SNAPSHOT')) include(dependency('com.squareup.retrofit2:retrofit:2.4.0')) diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/BukkitMain.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/BukkitMain.java index b8cc83032..8a4574a0d 100644 --- a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/BukkitMain.java +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/BukkitMain.java @@ -1,11 +1,20 @@ package com.github.intellectualsites.plotsquared.bukkit; import com.github.intellectualsites.plotsquared.bukkit.generator.BukkitPlotGenerator; -import com.github.intellectualsites.plotsquared.bukkit.listeners.*; +import com.github.intellectualsites.plotsquared.bukkit.listeners.ChunkListener; +import com.github.intellectualsites.plotsquared.bukkit.listeners.EntitySpawnListener; +import com.github.intellectualsites.plotsquared.bukkit.listeners.PlayerEvents; +import com.github.intellectualsites.plotsquared.bukkit.listeners.PlotPlusListener; +import com.github.intellectualsites.plotsquared.bukkit.listeners.SingleWorldListener; +import com.github.intellectualsites.plotsquared.bukkit.listeners.WorldEvents; import com.github.intellectualsites.plotsquared.bukkit.titles.DefaultTitle; import com.github.intellectualsites.plotsquared.bukkit.util.*; import com.github.intellectualsites.plotsquared.bukkit.util.block.BukkitLocalQueue; -import com.github.intellectualsites.plotsquared.bukkit.uuid.*; +import com.github.intellectualsites.plotsquared.bukkit.uuid.DefaultUUIDWrapper; +import com.github.intellectualsites.plotsquared.bukkit.uuid.FileUUIDHandler; +import com.github.intellectualsites.plotsquared.bukkit.uuid.LowerOfflineUUIDWrapper; +import com.github.intellectualsites.plotsquared.bukkit.uuid.OfflineUUIDWrapper; +import com.github.intellectualsites.plotsquared.bukkit.uuid.SQLUUIDHandler; import com.github.intellectualsites.plotsquared.configuration.ConfigurationSection; import com.github.intellectualsites.plotsquared.plot.IPlotMain; import com.github.intellectualsites.plotsquared.plot.PlotSquared; @@ -16,7 +25,12 @@ import com.github.intellectualsites.plotsquared.plot.generator.GeneratorWrapper; import com.github.intellectualsites.plotsquared.plot.generator.HybridGen; import com.github.intellectualsites.plotsquared.plot.generator.HybridUtils; import com.github.intellectualsites.plotsquared.plot.generator.IndependentPlotGenerator; -import com.github.intellectualsites.plotsquared.plot.object.*; +import com.github.intellectualsites.plotsquared.plot.object.BlockRegistry; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotArea; +import com.github.intellectualsites.plotsquared.plot.object.PlotId; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.object.SetupObject; import com.github.intellectualsites.plotsquared.plot.object.chat.PlainChatManager; import com.github.intellectualsites.plotsquared.plot.object.worlds.PlotAreaManager; import com.github.intellectualsites.plotsquared.plot.object.worlds.SinglePlotArea; @@ -30,8 +44,6 @@ import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.extension.platform.Capability; import lombok.Getter; import lombok.NonNull; -import org.bstats.bukkit.Metrics; -import org.bukkit.Location; import org.bukkit.*; import org.bukkit.command.PluginCommand; import org.bukkit.entity.Entity; @@ -48,7 +60,11 @@ import org.bukkit.plugin.java.JavaPlugin; import javax.annotation.Nullable; import java.io.File; import java.lang.reflect.Method; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; import static com.github.intellectualsites.plotsquared.plot.util.ReflectionUtils.getRefClass; @@ -175,11 +191,7 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain getLogger().warning("Update checking disabled. Skipping."); } - if (Settings.Enabled_Components.METRICS) { - this.startMetrics(); - } else { - PlotSquared.log(Captions.CONSOLE_PLEASE_ENABLE_METRICS.f(getPluginName())); - } + this.startMetrics(); if (Settings.Enabled_Components.WORLDS) { TaskManager.IMP.taskRepeat(this::unload, 20); try { @@ -660,14 +672,8 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain return; } this.metricsStarted = true; - try { - System.setProperty("bstats.relocatecheck", - "false"); // We do not want to relocate the package... - Metrics metrics = new Metrics(this);// bstats - PlotSquared.log(Captions.PREFIX + "&6Metrics enabled."); - } catch (Throwable e) { - e.printStackTrace(); - } + Metrics metrics = new Metrics(this);// bstats + PlotSquared.log(Captions.PREFIX + "&6Metrics enabled."); } @Override public ChunkManager initChunkManager() { diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/Metrics.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/Metrics.java new file mode 100644 index 000000000..ff6e1b310 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/Metrics.java @@ -0,0 +1,695 @@ +package com.github.intellectualsites.plotsquared.bukkit.util; + +import org.bukkit.Bukkit; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.RegisteredServiceProvider; +import org.bukkit.plugin.ServicePriority; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; + +import javax.net.ssl.HttpsURLConnection; +import java.io.*; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.Callable; +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! + */ +@SuppressWarnings({"WeakerAccess", "unused"}) +public class Metrics { + + static { + // You can use the property to disable the check in your test environment + if (System.getProperty("bstats.relocatecheck") == null || !System.getProperty("bstats.relocatecheck").equals("false")) { + // Maven's Relocate is clever and changes strings, too. So we have to use this little "trick" ... :D + final String defaultPackage = new String( + new byte[]{'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's', '.', 'b', 'u', 'k', 'k', 'i', 't'}); + 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 (Metrics.class.getPackage().getName().equals(defaultPackage) || Metrics.class.getPackage().getName().equals(examplePackage)) { + throw new IllegalStateException("bStats Metrics class has not been relocated correctly!"); + } + } + } + + // 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"; + + // Is bStats enabled on this server? + private boolean enabled; + + // Should failed requests be logged? + private static boolean logFailedRequests; + + // Should the sent data be logged? + private static boolean logSentData; + + // Should the response text be logged? + private static boolean logResponseStatusText; + + // The uuid of the server + private static String serverUUID; + + // The plugin + private final Plugin plugin; + + // A list with all custom charts + private final List charts = new ArrayList<>(); + + /** + * Class constructor. + * + * @param plugin The plugin which stats should be submitted. + */ + public Metrics(Plugin 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); + // Should the sent data be logged? + config.addDefault("logSentData", false); + // Should the response text be logged? + config.addDefault("logResponseStatusText", 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 + enabled = config.getBoolean("enabled", true); + serverUUID = config.getString("serverUuid"); + logFailedRequests = config.getBoolean("logFailedRequests", false); + logSentData = config.getBoolean("logSentData", false); + logResponseStatusText = config.getBoolean("logResponseStatusText", false); + + if (enabled) { + 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(Metrics.class, this, plugin, ServicePriority.Normal); + if (!found) { + // We are the first! + startSubmitting(); + } + } + } + + /** + * Checks if bStats is enabled. + * + * @return Whether bStats is enabled or not. + */ + public boolean isEnabled() { + return enabled; + } + + /** + * Adds a custom chart. + * + * @param chart The chart to add. + */ + public void addCustomChart(CustomChart chart) { + if (chart == null) { + throw new IllegalArgumentException("Chart cannot be null!"); + } + charts.add(chart); + } + + /** + * 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, () -> 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.put("pluginName", pluginName); // Append the name of the plugin + data.put("pluginVersion", pluginVersion); // Append the version of the plugin + JSONArray customCharts = new JSONArray(); + for (CustomChart customChart : charts) { + // Add the data of the custom charts + JSONObject chart = customChart.getRequestJsonObject(); + if (chart == null) { // If the chart is null, we skip it + continue; + } + customCharts.add(chart); + } + data.put("customCharts", customCharts); + + return data; + } + + /** + * Gets the server specific data. + * + * @return The server specific data. + */ + private JSONObject getServerData() { + // Minecraft specific data + int playerAmount; + try { + // Around MC 1.8 the return type was changed to a collection from an array, + // This fixes java.lang.NoSuchMethodError: org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection; + Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers"); + playerAmount = onlinePlayersMethod.getReturnType().equals(Collection.class) + ? ((Collection) onlinePlayersMethod.invoke(Bukkit.getServer())).size() + : ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length; + } catch (Exception e) { + playerAmount = Bukkit.getOnlinePlayers().size(); // Just use the new method if the Reflection failed + } + int onlineMode = Bukkit.getOnlineMode() ? 1 : 0; + String bukkitVersion = Bukkit.getVersion(); + + // 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 :) + + for (RegisteredServiceProvider provider : Bukkit.getServicesManager().getRegistrations(service)) { + try { + pluginData.add(provider.getService().getMethod("getPluginData").invoke(provider.getProvider())); + } catch (NullPointerException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { } + } + } catch (NoSuchFieldException 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(plugin, data); + } catch (Exception e) { + // Something went wrong! :( + if (logFailedRequests) { + plugin.getLogger().log(Level.WARNING, "Could not submit plugin stats of " + plugin.getName(), e); + } + } + } + }).start(); + } + + /** + * Sends the data to the bStats server. + * + * @param plugin Any plugin. It's just used to get a logger instance. + * @param data The data to send. + * @throws Exception If the request failed. + */ + private static void sendData(Plugin plugin, 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!"); + } + if (logSentData) { + plugin.getLogger().info("Sending data to bStats: " + data.toString()); + } + 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(); + + InputStream inputStream = connection.getInputStream(); + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); + + StringBuilder builder = new StringBuilder(); + String line; + while ((line = bufferedReader.readLine()) != null) { + builder.append(line); + } + bufferedReader.close(); + if (logResponseStatusText) { + plugin.getLogger().info("Sent data to bStats and received response: " + builder.toString()); + } + } + + /** + * 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(StandardCharsets.UTF_8)); + gzip.close(); + return outputStream.toByteArray(); + } + + /** + * Represents a custom chart. + */ + public static abstract class CustomChart { + + // The id of the chart + final String chartId; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + */ + CustomChart(String chartId) { + if (chartId == null || chartId.isEmpty()) { + throw new IllegalArgumentException("ChartId cannot be null or empty!"); + } + this.chartId = chartId; + } + + private JSONObject getRequestJsonObject() { + JSONObject chart = new JSONObject(); + chart.put("chartId", chartId); + try { + JSONObject data = getChartData(); + if (data == null) { + // If the data is null we don't send the chart. + return null; + } + chart.put("data", data); + } catch (Throwable t) { + if (logFailedRequests) { + Bukkit.getLogger().log(Level.WARNING, "Failed to get data for custom chart with id " + chartId, t); + } + return null; + } + return chart; + } + + protected abstract JSONObject getChartData() throws Exception; + + } + + /** + * Represents a custom simple pie. + */ + public static class SimplePie extends CustomChart { + + private final Callable callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SimplePie(String chartId, Callable callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JSONObject getChartData() throws Exception { + JSONObject data = new JSONObject(); + String value = callable.call(); + if (value == null || value.isEmpty()) { + // Null = skip the chart + return null; + } + data.put("value", value); + return data; + } + } + + /** + * Represents a custom advanced pie. + */ + public static class AdvancedPie extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public AdvancedPie(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JSONObject getChartData() throws Exception { + JSONObject data = new JSONObject(); + JSONObject values = new JSONObject(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + continue; // Skip this invalid + } + allSkipped = false; + values.put(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + data.put("values", values); + return data; + } + } + + /** + * Represents a custom drilldown pie. + */ + public static class DrilldownPie extends CustomChart { + + private final Callable>> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public DrilldownPie(String chartId, Callable>> callable) { + super(chartId); + this.callable = callable; + } + + @Override + public JSONObject getChartData() throws Exception { + JSONObject data = new JSONObject(); + JSONObject values = new JSONObject(); + Map> map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean reallyAllSkipped = true; + for (Map.Entry> entryValues : map.entrySet()) { + JSONObject value = new JSONObject(); + boolean allSkipped = true; + for (Map.Entry valueEntry : map.get(entryValues.getKey()).entrySet()) { + value.put(valueEntry.getKey(), valueEntry.getValue()); + allSkipped = false; + } + if (!allSkipped) { + reallyAllSkipped = false; + values.put(entryValues.getKey(), value); + } + } + if (reallyAllSkipped) { + // Null = skip the chart + return null; + } + data.put("values", values); + return data; + } + } + + /** + * Represents a custom single line chart. + */ + public static class SingleLineChart extends CustomChart { + + private final Callable callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SingleLineChart(String chartId, Callable callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JSONObject getChartData() throws Exception { + JSONObject data = new JSONObject(); + int value = callable.call(); + if (value == 0) { + // Null = skip the chart + return null; + } + data.put("value", value); + return data; + } + + } + + /** + * Represents a custom multi line chart. + */ + public static class MultiLineChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public MultiLineChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JSONObject getChartData() throws Exception { + JSONObject data = new JSONObject(); + JSONObject values = new JSONObject(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + continue; // Skip this invalid + } + allSkipped = false; + values.put(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + data.put("values", values); + return data; + } + + } + + /** + * Represents a custom simple bar chart. + */ + public static class SimpleBarChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SimpleBarChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JSONObject getChartData() throws Exception { + JSONObject data = new JSONObject(); + JSONObject values = new JSONObject(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + for (Map.Entry entry : map.entrySet()) { + JSONArray categoryValues = new JSONArray(); + categoryValues.add(entry.getValue()); + values.put(entry.getKey(), categoryValues); + } + data.put("values", values); + return data; + } + + } + + /** + * Represents a custom advanced bar chart. + */ + public static class AdvancedBarChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public AdvancedBarChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JSONObject getChartData() throws Exception { + JSONObject data = new JSONObject(); + JSONObject values = new JSONObject(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue().length == 0) { + continue; // Skip this invalid + } + allSkipped = false; + JSONArray categoryValues = new JSONArray(); + for (int categoryValue : entry.getValue()) { + categoryValues.add(categoryValue); + } + values.put(entry.getKey(), categoryValues); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + data.put("values", values); + return data; + } + } + +} diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/PlotSquared.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/PlotSquared.java index 8823118b1..7c94060fd 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/PlotSquared.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/PlotSquared.java @@ -9,7 +9,11 @@ import com.github.intellectualsites.plotsquared.plot.config.Captions; import com.github.intellectualsites.plotsquared.plot.config.Configuration; import com.github.intellectualsites.plotsquared.plot.config.Settings; import com.github.intellectualsites.plotsquared.plot.config.Storage; -import com.github.intellectualsites.plotsquared.plot.database.*; +import com.github.intellectualsites.plotsquared.plot.database.DBFunc; +import com.github.intellectualsites.plotsquared.plot.database.Database; +import com.github.intellectualsites.plotsquared.plot.database.MySQL; +import com.github.intellectualsites.plotsquared.plot.database.SQLManager; +import com.github.intellectualsites.plotsquared.plot.database.SQLite; import com.github.intellectualsites.plotsquared.plot.generator.GeneratorWrapper; import com.github.intellectualsites.plotsquared.plot.generator.HybridPlotWorld; import com.github.intellectualsites.plotsquared.plot.generator.HybridUtils; @@ -157,11 +161,6 @@ import java.util.zip.ZipInputStream; } // Required this.IMP.registerWorldEvents(); - if (Settings.Enabled_Components.METRICS) { - this.IMP.startMetrics(); - } else { - PlotSquared.log(Captions.CONSOLE_PLEASE_ENABLE_METRICS.f(IMP.getPluginName())); - } if (Settings.Enabled_Components.CHUNK_PROCESSOR) { this.IMP.registerChunkProcessor(); } diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/config/Captions.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/config/Captions.java index a5a1c559c..2037bcdf1 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/config/Captions.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/config/Captions.java @@ -5,6 +5,7 @@ import com.github.intellectualsites.plotsquared.configuration.ConfigurationSecti import com.github.intellectualsites.plotsquared.configuration.file.YamlConfiguration; import com.github.intellectualsites.plotsquared.plot.PlotSquared; import com.github.intellectualsites.plotsquared.plot.util.StringMan; + import java.io.File; import java.io.IOException; import java.util.EnumSet; @@ -36,7 +37,8 @@ public enum Captions { FLAG_VEHICLE_BREAK("vehicle-break", "static.flags"), FLAG_HOSTILE_INTERACT("hostile-interact", "static.flags"), FLAG_DEVICE_INTERACT("device-interact", "static.flags"), - FLAG_ANIMAL_INTERACT("animal-interact", "static.flags"), FLAG_VEHICLE_USE("vehicle-use", "static.flags"), + FLAG_ANIMAL_INTERACT("animal-interact", "static.flags"), + FLAG_VEHICLE_USE("vehicle-use", "static.flags"), FLAG_VEHICLE_PLACE("vehicle-place", "static.flags"), FLAG_PLAYER_INTERACT("player-interact", "static.flags"), FLAG_TAMED_INTERACT("tamed-interact", "static.flags"), @@ -147,24 +149,19 @@ public enum Captions { PERMISSION_ADMIN_COMMAND_SCHEMATIC_PASTE("plots.admin.command.schematic.paste", "static.permissions"), PERMISSION_SCHEMATIC_PASTE("plots.schematic.paste", "static.permissions"), PERMISSION_SCHEMATIC_LIST("plots.schematic.list", "static.permissions"), - PERMISSION_SCHEMATIC_SAVE("plots.schematic.save", "static.permissions"), PERMISSION_ADMIN_COMMAND_SCHEMATIC_SAVE("plots.admin.command.schematic.save", "static.permissions"), - PERMISSION_SET_COMPONENT("plots.set.%s0", "static.permissions"), - PERMISSION_ADMIN_COMMAND( - "plots.admin.command.%s0", "static.permissions"), + PERMISSION_ADMIN_COMMAND("plots.admin.command.%s0", "static.permissions"), PERMISSION_ADMIN_COMMAND_UNLINK("plots.ad2min.command.unlink", "static.permissions"), PERMISSION_VISIT_UNOWNED("plots.visit.unowned", "static.permissions"), PERMISSION_VISIT_OWNED("plots.visit.owned", "static.permissions"), PERMISSION_SHARED("plots.visit.shared", "static.permissions"), PERMISSION_VISIT_OTHER("plots.visit.other", "static.permissions"), PERMISSION_HOME("plots.home", "static.permissions"), - PERMISSION_ALIAS_SET_OBSOLETE("plots.set.alias", "static.permissions"), // Note this is for backwards compatibility PERMISSION_ALIAS_SET("plots.alias.set", "static.permissions"), PERMISSION_ALIAS_REMOVE("plots.alias.remove", "static.permissions"), - /* * Static console */ @@ -173,49 +170,44 @@ public enum Captions { + "and security. %s0 will require Java 8 in a future update.", "static.console"), CONSOLE_PLEASE_ENABLE_METRICS( "&dPlease enable metrics for %s0. Using metrics improves plugin stability, performance, and features. " - + "Bug fixes and new features are influenced on metrics.", "static.console"), /* + + "Bug fixes and new features are influenced on metrics.", "static.console"), + /* * Confirm */ - - EXPIRED_CONFIRM("$2Confirmation has expired, please run the command again!", - "Confirm"), FAILED_CONFIRM("$2You have no pending actions to confirm!", "Confirm"), - + EXPIRED_CONFIRM("$2Confirmation has expired, please run the command again!", "Confirm"), + FAILED_CONFIRM("$2You have no pending actions to confirm!", "Confirm"), REQUIRES_CONFIRM( "$2Are you sure you wish to execute: $1%s$2?&-$2This cannot be undone! If you are sure: $1/plot confirm", - "Confirm"), /* + "Confirm"), + /* * Move */ - MOVE_SUCCESS("$4Successfully moved plot.", "Move"), COPY_SUCCESS("$4Successfully copied plot.", "Move"), - - REQUIRES_UNOWNED("$2The location specified is already occupied.", "Move"), /* + REQUIRES_UNOWNED("$2The location specified is already occupied.", "Move"), + /* * Area Create */ - REQUIRES_UNMERGED("$2The plot cannot be merged", "debug"), - - SET_ATTRIBUTE("$4Successfully set %s0 set to %s1", "Set"), /* + SET_ATTRIBUTE("$4Successfully set %s0 set to %s1", "Set"), + /* * Web */ - - GENERATING_LINK("$1Processing plot...", "Web"), GENERATING_LINK_FAILED( + GENERATING_LINK("$1Processing plot...", "Web"), + GENERATING_LINK_FAILED( "$2Failed to generate download link!", "Web"), - - SAVE_FAILED("$2Failed to save", "Web"), LOAD_NULL( - "$2Please use $4/plot load $2to get a list of schematics", "Web"), - - LOAD_FAILED("$2Failed to load schematic", "Web"), LOAD_LIST( - "$2To load a schematic, use $1/plot load #", "Web"), - - SAVE_SUCCESS("$1Successfully saved!", "Web"), /* + SAVE_FAILED("$2Failed to save", "Web"), + LOAD_NULL("$2Please use $4/plot load $2to get a list of schematics", "Web"), + LOAD_FAILED("$2Failed to load schematic", "Web"), + LOAD_LIST("$2To load a schematic, use $1/plot load #", "Web"), + SAVE_SUCCESS("$1Successfully saved!", "Web"), + /* * Compass */ - - COMPASS_TARGET("$4Successfully targeted plot with compass", "Compass"), /* + COMPASS_TARGET("$4Successfully targeted plot with compass", "Compass"), + /* * Cluster */ - CLUSTER_AVAILABLE_ARGS( "$1The following sub commands are available: $4list$2, $4create$2, $4delete$2, $4resize$2, $4invite$2, $4kick$2, $4leave$2, " + "$4members$2, $4info$2, $4tp$2, $4sethome", "Cluster"), CLUSTER_LIST_HEADING( @@ -252,23 +244,22 @@ public enum Captions { CLUSTER_INFO( "$1Current cluster: $2%id%&-$1Name: $2%name%&-$1Owner: $2%owner%&-$1Size: $2%size%&-$1Rights: $2%rights%", - "Cluster"), /* + "Cluster"), + /* * Border */ - - BORDER("$2You are outside the current map border", "Border"), /* - * Unclaim + BORDER("$2You are outside the current map border", "Border"), + /* + * Un-claim */ - UNCLAIM_SUCCESS("$4You successfully unclaimed the plot.", "Unclaim"), UNCLAIM_FAILED( - "$2Could not unclaim the plot", "Unclaim"), /* + "$2Could not unclaim the plot", "Unclaim"), + /* * WorldEdit masks */ - WORLDEDIT_DELAYED("$2Please wait while we process your WorldEdit action...", "WorldEdit Masks"), WORLDEDIT_RUN("$2Apologies for the delay. Now executing: %s", "WorldEdit Masks"), - REQUIRE_SELECTION_IN_MASK( "$2%s of your selection is not within your plot mask. You can only make edits within your plot.", "WorldEdit Masks"), WORLDEDIT_VOLUME( @@ -290,26 +281,26 @@ public enum Captions { GAMEMODE_WAS_BYPASSED("$1You bypassed the GameMode ($2{gamemode}$1) $1set for $2{plot}", "GameMode"), HEIGHT_LIMIT("$1This plot area has a height limit of $2{limit}", - "Height Limit"), /* + "Height Limit"), + /* * Records */ - RECORD_PLAY("$2%player $2started playing record $1%name", "Records"), NOTIFY_ENTER( "$2%player $2entered your plot ($1%plot$2)", "Records"), - NOTIFY_LEAVE("$2%player $2left your plot ($1%plot$2)", "Records"), /* + NOTIFY_LEAVE("$2%player $2left your plot ($1%plot$2)", "Records"), + /* * Swap */ - SWAP_OVERLAP("$2The proposed areas are not allowed to overlap", "Swap"), SWAP_DIMENSIONS( "$2The proposed areas must have comparable dimensions", "Swap"), SWAP_SYNTAX("$2/plot swap ", "Swap"), SWAP_SUCCESS("$4Successfully swapped plots", "Swap"), - STARTED_SWAP("$2Started plot swap task. You will be notified when it finishes", "Swap"), /* + STARTED_SWAP("$2Started plot swap task. You will be notified when it finishes", "Swap"), + /* * Comment */ - INBOX_NOTIFICATION("%s unread messages. Use /plot inbox", "Comment"), NOT_VALID_INBOX_INDEX( "$2No comment at index %s", "Comment"), @@ -326,13 +317,12 @@ public enum Captions { "$4A comment has been left", "Comment"), COMMENT_HEADER("$2&m---------&r $1Comments $2&m---------&r", "Comment"), INBOX_EMPTY( - "$2No comments", "Comment"), /* + "$2No comments", "Comment"), + /* * Console */ - NOT_CONSOLE("$2For safety reasons, this command can only be executed by console.", "Console"), IS_CONSOLE("$2This command can only be executed by a player.", "Console"), - /* Inventory */ @@ -340,7 +330,6 @@ public enum Captions { "Inventory"), INVENTORY_CATEGORY("&cCategory: &6{category}", "Inventory"), - /* * Clipboard */ @@ -355,17 +344,17 @@ public enum Captions { CLIPBOARD_INFO( "$2Current Selection - Plot ID: $1%id$2, Width: $1%width$2, Total Blocks: $1%total$2", - "Clipboard"), /* + "Clipboard"), + /* * Toggle */ - TOGGLE_ENABLED("$2Enabled setting: %s", "Toggle"), TOGGLE_DISABLED("$2Disabled setting: %s", "Toggle"), - COMMAND_BLOCKED("$2That command is not allowed in this plot", "Blocked Command"), /* + COMMAND_BLOCKED("$2That command is not allowed in this plot", "Blocked Command"), + /* * Done */ - DONE_ALREADY_DONE("$2This plot is already marked as done", "Done"), DONE_NOT_DONE( "$2This plot is not marked as done.", "Done"), @@ -373,7 +362,8 @@ public enum Captions { "$2This plot is too simple. Please add more detail before using this command.", "Done"), DONE_SUCCESS("$1Successfully marked this plot as done.", "Done"), - DONE_REMOVED("$1You may now continue building in this plot.", "Done"), /* + DONE_REMOVED("$1You may now continue building in this plot.", "Done"), + /* * Ratings */ @@ -389,12 +379,14 @@ public enum Captions { RATING_NOT_YOUR_OWN("$2You cannot rate your own plot", "Ratings"), RATING_NOT_DONE( "$2You can only rate finished plots.", "Ratings"), - RATING_NOT_OWNED("$2You cannot rate a plot that is not claimed by anyone", "Ratings"), /* + RATING_NOT_OWNED("$2You cannot rate a plot that is not claimed by anyone", "Ratings"), + /* * Tutorial */ RATE_THIS("$2Rate this plot!", "Tutorial"), COMMENT_THIS( - "$2Leave some feedback on this plot: %s", "Tutorial"), /* + "$2Leave some feedback on this plot: %s", "Tutorial"), + /* * Economy Stuff */ @@ -411,7 +403,8 @@ public enum Captions { ADDED_BALANCE("$1%s $2has been added to your balance", "Economy"), REMOVED_BALANCE( "$1%s $2has been taken from your balance", "Economy"), - REMOVED_GRANTED_PLOT("$2You used %s plot grant(s), you've got $1%s $2left", "Economy"), /* + REMOVED_GRANTED_PLOT("$2You used %s plot grant(s), you've got $1%s $2left", "Economy"), + /* * Setup Stuff */ @@ -433,7 +426,8 @@ public enum Captions { "$2You need to specify a generator ($1/plot setup &l&r$2)&-$1Additional commands:&-$2 - $1/plot setup &-$2 - " + "$1/plot setup back&-$2 - $1/plot setup cancel", "Setup"), - SETUP_INVALID_GENERATOR("$2Invalid generator. Possible options: %s", "Setup"), /* + SETUP_INVALID_GENERATOR("$2Invalid generator. Possible options: %s", "Setup"), + /* * Schematic Stuff */ @@ -456,13 +450,15 @@ public enum Captions { TITLE_ENTERED_PLOT("$1Plot: %world%;%x%;%z%", "Titles"), TITLE_ENTERED_PLOT_SUB("$4Owned by %s", "Titles"), - PREFIX_GREETING("$1%id%$2> ", "Titles"), PREFIX_FAREWELL("$1%id%$2> ", "Titles"), /* + PREFIX_GREETING("$1%id%$2> ", "Titles"), PREFIX_FAREWELL("$1%id%$2> ", "Titles"), + /* * Core Stuff */ TASK_START("Starting task...", "Core"), PREFIX("$3[$1P2$3] $2", "Core"), - ENABLED("$1%s0 is now enabled", "Core"), /* + ENABLED("$1%s0 is now enabled", "Core"), + /* * Reload */ @@ -485,7 +481,8 @@ public enum Captions { MISSING_ALIAS("$2You need to specify an alias", "Alias"), ALIAS_TOO_LONG( "$2The alias must be < 50 characters in length", "Alias"), - ALIAS_IS_TAKEN("$2That alias is already taken", "Alias"), /* + ALIAS_IS_TAKEN("$2That alias is already taken", "Alias"), + /* * Position */ @@ -495,15 +492,18 @@ public enum Captions { POSITION_UNSET("$1Home position reset to the default location", "Position"), HOME_ARGUMENT( "$2Use /plot set home [none]", "Position"), - INVALID_POSITION("$2That is not a valid position value", "Position"), /* + INVALID_POSITION("$2That is not a valid position value", "Position"), + /* * Cap */ - ENTITY_CAP("$2You are not allowed to spawn more mobs", "cap"), /* + ENTITY_CAP("$2You are not allowed to spawn more mobs", "cap"), + /* * Time */ - TIME_FORMAT("$1%hours%, %min%, %sec%", "Time"), /* + TIME_FORMAT("$1%hours%, %min%, %sec%", "Time"), + /* * Permission */ @@ -539,7 +539,8 @@ public enum Captions { "Merge"), UNLINK_REQUIRED("$2An unlink is required to do this.", "Merge"), UNLINK_IMPOSSIBLE("$2You can only unlink a mega-plot", "Merge"), UNLINK_SUCCESS( - "$2Successfully unlinked plots.", "Merge"), /* + "$2Successfully unlinked plots.", "Merge"), + /* * CommandConfig */ @@ -550,14 +551,16 @@ public enum Captions { "$2I'm sorry, but you're not permitted to use any subcommands.", "CommandConfig"), SUBCOMMAND_SET_OPTIONS_HEADER("$2Possible Values: ", "CommandConfig"), COMMAND_SYNTAX( - "$1Usage: $2%s", "CommandConfig"), /* + "$1Usage: $2%s", "CommandConfig"), + /* * Player not found */ INVALID_PLAYER_WAIT("$2Player not found: $1%s$2, fetching it. Try again soon.", "Errors"), INVALID_PLAYER("$2Player not found: $1%s$2.", "Errors"), - INVALID_PLAYER_OFFLINE("$2The player must be online: $1%s.", "Errors"), /* + INVALID_PLAYER_OFFLINE("$2The player must be online: $1%s.", "Errors"), + /* * Command flag */ @@ -569,21 +572,22 @@ public enum Captions { "Errors"), // SETTINGS_PASTE_UPLOADED("$2settings.yml was uploaded to: $1%url%", "Paste"), // LATEST_LOG_UPLOADED("$2latest.log was uploaded to: $1%url%", "Paste"), - DEBUG_REPORT_CREATED("$1Uploaded a full debug to: $1%url%", "Paste"), /* - * - */ + DEBUG_REPORT_CREATED("$1Uploaded a full debug to: $1%url%", "Paste"), - COMMAND_WENT_WRONG("$2Something went wrong when executing that command...", "Errors"), /* + COMMAND_WENT_WRONG("$2Something went wrong when executing that command...", "Errors"), + /* * purge */ - PURGE_SUCCESS("$4Successfully purged %s plots", "Purge"), /* + PURGE_SUCCESS("$4Successfully purged %s plots", "Purge"), + /* * trim */ TRIM_IN_PROGRESS("A world trim task is already in progress!", "Trim"), NOT_VALID_HYBRID_PLOT_WORLD( - "The hybrid plot manager is required to perform this action", "Trim"), /* + "The hybrid plot manager is required to perform this action", "Trim"), + /* * No */ @@ -599,16 +603,19 @@ public enum Captions { NOT_VALID_WORLD("$2That is not a valid world (case sensitive)", "Errors"), NOT_VALID_PLOT_WORLD( "$2That is not a valid plot area (case sensitive)", "Errors"), - NO_PLOTS("$2You don't have any plots", "Errors"), /* + NO_PLOTS("$2You don't have any plots", "Errors"), + /* * Block List */ - BLOCK_LIST_SEPARATER("$1,$2 ", "Block List"), /* + BLOCK_LIST_SEPARATER("$1,$2 ", "Block List"), + /* * Biome */ NEED_BIOME("$2You need to specify a valid biome.", "Biome"), BIOME_SET_TO( - "$2Plot biome set to $2", "Biome"), /* + "$2Plot biome set to $2", "Biome"), + /* * Teleport / Entry */ @@ -616,7 +623,8 @@ public enum Captions { "$2You got teleported to the road", "Teleport"), TELEPORT_IN_SECONDS("$1Teleporting in %s seconds. Do not move...", "Teleport"), TELEPORT_FAILED( - "$2Teleportation cancelled due to movement or damage", "Teleport"), /* + "$2Teleportation cancelled due to movement or damage", "Teleport"), + /* * Set Block */ @@ -626,13 +634,16 @@ public enum Captions { AllowUnsafe */ DEBUGALLOWUNSAFE_ON("$2Unsafe actions allowed", "unsafe"), DEBUGALLOWUNSAFE_OFF( - "$2Unsafe actions disabled", "unsafe"), /* + "$2Unsafe actions disabled", "unsafe"), + /* * Debug */ DEBUG_HEADER("$1Debug Information&-", "Debug"), DEBUG_SECTION("$2>> $1&l%val%", "Debug"), - DEBUG_LINE("$2>> $1%var%$2:$1 %val%&-", "Debug"), /* + DEBUG_LINE("$2>> $1%var%$2:$1 %val%&-", "Debug"), + + /* * Invalid */ @@ -651,29 +662,24 @@ public enum Captions { PLAYER_HAS_NOT_BEEN_ON("$2That player hasn't been in the plotworld", "Invalid"), FOUND_NO_PLOTS( "$2Found no plots with your search query", "Invalid"), - FOUND_NO_PLOTS_FOR_PLAYER("$2No plots found for player: %s", "Invalid"), /* - * Camera - */ - - CAMERA_STARTED("$2You have entered camera mode for plot $1%s", "Camera"), CAMERA_STOPPED( - "$2You are no longer in camera mode", "Camera"), /* + FOUND_NO_PLOTS_FOR_PLAYER("$2No plots found for player: %s", "Invalid"), + /* * Need */ - NEED_PLOT_NUMBER("$2You've got to specify a plot number or alias", "Need"), NEED_BLOCK( "$2You've got to specify a block", "Need"), NEED_PLOT_ID("$2You've got to specify a plot id.", "Need"), NEED_PLOT_WORLD( "$2You've got to specify a plot area.", "Need"), - NEED_USER("$2You need to specify a username", "Need"), /* + NEED_USER("$2You need to specify a username", "Need"), + /* * Near */ - - PLOT_NEAR("$1Players: %s0", "Near"), /* + PLOT_NEAR("$1Players: %s0", "Near"), + /* * Info */ - NONE("None", "Info"), NOW("Now", "Info"), NEVER("Never", "Info"), UNKNOWN("Unknown", "Info"), @@ -709,25 +715,29 @@ public enum Captions { PLOT_INFO_SEEN("$1Seen:$2 %seen%", "Info"), PLOT_USER_LIST(" $1%user%$2,", "Info"), - PLOT_FLAG_LIST("$1%s0:%s1$2", "Info"), INFO_SYNTAX_CONSOLE("$2/plot info X;Y", "Info"), /* + PLOT_FLAG_LIST("$1%s0:%s1$2", "Info"), INFO_SYNTAX_CONSOLE("$2/plot info X;Y", "Info"), + /* * Generating */ - GENERATING_COMPONENT("$1Started generating component from your settings", "Working"), /* + GENERATING_COMPONENT("$1Started generating component from your settings", "Working"), + /* * Clearing */ CLEARING_PLOT("$2Clearing plot async.", "Working"), CLEARING_DONE( "$4Clear completed! Took %sms.", "Working"), - DELETING_DONE("$4Delete completed! Took %sms.", "Working"), /* + DELETING_DONE("$4Delete completed! Took %sms.", "Working"), + /* * Claiming */ PLOT_NOT_CLAIMED("$2Plot not claimed", "Working"), PLOT_IS_CLAIMED( "$2This plot is already claimed", "Working"), - CLAIMED("$4You successfully claimed the plot", "Working"), /* + CLAIMED("$4You successfully claimed the plot", "Working"), + /* * List */ @@ -742,17 +752,20 @@ public enum Captions { "$2>> $1%id$2:$1%world $2- $1%owner", "List"), PLOT_LIST_ITEM_ORDERED("$2[$1%in$2] >> $1%id$2:$1%world $2- $1%owner", - "List"), PLOT_LIST_FOOTER("$2>> $1%word% a total of $2%num% $1claimed %plot%.", "List"), /* + "List"), PLOT_LIST_FOOTER("$2>> $1%word% a total of $2%num% $1claimed %plot%.", "List"), + /* * Left */ - LEFT_PLOT("$2You left a plot", "Left"), /* + LEFT_PLOT("$2You left a plot", "Left"), + /* * Wait */ WAIT_FOR_TIMER( "$2A setblock timer is bound to either the current plot or you. Please wait for it to finish", - "Errors"), /* + "Errors"), + /* * Chat */ @@ -762,7 +775,8 @@ public enum Captions { PLOT_CHAT_FORCED("$2This world forces everyone to use plot chat.", "Chat"), PLOT_CHAT_ON( "$4Plot chat enabled.", "Chat"), - PLOT_CHAT_OFF("$4Plot chat disabled.", "Chat"), /* + PLOT_CHAT_OFF("$4Plot chat disabled.", "Chat"), + /* * Denied */ @@ -775,16 +789,19 @@ public enum Captions { YOU_GOT_DENIED( "$4You are denied from the plot you were previously on, and got teleported to spawn", - "Deny"), /* + "Deny"), + /* * Kick */ - YOU_GOT_KICKED("$4You got kicked!", "Kick"), /* + YOU_GOT_KICKED("$4You got kicked!", "Kick"), + /* * Rain */ NEED_ON_OFF("$2You need to specify a value. Possible values: $1on$2, $1off", - "Rain"), SETTING_UPDATED("$4You successfully updated the setting", "Rain"), /* + "Rain"), SETTING_UPDATED("$4You successfully updated the setting", "Rain"), + /* * Flag */ @@ -802,7 +819,8 @@ public enum Captions { "$4Successfully removed flag", "Flag"), FLAG_ADDED("$4Successfully added flag", "Flag"), FLAG_TUTORIAL_USAGE( - "$1Have an admin set the flag: $2%s", "CommandConfig"), /* + "$1Have an admin set the flag: $2%s", "CommandConfig"), + /* * Trusted */ @@ -811,7 +829,8 @@ public enum Captions { WAS_NOT_ADDED("$2That player was not trusted on this plot", "Trusted"), PLOT_REMOVED_USER( "$1Plot %s of which you were added to has been deleted due to owner inactivity", - "Trusted"), /* + "Trusted"), + /* * Member */ @@ -825,20 +844,23 @@ public enum Captions { "Member"), MEMBER_WAS_NOT_ADDED("$2That player was not added as a user on this plot", "Member"), - PLOT_MAX_MEMBERS("$2You are not allowed to add any more players to this plot", "Member"), /* + PLOT_MAX_MEMBERS("$2You are not allowed to add any more players to this plot", "Member"), + /* * Set Owner */ SET_OWNER("$4You successfully set the plot owner", "Owner"), SET_OWNER_CANCELLED( "$2The setowner action was cancelled", "Owner"), - NOW_OWNER("$4You are now owner of plot %s", "Owner"), /* + NOW_OWNER("$4You are now owner of plot %s", "Owner"), + /* * Signs */ OWNER_SIGN_LINE_1("$1ID: $1%id%", "Signs"), OWNER_SIGN_LINE_2("$1Owner:", "Signs"), - OWNER_SIGN_LINE_3("$2%plr%", "Signs"), OWNER_SIGN_LINE_4("$3Claimed", "Signs"), /* + OWNER_SIGN_LINE_3("$2%plr%", "Signs"), OWNER_SIGN_LINE_4("$3Claimed", "Signs"), + /* * Help */ @@ -871,14 +893,16 @@ public enum Captions { * Direction */ - DIRECTION("$1Current direction: %dir%", "Help"), /* + DIRECTION("$1Current direction: %dir%", "Help"), + /* * Grant */ GRANTED_PLOTS("$1Result: $2%s $1grants left", "Grants"), GRANTED_PLOT( "$1You granted %s0 plot to $2%s1", "Grants"), - GRANTED_PLOT_FAILED("$1Grant failed: $2%s", "Grants"), /* + GRANTED_PLOT_FAILED("$1Grant failed: $2%s", "Grants"), + /* * Custom */