diff --git a/.travis.yml b/.travis.yml index 1cd525b712..7f19acceeb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,40 @@ sudo: false language: java jdk: - - openjdk7 - - oraclejdk7 - oraclejdk8 +branches: + except: + - /^v[0-9]*/ notifications: email: false + irc: + channels: + - "irc.spi.gt#hexagonmc" + use_notice: true + skip_join: true +install: + - mvn install -DskipTests=true -Dmaven.javadoc.skip=true -Dbuild.number=$TRAVIS_BUILD_NUMBER -B -V +after_success: + # CREATE GIT TAG + - git config --global user.email "builds@travis-ci.com" + - git config --global user.name "Travis CI" + - export GIT_TAG=v$TRAVIS_BUILD_NUMBER + - echo -n $GIT_TAG > VERSION + - git commit -m "Set build VERSION number" VERSION + - git tag $GIT_TAG -a -m "Generated tag from TravisCI build $TRAVIS_BUILD_NUMBER" + - git push --quiet https://$GITHUBKEY@github.com/dev-confidence/example-backend-api $GIT_TAG > /dev/null 2>&1 +deploy: + provider: releases + skip_cleanup: true + api_key: + secure: ljpg29wmo0yPs+qXBVj1vHnY4WPXB1hNMDnHMxhXbPRhK5l9kCqJWy4YjJ6BbEb4keU5dMmt+cyB+Njr3IomJMoupVu0Osut/SNz4g0UZFTYYJQjvrurdmGxoh9E7xmc6Pcly+Pw99RSpqK+yD8SDDepTleHDv/8pC0d4Z5NZIJ9JJUeY2in1RXpStj7rJtmSN5XWFpWBGpHElFQqaSDfh62zn3bvb7J9oVA+NtBDXgpY1Km1Q76Evt4PuijOgdWx4rcNpi7UOd6XurkYuo4/igBEUE8HQSEIqgC0jxJg0gxtLbymPvW4sPXmEPhZwIUvoYFjX0DvlIqU8hbr/2CPtcHiKqnqTU92wgFFnf3Xvn2mdoCrgHDOcSA2JWsR70077bPzv+llNHN17mDlGE7vIiv54jNBkJpem8OBgDNIU2lDnhwZQr3ifZJ0ydhdhkYK7Kp1lAZtEZwbqs6cetlwLiuBH6wd3dErBduPQNLnl22qdhQQJFBXPkj+vHBAt9uSB3irWWME0XsR6G9OpzDYoO64vkkHnz1k7VK37ud2pe7yKYuUr+MUbyBnzycbKOhYRufPkMv8RJIbRH6lChRrZOamqbZTa1FFYsemgcJ9NG990tE0zJHw0G3vU+emxPY35UPIMZrSbzQ8mCOlwKfhAtubZRNe+V0ohJFvVx/dhI= + file: + - bootstrap/target/BungeeCord.jar + - module/*/target/*.jar + file_glob: true + on: + branch: master +cache: + directories: + - $HOME/.m2 + diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md new file mode 100644 index 0000000000..c175fce1b6 --- /dev/null +++ b/ISSUE_TEMPLATE.md @@ -0,0 +1,13 @@ +### What Hexacord version are you using? Post the output of /bungee + + +### Are you using Bungee plugins? If yes, please list all of them + versionnumber + + +### How can we reproduce the error/bug? + + +### Is an error message (bungee/spigot/client)? If yes, use pastebin.com and share the link. + + +### In addidtion to that, please explain your issue as detailed as possible. diff --git a/README.md b/README.md index 331a448902..cd69390b53 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,22 @@ -BungeeCord + +BungeeCord for 1.7/1.8/1.9/1.10/1.11/1.12 ========== -Layer 7 proxy designed to link Minecraft servers. --------------------------------------------------- +[![Build Status](https://travis-ci.org/HexagonMC/BungeeCord.svg?branch=master)](https://travis-ci.org/HexagonMC/BungeeCord) + +This is a fork of md_5's BungeeCord +https://www.spigotmc.org/threads/1-8-1-9-bungeecord.392/ -BungeeCord is a sophisticated proxy and API designed mainly to teleport players between multiple Minecraft servers. It is the latest incarnation of similar software written by the author from 2011-present. +This version reimplements Minecraft 1.7.10 and basic 1.7.10 Forge support. -Information ------------ -BungeeCord is maintained by [SpigotMC](https://www.spigotmc.org/) and has its own [discussion thread](https://www.spigotmc.org/go/bungeecord) with plenty of helpful information and links. +Since release 134+, SpongePls is no longer needed when using Sponge-servers within your network! -Source ------- -Source code is currently available on [GitHub](https://www.spigotmc.org/go/bungeecord-git). +IMPORTANT: We WON'T fix any 1.7 bugs. +This fork is designed for keeping your old servers in your network, until your modspacks are available for 1.10.2/1.11.2 or higher. +Most of them are, so get rid of 1.7 fast and move to 1.10.2/1.11.2 modpacks asap. -Binaries --------- -Precompiled binaries are available for end users on [Jenkins](https://www.spigotmc.org/go/bungeecord-dl). +This version is maintained by https://hexagonmc.eu -(c) 2012-2017 SpigotMC Pty. Ltd. +###Releases can be downloaded here: [Releases](https://github.com/HexagonMC/BungeeCord/releases) +``` +Modules are automatically downloaded from the releases page. +``` diff --git a/api/src/main/java/net/md_5/bungee/api/ProxyConfig.java b/api/src/main/java/net/md_5/bungee/api/ProxyConfig.java index edd82c1e0e..d44a356a00 100644 --- a/api/src/main/java/net/md_5/bungee/api/ProxyConfig.java +++ b/api/src/main/java/net/md_5/bungee/api/ProxyConfig.java @@ -79,4 +79,14 @@ public interface ProxyConfig * The favicon used for the server ping list. */ Favicon getFaviconObject(); + + /** + * The server name for the server ping list. + */ + String getCustomServerName(); + + /** + * Whether the server should handle packets before the player has connected to a server + */ + boolean getAlwaysHandlePackets(); } diff --git a/bootstrap/pom.xml b/bootstrap/pom.xml index 9b5c98f7d5..0de8409018 100644 --- a/bootstrap/pom.xml +++ b/bootstrap/pom.xml @@ -52,7 +52,7 @@ net.md_5.bungee.Bootstrap ${describe} - ${maven.build.timestamp} + ${build.number} diff --git a/bootstrap/src/main/java/net/md_5/bungee/BungeeCordLauncher.java b/bootstrap/src/main/java/net/md_5/bungee/BungeeCordLauncher.java index 3c1bbe9360..109a61c5b9 100644 --- a/bootstrap/src/main/java/net/md_5/bungee/BungeeCordLauncher.java +++ b/bootstrap/src/main/java/net/md_5/bungee/BungeeCordLauncher.java @@ -1,51 +1,107 @@ package net.md_5.bungee; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; +import java.net.URLConnection; import java.security.Security; -import java.text.SimpleDateFormat; import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; import java.util.concurrent.TimeUnit; + +import com.google.gson.JsonIOException; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; + import joptsimple.OptionParser; import joptsimple.OptionSet; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.command.ConsoleCommandSender; + public class BungeeCordLauncher { - public static void main(String[] args) throws Exception { Security.setProperty( "networkaddress.cache.ttl", "30" ); Security.setProperty( "networkaddress.cache.negative.ttl", "10" ); - + OptionParser parser = new OptionParser(); parser.allowsUnrecognizedOptions(); - parser.acceptsAll( Arrays.asList( "v", "version" ) ); + parser.acceptsAll( Arrays.asList( "v", "version") ); parser.acceptsAll( Arrays.asList( "noconsole" ) ); OptionSet options = parser.parse( args ); - if ( options.has( "version" ) ) + if ( options.has("version") ) { - System.out.println( Bootstrap.class.getPackage().getImplementationVersion() ); + System.out.println(Bootstrap.class.getPackage().getImplementationVersion()); return; } - if ( BungeeCord.class.getPackage().getSpecificationVersion() != null && System.getProperty( "IReallyKnowWhatIAmDoingISwear" ) == null ) + if ( BungeeCord.class.getPackage().getSpecificationVersion() != null && System.getProperty( "IReallyKnowWhatIAmDoingISwear" ) == null) { - Date buildDate = new SimpleDateFormat( "yyyyMMdd" ).parse( BungeeCord.class.getPackage().getSpecificationVersion() ); - - Calendar deadline = Calendar.getInstance(); - deadline.add( Calendar.WEEK_OF_YEAR, -4 ); - if ( buildDate.before( deadline.getTime() ) ) + String version = BungeeCord.class.getPackage().getSpecificationVersion(); + + if ( version.equalsIgnoreCase("unknown") ) + { + System.err.println( "*** You are using a self compiled version ***" ); + System.err.println( "*** Please make sure your server is up to date ***" ); + System.err.println( "*** Using current version without warranty ***" ); + System.err.println( "*** Server will start in 2 seconds ***" ); + Thread.sleep( TimeUnit.SECONDS.toMillis( 2 ) ); + } else { - System.err.println( "*** Warning, this build is outdated ***" ); - System.err.println( "*** Please download a new build from http://ci.md-5.net/job/BungeeCord ***" ); - System.err.println( "*** You will get NO support regarding this build ***" ); - System.err.println( "*** Server will start in 10 seconds ***" ); - Thread.sleep( TimeUnit.SECONDS.toMillis( 10 ) ); + int currentVersion = Integer.parseInt( version ); + + try + { + URL api = new URL( "https://api.github.com/repos/HexagonMC/BungeeCord/releases/latest" ); + URLConnection con = api.openConnection(); + // 15 second timeout at various stages + con.setConnectTimeout( 15000 ); + con.setReadTimeout( 15000 ); + + String tagName = null; + + try + { + JsonObject json = new JsonParser().parse( new InputStreamReader( con.getInputStream() ) ).getAsJsonObject(); + tagName = json.get( "tag_name" ).getAsString(); + + int latestVersion = Integer.parseInt( tagName.substring( 1, tagName.length() ) ); + + if ( latestVersion > currentVersion ) + { + System.err.println("*** Warning, this build is outdated ***"); + System.err.println("*** Please download a new build from https://github.com/HexagonMC/BungeeCord/releases ***"); + System.err.println("*** You will get NO support regarding this build ***"); + System.err.println("*** Server will start in 10 seconds ***"); + Thread.sleep(TimeUnit.SECONDS.toMillis(10)); + } + } + catch ( JsonIOException e ) + { + throw new IOException(e); + } + catch ( JsonSyntaxException e ) + { + throw new IOException( e ); + } + catch( NumberFormatException e ) + { + throw new IOException( e ); + } + } + catch ( IOException e ) + { + System.err.println( "*** Can not test if up to date ***" ); + System.err.println( "*** Using current version without warranty ***" ); + System.err.println( "*** Server will start in 2 seconds ***" ); + Thread.sleep( TimeUnit.SECONDS.toMillis( 2 ) ); + } } } @@ -59,7 +115,7 @@ public static void main(String[] args) throws Exception String line; while ( bungee.isRunning && ( line = bungee.getConsoleReader().readLine( ">" ) ) != null ) { - if ( !bungee.getPluginManager().dispatchCommand( ConsoleCommandSender.getInstance(), line ) ) + if ( !bungee.getPluginManager().dispatchCommand(ConsoleCommandSender.getInstance(), line ) ) { bungee.getConsole().sendMessage( ChatColor.RED + "Command not found" ); } diff --git a/pom.xml b/pom.xml index 714d421d65..87bf735183 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ BungeeCord-Parent Parent project for all BungeeCord modules. - https://github.com/SpigotMC/BungeeCord + https://github.com/HexagonMC/BungeeCord 2012 SpigotMC @@ -34,6 +34,12 @@ md_5 + + Zartec + + + ghac + @@ -51,17 +57,17 @@ - scm:git:git@github.com:SpigotMC/BungeeCord.git - scm:git:git@github.com:SpigotMC/BungeeCord.git - git@github.com:SpigotMC/BungeeCord.git + scm:git:git@github.com:HexagonMC/BungeeCord.git + scm:git:git@github.com:HexagonMC/BungeeCord.git + git@github.com:HexagonMC/BungeeCord.git GitHub - https://github.com/SpigotMC/BungeeCord/issues + https://github.com/HexagonMC/BungeeCord/issues - jenkins - http://ci.md-5.net/job/BungeeCord + travis-ci + https://travis-ci.org/HexagonMC/BungeeCord 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 10e16d794e..543487229c 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 @@ -1,6 +1,7 @@ package net.md_5.bungee.protocol; import com.google.common.base.Charsets; +import com.google.common.base.Preconditions; import io.netty.buffer.ByteBuf; import java.util.ArrayList; import java.util.List; @@ -72,6 +73,36 @@ public static byte[] readArray(ByteBuf buf, int limit) buf.readBytes( ret ); return ret; } + + public static void writeArrayLegacy(byte[] b, ByteBuf buf, boolean allowExtended) + { + // (Integer.MAX_VALUE & 0x1FFF9A ) = 2097050 - Forge's current upper limit + if ( allowExtended ) + { + Preconditions.checkArgument( b.length <= ( Integer.MAX_VALUE & 0x1FFF9A ), "Cannot send array longer than 2097050 (got %s bytes)", b.length ); + } else + { + Preconditions.checkArgument( b.length <= Short.MAX_VALUE, "Cannot send array longer than Short.MAX_VALUE (got %s bytes)", b.length ); + } + // Write a 2 or 3 byte number that represents the length of the packet. (3 byte "shorts" for Forge only) + // No vanilla packet should give a 3 byte packet, this method will still retain vanilla behaviour. + writeVarShort( buf, b.length ); + buf.writeBytes( b ); + } + + public static byte[] readArrayLegacy(ByteBuf buf) + { + // Read in a 2 or 3 byte number that represents the length of the packet. (3 byte "shorts" for Forge only) + // No vanilla packet should give a 3 byte packet, this method will still retain vanilla behaviour. + int len = readVarShort( buf ); + + // (Integer.MAX_VALUE & 0x1FFF9A ) = 2097050 - Forge's current upper limit + Preconditions.checkArgument( len <= ( Integer.MAX_VALUE & 0x1FFF9A ), "Cannot receive array longer than 2097050 (got %s bytes)", len ); + + byte[] ret = new byte[ len ]; + buf.readBytes( ret ); + return ret; + } public static void writeStringArray(List s, ByteBuf buf) { 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 e7cb380342..9c5d4da17f 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 @@ -34,7 +34,7 @@ protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) t if ( in.isReadable() ) { - throw new BadPacketException( "Did not read all bytes from packet " + packet.getClass() + " " + packetId + " Protocol " + protocol + " Direction " + prot ); + throw new BadPacketException( "Did not read all bytes from packet " + packet.getClass() + " " + packetId + " Protocol " + protocol + " Direction " + prot.getDirection().name() ); } } else { diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/MinecraftInput.java b/protocol/src/main/java/net/md_5/bungee/protocol/MinecraftInput.java new file mode 100644 index 0000000000..ef2e269556 --- /dev/null +++ b/protocol/src/main/java/net/md_5/bungee/protocol/MinecraftInput.java @@ -0,0 +1,38 @@ +package net.md_5.bungee.protocol; + +import io.netty.buffer.ByteBuf; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class MinecraftInput +{ + + private final ByteBuf buf; + + public byte readByte() + { + return buf.readByte(); + } + + public short readUnsignedByte() + { + return buf.readUnsignedByte(); + } + + public int readInt() + { + return buf.readInt(); + } + + public String readString() + { + short len = buf.readShort(); + char[] c = new char[ len ]; + for ( int i = 0; i < c.length; i++ ) + { + c[i] = buf.readChar(); + } + + return new String( c ); + } +} diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/MinecraftOutput.java b/protocol/src/main/java/net/md_5/bungee/protocol/MinecraftOutput.java new file mode 100644 index 0000000000..94f6613d5d --- /dev/null +++ b/protocol/src/main/java/net/md_5/bungee/protocol/MinecraftOutput.java @@ -0,0 +1,56 @@ +package net.md_5.bungee.protocol; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import java.nio.charset.Charset; +import java.util.Arrays; + +public class MinecraftOutput +{ + + private final ByteBuf buf; + + public MinecraftOutput() + { + buf = Unpooled.buffer(); + } + + public byte[] toArray() + { + if ( buf.hasArray() ) + { + return Arrays.copyOfRange( buf.array(), buf.arrayOffset(), buf.arrayOffset() + buf.writerIndex() ); + } else + { + byte[] b = new byte[ buf.writerIndex() ]; + buf.readBytes( b ); + return b; + } + } + + public MinecraftOutput writeByte(byte b) + { + buf.writeByte( b ); + return this; + } + + public void writeInt(int i) + { + buf.writeInt( i ); + } + + public void writeString(String s) + { + char[] cc = s.toCharArray(); + buf.writeShort( cc.length ); + for ( char c : cc ) + { + buf.writeChar( c ); + } + } + + public void writeStringUTF8WithoutLengthHeaderBecauseDinnerboneStuffedUpTheMCBrandPacket(String s) + { + buf.writeBytes( s.getBytes( Charset.forName( "UTF-8" ) ) ); + } +} 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 f06aa95ab9..90b3ff13b9 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 @@ -154,6 +154,12 @@ public enum Protocol map( ProtocolConstants.MINECRAFT_1_12, 0x49 ), map( ProtocolConstants.MINECRAFT_1_12_1, 0x4A ) ); + TO_CLIENT.registerPacket( + SetCompression.class, + map( ProtocolConstants.MINECRAFT_1_7_2, 0x46 , false ), + map( ProtocolConstants.MINECRAFT_1_7_6, 0x46 , false ), + map( ProtocolConstants.MINECRAFT_1_8, 0x46 , false ) + ); TO_SERVER.registerPacket( KeepAlive.class, @@ -300,10 +306,14 @@ private static class ProtocolData { private static class ProtocolMapping { private final int protocolVersion; private final int packetID; + private final boolean inherit; } // Helper method private static ProtocolMapping map(int protocol, int id) { - return new ProtocolMapping(protocol, id); + return map(protocol, id, true); + } + private static ProtocolMapping map(int protocol, int id, boolean inherit) { + return new ProtocolMapping(protocol, id, inherit); } @RequiredArgsConstructor @@ -320,7 +330,11 @@ public static class DirectionData } private final TIntObjectMap> linkedProtocols = new TIntObjectHashMap<>(); { + linkedProtocols.put( ProtocolConstants.MINECRAFT_1_7_2, Arrays.asList( + ProtocolConstants.MINECRAFT_1_7_6 + )); linkedProtocols.put( ProtocolConstants.MINECRAFT_1_8, Arrays.asList( + ProtocolConstants.MINECRAFT_1_7_2, ProtocolConstants.MINECRAFT_1_9, ProtocolConstants.MINECRAFT_1_12 ) ); @@ -388,20 +402,23 @@ protected final void registerPacket(Class packetClass, data.packetMap.put( packetClass, mapping.packetID ); data.packetConstructors[mapping.packetID] = constructor; - List links = linkedProtocols.get( mapping.protocolVersion ); - if ( links != null ) + if (mapping.inherit) { - links: for ( int link : links ) + List links = linkedProtocols.get( mapping.protocolVersion ); + if ( links != null ) { - // Check for manual mappings - for ( ProtocolMapping m : mappings ) + links: for ( int link : links ) { - if ( m == mapping ) continue; - if ( m.protocolVersion == link ) continue links; - List innerLinks = linkedProtocols.get( m.protocolVersion ); - if ( innerLinks != null && innerLinks.contains( link ) ) continue links; + // Check for manual mappings + for ( ProtocolMapping m : mappings ) + { + if ( m == mapping ) continue; + if ( m.protocolVersion == link ) continue links; + List innerLinks = linkedProtocols.get( m.protocolVersion ); + if ( innerLinks != null && innerLinks.contains( link ) ) continue links; + } + registerPacket( packetClass, map( link, mapping.packetID ) ); } - registerPacket( packetClass, map( link, mapping.packetID ) ); } } } diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/ProtocolConstants.java b/protocol/src/main/java/net/md_5/bungee/protocol/ProtocolConstants.java index ac9adf3323..4ed107f5c9 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/ProtocolConstants.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/ProtocolConstants.java @@ -5,7 +5,8 @@ public class ProtocolConstants { - + public static final int MINECRAFT_1_7_2 = 4; + public static final int MINECRAFT_1_7_6 = 5; public static final int MINECRAFT_1_8 = 47; public static final int MINECRAFT_1_9 = 107; public static final int MINECRAFT_1_9_1 = 108; @@ -18,13 +19,18 @@ public class ProtocolConstants public static final int MINECRAFT_1_12_1 = 338; public static final int MINECRAFT_1_12_2 = 340; public static final List SUPPORTED_VERSIONS = Arrays.asList( + "1.7.x", "1.8.x", "1.9.x", "1.10.x", "1.11.x", "1.12.x" ); - public static final List SUPPORTED_VERSION_IDS = Arrays.asList( ProtocolConstants.MINECRAFT_1_8, + + public static final List SUPPORTED_VERSION_IDS = Arrays.asList( + ProtocolConstants.MINECRAFT_1_7_2, + ProtocolConstants.MINECRAFT_1_7_6, + ProtocolConstants.MINECRAFT_1_8, ProtocolConstants.MINECRAFT_1_9, ProtocolConstants.MINECRAFT_1_9_1, ProtocolConstants.MINECRAFT_1_9_2, 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 95ad39b766..6144bd6195 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 @@ -28,7 +28,7 @@ public Chat(String message) public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) { message = readString( buf ); - if ( direction == ProtocolConstants.Direction.TO_CLIENT ) + if ( direction == ProtocolConstants.Direction.TO_CLIENT && protocolVersion >= ProtocolConstants.MINECRAFT_1_8 ) { position = buf.readByte(); } @@ -38,7 +38,7 @@ public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protoco public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) { writeString( message, buf ); - if ( direction == ProtocolConstants.Direction.TO_CLIENT ) + if ( direction == ProtocolConstants.Direction.TO_CLIENT && protocolVersion >= ProtocolConstants.MINECRAFT_1_8 ) { buf.writeByte( position ); } 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 5c79727ca2..b17b6cebb1 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 @@ -31,6 +31,10 @@ public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protoco viewDistance = buf.readByte(); chatFlags = protocolVersion >= ProtocolConstants.MINECRAFT_1_9 ? DefinedPacket.readVarInt( buf ) : buf.readUnsignedByte(); chatColours = buf.readBoolean(); + if ( protocolVersion <= ProtocolConstants.MINECRAFT_1_7_6 ) + { + difficulty = buf.readByte(); + } skinParts = buf.readByte(); if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_9 ) { @@ -51,6 +55,10 @@ public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protoc buf.writeByte( chatFlags ); } buf.writeBoolean( chatColours ); + if ( protocolVersion <= ProtocolConstants.MINECRAFT_1_7_6 ) + { + buf.writeByte( difficulty ); + } buf.writeByte( skinParts ); if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_9 ) { diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/packet/EncryptionRequest.java b/protocol/src/main/java/net/md_5/bungee/protocol/packet/EncryptionRequest.java index a29524ca81..3d1a3f7904 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/packet/EncryptionRequest.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/packet/EncryptionRequest.java @@ -24,16 +24,30 @@ public class EncryptionRequest extends DefinedPacket public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) { serverId = readString( buf ); - publicKey = readArray( buf ); - verifyToken = readArray( buf ); + if ( protocolVersion < ProtocolConstants.MINECRAFT_1_8 ) + { + publicKey = readArrayLegacy( buf ); + verifyToken = readArrayLegacy( buf ); + } else + { + publicKey = readArray( buf ); + verifyToken = readArray( buf ); + } } @Override public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) { writeString( serverId, buf ); - writeArray( publicKey, buf ); - writeArray( verifyToken, buf ); + if ( protocolVersion < ProtocolConstants.MINECRAFT_1_8 ) + { + writeArrayLegacy( publicKey, buf, false ); + writeArrayLegacy( verifyToken, buf, false ); + } else + { + writeArray( publicKey, buf ); + writeArray( verifyToken, buf ); + } } @Override diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/packet/EncryptionResponse.java b/protocol/src/main/java/net/md_5/bungee/protocol/packet/EncryptionResponse.java index 06676e428e..067058499d 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/packet/EncryptionResponse.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/packet/EncryptionResponse.java @@ -22,15 +22,29 @@ public class EncryptionResponse extends DefinedPacket @Override public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) { - sharedSecret = readArray( buf, 128 ); - verifyToken = readArray( buf, 128 ); + if ( protocolVersion < ProtocolConstants.MINECRAFT_1_8 ) + { + sharedSecret = readArrayLegacy( buf ); + verifyToken = readArrayLegacy( buf ); + } else + { + sharedSecret = readArray( buf, 128 ); + verifyToken = readArray( buf, 128 ); + } } @Override public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) { - writeArray( sharedSecret, buf ); - writeArray( verifyToken, buf ); + if ( protocolVersion < ProtocolConstants.MINECRAFT_1_8 ) + { + writeArrayLegacy( sharedSecret, buf, false ); + writeArrayLegacy( verifyToken, buf, false ); + } else + { + writeArray( sharedSecret, buf ); + writeArray( verifyToken, buf ); + } } @Override diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/packet/KeepAlive.java b/protocol/src/main/java/net/md_5/bungee/protocol/packet/KeepAlive.java index 9df9ef567a..3a224a7496 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/packet/KeepAlive.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/packet/KeepAlive.java @@ -21,7 +21,16 @@ public class KeepAlive extends DefinedPacket @Override public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) { - randomId = ( protocolVersion >= ProtocolConstants.MINECRAFT_1_12_2 ) ? buf.readLong() : readVarInt( buf ); + if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_12_2 ) + { + randomId = buf.readLong(); + } else if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_8 ) + { + randomId = readVarInt( buf ); + } else + { + randomId = buf.readInt(); + } } @Override @@ -30,9 +39,12 @@ public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protoc if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_12_2 ) { buf.writeLong( randomId ); - } else + } else if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_8 ) { writeVarInt( (int) randomId, buf ); + } else + { + buf.writeInt( (int) randomId ); } } diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/packet/PlayerListItem.java b/protocol/src/main/java/net/md_5/bungee/protocol/packet/PlayerListItem.java index 9983ef2e4d..e912882633 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/packet/PlayerListItem.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/packet/PlayerListItem.java @@ -22,53 +22,63 @@ public class PlayerListItem extends DefinedPacket @Override public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) { - action = Action.values()[DefinedPacket.readVarInt( buf )]; - items = new Item[ DefinedPacket.readVarInt( buf ) ]; - for ( int i = 0; i < items.length; i++ ) + if ( protocolVersion < ProtocolConstants.MINECRAFT_1_8 ) { - Item item = items[i] = new Item(); - item.setUuid( DefinedPacket.readUUID( buf ) ); - switch ( action ) + items = new Item[ 1 ]; + Item item = items[ 0 ] = new Item(); + item.displayName = item.username = readString( buf ); + action = !buf.readBoolean() ? Action.REMOVE_PLAYER : Action.ADD_PLAYER; + item.ping = buf.readShort(); + } else + { + action = Action.values()[ DefinedPacket.readVarInt( buf )]; + items = new Item[ DefinedPacket.readVarInt( buf ) ]; + for ( int i = 0; i < items.length; i++ ) { - case ADD_PLAYER: - item.username = DefinedPacket.readString( buf ); - item.properties = new String[ DefinedPacket.readVarInt( buf ) ][]; - for ( int j = 0; j < item.properties.length; j++ ) - { - String name = DefinedPacket.readString( buf ); - String value = DefinedPacket.readString( buf ); - if ( buf.readBoolean() ) + Item item = items[ i ] = new Item(); + item.setUuid( DefinedPacket.readUUID( buf ) ); + switch ( action ) + { + case ADD_PLAYER: + item.username = DefinedPacket.readString( buf ); + item.properties = new String[ DefinedPacket.readVarInt( buf ) ][]; + for ( int j = 0; j < item.properties.length; j++ ) { - item.properties[j] = new String[] + String name = DefinedPacket.readString( buf ); + String value = DefinedPacket.readString( buf ); + if ( buf.readBoolean() ) { - name, value, DefinedPacket.readString( buf ) - }; - } else - { - item.properties[j] = new String[] + item.properties[j] = new String[] + { + name, value, DefinedPacket.readString( buf ) + }; + } else { - name, value - }; + item.properties[j] = new String[] + { + name, value + }; + } + } + item.gamemode = DefinedPacket.readVarInt( buf ); + item.ping = DefinedPacket.readVarInt( buf ); + if ( buf.readBoolean() ) + { + item.displayName = DefinedPacket.readString( buf ); } - } - item.gamemode = DefinedPacket.readVarInt( buf ); - item.ping = DefinedPacket.readVarInt( buf ); - if ( buf.readBoolean() ) - { - item.displayName = DefinedPacket.readString( buf ); - } - break; - case UPDATE_GAMEMODE: - item.gamemode = DefinedPacket.readVarInt( buf ); - break; - case UPDATE_LATENCY: - item.ping = DefinedPacket.readVarInt( buf ); - break; - case UPDATE_DISPLAY_NAME: - if ( buf.readBoolean() ) - { - item.displayName = DefinedPacket.readString( buf ); - } + break; + case UPDATE_GAMEMODE: + item.gamemode = DefinedPacket.readVarInt( buf ); + break; + case UPDATE_LATENCY: + item.ping = DefinedPacket.readVarInt( buf ); + break; + case UPDATE_DISPLAY_NAME: + if ( buf.readBoolean() ) + { + item.displayName = DefinedPacket.readString( buf ); + } + } } } } @@ -76,50 +86,59 @@ public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protoco @Override public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) { - DefinedPacket.writeVarInt( action.ordinal(), buf ); - DefinedPacket.writeVarInt( items.length, buf ); - for ( Item item : items ) + if ( protocolVersion < ProtocolConstants.MINECRAFT_1_8 ) + { + Item item = items[0]; // Only one at a time + writeString( item.displayName, buf ); // TODO: Server unique only! + buf.writeBoolean( action != Action.REMOVE_PLAYER ); + buf.writeShort( item.ping ); + } else { - DefinedPacket.writeUUID( item.uuid, buf ); - switch ( action ) + DefinedPacket.writeVarInt( action.ordinal(), buf ); + DefinedPacket.writeVarInt( items.length, buf ); + for ( Item item : items ) { - case ADD_PLAYER: - DefinedPacket.writeString( item.username, buf ); - DefinedPacket.writeVarInt( item.properties.length, buf ); - for ( String[] prop : item.properties ) - { - DefinedPacket.writeString( prop[0], buf ); - DefinedPacket.writeString( prop[1], buf ); - if ( prop.length >= 3 ) + DefinedPacket.writeUUID( item.uuid, buf ); + switch ( action ) + { + case ADD_PLAYER: + DefinedPacket.writeString( item.username, buf ); + DefinedPacket.writeVarInt( item.properties.length, buf ); + for ( String[] prop : item.properties ) { - buf.writeBoolean( true ); - DefinedPacket.writeString( prop[2], buf ); - } else + DefinedPacket.writeString( prop[ 0], buf ); + DefinedPacket.writeString( prop[ 1], buf ); + if ( prop.length >= 3 ) + { + buf.writeBoolean( true ); + DefinedPacket.writeString( prop[ 2], buf ); + } else + { + buf.writeBoolean( false ); + } + } + DefinedPacket.writeVarInt( item.gamemode, buf ); + DefinedPacket.writeVarInt( item.ping, buf ); + buf.writeBoolean( item.displayName != null ); + if ( item.displayName != null ) + { + DefinedPacket.writeString( item.displayName, buf ); + } + break; + case UPDATE_GAMEMODE: + DefinedPacket.writeVarInt( item.gamemode, buf ); + break; + case UPDATE_LATENCY: + DefinedPacket.writeVarInt( item.ping, buf ); + break; + case UPDATE_DISPLAY_NAME: + buf.writeBoolean( item.displayName != null ); + if ( item.displayName != null ) { - buf.writeBoolean( false ); + DefinedPacket.writeString( item.displayName, buf ); } - } - DefinedPacket.writeVarInt( item.gamemode, buf ); - DefinedPacket.writeVarInt( item.ping, buf ); - buf.writeBoolean( item.displayName != null ); - if ( item.displayName != null ) - { - DefinedPacket.writeString( item.displayName, buf ); - } - break; - case UPDATE_GAMEMODE: - DefinedPacket.writeVarInt( item.gamemode, buf ); - break; - case UPDATE_LATENCY: - DefinedPacket.writeVarInt( item.ping, buf ); - break; - case UPDATE_DISPLAY_NAME: - buf.writeBoolean( item.displayName != null ); - if ( item.displayName != null ) - { - DefinedPacket.writeString( item.displayName, buf ); - } - break; + break; + } } } } diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/packet/PluginMessage.java b/protocol/src/main/java/net/md_5/bungee/protocol/packet/PluginMessage.java index 6dcdece585..85decbb1df 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/packet/PluginMessage.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/packet/PluginMessage.java @@ -4,6 +4,7 @@ import com.google.common.base.Predicate; import net.md_5.bungee.protocol.DefinedPacket; import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; import java.io.ByteArrayInputStream; import java.io.DataInput; import java.io.DataInputStream; @@ -11,6 +12,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; +import net.md_5.bungee.protocol.MinecraftInput; import net.md_5.bungee.protocol.AbstractPacketHandler; import net.md_5.bungee.protocol.ProtocolConstants; @@ -42,17 +44,29 @@ public boolean apply(PluginMessage input) public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) { tag = readString( buf ); - int maxSize = direction == ProtocolConstants.Direction.TO_SERVER ? Short.MAX_VALUE : 0x100000; - Preconditions.checkArgument( buf.readableBytes() < maxSize ); - data = new byte[ buf.readableBytes() ]; - buf.readBytes( data ); + if ( protocolVersion < ProtocolConstants.MINECRAFT_1_8 ) + { + data = readArrayLegacy( buf ); + } else + { + int maxSize = direction == ProtocolConstants.Direction.TO_SERVER ? Short.MAX_VALUE : 0x100000; + Preconditions.checkArgument(buf.readableBytes() < maxSize); + data = new byte[ buf.readableBytes() ]; + buf.readBytes( data ); + } } @Override public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) { writeString( tag, buf ); - buf.writeBytes( data ); + if ( protocolVersion < ProtocolConstants.MINECRAFT_1_8 ) + { + writeArrayLegacy( data, buf, allowExtendedPacket ); + } else + { + buf.writeBytes( data ); + } } @Override @@ -65,4 +79,9 @@ public DataInput getStream() { return new DataInputStream( new ByteArrayInputStream( data ) ); } + + public MinecraftInput getMCStream() + { + return new MinecraftInput( Unpooled.wrappedBuffer( data ) ); + } } diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/packet/ScoreboardObjective.java b/protocol/src/main/java/net/md_5/bungee/protocol/packet/ScoreboardObjective.java index ef9b8cf68a..a650b48245 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/packet/ScoreboardObjective.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/packet/ScoreboardObjective.java @@ -28,8 +28,12 @@ public class ScoreboardObjective extends DefinedPacket public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) { name = readString( buf ); + if ( protocolVersion <= ProtocolConstants.MINECRAFT_1_7_6 ) + { + value = readString( buf ); + } action = buf.readByte(); - if ( action == 0 || action == 2 ) + if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_8 && ( action == 0 || action == 2 ) ) { value = readString( buf ); type = readString( buf ); @@ -40,8 +44,12 @@ public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protoco public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) { writeString( name, buf ); + if ( protocolVersion <= ProtocolConstants.MINECRAFT_1_7_6 ) + { + writeString( value, buf ); + } buf.writeByte( action ); - if ( action == 0 || action == 2 ) + if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_8 && ( action == 0 || action == 2 ) ) { writeString( value, buf ); writeString( type, buf ); 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 6f0de535d4..e8157005c8 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 @@ -29,10 +29,20 @@ public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protoco { itemName = readString( buf ); action = buf.readByte(); - scoreName = readString( buf ); - if ( action != 1 ) + if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_8 ) { - value = readVarInt( buf ); + scoreName = readString( buf ); + if ( action != 1 ) + { + value = readVarInt( buf ); + } + } else + { + if ( action != 1 ) + { + scoreName = readString( buf ); + value = buf.readInt(); + } } } @@ -41,10 +51,20 @@ public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protoc { writeString( itemName, buf ); buf.writeByte( action ); - writeString( scoreName, buf ); - if ( action != 1 ) + if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_8 ) + { + writeString( scoreName, buf ); + if ( action != 1 ) + { + writeVarInt( value, buf ); + } + } else { - writeVarInt( value, buf ); + if ( action != 1 ) + { + writeString( scoreName, buf ); + buf.writeInt( value ); + } } } diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/packet/TabCompleteRequest.java b/protocol/src/main/java/net/md_5/bungee/protocol/packet/TabCompleteRequest.java index e3bcbc330b..5234252aa1 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/packet/TabCompleteRequest.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/packet/TabCompleteRequest.java @@ -25,14 +25,17 @@ public class TabCompleteRequest extends DefinedPacket public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) { cursor = readString( buf ); - if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_9 ) + if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_8 ) { - assumeCommand = buf.readBoolean(); - } - - if ( hasPositon = buf.readBoolean() ) - { - position = buf.readLong(); + if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_9 ) + { + assumeCommand = buf.readBoolean(); + } + + if ( hasPositon = buf.readBoolean() ) + { + position = buf.readLong(); + } } } @@ -40,15 +43,18 @@ public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protoco public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) { writeString( cursor, buf ); - if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_9 ) - { - buf.writeBoolean( assumeCommand ); - } - - buf.writeBoolean( hasPositon ); - if ( hasPositon ) + if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_8 ) { - buf.writeLong( position ); + if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_9 ) + { + buf.writeBoolean( assumeCommand ); + } + + buf.writeBoolean( hasPositon ); + if ( hasPositon ) + { + buf.writeLong( position ); + } } } 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 b470579952..a5247a8601 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 @@ -50,16 +50,19 @@ public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protoco prefix = readString( buf ); suffix = readString( buf ); friendlyFire = buf.readByte(); - nameTagVisibility = readString( buf ); - if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_9 ) + if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_8 ) { - collisionRule = readString( buf ); + nameTagVisibility = readString( buf ); + if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_9 ) + { + collisionRule = readString(buf); + } + color = buf.readByte(); } - color = buf.readByte(); } if ( mode == 0 || mode == 3 || mode == 4 ) { - int len = readVarInt( buf ); + int len = ( protocolVersion >= ProtocolConstants.MINECRAFT_1_8 ) ? readVarInt( buf ) : buf.readShort(); players = new String[ len ]; for ( int i = 0; i < len; i++ ) { @@ -79,16 +82,25 @@ public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protoc writeString( prefix, buf ); writeString( suffix, buf ); buf.writeByte( friendlyFire ); - writeString( nameTagVisibility, buf ); - if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_9 ) + if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_8 ) { - writeString( collisionRule, buf ); + writeString( nameTagVisibility, buf ); + if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_9 ) + { + writeString( collisionRule, buf); + } + buf.writeByte( color ); } - buf.writeByte( color ); } if ( mode == 0 || mode == 3 || mode == 4 ) { - writeVarInt( players.length, buf ); + if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_8 ) + { + 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 b4c8bcfc06..f889533261 100644 --- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java +++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java @@ -151,7 +151,13 @@ public class BungeeCord extends ProxyServer .registerTypeAdapter( BaseComponent.class, new ComponentSerializer() ) .registerTypeAdapter( TextComponent.class, new TextComponentSerializer() ) .registerTypeAdapter( TranslatableComponent.class, new TranslatableComponentSerializer() ) - .registerTypeAdapter( ServerPing.PlayerInfo.class, new PlayerInfoSerializer() ) + .registerTypeAdapter( ServerPing.PlayerInfo.class, new PlayerInfoSerializer( ProtocolConstants.MINECRAFT_1_7_6 ) ) + .registerTypeAdapter( Favicon.class, Favicon.getFaviconTypeAdapter() ).create(); + public final Gson gsonLegacy = new GsonBuilder() + .registerTypeAdapter( BaseComponent.class, new ComponentSerializer() ) + .registerTypeAdapter( TextComponent.class, new TextComponentSerializer() ) + .registerTypeAdapter( TranslatableComponent.class, new TranslatableComponentSerializer() ) + .registerTypeAdapter( ServerPing.PlayerInfo.class, new PlayerInfoSerializer( ProtocolConstants.MINECRAFT_1_7_2 ) ) .registerTypeAdapter( Favicon.class, Favicon.getFaviconTypeAdapter() ).create(); @Getter private ConnectionThrottle connectionThrottle; @@ -475,7 +481,7 @@ public void broadcast(DefinedPacket packet) @Override public String getName() { - return "BungeeCord"; + return config.getCustomServerName(); } @Override diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeTitle.java b/proxy/src/main/java/net/md_5/bungee/BungeeTitle.java index 494213db8e..e9073c5d4c 100644 --- a/proxy/src/main/java/net/md_5/bungee/BungeeTitle.java +++ b/proxy/src/main/java/net/md_5/bungee/BungeeTitle.java @@ -5,6 +5,7 @@ import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.chat.ComponentSerializer; import net.md_5.bungee.protocol.DefinedPacket; +import net.md_5.bungee.protocol.ProtocolConstants; import net.md_5.bungee.protocol.packet.Title.Action; public class BungeeTitle implements Title @@ -151,11 +152,14 @@ private static void sendPacket(ProxiedPlayer player, DefinedPacket packet) @Override public Title send(ProxiedPlayer player) { - sendPacket( player, clear ); - sendPacket( player, reset ); - sendPacket( player, times ); - sendPacket( player, subtitle ); - sendPacket( player, title ); + if ( player.getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_8 ) + { + sendPacket( player, clear ); + sendPacket( player, reset ); + sendPacket( player, times ); + sendPacket( player, subtitle ); + sendPacket( player, title ); + } return this; } } diff --git a/proxy/src/main/java/net/md_5/bungee/PlayerInfoSerializer.java b/proxy/src/main/java/net/md_5/bungee/PlayerInfoSerializer.java index 491cf1a168..bba0641b08 100644 --- a/proxy/src/main/java/net/md_5/bungee/PlayerInfoSerializer.java +++ b/proxy/src/main/java/net/md_5/bungee/PlayerInfoSerializer.java @@ -13,14 +13,20 @@ public class PlayerInfoSerializer implements JsonSerializer, JsonDeserializer { + private final int protocol; + public PlayerInfoSerializer(int protocol) + { + this.protocol = protocol; + } + @Override public ServerPing.PlayerInfo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { JsonObject js = json.getAsJsonObject(); ServerPing.PlayerInfo info = new ServerPing.PlayerInfo( js.get( "name" ).getAsString(), (UUID) null ); String id = js.get( "id" ).getAsString(); - if ( !id.contains( "-" ) ) + if ( protocol == 4 || !id.contains( "-" ) ) { info.setId( id ); } else @@ -35,7 +41,13 @@ public JsonElement serialize(ServerPing.PlayerInfo src, Type typeOfSrc, JsonSeri { JsonObject out = new JsonObject(); out.addProperty( "name", src.getName() ); - out.addProperty( "id", src.getUniqueId().toString() ); + if ( protocol == 4 ) + { + out.addProperty( "id", src.getId() ); + } else + { + out.addProperty( "id", src.getUniqueId().toString() ); + } return out; } } diff --git a/proxy/src/main/java/net/md_5/bungee/ServerConnector.java b/proxy/src/main/java/net/md_5/bungee/ServerConnector.java index 6c31f15ff3..0d51263c8a 100644 --- a/proxy/src/main/java/net/md_5/bungee/ServerConnector.java +++ b/proxy/src/main/java/net/md_5/bungee/ServerConnector.java @@ -1,11 +1,14 @@ package net.md_5.bungee; -import com.google.common.base.Preconditions; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; +import java.util.Arrays; import java.util.Queue; import java.util.Set; import java.util.UUID; + +import com.google.common.base.Preconditions; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; import lombok.Getter; import lombok.RequiredArgsConstructor; import net.md_5.bungee.api.ChatColor; @@ -29,7 +32,9 @@ import net.md_5.bungee.netty.HandlerBoss; import net.md_5.bungee.netty.PacketHandler; import net.md_5.bungee.protocol.DefinedPacket; +import net.md_5.bungee.protocol.MinecraftOutput; import net.md_5.bungee.protocol.Protocol; +import net.md_5.bungee.protocol.ProtocolConstants; import net.md_5.bungee.protocol.packet.EncryptionRequest; import net.md_5.bungee.protocol.packet.Handshake; import net.md_5.bungee.protocol.packet.Kick; @@ -42,88 +47,111 @@ import net.md_5.bungee.protocol.packet.ScoreboardScore; import net.md_5.bungee.protocol.packet.SetCompression; + @RequiredArgsConstructor public class ServerConnector extends PacketHandler { - - private final ProxyServer bungee; - private ChannelWrapper ch; - private final UserConnection user; + + private final ProxyServer bungee; + private ChannelWrapper ch; + private final UserConnection user; private final BungeeServerInfo target; - private State thisState = State.LOGIN_SUCCESS; + private State thisState = State.LOGIN_SUCCESS; @Getter - private ForgeServerHandler handshakeHandler; - private boolean obsolete; - + private ForgeServerHandler handshakeHandler; + private boolean obsolete; + private enum State { - - LOGIN_SUCCESS, ENCRYPT_RESPONSE, LOGIN, FINISHED; + + LOGIN_SUCCESS, + ENCRYPT_RESPONSE, + LOGIN, + FINISHED; } - + @Override public void exception(Throwable t) throws Exception { - if ( obsolete ) - { + if (obsolete) return; - } - - String message = "Exception Connecting:" + Util.exception( t ); - if ( user.getServer() == null ) - { - user.disconnect( message ); - } else - { - user.sendMessage( ChatColor.RED + message ); - } + + String message = "Exception Connecting:" + Util.exception(t); + if (user.getServer() == null) + user.disconnect(message); + else + user.sendMessage(ChatColor.RED + message); } - + @Override public void connected(ChannelWrapper channel) throws Exception { this.ch = channel; - - this.handshakeHandler = new ForgeServerHandler( user, ch, target ); + + this.handshakeHandler = new ForgeServerHandler(user, ch, target); Handshake originalHandshake = user.getPendingConnection().getHandshake(); - Handshake copiedHandshake = new Handshake( originalHandshake.getProtocolVersion(), originalHandshake.getHost(), originalHandshake.getPort(), 2 ); - - if ( BungeeCord.getInstance().config.isIpForward() ) + Handshake copiedHandshake = new Handshake(originalHandshake.getProtocolVersion(), originalHandshake.getHost(), originalHandshake.getPort(), 2); + + if (BungeeCord.getInstance().config.isIpForward()) { String newHost = copiedHandshake.getHost() + "\00" + user.getAddress().getHostString() + "\00" + user.getUUID(); + // Handle properties. + LoginResult.Property[] properties = new LoginResult.Property[0]; + LoginResult profile = user.getPendingConnection().getLoginProfile(); - if ( profile != null && profile.getProperties() != null && profile.getProperties().length > 0 ) + if (profile != null && profile.getProperties() != null && profile.getProperties().length > 0) { - newHost += "\00" + BungeeCord.getInstance().gson.toJson( profile.getProperties() ); + properties = profile.getProperties(); } - copiedHandshake.setHost( newHost ); - } else if ( !user.getExtraDataInHandshake().isEmpty() ) - { - // Only restore the extra data if IP forwarding is off. - // TODO: Add support for this data with IP forwarding. - copiedHandshake.setHost( copiedHandshake.getHost() + user.getExtraDataInHandshake() ); - } - channel.write( copiedHandshake ); + if ( user.getForgeClientHandler().isFmlTokenInHandshake() ) + { + // Get the current properties and copy them into a slightly bigger array. + LoginResult.Property[] newp = Arrays.copyOf( properties, properties.length + 2 ); + + // Add a new profile property that specifies that this user is a Forge user. + newp[newp.length - 2] = new LoginResult.Property( ForgeConstants.FML_LOGIN_PROFILE, "true", null ); - channel.setProtocol( Protocol.LOGIN ); - channel.write( new LoginRequest( user.getName() ) ); - } + // If we do not perform the replacement, then the IP Forwarding code in Spigot et. al. will try to split on this prematurely. + newp[newp.length - 1] = new LoginResult.Property( ForgeConstants.EXTRA_DATA, user.getExtraDataInHandshake().replaceAll( "\0", "\1"), "" ); + + // All done. + properties = newp; + } + + // If we touched any properties, then append them + if (properties.length > 0) + { + newHost += "\00" + BungeeCord.getInstance().gson.toJson(properties); + } + copiedHandshake.setHost(newHost); + } + else if (!user.getExtraDataInHandshake().isEmpty()) { + // Restore the extra data + copiedHandshake.setHost(copiedHandshake.getHost() + user.getExtraDataInHandshake()); + } + + channel.write(copiedHandshake); + + channel.setProtocol(Protocol.LOGIN); + channel.write(new LoginRequest(user.getName())); +} + @Override public void disconnected(ChannelWrapper channel) throws Exception { - user.getPendingConnects().remove( target ); + user.getPendingConnects().remove(target); } - + @Override public void handle(LoginSuccess loginSuccess) throws Exception { - Preconditions.checkState( thisState == State.LOGIN_SUCCESS, "Not expecting LOGIN_SUCCESS" ); - ch.setProtocol( Protocol.GAME ); + Preconditions.checkState(thisState == State.LOGIN_SUCCESS, "Not expecting LOGIN_SUCCESS"); + ch.setProtocol(Protocol.GAME); thisState = State.LOGIN; - + // Only reset the Forge client when: // 1) The user is switching servers (so has a current server) // 2) The handshake is complete @@ -137,38 +165,33 @@ public void handle(LoginSuccess loginSuccess) throws Exception // we need to switch to a modded connection. However, we always need to reset the // connection when we have a modded server regardless of where we go - doing it // here makes sense. - if ( user.getServer() != null && user.getForgeClientHandler().isHandshakeComplete() - && user.getServer().isForgeServer() ) - { + if (user.getServer() != null && user.getForgeClientHandler().isHandshakeComplete() && user.getServer().isForgeServer()) user.getForgeClientHandler().resetHandshake(); - } - + throw CancelSendSignal.INSTANCE; } - + @Override public void handle(SetCompression setCompression) throws Exception { - ch.setCompressionThreshold( setCompression.getThreshold() ); + ch.setCompressionThreshold(setCompression.getThreshold()); } - + @Override public void handle(Login login) throws Exception { - Preconditions.checkState( thisState == State.LOGIN, "Not expecting LOGIN" ); - - ServerConnection server = new ServerConnection( ch, target ); - ServerConnectedEvent event = new ServerConnectedEvent( user, server ); - bungee.getPluginManager().callEvent( event ); - - ch.write( BungeeCord.getInstance().registerChannels() ); + Preconditions.checkState(thisState == State.LOGIN, "Not expecting LOGIN"); + + ServerConnection server = new ServerConnection(ch, target); + ServerConnectedEvent event = new ServerConnectedEvent(user, server); + bungee.getPluginManager().callEvent(event); + + ch.write(BungeeCord.getInstance().registerChannels()); Queue packetQueue = target.getPacketQueue(); - synchronized ( packetQueue ) + synchronized (packetQueue) { - while ( !packetQueue.isEmpty() ) - { - ch.write( packetQueue.poll() ); - } + while (!packetQueue.isEmpty()) + ch.write(packetQueue.poll()); } for ( PluginMessage message : user.getPendingConnection().getRelayMessages() ) @@ -185,30 +208,51 @@ public void handle(Login login) throws Exception { user.getForgeClientHandler().setHandshakeComplete(); } - - if ( user.getServer() == null ) + + if (user.getServer() == null) { // Once again, first connection - user.setClientEntityId( login.getEntityId() ); - user.setServerEntityId( login.getEntityId() ); - + user.setClientEntityId(login.getEntityId()); + user.setServerEntityId(login.getEntityId()); + // Set tab list size, this sucks balls, TODO: what shall we do about packet mutability - Login modLogin = new Login( login.getEntityId(), login.getGameMode(), (byte) login.getDimension(), login.getDifficulty(), - (byte) user.getPendingConnection().getListener().getTabListSize(), login.getLevelType(), login.isReducedDebugInfo() ); + // Forge allows dimension ID's > 127 + + Login modLogin; + if ( handshakeHandler != null && handshakeHandler.isServerForge() ) + { + modLogin = new Login( login.getEntityId(), login.getGameMode(), login.getDimension(), login.getDifficulty(), + (byte) user.getPendingConnection().getListener().getTabListSize(), login.getLevelType(), login.isReducedDebugInfo() ); + } + else + { + modLogin = new Login( login.getEntityId(), login.getGameMode(), (byte) login.getDimension(), login.getDifficulty(), + (byte) user.getPendingConnection().getListener().getTabListSize(), login.getLevelType(), login.isReducedDebugInfo() ); + } user.unsafe().sendPacket( modLogin ); - ByteBuf brand = ByteBufAllocator.DEFAULT.heapBuffer(); - DefinedPacket.writeString( bungee.getName() + " (" + bungee.getVersion() + ")", brand ); - user.unsafe().sendPacket( new PluginMessage( "MC|Brand", DefinedPacket.toArray( brand ), handshakeHandler.isServerForge() ) ); - brand.release(); - + if (user.getPendingConnection().getVersion() < ProtocolConstants.MINECRAFT_1_8) + { + MinecraftOutput out = new MinecraftOutput(); + out.writeStringUTF8WithoutLengthHeaderBecauseDinnerboneStuffedUpTheMCBrandPacket(ProxyServer.getInstance().getName() + " (" + ProxyServer.getInstance().getVersion() + ")"); + user.unsafe().sendPacket(new PluginMessage("MC|Brand", out.toArray(), handshakeHandler.isServerForge())); + } + else + { + ByteBuf brand = ByteBufAllocator.DEFAULT.heapBuffer(); + DefinedPacket.writeString( bungee.getName() + " (" + bungee.getVersion() + ")", brand ); + user.unsafe().sendPacket( new PluginMessage( "MC|Brand", DefinedPacket.toArray( brand ), handshakeHandler.isServerForge() ) ); + brand.release(); + } + user.setDimension( login.getDimension() ); - } else + } + else { - user.getServer().setObsolete( true ); + user.getServer().setObsolete(true); user.getTabListHandler().onServerChange(); - + Scoreboard serverScoreboard = user.getServerSentScoreboard(); for ( Objective objective : serverScoreboard.getObjectives() ) { @@ -219,16 +263,12 @@ public void handle(Login login) throws Exception user.unsafe().sendPacket( new ScoreboardScore( score.getItemName(), (byte) 1, score.getScoreName(), score.getValue() ) ); } for ( Team team : serverScoreboard.getTeams() ) - { - user.unsafe().sendPacket( new net.md_5.bungee.protocol.packet.Team( team.getName() ) ); - } + user.unsafe().sendPacket(new net.md_5.bungee.protocol.packet.Team(team.getName())); serverScoreboard.clear(); - - for ( UUID bossbar : user.getSentBossBars() ) - { + + for (UUID bossbar : user.getSentBossBars()) // Send remove bossbar packet - user.unsafe().sendPacket( new net.md_5.bungee.protocol.packet.BossBar( bossbar, 1 ) ); - } + user.unsafe().sendPacket(new net.md_5.bungee.protocol.packet.BossBar(bossbar, 1)); user.getSentBossBars().clear(); user.setDimensionChange( true ); @@ -242,117 +282,107 @@ public void handle(Login login) throws Exception user.setDimension( login.getDimension() ); // Remove from old servers - user.getServer().disconnect( "Quitting" ); + user.getServer().disconnect("Quitting"); } - + // TODO: Fix this? - if ( !user.isActive() ) + if (!user.isActive()) { - server.disconnect( "Quitting" ); + server.disconnect("Quitting"); // Silly server admins see stack trace and die - bungee.getLogger().warning( "No client connected for pending server!" ); + bungee.getLogger().warning("No client connected for pending server!"); return; } - + // Add to new server // TODO: Move this to the connected() method of DownstreamBridge - target.addPlayer( user ); - user.getPendingConnects().remove( target ); - user.setServerJoinQueue( null ); - user.setDimensionChange( false ); - - user.setServer( server ); - ch.getHandle().pipeline().get( HandlerBoss.class ).setHandler( new DownstreamBridge( bungee, user, server ) ); - - bungee.getPluginManager().callEvent( new ServerSwitchEvent( user ) ); - + target.addPlayer(user); + user.getPendingConnects().remove(target); + user.setServerJoinQueue(null); + user.setDimensionChange(false); + + user.setServer(server); + ch.getHandle().pipeline().get(HandlerBoss.class).setHandler(new DownstreamBridge(bungee, user, server)); + + bungee.getPluginManager().callEvent(new ServerSwitchEvent(user)); + thisState = State.FINISHED; - + throw CancelSendSignal.INSTANCE; } - + @Override public void handle(EncryptionRequest encryptionRequest) throws Exception { - throw new RuntimeException( "Server is online mode!" ); + throw new RuntimeException("Server is online mode!"); } - + @Override public void handle(Kick kick) throws Exception { - ServerInfo def = user.updateAndGetNextServer( target ); - ServerKickEvent event = new ServerKickEvent( user, target, ComponentSerializer.parse( kick.getMessage() ), def, ServerKickEvent.State.CONNECTING ); - if ( event.getKickReason().toLowerCase().contains( "outdated" ) && def != null ) - { + ServerInfo def = user.updateAndGetNextServer(target); + ServerKickEvent event = new ServerKickEvent(user, target, ComponentSerializer.parse(kick.getMessage()), def, ServerKickEvent.State.CONNECTING); + if (event.getKickReason().toLowerCase().contains("outdated") && def != null) // Pre cancel the event if we are going to try another server - event.setCancelled( true ); - } - bungee.getPluginManager().callEvent( event ); - if ( event.isCancelled() && event.getCancelServer() != null ) + event.setCancelled(true); + bungee.getPluginManager().callEvent(event); + if (event.isCancelled() && event.getCancelServer() != null) { obsolete = true; - user.connect( event.getCancelServer() ); + user.connect(event.getCancelServer()); throw CancelSendSignal.INSTANCE; } - - String message = bungee.getTranslation( "connect_kick", target.getName(), event.getKickReason() ); - if ( user.isDimensionChange() ) - { - user.disconnect( message ); - } else - { - user.sendMessage( message ); - } - + + String message = bungee.getTranslation("connect_kick", target.getName(), event.getKickReason()); + if (user.isDimensionChange()) + user.disconnect(message); + else + user.sendMessage(message); + throw CancelSendSignal.INSTANCE; } - + @Override public void handle(PluginMessage pluginMessage) throws Exception { - if ( pluginMessage.getTag().equals( ForgeConstants.FML_REGISTER ) ) + if (pluginMessage.getTag().equals(ForgeConstants.FML_REGISTER)) { - Set channels = ForgeUtils.readRegisteredChannels( pluginMessage ); + Set channels = ForgeUtils.readRegisteredChannels(pluginMessage); boolean isForgeServer = false; - for ( String channel : channels ) - { - if ( channel.equals( ForgeConstants.FML_HANDSHAKE_TAG ) ) + for (String channel : channels) + if (channel.equals(ForgeConstants.FML_HANDSHAKE_TAG)) { // If we have a completed handshake and we have been asked to register a FML|HS // packet, let's send the reset packet now. Then, we can continue the message sending. // The handshake will not be complete if we reset this earlier. - if ( user.getServer() != null && user.getForgeClientHandler().isHandshakeComplete() ) - { + if (user.getServer() != null && user.getForgeClientHandler().isHandshakeComplete()) user.getForgeClientHandler().resetHandshake(); - } - + isForgeServer = true; break; } - } - - if ( isForgeServer && !this.handshakeHandler.isServerForge() ) + + if (isForgeServer && !this.handshakeHandler.isServerForge()) { // We now set the server-side handshake handler for the client to this. handshakeHandler.setServerAsForgeServer(); - user.setForgeServerHandler( handshakeHandler ); + user.setForgeServerHandler(handshakeHandler); } } - - if ( pluginMessage.getTag().equals( ForgeConstants.FML_HANDSHAKE_TAG ) || pluginMessage.getTag().equals( ForgeConstants.FORGE_REGISTER ) ) + + if (!handshakeHandler.isHandshakeComplete() && ( pluginMessage.getTag().equals(ForgeConstants.FML_HANDSHAKE_TAG) || pluginMessage.getTag().equals(ForgeConstants.FORGE_REGISTER ) )) { - this.handshakeHandler.handle( pluginMessage ); - + handshakeHandler.handle( pluginMessage ); + // We send the message as part of the handler, so don't send it here. throw CancelSendSignal.INSTANCE; - } else - { + } + else // We have to forward these to the user, especially with Forge as stuff might break // This includes any REGISTER messages we intercepted earlier. - user.unsafe().sendPacket( pluginMessage ); - } + user.unsafe().sendPacket(pluginMessage); } - + @Override public String toString() { 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 93df974770..2ef0d74d8c 100644 --- a/proxy/src/main/java/net/md_5/bungee/UserConnection.java +++ b/proxy/src/main/java/net/md_5/bungee/UserConnection.java @@ -56,7 +56,6 @@ import net.md_5.bungee.protocol.packet.Kick; import net.md_5.bungee.protocol.packet.PlayerListHeaderFooter; import net.md_5.bungee.protocol.packet.PluginMessage; -import net.md_5.bungee.protocol.packet.Respawn; import net.md_5.bungee.protocol.packet.SetCompression; import net.md_5.bungee.tab.ServerUnique; import net.md_5.bungee.tab.TabList; @@ -178,8 +177,12 @@ public void init() forgeClientHandler = new ForgeClientHandler( this ); + // No-config FML handshake marker. // Set whether the connection has a 1.8 FML marker in the handshake. - forgeClientHandler.setFmlTokenInHandshake( this.getPendingConnection().getExtraDataInHandshake().contains( ForgeConstants.FML_HANDSHAKE_TOKEN ) ); + if (this.getPendingConnection().getExtraDataInHandshake().contains( ForgeConstants.FML_HANDSHAKE_TOKEN )) + { + forgeClientHandler.setFmlTokenInHandshake( true ); + } } public void sendPacket(PacketWrapper packet) @@ -197,6 +200,10 @@ public boolean isActive() public void setDisplayName(String name) { Preconditions.checkNotNull( name, "displayName" ); + if( pendingConnection.getVersion() <= ProtocolConstants.MINECRAFT_1_7_6 ) + { + Preconditions.checkArgument( name.length() <= 16, "Display name cannot be longer than 16 characters" ); + } displayName = name; } @@ -419,7 +426,7 @@ private void sendMessage(ChatMessageType position, String message) public void sendMessage(ChatMessageType position, BaseComponent... message) { // Action bar doesn't display the new JSON formattings, legacy works - send it using this for now - if ( position == ChatMessageType.ACTION_BAR ) + if ( position == ChatMessageType.ACTION_BAR && pendingConnection.getVersion() >= ProtocolConstants.MINECRAFT_1_8 ) { sendMessage( position, ComponentSerializer.toString( new TextComponent( BaseComponent.toLegacyText( message ) ) ) ); } else @@ -432,7 +439,7 @@ public void sendMessage(ChatMessageType position, BaseComponent... message) public void sendMessage(ChatMessageType position, BaseComponent message) { // Action bar doesn't display the new JSON formattings, legacy works - send it using this for now - if ( position == ChatMessageType.ACTION_BAR ) + if ( position == ChatMessageType.ACTION_BAR && pendingConnection.getVersion() >= ProtocolConstants.MINECRAFT_1_8 ) { sendMessage( position, ComponentSerializer.toString( new TextComponent( BaseComponent.toLegacyText( message ) ) ) ); } else @@ -613,19 +620,25 @@ public Map getModList() @Override public void setTabHeader(BaseComponent header, BaseComponent footer) { - unsafe().sendPacket( new PlayerListHeaderFooter( - ( header != null ) ? ComponentSerializer.toString( header ) : EMPTY_TEXT, - ( footer != null ) ? ComponentSerializer.toString( footer ) : EMPTY_TEXT - ) ); + if ( pendingConnection.getVersion() >= ProtocolConstants.MINECRAFT_1_8 ) + { + unsafe().sendPacket( new PlayerListHeaderFooter( + ( header != null ) ? ComponentSerializer.toString( header ) : EMPTY_TEXT, + ( footer != null ) ? ComponentSerializer.toString( footer ) : EMPTY_TEXT + ) ); + } } @Override public void setTabHeader(BaseComponent[] header, BaseComponent[] footer) { - unsafe().sendPacket( new PlayerListHeaderFooter( - ( header != null ) ? ComponentSerializer.toString( header ) : EMPTY_TEXT, - ( footer != null ) ? ComponentSerializer.toString( footer ) : EMPTY_TEXT - ) ); + if ( pendingConnection.getVersion() >= ProtocolConstants.MINECRAFT_1_8 ) + { + unsafe().sendPacket( new PlayerListHeaderFooter( + ( header != null ) ? ComponentSerializer.toString( header ) : EMPTY_TEXT, + ( footer != null ) ? ComponentSerializer.toString( footer ) : EMPTY_TEXT + ) ); + } } @Override @@ -648,7 +661,7 @@ public String getExtraDataInHandshake() public void setCompressionThreshold(int compressionThreshold) { - if ( !ch.isClosing() && this.compressionThreshold == -1 && compressionThreshold >= 0 ) + if ( !ch.isClosing() && this.compressionThreshold == -1 && getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_8 && compressionThreshold >= 0 ) { this.compressionThreshold = compressionThreshold; unsafe.sendPacket( new SetCompression( compressionThreshold ) ); diff --git a/proxy/src/main/java/net/md_5/bungee/command/CommandBungee.java b/proxy/src/main/java/net/md_5/bungee/command/CommandBungee.java index b07987915f..5bb1dee6cd 100644 --- a/proxy/src/main/java/net/md_5/bungee/command/CommandBungee.java +++ b/proxy/src/main/java/net/md_5/bungee/command/CommandBungee.java @@ -16,6 +16,7 @@ public CommandBungee() @Override public void execute(CommandSender sender, String[] args) { - sender.sendMessage( ChatColor.BLUE + "This server is running BungeeCord version " + ProxyServer.getInstance().getVersion() + " by md_5" ); + sender.sendMessage( ChatColor.BLUE + "This server is running " + ProxyServer.getInstance().getName() + " version " + ProxyServer.getInstance().getVersion() + " by md_5" ); + sender.sendMessage( ChatColor.BLUE + "Protocol support for 1.7.x by Zartec, ghac and I9hdkill" ); } } diff --git a/proxy/src/main/java/net/md_5/bungee/conf/Configuration.java b/proxy/src/main/java/net/md_5/bungee/conf/Configuration.java index 907246a98a..8b776dbad1 100644 --- a/proxy/src/main/java/net/md_5/bungee/conf/Configuration.java +++ b/proxy/src/main/java/net/md_5/bungee/conf/Configuration.java @@ -57,6 +57,8 @@ public class Configuration implements ProxyConfig private boolean ipForward; private Favicon favicon; private int compressionThreshold = 256; + private String customServerName = "HexaCord"; + private boolean alwaysHandlePackets = false; private boolean preventProxyConnections; public void load() @@ -85,6 +87,8 @@ public void load() throttle = adapter.getInt( "connection_throttle", throttle ); ipForward = adapter.getBoolean( "ip_forward", ipForward ); compressionThreshold = adapter.getInt( "network_compression_threshold", compressionThreshold ); + customServerName = adapter.getString( "custom_server_name", "HexaCord" ); + alwaysHandlePackets = adapter.getBoolean( "always_handle_packets", false ); preventProxyConnections = adapter.getBoolean( "prevent_proxy_connections", preventProxyConnections ); disabledCommands = new CaseInsensitiveSet( (Collection) adapter.getList( "disabled_commands", Arrays.asList( "disabledcommandhere" ) ) ); @@ -144,4 +148,15 @@ public Favicon getFaviconObject() { return favicon; } + + @Override + public String getCustomServerName() + { + return customServerName; + } + + @Override + public boolean getAlwaysHandlePackets() { + return alwaysHandlePackets; + } } diff --git a/proxy/src/main/java/net/md_5/bungee/connection/DownstreamBridge.java b/proxy/src/main/java/net/md_5/bungee/connection/DownstreamBridge.java index 6b8ae2452c..253126a829 100644 --- a/proxy/src/main/java/net/md_5/bungee/connection/DownstreamBridge.java +++ b/proxy/src/main/java/net/md_5/bungee/connection/DownstreamBridge.java @@ -1,24 +1,27 @@ package net.md_5.bungee.connection; + +import java.io.DataInput; + import com.google.common.base.Preconditions; import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; -import java.io.DataInput; + import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.Unpooled; import lombok.RequiredArgsConstructor; import net.md_5.bungee.ServerConnection; -import net.md_5.bungee.api.chat.TextComponent; -import net.md_5.bungee.api.event.ServerDisconnectEvent; -import net.md_5.bungee.api.event.TabCompleteResponseEvent; import net.md_5.bungee.UserConnection; import net.md_5.bungee.Util; import net.md_5.bungee.api.ProxyServer; +import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.config.ServerInfo; import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.event.PluginMessageEvent; +import net.md_5.bungee.api.event.ServerDisconnectEvent; import net.md_5.bungee.api.event.ServerKickEvent; +import net.md_5.bungee.api.event.TabCompleteResponseEvent; import net.md_5.bungee.api.score.Objective; import net.md_5.bungee.api.score.Position; import net.md_5.bungee.api.score.Score; @@ -29,105 +32,100 @@ import net.md_5.bungee.netty.PacketHandler; import net.md_5.bungee.protocol.DefinedPacket; import net.md_5.bungee.protocol.PacketWrapper; +import net.md_5.bungee.protocol.ProtocolConstants; import net.md_5.bungee.protocol.packet.BossBar; import net.md_5.bungee.protocol.packet.KeepAlive; +import net.md_5.bungee.protocol.packet.Kick; import net.md_5.bungee.protocol.packet.PlayerListItem; +import net.md_5.bungee.protocol.packet.PluginMessage; import net.md_5.bungee.protocol.packet.Respawn; +import net.md_5.bungee.protocol.packet.ScoreboardDisplay; import net.md_5.bungee.protocol.packet.ScoreboardObjective; import net.md_5.bungee.protocol.packet.ScoreboardScore; -import net.md_5.bungee.protocol.packet.ScoreboardDisplay; -import net.md_5.bungee.protocol.packet.PluginMessage; -import net.md_5.bungee.protocol.packet.Kick; import net.md_5.bungee.protocol.packet.SetCompression; import net.md_5.bungee.protocol.packet.TabCompleteResponse; import net.md_5.bungee.tab.TabList; + @RequiredArgsConstructor public class DownstreamBridge extends PacketHandler { - - private final ProxyServer bungee; - private final UserConnection con; + + private final ProxyServer bungee; + private final UserConnection con; private final ServerConnection server; - + @Override public void exception(Throwable t) throws Exception { - if ( server.isObsolete() ) - { + if (server.isObsolete()) // do not perform any actions if the user has already moved return; - } ServerInfo def = con.updateAndGetNextServer( server.getInfo() ); if ( def != null ) { - server.setObsolete( true ); - con.connectNow( def ); - con.sendMessage( bungee.getTranslation( "server_went_down" ) ); - } else - { - con.disconnect( Util.exception( t ) ); + server.setObsolete(true); + con.connectNow(def); + con.sendMessage(bungee.getTranslation("server_went_down")); } + else + con.disconnect(Util.exception(t)); } - + @Override public void disconnected(ChannelWrapper channel) throws Exception { // We lost connection to the server - server.getInfo().removePlayer( con ); - if ( bungee.getReconnectHandler() != null ) - { - bungee.getReconnectHandler().setServer( con ); - } - - if ( !server.isObsolete() ) - { - con.disconnect( bungee.getTranslation( "lost_connection" ) ); - } - - ServerDisconnectEvent serverDisconnectEvent = new ServerDisconnectEvent( con, server.getInfo() ); - bungee.getPluginManager().callEvent( serverDisconnectEvent ); + server.getInfo().removePlayer(con); + if (bungee.getReconnectHandler() != null) + bungee.getReconnectHandler().setServer(con); + + if (!server.isObsolete()) + con.disconnect(bungee.getTranslation("lost_connection")); + + ServerDisconnectEvent serverDisconnectEvent = new ServerDisconnectEvent(con, server.getInfo()); + bungee.getPluginManager().callEvent(serverDisconnectEvent); } - + @Override public boolean shouldHandle(PacketWrapper packet) throws Exception { return !server.isObsolete(); } - + @Override public void handle(PacketWrapper packet) throws Exception { - con.getEntityRewrite().rewriteClientbound( packet.buf, con.getServerEntityId(), con.getClientEntityId() ); - con.sendPacket( packet ); + con.getEntityRewrite().rewriteClientbound(packet.buf, con.getServerEntityId(), con.getClientEntityId()); + con.sendPacket(packet); } - + @Override public void handle(KeepAlive alive) throws Exception { server.setSentPingId( alive.getRandomId() ); con.setSentPingTime( System.currentTimeMillis() ); } - + @Override public void handle(PlayerListItem playerList) throws Exception { - con.getTabListHandler().onUpdate( TabList.rewrite( playerList ) ); + con.getTabListHandler().onUpdate(TabList.rewrite(playerList)); throw CancelSendSignal.INSTANCE; // Always throw because of profile rewriting } - + @Override public void handle(ScoreboardObjective objective) throws Exception { Scoreboard serverScoreboard = con.getServerSentScoreboard(); - switch ( objective.getAction() ) + switch (objective.getAction()) { case 0: - serverScoreboard.addObjective( new Objective( objective.getName(), objective.getValue(), objective.getType() ) ); + serverScoreboard.addObjective(new Objective(objective.getName(), objective.getValue(), objective.getType())); break; case 1: - serverScoreboard.removeObjective( objective.getName() ); + serverScoreboard.removeObjective(objective.getName()); break; case 2: Objective oldObjective = serverScoreboard.getObjective( objective.getName() ); @@ -138,59 +136,58 @@ public void handle(ScoreboardObjective objective) throws Exception } break; default: - throw new IllegalArgumentException( "Unknown objective action: " + objective.getAction() ); + throw new IllegalArgumentException("Unknown objective action: " + objective.getAction()); } } - + @Override public void handle(ScoreboardScore score) throws Exception { Scoreboard serverScoreboard = con.getServerSentScoreboard(); - switch ( score.getAction() ) + switch (score.getAction()) { case 0: - Score s = new Score( score.getItemName(), score.getScoreName(), score.getValue() ); - serverScoreboard.removeScore( score.getItemName() ); - serverScoreboard.addScore( s ); + Score s = new Score(score.getItemName(), score.getScoreName(), score.getValue()); + serverScoreboard.removeScore(score.getItemName()); + serverScoreboard.addScore(s); break; case 1: - serverScoreboard.removeScore( score.getItemName() ); + serverScoreboard.removeScore(score.getItemName()); break; default: - throw new IllegalArgumentException( "Unknown scoreboard action: " + score.getAction() ); + throw new IllegalArgumentException("Unknown scoreboard action: " + score.getAction()); } } - + @Override public void handle(ScoreboardDisplay displayScoreboard) throws Exception { Scoreboard serverScoreboard = con.getServerSentScoreboard(); - serverScoreboard.setName( displayScoreboard.getName() ); - serverScoreboard.setPosition( Position.values()[displayScoreboard.getPosition()] ); + serverScoreboard.setName(displayScoreboard.getName()); + serverScoreboard.setPosition(Position.values()[displayScoreboard.getPosition()]); } - + @Override public void handle(net.md_5.bungee.protocol.packet.Team team) throws Exception { Scoreboard serverScoreboard = con.getServerSentScoreboard(); // Remove team and move on - if ( team.getMode() == 1 ) + if (team.getMode() == 1) { - serverScoreboard.removeTeam( team.getName() ); + serverScoreboard.removeTeam(team.getName()); return; } - + // Create or get old team Team t; - if ( team.getMode() == 0 ) + if (team.getMode() == 0) { - t = new Team( team.getName() ); - serverScoreboard.addTeam( t ); - } else - { - t = serverScoreboard.getTeam( team.getName() ); + t = new Team(team.getName()); + serverScoreboard.addTeam(t); } - + else + t = serverScoreboard.getTeam(team.getName()); + if ( t != null ) { if ( team.getMode() == 0 || team.getMode() == 2 ) @@ -218,238 +215,233 @@ public void handle(net.md_5.bungee.protocol.packet.Team team) throws Exception } } } - + @Override public void handle(PluginMessage pluginMessage) throws Exception { DataInput in = pluginMessage.getStream(); - PluginMessageEvent event = new PluginMessageEvent( con.getServer(), con, pluginMessage.getTag(), pluginMessage.getData().clone() ); - - if ( bungee.getPluginManager().callEvent( event ).isCancelled() ) - { + PluginMessageEvent event = new PluginMessageEvent(con.getServer(), con, pluginMessage.getTag(), pluginMessage.getData().clone()); + + if (bungee.getPluginManager().callEvent(event).isCancelled()) throw CancelSendSignal.INSTANCE; - } - - if ( pluginMessage.getTag().equals( "MC|Brand" ) ) + + if (pluginMessage.getTag().equals("MC|Brand")) { - ByteBuf brand = Unpooled.wrappedBuffer( pluginMessage.getData() ); - String serverBrand = DefinedPacket.readString( brand ); - brand.release(); + if (con.getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_8) + { + ByteBuf brand = Unpooled.wrappedBuffer(pluginMessage.getData()); + String serverBrand = DefinedPacket.readString(brand); + brand.release(); + + Preconditions.checkState( !serverBrand.contains( bungee.getName() ), "Cannot connect proxy to itself!" ); + + brand = ByteBufAllocator.DEFAULT.heapBuffer(); + DefinedPacket.writeString(bungee.getName() + " (" + bungee.getVersion() + ")" + " <- " + serverBrand, brand); + pluginMessage.setData(DefinedPacket.readArray( brand )); + brand.release(); + } + else + { + String serverBrand = new String(pluginMessage.getData(), "UTF-8"); - Preconditions.checkState( !serverBrand.contains( bungee.getName() ), "Cannot connect proxy to itself!" ); + Preconditions.checkState( !serverBrand.contains( bungee.getName() ), "Cannot connect proxy to itself!" ); - brand = ByteBufAllocator.DEFAULT.heapBuffer(); - DefinedPacket.writeString( bungee.getName() + " (" + bungee.getVersion() + ")" + " <- " + serverBrand, brand ); - pluginMessage.setData( DefinedPacket.toArray( brand ) ); - brand.release(); + pluginMessage.setData((bungee.getName() + " (" + bungee.getVersion() + ")" + " <- " + serverBrand).getBytes("UTF-8")); + } // changes in the packet are ignored so we need to send it manually - con.unsafe().sendPacket( pluginMessage ); + con.unsafe().sendPacket(pluginMessage); throw CancelSendSignal.INSTANCE; } - - if ( pluginMessage.getTag().equals( "BungeeCord" ) ) + + if (pluginMessage.getTag().equals("BungeeCord")) { ByteArrayDataOutput out = ByteStreams.newDataOutput(); String subChannel = in.readUTF(); - - if ( subChannel.equals( "ForwardToPlayer" ) ) + + if (subChannel.equals("ForwardToPlayer")) { - ProxiedPlayer target = bungee.getPlayer( in.readUTF() ); - if ( target != null ) + ProxiedPlayer target = bungee.getPlayer(in.readUTF()); + if (target != null) { // Read data from server String channel = in.readUTF(); short len = in.readShort(); - byte[] data = new byte[ len ]; - in.readFully( data ); - + byte[] data = new byte[len]; + in.readFully(data); + // Prepare new data to send - out.writeUTF( channel ); - out.writeShort( data.length ); - out.write( data ); + out.writeUTF(channel); + out.writeShort(data.length); + out.write(data); byte[] payload = out.toByteArray(); - - target.getServer().sendData( "BungeeCord", payload ); + + target.getServer().sendData("BungeeCord", payload); } - + // Null out stream, important as we don't want to send to ourselves out = null; } - if ( subChannel.equals( "Forward" ) ) + if (subChannel.equals("Forward")) { // Read data from server String target = in.readUTF(); String channel = in.readUTF(); short len = in.readShort(); - byte[] data = new byte[ len ]; - in.readFully( data ); - + byte[] data = new byte[len]; + in.readFully(data); + // Prepare new data to send - out.writeUTF( channel ); - out.writeShort( data.length ); - out.write( data ); + out.writeUTF(channel); + out.writeShort(data.length); + out.write(data); byte[] payload = out.toByteArray(); - + // Null out stream, important as we don't want to send to ourselves out = null; - - if ( target.equals( "ALL" ) ) + + if (target.equals("ALL")) { - for ( ServerInfo server : bungee.getServers().values() ) - { - if ( server != con.getServer().getInfo() ) - { - server.sendData( "BungeeCord", payload ); - } - } - } else if ( target.equals( "ONLINE" ) ) + for (ServerInfo server : bungee.getServers().values()) + if (server != con.getServer().getInfo()) + server.sendData("BungeeCord", payload); + } + else if (target.equals("ONLINE")) { - for ( ServerInfo server : bungee.getServers().values() ) - { - if ( server != con.getServer().getInfo() ) - { - server.sendData( "BungeeCord", payload, false ); - } - } - } else + for (ServerInfo server : bungee.getServers().values()) + if (server != con.getServer().getInfo()) + server.sendData("BungeeCord", payload, false); + } + else { - ServerInfo server = bungee.getServerInfo( target ); - if ( server != null ) - { - server.sendData( "BungeeCord", payload ); - } + ServerInfo server = bungee.getServerInfo(target); + if (server != null) + server.sendData("BungeeCord", payload); } } - if ( subChannel.equals( "Connect" ) ) + if (subChannel.equals("Connect")) { - ServerInfo server = bungee.getServerInfo( in.readUTF() ); - if ( server != null ) - { - con.connect( server ); - } + ServerInfo server = bungee.getServerInfo(in.readUTF()); + if (server != null) + con.connect(server); } - if ( subChannel.equals( "ConnectOther" ) ) + if (subChannel.equals("ConnectOther")) { - ProxiedPlayer player = bungee.getPlayer( in.readUTF() ); - if ( player != null ) + ProxiedPlayer player = bungee.getPlayer(in.readUTF()); + if (player != null) { - ServerInfo server = bungee.getServerInfo( in.readUTF() ); - if ( server != null ) - { - player.connect( server ); - } + ServerInfo server = bungee.getServerInfo(in.readUTF()); + if (server != null) + player.connect(server); } } - if ( subChannel.equals( "IP" ) ) + if (subChannel.equals("IP")) { - out.writeUTF( "IP" ); - out.writeUTF( con.getAddress().getHostString() ); - out.writeInt( con.getAddress().getPort() ); + out.writeUTF("IP"); + out.writeUTF(con.getAddress().getHostString()); + out.writeInt(con.getAddress().getPort()); } - if ( subChannel.equals( "PlayerCount" ) ) + if (subChannel.equals("PlayerCount")) { String target = in.readUTF(); - out.writeUTF( "PlayerCount" ); - if ( target.equals( "ALL" ) ) + out.writeUTF("PlayerCount"); + if (target.equals("ALL")) { - out.writeUTF( "ALL" ); - out.writeInt( bungee.getOnlineCount() ); - } else + out.writeUTF("ALL"); + out.writeInt(bungee.getOnlineCount()); + } + else { - ServerInfo server = bungee.getServerInfo( target ); - if ( server != null ) + ServerInfo server = bungee.getServerInfo(target); + if (server != null) { - out.writeUTF( server.getName() ); - out.writeInt( server.getPlayers().size() ); + out.writeUTF(server.getName()); + out.writeInt(server.getPlayers().size()); } } } - if ( subChannel.equals( "PlayerList" ) ) + if (subChannel.equals("PlayerList")) { String target = in.readUTF(); - out.writeUTF( "PlayerList" ); - if ( target.equals( "ALL" ) ) + out.writeUTF("PlayerList"); + if (target.equals("ALL")) { - out.writeUTF( "ALL" ); - out.writeUTF( Util.csv( bungee.getPlayers() ) ); - } else + out.writeUTF("ALL"); + out.writeUTF(Util.csv(bungee.getPlayers())); + } + else { - ServerInfo server = bungee.getServerInfo( target ); - if ( server != null ) + ServerInfo server = bungee.getServerInfo(target); + if (server != null) { - out.writeUTF( server.getName() ); - out.writeUTF( Util.csv( server.getPlayers() ) ); + out.writeUTF(server.getName()); + out.writeUTF(Util.csv(server.getPlayers())); } } } - if ( subChannel.equals( "GetServers" ) ) + if (subChannel.equals("GetServers")) { - out.writeUTF( "GetServers" ); - out.writeUTF( Util.csv( bungee.getServers().keySet() ) ); + out.writeUTF("GetServers"); + out.writeUTF(Util.csv(bungee.getServers().keySet())); } - if ( subChannel.equals( "Message" ) ) + if (subChannel.equals("Message")) { - ProxiedPlayer target = bungee.getPlayer( in.readUTF() ); - if ( target != null ) - { - target.sendMessage( in.readUTF() ); - } + ProxiedPlayer target = bungee.getPlayer(in.readUTF()); + if (target != null) + target.sendMessage(in.readUTF()); } - if ( subChannel.equals( "GetServer" ) ) + if (subChannel.equals("GetServer")) { - out.writeUTF( "GetServer" ); - out.writeUTF( server.getInfo().getName() ); + out.writeUTF("GetServer"); + out.writeUTF(server.getInfo().getName()); } - if ( subChannel.equals( "UUID" ) ) + if (subChannel.equals("UUID")) { - out.writeUTF( "UUID" ); - out.writeUTF( con.getUUID() ); + out.writeUTF("UUID"); + out.writeUTF(con.getUUID()); } - if ( subChannel.equals( "UUIDOther" ) ) + if (subChannel.equals("UUIDOther")) { - ProxiedPlayer player = bungee.getPlayer( in.readUTF() ); - if ( player != null ) + ProxiedPlayer player = bungee.getPlayer(in.readUTF()); + if (player != null) { - out.writeUTF( "UUIDOther" ); - out.writeUTF( player.getName() ); - out.writeUTF( player.getUUID() ); + out.writeUTF("UUIDOther"); + out.writeUTF(player.getName()); + out.writeUTF(player.getUUID()); } } - if ( subChannel.equals( "ServerIP" ) ) + if (subChannel.equals("ServerIP")) { - ServerInfo info = bungee.getServerInfo( in.readUTF() ); - if ( info != null ) + ServerInfo info = bungee.getServerInfo(in.readUTF()); + if (info != null) { - out.writeUTF( "ServerIP" ); - out.writeUTF( info.getName() ); - out.writeUTF( info.getAddress().getAddress().getHostAddress() ); - out.writeShort( info.getAddress().getPort() ); + out.writeUTF("ServerIP"); + out.writeUTF(info.getName()); + out.writeUTF(info.getAddress().getAddress().getHostAddress()); + out.writeShort(info.getAddress().getPort()); } } - if ( subChannel.equals( "KickPlayer" ) ) + if (subChannel.equals("KickPlayer")) { - ProxiedPlayer player = bungee.getPlayer( in.readUTF() ); - if ( player != null ) + ProxiedPlayer player = bungee.getPlayer(in.readUTF()); + if (player != null) { String kickReason = in.readUTF(); - player.disconnect( new TextComponent( kickReason ) ); + player.disconnect(new TextComponent(kickReason)); } } - + // Check we haven't set out to null, and we have written data, if so reply back back along the BungeeCord channel - if ( out != null ) + if (out != null) { byte[] b = out.toByteArray(); - if ( b.length != 0 ) - { - con.getServer().sendData( "BungeeCord", b ); - } + if (b.length != 0) + con.getServer().sendData("BungeeCord", b); } - + throw CancelSendSignal.INSTANCE; } } - + @Override public void handle(Kick kick) throws Exception { @@ -465,42 +457,40 @@ public void handle(Kick kick) throws Exception server.setObsolete( true ); throw CancelSendSignal.INSTANCE; } - + @Override public void handle(SetCompression setCompression) throws Exception { - server.getCh().setCompressionThreshold( setCompression.getThreshold() ); + server.getCh().setCompressionThreshold(setCompression.getThreshold()); } - + @Override public void handle(TabCompleteResponse tabCompleteResponse) throws Exception { - TabCompleteResponseEvent tabCompleteResponseEvent = new TabCompleteResponseEvent( con.getServer(), con, tabCompleteResponse.getCommands() ); - - if ( !bungee.getPluginManager().callEvent( tabCompleteResponseEvent ).isCancelled() ) - { - con.unsafe().sendPacket( tabCompleteResponse ); - } - + TabCompleteResponseEvent tabCompleteResponseEvent = new TabCompleteResponseEvent(con.getServer(), con, tabCompleteResponse.getCommands()); + + if (!bungee.getPluginManager().callEvent(tabCompleteResponseEvent).isCancelled()) + con.unsafe().sendPacket(tabCompleteResponse); + throw CancelSendSignal.INSTANCE; } - + @Override public void handle(BossBar bossBar) { - switch ( bossBar.getAction() ) + switch (bossBar.getAction()) { // Handle add bossbar case 0: - con.getSentBossBars().add( bossBar.getUuid() ); + con.getSentBossBars().add(bossBar.getUuid()); break; // Handle remove bossbar case 1: - con.getSentBossBars().remove( bossBar.getUuid() ); + con.getSentBossBars().remove(bossBar.getUuid()); break; } } - + @Override public void handle(Respawn respawn) { 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 e596f82237..7b5157b4e3 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 @@ -222,7 +222,7 @@ public void done(ServerPing result, Throwable error) @Override public void done(ProxyPingEvent pingResult, Throwable error) { - Gson gson = BungeeCord.getInstance().gson; + Gson gson = handshake.getProtocolVersion() == ProtocolConstants.MINECRAFT_1_7_2 ? BungeeCord.getInstance().gsonLegacy : BungeeCord.getInstance().gson; unsafe.sendPacket( new StatusResponse( gson.toJson( pingResult.getResponse() ) ) ); } }; @@ -500,7 +500,13 @@ public void run() userCon.setCompressionThreshold( BungeeCord.getInstance().config.getCompressionThreshold() ); userCon.init(); - unsafe.sendPacket( new LoginSuccess( getUniqueId().toString(), getName() ) ); // With dashes in between + if ( getVersion() >= ProtocolConstants.MINECRAFT_1_7_6 ) + { + unsafe.sendPacket( new LoginSuccess( getUniqueId().toString(), getName() ) ); // With dashes in between + } else + { + unsafe.sendPacket( new LoginSuccess( getUUID(), getName() ) ); // Without dashes, for older clients. + } ch.setProtocol( Protocol.GAME ); ch.getHandle().pipeline().get( HandlerBoss.class ).setHandler( new UpstreamBridge( bungee, userCon ) ); 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 3cd5cf6962..ba3260f399 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 @@ -14,6 +14,7 @@ import net.md_5.bungee.protocol.MinecraftDecoder; import net.md_5.bungee.protocol.MinecraftEncoder; import net.md_5.bungee.protocol.Protocol; +import net.md_5.bungee.protocol.ProtocolConstants; import net.md_5.bungee.protocol.packet.Handshake; import net.md_5.bungee.protocol.packet.StatusRequest; import net.md_5.bungee.protocol.packet.StatusResponse; @@ -52,7 +53,7 @@ public void exception(Throwable t) throws Exception @SuppressFBWarnings("UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR") public void handle(StatusResponse statusResponse) throws Exception { - Gson gson = BungeeCord.getInstance().gson; + Gson gson = protocol == ProtocolConstants.MINECRAFT_1_7_2 ? BungeeCord.getInstance().gsonLegacy : BungeeCord.getInstance().gson; callback.done( gson.fromJson( statusResponse.getResponse(), ServerPing.class ), null ); channel.close(); } diff --git a/proxy/src/main/java/net/md_5/bungee/connection/UpstreamBridge.java b/proxy/src/main/java/net/md_5/bungee/connection/UpstreamBridge.java index bb43810bbc..52e2ca17e1 100644 --- a/proxy/src/main/java/net/md_5/bungee/connection/UpstreamBridge.java +++ b/proxy/src/main/java/net/md_5/bungee/connection/UpstreamBridge.java @@ -75,7 +75,10 @@ public void disconnected(ChannelWrapper channel) throws Exception } ); for ( ProxiedPlayer player : con.getServer().getInfo().getPlayers() ) { - player.unsafe().sendPacket( packet ); + if ( player.getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_8 ) + { + player.unsafe().sendPacket( packet ); + } } con.getServer().disconnect( "Quitting" ); } @@ -100,7 +103,7 @@ public void writabilityChanged(ChannelWrapper channel) throws Exception @Override public boolean shouldHandle(PacketWrapper packet) throws Exception { - return con.getServer() != null || packet.packet instanceof PluginMessage; + return bungee.getConfig().getAlwaysHandlePackets() || con.getServer() != null || packet.packet instanceof PluginMessage; } @Override diff --git a/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap.java b/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap.java index 847a3ecac7..dc08926ff8 100644 --- a/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap.java +++ b/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap.java @@ -29,6 +29,10 @@ public static EntityMap getEntityMap(int version) { switch ( version ) { + case ProtocolConstants.MINECRAFT_1_7_2: + return EntityMap_1_7_2.INSTANCE; + case ProtocolConstants.MINECRAFT_1_7_6: + return EntityMap_1_7_6.INSTANCE; case ProtocolConstants.MINECRAFT_1_8: return EntityMap_1_8.INSTANCE; case ProtocolConstants.MINECRAFT_1_9: @@ -211,12 +215,14 @@ private static void rewrite(ByteBuf packet, int oldId, int newId, boolean[] ints int packetId = DefinedPacket.readVarInt( packet ); int packetIdLength = packet.readerIndex() - readerIndex; - if ( ints[packetId] ) - { - rewriteInt( packet, oldId, newId, readerIndex + packetIdLength ); - } else if ( varints[packetId] ) - { - rewriteVarInt( packet, oldId, newId, readerIndex + packetIdLength ); + if(packetId>=0) { + if ( ints[ packetId ] ) + { + rewriteInt( packet, oldId, newId, readerIndex + packetIdLength ); + } else if ( varints[ packetId ] ) + { + rewriteVarInt( packet, oldId, newId, readerIndex + packetIdLength ); + } } packet.readerIndex( readerIndex ); } diff --git a/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap_1_7_2.java b/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap_1_7_2.java new file mode 100644 index 0000000000..05097bba44 --- /dev/null +++ b/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap_1_7_2.java @@ -0,0 +1,100 @@ +package net.md_5.bungee.entitymap; + +import io.netty.buffer.ByteBuf; +import net.md_5.bungee.protocol.DefinedPacket; +import net.md_5.bungee.protocol.ProtocolConstants; + +class EntityMap_1_7_2 extends EntityMap +{ + + static final EntityMap INSTANCE = new EntityMap_1_7_2(); + + EntityMap_1_7_2() + { + addRewrite( 0x04, ProtocolConstants.Direction.TO_CLIENT, false ); // Entity Equipment + addRewrite( 0x0A, ProtocolConstants.Direction.TO_CLIENT, false ); // Use bed + addRewrite( 0x0B, ProtocolConstants.Direction.TO_CLIENT, true ); // Animation + addRewrite( 0x0C, ProtocolConstants.Direction.TO_CLIENT, true ); // Spawn Player + addRewrite( 0x0D, ProtocolConstants.Direction.TO_CLIENT, false ); // Collect Item + addRewrite( 0x0E, ProtocolConstants.Direction.TO_CLIENT, true ); // Spawn Object + addRewrite( 0x0F, ProtocolConstants.Direction.TO_CLIENT, true ); // Spawn Mob + addRewrite( 0x10, ProtocolConstants.Direction.TO_CLIENT, true ); // Spawn Painting + addRewrite( 0x11, ProtocolConstants.Direction.TO_CLIENT, true ); // Spawn Experience Orb + addRewrite( 0x12, ProtocolConstants.Direction.TO_CLIENT, false ); // Entity Velocity + addRewrite( 0x14, ProtocolConstants.Direction.TO_CLIENT, false ); // Entity + addRewrite( 0x15, ProtocolConstants.Direction.TO_CLIENT, false ); // Entity Relative Move + addRewrite( 0x16, ProtocolConstants.Direction.TO_CLIENT, false ); // Entity Look + addRewrite( 0x17, ProtocolConstants.Direction.TO_CLIENT, false ); // Entity Look and Relative Move + addRewrite( 0x18, ProtocolConstants.Direction.TO_CLIENT, false ); // Entity Teleport + addRewrite( 0x19, ProtocolConstants.Direction.TO_CLIENT, false ); // Entity Head Look + addRewrite( 0x1A, ProtocolConstants.Direction.TO_CLIENT, false ); // Entity Status + addRewrite( 0x1B, ProtocolConstants.Direction.TO_CLIENT, false ); // Attach Entity + addRewrite( 0x1C, ProtocolConstants.Direction.TO_CLIENT, false ); // Entity Metadata + addRewrite( 0x1D, ProtocolConstants.Direction.TO_CLIENT, false ); // Entity Effect + addRewrite( 0x1E, ProtocolConstants.Direction.TO_CLIENT, false ); // Remove Entity Effect + addRewrite( 0x20, ProtocolConstants.Direction.TO_CLIENT, false ); // Entity Properties + addRewrite( 0x25, ProtocolConstants.Direction.TO_CLIENT, true ); // Block Break Animation + addRewrite( 0x2C, ProtocolConstants.Direction.TO_CLIENT, true ); // Spawn Global Entity + + addRewrite( 0x02, ProtocolConstants.Direction.TO_SERVER, false ); // Use Entity + addRewrite( 0x0A, ProtocolConstants.Direction.TO_SERVER, false ); // Animation + addRewrite( 0x0B, ProtocolConstants.Direction.TO_SERVER, false ); // Entity Action + } + + @Override + public void rewriteClientbound(ByteBuf packet, int oldId, int newId) + { + super.rewriteClientbound( packet, oldId, newId ); + + //Special cases + int readerIndex = packet.readerIndex(); + int packetId = DefinedPacket.readVarInt( packet ); + int packetIdLength = packet.readerIndex() - readerIndex; + if ( packetId == 0x0D /* Collect Item */ || packetId == 0x1B /* Attach Entity */ ) + { + rewriteInt( packet, oldId, newId, readerIndex + packetIdLength + 4 ); + } else if ( packetId == 0x13 /* Destroy Entities */ ) + { + int count = packet.getByte( packetIdLength ); + for ( int i = 0; i < count; i++ ) + { + rewriteInt( packet, oldId, newId, packetIdLength + 1 + i * 4 ); + } + } else if ( packetId == 0x0E /* Spawn Object */ ) + { + DefinedPacket.readVarInt( packet ); + int type = packet.readUnsignedByte(); + + if ( type == 60 || type == 90 ) + { + packet.skipBytes( 14 ); + int position = packet.readerIndex(); + int readId = packet.readInt(); + int changedId = -1; + if ( readId == oldId ) + { + packet.setInt( position, newId ); + changedId = newId; + } else if ( readId == newId ) + { + packet.setInt( position, oldId ); + changedId = oldId; + } + if ( changedId != -1 ) + { + if ( changedId == 0 && readId != 0 ) + { // Trim off the extra data + packet.readerIndex( readerIndex ); + packet.writerIndex( packet.readableBytes() - 6 ); + } else if ( changedId != 0 && readId == 0 ) + { // Add on the extra data + packet.readerIndex( readerIndex ); + packet.capacity( packet.readableBytes() + 6 ); + packet.writerIndex( packet.readableBytes() + 6 ); + } + } + } + } + packet.readerIndex( readerIndex ); + } +} diff --git a/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap_1_7_6.java b/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap_1_7_6.java new file mode 100644 index 0000000000..301da0e700 --- /dev/null +++ b/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap_1_7_6.java @@ -0,0 +1,60 @@ +package net.md_5.bungee.entitymap; + +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import io.netty.buffer.ByteBuf; +import net.md_5.bungee.BungeeCord; +import net.md_5.bungee.UserConnection; +import net.md_5.bungee.connection.LoginResult; +import net.md_5.bungee.protocol.DefinedPacket; + +class EntityMap_1_7_6 extends EntityMap_1_7_2 +{ + + static final EntityMap_1_7_6 INSTANCE = new EntityMap_1_7_6(); + + @Override + @SuppressFBWarnings("DLS_DEAD_LOCAL_STORE") + public void rewriteClientbound(ByteBuf packet, int oldId, int newId) + { + super.rewriteClientbound( packet, oldId, newId ); + + int readerIndex = packet.readerIndex(); + int packetId = DefinedPacket.readVarInt( packet ); + int packetIdLength = packet.readerIndex() - readerIndex; + if ( packetId == 0x0C /* Spawn Player */ ) + { + DefinedPacket.readVarInt( packet ); + int idLength = packet.readerIndex() - readerIndex - packetIdLength; + String uuid = DefinedPacket.readString( packet ); + String username = DefinedPacket.readString( packet ); + int props = DefinedPacket.readVarInt( packet ); + if ( props == 0 ) + { + UserConnection player = (UserConnection) BungeeCord.getInstance().getPlayer( username ); + if ( player != null ) + { + LoginResult profile = player.getPendingConnection().getLoginProfile(); + if ( profile != null && profile.getProperties() != null + && profile.getProperties().length >= 1 ) + { + ByteBuf rest = packet.copy(); + packet.readerIndex( readerIndex ); + packet.writerIndex( readerIndex + packetIdLength + idLength ); + DefinedPacket.writeString( player.getUniqueId().toString(), packet ); + DefinedPacket.writeString( username, packet ); + DefinedPacket.writeVarInt( profile.getProperties().length, packet ); + for ( LoginResult.Property property : profile.getProperties() ) + { + DefinedPacket.writeString( property.getName(), packet ); + DefinedPacket.writeString( property.getValue(), packet ); + DefinedPacket.writeString( property.getSignature(), packet ); + } + packet.writeBytes( rest ); + rest.release(); + } + } + } + } + packet.readerIndex( readerIndex ); + } +} diff --git a/proxy/src/main/java/net/md_5/bungee/forge/ForgeConstants.java b/proxy/src/main/java/net/md_5/bungee/forge/ForgeConstants.java index 6dca204830..f5253b897b 100644 --- a/proxy/src/main/java/net/md_5/bungee/forge/ForgeConstants.java +++ b/proxy/src/main/java/net/md_5/bungee/forge/ForgeConstants.java @@ -14,6 +14,10 @@ public class ForgeConstants public static final String FML_HANDSHAKE_TAG = "FML|HS"; public static final String FML_REGISTER = "REGISTER"; + // Game profile key + public static final String FML_LOGIN_PROFILE = "forgeClient"; + public static final String EXTRA_DATA = "extraData"; + /** * The FML 1.8 handshake token. */ diff --git a/proxy/src/main/java/net/md_5/bungee/forge/ForgeServerHandler.java b/proxy/src/main/java/net/md_5/bungee/forge/ForgeServerHandler.java index 3fe5ec5fd3..56215d4b1c 100644 --- a/proxy/src/main/java/net/md_5/bungee/forge/ForgeServerHandler.java +++ b/proxy/src/main/java/net/md_5/bungee/forge/ForgeServerHandler.java @@ -82,4 +82,15 @@ public void setServerAsForgeServer() { serverForge = true; } + + + /** + * Returns whether the handshake is complete. + * + * @return true if the handshake has been completed. + */ + public boolean isHandshakeComplete() + { + return this.state == ForgeServerHandshakeState.DONE; + } } diff --git a/proxy/src/main/java/net/md_5/bungee/forge/ForgeServerHandshakeState.java b/proxy/src/main/java/net/md_5/bungee/forge/ForgeServerHandshakeState.java index d58b4945fd..00f92ad7d5 100644 --- a/proxy/src/main/java/net/md_5/bungee/forge/ForgeServerHandshakeState.java +++ b/proxy/src/main/java/net/md_5/bungee/forge/ForgeServerHandshakeState.java @@ -132,6 +132,9 @@ public ForgeServerHandshakeState handle(PluginMessage message, ChannelWrapper ch @Override public ForgeServerHandshakeState send(PluginMessage message, UserConnection con) { + // Packets should never make it here but if they ever do, pass everything to client + ForgeLogger.logServer( LogDirection.SENDING, this.name(), message); + con.unsafe().sendPacket(message); return this; } } diff --git a/proxy/src/main/java/net/md_5/bungee/module/ModuleManager.java b/proxy/src/main/java/net/md_5/bungee/module/ModuleManager.java index 901fc5a37c..8c14590090 100644 --- a/proxy/src/main/java/net/md_5/bungee/module/ModuleManager.java +++ b/proxy/src/main/java/net/md_5/bungee/module/ModuleManager.java @@ -29,6 +29,7 @@ public class ModuleManager public ModuleManager() { knownSources.put( "jenkins", new JenkinsModuleSource() ); + knownSources.put( "travis-ci", new TravisCiModuleSource() ); } @SuppressFBWarnings( @@ -80,13 +81,13 @@ public void load(ProxyServer proxy, File moduleDirectory) throws Exception switch ( version ) { case 0: - defaults.add( "jenkins://cmd_alert" ); - defaults.add( "jenkins://cmd_find" ); - defaults.add( "jenkins://cmd_list" ); - defaults.add( "jenkins://cmd_send" ); - defaults.add( "jenkins://cmd_server" ); + defaults.add( "travis-ci://cmd_alert" ); + defaults.add( "travis-ci://cmd_find" ); + defaults.add( "travis-ci://cmd_list" ); + defaults.add( "travis-ci://cmd_send" ); + defaults.add( "travis-ci://cmd_server" ); case 1: - defaults.add( "jenkins://reconnect_yaml" ); + defaults.add( "travis-ci://reconnect_yaml" ); } config.put( "modules", defaults ); config.put( "version", 2 ); diff --git a/proxy/src/main/java/net/md_5/bungee/module/TravisCiModuleSource.java b/proxy/src/main/java/net/md_5/bungee/module/TravisCiModuleSource.java new file mode 100644 index 0000000000..fd40cf934c --- /dev/null +++ b/proxy/src/main/java/net/md_5/bungee/module/TravisCiModuleSource.java @@ -0,0 +1,39 @@ +package net.md_5.bungee.module; + + +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; + +import com.google.common.io.ByteStreams; +import com.google.common.io.Files; + +import lombok.Data; +import net.md_5.bungee.Util; + + +@Data +public class TravisCiModuleSource implements ModuleSource +{ + + @Override + public void retrieve(ModuleSpec module, ModuleVersion version) + { + System.out.println("Attempting to download Tracis-CI module " + module.getName() + " v" + version.getBuild()); + try + { + URL website = new URL("https://github.com/HexagonMC/BungeeCord/releases/download/v" + version.getBuild() + "/" + module.getName() + ".jar"); + URLConnection con = website.openConnection(); + // 15 second timeout at various stages + con.setConnectTimeout(15000); + con.setReadTimeout(15000); + + Files.write(ByteStreams.toByteArray(con.getInputStream()), module.getFile()); + System.out.println("Download complete"); + } + catch (IOException ex) + { + System.out.println("Failed to download: " + Util.exception(ex)); + } + } +} diff --git a/proxy/src/main/java/net/md_5/bungee/tab/Global.java b/proxy/src/main/java/net/md_5/bungee/tab/Global.java index 0cf1d21873..e164cabd62 100644 --- a/proxy/src/main/java/net/md_5/bungee/tab/Global.java +++ b/proxy/src/main/java/net/md_5/bungee/tab/Global.java @@ -6,6 +6,7 @@ import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.chat.ComponentSerializer; import net.md_5.bungee.connection.LoginResult; +import net.md_5.bungee.protocol.ProtocolConstants; import net.md_5.bungee.protocol.packet.PlayerListItem; import java.util.Collection; @@ -37,7 +38,7 @@ public void onPingChange(int ping) PlayerListItem.Item item = new PlayerListItem.Item(); item.setUuid( player.getUniqueId() ); item.setUsername( player.getName() ); - item.setDisplayName( ComponentSerializer.toString( TextComponent.fromLegacyText( player.getDisplayName() ) ) ); + item.setDisplayName( player.getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_8 ? ComponentSerializer.toString( TextComponent.fromLegacyText( player.getDisplayName() ) ) : player.getDisplayName() ); item.setPing( player.getPing() ); packet.setItems( new PlayerListItem.Item[] { @@ -67,7 +68,7 @@ public void onConnect() PlayerListItem.Item item = items[i++] = new PlayerListItem.Item(); item.setUuid( p.getUniqueId() ); item.setUsername( p.getName() ); - item.setDisplayName( ComponentSerializer.toString( TextComponent.fromLegacyText( p.getDisplayName() ) ) ); + item.setDisplayName( player.getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_8 ? ComponentSerializer.toString( TextComponent.fromLegacyText( p.getDisplayName() ) ) : p.getDisplayName() ); LoginResult loginResult = ( (UserConnection) p ).getPendingConnection().getLoginProfile(); if ( loginResult != null ) { @@ -89,13 +90,30 @@ public void onConnect() item.setGamemode( ( (UserConnection) p ).getGamemode() ); item.setPing( p.getPing() ); } - player.unsafe().sendPacket( playerListItem ); + if ( player.getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_8 ) + { + player.unsafe().sendPacket( playerListItem ); + } else + { + // Split up the packet + for ( PlayerListItem.Item item : playerListItem.getItems() ) + { + PlayerListItem packet = new PlayerListItem(); + packet.setAction( playerListItem.getAction() ); + + packet.setItems( new PlayerListItem.Item[] + { + item + } ); + player.unsafe().sendPacket( packet ); + } + } PlayerListItem packet = new PlayerListItem(); packet.setAction( PlayerListItem.Action.ADD_PLAYER ); PlayerListItem.Item item = new PlayerListItem.Item(); item.setUuid( player.getUniqueId() ); item.setUsername( player.getName() ); - item.setDisplayName( ComponentSerializer.toString( TextComponent.fromLegacyText( player.getDisplayName() ) ) ); + item.setDisplayName( player.getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_8 ? ComponentSerializer.toString( TextComponent.fromLegacyText( player.getDisplayName() ) ) : player.getDisplayName() ); LoginResult loginResult = ( (UserConnection) player ).getPendingConnection().getLoginProfile(); if ( loginResult != null ) { diff --git a/proxy/src/main/java/net/md_5/bungee/tab/GlobalPing.java b/proxy/src/main/java/net/md_5/bungee/tab/GlobalPing.java index fb4991c1d6..25ed37aeee 100644 --- a/proxy/src/main/java/net/md_5/bungee/tab/GlobalPing.java +++ b/proxy/src/main/java/net/md_5/bungee/tab/GlobalPing.java @@ -4,6 +4,7 @@ import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.chat.ComponentSerializer; +import net.md_5.bungee.protocol.ProtocolConstants; import net.md_5.bungee.protocol.packet.PlayerListItem; public class GlobalPing extends Global @@ -29,7 +30,7 @@ public void onPingChange(int ping) PlayerListItem.Item item = new PlayerListItem.Item(); item.setUuid( player.getUniqueId() ); item.setUsername( player.getName() ); - item.setDisplayName( ComponentSerializer.toString( TextComponent.fromLegacyText( player.getDisplayName() ) ) ); + item.setDisplayName( player.getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_8 ? ComponentSerializer.toString( TextComponent.fromLegacyText( player.getDisplayName() ) ) : player.getDisplayName() ); item.setPing( player.getPing() ); packet.setItems( new PlayerListItem.Item[] { diff --git a/proxy/src/main/java/net/md_5/bungee/tab/ServerUnique.java b/proxy/src/main/java/net/md_5/bungee/tab/ServerUnique.java index daf12f74e4..835a301ce8 100644 --- a/proxy/src/main/java/net/md_5/bungee/tab/ServerUnique.java +++ b/proxy/src/main/java/net/md_5/bungee/tab/ServerUnique.java @@ -4,12 +4,14 @@ import java.util.HashSet; import java.util.UUID; import net.md_5.bungee.api.connection.ProxiedPlayer; +import net.md_5.bungee.protocol.ProtocolConstants; import net.md_5.bungee.protocol.packet.PlayerListItem; public class ServerUnique extends TabList { private final Collection uuids = new HashSet<>(); + private final Collection usernames = new HashSet<>(); // Support for <=1.7.9 public ServerUnique(ProxiedPlayer player) { @@ -23,10 +25,22 @@ public void onUpdate(PlayerListItem playerListItem) { if ( playerListItem.getAction() == PlayerListItem.Action.ADD_PLAYER ) { - uuids.add( item.getUuid() ); + if ( item.getUuid() != null ) + { + uuids.add( item.getUuid() ); + } else + { + usernames.add( item.getUsername() ); + } } else if ( playerListItem.getAction() == PlayerListItem.Action.REMOVE_PLAYER ) { - uuids.remove( item.getUuid() ); + if ( item.getUuid() != null ) + { + uuids.remove( item.getUuid() ); + } else + { + usernames.remove( item.getUsername() ); + } } } player.unsafe().sendPacket( playerListItem ); @@ -43,16 +57,40 @@ public void onServerChange() { PlayerListItem packet = new PlayerListItem(); packet.setAction( PlayerListItem.Action.REMOVE_PLAYER ); - PlayerListItem.Item[] items = new PlayerListItem.Item[ uuids.size() ]; + PlayerListItem.Item[] items = new PlayerListItem.Item[ uuids.size() + usernames.size() ]; int i = 0; for ( UUID uuid : uuids ) { PlayerListItem.Item item = items[i++] = new PlayerListItem.Item(); item.setUuid( uuid ); } + for ( String username : usernames ) + { + PlayerListItem.Item item = items[i++] = new PlayerListItem.Item(); + item.setUsername( username ); + item.setDisplayName( username ); + } packet.setItems( items ); - player.unsafe().sendPacket( packet ); + if ( player.getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_8 ) + { + player.unsafe().sendPacket( packet ); + } else + { + // Split up the packet + for ( PlayerListItem.Item item : packet.getItems() ) + { + PlayerListItem p2 = new PlayerListItem(); + p2.setAction( packet.getAction() ); + + p2.setItems( new PlayerListItem.Item[] + { + item + } ); + player.unsafe().sendPacket( p2 ); + } + } uuids.clear(); + usernames.clear(); } @Override diff --git a/proxy/src/main/java/net/md_5/bungee/tab/TabList.java b/proxy/src/main/java/net/md_5/bungee/tab/TabList.java index 7b59c75722..29f2a7ddce 100644 --- a/proxy/src/main/java/net/md_5/bungee/tab/TabList.java +++ b/proxy/src/main/java/net/md_5/bungee/tab/TabList.java @@ -3,8 +3,11 @@ import lombok.RequiredArgsConstructor; import net.md_5.bungee.BungeeCord; import net.md_5.bungee.UserConnection; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.connection.LoginResult; +import net.md_5.bungee.protocol.ProtocolConstants; import net.md_5.bungee.protocol.packet.PlayerListItem; @RequiredArgsConstructor diff --git a/query/src/main/java/net/md_5/bungee/query/QueryHandler.java b/query/src/main/java/net/md_5/bungee/query/QueryHandler.java index 79d6886a60..4ac87e7d88 100644 --- a/query/src/main/java/net/md_5/bungee/query/QueryHandler.java +++ b/query/src/main/java/net/md_5/bungee/query/QueryHandler.java @@ -110,7 +110,7 @@ protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throw data.put( "gametype", "SMP" ); // Start Extra Info data.put( "game_id", "MINECRAFT" ); - data.put( "version", bungee.getGameVersion() ); + data.put( "version", bungee.getConfig().getCustomServerName() + " " + bungee.getGameVersion() ); data.put( "plugins", "" ); // End Extra Info data.put( "map", "BungeeCord_Proxy" );