Minecraft插件开发咨询:批量挖矿致权限提示消息刷屏的解决方案
解决Minecraft插件权限提示刷屏问题
我来帮你搞定这个烦人的刷屏问题!核心原因很简单:那个支持一次挖9个方块的插件会触发9次BlockBreakEvent,而你的代码每一次都会发送权限提示,自然就刷满屏了。下面是几个实用的优化方案,从快速解决到代码重构都有:
方案1:添加消息冷却机制(最直接有效)
思路是给每个玩家记录最后一次发送某类矿石权限提示的时间,在冷却时间内不再重复发送。我们可以用HashMap来存储玩家UUID和对应的冷却数据:
首先在你的插件类里定义全局的冷却存储和冷却时间:
import org.bukkit.entity.Player; import org.bukkit.Material; import org.bukkit.plugin.java.JavaPlugin; import java.util.HashMap; import java.util.Map; import java.util.UUID; public class YourPlugin extends JavaPlugin { // 存储玩家的矿石冷却记录:玩家UUID -> (矿石类型 -> 最后发送提示的时间) private final HashMap<UUID, Map<Material, Long>> cooldownMap = new HashMap<>(); // 冷却时间(毫秒),这里设为2秒,可根据需求调整 private static final long COOLDOWN_DURATION = 2000L; // 你的事件监听代码放在这里... }
然后修改你的事件处理逻辑,以煤炭矿石为例:
case COAL_ORE: if (!player.hasPermission("PluginName.coal") && !player.isOp()) { event.setCancelled(true); UUID playerUUID = player.getUniqueId(); // 获取该玩家的冷却记录,没有则创建新的Map Map<Material, Long> playerCooldowns = cooldownMap.computeIfAbsent(playerUUID, k -> new HashMap<>()); long currentTime = System.currentTimeMillis(); // 检查是否在冷却时间外 if (!playerCooldowns.containsKey(Material.COAL_ORE) || currentTime - playerCooldowns.get(Material.COAL_ORE) > COOLDOWN_DURATION) { player.sendMessage(ChatColor.DARK_RED + "You do not have permission to mine Coal Ore!"); // 更新该矿石的冷却时间 playerCooldowns.put(Material.COAL_ORE, currentTime); } } break;
如果你希望全局冷却(不管挖哪种无权限矿石,短时间内只发一次提示),可以把
Map<Material, Long>改成Long,只记录玩家最后发送任意提示的时间即可。
方案2:重构代码(简化逻辑+统一控制)
你的代码有大量重复的权限检查和消息发送逻辑,我们可以把这部分抽成一个工具方法,既简化代码,也方便统一修改冷却规则:
先定义工具方法:
/** * 检查玩家是否有挖掘指定矿石的权限,无权限时按需发送提示(带冷却) * @return 有权限返回true,无权限返回false */ private boolean hasOrePermission(Player player, Material oreType, String permissionNode, String noPermMessage) { // OP或有权限直接放行 if (player.isOp() || player.hasPermission(permissionNode)) { return true; } // 冷却检查逻辑 UUID playerUUID = player.getUniqueId(); Map<Material, Long> playerCooldowns = cooldownMap.computeIfAbsent(playerUUID, k -> new HashMap<>()); long currentTime = System.currentTimeMillis(); if (!playerCooldowns.containsKey(oreType) || currentTime - playerCooldowns.get(oreType) > COOLDOWN_DURATION) { player.sendMessage(ChatColor.DARK_RED + noPermMessage); playerCooldowns.put(oreType, currentTime); } return false; }
然后在switch里调用这个方法,代码瞬间简洁很多:
switch (type) { case COAL_ORE: if (!hasOrePermission(player, Material.COAL_ORE, "PluginName.coal", "You do not have permission to mine Coal Ore!")) { event.setCancelled(true); } break; case IRON_ORE: if (!hasOrePermission(player, Material.IRON_ORE, "PluginName.iron", "You do not have permission to mine Iron Ore!")) { event.setCancelled(true); } break; case GOLD_ORE: if (!hasOrePermission(player, Material.GOLD_ORE, "PluginName.gold", "You do not have permission to mine Gold Ore!")) { event.setCancelled(true); } break; case DIAMOND_ORE: if (!hasOrePermission(player, Material.DIAMOND_ORE, "PluginName.diamond", "You do not have permission to mine Diamond Ore!")) { event.setCancelled(true); } break; case EMERALD_ORE: if (!hasOrePermission(player, Material.EMERALD_ORE, "PluginName.emerald", "You do not have permission to mine Emerald Ore!")) { event.setCancelled(true); } break; }
额外优化:清理过期冷却数据
为了避免cooldownMap占用过多内存,可以定期清理超过冷却时间的记录。在插件启用时添加一个定时任务:
@Override public void onEnable() { // 其他初始化代码... // 每分钟清理一次过期冷却记录(1200 ticks = 60秒) getServer().getScheduler().scheduleSyncRepeatingTask(this, () -> { long currentTime = System.currentTimeMillis(); Iterator<Map.Entry<UUID, Map<Material, Long>>> playerIterator = cooldownMap.entrySet().iterator(); while (playerIterator.hasNext()) { Map.Entry<UUID, Map<Material, Long>> playerEntry = playerIterator.next(); Map<Material, Long> cooldowns = playerEntry.getValue(); Iterator<Map.Entry<Material, Long>> oreIterator = cooldowns.entrySet().iterator(); while (oreIterator.hasNext()) { Map.Entry<Material, Long> oreEntry = oreIterator.next(); // 移除超过冷却时间的记录 if (currentTime - oreEntry.getValue() > COOLDOWN_DURATION) { oreIterator.remove(); } } // 如果玩家的冷却记录为空,移除该玩家的条目 if (cooldowns.isEmpty()) { playerIterator.remove(); } } }, 0L, 1200L); }
这些方案都能完美解决范围挖矿插件导致的刷屏问题,同时保留了权限提示的作用,代码也更易于维护。
内容的提问来源于stack exchange,提问作者Brian Adams




