From 2fd01200b0c2ca7122de07e8f33fce8324941c1f Mon Sep 17 00:00:00 2001 From: LotusRPG Date: Fri, 13 Feb 2026 18:06:33 +0100 Subject: [PATCH 1/2] Handle durability via Divinity stats while preserving vanilla bar - Vanilla durability bar is shown correctly - Divinity lore durability is used as main source - Mending event handled to sync values --- .../object/ItemDurabilityListener.java | 50 +++++++++++++++++++ .../attributes/stats/DurabilityStat.java | 29 ++++++++++- 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/src/main/java/studio/magemonkey/divinity/manager/listener/object/ItemDurabilityListener.java b/src/main/java/studio/magemonkey/divinity/manager/listener/object/ItemDurabilityListener.java index 42c3ee8d..40245cb9 100644 --- a/src/main/java/studio/magemonkey/divinity/manager/listener/object/ItemDurabilityListener.java +++ b/src/main/java/studio/magemonkey/divinity/manager/listener/object/ItemDurabilityListener.java @@ -1,5 +1,8 @@ package studio.magemonkey.divinity.manager.listener.object; +import org.bukkit.inventory.meta.Damageable; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.event.player.PlayerItemMendEvent; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.entity.LivingEntity; @@ -113,4 +116,51 @@ public void onDuraHoe(PlayerInteractEvent e) { } } } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onMend(PlayerItemMendEvent e) { + + ItemStack item = e.getItem(); + + if (!ItemStats.hasStat(item, null, TypedStat.Type.DURABILITY)) return; + + double[] durability = duraStat.getRaw(item); + if (durability == null) return; + + if (duraStat.isUnbreakable(item)) return; + + double current = durability[0]; + double max = durability[1]; + + int vanillaMax = item.getType().getMaxDurability(); + if (vanillaMax <= 0) return; + + int repair = e.getRepairAmount(); + + double customRepair = ((double) repair / vanillaMax) * max; + + double newValue = current + customRepair; + + if (newValue > max) { + newValue = max; + } + + newValue = Math.round(newValue * 100.0) / 100.0; + + duraStat.add(item, new double[]{newValue, max}, -1); + duraStat.syncVanillaBar(item, newValue, max); + + e.setCancelled(true); + + Damageable damageable = (Damageable) item.getItemMeta(); + + int vanillaDamage = damageable.getDamage(); + + if (vanillaDamage == 0) { + duraStat.add(item, new double[]{max, max}, -1); + duraStat.syncVanillaBar(item, max, max); + e.setCancelled(true); + return; + } + } } diff --git a/src/main/java/studio/magemonkey/divinity/stats/items/attributes/stats/DurabilityStat.java b/src/main/java/studio/magemonkey/divinity/stats/items/attributes/stats/DurabilityStat.java index 347a1e7c..ba7a33bf 100644 --- a/src/main/java/studio/magemonkey/divinity/stats/items/attributes/stats/DurabilityStat.java +++ b/src/main/java/studio/magemonkey/divinity/stats/items/attributes/stats/DurabilityStat.java @@ -1,5 +1,7 @@ package studio.magemonkey.divinity.stats.items.attributes.stats; + +import org.bukkit.inventory.meta.Damageable; import org.bukkit.NamespacedKey; import org.bukkit.Sound; import org.bukkit.enchantments.Enchantment; @@ -155,7 +157,14 @@ public boolean reduceDurability( } } - return this.add(item, new double[]{lose, max}, -1); + boolean result = this.add(item, new double[]{lose, max}, -1); + + if (result) { + syncVanillaBar(item, lose, max); + } + + return result; + } @Override @@ -163,4 +172,22 @@ public boolean reduceDurability( public String formatValue(@NotNull ItemStack item, double[] values) { return EngineCfg.getDurabilityFormat((int) values[0], (int) values[1]); } + public void syncVanillaBar(@NotNull ItemStack item, double current, double maxCustom) { + + ItemMeta meta = item.getItemMeta(); + if (!(meta instanceof org.bukkit.inventory.meta.Damageable)) return; + + org.bukkit.inventory.meta.Damageable damageable = + (org.bukkit.inventory.meta.Damageable) meta; + + int maxVanilla = item.getType().getMaxDurability(); + if (maxVanilla <= 0) return; + + double percent = current / maxCustom; + int vanillaDamage = (int) ((1.0 - percent) * maxVanilla); + + damageable.setDamage(vanillaDamage); + item.setItemMeta((ItemMeta) damageable); } + +} \ No newline at end of file From 890d889e74c11bbcd172dbbf26e4c5ccb28084ac Mon Sep 17 00:00:00 2001 From: Trav Date: Thu, 26 Mar 2026 21:39:22 -0600 Subject: [PATCH 2/2] Little bit of code cleanup --- .../object/ItemDurabilityListener.java | 38 +++++++-------- .../attributes/stats/DurabilityStat.java | 47 ++++++++++--------- 2 files changed, 41 insertions(+), 44 deletions(-) diff --git a/src/main/java/studio/magemonkey/divinity/manager/listener/object/ItemDurabilityListener.java b/src/main/java/studio/magemonkey/divinity/manager/listener/object/ItemDurabilityListener.java index 40245cb9..e9637e4d 100644 --- a/src/main/java/studio/magemonkey/divinity/manager/listener/object/ItemDurabilityListener.java +++ b/src/main/java/studio/magemonkey/divinity/manager/listener/object/ItemDurabilityListener.java @@ -1,8 +1,5 @@ package studio.magemonkey.divinity.manager.listener.object; -import org.bukkit.inventory.meta.Damageable; -import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.event.player.PlayerItemMendEvent; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.entity.LivingEntity; @@ -13,8 +10,10 @@ import org.bukkit.event.player.PlayerFishEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerItemDamageEvent; +import org.bukkit.event.player.PlayerItemMendEvent; import org.bukkit.inventory.EntityEquipment; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.Damageable; import org.jetbrains.annotations.NotNull; import studio.magemonkey.codex.manager.IListener; import studio.magemonkey.codex.util.ItemUT; @@ -119,28 +118,26 @@ public void onDuraHoe(PlayerInteractEvent e) { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onMend(PlayerItemMendEvent e) { - ItemStack item = e.getItem(); if (!ItemStats.hasStat(item, null, TypedStat.Type.DURABILITY)) return; double[] durability = duraStat.getRaw(item); - if (durability == null) return; - - if (duraStat.isUnbreakable(item)) return; + if (durability == null || duraStat.isUnbreakable(item)) return; - double current = durability[0]; - double max = durability[1]; + double current = durability[0]; + double max = durability[1]; + int vanillaMax = item.getType().getMaxDurability(); - int vanillaMax = item.getType().getMaxDurability(); if (vanillaMax <= 0) return; int repair = e.getRepairAmount(); - + // Scale the repair amount to the durability max, so we can + // properly update the custom durability amount. double customRepair = ((double) repair / vanillaMax) * max; + double newValue = current + customRepair; - double newValue = current + customRepair; - + // Cap the durability at the max if (newValue > max) { newValue = max; } @@ -153,14 +150,13 @@ public void onMend(PlayerItemMendEvent e) { e.setCancelled(true); Damageable damageable = (Damageable) item.getItemMeta(); - - int vanillaDamage = damageable.getDamage(); - - if (vanillaDamage == 0) { - duraStat.add(item, new double[]{max, max}, -1); - duraStat.syncVanillaBar(item, max, max); - e.setCancelled(true); - return; + if (damageable != null) { + int vanillaDamage = damageable.getDamage(); + if (vanillaDamage == 0) { + duraStat.add(item, new double[]{max, max}, -1); + duraStat.syncVanillaBar(item, max, max); + e.setCancelled(true); + } } } } diff --git a/src/main/java/studio/magemonkey/divinity/stats/items/attributes/stats/DurabilityStat.java b/src/main/java/studio/magemonkey/divinity/stats/items/attributes/stats/DurabilityStat.java index ba7a33bf..3093139b 100644 --- a/src/main/java/studio/magemonkey/divinity/stats/items/attributes/stats/DurabilityStat.java +++ b/src/main/java/studio/magemonkey/divinity/stats/items/attributes/stats/DurabilityStat.java @@ -1,13 +1,12 @@ package studio.magemonkey.divinity.stats.items.attributes.stats; - -import org.bukkit.inventory.meta.Damageable; import org.bukkit.NamespacedKey; import org.bukkit.Sound; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.Damageable; import org.bukkit.inventory.meta.ItemMeta; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -25,12 +24,8 @@ public class DurabilityStat extends ItemLoreStat implements TypedStat { private double cap; - public DurabilityStat( - @NotNull String name, - @NotNull String format, - double cap) { - super( - TypedStat.Type.DURABILITY.name(), + public DurabilityStat(@NotNull String name, @NotNull String format, double cap) { + super(TypedStat.Type.DURABILITY.name(), name, format, "%ITEM_STAT_" + TypedStat.Type.DURABILITY.name() + "%", @@ -116,9 +111,7 @@ public boolean isBroken(@NotNull ItemStack item) { return durability != null && durability[0] == 0 && !EngineCfg.ATTRIBUTES_DURABILITY_BREAK_ITEMS; } - public boolean reduceDurability( - @NotNull LivingEntity li, @NotNull ItemStack item, int amount) { - + public boolean reduceDurability(@NotNull LivingEntity li, @NotNull ItemStack item, int amount) { if (!(li instanceof Player) && !EngineCfg.ATTRIBUTES_DURABILITY_REDUCE_FOR_MOBS) return false; if (this.isUnbreakable(item)) return false; @@ -172,22 +165,30 @@ public boolean reduceDurability( public String formatValue(@NotNull ItemStack item, double[] values) { return EngineCfg.getDurabilityFormat((int) values[0], (int) values[1]); } - public void syncVanillaBar(@NotNull ItemStack item, double current, double maxCustom) { - ItemMeta meta = item.getItemMeta(); - if (!(meta instanceof org.bukkit.inventory.meta.Damageable)) return; + /** + * Syncs the durability stat with the vanilla durability bar. Should be called after any change to the durability stat. + * Note: This method assumes that the durability stat is already updated with the new values before calling it. + * + * @param item the item that needs updating + * @param current the current durability value on the item + * @param maxCustom the max value possible to be set for the item + */ + public void syncVanillaBar(@NotNull ItemStack item, double current, double maxCustom) { + ItemMeta meta = item.getItemMeta(); + if (!(meta instanceof Damageable)) return; - org.bukkit.inventory.meta.Damageable damageable = - (org.bukkit.inventory.meta.Damageable) meta; + Damageable damageable = (Damageable) meta; - int maxVanilla = item.getType().getMaxDurability(); - if (maxVanilla <= 0) return; + int maxVanilla = item.getType().getMaxDurability(); + if (maxVanilla <= 0) return; - double percent = current / maxCustom; - int vanillaDamage = (int) ((1.0 - percent) * maxVanilla); + double percent = current / maxCustom; + // Scale the vanilla value to the custom percentage + int vanillaDamage = (int) ((1.0 - percent) * maxVanilla); - damageable.setDamage(vanillaDamage); - item.setItemMeta((ItemMeta) damageable); -} + damageable.setDamage(vanillaDamage); + item.setItemMeta(damageable); + } } \ No newline at end of file