From 15a55ee45bc9979ae5a5aa753180aa3f25a69ffc Mon Sep 17 00:00:00 2001 From: Biscuit Date: Sat, 23 Mar 2019 22:10:22 -0400 Subject: [PATCH] Fixed a bug when placing the voidchest for 1.13 servers, added metrics. --- pom.xml | 2 +- .../codes/biscuit/sellchest/SellChest.java | 2 + .../sellchest/events/PlayerEvents.java | 19 +- .../biscuit/sellchest/hooks/MetricsLite.java | 208 ++++++++++++++++++ .../codes/biscuit/sellchest/utils/Utils.java | 5 +- 5 files changed, 227 insertions(+), 9 deletions(-) create mode 100644 src/main/java/codes/biscuit/sellchest/hooks/MetricsLite.java diff --git a/pom.xml b/pom.xml index df240ad..994936c 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ codes.biscuit SellChest - 1.0.3 + 1.0.5 jar SellChest diff --git a/src/main/java/codes/biscuit/sellchest/SellChest.java b/src/main/java/codes/biscuit/sellchest/SellChest.java index b0881d2..5826d6e 100644 --- a/src/main/java/codes/biscuit/sellchest/SellChest.java +++ b/src/main/java/codes/biscuit/sellchest/SellChest.java @@ -4,6 +4,7 @@ import codes.biscuit.sellchest.events.OtherEvents; import codes.biscuit.sellchest.events.PlayerEvents; import codes.biscuit.sellchest.hooks.HookUtils; +import codes.biscuit.sellchest.hooks.MetricsLite; import codes.biscuit.sellchest.utils.ConfigValues; import codes.biscuit.sellchest.utils.Utils; import org.bukkit.Bukkit; @@ -28,6 +29,7 @@ public void onEnable() { Bukkit.getPluginManager().registerEvents(new PlayerEvents(this), this); Bukkit.getPluginManager().registerEvents(new OtherEvents(this), this); configValues.setupSellChests(); + new MetricsLite(this); } @Override diff --git a/src/main/java/codes/biscuit/sellchest/events/PlayerEvents.java b/src/main/java/codes/biscuit/sellchest/events/PlayerEvents.java index 2f8a17c..3bd9370 100644 --- a/src/main/java/codes/biscuit/sellchest/events/PlayerEvents.java +++ b/src/main/java/codes/biscuit/sellchest/events/PlayerEvents.java @@ -27,7 +27,9 @@ import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.EnumSet; import java.util.Map; +import java.util.Set; public class PlayerEvents implements Listener { @@ -48,22 +50,25 @@ public void onVoidChestPlace(PlayerInteractEvent e) { if (bypassing || !main.getUtils().reachedLimit(p)) { e.setCancelled(true); Block newBlock; - Material longGrass = null; + Set placeOver = EnumSet.of(Material.AIR, Material.SNOW, Material.LAVA, Material.WATER); try { - longGrass = Material.valueOf("LONG_GRASS"); + placeOver.add(Material.valueOf("LONG_GRASS")); } catch (IllegalArgumentException ex) { try { - longGrass = Material.valueOf("TALL_GRASS"); - } catch (IllegalArgumentException ignored) { - } + placeOver.add(Material.valueOf("TALL_GRASS")); + } catch (IllegalArgumentException ignored) {} } + try { + placeOver.add(Material.valueOf("STATIONARY_WATER")); + placeOver.add(Material.valueOf("STATIONARY_LAVA")); + } catch (IllegalArgumentException ignored) {} if (e.getClickedBlock().getState() instanceof InventoryHolder && !p.isSneaking()) { return; - } else if (e.getClickedBlock().getType().equals(longGrass)) { + } else if (placeOver.contains(e.getClickedBlock().getType())) { newBlock = e.getClickedBlock(); // Blocks place directly on grass } else { newBlock = e.getClickedBlock().getRelative(e.getBlockFace()); - if (!newBlock.getType().equals(Material.AIR)) { // For hackers + if (!newBlock.getType().equals(Material.AIR)) { // For hackers/glitched block placement return; } } diff --git a/src/main/java/codes/biscuit/sellchest/hooks/MetricsLite.java b/src/main/java/codes/biscuit/sellchest/hooks/MetricsLite.java new file mode 100644 index 0000000..303d34f --- /dev/null +++ b/src/main/java/codes/biscuit/sellchest/hooks/MetricsLite.java @@ -0,0 +1,208 @@ +package codes.biscuit.sellchest.hooks; + +import org.bukkit.Bukkit; +import org.bukkit.configuration.file.YamlConfiguration; +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.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Timer; +import java.util.TimerTask; +import java.util.UUID; +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({"unused", "unchecked"}) +public class MetricsLite { + + private boolean enabled; + private static boolean logFailedRequests; + private static boolean logSentData; + private static boolean logResponseStatusText; + private static String serverUUID; + private final Plugin plugin; + + public MetricsLite(Plugin plugin) { + if (plugin == null) { + throw new IllegalArgumentException("Plugin cannot be null!"); + } + this.plugin = plugin; + File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats"); + File configFile = new File(bStatsFolder, "config.yml"); + YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); + if (!config.isSet("serverUuid")) { + config.addDefault("enabled", true); + config.addDefault("serverUuid", UUID.randomUUID().toString()); + config.addDefault("logFailedRequests", false); + config.addDefault("logSentData", false); + config.addDefault("logResponseStatusText", false); + 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) { } + } + serverUUID = config.getString("serverUuid"); + logFailedRequests = config.getBoolean("logFailedRequests", false); + enabled = config.getBoolean("enabled", true); + if (enabled) { + boolean found = false; + for (Class service : Bukkit.getServicesManager().getKnownServices()) { + try { + service.getField("B_STATS_VERSION"); + found = true; + break; + } catch (NoSuchFieldException ignored) { } + } + Bukkit.getServicesManager().register(MetricsLite.class, this, plugin, ServicePriority.Normal); + if (!found) { + startSubmitting(); + } + } + } + + public boolean isEnabled() { + return enabled; + } + + private void startSubmitting() { + final Timer timer = new Timer(true); + timer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + if (!plugin.isEnabled()) { + timer.cancel(); + return; + } + Bukkit.getScheduler().runTask(plugin, () -> submitData()); + } + }, 1000 * 60 * 5, 1000 * 60 * 30); + } + + public JSONObject getPluginData() { + JSONObject data = new JSONObject(); + + String pluginName = plugin.getDescription().getName(); + String pluginVersion = plugin.getDescription().getVersion(); + + data.put("pluginName", pluginName); + data.put("pluginVersion", pluginVersion); + JSONArray customCharts = new JSONArray(); + data.put("customCharts", customCharts); + + return data; + } + + private JSONObject getServerData() { + int playerAmount = Bukkit.getOnlinePlayers().size(); + int onlineMode = Bukkit.getOnlineMode() ? 1 : 0; + String bukkitVersion = Bukkit.getVersion(); + 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; + } + + private void submitData() { + final JSONObject data = getServerData(); + JSONArray pluginData = new JSONArray(); + for (Class service : Bukkit.getServicesManager().getKnownServices()) { + try { + service.getField("B_STATS_VERSION"); + 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); + new Thread(() -> { + try { + sendData(plugin, data); + } catch (Exception e) { + if (logFailedRequests) { + plugin.getLogger().log(Level.WARNING, "Could not submit plugin stats of " + plugin.getName(), e); + } + } + }).start(); + } + + 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("https://bStats.org/submitData/bukkit").openConnection(); + byte[] compressedData = compress(data.toString()); + 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/1"); + 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()); + } + } + + 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(); + } + +} \ No newline at end of file diff --git a/src/main/java/codes/biscuit/sellchest/utils/Utils.java b/src/main/java/codes/biscuit/sellchest/utils/Utils.java index 205bfde..3d59dc5 100644 --- a/src/main/java/codes/biscuit/sellchest/utils/Utils.java +++ b/src/main/java/codes/biscuit/sellchest/utils/Utils.java @@ -4,7 +4,10 @@ import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.chat.ClickEvent; import net.md_5.bungee.api.chat.TextComponent; -import org.bukkit.*; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.OfflinePlayer; import org.bukkit.block.BlockFace; import org.bukkit.block.Chest; import org.bukkit.command.CommandSender;