From 6d707c34a83044fc64a0379ea5076e8e4e4d62fd Mon Sep 17 00:00:00 2001 From: Pim van der Loos Date: Tue, 26 Sep 2017 15:53:57 +0200 Subject: [PATCH] - Added update checker (with config option to disable). - Added support for %ARMOR_TIER% variable in config. - Removed order requirement when crafting armored elytas (armor+elytra and elytra+armor both works now). - Added support for enchanted books. - Removed some code duplication. --- pom.xml | 16 +- .../armoredElytra/ArmoredElytra.java | 211 +++++++++++------- .../armoredElytra/EventHandlers.java | 18 +- .../pim16aap2/armoredElytra/LoginHandler.java | 36 +++ .../pim16aap2/armoredElytra/util/Update.java | 137 ++++++++++++ src/main/resources/config.yml | 8 +- src/main/resources/plugin.yml | 8 +- 7 files changed, 330 insertions(+), 104 deletions(-) create mode 100644 src/main/java/nl/pim16aap2/armoredElytra/LoginHandler.java create mode 100644 src/main/java/nl/pim16aap2/armoredElytra/util/Update.java diff --git a/pom.xml b/pom.xml index 3d76860..aab7640 100644 --- a/pom.xml +++ b/pom.xml @@ -1,14 +1,18 @@ - - 4.0.0 + 4.0.0 nl.pim16aap2 ArmoredElytra - 1.5.0-SNAPSHOT + 1.6.0-SNAPSHOT + + spigot-repo https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + @@ -17,12 +21,14 @@ 1.11.2-R0.1-SNAPSHOT provided + org.spigotmc spigot-api 1.12.1-R0.1-SNAPSHOT provided + org.bukkit @@ -30,6 +36,7 @@ 1.11.2-R0.1-SNAPSHOT provided + org.bukkit craftbukkit @@ -37,6 +44,9 @@ provided + + + diff --git a/src/main/java/nl/pim16aap2/armoredElytra/ArmoredElytra.java b/src/main/java/nl/pim16aap2/armoredElytra/ArmoredElytra.java index ee12d6b..31e82f6 100644 --- a/src/main/java/nl/pim16aap2/armoredElytra/ArmoredElytra.java +++ b/src/main/java/nl/pim16aap2/armoredElytra/ArmoredElytra.java @@ -18,6 +18,7 @@ import net.md_5.bungee.api.ChatColor; import nl.pim16aap2.armoredElytra.nms.NBTEditor; import nl.pim16aap2.armoredElytra.nms.NBTEditor_V1_11_R1; import nl.pim16aap2.armoredElytra.nms.NBTEditor_V1_12_R1; +import nl.pim16aap2.armoredElytra.util.Update; public class ArmoredElytra extends JavaPlugin implements Listener { @@ -30,6 +31,8 @@ public class ArmoredElytra extends JavaPlugin implements Listener private String[] allowedEnchants; private String usageDeniedMessage; private String elytraReceivedMessage; + private boolean checkForUpdates; + private boolean upToDate; @Override public void onEnable() @@ -42,8 +45,9 @@ public class ArmoredElytra extends JavaPlugin implements Listener config.addDefault("allowCurses", true); config.addDefault("allowedEnchantments", new String[]{"DURABILITY","PROTECTION_FIRE","PROTECTION_EXPLOSIONS", "PROTECTION_PROJECTILE","PROTECTION_ENVIRONMENTAL","THORNS"}); - config.addDefault("usageDeniedMessage", "You do not have the required permission node for this armor tier!"); - config.addDefault("elytraReceivedMessage", "An armored elytra has been bestowed upon you!"); + config.addDefault("usageDeniedMessage", "You do not have the required permissions to wear %ARMOR_TIER% armored elytras!"); + config.addDefault("elytraReceivedMessage", "A(n) %ARMOR_TIER% armored elytra has been bestowed upon you!"); + config.addDefault("checkForUpdates", true); saveDefaultConfig(); LEATHER_TO_FULL = config.getInt("leatherRepair", 6); @@ -55,15 +59,32 @@ public class ArmoredElytra extends JavaPlugin implements Listener allowedEnchants = list.toArray(new String[0]); usageDeniedMessage = config.getString("usageDeniedMessage"); elytraReceivedMessage = config.getString("elytraReceivedMessage"); + checkForUpdates = config.getBoolean("checkForUpdates"); + + usageDeniedMessage = (Objects.equals(usageDeniedMessage, new String("NONE")) ? null : usageDeniedMessage); + elytraReceivedMessage = (Objects.equals(elytraReceivedMessage, new String("NONE")) ? null : elytraReceivedMessage); - if (Objects.equals(usageDeniedMessage, new String("NONE"))) - { - usageDeniedMessage = null; - } - if (Objects.equals(elytraReceivedMessage, new String("NONE"))) + // Check if the user allows checking for updates. + if (checkForUpdates) { - elytraReceivedMessage = null; + Bukkit.getPluginManager().registerEvents(new LoginHandler(this), this); + + Update update = new Update(278437, this); + + String latestVersion = update.getLatestVersion(); + String thisVersion = this.getDescription().getVersion(); + int updateStatus = update.versionCompare(latestVersion, thisVersion); + + if (updateStatus > 0) + { + myLogger(Level.INFO, "Plugin out of date! You are using version "+thisVersion+" but the latest version is version "+latestVersion+"!"); + this.upToDate = false; + }else + { + this.upToDate = true; + myLogger(Level.INFO, "You seem to be using the latest version of this plugin!"); + } } config.options().copyDefaults(true); @@ -77,12 +98,18 @@ public class ArmoredElytra extends JavaPlugin implements Listener if (compatibleMCVer()) { - Bukkit.getPluginManager().registerEvents(new EventHandlers(this, nbtEditor, cursesAllowed, LEATHER_TO_FULL, GOLD_TO_FULL, IRON_TO_FULL, DIAMONDS_TO_FULL, allowedEnchants, usageDeniedMessage), this); + Bukkit.getPluginManager().registerEvents(new EventHandlers(this, nbtEditor, cursesAllowed, LEATHER_TO_FULL, GOLD_TO_FULL, IRON_TO_FULL, DIAMONDS_TO_FULL, allowedEnchants), this); } else { myLogger(Level.WARNING, "Trying to load the plugin on an incompatible version of Minecraft!"); } } + + public boolean isUpToDate() + { + return upToDate; + } + // Send a message to a player in a specific color. public void messagePlayer(Player player, ChatColor color, String s) { @@ -95,6 +122,50 @@ public class ArmoredElytra extends JavaPlugin implements Listener messagePlayer(player, ChatColor.WHITE, s); } + public String armorTierToString(int armorTier) + { + String armorTierName = null; + switch(armorTier) + { + case 0: + armorTierName = "unarmored"; + case 1: + armorTierName = "leather"; + case 2: + armorTierName = "gold"; + case 3: + armorTierName = "chain"; + case 4: + armorTierName = "iron"; + case 5: + armorTierName = "diamond"; + } + + return armorTierName; + } + + // Send the usageDeniedMessage message to the player. + public void usageDeniedMessage(Player player, int armorTier) + { + if (usageDeniedMessage != null) + { + String armorTierName = armorTierToString(armorTier); + String message = usageDeniedMessage.replace("%ARMOR_TIER%", armorTierName); + messagePlayer(player, ChatColor.RED, message); + } + } + + // Send the elytraReceivedMessage message to the player. + public void elytraReceivedMessage(Player player, int armorTier) + { + if (elytraReceivedMessage != null) + { + String armorTierName = armorTierToString(armorTier); + String message = elytraReceivedMessage.replace("%ARMOR_TIER%", armorTierName); + messagePlayer(player, ChatColor.GREEN, message); + } + } + // Print a string to the log. public void myLogger(Level level, String s) { @@ -111,23 +182,34 @@ public class ArmoredElytra extends JavaPlugin implements Listener player = (Player) sender; if (cmd.getName().equalsIgnoreCase("ArmoredElytra")) { - if (args.length == 1) + if (args.length == 1 || args.length == 2) { ItemStack newElytra = null; - String tier = args[0]; + String tier = null; + Player receiver; + boolean allowed = false; + int armorTier = 0; + if (args.length == 1) + { + receiver = player; + tier = args[0]; + } else + { + receiver = Bukkit.getPlayer(args[0]); + if (receiver == null) + { + messagePlayer(player, ChatColor.RED, "Player \""+args[0]+"\" not found!"); + return true; + } + tier = args[1]; + } // Leather armor. if (tier.equalsIgnoreCase("leather")) { if (player.hasPermission("armoredelytra.give.leather")) { - if (elytraReceivedMessage != null) - { - messagePlayer(player, elytraReceivedMessage); - } - newElytra = nbtEditor.addArmorNBTTags(new ItemStack(Material.ELYTRA, 1), 1); - } else - { - messagePlayer(player, ChatColor.RED, "You do not have the required permission node for this armor tier!"); + armorTier = 1; + allowed = true; } // Gold armor. @@ -135,14 +217,8 @@ public class ArmoredElytra extends JavaPlugin implements Listener { if (player.hasPermission("armoredelytra.give.gold")) { - if (elytraReceivedMessage != null) - { - messagePlayer(player, elytraReceivedMessage); - } - newElytra = nbtEditor.addArmorNBTTags(new ItemStack(Material.ELYTRA, 1), 2); - } else - { - messagePlayer(player, "You do not have the required permission node for this armor tier!"); + armorTier = 2; + allowed = true; } // Chain armor. @@ -150,14 +226,8 @@ public class ArmoredElytra extends JavaPlugin implements Listener { if (player.hasPermission("armoredelytra.give.chain")) { - if (elytraReceivedMessage != null) - { - messagePlayer(player, elytraReceivedMessage); - } - newElytra = nbtEditor.addArmorNBTTags(new ItemStack(Material.ELYTRA, 1), 3); - } else - { - messagePlayer(player, "You do not have the required permission node for this armor tier!"); + armorTier = 3; + allowed = true; } // Iron armor. @@ -165,14 +235,8 @@ public class ArmoredElytra extends JavaPlugin implements Listener { if (player.hasPermission("armoredelytra.give.iron")) { - if (elytraReceivedMessage != null) - { - messagePlayer(player, elytraReceivedMessage); - } - newElytra = nbtEditor.addArmorNBTTags(new ItemStack(Material.ELYTRA, 1), 4); - } else - { - messagePlayer(player, "You do not have the required permission node for this armor tier!"); + armorTier = 4; + allowed = true; } // Diamond armor. @@ -180,21 +244,22 @@ public class ArmoredElytra extends JavaPlugin implements Listener { if (player.hasPermission("armoredelytra.give.diamond")) { - if (elytraReceivedMessage != null) - { - messagePlayer(player, elytraReceivedMessage); - } - newElytra = nbtEditor.addArmorNBTTags(new ItemStack(Material.ELYTRA, 1), 5); - } else - { - messagePlayer(player, "You do not have the required permission node for this armor tier!"); + armorTier = 5; + allowed = true; } - } else { messagePlayer(player, "Not a supported armor tier! Try one of these: leather, gold, chain, iron, diamond."); } - giveArmoredElytraToPlayer(player, newElytra); + if (allowed) + { + elytraReceivedMessage(receiver, armorTier); + newElytra = nbtEditor.addArmorNBTTags(new ItemStack(Material.ELYTRA, 1), armorTier); + giveArmoredElytraToPlayer(receiver, newElytra); + } else + { + messagePlayer(player, "You do not have the required permission node to give "+ armorTierToString(armorTier) + " armored elytras."); + } return true; } } @@ -207,54 +272,34 @@ public class ArmoredElytra extends JavaPlugin implements Listener if (Bukkit.getPlayer(args[0]) != null) { player = Bukkit.getPlayer(args[0]); + int armorTier = 0; // Leather armor tier. if (tier.equalsIgnoreCase("leather")) { - if (elytraReceivedMessage != null) - { - messagePlayer(player, elytraReceivedMessage); - } - myLogger(Level.INFO, ("Giving an armored elytra of the leather armor tier to player "+player.getName())); - newElytra = nbtEditor.addArmorNBTTags(new ItemStack(Material.ELYTRA, 1), 1); + armorTier = 1; // Gold armor tier. } else if (tier.equalsIgnoreCase("gold")) { - if (elytraReceivedMessage != null) - { - messagePlayer(player, elytraReceivedMessage); - } - myLogger(Level.INFO, ("Giving an armored elytra of the gold armor tier to player "+player.getName())); - newElytra = nbtEditor.addArmorNBTTags(new ItemStack(Material.ELYTRA, 1), 2); + armorTier = 2; // Chain armor tier. } else if (tier.equalsIgnoreCase("chain")) { - if (elytraReceivedMessage != null) - { - messagePlayer(player, elytraReceivedMessage); - } - myLogger(Level.INFO, ("Giving an armored elytra of the chain armor tier to player "+player.getName())); - newElytra = nbtEditor.addArmorNBTTags(new ItemStack(Material.ELYTRA, 1), 3); + armorTier = 3; // Iron armor tier. } else if (tier.equalsIgnoreCase("iron")) { - if (elytraReceivedMessage != null) - { - messagePlayer(player, elytraReceivedMessage); - } - myLogger(Level.INFO, ("Giving an armored elytra of the iron armor tier to player "+player.getName())); - newElytra = nbtEditor.addArmorNBTTags(new ItemStack(Material.ELYTRA, 1), 4); + armorTier = 4; // Diamond armor tier. } else if (tier.equalsIgnoreCase("diamond")) { - if (elytraReceivedMessage != null) - { - messagePlayer(player, elytraReceivedMessage); - } - myLogger(Level.INFO, ("Giving an armored elytra of the armor armor tier to player "+player.getName())); - newElytra = nbtEditor.addArmorNBTTags(new ItemStack(Material.ELYTRA, 1), 5); + armorTier = 5; } + + elytraReceivedMessage(player, armorTier); + newElytra = nbtEditor.addArmorNBTTags(new ItemStack(Material.ELYTRA, 1), armorTier); giveArmoredElytraToPlayer(player, newElytra); + myLogger(Level.INFO, ("Giving an armored elytra of the "+ armorTierToString(armorTier) +" armor tier to player "+player.getName())); return true; } else { diff --git a/src/main/java/nl/pim16aap2/armoredElytra/EventHandlers.java b/src/main/java/nl/pim16aap2/armoredElytra/EventHandlers.java index 46c43f5..d015909 100644 --- a/src/main/java/nl/pim16aap2/armoredElytra/EventHandlers.java +++ b/src/main/java/nl/pim16aap2/armoredElytra/EventHandlers.java @@ -32,13 +32,12 @@ public class EventHandlers implements Listener private boolean cursesAllowed; private NBTEditor nbtEditor; private final ArmoredElytra plugin; - private String usageDeniedMessage; private String[] allowedEnchantments; private String[] cursedEnchantments = {"MENDING", "VANISHING_CURSE", "BINDING_CURSE"}; - public EventHandlers(ArmoredElytra plugin, NBTEditor nbtEditor, boolean allowCurses, int LEATHER_TO_FULL, int GOLD_TO_FULL, int IRON_TO_FULL, int DIAMONDS_TO_FULL, String[] allowedEnchantments, String usageDeniedMessage) + public EventHandlers(ArmoredElytra plugin, NBTEditor nbtEditor, boolean allowCurses, int LEATHER_TO_FULL, int GOLD_TO_FULL, int IRON_TO_FULL, int DIAMONDS_TO_FULL, String[] allowedEnchantments) { this.plugin = plugin; this.nbtEditor = nbtEditor; @@ -48,7 +47,6 @@ public class EventHandlers implements Listener this.LEATHER_TO_FULL = LEATHER_TO_FULL; this.GOLD_TO_FULL = GOLD_TO_FULL; this.IRON_TO_FULL = IRON_TO_FULL; - this.usageDeniedMessage = usageDeniedMessage; } @@ -263,8 +261,8 @@ public class EventHandlers implements Listener result = null; } } - - + + // Check if there are items in both input slots. if (itemA != null && itemB != null) { @@ -450,10 +448,7 @@ public class EventHandlers implements Listener (armorTier == 4 && !player.hasPermission("armoredelytra.wear.iron")) || (armorTier == 5 && !player.hasPermission("armoredelytra.wear.diamond"))) { - if (usageDeniedMessage != null) - { - plugin.messagePlayer(player, ChatColor.RED + usageDeniedMessage); - } + plugin.usageDeniedMessage(player, armorTier); event.setCancelled(true); } } @@ -491,10 +486,7 @@ public class EventHandlers implements Listener (armorTier == 4 && !player.hasPermission("armoredelytra.wear.iron")) || (armorTier == 5 && !player.hasPermission("armoredelytra.wear.diamond"))) { - if (usageDeniedMessage != null) - { - plugin.messagePlayer(player, ChatColor.RED + usageDeniedMessage); - } + plugin.usageDeniedMessage(player, armorTier); unenquipChestPlayer(player); } player.updateInventory(); diff --git a/src/main/java/nl/pim16aap2/armoredElytra/LoginHandler.java b/src/main/java/nl/pim16aap2/armoredElytra/LoginHandler.java new file mode 100644 index 0000000..3270b91 --- /dev/null +++ b/src/main/java/nl/pim16aap2/armoredElytra/LoginHandler.java @@ -0,0 +1,36 @@ +package nl.pim16aap2.armoredElytra; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerLoginEvent; +import org.bukkit.scheduler.BukkitRunnable; + +import net.md_5.bungee.api.ChatColor; + +public class LoginHandler implements Listener { + + ArmoredElytra plugin; + + public LoginHandler(ArmoredElytra plugin) + { + this.plugin = plugin; + } + + @EventHandler + public void onLogin(PlayerLoginEvent event) + { + Player player = event.getPlayer(); + if (player.hasPermission("armoredElytra.admin") && !plugin.isUpToDate()) + { + new BukkitRunnable() + { + @Override + public void run() + { + plugin.messagePlayer(player, ChatColor.AQUA, "The Armored Elytra plugin is out of date!"); + } + }.runTaskLater(this.plugin, 10); + } + } +} diff --git a/src/main/java/nl/pim16aap2/armoredElytra/util/Update.java b/src/main/java/nl/pim16aap2/armoredElytra/util/Update.java new file mode 100644 index 0000000..7a94d1f --- /dev/null +++ b/src/main/java/nl/pim16aap2/armoredElytra/util/Update.java @@ -0,0 +1,137 @@ +package nl.pim16aap2.armoredElytra.util; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; + +import nl.pim16aap2.armoredElytra.ArmoredElytra; + + +public class Update { + + // The project's unique ID + private final int projectID; + + // An optional API key to use, will be null if not submitted + private final String apiKey; + + // Keys for extracting file information from JSON response + private static final String API_NAME_VALUE = "name"; + + // Static information for querying the API + private static final String API_QUERY = "/servermods/files?projectIds="; + private static final String API_HOST = "https://api.curseforge.com"; + + private String versionName; + ArmoredElytra plugin; + + /** + * Check for updates anonymously (keyless) + * + * @param projectID The BukkitDev Project ID, found in the "Facts" panel on the right-side of your project page. + */ + public Update(int projectID, ArmoredElytra plugin) { + this(projectID, null, plugin); + } + + /** + * Check for updates using your Curse account (with key) + * + * @param projectID The BukkitDev Project ID, found in the "Facts" panel on the right-side of your project page. + * @param apiKey Your ServerMods API key, found at https://dev.bukkit.org/home/servermods-apikey/ + */ + public Update(int projectID, String apiKey, ArmoredElytra plugin) { + this.projectID = projectID; + this.apiKey = apiKey; + this.plugin = plugin; + + query(); + } + + + + public int versionCompare(String str1, String str2) { + String[] vals1 = str1.split("\\."); + String[] vals2 = str2.split("\\."); + int i = 0; + // set index to first non-equal ordinal or length of shortest version string + while (i < vals1.length && i < vals2.length && vals1[i].equals(vals2[i])) { + i++; + } + // compare first non-equal ordinal number + if (i < vals1.length && i < vals2.length) { + int diff = Integer.valueOf(vals1[i]).compareTo(Integer.valueOf(vals2[i])); + return Integer.signum(diff); + } + // the strings are equal or one string is a substring of the other + // e.g. "1.2.3" = "1.2.3" or "1.2.3" < "1.2.3.4" + return Integer.signum(vals1.length - vals2.length); + } + + // Get the latest version of the plugin. + public String getLatestVersion() + { + return versionName.replaceAll("Armored Elytra ", ""); + } + + + /** + * Query the API to find the latest approved file's details. + */ + public void query() { + URL url = null; + + try { + // Create the URL to query using the project's ID + url = new URL(API_HOST + API_QUERY + projectID); + } catch (MalformedURLException e) { + // There was an error creating the URL + + e.printStackTrace(); + return; + } + + try { + // Open a connection and query the project + URLConnection conn = url.openConnection(); + + if (apiKey != null) { + // Add the API key to the request if present + conn.addRequestProperty("X-API-Key", apiKey); + } + + // Add the user-agent to identify the program + conn.addRequestProperty("User-Agent", "ServerModsAPI-Example (by Gravity)"); + + // Read the response of the query + // The response will be in a JSON format, so only reading one line is necessary. + final BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); + String response = reader.readLine(); + + // Parse the array of files from the query's response + JSONArray array = (JSONArray) JSONValue.parse(response); + + if (array.size() > 0) { + // Get the newest file's details + JSONObject latest = (JSONObject) array.get(array.size() - 1); + + // Get the version's title + this.versionName = (String) latest.get(API_NAME_VALUE); + } else { + + } + } catch (IOException e) { + // There was an error reading the query + + e.printStackTrace(); + return; + } + } +} \ No newline at end of file diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index e7ddc70..191d4ca 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,4 +1,5 @@ # Amount of items it takes to fully repair an armored elytra +# Repair cost for every tier of armored elytra in number of items to repair 100%. leatherRepair: 6 goldRepair: 5 ironRepair: 4 @@ -19,7 +20,10 @@ allowedEnchantments: - THORNS # Message players receive when they lack the required permissions to wear a certain armor tier. "NONE" = no message -usageDeniedMessage: "You do not have the required permission node for this armor tier!" +usageDeniedMessage: "You do not have the required permissions to wear %ARMOR_TIER% armored elytras!" # Message players receive when they are given an armored elytra using commands. "NONE" = no message -elytraReceivedMessage: "An armored elytra has been bestowed upon you!" \ No newline at end of file +elytraReceivedMessage: "A(n) %ARMOR_TIER% armored elytra has been bestowed upon you!" + +# Allow this plugin to check for updates on startup. It will not download new versions! +checkForUpdates: true \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 9b63043..092d041 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,11 +1,11 @@ name: ArmoredElytra main: nl.pim16aap2.armoredElytra.ArmoredElytra -version: 1.5.0 +version: 1.6.0 author: Pim commands: ArmoredElytra: description: Give an armored elytra of the specified tier. - usage: /ArmoredElytra + usage: /ArmoredElytra [receiver] permission: armoredelytra.give permission-message: You do not have the armoredelytra.give permission node. permissions: @@ -28,4 +28,6 @@ permissions: armoredelytra.give.iron: description: Allow the player to spawn in iron tier armored elytras. armoredelytra.give.diamond: - description: Allow the player to spawn in diamond tier armored elytras. \ No newline at end of file + description: Allow the player to spawn in diamond tier armored elytras. + armoredElytra.admin: + description: Receive a message upon joining the game if this plugin is out of date. \ No newline at end of file