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

Progress towards a server connection pipeline.

Dieser Commit ist enthalten in:
Andrew Steinborn 2018-07-24 17:58:20 -04:00
Ursprung 0515a5d86f
Commit 9e397b10b5
14 geänderte Dateien mit 243 neuen und 35 gelöschten Zeilen

Datei anzeigen

@ -1,34 +1,15 @@
package io.minimum.minecraft.velocity;
import io.minimum.minecraft.velocity.protocol.ProtocolConstants;
import io.minimum.minecraft.velocity.protocol.netty.*;
import io.minimum.minecraft.velocity.proxy.InboundMinecraftConnection;
import io.minimum.minecraft.velocity.proxy.MinecraftClientSessionHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.minimum.minecraft.velocity.proxy.VelocityServer;
public class Velocity {
public static void main(String... args) throws InterruptedException {
new ServerBootstrap()
.channel(NioServerSocketChannel.class)
.group(new NioEventLoopGroup())
.childHandler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.attr(InboundMinecraftConnection.CONNECTION).set(new InboundMinecraftConnection(ch));
ch.pipeline().addLast("legacy-ping-decode", new LegacyPingDecoder());
ch.pipeline().addLast("frame-decoder", new MinecraftVarintFrameDecoder());
ch.pipeline().addLast("legacy-ping-encode", new LegacyPingEncoder());
ch.pipeline().addLast("frame-encoder", new MinecraftVarintLengthEncoder());
ch.pipeline().addLast("minecraft-decoder", new MinecraftDecoder(ProtocolConstants.Direction.TO_SERVER));
ch.pipeline().addLast("minecraft-encoder", new MinecraftEncoder(ProtocolConstants.Direction.TO_CLIENT));
ch.pipeline().addLast("handler", new MinecraftClientSessionHandler());
}
})
.bind(26671)
.await();
VelocityServer server = new VelocityServer();
server.initialize();
while (true) {
// temporary until jline is added.
Thread.sleep(999999);
}
}
}

Datei anzeigen

