基于Velocity代理的后端PaperMC插件跨服传送方法咨询
在PaperMC插件中实现Velocity代理下的跨服传送方法
核心思路
后端PaperMC服务器无法直接调用Velocity的传送逻辑,必须通过**插件消息通道(Plugin Message Channel)**与Velocity代理通信,由Velocity执行实际的跨服操作。以下是两种可行方案:
方案一:利用Velocity的BungeeCord兼容通道(无需额外Velocity插件)
Velocity原生兼容BungeeCord的插件消息协议,可直接通过内置的BungeeCord通道发送跨服请求,无需编写Velocity端插件。
1. 注册插件消息通道
在Paper插件的onEnable()方法中注册 outgoing 通道:
@Override public void onEnable() { getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord"); }
2. 编写跨服传送方法
构建符合BungeeCord协议的消息包,发送给Velocity:
import org.bukkit.entity.Player; import com.google.common.io.ByteStreams; import java.io.ByteArrayDataOutput; public void sendPlayerToServer(Player player, String targetServerName) { ByteArrayDataOutput out = ByteStreams.newDataOutput(); // 指定操作类型为"Connect"(BungeeCord协议约定) out.writeUTF("Connect"); // 目标服务器名称(需与Velocity配置文件中的server name一致) out.writeUTF(targetServerName); // 发送插件消息 player.sendPluginMessage(this, "BungeeCord", out.toByteArray()); }
方案二:自定义插件消息通道(需编写Velocity端插件)
如果需要定制化逻辑(如传送前权限校验、状态同步),可通过自定义通道实现Paper与Velocity的双向通信。
Paper端实现
- 注册自定义通道:
@Override public void onEnable() { getServer().getMessenger().registerOutgoingPluginChannel(this, "velocity:player-transfer"); }
- 发送传送请求:
import org.bukkit.entity.Player; import com.google.common.io.ByteStreams; import java.io.ByteArrayDataOutput; import java.util.UUID; public void transferPlayer(Player player, String targetServer) { ByteArrayDataOutput out = ByteStreams.newDataOutput(); // 传递玩家UUID(Velocity端用于定位玩家) out.writeUTF(player.getUniqueId().toString()); // 目标服务器名称 out.writeUTF(targetServer); player.sendPluginMessage(this, "velocity:player-transfer", out.toByteArray()); }
Velocity端实现
- 注册自定义通道并监听消息:
import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.connection.PluginMessageEvent; import com.velocitypowered.api.plugin.Plugin; import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.proxy.player.Player; import com.velocitypowered.api.proxy.server.RegisteredServer; import com.google.common.io.ByteStreams; import java.io.ByteArrayDataInput; import java.util.Optional; import java.util.UUID; @Plugin(id = "transferplugin", name = "TransferPlugin", version = "1.0") public class TransferPlugin { private final ProxyServer proxy; public TransferPlugin(ProxyServer proxy) { this.proxy = proxy; // 注册自定义插件通道 proxy.getPluginManager().registerPluginChannel(this, "velocity:player-transfer"); } @Subscribe public void onPluginMessage(PluginMessageEvent event) { // 过滤非目标通道的消息 if (!event.getIdentifier().getId().equals("velocity:player-transfer")) { return; } ByteArrayDataInput in = ByteStreams.newDataInput(event.getData()); UUID playerId = UUID.fromString(in.readUTF()); String targetServerName = in.readUTF(); // 定位玩家与目标服务器 Optional<Player> player = proxy.getPlayer(playerId); Optional<RegisteredServer> targetServer = proxy.getServer(targetServerName); // 执行传送 if (player.isPresent() && targetServer.isPresent()) { player.get().createConnectionRequest(targetServer.get()).fireAndForget(); } } }
关键注意事项
- 确保Velocity配置文件
velocity.toml中已正确配置所有目标服务器,代码中使用的服务器名称必须与配置中的name字段完全一致。 - 插件消息通道名称需在Paper和Velocity两端保持严格一致,自定义通道建议添加前缀(如
velocity:)避免冲突。 - 使用BungeeCord兼容通道时,Velocity会自动处理请求,但仅支持基础操作;自定义通道方案更灵活,可扩展复杂业务逻辑。
- 发送插件消息前,务必确认通道已完成注册,否则会抛出
IllegalArgumentException。
内容的提问来源于stack exchange,提问作者aquestry
相关产品推荐
相关产品推荐

