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;
|
||||
|
||||
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());
|
||||
VelocityServer server = new VelocityServer();
|
||||
server.initialize();
|
||||
|
||||
while (true) {
|
||||
// temporary until jline is added.
|
||||
Thread.sleep(999999);
|
||||
}
|
||||
})
|
||||
.bind(26671)
|
||||
.await();
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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.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());
|
||||
|
@ -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.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;
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -9,4 +9,8 @@ public interface MinecraftSessionHandler {
|
||||
default void handleUnknown(ByteBuf buf) {
|
||||
// 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 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));
|
||||
}
|
||||
}
|
||||
|
@ -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