diff --git a/api/src/main/java/net/md_5/bungee/api/connection/PendingConnection.java b/api/src/main/java/net/md_5/bungee/api/connection/PendingConnection.java index 98456e4b..edf570de 100644 --- a/api/src/main/java/net/md_5/bungee/api/connection/PendingConnection.java +++ b/api/src/main/java/net/md_5/bungee/api/connection/PendingConnection.java @@ -65,4 +65,12 @@ public interface PendingConnection extends Connection * Set this connection's online mode. */ void setOnlineMode(boolean onlineMode); + + /** + * Check if the client is using the older unsupported Minecraft protocol + * used by Minecraft clients older than 1.7. + * + * @return Whether the client is using a legacy client. + */ + boolean isLegacy(); } diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/LegacyDecoder.java b/protocol/src/main/java/net/md_5/bungee/protocol/LegacyDecoder.java index 1f19286a..334a8eab 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/LegacyDecoder.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/LegacyDecoder.java @@ -14,25 +14,26 @@ public class LegacyDecoder extends ByteToMessageDecoder @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { - if ( in.readableBytes() < 3 ) + if ( !in.isReadable() ) { return; } - int i = in.readerIndex(); - short b1 = in.getUnsignedByte( i++ ); - short b2 = in.getUnsignedByte( i++ ); - short b3 = in.getUnsignedByte( i++ ); - if ( b1 == 0xFE && b2 == 0x01 && b3 == 0xFA ) + in.markReaderIndex(); + short packetID = in.readUnsignedByte(); + + if ( packetID == 0xFE ) { - out.add( new PacketWrapper( new LegacyPing(), Unpooled.EMPTY_BUFFER ) ); + out.add( new PacketWrapper( new LegacyPing( in.isReadable() && in.readUnsignedByte() == 0x01 ), Unpooled.EMPTY_BUFFER ) ); return; - } - if ( b1 == 0x02 && b2 >= 60 && b2 <= 78 ) + } else if ( packetID == 0x02 && in.isReadable() ) { + in.skipBytes( in.readableBytes() ); out.add( new PacketWrapper( new LegacyHandshake(), Unpooled.EMPTY_BUFFER ) ); return; } + + in.resetReaderIndex(); ctx.pipeline().remove( this ); } } diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/packet/LegacyPing.java b/protocol/src/main/java/net/md_5/bungee/protocol/packet/LegacyPing.java index 2ead20af..76137e36 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/packet/LegacyPing.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/packet/LegacyPing.java @@ -1,11 +1,19 @@ package net.md_5.bungee.protocol.packet; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.RequiredArgsConstructor; + import io.netty.buffer.ByteBuf; import net.md_5.bungee.protocol.AbstractPacketHandler; import net.md_5.bungee.protocol.DefinedPacket; +@Data +@RequiredArgsConstructor +@EqualsAndHashCode(callSuper = false) public class LegacyPing extends DefinedPacket { + private final boolean v1_5; @Override public void read(ByteBuf buf) @@ -24,23 +32,4 @@ public class LegacyPing extends DefinedPacket { handler.handle( this ); } - - @Override - public boolean equals(Object obj) - { - throw new UnsupportedOperationException( "Not supported yet." ); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public int hashCode() - { - throw new UnsupportedOperationException( "Not supported yet." ); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public String toString() - { - throw new UnsupportedOperationException( "Not supported yet." ); //To change body of generated methods, choose Tools | Templates. - } - } 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 cdf00ecf..5bee22ca 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 @@ -92,6 +92,8 @@ public class InitialHandler extends PacketHandler implements PendingConnection private UUID offlineId; @Getter private LoginResult loginProfile; + @Getter + private boolean legacy; private enum State { @@ -125,6 +127,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection @Override public void handle(LegacyHandshake legacyHandshake) throws Exception { + this.legacy = true; ch.getHandle().writeAndFlush( bungee.getTranslation( "outdated_client" ) ); ch.close(); } @@ -132,6 +135,9 @@ public class InitialHandler extends PacketHandler implements PendingConnection @Override public void handle(LegacyPing ping) throws Exception { + this.legacy = true; + final boolean v1_5 = ping.isV1_5(); + ServerPing legacy = new ServerPing( new ServerPing.Protocol( bungee.getName() + " " + bungee.getGameVersion(), bungee.getProtocolVersion() ), new ServerPing.Players( listener.getMaxPlayers(), bungee.getOnlineCount(), null ), listener.getMotd(), (Favicon) null ); @@ -145,14 +151,24 @@ public class InitialHandler extends PacketHandler implements PendingConnection return; } - ServerPing ping = result.getResponse(); + ServerPing legacy = result.getResponse(); + String kickMessage; - String kickMessage = ChatColor.DARK_BLUE - + "\00" + 127 - + "\00" + ping.getVersion().getName() - + "\00" + ping.getDescription() - + "\00" + ping.getPlayers().getOnline() - + "\00" + ping.getPlayers().getMax(); + if ( v1_5 ) + { + kickMessage = ChatColor.DARK_BLUE + + "\00" + 127 + + '\00' + legacy.getVersion().getName() + + '\00' + getFirstLine( legacy.getDescription() ) + + '\00' + legacy.getPlayers().getOnline() + + '\00' + legacy.getPlayers().getMax(); + } else + { + // Clients <= 1.3 don't support colored motds because the color char is used as delimiter + kickMessage = ChatColor.stripColor( getFirstLine( legacy.getDescription() ) ) + + '\u00a7' + legacy.getPlayers().getOnline() + + '\u00a7' + legacy.getPlayers().getMax(); + } ch.getHandle().writeAndFlush( kickMessage ); ch.close(); @@ -162,6 +178,12 @@ public class InitialHandler extends PacketHandler implements PendingConnection bungee.getPluginManager().callEvent( new ProxyPingEvent( this, legacy, callback ) ); } + private static String getFirstLine(String str) + { + int pos = str.indexOf( '\n' ); + return pos == -1 ? str : str.substring( 0, pos ); + } + @Override public void handle(StatusRequest statusRequest) throws Exception {