Mirror von
https://github.com/PaperMC/Velocity.git
synchronisiert 2024-11-16 21:10:30 +01:00
Progress towards a server connection pipeline.
Dieser Commit ist enthalten in:
Ursprung
0515a5d86f
Commit
9e397b10b5
@ -1,34 +1,15 @@
|
|||||||
package io.minimum.minecraft.velocity;
|
package io.minimum.minecraft.velocity;
|
||||||
|
|
||||||
import io.minimum.minecraft.velocity.protocol.ProtocolConstants;
|
import io.minimum.minecraft.velocity.proxy.VelocityServer;
|
||||||
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;
|
|
||||||
|
|
||||||
public class Velocity {
|
public class Velocity {
|
||||||
public static void main(String... args) throws InterruptedException {
|
public static void main(String... args) throws InterruptedException {
|
||||||
new ServerBootstrap()
|
VelocityServer server = new VelocityServer();
|
||||||
.channel(NioServerSocketChannel.class)
|
server.initialize();
|
||||||
.group(new NioEventLoopGroup())
|
|
||||||
.childHandler(new ChannelInitializer<Channel>() {
|
while (true) {
|
||||||
@Override
|
// temporary until jline is added.
|
||||||
protected void initChannel(Channel ch) throws Exception {
|
Thread.sleep(999999);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,10 @@ public enum StateRegistry {
|
|||||||
LOGIN {
|
LOGIN {
|
||||||
{
|
{
|
||||||
TO_SERVER.register(0x00, ServerLogin.class, ServerLogin::new);
|
TO_SERVER.register(0x00, ServerLogin.class, ServerLogin::new);
|
||||||
|
|
||||||
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
|
||||||
|
TO_CLIENT.register(0x02, ServerLoginSuccess.class, ServerLogin::new);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2,16 +2,23 @@ package io.minimum.minecraft.velocity.protocol.netty;
|
|||||||
|
|
||||||
import com.google.common.base.Joiner;
|
import com.google.common.base.Joiner;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import io.minimum.minecraft.velocity.protocol.packets.LegacyPing;
|
||||||
import io.minimum.minecraft.velocity.protocol.packets.LegacyPingResponse;
|
import io.minimum.minecraft.velocity.protocol.packets.LegacyPingResponse;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.ByteBufUtil;
|
import io.netty.buffer.ByteBufUtil;
|
||||||
|
import io.netty.channel.ChannelHandler;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.MessageToByteEncoder;
|
import io.netty.handler.codec.MessageToByteEncoder;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ChannelHandler.Sharable
|
||||||
public class LegacyPingEncoder extends MessageToByteEncoder<LegacyPingResponse> {
|
public class LegacyPingEncoder extends MessageToByteEncoder<LegacyPingResponse> {
|
||||||
|
public static final LegacyPingEncoder INSTANCE = new LegacyPingEncoder();
|
||||||
|
|
||||||
|
private LegacyPingEncoder() {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void encode(ChannelHandlerContext ctx, LegacyPingResponse msg, ByteBuf out) throws Exception {
|
protected void encode(ChannelHandlerContext ctx, LegacyPingResponse msg, ByteBuf out) throws Exception {
|
||||||
out.writeByte(0xff);
|
out.writeByte(0xff);
|
||||||
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
@ -2,10 +2,16 @@ package io.minimum.minecraft.velocity.protocol.netty;
|
|||||||
|
|
||||||
import io.minimum.minecraft.velocity.protocol.ProtocolUtils;
|
import io.minimum.minecraft.velocity.protocol.ProtocolUtils;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.channel.ChannelHandler;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.MessageToByteEncoder;
|
import io.netty.handler.codec.MessageToByteEncoder;
|
||||||
|
|
||||||
|
@ChannelHandler.Sharable
|
||||||
public class MinecraftVarintLengthEncoder extends MessageToByteEncoder<ByteBuf> {
|
public class MinecraftVarintLengthEncoder extends MessageToByteEncoder<ByteBuf> {
|
||||||
|
public static final MinecraftVarintLengthEncoder INSTANCE = new MinecraftVarintLengthEncoder();
|
||||||
|
|
||||||
|
private MinecraftVarintLengthEncoder() { }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception {
|
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception {
|
||||||
ProtocolUtils.writeVarInt(out, msg.readableBytes());
|
ProtocolUtils.writeVarInt(out, msg.readableBytes());
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -66,10 +66,12 @@ public class InboundMinecraftConnection {
|
|||||||
this.setStatus(StateRegistry.STATUS);
|
this.setStatus(StateRegistry.STATUS);
|
||||||
this.sessionHandler = new StatusSessionHandler(this);
|
this.sessionHandler = new StatusSessionHandler(this);
|
||||||
break;
|
break;
|
||||||
default:
|
case 2:
|
||||||
this.setStatus(StateRegistry.LOGIN);
|
this.setStatus(StateRegistry.LOGIN);
|
||||||
this.sessionHandler = new LoginSessionHandler(this);
|
this.sessionHandler = new LoginSessionHandler(this);
|
||||||
break;
|
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(MinecraftEncoder.class).setState(state);
|
||||||
channel.pipeline().get(MinecraftDecoder.class).setState(state);
|
channel.pipeline().get(MinecraftDecoder.class).setState(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void teardown() {
|
||||||
|
closed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
@Override
|
||||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||||
cause.printStackTrace();
|
cause.printStackTrace();
|
||||||
|
@ -9,4 +9,8 @@ public interface MinecraftSessionHandler {
|
|||||||
default void handleUnknown(ByteBuf buf) {
|
default void handleUnknown(ByteBuf buf) {
|
||||||
// No-op: we'll release the buffer later.
|
// No-op: we'll release the buffer later.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default void connectionClosed() {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -2,12 +2,13 @@ package io.minimum.minecraft.velocity.proxy.handler;
|
|||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import io.minimum.minecraft.velocity.protocol.MinecraftPacket;
|
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.ServerLogin;
|
||||||
|
import io.minimum.minecraft.velocity.protocol.packets.ServerLoginSuccess;
|
||||||
import io.minimum.minecraft.velocity.proxy.InboundMinecraftConnection;
|
import io.minimum.minecraft.velocity.proxy.InboundMinecraftConnection;
|
||||||
import io.minimum.minecraft.velocity.proxy.MinecraftSessionHandler;
|
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 {
|
public class LoginSessionHandler implements MinecraftSessionHandler {
|
||||||
private final InboundMinecraftConnection connection;
|
private final InboundMinecraftConnection connection;
|
||||||
@ -20,9 +21,15 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
|||||||
public void handle(MinecraftPacket packet) {
|
public void handle(MinecraftPacket packet) {
|
||||||
Preconditions.checkArgument(packet instanceof ServerLogin, "Expected a ServerLogin packet, not " + packet.getClass().getName());
|
Preconditions.checkArgument(packet instanceof ServerLogin, "Expected a ServerLogin packet, not " + packet.getClass().getName());
|
||||||
|
|
||||||
// Disconnect with test message
|
String username = ((ServerLogin) packet).getUsername();
|
||||||
Disconnect disconnect = new Disconnect();
|
ServerLoginSuccess success = new ServerLoginSuccess();
|
||||||
disconnect.setReason(ComponentSerializers.JSON.serialize(TextComponent.of("Hi there!")));
|
success.setUsername(username);
|
||||||
connection.closeWith(disconnect);
|
success.setUuid(generateOfflinePlayerUuid(username));
|
||||||
|
|
||||||
|
connection.write(success);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static UUID generateOfflinePlayerUuid(String username) {
|
||||||
|
return UUID.nameUUIDFromBytes(username.getBytes(StandardCharsets.UTF_8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren