From b2f517fa63c2439175ff58323ae38469b9a951df Mon Sep 17 00:00:00 2001 From: md_5 Date: Mon, 27 Jan 2014 11:26:27 +1100 Subject: [PATCH] Implement dual protocol version support. --- .../java/net/md_5/bungee/api/ProxyServer.java | 2 ++ .../md_5/bungee/protocol/DefinedPacket.java | 20 ++++++++++++++-- .../bungee/protocol/MinecraftDecoder.java | 5 ++-- .../bungee/protocol/MinecraftEncoder.java | 4 +++- .../net/md_5/bungee/protocol/Protocol.java | 5 ++-- .../net/md_5/bungee/protocol/packet/Chat.java | 23 +++++++++++++++---- .../protocol/packet/ClientSettings.java | 21 +++++++++++------ .../protocol/packet/ScoreboardScore.java | 21 +++++++++++++---- .../net/md_5/bungee/protocol/packet/Team.java | 22 ++++++++++++------ .../main/java/net/md_5/bungee/BungeeCord.java | 4 ++-- .../java/net/md_5/bungee/UserConnection.java | 4 ++-- .../bungee/connection/InitialHandler.java | 10 ++++---- .../md_5/bungee/connection/PingHandler.java | 7 +++--- .../net/md_5/bungee/netty/ChannelWrapper.java | 6 +++++ .../net/md_5/bungee/netty/PipelineUtils.java | 4 ++-- 15 files changed, 114 insertions(+), 44 deletions(-) diff --git a/api/src/main/java/net/md_5/bungee/api/ProxyServer.java b/api/src/main/java/net/md_5/bungee/api/ProxyServer.java index f2ef12d0..5a165b22 100644 --- a/api/src/main/java/net/md_5/bungee/api/ProxyServer.java +++ b/api/src/main/java/net/md_5/bungee/api/ProxyServer.java @@ -174,6 +174,7 @@ public abstract class ProxyServer * * @return the supported Minecraft version */ + @Deprecated public abstract String getGameVersion(); /** @@ -181,6 +182,7 @@ public abstract class ProxyServer * * @return the Minecraft protocol version */ + @Deprecated public abstract int getProtocolVersion(); /** diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/DefinedPacket.java b/protocol/src/main/java/net/md_5/bungee/protocol/DefinedPacket.java index bbb43a6d..2bb5068e 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/DefinedPacket.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/DefinedPacket.java @@ -114,9 +114,25 @@ public abstract class DefinedPacket } } - public abstract void read(ByteBuf buf); + public void read(ByteBuf buf) + { + throw new UnsupportedOperationException( "Packet must implement read method" ); + } - public abstract void write(ByteBuf buf); + public void read(ByteBuf buf, Protocol.ProtocolDirection direction, int protocolVersion) + { + read( buf ); + } + + public void write(ByteBuf buf) + { + throw new UnsupportedOperationException( "Packet must implement write method" ); + } + + public void write(ByteBuf buf, Protocol.ProtocolDirection direction, int protocolVersion) + { + write( buf ); + } public abstract void handle(AbstractPacketHandler handler) throws Exception; diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/MinecraftDecoder.java b/protocol/src/main/java/net/md_5/bungee/protocol/MinecraftDecoder.java index 7a222d66..8d8319a6 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/MinecraftDecoder.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/MinecraftDecoder.java @@ -1,6 +1,5 @@ package net.md_5.bungee.protocol; -import com.google.common.base.Charsets; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; @@ -15,6 +14,8 @@ public class MinecraftDecoder extends ByteToMessageDecoder @Setter private Protocol protocol; private boolean server; + @Setter + private int protocolVersion; @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception @@ -28,7 +29,7 @@ public class MinecraftDecoder extends ByteToMessageDecoder if ( prot.hasPacket( packetId ) ) { packet = prot.createPacket( packetId ); - packet.read( in ); + packet.read( in, prot, protocolVersion ); if ( in.readableBytes() != 0 ) { throw new BadPacketException( "Did not read all bytes from packet " + packet.getClass() + " " + packetId + " Protocol " + protocol + " Direction " + prot ); diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/MinecraftEncoder.java b/protocol/src/main/java/net/md_5/bungee/protocol/MinecraftEncoder.java index 28689b9f..0adccdc0 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/MinecraftEncoder.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/MinecraftEncoder.java @@ -13,12 +13,14 @@ public class MinecraftEncoder extends MessageToByteEncoder @Setter private Protocol protocol; private boolean server; + @Setter + private int protocolVersion; @Override protected void encode(ChannelHandlerContext ctx, DefinedPacket msg, ByteBuf out) throws Exception { Protocol.ProtocolDirection prot = ( server ) ? protocol.TO_CLIENT : protocol.TO_SERVER; DefinedPacket.writeVarInt( prot.getId( msg.getClass() ), out ); - msg.write( out ); + msg.write( out, prot, protocolVersion ); } } diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/Protocol.java b/protocol/src/main/java/net/md_5/bungee/protocol/Protocol.java index 282a7bf0..7769014b 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/Protocol.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/Protocol.java @@ -4,6 +4,8 @@ import com.google.common.base.Preconditions; import gnu.trove.map.TObjectIntMap; import gnu.trove.map.hash.TObjectIntHashMap; import java.lang.reflect.Constructor; +import java.util.Arrays; +import java.util.List; import lombok.RequiredArgsConstructor; import net.md_5.bungee.protocol.packet.Chat; import net.md_5.bungee.protocol.packet.ClientSettings; @@ -95,8 +97,7 @@ public enum Protocol }; /*========================================================================*/ public static final int MAX_PACKET_ID = 0xFF; - public static final int PROTOCOL_VERSION = 0x04; - public static final String MINECRAFT_VERSION = "1.7.2"; + public static List supportedVersions = Arrays.asList( 4, 8 ); /*========================================================================*/ public final ProtocolDirection TO_SERVER = new ProtocolDirection( "TO_SERVER" ); public final ProtocolDirection TO_CLIENT = new ProtocolDirection( "TO_CLIENT" ); diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/packet/Chat.java b/protocol/src/main/java/net/md_5/bungee/protocol/packet/Chat.java index 40e92d68..d4d8aefc 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/packet/Chat.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/packet/Chat.java @@ -7,6 +7,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import net.md_5.bungee.protocol.AbstractPacketHandler; +import net.md_5.bungee.protocol.Protocol; @Data @NoArgsConstructor @@ -16,17 +17,31 @@ public class Chat extends DefinedPacket { private String message; + private byte position; - @Override - public void read(ByteBuf buf) + public Chat(String message) { - message = readString( buf ); + this( message, (byte) 0 ); } @Override - public void write(ByteBuf buf) + public void read(ByteBuf buf, Protocol.ProtocolDirection direction, int protocolVersion) + { + message = readString( buf ); + if ( direction.toString().equals( "TO_CLIENT" ) && protocolVersion >= 5 ) + { + position = buf.readByte(); + } + } + + @Override + public void write(ByteBuf buf, Protocol.ProtocolDirection direction, int protocolVersion) { writeString( message, buf ); + if ( direction.toString().equals( "TO_CLIENT" ) && protocolVersion >= 5 ) + { + buf.writeByte( position ); + } } @Override diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/packet/ClientSettings.java b/protocol/src/main/java/net/md_5/bungee/protocol/packet/ClientSettings.java index e3078ba0..eb8c412c 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/packet/ClientSettings.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/packet/ClientSettings.java @@ -7,6 +7,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import net.md_5.bungee.protocol.AbstractPacketHandler; +import net.md_5.bungee.protocol.Protocol; @Data @NoArgsConstructor @@ -20,28 +21,34 @@ public class ClientSettings extends DefinedPacket private byte chatFlags; private boolean unknown; private byte difficulty; - private boolean showCape; + private byte showCape; @Override - public void read(ByteBuf buf) + public void read(ByteBuf buf, Protocol.ProtocolDirection direction, int protocolVersion) { locale = readString( buf ); viewDistance = buf.readByte(); chatFlags = buf.readByte(); unknown = buf.readBoolean(); - difficulty = buf.readByte(); - showCape = buf.readBoolean(); + if ( protocolVersion < 5 ) + { + difficulty = buf.readByte(); + } + showCape = buf.readByte(); } @Override - public void write(ByteBuf buf) + public void write(ByteBuf buf, Protocol.ProtocolDirection direction, int protocolVersion) { writeString( locale, buf ); buf.writeByte( viewDistance ); buf.writeByte( chatFlags ); buf.writeBoolean( unknown ); - buf.writeByte( difficulty ); - buf.writeBoolean( showCape ); + if ( protocolVersion < 5 ) + { + buf.writeByte( difficulty ); + } + buf.writeByte( showCape ); } @Override diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/packet/ScoreboardScore.java b/protocol/src/main/java/net/md_5/bungee/protocol/packet/ScoreboardScore.java index a14fd155..3d6ea97c 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/packet/ScoreboardScore.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/packet/ScoreboardScore.java @@ -7,6 +7,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import net.md_5.bungee.protocol.AbstractPacketHandler; +import net.md_5.bungee.protocol.Protocol; @Data @NoArgsConstructor @@ -24,26 +25,38 @@ public class ScoreboardScore extends DefinedPacket private int value; @Override - public void read(ByteBuf buf) + public void read(ByteBuf buf, Protocol.ProtocolDirection direction, int protocolVersion) { itemName = readString( buf ); action = buf.readByte(); if ( action != 1 ) { scoreName = readString( buf ); - value = buf.readInt(); + if ( protocolVersion >= 7 ) + { + value = readVarInt( buf ); + } else + { + value = buf.readInt(); + } } } @Override - public void write(ByteBuf buf) + public void write(ByteBuf buf, Protocol.ProtocolDirection direction, int protocolVersion) { writeString( itemName, buf ); buf.writeByte( action ); if ( action != 1 ) { writeString( scoreName, buf ); - buf.writeInt( value ); + if ( protocolVersion >= 7 ) + { + writeVarInt( value, buf ); + } else + { + buf.writeInt( value ); + } } } diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/packet/Team.java b/protocol/src/main/java/net/md_5/bungee/protocol/packet/Team.java index 2ecce118..91db8628 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/packet/Team.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/packet/Team.java @@ -7,6 +7,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import net.md_5.bungee.protocol.AbstractPacketHandler; +import net.md_5.bungee.protocol.Protocol; @Data @NoArgsConstructor @@ -40,7 +41,7 @@ public class Team extends DefinedPacket } @Override - public void read(ByteBuf buf) + public void read(ByteBuf buf, Protocol.ProtocolDirection direction, int protocolVersion) { name = readString( buf ); mode = buf.readByte(); @@ -53,8 +54,9 @@ public class Team extends DefinedPacket } if ( mode == 0 || mode == 3 || mode == 4 ) { - players = new String[ buf.readShort() ]; - for ( int i = 0; i < getPlayers().length; i++ ) + int len = ( protocolVersion >= 7 ) ? readVarInt( buf ) : buf.readInt(); + players = new String[ len ]; + for ( int i = 0; i < len; i++ ) { players[i] = readString( buf ); } @@ -62,7 +64,7 @@ public class Team extends DefinedPacket } @Override - public void write(ByteBuf buf) + public void write(ByteBuf buf, Protocol.ProtocolDirection direction, int protocolVersion) { writeString( name, buf ); buf.writeByte( mode ); @@ -75,10 +77,16 @@ public class Team extends DefinedPacket } if ( mode == 0 || mode == 3 || mode == 4 ) { - buf.writeShort( players.length ); - for ( int i = 0; i < players.length; i++ ) + if ( protocolVersion >= 7 ) { - writeString( players[i], buf ); + writeVarInt( players.length, buf ); + } else + { + buf.writeShort( players.length ); + } + for ( String player : players ) + { + writeString( player, buf ); } } } diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java index c13a3137..f038275a 100644 --- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java +++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java @@ -469,13 +469,13 @@ public class BungeeCord extends ProxyServer @Override public int getProtocolVersion() { - return Protocol.PROTOCOL_VERSION; + return Protocol.supportedVersions.get( Protocol.supportedVersions.size() - 1 ); } @Override public String getGameVersion() { - return Protocol.MINECRAFT_VERSION; + return "1.7.4"; } @Override diff --git a/proxy/src/main/java/net/md_5/bungee/UserConnection.java b/proxy/src/main/java/net/md_5/bungee/UserConnection.java index 3b1fccdb..59005d05 100644 --- a/proxy/src/main/java/net/md_5/bungee/UserConnection.java +++ b/proxy/src/main/java/net/md_5/bungee/UserConnection.java @@ -216,8 +216,8 @@ public final class UserConnection implements ProxiedPlayer protected void initChannel(Channel ch) throws Exception { PipelineUtils.BASE.initChannel( ch ); - ch.pipeline().addAfter( PipelineUtils.FRAME_DECODER, PipelineUtils.PACKET_DECODER, new MinecraftDecoder( Protocol.HANDSHAKE, false ) ); - ch.pipeline().addAfter( PipelineUtils.FRAME_PREPENDER, PipelineUtils.PACKET_ENCODER, new MinecraftEncoder( Protocol.HANDSHAKE, false ) ); + ch.pipeline().addAfter( PipelineUtils.FRAME_DECODER, PipelineUtils.PACKET_DECODER, new MinecraftDecoder( Protocol.HANDSHAKE, false, getPendingConnection().getVersion() ) ); + ch.pipeline().addAfter( PipelineUtils.FRAME_PREPENDER, PipelineUtils.PACKET_ENCODER, new MinecraftEncoder( Protocol.HANDSHAKE, false, getPendingConnection().getVersion() ) ); ch.pipeline().get( HandlerBoss.class ).setHandler( new ServerConnector( bungee, UserConnection.this, target ) ); } }; diff --git a/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java b/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java index 752f807a..dafd942c 100644 --- a/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java +++ b/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java @@ -175,8 +175,9 @@ public class InitialHandler extends PacketHandler implements PendingConnection forced.ping( pingBack ); } else { + int protocol = ( Protocol.supportedVersions.contains( handshake.getProtocolVersion() ) ) ? handshake.getProtocolVersion() : -1; pingBack.done( new ServerPing( - new ServerPing.Protocol( bungee.getGameVersion(), bungee.getProtocolVersion() ), + new ServerPing.Protocol( bungee.getGameVersion(), protocol ), new ServerPing.Players( listener.getMaxPlayers(), bungee.getOnlineCount(), null ), motd, BungeeCord.getInstance().config.favicon ), null ); @@ -198,6 +199,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection { Preconditions.checkState( thisState == State.HANDSHAKE, "Not expecting HANDSHAKE" ); this.handshake = handshake; + ch.setVersion( handshake.getProtocolVersion() ); // SRV records can end with a . depending on DNS / client. if ( handshake.getHost().endsWith( "." ) ) @@ -233,14 +235,10 @@ public class InitialHandler extends PacketHandler implements PendingConnection Preconditions.checkState( thisState == State.USERNAME, "Not expecting USERNAME" ); this.loginRequest = loginRequest; - if ( handshake.getProtocolVersion() > bungee.getProtocolVersion() ) + if ( !Protocol.supportedVersions.contains( handshake.getProtocolVersion() ) ) { disconnect( bungee.getTranslation( "outdated_server" ) ); return; - } else if ( handshake.getProtocolVersion() < bungee.getProtocolVersion() ) - { - disconnect( bungee.getTranslation( "outdated_client" ) ); - return; } if ( getName().length() > 16 ) diff --git a/proxy/src/main/java/net/md_5/bungee/connection/PingHandler.java b/proxy/src/main/java/net/md_5/bungee/connection/PingHandler.java index 5ca29c1d..50f7a414 100644 --- a/proxy/src/main/java/net/md_5/bungee/connection/PingHandler.java +++ b/proxy/src/main/java/net/md_5/bungee/connection/PingHandler.java @@ -3,6 +3,7 @@ package net.md_5.bungee.connection; import lombok.RequiredArgsConstructor; import net.md_5.bungee.BungeeCord; import net.md_5.bungee.api.Callback; +import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.ServerPing; import net.md_5.bungee.api.config.ServerInfo; import net.md_5.bungee.netty.ChannelWrapper; @@ -27,12 +28,12 @@ public class PingHandler extends PacketHandler public void connected(ChannelWrapper channel) throws Exception { this.channel = channel; - MinecraftEncoder encoder = new MinecraftEncoder( Protocol.HANDSHAKE, false ); + MinecraftEncoder encoder = new MinecraftEncoder( Protocol.HANDSHAKE, false, ProxyServer.getInstance().getProtocolVersion() ); - channel.getHandle().pipeline().addAfter( PipelineUtils.FRAME_DECODER, PipelineUtils.PACKET_DECODER, new MinecraftDecoder( Protocol.STATUS, false ) ); + channel.getHandle().pipeline().addAfter( PipelineUtils.FRAME_DECODER, PipelineUtils.PACKET_DECODER, new MinecraftDecoder( Protocol.STATUS, false, ProxyServer.getInstance().getProtocolVersion() ) ); channel.getHandle().pipeline().addAfter( PipelineUtils.FRAME_PREPENDER, PipelineUtils.PACKET_ENCODER, encoder ); - channel.write( new Handshake( Protocol.PROTOCOL_VERSION, target.getAddress().getHostString(), target.getAddress().getPort(), 1 ) ); + channel.write( new Handshake( ProxyServer.getInstance().getProtocolVersion(), target.getAddress().getHostString(), target.getAddress().getPort(), 1 ) ); encoder.setProtocol( Protocol.STATUS ); channel.write( new StatusRequest() ); diff --git a/proxy/src/main/java/net/md_5/bungee/netty/ChannelWrapper.java b/proxy/src/main/java/net/md_5/bungee/netty/ChannelWrapper.java index 77ecd687..93962e27 100644 --- a/proxy/src/main/java/net/md_5/bungee/netty/ChannelWrapper.java +++ b/proxy/src/main/java/net/md_5/bungee/netty/ChannelWrapper.java @@ -28,6 +28,12 @@ public class ChannelWrapper ch.pipeline().get( MinecraftEncoder.class ).setProtocol( protocol ); } + public void setVersion(int protocol) + { + ch.pipeline().get( MinecraftDecoder.class ).setProtocolVersion( protocol ); + ch.pipeline().get( MinecraftEncoder.class ).setProtocolVersion( protocol ); + } + public synchronized void write(Object packet) { if ( !closed ) diff --git a/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java b/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java index ef78cd00..24261072 100644 --- a/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java +++ b/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java @@ -43,8 +43,8 @@ public class PipelineUtils BASE.initChannel( ch ); ch.pipeline().addBefore( FRAME_DECODER, LEGACY_DECODER, new LegacyDecoder() ); - ch.pipeline().addAfter( FRAME_DECODER, PACKET_DECODER, new MinecraftDecoder( Protocol.HANDSHAKE, true ) ); - ch.pipeline().addAfter( FRAME_PREPENDER, PACKET_ENCODER, new MinecraftEncoder( Protocol.HANDSHAKE, true ) ); + ch.pipeline().addAfter( FRAME_DECODER, PACKET_DECODER, new MinecraftDecoder( Protocol.HANDSHAKE, true, ProxyServer.getInstance().getProtocolVersion() ) ); + ch.pipeline().addAfter( FRAME_PREPENDER, PACKET_ENCODER, new MinecraftEncoder( Protocol.HANDSHAKE, true, ProxyServer.getInstance().getProtocolVersion() ) ); ch.pipeline().addBefore( FRAME_PREPENDER, LEGACY_KICKER, new KickStringWriter() ); ch.pipeline().get( HandlerBoss.class ).setHandler( new InitialHandler( ProxyServer.getInstance(), ch.attr( LISTENER ).get() ) ); }