commit 3809083007dd97e3a947ed0b20cd6523c420f4db Author: Techcable Date: Sat May 28 10:34:39 2016 -0600 Turn waterfall into a patch-based fork like Spigot and Paper (WIP) Allows us to easily see and manage the diff with upstream. Makes fixing conflicts with upstream easier and shows a cleaner, more acurate commit history. All credits to scripts go to @md_5 @aikar @Zbob750 @Thinkofname @Byteflux @Techcable (GPL3 Licensed) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e05068e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +Waterfall-Proxy diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..5f702c0 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "BungeeCord"] + path = BungeeCord + url = https://github.com/SpigotMC/BungeeCord.git diff --git a/BungeeCord b/BungeeCord new file mode 160000 index 0000000..ec48077 --- /dev/null +++ b/BungeeCord @@ -0,0 +1 @@ +Subproject commit ec48077dbe2c2c4164468b874d0cb8da949b4d4e diff --git a/BungeeCord-Patches/0001-POM-Changes.patch b/BungeeCord-Patches/0001-POM-Changes.patch new file mode 100644 index 0000000..0125746 --- /dev/null +++ b/BungeeCord-Patches/0001-POM-Changes.patch @@ -0,0 +1,792 @@ +From 8a67ee0be0b56fcefea96a90b54c251f5660cc5f Mon Sep 17 00:00:00 2001 +From: Tux +Date: Thu, 19 May 2016 10:33:31 -0700 +Subject: [PATCH] POM Changes + +Require Java 8 + +diff --git a/api/pom.xml b/api/pom.xml +index d9363b6..c71c1b1 100644 +--- a/api/pom.xml ++++ b/api/pom.xml +@@ -4,42 +4,42 @@ + 4.0.0 + + +- net.md-5 +- bungeecord-parent ++ io.github.waterfallmc ++ waterfall-parent + 1.9-SNAPSHOT + ../pom.xml + + +- net.md-5 +- bungeecord-api ++ io.github.waterfallmc ++ waterfall-api + 1.9-SNAPSHOT + jar + +- BungeeCord-API ++ Waterfall-API + API implemented by the Elastic Portal Suite + + + +- net.md-5 +- bungeecord-chat ++ io.github.waterfallmc ++ waterfall-chat + ${project.version} + compile + + +- net.md-5 +- bungeecord-config ++ io.github.waterfallmc ++ waterfall-config + ${project.version} + compile + + +- net.md-5 +- bungeecord-event ++ io.github.waterfallmc ++ waterfall-event + ${project.version} + compile + + +- net.md-5 +- bungeecord-protocol ++ io.github.waterfallmc ++ waterfall-protocol + ${project.version} + compile + +diff --git a/bootstrap/pom.xml b/bootstrap/pom.xml +index 0c02349..0785736 100644 +--- a/bootstrap/pom.xml ++++ b/bootstrap/pom.xml +@@ -4,19 +4,19 @@ + 4.0.0 + + +- net.md-5 +- bungeecord-parent ++ io.github.waterfallmc ++ waterfall-parent + 1.9-SNAPSHOT + ../pom.xml + + +- net.md-5 +- bungeecord-bootstrap ++ io.github.waterfallmc ++ waterfall-bootstrap + 1.9-SNAPSHOT + jar + +- BungeeCord-Bootstrap +- Java 1.6 loader for BungeeCord ++ Waterfall-Bootstrap ++ Java 1.6 loader for Waterfall + + + 1.6 +@@ -26,8 +26,8 @@ + + + +- net.md-5 +- bungeecord-proxy ++ io.github.waterfallmc ++ waterfall-proxy + ${project.version} + compile + +@@ -40,7 +40,7 @@ + + + +- BungeeCord ++ Waterfall + + + +@@ -57,7 +57,7 @@ + + + +- net.md_5.bungee.Bootstrap ++ net.md_5.bungee.Bootstrap + ${describe} + ${maven.build.timestamp} + +diff --git a/bootstrap/src/main/java/net/md_5/bungee/Bootstrap.java b/bootstrap/src/main/java/net/md_5/bungee/Bootstrap.java +index b7cb81e..a4516ed 100644 +--- a/bootstrap/src/main/java/net/md_5/bungee/Bootstrap.java ++++ b/bootstrap/src/main/java/net/md_5/bungee/Bootstrap.java +@@ -5,9 +5,9 @@ public class Bootstrap + + public static void main(String[] args) throws Exception + { +- if ( Float.parseFloat( System.getProperty( "java.class.version" ) ) < 51.0 ) ++ if ( Float.parseFloat( System.getProperty( "java.class.version" ) ) < 52.0 ) + { +- System.err.println( "*** ERROR *** BungeeCord requires Java 7 or above to function! Please download and install it!" ); ++ System.err.println( "*** ERROR *** Waterfall requires Java 8 or above to function! Please download and install it!" ); + System.out.println( "You can check your Java version with the command: java -version" ); + return; + } +diff --git a/chat/pom.xml b/chat/pom.xml +index 0b447c1..7ff3224 100644 +--- a/chat/pom.xml ++++ b/chat/pom.xml +@@ -4,23 +4,24 @@ + 4.0.0 + + +- net.md-5 +- bungeecord-parent ++ io.github.waterfallmc ++ waterfall-parent + 1.9-SNAPSHOT + ../pom.xml + + +- net.md-5 +- bungeecord-chat ++ io.github.waterfallmc ++ waterfall-chat + 1.9-SNAPSHOT + jar + +- BungeeCord-Chat +- Minecraft JSON chat API intended for use with BungeeCord ++ Waterfall-Chat ++ Minecraft JSON chat API intended for use with Waterfall + + +- 1.6 +- 1.6 ++ ++ 1.8 ++ 1.8 + + + +diff --git a/config/pom.xml b/config/pom.xml +index 5c99e14..29e50dc 100644 +--- a/config/pom.xml ++++ b/config/pom.xml +@@ -4,19 +4,19 @@ + 4.0.0 + + +- net.md-5 +- bungeecord-parent ++ io.github.waterfallmc ++ waterfall-parent + 1.9-SNAPSHOT + ../pom.xml + + +- net.md-5 +- bungeecord-config ++ io.github.waterfallmc ++ waterfall-config + 1.9-SNAPSHOT + jar + +- BungeeCord-Config +- Generic java configuration API intended for use with BungeeCord ++ Waterfall-Config ++ Generic java configuration API intended for use with Waterfall + + + +diff --git a/event/pom.xml b/event/pom.xml +index a5fee80..b6ef990 100644 +--- a/event/pom.xml ++++ b/event/pom.xml +@@ -4,17 +4,17 @@ + 4.0.0 + + +- net.md-5 +- bungeecord-parent ++ io.github.waterfallmc ++ waterfall-parent + 1.9-SNAPSHOT + ../pom.xml + + +- net.md-5 +- bungeecord-event ++ io.github.waterfallmc ++ waterfall-event + 1.9-SNAPSHOT + jar + +- BungeeCord-Event +- Generic java event dispatching API intended for use with BungeeCord ++ Waterfall-Event ++ Generic java event dispatching API intended for use with Waterfall. + +diff --git a/module/cmd-alert/pom.xml b/module/cmd-alert/pom.xml +index 1cc7fef..bc71a34 100644 +--- a/module/cmd-alert/pom.xml ++++ b/module/cmd-alert/pom.xml +@@ -4,14 +4,14 @@ + 4.0.0 + + +- net.md-5 +- bungeecord-module ++ io.github.waterfallmc ++ waterfall-module + 1.9-SNAPSHOT + ../pom.xml + + +- net.md-5 +- bungeecord-module-cmd-alert ++ io.github.waterfallmc ++ waterfall-module-cmd-alert + 1.9-SNAPSHOT + jar + +diff --git a/module/cmd-find/pom.xml b/module/cmd-find/pom.xml +index 10b6a4f..a4e9f89 100644 +--- a/module/cmd-find/pom.xml ++++ b/module/cmd-find/pom.xml +@@ -4,14 +4,14 @@ + 4.0.0 + + +- net.md-5 +- bungeecord-module ++ io.github.waterfallmc ++ waterfall-module + 1.9-SNAPSHOT + ../pom.xml + + +- net.md-5 +- bungeecord-module-cmd-find ++ io.github.waterfallmc ++ waterfall-module-cmd-find + 1.9-SNAPSHOT + jar + +diff --git a/module/cmd-list/pom.xml b/module/cmd-list/pom.xml +index 774b694..6f4f4a7 100644 +--- a/module/cmd-list/pom.xml ++++ b/module/cmd-list/pom.xml +@@ -4,14 +4,14 @@ + 4.0.0 + + +- net.md-5 +- bungeecord-module ++ io.github.waterfallmc ++ waterfall-module + 1.9-SNAPSHOT + ../pom.xml + + +- net.md-5 +- bungeecord-module-cmd-list ++ io.github.waterfallmc ++ waterfall-module-cmd-list + 1.9-SNAPSHOT + jar + +diff --git a/module/cmd-send/pom.xml b/module/cmd-send/pom.xml +index 15d03fc..7481b49 100644 +--- a/module/cmd-send/pom.xml ++++ b/module/cmd-send/pom.xml +@@ -4,14 +4,14 @@ + 4.0.0 + + +- net.md-5 +- bungeecord-module ++ io.github.waterfallmc ++ waterfall-module + 1.9-SNAPSHOT + ../pom.xml + + +- net.md-5 +- bungeecord-module-cmd-send ++ io.github.waterfallmc ++ waterfall-module-cmd-send + 1.9-SNAPSHOT + jar + +diff --git a/module/cmd-server/pom.xml b/module/cmd-server/pom.xml +index a72db68..1be3c11 100644 +--- a/module/cmd-server/pom.xml ++++ b/module/cmd-server/pom.xml +@@ -4,14 +4,14 @@ + 4.0.0 + + +- net.md-5 +- bungeecord-module ++ io.github.waterfallmc ++ waterfall-module + 1.9-SNAPSHOT + ../pom.xml + + +- net.md-5 +- bungeecord-module-cmd-server ++ io.github.waterfallmc ++ waterfall-module-cmd-server + 1.9-SNAPSHOT + jar + +diff --git a/module/pom.xml b/module/pom.xml +index 3482d0d..100b8d7 100644 +--- a/module/pom.xml ++++ b/module/pom.xml +@@ -4,19 +4,19 @@ + 4.0.0 + + +- net.md-5 +- bungeecord-parent ++ io.github.waterfallmc ++ waterfall-parent + 1.9-SNAPSHOT + ../pom.xml + + +- net.md-5 +- bungeecord-module ++ io.github.waterfallmc ++ waterfall-module + 1.9-SNAPSHOT + pom + +- BungeeCord Modules +- Parent project for all BungeeCord modules. ++ Waterfall Modules ++ Parent project for all Waterfall modules. + + + cmd-alert +@@ -33,8 +33,8 @@ + + + +- net.md-5 +- bungeecord-api ++ io.github.waterfallmc ++ waterfall-api + ${project.version} + compile + +diff --git a/module/reconnect-yaml/pom.xml b/module/reconnect-yaml/pom.xml +index bf5ae48..c0f55ba 100644 +--- a/module/reconnect-yaml/pom.xml ++++ b/module/reconnect-yaml/pom.xml +@@ -4,14 +4,14 @@ + 4.0.0 + + +- net.md-5 +- bungeecord-module ++ io.github.waterfallmc ++ waterfall-module + 1.9-SNAPSHOT + ../pom.xml + + +- net.md-5 +- bungeecord-module-reconnect-yaml ++ io.github.waterfallmc ++ waterfall-module-reconnect-yaml + 1.9-SNAPSHOT + jar + +diff --git a/native/pom.xml b/native/pom.xml +index fb12cc4..5dd2e51 100644 +--- a/native/pom.xml ++++ b/native/pom.xml +@@ -4,19 +4,19 @@ + 4.0.0 + + +- net.md-5 +- bungeecord-parent ++ io.github.waterfallmc ++ waterfall-parent + 1.9-SNAPSHOT + ../pom.xml + + +- net.md-5 +- bungeecord-native ++ io.github.waterfallmc ++ waterfall-native + 1.9-SNAPSHOT + jar + +- BungeeCord-Native +- Optional native code to speed up and enhance BungeeCord functionality. ++ Waterfall-Native ++ Optional native code to speed up and enhance Waterfall functionality. + + + +diff --git a/pom.xml b/pom.xml +index d8d7c02..badd9c4 100644 +--- a/pom.xml ++++ b/pom.xml +@@ -3,24 +3,18 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + +- +- org.sonatype.oss +- oss-parent +- 9 +- +- +- net.md-5 +- bungeecord-parent ++ io.github.waterfallmc ++ waterfall-parent + 1.9-SNAPSHOT + pom + +- BungeeCord-Parent +- Parent project for all BungeeCord modules. +- https://github.com/SpigotMC/BungeeCord +- 2012 ++ Waterfall-Parent ++ Parent project for all Waterfall modules. ++ https://github.com/WaterfallMC/Waterfall ++ 2015 + +- SpigotMC +- https://github.com/SpigotMC ++ WaterfallMC ++ https://github.com/WaterfallMC + + + +@@ -32,7 +26,13 @@ + + + +- md_5 ++ Tux ++ ++ ++ Techcable ++ ++ ++ kashike + + + +@@ -50,24 +50,36 @@ + + + +- 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:com:WaterfallMC/Waterfall.git ++ scm:git:git@github.com:WaterfallMC/Waterfall.git ++ git@github.com:WaterfallMC/Waterfall.git + + + GitHub +- https://github.com/SpigotMC/BungeeCord/issues ++ https://github.com/WaterfallMC/Waterfall/issues + + +- jenkins +- http://ci.md-5.net/job/BungeeCord ++ teamcity ++ https://getwaterfall.xyz/builds/ + + ++ ++ ++ ellune-releases ++ https://repo.ellune.net/content/repositories/releases/ ++ ++ ++ ellune-snapshots ++ https://repo.ellune.net/content/repositories/snapshots/ ++ ++ ++ + + unknown + 4.0.33.Final +- 1.7 +- 1.7 ++ ++ 1.8 ++ 1.8 + UTF-8 + + +@@ -93,12 +105,13 @@ + + org.projectlombok + lombok +- 1.14.8 ++ 1.16.8 + provided + + + + ++ clean install + + + net.md-5 +@@ -116,36 +129,14 @@ + + + +- +- org.codehaus.mojo +- animal-sniffer-maven-plugin +- 1.13 +- +- +- process-classes +- +- check +- +- +- +- +- +- java.lang.ClassLoader +- java.lang.Throwable +- java.util.Locale +- +- +- org.codehaus.mojo.signature +- java16 +- 1.1 +- +- +- + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.7 ++ ++ -Xdoclint:none ++ + + + +@@ -180,4 +171,49 @@ + + + ++ ++ ++ ++ deployment ++ ++ ++ ++ org.apache.maven.plugins ++ maven-javadoc-plugin ++ 2.7 ++ ++ ++ attach-javadocs ++ package ++ ++ jar ++ ++ ++ -Xdoclint:none ++ ++ ++ ++ ++ ++ org.apache.maven.plugins ++ maven-source-plugin ++ 2.4 ++ ++ ++ attach-sources ++ package ++ ++ jar-no-fork ++ ++ ++ ++ ++ ++ org.apache.maven.plugins ++ maven-deploy-plugin ++ ++ ++ ++ ++ + +diff --git a/protocol/pom.xml b/protocol/pom.xml +index 9e816ab..8b462f5 100644 +--- a/protocol/pom.xml ++++ b/protocol/pom.xml +@@ -4,24 +4,24 @@ + 4.0.0 + + +- net.md-5 +- bungeecord-parent ++ io.github.waterfallmc ++ waterfall-parent + 1.9-SNAPSHOT + ../pom.xml + + +- net.md-5 +- bungeecord-protocol ++ io.github.waterfallmc ++ waterfall-protocol + 1.9-SNAPSHOT + jar + +- BungeeCord-Protocol +- Minimal implementation of the Minecraft protocol for use in BungeeCord ++ Waterfall-Protocol ++ Minimal implementation of the Minecraft protocol for use in Waterfall + + + +- net.md-5 +- bungeecord-chat ++ io.github.waterfallmc ++ waterfall-chat + ${project.version} + compile + +diff --git a/proxy/pom.xml b/proxy/pom.xml +index 44ff3ff..3fe4937 100644 +--- a/proxy/pom.xml ++++ b/proxy/pom.xml +@@ -4,18 +4,18 @@ + 4.0.0 + + +- net.md-5 +- bungeecord-parent ++ io.github.waterfallmc ++ waterfall-parent + 1.9-SNAPSHOT + ../pom.xml + + +- net.md-5 +- bungeecord-proxy ++ io.github.waterfallmc ++ waterfall-proxy + 1.9-SNAPSHOT + jar + +- BungeeCord-Proxy ++ Waterfall-Proxy + Proxy component of the Elastic Portal Suite + + +@@ -39,26 +39,26 @@ + compile + + +- net.md-5 +- bungeecord-api ++ io.github.waterfallmc ++ waterfall-api + ${project.version} + compile + + +- net.md-5 +- bungeecord-native ++ io.github.waterfallmc ++ waterfall-native + ${project.version} + compile + + +- net.md-5 +- bungeecord-protocol ++ io.github.waterfallmc ++ waterfall-protocol + ${project.version} + compile + + +- net.md-5 +- bungeecord-query ++ io.github.waterfallmc ++ waterfall-query + ${project.version} + compile + +diff --git a/query/pom.xml b/query/pom.xml +index 81bd2c7..dbb2e81 100644 +--- a/query/pom.xml ++++ b/query/pom.xml +@@ -4,19 +4,19 @@ + 4.0.0 + + +- net.md-5 +- bungeecord-parent ++ io.github.waterfallmc ++ waterfall-parent + 1.9-SNAPSHOT + ../pom.xml + + +- net.md-5 +- bungeecord-query ++ io.github.waterfallmc ++ waterfall-query + 1.9-SNAPSHOT + jar + +- BungeeCord-Query +- Minecraft query implementation based on the BungeeCord API. ++ Waterfall-Query ++ Minecraft query implementation based on the Waterfall API. + + + +@@ -26,8 +26,8 @@ + compile + + +- net.md-5 +- bungeecord-api ++ io.github.waterfallmc ++ waterfall-api + ${project.version} + compile + +-- +2.8.3 + diff --git a/BungeeCord-Patches/0002-Rename-references-from-BungeeCord-to-Waterfall.patch b/BungeeCord-Patches/0002-Rename-references-from-BungeeCord-to-Waterfall.patch new file mode 100644 index 0000000..d74040c --- /dev/null +++ b/BungeeCord-Patches/0002-Rename-references-from-BungeeCord-to-Waterfall.patch @@ -0,0 +1,109 @@ +From 8b0e4da4f4b65ace743c2124dffb55cc5e9b2ea1 Mon Sep 17 00:00:00 2001 +From: Tux +Date: Thu, 19 May 2016 11:28:45 -0700 +Subject: [PATCH] Rename references from BungeeCord to Waterfall + + +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 3c1bbe9..2a41a50 100644 +--- a/bootstrap/src/main/java/net/md_5/bungee/BungeeCordLauncher.java ++++ b/bootstrap/src/main/java/net/md_5/bungee/BungeeCordLauncher.java +@@ -51,7 +51,7 @@ public class BungeeCordLauncher + + BungeeCord bungee = new BungeeCord(); + ProxyServer.setInstance( bungee ); +- bungee.getLogger().info( "Enabled BungeeCord version " + bungee.getVersion() ); ++ bungee.getLogger().info( "Enabled Waterfall version " + bungee.getVersion() ); + bungee.start(); + + if ( !options.has( "noconsole" ) ) +diff --git a/proxy/src/main/java/Test.java b/proxy/src/main/java/Test.java +index 9d51608..446dfe2 100644 +--- a/proxy/src/main/java/Test.java ++++ b/proxy/src/main/java/Test.java +@@ -19,7 +19,7 @@ public class Test + { + BungeeCord bungee = new BungeeCord(); + ProxyServer.setInstance( bungee ); +- bungee.getLogger().info( "Enabled BungeeCord version " + bungee.getVersion() ); ++ bungee.getLogger().info( "Enabled Waterfall version " + bungee.getVersion() ); + bungee.start(); + + while ( bungee.isRunning ) +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 ac08d8e..8ce4ced 100644 +--- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java ++++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java +@@ -172,7 +172,7 @@ public class BungeeCord extends ProxyServer + public BungeeCord() throws IOException + { + // Java uses ! to indicate a resource inside of a jar/zip/other container. Running Bungee from within a directory that has a ! will cause this to muck up. +- Preconditions.checkState( new File( "." ).getAbsolutePath().indexOf( '!' ) == -1, "Cannot use BungeeCord in directory with ! in path." ); ++ Preconditions.checkState( new File( "." ).getAbsolutePath().indexOf( '!' ) == -1, "Cannot use Waterfall in directory with ! in path." ); + + System.setSecurityManager( new BungeeSecurityManager() ); + +@@ -457,7 +457,7 @@ public class BungeeCord extends ProxyServer + @Override + public String getName() + { +- return "BungeeCord"; ++ return "Waterfall"; + } + + @Override +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 b079879..b26035c 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,6 @@ public class CommandBungee extends Command + @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 Waterfall version " + ProxyServer.getInstance().getVersion() + " by md_5" ); + } + } +diff --git a/proxy/src/main/java/net/md_5/bungee/command/CommandReload.java b/proxy/src/main/java/net/md_5/bungee/command/CommandReload.java +index cbbe03c..4a49241 100644 +--- a/proxy/src/main/java/net/md_5/bungee/command/CommandReload.java ++++ b/proxy/src/main/java/net/md_5/bungee/command/CommandReload.java +@@ -22,7 +22,7 @@ public class CommandReload extends Command + BungeeCord.getInstance().startListeners(); + BungeeCord.getInstance().getPluginManager().callEvent( new ProxyReloadEvent( sender ) ); + +- sender.sendMessage( ChatColor.BOLD.toString() + ChatColor.RED.toString() + "BungeeCord has been reloaded." +- + " This is NOT advisable and you will not be supported with any issues that arise! Please restart BungeeCord ASAP." ); ++ sender.sendMessage( ChatColor.BOLD.toString() + ChatColor.RED.toString() + "Waterfall has been reloaded." ++ + " This is NOT advisable and you will not be supported with any issues that arise! Please restart Waterfall ASAP." ); + } + } +diff --git a/proxy/src/main/java/net/md_5/bungee/conf/YamlConfig.java b/proxy/src/main/java/net/md_5/bungee/conf/YamlConfig.java +index c7547c7..82ff91a 100644 +--- a/proxy/src/main/java/net/md_5/bungee/conf/YamlConfig.java ++++ b/proxy/src/main/java/net/md_5/bungee/conf/YamlConfig.java +@@ -200,7 +200,7 @@ public class YamlConfig implements ConfigurationAdapter + Map val = entry.getValue(); + String name = entry.getKey(); + String addr = get( "address", "localhost:25565", val ); +- String motd = ChatColor.translateAlternateColorCodes( '&', get( "motd", "&1Just another BungeeCord - Forced Host", val ) ); ++ String motd = ChatColor.translateAlternateColorCodes( '&', get( "motd", "&1Just another Waterfall - Forced Host", val ) ); + boolean restricted = get( "restricted", false, val ); + InetSocketAddress address = Util.getAddr( addr ); + ServerInfo info = ProxyServer.getInstance().constructServerInfo( name, address, motd, restricted ); +diff --git a/proxy/src/main/java/net/md_5/bungee/log/LogDispatcher.java b/proxy/src/main/java/net/md_5/bungee/log/LogDispatcher.java +index f1ccd4f..d703d6d 100644 +--- a/proxy/src/main/java/net/md_5/bungee/log/LogDispatcher.java ++++ b/proxy/src/main/java/net/md_5/bungee/log/LogDispatcher.java +@@ -12,7 +12,7 @@ public class LogDispatcher extends Thread + + public LogDispatcher(BungeeLogger logger) + { +- super( "BungeeCord Logger Thread" ); ++ super( "Waterfall Logger Thread" ); + this.logger = logger; + } + +-- +2.8.3 + diff --git a/BungeeCord-Patches/0003-Add-Waterfall-configuration-files.patch b/BungeeCord-Patches/0003-Add-Waterfall-configuration-files.patch new file mode 100644 index 0000000..94ceb87 --- /dev/null +++ b/BungeeCord-Patches/0003-Add-Waterfall-configuration-files.patch @@ -0,0 +1,124 @@ +From b790b1d946c66a57af7550795bf63fad398bb137 Mon Sep 17 00:00:00 2001 +From: Techcable +Date: Thu, 19 May 2016 10:46:46 -0700 +Subject: [PATCH] Add Waterfall configuration files + + +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 edd82c1..b30541b 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,9 @@ public interface ProxyConfig + * The favicon used for the server ping list. + */ + Favicon getFaviconObject(); ++ ++ // ++ // Waterfall Options ++ // ++ + } +diff --git a/proxy/src/main/java/io/github/waterfallmc/waterfall/conf/WaterfallConfiguration.java b/proxy/src/main/java/io/github/waterfallmc/waterfall/conf/WaterfallConfiguration.java +new file mode 100644 +index 0000000..03160da +--- /dev/null ++++ b/proxy/src/main/java/io/github/waterfallmc/waterfall/conf/WaterfallConfiguration.java +@@ -0,0 +1,19 @@ ++ ++package io.github.waterfallmc.waterfall.conf; ++ ++import lombok.*; ++ ++import java.io.File; ++ ++import net.md_5.bungee.conf.Configuration; ++import net.md_5.bungee.conf.YamlConfig; ++ ++public class WaterfallConfiguration extends Configuration { ++ ++ @Override ++ public void load() { ++ super.load(); ++ YamlConfig config = new YamlConfig(new File("waterfall.yml")); ++ config.load(false); // Load, but no permissions ++ } ++} +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 8ce4ced..3dceb6e 100644 +--- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java ++++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java +@@ -23,6 +23,7 @@ import net.md_5.bungee.scheduler.BungeeScheduler; + import com.google.common.util.concurrent.ThreadFactoryBuilder; + import com.google.gson.Gson; + import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; ++import io.github.waterfallmc.waterfall.conf.WaterfallConfiguration; + import io.netty.bootstrap.ServerBootstrap; + import io.netty.channel.Channel; + import io.netty.channel.ChannelException; +@@ -98,7 +99,7 @@ public class BungeeCord extends ProxyServer + * Configuration. + */ + @Getter +- public final Configuration config = new Configuration(); ++ public final Configuration config = new WaterfallConfiguration(); + /** + * Localization bundle. + */ +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 25d87d9..81dd4af 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 +@@ -24,7 +24,7 @@ import net.md_5.bungee.util.CaseInsensitiveSet; + * Core configuration for the proxy. + */ + @Getter +-public class Configuration implements ProxyConfig ++public abstract class Configuration implements ProxyConfig + { + + /** +diff --git a/proxy/src/main/java/net/md_5/bungee/conf/YamlConfig.java b/proxy/src/main/java/net/md_5/bungee/conf/YamlConfig.java +index 82ff91a..4ec9782 100644 +--- a/proxy/src/main/java/net/md_5/bungee/conf/YamlConfig.java ++++ b/proxy/src/main/java/net/md_5/bungee/conf/YamlConfig.java +@@ -42,10 +42,15 @@ public class YamlConfig implements ConfigurationAdapter + } + private final Yaml yaml; + private Map config; +- private final File file = new File( "config.yml" ); ++ private final File file; + +- public YamlConfig() ++ public YamlConfig() { ++ this(new File("config.yml")); ++ } ++ ++ public YamlConfig(File file) + { ++ this.file = file; + DumperOptions options = new DumperOptions(); + options.setDefaultFlowStyle( DumperOptions.FlowStyle.BLOCK ); + yaml = new Yaml( options ); +@@ -54,6 +59,11 @@ public class YamlConfig implements ConfigurationAdapter + @Override + public void load() + { ++ load(true); ++ } ++ ++ public void load(boolean doPermissions) ++ { + try + { + file.createNewFile(); +@@ -75,6 +85,7 @@ public class YamlConfig implements ConfigurationAdapter + throw new RuntimeException( "Could not load configuration!", ex ); + } + ++ if (!doPermissions) return; + Map permissions = get( "permissions", new HashMap() ); + if ( permissions.isEmpty() ) + { +-- +2.8.3 + diff --git a/BungeeCord-Patches/0004-Configurable-Waterfall-Metrics.patch b/BungeeCord-Patches/0004-Configurable-Waterfall-Metrics.patch new file mode 100644 index 0000000..f383863 --- /dev/null +++ b/BungeeCord-Patches/0004-Configurable-Waterfall-Metrics.patch @@ -0,0 +1,345 @@ +From 5c789d7ac0a98e7ccc5ae6bccedef59621bb9c7f Mon Sep 17 00:00:00 2001 +From: Techcable +Date: Thu, 19 May 2016 10:55:20 -0700 +Subject: [PATCH] Configurable Waterfall Metrics + + +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 b30541b..293ec4e 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 +@@ -84,4 +84,8 @@ public interface ProxyConfig + // Waterfall Options + // + ++ /** ++ * If metrics is enabled ++ */ ++ boolean isMetrics(); + } +diff --git a/proxy/src/main/java/io/github/waterfallmc/waterfall/Metrics.java b/proxy/src/main/java/io/github/waterfallmc/waterfall/Metrics.java +new file mode 100644 +index 0000000..ae5a2a9 +--- /dev/null ++++ b/proxy/src/main/java/io/github/waterfallmc/waterfall/Metrics.java +@@ -0,0 +1,131 @@ ++package io.github.waterfallmc.waterfall; ++ ++import java.io.BufferedReader; ++import java.io.IOException; ++import java.io.InputStreamReader; ++import java.io.OutputStreamWriter; ++import java.io.UnsupportedEncodingException; ++import java.net.URL; ++import java.net.URLConnection; ++import java.net.URLEncoder; ++import java.util.TimerTask; ++ ++import net.md_5.bungee.BungeeCord; ++import net.md_5.bungee.api.ProxyServer; ++ ++public class Metrics extends TimerTask ++{ ++ ++ /** ++ * The current revision number ++ */ ++ private final static int REVISION = 5; ++ /** ++ * The base url of the metrics domain ++ */ ++ private static final String BASE_URL = "http://mcstats.org"; ++ /** ++ * The url used to report a server's status ++ */ ++ private static final String REPORT_URL = "/report/%s"; ++ /** ++ * Interval of time to ping (in minutes) ++ */ ++ public final static int PING_INTERVAL = 10; ++ boolean firstPost = true; ++ ++ @Override ++ public void run() ++ { ++ try ++ { ++ // We use the inverse of firstPost because if it is the first time we are posting, ++ // it is not a interval ping, so it evaluates to FALSE ++ // Each time thereafter it will evaluate to TRUE, i.e PING! ++ postPlugin( !firstPost ); ++ ++ // After the first post we set firstPost to false ++ // Each post thereafter will be a ping ++ firstPost = false; ++ } catch ( IOException ex ) ++ { ++ // ProxyServer.getInstance().getLogger().info( "[Metrics] " + ex.getMessage() ); ++ } ++ } ++ ++ /** ++ * Generic method that posts a plugin to the metrics website ++ */ ++ private void postPlugin(boolean isPing) throws IOException ++ { ++ // Construct the post data ++ final StringBuilder data = new StringBuilder(); ++ data.append( encode( "guid" ) ).append( '=' ).append( encode( BungeeCord.getInstance().config.getUuid() ) ); ++ encodeDataPair( data, "version", ProxyServer.getInstance().getVersion() ); ++ encodeDataPair( data, "server", "0" ); ++ encodeDataPair( data, "players", Integer.toString( ProxyServer.getInstance().getOnlineCount() ) ); ++ encodeDataPair( data, "revision", String.valueOf( REVISION ) ); ++ ++ // If we're pinging, append it ++ if ( isPing ) ++ { ++ encodeDataPair( data, "ping", "true" ); ++ } ++ ++ // Create the url ++ URL url = new URL( BASE_URL + String.format( REPORT_URL, encode( "Waterfall" ) ) ); ++ ++ // Connect to the website ++ URLConnection connection; ++ ++ connection = url.openConnection(); ++ ++ connection.setDoOutput( true ); ++ final BufferedReader reader; ++ final String response; ++ try ( OutputStreamWriter writer = new OutputStreamWriter( connection.getOutputStream() ) ) ++ { ++ writer.write( data.toString() ); ++ writer.flush(); ++ reader = new BufferedReader( new InputStreamReader( connection.getInputStream() ) ); ++ response = reader.readLine(); ++ } ++ reader.close(); ++ ++ if ( response == null || response.startsWith( "ERR" ) ) ++ { ++ throw new IOException( response ); //Throw the exception ++ } ++ } ++ ++ /** ++ *

