Mirror von
https://github.com/PaperMC/Velocity.git
synchronisiert 2024-11-06 00:00:47 +01:00
Merge pull request #255 from VelocityPowered/bungeequack-integrate
Integrate BungeeQuack functionality into Velocity
Dieser Commit ist enthalten in:
Commit
94035366c2
@ -1,5 +1,8 @@
|
|||||||
package com.velocitypowered.proxy.connection.backend;
|
package com.velocitypowered.proxy.connection.backend;
|
||||||
|
|
||||||
|
import static com.velocitypowered.proxy.connection.backend.BungeeCordMessageResponder.getBungeeCordChannel;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
||||||
@ -31,6 +34,7 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
private final VelocityServerConnection serverConn;
|
private final VelocityServerConnection serverConn;
|
||||||
private final ClientPlaySessionHandler playerSessionHandler;
|
private final ClientPlaySessionHandler playerSessionHandler;
|
||||||
private final MinecraftConnection playerConnection;
|
private final MinecraftConnection playerConnection;
|
||||||
|
private final BungeeCordMessageResponder bungeecordMessageResponder;
|
||||||
private boolean exceptionTriggered = false;
|
private boolean exceptionTriggered = false;
|
||||||
|
|
||||||
BackendPlaySessionHandler(VelocityServer server, VelocityServerConnection serverConn) {
|
BackendPlaySessionHandler(VelocityServer server, VelocityServerConnection serverConn) {
|
||||||
@ -44,11 +48,18 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
"Initializing BackendPlaySessionHandler with no backing client play session handler!");
|
"Initializing BackendPlaySessionHandler with no backing client play session handler!");
|
||||||
}
|
}
|
||||||
this.playerSessionHandler = (ClientPlaySessionHandler) psh;
|
this.playerSessionHandler = (ClientPlaySessionHandler) psh;
|
||||||
|
|
||||||
|
this.bungeecordMessageResponder = new BungeeCordMessageResponder(server,
|
||||||
|
serverConn.getPlayer());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void activated() {
|
public void activated() {
|
||||||
serverConn.getServer().addPlayer(serverConn.getPlayer());
|
serverConn.getServer().addPlayer(serverConn.getPlayer());
|
||||||
|
MinecraftConnection serverMc = serverConn.ensureConnected();
|
||||||
|
serverMc.write(PluginMessageUtil.constructChannelsPacket(serverMc.getProtocolVersion(),
|
||||||
|
ImmutableList.of(getBungeeCordChannel(serverMc.getProtocolVersion()))
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -86,6 +97,10 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handle(PluginMessage packet) {
|
public boolean handle(PluginMessage packet) {
|
||||||
|
if (bungeecordMessageResponder.process(packet)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!serverConn.getPlayer().canForwardPluginMessage(serverConn.ensureConnected()
|
if (!serverConn.getPlayer().canForwardPluginMessage(serverConn.ensureConnected()
|
||||||
.getProtocolVersion(), packet)) {
|
.getProtocolVersion(), packet)) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -0,0 +1,329 @@
|
|||||||
|
package com.velocitypowered.proxy.connection.backend;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
|
import com.velocitypowered.api.proxy.Player;
|
||||||
|
import com.velocitypowered.api.proxy.messages.LegacyChannelIdentifier;
|
||||||
|
import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
|
||||||
|
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||||
|
import com.velocitypowered.api.util.UuidUtils;
|
||||||
|
import com.velocitypowered.proxy.VelocityServer;
|
||||||
|
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
||||||
|
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.PluginMessage;
|
||||||
|
import com.velocitypowered.proxy.protocol.util.ByteBufDataInput;
|
||||||
|
import com.velocitypowered.proxy.protocol.util.ByteBufDataOutput;
|
||||||
|
import com.velocitypowered.proxy.server.VelocityRegisteredServer;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import java.util.StringJoiner;
|
||||||
|
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
|
|
||||||
|
class BungeeCordMessageResponder {
|
||||||
|
|
||||||
|
private static final MinecraftChannelIdentifier MODERN_CHANNEL = MinecraftChannelIdentifier
|
||||||
|
.create("bungeecord", "main");
|
||||||
|
private static final LegacyChannelIdentifier LEGACY_CHANNEL =
|
||||||
|
new LegacyChannelIdentifier("BungeeCord");
|
||||||
|
|
||||||
|
private final VelocityServer proxy;
|
||||||
|
private final ConnectedPlayer player;
|
||||||
|
|
||||||
|
BungeeCordMessageResponder(VelocityServer proxy, ConnectedPlayer player) {
|
||||||
|
this.proxy = proxy;
|
||||||
|
this.player = player;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processConnect(ByteBufDataInput in) {
|
||||||
|
String serverName = in.readUTF();
|
||||||
|
proxy.getServer(serverName).ifPresent(server -> player.createConnectionRequest(server)
|
||||||
|
.fireAndForget());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processConnectOther(ByteBufDataInput in) {
|
||||||
|
String playerName = in.readUTF();
|
||||||
|
String serverName = in.readUTF();
|
||||||
|
|
||||||
|
proxy.getPlayer(playerName).flatMap(player -> proxy.getServer(serverName))
|
||||||
|
.ifPresent(server -> player.createConnectionRequest(server).fireAndForget());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processIp(ByteBufDataInput in) {
|
||||||
|
ByteBuf buf = Unpooled.buffer();
|
||||||
|
ByteBufDataOutput out = new ByteBufDataOutput(buf);
|
||||||
|
out.writeUTF("IP");
|
||||||
|
out.writeUTF(player.getRemoteAddress().getHostString());
|
||||||
|
out.writeInt(player.getRemoteAddress().getPort());
|
||||||
|
sendResponseOnConnection(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processPlayerCount(ByteBufDataInput in) {
|
||||||
|
ByteBuf buf = Unpooled.buffer();
|
||||||
|
ByteBufDataOutput out = new ByteBufDataOutput(buf);
|
||||||
|
|
||||||
|
String target = in.readUTF();
|
||||||
|
if (target.equals("ALL")) {
|
||||||
|
out.writeUTF("PlayerCount");
|
||||||
|
out.writeUTF("ALL");
|
||||||
|
out.writeInt(proxy.getPlayerCount());
|
||||||
|
} else {
|
||||||
|
proxy.getServer(target).ifPresent(rs -> {
|
||||||
|
int playersOnServer = rs.getPlayersConnected().size();
|
||||||
|
out.writeUTF("PlayerCount");
|
||||||
|
out.writeUTF(rs.getServerInfo().getName());
|
||||||
|
out.writeInt(playersOnServer);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf.isReadable()) {
|
||||||
|
sendResponseOnConnection(buf);
|
||||||
|
} else {
|
||||||
|
buf.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processPlayerList(ByteBufDataInput in) {
|
||||||
|
ByteBuf buf = Unpooled.buffer();
|
||||||
|
ByteBufDataOutput out = new ByteBufDataOutput(buf);
|
||||||
|
|
||||||
|
String target = in.readUTF();
|
||||||
|
if (target.equals("ALL")) {
|
||||||
|
out.writeUTF("PlayerList");
|
||||||
|
out.writeUTF("ALL");
|
||||||
|
|
||||||
|
StringJoiner joiner = new StringJoiner(", ");
|
||||||
|
for (Player online : proxy.getAllPlayers()) {
|
||||||
|
joiner.add(online.getUsername());
|
||||||
|
}
|
||||||
|
out.writeUTF(joiner.toString());
|
||||||
|
} else {
|
||||||
|
proxy.getServer(target).ifPresent(info -> {
|
||||||
|
out.writeUTF("PlayerList");
|
||||||
|
out.writeUTF(info.getServerInfo().getName());
|
||||||
|
|
||||||
|
StringJoiner joiner = new StringJoiner(", ");
|
||||||
|
for (Player online : info.getPlayersConnected()) {
|
||||||
|
joiner.add(online.getUsername());
|
||||||
|
}
|
||||||
|
out.writeUTF(joiner.toString());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf.isReadable()) {
|
||||||
|
sendResponseOnConnection(buf);
|
||||||
|
} else {
|
||||||
|
buf.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processGetServers() {
|
||||||
|
StringJoiner joiner = new StringJoiner(", ");
|
||||||
|
for (RegisteredServer server : proxy.getAllServers()) {
|
||||||
|
joiner.add(server.getServerInfo().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBuf buf = Unpooled.buffer();
|
||||||
|
ByteBufDataOutput out = new ByteBufDataOutput(buf);
|
||||||
|
out.writeUTF("GetServers");
|
||||||
|
out.writeUTF(joiner.toString());
|
||||||
|
|
||||||
|
sendResponseOnConnection(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processMessage(ByteBufDataInput in) {
|
||||||
|
String target = in.readUTF();
|
||||||
|
String message = in.readUTF();
|
||||||
|
if (target.equals("ALL")) {
|
||||||
|
for (Player player : proxy.getAllPlayers()) {
|
||||||
|
player.sendMessage(LegacyComponentSerializer.INSTANCE.deserialize(message));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
proxy.getPlayer(target).ifPresent(player -> {
|
||||||
|
player.sendMessage(LegacyComponentSerializer.INSTANCE.deserialize(message));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processGetServer() {
|
||||||
|
ByteBuf buf = Unpooled.buffer();
|
||||||
|
ByteBufDataOutput out = new ByteBufDataOutput(buf);
|
||||||
|
|
||||||
|
out.writeUTF("GetServer");
|
||||||
|
out.writeUTF(player.ensureAndGetCurrentServer().getServerInfo().getName());
|
||||||
|
|
||||||
|
sendResponseOnConnection(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processUuid() {
|
||||||
|
ByteBuf buf = Unpooled.buffer();
|
||||||
|
ByteBufDataOutput out = new ByteBufDataOutput(buf);
|
||||||
|
|
||||||
|
out.writeUTF("UUID");
|
||||||
|
out.writeUTF(UuidUtils.toUndashed(player.getUniqueId()));
|
||||||
|
|
||||||
|
sendResponseOnConnection(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processUuidOther(ByteBufDataInput in) {
|
||||||
|
proxy.getPlayer(in.readUTF()).ifPresent(player -> {
|
||||||
|
ByteBuf buf = Unpooled.buffer();
|
||||||
|
ByteBufDataOutput out = new ByteBufDataOutput(buf);
|
||||||
|
|
||||||
|
out.writeUTF("UUIDOther");
|
||||||
|
out.writeUTF(player.getUsername());
|
||||||
|
out.writeUTF(UuidUtils.toUndashed(player.getUniqueId()));
|
||||||
|
|
||||||
|
sendResponseOnConnection(buf);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processServerIp(ByteBufDataInput in) {
|
||||||
|
proxy.getServer(in.readUTF()).ifPresent(info -> {
|
||||||
|
ByteBuf buf = Unpooled.buffer();
|
||||||
|
ByteBufDataOutput out = new ByteBufDataOutput(buf);
|
||||||
|
|
||||||
|
out.writeUTF("ServerIP");
|
||||||
|
out.writeUTF(info.getServerInfo().getName());
|
||||||
|
out.writeUTF(info.getServerInfo().getAddress().getHostString());
|
||||||
|
out.writeShort(info.getServerInfo().getAddress().getPort());
|
||||||
|
|
||||||
|
sendResponseOnConnection(buf);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processKick(ByteBufDataInput in) {
|
||||||
|
proxy.getPlayer(in.readUTF()).ifPresent(player -> {
|
||||||
|
String kickReason = in.readUTF();
|
||||||
|
player.disconnect(LegacyComponentSerializer.INSTANCE.deserialize(kickReason));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private ByteBuf prepareForwardMessage(ByteBufDataInput in) {
|
||||||
|
String channel = in.readUTF();
|
||||||
|
short messageLength = in.readShort();
|
||||||
|
|
||||||
|
ByteBuf buf = Unpooled.buffer();
|
||||||
|
ByteBufDataOutput forwarded = new ByteBufDataOutput(buf);
|
||||||
|
forwarded.writeUTF(channel);
|
||||||
|
forwarded.writeShort(messageLength);
|
||||||
|
buf.writeBytes(in.unwrap().readSlice(messageLength));
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processForwardToPlayer(ByteBufDataInput in) {
|
||||||
|
proxy.getPlayer(in.readUTF())
|
||||||
|
.flatMap(Player::getCurrentServer)
|
||||||
|
.ifPresent(server -> sendServerResponse(player, prepareForwardMessage(in)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processForwardToServer(ByteBufDataInput in) {
|
||||||
|
ByteBuf toForward = prepareForwardMessage(in);
|
||||||
|
String target = in.readUTF();
|
||||||
|
if (target.equals("ALL")) {
|
||||||
|
ByteBuf unreleasableForward = Unpooled.unreleasableBuffer(toForward);
|
||||||
|
try {
|
||||||
|
for (RegisteredServer rs : proxy.getAllServers()) {
|
||||||
|
((VelocityRegisteredServer) rs).sendPluginMessage(LEGACY_CHANNEL, unreleasableForward);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
toForward.release();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
proxy.getServer(target).ifPresent(rs -> ((VelocityRegisteredServer) rs)
|
||||||
|
.sendPluginMessage(LEGACY_CHANNEL, toForward));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: this method will always release the buffer!
|
||||||
|
private void sendResponseOnConnection(ByteBuf buf) {
|
||||||
|
sendServerResponse(this.player, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static String getBungeeCordChannel(ProtocolVersion version) {
|
||||||
|
return version.compareTo(ProtocolVersion.MINECRAFT_1_13) >= 0 ? MODERN_CHANNEL.getId()
|
||||||
|
: LEGACY_CHANNEL.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: this method will always release the buffer!
|
||||||
|
private static void sendServerResponse(ConnectedPlayer player, ByteBuf buf) {
|
||||||
|
MinecraftConnection serverConnection = player.ensureAndGetCurrentServer().ensureConnected();
|
||||||
|
String chan = getBungeeCordChannel(serverConnection.getProtocolVersion());
|
||||||
|
|
||||||
|
PluginMessage msg = null;
|
||||||
|
boolean released = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
VelocityServerConnection vsc = player.getConnectedServer();
|
||||||
|
if (vsc == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MinecraftConnection serverConn = vsc.ensureConnected();
|
||||||
|
msg = new PluginMessage(chan, buf);
|
||||||
|
serverConn.write(msg);
|
||||||
|
released = true;
|
||||||
|
} finally {
|
||||||
|
if (!released && msg != null) {
|
||||||
|
msg.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean process(PluginMessage message) {
|
||||||
|
if (!MODERN_CHANNEL.getId().equals(message.getChannel()) && !LEGACY_CHANNEL.getId()
|
||||||
|
.equals(message.getChannel())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBufDataInput in = new ByteBufDataInput(message.content());
|
||||||
|
String subChannel = in.readUTF();
|
||||||
|
switch (subChannel) {
|
||||||
|
case "ForwardToPlayer":
|
||||||
|
this.processForwardToPlayer(in);
|
||||||
|
break;
|
||||||
|
case "Forward":
|
||||||
|
this.processForwardToServer(in);
|
||||||
|
break;
|
||||||
|
case "Connect":
|
||||||
|
this.processConnect(in);
|
||||||
|
break;
|
||||||
|
case "ConnectOther":
|
||||||
|
this.processConnectOther(in);
|
||||||
|
break;
|
||||||
|
case "IP":
|
||||||
|
this.processIp(in);
|
||||||
|
break;
|
||||||
|
case "PlayerCount":
|
||||||
|
this.processPlayerCount(in);
|
||||||
|
break;
|
||||||
|
case "PlayerList":
|
||||||
|
this.processPlayerList(in);
|
||||||
|
break;
|
||||||
|
case "GetServers":
|
||||||
|
this.processGetServers();
|
||||||
|
break;
|
||||||
|
case "Message":
|
||||||
|
this.processMessage(in);
|
||||||
|
break;
|
||||||
|
case "GetServer":
|
||||||
|
this.processGetServer();
|
||||||
|
break;
|
||||||
|
case "UUID":
|
||||||
|
this.processUuid();
|
||||||
|
break;
|
||||||
|
case "UUIDOther":
|
||||||
|
this.processUuidOther(in);
|
||||||
|
break;
|
||||||
|
case "ServerIP":
|
||||||
|
this.processServerIp(in);
|
||||||
|
break;
|
||||||
|
case "KickPlayer":
|
||||||
|
this.processKick(in);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Do nothing, unknown command
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -34,6 +34,7 @@ import com.velocitypowered.proxy.protocol.packet.Handshake;
|
|||||||
import com.velocitypowered.proxy.protocol.packet.PluginMessage;
|
import com.velocitypowered.proxy.protocol.packet.PluginMessage;
|
||||||
import com.velocitypowered.proxy.protocol.packet.ServerLogin;
|
import com.velocitypowered.proxy.protocol.packet.ServerLogin;
|
||||||
import com.velocitypowered.proxy.server.VelocityRegisteredServer;
|
import com.velocitypowered.proxy.server.VelocityRegisteredServer;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
import io.netty.channel.ChannelFutureListener;
|
import io.netty.channel.ChannelFutureListener;
|
||||||
@ -210,12 +211,22 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation,
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean sendPluginMessage(ChannelIdentifier identifier, byte[] data) {
|
public boolean sendPluginMessage(ChannelIdentifier identifier, byte[] data) {
|
||||||
|
return sendPluginMessage(identifier, Unpooled.wrappedBuffer(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a plugin message to the server through this connection.
|
||||||
|
* @param identifier the channel ID to use
|
||||||
|
* @param data the data
|
||||||
|
* @return whether or not the message was sent
|
||||||
|
*/
|
||||||
|
public boolean sendPluginMessage(ChannelIdentifier identifier, ByteBuf data) {
|
||||||
Preconditions.checkNotNull(identifier, "identifier");
|
Preconditions.checkNotNull(identifier, "identifier");
|
||||||
Preconditions.checkNotNull(data, "data");
|
Preconditions.checkNotNull(data, "data");
|
||||||
|
|
||||||
MinecraftConnection mc = ensureConnected();
|
MinecraftConnection mc = ensureConnected();
|
||||||
|
|
||||||
PluginMessage message = new PluginMessage(identifier.getId(), Unpooled.wrappedBuffer(data));
|
PluginMessage message = new PluginMessage(identifier.getId(), data);
|
||||||
mc.write(message);
|
mc.write(message);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -135,6 +135,18 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
|||||||
return Optional.ofNullable(connectedServer);
|
return Optional.ofNullable(connectedServer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes sure the player is connected to a server and returns the server they are connected to.
|
||||||
|
* @return the server the player is connected to
|
||||||
|
*/
|
||||||
|
public VelocityServerConnection ensureAndGetCurrentServer() {
|
||||||
|
VelocityServerConnection con = this.connectedServer;
|
||||||
|
if (con == null) {
|
||||||
|
throw new IllegalStateException("Not connected to server!");
|
||||||
|
}
|
||||||
|
return con;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GameProfile getGameProfile() {
|
public GameProfile getGameProfile() {
|
||||||
return profile;
|
return profile;
|
||||||
|
@ -0,0 +1,110 @@
|
|||||||
|
package com.velocitypowered.proxy.protocol.util;
|
||||||
|
|
||||||
|
import com.google.common.io.ByteArrayDataInput;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper around {@link io.netty.buffer.ByteBuf} that implements the exception-free
|
||||||
|
* {@link ByteArrayDataInput} interface from Guava.
|
||||||
|
*/
|
||||||
|
public class ByteBufDataInput implements ByteArrayDataInput, DataInput {
|
||||||
|
|
||||||
|
private final ByteBuf in;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new ByteBufDataInput instance. The ByteBufDataInput simply "borrows" the ByteBuf
|
||||||
|
* while it is in use.
|
||||||
|
*
|
||||||
|
* @param buf the buffer to read from
|
||||||
|
*/
|
||||||
|
public ByteBufDataInput(ByteBuf buf) {
|
||||||
|
this.in = buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ByteBuf unwrap() {
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFully(byte[] b) {
|
||||||
|
in.readBytes(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFully(byte[] b, int off, int len) {
|
||||||
|
in.readBytes(b, off, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int skipBytes(int n) {
|
||||||
|
in.skipBytes(n);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean readBoolean() {
|
||||||
|
return in.readBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte readByte() {
|
||||||
|
return in.readByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int readUnsignedByte() {
|
||||||
|
return in.readUnsignedByte() & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public short readShort() {
|
||||||
|
return in.readShort();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int readUnsignedShort() {
|
||||||
|
return in.readUnsignedShort();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public char readChar() {
|
||||||
|
return in.readChar();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int readInt() {
|
||||||
|
return in.readInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long readLong() {
|
||||||
|
return in.readLong();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float readFloat() {
|
||||||
|
return in.readFloat();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double readDouble() {
|
||||||
|
return in.readDouble();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String readLine() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String readUTF() {
|
||||||
|
try {
|
||||||
|
return DataInputStream.readUTF(this);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,105 @@
|
|||||||
|
package com.velocitypowered.proxy.protocol.util;
|
||||||
|
|
||||||
|
import com.google.common.io.ByteArrayDataOutput;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.ByteBufUtil;
|
||||||
|
import java.io.DataOutput;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link DataOutput} equivalent to {@link ByteBufDataInput}.
|
||||||
|
*/
|
||||||
|
public class ByteBufDataOutput extends OutputStream implements DataOutput, ByteArrayDataOutput {
|
||||||
|
|
||||||
|
private final ByteBuf buf;
|
||||||
|
private final DataOutputStream utf8out;
|
||||||
|
|
||||||
|
public ByteBufDataOutput(ByteBuf buf) {
|
||||||
|
this.buf = buf;
|
||||||
|
this.utf8out = new DataOutputStream(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] toByteArray() {
|
||||||
|
return ByteBufUtil.getBytes(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(int b) {
|
||||||
|
buf.writeByte(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte[] b) {
|
||||||
|
buf.writeBytes(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte[] b, int off, int len) {
|
||||||
|
buf.writeBytes(b, off, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeBoolean(boolean v) {
|
||||||
|
buf.writeBoolean(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeByte(int v) {
|
||||||
|
buf.writeByte(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeShort(int v) {
|
||||||
|
buf.writeShort(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeChar(int v) {
|
||||||
|
buf.writeChar(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeInt(int v) {
|
||||||
|
buf.writeInt(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeLong(long v) {
|
||||||
|
buf.writeLong(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeFloat(float v) {
|
||||||
|
buf.writeFloat(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeDouble(double v) {
|
||||||
|
buf.writeDouble(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeBytes(String s) {
|
||||||
|
buf.writeCharSequence(s, StandardCharsets.US_ASCII);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeChars(String s) {
|
||||||
|
for (char c : s.toCharArray()) {
|
||||||
|
buf.writeChar(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeUTF(String s) {
|
||||||
|
try {
|
||||||
|
this.utf8out.writeUTF(s);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,12 +18,16 @@ import com.velocitypowered.api.proxy.server.ServerInfo;
|
|||||||
import com.velocitypowered.api.proxy.server.ServerPing;
|
import com.velocitypowered.api.proxy.server.ServerPing;
|
||||||
import com.velocitypowered.proxy.VelocityServer;
|
import com.velocitypowered.proxy.VelocityServer;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
||||||
|
import com.velocitypowered.proxy.connection.backend.VelocityServerConnection;
|
||||||
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
|
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.netty.MinecraftDecoder;
|
import com.velocitypowered.proxy.protocol.netty.MinecraftDecoder;
|
||||||
import com.velocitypowered.proxy.protocol.netty.MinecraftEncoder;
|
import com.velocitypowered.proxy.protocol.netty.MinecraftEncoder;
|
||||||
import com.velocitypowered.proxy.protocol.netty.MinecraftVarintFrameDecoder;
|
import com.velocitypowered.proxy.protocol.netty.MinecraftVarintFrameDecoder;
|
||||||
import com.velocitypowered.proxy.protocol.netty.MinecraftVarintLengthEncoder;
|
import com.velocitypowered.proxy.protocol.netty.MinecraftVarintLengthEncoder;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.PluginMessage;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.ChannelFuture;
|
||||||
import io.netty.channel.ChannelFutureListener;
|
import io.netty.channel.ChannelFutureListener;
|
||||||
@ -119,8 +123,18 @@ public class VelocityRegisteredServer implements RegisteredServer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean sendPluginMessage(ChannelIdentifier identifier, byte[] data) {
|
public boolean sendPluginMessage(ChannelIdentifier identifier, byte[] data) {
|
||||||
|
return sendPluginMessage(identifier, Unpooled.wrappedBuffer(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a plugin message to the server through this connection.
|
||||||
|
* @param identifier the channel ID to use
|
||||||
|
* @param data the data
|
||||||
|
* @return whether or not the message was sent
|
||||||
|
*/
|
||||||
|
public boolean sendPluginMessage(ChannelIdentifier identifier, ByteBuf data) {
|
||||||
for (ConnectedPlayer player : players) {
|
for (ConnectedPlayer player : players) {
|
||||||
ServerConnection connection = player.getConnectedServer();
|
VelocityServerConnection connection = player.getConnectedServer();
|
||||||
if (connection != null && connection.getServerInfo().equals(serverInfo)) {
|
if (connection != null && connection.getServerInfo().equals(serverInfo)) {
|
||||||
return connection.sendPluginMessage(identifier, data);
|
return connection.sendPluginMessage(identifier, data);
|
||||||
}
|
}
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren