From cc32af4d0f4bed54f730cbd006141e057d2e1269 Mon Sep 17 00:00:00 2001 From: Geolykt Date: Sat, 17 Oct 2020 01:23:50 +0200 Subject: [PATCH] Optimised item durabillity deduction & Updated Javadoc Also added metadata within the magicCompat.yml file that is currently unused, but will be used in the future to warn the User from invalid versions of the magicCompat, as I got already some (private) bug reports about this issue and I suspect this may occour more often in the future. The optimisation itself has the side effect that the item damaging may be a bit more grainy and predictable, but the optimisation negates this issue At some point we will have all the methods documented, albeit this is likely to take a long while as there are a lot of methods, however documenting each of them is a good way to know which methods are unused or not which allows us to remove them in the next bigger release --- resources/magicCompat.yml | 3 + .../de/geolykt/enchantments_plus/Config.java | 6 +- .../compatibility/CompatibilityAdapter.java | 100 +++++++++++++++--- 3 files changed, 94 insertions(+), 15 deletions(-) diff --git a/resources/magicCompat.yml b/resources/magicCompat.yml index 656fe69..b0bcd54 100644 --- a/resources/magicCompat.yml +++ b/resources/magicCompat.yml @@ -4,6 +4,9 @@ # default configurations as of Version 2.1.0 of the Enchantments+ Plugin, meant for use for minecraft 1.16.3 +version: "0" # currently unused and meant for future use. Version 0 is the default as of v2.1.2 +target: "16" + grownCrops: # grown crops, used by the harvest enchantment - "WHEAT" diff --git a/src/main/java/de/geolykt/enchantments_plus/Config.java b/src/main/java/de/geolykt/enchantments_plus/Config.java index 43123e5..9dae9f9 100644 --- a/src/main/java/de/geolykt/enchantments_plus/Config.java +++ b/src/main/java/de/geolykt/enchantments_plus/Config.java @@ -30,15 +30,15 @@ // to automatically update the config files if they are old public class Config { - public static final Map CONFIGS = new HashMap<>(); // Map of all world configs on the current server - public static final Set allEnchants = new HashSet<>(72); // Set of all active Custom enchantments in form of instances. + public static final Map CONFIGS = new HashMap<>(3, 1); // Map of all world configs on the current server + public static final Set allEnchants = new HashSet<>(72, 1); // Set of all active Custom enchantments in form of instances. /** * This variable holds the classes of every registered enchantment in the plugin, please do not modify the variable, as it may have some * Unforeseen consequences. * @since 1.2.2 */ - public static final Set> REGISTERED_ENCHANTMENTS = new HashSet<>(72); + public static final Set> REGISTERED_ENCHANTMENTS = new HashSet<>(72, 1); private static final int CONFIG_BUFFER_SIZE = 16 * 1024; private final Set worldEnchants; // Set of active Custom Enchantments diff --git a/src/main/java/de/geolykt/enchantments_plus/compatibility/CompatibilityAdapter.java b/src/main/java/de/geolykt/enchantments_plus/compatibility/CompatibilityAdapter.java index 1d4234a..c80c74a 100644 --- a/src/main/java/de/geolykt/enchantments_plus/compatibility/CompatibilityAdapter.java +++ b/src/main/java/de/geolykt/enchantments_plus/compatibility/CompatibilityAdapter.java @@ -16,6 +16,7 @@ import org.bukkit.block.data.Ageable; import org.bukkit.block.data.BlockData; import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.*; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; @@ -317,9 +318,16 @@ public EnumMap spectralConversionMap() { return spectralMaterialConversion; } - // Removes the given ItemStack's durability by the given 'damage' and then sets the item direction the given - // players hand. - // This also takes into account the unbreaking enchantment + /** + * Damages the tool that is stored in a given index of a player's inventory with + * a given amount of damage (deducting the amount of unbreaking). + * If the durability of the result item is below 0, then the item will break. + * This has the side effect that items that do not have durability will break instantly. + * @param player The player that should be targeted + * @param damage The amount of damage that should be applied + * @param slotIndex The index of the item within the inventory + * @since 1.0 + */ public static void damageTool(Player player, int damage, boolean handUsed) { if (handUsed) { damageToolInSlot(player, damage, player.getInventory().getHeldItemSlot()); @@ -328,6 +336,16 @@ public static void damageTool(Player player, int damage, boolean handUsed) { } } + /** + * Damages the tool that is stored in a given index of a player's inventory with + * a given amount of damage (deducting the amount of unbreaking). + * If the durability of the result item is below 0, then the item will break. + * This has the side effect that items that do not have durability will break instantly. + * @param player The player that should be targeted + * @param damage The amount of damage that should be applied + * @param slotIndex The index of the item within the inventory + * @since 1.0 + */ public static void damageToolInSlot(Player player, int damage, int slotIndex) { ItemStack stack = damageItem(player.getInventory().getItem(slotIndex), damage); if (getDamage(stack) < 0) { @@ -337,14 +355,22 @@ public static void damageToolInSlot(Player player, int damage, int slotIndex) { } } - public static ItemStack damageItem(ItemStack stack, int damage) { + /** + * Damages a given itemstack with a given amount of damage (deducting the amount of unbreaking) and returns that itemstack. + * The item may have a durability below 0 afterwards. + * @param stack The stack that should be targeted + * @param damage The amount of damage that should be applied + * @return The new damaged item or Air if the input stack is null or air + * @since 1.0 + */ + public static @NotNull ItemStack damageItem(@Nullable ItemStack stack, int damage) { if (stack == null || stack.getType() == Material.AIR) return new ItemStack(Material.AIR); if (!stack.getItemMeta().isUnbreakable()) { - for (int i = 0; i < damage; i++) { - if (RND.nextInt(100) <= (100 / (stack.getEnchantmentLevel(org.bukkit.enchantments.Enchantment.DURABILITY) + 1))) { - setDamage(stack, getDamage(stack) + 1); - } + // chance that the item is broken is 1/(level+1) + // So at level = 2 it's 33%, at level = 0 it's 100%, at level 1 it's 50%, at level = 3 it's 25% + if (RND.nextInt(1000) <= (1000/(stack.getEnchantmentLevel(Enchantment.DURABILITY)+1))) { + setDamage(stack, getDamage(stack) + damage); } } return stack; @@ -357,8 +383,17 @@ public static void display(Location loc, Particle particle, int amount, double s (float) zO, (float) speed); } - // Removes the given ItemStack's durability by the given 'damage' - // This also takes into account the unbreaking enchantment + /** + * @deprecated Duplicate method. Use {@link #damageItem(ItemStack, int)} instead. + * Damages a given itemstack with a given amount of damage (deducting the amount of unbreaking). Also checks for the appropriate GameMode + * of the player.
+ * The item may have a durability below 0 afterwards, so caution is advised.
+ * This uses the old unoptimized method for strange backwards compatibility. + * @param player The player whose GameMode should be checked + * @param is The stack that should be targeted + * @param damage The amount of damage that should be applied + * @since 1.0 + */ public static void addUnbreaking(Player player, ItemStack is, int damage) { if (!player.getGameMode().equals(GameMode.CREATIVE)) { for (int i = 0; i < damage; i++) { @@ -369,6 +404,14 @@ public static void addUnbreaking(Player player, ItemStack is, int damage) { } } + /** + * Sets the amount of Damage that a given ItemStack has (which is the inverse of the remaining durability).
+ * Does not perform anything if the ItemMeta is not a {@link org.bukkit.inventory.meta.Damageable} instance.
+ * Does not check whether the itemstack has the unbreakable flag set, caution is advised. + * @param is The target itemstack + * @param damage The value that the damage should now have + * @since 1.0 + */ public static void setDamage(ItemStack is, int damage) { if (is.getItemMeta() instanceof org.bukkit.inventory.meta.Damageable) { org.bukkit.inventory.meta.Damageable dm = ((org.bukkit.inventory.meta.Damageable) is.getItemMeta()); @@ -377,6 +420,14 @@ public static void setDamage(ItemStack is, int damage) { } } + /** + * Sets the amount of Damage that a given ItemStack has (which is the inverse of the remaining durability).
+ * Does not perform anything if the ItemMeta is not a {@link org.bukkit.inventory.meta.Damageable} instance.
+ * Does not check whether the itemstack has the unbreakable flag set, caution is advised. + * @param is The target itemstack + * @param damage The value that the damage should now have + * @since 1.0 + */ public static int getDamage(ItemStack is) { if (is.getItemMeta() instanceof org.bukkit.inventory.meta.Damageable) { org.bukkit.inventory.meta.Damageable dm = ((org.bukkit.inventory.meta.Damageable) is.getItemMeta()); @@ -385,6 +436,13 @@ public static int getDamage(ItemStack is) { return 0; } + /** + * Calls the appropriate event, breaks the block naturally (particles are emitted) and damages the tool in hand. + * @param block The targeted block + * @param player The player that breaks the block. + * @return Whether the operation was performed successfully. + * @since 1.0 + */ public boolean breakBlockNMS(Block block, Player player) { BlockBreakEvent evt = new BlockBreakEvent(block, player); Bukkit.getPluginManager().callEvent(evt); @@ -400,7 +458,9 @@ public boolean breakBlockNMS(Block block, Player player) { * Places a block on the given player's behalf. Fires a BlockPlaceEvent with * (nearly) appropriate parameters to probe the legitimacy (permissions etc) * of the action and to communicate to other plugins where the block is - * coming from. + * coming from.
+ * The method always assumes that the block is placed against the lower block, + * unless it's not possible otherwise. * * @param blockPlaced the block to be changed * @param player the player whose identity to use @@ -408,6 +468,7 @@ public boolean breakBlockNMS(Block block, Player player) { * @param data the block data to set for the block, if allowed * * @return true if the block placement has been successful + * @since 1.0 */ public boolean placeBlock(Block blockPlaced, Player player, Material mat, BlockData data) { Block blockAgainst = blockPlaced.getRelative((blockPlaced.getY() == 0) ? BlockFace.UP : BlockFace.DOWN); @@ -427,14 +488,29 @@ public boolean placeBlock(Block blockPlaced, Player player, Material mat, BlockD return false; } + /** + * Places a block on the given player's behalf. Fires a BlockPlaceEvent with + * (nearly) appropriate parameters to probe the legitimacy (permissions etc) + * of the action and to communicate to other plugins where the block is + * coming from.
+ * The method always assumes that the block is placed against the lower block, + * unless it's not possible otherwise. + * + * @deprecated Probably doesn't even work. Unused internally + * @param blockPlaced the block to be changed + * @param player the player whose identity to use + * @param is The itemstack that is used to get which block data should be used and of which material the block should be. + * @return true if the block placement has been successful + * @since 1.0 + */ public boolean placeBlock(Block blockPlaced, Player player, ItemStack is) { return placeBlock(blockPlaced, player, is.getType(), (BlockData) is.getData()); } - /** * * @return True if damaged, false otherwise + * @since 1.0 */ public boolean attackEntity(LivingEntity target, Player attacker, double damage) { return attackEntity(target, attacker, damage, true);