++ * Encode a key/value data pair to be used in a HTTP post request. This ++ * INCLUDES a & so the first key/value pair MUST be included manually, ++ * e.g:

++ * ++ * StringBuffer data = new StringBuffer(); ++ * data.append(encode("guid")).append('=').append(encode(guid)); ++ * encodeDataPair(data, "version", description.getVersion()); ++ * ++ * ++ * @param buffer the StringBuilder to append the data pair onto ++ * @param key the key value ++ * @param value the value ++ */ ++ private static void encodeDataPair(final StringBuilder buffer, final String key, final String value) throws UnsupportedEncodingException ++ { ++ buffer.append( '&' ).append( encode( key ) ).append( '=' ).append( encode( value ) ); ++ } ++ ++ /** ++ * Encode text as UTF-8 ++ * ++ * @param text the text to encode ++ * @return the encoded text, as UTF-8 ++ */ ++ private static String encode(final String text) throws UnsupportedEncodingException ++ { ++ return URLEncoder.encode( text, "UTF-8" ); ++ } ++} +diff --git a/proxy/src/main/java/io/github/waterfallmc/waterfall/conf/WaterfallConfiguration.java b/proxy/src/main/java/io/github/waterfallmc/waterfall/conf/WaterfallConfiguration.java +index 03160da..1fa3ecd 100644 +--- a/proxy/src/main/java/io/github/waterfallmc/waterfall/conf/WaterfallConfiguration.java ++++ b/proxy/src/main/java/io/github/waterfallmc/waterfall/conf/WaterfallConfiguration.java +@@ -10,10 +10,23 @@ import net.md_5.bungee.conf.YamlConfig; + + public class WaterfallConfiguration extends Configuration { + ++ /** ++ * If metrics is enabled ++ *

++ * Default is true (enabled) ++ */ ++ private boolean metrics = true; ++ + @Override + public void load() { + super.load(); + YamlConfig config = new YamlConfig(new File("waterfall.yml")); + config.load(false); // Load, but no permissions ++ metrics = config.getBoolean("metrics", metrics); ++ } ++ ++ @Override ++ public boolean isMetrics() { ++ return metrics; + } + } +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 3dceb6e..3578aa4 100644 +--- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java ++++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java +@@ -23,6 +23,7 @@ import net.md_5.bungee.scheduler.BungeeScheduler; + import com.google.common.util.concurrent.ThreadFactoryBuilder; + import com.google.gson.Gson; + import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; ++import io.github.waterfallmc.waterfall.Metrics; + import io.github.waterfallmc.waterfall.conf.WaterfallConfiguration; + import io.netty.bootstrap.ServerBootstrap; + import io.netty.channel.Channel; +@@ -284,7 +285,9 @@ public class BungeeCord extends ProxyServer + } + } + }, 0, TimeUnit.MINUTES.toMillis( 5 ) ); +- metricsThread.scheduleAtFixedRate( new Metrics(), 0, TimeUnit.MINUTES.toMillis( Metrics.PING_INTERVAL ) ); ++ if (config.isMetrics()) { ++ metricsThread.scheduleAtFixedRate( new Metrics(), 0, TimeUnit.MINUTES.toMillis( Metrics.PING_INTERVAL ) ); ++ } + } + + public void startListeners() +diff --git a/proxy/src/main/java/net/md_5/bungee/Metrics.java b/proxy/src/main/java/net/md_5/bungee/Metrics.java +deleted file mode 100644 +index 9523987..0000000 +--- a/proxy/src/main/java/net/md_5/bungee/Metrics.java ++++ /dev/null +@@ -1,129 +0,0 @@ +-package net.md_5.bungee; +- +-import java.io.BufferedReader; +-import java.io.IOException; +-import java.io.InputStreamReader; +-import java.io.OutputStreamWriter; +-import java.io.UnsupportedEncodingException; +-import java.net.URL; +-import java.net.URLConnection; +-import java.net.URLEncoder; +-import java.util.TimerTask; +-import net.md_5.bungee.api.ProxyServer; +- +-public class Metrics extends TimerTask +-{ +- +- /** +- * The current revision number +- */ +- private final static int REVISION = 5; +- /** +- * The base url of the metrics domain +- */ +- private static final String BASE_URL = "http://mcstats.org"; +- /** +- * The url used to report a server's status +- */ +- private static final String REPORT_URL = "/report/%s"; +- /** +- * Interval of time to ping (in minutes) +- */ +- final static int PING_INTERVAL = 10; +- boolean firstPost = true; +- +- @Override +- public void run() +- { +- try +- { +- // We use the inverse of firstPost because if it is the first time we are posting, +- // it is not a interval ping, so it evaluates to FALSE +- // Each time thereafter it will evaluate to TRUE, i.e PING! +- postPlugin( !firstPost ); +- +- // After the first post we set firstPost to false +- // Each post thereafter will be a ping +- firstPost = false; +- } catch ( IOException ex ) +- { +- // ProxyServer.getInstance().getLogger().info( "[Metrics] " + ex.getMessage() ); +- } +- } +- +- /** +- * Generic method that posts a plugin to the metrics website +- */ +- private void postPlugin(boolean isPing) throws IOException +- { +- // Construct the post data +- final StringBuilder data = new StringBuilder(); +- data.append( encode( "guid" ) ).append( '=' ).append( encode( BungeeCord.getInstance().config.getUuid() ) ); +- encodeDataPair( data, "version", ProxyServer.getInstance().getVersion() ); +- encodeDataPair( data, "server", "0" ); +- encodeDataPair( data, "players", Integer.toString( ProxyServer.getInstance().getOnlineCount() ) ); +- encodeDataPair( data, "revision", String.valueOf( REVISION ) ); +- +- // If we're pinging, append it +- if ( isPing ) +- { +- encodeDataPair( data, "ping", "true" ); +- } +- +- // Create the url +- URL url = new URL( BASE_URL + String.format( REPORT_URL, encode( "BungeeCord" ) ) ); +- +- // Connect to the website +- URLConnection connection; +- +- connection = url.openConnection(); +- +- connection.setDoOutput( true ); +- final BufferedReader reader; +- final String response; +- try ( OutputStreamWriter writer = new OutputStreamWriter( connection.getOutputStream() ) ) +- { +- writer.write( data.toString() ); +- writer.flush(); +- reader = new BufferedReader( new InputStreamReader( connection.getInputStream() ) ); +- response = reader.readLine(); +- } +- reader.close(); +- +- if ( response == null || response.startsWith( "ERR" ) ) +- { +- throw new IOException( response ); //Throw the exception +- } +- } +- +- /** +- *

+- * Encode a key/value data pair to be used in a HTTP post request. This +- * INCLUDES a & so the first key/value pair MUST be included manually, +- * e.g:

+- * +- * StringBuffer data = new StringBuffer(); +- * data.append(encode("guid")).append('=').append(encode(guid)); +- * encodeDataPair(data, "version", description.getVersion()); +- * +- * +- * @param buffer the StringBuilder to append the data pair onto +- * @param key the key value +- * @param value the value +- */ +- private static void encodeDataPair(final StringBuilder buffer, final String key, final String value) throws UnsupportedEncodingException +- { +- buffer.append( '&' ).append( encode( key ) ).append( '=' ).append( encode( value ) ); +- } +- +- /** +- * Encode text as UTF-8 +- * +- * @param text the text to encode +- * @return the encoded text, as UTF-8 +- */ +- private static String encode(final String text) throws UnsupportedEncodingException +- { +- return URLEncoder.encode( text, "UTF-8" ); +- } +-} +-- +2.8.3 + diff --git a/BungeeCord-Patches/0005-Fetch-modules-from-the-Waterfall-CI.patch b/BungeeCord-Patches/0005-Fetch-modules-from-the-Waterfall-CI.patch new file mode 100644 index 0000000..79d2ad5 --- /dev/null +++ b/BungeeCord-Patches/0005-Fetch-modules-from-the-Waterfall-CI.patch @@ -0,0 +1,45 @@ +From 248f19f83a821f87e64714766803284e73187be8 Mon Sep 17 00:00:00 2001 +From: Tux +Date: Thu, 19 May 2016 11:34:52 -0700 +Subject: [PATCH] Fetch modules from the Waterfall CI + +Don't fetch from the BungeeCord CI, as that only has their modules + +diff --git a/proxy/src/main/java/net/md_5/bungee/module/JenkinsModuleSource.java b/proxy/src/main/java/net/md_5/bungee/module/JenkinsModuleSource.java +index 9bd2dc9..97a08da 100644 +--- a/proxy/src/main/java/net/md_5/bungee/module/JenkinsModuleSource.java ++++ b/proxy/src/main/java/net/md_5/bungee/module/JenkinsModuleSource.java +@@ -1,10 +1,11 @@ + package net.md_5.bungee.module; + +-import com.google.common.io.ByteStreams; +-import com.google.common.io.Files; + import java.io.IOException; + import java.net.URL; + import java.net.URLConnection; ++import java.nio.file.Files; ++import java.nio.file.StandardCopyOption; ++ + import lombok.Data; + import net.md_5.bungee.Util; + +@@ -18,13 +19,14 @@ public class JenkinsModuleSource implements ModuleSource + System.out.println( "Attempting to Jenkins download module " + module.getName() + " v" + version.getBuild() ); + try + { +- URL website = new URL( "http://ci.md-5.net/job/BungeeCord/" + version.getBuild() + "/artifact/module/" + module.getName().replace( '_', '-' ) + "/target/" + module.getName() + ".jar" ); ++ URL website = new URL( "https://tc.demonwav.com/guestAuth/repository/download/Waterfall_Build/" + version.getBuild() + "/" + module.getName() + ".jar" ); + URLConnection con = website.openConnection(); + // 15 second timeout at various stages + con.setConnectTimeout( 15000 ); + con.setReadTimeout( 15000 ); ++ con.setRequestProperty("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36"); + +- Files.write( ByteStreams.toByteArray( con.getInputStream() ), module.getFile() ); ++ Files.copy(con.getInputStream(), module.getFile().toPath(), StandardCopyOption.REPLACE_EXISTING); + System.out.println( "Download complete" ); + } catch ( IOException ex ) + { +-- +2.8.3 + diff --git a/BungeeCord-Patches/0006-Get-rid-of-the-security-manager.patch b/BungeeCord-Patches/0006-Get-rid-of-the-security-manager.patch new file mode 100644 index 0000000..95159f7 --- /dev/null +++ b/BungeeCord-Patches/0006-Get-rid-of-the-security-manager.patch @@ -0,0 +1,107 @@ +From 4229c32ccf8c2f9db70fa2155bd9f46f816a4c3f Mon Sep 17 00:00:00 2001 +From: Tux +Date: Mon, 25 Jan 2016 01:19:07 -0500 +Subject: [PATCH] Get rid of the security manager. + +There's a lot of opinions running on both sides of the debate, but we overwhelmingly feel that the security manager does not help the vast majority of BungeeCord users or plugin developers create correct code. + +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 3578aa4..3cef2cf 100644 +--- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java ++++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java +@@ -176,8 +176,6 @@ public class BungeeCord extends ProxyServer + // Java uses ! to indicate a resource inside of a jar/zip/other container. Running Bungee from within a directory that has a ! will cause this to muck up. + Preconditions.checkState( new File( "." ).getAbsolutePath().indexOf( '!' ) == -1, "Cannot use Waterfall in directory with ! in path." ); + +- System.setSecurityManager( new BungeeSecurityManager() ); +- + try + { + baseBundle = ResourceBundle.getBundle( "messages" ); +diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeSecurityManager.java b/proxy/src/main/java/net/md_5/bungee/BungeeSecurityManager.java +deleted file mode 100644 +index 53c8192..0000000 +--- a/proxy/src/main/java/net/md_5/bungee/BungeeSecurityManager.java ++++ /dev/null +@@ -1,78 +0,0 @@ +-package net.md_5.bungee; +- +-import java.io.PrintWriter; +-import java.io.StringWriter; +-import java.security.AccessControlException; +-import java.security.Permission; +-import java.util.HashSet; +-import java.util.Set; +-import java.util.logging.Level; +-import net.md_5.bungee.api.ProxyServer; +-import net.md_5.bungee.api.scheduler.GroupedThreadFactory; +- +-public class BungeeSecurityManager extends SecurityManager +-{ +- +- private static final boolean ENFORCE = false; +- private final Set seen = new HashSet<>(); +- +- private void checkRestricted(String text) +- { +- Class[] context = getClassContext(); +- for ( int i = 2; i < context.length; i++ ) +- { +- ClassLoader loader = context[i].getClassLoader(); +- +- // Bungee / system can do everything +- if ( loader == ClassLoader.getSystemClassLoader() || loader == null ) +- { +- break; +- } +- +- AccessControlException ex = new AccessControlException( "Plugin violation: " + text ); +- if ( ENFORCE ) +- { +- throw ex; +- } +- +- StringWriter stack = new StringWriter(); +- ex.printStackTrace( new PrintWriter( stack ) ); +- if ( seen.add( stack.toString() ) ) +- { +- ProxyServer.getInstance().getLogger().log( Level.WARNING, "Plugin performed restricted action, please inform them to use proper API methods: " + text, ex ); +- } +- break; +- } +- } +- +- @Override +- public void checkExit(int status) +- { +- checkRestricted( "Exit: Cannot close VM" ); +- } +- +- @Override +- public void checkAccess(ThreadGroup g) +- { +- if ( !( g instanceof GroupedThreadFactory.BungeeGroup ) ) +- { +- checkRestricted( "Illegal thread group access" ); +- } +- } +- +- @Override +- public void checkPermission(Permission perm, Object context) +- { +- checkPermission( perm ); +- } +- +- @Override +- public void checkPermission(Permission perm) +- { +- switch ( perm.getName() ) +- { +- case "setSecurityManager": +- throw new AccessControlException( "Restricted Action", perm ); +- } +- } +-} +-- +2.8.3 + diff --git a/BungeeCord-Patches/0007-Presize-the-HTTP-response-buffer.patch b/BungeeCord-Patches/0007-Presize-the-HTTP-response-buffer.patch new file mode 100644 index 0000000..8be81bd --- /dev/null +++ b/BungeeCord-Patches/0007-Presize-the-HTTP-response-buffer.patch @@ -0,0 +1,23 @@ +From 413435b7f36587ca4cc562d1ffc373fa24b6296d Mon Sep 17 00:00:00 2001 +From: Tux +Date: Wed, 13 Apr 2016 15:17:05 -0400 +Subject: [PATCH] Presize the HTTP response buffer + +16 characters is extremely small, and all responses start around 256 bytes. 640 characters seems to be good (covering skins and capes), based on sampling profile API responses. + +diff --git a/proxy/src/main/java/net/md_5/bungee/http/HttpHandler.java b/proxy/src/main/java/net/md_5/bungee/http/HttpHandler.java +index 96d0a71..bac6b1b 100644 +--- a/proxy/src/main/java/net/md_5/bungee/http/HttpHandler.java ++++ b/proxy/src/main/java/net/md_5/bungee/http/HttpHandler.java +@@ -16,7 +16,7 @@ public class HttpHandler extends SimpleChannelInboundHandler + { + + private final Callback callback; +- private final StringBuilder buffer = new StringBuilder(); ++ private final StringBuilder buffer = new StringBuilder(640); + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception +-- +2.8.3 + diff --git a/BungeeCord-Patches/0008-Allow-configuration-of-the-log-file-path-filename.patch b/BungeeCord-Patches/0008-Allow-configuration-of-the-log-file-path-filename.patch new file mode 100644 index 0000000..d10a7db --- /dev/null +++ b/BungeeCord-Patches/0008-Allow-configuration-of-the-log-file-path-filename.patch @@ -0,0 +1,22 @@ +From ca5884cd49b8a748e4efd99b72704513c8ea008f Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Fri, 11 Sep 2015 23:50:52 -0400 +Subject: [PATCH] Allow configuration of the log file path/filename + + +diff --git a/proxy/src/main/java/net/md_5/bungee/log/BungeeLogger.java b/proxy/src/main/java/net/md_5/bungee/log/BungeeLogger.java +index 94e924b..cde3194 100644 +--- a/proxy/src/main/java/net/md_5/bungee/log/BungeeLogger.java ++++ b/proxy/src/main/java/net/md_5/bungee/log/BungeeLogger.java +@@ -27,7 +27,7 @@ public class BungeeLogger extends Logger + + try + { +- FileHandler fileHandler = new FileHandler( "proxy.log", 1 << 24, 8, true ); ++ FileHandler fileHandler = new FileHandler( System.getProperty("bungee.log-file", "proxy.log"), 1 << 24, 8, true ); + fileHandler.setFormatter( formatter ); + addHandler( fileHandler ); + +-- +2.8.3 + diff --git a/BungeeCord-Patches/0009-Fix-unicode-characters-in-configuration-files.patch b/BungeeCord-Patches/0009-Fix-unicode-characters-in-configuration-files.patch new file mode 100644 index 0000000..dd3ca25 --- /dev/null +++ b/BungeeCord-Patches/0009-Fix-unicode-characters-in-configuration-files.patch @@ -0,0 +1,57 @@ +From f48dd938af3f64fdaf55b7faee68eee70d20899e Mon Sep 17 00:00:00 2001 +From: kamcio96 +Date: Sat, 21 May 2016 17:17:36 -0600 +Subject: [PATCH] Fix unicode characters in configuration files + + +diff --git a/config/src/main/java/net/md_5/bungee/config/YamlConfiguration.java b/config/src/main/java/net/md_5/bungee/config/YamlConfiguration.java +index 0a93602..efeaa6a 100644 +--- a/config/src/main/java/net/md_5/bungee/config/YamlConfiguration.java ++++ b/config/src/main/java/net/md_5/bungee/config/YamlConfiguration.java +@@ -1,16 +1,25 @@ + package net.md_5.bungee.config; + ++import java.io.BufferedReader; ++import java.io.BufferedWriter; + import java.io.File; ++import java.io.FileInputStream; ++import java.io.FileOutputStream; + import java.io.FileReader; + import java.io.FileWriter; + import java.io.IOException; + import java.io.InputStream; ++import java.io.InputStreamReader; ++import java.io.OutputStreamWriter; + import java.io.Reader; + import java.io.Writer; + import java.util.LinkedHashMap; + import java.util.Map; + import lombok.AccessLevel; + import lombok.NoArgsConstructor; ++ ++import com.google.common.base.Charsets; ++ + import org.yaml.snakeyaml.DumperOptions; + import org.yaml.snakeyaml.Yaml; + +@@ -32,7 +41,7 @@ public class YamlConfiguration extends ConfigurationProvider + @Override + public void save(Configuration config, File file) throws IOException + { +- try ( FileWriter writer = new FileWriter( file ) ) ++ try (Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), Charsets.UTF_8))) + { + save( config, writer ); + } +@@ -53,7 +62,7 @@ public class YamlConfiguration extends ConfigurationProvider + @Override + public Configuration load(File file, Configuration defaults) throws IOException + { +- try ( FileReader reader = new FileReader( file ) ) ++ try (Reader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), Charsets.UTF_8))) + { + return load( reader, defaults ); + } +-- +2.8.3 + diff --git a/BungeeCord-Patches/0010-Clean-up-and-unit-test-the-UUID-code.patch b/BungeeCord-Patches/0010-Clean-up-and-unit-test-the-UUID-code.patch new file mode 100644 index 0000000..ec26c6d --- /dev/null +++ b/BungeeCord-Patches/0010-Clean-up-and-unit-test-the-UUID-code.patch @@ -0,0 +1,80 @@ +From c5c7f68d947f366fef739e0ac3a655baed507bfe Mon Sep 17 00:00:00 2001 +From: Tux +Date: Thu, 19 May 2016 18:13:48 -0600 +Subject: [PATCH] Clean up and unit test the UUID code. + +Also optimizes conversion to mojang-style uuids (by avoiding regex). + +diff --git a/api/src/main/java/net/md_5/bungee/Util.java b/api/src/main/java/net/md_5/bungee/Util.java +index 86a0055..37e12e9 100644 +--- a/api/src/main/java/net/md_5/bungee/Util.java ++++ b/api/src/main/java/net/md_5/bungee/Util.java +@@ -80,4 +80,8 @@ public class Util + { + return UUID.fromString( uuid.substring( 0, 8 ) + "-" + uuid.substring( 8, 12 ) + "-" + uuid.substring( 12, 16 ) + "-" + uuid.substring( 16, 20 ) + "-" + uuid.substring( 20, 32 ) ); + } ++ ++ public static String getMojangUUID(UUID uuid) { ++ return uuid.toString().replace( "-", "" ); ++ } + } +diff --git a/api/src/main/java/net/md_5/bungee/api/ServerPing.java b/api/src/main/java/net/md_5/bungee/api/ServerPing.java +index 314a1d2..6804ad9 100644 +--- a/api/src/main/java/net/md_5/bungee/api/ServerPing.java ++++ b/api/src/main/java/net/md_5/bungee/api/ServerPing.java +@@ -73,7 +73,7 @@ public class ServerPing + + public String getId() + { +- return uniqueId.toString().replaceAll( "-", "" ); ++ return Util.getMojangUUID(uniqueId); + } + } + +diff --git a/api/src/test/java/net/md_5/bungee/util/UtilTest.java b/api/src/test/java/net/md_5/bungee/util/UtilTest.java +new file mode 100644 +index 0000000..030b5cd +--- /dev/null ++++ b/api/src/test/java/net/md_5/bungee/util/UtilTest.java +@@ -0,0 +1,25 @@ ++package net.md_5.bungee.util; ++ ++import net.md_5.bungee.Util; ++import org.junit.Assert; ++import org.junit.Test; ++ ++import java.util.UUID; ++ ++import static org.junit.Assert.*; ++ ++public class UtilTest { ++ ++ private static final String FULL_UUID = "982709b9-6fd8-4627-929d-e7d3b91166ea"; ++ private static final String MOJANG_UUID = "982709b96fd84627929de7d3b91166ea"; ++ ++ @Test ++ public void testGetUUID() throws Exception { ++ Assert.assertEquals(FULL_UUID, Util.getUUID(MOJANG_UUID).toString()); ++ } ++ ++ @Test ++ public void testGetMojangUUID() throws Exception { ++ assertEquals(MOJANG_UUID, Util.getMojangUUID(UUID.fromString(FULL_UUID))); ++ } ++} +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 dab6ef2..ad19168 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 +@@ -603,7 +603,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection + @Override + public String getUUID() + { +- return uniqueId.toString().replaceAll( "-", "" ); ++ return Util.getMojangUUID(uniqueId); + } + + @Override +-- +2.8.3 + diff --git a/BungeeCord-Patches/0011-Optimize-uuid-conversions.patch b/BungeeCord-Patches/0011-Optimize-uuid-conversions.patch new file mode 100644 index 0000000..0f03fa8 --- /dev/null +++ b/BungeeCord-Patches/0011-Optimize-uuid-conversions.patch @@ -0,0 +1,258 @@ +From 84dc97a63f6f751464fcef7853dbc375c4a10439 Mon Sep 17 00:00:00 2001 +From: Techcable +Date: Mon, 14 Mar 2016 15:40:44 -0700 +Subject: [PATCH] Optimize uuid conversions + +Optimizes converting to and from mojang format. +Manually decode uuids to and from hex. + +diff --git a/api/src/main/java/io/github/waterfallmc/waterfall/utils/Hex.java b/api/src/main/java/io/github/waterfallmc/waterfall/utils/Hex.java +new file mode 100644 +index 0000000..ece5f79 +--- /dev/null ++++ b/api/src/main/java/io/github/waterfallmc/waterfall/utils/Hex.java +@@ -0,0 +1,113 @@ ++package io.github.waterfallmc.waterfall.utils; ++ ++import java.util.Arrays; ++import java.util.Objects; ++ ++public class Hex { ++ ++ public static byte[] decode(CharSequence chars) { ++ byte[] bytes = new byte[chars.length() >> 1]; ++ decode(chars, 0, bytes, 0, bytes.length); ++ return bytes; ++ } ++ ++ public static void decode(char[] chars, int charOffset, byte[] dest, int offset, int length) { ++ decode(new CharSequence() { ++ @Override ++ public int length() { ++ return chars.length; ++ } ++ ++ @Override ++ public char charAt(int index) { ++ return chars[index]; ++ } ++ ++ @Override ++ public CharSequence subSequence(int start, int end) { ++ return toString().substring(start, end); ++ } ++ ++ @Override ++ public String toString() { ++ return new String(chars, charOffset, chars.length); ++ } ++ }); ++ } ++ ++ public static void decode(CharSequence chars, int charOffset, byte[] dest, int offset, int length) { ++ Objects.requireNonNull(chars, "Null chars"); ++ Objects.requireNonNull(chars, "Null destination"); ++ final int numChars = chars.length(); ++ if ((numChars & 0x01) != 0) { ++ throw new IllegalArgumentException("Odd number of characters: " + numChars); ++ } else if (length < (numChars - charOffset) >> 1) { ++ throw new IllegalArgumentException("Too many bytes to fill with " + numChars + " characters: " + length); ++ } else if (offset < 0 || charOffset < 0 || length < 0 || length * 2 > numChars - charOffset || length > dest.length - offset) { ++ throw new IndexOutOfBoundsException(); ++ } ++ for (int i = 0, charIndex = charOffset; i < length; i++) { ++ char first = chars.charAt(charIndex++); ++ char second = chars.charAt(charIndex++); ++ dest[i + offset] = (byte) ((toDigit(first) << 4) | (toDigit(second))); ++ } ++ } ++ ++ public static String encodeString(byte[] bytes) { ++ return new String(encode(bytes)); ++ } ++ ++ public static char[] encode(byte[] bytes) { ++ char[] chars = new char[bytes.length << 1]; ++ encode(chars, 0, bytes, 0, bytes.length); ++ return chars; ++ } ++ ++ public static void encode(char[] chars, int charOffset, byte[] source, int offset, int length) { ++ Objects.requireNonNull(chars, "Null chars"); ++ Objects.requireNonNull(chars, "Null bytes"); ++ if (offset < 0 || charOffset < 0 || length < 0 || length * 2 > chars.length - charOffset || length > source.length - offset) { ++ throw new IndexOutOfBoundsException(); ++ } else if (length == 0) { ++ return; ++ } ++ for (int i = 0, charIndex = charOffset; i < length; i++) { ++ byte b = source[i + offset]; ++ chars[charIndex++] = fromDigit((byte) ((b >> 4) & 0xF)); ++ chars[charIndex++] = fromDigit((byte) (b & 0xF)); ++ } ++ } ++ private static final char[] ENCODE_TABLE = new char[]{ ++ '0', '1', '2', '3', '4', '5', '6', '7', ++ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' ++ }; ++ private static final byte[] DECODE_TABLE = new byte[128]; ++ ++ static { ++ Arrays.fill(DECODE_TABLE, (byte) -1); ++ for (int value = 0; value < ENCODE_TABLE.length; value++) { ++ char c = ENCODE_TABLE[value]; ++ DECODE_TABLE[c] = (byte) value; ++ char upper; ++ if ((upper = Character.toUpperCase(c)) != c) { ++ DECODE_TABLE[upper] = (byte) value; ++ } ++ } ++ } ++ ++ public static byte toDigit(char c) { ++ byte value; ++ if (c < DECODE_TABLE.length) { ++ value = DECODE_TABLE[c]; ++ } else { ++ value = -1; ++ } ++ if (value < 0) throw new IllegalArgumentException("Invalid character " + c); ++ return value; ++ } ++ ++ private static char fromDigit(byte b) { ++ assert (b & 0xF) == b : "Out of range " + b; ++ return ENCODE_TABLE[b]; ++ } ++} +\ No newline at end of file +diff --git a/api/src/main/java/io/github/waterfallmc/waterfall/utils/UUIDUtils.java b/api/src/main/java/io/github/waterfallmc/waterfall/utils/UUIDUtils.java +new file mode 100644 +index 0000000..7258a26 +--- /dev/null ++++ b/api/src/main/java/io/github/waterfallmc/waterfall/utils/UUIDUtils.java +@@ -0,0 +1,70 @@ ++package io.github.waterfallmc.waterfall.utils; ++import java.util.UUID; ++ ++import com.google.common.base.Preconditions; ++import com.google.common.primitives.Longs; ++ ++public class UUIDUtils { ++ private UUIDUtils() {} ++ ++ public static String toMojangString(UUID id) { ++ Preconditions.checkNotNull(id, "Null id"); ++ return Hex.encodeString(toBytes(id)); ++ } ++ ++ public static UUID fromString(String s) { ++ Preconditions.checkNotNull(s, "Null string"); ++ if (s.length() == 36) { // UUID.toString() uuid ++ s = s.replaceAll("-", ""); ++ } else if (s.length() != 32) { ++ throw new IllegalArgumentException("Invalid UUID: " + s); ++ } ++ return fromMojangString0(s); ++ } ++ ++ public static UUID fromMojangString(String s) { ++ Preconditions.checkNotNull(s, "Null string"); ++ if (s.length() != 32) { ++ throw new IllegalArgumentException("UUID not in mojang format: " + s); ++ } ++ return fromMojangString0(s); ++ } ++ ++ private static UUID fromMojangString0(String s) { ++ assert s != null : "Null string"; ++ assert s.length() == 32 : "invalid length: " + s; ++ try { ++ return fromBytes(Hex.decode(s)); ++ } catch (IllegalArgumentException e) { ++ throw new IllegalArgumentException("Invalid UUID: " + s); ++ } ++ } ++ ++ public static byte[] toBytes(UUID id) { ++ Preconditions.checkNotNull(id, "Null id"); ++ byte[] result = new byte[16]; ++ long lsb = id.getLeastSignificantBits(); ++ for (int i = 15; i >= 8; i--) { ++ result[i] = (byte) (lsb & 0xffL); ++ lsb >>= 8; ++ } ++ long msb = id.getMostSignificantBits(); ++ for (int i = 7; i >= 0; i--) { ++ result[i] = (byte) (msb & 0xffL); ++ msb >>= 8; ++ } ++ return result; ++ } ++ ++ public static UUID fromBytes(byte[] bytes) { ++ Preconditions.checkNotNull(bytes, "Null bytes"); ++ if (bytes.length != 16) { ++ throw new IllegalArgumentException("Invalid length: " + bytes.length); ++ } ++ long msb = Longs.fromBytes(bytes[0], bytes[1], bytes[2], bytes[3], ++ bytes[4], bytes[5], bytes[6], bytes[7]); ++ long lsb = Longs.fromBytes(bytes[8], bytes[9], bytes[10], bytes[11], ++ bytes[12], bytes[13], bytes[14], bytes[15]); ++ return new UUID(msb, lsb); ++ } ++} +\ No newline at end of file +diff --git a/api/src/main/java/net/md_5/bungee/Util.java b/api/src/main/java/net/md_5/bungee/Util.java +index 37e12e9..b268bef 100644 +--- a/api/src/main/java/net/md_5/bungee/Util.java ++++ b/api/src/main/java/net/md_5/bungee/Util.java +@@ -1,11 +1,15 @@ + package net.md_5.bungee; + + import com.google.common.base.Joiner; ++import com.google.common.primitives.Ints; + import java.net.InetSocketAddress; + import java.net.URI; + import java.net.URISyntaxException; + import java.util.UUID; + ++import io.github.waterfallmc.waterfall.utils.Hex; ++import io.github.waterfallmc.waterfall.utils.UUIDUtils; ++ + /** + * Series of utility classes to perform various operations. + */ +@@ -42,7 +46,7 @@ public class Util + */ + public static String hex(int i) + { +- return String.format( "0x%02X", i ); ++ return Hex.encodeString(Ints.toByteArray(i)); + } + + /** +@@ -78,10 +82,17 @@ public class Util + */ + public static UUID getUUID(String uuid) + { +- return UUID.fromString( uuid.substring( 0, 8 ) + "-" + uuid.substring( 8, 12 ) + "-" + uuid.substring( 12, 16 ) + "-" + uuid.substring( 16, 20 ) + "-" + uuid.substring( 20, 32 ) ); ++ return UUIDUtils.fromString(uuid); + } + +- public static String getMojangUUID(UUID uuid) { +- return uuid.toString().replace( "-", "" ); ++ /** ++ * Converts a UUID to a Mojang UUID ++ * ++ * @param uuid The string to be converted ++ * @return The result ++ */ ++ public static String getMojangUUID(UUID uuid) ++ { ++ return UUIDUtils.toMojangString(uuid); + } + } +-- +2.8.3 + diff --git a/BungeeCord-Patches/0012-Add-support-for-FML-with-IP-Forwarding-enabled.patch b/BungeeCord-Patches/0012-Add-support-for-FML-with-IP-Forwarding-enabled.patch new file mode 100644 index 0000000..a4bffe5 --- /dev/null +++ b/BungeeCord-Patches/0012-Add-support-for-FML-with-IP-Forwarding-enabled.patch @@ -0,0 +1,121 @@ +From 181fb185d832bbea34d4744bb7e426d9ff6bc216 Mon Sep 17 00:00:00 2001 +From: Daniel Naylor +Date: Sun, 9 Aug 2015 13:43:57 +0100 +Subject: [PATCH] Add support for FML with IP Forwarding enabled + +FML adds a \00FML\00 marker to the host field, so Forge can determine whether or not to start a Forge handshake, making way to allow vanilla clients to connect to Forge servers that don't need a client modification. However, Bungee also uses the field, and the two implementations collide when using Spigot. + +The original fix was to not send the FML information at the same time as the IP forwarding, you could have one or the other, but not both. This was OK, as no FML servers supported IP forwarding as of time of the patch. This was implemented in commit 4809f1f80ace9ae87b91453c8887c70f5e098bd0. + +However, there is now at least one Forge coremod that intends to support IP forwarding. To be able to support Forge with IP forwarding, a way to be able to support the FML token (and any other host data) is needed. This adds a property to the user Game Profile to forward on whether the user is a FML client, along with whether there is any extra data. + +No breaking changes occur due to this patch. + +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 dd00192..5ed9fe4 100644 +--- a/proxy/src/main/java/net/md_5/bungee/ServerConnector.java ++++ b/proxy/src/main/java/net/md_5/bungee/ServerConnector.java +@@ -4,6 +4,7 @@ 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; +@@ -92,15 +93,39 @@ public class ServerConnector extends PacketHandler + String newHost = copiedHandshake.getHost() + "\00" + user.getAddress().getHostString() + "\00" + user.getUUID(); + + LoginResult profile = user.getPendingConnection().getLoginProfile(); ++ ++ // Handle properties. ++ LoginResult.Property[] properties = new LoginResult.Property[0]; ++ + if ( profile != null && profile.getProperties() != null && profile.getProperties().length > 0 ) + { +- newHost += "\00" + BungeeCord.getInstance().gson.toJson( profile.getProperties() ); ++ properties = profile.getProperties(); + } ++ ++ 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 ); ++ ++ // 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() ) + { +- // Only restore the extra data if IP forwarding is off. +- // TODO: Add support for this data with IP forwarding. ++ // Restore the extra data + copiedHandshake.setHost( copiedHandshake.getHost() + user.getExtraDataInHandshake() ); + } + +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 a5010f3..018c02e 100644 +--- a/proxy/src/main/java/net/md_5/bungee/UserConnection.java ++++ b/proxy/src/main/java/net/md_5/bungee/UserConnection.java +@@ -12,6 +12,7 @@ import io.netty.channel.ChannelOption; + import io.netty.util.internal.PlatformDependent; + import java.net.InetSocketAddress; + import java.util.ArrayList; ++import java.util.Arrays; + import java.util.Collection; + import java.util.Collections; + import java.util.HashSet; +@@ -40,6 +41,8 @@ import net.md_5.bungee.api.event.ServerConnectEvent; + import net.md_5.bungee.api.score.Scoreboard; + import net.md_5.bungee.chat.ComponentSerializer; + import net.md_5.bungee.connection.InitialHandler; ++import net.md_5.bungee.connection.LoginResult; ++import net.md_5.bungee.connection.LoginResult.Property; + import net.md_5.bungee.entitymap.EntityMap; + import net.md_5.bungee.forge.ForgeClientHandler; + import net.md_5.bungee.forge.ForgeConstants; +@@ -181,8 +184,12 @@ public final class UserConnection implements ProxiedPlayer + + 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) +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 6dca204..f5253b8 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. + */ +-- +2.8.3 + diff --git a/BungeeCord-Patches/0013-Better-unit-tests-for-Chat-API.patch b/BungeeCord-Patches/0013-Better-unit-tests-for-Chat-API.patch new file mode 100644 index 0000000..709d8ec --- /dev/null +++ b/BungeeCord-Patches/0013-Better-unit-tests-for-Chat-API.patch @@ -0,0 +1,79 @@ +From 6ee13e629b72a93e352cea0d99d142a066d12bee Mon Sep 17 00:00:00 2001 +From: Tux +Date: Thu, 19 May 2016 17:36:31 -0600 +Subject: [PATCH] Better unit tests for Chat API + + +diff --git a/chat/src/test/java/net/md_5/bungee/api/chat/TranslatableComponentTest.java b/chat/src/test/java/net/md_5/bungee/api/chat/TranslatableComponentTest.java +index 453d375..1a2ffd0 100644 +--- a/chat/src/test/java/net/md_5/bungee/api/chat/TranslatableComponentTest.java ++++ b/chat/src/test/java/net/md_5/bungee/api/chat/TranslatableComponentTest.java +@@ -3,6 +3,8 @@ package net.md_5.bungee.api.chat; + import net.md_5.bungee.api.chat.TranslatableComponent; + import org.junit.Test; + ++import java.util.List; ++ + import static org.junit.Assert.assertEquals; + + public class TranslatableComponentTest +@@ -15,4 +17,25 @@ public class TranslatableComponentTest + assertEquals( "Test string with 2 placeholders: aoeu", testComponent.toPlainText() ); + assertEquals( "§fTest string with §f2§f placeholders: §faoeu", testComponent.toLegacyText() ); + } ++ ++ @Test ++ public void testDuplicateNullWithDoesntThrowException() { ++ TranslatableComponent component = new TranslatableComponent("Test") { ++ @Override ++ public List getExtra() { ++ return null; ++ } ++ }; ++ ++ TranslatableComponent copy = new TranslatableComponent(component); ++ // The fact that we don't throw an exception means it's working as intended. ++ } ++ ++ @Test ++ public void testEscapedPercentInPlainText() ++ { ++ TranslatableComponent testComponent = new TranslatableComponent( "Test string with %% sign" ); ++ assertEquals( "Test string with % sign", testComponent.toPlainText() ); ++ assertEquals( "§fTest string with §f%§f sign", testComponent.toLegacyText() ); ++ } + } +diff --git a/proxy/src/test/java/net/md_5/bungee/chat/ComponentsTest.java b/proxy/src/test/java/net/md_5/bungee/chat/ComponentsTest.java +index 004a2b7..f34eb3d 100644 +--- a/proxy/src/test/java/net/md_5/bungee/chat/ComponentsTest.java ++++ b/proxy/src/test/java/net/md_5/bungee/chat/ComponentsTest.java +@@ -123,6 +123,26 @@ public class ComponentsTest + Assert.assertEquals( eventRetention[1].getClickEvent(), testClickEvent ); + } + ++ @Test ++ public void testBuilderSpecialFormatting() ++ { ++ BaseComponent[] components = new ComponentBuilder( "Hello " ) ++ .bold(true).underlined(true).italic(true).strikethrough(true).obfuscated(true) ++ .append("World").underlined(false).strikethrough(false).create(); ++ ++ Assert.assertTrue( components[0].isBold() ); ++ Assert.assertTrue( components[0].isUnderlined() ); ++ Assert.assertTrue( components[0].isItalic() ); ++ Assert.assertTrue( components[0].isStrikethrough() ); ++ Assert.assertTrue( components[0].isObfuscated() ); ++ ++ Assert.assertTrue( components[1].isBold() ); ++ Assert.assertFalse( components[1].isUnderlined() ); ++ Assert.assertTrue( components[1].isItalic() ); ++ Assert.assertFalse( components[1].isStrikethrough() ); ++ Assert.assertTrue( components[1].isObfuscated() ); ++ } ++ + @Test(expected = IllegalArgumentException.class) + public void testLoopSimple() + { +-- +2.8.3 + diff --git a/BungeeCord-Patches/0014-Don-t-allow-channel-buffers-to-grow-beyond-a-reasona.patch b/BungeeCord-Patches/0014-Don-t-allow-channel-buffers-to-grow-beyond-a-reasona.patch new file mode 100644 index 0000000..d87abd8 --- /dev/null +++ b/BungeeCord-Patches/0014-Don-t-allow-channel-buffers-to-grow-beyond-a-reasona.patch @@ -0,0 +1,22 @@ +From 7937df226bd632a263f9db241fac040845cb916c Mon Sep 17 00:00:00 2001 +From: Iceee +Date: Mon, 6 Jul 2015 18:59:29 -0500 +Subject: [PATCH] Don't allow channel buffers to grow beyond a reasonable limit + + +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 3cef2cf..fd8d9b0 100644 +--- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java ++++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java +@@ -310,6 +310,8 @@ public class BungeeCord extends ProxyServer + new ServerBootstrap() + .channel( PipelineUtils.getServerChannel() ) + .option( ChannelOption.SO_REUSEADDR, true ) // TODO: Move this elsewhere! ++ .childOption( ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 1024 * 1024 * 10 ) ++ .childOption( ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 1024 * 1024 * 1 ) + .childAttr( PipelineUtils.LISTENER, info ) + .childHandler( PipelineUtils.SERVER_CHILD ) + .group( eventLoops ) +-- +2.8.3 + diff --git a/BungeeCord-Patches/0015-Allow-removing-servers-or-changing-addresses-on-relo.patch b/BungeeCord-Patches/0015-Allow-removing-servers-or-changing-addresses-on-relo.patch new file mode 100644 index 0000000..fc15d82 --- /dev/null +++ b/BungeeCord-Patches/0015-Allow-removing-servers-or-changing-addresses-on-relo.patch @@ -0,0 +1,76 @@ +From e3161d727171388b974b829ae6ca08abeb71fa79 Mon Sep 17 00:00:00 2001 +From: Techcable +Date: Thu, 28 Jan 2016 15:13:29 -0700 +Subject: [PATCH] Allow removing servers or changing addresses on reload + +Moves all players on the removed server to the default server. +Address changes also move the players to the default server. +Kicks players on failure to move. + +Original Issue: https://github.com/WaterfallMC/Waterfall-Old/issues/17 + +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 81dd4af..db9ebbd 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 +@@ -11,12 +11,15 @@ import java.util.UUID; + import java.util.logging.Level; + import javax.imageio.ImageIO; + import lombok.Getter; ++ ++import net.md_5.bungee.BungeeCord; + import net.md_5.bungee.api.Favicon; + import net.md_5.bungee.api.ProxyConfig; + import net.md_5.bungee.api.ProxyServer; + import net.md_5.bungee.api.config.ConfigurationAdapter; + import net.md_5.bungee.api.config.ListenerInfo; + import net.md_5.bungee.api.config.ServerInfo; ++import net.md_5.bungee.api.connection.ProxiedPlayer; + import net.md_5.bungee.util.CaseInsensitiveMap; + import net.md_5.bungee.util.CaseInsensitiveSet; + +@@ -97,18 +100,31 @@ public abstract class Configuration implements ProxyConfig + servers = new CaseInsensitiveMap<>( newServers ); + } else + { +- for ( ServerInfo oldServer : servers.values() ) +- { +- // Don't allow servers to be removed +- Preconditions.checkArgument( newServers.containsKey( oldServer.getName() ), "Server %s removed on reload!", oldServer.getName() ); +- } ++ Map oldServers = this.servers; ++ this.servers = new CaseInsensitiveMap<>(newServers); + +- // Add new servers +- for ( Map.Entry newServer : newServers.entrySet() ) ++ for ( ServerInfo oldServer : oldServers.values() ) + { +- if ( !servers.containsValue( newServer.getValue() ) ) +- { +- servers.put( newServer.getKey(), newServer.getValue() ); ++ ServerInfo newServer = newServers.get(oldServer.getName()); ++ if ((newServer == null || !oldServer.getAddress().equals(newServer.getAddress())) && !oldServer.getPlayers().isEmpty()) { ++ BungeeCord.getInstance().getLogger().info("Moving players off of server: " + oldServer.getName()); ++ // The server is being removed, or having it's address changed ++ for (ProxiedPlayer player : oldServer.getPlayers()) { ++ ListenerInfo listener = player.getPendingConnection().getListener(); ++ String destinationName = newServers.get(listener.getDefaultServer()) == null ? listener.getDefaultServer() : listener.getFallbackServer(); ++ ServerInfo destination = newServers.get(destinationName); ++ if (destination == null) { ++ BungeeCord.getInstance().getLogger().severe("Couldn't find server " + listener.getDefaultServer() + " or " + listener.getFallbackServer() + " to put player " + player.getName() + " on"); ++ player.disconnect(BungeeCord.getInstance().getTranslation("fallback_kick", "Not found on reload")); ++ continue; ++ } ++ player.connect(destination, (success, cause) -> { ++ if (!success) { ++ BungeeCord.getInstance().getLogger().log(Level.WARNING, "Failed to connect " + player.getName() + " to " + destination.getName(), cause); ++ player.disconnect(BungeeCord.getInstance().getTranslation("fallback_kick", cause.getCause().getClass().getName())); ++ } ++ }); ++ } + } + } + } +-- +2.8.3 + diff --git a/BungeeCord-Patches/0016-Use-ASM-for-events-via-the-Event4J-library.patch b/BungeeCord-Patches/0016-Use-ASM-for-events-via-the-Event4J-library.patch new file mode 100644 index 0000000..29a900e --- /dev/null +++ b/BungeeCord-Patches/0016-Use-ASM-for-events-via-the-Event4J-library.patch @@ -0,0 +1,272 @@ +From 81c24fbb9f86c8bd14cc33208504f53147235cff Mon Sep 17 00:00:00 2001 +From: Techcable +Date: Sun, 28 Feb 2016 22:46:22 -0700 +Subject: [PATCH] Use ASM for events, via the Event4J library + +According to benchmarks, this is about 7 nanoseconds faster than reflection (34 ns -> 27 ns). +Event4J falls back to Java 8's new MethodHandle if the event method isn't public. + +diff --git a/event/pom.xml b/event/pom.xml +index b6ef990..ff72600 100644 +--- a/event/pom.xml ++++ b/event/pom.xml +@@ -17,4 +17,24 @@ + + Waterfall-Event + Generic java event dispatching API intended for use with Waterfall. ++ ++ ++ ++ net.techcable ++ event4j ++ 1.1.0 ++ ++ ++ org.ow2.asm ++ asm-all ++ 5.0.4 ++ ++ ++ ++ ++ ++ techcable-repo ++ https://repo.techcable.net/content/groups/public/ ++ ++ + +diff --git a/event/src/main/java/net/md_5/bungee/event/EventBus.java b/event/src/main/java/net/md_5/bungee/event/EventBus.java +index 5b5d420..c93aa16 100644 +--- a/event/src/main/java/net/md_5/bungee/event/EventBus.java ++++ b/event/src/main/java/net/md_5/bungee/event/EventBus.java +@@ -1,26 +1,13 @@ + package net.md_5.bungee.event; + +-import java.lang.reflect.InvocationTargetException; +-import java.lang.reflect.Method; +-import java.text.MessageFormat; +-import java.util.ArrayList; +-import java.util.HashMap; +-import java.util.HashSet; +-import java.util.List; +-import java.util.Map; +-import java.util.Set; +-import java.util.concurrent.ConcurrentHashMap; +-import java.util.concurrent.locks.Lock; +-import java.util.concurrent.locks.ReentrantLock; +-import java.util.logging.Level; + import java.util.logging.Logger; + + public class EventBus + { + +- private final Map, Map>> byListenerAndPriority = new HashMap<>(); +- private final Map, EventHandlerMethod[]> byEventBaked = new ConcurrentHashMap<>(); +- private final Lock lock = new ReentrantLock(); ++ private final net.techcable.event4j.EventBus event4JBus = net.techcable.event4j.EventBus.builder() ++ .eventMarker((m) -> m.isAnnotationPresent(EventHandler.class) ? m.getAnnotation(EventHandler.class)::priority : null) ++ .build(); + private final Logger logger; + + public EventBus() +@@ -35,167 +22,16 @@ public class EventBus + + public void post(Object event) + { +- EventHandlerMethod[] handlers = byEventBaked.get( event.getClass() ); +- +- if ( handlers != null ) +- { +- for ( EventHandlerMethod method : handlers ) +- { +- try +- { +- method.invoke( event ); +- } catch ( IllegalAccessException ex ) +- { +- throw new Error( "Method became inaccessible: " + event, ex ); +- } catch ( IllegalArgumentException ex ) +- { +- throw new Error( "Method rejected target/argument: " + event, ex ); +- } catch ( InvocationTargetException ex ) +- { +- logger.log( Level.WARNING, MessageFormat.format( "Error dispatching event {0} to listener {1}", event, method.getListener() ), ex.getCause() ); +- } +- } +- } +- } +- +- private Map, Map>> findHandlers(Object listener) +- { +- Map, Map>> handler = new HashMap<>(); +- for ( Method m : listener.getClass().getDeclaredMethods() ) +- { +- EventHandler annotation = m.getAnnotation( EventHandler.class ); +- if ( annotation != null ) +- { +- Class[] params = m.getParameterTypes(); +- if ( params.length != 1 ) +- { +- logger.log( Level.INFO, "Method {0} in class {1} annotated with {2} does not have single argument", new Object[] +- { +- m, listener.getClass(), annotation +- } ); +- continue; +- } +- Map> prioritiesMap = handler.get( params[0] ); +- if ( prioritiesMap == null ) +- { +- prioritiesMap = new HashMap<>(); +- handler.put( params[0], prioritiesMap ); +- } +- Set priority = prioritiesMap.get( annotation.priority() ); +- if ( priority == null ) +- { +- priority = new HashSet<>(); +- prioritiesMap.put( annotation.priority(), priority ); +- } +- priority.add( m ); +- } +- } +- return handler; ++ event4JBus.fire(event); + } + + public void register(Object listener) + { +- Map, Map>> handler = findHandlers( listener ); +- lock.lock(); +- try +- { +- for ( Map.Entry, Map>> e : handler.entrySet() ) +- { +- Map> prioritiesMap = byListenerAndPriority.get( e.getKey() ); +- if ( prioritiesMap == null ) +- { +- prioritiesMap = new HashMap<>(); +- byListenerAndPriority.put( e.getKey(), prioritiesMap ); +- } +- for ( Map.Entry> entry : e.getValue().entrySet() ) +- { +- Map currentPriorityMap = prioritiesMap.get( entry.getKey() ); +- if ( currentPriorityMap == null ) +- { +- currentPriorityMap = new HashMap<>(); +- prioritiesMap.put( entry.getKey(), currentPriorityMap ); +- } +- Method[] baked = new Method[ entry.getValue().size() ]; +- currentPriorityMap.put( listener, entry.getValue().toArray( baked ) ); +- } +- bakeHandlers( e.getKey() ); +- } +- } finally +- { +- lock.unlock(); +- } ++ event4JBus.register(listener); + } + + public void unregister(Object listener) + { +- Map, Map>> handler = findHandlers( listener ); +- lock.lock(); +- try +- { +- for ( Map.Entry, Map>> e : handler.entrySet() ) +- { +- Map> prioritiesMap = byListenerAndPriority.get( e.getKey() ); +- if ( prioritiesMap != null ) +- { +- for ( Byte priority : e.getValue().keySet() ) +- { +- Map currentPriority = prioritiesMap.get( priority ); +- if ( currentPriority != null ) +- { +- currentPriority.remove( listener ); +- if ( currentPriority.isEmpty() ) +- { +- prioritiesMap.remove( priority ); +- } +- } +- } +- if ( prioritiesMap.isEmpty() ) +- { +- byListenerAndPriority.remove( e.getKey() ); +- } +- } +- bakeHandlers( e.getKey() ); +- } +- } finally +- { +- lock.unlock(); +- } +- } +- +- /** +- * Shouldn't be called without first locking the writeLock; intended for use +- * only inside {@link #register(java.lang.Object) register(Object)} or +- * {@link #unregister(java.lang.Object) unregister(Object)}. +- */ +- private void bakeHandlers(Class eventClass) +- { +- Map> handlersByPriority = byListenerAndPriority.get( eventClass ); +- if ( handlersByPriority != null ) +- { +- List handlersList = new ArrayList<>( handlersByPriority.size() * 2 ); +- +- // Either I'm really tired, or the only way we can iterate between Byte.MIN_VALUE and Byte.MAX_VALUE inclusively, +- // with only a byte on the stack is by using a do {} while() format loop. +- byte value = Byte.MIN_VALUE; +- do +- { +- Map handlersByListener = handlersByPriority.get( value ); +- if ( handlersByListener != null ) +- { +- for ( Map.Entry listenerHandlers : handlersByListener.entrySet() ) +- { +- for ( Method method : listenerHandlers.getValue() ) +- { +- EventHandlerMethod ehm = new EventHandlerMethod( listenerHandlers.getKey(), method ); +- handlersList.add( ehm ); +- } +- } +- } +- } while ( value++ < Byte.MAX_VALUE ); +- byEventBaked.put( eventClass, handlersList.toArray( new EventHandlerMethod[ handlersList.size() ] ) ); +- } else +- { +- byEventBaked.remove( eventClass ); +- } ++ event4JBus.unregister(listener); + } + } +diff --git a/event/src/main/java/net/md_5/bungee/event/EventHandlerMethod.java b/event/src/main/java/net/md_5/bungee/event/EventHandlerMethod.java +deleted file mode 100644 +index ad19c02..0000000 +--- a/event/src/main/java/net/md_5/bungee/event/EventHandlerMethod.java ++++ /dev/null +@@ -1,21 +0,0 @@ +-package net.md_5.bungee.event; +- +-import java.lang.reflect.InvocationTargetException; +-import java.lang.reflect.Method; +-import lombok.AllArgsConstructor; +-import lombok.Getter; +- +-@AllArgsConstructor +-public class EventHandlerMethod +-{ +- +- @Getter +- private final Object listener; +- @Getter +- private final Method method; +- +- public void invoke(Object event) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException +- { +- method.invoke( listener, event ); +- } +-} +-- +2.8.3 + diff --git a/BungeeCord-Patches/0017-Enable-TCP_NODELAY.patch b/BungeeCord-Patches/0017-Enable-TCP_NODELAY.patch new file mode 100644 index 0000000..209dfc2 --- /dev/null +++ b/BungeeCord-Patches/0017-Enable-TCP_NODELAY.patch @@ -0,0 +1,22 @@ +From f78252248fff2adf844a59aa117d4eabda721144 Mon Sep 17 00:00:00 2001 +From: Harry +Date: Wed, 24 Feb 2016 17:16:23 +0000 +Subject: [PATCH] Enable TCP_NODELAY. + +This is enabled by default on CraftBukkit/Spigot >= 1.8 and may help with network performance. + +diff --git a/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java b/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java +index 621a06c..76cce0c 100644 +--- a/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java ++++ b/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java +@@ -121,6 +121,7 @@ public class PipelineUtils + { + // IP_TOS is not supported (Windows XP / Windows Server 2003) + } ++ ch.config().setOption( ChannelOption.TCP_NODELAY, true ); + ch.config().setAllocator( PooledByteBufAllocator.DEFAULT ); + + ch.pipeline().addLast( TIMEOUT_HANDLER, new ReadTimeoutHandler( BungeeCord.getInstance().config.getTimeout(), TimeUnit.MILLISECONDS ) ); +-- +2.8.3 + diff --git a/BungeeCord-Patches/0018-Micro-optimizations.patch b/BungeeCord-Patches/0018-Micro-optimizations.patch new file mode 100644 index 0000000..a80c8ab --- /dev/null +++ b/BungeeCord-Patches/0018-Micro-optimizations.patch @@ -0,0 +1,45 @@ +From 01c78e08ab372071eb749652dc8bcbdeace6ab23 Mon Sep 17 00:00:00 2001 +From: Tux +Date: Thu, 19 May 2016 18:05:33 -0600 +Subject: [PATCH] Micro-optimizations + +- PluginManager.dispatchCommand() avoids regex while splitting commands. Java 7 introduced an optimized String.split() that should be used instead (affects command dispatch). +- Avoid regex in getLocale() by changing from replaceAll(String, String) to replaceAll(char, char) + +diff --git a/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java b/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java +index 2426bdb..7203d04 100644 +--- a/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java ++++ b/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java +@@ -42,7 +42,6 @@ import org.yaml.snakeyaml.introspector.PropertyUtils; + public class PluginManager + { + +- private static final Pattern argsSplit = Pattern.compile( " " ); + /*========================================================================*/ + private final ProxyServer proxy; + /*========================================================================*/ +@@ -126,7 +125,7 @@ public class PluginManager + */ + public boolean dispatchCommand(CommandSender sender, String commandLine, List tabResults) + { +- String[] split = argsSplit.split( commandLine, -1 ); ++ String[] split = commandLine.split(" ", -1); + // Check for chat that only contains " " + if ( split.length == 0 ) + { +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 018c02e..9881b75 100644 +--- a/proxy/src/main/java/net/md_5/bungee/UserConnection.java ++++ b/proxy/src/main/java/net/md_5/bungee/UserConnection.java +@@ -567,7 +567,7 @@ public final class UserConnection implements ProxiedPlayer + @Override + public Locale getLocale() + { +- return ( locale == null && settings != null ) ? locale = Locale.forLanguageTag( settings.getLocale().replaceAll( "_", "-" ) ) : locale; ++ return ( locale == null && settings != null ) ? locale = Locale.forLanguageTag( settings.getLocale().replace( '_', '-' ) ) : locale; + } + + @Override +-- +2.8.3 + diff --git a/BungeeCord-Patches/0019-Allow-invalid-packet-ids-for-forge-servers.patch b/BungeeCord-Patches/0019-Allow-invalid-packet-ids-for-forge-servers.patch new file mode 100644 index 0000000..6f7e5c3 --- /dev/null +++ b/BungeeCord-Patches/0019-Allow-invalid-packet-ids-for-forge-servers.patch @@ -0,0 +1,122 @@ +From e41f8d2465c135cede5d3065647c943c2e3e5435 Mon Sep 17 00:00:00 2001 +From: Techcable +Date: Thu, 19 May 2016 17:09:22 -0600 +Subject: [PATCH] Allow invalid packet ids for forge servers + +Some forge mods (COFH) use negative packet ids instead of plugin channels for 'reasons'. +Vanilla servers still error on negative/invalid packets. + +Original issue: https://github.com/WaterfallMC/Waterfall-Old/issues/11 + +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 e7cb380..447eaae 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 +@@ -16,6 +16,14 @@ public class MinecraftDecoder extends MessageToMessageDecoder + private final boolean server; + @Setter + private int protocolVersion; ++ @Setter ++ private boolean supportsForge = false; ++ ++ public MinecraftDecoder(Protocol protocol, boolean server, int protocolVersion) { ++ this.protocol = protocol; ++ this.server = server; ++ this.protocolVersion = protocolVersion; ++ } + + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception +@@ -27,7 +35,7 @@ public class MinecraftDecoder extends MessageToMessageDecoder + { + int packetId = DefinedPacket.readVarInt( in ); + +- DefinedPacket packet = prot.createPacket( packetId, protocolVersion ); ++ DefinedPacket packet = prot.createPacket( packetId, protocolVersion, supportsForge ); + if ( packet != null ) + { + packet.read( in, prot.getDirection(), protocolVersion ); +diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/Protocol.java b/protocol/src/main/java/net/md_5/bungee/protocol/Protocol.java +index 2cbe052..08621b6 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 +@@ -275,14 +275,18 @@ public enum Protocol + return protocol; + } + +- public final DefinedPacket createPacket(int id, int version) ++ public boolean hasPacket(int i, boolean supportsForge) { ++ return supportsForge || i >= 0 && i <= MAX_PACKET_ID; ++ } ++ ++ public final DefinedPacket createPacket(int id, int version, boolean supportsForge) + { + ProtocolData protocolData = getProtocolData( version ); + if (protocolData == null) + { + throw new BadPacketException( "Unsupported protocol version" ); + } +- if ( id > MAX_PACKET_ID ) ++ if ( !hasPacket(id, supportsForge) ) + { + throw new BadPacketException( "Packet with id " + id + " outside of range " ); + } +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 5ed9fe4..7d14ea7 100644 +--- a/proxy/src/main/java/net/md_5/bungee/ServerConnector.java ++++ b/proxy/src/main/java/net/md_5/bungee/ServerConnector.java +@@ -29,7 +29,9 @@ import net.md_5.bungee.forge.ForgeUtils; + import net.md_5.bungee.netty.ChannelWrapper; + import net.md_5.bungee.netty.HandlerBoss; + import net.md_5.bungee.netty.PacketHandler; ++import net.md_5.bungee.netty.PipelineUtils; + import net.md_5.bungee.protocol.DefinedPacket; ++import net.md_5.bungee.protocol.MinecraftDecoder; + import net.md_5.bungee.protocol.Protocol; + import net.md_5.bungee.protocol.packet.BossBar; + import net.md_5.bungee.protocol.packet.EncryptionRequest; +@@ -183,6 +185,12 @@ public class ServerConnector extends PacketHandler + + ServerConnection server = new ServerConnection( ch, target ); + ServerConnectedEvent event = new ServerConnectedEvent( user, server ); ++ ++ if (server.isForgeServer() && user.isForgeUser()) { ++ ((MinecraftDecoder) server.getCh().getHandle().pipeline().get(PipelineUtils.PACKET_DECODER)).setSupportsForge(true); ++ ((MinecraftDecoder) user.getCh().getHandle().pipeline().get(PipelineUtils.PACKET_DECODER)).setSupportsForge(true); ++ } ++ + bungee.getPluginManager().callEvent( event ); + + ch.write( BungeeCord.getInstance().registerChannels() ); +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 9881b75..c88ab49 100644 +--- a/proxy/src/main/java/net/md_5/bungee/UserConnection.java ++++ b/proxy/src/main/java/net/md_5/bungee/UserConnection.java +@@ -76,6 +76,7 @@ public final class UserConnection implements ProxiedPlayer + @NonNull + private final ProxyServer bungee; + @NonNull ++ @Getter + private final ChannelWrapper ch; + @Getter + @NonNull +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 02881ac..9ba9633 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 +@@ -103,6 +103,12 @@ public abstract class EntityMap + int packetId = DefinedPacket.readVarInt( packet ); + int packetIdLength = packet.readerIndex() - readerIndex; + ++ if (packetId < 0 || packetId > ints.length || packetId > varints.length) { // Invalid packet id ++ // Ignore these invalid packets for compatibility reasons ++ packet.readerIndex( readerIndex ); ++ return; ++ } ++ + if ( ints[packetId] ) + { + rewriteInt( packet, oldId, newId, readerIndex + packetIdLength ); +-- +2.8.3 + diff --git a/BungeeCord-Patches/0020-Resolve-sendData-deadlocks.patch b/BungeeCord-Patches/0020-Resolve-sendData-deadlocks.patch new file mode 100644 index 0000000..0d30312 --- /dev/null +++ b/BungeeCord-Patches/0020-Resolve-sendData-deadlocks.patch @@ -0,0 +1,47 @@ +From 5657f0dd4286279c4d4ff0ac8a659ca1818fa954 Mon Sep 17 00:00:00 2001 +From: Tux +Date: Fri, 12 Feb 2016 23:55:53 -0500 +Subject: [PATCH] Resolve sendData() deadlocks + + +diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeServerInfo.java b/proxy/src/main/java/net/md_5/bungee/BungeeServerInfo.java +index 1dd0aeb..bc56d4f 100644 +--- a/proxy/src/main/java/net/md_5/bungee/BungeeServerInfo.java ++++ b/proxy/src/main/java/net/md_5/bungee/BungeeServerInfo.java +@@ -101,19 +101,22 @@ public class BungeeServerInfo implements ServerInfo + Preconditions.checkNotNull( channel, "channel" ); + Preconditions.checkNotNull( data, "data" ); + +- synchronized ( packetQueue ) +- { +- Server server = ( players.isEmpty() ) ? null : players.iterator().next().getServer(); +- if ( server != null ) +- { +- server.sendData( channel, data ); +- return true; +- } else if ( queue ) +- { +- packetQueue.add( new PluginMessage( channel, data, false ) ); ++ Server server; ++ ++ synchronized (players) { ++ server = players.isEmpty() ? null : players.iterator().next().getServer(); ++ } ++ ++ if (server != null) { ++ server.sendData(channel, data); ++ return true; ++ } else if (queue) { ++ synchronized (packetQueue) { ++ packetQueue.add(new PluginMessage(channel, data, false)); + } +- return false; + } ++ ++ return false; + } + + @Override +-- +2.8.3 + diff --git a/BungeeCord-Patches/0021-Add-basic-support-for-configurable-tab-complete-thro.patch b/BungeeCord-Patches/0021-Add-basic-support-for-configurable-tab-complete-thro.patch new file mode 100644 index 0000000..308d803 --- /dev/null +++ b/BungeeCord-Patches/0021-Add-basic-support-for-configurable-tab-complete-thro.patch @@ -0,0 +1,98 @@ +From 4b36feac0d134f081b418653e41547fb5b243081 Mon Sep 17 00:00:00 2001 +From: Johannes Donath +Date: Sat, 4 Jul 2015 06:31:33 +0200 +Subject: [PATCH] Add basic support for configurable tab-complete throttling + + +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 293ec4e..66d0b8a 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 +@@ -88,4 +88,13 @@ public interface ProxyConfig + * If metrics is enabled + */ + boolean isMetrics(); ++ ++ // Throttling options ++ ++ /** ++ * How often tab-complete packets can be sent. ++ *

++ * Values in milliseconds. ++ */ ++ int getTabThrottle(); + } +diff --git a/proxy/src/main/java/io/github/waterfallmc/waterfall/conf/WaterfallConfiguration.java b/proxy/src/main/java/io/github/waterfallmc/waterfall/conf/WaterfallConfiguration.java +index 1fa3ecd..23a5c94 100644 +--- a/proxy/src/main/java/io/github/waterfallmc/waterfall/conf/WaterfallConfiguration.java ++++ b/proxy/src/main/java/io/github/waterfallmc/waterfall/conf/WaterfallConfiguration.java +@@ -17,16 +17,36 @@ public class WaterfallConfiguration extends Configuration { + */ + private boolean metrics = true; + ++ /* ++ * Throttling options ++ * Helps prevent players from overloading the servers behind us ++ */ ++ ++ /** ++ * How often players are allowed to send tab throttle. ++ * Value in milliseconds. ++ *

++ * Default is one packet per second. ++ */ ++ private int tabThrottle = 1000; ++ + @Override + public void load() { + super.load(); + YamlConfig config = new YamlConfig(new File("waterfall.yml")); + config.load(false); // Load, but no permissions + metrics = config.getBoolean("metrics", metrics); ++ // Throttling options ++ tabThrottle = config.getInt("throttling.tab_complete", tabThrottle); + } + + @Override + public boolean isMetrics() { + return metrics; + } ++ ++ @Override ++ public int getTabThrottle() { ++ return tabThrottle; ++ } + } +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 23d4f25..28791a6 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 +@@ -31,6 +31,8 @@ public class UpstreamBridge extends PacketHandler + private final ProxyServer bungee; + private final UserConnection con; + ++ private long lastTabCompletion = -1; ++ + public UpstreamBridge(ProxyServer bungee, UserConnection con) + { + this.bungee = bungee; +@@ -121,6 +123,16 @@ public class UpstreamBridge extends PacketHandler + @Override + public void handle(TabCompleteRequest tabComplete) throws Exception + { ++ if ( bungee.getConfig().getTabThrottle() > 0 ) ++ { ++ long now = System.currentTimeMillis(); ++ if ( lastTabCompletion > 0 && (now - lastTabCompletion) <= bungee.getConfig().getTabThrottle() ) ++ { ++ throw CancelSendSignal.INSTANCE; ++ } ++ lastTabCompletion = now; ++ } ++ + List suggestions = new ArrayList<>(); + + if ( tabComplete.getCursor().startsWith( "/" ) ) +-- +2.8.3 + diff --git a/BungeeCord-Patches/0022-Don-t-create-a-new-KickStringWriter-for-each-new-con.patch b/BungeeCord-Patches/0022-Don-t-create-a-new-KickStringWriter-for-each-new-con.patch new file mode 100644 index 0000000..c2094af --- /dev/null +++ b/BungeeCord-Patches/0022-Don-t-create-a-new-KickStringWriter-for-each-new-con.patch @@ -0,0 +1,46 @@ +From 41ff2cd5701b5c40003385c1901df3b39045365a Mon Sep 17 00:00:00 2001 +From: Harry +Date: Tue, 26 Jan 2016 01:01:57 +0000 +Subject: [PATCH] Don't create a new KickStringWriter for each new connection. + + +diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/KickStringWriter.java b/protocol/src/main/java/net/md_5/bungee/protocol/KickStringWriter.java +index eda9571..e5275c7 100644 +--- a/protocol/src/main/java/net/md_5/bungee/protocol/KickStringWriter.java ++++ b/protocol/src/main/java/net/md_5/bungee/protocol/KickStringWriter.java +@@ -1,9 +1,11 @@ + package net.md_5.bungee.protocol; + + import io.netty.buffer.ByteBuf; ++import io.netty.channel.ChannelHandler.Sharable; + import io.netty.channel.ChannelHandlerContext; + import io.netty.handler.codec.MessageToByteEncoder; + ++@Sharable + public class KickStringWriter extends MessageToByteEncoder + { + +diff --git a/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java b/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java +index 76cce0c..f0d0189 100644 +--- a/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java ++++ b/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java +@@ -53,7 +53,7 @@ public class PipelineUtils + ch.pipeline().addBefore( FRAME_DECODER, LEGACY_DECODER, new LegacyDecoder() ); + ch.pipeline().addAfter( FRAME_DECODER, PACKET_DECODER, new MinecraftDecoder( Protocol.HANDSHAKE, true, ProxyServer.getInstance().getProtocolVersion() ) ); + ch.pipeline().addAfter( FRAME_PREPENDER, PACKET_ENCODER, new MinecraftEncoder( Protocol.HANDSHAKE, true, ProxyServer.getInstance().getProtocolVersion() ) ); +- ch.pipeline().addBefore( FRAME_PREPENDER, LEGACY_KICKER, new KickStringWriter() ); ++ ch.pipeline().addBefore( FRAME_PREPENDER, LEGACY_KICKER, PipelineUtils.KICK_STRING_WRITER ); + ch.pipeline().get( HandlerBoss.class ).setHandler( new InitialHandler( BungeeCord.getInstance(), ch.attr( LISTENER ).get() ) ); + } + }; +@@ -69,6 +69,7 @@ public class PipelineUtils + public static final String FRAME_PREPENDER = "frame-prepender"; + public static final String LEGACY_DECODER = "legacy-decoder"; + public static final String LEGACY_KICKER = "legacy-kick"; ++ private static final KickStringWriter KICK_STRING_WRITER = new KickStringWriter(); + + private static boolean epoll; + +-- +2.8.3 + diff --git a/BungeeCord-Patches/0023-Optional-server-list-ping-logging.patch b/BungeeCord-Patches/0023-Optional-server-list-ping-logging.patch new file mode 100644 index 0000000..301a575 --- /dev/null +++ b/BungeeCord-Patches/0023-Optional-server-list-ping-logging.patch @@ -0,0 +1,138 @@ +From 538e4649bc72a9a167768f0fb1bef46c4040e863 Mon Sep 17 00:00:00 2001 +From: Janmm14 +Date: Sat, 12 Dec 2015 23:43:30 +0100 +Subject: [PATCH] Optional server list ping logging. + +Add IPs to the log where user names are shown. + +This avoids spamming the logs with connection notices. +Server list pings are only logged if the log_server_list_pings config.yml option is true, defaults to false + +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 66d0b8a..5a49050 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 +@@ -89,6 +89,11 @@ public interface ProxyConfig + */ + boolean isMetrics(); + ++ /** ++ * Whether we log server list pings ++ */ ++ boolean isLogServerListPing(); ++ + // Throttling options + + /** +diff --git a/proxy/src/main/java/io/github/waterfallmc/waterfall/conf/WaterfallConfiguration.java b/proxy/src/main/java/io/github/waterfallmc/waterfall/conf/WaterfallConfiguration.java +index 23a5c94..114961d 100644 +--- a/proxy/src/main/java/io/github/waterfallmc/waterfall/conf/WaterfallConfiguration.java ++++ b/proxy/src/main/java/io/github/waterfallmc/waterfall/conf/WaterfallConfiguration.java +@@ -17,6 +17,13 @@ public class WaterfallConfiguration extends Configuration { + */ + private boolean metrics = true; + ++ /** ++ * Whether we log server list pings ++ *

++ * Default is false (don't log) ++ */ ++ private boolean logServerListPing = false; ++ + /* + * Throttling options + * Helps prevent players from overloading the servers behind us +@@ -36,6 +43,7 @@ public class WaterfallConfiguration extends Configuration { + YamlConfig config = new YamlConfig(new File("waterfall.yml")); + config.load(false); // Load, but no permissions + metrics = config.getBoolean("metrics", metrics); ++ logServerListPing = config.getBoolean( "log_server_list_ping", logServerListPing ); + // Throttling options + tabThrottle = config.getInt("throttling.tab_complete", tabThrottle); + } +@@ -49,4 +57,9 @@ public class WaterfallConfiguration extends Configuration { + public int getTabThrottle() { + return tabThrottle; + } ++ ++ @Override ++ public boolean isLogServerListPing() { ++ return logServerListPing; ++ } + } +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 7d14ea7..44f0b61 100644 +--- a/proxy/src/main/java/net/md_5/bungee/ServerConnector.java ++++ b/proxy/src/main/java/net/md_5/bungee/ServerConnector.java +@@ -377,6 +377,6 @@ public class ServerConnector extends PacketHandler + @Override + public String toString() + { +- return "[" + user.getName() + "] <-> ServerConnector [" + target.getName() + "]"; ++ return "[" + user.getName() + "|" + user.getAddress() + "] <-> ServerConnector [" + target.getName() + "]"; + } + } +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 cb9dbaf..7ba0bcb 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 +@@ -503,6 +503,6 @@ public class DownstreamBridge extends PacketHandler + @Override + public String toString() + { +- return "[" + con.getName() + "] <-> DownstreamBridge <-> [" + server.getInfo().getName() + "]"; ++ return "[" + con.getAddress() + "|" + con.getName() + "] <-> DownstreamBridge <-> [" + server.getInfo().getName() + "]"; + } + } +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 ad19168..2056907 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 +@@ -277,19 +277,22 @@ public class InitialHandler extends PacketHandler implements PendingConnection + } + + this.virtualHost = InetSocketAddress.createUnresolved( handshake.getHost(), handshake.getPort() ); +- bungee.getLogger().log( Level.INFO, "{0} has connected", this ); + + bungee.getPluginManager().callEvent( new PlayerHandshakeEvent( InitialHandler.this, handshake ) ); + + switch ( handshake.getRequestedProtocol() ) + { + case 1: ++ if (BungeeCord.getInstance().getConfig().isLogServerListPing()) { ++ bungee.getLogger().log( Level.INFO, "{0} is pinging", this ); ++ } + // Ping + thisState = State.STATUS; + ch.setProtocol( Protocol.STATUS ); + break; + case 2: + // Login ++ bungee.getLogger().log( Level.INFO, "{0} has connected", this ); + thisState = State.USERNAME; + ch.setProtocol( Protocol.LOGIN ); + +@@ -609,7 +612,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection + @Override + public String toString() + { +- return "[" + ( ( getName() != null ) ? getName() : getAddress() ) + "] <-> InitialHandler"; ++ return "[" + getAddress() + ( getName() != null ? "|" + getName() : "" ) + "] <-> InitialHandler"; + } + + @Override +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 28791a6..a96e793 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 +@@ -206,6 +206,6 @@ public class UpstreamBridge extends PacketHandler + @Override + public String toString() + { +- return "[" + con.getName() + "] -> UpstreamBridge"; ++ return "[" + con.getAddress() + "|" + con.getName() + "] -> UpstreamBridge"; + } + } +-- +2.8.3 + diff --git a/BungeeCord-Patches/0024-Set-a-more-reasonable-Recycler-Capacity.patch b/BungeeCord-Patches/0024-Set-a-more-reasonable-Recycler-Capacity.patch new file mode 100644 index 0000000..6db3a02 --- /dev/null +++ b/BungeeCord-Patches/0024-Set-a-more-reasonable-Recycler-Capacity.patch @@ -0,0 +1,30 @@ +From 6d0fcbace0fb04518462a064d3f08de8e85ade3b Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Mon, 5 Oct 2015 23:20:54 -0400 +Subject: [PATCH] Set a more reasonable Recycler Capacity + +Default Netty Recycler capacity is 262k~, resulting in major memory +consumption over long runtimes that will never free. + +This lowers it by 80%, which should only even be hit on the largest of servers. + +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 2a41a50..29e2294 100644 +--- a/bootstrap/src/main/java/net/md_5/bungee/BungeeCordLauncher.java ++++ b/bootstrap/src/main/java/net/md_5/bungee/BungeeCordLauncher.java +@@ -20,6 +20,12 @@ public class BungeeCordLauncher + Security.setProperty( "networkaddress.cache.ttl", "30" ); + Security.setProperty( "networkaddress.cache.negative.ttl", "10" ); + ++ // TODO: remove .default for netty 5! ++ if ( System.getProperty( "io.netty.recycler.maxCapacity.default" ) == null ) ++ { ++ System.setProperty( "io.netty.recycler.maxCapacity.default", "50000" ); ++ } ++ + OptionParser parser = new OptionParser(); + parser.allowsUnrecognizedOptions(); + parser.acceptsAll( Arrays.asList( "v", "version" ) ); +-- +2.8.3 + diff --git a/BungeeCord-Patches/0025-Reduce-max-log-size-to-8MB-and-don-t-append-to-exist.patch b/BungeeCord-Patches/0025-Reduce-max-log-size-to-8MB-and-don-t-append-to-exist.patch new file mode 100644 index 0000000..c4ff1bd --- /dev/null +++ b/BungeeCord-Patches/0025-Reduce-max-log-size-to-8MB-and-don-t-append-to-exist.patch @@ -0,0 +1,23 @@ +From be14a36864738f608de88028912627a57eb20515 Mon Sep 17 00:00:00 2001 +From: Tux +Date: Sun, 14 Feb 2016 01:03:27 -0500 +Subject: [PATCH] Reduce max log size to 8MB and don't append to existing log + files + + +diff --git a/proxy/src/main/java/net/md_5/bungee/log/BungeeLogger.java b/proxy/src/main/java/net/md_5/bungee/log/BungeeLogger.java +index cde3194..54275f6 100644 +--- a/proxy/src/main/java/net/md_5/bungee/log/BungeeLogger.java ++++ b/proxy/src/main/java/net/md_5/bungee/log/BungeeLogger.java +@@ -27,7 +27,7 @@ public class BungeeLogger extends Logger + + try + { +- FileHandler fileHandler = new FileHandler( System.getProperty("bungee.log-file", "proxy.log"), 1 << 24, 8, true ); ++ FileHandler fileHandler = new FileHandler( System.getProperty("bungee.log-file", "proxy.log"), 1 << 23, 8, false ); + fileHandler.setFormatter( formatter ); + addHandler( fileHandler ); + +-- +2.8.3 + diff --git a/BungeeCord-Patches/0026-Add-a-property-to-accept-invalid-ping-packets.patch b/BungeeCord-Patches/0026-Add-a-property-to-accept-invalid-ping-packets.patch new file mode 100644 index 0000000..5d2abc8 --- /dev/null +++ b/BungeeCord-Patches/0026-Add-a-property-to-accept-invalid-ping-packets.patch @@ -0,0 +1,33 @@ +From c45b17cb631a5cf8ff869199b2b6e1331a548474 Mon Sep 17 00:00:00 2001 +From: Techcable +Date: Sun, 7 Feb 2016 00:01:19 -0700 +Subject: [PATCH] Add a property to accept invalid ping packets + +This is disabled by default, as I don't wanna accept invalid packets +You can enable it by setting '-Dwaterfall.acceptInvalidPackets=true' at the command line + +Fixes #23 + +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 2056907..53d7ef8 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 +@@ -243,10 +243,14 @@ public class InitialHandler extends PacketHandler implements PendingConnection + thisState = State.PING; + } + ++ private static final boolean ACCEPT_INVALID_PACKETS = Boolean.parseBoolean(System.getProperty("waterfall.acceptInvalidPackets", "false")); ++ + @Override + public void handle(PingPacket ping) throws Exception + { +- Preconditions.checkState( thisState == State.PING, "Not expecting PING" ); ++ if (!ACCEPT_INVALID_PACKETS) { ++ Preconditions.checkState(thisState == State.PING, "Not expecting PING"); ++ } + unsafe.sendPacket( ping ); + disconnect( "" ); + } +-- +2.8.3 + diff --git a/BungeeCord-Patches/0027-Ignore-incoming-chat-messages-before-connecting-to-t.patch b/BungeeCord-Patches/0027-Ignore-incoming-chat-messages-before-connecting-to-t.patch new file mode 100644 index 0000000..fb90ff4 --- /dev/null +++ b/BungeeCord-Patches/0027-Ignore-incoming-chat-messages-before-connecting-to-t.patch @@ -0,0 +1,47 @@ +From 48727687f5d0091dc4a79106630aee820d464a6d Mon Sep 17 00:00:00 2001 +From: Jonas Konrad +Date: Tue, 23 Jun 2015 21:56:13 +0200 +Subject: [PATCH] Ignore incoming chat messages before connecting to the + backend + +Merges SpigotMC/BungeeCord#1515 + +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 a96e793..50f0308 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 +@@ -2,6 +2,7 @@ package net.md_5.bungee.connection; + + import com.google.common.base.Preconditions; + import net.md_5.bungee.BungeeCord; ++import net.md_5.bungee.ServerConnection; + import net.md_5.bungee.UserConnection; + import net.md_5.bungee.Util; + import net.md_5.bungee.api.ProxyServer; +@@ -108,13 +109,21 @@ public class UpstreamBridge extends PacketHandler + { + Preconditions.checkArgument( chat.getMessage().length() <= 100, "Chat message too long" ); // Mojang limit, check on updates + +- ChatEvent chatEvent = new ChatEvent( con, con.getServer(), chat.getMessage() ); ++ ServerConnection server = con.getServer(); ++ ++ // if we're still connecting just ignore this packet ++ if ( server == null ) ++ { ++ throw CancelSendSignal.INSTANCE; ++ } ++ ++ ChatEvent chatEvent = new ChatEvent( con, server, chat.getMessage() ); + if ( !bungee.getPluginManager().callEvent( chatEvent ).isCancelled() ) + { + chat.setMessage( chatEvent.getMessage() ); + if ( !chatEvent.isCommand() || !bungee.getPluginManager().dispatchCommand( con, chat.getMessage().substring( 1 ) ) ) + { +- con.getServer().unsafe().sendPacket( chat ); ++ server.unsafe().sendPacket( chat ); + } + } + throw CancelSendSignal.INSTANCE; +-- +2.8.3 + diff --git a/BungeeCord-Patches/0028-Improve-connection-closing-fixing-the-kick-delay.patch b/BungeeCord-Patches/0028-Improve-connection-closing-fixing-the-kick-delay.patch new file mode 100644 index 0000000..94c62eb --- /dev/null +++ b/BungeeCord-Patches/0028-Improve-connection-closing-fixing-the-kick-delay.patch @@ -0,0 +1,200 @@ +From cd50f5e9403ffc31c760f29aa6fce77490ae5ac3 Mon Sep 17 00:00:00 2001 +From: kamcio96 +Date: Mon, 14 Mar 2016 15:59:52 -0700 +Subject: [PATCH] Improve connection closing, fixing the kick delay. + +Merges some of https://github.com/SpigotMC/BungeeCord/pull/1706 by @kamcio96 + +@kamcio96 claims that these channel closing changes are removing the need of delayed kick packets +@Janmm14 can confirm this (at login state) on a no-latency and low-latency connection (<1ms; ~16ms), high-latency connection was not tested, but it should work on these too. + +diff --git a/proxy/src/main/java/net/md_5/bungee/ServerConnection.java b/proxy/src/main/java/net/md_5/bungee/ServerConnection.java +index 8c1260a..a7dfd1f 100644 +--- a/proxy/src/main/java/net/md_5/bungee/ServerConnection.java ++++ b/proxy/src/main/java/net/md_5/bungee/ServerConnection.java +@@ -59,7 +59,7 @@ public class ServerConnection implements Server + @Override + public void run() + { +- ch.getHandle().close(); ++ ch.close(); + } + }, 100, TimeUnit.MILLISECONDS ); + } +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 c88ab49..9a13f5c 100644 +--- a/proxy/src/main/java/net/md_5/bungee/UserConnection.java ++++ b/proxy/src/main/java/net/md_5/bungee/UserConnection.java +@@ -379,21 +379,7 @@ public final class UserConnection implements ProxiedPlayer + getName(), BaseComponent.toLegacyText( reason ) + } ); + +- // Why do we have to delay this you might ask? Well the simple reason is MOJANG. +- // Despite many a bug report posted, ever since the 1.7 protocol rewrite, the client STILL has a race condition upon switching protocols. +- // As such, despite the protocol switch packets already having been sent, there is the possibility of a client side exception +- // To help combat this we will wait half a second before actually sending the disconnected packet so that whoever is on the other +- // end has a somewhat better chance of receiving the proper packet. +- ch.getHandle().eventLoop().schedule( new Runnable() +- { +- +- @Override +- public void run() +- { +- unsafe().sendPacket( new Kick( ComponentSerializer.toString( reason ) ) ); +- ch.close(); +- } +- }, 500, TimeUnit.MILLISECONDS ); ++ ch.close(new Kick(ComponentSerializer.toString( reason ))); + + if ( server != null ) + { +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 53d7ef8..0b1be45 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 +@@ -136,8 +136,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection + public void handle(LegacyHandshake legacyHandshake) throws Exception + { + this.legacy = true; +- ch.getHandle().writeAndFlush( bungee.getTranslation( "outdated_client" ) ); +- ch.close(); ++ ch.close( bungee.getTranslation( "outdated_client" ) ); + } + + @Override +@@ -179,8 +178,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection + + '\u00a7' + legacy.getPlayers().getMax(); + } + +- ch.getHandle().writeAndFlush( kickMessage ); +- ch.close(); ++ ch.close( kickMessage ); + } + }; + +@@ -251,8 +249,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection + if (!ACCEPT_INVALID_PACKETS) { + Preconditions.checkState(thisState == State.PING, "Not expecting PING"); + } +- unsafe.sendPacket( ping ); +- disconnect( "" ); ++ ch.close( ping ); + } + + @Override +@@ -538,24 +535,11 @@ public class InitialHandler extends PacketHandler implements PendingConnection + if ( !disconnecting || !ch.isClosed() ) + { + disconnecting = true; +- // Why do we have to delay this you might ask? Well the simple reason is MOJANG. +- // Despite many a bug report posted, ever since the 1.7 protocol rewrite, the client STILL has a race condition upon switching protocols. +- // As such, despite the protocol switch packets already having been sent, there is the possibility of a client side exception +- // To help combat this we will wait half a second before actually sending the disconnected packet so that whoever is on the other +- // end has a somewhat better chance of receiving the proper packet. +- ch.getHandle().eventLoop().schedule( new Runnable() +- { +- +- @Override +- public void run() +- { +- if ( thisState != State.STATUS && thisState != State.PING ) +- { +- unsafe().sendPacket( new Kick( ComponentSerializer.toString( reason ) ) ); +- } +- ch.close(); +- } +- }, 500, TimeUnit.MILLISECONDS ); ++ if ( thisState != State.STATUS && thisState != State.PING ) { ++ ch.close( new Kick( ComponentSerializer.toString( reason ) ) ); ++ } else { ++ ch.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 50f0308..7565ff9 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 +@@ -79,6 +79,7 @@ public class UpstreamBridge extends PacketHandler + { + player.unsafe().sendPacket( packet ); + } ++ con.getServer().setObsolete(true); + con.getServer().disconnect( "Quitting" ); + } + } +diff --git a/proxy/src/main/java/net/md_5/bungee/netty/ChannelWrapper.java b/proxy/src/main/java/net/md_5/bungee/netty/ChannelWrapper.java +index 06d19c3..76bdff2 100644 +--- a/proxy/src/main/java/net/md_5/bungee/netty/ChannelWrapper.java ++++ b/proxy/src/main/java/net/md_5/bungee/netty/ChannelWrapper.java +@@ -5,6 +5,7 @@ import net.md_5.bungee.compress.PacketDecompressor; + import net.md_5.bungee.protocol.PacketWrapper; + import com.google.common.base.Preconditions; + import io.netty.channel.Channel; ++import io.netty.channel.ChannelFutureListener; + import io.netty.channel.ChannelHandler; + import io.netty.channel.ChannelHandlerContext; + import lombok.Getter; +@@ -16,7 +17,6 @@ public class ChannelWrapper + { + + private final Channel ch; +- @Getter + private volatile boolean closed; + + public ChannelWrapper(ChannelHandlerContext ctx) +@@ -38,23 +38,22 @@ public class ChannelWrapper + + public void write(Object packet) + { +- if ( !closed ) ++ if ( !isClosed() ) + { + if ( packet instanceof PacketWrapper ) + { + ( (PacketWrapper) packet ).setReleased( true ); +- ch.write( ( (PacketWrapper) packet ).buf, ch.voidPromise() ); ++ ch.writeAndFlush( ( (PacketWrapper) packet ).buf, ch.voidPromise() ); + } else + { +- ch.write( packet, ch.voidPromise() ); ++ ch.writeAndFlush( packet, ch.voidPromise() ); + } +- ch.flush(); + } + } + + public void close() + { +- if ( !closed ) ++ if ( !isClosed() ) + { + closed = true; + ch.flush(); +@@ -62,6 +61,22 @@ public class ChannelWrapper + } + } + ++ /** ++ * Send the given packet, then close the connection ++ * ++ * @param packet the packet to send before closing ++ */ ++ public void close(Object packet) { ++ if (!isClosed()) { ++ closed = true; ++ ch.writeAndFlush(packet).addListeners(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE, ChannelFutureListener.CLOSE); ++ } ++ } ++ ++ public boolean isClosed() { ++ return closed || !ch.isActive(); ++ } ++ + public void addBefore(String baseName, String name, ChannelHandler handler) + { + Preconditions.checkState( ch.eventLoop().inEventLoop(), "cannot add handler outside of event loop" ); +-- +2.8.3 + diff --git a/BungeeCord-Patches/0029-Use-a-worker-and-a-boss-event-loop-group.patch b/BungeeCord-Patches/0029-Use-a-worker-and-a-boss-event-loop-group.patch new file mode 100644 index 0000000..d71b125 --- /dev/null +++ b/BungeeCord-Patches/0029-Use-a-worker-and-a-boss-event-loop-group.patch @@ -0,0 +1,87 @@ +From 465cc07d8909d48ac81e5a71916a8bc0b7e3a193 Mon Sep 17 00:00:00 2001 +From: kamcio96 +Date: Mon, 14 Mar 2016 16:07:20 -0700 +Subject: [PATCH] Use a worker and a boss event loop group. + +Merges the rest of https://github.com/SpigotMC/BungeeCord/pull/1706 by @kamcio96 along with b8845c4edbae46bb66f6adda338330a1d4032057 + +This is proper practice for netty. + +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 fd8d9b0..d0739c1 100644 +--- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java ++++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java +@@ -106,7 +106,7 @@ public class BungeeCord extends ProxyServer + */ + private ResourceBundle baseBundle; + private ResourceBundle customBundle; +- public EventLoopGroup eventLoops; ++ public EventLoopGroup bossEventLoopGroup, workerEventLoopGroup; + /** + * locations.yml save thread. + */ +@@ -246,7 +246,8 @@ public class BungeeCord extends ProxyServer + ResourceLeakDetector.setLevel( ResourceLeakDetector.Level.DISABLED ); // Eats performance + } + +- eventLoops = PipelineUtils.newEventLoopGroup( 0, new ThreadFactoryBuilder().setNameFormat( "Netty IO Thread #%1$d" ).build() ); ++ bossEventLoopGroup = PipelineUtils.newEventLoopGroup( 0, new ThreadFactoryBuilder().setNameFormat( "Netty Boss IO Thread #%1$d" ).build() ); ++ workerEventLoopGroup = PipelineUtils.newEventLoopGroup( 0, new ThreadFactoryBuilder().setNameFormat( "Netty Worker IO Thread #%1$d" ).build() ); + + File moduleDirectory = new File( "modules" ); + moduleManager.load( this, moduleDirectory ); +@@ -314,7 +315,7 @@ public class BungeeCord extends ProxyServer + .childOption( ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 1024 * 1024 * 1 ) + .childAttr( PipelineUtils.LISTENER, info ) + .childHandler( PipelineUtils.SERVER_CHILD ) +- .group( eventLoops ) ++ .group( bossEventLoopGroup, workerEventLoopGroup ) + .localAddress( info.getHost() ) + .bind().addListener( listener ); + +@@ -335,7 +336,7 @@ public class BungeeCord extends ProxyServer + } + } + }; +- new RemoteQuery( this, info ).start( PipelineUtils.getDatagramChannel(), new InetSocketAddress( info.getHost().getAddress(), info.getQueryPort() ), eventLoops, bindListener ); ++ new RemoteQuery( this, info ).start( PipelineUtils.getDatagramChannel(), new InetSocketAddress( info.getHost().getAddress(), info.getQueryPort() ), workerEventLoopGroup, bindListener ); + } + } + } +@@ -391,12 +392,14 @@ public class BungeeCord extends ProxyServer + } + + getLogger().info( "Closing IO threads" ); +- eventLoops.shutdownGracefully(); +- try +- { +- eventLoops.awaitTermination( Long.MAX_VALUE, TimeUnit.NANOSECONDS ); +- } catch ( InterruptedException ex ) +- { ++ bossEventLoopGroup.shutdownGracefully(); ++ workerEventLoopGroup.shutdownGracefully(); ++ while (true) { ++ try { ++ bossEventLoopGroup.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); ++ workerEventLoopGroup.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); ++ break; ++ } catch (InterruptedException ignored) {} + } + + if ( reconnectHandler != null ) +diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeServerInfo.java b/proxy/src/main/java/net/md_5/bungee/BungeeServerInfo.java +index bc56d4f..efcba31 100644 +--- a/proxy/src/main/java/net/md_5/bungee/BungeeServerInfo.java ++++ b/proxy/src/main/java/net/md_5/bungee/BungeeServerInfo.java +@@ -145,7 +145,7 @@ public class BungeeServerInfo implements ServerInfo + }; + new Bootstrap() + .channel( PipelineUtils.getChannel() ) +- .group( BungeeCord.getInstance().eventLoops ) ++ .group( BungeeCord.getInstance().workerEventLoopGroup ) + .handler( PipelineUtils.BASE ) + .option( ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000 ) // TODO: Configurable + .remoteAddress( getAddress() ) +-- +2.8.3 + diff --git a/BungeeCord-Patches/0030-Better-Decompression-Sanity.patch b/BungeeCord-Patches/0030-Better-Decompression-Sanity.patch new file mode 100644 index 0000000..e7143a4 --- /dev/null +++ b/BungeeCord-Patches/0030-Better-Decompression-Sanity.patch @@ -0,0 +1,62 @@ +From 18a1e9fa9a98f93e8877616607b37cc92eaa07fb Mon Sep 17 00:00:00 2001 +From: Techcable +Date: Fri, 18 Mar 2016 10:53:24 -0700 +Subject: [PATCH] Better Decompression Sanity + +Fixes #40 + +diff --git a/proxy/src/main/java/net/md_5/bungee/compress/PacketDecompressor.java b/proxy/src/main/java/net/md_5/bungee/compress/PacketDecompressor.java +index 21b3ea2..37fe6ac 100644 +--- a/proxy/src/main/java/net/md_5/bungee/compress/PacketDecompressor.java ++++ b/proxy/src/main/java/net/md_5/bungee/compress/PacketDecompressor.java +@@ -1,5 +1,7 @@ + package net.md_5.bungee.compress; + ++import lombok.*; ++ + import com.google.common.base.Preconditions; + import io.netty.buffer.ByteBuf; + import io.netty.channel.ChannelHandlerContext; +@@ -8,9 +10,11 @@ import java.util.List; + import net.md_5.bungee.jni.zlib.BungeeZlib; + import net.md_5.bungee.protocol.DefinedPacket; + ++@RequiredArgsConstructor + public class PacketDecompressor extends MessageToMessageDecoder + { + ++ private final int compressionThreshold; + private final BungeeZlib zlib = CompressFactory.zlib.newInstance(); + + @Override +@@ -35,12 +39,13 @@ public class PacketDecompressor extends MessageToMessageDecoder + in.skipBytes( in.readableBytes() ); + } else + { ++ Preconditions.checkArgument( size >= compressionThreshold, "Decompressed size %s less than compression threshold %s", size, compressionThreshold); + ByteBuf decompressed = ctx.alloc().directBuffer(); + + try + { + zlib.process( in, decompressed ); +- Preconditions.checkState( decompressed.readableBytes() == size, "Decompressed packet size mismatch" ); ++ Preconditions.checkArgument( decompressed.readableBytes() == size, "Decompressed size %s is not equal to actual decompressed bytes", size, decompressed.readableBytes()); + + out.add( decompressed ); + decompressed = null; +diff --git a/proxy/src/main/java/net/md_5/bungee/netty/ChannelWrapper.java b/proxy/src/main/java/net/md_5/bungee/netty/ChannelWrapper.java +index 76bdff2..f5c8f0a 100644 +--- a/proxy/src/main/java/net/md_5/bungee/netty/ChannelWrapper.java ++++ b/proxy/src/main/java/net/md_5/bungee/netty/ChannelWrapper.java +@@ -105,7 +105,7 @@ public class ChannelWrapper + + if ( ch.pipeline().get( PacketDecompressor.class ) == null && compressionThreshold != -1 ) + { +- addBefore( PipelineUtils.PACKET_DECODER, "decompress", new PacketDecompressor() ); ++ addBefore( PipelineUtils.PACKET_DECODER, "decompress", new PacketDecompressor(compressionThreshold) ); + } + if ( compressionThreshold == -1 ) + { +-- +2.8.3 + diff --git a/BungeeCord-Patches/0031-Better-race-condition-check-for-disconnect.patch b/BungeeCord-Patches/0031-Better-race-condition-check-for-disconnect.patch new file mode 100644 index 0000000..63a7186 --- /dev/null +++ b/BungeeCord-Patches/0031-Better-race-condition-check-for-disconnect.patch @@ -0,0 +1,47 @@ +From 851c2b19e31527f7b758f9c924290ad0c950849d Mon Sep 17 00:00:00 2001 +From: Tux +Date: Sun, 20 Mar 2016 01:36:23 -0400 +Subject: [PATCH] Better race condition check for disconnect() + + +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 0b1be45..9ced50c 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 +@@ -8,6 +8,7 @@ import java.net.URLEncoder; + import java.security.MessageDigest; + import java.util.List; + import java.util.UUID; ++import java.util.concurrent.atomic.AtomicBoolean; + import java.util.logging.Level; + import javax.crypto.SecretKey; + import com.google.gson.Gson; +@@ -96,12 +97,11 @@ public class InitialHandler extends PacketHandler implements PendingConnection + private boolean legacy; + @Getter + private String extraDataInHandshake = ""; +- private boolean disconnecting; ++ private final AtomicBoolean disconnecting = new AtomicBoolean(false); + +- @Override + public boolean shouldHandle(PacketWrapper packet) throws Exception + { +- return !disconnecting; ++ return !disconnecting.get(); + } + + private enum State +@@ -532,9 +532,8 @@ public class InitialHandler extends PacketHandler implements PendingConnection + @Override + public void disconnect(final BaseComponent... reason) + { +- if ( !disconnecting || !ch.isClosed() ) ++ if ( disconnecting.compareAndSet(false, true) || !ch.isClosed() ) + { +- disconnecting = true; + if ( thisState != State.STATUS && thisState != State.PING ) { + ch.close( new Kick( ComponentSerializer.toString( reason ) ) ); + } else { +-- +2.8.3 + diff --git a/BungeeCord-Patches/0032-Upgrade-to-netty-4.1.patch b/BungeeCord-Patches/0032-Upgrade-to-netty-4.1.patch new file mode 100644 index 0000000..b7bf846 --- /dev/null +++ b/BungeeCord-Patches/0032-Upgrade-to-netty-4.1.patch @@ -0,0 +1,120 @@ +From da4c0a77fa856feae15b346aa2428714270afccf Mon Sep 17 00:00:00 2001 +From: Techcable +Date: Tue, 3 May 2016 20:31:52 -0700 +Subject: [PATCH] Upgrade to netty 4.1 + +Don't access a ByteBuf's underlying array with ByteBuf.array() + - ByteBuf.array() returns the underlying array storage, and does *not* return a view of the buffer as an array + +diff --git a/pom.xml b/pom.xml +index fda3278..d2f458a 100644 +--- a/pom.xml ++++ b/pom.xml +@@ -76,7 +76,7 @@ + + + unknown +- 4.0.33.Final ++ 4.1.0.CR7 + + 1.8 + 1.8 +diff --git a/protocol/pom.xml b/protocol/pom.xml +index 8b462f5..ccee47e 100644 +--- a/protocol/pom.xml ++++ b/protocol/pom.xml +@@ -32,6 +32,12 @@ + compile + + ++ io.netty ++ netty-handler ++ ${netty.version} ++ compile ++ ++ + net.sf.trove4j + trove4j + 3.0.3 +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 bbaef39..e094932 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 +@@ -9,6 +9,8 @@ import java.io.DataInputStream; + import lombok.AllArgsConstructor; + import lombok.Data; + import lombok.EqualsAndHashCode; ++import io.netty.buffer.ByteBufInputStream; ++import io.netty.buffer.ByteBufUtil; + import lombok.NoArgsConstructor; + import net.md_5.bungee.protocol.AbstractPacketHandler; + import net.md_5.bungee.protocol.ProtocolConstants; +@@ -20,9 +22,22 @@ import net.md_5.bungee.protocol.ProtocolConstants; + public class PluginMessage extends DefinedPacket + { + ++ public PluginMessage(String tag, ByteBuf data, boolean allowExtendedPacket) { ++ this(tag, ByteBufUtil.getBytes(data), allowExtendedPacket); ++ } ++ + private String tag; + private byte[] data; + ++ public void setData(byte[] data) { ++ this.data = Preconditions.checkNotNull(data, "Null data"); ++ } ++ ++ public void setData(ByteBuf buf) { ++ Preconditions.checkNotNull(buf, "Null buffer"); ++ setData(ByteBufUtil.getBytes(buf)); ++ } ++ + /** + * Allow this packet to be sent as an "extended" packet. + */ +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 44f0b61..e327325 100644 +--- a/proxy/src/main/java/net/md_5/bungee/ServerConnector.java ++++ b/proxy/src/main/java/net/md_5/bungee/ServerConnector.java +@@ -232,7 +232,7 @@ public class ServerConnector extends PacketHandler + + ByteBuf brand = ByteBufAllocator.DEFAULT.heapBuffer(); + DefinedPacket.writeString( bungee.getName() + " (" + bungee.getVersion() + ")", brand ); +- user.unsafe().sendPacket( new PluginMessage( "MC|Brand", brand.array().clone(), handshakeHandler.isServerForge() ) ); ++ user.unsafe().sendPacket( new PluginMessage( "MC|Brand", brand, handshakeHandler.isServerForge() ) ); + brand.release(); + } else + { +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 7ba0bcb..fa57f28 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 +@@ -235,7 +235,7 @@ public class DownstreamBridge extends PacketHandler + brand.release(); + brand = ByteBufAllocator.DEFAULT.heapBuffer(); + DefinedPacket.writeString( bungee.getName() + " (" + bungee.getVersion() + ")" + " <- " + serverBrand, brand ); +- pluginMessage.setData( brand.array().clone() ); ++ pluginMessage.setData( brand ); + brand.release(); + // changes in the packet are ignored so we need to send it manually + con.unsafe().sendPacket( pluginMessage ); +diff --git a/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java b/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java +index f0d0189..aec8251 100644 +--- a/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java ++++ b/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java +@@ -41,9 +41,9 @@ import net.md_5.bungee.protocol.Varint21LengthFieldPrepender; + public class PipelineUtils + { + +- public static final AttributeKey LISTENER = new AttributeKey<>( "ListerInfo" ); +- public static final AttributeKey USER = new AttributeKey<>( "User" ); +- public static final AttributeKey TARGET = new AttributeKey<>( "Target" ); ++ public static final AttributeKey LISTENER = AttributeKey.newInstance("ListerInfo"); ++ public static final AttributeKey USER = AttributeKey.newInstance("User"); ++ public static final AttributeKey TARGET = AttributeKey.newInstance("Target"); + public static final ChannelInitializer SERVER_CHILD = new ChannelInitializer() + { + @Override +-- +2.8.3 + diff --git a/BungeeCord-Patches/0033-Print-stack-trace-when-the-ByteBuf-is-not-direct.patch b/BungeeCord-Patches/0033-Print-stack-trace-when-the-ByteBuf-is-not-direct.patch new file mode 100644 index 0000000..d3ac33b --- /dev/null +++ b/BungeeCord-Patches/0033-Print-stack-trace-when-the-ByteBuf-is-not-direct.patch @@ -0,0 +1,23 @@ +From ced5b9324cc6270083caa16674d09e78e8ae72cd Mon Sep 17 00:00:00 2001 +From: Techcable +Date: Tue, 5 Apr 2016 11:00:16 -0700 +Subject: [PATCH] Print stack trace when the ByteBuf is not direct. + +The issue with ByteBufs not being direct should be fixed as of netty 4.1, and stacktraces provide valuable information. + +diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/Varint21FrameDecoder.java b/protocol/src/main/java/net/md_5/bungee/protocol/Varint21FrameDecoder.java +index 29e54db..6da27fc 100644 +--- a/protocol/src/main/java/net/md_5/bungee/protocol/Varint21FrameDecoder.java ++++ b/protocol/src/main/java/net/md_5/bungee/protocol/Varint21FrameDecoder.java +@@ -51,7 +51,7 @@ public class Varint21FrameDecoder extends ByteToMessageDecoder + if ( !DIRECT_WARNING ) + { + DIRECT_WARNING = true; +- System.out.println( "Netty is not using direct IO buffers." ); ++ new Throwable("Using a " + in.getClass().getTypeName() + ", not a direct byte buf!").printStackTrace(); + } + + // See https://github.com/SpigotMC/BungeeCord/issues/1717 +-- +2.8.3 + diff --git a/BungeeCord-Patches/0034-Validate-that-chat-messages-are-non-blank.patch b/BungeeCord-Patches/0034-Validate-that-chat-messages-are-non-blank.patch new file mode 100644 index 0000000..92dba9f --- /dev/null +++ b/BungeeCord-Patches/0034-Validate-that-chat-messages-are-non-blank.patch @@ -0,0 +1,57 @@ +From bc91805c7d00866d7c320cf01ee5bc79e450cc72 Mon Sep 17 00:00:00 2001 +From: Tux +Date: Wed, 13 Apr 2016 14:00:40 -0400 +Subject: [PATCH] Validate that chat messages are non-blank + + +diff --git a/proxy/src/main/java/io/github/waterfallmc/waterfall/StringUtil.java b/proxy/src/main/java/io/github/waterfallmc/waterfall/StringUtil.java +new file mode 100644 +index 0000000..940ad80 +--- /dev/null ++++ b/proxy/src/main/java/io/github/waterfallmc/waterfall/StringUtil.java +@@ -0,0 +1,22 @@ ++package io.github.waterfallmc.waterfall; ++ ++import lombok.AccessLevel; ++import lombok.NoArgsConstructor; ++ ++@NoArgsConstructor(access = AccessLevel.PRIVATE) ++public class StringUtil { ++ public static boolean isBlank(String str) { ++ if (str.isEmpty()) { ++ return true; ++ } ++ ++ int l = str.length(); ++ for (int i = 0; i < l; i++) { ++ if (!Character.isWhitespace(str.charAt(i))) { ++ return false; ++ } ++ } ++ ++ return true; ++ } ++} +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 7565ff9..42bb2fb 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 +@@ -1,6 +1,7 @@ + package net.md_5.bungee.connection; + + import com.google.common.base.Preconditions; ++import io.github.waterfallmc.waterfall.StringUtil; + import net.md_5.bungee.BungeeCord; + import net.md_5.bungee.ServerConnection; + import net.md_5.bungee.UserConnection; +@@ -109,6 +110,7 @@ public class UpstreamBridge extends PacketHandler + public void handle(Chat chat) throws Exception + { + Preconditions.checkArgument( chat.getMessage().length() <= 100, "Chat message too long" ); // Mojang limit, check on updates ++ Preconditions.checkArgument(!StringUtil.isBlank(chat.getMessage()), "Chat message is empty"); + + ServerConnection server = con.getServer(); + +-- +2.8.3 + diff --git a/BungeeCord-Patches/0035-Reduce-the-overhead-of-lots-and-lots-of-teams-with-t.patch b/BungeeCord-Patches/0035-Reduce-the-overhead-of-lots-and-lots-of-teams-with-t.patch new file mode 100644 index 0000000..4f049f1 --- /dev/null +++ b/BungeeCord-Patches/0035-Reduce-the-overhead-of-lots-and-lots-of-teams-with-t.patch @@ -0,0 +1,297 @@ +From be2a4b8a6d0f1d6e2e4ceea0bf35a8c3209af118 Mon Sep 17 00:00:00 2001 +From: Techcable +Date: Mon, 25 Apr 2016 23:46:00 -0700 +Subject: [PATCH] Reduce the overhead of lots and lots of teams with the same + names + +Featherboard (and other bad plugins) use persistent scoreboards (scoreboard.dat), causing every team ever to be sent to waterfall. This is bad, and takes tons of memory. + +Uses String.intern() to avoid duplicating strings +Uses a sorted array to avoid the overhead of the hashset in a team. + +diff --git a/api/src/main/java/io/github/waterfallmc/waterfall/utils/LowMemorySet.java b/api/src/main/java/io/github/waterfallmc/waterfall/utils/LowMemorySet.java +new file mode 100644 +index 0000000..3a062b6 +--- /dev/null ++++ b/api/src/main/java/io/github/waterfallmc/waterfall/utils/LowMemorySet.java +@@ -0,0 +1,177 @@ ++package io.github.waterfallmc.waterfall.utils; ++ ++import lombok.*; ++ ++import java.util.AbstractSet; ++import java.util.ArrayList; ++import java.util.Collection; ++import java.util.Collections; ++import java.util.Iterator; ++import java.util.List; ++import java.util.Set; ++import java.util.function.Consumer; ++import java.util.function.Predicate; ++import java.util.stream.Stream; ++ ++import static com.google.common.base.Preconditions.checkNotNull; ++ ++/** ++ * A set that uses a binary search to find objects in a sorted array. ++ * Avoids the memory cost of {@link java.util.HashSet}, while maintaining reasonable {@link Set#contains} ++ * Insertions ma O(N)! ++ */ ++public class LowMemorySet> extends AbstractSet implements Set { ++ private final List backing; ++ @Setter ++ private boolean trimAggressively; ++ ++ protected LowMemorySet(List list) { ++ this.backing = checkNotNull(list, "Null list"); ++ this.sort(); // We have to sort any initial elements ++ this.trim(true); ++ } ++ ++ public static > LowMemorySet create() { ++ return new LowMemorySet<>(new ArrayList()); ++ } ++ ++ public static > LowMemorySet copyOf(Collection c) { ++ return new LowMemorySet<>(new ArrayList<>(c)); ++ } ++ ++ @SuppressWarnings("unchecked") // nope ++ private int indexOf(Object o) { ++ return Collections.binarySearch((List) backing, o); ++ } ++ ++ private void sort() { ++ backing.sort(null); ++ this.trim(); ++ } ++ ++ private void trim() { ++ trim(false); ++ } ++ ++ private void trim(boolean force) { ++ if (backing instanceof ArrayList && force || trimAggressively) ((ArrayList) backing).trimToSize(); ++ } ++ ++ @Override ++ public int size() { ++ return backing.size(); ++ } ++ ++ @Override ++ public boolean contains(Object o) { ++ return indexOf(o) >= 0; ++ } ++ ++ @Override ++ public Iterator iterator() { ++ Iterator backing = this.backing.iterator(); ++ return new Iterator() { ++ private T last; ++ ++ @Override ++ public boolean hasNext() { ++ return backing.hasNext(); ++ } ++ ++ @Override ++ public T next() { ++ return (last = backing.next()); ++ } ++ ++ @Override ++ public void remove() { ++ LowMemorySet.this.remove(last); ++ } ++ ++ @Override ++ public void forEachRemaining(Consumer action) { ++ backing.forEachRemaining(action); ++ } ++ }; ++ } ++ ++ @Override ++ public Object[] toArray() { ++ return backing.toArray(); ++ } ++ ++ @Override ++ public T1[] toArray(T1[] a) { ++ return backing.toArray(a); ++ } ++ ++ @Override ++ public boolean add(T t) { ++ if (contains(t)) return false; ++ backing.add(t); ++ this.sort(); ++ return true; ++ } ++ ++ @Override ++ public boolean remove(Object o) { ++ T old = backing.remove(indexOf(o)); ++ this.trim(); ++ assert old == o; ++ return old != null; ++ } ++ ++ @Override ++ public boolean removeAll(Collection c) { ++ int oldSize = this.size(); ++ boolean result = backing.removeIf(c::contains); ++ this.trim(oldSize - this.size() > 10); ++ return result; ++ } ++ ++ @Override ++ public boolean retainAll(Collection c) { ++ int oldSize = this.size(); ++ boolean result = backing.removeIf((o) -> !c.contains(o)); ++ this.trim(oldSize - this.size() > 10); ++ return result; ++ } ++ ++ @Override ++ @SuppressWarnings("unchecked") ++ public boolean addAll(Collection c) { ++ if (containsAll(c)) return false; ++ backing.addAll(c); ++ this.sort(); ++ return true; ++ } ++ ++ @Override ++ public void clear() { ++ backing.clear(); ++ this.trim(true); ++ } ++ ++ @Override ++ public void forEach(Consumer action) { ++ backing.forEach(action); ++ } ++ ++ @Override ++ public Stream stream() { ++ return backing.stream(); ++ } ++ ++ @Override ++ public Stream parallelStream() { ++ return backing.parallelStream(); ++ } ++ ++ @Override ++ public boolean removeIf(Predicate filter) { ++ int oldSize = this.size(); ++ boolean worked = backing.removeIf(filter); ++ this.trim(this.size() - oldSize > 10); ++ return worked; ++ } ++} +diff --git a/api/src/main/java/net/md_5/bungee/api/score/Team.java b/api/src/main/java/net/md_5/bungee/api/score/Team.java +index 4166037..f0f019b 100644 +--- a/api/src/main/java/net/md_5/bungee/api/score/Team.java ++++ b/api/src/main/java/net/md_5/bungee/api/score/Team.java +@@ -1,11 +1,12 @@ + package net.md_5.bungee.api.score; + ++import lombok.*; ++ + import java.util.Collection; + import java.util.Collections; +-import java.util.HashSet; + import java.util.Set; +-import lombok.Data; +-import lombok.NonNull; ++ ++import io.github.waterfallmc.waterfall.utils.LowMemorySet; + + @Data + public class Team +@@ -20,7 +21,7 @@ public class Team + private String nameTagVisibility; + private String collisionRule; + private byte color; +- private Set players = new HashSet<>(); ++ private Set players = LowMemorySet.create(); + + public Collection getPlayers() + { +@@ -29,7 +30,7 @@ public class Team + + public void addPlayer(String name) + { +- players.add( name ); ++ players.add(name.intern()); + } + + public void removePlayer(String name) +diff --git a/api/src/test/java/io/github/waterfallmc/waterfall/utils/LowMemorySetTest.java b/api/src/test/java/io/github/waterfallmc/waterfall/utils/LowMemorySetTest.java +new file mode 100644 +index 0000000..5aa306a +--- /dev/null ++++ b/api/src/test/java/io/github/waterfallmc/waterfall/utils/LowMemorySetTest.java +@@ -0,0 +1,56 @@ ++package io.github.waterfallmc.waterfall.utils; ++ ++import com.google.common.collect.ImmutableList; ++import com.google.common.collect.ImmutableMap; ++ ++import org.junit.Test; ++ ++import static org.junit.Assert.*; ++ ++public class LowMemorySetTest { ++ ++ private static final ImmutableList ELEMENTS = ImmutableList.of("test", "bob", "road", "food", "sleep", "sore-thought", "pain"); ++ ++ @Test ++ public void testContains() { ++ LowMemorySet set = LowMemorySet.copyOf(ELEMENTS); ++ assertTrue(set.contains("test")); ++ assertTrue(set.contains("bob")); ++ assertFalse(set.contains("stupid")); ++ assertFalse(set.contains("head")); ++ } ++ ++ @Test ++ public void testRemove() { ++ LowMemorySet set = LowMemorySet.copyOf(ELEMENTS); ++ assertTrue(set.contains("test")); ++ set.remove("test"); ++ assertFalse(set.contains("test")); ++ assertTrue(set.contains("bob")); ++ set.remove("bob"); ++ assertFalse(set.contains("bob")); ++ assertTrue(ELEMENTS.size() - set.size() == 2); ++ assertTrue(set.contains("road")); ++ assertTrue(set.contains("food")); ++ assertTrue(set.contains("pain")); ++ set.removeAll(ImmutableList.of("road", "food", "pain")); ++ assertFalse(set.contains("road")); ++ assertFalse(set.contains("food")); ++ assertFalse(set.contains("pain")); ++ assertTrue(ELEMENTS.size() - set.size() == 5); ++ } ++ ++ @Test ++ public void testAdd() { ++ LowMemorySet set = LowMemorySet.copyOf(ELEMENTS); ++ assertFalse(set.contains("Techcable")); ++ set.add("Techcable"); ++ assertTrue(set.contains("Techcable")); ++ set.addAll(ImmutableList.of("Techcable", "PhanaticD", "Dragonslayer293", "Aikar")); ++ assertTrue(set.contains("Techcable")); ++ assertTrue(set.contains("PhanaticD")); ++ assertTrue(set.contains("Aikar")); ++ assertFalse(set.contains("md_5")); ++ } ++ ++} +-- +2.8.3 + diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..f129e01 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2015-2016 Waterfall Team + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..171254b --- /dev/null +++ b/README.md @@ -0,0 +1,30 @@ +# Waterfall + +Waterfall is a fork of the well-known [BungeeCord](https://github.com/SpigotMC/BungeeCord) server teleportation suite. + +Waterfall focuses on three main areas: + +* **Stability**: Waterfall aims to be stable. We will achieve this through making the code base testable and discouraging practices that lead to proxy lag. +* **Features**: Waterfall aims to include more features than canonical BungeeCord. +* **Scalability**: Waterfall should be able to handle a large number of concurrent players, given a reasonably modern CPU, memory, and good network connection. + +## Why fork BungeeCord? + +Think of Waterfall as a principles fork. + +Waterfall was forked because of the fact that upstream does not accept many contributions that are intended to better the ecosystem. Simply put, Waterfall aims to better +the ecosystem by allowing changes to be exposed to a wider audience more quickly. + +Waterfall will still track upstream BungeeCord and merge changes as needed. + +## Join us + +* Feel free to open a PR! We accept contributions. +* Join us on IRC (irc.esper.net #waterfall, [webchat](http://webchat.esper.net/?nick=&channels=waterfall)). +* Visit our forums on [Aquifer](https://aquifermc.org). + +Special Thanks To +----------------- +![YourKit-Logo](https://yourkit.com/images/yklogo.png) + +[YourKit](https://yourkit.com/), makers of the outstanding Java profiler, supports open source projects of all kinds with their full-featured [Java](https://yourkit.com/features/) and [.NET](https://yourkit.com/dotnet/features/) application profilers. We thank them for granting Waterfall an OSS license so that we can make our software the best it can be. diff --git a/applyPatches.sh b/applyPatches.sh new file mode 100755 index 0000000..c990157 --- /dev/null +++ b/applyPatches.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash + +( +PS1="$" +basedir="$(cd "$1" && pwd -P)" +workdir="$basedir/work" +gpgsign="$(git config commit.gpgsign || echo "false")" +echo "Rebuilding Forked projects.... " + +function applyPatch { + what=$1 + what_name=$(basename "$what") + target=$2 + branch=$3 + + cd "$basedir/$what" + git fetch + git branch -f upstream "$branch" >/dev/null + + cd "$basedir" + if [ ! -d "$basedir/$target" ]; then + git clone "$what" "$target" + fi + cd "$basedir/$target" + + # Disable GPG signing before AM, slows things down and doesn't play nicely. + # There is also zero rational or logical reason to do so for these sub-repo AMs. + # Calm down kids, it's re-enabled (if needed) immediately after, pass or fail. + git config commit.gpgsign false + + echo "Resetting $target to $what_name..." + git remote rm upstream > /dev/null 2>&1 + git remote add upstream "$basedir/$what" >/dev/null 2>&1 + git checkout master 2>/dev/null || git checkout -b master + git fetch upstream >/dev/null 2>&1 + git reset --hard upstream/upstream + + echo " Applying patches to $target..." + + git am --abort >/dev/null 2>&1 + git am --3way --ignore-whitespace "$basedir/${what_name}-Patches/"*.patch + if [ "$?" != "0" ]; then + echo " Something did not apply cleanly to $target." + echo " Please review above details and finish the apply then" + echo " save the changes with rebuildPatches.sh" + exit 1 + else + echo " Patches applied cleanly to $target" + fi +} + +function enableCommitSigningIfNeeded { + if [[ "$gpgsign" == "true" ]]; then + git config commit.gpgsign true + fi +} + +# Apply paper +cd "$basedir" +( + applyPatch "BungeeCord" Waterfall-Proxy HEAD + enableCommitSigningIfNeeded +) || ( + echo "Failed to apply WaterfallPatches" + enableCommitSigningIfNeeded + exit 1 +) || exit 1 +) diff --git a/rebuildPatches.sh b/rebuildPatches.sh new file mode 100755 index 0000000..866e6f7 --- /dev/null +++ b/rebuildPatches.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash + +( +PS1="$" +basedir="$(cd "$1" && pwd -P)" +workdir="$basedir/work" +echo "Rebuilding patch files from current fork state..." +git config core.safecrlf false + +function cleanupPatches { + cd "$1" + for patch in *.patch; do + echo "$patch" + gitver=$(tail -n 2 "$patch" | grep -ve "^$" | tail -n 1) + diffs=$(git diff --staged "$patch" | grep -E "^(\+|\-)" | grep -Ev "(From [a-z0-9]{32,}|\-\-\- a|\+\+\+ b|.index)") + + testver=$(echo "$diffs" | tail -n 2 | grep -ve "^$" | tail -n 1 | grep "$gitver") + if [ "x$testver" != "x" ]; then + diffs=$(echo "$diffs" | sed 'N;$!P;$!D;$d') + fi + + if [ "x$diffs" == "x" ] ; then + git reset HEAD "$patch" >/dev/null + git checkout -- "$patch" >/dev/null + fi + done +} + +function savePatches { + what=$1 + what_name=$(basename "$what") + target=$2 + echo "Formatting patches for $what..." + + cd "$basedir/${what_name}-Patches/" + if [ -d "$basedir/$target/.git/rebase-apply" ]; then + # in middle of a rebase, be smarter + echo "REBASE DETECTED - PARTIAL SAVE" + last=$(cat "$basedir/$target/.git/rebase-apply/last") + next=$(cat "$basedir/$target/.git/rebase-apply/next") + for i in $(seq -f "%04g" 1 1 $last) + do + if [ $i -lt $next ]; then + rm ${i}-*.patch + fi + done + else + rm -rf *.patch + fi + + cd "$basedir/$target" + + git format-patch --no-stat -N -o "$basedir/${what_name}-Patches/" upstream/upstream >/dev/null + cd "$basedir" + git add -A "$basedir/${what_name}-Patches" + cleanupPatches "$basedir/${what_name}-Patches" + echo " Patches saved for $what to $what_name-Patches/" +} + +savePatches "BungeeCord" "Waterfall-Proxy" +)