You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Minecraft Bukkit:如何检测自定义命令是否由告示牌触发?

问题:限制自定义命令仅通过告示牌点击触发

我想编写一个自定义Bukkit命令,只有同时满足以下两个条件时才触发玩家传送:

  • 玩家通过右键点击告示牌触发该命令
  • 满足预先设定的其他条件

目前我的CommandExecutor的onCommand函数代码如下:

public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
        if (!(sender instanceof Player)) {
            sender.sendMessage("ERROR: You must be a player to use this command.");
            return true;
        }
        if (sender.hasPermission(permission) && /* Other conditions */) { // permission是命令的传入参数
            ((Player) sender).teleport(new Location(world, destX, destY, destZ, destYw, destPt)); // 这些变量均由命令参数决定
            return true;
        }
        return true;
}

现在遇到的问题是:只要玩家拥有对应权限(比如LuckPerms的group.default),就能直接在聊天框输入/[自定义命令名称]执行传送,这不符合我的预期。

对比原版Minecraft的情况:使用以下指令生成的告示牌,无OP权限的玩家点击后可以执行tp @s 0 100 0完成传送,但直接在聊天框输入/tp命令会被系统禁止:

/give @s minecraft:oak_sign{BlockEntityTag:{front_text:{messages:['{"text":"","clickEvent":{"action":"run_command","value":"tp @s 0 100 0"}}','{"text":"MySign"}','{"text":"Select to teleport.","italic":true,"color":"white"}','{"text":""}']},is_waxed:1b}}

请问怎么在自定义Bukkit命令中实现这种效果?能不能检测玩家是否通过右键点击告示牌触发命令?或者有没有更简便的实现方式?


解决方案

方式一:通过事件监听检测命令触发来源(适合复杂自定义命令)

Bukkit/Spigot没有在onCommand方法中直接提供命令触发来源的判断,但可以通过监听事件来实现:

  1. 权限配置:给自定义命令设置一个高权限节点(比如mycommand.use),默认不给任何玩家(包括默认组)分配这个权限,这样玩家直接输入命令会因为缺权限被拦截。
  2. 监听事件临时授权:通过PlayerCommandPreprocessEvent检测玩家是否是通过点击告示牌触发命令,若是则临时授予权限,命令执行完后再移除:
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.permissions.PermissionAttachment;
import org.bukkit.plugin.Plugin;

import java.util.HashMap;
import java.util.UUID;

public class CommandSourceListener implements Listener {
    private final Plugin plugin;
    private final HashMap<UUID, PermissionAttachment> tempPerms = new HashMap<>();

    public CommandSourceListener(Plugin plugin) {
        this.plugin = plugin;
    }

    @EventHandler
    public void onCommandPreprocess(PlayerCommandPreprocessEvent event) {
        String cmd = event.getMessage().toLowerCase();
        // 替换成你的自定义命令,比如"/myteleport"
        if (cmd.startsWith("/myteleport")) {
            // 判断玩家最近右键的是否是告示牌
            if (event.getPlayer().getLastTwoTargetBlocks(null, 5).get(0).getType().name().contains("SIGN")) {
                // 临时授予权限
                PermissionAttachment attachment = event.getPlayer().addAttachment(plugin);
                attachment.setPermission("mycommand.use", true);
                tempPerms.put(event.getPlayer().getUniqueId(), attachment);

                // 延迟1tick移除权限,确保命令执行完成
                plugin.getServer().getScheduler().runTaskLater(plugin, () -> {
                    event.getPlayer().removeAttachment(attachment);
                    tempPerms.remove(event.getPlayer().getUniqueId());
                }, 1L);
            }
        }
    }
}
  1. 修改onCommand方法:只需要检查权限和你的预设条件即可,直接输入命令的玩家因为没权限会触发提示:
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
    if (!(sender instanceof Player)) {
        sender.sendMessage("ERROR: You must be a player to use this command.");
        return true;
    }
    Player player = (Player) sender;
    if (player.hasPermission("mycommand.use") && /* 你的其他预设条件 */) {
        player.teleport(new Location(world, destX, destY, destZ, destYaw, destPitch));
        return true;
    }
    player.sendMessage("只能通过点击指定告示牌使用该命令!");
    return true;
}

方式二:利用原版指令+权限系统(更简便,适合简单需求)

如果你的需求只是简单的传送,完全不用写自定义命令,直接在告示牌的clickEvent里用execute指令配合权限节点即可:

把告示牌的clickEvent的value设置为:

execute if entity @s[permission=myteleport.allow] run tp @s <目标X> <目标Y> <目标Z>

然后给需要使用的玩家组分配myteleport.allow权限,但不分配minecraft.command.tp和minecraft.command.execute权限。这样:

  • 玩家点击告示牌时,execute会检查权限,满足条件就执行传送;
  • 直接输入/tp或execute命令会因为缺少对应权限被系统拦截。

这种方式不需要编写自定义命令的代码,完全利用原版机制实现,轻量化且高效。


内容的提问来源于stack exchange,提问作者Laurita S.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 02:27:07