diff --git a/src/main/java/com/codingforcookies/armorequip/ArmorEquipEvent.java b/src/main/java/com/codingforcookies/armorequip/ArmorEquipEvent.java new file mode 100644 index 0000000..30720ba --- /dev/null +++ b/src/main/java/com/codingforcookies/armorequip/ArmorEquipEvent.java @@ -0,0 +1,163 @@ +package com.codingforcookies.armorequip; + +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; +import org.bukkit.inventory.ItemStack; + +/** + * @author Arnah + * @since Jul 30, 2015 + */ +public final class ArmorEquipEvent extends PlayerEvent implements Cancellable +{ + private static final HandlerList handlers = new HandlerList(); + private boolean cancel = false; + private final EquipMethod equipType; + private final ArmorType type; + private ItemStack oldArmorPiece, newArmorPiece; + + /** + * Constructor for the ArmorEquipEvent. + * + * @param player The player who put on / removed the armor. + * @param type The ArmorType of the armor added + * @param oldArmorPiece The ItemStack of the armor removed. + * @param newArmorPiece The ItemStack of the armor added. + */ + public ArmorEquipEvent(final Player player, final EquipMethod equipType, final ArmorType type, + final ItemStack oldArmorPiece, final ItemStack newArmorPiece) + { + super(player); + this.equipType = equipType; + this.type = type; + this.oldArmorPiece = oldArmorPiece; + this.newArmorPiece = newArmorPiece; + } + + /** + * Gets a list of handlers handling this event. + * + * @return A list of handlers handling this event. + */ + public final static HandlerList getHandlerList() + { + return handlers; + } + + /** + * Gets a list of handlers handling this event. + * + * @return A list of handlers handling this event. + */ + @Override + public final HandlerList getHandlers() + { + return handlers; + } + + /** + * Sets if this event should be cancelled. + * + * @param cancel If this event should be cancelled. + */ + @Override + public final void setCancelled(final boolean cancel) + { + this.cancel = cancel; + } + + /** + * Gets if this event is cancelled. + * + * @return If this event is cancelled + */ + @Override + public final boolean isCancelled() + { + return cancel; + } + + public final ArmorType getType() + { + return type; + } + + /** + * Returns the last equipped armor piece, could be a piece of armor, + * {@link Material#Air}, or null. + */ + public final ItemStack getOldArmorPiece() + { + return oldArmorPiece; + } + + public final void setOldArmorPiece(final ItemStack oldArmorPiece) + { + this.oldArmorPiece = oldArmorPiece; + } + + /** + * Returns the newly equipped armor, could be a piece of armor, + * {@link Material#Air}, or null. + */ + public final ItemStack getNewArmorPiece() + { + return newArmorPiece; + } + + public final void setNewArmorPiece(final ItemStack newArmorPiece) + { + this.newArmorPiece = newArmorPiece; + } + + /** + * Gets the method used to either equip or unequip an armor piece. + */ + public EquipMethod getMethod() + { + return equipType; + } + + public enum EquipMethod + {// These have got to be the worst documentations ever. + /** + * When you shift click an armor piece to equip or unequip + */ + SHIFT_CLICK, + /** + * When you drag and drop the item to equip or unequip + */ + DRAG, + /** + * When you manually equip or unequip the item. Use to be DRAG + */ + PICK_DROP, + /** + * When you right click an armor piece in the hotbar without the inventory open + * to equip. + */ + HOTBAR, + /** + * When you press the hotbar slot number while hovering over the armor slot to + * equip or unequip + */ + HOTBAR_SWAP, + /** + * When in range of a dispenser that shoots an armor piece to equip.
+ * Requires the spigot version to have + * {@link org.bukkit.event.block.BlockDispenseArmorEvent} implemented. + */ + DISPENSER, + /** + * When an armor piece is removed due to it losing all durability. + */ + BROKE, + /** + * When you die causing all armor to unequip + */ + DEATH,; + } +} \ No newline at end of file diff --git a/src/main/java/com/codingforcookies/armorequip/ArmorListener.java b/src/main/java/com/codingforcookies/armorequip/ArmorListener.java new file mode 100644 index 0000000..f37eda3 --- /dev/null +++ b/src/main/java/com/codingforcookies/armorequip/ArmorListener.java @@ -0,0 +1,265 @@ +package com.codingforcookies.armorequip; + +import java.util.List; + +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.Event.Result; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.event.inventory.InventoryAction; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryDragEvent; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.event.inventory.InventoryType.SlotType; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerItemBreakEvent; +import org.bukkit.inventory.ItemStack; + +import com.codingforcookies.armorequip.ArmorEquipEvent.EquipMethod; + +/** + * @author Arnah + * @since Jul 30, 2015 + */ +public class ArmorListener implements Listener +{ + private final List blockedMaterials; + + public ArmorListener(List blockedMaterials) + { + this.blockedMaterials = blockedMaterials; + } + + @EventHandler + public final void inventoryClick(final InventoryClickEvent e) + { + boolean shift = false, numberkey = false; + if (e.isCancelled()) + return; + if (e.getAction() == InventoryAction.NOTHING) + return;// Why does this get called if nothing happens?? + if (e.getClick().equals(ClickType.SHIFT_LEFT) || e.getClick().equals(ClickType.SHIFT_RIGHT)) + shift = true; + if (e.getClick().equals(ClickType.NUMBER_KEY)) + numberkey = true; + if (e.getSlotType() != SlotType.ARMOR && e.getSlotType() != SlotType.QUICKBAR && + e.getSlotType() != SlotType.CONTAINER) + return; + if (e.getClickedInventory() != null && !e.getClickedInventory().getType().equals(InventoryType.PLAYER)) + return; + if (!e.getInventory().getType().equals(InventoryType.CRAFTING) && + !e.getInventory().getType().equals(InventoryType.PLAYER)) + return; + if (!(e.getWhoClicked() instanceof Player)) + return; + ArmorType newArmorType = ArmorType.matchType(shift ? e.getCurrentItem() : e.getCursor()); + if (!shift && newArmorType != null && e.getRawSlot() != newArmorType.getSlot()) + // Used for drag and drop checking to make sure you aren't trying to place a + // helmet in the boots slot. + return; + if (shift) + { + newArmorType = ArmorType.matchType(e.getCurrentItem()); + if (newArmorType != null) + { + boolean equipping = true; + if (e.getRawSlot() == newArmorType.getSlot()) + equipping = false; + if (newArmorType.equals(ArmorType.HELMET) && + (equipping ? isAirOrNull(e.getWhoClicked().getInventory().getHelmet()) : + !isAirOrNull(e.getWhoClicked().getInventory().getHelmet())) || + newArmorType.equals(ArmorType.CHESTPLATE) && (equipping ? + isAirOrNull(e.getWhoClicked().getInventory().getChestplate()) : + !isAirOrNull(e.getWhoClicked().getInventory().getChestplate())) || + newArmorType.equals(ArmorType.LEGGINGS) && (equipping ? + isAirOrNull(e.getWhoClicked().getInventory().getLeggings()) : + !isAirOrNull(e.getWhoClicked().getInventory().getLeggings())) || + newArmorType.equals(ArmorType.BOOTS) && (equipping ? + isAirOrNull(e.getWhoClicked().getInventory().getBoots()) : + !isAirOrNull(e.getWhoClicked().getInventory().getBoots()))) + { + ArmorEquipEvent armorEquipEvent = new ArmorEquipEvent((Player) e.getWhoClicked(), + EquipMethod.SHIFT_CLICK, newArmorType, + equipping ? null : e.getCurrentItem(), + equipping ? e.getCurrentItem() : null); + Bukkit.getServer().getPluginManager().callEvent(armorEquipEvent); + if (armorEquipEvent.isCancelled()) + e.setCancelled(true); + } + } + } + else + { + ItemStack newArmorPiece = e.getCursor(); + ItemStack oldArmorPiece = e.getCurrentItem(); + if (numberkey) + if (e.getClickedInventory().getType().equals(InventoryType.PLAYER)) + { // Prevents shit in the 2by2 crafting + // e.getClickedInventory() == The players inventory + // e.getHotBarButton() == key people are pressing to equip or unequip the item + // to or from. + // e.getRawSlot() == The slot the item is going to. + // e.getSlot() == Armor slot, can't use e.getRawSlot() as that gives a hotbar + // slot ;-; + ItemStack hotbarItem = e.getClickedInventory().getItem(e.getHotbarButton()); + if (!isAirOrNull(hotbarItem)) + { // Equipping + newArmorType = ArmorType.matchType(hotbarItem); + newArmorPiece = hotbarItem; + oldArmorPiece = e.getClickedInventory().getItem(e.getSlot()); + } + else + // Unequipping + newArmorType = ArmorType + .matchType(!isAirOrNull(e.getCurrentItem()) ? e.getCurrentItem() : e.getCursor()); + } + else + { + if (isAirOrNull(e.getCursor()) && !isAirOrNull(e.getCurrentItem())) + // unequip with no new item going into the slot. + newArmorType = ArmorType.matchType(e.getCurrentItem()); + // e.getCurrentItem() == Unequip + // e.getCursor() == Equip + // newArmorType = ArmorType.matchType(!isAirOrNull(e.getCurrentItem()) ? + // e.getCurrentItem() : e.getCursor()); + } + if (newArmorType != null && e.getRawSlot() == newArmorType.getSlot()) + { + EquipMethod method = EquipMethod.PICK_DROP; + if (e.getAction().equals(InventoryAction.HOTBAR_SWAP) || numberkey) + method = EquipMethod.HOTBAR_SWAP; + ArmorEquipEvent armorEquipEvent = new ArmorEquipEvent((Player) e.getWhoClicked(), method, newArmorType, + oldArmorPiece, newArmorPiece); + Bukkit.getServer().getPluginManager().callEvent(armorEquipEvent); + if (armorEquipEvent.isCancelled()) + e.setCancelled(true); + } + } + } + + @EventHandler + public void playerInteractEvent(PlayerInteractEvent e) + { + if (e.getAction() == Action.PHYSICAL) + return; + if (e.getAction() == Action.RIGHT_CLICK_AIR || e.getAction() == Action.RIGHT_CLICK_BLOCK) + { + final Player player = e.getPlayer(); + if (e.getClickedBlock() != null && e.getAction() == Action.RIGHT_CLICK_BLOCK) + { // Having both of these checks is useless, might as well do it though. + // Some blocks have actions when you right click them which stops the client + // from equipping the armor in hand. + Material mat = e.getClickedBlock().getType(); + for (String s : blockedMaterials) + if (mat.name().equalsIgnoreCase(s)) + return; + } + ArmorType newArmorType = ArmorType.matchType(e.getItem()); + if (newArmorType != null) + { + if (newArmorType.equals(ArmorType.HELMET) && isAirOrNull(e.getPlayer().getInventory().getHelmet()) || + newArmorType + .equals(ArmorType.CHESTPLATE) && isAirOrNull(e.getPlayer().getInventory().getChestplate()) || + newArmorType + .equals(ArmorType.LEGGINGS) && isAirOrNull(e.getPlayer().getInventory().getLeggings()) || + newArmorType.equals(ArmorType.BOOTS) && isAirOrNull(e.getPlayer().getInventory().getBoots())) + { + ArmorEquipEvent armorEquipEvent = new ArmorEquipEvent(e.getPlayer(), EquipMethod.HOTBAR, + ArmorType.matchType(e.getItem()), null, + e.getItem()); + Bukkit.getServer().getPluginManager().callEvent(armorEquipEvent); + if (armorEquipEvent.isCancelled()) + { + e.setCancelled(true); + player.updateInventory(); + } + } + } + } + } + + @EventHandler + public void inventoryDrag(InventoryDragEvent event) + { + // getType() seems to always be even. + // Old Cursor gives the item you are equipping + // Raw slot is the ArmorType slot + // Can't replace armor using this method making getCursor() useless. + ArmorType type = ArmorType.matchType(event.getOldCursor()); + if (event.getRawSlots().isEmpty()) + return;// Idk if this will ever happen + if (type != null && type.getSlot() == event.getRawSlots().stream().findFirst().orElse(0)) + { + ArmorEquipEvent armorEquipEvent = new ArmorEquipEvent((Player) event.getWhoClicked(), EquipMethod.DRAG, + type, null, event.getOldCursor()); + Bukkit.getServer().getPluginManager().callEvent(armorEquipEvent); + if (armorEquipEvent.isCancelled()) + { + event.setResult(Result.DENY); + event.setCancelled(true); + } + } + // Debug shit + /* + * System.out.println("Slots: " + event.getInventorySlots().toString()); + * System.out.println("Raw Slots: " + event.getRawSlots().toString()); + * if(event.getCursor() != null){ System.out.println("Cursor: " + + * event.getCursor().getType().name()); } if(event.getOldCursor() != null){ + * System.out.println("OldCursor: " + event.getOldCursor().getType().name()); } + * System.out.println("Type: " + event.getType().name()); + */ + } + + @EventHandler + public void itemBreakEvent(PlayerItemBreakEvent e) + { + ArmorType type = ArmorType.matchType(e.getBrokenItem()); + if (type != null) + { + Player p = e.getPlayer(); + ArmorEquipEvent armorEquipEvent = new ArmorEquipEvent(p, EquipMethod.BROKE, type, e.getBrokenItem(), null); + Bukkit.getServer().getPluginManager().callEvent(armorEquipEvent); + if (armorEquipEvent.isCancelled()) + { + ItemStack i = e.getBrokenItem().clone(); + i.setAmount(1); + i.setDurability((short) (i.getDurability() - 1)); + if (type.equals(ArmorType.HELMET)) + p.getInventory().setHelmet(i); + else if (type.equals(ArmorType.CHESTPLATE)) + p.getInventory().setChestplate(i); + else if (type.equals(ArmorType.LEGGINGS)) + p.getInventory().setLeggings(i); + else if (type.equals(ArmorType.BOOTS)) + p.getInventory().setBoots(i); + } + } + } + + @EventHandler + public void playerDeathEvent(PlayerDeathEvent e) + { + Player p = e.getEntity(); + for (ItemStack oldArmor : p.getInventory().getArmorContents()) + if (!isAirOrNull(oldArmor)) + { + ArmorType type = ArmorType.matchType(oldArmor); + Bukkit.getServer().getPluginManager().callEvent(new ArmorEquipEvent(p, EquipMethod.DEATH, + type, oldArmor, null)); + // No way to cancel a death event. + } + } + + /** + * A utility method to support versions that use null or air ItemStacks. + */ + private boolean isAirOrNull(ItemStack item) + { + return item == null || item.getType().equals(Material.AIR); + } +} diff --git a/src/main/java/com/codingforcookies/armorequip/ArmorType.java b/src/main/java/com/codingforcookies/armorequip/ArmorType.java new file mode 100644 index 0000000..99d7653 --- /dev/null +++ b/src/main/java/com/codingforcookies/armorequip/ArmorType.java @@ -0,0 +1,53 @@ +package com.codingforcookies.armorequip; + +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +/** + * @author Arnah + * @since Jul 30, 2015 + */ +public enum ArmorType +{ + HELMET (5), + CHESTPLATE (6), + LEGGINGS (7), + BOOTS (8); + + private final int slot; + + ArmorType(int slot) + { + this.slot = slot; + } + + /** + * Attempts to match the ArmorType for the specified ItemStack. + * + * @param itemStack The ItemStack to parse the type of. + * @return The parsed ArmorType. (null if none were found.) + */ + public final static ArmorType matchType(final ItemStack itemStack) + { + if (itemStack == null || itemStack.getType().equals(Material.AIR)) + return null; + if (itemStack.getType().equals(Material.ELYTRA)) + return CHESTPLATE; + String type = itemStack.getType().name(); + if (type.endsWith("_HELMET") || type.endsWith("_SKULL")) + return HELMET; + else if (type.endsWith("_CHESTPLATE")) + return CHESTPLATE; + else if (type.endsWith("_LEGGINGS")) + return LEGGINGS; + else if (type.endsWith("_BOOTS")) + return BOOTS; + else + return null; + } + + public int getSlot() + { + return slot; + } +} \ No newline at end of file diff --git a/src/main/java/com/codingforcookies/armorequip/DispenserArmorListener.java b/src/main/java/com/codingforcookies/armorequip/DispenserArmorListener.java new file mode 100644 index 0000000..587c8f1 --- /dev/null +++ b/src/main/java/com/codingforcookies/armorequip/DispenserArmorListener.java @@ -0,0 +1,30 @@ +package com.codingforcookies.armorequip; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockDispenseArmorEvent; + +/** + * @author Arnah + * @since Feb 08, 2019 + */ +public class DispenserArmorListener implements Listener +{ + @EventHandler + public void dispenseArmorEvent(BlockDispenseArmorEvent event) + { + ArmorType type = ArmorType.matchType(event.getItem()); + if (type != null) + if (event.getTargetEntity() instanceof Player) + { + Player p = (Player) event.getTargetEntity(); + ArmorEquipEvent armorEquipEvent = new ArmorEquipEvent(p, ArmorEquipEvent.EquipMethod.DISPENSER, type, + null, event.getItem()); + Bukkit.getServer().getPluginManager().callEvent(armorEquipEvent); + if (armorEquipEvent.isCancelled()) + event.setCancelled(true); + } + } +} diff --git a/src/main/java/nl/pim16aap2/armoredElytra/ArmoredElytra.java b/src/main/java/nl/pim16aap2/armoredElytra/ArmoredElytra.java index e03a3fd..ae077b9 100644 --- a/src/main/java/nl/pim16aap2/armoredElytra/ArmoredElytra.java +++ b/src/main/java/nl/pim16aap2/armoredElytra/ArmoredElytra.java @@ -1,7 +1,10 @@ package nl.pim16aap2.armoredElytra; +import java.util.EnumMap; +import java.util.Map; import java.util.Objects; import java.util.logging.Level; +import java.util.regex.Pattern; import org.bstats.bukkit.Metrics; import org.bukkit.Bukkit; @@ -18,6 +21,7 @@ import nl.pim16aap2.armoredElytra.handlers.LoginHandler; import nl.pim16aap2.armoredElytra.handlers.Uninstaller; import nl.pim16aap2.armoredElytra.nbtEditor.NBTEditor; import nl.pim16aap2.armoredElytra.util.ArmorTier; +import nl.pim16aap2.armoredElytra.util.ArmorTierName; import nl.pim16aap2.armoredElytra.util.ConfigLoader; import nl.pim16aap2.armoredElytra.util.Messages; import nl.pim16aap2.armoredElytra.util.Update; @@ -33,7 +37,8 @@ public class ArmoredElytra extends JavaPlugin implements Listener private Messages messages; private ConfigLoader config; - private String leatherName, ironName, goldName, chainName, diamondName; +// private String leatherName, ironName, goldName, chainName, diamondName; + private final Map armorTierNames = new EnumMap(ArmorTier.class); private String elytraReceivedMessage; private String usageDeniedMessage; private String elytraLore; @@ -137,18 +142,29 @@ public class ArmoredElytra extends JavaPlugin implements Listener return messages; } + private final String getColorCodedStringFromConfig(final String configEntry) + { + return getMyMessages().getString(configEntry).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1"); + } + private void readMessages() { // Replace color codes by the corresponding colors. - usageDeniedMessage = getMyMessages().getString("MESSAGES.UsageDenied" ).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1"); - elytraReceivedMessage = getMyMessages().getString("MESSAGES.ElytraReceived").replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1"); - elytraLore = getMyMessages().getString("MESSAGES.Lore" ).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1"); + usageDeniedMessage = getColorCodedStringFromConfig("MESSAGES.UsageDenied"); + elytraReceivedMessage = getColorCodedStringFromConfig("MESSAGES.ElytraReceived"); + elytraLore = getColorCodedStringFromConfig("MESSAGES.Lore"); - leatherName = getMyMessages().getString("TIER.Leather" ).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1"); - goldName = getMyMessages().getString("TIER.Gold" ).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1"); - chainName = getMyMessages().getString("TIER.Chain" ).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1"); - ironName = getMyMessages().getString("TIER.Iron" ).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1"); - diamondName = getMyMessages().getString("TIER.Diamond" ).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1"); + armorTierNames.put(ArmorTier.NONE, new ArmorTierName("NONE", "NONE")); // Shouldn't be used. + armorTierNames.put(ArmorTier.LEATHER, new ArmorTierName(getColorCodedStringFromConfig("TIER.Leather"), + getColorCodedStringFromConfig("TIER.SHORT.Leather"))); + armorTierNames.put(ArmorTier.GOLD, new ArmorTierName(getColorCodedStringFromConfig("TIER.Gold"), + getColorCodedStringFromConfig("TIER.SHORT.Gold"))); + armorTierNames.put(ArmorTier.CHAIN, new ArmorTierName(getColorCodedStringFromConfig("TIER.Chain"), + getColorCodedStringFromConfig("TIER.SHORT.Chain"))); + armorTierNames.put(ArmorTier.IRON, new ArmorTierName(getColorCodedStringFromConfig("TIER.Iron"), + getColorCodedStringFromConfig("TIER.SHORT.Iron"))); + armorTierNames.put(ArmorTier.DIAMOND, new ArmorTierName(getColorCodedStringFromConfig("TIER.Diamond"), + getColorCodedStringFromConfig("TIER.SHORT.Diamond"))); // Change the string to null if it says "NONE". usageDeniedMessage = (Objects.equals(usageDeniedMessage, new String("NONE")) ? null : usageDeniedMessage ); @@ -216,10 +232,20 @@ public class ArmoredElytra extends JavaPlugin implements Listener } } + private static final Pattern ARMOR_TIER = Pattern.compile("%ARMOR_TIER%"); + private static final Pattern ARMOR_TIER_SHORT = Pattern.compile("%ARMOR_TIER_SHORT%"); + // Replace %ARMOR_TIER% by the name of that armor tier in a string, but strip %ARMOR_TIER% of its color. public String fillInArmorTierInStringNoColor(String string, ArmorTier armorTier) { - return string.replace("%ARMOR_TIER%", ChatColor.stripColor(getArmoredElytrName(armorTier))); + if (armorTier == null) + { + getLogger().log(Level.INFO, "ArmorTier was null! Failed to obtain proper string!"); + return string; + } + final ArmorTierName tierName = armorTierNames.get(armorTier); + return ARMOR_TIER_SHORT.matcher(ARMOR_TIER.matcher(string).replaceAll(ChatColor.stripColor(tierName.getLongName()))) + .replaceAll(ChatColor.stripColor(tierName.getShortName())); } // Print a string to the log. @@ -254,30 +280,14 @@ public class ArmoredElytra extends JavaPlugin implements Listener return elytraLore; } - public String getArmoredElytrName(ArmorTier tier) + public String getArmoredElytraName(ArmorTier tier) { - String ret; - switch(tier) + if (tier == null) { - case LEATHER: - ret = leatherName; - break; - case GOLD: - ret = goldName; - break; - case CHAIN: - ret = chainName; - break; - case IRON: - ret = ironName; - break; - case DIAMOND: - ret = diamondName; - break; - default: - ret = "NONE"; + getLogger().log(Level.INFO, "ArmorTier was null! Failed to obtain proper string!"); + return "NULL"; } - return ret; + return armorTierNames.get(tier).getLongName(); } public void setUpToDate(boolean upToDate) diff --git a/src/main/java/nl/pim16aap2/armoredElytra/handlers/CommandHandler.java b/src/main/java/nl/pim16aap2/armoredElytra/handlers/CommandHandler.java index 02b4b6e..437fa1e 100644 --- a/src/main/java/nl/pim16aap2/armoredElytra/handlers/CommandHandler.java +++ b/src/main/java/nl/pim16aap2/armoredElytra/handlers/CommandHandler.java @@ -48,6 +48,7 @@ public class CommandHandler implements CommandExecutor String tier = null; Player receiver; boolean allowed = false; + if (args.length == 1) { receiver = player; diff --git a/src/main/java/nl/pim16aap2/armoredElytra/handlers/EventHandlers.java b/src/main/java/nl/pim16aap2/armoredElytra/handlers/EventHandlers.java index c7f38bb..fd04ad4 100644 --- a/src/main/java/nl/pim16aap2/armoredElytra/handlers/EventHandlers.java +++ b/src/main/java/nl/pim16aap2/armoredElytra/handlers/EventHandlers.java @@ -277,8 +277,9 @@ public class EventHandlers implements Listener // If the armored elytra is not of the leather tier, but itemTwo is leather, // Pick the block action, as that would repair the elytra by default (vanilla). - // Also block Armored Elytra + Elytra. - if (tier != ArmorTier.LEATHER && matTwo == Material.LEATHER || matTwo == Material.ELYTRA) + // Also block Armored Elytra + Elytra and Elytra + Membrane + if (tier != ArmorTier.LEATHER && matTwo == Material.LEATHER || matTwo == Material.ELYTRA || + matTwo.equals(XMaterial.PHANTOM_MEMBRANE.parseMaterial())) return Action.BLOCK; } return Action.NONE; diff --git a/src/main/java/nl/pim16aap2/armoredElytra/nbtEditor/NBTEditor.java b/src/main/java/nl/pim16aap2/armoredElytra/nbtEditor/NBTEditor.java index e69617e..361daff 100644 --- a/src/main/java/nl/pim16aap2/armoredElytra/nbtEditor/NBTEditor.java +++ b/src/main/java/nl/pim16aap2/armoredElytra/nbtEditor/NBTEditor.java @@ -66,7 +66,7 @@ public class NBTEditor String version; try { - version = Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3]; + version = Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3]; } catch (final ArrayIndexOutOfBoundsException useAVersionMentionedInTheDescriptionPleaseException) { @@ -74,9 +74,11 @@ public class NBTEditor return; } - // Old versions use the old format. It is assumed here that all versions from 1.13.2 on will use the new format. - // Spigot's 1.13.1 uses the old format, but 1.13.2 uses the new format. They share the same version number though. - if (version.equals("v1_9_R1" ) || version.equals("v1_9_R2" ) || version.equals("v1_10_R1") || + // Old versions use the old format. It is assumed here that all versions from + // 1.13.2 on will use the new format. + // Spigot's 1.13.1 uses the old format, but 1.13.2 uses the new format. They + // share the same version number though. + if (version.equals("v1_9_R1") || version.equals("v1_9_R2") || version.equals("v1_10_R1") || version.equals("v1_11_R1") || version.equals("v1_12_R1") || version.equals("v1_13_R1") || version.equals("v1_13_R2") && Bukkit.getVersion().split(" ")[2].equals("1.13.1)")) getArmorValue = new GetArmorValueOld(plugin); @@ -98,24 +100,27 @@ public class NBTEditor getTag = NMSItemStack.getMethod("getTag"); CraftItemStack = getCraftClass("inventory.CraftItemStack"); - asNMSCopy = CraftItemStack.getMethod("asNMSCopy", ItemStack.class); - asBukkitCopy = CraftItemStack.getMethod("asBukkitCopy", NMSItemStack); + asNMSCopy = CraftItemStack.getMethod("asNMSCopy", ItemStack.class); + asBukkitCopy = CraftItemStack.getMethod("asBukkitCopy", NMSItemStack); NBTBase = getNMSClass("NBTBase"); - NBTTagString = getNMSClass("NBTTagString"); - NBTTagStringCtor = NBTTagString.getConstructor(String.class); + NBTTagString = getNMSClass("NBTTagString"); + NBTTagStringCtor = NBTTagString.getDeclaredConstructor(String.class); + NBTTagStringCtor.setAccessible(true); - NBTTagByte = getNMSClass("NBTTagByte"); - NBTTagByteCtor = NBTTagByte.getConstructor(byte.class); + NBTTagByte = getNMSClass("NBTTagByte"); + NBTTagByteCtor = NBTTagByte.getDeclaredConstructor(byte.class); + NBTTagByteCtor.setAccessible(true); - NBTTagInt = getNMSClass("NBTTagInt"); - NBTTagIntCtor = NBTTagInt.getConstructor(int.class); + NBTTagInt = getNMSClass("NBTTagInt"); + NBTTagIntCtor = NBTTagInt.getDeclaredConstructor(int.class); + NBTTagIntCtor.setAccessible(true); NBTTagCompound = getNMSClass("NBTTagCompound"); - setTag = NBTTagCompound.getMethod("set", String.class, NBTBase); + setTag = NBTTagCompound.getMethod("set", String.class, NBTBase); - NBTTagList = getNMSClass("NBTTagList"); + NBTTagList = getNMSClass("NBTTagList"); // Starting in 1.14, you also need to provide an int value when adding nbt tags. try { @@ -127,7 +132,7 @@ public class NBTEditor } setCompoundTagList = NBTTagCompound.getMethod("set", String.class, NBTBase); - setCompoundByte = NBTTagCompound.getMethod("set", String.class, NBTBase); + setCompoundByte = NBTTagCompound.getMethod("set", String.class, NBTBase); success = true; } @@ -138,7 +143,8 @@ public class NBTEditor } } - private void addCompound(Object instance, Object nbtbase) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException + private void addCompound(Object instance, Object nbtbase) + throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { if (addCompound.getParameterCount() == 2) addCompound.invoke(instance, 0, nbtbase); @@ -151,36 +157,38 @@ public class NBTEditor { try { - ItemMeta itemmeta = item.getItemMeta(); + ItemMeta itemmeta = item.getItemMeta(); int armorProtection = ArmorTier.getArmor(armorTier); - int armorToughness = ArmorTier.getToughness(armorTier); + int armorToughness = ArmorTier.getToughness(armorTier); - itemmeta.setDisplayName(plugin.getArmoredElytrName(armorTier)); + itemmeta.setDisplayName(plugin.getArmoredElytraName(armorTier)); if (plugin.getElytraLore() != null) - itemmeta.setLore(Arrays.asList(plugin.fillInArmorTierInStringNoColor(plugin.getElytraLore(), armorTier))); + itemmeta + .setLore(Arrays.asList(plugin.fillInArmorTierInStringNoColor(plugin.getElytraLore(), armorTier))); item.setItemMeta(itemmeta); - Object nmsStack = asNMSCopy.invoke(null, item); - Object compound = ((boolean) hasTag.invoke(nmsStack) ? getTag.invoke(nmsStack) : NBTTagCompound.newInstance()); - Object modifiers = NBTTagList.newInstance(); - Object armor = NBTTagCompound.newInstance(); // I should be able to simply add custom tags here! - setTag.invoke (armor, "AttributeName", NBTTagStringCtor.newInstance("generic.armor")); - setTag.invoke (armor, "Name", NBTTagStringCtor.newInstance("generic.armor")); - setTag.invoke (armor, "Amount", NBTTagIntCtor.newInstance(armorProtection)); - setTag.invoke (armor, "Operation", NBTTagIntCtor.newInstance(0)); - setTag.invoke (armor, "UUIDLeast", NBTTagIntCtor.newInstance(894654)); - setTag.invoke (armor, "UUIDMost", NBTTagIntCtor.newInstance(2872)); - setTag.invoke (armor, "Slot", NBTTagStringCtor.newInstance("chest")); + Object nmsStack = asNMSCopy.invoke(null, item); + Object compound = ((boolean) hasTag.invoke(nmsStack) ? getTag.invoke(nmsStack) : + NBTTagCompound.newInstance()); + Object modifiers = NBTTagList.newInstance(); + Object armor = NBTTagCompound.newInstance(); // I should be able to simply add custom tags here! + setTag.invoke(armor, "AttributeName", NBTTagStringCtor.newInstance("generic.armor")); + setTag.invoke(armor, "Name", NBTTagStringCtor.newInstance("generic.armor")); + setTag.invoke(armor, "Amount", NBTTagIntCtor.newInstance(armorProtection)); + setTag.invoke(armor, "Operation", NBTTagIntCtor.newInstance(0)); + setTag.invoke(armor, "UUIDLeast", NBTTagIntCtor.newInstance(894654)); + setTag.invoke(armor, "UUIDMost", NBTTagIntCtor.newInstance(2872)); + setTag.invoke(armor, "Slot", NBTTagStringCtor.newInstance("chest")); addCompound(modifiers, armor); Object armorTough = NBTTagCompound.newInstance(); - setTag.invoke (armorTough, "AttributeName", NBTTagStringCtor.newInstance("generic.armorToughness")); - setTag.invoke (armorTough, "Name", NBTTagStringCtor.newInstance("generic.armorToughness")); - setTag.invoke (armorTough, "Amount", NBTTagIntCtor.newInstance(armorToughness)); - setTag.invoke (armorTough, "Operation", NBTTagIntCtor.newInstance(0)); - setTag.invoke (armorTough, "UUIDLeast", NBTTagIntCtor.newInstance(894654)); - setTag.invoke (armorTough, "UUIDMost", NBTTagIntCtor.newInstance(2872)); - setTag.invoke (armorTough, "Slot", NBTTagStringCtor.newInstance("chest")); + setTag.invoke(armorTough, "AttributeName", NBTTagStringCtor.newInstance("generic.armorToughness")); + setTag.invoke(armorTough, "Name", NBTTagStringCtor.newInstance("generic.armorToughness")); + setTag.invoke(armorTough, "Amount", NBTTagIntCtor.newInstance(armorToughness)); + setTag.invoke(armorTough, "Operation", NBTTagIntCtor.newInstance(0)); + setTag.invoke(armorTough, "UUIDLeast", NBTTagIntCtor.newInstance(894654)); + setTag.invoke(armorTough, "UUIDMost", NBTTagIntCtor.newInstance(2872)); + setTag.invoke(armorTough, "Slot", NBTTagStringCtor.newInstance("chest")); addCompound(modifiers, armorTough); if (unbreakable) @@ -192,7 +200,8 @@ public class NBTEditor } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | InstantiationException e) { - // TODO: Log this or something. Pretty serious issue for a plugin based entirely on this code. + // TODO: Log this or something. Pretty serious issue for a plugin based entirely + // on this code. e.printStackTrace(); } return item; diff --git a/src/main/java/nl/pim16aap2/armoredElytra/util/ArmorTierName.java b/src/main/java/nl/pim16aap2/armoredElytra/util/ArmorTierName.java new file mode 100644 index 0000000..ea397f9 --- /dev/null +++ b/src/main/java/nl/pim16aap2/armoredElytra/util/ArmorTierName.java @@ -0,0 +1,39 @@ +/** + * + */ +package nl.pim16aap2.armoredElytra.util; + +/** + * + * @author Pim + */ +public class ArmorTierName +{ + private String longName, shortName; + + public ArmorTierName(final String longName, final String shortName) + { + this.longName = longName; + this.shortName = shortName; + } + + public String getLongName() + { + return longName; + } + + public String getShortName() + { + return shortName; + } + + public void setLongName(final String longName) + { + this.longName = longName; + } + + public void setShortName(final String shortName) + { + this.shortName = shortName; + } +} diff --git a/src/main/java/nl/pim16aap2/armoredElytra/util/Messages.java b/src/main/java/nl/pim16aap2/armoredElytra/util/Messages.java index de05f30..df4188f 100644 --- a/src/main/java/nl/pim16aap2/armoredElytra/util/Messages.java +++ b/src/main/java/nl/pim16aap2/armoredElytra/util/Messages.java @@ -56,7 +56,7 @@ public class Messages while ((sCurrentLine = br.readLine()) != null) { // Ignore comments. - if (sCurrentLine.startsWith("#")) + if (sCurrentLine.startsWith("#") || sCurrentLine.isEmpty()) continue; String key, value; String[] parts = sCurrentLine.split("=", 2); diff --git a/src/main/java/nl/pim16aap2/armoredElytra/util/XMaterial.java b/src/main/java/nl/pim16aap2/armoredElytra/util/XMaterial.java index 42b25a4..09354c2 100644 --- a/src/main/java/nl/pim16aap2/armoredElytra/util/XMaterial.java +++ b/src/main/java/nl/pim16aap2/armoredElytra/util/XMaterial.java @@ -62,6 +62,7 @@ public enum XMaterial GOLDEN_CHESTPLATE(0, "GOLD_CHESTPLATE"), IRON_CHESTPLATE(0, ""), LEATHER_CHESTPLATE(0, ""), + PHANTOM_MEMBRANE(0, "1.13"), AIR(0, ""), ; diff --git a/src/main/resources/en_US.txt b/src/main/resources/en_US.txt index d616474..1761d36 100644 --- a/src/main/resources/en_US.txt +++ b/src/main/resources/en_US.txt @@ -4,15 +4,25 @@ # The format is "key=value" (without quotation marks). You can modify the values, but not the keys. # Order doesn't matter and you can use comments if you so desire. # Please do note that white space does matter! (so spaces at the end of lines, for example). +# The long names (without 'SHORT') are the names the elytras will have. TIER.Leather=&2Leather Armored Elytra TIER.Gold=&EGolden Armored Elytra TIER.Chain=&8Chain Armored Elytra TIER.Iron=&7Iron Armored Elytra TIER.Diamond=&BDiamond Armored Elytra -MESSAGES.Lore=Elytra with %ARMOR_TIER% level protection -MESSAGES.UsageDenied=You do not have the required permissions to wear %ARMOR_TIER%! -MESSAGES.ElytraReceived=&2A(n) %ARMOR_TIER% has been bestowed upon you! +TIER.SHORT.Leather=&2Leather +TIER.SHORT.Gold=&EGold +TIER.SHORT.Chain=&8Chain +TIER.SHORT.Iron=&7Iron +TIER.SHORT.Diamond=&BDiamond MESSAGES.UninstallMode=&cPlugin in uninstall mode! New Armored Elytras are not allowed! MESSAGES.UnsupportedTier=&cNot a supported armor tier! Try one of these: leather, gold, chain, iron, diamond. -MESSAGES.NoGivePermission=&cYou do not have the required permission node to give %ARMOR_TIER%s. -MESSAGES.RepairNeeded=&cYou cannot equip this elytra! Please repair it in an anvil first. \ No newline at end of file +MESSAGES.RepairNeeded=&cYou cannot equip this elytra! Please repair it in an anvil first. + +# The following messages support the following variables: +# - %ARMOR_TIER% (refers to TIER.X (e.g. TIER.Leather)) +# - %ARMOR_TIER_SHORT% (refers to TIER.SHORT.X (e.g. TIER.SHORT.Leather)). +MESSAGES.Lore=Elytra with %ARMOR_TIER_SHORT% level protection. +MESSAGES.NoGivePermission=&cYou do not have the required permission node to give a(n) %ARMOR_TIER%s. +MESSAGES.UsageDenied=You do not have the required permissions to wear a(n) %ARMOR_TIER%! +MESSAGES.ElytraReceived=&2A(n) %ARMOR_TIER% has been bestowed upon you! \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 389dc4d..7eaac6f 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -2,6 +2,7 @@ name: ArmoredElytra main: nl.pim16aap2.armoredElytra.ArmoredElytra version: ${project.version} author: pim16aap2 +api-version: 1.13 commands: ArmoredElytra: description: Give an armored elytra of the specified tier.