From 394be0ec3896fb71df83056043b3dc97f616e2ad Mon Sep 17 00:00:00 2001 From: Nathan Wolf Date: Tue, 22 Jun 2021 11:23:47 -0700 Subject: [PATCH] Re-work to use API only, no NMS Dropped custom skull support Only supports 1.16+ --- CHANGELOG.md | 5 +- .../mine/bukkit/heroes/HotbarController.java | 114 +++++---------- .../mine/bukkit/heroes/HotbarPlugin.java | 17 +-- .../mine/bukkit/heroes/HotbarUpdateTask.java | 36 +---- .../mine/bukkit/heroes/InventoryListener.java | 6 +- .../mine/bukkit/heroes/SkillDescription.java | 20 +-- .../mine/bukkit/heroes/SkillSelector.java | 9 +- .../heroes/utilities/CompatibilityUtils.java | 138 ++++++++++++++++++ 8 files changed, 204 insertions(+), 141 deletions(-) create mode 100644 src/main/java/com/elmakers/mine/bukkit/heroes/utilities/CompatibilityUtils.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 72b3284..2cd3f0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,10 @@ # 2.0 - - 1.16, 1.15, 1.14 1.13 compatibility + - 1.16 compatibility (only works with 1.16+ now) + - CustomModelData icon support + - Drop custom skull support + - Uses API only for forward-compatibility # 1.8 diff --git a/src/main/java/com/elmakers/mine/bukkit/heroes/HotbarController.java b/src/main/java/com/elmakers/mine/bukkit/heroes/HotbarController.java index 7ba8f41..0b1e812 100644 --- a/src/main/java/com/elmakers/mine/bukkit/heroes/HotbarController.java +++ b/src/main/java/com/elmakers/mine/bukkit/heroes/HotbarController.java @@ -1,32 +1,5 @@ package com.elmakers.mine.bukkit.heroes; -import com.elmakers.mine.bukkit.utility.CompatibilityUtils; -import com.elmakers.mine.bukkit.utility.InventoryUtils; -import com.elmakers.mine.bukkit.utility.NMSUtils; -import com.google.common.collect.Multimap; -import com.google.common.collect.Ordering; -import com.google.common.collect.TreeMultimap; -import com.herocraftonline.heroes.Heroes; -import com.herocraftonline.heroes.characters.CharacterManager; -import com.herocraftonline.heroes.characters.Hero; -import com.herocraftonline.heroes.characters.classes.HeroClass; -import com.herocraftonline.heroes.characters.skill.ActiveSkill; -import com.herocraftonline.heroes.characters.skill.OutsourcedSkill; -import com.herocraftonline.heroes.characters.skill.PassiveSkill; -import com.herocraftonline.heroes.characters.skill.Skill; -import com.herocraftonline.heroes.characters.skill.SkillConfigManager; -import com.herocraftonline.heroes.characters.skill.SkillManager; -import com.herocraftonline.heroes.characters.skill.SkillSetting; -import org.bukkit.ChatColor; -import org.bukkit.Material; -import org.bukkit.Server; -import org.bukkit.configuration.Configuration; -import org.bukkit.entity.HumanEntity; -import org.bukkit.entity.Player; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.ItemStack; -import org.bukkit.plugin.Plugin; - import java.net.MalformedURLException; import java.net.URL; import java.text.DecimalFormat; @@ -42,6 +15,32 @@ import java.util.UUID; import java.util.logging.Logger; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.Server; +import org.bukkit.configuration.Configuration; +import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.Plugin; + +import com.elmakers.mine.bukkit.heroes.utilities.CompatibilityUtils; +import com.google.common.collect.Multimap; +import com.google.common.collect.Ordering; +import com.google.common.collect.TreeMultimap; +import com.herocraftonline.heroes.Heroes; +import com.herocraftonline.heroes.characters.CharacterManager; +import com.herocraftonline.heroes.characters.Hero; +import com.herocraftonline.heroes.characters.classes.HeroClass; +import com.herocraftonline.heroes.characters.skill.ActiveSkill; +import com.herocraftonline.heroes.characters.skill.OutsourcedSkill; +import com.herocraftonline.heroes.characters.skill.PassiveSkill; +import com.herocraftonline.heroes.characters.skill.Skill; +import com.herocraftonline.heroes.characters.skill.SkillConfigManager; +import com.herocraftonline.heroes.characters.skill.SkillManager; +import com.herocraftonline.heroes.characters.skill.SkillSetting; + /** * This class manages the centralized hotbar functionality. */ @@ -59,7 +58,6 @@ public class HotbarController { private int skillInventoryRows; private MaterialAndData defaultSkillIcon; private String defaultDisabledIconURL; - private MaterialAndData skullMaterial; private Map selectors = new HashMap<>(); @@ -124,55 +122,34 @@ public String getSkillTitle(Player player, String skillName) { public ItemStack createSkillItem(SkillDescription skill, Player player) { ItemStack item = null; MaterialAndData icon = skill.getIcon(); - String iconURL = skill.getIconURL(); if (icon == null) { icon = defaultSkillIcon; } - boolean unavailable = !canUseSkill(player, skill.getName()); + boolean unavailable = !canUseSkill(player, skill.getKey()); if (unavailable) { MaterialAndData disabledIcon = skill.getDisabledIcon(); if (disabledIcon != null) { icon = disabledIcon; } - String disabledIconURL = skill.getDisabledIconURL(); - if (disabledIconURL != null && !disabledIconURL.isEmpty()) { - iconURL = disabledIconURL; - } - } - - if (iconURL != null && !iconURL.isEmpty()) { - try { - MaterialAndData skullMaterial = getSkullMaterial(); - if (skullMaterial == null) { - getLogger().warning("Unable to find a skull material to use for icons"); - } else { - item = new ItemStack(skullMaterial.getMaterial(), 1, skullMaterial.getData()); - InventoryUtils.setSkullURLAndName(item, new URL(iconURL), "MHF_Question", UUID.randomUUID()); - } - } catch (MalformedURLException e) { - getLogger().warning("Invalid URL: " + iconURL); - } - } else { - item = icon.createItemStack(); } - item = NMSUtils.makeReal(item); + item = icon.createItemStack(); if (item == null) { plugin.getLogger().warning("Unable to create item stack for skill: " + skill.getName()); return null; } // Set flags and NBT data - NMSUtils.setMeta(item, skillNBTKey, skill.getName()); - NMSUtils.makeUnbreakable(item); - InventoryUtils.hideFlags(item, (byte) 63); + CompatibilityUtils.setMeta(item, skillNBTKey, skill.getKey()); + CompatibilityUtils.makeUnbreakable(item); + CompatibilityUtils.hideFlags(item); boolean passive = skill.getSkill() instanceof PassiveSkill || skill.getSkill() instanceof OutsourcedSkill; if (unavailable) { - InventoryUtils.setMetaBoolean(item, "unavailable", true); + CompatibilityUtils.setMetaBoolean(item, "unavailable", true); } if (passive) { - InventoryUtils.setMetaBoolean(item, "passive", true); + CompatibilityUtils.setMetaBoolean(item, "passive", true); } // Set display name @@ -186,23 +163,6 @@ public ItemStack createSkillItem(SkillDescription skill, Player player) { return item; } - protected MaterialAndData getSkullMaterial() { - if (skullMaterial == null) { - try { - skullMaterial = new MaterialAndData(Material.SKULL_ITEM, (short)3); - getLogger().info("Using legacy skull item"); - } catch (Exception not14) { - try { - skullMaterial = new MaterialAndData(Material.valueOf("PLAYER_HEAD"), (short)0); - getLogger().info("Using modern skull item"); - } catch (Exception ex) { - - } - } - } - return skullMaterial; - } - protected Skill getSkill(String key) { if (skills == null) return null; return skills.getSkill(key); @@ -262,7 +222,7 @@ public void addSkillLore(SkillDescription skillDescription, List lore, P String description = skill.getDescription(hero); if (description != null && description.length() > 0) { description = getMessage("skills.description", "$description").replace("$description", description); - InventoryUtils.wrapText(description, MAX_LORE_LENGTH, lore); + CompatibilityUtils.wrapText(description, MAX_LORE_LENGTH, lore); } /* @@ -416,11 +376,11 @@ public void clearActiveSkillSelector(HumanEntity player) { } public boolean isSkill(ItemStack item) { - return InventoryUtils.hasMeta(item, skillNBTKey); + return CompatibilityUtils.hasMeta(item, skillNBTKey); } public boolean isLegacySkill(ItemStack item) { - return InventoryUtils.hasMeta(item, legacyNBTKey); + return CompatibilityUtils.hasMeta(item, legacyNBTKey); } public void useSkill(Player player, ItemStack item) { @@ -526,7 +486,7 @@ public boolean prepareSkill(Player player, ItemStack item) { } public String getSkillKey(ItemStack item) { - return InventoryUtils.getMetaString(item, skillNBTKey); + return CompatibilityUtils.getMetaString(item, skillNBTKey); } public Logger getLogger() { diff --git a/src/main/java/com/elmakers/mine/bukkit/heroes/HotbarPlugin.java b/src/main/java/com/elmakers/mine/bukkit/heroes/HotbarPlugin.java index bd48ba7..1abd8ae 100644 --- a/src/main/java/com/elmakers/mine/bukkit/heroes/HotbarPlugin.java +++ b/src/main/java/com/elmakers/mine/bukkit/heroes/HotbarPlugin.java @@ -1,13 +1,14 @@ package com.elmakers.mine.bukkit.heroes; -import com.elmakers.mine.bukkit.utility.NMSUtils; -import com.herocraftonline.heroes.Heroes; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.command.CommandExecutor; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.java.JavaPlugin; +import com.elmakers.mine.bukkit.heroes.utilities.CompatibilityUtils; +import com.herocraftonline.heroes.Heroes; + /** * This is the main Plugin class for the Heroes Hotbar plugin. */ @@ -35,16 +36,7 @@ public void onEnable() { getLogger().warning(ex.getMessage()); return; } - - if (NMSUtils.getFailed()) { - Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "[HeroesHotbar] Something went wrong with some Deep Magic, plugin will not load."); - Bukkit.getConsoleSender().sendMessage(ChatColor.DARK_RED + "[HeroesHotbar] Please make sure you are running a compatible version of " + ChatColor.RED + "Spigot (1.9 or Higher)!"); - } else { - if (NMSUtils.isLegacy()) { - Bukkit.getConsoleSender().sendMessage(ChatColor.YELLOW + "[HeroesHotbar] Using backwards-compatibility layer. It is highly recommended that you update to the latest Spigot version and/or the latest plugin version."); - } - initialize(); - } + initialize(); } @Override @@ -58,6 +50,7 @@ public void onDisable() { * Initialization, set up commands, listeners and controller */ protected void initialize() { + CompatibilityUtils.initialize(this); saveDefaultConfig(); // Set up controller diff --git a/src/main/java/com/elmakers/mine/bukkit/heroes/HotbarUpdateTask.java b/src/main/java/com/elmakers/mine/bukkit/heroes/HotbarUpdateTask.java index b0cbbf5..a56077a 100644 --- a/src/main/java/com/elmakers/mine/bukkit/heroes/HotbarUpdateTask.java +++ b/src/main/java/com/elmakers/mine/bukkit/heroes/HotbarUpdateTask.java @@ -1,16 +1,16 @@ package com.elmakers.mine.bukkit.heroes; -import com.elmakers.mine.bukkit.utility.InventoryUtils; +import java.util.logging.Level; + +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + import com.herocraftonline.heroes.characters.Hero; import com.herocraftonline.heroes.characters.skill.Skill; import com.herocraftonline.heroes.characters.skill.SkillConfigManager; import com.herocraftonline.heroes.characters.skill.SkillSetting; -import org.bukkit.Material; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; - -import java.util.logging.Level; +@SuppressWarnings("deprecation") public class HotbarUpdateTask implements Runnable { private final HotbarController controller; @@ -87,10 +87,7 @@ private void updateHotbar(Player player) { MaterialAndData disabledIcon = skillDescription.getDisabledIcon(); MaterialAndData spellIcon = skillDescription.getIcon(); - String urlIcon = skillDescription.getIconURL(); - String disabledUrlIcon = skillDescription.getDisabledIconURL(); - boolean usingURLIcon = urlIcon != null && !urlIcon.isEmpty(); - if (disabledIcon != null && spellIcon != null && !usingURLIcon) { + if (disabledIcon != null && spellIcon != null) { if (!canUse) { if (disabledIcon.getMaterial() != skillItem.getType() || disabledIcon.getData() != skillItem.getDurability()) { disabledIcon.applyToItem(skillItem); @@ -106,25 +103,6 @@ private void updateHotbar(Player player) { spellIcon.applyToItem(skillItem); } } - } else if (usingURLIcon && disabledUrlIcon != null && !disabledUrlIcon.isEmpty() && skillItem.getType() == Material.SKULL_ITEM) { - String currentURL = InventoryUtils.getSkullURL(skillItem); - if (!canUse) { - if (!disabledUrlIcon.equals(currentURL)) { - InventoryUtils.setSkullURL(skillItem, disabledUrlIcon); - player.getInventory().setItem(i, skillItem); - } - if (targetAmount == 99) { - if (skillItem.getAmount() != 1) { - skillItem.setAmount(1); - } - setAmount = true; - } - } else { - if (!urlIcon.equals(currentURL)) { - InventoryUtils.setSkullURL(skillItem, urlIcon); - player.getInventory().setItem(i, skillItem); - } - } } if (!setAmount && skillItem.getAmount() != targetAmount) { diff --git a/src/main/java/com/elmakers/mine/bukkit/heroes/InventoryListener.java b/src/main/java/com/elmakers/mine/bukkit/heroes/InventoryListener.java index e804fb3..888c806 100644 --- a/src/main/java/com/elmakers/mine/bukkit/heroes/InventoryListener.java +++ b/src/main/java/com/elmakers/mine/bukkit/heroes/InventoryListener.java @@ -1,6 +1,6 @@ package com.elmakers.mine.bukkit.heroes; -import com.elmakers.mine.bukkit.utility.InventoryUtils; +import com.elmakers.mine.bukkit.heroes.utilities.CompatibilityUtils; import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -24,12 +24,12 @@ public void onInventoryClick(InventoryClickEvent event) { ItemStack clickedItem = event.getCurrentItem(); HumanEntity player = event.getWhoClicked(); - if (InventoryUtils.getMetaBoolean(clickedItem, "unavailable", false)) { + if (CompatibilityUtils.getMetaBoolean(clickedItem, "unavailable", false)) { event.setCancelled(true); player.sendMessage(controller.getMessage("skills.unlearned").replace("$skill", controller.getSkillKey(clickedItem))); return; } - if (InventoryUtils.getMetaBoolean(clickedItem, "passive", false)) { + if (CompatibilityUtils.getMetaBoolean(clickedItem, "passive", false)) { event.setCancelled(true); return; } diff --git a/src/main/java/com/elmakers/mine/bukkit/heroes/SkillDescription.java b/src/main/java/com/elmakers/mine/bukkit/heroes/SkillDescription.java index 06ca871..9324b3f 100644 --- a/src/main/java/com/elmakers/mine/bukkit/heroes/SkillDescription.java +++ b/src/main/java/com/elmakers/mine/bukkit/heroes/SkillDescription.java @@ -12,22 +12,18 @@ public class SkillDescription implements Comparable { private final int skillLevel; private final MaterialAndData icon; private final MaterialAndData disabledIcon; - private final String iconURL; - private final String disabledIconURL; public SkillDescription(HotbarController controller, Player player, String skillKey) { this.skill = controller.getSkill(skillKey); this.skillKey = skillKey; this.skillLevel = controller.getSkillLevel(player, skillKey); - String iconURL = skill == null ? null : SkillConfigManager.getRaw(skill, "icon-url", SkillConfigManager.getRaw(skill, "icon_url", null)); String icon = skill == null ? null : SkillConfigManager.getRaw(skill, "icon", null); if (icon != null && icon.startsWith("http://")) { icon = null; - iconURL = icon; + controller.getLogger().warning("Skull icons are no longer supported"); } this.icon = icon == null || icon.isEmpty() ? null : new MaterialAndData(icon); - this.iconURL = iconURL; String iconDisabledURL = skill == null ? null : SkillConfigManager.getRaw(skill, "icon-disabled-url", SkillConfigManager.getRaw(skill, "icon_disabled_url", null)); String iconDisabled = skill == null ? null : SkillConfigManager.getRaw(skill, "icon-disabled", SkillConfigManager.getRaw(skill, "icon_disabled", null)); @@ -42,8 +38,6 @@ public SkillDescription(HotbarController controller, Player player, String skill iconDisabledURL = controller.getDefaultDisabledIconURL(); } - this.disabledIconURL = iconDisabledURL; - String skillDisplayName = skill == null ? null : SkillConfigManager.getRaw(skill, "name", skill.getName()); this.name = skillDisplayName == null || skillDisplayName.isEmpty() ? skillKey : skillDisplayName; this.description = skill == null ? null : SkillConfigManager.getRaw(skill, "description", ""); @@ -65,22 +59,18 @@ public MaterialAndData getIcon() { return icon; } - public String getIconURL() { - return iconURL; - } - public MaterialAndData getDisabledIcon() { return disabledIcon; } - public String getDisabledIconURL() { - return disabledIconURL; - } - public String getName() { return name; } + public String getKey() { + return skillKey; + } + public Skill getSkill() { return skill; } diff --git a/src/main/java/com/elmakers/mine/bukkit/heroes/SkillSelector.java b/src/main/java/com/elmakers/mine/bukkit/heroes/SkillSelector.java index 15191b2..9701eaa 100644 --- a/src/main/java/com/elmakers/mine/bukkit/heroes/SkillSelector.java +++ b/src/main/java/com/elmakers/mine/bukkit/heroes/SkillSelector.java @@ -1,6 +1,9 @@ package com.elmakers.mine.bukkit.heroes; -import com.elmakers.mine.bukkit.utility.CompatibilityUtils; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + import org.bukkit.entity.Player; import org.bukkit.event.inventory.ClickType; import org.bukkit.event.inventory.InventoryAction; @@ -8,9 +11,7 @@ import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import com.elmakers.mine.bukkit.heroes.utilities.CompatibilityUtils; public class SkillSelector { private final HotbarController controller; diff --git a/src/main/java/com/elmakers/mine/bukkit/heroes/utilities/CompatibilityUtils.java b/src/main/java/com/elmakers/mine/bukkit/heroes/utilities/CompatibilityUtils.java new file mode 100644 index 0000000..acb0332 --- /dev/null +++ b/src/main/java/com/elmakers/mine/bukkit/heroes/utilities/CompatibilityUtils.java @@ -0,0 +1,138 @@ +package com.elmakers.mine.bukkit.heroes.utilities; + +import java.util.Collection; +import java.util.List; + +import org.apache.commons.lang.StringUtils; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.NamespacedKey; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataType; +import org.bukkit.plugin.Plugin; + +public class CompatibilityUtils { + private static Plugin plugin; + + public static void initialize(Plugin owningPlugin) { + plugin = owningPlugin; + } + + public static Inventory createInventory(InventoryHolder holder, int size, final String name) { + size = (int) (Math.ceil((double) size / 9) * 9); + size = Math.min(size, 54); + String translatedName = translateColors(name); + return Bukkit.createInventory(holder, size, translatedName); + } + + public static String translateColors(String message) { + return ChatColor.translateAlternateColorCodes('&', message); + } + + public static void setDisplayName(ItemStack itemStack, String name) { + ItemMeta meta = itemStack.getItemMeta(); + meta.setDisplayName(name); + itemStack.setItemMeta(meta); + } + + public static void setLore(ItemStack itemStack, List lore) { + ItemMeta meta = itemStack.getItemMeta(); + meta.setLore(lore); + itemStack.setItemMeta(meta); + } + + private static NamespacedKey getKey(String key) { + return new NamespacedKey(plugin, key); + } + + public static boolean getMetaBoolean(ItemStack itemStack, String key) { + return getMetaBoolean(itemStack, key, false); + } + + public static boolean getMetaBoolean(ItemStack itemStack, String key, boolean defaultValue) { + if (itemStack == null) return false; + ItemMeta meta = itemStack.getItemMeta(); + if (meta == null) return false; + Byte data = meta.getPersistentDataContainer().get(getKey(key), PersistentDataType.BYTE); + if (data == null) { + return defaultValue; + } + return data != 0; + } + + public static void setMetaBoolean(ItemStack itemStack, String key, boolean value) { + if (itemStack == null) return; + ItemMeta meta = itemStack.getItemMeta(); + if (meta == null) return; + meta.getPersistentDataContainer().set(getKey(key), PersistentDataType.BYTE, (byte)(value ? 1 : 0)); + itemStack.setItemMeta(meta); + } + + public static void setMeta(ItemStack itemStack, String key, String value) { + if (itemStack == null) return; + ItemMeta meta = itemStack.getItemMeta(); + if (meta == null) return; + meta.getPersistentDataContainer().set(getKey(key), PersistentDataType.STRING, value); + itemStack.setItemMeta(meta); + } + + public static boolean hasMeta(ItemStack itemStack, String key) { + if (itemStack == null) return false; + ItemMeta meta = itemStack.getItemMeta(); + if (meta == null) return false; + return meta.getPersistentDataContainer().has(getKey(key), PersistentDataType.STRING); + } + + public static String getMetaString(ItemStack itemStack, String key) { + if (itemStack == null) return null; + ItemMeta meta = itemStack.getItemMeta(); + if (meta == null) return null; + return meta.getPersistentDataContainer().get(getKey(key), PersistentDataType.STRING); + } + + public static void makeUnbreakable(ItemStack itemStack) { + if (itemStack == null) return; + ItemMeta meta = itemStack.getItemMeta(); + if (meta == null) return; + meta.setUnbreakable(true); + itemStack.setItemMeta(meta); + } + + public static void hideFlags(ItemStack itemStack) { + if (itemStack == null) return; + ItemMeta meta = itemStack.getItemMeta(); + if (meta == null) return; + meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_UNBREAKABLE); + itemStack.setItemMeta(meta); + } + + public static void wrapText(String text, int maxLength, Collection list) { + wrapText(text, "", maxLength, list); + } + + public static void wrapText(String text, String prefix, int maxLength, Collection list) { + String colorPrefix = ""; + String[] lines = StringUtils.split(text, "\n\r"); + for (String line : lines) { + line = prefix + line; + while (line.length() > maxLength) + { + int spaceIndex = line.lastIndexOf(' ', maxLength); + if (spaceIndex <= 0) { + list.add(colorPrefix + line); + return; + } + String colorText = colorPrefix + line.substring(0, spaceIndex); + colorPrefix = ChatColor.getLastColors(colorText); + list.add(colorText); + line = line.substring(spaceIndex); + } + + list.add(colorPrefix + line); + } + } +}