@ -27,7 +27,10 @@ public enum StateRegistry {
LOGIN {
{
TO_SERVER.register(0x00, ServerLogin.class, ServerLogin::new);
TO_CLIENT.register(0x00, Disconnect.class, Disconnect::new);
// Encryption Success will follow once Mojang auth/encryption is done
TO_CLIENT.register(0x02, ServerLoginSuccess.class, ServerLogin::new);
}
};

Datei anzeigen

@ -2,16 +2,23 @@ package io.minimum.minecraft.velocity.protocol.netty;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import io.minimum.minecraft.velocity.protocol.packets.LegacyPing;
import io.minimum.minecraft.velocity.protocol.packets.LegacyPingResponse;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
@ChannelHandler.Sharable
public class LegacyPingEncoder extends MessageToByteEncoder<LegacyPingResponse> {
public static final LegacyPingEncoder INSTANCE = new LegacyPingEncoder();
private LegacyPingEncoder() {}
@Override
protected void encode(ChannelHandlerContext ctx, LegacyPingResponse msg, ByteBuf out) throws Exception {
out.writeByte(0xff);

Datei anzeigen

@ -0,0 +1,15 @@
package io.minimum.minecraft.velocity.protocol.netty;
import io.minimum.minecraft.velocity.protocol.ProtocolConstants;
import io.netty.channel.Channel;
public class MinecraftPipelineUtils {
public static void strapPipeline(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_SERVER));
ch.pipeline().addLast("minecraft-encoder", new MinecraftEncoder(ProtocolConstants.Direction.TO_CLIENT));
}
}

Datei anzeigen

@ -2,10 +2,16 @@ package io.minimum.minecraft.velocity.protocol.netty;
import io.minimum.minecraft.velocity.protocol.ProtocolUtils;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
@ChannelHandler.Sharable
public class MinecraftVarintLengthEncoder extends MessageToByteEncoder<ByteBuf> {
public static final MinecraftVarintLengthEncoder INSTANCE = new MinecraftVarintLengthEncoder();
private MinecraftVarintLengthEncoder() { }
@Override
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception {
ProtocolUtils.writeVarInt(out, msg.readableBytes());

Datei anzeigen

@ -0,0 +1,49 @@
package io.minimum.minecraft.velocity.protocol.packets;
import io.minimum.minecraft.velocity.protocol.MinecraftPacket;
import io.minimum.minecraft.velocity.protocol.ProtocolConstants;
import io.minimum.minecraft.velocity.protocol.ProtocolUtils;
import io.netty.buffer.ByteBuf;
import java.util.UUID;
public class ServerLoginSuccess implements MinecraftPacket {
private UUID uuid;
private String username;
public UUID getUuid() {
return uuid;
}
public void setUuid(UUID uuid) {
this.uuid = uuid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public String toString() {
return "ServerLoginSuccess{" +
"uuid=" + uuid +
", username='" + username + '\'' +
'}';
}
@Override
public void decode(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) {
uuid = UUID.fromString(ProtocolUtils.readString(buf, 36));
username = ProtocolUtils.readString(buf, 16);
}
@Override
public void encode(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) {
ProtocolUtils.writeString(buf, uuid.toString());
ProtocolUtils.writeString(buf, username);
}
}

Datei anzeigen

@ -0,0 +1,34 @@
package io.minimum.minecraft.velocity.proxy;
import io.minimum.minecraft.velocity.proxy.server.ServerConnection;
import java.util.UUID;
public class ConnectedPlayer {
private final String username;
private final UUID uniqueId;
private final InboundMinecraftConnection connection;
private ServerConnection connectedServer;
public ConnectedPlayer(String username, UUID uniqueId, InboundMinecraftConnection connection) {
this.username = username;
this.uniqueId = uniqueId;
this.connection = connection;
}
public String getUsername() {
return username;
}
public UUID getUniqueId() {
return uniqueId;
}
public InboundMinecraftConnection getConnection() {
return connection;
}
public ServerConnection getConnectedServer() {
return connectedServer;
}
}

Datei anzeigen

@ -66,10 +66,12 @@ public class InboundMinecraftConnection {
this.setStatus(StateRegistry.STATUS);
this.sessionHandler = new StatusSessionHandler(this);
break;
default:
case 2:
this.setStatus(StateRegistry.LOGIN);
this.sessionHandler = new LoginSessionHandler(this);
break;
default:
throw new IllegalArgumentException("Invalid state " + handshake.getNextStatus());
}
}
@ -83,4 +85,8 @@ public class InboundMinecraftConnection {
channel.pipeline().get(MinecraftEncoder.class).setState(state);
channel.pipeline().get(MinecraftDecoder.class).setState(state);
}
public void teardown() {
closed = true;
}
}

Datei anzeigen

@ -52,6 +52,12 @@ public class MinecraftClientSessionHandler extends ChannelInboundHandlerAdapter
}
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
InboundMinecraftConnection connection = ctx.channel().attr(InboundMinecraftConnection.CONNECTION).get();
connection.teardown();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();

Datei anzeigen

@ -9,4 +9,8 @@ public interface MinecraftSessionHandler {
default void handleUnknown(ByteBuf buf) {
// No-op: we'll release the buffer later.
}
default void connectionClosed() {
}
}

Datei anzeigen

@ -0,0 +1,54 @@
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.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
public class VelocityServer {
private EventLoopGroup bossGroup;
private EventLoopGroup childGroup;
public VelocityServer() {
}
public void initialize() {
bossGroup = new NioEventLoopGroup();
childGroup = new NioEventLoopGroup();
new ServerBootstrap()
.channel(NioServerSocketChannel.class)
.group(bossGroup, childGroup)
.childHandler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.attr(InboundMinecraftConnection.CONNECTION).set(new InboundMinecraftConnection(ch));
MinecraftPipelineUtils.strapPipeline(ch);
ch.pipeline().addLast("handler", new MinecraftClientSessionHandler());
}
})
.bind(26671)
.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
System.out.println("Listening on " + future.channel().localAddress());
} else {
System.out.println("Can't bind to " + future.channel().localAddress());
future.cause().printStackTrace();
}
}
});
}
Bootstrap initializeGenericBootstrap() {
return new Bootstrap()
.channel(NioSocketChannel.class)
.group(childGroup);
}
}

Datei anzeigen

@ -2,12 +2,13 @@ package io.minimum.minecraft.velocity.proxy.handler;
import com.google.common.base.Preconditions;
import io.minimum.minecraft.velocity.protocol.MinecraftPacket;
import io.minimum.minecraft.velocity.protocol.packets.Disconnect;
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 net.kyori.text.TextComponent;
import net.kyori.text.serializer.ComponentSerializers;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
public class LoginSessionHandler implements MinecraftSessionHandler {
private final InboundMinecraftConnection connection;
@ -20,9 +21,15 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
public void handle(MinecraftPacket packet) {
Preconditions.checkArgument(packet instanceof ServerLogin, "Expected a ServerLogin packet, not " + packet.getClass().getName());
// Disconnect with test message
Disconnect disconnect = new Disconnect();
disconnect.setReason(ComponentSerializers.JSON.serialize(TextComponent.of("Hi there!")));
connection.closeWith(disconnect);
String username = ((ServerLogin) packet).getUsername();
ServerLoginSuccess success = new ServerLoginSuccess();
success.setUsername(username);
success.setUuid(generateOfflinePlayerUuid(username));
connection.write(success);
}
private static UUID generateOfflinePlayerUuid(String username) {
return UUID.nameUUIDFromBytes(username.getBytes(StandardCharsets.UTF_8));
}
}

Datei anzeigen

@ -0,0 +1,17 @@
package io.minimum.minecraft.velocity.proxy.handler;
import io.minimum.minecraft.velocity.protocol.MinecraftPacket;
import io.minimum.minecraft.velocity.proxy.MinecraftSessionHandler;
import io.netty.buffer.ByteBuf;
public class PlaySessionHandler implements MinecraftSessionHandler {
@Override
public void handle(MinecraftPacket packet) {
}
@Override
public void handleUnknown(ByteBuf buf) {
}
}

Datei anzeigen

@ -0,0 +1,19 @@
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;
}
}