3
0
Mirror von https://github.com/PaperMC/Velocity.git synchronisiert 2024-12-24 15:20:35 +01:00

Initial client connection pipeline, this isn't done yet.

Dieser Commit ist enthalten in:
Andrew Steinborn 2018-07-24 20:11:37 -04:00
Ursprung 6c0ab73a91
Commit 7867c496ec
12 geänderte Dateien mit 225 neuen und 33 gelöschten Zeilen

Datei anzeigen

@ -0,0 +1,44 @@
package io.minimum.minecraft.velocity.data;
import java.net.InetSocketAddress;
import java.util.Objects;
public class ServerInfo {
private final String name;
private final InetSocketAddress address;
public ServerInfo(String name, InetSocketAddress address) {
this.name = name;
this.address = address;
}
public String getName() {
return name;
}
public InetSocketAddress getAddress() {
return address;
}
@Override
public String toString() {
return "ServerInfo{" +
"name='" + name + '\'' +
", address=" + address +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ServerInfo that = (ServerInfo) o;
return Objects.equals(name, that.name) &&
Objects.equals(address, that.address);
}
@Override
public int hashCode() {
return Objects.hash(name, address);
}
}

Datei anzeigen

@ -22,7 +22,9 @@ public enum StateRegistry {
}
},
PLAY {
{
TO_CLIENT.register(0x1A, Disconnect.class, Disconnect::new);
}
},
LOGIN {
{

Datei anzeigen

@ -30,9 +30,7 @@ public class MinecraftDecoder extends MessageToMessageDecoder<ByteBuf> {
int packetId = ProtocolUtils.readVarInt(msg);
StateRegistry.ProtocolMappings mappings = direction == ProtocolConstants.Direction.TO_CLIENT ? state.TO_CLIENT : state.TO_SERVER;
MinecraftPacket packet = mappings.createPacket(packetId);
System.out.println("Decode!");
System.out.println("packet ID: " + packetId);
System.out.println("packet hexdump: " + ByteBufUtil.hexDump(slice));
System.out.println(direction + " <- " + ByteBufUtil.hexDump(slice));
if (packet == null) {
msg.skipBytes(msg.readableBytes());
out.add(new PacketWrapper(null, slice));

Datei anzeigen

@ -3,6 +3,7 @@ package io.minimum.minecraft.velocity.protocol.netty;
import com.google.common.base.Preconditions;
import io.minimum.minecraft.velocity.protocol.*;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
@ -22,6 +23,8 @@ public class MinecraftEncoder extends MessageToByteEncoder<MinecraftPacket> {
int packetId = mappings.getId(msg);
ProtocolUtils.writeVarInt(out, packetId);
msg.encode(out, direction, protocolVersion);
System.out.println(direction + " -> " + ByteBufUtil.hexDump(out));
}
public int getProtocolVersion() {

Datei anzeigen

@ -4,7 +4,7 @@ import io.minimum.minecraft.velocity.protocol.ProtocolConstants;
import io.netty.channel.Channel;
public class MinecraftPipelineUtils {
public static void strapPipeline(Channel ch) {
public static void strapPipelineForServer(Channel ch) {
ch.pipeline().addLast("legacy-ping-decode", new LegacyPingDecoder());
ch.pipeline().addLast("frame-decoder", new MinecraftVarintFrameDecoder());
ch.pipeline().addLast("legacy-ping-encode", LegacyPingEncoder.INSTANCE);
@ -12,4 +12,13 @@ public class MinecraftPipelineUtils {
ch.pipeline().addLast("minecraft-decoder", new MinecraftDecoder(ProtocolConstants.Direction.TO_SERVER));
ch.pipeline().addLast("minecraft-encoder", new MinecraftEncoder(ProtocolConstants.Direction.TO_CLIENT));
}
public static void strapPipelineForProxy(Channel ch) {
ch.pipeline().addLast("legacy-ping-decode", new LegacyPingDecoder());
ch.pipeline().addLast("frame-decoder", new MinecraftVarintFrameDecoder());
ch.pipeline().addLast("legacy-ping-encode", LegacyPingEncoder.INSTANCE);
ch.pipeline().addLast("frame-encoder", MinecraftVarintLengthEncoder.INSTANCE);
ch.pipeline().addLast("minecraft-decoder", new MinecraftDecoder(ProtocolConstants.Direction.TO_CLIENT));
ch.pipeline().addLast("minecraft-encoder", new MinecraftEncoder(ProtocolConstants.Direction.TO_SERVER));
}
}

Datei anzeigen

@ -21,7 +21,6 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder {
return;
}
System.out.println("Got a varint-prefixed packet length " + packetLength);
out.add(in.slice(in.readerIndex(), packetLength).retain());
in.skipBytes(packetLength);
}

Datei anzeigen

@ -1,6 +1,9 @@
package io.minimum.minecraft.velocity.proxy;
import io.minimum.minecraft.velocity.proxy.server.ServerConnection;
import io.minimum.minecraft.velocity.protocol.packets.Disconnect;
import net.kyori.text.TextComponent;
import net.kyori.text.format.TextColor;
import net.kyori.text.serializer.ComponentSerializers;
import java.util.UUID;
@ -31,4 +34,17 @@ public class ConnectedPlayer {
public ServerConnection getConnectedServer() {
return connectedServer;
}
public void handleConnectionException(Throwable throwable) {
String error = "Exception: " + throwable.getClass().getName() + ": " + throwable.getMessage();
if (connectedServer == null) {
// 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);
} else {
// TODO
}
}
}

Datei anzeigen

@ -13,6 +13,8 @@ import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.util.AttributeKey;
import java.util.Optional;
public class InboundMinecraftConnection {
public static final AttributeKey<InboundMinecraftConnection> CONNECTION = AttributeKey.newInstance("velocity-connection");
@ -21,6 +23,7 @@ public class InboundMinecraftConnection {
private Handshake handshake;
private StateRegistry state;
private MinecraftSessionHandler sessionHandler;
private ConnectedPlayer connectedPlayer;
public InboundMinecraftConnection(Channel channel) {
this.channel = channel;
@ -79,7 +82,7 @@ public class InboundMinecraftConnection {
Preconditions.checkState(!closed, "Connection is closed.");
}
private void setStatus(StateRegistry state) {
public void setStatus(StateRegistry state) {
Preconditions.checkNotNull(state, "state");
this.state = state;
channel.pipeline().get(MinecraftEncoder.class).setState(state);
@ -89,4 +92,12 @@ public class InboundMinecraftConnection {
public void teardown() {
closed = true;
}
public boolean isClosed() {
return closed;
}
public Optional<ConnectedPlayer> getConnectedPlayer() {
return Optional.ofNullable(connectedPlayer);
}
}

Datei anzeigen

@ -0,0 +1,114 @@
package io.minimum.minecraft.velocity.proxy;
import io.minimum.minecraft.velocity.protocol.MinecraftPacket;
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.data.ServerInfo;
import io.minimum.minecraft.velocity.protocol.netty.MinecraftDecoder;
import io.minimum.minecraft.velocity.protocol.netty.MinecraftEncoder;
import io.minimum.minecraft.velocity.protocol.netty.MinecraftPipelineUtils;
import io.minimum.minecraft.velocity.protocol.packets.Disconnect;
import io.minimum.minecraft.velocity.protocol.packets.Handshake;
import io.minimum.minecraft.velocity.protocol.packets.ServerLogin;
import io.minimum.minecraft.velocity.protocol.packets.ServerLoginSuccess;
import io.netty.channel.*;
import net.kyori.text.serializer.ComponentSerializers;
import java.io.IOException;
public class ServerConnection {
private Channel channel;
private final ServerInfo info;
private final ConnectedPlayer proxyPlayer;
private StateRegistry registry;
private final VelocityServer server;
public ServerConnection(ServerInfo target, ConnectedPlayer proxyPlayer, VelocityServer server) {
this.info = target;
this.proxyPlayer = proxyPlayer;
this.server = server;
this.registry = StateRegistry.HANDSHAKE;
}
public void connect() {
server.initializeGenericBootstrap()
.handler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
MinecraftPipelineUtils.strapPipelineForProxy(ch);
ch.pipeline().addLast("state-based-interceptor", new StateBasedInterceptor());
}
})
.connect(info.getAddress())
.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
channel = future.channel();
}
});
}
private class StateBasedInterceptor extends ChannelInboundHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// Initiate a handshake.
Handshake handshake = new Handshake();
handshake.setNextStatus(2); // login
handshake.setProtocolVersion(ProtocolConstants.MINECRAFT_1_12); // TODO: Expose client version
handshake.setServerAddress(info.getAddress().getHostString());
handshake.setPort(info.getAddress().getPort());
ctx.writeAndFlush(handshake, ctx.voidPromise());
setRegistry(StateRegistry.LOGIN);
// Login
ServerLogin login = new ServerLogin();
login.setUsername(proxyPlayer.getUsername());
ctx.writeAndFlush(login, ctx.voidPromise());
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof PacketWrapper) {
PacketWrapper pw = (PacketWrapper) msg;
try {
switch (registry) {
case LOGIN:
onLogin(ctx, pw);
break;
default:
throw new UnsupportedOperationException("Unsupported state " + registry);
}
} finally {
((PacketWrapper) msg).getBuffer().release();
}
}
}
private void onLogin(ChannelHandlerContext ctx, PacketWrapper wrapper) {
MinecraftPacket packet = wrapper.getPacket();
if (packet instanceof Disconnect) {
Disconnect disconnect = (Disconnect) packet;
ctx.close();
proxyPlayer.handleConnectionException(new IOException("Disconnected from target: " + jsonToPlain(disconnect.getReason())));
}
if (packet instanceof ServerLoginSuccess) {
System.out.println("got it");
}
}
}
private void setRegistry(StateRegistry registry) {
this.registry = registry;
this.channel.pipeline().get(MinecraftEncoder.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]", "");
}
}

Datei anzeigen

@ -1,8 +1,6 @@
package io.minimum.minecraft.velocity.proxy;
import io.minimum.minecraft.velocity.protocol.ProtocolConstants;
import io.minimum.minecraft.velocity.protocol.netty.*;
import io.minimum.minecraft.velocity.proxy.server.ServerConnection;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
@ -11,6 +9,8 @@ import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
public class VelocityServer {
private static VelocityServer server;
private EventLoopGroup bossGroup;
private EventLoopGroup childGroup;
@ -18,9 +18,14 @@ public class VelocityServer {
}
public static VelocityServer getServer() {
return server;
}
public void initialize() {
bossGroup = new NioEventLoopGroup();
childGroup = new NioEventLoopGroup();
server = this;
new ServerBootstrap()
.channel(NioServerSocketChannel.class)
.group(bossGroup, childGroup)
@ -28,7 +33,7 @@ public class VelocityServer {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.attr(InboundMinecraftConnection.CONNECTION).set(new InboundMinecraftConnection(ch));
MinecraftPipelineUtils.strapPipeline(ch);
MinecraftPipelineUtils.strapPipelineForServer(ch);
ch.pipeline().addLast("handler", new MinecraftClientSessionHandler());
}
})

Datei anzeigen

@ -1,12 +1,14 @@
package io.minimum.minecraft.velocity.proxy.handler;
import com.google.common.base.Preconditions;
import io.minimum.minecraft.velocity.data.ServerInfo;
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.ServerLoginSuccess;
import io.minimum.minecraft.velocity.proxy.InboundMinecraftConnection;
import io.minimum.minecraft.velocity.proxy.MinecraftSessionHandler;
import io.minimum.minecraft.velocity.proxy.*;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
@ -21,12 +23,20 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
public void handle(MinecraftPacket packet) {
Preconditions.checkArgument(packet instanceof ServerLogin, "Expected a ServerLogin packet, not " + packet.getClass().getName());
// TODO: Encryption and compression
String username = ((ServerLogin) packet).getUsername();
ServerLoginSuccess success = new ServerLoginSuccess();
success.setUsername(username);
success.setUuid(generateOfflinePlayerUuid(username));
connection.write(success);
connection.setStatus(StateRegistry.PLAY);
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) {

Datei anzeigen

@ -1,19 +0,0 @@
package io.minimum.minecraft.velocity.proxy.server;
import io.minimum.minecraft.velocity.protocol.StateRegistry;
import io.minimum.minecraft.velocity.proxy.ConnectedPlayer;
import io.netty.channel.Channel;
public class ServerConnection {
private final Channel remoteServer;
private final ConnectedPlayer proxyPlayer;
private StateRegistry registry;
public ServerConnection(Channel remoteServer, ConnectedPlayer proxyPlayer) {
this.remoteServer = remoteServer;
this.proxyPlayer = proxyPlayer;
this.registry = StateRegistry.HANDSHAKE;
}
}