From 1b952ea4d4571e11030891a804b340c8f3bdc571 Mon Sep 17 00:00:00 2001 From: Adrien Prokopowicz Date: Sun, 11 Apr 2021 20:34:58 +0200 Subject: [PATCH] Remove reflection-based DualWielding implementation, and update related utilities (#70) * Remove reflection-based DualWielding implementation, and update related utilities * Fix checkstyle * Bring back break sound * Updated CHANGELOG. Co-authored-by: Amaury Carrade --- CHANGELOG.md | 25 +++ .../quartzlib/tools/items/DualWielding.java | 156 ------------------ .../quartzlib/tools/items/InventoryUtils.java | 74 +++++++++ .../quartzlib/tools/items/ItemUtils.java | 77 +++++---- 4 files changed, 137 insertions(+), 195 deletions(-) delete mode 100644 src/main/java/fr/zcraft/quartzlib/tools/items/DualWielding.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ef4c3fb..a32a27d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,11 +13,36 @@ _Published one day_ ### Changed #### `CraftingRecipes` + - :warning: All recipes are now required to provide names, therefore all helper methods to generate recipes take a mandatory name argument. The name is automatically namespaced with the plugin's name. - :warning: All helpers that were consuming the now-deprecated `MaterialData` now consume the more flexible `RecipeChoice` instead. - All helpers that generate shaped recipes (2x2, 2x2 diagonal, etc.) now return `ShapedRecipe`s explicitely, since there is no way those recipes can be anything other than shaped, and hiding this detail is not useful at all. + +#### Glow effect + +This tool was rewritten to register a namespaced enchantment, avoiding future incompatibilities with other plugins +registering new enchants. + +- :warning: The glow effect is now a QuartzLib component. You still use glow effect as usual (either using `GlowEffect` + or through the `ItemStackBuilder`), but you have to load the effect using `loadComponents(GlowEffect.class)` in your + plugin's `onEnable`. + +#### `DualWielding` + +This API was added when Bukkit had no support for dual wielding. As there is support now, we cleaned up all of this +and removed some things. We kept some useful methods and moved things to other classes for coherence. + +- Added `ItemUtils.consumeItemInOffHand`. +- :warning: Moved `ItemUtils.consumeItem` to `ItemUtils.consumeItemInMainHand`. +- :warning: Moved `ItemUtils.damageItemInHand` to `ItemUtils.damageItem`. +- `ItemUtils.damageItem` now returns `true` if the damaged item was broken. +- :warning: Moved `ItemUtils.breakItemInHand` methods to `InventoryUtils.breakItemInHand`. +- :warning: Moved `DualWielding` to `InventoryUtils.DualWielding`. +- :warning: Moved `DualWieldling` methods to `InventoryUtils`. +- :warning: Removed `DualWieldling.setItemInHand` and `DualWieldling.getItemInHand` (use Bukkit API instead). + #### `GlowEffect` - :warning: This class is not an enchantment anymore and has been re-implemented. It is now a `QuartzComponent` that diff --git a/src/main/java/fr/zcraft/quartzlib/tools/items/DualWielding.java b/src/main/java/fr/zcraft/quartzlib/tools/items/DualWielding.java deleted file mode 100644 index 46d0fc61..00000000 --- a/src/main/java/fr/zcraft/quartzlib/tools/items/DualWielding.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright or © or Copr. QuartzLib contributors (2015 - 2020) - * - * This software is governed by the CeCILL-B license under French law and - * abiding by the rules of distribution of free software. You can use, - * modify and/ or redistribute the software under the terms of the CeCILL-B - * license as circulated by CEA, CNRS and INRIA at the following URL - * "http://www.cecill.info". - * - * As a counterpart to the access to the source code and rights to copy, - * modify and redistribute granted by the license, users are provided only - * with a limited warranty and the software's author, the holder of the - * economic rights, and the successive licensors have only limited - * liability. - * - * In this respect, the user's attention is drawn to the risks associated - * with loading, using, modifying and/or developing or reproducing the - * software by the user in light of its specific status of free software, - * that may mean that it is complicated to manipulate, and that also - * therefore means that it is reserved for developers and experienced - * professionals having in-depth computer knowledge. Users are therefore - * encouraged to load and test the software's suitability as regards their - * requirements in conditions enabling the security of their systems and/or - * data to be ensured and, more generally, to use and operate it in the - * same conditions as regards security. - * - * The fact that you are presently reading this means that you have had - * knowledge of the CeCILL-B license and that you accept its terms. - */ - -package fr.zcraft.quartzlib.tools.items; - -import fr.zcraft.quartzlib.tools.reflection.Reflection; -import java.lang.reflect.InvocationTargetException; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.PlayerInventory; - -/** - * This class provides various utilities for handling dual-wielding. - */ -public enum DualWielding { - /** - * Represents the main hand of the player. - */ - MAIN_HAND, - /** - * Represents the off hand of the player. - */ - OFF_HAND; - - private static Boolean available = null; - - // Dual-wielding isn't available in all builds of Bukkit/Spigot - private static void init() { - available = Reflection.hasMethod(PlayerInventory.class, "getItemInMainHand") - && Reflection.hasMethod(PlayerInventory.class, "getItemInOffHand") - && Reflection.hasMethod(PlayerInventory.class, "setItemInMainHand", ItemStack.class) - && Reflection.hasMethod(PlayerInventory.class, "setItemInOffHand", ItemStack.class); - } - - private static boolean checkAvailable() { - if (available == null) { - init(); - } - return available; - } - - /** - * Retrieves the item in the given player's hand. - * If dual-wielding is not available, it is retrieved from the players' only hand. - * - * @param player The player to get the item from - * @param hand The hand - * @return The retrieved item. - */ - public static ItemStack getItemInHand(Player player, DualWielding hand) { - try { - if (!checkAvailable()) { - return player.getItemInHand(); - } - - switch (hand) { - case MAIN_HAND: - return (ItemStack) Reflection.call(player.getInventory(), "getItemInMainHand"); - case OFF_HAND: - return (ItemStack) Reflection.call(player.getInventory(), "getItemInOffHand"); - default: - return player.getItemInHand(); - } - } catch (NoSuchMethodException | IllegalAccessException - | IllegalArgumentException | InvocationTargetException ex) { - return player.getItemInHand(); - } - } - - /** - * Sets the item in the given player's hand. - * If dual-wielding is not available, it is put in the players' only hand. - * - * @param player The player - * @param hand The player's hand - * @param item The item to put in the specified hand. - */ - public static void setItemInHand(Player player, DualWielding hand, ItemStack item) { - if (hand == null) { - return; - } - - if (!checkAvailable()) { - player.setItemInHand(item); - return; - } - - try { - switch (hand) { - case MAIN_HAND: - Reflection.call(player.getInventory(), "setItemInMainHand", item); - break; - case OFF_HAND: - Reflection.call(player.getInventory(), "setItemInOffHand", item); - break; - default: - player.setItemInHand(item); - } - } catch (NoSuchMethodException | IllegalAccessException - | IllegalArgumentException | InvocationTargetException ex) { - player.setItemInHand(item); - } - } - - /** - * Returns which player's hand is holding the specific item. - * If dual-wielding is not available, the item is tested against the - * player's only hand. - * - * @param player The player - * @param item The item - * @return The hand holding the given item, or null if neither of them is holding it. - */ - public static DualWielding getHoldingHand(Player player, ItemStack item) { - if (!checkAvailable()) { - return player.getItemInHand().equals(item) ? MAIN_HAND : null; - } - - if (getItemInHand(player, OFF_HAND).equals(item)) { - return OFF_HAND; - } - - if (getItemInHand(player, MAIN_HAND).equals(item)) { - return MAIN_HAND; - } - - return null; - } -} diff --git a/src/main/java/fr/zcraft/quartzlib/tools/items/InventoryUtils.java b/src/main/java/fr/zcraft/quartzlib/tools/items/InventoryUtils.java index 3c25f48c..7f69df06 100644 --- a/src/main/java/fr/zcraft/quartzlib/tools/items/InventoryUtils.java +++ b/src/main/java/fr/zcraft/quartzlib/tools/items/InventoryUtils.java @@ -33,10 +33,14 @@ import fr.zcraft.quartzlib.tools.reflection.Reflection; import fr.zcraft.quartzlib.tools.runners.RunTask; import java.lang.reflect.InvocationTargetException; +import org.bukkit.Material; +import org.bukkit.Sound; import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * This class provides various utilities for inventory management. @@ -118,4 +122,74 @@ public static void updateInventoryLater(final Inventory inventory) { }); } + /** + * Returns which player's hand is holding the specific item. + * If dual-wielding is not available, the item is tested against the + * player's only hand. + * + * @param player The player + * @param item The item + * @return The hand holding the given item, or null if neither of them is holding it. + */ + public static @Nullable DualWielding getHoldingHand(@NotNull Player player, @NotNull ItemStack item) { + if (player.getInventory().getItemInOffHand().equals(item)) { + return DualWielding.OFF_HAND; + } + + if (player.getInventory().getItemInMainHand().equals(item)) { + return DualWielding.MAIN_HAND; + } + + return null; + } + + /** + * Breaks the item currently in the hand of the player. + * + * @param player The player. + * @param hand The hand to retrieve the item from. This will always be the main hand if + * the Bukkit build don't support dual-wielding. + */ + public static void breakItemInHand(Player player, @NotNull InventoryUtils.DualWielding hand) { + final ItemStack item = new ItemStack(Material.AIR); + + switch (hand) { + case MAIN_HAND: + player.getInventory().setItemInMainHand(item); + break; + case OFF_HAND: + player.getInventory().setItemInOffHand(item); + break; + default: break; + } + + player.playSound(player.getLocation(), Sound.ENTITY_ITEM_BREAK, 0.8f, 1); + } + + /** + * Breaks the given item if it is found in one of the player's hands. + * + * @param player The player. + * @param item The item to break. + */ + public static void breakItemInHand(Player player, ItemStack item) { + DualWielding hand = getHoldingHand(player, item); + if (hand != null) { + breakItemInHand(player, hand); + } + } + + /** + * This class provides various utilities for handling dual-wielding. + */ + public enum DualWielding { + /** + * Represents the main hand of the player. + */ + MAIN_HAND, + /** + * Represents the off hand of the player. + */ + OFF_HAND; + } } diff --git a/src/main/java/fr/zcraft/quartzlib/tools/items/ItemUtils.java b/src/main/java/fr/zcraft/quartzlib/tools/items/ItemUtils.java index 02ffb2e0..de994007 100644 --- a/src/main/java/fr/zcraft/quartzlib/tools/items/ItemUtils.java +++ b/src/main/java/fr/zcraft/quartzlib/tools/items/ItemUtils.java @@ -47,6 +47,7 @@ import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.Damageable; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.potion.Potion; @@ -67,16 +68,30 @@ private ItemUtils() { } /** - * Simulates the player consuming the itemstack in its hand, depending on - * his game mode. This decreases the ItemStack's size by one, and replaces + * Simulates the player consuming the ItemStack in their main hand, depending on + * their game mode. This decreases the ItemStack's size by one, and replaces * it with air if nothing is left. * * @param player The player that will consume the stack. - * @return The updated stack. + * @return The updated ItemStack. */ - public static ItemStack consumeItem(Player player) { - ItemStack newStack = consumeItem(player, player.getItemInHand()); - player.setItemInHand(newStack); + public static ItemStack consumeItemInMainHand(Player player) { + ItemStack newStack = consumeItem(player, player.getInventory().getItemInMainHand()); + player.getInventory().setItemInMainHand(newStack); + return newStack; + } + + /** + * Simulates the player consuming the ItemStack in their main hand, depending on + * their game mode. This decreases the ItemStack's size by one, and replaces + * it with air if nothing is left. + * + * @param player The player that will consume the stack. + * @return The updated ItemStack. + */ + public static ItemStack consumeItemInOffHand(Player player) { + ItemStack newStack = consumeItem(player, player.getInventory().getItemInOffHand()); + player.getInventory().setItemInOffHand(newStack); return newStack; } @@ -182,48 +197,32 @@ public static boolean hasDisplayName(ItemStack stack, String displayName) { * @param player The player that is using the item. * @param item The item in the player's hand. * @param factor The amount of damage taken. + * @return `true` if the damaged item was broken, `false` otherwise. */ - public static void damageItemInHand(Player player, ItemStack item, int factor) { - if (player == null) { - throw new IllegalArgumentException("Player can't be null."); - } + public static boolean damageItem(@NotNull Player player, @NotNull ItemStack item, int factor) { if (player.getGameMode() == GameMode.CREATIVE) { - return; + return false; } - short newDurability = item.getDurability(); + ItemMeta meta = item.getItemMeta(); + + if (!(meta instanceof Damageable)) { + return false; + } + + int newDurability = ((Damageable) meta).getDamage(); newDurability += newDurability(item.getEnchantmentLevel(Enchantment.DURABILITY)) * factor; if (newDurability >= item.getType().getMaxDurability()) { - breakItemInHand(player, item); + InventoryUtils.breakItemInHand(player, item); + player.updateInventory(); + return true; } else { - item.setDurability(newDurability); - //player.getInventory().setItemInHand(item); + ((Damageable) meta).setDamage(newDurability); + item.setItemMeta(meta); + player.updateInventory(); + return false; } - - player.updateInventory(); - } - - /** - * Breaks the item currently in the hand of the player. - * - * @param player The player. - * @param hand The hand to retrieve the item from. This will always be the main hand if - * the Bukkit build don't support dual-wielding. - */ - public static void breakItemInHand(Player player, DualWielding hand) { - DualWielding.setItemInHand(player, hand, new ItemStack(Material.AIR)); - //player.playSound(player.getLocation(), Sound.ITEM_BREAK, 0.8f, 1); - } - - /** - * Breaks the given item if it is found in one of the player's hands. - * - * @param player The player. - * @param item The item to break. - */ - public static void breakItemInHand(Player player, ItemStack item) { - breakItemInHand(player, DualWielding.getHoldingHand(player, item)); } /**