Mirror von
https://github.com/PaperMC/Velocity.git
synchronisiert 2024-11-17 05:20:14 +01:00
Fix a bunch of small issues, so that the proxy can establish a connection
This is still broken and has performance/bandwidth problems, which I will fix very soon. For a first try, it's good enough.
Dieser Commit ist enthalten in:
Ursprung
dd8557d367
Commit
32772d1e9b
@ -9,33 +9,27 @@ public enum ProtocolUtils { ;
|
|||||||
private static final int DEFAULT_MAX_STRING_SIZE = 65536; // 64KiB
|
private static final int DEFAULT_MAX_STRING_SIZE = 65536; // 64KiB
|
||||||
|
|
||||||
public static int readVarInt(ByteBuf buf) {
|
public static int readVarInt(ByteBuf buf) {
|
||||||
int numRead = 0;
|
int i = 0;
|
||||||
int result = 0;
|
int j = 0;
|
||||||
byte read;
|
while (true) {
|
||||||
do {
|
int k = buf.readByte();
|
||||||
read = buf.readByte();
|
i |= (k & 0x7F) << j++ * 7;
|
||||||
int value = (read & 0b01111111);
|
if (j > 5) throw new RuntimeException("VarInt too big");
|
||||||
result |= (value << (7 * numRead));
|
if ((k & 0x80) != 128) break;
|
||||||
|
}
|
||||||
numRead++;
|
return i;
|
||||||
if (numRead > 5) {
|
|
||||||
throw new RuntimeException("VarInt is too big");
|
|
||||||
}
|
|
||||||
} while ((read & 0b10000000) != 0);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void writeVarInt(ByteBuf buf, int value) {
|
public static void writeVarInt(ByteBuf buf, int value) {
|
||||||
do {
|
while (true) {
|
||||||
byte temp = (byte)(value & 0b01111111);
|
if ((value & 0xFFFFFF80) == 0) {
|
||||||
// Note: >>> means that the sign bit is shifted with the rest of the number rather than being left alone
|
buf.writeByte(value);
|
||||||
value >>>= 7;
|
return;
|
||||||
if (value != 0) {
|
|
||||||
temp |= 0b10000000;
|
|
||||||
}
|
}
|
||||||
buf.writeByte(temp);
|
|
||||||
} while (value != 0);
|
buf.writeByte(value & 0x7F | 0x80);
|
||||||
|
value >>>= 7;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String readString(ByteBuf buf) {
|
public static String readString(ByteBuf buf) {
|
||||||
@ -44,7 +38,7 @@ public enum ProtocolUtils { ;
|
|||||||
|
|
||||||
public static String readString(ByteBuf buf, int cap) {
|
public static String readString(ByteBuf buf, int cap) {
|
||||||
int length = readVarInt(buf);
|
int length = readVarInt(buf);
|
||||||
Preconditions.checkArgument(length < cap, "Bad string size (got %s, maximum is %s)", length, cap);
|
Preconditions.checkArgument(length <= cap, "Bad string size (got %s, maximum is %s)", length, cap);
|
||||||
byte[] str = new byte[length];
|
byte[] str = new byte[length];
|
||||||
buf.readBytes(str);
|
buf.readBytes(str);
|
||||||
return new String(str, StandardCharsets.UTF_8);
|
return new String(str, StandardCharsets.UTF_8);
|
||||||
|
@ -32,7 +32,7 @@ public enum StateRegistry {
|
|||||||
|
|
||||||
TO_CLIENT.register(0x00, Disconnect.class, Disconnect::new);
|
TO_CLIENT.register(0x00, Disconnect.class, Disconnect::new);
|
||||||
// Encryption Success will follow once Mojang auth/encryption is done
|
// Encryption Success will follow once Mojang auth/encryption is done
|
||||||
TO_CLIENT.register(0x02, ServerLoginSuccess.class, ServerLogin::new);
|
TO_CLIENT.register(0x02, ServerLoginSuccess.class, ServerLoginSuccess::new);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import io.minimum.minecraft.velocity.protocol.*;
|
|||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.ByteBufUtil;
|
import io.netty.buffer.ByteBufUtil;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.handler.codec.CorruptedFrameException;
|
||||||
import io.netty.handler.codec.MessageToMessageDecoder;
|
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -35,7 +36,12 @@ public class MinecraftDecoder extends MessageToMessageDecoder<ByteBuf> {
|
|||||||
msg.skipBytes(msg.readableBytes());
|
msg.skipBytes(msg.readableBytes());
|
||||||
out.add(new PacketWrapper(null, slice));
|
out.add(new PacketWrapper(null, slice));
|
||||||
} else {
|
} else {
|
||||||
packet.decode(msg, direction, protocolVersion);
|
try {
|
||||||
|
packet.decode(msg, direction, protocolVersion);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new CorruptedFrameException("Error decoding " + packet.getClass() + " Direction " + direction
|
||||||
|
+ " Protocol " + protocolVersion + " State " + state + " ID " + Integer.toHexString(packetId), e);
|
||||||
|
}
|
||||||
out.add(new PacketWrapper(packet, slice));
|
out.add(new PacketWrapper(packet, slice));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,17 +55,17 @@ public class Handshake implements MinecraftPacket {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void decode(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) {
|
public void decode(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) {
|
||||||
protocolVersion = ProtocolUtils.readVarInt(buf);
|
this.protocolVersion = ProtocolUtils.readVarInt(buf);
|
||||||
serverAddress = ProtocolUtils.readString(buf, 255);
|
this.serverAddress = ProtocolUtils.readString(buf, 255);
|
||||||
port = buf.readUnsignedShort();
|
this.port = buf.readUnsignedShort();
|
||||||
nextStatus = ProtocolUtils.readVarInt(buf);
|
this.nextStatus = ProtocolUtils.readVarInt(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void encode(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) {
|
public void encode(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) {
|
||||||
ProtocolUtils.writeVarInt(buf, protocolVersion);
|
ProtocolUtils.writeVarInt(buf, this.protocolVersion);
|
||||||
ProtocolUtils.writeString(buf, serverAddress);
|
ProtocolUtils.writeString(buf, this.serverAddress);
|
||||||
buf.writeShort(port);
|
buf.writeShort(this.port);
|
||||||
ProtocolUtils.writeVarInt(buf, nextStatus);
|
ProtocolUtils.writeVarInt(buf, this.nextStatus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,11 +37,14 @@ public class ConnectedPlayer {
|
|||||||
|
|
||||||
public void handleConnectionException(Throwable throwable) {
|
public void handleConnectionException(Throwable throwable) {
|
||||||
String error = "Exception: " + throwable.getClass().getName() + ": " + throwable.getMessage();
|
String error = "Exception: " + throwable.getClass().getName() + ": " + throwable.getMessage();
|
||||||
|
Disconnect disconnect = new Disconnect();
|
||||||
|
disconnect.setReason(ComponentSerializers.JSON.serialize(TextComponent.of(error, TextColor.RED)));
|
||||||
|
handleConnectionException(disconnect);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleConnectionException(Disconnect disconnect) {
|
||||||
if (connectedServer == null) {
|
if (connectedServer == null) {
|
||||||
// The player isn't yet connected to a server - we should disconnect them.
|
// The player isn't yet connected to a server - we should disconnect them.
|
||||||
Disconnect disconnect = new Disconnect();
|
|
||||||
disconnect.setReason(ComponentSerializers.JSON.serialize(TextComponent.of(error, TextColor.RED)));
|
|
||||||
connection.closeWith(disconnect);
|
connection.closeWith(disconnect);
|
||||||
} else {
|
} else {
|
||||||
// TODO
|
// TODO
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
package io.minimum.minecraft.velocity.proxy;
|
package io.minimum.minecraft.velocity.proxy;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
import io.minimum.minecraft.velocity.data.ServerInfo;
|
||||||
|
import io.minimum.minecraft.velocity.protocol.ProtocolConstants;
|
||||||
import io.minimum.minecraft.velocity.protocol.StateRegistry;
|
import io.minimum.minecraft.velocity.protocol.StateRegistry;
|
||||||
import io.minimum.minecraft.velocity.protocol.netty.MinecraftDecoder;
|
import io.minimum.minecraft.velocity.protocol.netty.MinecraftDecoder;
|
||||||
import io.minimum.minecraft.velocity.protocol.netty.MinecraftEncoder;
|
import io.minimum.minecraft.velocity.protocol.netty.MinecraftEncoder;
|
||||||
import io.minimum.minecraft.velocity.protocol.packets.Handshake;
|
import io.minimum.minecraft.velocity.protocol.packets.Handshake;
|
||||||
|
import io.minimum.minecraft.velocity.protocol.packets.ServerLoginSuccess;
|
||||||
import io.minimum.minecraft.velocity.proxy.handler.HandshakeSessionHandler;
|
import io.minimum.minecraft.velocity.proxy.handler.HandshakeSessionHandler;
|
||||||
import io.minimum.minecraft.velocity.proxy.handler.LoginSessionHandler;
|
import io.minimum.minecraft.velocity.proxy.handler.LoginSessionHandler;
|
||||||
import io.minimum.minecraft.velocity.proxy.handler.StatusSessionHandler;
|
import io.minimum.minecraft.velocity.proxy.handler.StatusSessionHandler;
|
||||||
@ -13,6 +16,7 @@ import io.netty.channel.ChannelFuture;
|
|||||||
import io.netty.channel.ChannelFutureListener;
|
import io.netty.channel.ChannelFutureListener;
|
||||||
import io.netty.util.AttributeKey;
|
import io.netty.util.AttributeKey;
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
public class InboundMinecraftConnection {
|
public class InboundMinecraftConnection {
|
||||||
@ -82,7 +86,7 @@ public class InboundMinecraftConnection {
|
|||||||
Preconditions.checkState(!closed, "Connection is closed.");
|
Preconditions.checkState(!closed, "Connection is closed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStatus(StateRegistry state) {
|
private void setStatus(StateRegistry state) {
|
||||||
Preconditions.checkNotNull(state, "state");
|
Preconditions.checkNotNull(state, "state");
|
||||||
this.state = state;
|
this.state = state;
|
||||||
channel.pipeline().get(MinecraftEncoder.class).setState(state);
|
channel.pipeline().get(MinecraftEncoder.class).setState(state);
|
||||||
@ -100,4 +104,16 @@ public class InboundMinecraftConnection {
|
|||||||
public Optional<ConnectedPlayer> getConnectedPlayer() {
|
public Optional<ConnectedPlayer> getConnectedPlayer() {
|
||||||
return Optional.ofNullable(connectedPlayer);
|
return Optional.ofNullable(connectedPlayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getProtocolVersion() {
|
||||||
|
return handshake == null ? ProtocolConstants.MINECRAFT_1_12 : handshake.getProtocolVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initiatePlay(ServerLoginSuccess success) {
|
||||||
|
setStatus(StateRegistry.PLAY);
|
||||||
|
ConnectedPlayer player = new ConnectedPlayer(success.getUsername(), success.getUuid(), this);
|
||||||
|
ServerInfo info = new ServerInfo("test", new InetSocketAddress("127.0.0.1", 25565));
|
||||||
|
ServerConnection connection = new ServerConnection(info, player, VelocityServer.getServer());
|
||||||
|
connection.connect();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package io.minimum.minecraft.velocity.proxy;
|
|||||||
|
|
||||||
import io.minimum.minecraft.velocity.protocol.MinecraftPacket;
|
import io.minimum.minecraft.velocity.protocol.MinecraftPacket;
|
||||||
import io.minimum.minecraft.velocity.protocol.PacketWrapper;
|
import io.minimum.minecraft.velocity.protocol.PacketWrapper;
|
||||||
import io.minimum.minecraft.velocity.protocol.ProtocolConstants;
|
|
||||||
import io.minimum.minecraft.velocity.protocol.StateRegistry;
|
import io.minimum.minecraft.velocity.protocol.StateRegistry;
|
||||||
import io.minimum.minecraft.velocity.data.ServerInfo;
|
import io.minimum.minecraft.velocity.data.ServerInfo;
|
||||||
import io.minimum.minecraft.velocity.protocol.netty.MinecraftDecoder;
|
import io.minimum.minecraft.velocity.protocol.netty.MinecraftDecoder;
|
||||||
@ -13,9 +12,6 @@ import io.minimum.minecraft.velocity.protocol.packets.Handshake;
|
|||||||
import io.minimum.minecraft.velocity.protocol.packets.ServerLogin;
|
import io.minimum.minecraft.velocity.protocol.packets.ServerLogin;
|
||||||
import io.minimum.minecraft.velocity.protocol.packets.ServerLoginSuccess;
|
import io.minimum.minecraft.velocity.protocol.packets.ServerLoginSuccess;
|
||||||
import io.netty.channel.*;
|
import io.netty.channel.*;
|
||||||
import net.kyori.text.serializer.ComponentSerializers;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class ServerConnection {
|
public class ServerConnection {
|
||||||
private Channel channel;
|
private Channel channel;
|
||||||
@ -55,7 +51,7 @@ public class ServerConnection {
|
|||||||
// Initiate a handshake.
|
// Initiate a handshake.
|
||||||
Handshake handshake = new Handshake();
|
Handshake handshake = new Handshake();
|
||||||
handshake.setNextStatus(2); // login
|
handshake.setNextStatus(2); // login
|
||||||
handshake.setProtocolVersion(ProtocolConstants.MINECRAFT_1_12); // TODO: Expose client version
|
handshake.setProtocolVersion(proxyPlayer.getConnection().getProtocolVersion()); // TODO: Expose client version
|
||||||
handshake.setServerAddress(info.getAddress().getHostString());
|
handshake.setServerAddress(info.getAddress().getHostString());
|
||||||
handshake.setPort(info.getAddress().getPort());
|
handshake.setPort(info.getAddress().getPort());
|
||||||
ctx.writeAndFlush(handshake, ctx.voidPromise());
|
ctx.writeAndFlush(handshake, ctx.voidPromise());
|
||||||
@ -77,6 +73,9 @@ public class ServerConnection {
|
|||||||
case LOGIN:
|
case LOGIN:
|
||||||
onLogin(ctx, pw);
|
onLogin(ctx, pw);
|
||||||
break;
|
break;
|
||||||
|
case PLAY:
|
||||||
|
onPlay(ctx, pw);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new UnsupportedOperationException("Unsupported state " + registry);
|
throw new UnsupportedOperationException("Unsupported state " + registry);
|
||||||
}
|
}
|
||||||
@ -86,16 +85,23 @@ public class ServerConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onPlay(ChannelHandlerContext ctx, PacketWrapper pw) {
|
||||||
|
proxyPlayer.getConnection().write(pw.getBuffer().retain());
|
||||||
|
}
|
||||||
|
|
||||||
private void onLogin(ChannelHandlerContext ctx, PacketWrapper wrapper) {
|
private void onLogin(ChannelHandlerContext ctx, PacketWrapper wrapper) {
|
||||||
|
//System.out.println("FROM PROXIED SERVER -> " + wrapper.getPacket() + " / " + ByteBufUtil.hexDump(wrapper.getBuffer()));
|
||||||
MinecraftPacket packet = wrapper.getPacket();
|
MinecraftPacket packet = wrapper.getPacket();
|
||||||
if (packet instanceof Disconnect) {
|
if (packet instanceof Disconnect) {
|
||||||
Disconnect disconnect = (Disconnect) packet;
|
Disconnect disconnect = (Disconnect) packet;
|
||||||
ctx.close();
|
ctx.close();
|
||||||
proxyPlayer.handleConnectionException(new IOException("Disconnected from target: " + jsonToPlain(disconnect.getReason())));
|
proxyPlayer.handleConnectionException(disconnect);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packet instanceof ServerLoginSuccess) {
|
if (packet instanceof ServerLoginSuccess) {
|
||||||
System.out.println("got it");
|
// the player has been logged on.
|
||||||
|
System.out.println("Player connected to remote server");
|
||||||
|
setRegistry(StateRegistry.PLAY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -105,10 +111,4 @@ public class ServerConnection {
|
|||||||
this.channel.pipeline().get(MinecraftEncoder.class).setState(registry);
|
this.channel.pipeline().get(MinecraftEncoder.class).setState(registry);
|
||||||
this.channel.pipeline().get(MinecraftDecoder.class).setState(registry);
|
this.channel.pipeline().get(MinecraftDecoder.class).setState(registry);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String jsonToPlain(String j) {
|
|
||||||
return ComponentSerializers.LEGACY.serialize(
|
|
||||||
ComponentSerializers.JSON.deserialize(j)
|
|
||||||
).replaceAll("\\u00A7[a-z0-9]", "");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package io.minimum.minecraft.velocity.proxy.handler;
|
|||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import io.minimum.minecraft.velocity.data.ServerInfo;
|
import io.minimum.minecraft.velocity.data.ServerInfo;
|
||||||
import io.minimum.minecraft.velocity.protocol.MinecraftPacket;
|
import io.minimum.minecraft.velocity.protocol.MinecraftPacket;
|
||||||
import io.minimum.minecraft.velocity.protocol.StateRegistry;
|
|
||||||
import io.minimum.minecraft.velocity.protocol.packets.ServerLogin;
|
import io.minimum.minecraft.velocity.protocol.packets.ServerLogin;
|
||||||
import io.minimum.minecraft.velocity.protocol.packets.ServerLoginSuccess;
|
import io.minimum.minecraft.velocity.protocol.packets.ServerLoginSuccess;
|
||||||
import io.minimum.minecraft.velocity.proxy.*;
|
import io.minimum.minecraft.velocity.proxy.*;
|
||||||
@ -30,13 +29,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
|||||||
success.setUuid(generateOfflinePlayerUuid(username));
|
success.setUuid(generateOfflinePlayerUuid(username));
|
||||||
connection.write(success);
|
connection.write(success);
|
||||||
|
|
||||||
connection.setStatus(StateRegistry.PLAY);
|
connection.initiatePlay(success);
|
||||||
|
|
||||||
ConnectedPlayer player = new ConnectedPlayer(username, generateOfflinePlayerUuid(username), connection);
|
|
||||||
|
|
||||||
ServerInfo info = new ServerInfo("test", new InetSocketAddress("127.0.0.1", 25565));
|
|
||||||
ServerConnection connection = new ServerConnection(info, player, VelocityServer.getServer());
|
|
||||||
connection.connect();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static UUID generateOfflinePlayerUuid(String username) {
|
private static UUID generateOfflinePlayerUuid(String username) {
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren