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

Velocity向Spigot发插件消息时onPluginMessageReceived无响应排查

Velocity向Spigot发送插件消息无响应排查与解决

我正在为Minecraft服务器集群开发Velocity插件,实现/screenshare <玩家>命令,将员工玩家和嫌疑玩家转移到录屏服务器。为了让仅部署在录屏服务器的Spigot插件区分两者角色,使用了Plugin Messaging Channel。目前Spigot向Velocity发消息能正常接收,但Velocity发消息给Spigot时,Spigot端的onPluginMessageReceived完全没反应。

已知Velocity仅在有在线玩家时才会发送消息,已经设置了2秒延迟执行代码,没用。Velocity日志显示消息发送成功,但Spigot端无任何日志输出。试过用Bungee频道替代自定义频道、延长延迟时间,都没解决。

Spigot端代码

@Override
public void onEnable() {
    getServer().getMessenger().registerOutgoingPluginChannel(this, "test:screenshare");
    getServer().getMessenger().registerIncomingPluginChannel(this, "test:screenshare", this);

    // 注册PlayerJoin事件
    getServer().getPluginManager().registerEvents(this, this);
}

@Override
public void onPluginMessageReceived(String channel, Player player, byte[] message) {
    if (!(channel.equals("test:screenshare"))) {
        getLogger().info("Wrong channel: " + channel);
        return;
    }

    new BukkitRunnable() {
        @Override
        public void run() {
            ByteArrayDataInput in = ByteStreams.newDataInput(message);
            String subchannel = in.readUTF();

            if (subchannel.equals("RoleUpdate")) {
                String stafferRole = in.readUTF();
                String stafferName = in.readUTF();
                String suspectRole = in.readUTF();
                String suspectName = in.readUTF();

                getLogger().info("Received roles: " + stafferRole + " for " + stafferName + " and " + suspectRole + " for " + suspectName);
            } else {
                getLogger().info("Subchannel not found: " + subchannel);
            }
        }
    }.runTaskLater(this, 40L);
}

Velocity端代码

频道定义:

public static final MinecraftChannelIdentifier IDENTIFIER = MinecraftChannelIdentifier.from("test:screenshare");

调用触发:执行Velocity端/ss命令时调用sendPluginMessage(staffer.getUsername(), suspect.getUsername(), "Staffer", "Suspect");

消息发送方法:

private void sendPluginMessage(String stafferName, String suspectName, String stafferRole, String suspectRole) {
        ByteArrayDataOutput out = ByteStreams.newDataOutput();

        out.writeUTF("RoleUpdate");
        out.writeUTF(stafferRole);
        out.writeUTF(stafferName);
        out.writeUTF(suspectRole);
        out.writeUTF(suspectName);

        Optional<Player> anyConnectedPlayer = proxy.getAllPlayers().stream().findAny();
        if (anyConnectedPlayer.isPresent()) {
            Optional<ServerConnection> connection = anyConnectedPlayer.get().getCurrentServer();
            if (connection.isPresent()) {
                connection.get().sendPluginMessage(IDENTIFIER, out.toByteArray());
                logger.info("Message sent to spigot, staffer name: " + stafferName + " (role: " + stafferRole + ") and suspect: " + suspectName + " (role: " + suspectRole + ")");
            } else {
                logger.warn("No connection was found for player: " + anyConnectedPlayer.get().getUsername());
            }
        } else {
            logger.warn("No players connected to send message to the spigot server.");
        }
    }

排查与解决步骤

  • 修正消息目标服务器:当前代码是随机找一个在线玩家的服务器发送消息,但该玩家大概率不在录屏服务器上。直接定位录屏服务器发送:

    // 替换原来的玩家查找逻辑,直接获取录屏服务器实例
    Optional<RegisteredServer> screenShareServer = proxy.getServer("录屏服务器的名称");
    if (screenShareServer.isPresent()) {
        // 检查服务器是否有在线玩家(Velocity要求必须有玩家才能发消息)
        if (!screenShareServer.get().getPlayersConnected().isEmpty()) {
            // 取该服务器上的任意一个玩家连接
            screenShareServer.get().getPlayersConnected().stream().findAny().ifPresent(player -> {
                player.getCurrentServer().ifPresent(connection -> {
                    connection.sendPluginMessage(IDENTIFIER, out.toByteArray());
                    logger.info("Message sent to screen share server, staffer name: " + stafferName + " (role: " + stafferRole + ") and suspect: " + suspectName + " (role: " + suspectRole + ")");
                });
            });
        } else {
            logger.warn("No players on screen share server, cannot send plugin message.");
        }
    } else {
        logger.warn("Screen share server not found in proxy config.");
    }
    
  • 移除Spigot端不必要的延迟:onPluginMessageReceived本身在主线程执行,无需额外延迟,直接处理消息:

    @Override
    public void onPluginMessageReceived(String channel, Player player, byte[] message) {
        if (!channel.equals("test:screenshare")) {
            getLogger().info("Wrong channel: " + channel);
            return;
        }
    
        ByteArrayDataInput in = ByteStreams.newDataInput(message);
        String subchannel = in.readUTF();
    
        if (subchannel.equals("RoleUpdate")) {
            String stafferRole = in.readUTF();
            String stafferName = in.readUTF();
            String suspectRole = in.readUTF();
            String suspectName = in.readUTF();
    
            getLogger().info("Received roles: " + stafferRole + " for " + stafferName + " and " + suspectRole + " for " + suspectName);
        } else {
            getLogger().info("Subchannel not found: " + subchannel);
        }
    }
    
  • 确认频道注册一致性:在Spigot插件的plugin.yml中显式声明频道,确保服务器加载时正确注册:

    plugin:
      channels:
        - test:screenshare
    
  • 添加注册日志验证:在Spigot端onEnable中添加日志,确认频道注册成功:

    @Override
    public void onEnable() {
        getServer().getMessenger().registerOutgoingPluginChannel(this, "test:screenshare");
        getServer().getMessenger().registerIncomingPluginChannel(this, "test:screenshare", this);
        getLogger().info("Registered plugin channel: test:screenshare");
        // ...其他代码
    }
    

内容的提问来源于stack exchange,提问作者Giuseppe Gentile

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 00:27:08