Velocity向Spigot发插件消息时onPluginMessageReceived无响应排查
我正在为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

