Minecraft Bukkit插件InventoryClickEvent失效问题求助
我仔细看了你的代码,发现几个导致GUI点击没反应的关键问题,咱们一步步来修复:
核心问题:事件监听器未正确注册
你的CommandRtp类里写了@EventHandler注解的onClick方法,但这个类没有实现Listener接口,再加上主类里的事件注册代码有错误,导致Bukkit根本没把这个方法当成事件监听器来处理。
修复步骤:
1. 让CommandRtp类实现Listener接口
修改CommandRtp的类定义,加上implements Listener——这是Bukkit识别事件监听器的必要条件:
public class CommandRtp implements CommandExecutor, Listener {
2. 修正主类Main中的事件注册代码
你的主类里有一行完全错误的注册代码:
Bukkit.getPluginManager().registerEvents((Listener) this, Bukkit.getPluginManager().getPlugins()[0]);
这行不仅没必要,还会抛出ClassCastException(因为Main类没实现Listener),直接删掉就行。
保留正确的注册代码,而且现在不需要强制类型转换了(因为CommandRtp已经实现了Listener):
Bukkit.getPluginManager().registerEvents(new CommandRtp(), this);
这里第二个参数this是对的,它代表你的插件实例(Main是JavaPlugin子类)。
3. 优化InventoryClickEvent的判断逻辑
为了避免误触发(比如玩家点击自己的背包也会触发这个事件),建议加上额外判断,确保点击的是咱们创建的GUI:
@EventHandler public void onClick(InventoryClickEvent event) { // 先判断点击者是不是玩家 if (!(event.getWhoClicked() instanceof Player)) return; Player player = (Player) event.getWhoClicked(); ItemStack current = event.getCurrentItem(); // 过滤空物品、点击的不是GUI的情况 if (current == null || event.getClickedInventory() == null || !event.getClickedInventory().equals(event.getInventory())) return; // 确认是咱们的GUI if (event.getInventory().getTitle().equals("Menu de tp aléatoire")) { event.setCancelled(true); // 取消默认行为,防止物品被移动 if (current.getType() == Material.GOLD_BLOCK) { player.closeInventory(); player.performCommand("rtpPlayer"); // 用performCommand比chat更规范,不会在聊天框发消息 } if (current.getType() == Material.DIAMOND_BLOCK) { player.closeInventory(); player.setFlying(true); } } }
另外,执行命令的时候用player.performCommand("rtpPlayer")比player.chat("/rtpPlayer")更合适,前者是直接执行命令,不会在聊天框显示内容,更符合插件的逻辑。
4. 检查控制台错误
启动服务器时看看控制台,如果有ClassCastException或者IllegalArgumentException之类的错误,说明还有遗漏的问题。确保所有导入的类都是正确的,比如Listener是org.bukkit.event.Listener。
完整修正后的代码片段
CommandRtp类:
package can.evilestvirus.randomtp; import java.util.Arrays; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; public class CommandRtp implements CommandExecutor, Listener { @Override public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) { if (sender instanceof Player) { Player player = (Player) sender; Inventory inv = Bukkit.createInventory(null, 9, "Menu de tp aléatoire"); ItemStack goldBlock = new ItemStack(Material.GOLD_BLOCK, 1); ItemMeta goldBlockM = goldBlock.getItemMeta(); goldBlockM.setDisplayName("§8[§a+§8] §aRandomTP Normal §8[§a+§8]"); goldBlockM.setLore(Arrays.asList("§b- §6Distance de TP: 2500 Blocks", "§b- §6Prix: $0", "§b- §6Cooldown de 60 secondes", "§a§lCliquez ici pour utiliser")); goldBlockM.addEnchant(Enchantment.DURABILITY, 10, true); goldBlockM.addItemFlags(ItemFlag.HIDE_ENCHANTS); goldBlock.setItemMeta(goldBlockM); inv.setItem(3, goldBlock); ItemStack diamondBlock = new ItemStack(Material.DIAMOND_BLOCK, 1); ItemMeta diamondBlockM = diamondBlock.getItemMeta(); diamondBlockM.setDisplayName("§8[§a+§8] §aRandomTP §6§lVIP §8[§a+§8]"); diamondBlockM.setLore(Arrays.asList("§b- §6Distance de TP: 5000 Blocks", "§b- §6Prix: $1000", "§b- §6Cooldown de 5 minutes", "§a§lCliquez ici pour utiliser")); diamondBlockM.addEnchant(Enchantment.DURABILITY, 10, true); diamondBlockM.addItemFlags(ItemFlag.HIDE_ENCHANTS); diamondBlock.setItemMeta(diamondBlockM); inv.setItem(5, diamondBlock); player.openInventory(inv); } return true; } @EventHandler public void onClick(InventoryClickEvent event) { if (!(event.getWhoClicked() instanceof Player)) return; Player player = (Player) event.getWhoClicked(); ItemStack current = event.getCurrentItem(); if (current == null || event.getClickedInventory() == null || !event.getClickedInventory().equals(event.getInventory())) return; if (event.getInventory().getTitle().equals("Menu de tp aléatoire")) { event.setCancelled(true); if (current.getType() == Material.GOLD_BLOCK) { player.closeInventory(); player.performCommand("rtpPlayer"); } if (current.getType() == Material.DIAMOND_BLOCK) { player.closeInventory(); player.setFlying(true); } } } }
Main类:
package can.evilestvirus.randomtp; import org.bukkit.plugin.java.JavaPlugin; import can.evilestvirus.randomtp.CommandRtpPlayer; public class Main extends JavaPlugin { @Override public void onEnable() { System.out.println("HELLO PEOPLE!"); this.getCommand("rtpplayer").setExecutor(new CommandRtpPlayer()); this.getCommand("rtp").setExecutor(new CommandRtp()); // 正确注册CommandRtp作为事件监听器 getServer().getPluginManager().registerEvents(new CommandRtp(), this); } }
额外提示
- 确保你的
plugin.yml文件里正确声明了rtp和rtpplayer这两个命令,否则命令会无法被Bukkit识别。 - 如果你的
CommandRtpPlayer类也需要处理事件,记得也要让它实现Listener接口并在主类里注册。
内容的提问来源于stack exchange,提问作者nat.laliberte

