Mirror von
https://github.com/PaperMC/Velocity.git
synchronisiert 2024-11-16 21:10:30 +01:00
Refactored connection handling
Dieser Commit ist enthalten in:
Ursprung
1ab926b572
Commit
286be4987a
@ -2,6 +2,7 @@ package io.minimum.minecraft.velocity;
|
|||||||
|
|
||||||
import io.minimum.minecraft.velocity.protocol.ProtocolConstants;
|
import io.minimum.minecraft.velocity.protocol.ProtocolConstants;
|
||||||
import io.minimum.minecraft.velocity.protocol.netty.*;
|
import io.minimum.minecraft.velocity.protocol.netty.*;
|
||||||
|
import io.minimum.minecraft.velocity.proxy.InboundMinecraftConnection;
|
||||||
import io.minimum.minecraft.velocity.proxy.MinecraftClientSessionHandler;
|
import io.minimum.minecraft.velocity.proxy.MinecraftClientSessionHandler;
|
||||||
import io.netty.bootstrap.ServerBootstrap;
|
import io.netty.bootstrap.ServerBootstrap;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
@ -17,6 +18,7 @@ public class Velocity {
|
|||||||
.childHandler(new ChannelInitializer<Channel>() {
|
.childHandler(new ChannelInitializer<Channel>() {
|
||||||
@Override
|
@Override
|
||||||
protected void initChannel(Channel ch) throws Exception {
|
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("legacy-ping-decode", new LegacyPingDecoder());
|
||||||
ch.pipeline().addLast("frame-decoder", new MinecraftVarintFrameDecoder());
|
ch.pipeline().addLast("frame-decoder", new MinecraftVarintFrameDecoder());
|
||||||
ch.pipeline().addLast("legacy-ping-encode", new LegacyPingEncoder());
|
ch.pipeline().addLast("legacy-ping-encode", new LegacyPingEncoder());
|
||||||
|
@ -0,0 +1,83 @@
|
|||||||
|
package io.minimum.minecraft.velocity.proxy;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import io.minimum.minecraft.velocity.protocol.StateRegistry;
|
||||||
|
import io.minimum.minecraft.velocity.protocol.netty.MinecraftDecoder;
|
||||||
|
import io.minimum.minecraft.velocity.protocol.netty.MinecraftEncoder;
|
||||||
|
import io.minimum.minecraft.velocity.protocol.packets.Handshake;
|
||||||
|
import io.minimum.minecraft.velocity.proxy.handler.HandshakeSessionHandler;
|
||||||
|
import io.minimum.minecraft.velocity.proxy.handler.StatusSessionHandler;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.ChannelFuture;
|
||||||
|
import io.netty.channel.ChannelFutureListener;
|
||||||
|
import io.netty.util.AttributeKey;
|
||||||
|
|
||||||
|
public class InboundMinecraftConnection {
|
||||||
|
public static final AttributeKey<InboundMinecraftConnection> CONNECTION = AttributeKey.newInstance("velocity-connection");
|
||||||
|
|
||||||
|
private final Channel channel;
|
||||||
|
private boolean closed;
|
||||||
|
private Handshake handshake;
|
||||||
|
private StateRegistry state;
|
||||||
|
private MinecraftSessionHandler sessionHandler;
|
||||||
|
|
||||||
|
public InboundMinecraftConnection(Channel channel) {
|
||||||
|
this.channel = channel;
|
||||||
|
this.closed = false;
|
||||||
|
this.state = StateRegistry.HANDSHAKE;
|
||||||
|
this.sessionHandler = new HandshakeSessionHandler(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write(Object msg) {
|
||||||
|
ensureOpen();
|
||||||
|
channel.writeAndFlush(msg, channel.voidPromise());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void closeWith(Object msg) {
|
||||||
|
ensureOpen();
|
||||||
|
closed = true;
|
||||||
|
channel.writeAndFlush(msg).addListener(new ChannelFutureListener() {
|
||||||
|
@Override
|
||||||
|
public void operationComplete(ChannelFuture future) throws Exception {
|
||||||
|
future.channel().close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
ensureOpen();
|
||||||
|
channel.close();
|
||||||
|
closed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MinecraftSessionHandler getSessionHandler() {
|
||||||
|
return sessionHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleHandshake(Handshake handshake) {
|
||||||
|
ensureOpen();
|
||||||
|
Preconditions.checkNotNull(handshake, "handshake");
|
||||||
|
Preconditions.checkState(this.handshake == null, "Already handled a handshake for this connection!");
|
||||||
|
this.handshake = handshake;
|
||||||
|
switch (handshake.getNextStatus()) {
|
||||||
|
case 1:
|
||||||
|
// Status protocol
|
||||||
|
this.setStatus(StateRegistry.STATUS);
|
||||||
|
this.sessionHandler = new StatusSessionHandler(this);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new UnsupportedOperationException("Unsupported next protocol state " + handshake.getNextStatus());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureOpen() {
|
||||||
|
Preconditions.checkState(!closed, "Connection is closed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setStatus(StateRegistry state) {
|
||||||
|
Preconditions.checkNotNull(state, "state");
|
||||||
|
this.state = state;
|
||||||
|
channel.pipeline().get(MinecraftEncoder.class).setState(state);
|
||||||
|
channel.pipeline().get(MinecraftDecoder.class).setState(state);
|
||||||
|
}
|
||||||
|
}
|
@ -24,15 +24,22 @@ public class MinecraftClientSessionHandler extends ChannelInboundHandlerAdapter
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||||
|
InboundMinecraftConnection connection = ctx.channel().attr(InboundMinecraftConnection.CONNECTION).get();
|
||||||
if (msg instanceof PacketWrapper) {
|
if (msg instanceof PacketWrapper) {
|
||||||
|
PacketWrapper pw = (PacketWrapper) msg;
|
||||||
try {
|
try {
|
||||||
handle(ctx, (PacketWrapper) msg);
|
if (pw.getPacket() == null) {
|
||||||
|
connection.getSessionHandler().handleUnknown(pw.getBuffer());
|
||||||
|
} else {
|
||||||
|
connection.getSessionHandler().handle(pw.getPacket());
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
((PacketWrapper) msg).getBuffer().release();
|
((PacketWrapper) msg).getBuffer().release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg instanceof LegacyPing) {
|
if (msg instanceof LegacyPing) {
|
||||||
|
// TODO: port this
|
||||||
System.out.println("Got LEGACY status request!");
|
System.out.println("Got LEGACY status request!");
|
||||||
ServerPing ping = new ServerPing(
|
ServerPing ping = new ServerPing(
|
||||||
new ServerPing.Version(340, "1.12"),
|
new ServerPing.Version(340, "1.12"),
|
||||||
@ -50,44 +57,4 @@ public class MinecraftClientSessionHandler extends ChannelInboundHandlerAdapter
|
|||||||
cause.printStackTrace();
|
cause.printStackTrace();
|
||||||
ctx.close();
|
ctx.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handle(ChannelHandlerContext ctx, PacketWrapper msg) {
|
|
||||||
MinecraftPacket packet = msg.getPacket();
|
|
||||||
if (packet == null) {
|
|
||||||
System.out.println("no packet!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (packet instanceof Handshake) {
|
|
||||||
System.out.println("Handshake: " + packet);
|
|
||||||
switch (((Handshake) packet).getNextStatus()) {
|
|
||||||
case 1:
|
|
||||||
// status
|
|
||||||
ctx.pipeline().get(MinecraftDecoder.class).setState(StateRegistry.STATUS);
|
|
||||||
ctx.pipeline().get(MinecraftEncoder.class).setState(StateRegistry.STATUS);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
// login
|
|
||||||
throw new UnsupportedOperationException("Login not supported yet");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (packet instanceof StatusRequest) {
|
|
||||||
System.out.println("Got status request!");
|
|
||||||
ServerPing ping = new ServerPing(
|
|
||||||
new ServerPing.Version(340, "1.12.2"),
|
|
||||||
new ServerPing.Players(0, 0),
|
|
||||||
TextComponent.of("test"),
|
|
||||||
null
|
|
||||||
);
|
|
||||||
StatusResponse response = new StatusResponse();
|
|
||||||
response.setStatus(GSON.toJson(ping));
|
|
||||||
ctx.writeAndFlush(response, ctx.voidPromise());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (packet instanceof Ping) {
|
|
||||||
System.out.println("Ping: " + packet);
|
|
||||||
ctx.writeAndFlush(packet).addListener(ChannelFutureListener.CLOSE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
package io.minimum.minecraft.velocity.proxy;
|
||||||
|
|
||||||
|
import io.minimum.minecraft.velocity.protocol.MinecraftPacket;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
|
public interface MinecraftSessionHandler {
|
||||||
|
void handle(MinecraftPacket packet);
|
||||||
|
|
||||||
|
default void handleUnknown(ByteBuf buf) {
|
||||||
|
// No-op: we'll release the buffer later.
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
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.Handshake;
|
||||||
|
import io.minimum.minecraft.velocity.proxy.InboundMinecraftConnection;
|
||||||
|
import io.minimum.minecraft.velocity.proxy.MinecraftSessionHandler;
|
||||||
|
|
||||||
|
public class HandshakeSessionHandler implements MinecraftSessionHandler {
|
||||||
|
private final InboundMinecraftConnection connection;
|
||||||
|
|
||||||
|
public HandshakeSessionHandler(InboundMinecraftConnection connection) {
|
||||||
|
this.connection = Preconditions.checkNotNull(connection, "connection");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(MinecraftPacket packet) {
|
||||||
|
if (!(packet instanceof Handshake)) {
|
||||||
|
throw new IllegalArgumentException("Did not expect packet " + packet.getClass().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
Handshake handshake = (Handshake) packet;
|
||||||
|
connection.handleHandshake(handshake);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
package io.minimum.minecraft.velocity.proxy.handler;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import io.minimum.minecraft.velocity.data.ServerPing;
|
||||||
|
import io.minimum.minecraft.velocity.protocol.MinecraftPacket;
|
||||||
|
import io.minimum.minecraft.velocity.protocol.packets.LegacyPing;
|
||||||
|
import io.minimum.minecraft.velocity.protocol.packets.Ping;
|
||||||
|
import io.minimum.minecraft.velocity.protocol.packets.StatusRequest;
|
||||||
|
import io.minimum.minecraft.velocity.protocol.packets.StatusResponse;
|
||||||
|
import io.minimum.minecraft.velocity.proxy.InboundMinecraftConnection;
|
||||||
|
import io.minimum.minecraft.velocity.proxy.MinecraftSessionHandler;
|
||||||
|
import net.kyori.text.Component;
|
||||||
|
import net.kyori.text.TextComponent;
|
||||||
|
import net.kyori.text.serializer.GsonComponentSerializer;
|
||||||
|
|
||||||
|
public class StatusSessionHandler implements MinecraftSessionHandler {
|
||||||
|
private static final Gson GSON = new GsonBuilder()
|
||||||
|
.registerTypeHierarchyAdapter(Component.class, new GsonComponentSerializer())
|
||||||
|
.create();
|
||||||
|
private final InboundMinecraftConnection connection;
|
||||||
|
|
||||||
|
public StatusSessionHandler(InboundMinecraftConnection connection) {
|
||||||
|
this.connection = connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(MinecraftPacket packet) {
|
||||||
|
Preconditions.checkArgument(packet instanceof Ping || packet instanceof StatusRequest,
|
||||||
|
"Unrecognized packet type " + packet.getClass().getName());
|
||||||
|
|
||||||
|
if (packet instanceof Ping) {
|
||||||
|
// Just send back the client's packet, no processing to do here.
|
||||||
|
connection.closeWith(packet);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status request
|
||||||
|
System.out.println("Got status request!");
|
||||||
|
ServerPing ping = new ServerPing(
|
||||||
|
new ServerPing.Version(340, "1.12.2"),
|
||||||
|
new ServerPing.Players(0, 0),
|
||||||
|
TextComponent.of("test"),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
StatusResponse response = new StatusResponse();
|
||||||
|
response.setStatus(GSON.toJson(ping));
|
||||||
|
connection.write(response);
|
||||||
|
}
|
||||||
|
}
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren