1.8.8自定义Mending附魔插件无法生效问题求助
我首次开发插件,目标为1.8.8版本制作一个可通过/mending指令添加Mending附魔的插件。当前问题:使用/mending指令给钻石剑等物品附魔后,物品仅出现发光效果和NBT标签,但未实际应用自定义Mending附魔,获取XP时也无法修复耐久度。以下是插件的4个类代码:
主类(Mending2)
package me.marmosat.mending2; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerExpChangeEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.java.JavaPlugin; public class Mending2 extends JavaPlugin implements Listener { public static final CustomMendingEnchantment mendingEnchant = new CustomMendingEnchantment(240); @Override public void onLoad() { // Register the custom Mending enchantment CustomMendingEnchantment.registerEnchantment(this.getLogger()); } @Override public void onEnable() { // Register events getLogger().info("Mending2 plugin has been enabled!"); getServer().getPluginManager().registerEvents(this, this); // Register the /mending command getCommand("mending").setExecutor(new MendingCommandExecutor(getLogger())); } @Override public void onDisable() { // Plugin shutdown logic } @EventHandler public void onPlayerExpChange(PlayerExpChangeEvent event) { // Check if player has Mending enchanted items for (ItemStack item : event.getPlayer().getInventory().getContents()) { if (item != null && item.containsEnchantment(CustomMendingEnchantment.getCustomMendingEnchantment())) { // Calculate repair cost based on damage int repairCost = calculateRepairCost(item); // Deduct repair cost from player's experience if (event.getAmount() >= repairCost) { event.setAmount(event.getAmount() - repairCost); // Repair the item repairItem(item); } } } } private int calculateRepairCost(ItemStack item) { // Calculate repair cost based on damage int maxDurability = item.getType().getMaxDurability(); int durability = maxDurability - item.getDurability(); double repairCostPercentage = 0.2; // Example: 20% repair cost per durability point return (int) Math.ceil(durability * repairCostPercentage); } private void repairItem(ItemStack item) { // Repair the item by setting its durability to its maximum item.setDurability((short) 0); } }
CustomMendingEnchantment类
package me.marmosat.mending2; import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.EnchantmentTarget; import org.bukkit.inventory.ItemStack; import java.util.logging.Logger; import java.lang.reflect.Field; public class CustomMendingEnchantment extends Enchantment { private static boolean registered = false; private static Logger logger; private static CustomMendingEnchantment instance; // Constructor public CustomMendingEnchantment(int id) { super(id); } // Static method to register the custom enchantment public static void registerEnchantment(Logger pluginLogger) { logger = pluginLogger; instance = new CustomMendingEnchantment(240); try { Field acceptingNewField = Enchantment.class.getDeclaredField("acceptingNew"); acceptingNewField.setAccessible(true); acceptingNewField.set(null, true); // Allow registering new enchantments Enchantment.registerEnchantment(instance); logger.info("Custom Mending enchantment registered!"); registered = true; } catch (Exception e) { // Failed to register the enchantment logger.severe("Failed to register custom Mending enchantment!"); } } // Static method to get the custom enchantment instance public static CustomMendingEnchantment getCustomMendingEnchantment() { if (instance == null) { // If the enchantment is not registered, return null logger.warning("Custom Mending enchantment has not been registered!"); } return instance; } // Method to check if the enchantment is registered public static boolean isRegistered() { return registered; } // Implementing abstract method getName() from Enchantment @Override public String getName() { return "Mending"; // Set the name of the enchantment } // Implementing abstract method getMaxLevel() from Enchantment @Override public int getMaxLevel() { return 1; // Set the maximum level of the enchantment } // Implementing abstract method getStartLevel() from Enchantment @Override public int getStartLevel() { return 1; // Set the starting level of the enchantment } // Implementing abstract method getItemTarget() from Enchantment @Override public EnchantmentTarget getItemTarget() { return EnchantmentTarget.BREAKABLE; // Specify the item target for the enchantment } // Implementing abstract method isTreasure() from Enchantment @Override public boolean isTreasure() { return false; // Indicate whether the enchantment is considered a treasure enchantment } // Implementing abstract method isCursed() from Enchantment @Override public boolean isCursed() { return false; // Indicate whether the enchantment is considered a curse } // Implementing abstract method conflictsWith(Enchantment) from Enchantment @Override public boolean conflictsWith(Enchantment other) { // Indicate whether this enchantment conflicts with another enchantment return false; // Mending does not conflict with other enchantments } // Implementing abstract method canEnchantItem(ItemStack) from Enchantment @Override public boolean canEnchantItem(ItemStack item) { // Return true if the item can be enchanted with this enchantment return true; // Can enchant any item } // Implementing other Enchantment methods as needed }
MendingCommandExecutor类
package me.marmosat.mending2; import org.bukkit.Material; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import java.util.logging.Logger; public class MendingCommandExecutor implements CommandExecutor { private final Logger logger; // Constructor with Logger parameter public MendingCommandExecutor(Logger logger) { this.logger = logger; } @Override public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { // Check if the sender is a player if (!(sender instanceof Player)) { sender.sendMessage("This command can only be executed by players."); return false; } Player player = (Player) sender; // Check if the player has permission to use the command if (!player.isOp()) { sender.sendMessage("You do not have permission to use this command."); return false; } try { // Get the item the player is currently holding in the main hand ItemStack heldItem = player.getInventory().getItemInHand(); // Deprecated in newer versions, but still usable in 1.8.8 // Check if the held item is not air if (heldItem != null && heldItem.getType() != Material.AIR) { // Apply the Mending enchantment to the held item if (CustomMendingEnchantment.isRegistered()) { heldItem.addUnsafeEnchantment(CustomMendingEnchantment.getCustomMendingEnchantment(), 1); player.sendMessage("The item in your hand now has the Mending enchantment."); } else { player.sendMessage("An error occurred while executing the command."); logger.severe("Custom Mending enchantment is not registered."); } } else { player.sendMessage("You are not holding any item."); } return true; } catch (Exception e) { // Handle any exceptions sender.sendMessage("An error occurred while executing the command."); logger.severe("Error while executing /mending command: " + e.getMessage()); return false; } } }
MendingListener类
package me.marmosat.mending2; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerExpChangeEvent; import org.bukkit.inventory.ItemStack; public class MendingListener implements Listener { @EventHandler public void onPlayerExpChange(PlayerExpChangeEvent event) { // Check if player has Mending enchanted items for (ItemStack item : event.getPlayer().getInventory().getContents()) { if (item != null && item.containsEnchantment(CustomMendingEnchantment.getCustomMendingEnchantment())) { // Calculate repair cost based on damage int repairCost = calculateRepairCost(item); // Deduct repair cost from player's experience if (event.getAmount() >= repairCost) { event.setAmount(event.getAmount() - repairCost); // Repair the item repairItem(item); } } } } private int calculateRepairCost(ItemStack item) { // Calculate repair cost based on damage int maxDurability = item.getType().getMaxDurability(); int durability = maxDurability - item.getDurability(); double repairCostPercentage = 0.2; // Example: 20% repair cost per durability point return (int) Math.ceil(durability * repairCostPercentage); } private void repairItem(ItemStack item) { // Repair the item by setting its durability to its maximum item.setDurability((short) 0); } }
问题排查与修复方案
1. 附魔实例不一致
主类中定义了mendingEnchant静态实例,但CustomMendingEnchantment的注册方法又新建了instance实例,导致指令添加的附魔和监听器检查的附魔不是同一个对象,自然无法触发修复逻辑。
修复:删除主类中的public static final CustomMendingEnchantment mendingEnchant = new CustomMendingEnchantment(240);,全程使用CustomMendingEnchantment.getCustomMendingEnchantment()获取唯一实例。
2. 监听器冗余与冲突
主类已经实现Listener并注册了PlayerExpChangeEvent处理逻辑,同时存在重复的MendingListener类,两者逻辑完全一致,可能导致监听器触发异常。
修复:删除MendingListener类,或者在主类onEnable()中注册该监听器(二选一,推荐删除冗余类)。
3. 耐久计算与修复逻辑错误
calculateRepairCost方法中,int durability = maxDurability - item.getDurability();计算的是剩余耐久,而我们需要的是已损耗的耐久(需要修复的点数),1.8.8中item.getDurability()返回的就是已损耗值,正确计算应为:int damagedPoints = item.getDurability();repairItem直接将耐久设为0,不符合Mending逐步修复的逻辑,且会导致一次XP直接修满所有耐久,正确逻辑应为根据消耗的XP修复对应点数:private void repairItem(ItemStack item, int repairAmount) { // 确保修复后耐久不低于0 int newDurability = Math.max(0, item.getDurability() - repairAmount); item.setDurability((short) newDurability); }- XP消耗比例调整:参考原版Mending,1点XP修复2点耐久,对应修改
calculateRepairCost方法,比如1点耐久消耗0.5XP,向上取整。
4. 客户端同步问题
修改物品耐久后,需要通知客户端更新物品状态,否则客户端看不到耐久变化,在修复后添加:
event.getPlayer().updateInventory();
5. 附魔类优化
将CustomMendingEnchantment的构造函数改为private,避免外部随意创建实例,确保只有注册方法生成的唯一实例被使用:
private CustomMendingEnchantment(int id) { super(id); }
内容的提问来源于stack exchange,提问作者marmosat

