geforkt von Mirrors/Velocity
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;
|
||||
|
||||
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.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
||||
@ -31,6 +34,7 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
||||
private final VelocityServerConnection serverConn;
|
||||
private final ClientPlaySessionHandler playerSessionHandler;
|
||||
private final MinecraftConnection playerConnection;
|
||||
private final BungeeCordMessageResponder bungeecordMessageResponder;
|
||||
private boolean exceptionTriggered = false;
|
||||
|
||||
BackendPlaySessionHandler(VelocityServer server, VelocityServerConnection serverConn) {
|
||||
@ -44,11 +48,18 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
||||
"Initializing BackendPlaySessionHandler with no backing client play session handler!");
|
||||
}
|
||||
this.playerSessionHandler = (ClientPlaySessionHandler) psh;
|
||||
|
||||
this.bungeecordMessageResponder = new BungeeCordMessageResponder(server,
|
||||
serverConn.getPlayer());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activated() {
|
||||
serverConn.getServer().addPlayer(serverConn.getPlayer());
|
||||
MinecraftConnection serverMc = serverConn.ensureConnected();
|
||||
serverMc.write(PluginMessageUtil.constructChannelsPacket(serverMc.getProtocolVersion(),
|
||||
ImmutableList.of(getBungeeCordChannel(serverMc.getProtocolVersion()))
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -86,6 +97,10 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
||||
|
||||
@Override
|
||||
public boolean handle(PluginMessage packet) {
|
||||
if (bungeecordMessageResponder.process(packet)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!serverConn.getPlayer().canForwardPluginMessage(serverConn.ensureConnected()
|
||||
.getProtocolVersion(), packet)) {
|
||||
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.ServerLogin;
|
||||
import com.velocitypowered.proxy.server.VelocityRegisteredServer;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
@ -210,12 +211,22 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation,
|
||||
|
||||
@Override
|
||||
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(data, "data");
|
||||
|
||||
MinecraftConnection mc = ensureConnected();
|
||||
|
||||
PluginMessage message = new PluginMessage(identifier.getId(), Unpooled.wrappedBuffer(data));
|
||||
PluginMessage message = new PluginMessage(identifier.getId(), data);
|
||||
mc.write(message);
|
||||
return true;
|
||||
}
|
||||
|
@ -135,6 +135,18 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
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
|
||||
public GameProfile getGameProfile() {
|
||||
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.proxy.VelocityServer;
|
||||
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
||||
import com.velocitypowered.proxy.connection.backend.VelocityServerConnection;
|
||||
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.netty.MinecraftDecoder;
|
||||
import com.velocitypowered.proxy.protocol.netty.MinecraftEncoder;
|
||||
import com.velocitypowered.proxy.protocol.netty.MinecraftVarintFrameDecoder;
|
||||
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.ChannelFuture;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
@ -119,8 +123,18 @@ public class VelocityRegisteredServer implements RegisteredServer {
|
||||
|
||||
@Override
|
||||
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) {
|
||||
ServerConnection connection = player.getConnectedServer();
|
||||
VelocityServerConnection connection = player.getConnectedServer();
|
||||
if (connection != null && connection.getServerInfo().equals(serverInfo)) {
|
||||
return connection.sendPluginMessage(identifier, data);
|
||||
}
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren