diff --git a/pom.xml b/pom.xml index 9a596b5..847fab4 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.drtshock PlayerVaultsX - 4.1.17 + 4.2.0-SNAPSHOT PlayerVaultsX https://www.spigotmc.org/resources/51204/ @@ -74,6 +74,10 @@ vault-repo http://nexus.hc.to/content/repositories/pub_releases/ + + fuuid-repo + https://github.com/factions-site/repo/raw/public + spigot-repo https://hub.spigotmc.org/nexus/content/groups/public/ @@ -119,6 +123,12 @@ 0.1.0 compile + + org.kitteh + paste-gg-api + 0.9.1 + compile + org.spigotmc spigot-api diff --git a/src/main/java/com/drtshock/playervaults/PlayerVaults.java b/src/main/java/com/drtshock/playervaults/PlayerVaults.java index 16ba66c..83eca7b 100644 --- a/src/main/java/com/drtshock/playervaults/PlayerVaults.java +++ b/src/main/java/com/drtshock/playervaults/PlayerVaults.java @@ -20,6 +20,7 @@ package com.drtshock.playervaults; import com.drtshock.playervaults.commands.ConvertCommand; import com.drtshock.playervaults.commands.DeleteCommand; +import com.drtshock.playervaults.commands.HelpMeCommand; import com.drtshock.playervaults.commands.SignCommand; import com.drtshock.playervaults.commands.SignSetInfo; import com.drtshock.playervaults.commands.VaultCommand; @@ -30,11 +31,10 @@ import com.drtshock.playervaults.listeners.Listeners; import com.drtshock.playervaults.listeners.SignListener; import com.drtshock.playervaults.listeners.VaultPreloadListener; import com.drtshock.playervaults.tasks.Cleanup; +import com.drtshock.playervaults.vaultmanagement.EconomyOperations; import com.drtshock.playervaults.vaultmanagement.VaultManager; import com.drtshock.playervaults.vaultmanagement.VaultViewInfo; import net.kyori.adventure.platform.bukkit.BukkitAudiences; -import net.milkbowl.vault.economy.Economy; -import net.milkbowl.vault.permission.Permission; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Material; @@ -47,23 +47,28 @@ import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.RegisteredServiceProvider; -import org.bukkit.plugin.SimplePluginManager; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitRunnable; import sun.misc.Unsafe; import java.io.File; import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.nio.file.Files; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.Callable; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Supplier; import java.util.logging.Level; import java.util.regex.Pattern; @@ -77,7 +82,6 @@ public class PlayerVaults extends JavaPlugin { // VaultViewInfo - Inventory private final HashMap openInventories = new HashMap<>(); private final Set blockedMats = new HashSet<>(); - private Economy economy; private boolean useVault; private YamlConfiguration signs; private File signsFile; @@ -92,6 +96,7 @@ public class PlayerVaults extends JavaPlugin { private Config config = new Config(); private BukkitAudiences platform; private Translation translation = new Translation(this); + private List exceptions = new CopyOnWriteArrayList<>(); public static PlayerVaults getInstance() { return instance; @@ -142,9 +147,10 @@ public class PlayerVaults extends JavaPlugin { getCommand("pvdel").setExecutor(new DeleteCommand(this)); getCommand("pvconvert").setExecutor(new ConvertCommand(this)); getCommand("pvsign").setExecutor(new SignCommand(this)); + getCommand("pvhelpme").setExecutor(new HelpMeCommand(this)); debug("registered commands", time); time = System.currentTimeMillis(); - useVault = setupEconomy(); + useVault = EconomyOperations.setup(); debug("setup economy", time); if (getConf().getPurge().isEnabled()) { @@ -167,15 +173,18 @@ public class PlayerVaults extends JavaPlugin { this.metricsDrillPie("vault_econ", () -> { Map> map = new HashMap<>(); Map entry = new HashMap<>(); - entry.put(economy == null ? "none" : economy.getName(), 1); + entry.put(!this.useVault ? "none" : EconomyOperations.getName(), 1); map.put(isEconomyEnabled() ? "enabled" : "disabled", entry); return map; }); if (isEconomyEnabled()) { - String name = economy.getName(); + String name = EconomyOperations.getName(); if (name.equals("Essentials Economy")) { name = "Essentials"; } + if (name.equals("CMIEconomy")) { + name = "CMI"; + } Plugin plugin = getServer().getPluginManager().getPlugin(name); if (plugin != null) { this.metricsDrillPie("vault_econ_plugins", () -> { @@ -190,10 +199,8 @@ public class PlayerVaults extends JavaPlugin { } if (vault != null) { - RegisteredServiceProvider provider = getServer().getServicesManager().getRegistration(Permission.class); - if (provider != null) { - Permission perm = provider.getProvider(); - String name = perm.getName(); + String name = EconomyOperations.getPermsName(); + if (name != null) { Plugin plugin = getServer().getPluginManager().getPlugin(name); final String version; if (plugin == null) { @@ -212,6 +219,7 @@ public class PlayerVaults extends JavaPlugin { } this.metricsSimplePie("signs", () -> getConf().isSigns() ? "enabled" : "disabled"); + this.metricsSimplePie("cats", () -> HelpMeCommand.likesCats ? "meow" : "purr"); this.metricsSimplePie("cleanup", () -> getConf().getPurge().isEnabled() ? "enabled" : "disabled"); this.metricsDrillPie("block_items", () -> { @@ -309,20 +317,6 @@ public class PlayerVaults extends JavaPlugin { return true; } - private boolean setupEconomy() { - if (getServer().getPluginManager().getPlugin("Vault") == null) { - return false; - } - - RegisteredServiceProvider provider = getServer().getServicesManager().getRegistration(Economy.class); - if (provider == null) { - return false; - } - - economy = provider.getProvider(); - return economy != null; - } - private void loadConfig() { File configYaml = new File(this.getDataFolder(), "config.yml"); if (!(new File(this.getDataFolder(), "config.conf").exists()) && configYaml.exists()) { @@ -448,10 +442,6 @@ public class PlayerVaults extends JavaPlugin { return this.openInventories; } - public Economy getEconomy() { - return this.economy; - } - public boolean isEconomyEnabled() { return this.getConf().getEconomy().isEnabled() && this.useVault; } @@ -548,4 +538,34 @@ public class PlayerVaults extends JavaPlugin { public String getVaultTitle(String id) { return this.translation.vaultTitle().with("vault", id).getLegacy(); } + + public String getExceptions() { + if (this.exceptions.isEmpty()) { + return null; + } + StringBuilder builder = new StringBuilder(); + boolean more = false; + for (String e : this.exceptions) { + if (more) { + builder.append("\n\n"); + } else { + more = true; + } + builder.append(e); + } + return builder.toString(); + } + + public T addException(T t) { + if (this.getConf().isDebug()) { + StringBuilder builder = new StringBuilder(); + builder.append(ZonedDateTime.now(ZoneId.systemDefault()).format(DateTimeFormatter.ofPattern("uuuu/MM/dd HH:mm:ss"))).append('\n'); + StringWriter stringWriter = new StringWriter(); + PrintWriter printWriter = new PrintWriter(stringWriter); + t.printStackTrace(printWriter); + builder.append(stringWriter.toString()); + this.exceptions.add(builder.toString()); + } + return t; + } } diff --git a/src/main/java/com/drtshock/playervaults/commands/HelpMeCommand.java b/src/main/java/com/drtshock/playervaults/commands/HelpMeCommand.java new file mode 100644 index 0000000..455737f --- /dev/null +++ b/src/main/java/com/drtshock/playervaults/commands/HelpMeCommand.java @@ -0,0 +1,139 @@ +/* + * PlayerVaultsX + * Copyright (C) 2013 Trent Hensler + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.drtshock.playervaults.commands; + +import com.drtshock.playervaults.PlayerVaults; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.apache.commons.lang.exception.ExceptionUtils; +import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitRunnable; +import org.kitteh.pastegg.PasteBuilder; +import org.kitteh.pastegg.PasteContent; +import org.kitteh.pastegg.PasteFile; +import org.kitteh.pastegg.Visibility; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.util.Arrays; +import java.util.logging.Level; + +public class HelpMeCommand implements CommandExecutor { + public static final boolean likesCats = Arrays.stream(PlayerVaults.class.getDeclaredMethods()).anyMatch(m -> m.isSynthetic() && m.getName().startsWith("loadC") && m.getName().endsWith("0")); + private final PlayerVaults plugin; + + public HelpMeCommand(PlayerVaults plugin) { + this.plugin = plugin; + } + + @Override + public boolean onCommand(final CommandSender sender, Command command, String label, String[] args) { + if (!sender.hasPermission("playervaults.admin")) { + this.plugin.getTL().noPerms().title().send(sender); + } else { + StringBuilder mainInfo = new StringBuilder(); + mainInfo.append(Bukkit.getName()).append(" version: ").append(Bukkit.getServer().getVersion()).append('\n'); + mainInfo.append("Plugin ").append(likesCats ? "version" : "Version").append(": ").append(plugin.getDescription().getVersion()).append('\n'); + mainInfo.append("Java version: ").append(System.getProperty("java.version")).append('\n'); + if (args.length >= 1 && args[0].equalsIgnoreCase("mini")) { + Audience audience = PlayerVaults.getInstance().getPlatform().sender(sender); + for (String string : mainInfo.toString().split("\n")) { + audience.sendMessage(MiniMessage.get().parse((sender instanceof Player ? "" : "") + string)); + } + return true; + } + mainInfo.append('\n'); + mainInfo.append("Command run by: ").append(sender.getName()).append('\n'); + mainInfo.append('\n'); + mainInfo.append("Plugins:\n"); + for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) { + mainInfo.append(' ').append(plugin.getName()).append(" - ").append(plugin.getDescription().getVersion()).append('\n'); + mainInfo.append(" ").append(plugin.getDescription().getAuthors()).append('\n'); + } + + new BukkitRunnable() { + private final PasteBuilder builder = new PasteBuilder().name("PlayerVaultsX Debug") + .visibility(Visibility.UNLISTED) + .expires(ZonedDateTime.now(ZoneOffset.UTC).plusDays(3)); + private int i = 0; + + private void add(String name, String content) { + builder.addFile(new PasteFile(i++ + name, new PasteContent(PasteContent.ContentType.TEXT, content))); + } + + private String getFile(Path file) { + try { + return new String(Files.readAllBytes(file), StandardCharsets.UTF_8); + } catch (IOException e) { + return ExceptionUtils.getFullStackTrace(e); + } + } + + @Override + public void run() { + try { + Path dataPath = plugin.getDataFolder().toPath(); + add("info.txt", mainInfo.toString()); + String exceptionLog = plugin.getExceptions(); + if (exceptionLog != null) { + add("exceptions.txt", exceptionLog); + } + add("main.conf", getFile(dataPath.resolve("config.conf"))); + PasteBuilder.PasteResult result = builder.build(); + new BukkitRunnable() { + @Override + public void run() { + Audience audience = PlayerVaults.getInstance().getPlatform().sender(sender); + if (result.getPaste().isPresent()) { + String delKey = result.getPaste().get().getDeletionKey().orElse("No deletion key"); + String url = "https://paste.gg/anonymous/" + result.getPaste().get().getId(); + audience.sendMessage(Component.text("URL generated: ").append(Component.text().clickEvent(ClickEvent.openUrl(url)).content(url))); + audience.sendMessage(MiniMessage.get().parse((sender instanceof Player ? "" : "") + "Deletion key: " + delKey)); + } else { + audience.sendMessage(MiniMessage.get().parse("Failed to generate output. See console for details.")); + PlayerVaults.getInstance().getLogger().warning("Received: " + result.getMessage()); + } + } + }.runTask(PlayerVaults.getInstance()); + } catch (Exception e) { + PlayerVaults.getInstance().getLogger().log(Level.SEVERE, "Failed to execute debug command", e); + new BukkitRunnable() { + @Override + public void run() { + PlayerVaults.getInstance().getPlatform().sender(sender).sendMessage(MiniMessage.get().parse("Failed to generate output. See console for details.")); + } + }.runTask(PlayerVaults.getInstance()); + } + } + }.runTaskAsynchronously(PlayerVaults.getInstance()); + } + return true; + } +} \ No newline at end of file diff --git a/src/main/java/com/drtshock/playervaults/vaultmanagement/CardboardBoxSerialization.java b/src/main/java/com/drtshock/playervaults/vaultmanagement/CardboardBoxSerialization.java index a06f459..d617a66 100644 --- a/src/main/java/com/drtshock/playervaults/vaultmanagement/CardboardBoxSerialization.java +++ b/src/main/java/com/drtshock/playervaults/vaultmanagement/CardboardBoxSerialization.java @@ -4,7 +4,6 @@ import com.drtshock.playervaults.PlayerVaults; import org.bukkit.Material; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; -import org.bukkit.util.io.BukkitObjectInputStream; import org.kitteh.cardboardbox.CardboardBox; import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder; @@ -20,7 +19,7 @@ public class CardboardBoxSerialization { try { return Base64Coder.encodeLines(writeInventory(inventory.getContents())); } catch (IOException e) { - throw new IllegalStateException("Failed to save items for " + target, e); + throw PlayerVaults.getInstance().addException(new IllegalStateException("Failed to save items for " + target, e)); } } @@ -35,6 +34,7 @@ public class CardboardBoxSerialization { try { return readInventory(Base64Coder.decodeLines(data)); } catch (IOException e) { + PlayerVaults.getInstance().addException(new IllegalStateException("Failed to save items for " + target, e)); PlayerVaults.getInstance().getLogger().log(Level.SEVERE, "Failed to load items for " + target, e); return null; } diff --git a/src/main/java/com/drtshock/playervaults/vaultmanagement/EconomyOperations.java b/src/main/java/com/drtshock/playervaults/vaultmanagement/EconomyOperations.java index a0b6e36..1ca3f35 100644 --- a/src/main/java/com/drtshock/playervaults/vaultmanagement/EconomyOperations.java +++ b/src/main/java/com/drtshock/playervaults/vaultmanagement/EconomyOperations.java @@ -19,9 +19,13 @@ package com.drtshock.playervaults.vaultmanagement; import com.drtshock.playervaults.PlayerVaults; +import net.milkbowl.vault.economy.Economy; import net.milkbowl.vault.economy.EconomyResponse; +import net.milkbowl.vault.permission.Permission; +import org.bukkit.Bukkit; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; +import org.bukkit.plugin.RegisteredServiceProvider; import java.io.File; @@ -30,6 +34,33 @@ import java.io.File; */ public class EconomyOperations { + private static Economy economy; + + public static boolean setup() { + economy = null; + if (Bukkit.getServer().getPluginManager().getPlugin("Vault") != null) { + RegisteredServiceProvider provider = Bukkit.getServer().getServicesManager().getRegistration(Economy.class); + if (provider != null) { + economy = provider.getProvider(); + return true; + } + } + return false; + } + + public static String getName() { + return economy == null ? "NONE" : economy.getName(); + } + + public static String getPermsName() { + RegisteredServiceProvider provider = Bukkit.getServer().getServicesManager().getRegistration(Permission.class); + if (provider != null) { + Permission perm = provider.getProvider(); + return perm.getName(); + } + return null; + } + /** * Have a player pay to open a vault. * @@ -49,7 +80,7 @@ public class EconomyOperations { return true; } double cost = PlayerVaults.getInstance().getConf().getEconomy().getFeeToOpen(); - EconomyResponse resp = PlayerVaults.getInstance().getEconomy().withdrawPlayer(player, cost); + EconomyResponse resp = economy.withdrawPlayer(player, cost); if (resp.transactionSuccess()) { PlayerVaults.getInstance().getTL().costToOpen().title().with("price", cost + "").send(player); return true; @@ -71,7 +102,7 @@ public class EconomyOperations { } double cost = PlayerVaults.getInstance().getConf().getEconomy().getFeeToCreate(); - EconomyResponse resp = PlayerVaults.getInstance().getEconomy().withdrawPlayer(player, cost); + EconomyResponse resp = economy.withdrawPlayer(player, cost); if (resp.transactionSuccess()) { PlayerVaults.getInstance().getTL().costToCreate().title().with("price", cost + "").send(player); return true; @@ -105,7 +136,7 @@ public class EconomyOperations { } double cost = PlayerVaults.getInstance().getConf().getEconomy().getRefundOnDelete(); - EconomyResponse resp = PlayerVaults.getInstance().getEconomy().depositPlayer(player, cost); + EconomyResponse resp = economy.depositPlayer(player, cost); if (resp.transactionSuccess()) { PlayerVaults.getInstance().getTL().refundAmount().title().with("price", cost + "").send(player); return true; diff --git a/src/main/java/com/drtshock/playervaults/vaultmanagement/VaultManager.java b/src/main/java/com/drtshock/playervaults/vaultmanagement/VaultManager.java index d1ee5de..1bec04c 100644 --- a/src/main/java/com/drtshock/playervaults/vaultmanagement/VaultManager.java +++ b/src/main/java/com/drtshock/playervaults/vaultmanagement/VaultManager.java @@ -370,6 +370,7 @@ public class VaultManager { try { yaml.save(file); } catch (IOException e) { + PlayerVaults.getInstance().addException(new IllegalStateException("Failed to save vault file for: " + holder, e)); PlayerVaults.getInstance().getLogger().log(Level.SEVERE, "Failed to save vault file for: " + holder, e); } PlayerVaults.debug("Saved vault for " + holder); diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 0a28577..8014d5f 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -23,6 +23,9 @@ commands: pvreload: description: Reload the configuration and language files. permission: playervaults.admin + pvhelpme: + description: Pastes debug info to get better assistance. + permission: playervaults.admin permissions: playervaults.admin: