diff --git a/src/main/java/me/libraryaddict/disguise/DisguiseConfig.java b/src/main/java/me/libraryaddict/disguise/DisguiseConfig.java index f80dfb51..c9a383a4 100644 --- a/src/main/java/me/libraryaddict/disguise/DisguiseConfig.java +++ b/src/main/java/me/libraryaddict/disguise/DisguiseConfig.java @@ -228,6 +228,9 @@ public class DisguiseConfig { @Getter @Setter private static boolean scoreboardDisguiseNames; + @Getter + @Setter + private static int tablistRemoveDelay; public static PermissionDefault getCommandVisibility() { return commandVisibility; @@ -443,6 +446,7 @@ public class DisguiseConfig { setWitherSkullPacketsEnabled(config.getBoolean("PacketsEnabled.WitherSkull")); setWolfDyeable(config.getBoolean("DyeableWolf")); setScoreboardDisguiseNames(config.getBoolean("ScoreboardNames")); + setTablistRemoveDelay(config.getInt("TablistRemoveDelay")); if (!LibsPremium.isPremium() && (isSavePlayerDisguises() || isSaveEntityDisguises())) { DisguiseUtilities.getLogger().warning("You must purchase the plugin to use saved disguises!"); diff --git a/src/main/java/me/libraryaddict/disguise/DisguiseListener.java b/src/main/java/me/libraryaddict/disguise/DisguiseListener.java index d8283b31..1a8a369e 100644 --- a/src/main/java/me/libraryaddict/disguise/DisguiseListener.java +++ b/src/main/java/me/libraryaddict/disguise/DisguiseListener.java @@ -103,15 +103,22 @@ public class DisguiseListener implements Listener { } private void runUpdateScheduler() { + boolean autoUpdate = plugin.getConfig().getBoolean("AutoUpdateDev"); + if (!plugin.getConfig().getBoolean("NotifyUpdate")) { return; } + if (autoUpdate && !isCheckReleases()) { + DisguiseUtilities.getLogger() + .info("Plugin will attempt to auto update when new builds are ready! Check config to disable."); + } + updaterTask = Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, new Runnable() { @Override public void run() { try { - UpdateChecker updateChecker = new UpdateChecker("32453"); + UpdateChecker updateChecker = LibsDisguises.getInstance().getUpdateChecker(); boolean checkReleases = isCheckReleases(); if (checkReleases) { @@ -126,15 +133,21 @@ public class DisguiseListener implements Listener { latestVersion = version; updateMessage = LibsMsg.UPDATE_READY; } else { - updateChecker.checkSnapshotUpdate(Integer.parseInt(plugin.getBuildNo())); + updateChecker.checkSnapshotUpdate(plugin.getBuildNumber()); if (updateChecker.getLatestSnapshot() <= 0) { return; } - currentVersion = plugin.getBuildNo(); latestVersion = "" + updateChecker.getLatestSnapshot(); - updateMessage = LibsMsg.UPDATE_READY_SNAPSHOT; + + if (autoUpdate && plugin.isNumberedBuild()) { + boolean result = updateChecker.grabSnapshotBuild(); + updateMessage = result ? LibsMsg.UPDATE_SUCCESS : LibsMsg.UPDATE_FAILED; + } else { + currentVersion = plugin.getBuildNo(); + updateMessage = LibsMsg.UPDATE_READY_SNAPSHOT; + } } Bukkit.getScheduler().runTask(plugin, new Runnable() { @@ -165,7 +178,11 @@ public class DisguiseListener implements Listener { return; } - player.sendMessage(updateMessage.get(currentVersion, latestVersion)); + if (updateMessage == LibsMsg.UPDATE_SUCCESS || updateMessage == LibsMsg.UPDATE_FAILED) { + player.sendMessage(updateMessage.get()); + } else { + player.sendMessage(updateMessage.get(currentVersion, latestVersion)); + } } public void cleanup() { @@ -477,7 +494,6 @@ public class DisguiseListener implements Listener { } } }.runTaskLater(LibsDisguises.getInstance(), 60); - } /** diff --git a/src/main/java/me/libraryaddict/disguise/LibsDisguises.java b/src/main/java/me/libraryaddict/disguise/LibsDisguises.java index 1184c961..fa36e09b 100644 --- a/src/main/java/me/libraryaddict/disguise/LibsDisguises.java +++ b/src/main/java/me/libraryaddict/disguise/LibsDisguises.java @@ -17,6 +17,7 @@ import me.libraryaddict.disguise.commands.undisguise.UndisguiseRadiusCommand; import me.libraryaddict.disguise.commands.utils.*; import me.libraryaddict.disguise.utilities.DisguiseUtilities; import me.libraryaddict.disguise.utilities.LibsPremium; +import me.libraryaddict.disguise.utilities.UpdateChecker; import me.libraryaddict.disguise.utilities.metrics.MetricsInitalizer; import me.libraryaddict.disguise.utilities.packets.PacketsManager; import me.libraryaddict.disguise.utilities.parser.DisguiseParser; @@ -42,6 +43,8 @@ public class LibsDisguises extends JavaPlugin { private String buildNumber; @Getter private boolean reloaded; + @Getter + private final UpdateChecker updateChecker = new UpdateChecker("32453"); @Override public void onLoad() { @@ -168,6 +171,10 @@ public class LibsDisguises extends JavaPlugin { return buildNumber; } + public int getBuildNumber() { + return isNumberedBuild() ? Integer.parseInt(getBuildNo()) : 0; + } + public boolean isNumberedBuild() { return getBuildNo() != null && getBuildNo().matches("[0-9]+"); } diff --git a/src/main/java/me/libraryaddict/disguise/commands/LibsDisguisesCommand.java b/src/main/java/me/libraryaddict/disguise/commands/LibsDisguisesCommand.java index 787ddd16..6164e46a 100644 --- a/src/main/java/me/libraryaddict/disguise/commands/LibsDisguisesCommand.java +++ b/src/main/java/me/libraryaddict/disguise/commands/LibsDisguisesCommand.java @@ -8,6 +8,7 @@ import me.libraryaddict.disguise.disguisetypes.DisguiseType; import me.libraryaddict.disguise.disguisetypes.MetaIndex; import me.libraryaddict.disguise.utilities.DisguiseUtilities; import me.libraryaddict.disguise.utilities.LibsPremium; +import me.libraryaddict.disguise.utilities.UpdateChecker; import me.libraryaddict.disguise.utilities.params.ParamInfoManager; import me.libraryaddict.disguise.utilities.parser.DisguisePerm; import me.libraryaddict.disguise.utilities.parser.DisguisePermissions; @@ -27,6 +28,7 @@ import org.bukkit.command.TabCompleter; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.permissions.Permissible; +import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scoreboard.Scoreboard; import org.bukkit.scoreboard.Team; @@ -88,10 +90,22 @@ public class LibsDisguisesCommand implements CommandExecutor, TabCompleter { } sender.sendMessage(ChatColor.DARK_GREEN + "This server is running " + "Lib's Disguises v" + version + - " by libraryaddict, formerly maintained by Byteflux and NavidK0." + - (sender.hasPermission("libsdisguises.reload") ? - "\nUse " + ChatColor.GREEN + "/libsdisguises " + "reload" + ChatColor.DARK_GREEN + - " to reload the config. All disguises will be blown by doing this" + "." : "")); + " by libraryaddict, formerly maintained by Byteflux and NavidK0."); + + if (sender.hasPermission("libsdisguises.reload")) { + sender.sendMessage(ChatColor.DARK_GREEN + "Use " + ChatColor.GREEN + "/libsdisguises " + "reload" + + ChatColor.DARK_GREEN + " to reload the config. All disguises will be blown by doing this" + + "."); + } + + if (sender.hasPermission("libsdisguises.update")) { + sender.sendMessage(ChatColor.DARK_GREEN + "Use " + ChatColor.GREEN + "/libsdisguises update" + + ChatColor.DARK_GREEN + + " to update Lib's Disguises to latest jenkins build. This will be updated on server restart. " + + "To force an update, use /libsdisguises update! with an ! on the end"); + } + + // TODO Other options if (LibsPremium.isPremium()) { sender.sendMessage(ChatColor.DARK_GREEN + "This server supports the plugin developer!"); @@ -352,6 +366,56 @@ public class LibsDisguisesCommand implements CommandExecutor, TabCompleter { .get(StringUtils.join(names, LibsMsg.META_VALUE_SEPERATOR.get()))); } } + } else if (args[0].equalsIgnoreCase("update") || args[0].equalsIgnoreCase("update!")) { + if (!sender.hasPermission("libsdisguises.update")) { + sender.sendMessage(LibsMsg.NO_PERM.get()); + return true; + } + + UpdateChecker checker = LibsDisguises.getInstance().getUpdateChecker(); + + if (checker.isDownloading()) { + sender.sendMessage(LibsMsg.UPDATE_IN_PROGRESS.get()); + return true; + } + + boolean force = args[0].endsWith("!"); + + if (!force) { + if (checker.getLatestSnapshot() <= 0) { + sender.sendMessage(LibsMsg.UPDATE_NOT_READY.get()); + return true; + } + + if (checker.getLatestSnapshot() == LibsDisguises.getInstance().getBuildNumber()) { + sender.sendMessage(LibsMsg.UPDATE_ON_LATEST.get()); + return true; + } + } + + new BukkitRunnable() { + @Override + public void run() { + boolean result; + + if (force) { + result = checker.grabLatestSnapshot(); + } else { + result = checker.grabSnapshotBuild(); + } + + if (!result) { + sender.sendMessage(LibsMsg.UPDATE_FAILED.get()); + return; + } + + sender.sendMessage(LibsMsg.UPDATE_SUCCESS.get()); // Update success, please restart to update + + if (sender instanceof Player) { + Bukkit.getConsoleSender().sendMessage(LibsMsg.UPDATE_SUCCESS.get()); + } + } + }.runTaskAsynchronously(LibsDisguises.getInstance()); } else { sender.sendMessage(LibsMsg.LIBS_COMMAND_WRONG_ARG.get()); } @@ -402,7 +466,8 @@ public class LibsDisguisesCommand implements CommandExecutor, TabCompleter { String[] args = getArgs(origArgs); if (args.length == 0) - tabs.addAll(Arrays.asList("reload", "scoreboard", "permtest", "json", "metainfo", "config", "mods")); + tabs.addAll( + Arrays.asList("reload", "scoreboard", "permtest", "json", "metainfo", "config", "mods", "update")); return filterTabs(tabs, origArgs); } diff --git a/src/main/java/me/libraryaddict/disguise/utilities/UpdateChecker.java b/src/main/java/me/libraryaddict/disguise/utilities/UpdateChecker.java index 97eb90a1..6967c03a 100644 --- a/src/main/java/me/libraryaddict/disguise/utilities/UpdateChecker.java +++ b/src/main/java/me/libraryaddict/disguise/utilities/UpdateChecker.java @@ -2,8 +2,12 @@ package me.libraryaddict.disguise.utilities; import com.google.gson.Gson; import lombok.Getter; +import me.libraryaddict.disguise.LibsDisguises; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.libs.org.apache.commons.io.FileUtils; import java.io.BufferedReader; +import java.io.File; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; @@ -21,11 +25,92 @@ public class UpdateChecker { @Getter private int latestSnapshot; private final long started = System.currentTimeMillis(); + private int lastDownload; public UpdateChecker(String resourceID) { this.resourceID = resourceID; } + public boolean grabSnapshotBuild() { + if (getLatestSnapshot() == 0) { + throw new IllegalArgumentException(); + } + + if (lastDownload == -1) { + return false; + } + + if (getLatestSnapshot() == lastDownload) { + return false; + } + + return grabSnapshotBuild(getLatestSnapshot()); + } + + public boolean grabSnapshotBuild(int buildNo) { + boolean result = grabSnapshotBuild( + "https://ci.md-5.net/job/LibsDisguises/" + buildNo + "/artifact/target/LibsDisguises.jar"); + + if (result) { + lastDownload = buildNo; + } + + return result; + } + + public boolean grabLatestSnapshot() { + boolean result = grabSnapshotBuild( + "https://ci.md-5.net/job/LibsDisguises/lastSuccessfulBuild/artifact/target/LibsDisguises.jar"); + + if (result) { + lastDownload = LibsDisguises.getInstance().getBuildNumber(); + } + + return result; + } + + public boolean isDownloading() { + return lastDownload == -1; + } + + public int getLastDownload() { + return lastDownload; + } + + public boolean grabSnapshotBuild(String urlString) { + DisguiseUtilities.getLogger().info("Now downloading latest build of Lib's Disguises from " + urlString); + lastDownload = -1; + + File dest = new File(Bukkit.getUpdateFolderFile(), "LibsDisguises.jar"); + + if (!dest.exists()) { + dest.mkdirs(); + } + + try { + // We're connecting to spigot's API + URL url = new URL(urlString); + // Creating a connection + HttpURLConnection con = (HttpURLConnection) url.openConnection(); + + // Get the input stream, what we receive + try (InputStream input = con.getInputStream()) { + FileUtils.copyInputStreamToFile(input, dest); + } + + DisguiseUtilities.getLogger().info("Download success!"); + return true; + } + catch (Exception ex) { + // Failed, set the last download back to previous build + dest.delete(); + DisguiseUtilities.getLogger().warning("Failed to download snapshot build."); + lastDownload = 0; + } + + return false; + } + public void checkSnapshotUpdate(int buildNumber) { Map lastBuild = fetchLastSnapshotBuild(); diff --git a/src/main/java/me/libraryaddict/disguise/utilities/packets/packethandlers/PacketHandlerSpawn.java b/src/main/java/me/libraryaddict/disguise/utilities/packets/packethandlers/PacketHandlerSpawn.java index 85170afd..21f464f8 100644 --- a/src/main/java/me/libraryaddict/disguise/utilities/packets/packethandlers/PacketHandlerSpawn.java +++ b/src/main/java/me/libraryaddict/disguise/utilities/packets/packethandlers/PacketHandlerSpawn.java @@ -181,7 +181,7 @@ public class PacketHandlerSpawn implements IPacketHandler { if (LibsPremium.getPaidInformation() == null || LibsPremium.getPaidInformation().getBuildNumber().matches("#[0-9]+")) { - packets.addDelayedPacket(deleteTab, 2); + packets.addDelayedPacket(deleteTab, DisguiseConfig.getTablistRemoveDelay()); } } diff --git a/src/main/java/me/libraryaddict/disguise/utilities/translations/LibsMsg.java b/src/main/java/me/libraryaddict/disguise/utilities/translations/LibsMsg.java index 154221ee..19f44328 100644 --- a/src/main/java/me/libraryaddict/disguise/utilities/translations/LibsMsg.java +++ b/src/main/java/me/libraryaddict/disguise/utilities/translations/LibsMsg.java @@ -137,6 +137,11 @@ public enum LibsMsg { NO_MODS(ChatColor.RED + "%s is not using any mods!"), MODS_LIST(ChatColor.DARK_GREEN + "%s has the mods:" + ChatColor.AQUA + " %s"), NO_PERM(ChatColor.RED + "You are forbidden to use this command."), + UPDATE_NOT_READY(ChatColor.RED + "Lib's Disguises doesn't know what's the latest update!"), + UPDATE_ON_LATEST(ChatColor.RED + "You are already on the latest version of LibsDisguises!"), + UPDATE_FAILED(ChatColor.RED + "LibsDisguises update failed! Check console for errors."), + UPDATE_SUCCESS(ChatColor.DARK_GREEN + "LibsDisguises update success! Restart server to update!"), + UPDATE_IN_PROGRESS(ChatColor.DARK_GREEN + "LibsDisguises is now downloading an update..."), NO_PERM_DISGUISE(ChatColor.RED + "You do not have permission for that disguise!"), NO_MODS_LISTENING(ChatColor.RED + "This server is not listening for mods!"), NO_PERMS_USE_OPTIONS(ChatColor.RED + diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 27b2f2bb..9a35a993 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -70,6 +70,8 @@ ExtendedNames: false # Notch [DragonSlayer lvl: 28] # It's recommended to leave this on unless you need it off ScoreboardNames: true +# How many ticks before tab packet is sent to remove from tablist. This shouldn't need to be touched +TablistRemoveDelay: 2 # Does the player keep their disguise after they die? KeepDisguises: @@ -97,6 +99,7 @@ Scoreboard: WarnConflict: true # Shall I notify those with the correct permission when there's a LibsDisguises update? +# Disabling this will also disable auto updating NotifyUpdate: true # Whats the permission to get the notification? @@ -107,6 +110,8 @@ Permission: 'libsdisguises.update' # RELEASES - Only check for actual releases # SNAPSHOTS - Only check for new snapshots UpdatesBranch: SAME_BUILDS +# Should the plugin automatically update if the server is using dev builds? +AutoUpdateDev: true # Whats the max size allowed for command disguiseradius DisguiseRadiusMax: 50