You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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

火山引擎 最新活动