From 53f5c18f1459b3d6e3a5bd75f6d7df18a73495f8 Mon Sep 17 00:00:00 2001 From: Marc Baloup Date: Fri, 13 Aug 2021 20:23:24 +0200 Subject: [PATCH] Waterfall + Pandacube patches = PandaCord --- .gitignore | 2 +- .gitmodules | 3 + CONTRIBUTING.md | 68 +- LICENSE.txt | 21 - Waterfall | 1 + ...-configuration-and-POM-for-Pandacube.patch | 413 +++++ ...002-Remove-modules-and-startup-delay.patch | 1630 +++++++++++++++++ ...th-same-Minecraft-account-with-speci.patch | 150 ++ ...-and-server-branding-displayed-in-F3.patch | 43 + ...areEvent-to-declare-commands-with-br.patch | 1048 +++++++++++ ...pleteRequestEvent-and-deprecate-TabC.patch | 194 ++ pandacord | 28 + pom.xml | 25 - scripts/applyPatches.sh | 4 +- scripts/build.sh | 4 - scripts/edit.sh | 2 +- scripts/rebuildPatches.sh | 3 +- scripts/wigglePatch.py | 149 -- travertine | 35 - 19 files changed, 3531 insertions(+), 292 deletions(-) create mode 100644 .gitmodules delete mode 100644 LICENSE.txt create mode 160000 Waterfall create mode 100644 Waterfall-Proxy-Patches/0001-Change-projet-configuration-and-POM-for-Pandacube.patch create mode 100644 Waterfall-Proxy-Patches/0002-Remove-modules-and-startup-delay.patch create mode 100644 Waterfall-Proxy-Patches/0003-Multi-session-with-same-Minecraft-account-with-speci.patch create mode 100644 Waterfall-Proxy-Patches/0004-Inproved-proxy-and-server-branding-displayed-in-F3.patch create mode 100644 Waterfall-Proxy-Patches/0005-Add-CommandsDeclareEvent-to-declare-commands-with-br.patch create mode 100644 Waterfall-Proxy-Patches/0006-new-event-TabCompleteRequestEvent-and-deprecate-TabC.patch create mode 100644 pandacord delete mode 100644 pom.xml delete mode 100644 scripts/wigglePatch.py delete mode 100755 travertine diff --git a/.gitignore b/.gitignore index 78a508e..f19ce8a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -Travertine-Proxy +PandaCord-Proxy # intellij *.iml diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..8f51e7a --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "Waterfall"] + path = Waterfall + url = https://github.com/PaperMC/Waterfall.git diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6418a14..bdfc4c1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,33 +1,34 @@ -Contributing to Travertine +Contributing to PandaCord ========================== -WaterfallMC has a very lenient policy towards PRs, but would prefer that you try and adhere to the following guidelines. +This file explains how to deal with patch based projects, using the provided scripts. +This documentation is based on Waterfall’s CONTRIBUTING.md ## Understanding Patches -Patches to Travertine are very simple, but center around the directory 'Travertine-Proxy' +Patches to PandaCord are very simple, but center around the directory 'PandaCord-Proxy' Assuming you already have forked the repository: 1. Pull the latest changes from the main repository -2. Type `./travertine p` in git bash to apply the changes from upstream -3. cd into `Travertine-Proxy` for proxy changes +2. Type `./pandacord p` in git bash to apply the changes from upstream +3. cd into `PandaCord-Proxy` for proxy changes This directory is not a git repository in the traditional sense: -- Every single commit in Travertine-Proxy is a patch. -- 'origin/master' points to a directory similar to Travertine-Proxy but for Travertine -- Typing `git status` should show that we are 10 or 11 commits ahead of master, meaning we have 10 or 11 patches that Travertine, Waterfall, and Bungeecord don't - - If it says something like `212 commits ahead, 207 commits behind`, then type `git fetch` to update Travertine +- Every single commit in PandaCord-Proxy is a patch. +- 'origin/master' points to a directory similar to PandaCord-Proxy but for PandaCord +- Typing `git status` should show that we are 10 or 11 commits ahead of master, meaning we have 10 or 11 patches that PandaCord, Waterfall, and Bungeecord don't + - If it says something like `212 commits ahead, 207 commits behind`, then type `git fetch` to update PandaCord ## Adding Patches -Adding patches to Travertine is very simple: +Adding patches to PandaCord is very simple: -1. Modify `Travertine-Proxy` with the appropriate changes +1. Modify `PandaCord-Proxy` with the appropriate changes 2. Type `git add .` to add your changes 3. Run `git commit` with the desired patch message -4. Run `./travertine rb` in the main directory to convert your commit into a new patch +4. Run `./pandacord rb` in the main directory to convert your commit into a new patch 5. PR your patches back to this repository -Your commit will be converted into a patch that you can then PR into Travertine +Your commit will be converted into a patch that you can then PR into PandaCord ## Modifying Patches Modifying previous patches is a bit more complex: @@ -47,7 +48,7 @@ This method works by temporarily resetting HEAD to the desired commit to edit us - **MAKE SURE TO ADD `--amend`** or else a new patch will be created. - You can also modify the commit message here. 7. Type `git rebase --continue` to finish rebasing. -8. Type `./travertine rb` in the main directory. +8. Type `./pandacord rb` in the main directory. - This will modify the appropriate patches based on your commits. 9. PR your modifications back to this project. @@ -58,43 +59,6 @@ If you are simply editing a more recent commit or your change is small, simply m 2. Make a temporary commit. You don't need to make a message for this. 3. Type `git rebase -i upstream/upstream`, move (cut) your temporary commit and move it under the line of the patch you wish to modify. 4. Change the `pick` with `f` (fixup) or `s` (squash) if you need to edit the commit message -5. Type `./travertine rb` in the main directory. +5. Type `./pandacord rb` in the main directory. - This will modify the appropriate patches based on your commits. 6. PR your modifications to github - - -## PR Policy -We'll accept changes that make sense. You should be able to justify their existence, along with any maintenance costs that come with them. Remember, these changes will affect everyone who runs Travertine, not just you and your server. -While we will fix minor formatting issues, you should stick to the guide below when making and submitting changes. - -## Formatting -All modifications to non-Travertine files should be marked -- Multi line changes start with `// Travertine start` and end with `// Travertine end` -- You can put a messages with a change if it isn't obvious, like this: `// Travertine start - reason - - Should generally be about the reason the change was made, what it was before, or what the change is - - Multi-line messages should start with `// Travertine start` and use `/* Multi line message here */` for the message itself -- Single line changes should have `// Travertine` or `// Travertine - reason` -- For example: -````java -return getConfig().getNotStupid(); // Travertine - was return getConfig().getStupid(); - -// Travertine start -// con.disconnect( bungee.getTranslation( "lost_connection" ) ); -ServerInfo def = con.updateAndGetNextServer( server.getInfo() ); -ServerKickEvent event = bungee.getPluginManager().callEvent( new ServerKickEvent( con, server.getInfo(), TextComponent.fromLegacyText( bungee.getTranslation( "lost_connection" ) ), def, ServerKickEvent.State.CONNECTED, ServerKickEvent.Cause.LOST_CONNECTION ) ); -if ( event.isCancelled() && event.getCancelServer() != null ) -{ - server.setObsolete( true ); - con.connectNow( event.getCancelServer() ); -} -else -{ - con.disconnect0( event.getKickReasonComponent() ); -} -// Travertine end -```` -- We generally follow usual java style, or what is programmed into most IDEs and formatters by default - - This is also known as oracle style - - It is fine to go over 80 lines as long as it doesn't hurt readability - - There are exceptions, especially in Bungeecord-related files - - When in doubt, use the same style as the surrounding code diff --git a/LICENSE.txt b/LICENSE.txt deleted file mode 100644 index e43a8af..0000000 --- a/LICENSE.txt +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2015-2019 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/Waterfall b/Waterfall new file mode 160000 index 0000000..7e6af4c --- /dev/null +++ b/Waterfall @@ -0,0 +1 @@ +Subproject commit 7e6af4cef64d5d377a6ffd00a534379e6efa94cf diff --git a/Waterfall-Proxy-Patches/0001-Change-projet-configuration-and-POM-for-Pandacube.patch b/Waterfall-Proxy-Patches/0001-Change-projet-configuration-and-POM-for-Pandacube.patch new file mode 100644 index 0000000..1cc76d1 --- /dev/null +++ b/Waterfall-Proxy-Patches/0001-Change-projet-configuration-and-POM-for-Pandacube.patch @@ -0,0 +1,413 @@ +From 5bd6939857a7272ad7c338e202a7196010121aa8 Mon Sep 17 00:00:00 2001 +From: Marc Baloup +Date: Sat, 1 Oct 2016 23:26:27 +0200 +Subject: [PATCH] Change projet configuration and POM for Pandacube + + +diff --git a/api/pom.xml b/api/pom.xml +index 0680a5a5..1d46bfb4 100644 +--- a/api/pom.xml ++++ b/api/pom.xml +@@ -4,13 +4,12 @@ + 4.0.0 + + +- io.github.waterfallmc ++ fr.pandacube.pandacord + waterfall-parent + 1.17-R0.1-SNAPSHOT + ../pom.xml + + +- io.github.waterfallmc + waterfall-api + 1.17-R0.1-SNAPSHOT + jar +@@ -20,25 +19,25 @@ + + + +- io.github.waterfallmc ++ fr.pandacube.pandacord + waterfall-chat + ${project.version} + compile + + +- io.github.waterfallmc ++ fr.pandacube.pandacord + waterfall-config + ${project.version} + compile + + +- io.github.waterfallmc ++ fr.pandacube.pandacord + waterfall-event + ${project.version} + compile + + +- io.github.waterfallmc ++ fr.pandacube.pandacord + waterfall-protocol + ${project.version} + compile +diff --git a/bootstrap/pom.xml b/bootstrap/pom.xml +index 7a9e8258..0efba9cd 100644 +--- a/bootstrap/pom.xml ++++ b/bootstrap/pom.xml +@@ -4,13 +4,12 @@ + 4.0.0 + + +- io.github.waterfallmc ++ fr.pandacube.pandacord + waterfall-parent + 1.17-R0.1-SNAPSHOT + ../pom.xml + + +- io.github.waterfallmc + waterfall-bootstrap + 1.17-R0.1-SNAPSHOT + jar +@@ -29,7 +28,7 @@ + + + +- io.github.waterfallmc ++ fr.pandacube.pandacord + waterfall-proxy + ${project.version} + compile +diff --git a/chat/pom.xml b/chat/pom.xml +index cfa0e16e..dbe64d6d 100644 +--- a/chat/pom.xml ++++ b/chat/pom.xml +@@ -4,13 +4,12 @@ + 4.0.0 + + +- io.github.waterfallmc ++ fr.pandacube.pandacord + waterfall-parent + 1.17-R0.1-SNAPSHOT + ../pom.xml + + +- io.github.waterfallmc + waterfall-chat + 1.17-R0.1-SNAPSHOT + jar +diff --git a/config/pom.xml b/config/pom.xml +index 67e2500f..212c7371 100644 +--- a/config/pom.xml ++++ b/config/pom.xml +@@ -4,13 +4,12 @@ + 4.0.0 + + +- io.github.waterfallmc ++ fr.pandacube.pandacord + waterfall-parent + 1.17-R0.1-SNAPSHOT + ../pom.xml + + +- io.github.waterfallmc + waterfall-config + 1.17-R0.1-SNAPSHOT + jar +diff --git a/event/pom.xml b/event/pom.xml +index 563783e9..4263081e 100644 +--- a/event/pom.xml ++++ b/event/pom.xml +@@ -4,13 +4,12 @@ + 4.0.0 + + +- io.github.waterfallmc ++ fr.pandacube.pandacord + waterfall-parent + 1.17-R0.1-SNAPSHOT + ../pom.xml + + +- io.github.waterfallmc + waterfall-event + 1.17-R0.1-SNAPSHOT + jar +diff --git a/log/pom.xml b/log/pom.xml +index 3663d6d9..f1e8ace8 100644 +--- a/log/pom.xml ++++ b/log/pom.xml +@@ -4,13 +4,12 @@ + 4.0.0 + + +- io.github.waterfallmc ++ fr.pandacube.pandacord + waterfall-parent + 1.17-R0.1-SNAPSHOT + ../pom.xml + + +- io.github.waterfallmc + waterfall-log + 1.17-R0.1-SNAPSHOT + jar +@@ -26,7 +25,7 @@ + compile + + +- io.github.waterfallmc ++ fr.pandacube.pandacord + waterfall-chat + ${project.version} + compile +diff --git a/log4j/pom.xml b/log4j/pom.xml +index 7ec6e530..87c200d2 100644 +--- a/log4j/pom.xml ++++ b/log4j/pom.xml +@@ -3,13 +3,12 @@ + 4.0.0 + + +- io.github.waterfallmc ++ fr.pandacube.pandacord + waterfall-parent + 1.17-R0.1-SNAPSHOT + ../pom.xml + + +- io.github.waterfallmc + waterfall-log4j + 1.17-R0.1-SNAPSHOT + jar +diff --git a/native/pom.xml b/native/pom.xml +index 652a869d..2f87f4c2 100644 +--- a/native/pom.xml ++++ b/native/pom.xml +@@ -4,13 +4,12 @@ + 4.0.0 + + +- io.github.waterfallmc ++ fr.pandacube.pandacord + waterfall-parent + 1.17-R0.1-SNAPSHOT + ../pom.xml + + +- io.github.waterfallmc + waterfall-native + 1.17-R0.1-SNAPSHOT + jar +diff --git a/pom.xml b/pom.xml +index 8d86e36c..5b701203 100644 +--- a/pom.xml ++++ b/pom.xml +@@ -3,14 +3,7 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + +- +- io.github.waterfallmc +- waterfall-super +- dev-SNAPSHOT +- ../pom.xml +- +- +- io.github.waterfallmc ++ fr.pandacube.pandacord + waterfall-parent + 1.17-R0.1-SNAPSHOT + pom +@@ -129,7 +122,7 @@ + scriptus + 0.4.1 + +- git:${project.name}:${project.version}:%s:${build.number} ++ git:PandaCord:${project.version}:%s:${build.number} + + + +@@ -201,6 +194,62 @@ + + + ++ ++ ++ ++ ++ org.eclipse.m2e ++ lifecycle-mapping ++ 1.0.0 ++ ++ ++ ++ ++ ++ net.md-5 ++ scriptus ++ [0.3.1,) ++ ++ describe ++ ++ ++ ++ ++ false ++ ++ ++ ++ ++ ++ org.apache.maven.plugins ++ maven-enforcer-plugin ++ [1.0.0,) ++ ++ enforce ++ ++ ++ ++ ++ ++ ++ ++ ++ org.apache.maven.plugins ++ maven-checkstyle-plugin ++ [3.0.0,) ++ check ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + + + +diff --git a/protocol/pom.xml b/protocol/pom.xml +index dbc0a3ab..dd16e74e 100644 +--- a/protocol/pom.xml ++++ b/protocol/pom.xml +@@ -4,13 +4,12 @@ + 4.0.0 + + +- io.github.waterfallmc ++ fr.pandacube.pandacord + waterfall-parent + 1.17-R0.1-SNAPSHOT + ../pom.xml + + +- io.github.waterfallmc + waterfall-protocol + 1.17-R0.1-SNAPSHOT + jar +@@ -41,7 +40,7 @@ + compile + + +- io.github.waterfallmc ++ fr.pandacube.pandacord + waterfall-chat + ${project.version} + compile +diff --git a/proxy/pom.xml b/proxy/pom.xml +index c3a2eeb6..fe3a2197 100644 +--- a/proxy/pom.xml ++++ b/proxy/pom.xml +@@ -4,13 +4,12 @@ + 4.0.0 + + +- io.github.waterfallmc ++ fr.pandacube.pandacord + waterfall-parent + 1.17-R0.1-SNAPSHOT + ../pom.xml + + +- io.github.waterfallmc + waterfall-proxy + 1.17-R0.1-SNAPSHOT + jar +@@ -64,31 +63,31 @@ + compile + + +- io.github.waterfallmc ++ fr.pandacube.pandacord + waterfall-api + ${project.version} + compile + + +- io.github.waterfallmc ++ fr.pandacube.pandacord + waterfall-log4j + ${project.version} + compile + + +- io.github.waterfallmc ++ fr.pandacube.pandacord + waterfall-native + ${project.version} + compile + + +- io.github.waterfallmc ++ fr.pandacube.pandacord + waterfall-protocol + ${project.version} + compile + + +- io.github.waterfallmc ++ fr.pandacube.pandacord + waterfall-query + ${project.version} + compile +diff --git a/query/pom.xml b/query/pom.xml +index dea7d85f..55baf2e0 100644 +--- a/query/pom.xml ++++ b/query/pom.xml +@@ -4,13 +4,12 @@ + 4.0.0 + + +- io.github.waterfallmc ++ fr.pandacube.pandacord + waterfall-parent + 1.17-R0.1-SNAPSHOT + ../pom.xml + + +- io.github.waterfallmc + waterfall-query + 1.17-R0.1-SNAPSHOT + jar +@@ -26,7 +25,7 @@ + compile + + +- io.github.waterfallmc ++ fr.pandacube.pandacord + waterfall-api + ${project.version} + compile +-- +2.32.0.windows.2 + diff --git a/Waterfall-Proxy-Patches/0002-Remove-modules-and-startup-delay.patch b/Waterfall-Proxy-Patches/0002-Remove-modules-and-startup-delay.patch new file mode 100644 index 0000000..4135637 --- /dev/null +++ b/Waterfall-Proxy-Patches/0002-Remove-modules-and-startup-delay.patch @@ -0,0 +1,1630 @@ +From 23d6ba913bc063129277f8711027d1a209b67148 Mon Sep 17 00:00:00 2001 +From: Marc Baloup +Date: Wed, 23 Nov 2016 12:47:23 +0100 +Subject: [PATCH] Remove modules and startup delay +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We don’t need them for Pandacube + +diff --git a/module/cmd-alert/nb-configuration.xml b/module/cmd-alert/nb-configuration.xml +deleted file mode 100644 +index 7e465924..00000000 +--- a/module/cmd-alert/nb-configuration.xml ++++ /dev/null +@@ -1,31 +0,0 @@ +- +- +- +- +- +- project +- NEW_LINE +- NEW_LINE +- NEW_LINE +- true +- true +- true +- true +- true +- true +- true +- true +- true +- true +- +- +diff --git a/module/cmd-alert/pom.xml b/module/cmd-alert/pom.xml +deleted file mode 100644 +index 11e990d9..00000000 +--- a/module/cmd-alert/pom.xml ++++ /dev/null +@@ -1,20 +0,0 @@ +- +- +- 4.0.0 +- +- +- io.github.waterfallmc +- waterfall-module +- 1.17-R0.1-SNAPSHOT +- ../pom.xml +- +- +- io.github.waterfallmc +- waterfall-module-cmd-alert +- 1.17-R0.1-SNAPSHOT +- jar +- +- cmd_alert +- Provides the alert and alertraw commands +- +diff --git a/module/cmd-alert/src/main/java/net/md_5/bungee/module/cmd/alert/CommandAlert.java b/module/cmd-alert/src/main/java/net/md_5/bungee/module/cmd/alert/CommandAlert.java +deleted file mode 100644 +index 55d2f7b8..00000000 +--- a/module/cmd-alert/src/main/java/net/md_5/bungee/module/cmd/alert/CommandAlert.java ++++ /dev/null +@@ -1,46 +0,0 @@ +-package net.md_5.bungee.module.cmd.alert; +- +-import net.md_5.bungee.api.ChatColor; +-import net.md_5.bungee.api.CommandSender; +-import net.md_5.bungee.api.ProxyServer; +-import net.md_5.bungee.api.chat.TextComponent; +-import net.md_5.bungee.api.plugin.Command; +- +-public class CommandAlert extends Command +-{ +- +- public CommandAlert() +- { +- super( "alert", "bungeecord.command.alert" ); +- } +- +- @Override +- public void execute(CommandSender sender, String[] args) +- { +- if ( args.length == 0 ) +- { +- sender.sendMessage( ProxyServer.getInstance().getTranslation( "message_needed" ) ); +- } else +- { +- StringBuilder builder = new StringBuilder(); +- if ( args[0].startsWith( "&h" ) ) +- { +- // Remove &h +- args[0] = args[0].substring( 2, args[0].length() ); +- } else +- { +- builder.append( ProxyServer.getInstance().getTranslation( "alert" ) ); +- } +- +- for ( String s : args ) +- { +- builder.append( ChatColor.translateAlternateColorCodes( '&', s ) ); +- builder.append( " " ); +- } +- +- String message = builder.substring( 0, builder.length() - 1 ); +- +- ProxyServer.getInstance().broadcast( TextComponent.fromLegacyText( message ) ); +- } +- } +-} +diff --git a/module/cmd-alert/src/main/java/net/md_5/bungee/module/cmd/alert/CommandAlertRaw.java b/module/cmd-alert/src/main/java/net/md_5/bungee/module/cmd/alert/CommandAlertRaw.java +deleted file mode 100644 +index 7292899d..00000000 +--- a/module/cmd-alert/src/main/java/net/md_5/bungee/module/cmd/alert/CommandAlertRaw.java ++++ /dev/null +@@ -1,56 +0,0 @@ +-package net.md_5.bungee.module.cmd.alert; +- +-import com.google.common.base.Joiner; +-import net.md_5.bungee.api.ChatColor; +-import net.md_5.bungee.api.CommandSender; +-import net.md_5.bungee.api.ProxyServer; +-import net.md_5.bungee.api.chat.ComponentBuilder; +-import net.md_5.bungee.api.chat.HoverEvent; +-import net.md_5.bungee.api.connection.ProxiedPlayer; +-import net.md_5.bungee.api.plugin.Command; +-import net.md_5.bungee.chat.ComponentSerializer; +- +-public class CommandAlertRaw extends Command +-{ +- +- public CommandAlertRaw() +- { +- super( "alertraw", "bungeecord.command.alert" ); +- } +- +- @Override +- public void execute(CommandSender sender, String[] args) +- { +- if ( args.length == 0 ) +- { +- sender.sendMessage( ProxyServer.getInstance().getTranslation( "message_needed" ) ); +- } else +- { +- String message = Joiner.on( ' ' ).join( args ); +- +- try +- { +- ProxyServer.getInstance().broadcast( ComponentSerializer.parse( message ) ); +- } catch ( Exception e ) +- { +- Throwable error = e; +- while ( error.getCause() != null ) +- { +- error = error.getCause(); +- } +- if ( sender instanceof ProxiedPlayer ) +- { +- sender.sendMessage( new ComponentBuilder( ProxyServer.getInstance().getTranslation( "error_occurred_player" ) ) +- .event( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( error.getMessage() ) +- .color( ChatColor.RED ) +- .create() ) ) +- .create() +- ); +- } else +- { +- sender.sendMessage( ProxyServer.getInstance().getTranslation( "error_occurred_console", error.getMessage() ) ); +- } +- } +- } +- } +-} +diff --git a/module/cmd-alert/src/main/java/net/md_5/bungee/module/cmd/alert/PluginAlert.java b/module/cmd-alert/src/main/java/net/md_5/bungee/module/cmd/alert/PluginAlert.java +deleted file mode 100644 +index b6f84865..00000000 +--- a/module/cmd-alert/src/main/java/net/md_5/bungee/module/cmd/alert/PluginAlert.java ++++ /dev/null +@@ -1,14 +0,0 @@ +-package net.md_5.bungee.module.cmd.alert; +- +-import net.md_5.bungee.api.plugin.Plugin; +- +-public class PluginAlert extends Plugin +-{ +- +- @Override +- public void onEnable() +- { +- getProxy().getPluginManager().registerCommand( this, new CommandAlert() ); +- getProxy().getPluginManager().registerCommand( this, new CommandAlertRaw() ); +- } +-} +diff --git a/module/cmd-alert/src/main/resources/plugin.yml b/module/cmd-alert/src/main/resources/plugin.yml +deleted file mode 100644 +index 8ed58084..00000000 +--- a/module/cmd-alert/src/main/resources/plugin.yml ++++ /dev/null +@@ -1,5 +0,0 @@ +-name: ${project.name} +-main: net.md_5.bungee.module.cmd.alert.PluginAlert +-version: ${describe} +-description: ${project.description} +-author: ${module.author} +diff --git a/module/cmd-find/nb-configuration.xml b/module/cmd-find/nb-configuration.xml +deleted file mode 100644 +index 7e465924..00000000 +--- a/module/cmd-find/nb-configuration.xml ++++ /dev/null +@@ -1,31 +0,0 @@ +- +- +- +- +- +- project +- NEW_LINE +- NEW_LINE +- NEW_LINE +- true +- true +- true +- true +- true +- true +- true +- true +- true +- true +- +- +diff --git a/module/cmd-find/pom.xml b/module/cmd-find/pom.xml +deleted file mode 100644 +index b732d67f..00000000 +--- a/module/cmd-find/pom.xml ++++ /dev/null +@@ -1,20 +0,0 @@ +- +- +- 4.0.0 +- +- +- io.github.waterfallmc +- waterfall-module +- 1.17-R0.1-SNAPSHOT +- ../pom.xml +- +- +- io.github.waterfallmc +- waterfall-module-cmd-find +- 1.17-R0.1-SNAPSHOT +- jar +- +- cmd_find +- Provides the find command +- +diff --git a/module/cmd-find/src/main/java/net/md_5/bungee/module/cmd/find/CommandFind.java b/module/cmd-find/src/main/java/net/md_5/bungee/module/cmd/find/CommandFind.java +deleted file mode 100644 +index 7ea239ac..00000000 +--- a/module/cmd-find/src/main/java/net/md_5/bungee/module/cmd/find/CommandFind.java ++++ /dev/null +@@ -1,34 +0,0 @@ +-package net.md_5.bungee.module.cmd.find; +- +-import net.md_5.bungee.api.CommandSender; +-import net.md_5.bungee.api.ProxyServer; +-import net.md_5.bungee.api.connection.ProxiedPlayer; +-import net.md_5.bungee.command.PlayerCommand; +- +-public class CommandFind extends PlayerCommand +-{ +- +- public CommandFind() +- { +- super( "find", "bungeecord.command.find" ); +- } +- +- @Override +- public void execute(CommandSender sender, String[] args) +- { +- if ( args.length != 1 ) +- { +- sender.sendMessage( ProxyServer.getInstance().getTranslation( "username_needed" ) ); +- } else +- { +- ProxiedPlayer player = ProxyServer.getInstance().getPlayer( args[0] ); +- if ( player == null || player.getServer() == null ) +- { +- sender.sendMessage( ProxyServer.getInstance().getTranslation( "user_not_online" ) ); +- } else +- { +- sender.sendMessage( ProxyServer.getInstance().getTranslation( "user_online_at", player.getName(), player.getServer().getInfo().getName() ) ); +- } +- } +- } +-} +diff --git a/module/cmd-find/src/main/java/net/md_5/bungee/module/cmd/find/PluginFind.java b/module/cmd-find/src/main/java/net/md_5/bungee/module/cmd/find/PluginFind.java +deleted file mode 100644 +index 63757214..00000000 +--- a/module/cmd-find/src/main/java/net/md_5/bungee/module/cmd/find/PluginFind.java ++++ /dev/null +@@ -1,13 +0,0 @@ +-package net.md_5.bungee.module.cmd.find; +- +-import net.md_5.bungee.api.plugin.Plugin; +- +-public class PluginFind extends Plugin +-{ +- +- @Override +- public void onEnable() +- { +- getProxy().getPluginManager().registerCommand( this, new CommandFind() ); +- } +-} +diff --git a/module/cmd-find/src/main/resources/plugin.yml b/module/cmd-find/src/main/resources/plugin.yml +deleted file mode 100644 +index e0f346f9..00000000 +--- a/module/cmd-find/src/main/resources/plugin.yml ++++ /dev/null +@@ -1,5 +0,0 @@ +-name: ${project.name} +-main: net.md_5.bungee.module.cmd.find.PluginFind +-version: ${describe} +-description: ${project.description} +-author: ${module.author} +diff --git a/module/cmd-list/nb-configuration.xml b/module/cmd-list/nb-configuration.xml +deleted file mode 100644 +index 7e465924..00000000 +--- a/module/cmd-list/nb-configuration.xml ++++ /dev/null +@@ -1,31 +0,0 @@ +- +- +- +- +- +- project +- NEW_LINE +- NEW_LINE +- NEW_LINE +- true +- true +- true +- true +- true +- true +- true +- true +- true +- true +- +- +diff --git a/module/cmd-list/pom.xml b/module/cmd-list/pom.xml +deleted file mode 100644 +index d17cb787..00000000 +--- a/module/cmd-list/pom.xml ++++ /dev/null +@@ -1,20 +0,0 @@ +- +- +- 4.0.0 +- +- +- io.github.waterfallmc +- waterfall-module +- 1.17-R0.1-SNAPSHOT +- ../pom.xml +- +- +- io.github.waterfallmc +- waterfall-module-cmd-list +- 1.17-R0.1-SNAPSHOT +- jar +- +- cmd_list +- Provides the glist command +- +diff --git a/module/cmd-list/src/main/java/net/md_5/bungee/module/cmd/list/CommandList.java b/module/cmd-list/src/main/java/net/md_5/bungee/module/cmd/list/CommandList.java +deleted file mode 100644 +index c2227110..00000000 +--- a/module/cmd-list/src/main/java/net/md_5/bungee/module/cmd/list/CommandList.java ++++ /dev/null +@@ -1,47 +0,0 @@ +-package net.md_5.bungee.module.cmd.list; +- +-import java.util.ArrayList; +-import java.util.Collections; +-import java.util.List; +-import net.md_5.bungee.Util; +-import net.md_5.bungee.api.ChatColor; +-import net.md_5.bungee.api.CommandSender; +-import net.md_5.bungee.api.ProxyServer; +-import net.md_5.bungee.api.config.ServerInfo; +-import net.md_5.bungee.api.connection.ProxiedPlayer; +-import net.md_5.bungee.api.plugin.Command; +- +-/** +- * Command to list all players connected to the proxy. +- */ +-public class CommandList extends Command +-{ +- +- public CommandList() +- { +- super( "glist", "bungeecord.command.list" ); +- } +- +- @Override +- public void execute(CommandSender sender, String[] args) +- { +- for ( ServerInfo server : ProxyServer.getInstance().getServers().values() ) +- { +- if ( !server.canAccess( sender ) ) +- { +- continue; +- } +- +- List players = new ArrayList<>(); +- for ( ProxiedPlayer player : server.getPlayers() ) +- { +- players.add( player.getDisplayName() ); +- } +- Collections.sort( players, String.CASE_INSENSITIVE_ORDER ); +- +- sender.sendMessage( ProxyServer.getInstance().getTranslation( "command_list", server.getName(), server.getPlayers().size(), Util.format( players, ChatColor.RESET + ", " ) ) ); +- } +- +- sender.sendMessage( ProxyServer.getInstance().getTranslation( "total_players", ProxyServer.getInstance().getOnlineCount() ) ); +- } +-} +diff --git a/module/cmd-list/src/main/java/net/md_5/bungee/module/cmd/list/PluginList.java b/module/cmd-list/src/main/java/net/md_5/bungee/module/cmd/list/PluginList.java +deleted file mode 100644 +index e2a196c1..00000000 +--- a/module/cmd-list/src/main/java/net/md_5/bungee/module/cmd/list/PluginList.java ++++ /dev/null +@@ -1,13 +0,0 @@ +-package net.md_5.bungee.module.cmd.list; +- +-import net.md_5.bungee.api.plugin.Plugin; +- +-public class PluginList extends Plugin +-{ +- +- @Override +- public void onEnable() +- { +- getProxy().getPluginManager().registerCommand( this, new CommandList() ); +- } +-} +diff --git a/module/cmd-list/src/main/resources/plugin.yml b/module/cmd-list/src/main/resources/plugin.yml +deleted file mode 100644 +index 272e64eb..00000000 +--- a/module/cmd-list/src/main/resources/plugin.yml ++++ /dev/null +@@ -1,5 +0,0 @@ +-name: ${project.name} +-main: net.md_5.bungee.module.cmd.list.PluginList +-version: ${describe} +-description: ${project.description} +-author: ${module.author} +diff --git a/module/cmd-send/nb-configuration.xml b/module/cmd-send/nb-configuration.xml +deleted file mode 100644 +index 7e465924..00000000 +--- a/module/cmd-send/nb-configuration.xml ++++ /dev/null +@@ -1,31 +0,0 @@ +- +- +- +- +- +- project +- NEW_LINE +- NEW_LINE +- NEW_LINE +- true +- true +- true +- true +- true +- true +- true +- true +- true +- true +- +- +diff --git a/module/cmd-send/pom.xml b/module/cmd-send/pom.xml +deleted file mode 100644 +index d1972708..00000000 +--- a/module/cmd-send/pom.xml ++++ /dev/null +@@ -1,20 +0,0 @@ +- +- +- 4.0.0 +- +- +- io.github.waterfallmc +- waterfall-module +- 1.17-R0.1-SNAPSHOT +- ../pom.xml +- +- +- io.github.waterfallmc +- waterfall-module-cmd-send +- 1.17-R0.1-SNAPSHOT +- jar +- +- cmd_send +- Provides the gsend command +- +diff --git a/module/cmd-send/src/main/java/net/md_5/bungee/module/cmd/send/CommandSend.java b/module/cmd-send/src/main/java/net/md_5/bungee/module/cmd/send/CommandSend.java +deleted file mode 100644 +index f59f9457..00000000 +--- a/module/cmd-send/src/main/java/net/md_5/bungee/module/cmd/send/CommandSend.java ++++ /dev/null +@@ -1,200 +0,0 @@ +-package net.md_5.bungee.module.cmd.send; +- +-import com.google.common.base.Joiner; +-import com.google.common.collect.ImmutableSet; +-import java.util.ArrayList; +-import java.util.Collections; +-import java.util.HashMap; +-import java.util.HashSet; +-import java.util.List; +-import java.util.Locale; +-import java.util.Map; +-import java.util.Set; +-import net.md_5.bungee.api.Callback; +-import net.md_5.bungee.api.ChatColor; +-import net.md_5.bungee.api.CommandSender; +-import net.md_5.bungee.api.ProxyServer; +-import net.md_5.bungee.api.ServerConnectRequest; +-import net.md_5.bungee.api.chat.ComponentBuilder; +-import net.md_5.bungee.api.chat.HoverEvent; +-import net.md_5.bungee.api.config.ServerInfo; +-import net.md_5.bungee.api.connection.ProxiedPlayer; +-import net.md_5.bungee.api.event.ServerConnectEvent; +-import net.md_5.bungee.api.plugin.Command; +-import net.md_5.bungee.api.plugin.TabExecutor; +- +-public class CommandSend extends Command implements TabExecutor +-{ +- +- protected static class SendCallback +- { +- +- private final Map> results = new HashMap<>(); +- private final CommandSender sender; +- private int count = 0; +- +- public SendCallback(CommandSender sender) +- { +- this.sender = sender; +- for ( ServerConnectRequest.Result result : ServerConnectRequest.Result.values() ) +- { +- results.put( result, new ArrayList() ); +- } +- } +- +- public void lastEntryDone() +- { +- sender.sendMessage( ChatColor.GREEN.toString() + ChatColor.BOLD + "Send Results:" ); +- for ( Map.Entry> entry : results.entrySet() ) +- { +- ComponentBuilder builder = new ComponentBuilder( "" ); +- if ( !entry.getValue().isEmpty() ) +- { +- builder.event( new HoverEvent( HoverEvent.Action.SHOW_TEXT, +- new ComponentBuilder( Joiner.on( ", " ).join( entry.getValue() ) ).color( ChatColor.YELLOW ).create() ) ); +- } +- builder.append( entry.getKey().name() + ": " ).color( ChatColor.GREEN ); +- builder.append( "" + entry.getValue().size() ).bold( true ); +- sender.sendMessage( builder.create() ); +- } +- } +- +- public static class Entry implements Callback +- { +- +- private final SendCallback callback; +- private final ProxiedPlayer player; +- private final ServerInfo target; +- +- public Entry(SendCallback callback, ProxiedPlayer player, ServerInfo target) +- { +- this.callback = callback; +- this.player = player; +- this.target = target; +- this.callback.count++; +- } +- +- @Override +- public void done(ServerConnectRequest.Result result, Throwable error) +- { +- callback.results.get( result ).add( player.getName() ); +- if ( result == ServerConnectRequest.Result.SUCCESS ) +- { +- player.sendMessage( ProxyServer.getInstance().getTranslation( "you_got_summoned", target.getName(), callback.sender.getName() ) ); +- } +- +- if ( --callback.count == 0 ) +- { +- callback.lastEntryDone(); +- } +- } +- } +- } +- +- public CommandSend() +- { +- super( "send", "bungeecord.command.send" ); +- } +- +- @Override +- public void execute(CommandSender sender, String[] args) +- { +- if ( args.length != 2 ) +- { +- sender.sendMessage( ProxyServer.getInstance().getTranslation( "send_cmd_usage" ) ); +- return; +- } +- ServerInfo server = ProxyServer.getInstance().getServerInfo( args[1] ); +- if ( server == null ) +- { +- sender.sendMessage( ProxyServer.getInstance().getTranslation( "no_server" ) ); +- return; +- } +- +- List targets; +- if ( args[0].equalsIgnoreCase( "all" ) ) +- { +- targets = new ArrayList<>( ProxyServer.getInstance().getPlayers() ); +- } else if ( args[0].equalsIgnoreCase( "current" ) ) +- { +- if ( !( sender instanceof ProxiedPlayer ) ) +- { +- sender.sendMessage( ProxyServer.getInstance().getTranslation( "player_only" ) ); +- return; +- } +- ProxiedPlayer player = (ProxiedPlayer) sender; +- targets = new ArrayList<>( player.getServer().getInfo().getPlayers() ); +- } else +- { +- // If we use a server name, send the entire server. This takes priority over players. +- ServerInfo serverTarget = ProxyServer.getInstance().getServerInfo( args[0] ); +- if ( serverTarget != null ) +- { +- targets = new ArrayList<>( serverTarget.getPlayers() ); +- } else +- { +- ProxiedPlayer player = ProxyServer.getInstance().getPlayer( args[0] ); +- if ( player == null ) +- { +- sender.sendMessage( ProxyServer.getInstance().getTranslation( "user_not_online" ) ); +- return; +- } +- targets = Collections.singletonList( player ); +- } +- } +- +- final SendCallback callback = new SendCallback( sender ); +- for ( ProxiedPlayer player : targets ) +- { +- ServerConnectRequest request = ServerConnectRequest.builder() +- .target( server ) +- .reason( ServerConnectEvent.Reason.COMMAND ) +- .callback( new SendCallback.Entry( callback, player, server ) ) +- .build(); +- player.connect( request ); +- } +- +- sender.sendMessage( ChatColor.DARK_GREEN + "Attempting to send " + targets.size() + " players to " + server.getName() ); +- } +- +- @Override +- public Iterable onTabComplete(CommandSender sender, String[] args) +- { +- if ( args.length > 2 || args.length == 0 ) +- { +- return ImmutableSet.of(); +- } +- +- Set matches = new HashSet<>(); +- if ( args.length == 1 ) +- { +- String search = args[0].toLowerCase( Locale.ROOT ); +- for ( ProxiedPlayer player : ProxyServer.getInstance().getPlayers() ) +- { +- if ( player.getName().toLowerCase( Locale.ROOT ).startsWith( search ) ) +- { +- matches.add( player.getName() ); +- } +- } +- if ( "all".startsWith( search ) ) +- { +- matches.add( "all" ); +- } +- if ( "current".startsWith( search ) ) +- { +- matches.add( "current" ); +- } +- } else +- { +- String search = args[1].toLowerCase( Locale.ROOT ); +- for ( String server : ProxyServer.getInstance().getServers().keySet() ) +- { +- if ( server.toLowerCase( Locale.ROOT ).startsWith( search ) ) +- { +- matches.add( server ); +- } +- } +- } +- return matches; +- } +-} +diff --git a/module/cmd-send/src/main/java/net/md_5/bungee/module/cmd/send/PluginSend.java b/module/cmd-send/src/main/java/net/md_5/bungee/module/cmd/send/PluginSend.java +deleted file mode 100644 +index 4d4cf822..00000000 +--- a/module/cmd-send/src/main/java/net/md_5/bungee/module/cmd/send/PluginSend.java ++++ /dev/null +@@ -1,13 +0,0 @@ +-package net.md_5.bungee.module.cmd.send; +- +-import net.md_5.bungee.api.plugin.Plugin; +- +-public class PluginSend extends Plugin +-{ +- +- @Override +- public void onEnable() +- { +- getProxy().getPluginManager().registerCommand( this, new CommandSend() ); +- } +-} +diff --git a/module/cmd-send/src/main/resources/plugin.yml b/module/cmd-send/src/main/resources/plugin.yml +deleted file mode 100644 +index a613e78b..00000000 +--- a/module/cmd-send/src/main/resources/plugin.yml ++++ /dev/null +@@ -1,5 +0,0 @@ +-name: ${project.name} +-main: net.md_5.bungee.module.cmd.send.PluginSend +-version: ${describe} +-description: ${project.description} +-author: ${module.author} +diff --git a/module/cmd-server/nb-configuration.xml b/module/cmd-server/nb-configuration.xml +deleted file mode 100644 +index 7e465924..00000000 +--- a/module/cmd-server/nb-configuration.xml ++++ /dev/null +@@ -1,31 +0,0 @@ +- +- +- +- +- +- project +- NEW_LINE +- NEW_LINE +- NEW_LINE +- true +- true +- true +- true +- true +- true +- true +- true +- true +- true +- +- +diff --git a/module/cmd-server/pom.xml b/module/cmd-server/pom.xml +deleted file mode 100644 +index 3b2c4952..00000000 +--- a/module/cmd-server/pom.xml ++++ /dev/null +@@ -1,20 +0,0 @@ +- +- +- 4.0.0 +- +- +- io.github.waterfallmc +- waterfall-module +- 1.17-R0.1-SNAPSHOT +- ../pom.xml +- +- +- io.github.waterfallmc +- waterfall-module-cmd-server +- 1.17-R0.1-SNAPSHOT +- jar +- +- cmd_server +- Provides the server command +- +diff --git a/module/cmd-server/src/main/java/net/md_5/bungee/module/cmd/server/CommandServer.java b/module/cmd-server/src/main/java/net/md_5/bungee/module/cmd/server/CommandServer.java +deleted file mode 100644 +index 698b420f..00000000 +--- a/module/cmd-server/src/main/java/net/md_5/bungee/module/cmd/server/CommandServer.java ++++ /dev/null +@@ -1,104 +0,0 @@ +-package net.md_5.bungee.module.cmd.server; +- +-import com.google.common.base.Function; +-import com.google.common.base.Predicate; +-import com.google.common.collect.Iterables; +-import java.util.Collections; +-import java.util.Locale; +-import java.util.Map; +-import net.md_5.bungee.api.CommandSender; +-import net.md_5.bungee.api.ProxyServer; +-import net.md_5.bungee.api.chat.ClickEvent; +-import net.md_5.bungee.api.chat.ComponentBuilder; +-import net.md_5.bungee.api.chat.HoverEvent; +-import net.md_5.bungee.api.chat.TextComponent; +-import net.md_5.bungee.api.config.ServerInfo; +-import net.md_5.bungee.api.connection.ProxiedPlayer; +-import net.md_5.bungee.api.event.ServerConnectEvent; +-import net.md_5.bungee.api.plugin.Command; +-import net.md_5.bungee.api.plugin.TabExecutor; +- +-/** +- * Command to list and switch a player between available servers. +- */ +-public class CommandServer extends Command implements TabExecutor +-{ +- +- public CommandServer() +- { +- super( "server", "bungeecord.command.server" ); +- } +- +- @Override +- public void execute(CommandSender sender, String[] args) +- { +- Map servers = ProxyServer.getInstance().getServers(); +- if ( args.length == 0 ) +- { +- if ( sender instanceof ProxiedPlayer ) +- { +- sender.sendMessage( ProxyServer.getInstance().getTranslation( "current_server", ( (ProxiedPlayer) sender ).getServer().getInfo().getName() ) ); +- } +- +- ComponentBuilder serverList = new ComponentBuilder().appendLegacy( ProxyServer.getInstance().getTranslation( "server_list" ) ); +- boolean first = true; +- for ( ServerInfo server : servers.values() ) +- { +- if ( server.canAccess( sender ) ) +- { +- TextComponent serverTextComponent = new TextComponent( first ? server.getName() : ", " + server.getName() ); +- int count = server.getPlayers().size(); +- serverTextComponent.setHoverEvent( new HoverEvent( +- HoverEvent.Action.SHOW_TEXT, +- new ComponentBuilder( count + ( count == 1 ? " player" : " players" ) + "\n" ).appendLegacy( ProxyServer.getInstance().getTranslation( "click_to_connect" ) ).create() ) +- ); +- serverTextComponent.setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, "/server " + server.getName() ) ); +- serverList.append( serverTextComponent ); +- first = false; +- } +- } +- sender.sendMessage( serverList.create() ); +- } else +- { +- if ( !( sender instanceof ProxiedPlayer ) ) +- { +- return; +- } +- ProxiedPlayer player = (ProxiedPlayer) sender; +- +- ServerInfo server = servers.get( args[0] ); +- if ( server == null ) +- { +- player.sendMessage( ProxyServer.getInstance().getTranslation( "no_server" ) ); +- } else if ( !server.canAccess( player ) ) +- { +- player.sendMessage( ProxyServer.getInstance().getTranslation( "no_server_permission" ) ); +- } else +- { +- player.connect( server, ServerConnectEvent.Reason.COMMAND ); +- } +- } +- } +- +- @Override +- public Iterable onTabComplete(final CommandSender sender, final String[] args) +- { +- return ( args.length > 1 ) ? Collections.EMPTY_LIST : Iterables.transform( Iterables.filter( ProxyServer.getInstance().getServersCopy().values(), new Predicate() // Waterfall: use #getServersCopy() +- { +- private final String lower = ( args.length == 0 ) ? "" : args[0].toLowerCase( Locale.ROOT ); +- +- @Override +- public boolean apply(ServerInfo input) +- { +- return input.getName().toLowerCase( Locale.ROOT ).startsWith( lower ) && input.canAccess( sender ); +- } +- } ), new Function() +- { +- @Override +- public String apply(ServerInfo input) +- { +- return input.getName(); +- } +- } ); +- } +-} +diff --git a/module/cmd-server/src/main/java/net/md_5/bungee/module/cmd/server/PluginServer.java b/module/cmd-server/src/main/java/net/md_5/bungee/module/cmd/server/PluginServer.java +deleted file mode 100644 +index 4aaae7ec..00000000 +--- a/module/cmd-server/src/main/java/net/md_5/bungee/module/cmd/server/PluginServer.java ++++ /dev/null +@@ -1,13 +0,0 @@ +-package net.md_5.bungee.module.cmd.server; +- +-import net.md_5.bungee.api.plugin.Plugin; +- +-public class PluginServer extends Plugin +-{ +- +- @Override +- public void onEnable() +- { +- getProxy().getPluginManager().registerCommand( this, new CommandServer() ); +- } +-} +diff --git a/module/cmd-server/src/main/resources/plugin.yml b/module/cmd-server/src/main/resources/plugin.yml +deleted file mode 100644 +index 006f3e3f..00000000 +--- a/module/cmd-server/src/main/resources/plugin.yml ++++ /dev/null +@@ -1,5 +0,0 @@ +-name: ${project.name} +-main: net.md_5.bungee.module.cmd.server.PluginServer +-version: ${describe} +-description: ${project.description} +-author: ${module.author} +diff --git a/module/pom.xml b/module/pom.xml +deleted file mode 100644 +index 0ef98d58..00000000 +--- a/module/pom.xml ++++ /dev/null +@@ -1,54 +0,0 @@ +- +- +- 4.0.0 +- +- +- io.github.waterfallmc +- waterfall-parent +- 1.17-R0.1-SNAPSHOT +- ../pom.xml +- +- +- io.github.waterfallmc +- waterfall-module +- 1.17-R0.1-SNAPSHOT +- pom +- +- Waterfall Modules +- Parent project for all Waterfall modules. +- +- +- cmd-alert +- cmd-find +- cmd-list +- cmd-send +- cmd-server +- reconnect-yaml +- +- +- +- WaterfallMC +- true +- true +- +- +- +- +- io.github.waterfallmc +- waterfall-api +- ${project.version} +- compile +- +- +- +- +- ${project.name} +- +- +- true +- ${basedir}/src/main/resources +- +- +- +- +diff --git a/module/reconnect-yaml/nb-configuration.xml b/module/reconnect-yaml/nb-configuration.xml +deleted file mode 100644 +index 7e465924..00000000 +--- a/module/reconnect-yaml/nb-configuration.xml ++++ /dev/null +@@ -1,31 +0,0 @@ +- +- +- +- +- +- project +- NEW_LINE +- NEW_LINE +- NEW_LINE +- true +- true +- true +- true +- true +- true +- true +- true +- true +- true +- +- +diff --git a/module/reconnect-yaml/pom.xml b/module/reconnect-yaml/pom.xml +deleted file mode 100644 +index b88398cf..00000000 +--- a/module/reconnect-yaml/pom.xml ++++ /dev/null +@@ -1,20 +0,0 @@ +- +- +- 4.0.0 +- +- +- io.github.waterfallmc +- waterfall-module +- 1.17-R0.1-SNAPSHOT +- ../pom.xml +- +- +- io.github.waterfallmc +- waterfall-module-reconnect-yaml +- 1.17-R0.1-SNAPSHOT +- jar +- +- reconnect_yaml +- Provides reconnect location functionality in locations.yml +- +diff --git a/module/reconnect-yaml/src/main/java/net/md_5/bungee/module/reconnect/yaml/PluginYaml.java b/module/reconnect-yaml/src/main/java/net/md_5/bungee/module/reconnect/yaml/PluginYaml.java +deleted file mode 100644 +index 0d77ce2a..00000000 +--- a/module/reconnect-yaml/src/main/java/net/md_5/bungee/module/reconnect/yaml/PluginYaml.java ++++ /dev/null +@@ -1,22 +0,0 @@ +-package net.md_5.bungee.module.reconnect.yaml; +- +-import net.md_5.bungee.api.config.ListenerInfo; +-import net.md_5.bungee.api.plugin.Plugin; +- +-public class PluginYaml extends Plugin +-{ +- +- @Override +- public void onEnable() +- { +- // TODO: Abstract this for other reconnect modules +- for ( ListenerInfo info : getProxy().getConfig().getListeners() ) +- { +- if ( !info.isForceDefault() && getProxy().getReconnectHandler() == null ) +- { +- getProxy().setReconnectHandler( new YamlReconnectHandler() ); +- break; +- } +- } +- } +-} +diff --git a/module/reconnect-yaml/src/main/java/net/md_5/bungee/module/reconnect/yaml/YamlReconnectHandler.java b/module/reconnect-yaml/src/main/java/net/md_5/bungee/module/reconnect/yaml/YamlReconnectHandler.java +deleted file mode 100644 +index 3a514a76..00000000 +--- a/module/reconnect-yaml/src/main/java/net/md_5/bungee/module/reconnect/yaml/YamlReconnectHandler.java ++++ /dev/null +@@ -1,115 +0,0 @@ +-package net.md_5.bungee.module.reconnect.yaml; +- +-import java.io.File; +-import java.io.FileReader; +-import java.io.FileWriter; +-import java.io.IOException; +-import java.net.InetSocketAddress; +-import java.util.HashMap; +-import java.util.Map; +-import java.util.concurrent.locks.ReadWriteLock; +-import java.util.concurrent.locks.ReentrantReadWriteLock; +-import java.util.logging.Level; +-import net.md_5.bungee.api.AbstractReconnectHandler; +-import net.md_5.bungee.api.ProxyServer; +-import net.md_5.bungee.api.config.ServerInfo; +-import net.md_5.bungee.api.connection.ProxiedPlayer; +-import net.md_5.bungee.util.CaseInsensitiveMap; +-import org.yaml.snakeyaml.Yaml; +- +-public class YamlReconnectHandler extends AbstractReconnectHandler +-{ +- +- private final Yaml yaml = new Yaml(); +- private final File file = new File( "locations.yml" ); +- private final ReadWriteLock lock = new ReentrantReadWriteLock(); +- /*========================================================================*/ +- private CaseInsensitiveMap data; +- +- @SuppressWarnings("unchecked") +- public YamlReconnectHandler() +- { +- try +- { +- file.createNewFile(); +- try ( FileReader rd = new FileReader( file ) ) +- { +- Map map = yaml.loadAs( rd, Map.class ); +- if ( map != null ) +- { +- data = new CaseInsensitiveMap<>( map ); +- } +- } +- } catch ( Exception ex ) +- { +- file.renameTo( new File( "locations.yml.old" ) ); +- ProxyServer.getInstance().getLogger().log( Level.WARNING, "Could not load reconnect locations, resetting them" ); +- } +- +- if ( data == null ) +- { +- data = new CaseInsensitiveMap<>(); +- } +- } +- +- @Override +- protected ServerInfo getStoredServer(ProxiedPlayer player) +- { +- ServerInfo server = null; +- lock.readLock().lock(); +- try +- { +- server = ProxyServer.getInstance().getServerInfo( data.get( key( player ) ) ); +- } finally +- { +- lock.readLock().unlock(); +- } +- return server; +- } +- +- @Override +- public void setServer(ProxiedPlayer player) +- { +- lock.writeLock().lock(); +- try +- { +- data.put( key( player ), ( player.getReconnectServer() != null ) ? player.getReconnectServer().getName() : player.getServer().getInfo().getName() ); +- } finally +- { +- lock.writeLock().unlock(); +- } +- } +- +- private String key(ProxiedPlayer player) +- { +- InetSocketAddress host = player.getPendingConnection().getVirtualHost(); +- return player.getName() + ";" + host.getHostString() + ":" + host.getPort(); +- } +- +- @Override +- public void save() +- { +- Map copy = new HashMap<>(); +- lock.readLock().lock(); +- try +- { +- copy.putAll( data ); +- } finally +- { +- lock.readLock().unlock(); +- } +- +- try ( FileWriter wr = new FileWriter( file ) ) +- { +- yaml.dump( copy, wr ); +- } catch ( IOException ex ) +- { +- ProxyServer.getInstance().getLogger().log( Level.WARNING, "Could not save reconnect locations", ex ); +- } +- } +- +- @Override +- public void close() +- { +- } +-} +diff --git a/module/reconnect-yaml/src/main/resources/plugin.yml b/module/reconnect-yaml/src/main/resources/plugin.yml +deleted file mode 100644 +index 451e3c61..00000000 +--- a/module/reconnect-yaml/src/main/resources/plugin.yml ++++ /dev/null +@@ -1,5 +0,0 @@ +-name: ${project.name} +-main: net.md_5.bungee.module.reconnect.yaml.PluginYaml +-version: ${describe} +-description: ${project.description} +-author: ${module.author} +diff --git a/pom.xml b/pom.xml +index 5b701203..fd94fb4b 100644 +--- a/pom.xml ++++ b/pom.xml +@@ -50,7 +50,6 @@ + event + log + log4j +- module + protocol + proxy + query +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 07d74c67..cffe7a8d 100644 +--- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java ++++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java +@@ -85,7 +85,6 @@ import net.md_5.bungee.compress.CompressFactory; + import net.md_5.bungee.conf.Configuration; + import net.md_5.bungee.conf.YamlConfig; + import net.md_5.bungee.forge.ForgeConstants; +-import net.md_5.bungee.module.ModuleManager; + import net.md_5.bungee.netty.PipelineUtils; + import net.md_5.bungee.protocol.DefinedPacket; + import net.md_5.bungee.protocol.ProtocolConstants; +@@ -172,7 +171,6 @@ public class BungeeCord extends ProxyServer + .registerTypeAdapter( Favicon.class, Favicon.getFaviconTypeAdapter() ).create(); + @Getter + private ConnectionThrottle connectionThrottle; +- private final ModuleManager moduleManager = new ModuleManager(); + + { + // TODO: Proper fallback when we interface the manager +@@ -268,10 +266,6 @@ public class BungeeCord extends ProxyServer + 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 ); +- pluginManager.detectPlugins( moduleDirectory ); +- + pluginsFolder.mkdir(); + pluginManager.detectPlugins( pluginsFolder ); + +diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeCordLauncher.java b/proxy/src/main/java/net/md_5/bungee/BungeeCordLauncher.java +index 0db3d76a..0603df48 100644 +--- a/proxy/src/main/java/net/md_5/bungee/BungeeCordLauncher.java ++++ b/proxy/src/main/java/net/md_5/bungee/BungeeCordLauncher.java +@@ -51,6 +51,7 @@ public class BungeeCordLauncher + + Calendar deadline = Calendar.getInstance(); + deadline.add( Calendar.WEEK_OF_YEAR, -8 ); ++ /* PandaCord - we are dealing with that differently + if ( buildDate.before( deadline.getTime() ) ) + { + System.err.println( "*** Hey! This build is potentially outdated :( ***" ); +@@ -59,6 +60,7 @@ public class BungeeCordLauncher + System.err.println( "*** Server will start in 10 seconds ***" ); + Thread.sleep( TimeUnit.SECONDS.toMillis( 10 ) ); + } ++ */ + } + + BungeeCord bungee = new BungeeCord(); +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 +deleted file mode 100644 +index 338c30d3..00000000 +--- a/proxy/src/main/java/net/md_5/bungee/module/JenkinsModuleSource.java ++++ /dev/null +@@ -1,42 +0,0 @@ +-package net.md_5.bungee.module; +- +-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; +- +-@Data +-public class JenkinsModuleSource implements ModuleSource +-{ +- +- @Override +- public void retrieve(ModuleSpec module, ModuleVersion version) +- { +- System.out.println( "Attempting to Jenkins download module " + module.getName() + " v" + version.getBuild() ); +- try +- { +- final String url = String.format( +- "https://papermc.io/api/v2/projects/%1$s/versions/%2$s/builds/%3$s/downloads/%4$s-%2$s-%3$s.jar", +- "waterfall", +- net.md_5.bungee.api.ProxyServer.getInstance().getVersion().split(":")[2].split("-")[0], +- version.getBuild(), +- module.getName() +- ); +- URL website = new URL( url ); +- 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.copy( con.getInputStream(), module.getFile().toPath(), StandardCopyOption.REPLACE_EXISTING ); +- System.out.println( "Download complete" ); +- } catch ( IOException ex ) +- { +- System.out.println( "Failed to download: " + Util.exception( ex ) ); +- } +- } +-} +diff --git a/proxy/src/main/java/net/md_5/bungee/module/ModuleManager.java b/proxy/src/main/java/net/md_5/bungee/module/ModuleManager.java +deleted file mode 100644 +index d3abee44..00000000 +--- a/proxy/src/main/java/net/md_5/bungee/module/ModuleManager.java ++++ /dev/null +@@ -1,155 +0,0 @@ +-package net.md_5.bungee.module; +- +-import com.google.common.base.Preconditions; +-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +-import java.io.File; +-import java.io.FileInputStream; +-import java.io.FileWriter; +-import java.io.InputStream; +-import java.net.URI; +-import java.util.ArrayList; +-import java.util.Collection; +-import java.util.HashMap; +-import java.util.List; +-import java.util.Map; +-import java.util.jar.JarEntry; +-import java.util.jar.JarFile; +-import java.util.logging.Level; +-import net.md_5.bungee.api.ProxyServer; +-import net.md_5.bungee.api.plugin.PluginDescription; +-import net.md_5.bungee.util.CaseInsensitiveMap; +-import org.yaml.snakeyaml.DumperOptions; +-import org.yaml.snakeyaml.Yaml; +- +-public class ModuleManager +-{ +- +- private final Map knownSources = new HashMap<>(); +- +- public ModuleManager() +- { +- knownSources.put( "jenkins", new JenkinsModuleSource() ); +- } +- +- // CHECKSTYLE:OFF +- @SuppressFBWarnings( +- { +- "SF_SWITCH_FALLTHROUGH", "SF_SWITCH_NO_DEFAULT" +- }) +- // CHECKSTYLE:ON +- public void load(ProxyServer proxy, File moduleDirectory) throws Exception +- { +- moduleDirectory.mkdir(); +- +- ModuleVersion bungeeVersion = ModuleVersion.parse( proxy.getVersion() ); +- if ( bungeeVersion == null ) +- { +- proxy.getLogger().warning( "Couldn't detect bungee version. Custom build?" ); // Waterfall - Use logger +- return; +- } +- +- List modules = new ArrayList<>(); +- File configFile = new File( "modules.yml" ); +- // Start Yaml +- DumperOptions options = new DumperOptions(); +- options.setDefaultFlowStyle( DumperOptions.FlowStyle.BLOCK ); +- Yaml yaml = new Yaml( options ); +- +- Map config; +- +- configFile.createNewFile(); +- try ( InputStream is = new FileInputStream( configFile ) ) +- { +- config = (Map) yaml.load( is ); +- } +- +- if ( config == null ) +- { +- config = new CaseInsensitiveMap<>(); +- } else +- { +- config = new CaseInsensitiveMap<>( config ); +- } +- // End yaml +- +- List defaults = new ArrayList<>(); +- Object readModules = config.get( "modules" ); +- if ( readModules != null ) +- { +- defaults.addAll( (Collection) readModules ); +- } +- int version = ( config.containsKey( "version" ) ) ? (int) config.get( "version" ) : 0; +- switch ( version ) +- { +- case 0: +- defaults.add( "jenkins://cmd_alert" ); +- defaults.add( "jenkins://cmd_find" ); +- defaults.add( "jenkins://cmd_list" ); +- defaults.add( "jenkins://cmd_send" ); +- defaults.add( "jenkins://cmd_server" ); +- case 1: +- defaults.add( "jenkins://reconnect_yaml" ); +- } +- config.put( "modules", defaults ); +- config.put( "version", 2 ); +- +- try ( FileWriter wr = new FileWriter( configFile ) ) +- { +- yaml.dump( config, wr ); +- } +- +- for ( String s : (List) config.get( "modules" ) ) +- { +- URI uri = new URI( s ); +- +- ModuleSource source = knownSources.get( uri.getScheme() ); +- if ( source == null ) +- { +- System.out.println( "Unknown module source: " + s ); +- continue; +- } +- String name = uri.getAuthority(); +- if ( name == null ) +- { +- System.out.println( "Unknown module host: " + s ); +- continue; +- } +- +- ModuleSpec spec = new ModuleSpec( name, new File( moduleDirectory, name + ".jar" ), source ); +- modules.add( spec ); +- System.out.println( "Discovered module: " + spec ); +- } +- +- for ( ModuleSpec module : modules ) +- { +- ModuleVersion moduleVersion = ( module.getFile().exists() ) ? getVersion( module.getFile() ) : null; +- +- if ( !bungeeVersion.equals( moduleVersion ) ) +- { +- System.out.println( "Attempting to update plugin from " + moduleVersion + " to " + bungeeVersion ); +- module.getProvider().retrieve( module, bungeeVersion ); +- } +- } +- } +- +- @SuppressFBWarnings("REC_CATCH_EXCEPTION") +- private ModuleVersion getVersion(File file) +- { +- try ( JarFile jar = new JarFile( file ) ) +- { +- JarEntry pdf = jar.getJarEntry( "plugin.yml" ); +- Preconditions.checkNotNull( pdf, "Plugin must have a plugin.yml" ); +- +- try ( InputStream in = jar.getInputStream( pdf ) ) +- { +- PluginDescription desc = new Yaml().loadAs( in, PluginDescription.class ); +- return ModuleVersion.parse( desc.getVersion() ); +- } +- } catch ( Exception ex ) +- { +- ProxyServer.getInstance().getLogger().log( Level.WARNING, "Could not check module from file " + file, ex ); +- } +- +- return null; +- } +-} +diff --git a/proxy/src/main/java/net/md_5/bungee/module/ModuleSource.java b/proxy/src/main/java/net/md_5/bungee/module/ModuleSource.java +deleted file mode 100644 +index 09f5624c..00000000 +--- a/proxy/src/main/java/net/md_5/bungee/module/ModuleSource.java ++++ /dev/null +@@ -1,7 +0,0 @@ +-package net.md_5.bungee.module; +- +-interface ModuleSource +-{ +- +- void retrieve(ModuleSpec module, ModuleVersion version); +-} +diff --git a/proxy/src/main/java/net/md_5/bungee/module/ModuleSpec.java b/proxy/src/main/java/net/md_5/bungee/module/ModuleSpec.java +deleted file mode 100644 +index ebf6cf67..00000000 +--- a/proxy/src/main/java/net/md_5/bungee/module/ModuleSpec.java ++++ /dev/null +@@ -1,13 +0,0 @@ +-package net.md_5.bungee.module; +- +-import java.io.File; +-import lombok.Data; +- +-@Data +-public class ModuleSpec +-{ +- +- private final String name; +- private final File file; +- private final ModuleSource provider; +-} +diff --git a/proxy/src/main/java/net/md_5/bungee/module/ModuleVersion.java b/proxy/src/main/java/net/md_5/bungee/module/ModuleVersion.java +deleted file mode 100644 +index d52b8106..00000000 +--- a/proxy/src/main/java/net/md_5/bungee/module/ModuleVersion.java ++++ /dev/null +@@ -1,35 +0,0 @@ +-package net.md_5.bungee.module; +- +-import lombok.AccessLevel; +-import lombok.Data; +-import lombok.RequiredArgsConstructor; +- +-@Data +-@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +-public class ModuleVersion +-{ +- +- private final String build; +- private final String git; +- +- public static ModuleVersion parse(String version) +- { +- int lastColon = version.lastIndexOf( ':' ); +- int secondLastColon = version.lastIndexOf( ':', lastColon - 1 ); +- +- if ( lastColon == -1 || secondLastColon == -1 ) +- { +- return null; +- } +- +- String buildNumber = version.substring( lastColon + 1, version.length() ); +- String gitCommit = version.substring( secondLastColon + 1, lastColon ).replaceAll( "\"", "" ); +- +- if ( "unknown".equals( buildNumber ) || "unknown".equals( gitCommit ) ) +- { +- return null; +- } +- +- return new ModuleVersion( buildNumber, gitCommit ); +- } +-} +-- +2.32.0.windows.2 + diff --git a/Waterfall-Proxy-Patches/0003-Multi-session-with-same-Minecraft-account-with-speci.patch b/Waterfall-Proxy-Patches/0003-Multi-session-with-same-Minecraft-account-with-speci.patch new file mode 100644 index 0000000..582886c --- /dev/null +++ b/Waterfall-Proxy-Patches/0003-Multi-session-with-same-Minecraft-account-with-speci.patch @@ -0,0 +1,150 @@ +From dbb2441936118788203dc43a4c4582ee71e017c8 Mon Sep 17 00:00:00 2001 +From: Marc Baloup +Date: Sun, 2 Oct 2016 07:54:16 +0200 +Subject: [PATCH] Multi-session with same Minecraft account with specific + permission + +Players with permission bungeecord.multiple_connect can have multiples +connections with the same Minecraft account. To manage UUID and Name conflict, +an increment value is appended to the player name, and the uuid used is the +offline one. So be carefull: Spigot servers and plugins will considers 2 +players from the same account like if they were 2 different MC account. + +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 0f1716c0..b07d2e06 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 +@@ -110,6 +110,17 @@ public class InitialHandler extends PacketHandler implements PendingConnection + @Getter + private String extraDataInHandshake = ""; + ++ @Getter ++ private boolean duplication = false; ++ ++ @Getter ++ private String realName = null; ++ ++ @Getter ++ private UUID realId = null; ++ ++ private String gameName = null; ++ + @Override + public boolean shouldHandle(PacketWrapper packet) throws Exception + { +@@ -364,6 +375,8 @@ public class InitialHandler extends PacketHandler implements PendingConnection + { + Preconditions.checkState( thisState == State.USERNAME, "Not expecting USERNAME" ); + this.loginRequest = loginRequest; ++ this.realName = loginRequest.getData(); ++ this.gameName = this.realName; + + if ( getName().contains( " " ) ) + { +@@ -378,9 +391,21 @@ public class InitialHandler extends PacketHandler implements PendingConnection + return; + } + ++ ProxiedPlayer existingPlayer = bungee.getPlayer( getName() ); ++ ++ duplication = ( existingPlayer != null && existingPlayer.hasPermission( "bungeecord.multiple_connect" ) ); ++ ++ if ( duplication ) ++ { ++ gameName = generateDuplicatedName( realName ); ++ this.loginRequest.setData( gameName ); // gameName transmitted to Spigot server ++ } ++ ++ offlineId = UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + gameName ).getBytes( Charsets.UTF_8 ) ); ++ + // If offline mode and they are already on, don't allow connect + // We can just check by UUID here as names are based on UUID +- if ( !isOnlineMode() && bungee.getPlayer( getUniqueId() ) != null ) ++ if ( !isOnlineMode() && bungee.getPlayer( offlineId ) != null && !duplication ) + { + disconnect( bungee.getTranslation( "already_connected_proxy" ) ); + return; +@@ -435,7 +460,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection + BungeeCipher encrypt = EncryptionUtil.getCipher( true, sharedKey ); + ch.addBefore( PipelineUtils.FRAME_PREPENDER, PipelineUtils.ENCRYPT_HANDLER, new CipherEncoder( encrypt ) ); + +- String encName = URLEncoder.encode( InitialHandler.this.getName(), "UTF-8" ); ++ String encName = URLEncoder.encode( InitialHandler.this.realName, "UTF-8" ); + + MessageDigest sha = MessageDigest.getInstance( "SHA-1" ); + for ( byte[] bit : new byte[][] +@@ -461,8 +486,10 @@ public class InitialHandler extends PacketHandler implements PendingConnection + if ( obj != null && obj.getId() != null ) + { + loginProfile = obj; +- name = obj.getName(); +- uniqueId = Util.getUUID( obj.getId() ); ++ realName = obj.getName(); ++ realId = Util.getUUID( obj.getId() ); ++ if ( !duplication ) ++ uniqueId = realId; + finish(); + return; + } +@@ -470,7 +497,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection + } else + { + disconnect( bungee.getTranslation( "mojang_fail" ) ); +- bungee.getLogger().log( Level.SEVERE, "Error authenticating " + getName() + " with minecraft.net", error ); ++ bungee.getLogger().log( Level.SEVERE, "Error authenticating " + realName + " with minecraft.net", error ); + } + } + }; +@@ -480,6 +507,12 @@ public class InitialHandler extends PacketHandler implements PendingConnection + + private void finish() + { ++ ++ if ( uniqueId == null ) ++ { ++ uniqueId = offlineId; ++ } ++ + if ( isOnlineMode() ) + { + // Check for multiple connections +@@ -510,12 +543,6 @@ public class InitialHandler extends PacketHandler implements PendingConnection + + } + +- offlineId = UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + getName() ).getBytes( Charsets.UTF_8 ) ); +- if ( uniqueId == null ) +- { +- uniqueId = offlineId; +- } +- + Callback complete = new Callback() + { + @Override +@@ -615,7 +642,22 @@ public class InitialHandler extends PacketHandler implements PendingConnection + @Override + public String getName() + { +- return ( name != null ) ? name : ( loginRequest == null ) ? null : loginRequest.getData(); ++ return gameName; ++ } ++ ++ private String generateDuplicatedName(String original) ++ { ++ String newName; ++ int i = 0; ++ do ++ { ++ i++; ++ String strCount = Integer.toString( i ); ++ if ( original.length() > 16 - strCount.length() ) ++ original = original.substring( 0, 16 - strCount.length() ); ++ newName = original + i; ++ } while ( bungee.getPlayer( newName ) != null ); ++ return newName; + } + + @Override +-- +2.32.0.windows.2 + diff --git a/Waterfall-Proxy-Patches/0004-Inproved-proxy-and-server-branding-displayed-in-F3.patch b/Waterfall-Proxy-Patches/0004-Inproved-proxy-and-server-branding-displayed-in-F3.patch new file mode 100644 index 0000000..1b11ca0 --- /dev/null +++ b/Waterfall-Proxy-Patches/0004-Inproved-proxy-and-server-branding-displayed-in-F3.patch @@ -0,0 +1,43 @@ +From e814af4ff1a9b377eb2642d4d317407072f373de Mon Sep 17 00:00:00 2001 +From: Marc Baloup +Date: Tue, 29 Oct 2019 23:43:32 +0100 +Subject: [PATCH] Inproved proxy and server branding (displayed in F3) + + +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 cffe7a8d..51207270 100644 +--- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java ++++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java +@@ -51,6 +51,7 @@ import java.util.logging.Logger; + import lombok.Getter; + import lombok.Setter; + import lombok.Synchronized; ++import net.md_5.bungee.api.ChatColor; + import net.md_5.bungee.api.CommandSender; + import net.md_5.bungee.api.Favicon; + import net.md_5.bungee.api.ProxyServer; +@@ -533,7 +534,7 @@ public class BungeeCord extends ProxyServer + @Override + public String getName() + { +- return "Waterfall"; ++ return ChatColor.YELLOW + "[[" + ChatColor.GREEN + ChatColor.BOLD + "Pandacube" + ChatColor.YELLOW + "]]" + ChatColor.RESET; + } + + @Override +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 9e180c30..72538ddb 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 +@@ -293,7 +293,7 @@ public class DownstreamBridge extends PacketHandler + Preconditions.checkState( !serverBrand.contains( bungee.getName() ), "Cannot connect proxy to itself!" ); + + brand = ByteBufAllocator.DEFAULT.heapBuffer(); +- DefinedPacket.writeString( bungee.getName() + " <- " + serverBrand, brand ); // Waterfall ++ DefinedPacket.writeString( bungee.getName() + " <- " + server.getInfo().getName() + " (" + serverBrand + ")", brand ); // Waterfall + pluginMessage.setData( brand ); + brand.release(); + // changes in the packet are ignored so we need to send it manually +-- +2.32.0.windows.2 + diff --git a/Waterfall-Proxy-Patches/0005-Add-CommandsDeclareEvent-to-declare-commands-with-br.patch b/Waterfall-Proxy-Patches/0005-Add-CommandsDeclareEvent-to-declare-commands-with-br.patch new file mode 100644 index 0000000..435e0e9 --- /dev/null +++ b/Waterfall-Proxy-Patches/0005-Add-CommandsDeclareEvent-to-declare-commands-with-br.patch @@ -0,0 +1,1048 @@ +From 676b064e31a857821c9a08c6329a148b3739fff4 Mon Sep 17 00:00:00 2001 +From: Marc Baloup +Date: Mon, 8 Jun 2020 00:51:21 +0200 +Subject: [PATCH] Add CommandsDeclareEvent to declare commands with brigadier + API + + +diff --git a/api/src/main/java/net/md_5/bungee/api/event/CommandsDeclareEvent.java b/api/src/main/java/net/md_5/bungee/api/event/CommandsDeclareEvent.java +new file mode 100644 +index 00000000..ab96dd9b +--- /dev/null ++++ b/api/src/main/java/net/md_5/bungee/api/event/CommandsDeclareEvent.java +@@ -0,0 +1,157 @@ ++package net.md_5.bungee.api.event; ++ ++import com.mojang.brigadier.arguments.ArgumentType; ++import com.mojang.brigadier.arguments.IntegerArgumentType; ++import com.mojang.brigadier.arguments.StringArgumentType; ++import com.mojang.brigadier.builder.ArgumentBuilder; ++import com.mojang.brigadier.builder.RequiredArgumentBuilder; ++import com.mojang.brigadier.suggestion.SuggestionProvider; ++import com.mojang.brigadier.tree.CommandNode; ++import com.mojang.brigadier.tree.RootCommandNode; ++import lombok.AccessLevel; ++import lombok.Data; ++import lombok.EqualsAndHashCode; ++import lombok.Setter; ++import lombok.ToString; ++import net.md_5.bungee.api.CommandSender; ++import net.md_5.bungee.api.connection.Connection; ++import net.md_5.bungee.api.plugin.Command; ++import net.md_5.bungee.api.plugin.Plugin; ++import net.md_5.bungee.api.plugin.PluginManager; ++import net.md_5.bungee.api.plugin.TabExecutor; ++ ++/** ++ * Event called when a downstream server (on 1.13+) sends the command structure ++ * to a player, but before BungeeCord adds the dummy command nodes of ++ * registered commands. ++ *

++ * BungeeCord will not overwrite the modifications made by the listeners. ++ * ++ *

Usage example

++ * Here is a usage example of this event, to declare a command structure. ++ * This illustrates the commands /server and /send of Bungee. ++ *
++ * event.getRoot().addChild( LiteralArgumentBuilder.<CommandSender>literal( "server" )
++ *         .requires( sender -> sender.hasPermission( "bungeecord.command.server" ) )
++ *         .executes( a -> 0 )
++ *         .then( RequiredArgumentBuilder.argument( "serverName", StringArgumentType.greedyString() )
++ *                 .suggests( SuggestionRegistry.ASK_SERVER )
++ *         )
++ *         .build()
++ * );
++ * event.getRoot().addChild( LiteralArgumentBuilder.<CommandSender>literal( "send" )
++ *         .requires( sender -> sender.hasPermission( "bungeecord.command.send" ) )
++ *         .then( RequiredArgumentBuilder.argument( "playerName", StringArgumentType.word() )
++ *                 .suggests( SuggestionRegistry.ASK_SERVER )
++ *                 .then( RequiredArgumentBuilder.argument( "serverName", StringArgumentType.greedyString() )
++ *                         .suggests( SuggestionRegistry.ASK_SERVER )
++ *                 )
++ *         )
++ *         .build()
++ * );
++ * 
++ * ++ *

Flag a {@link CommandNode} as executable or not

++ * The implementation of a {@link com.mojang.brigadier.Command Command} used in ++ * {@link ArgumentBuilder#executes(com.mojang.brigadier.Command)} will never be ++ * executed. This will only tell to the client if the current node is ++ * executable or not. ++ *
    ++ *
  • ++ * {@code builder.executes(null)} (default) to mark the node as not ++ * executable. ++ *
  • ++ *
  • ++ * {@code builder.executes(a -> 0)}, or any non null argument, to mark ++ * the node as executable (the child arguments are displayed as ++ * optional). ++ *
  • ++ *
++ * ++ *

{@link CommandNode}’s suggestions management

++ * The implementation of a SuggestionProvider used in ++ * {@link RequiredArgumentBuilder#suggests(SuggestionProvider)} will never be ++ * executed. This will only tell to the client how to deal with the ++ * auto-completion of the argument. ++ *
    ++ *
  • ++ * {@code builder.suggests(null)} (default) to disable auto-completion ++ * for this argument. ++ *
  • ++ *
  • ++ * {@code builder.suggests(SuggestionRegistry.ALL_RECIPES)} to suggest ++ * Minecraft’s recipes. ++ *
  • ++ *
  • ++ * {@code builder.suggests(SuggestionRegistry.AVAILABLE_SOUNDS)} to ++ * suggest Minecraft’s default sound identifiers. ++ *
  • ++ *
  • ++ * {@code builder.suggests(SuggestionRegistry.SUMMONABLE_ENTITIES)} to ++ * suggest Minecraft’s default summonable entities identifiers. ++ *
  • ++ *
  • ++ * {@code builder.suggests(SuggestionRegistry.ASK_SERVER)}, or any ++ * other non null argument, to make the Minecraft client ask ++ * auto-completion to the server. Any specified implementation of ++ * {@link SuggestionProvider} will never be executed. ++ *
  • ++ *
++ * ++ *

Argument types

++ * When building a new argument command node using ++ * {@link RequiredArgumentBuilder#argument(String, ArgumentType)}, you have to ++ * specify an {@link ArgumentType}. You can use all subclasses of ++ * {@link ArgumentType} provided with brigadier (for instance, ++ * {@link StringArgumentType} or {@link IntegerArgumentType}), or call any ++ * {@code ArgumentRegistry.minecraft*()} methods to use a {@code minecraft:*} ++ * argument type. ++ * ++ *

Limitations with brigadier API

++ * This event is only used for the client to show command syntax, suggest ++ * sub-commands and color the arguments in the chat box. The command execution ++ * needs to be implemented using {@link PluginManager#registerCommand(Plugin, ++ * Command)} and the server-side tab-completion using {@link TabCompleteEvent} ++ * or {@link TabExecutor}. ++ */ ++@Data ++@ToString(callSuper = true) ++@EqualsAndHashCode(callSuper = true) ++public class CommandsDeclareEvent extends TargetedEvent ++{ ++ /** ++ * Wether or not the command tree is modified by this event. ++ * ++ * If this value is set to true, BungeeCord will ensure that the ++ * modifications made in the command tree, will be sent to the player. ++ * If this is false, the modifications may not be taken into account. ++ * ++ * When calling {@link #getRoot()}, this value is automatically set ++ * to true. ++ */ ++ @Setter(value = AccessLevel.NONE) ++ private boolean modified = false; ++ ++ /** ++ * The root command node of the command structure that will be send to the ++ * player. ++ */ ++ private final RootCommandNode root; ++ ++ public CommandsDeclareEvent(Connection sender, Connection receiver, RootCommandNode root) ++ { ++ super( sender, receiver ); ++ this.root = root; ++ } ++ ++ /** ++ * The root command node of the command structure that will be send to the ++ * player. ++ * @return The root command node ++ */ ++ public RootCommandNode getRoot() ++ { ++ modified = true; ++ return root; ++ } ++} +diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/packet/Commands.java b/protocol/src/main/java/net/md_5/bungee/protocol/packet/Commands.java +index 26edbca8..323d479c 100644 +--- a/protocol/src/main/java/net/md_5/bungee/protocol/packet/Commands.java ++++ b/protocol/src/main/java/net/md_5/bungee/protocol/packet/Commands.java +@@ -4,6 +4,7 @@ import com.google.common.base.Preconditions; + import com.mojang.brigadier.Command; + import com.mojang.brigadier.StringReader; + import com.mojang.brigadier.arguments.ArgumentType; ++import com.mojang.brigadier.arguments.BoolArgumentType; + import com.mojang.brigadier.arguments.DoubleArgumentType; + import com.mojang.brigadier.arguments.FloatArgumentType; + import com.mojang.brigadier.arguments.IntegerArgumentType; +@@ -36,6 +37,7 @@ import lombok.EqualsAndHashCode; + import lombok.NoArgsConstructor; + import net.md_5.bungee.protocol.AbstractPacketHandler; + import net.md_5.bungee.protocol.DefinedPacket; ++import net.md_5.bungee.protocol.ProtocolConstants; + + @Data + @NoArgsConstructor +@@ -126,7 +128,7 @@ public class Commands extends DefinedPacket + } + + @Override +- public void write(ByteBuf buf) ++ public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) + { + Map indexMap = new LinkedHashMap<>(); + Deque nodeQueue = new ArrayDeque<>(); +@@ -210,7 +212,7 @@ public class Commands extends DefinedPacket + ArgumentCommandNode argumentNode = (ArgumentCommandNode) node; + + writeString( argumentNode.getName(), buf ); +- ArgumentRegistry.write( argumentNode.getType(), buf ); ++ ArgumentRegistry.write( argumentNode.getType(), buf, protocolVersion ); + + if ( argumentNode.getCustomSuggestions() != null ) + { +@@ -304,11 +306,12 @@ public class Commands extends DefinedPacket + } + + @Data +- private static class ArgumentRegistry ++ public static class ArgumentRegistry + { + + private static final Map PROVIDERS = new HashMap<>(); + private static final Map, ProperArgumentSerializer> PROPER_PROVIDERS = new HashMap<>(); ++ private static final Map CONVERSION_PROVIDERS = new HashMap<>(); + // + private static final ArgumentSerializer VOID = new ArgumentSerializer() + { +@@ -323,18 +326,23 @@ public class Commands extends DefinedPacket + { + } + }; +- private static final ArgumentSerializer BOOLEAN = new ArgumentSerializer() ++ private static final ProperArgumentSerializer BOOLEAN = new ProperArgumentSerializer() + { + @Override +- protected Boolean read(ByteBuf buf) ++ protected BoolArgumentType read(ByteBuf buf) + { +- return buf.readBoolean(); ++ return BoolArgumentType.bool(); + } + + @Override +- protected void write(ByteBuf buf, Boolean t) ++ protected void write(ByteBuf buf, BoolArgumentType t) + { +- buf.writeBoolean( t ); ++ } ++ ++ @Override ++ protected String getKey() ++ { ++ return "brigadier:bool"; + } + }; + private static final ArgumentSerializer BYTE = new ArgumentSerializer() +@@ -351,7 +359,7 @@ public class Commands extends DefinedPacket + buf.writeByte( t ); + } + }; +- private static final ArgumentSerializer FLOAT = new ArgumentSerializer() ++ private static final ProperArgumentSerializer FLOAT = new ProperArgumentSerializer() + { + @Override + protected FloatArgumentType read(ByteBuf buf) +@@ -379,8 +387,14 @@ public class Commands extends DefinedPacket + buf.writeFloat( t.getMaximum() ); + } + } ++ ++ @Override ++ protected String getKey() ++ { ++ return "brigadier:float"; ++ } + }; +- private static final ArgumentSerializer DOUBLE = new ArgumentSerializer() ++ private static final ProperArgumentSerializer DOUBLE = new ProperArgumentSerializer() + { + @Override + protected DoubleArgumentType read(ByteBuf buf) +@@ -408,8 +422,14 @@ public class Commands extends DefinedPacket + buf.writeDouble( t.getMaximum() ); + } + } ++ ++ @Override ++ protected String getKey() ++ { ++ return "brigadier:double"; ++ } + }; +- private static final ArgumentSerializer INTEGER = new ArgumentSerializer() ++ private static final ProperArgumentSerializer INTEGER = new ProperArgumentSerializer() + { + @Override + protected IntegerArgumentType read(ByteBuf buf) +@@ -437,8 +457,14 @@ public class Commands extends DefinedPacket + buf.writeInt( t.getMaximum() ); + } + } ++ ++ @Override ++ protected String getKey() ++ { ++ return "brigadier:integer"; ++ } + }; +- private static final ArgumentSerializer LONG = new ArgumentSerializer() ++ private static final ProperArgumentSerializer LONG = new ProperArgumentSerializer() + { + @Override + protected LongArgumentType read(ByteBuf buf) +@@ -466,6 +492,12 @@ public class Commands extends DefinedPacket + buf.writeLong( t.getMaximum() ); + } + } ++ ++ @Override ++ protected String getKey() ++ { ++ return "brigadier:long"; ++ } + }; + private static final ProperArgumentSerializer STRING = new ProperArgumentSerializer() + { +@@ -501,11 +533,31 @@ public class Commands extends DefinedPacket + + static + { +- PROVIDERS.put( "brigadier:bool", VOID ); ++ PROVIDERS.put( "brigadier:bool", BOOLEAN ); ++ PROPER_PROVIDERS.put( BoolArgumentType.class, BOOLEAN ); ++ + PROVIDERS.put( "brigadier:float", FLOAT ); ++ PROPER_PROVIDERS.put( FloatArgumentType.class, FLOAT ); ++ + PROVIDERS.put( "brigadier:double", DOUBLE ); ++ PROPER_PROVIDERS.put( DoubleArgumentType.class, DOUBLE ); ++ + PROVIDERS.put( "brigadier:integer", INTEGER ); +- PROVIDERS.put( "brigadier:long", LONG ); ++ PROPER_PROVIDERS.put( IntegerArgumentType.class, INTEGER ); ++ ++ PROVIDERS.put( "brigadier:long", LONG ); // 1.14+ ++ PROPER_PROVIDERS.put( LongArgumentType.class, LONG ); ++ CONVERSION_PROVIDERS.put( "brigadier:long", ( originalType, protocolVersion ) -> ++ { ++ if ( protocolVersion < ProtocolConstants.MINECRAFT_1_14 ) ++ { ++ LongArgumentType type = (LongArgumentType) originalType; ++ int min = (int) Math.max( Integer.MIN_VALUE, Math.min( Integer.MAX_VALUE, type.getMinimum() ) ); ++ int max = (int) Math.max( Integer.MIN_VALUE, Math.min( Integer.MAX_VALUE, type.getMaximum() ) ); ++ return IntegerArgumentType.integer( min, max ); ++ } ++ return originalType; ++ } ); + + PROVIDERS.put( "brigadier:string", STRING ); + PROPER_PROVIDERS.put( StringArgumentType.class, STRING ); +@@ -523,9 +575,37 @@ public class Commands extends DefinedPacket + PROVIDERS.put( "minecraft:color", VOID ); + PROVIDERS.put( "minecraft:component", VOID ); + PROVIDERS.put( "minecraft:message", VOID ); +- PROVIDERS.put( "minecraft:nbt_compound_tag", VOID ); // 1.14 +- PROVIDERS.put( "minecraft:nbt_tag", VOID ); // 1.14 ++ ++ PROVIDERS.put( "minecraft:nbt_compound_tag", VOID ); // 1.14+, replaces minecraft:nbt ++ CONVERSION_PROVIDERS.put( "minecraft:nbt_compound_tag", ( originalType, protocolVersion ) -> ++ { ++ if ( protocolVersion < ProtocolConstants.MINECRAFT_1_14 ) ++ { ++ return minecraftNBT(); ++ } ++ return originalType; ++ } ); ++ ++ PROVIDERS.put( "minecraft:nbt_tag", VOID ); // 1.14+ ++ CONVERSION_PROVIDERS.put( "minecraft:nbt_tag", ( originalType, protocolVersion ) -> ++ { ++ if ( protocolVersion < ProtocolConstants.MINECRAFT_1_14 ) ++ { ++ return minecraftNBT(); ++ } ++ return originalType; ++ } ); ++ + PROVIDERS.put( "minecraft:nbt", VOID ); // 1.13 ++ CONVERSION_PROVIDERS.put( "minecraft:nbt", ( originalType, protocolVersion ) -> ++ { ++ if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_14 ) ++ { ++ return minecraftNBTCompoundTag(); ++ } ++ return originalType; ++ } ); ++ + PROVIDERS.put( "minecraft:nbt_path", VOID ); + PROVIDERS.put( "minecraft:objective", VOID ); + PROVIDERS.put( "minecraft:objective_criteria", VOID ); +@@ -546,11 +626,416 @@ public class Commands extends DefinedPacket + PROVIDERS.put( "minecraft:item_enchantment", VOID ); + PROVIDERS.put( "minecraft:entity_summon", VOID ); + PROVIDERS.put( "minecraft:dimension", VOID ); +- PROVIDERS.put( "minecraft:time", VOID ); // 1.14 +- PROVIDERS.put( "minecraft:uuid", VOID ); // 1.16 +- PROVIDERS.put( "minecraft:test_argument", VOID ); // 1.16, debug +- PROVIDERS.put( "minecraft:test_class", VOID ); // 1.16, debug +- PROVIDERS.put( "minecraft:angle", VOID ); // 1.16.2 ++ ++ PROVIDERS.put( "minecraft:time", VOID ); // 1.14+ ++ CONVERSION_PROVIDERS.put( "minecraft:time", ( originalType, protocolVersion ) -> ++ { ++ if ( protocolVersion < ProtocolConstants.MINECRAFT_1_14 ) ++ { ++ return StringArgumentType.word(); ++ } ++ return originalType; ++ } ); ++ ++ PROVIDERS.put( "minecraft:uuid", VOID ); // 1.16+ ++ CONVERSION_PROVIDERS.put( "minecraft:uuid", ( originalType, protocolVersion ) -> ++ { ++ if ( protocolVersion < ProtocolConstants.MINECRAFT_1_16 ) ++ { ++ return StringArgumentType.word(); ++ } ++ return originalType; ++ } ); ++ ++ PROVIDERS.put( "minecraft:test_argument", VOID ); // 1.16+, debug ++ PROVIDERS.put( "minecraft:test_class", VOID ); // 1.16+, debug ++ PROVIDERS.put( "minecraft:angle", VOID ); // 1.16.2+ ++ CONVERSION_PROVIDERS.put( "minecraft:angle", ( originalType, protocolVersion ) -> ++ { ++ if ( protocolVersion < ProtocolConstants.MINECRAFT_1_16_2 ) ++ { ++ return FloatArgumentType.floatArg(); ++ } ++ return originalType; ++ } ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:entity}. ++ * @param singleEntity if the argument restrict to only one entity ++ * @param onlyPlayers if the argument restrict to players only ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftEntity(boolean singleEntity, boolean onlyPlayers) ++ { ++ byte flags = 0; ++ if ( singleEntity ) ++ { ++ flags |= 1; ++ } ++ if ( onlyPlayers ) ++ { ++ flags |= 2; ++ } ++ ++ return minecraftArgumentType( "minecraft:entity", flags ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:game_profile}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftGameProfile() ++ { ++ return minecraftArgumentType( "minecraft:game_profile", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:block_pos}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftBlockPos() ++ { ++ return minecraftArgumentType( "minecraft:block_pos", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:column_pos}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftColumnPos() ++ { ++ return minecraftArgumentType( "minecraft:column_pos", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:vec3}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftVec3() ++ { ++ return minecraftArgumentType( "minecraft:vec3", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:vec2}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftVec2() ++ { ++ return minecraftArgumentType( "minecraft:vec2", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:block_state}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftBlockState() ++ { ++ return minecraftArgumentType( "minecraft:block_state", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:block_predicate}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftBlockPredicate() ++ { ++ return minecraftArgumentType( "minecraft:block_predicate", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:item_stack}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftItemStack() ++ { ++ return minecraftArgumentType( "minecraft:item_stack", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:item_predicate}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftItemPredicate() ++ { ++ return minecraftArgumentType( "minecraft:item_predicate", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:color}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftColor() ++ { ++ return minecraftArgumentType( "minecraft:color", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:component}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftComponent() ++ { ++ return minecraftArgumentType( "minecraft:component", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:message}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftMessage() ++ { ++ return minecraftArgumentType( "minecraft:message", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:nbt_compound_tag}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftNBTCompoundTag() ++ { ++ return minecraftArgumentType( "minecraft:nbt_compound_tag", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:nbt_tag}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftNBTTag() ++ { ++ return minecraftArgumentType( "minecraft:nbt_tag", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:nbt}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftNBT() ++ { ++ return minecraftArgumentType( "minecraft:nbt", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:nbt_path}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftNBTPath() ++ { ++ return minecraftArgumentType( "minecraft:nbt_path", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:objective}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftObjective() ++ { ++ return minecraftArgumentType( "minecraft:objective", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:objective_criteria}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftObjectiveCriteria() ++ { ++ return minecraftArgumentType( "minecraft:objective_criteria", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:operation}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftOperation() ++ { ++ return minecraftArgumentType( "minecraft:operation", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:particle}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftParticle() ++ { ++ return minecraftArgumentType( "minecraft:particle", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:rotation}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftRotation() ++ { ++ return minecraftArgumentType( "minecraft:rotation", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:scoreboard_slot}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftScoreboardSlot() ++ { ++ return minecraftArgumentType( "minecraft:scoreboard_slot", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:score_holder}. ++ * @param allowMultiple if the argument allows multiple entities ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftScoreHolder(boolean allowMultiple) ++ { ++ byte flags = 0; ++ if ( allowMultiple ) ++ { ++ flags |= 1; ++ } ++ ++ return minecraftArgumentType( "minecraft:score_holder", flags ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:swizzle}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftSwizzle() ++ { ++ return minecraftArgumentType( "minecraft:swizzle", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:team}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftTeam() ++ { ++ return minecraftArgumentType( "minecraft:team", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:item_slot}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftItemSlot() ++ { ++ return minecraftArgumentType( "minecraft:item_slot", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:resource_location}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftResourceLocation() ++ { ++ return minecraftArgumentType( "minecraft:resource_location", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:mob_effect}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftMobEffect() ++ { ++ return minecraftArgumentType( "minecraft:mob_effect", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:function}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftFunction() ++ { ++ return minecraftArgumentType( "minecraft:function", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:entity_anchor}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftEntityAnchor() ++ { ++ return minecraftArgumentType( "minecraft:entity_anchor", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:int_range}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftIntRange() ++ { ++ return minecraftArgumentType( "minecraft:int_range", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:float_range}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftFloatRange() ++ { ++ return minecraftArgumentType( "minecraft:float_range", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:item_enchantment}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftItemEnchantment() ++ { ++ return minecraftArgumentType( "minecraft:item_enchantment", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:entity_summon}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftEntitySummon() ++ { ++ return minecraftArgumentType( "minecraft:entity_summon", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:dimension}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftDimension() ++ { ++ return minecraftArgumentType( "minecraft:dimension", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:time}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftTime() ++ { ++ return minecraftArgumentType( "minecraft:time", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:uuid}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftUUID() ++ { ++ return minecraftArgumentType( "minecraft:uuid", null ); ++ } ++ ++ /** ++ * Returns the Minecraft ArgumentType {@code minecraft:angle}. ++ * @return an ArgumentType instance ++ */ ++ public static ArgumentType minecraftAngle() ++ { ++ return minecraftArgumentType( "minecraft:angle", null ); ++ } ++ ++ private static ArgumentType minecraftArgumentType(String key, Object rawValue) ++ { ++ ArgumentSerializer reader = PROVIDERS.get( key ); ++ Preconditions.checkArgument( reader != null, "No provider for argument " + key ); ++ ++ return new DummyType( key, reader, rawValue ); + } + + private static ArgumentType read(String key, ByteBuf buf) +@@ -562,8 +1047,10 @@ public class Commands extends DefinedPacket + return val != null && PROPER_PROVIDERS.containsKey( val.getClass() ) ? (ArgumentType) val : new DummyType( key, reader, val ); + } + +- private static void write(ArgumentType arg, ByteBuf buf) ++ private static void write(ArgumentType arg, ByteBuf buf, int protocolVersion) + { ++ arg = convertToVersion( arg, protocolVersion ); ++ + ProperArgumentSerializer proper = PROPER_PROVIDERS.get( arg.getClass() ); + if ( proper != null ) + { +@@ -579,6 +1066,34 @@ public class Commands extends DefinedPacket + } + } + ++ // Convert the provided argument type to a new one compatible with the provided protocol version ++ private static ArgumentType convertToVersion(ArgumentType arg, int protocolVersion) ++ { ++ ProperArgumentSerializer proper = PROPER_PROVIDERS.get( arg.getClass() ); ++ String key; ++ if ( proper != null ) ++ { ++ key = proper.getKey(); ++ } else ++ { ++ Preconditions.checkArgument( arg instanceof DummyType, "Non dummy arg " + arg.getClass() ); ++ key = ( (DummyType) arg ).key; ++ } ++ ++ ProtocolConversionProvider converter = CONVERSION_PROVIDERS.get( key ); ++ ++ if ( converter != null ) ++ { ++ return converter.convert( arg, protocolVersion ); ++ } ++ return arg; ++ } ++ ++ private interface ProtocolConversionProvider ++ { ++ public ArgumentType convert(ArgumentType originalType, int protocolVersion); ++ } ++ + @Data + private static class DummyType implements ArgumentType + { +@@ -612,17 +1127,39 @@ public class Commands extends DefinedPacket + @Data + public static class SuggestionRegistry + { +- ++ /** ++ * Tells the client to ask suggestions to the server. ++ */ + public static final SuggestionProvider ASK_SERVER = new DummyProvider( "minecraft:ask_server" ); ++ ++ /** ++ * Tells the client to suggest all the available recipes. The suggestions are stored client side. ++ */ ++ public static final SuggestionProvider ALL_RECIPES = new DummyProvider( "minecraft:all_recipes" ); ++ ++ /** ++ * Tells the client to suggest all the available sounds. The suggestions are stored client side. ++ */ ++ public static final SuggestionProvider AVAILABLE_SOUNDS = new DummyProvider( "minecraft:available_sounds" ); ++ ++ /** ++ * Tells the client to suggest all the available biomes. The suggestions are stored client side. ++ */ ++ public static final SuggestionProvider AVAILABLE_BIOMES = new DummyProvider( "minecraft:available_biomes" ); ++ ++ /** ++ * Tells the client to suggest all the available entities. The suggestions are stored client side. ++ */ ++ public static final SuggestionProvider SUMMONABLE_ENTITIES = new DummyProvider( "minecraft:summonable_entities" ); + private static final Map> PROVIDERS = new HashMap<>(); + + static + { + PROVIDERS.put( "minecraft:ask_server", ASK_SERVER ); +- registerDummy( "minecraft:all_recipes" ); +- registerDummy( "minecraft:available_sounds" ); +- registerDummy( "minecraft:available_biomes" ); +- registerDummy( "minecraft:summonable_entities" ); ++ PROVIDERS.put( "minecraft:all_recipes", ALL_RECIPES ); ++ PROVIDERS.put( "minecraft:available_sounds", AVAILABLE_SOUNDS ); ++ PROVIDERS.put( "minecraft:available_biomes", AVAILABLE_BIOMES ); ++ PROVIDERS.put( "minecraft:summonable_entities", SUMMONABLE_ENTITIES ); + } + + private static void registerDummy(String name) +@@ -640,9 +1177,13 @@ public class Commands extends DefinedPacket + + private static String getKey(SuggestionProvider provider) + { +- Preconditions.checkArgument( provider instanceof DummyProvider, "Non dummy provider " + provider ); ++ Preconditions.checkNotNull( provider ); ++ if ( provider instanceof DummyProvider ) ++ { ++ return ( (DummyProvider) provider ).key; ++ } + +- return ( (DummyProvider) provider ).key; ++ return ( (DummyProvider) ASK_SERVER ).key; + } + + @Data +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 72538ddb..4379a6c5 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 +@@ -6,12 +6,15 @@ import com.google.common.collect.Lists; + import com.google.common.io.ByteArrayDataOutput; + import com.google.common.io.ByteStreams; + import com.mojang.brigadier.arguments.StringArgumentType; ++import com.mojang.brigadier.builder.ArgumentBuilder; + import com.mojang.brigadier.builder.LiteralArgumentBuilder; + import com.mojang.brigadier.builder.RequiredArgumentBuilder; + import com.mojang.brigadier.context.StringRange; + import com.mojang.brigadier.suggestion.Suggestion; + import com.mojang.brigadier.suggestion.Suggestions; ++import com.mojang.brigadier.tree.CommandNode; + import com.mojang.brigadier.tree.LiteralCommandNode; ++import com.mojang.brigadier.tree.RootCommandNode; + + import io.github.waterfallmc.waterfall.event.ProxyDefineCommandsEvent; // Waterfall + import io.netty.buffer.ByteBuf; +@@ -21,10 +24,13 @@ import io.netty.channel.unix.DomainSocketAddress; + import java.io.DataInput; + import java.net.InetSocketAddress; + import java.util.ArrayList; ++import java.util.Collection; + import java.util.HashMap; // Waterfall ++import java.util.IdentityHashMap; + import java.util.List; + import java.util.Map; + import java.util.Objects; // Waterfall ++import java.util.logging.Level; + import lombok.RequiredArgsConstructor; + import net.md_5.bungee.ServerConnection; + import net.md_5.bungee.ServerConnection.KeepAliveData; +@@ -35,6 +41,7 @@ import net.md_5.bungee.api.chat.BaseComponent; + import net.md_5.bungee.api.chat.TextComponent; + import net.md_5.bungee.api.config.ServerInfo; + import net.md_5.bungee.api.connection.ProxiedPlayer; ++import net.md_5.bungee.api.event.CommandsDeclareEvent; + import net.md_5.bungee.api.event.PluginMessageEvent; + import net.md_5.bungee.api.event.ServerConnectEvent; + import net.md_5.bungee.api.event.ServerDisconnectEvent; +@@ -689,6 +696,11 @@ public class DownstreamBridge extends PacketHandler + { + boolean modified = false; + ++ CommandsDeclareEvent commandsDeclareEvent = new CommandsDeclareEvent( server, con, commands.getRoot() ); ++ bungee.getPluginManager().callEvent( commandsDeclareEvent ); ++ ++ modified = commandsDeclareEvent.isModified(); ++ + // Waterfall start + Map commandMap = new HashMap<>(); + for ( Map.Entry commandEntry : bungee.getPluginManager().getCommands() ) { +@@ -721,11 +733,65 @@ public class DownstreamBridge extends PacketHandler + + if ( modified ) + { ++ commands.setRoot( (RootCommandNode) filterCommandNode( commands.getRoot(), new IdentityHashMap<>() ) ); + con.unsafe().sendPacket( commands ); + throw CancelSendSignal.INSTANCE; + } + } + ++ /* ++ * Create a deep copy of the provided command node but removes any node that are not accessible by the player ++ * (using {@link CommandNode#getRequirement()}) ++ */ ++ private CommandNode filterCommandNode(CommandNode source, IdentityHashMap commandNodeMapping) ++ { ++ CommandNode dest; ++ if ( source instanceof RootCommandNode ) ++ { ++ dest = new RootCommandNode(); ++ } else ++ { ++ if ( source.getRequirement() != null ) ++ { ++ try ++ { ++ if ( !source.getRequirement().test( con ) ) ++ { ++ commandNodeMapping.put( source, null ); ++ return null; ++ } ++ } catch ( Throwable t ) ++ { ++ ProxyServer.getInstance().getLogger().log( Level.SEVERE, "Requirement test for command node " + source + " encountered an exception", t ); ++ } ++ } ++ ++ ArgumentBuilder destChildBuilder = source.createBuilder(); ++ destChildBuilder.requires( sender -> true ); ++ if ( destChildBuilder.getRedirect() != null ) ++ { ++ if ( commandNodeMapping.containsKey( destChildBuilder.getRedirect() ) ) ++ destChildBuilder.redirect( commandNodeMapping.get( destChildBuilder.getRedirect() ) ); ++ else ++ destChildBuilder.redirect( filterCommandNode( destChildBuilder.getRedirect(), commandNodeMapping ) ); ++ } ++ ++ dest = destChildBuilder.build(); ++ } ++ ++ commandNodeMapping.put( source, dest ); ++ ++ for ( CommandNode sourceChild : (Collection) source.getChildren() ) ++ { ++ CommandNode destChild = filterCommandNode( sourceChild, commandNodeMapping ); ++ if ( destChild == null ) ++ continue; ++ dest.addChild( destChild ); ++ } ++ ++ return dest; ++ } ++ + @Override + public String toString() + { +-- +2.32.0.windows.2 + diff --git a/Waterfall-Proxy-Patches/0006-new-event-TabCompleteRequestEvent-and-deprecate-TabC.patch b/Waterfall-Proxy-Patches/0006-new-event-TabCompleteRequestEvent-and-deprecate-TabC.patch new file mode 100644 index 0000000..7cd50f5 --- /dev/null +++ b/Waterfall-Proxy-Patches/0006-new-event-TabCompleteRequestEvent-and-deprecate-TabC.patch @@ -0,0 +1,194 @@ +From 999d7c782e22b1b1ac3bd614e8120c4b9d6d64cb Mon Sep 17 00:00:00 2001 +From: Marc Baloup +Date: Sun, 21 Jun 2020 21:49:31 +0200 +Subject: [PATCH] new event TabCompleteRequestEvent and deprecate + TabCompleteEvent + + +diff --git a/api/src/main/java/net/md_5/bungee/api/event/TabCompleteEvent.java b/api/src/main/java/net/md_5/bungee/api/event/TabCompleteEvent.java +index 2fcd8616..63031f7b 100644 +--- a/api/src/main/java/net/md_5/bungee/api/event/TabCompleteEvent.java ++++ b/api/src/main/java/net/md_5/bungee/api/event/TabCompleteEvent.java +@@ -9,7 +9,9 @@ import net.md_5.bungee.api.plugin.Cancellable; + + /** + * Event called when a player uses tab completion. ++ * @deprecated please use {@link TabCompleteRequestEvent} to support 1.13+ suggestions. + */ ++@Deprecated + @Data + @ToString(callSuper = true) + @EqualsAndHashCode(callSuper = true) +diff --git a/api/src/main/java/net/md_5/bungee/api/event/TabCompleteRequestEvent.java b/api/src/main/java/net/md_5/bungee/api/event/TabCompleteRequestEvent.java +new file mode 100644 +index 00000000..0093ae69 +--- /dev/null ++++ b/api/src/main/java/net/md_5/bungee/api/event/TabCompleteRequestEvent.java +@@ -0,0 +1,85 @@ ++package net.md_5.bungee.api.event; ++ ++import com.google.common.base.Preconditions; ++import com.mojang.brigadier.context.StringRange; ++import com.mojang.brigadier.suggestion.Suggestions; ++import lombok.Data; ++import lombok.EqualsAndHashCode; ++import lombok.ToString; ++import net.md_5.bungee.api.connection.Connection; ++import net.md_5.bungee.api.connection.ProxiedPlayer; ++import net.md_5.bungee.api.plugin.Cancellable; ++import net.md_5.bungee.protocol.ProtocolConstants; ++ ++/** ++ * Event called when a player uses tab completion. ++ */ ++@Data ++@ToString(callSuper = true) ++@EqualsAndHashCode(callSuper = true) ++public class TabCompleteRequestEvent extends TargetedEvent implements Cancellable ++{ ++ ++ /** ++ * Cancelled state. ++ */ ++ private boolean cancelled; ++ /** ++ * The message the player has already entered. ++ */ ++ private final String cursor; ++ /** ++ * Range corresponding to the last word of {@link #getCursor()}. ++ * If you want your suggestions to be compatible with 1.12 and older ++ * clients, you need to {@link #setSuggestions(Suggestions)} with ++ * a range equals to this one. ++ * For 1.13 and newer clients, any other range that cover any part of ++ * {@link #getCursor()} is fine.
++ * To check if the client supports custom ranges, use ++ * {@link #supportsCustomRange()}. ++ */ ++ private final StringRange legacyCompatibleRange; ++ /** ++ * The suggestions that will be sent to the client. If this list is empty, ++ * the request will be forwarded to the server. ++ */ ++ private Suggestions suggestions; ++ ++ public TabCompleteRequestEvent(Connection sender, Connection receiver, String cursor, StringRange legacyCompatibleRange, Suggestions suggestions) ++ { ++ super( sender, receiver ); ++ this.cursor = cursor; ++ this.legacyCompatibleRange = legacyCompatibleRange; ++ this.suggestions = suggestions; ++ } ++ ++ /** ++ * Sets the suggestions that will be sent to the client. ++ * If this list is empty, the request will be forwarded to the server. ++ * @param suggestions the new Suggestions. Cannot be null. ++ * @throws IllegalArgumentException if the client is on 1.12 or lower and ++ * {@code suggestions.getRange()} is not equals to {@link #legacyCompatibleRange}. ++ */ ++ public void setSuggestions(Suggestions suggestions) ++ { ++ Preconditions.checkNotNull( suggestions ); ++ Preconditions.checkArgument( supportsCustomRange() || legacyCompatibleRange.equals( suggestions.getRange() ), ++ "Clients on 1.12 or lower versions don't support the provided range for tab-completion: " + suggestions.getRange() ++ + ". Please use TabCompleteRequestEvent.getLegacyCompatibleRange() for legacy clients." ); ++ this.suggestions = suggestions; ++ } ++ ++ /** ++ * Convenient method to tell if the client supports custom range for ++ * suggestions. ++ * If the client is on 1.13 or above, this methods returns true, and any ++ * range can be used for {@link #setSuggestions(Suggestions)}. Otherwise, ++ * it returns false and the defined range must be equals to ++ * {@link #legacyCompatibleRange}. ++ * @return true if the client is on 1.13 or newer version, false otherwise. ++ */ ++ public boolean supportsCustomRange() ++ { ++ return ( (ProxiedPlayer) getSender() ).getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_13; ++ } ++} +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 d93d8851..bbb1ae91 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 +@@ -6,7 +6,6 @@ import com.mojang.brigadier.suggestion.Suggestion; + import com.mojang.brigadier.suggestion.Suggestions; + import io.netty.channel.Channel; + import java.util.ArrayList; +-import java.util.LinkedList; + import java.util.List; + import net.md_5.bungee.BungeeCord; + import net.md_5.bungee.ServerConnection.KeepAliveData; +@@ -19,6 +18,7 @@ import net.md_5.bungee.api.event.PlayerDisconnectEvent; + import net.md_5.bungee.api.event.PluginMessageEvent; + import net.md_5.bungee.api.event.SettingsChangedEvent; + import net.md_5.bungee.api.event.TabCompleteEvent; ++import net.md_5.bungee.api.event.TabCompleteRequestEvent; + import net.md_5.bungee.entitymap.EntityMap; + import net.md_5.bungee.forge.ForgeConstants; + import net.md_5.bungee.netty.ChannelWrapper; +@@ -200,32 +200,42 @@ public class UpstreamBridge extends PacketHandler + TabCompleteEvent tabCompleteEvent = new TabCompleteEvent( con, con.getServer(), tabComplete.getCursor(), suggestions ); + bungee.getPluginManager().callEvent( tabCompleteEvent ); + +- if ( tabCompleteEvent.isCancelled() ) ++ List legacyResults = tabCompleteEvent.getSuggestions(); ++ ++ int start = tabComplete.getCursor().lastIndexOf( ' ' ) + 1; ++ int end = tabComplete.getCursor().length(); ++ StringRange lastArgumentRange = StringRange.between( start, end ); ++ ++ List brigadier = new ArrayList<>( legacyResults.size() ); ++ for ( String s : legacyResults ) ++ { ++ brigadier.add( new Suggestion( lastArgumentRange, s ) ); ++ } ++ ++ TabCompleteRequestEvent tabCompleteRequestEvent = new TabCompleteRequestEvent( con, con.getServer(), tabComplete.getCursor(), lastArgumentRange, new Suggestions( lastArgumentRange, brigadier ) ); ++ tabCompleteRequestEvent.setCancelled( tabCompleteEvent.isCancelled() ); ++ bungee.getPluginManager().callEvent( tabCompleteRequestEvent ); ++ ++ if ( tabCompleteRequestEvent.isCancelled() ) + { + throw CancelSendSignal.INSTANCE; + } + +- List results = tabCompleteEvent.getSuggestions(); +- if ( !results.isEmpty() ) ++ Suggestions brigadierResults = tabCompleteRequestEvent.getSuggestions(); ++ ++ if ( !brigadierResults.isEmpty() ) + { +- // Unclear how to handle 1.13 commands at this point. Because we don't inject into the command packets we are unlikely to get this far unless +- // Bungee plugins are adding results for commands they don't own anyway + if ( con.getPendingConnection().getVersion() < ProtocolConstants.MINECRAFT_1_13 ) + { ++ List results = new ArrayList<>( brigadierResults.getList().size() ); ++ for ( Suggestion s : brigadierResults.getList() ) ++ { ++ results.add( s.getText() ); ++ } + con.unsafe().sendPacket( new TabCompleteResponse( results ) ); + } else + { +- int start = tabComplete.getCursor().lastIndexOf( ' ' ) + 1; +- int end = tabComplete.getCursor().length(); +- StringRange range = StringRange.between( start, end ); +- +- List brigadier = new LinkedList<>(); +- for ( String s : results ) +- { +- brigadier.add( new Suggestion( range, s ) ); +- } +- +- con.unsafe().sendPacket( new TabCompleteResponse( tabComplete.getTransactionId(), new Suggestions( range, brigadier ) ) ); ++ con.unsafe().sendPacket( new TabCompleteResponse( tabComplete.getTransactionId(), brigadierResults ) ); + } + throw CancelSendSignal.INSTANCE; + } +-- +2.32.0.windows.2 + diff --git a/pandacord b/pandacord new file mode 100644 index 0000000..c626b06 --- /dev/null +++ b/pandacord @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + + + +case "$1" in + "rb" | "rbp" | "rebuild") + scripts/rebuildPatches.sh + ;; + "p" | "patch") + scripts/build.sh + ;; + "m" | "up" | "merge") + scripts/mergeUpstream.sh + ;; + "e" | "edit") + scripts/edit.sh + ;; + *) + echo "PandaCord build tool command. This provides a variety of commands to control the PandaCord" + echo "build. View below for details of the available commands." + echo "" + echo "Commands:" + echo " * rb, rbp, rebuild | Rebuilds the patches" + echo " * p, patch | Applies all the patches to BungeeCord / Waterfall" + echo " * m, up, merge | Utility to aid in merging upstream" + echo " * e, edit | Runs git rebase -i for PandaCord, allowing patches to be easily modified" + ;; +esac diff --git a/pom.xml b/pom.xml deleted file mode 100644 index 442e1dd..0000000 --- a/pom.xml +++ /dev/null @@ -1,25 +0,0 @@ - - 4.0.0 - - io.github.waterfallmc - travertine-super - dev-SNAPSHOT - pom - - Travertine-Super - Super project for Travertine. - https://github.com/WaterfallMC/Travertine - - - Travertine-Proxy - - - - clean install - - - - UTF-8 - - diff --git a/scripts/applyPatches.sh b/scripts/applyPatches.sh index fad2174..a02816b 100755 --- a/scripts/applyPatches.sh +++ b/scripts/applyPatches.sh @@ -67,7 +67,7 @@ applyPatch BungeeCord Waterfall-Proxy HEAD popd basedir=$(dirname "$basedir") -# Apply travertine patches -applyPatch Waterfall/Waterfall-Proxy Travertine-Proxy HEAD +# Apply pandacord patches +applyPatch Waterfall/Waterfall-Proxy PandaCord-Proxy HEAD enableCommitSigningIfNeeded diff --git a/scripts/build.sh b/scripts/build.sh index 683134a..15beca4 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -1,7 +1,3 @@ #!/usr/bin/env bash git submodule update --recursive --init && ./scripts/applyPatches.sh -if [ "$1" == "--jar" ]; then - pushd Travertine-Proxy - mvn clean package -fi diff --git a/scripts/edit.sh b/scripts/edit.sh index dda5dd0..c92f9fa 100755 --- a/scripts/edit.sh +++ b/scripts/edit.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -pushd Travertine-Proxy +pushd PandaCord-Proxy git rebase --interactive upstream/upstream popd diff --git a/scripts/rebuildPatches.sh b/scripts/rebuildPatches.sh index 9535384..65d6699 100755 --- a/scripts/rebuildPatches.sh +++ b/scripts/rebuildPatches.sh @@ -3,7 +3,6 @@ ( PS1="$" basedir="$(cd "$1" && pwd -P)" -workdir="$basedir/work" echo "Rebuilding patch files from current fork state..." git config core.safecrlf false @@ -57,5 +56,5 @@ function savePatches { echo " Patches saved for $what to $what_name-Patches/" } -savePatches "Waterfall/Waterfall-Proxy" "Travertine-Proxy" +savePatches "Waterfall/Waterfall-Proxy" "PandaCord-Proxy" ) diff --git a/scripts/wigglePatch.py b/scripts/wigglePatch.py deleted file mode 100644 index d2a6bb6..0000000 --- a/scripts/wigglePatch.py +++ /dev/null @@ -1,149 +0,0 @@ -#!/usr/bin/env python3 -from subprocess import run, PIPE, CalledProcessError -from argparse import ArgumentParser -import os -from os import path -from sys import stderr, stdout -import re -from enum import Enum, unique - -@unique -class FileStatus(Enum): - UNTRACKED = '?' - UNMODIFIED = ' ' - MODIFIED = 'M' - ADDED = 'A' - DELETED = 'D' - RENAMED = 'R' - COPIED = 'C' - UNMERGED = 'U' - IGNORED = '!' - -class GitRepository: - def __init__(self, directory): - if not path.isdir(directory): - if not path.exists(directory): - raise ValueError("Repository doesn't exist:", directory) - else: - raise ValueError("Repository isn't a valid directory:", directory) - elif not path.isdir(path.join(directory, ".git")): - raise ValueError("Directory isn't a git repository:", directory) - self.directory = directory - - def status(self): - status_lines = run( - ["git", "status", "--porcelain"], - check=True, stdout=PIPE, universal_newlines=True, - cwd=self.directory - ).stdout - status = dict() - for line in status_lines.splitlines(): - old_status = FileStatus(line[0]) - new_status = FileStatus(line[1]) - file_name = line[3:] - status[file_name] = (old_status, new_status) - return status - - def is_clean(self): - try: - return len(self.status()) == 0 - except CalledProcessError: - return False - - def is_automatically_merging(self): - return path.exists(path.join(self.directory, ".git", "rebase-apply", "applying")) - - def wiggle_patch(self, patch): - assert self.is_clean() - # By default, wiggle won't create files the patch needs, and just fails - for created_file in patch.created_files: - # mkdir -p $(dirname created_file) - os.makedirs(path.join(self.directory, path.dirname(created_file)), exist_ok=True) - # touch created_file - with open(path.join(self.directory, created_file), 'a'): - pass - result = run(["wiggle", "-rp", path.relpath(patch.file, start=self.directory)], - stderr=stderr, cwd=self.directory) - for file_name, (old_status, new_status) in self.status().items(): - if new_status == FileStatus.UNTRACKED and old_status == FileStatus.UNTRACKED \ - and file_name.endswith(".porig"): - # Remove wiggle's automatically created backup files - # They're completely unessicary since the entire repo is version-controlled - os.remove(path.join(self.directory, file_name)) - if result.returncode == 1: - return False # There were unresolved conflicts - else: - # Check for an unexpected error - # Since conflicts were already checked for, this will only raise for unexpected errors - result.check_returncode() - return True # Successfully wiggled - - def __str__(self): - return path.basename(self.directory) - -class PatchFile: - def __init__(self, file): - if not path.isfile(file): - if not path.exists(file): - raise ValueError("Patch file doesn't exist:", file) - else: - raise ValueError("Patch isn't a file:", file) - self.file = file - try: - summary = run(["git", "apply", "--summary", file], - check=True, stdout=PIPE, universal_newlines=True).stdout - except CalledProcessError: - raise ValueError("Invalid patch file:", file) - summary_pattern = re.compile(r"\s*(create) mode \d+ (\S+)") - created_files = list() - for line in summary.splitlines(): - match = summary_pattern.match(line) - if not match: - raise NotImplementedError("Don't know how to parse summary line: {}".format(line)) - (action, target_file) = match.groups() - if action == "create": - created_files.append(target_file) - self.created_files = tuple(created_files) # Immutable copy - - def __str__(self): - return path.basename(self.file) - -parser = ArgumentParser(description="Wiggle the patch into the specified git repository") -parser.add_argument("repo", help="The git repository to apply the patch to", type=GitRepository) -parser.add_argument("patch", help="The patch to apply to the repository", type=PatchFile) -parser.add_argument("--git-am", "--am", "-a", action="store_true", - help="If an automatic merge is in progress, continue it after wiggling") - -args = parser.parse_args() - -repository, patch = args.repo, args.patch - -if not repository.is_clean(): - print(repository, "isn't a clean repo!") - exit(1) - - -was_automatically_merging = False -if args.git_am and repository.is_automatically_merging(): - print("Automatic merge in progress, will continue applying if successful") - was_automatically_merging = True - -if not repository.wiggle_patch(patch): - print("Unresolved conflicts found while wiggling!", file=stderr) - print("Manual intervention is required to fix the conflicts!", file=stderr) - exit(2) - -if args.git_am and was_automatically_merging: - assert repository.is_automatically_merging() - try: - print("Adding changed files to index") - run(["git", "add", "."], stdout=stdout, stderr=stderr, check=True, - cwd=repository.directory) - print("Continuing automatic merge after successful wiggle") - run(["git", "am", "--continue"], stdout=stdout, stderr=stderr, check=True, - cwd=repository.directory) - except CalledProcessError as e: - print("Failed to continue automatic merge!", file=stderr) - exit(3) -else: - print("Successfully Wiggled", patch, "into", repository) diff --git a/travertine b/travertine deleted file mode 100755 index 88cf4ec..0000000 --- a/travertine +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env bash - -case "$1" in - "rb" | "rbp" | "rebuild") - scripts/rebuildPatches.sh - ;; - "p" | "patch") - scripts/build.sh - ;; - "m" | "up" | "merge") - scripts/mergeUpstream.sh - ;; - "b" | "build") - scripts/build.sh --jar - ;; - "e" | "edit") - scripts/edit.sh - ;; - "w" | "wiggle") - scripts/wigglePatch.py - ;; - *) - echo "Travertine build tool command. This provides a variety of commands to control the Travertine" - echo "build. View below for details of the available commands." - echo "" - echo "Commands:" - echo " * rb, rbp, rebuild | Rebuilds the patches" - echo " * p, patch | Applies all the patches to BungeeCord" - echo " * m, up, merge | Utility to aid in merging upstream" - echo " * b, build | Builds the project" - echo " | The bootstrap artifact can be found in Travertine-Proxy/bootstrap/target/" - echo " * e, edit | Runs git rebase -i for Waterfall, allowing patches to be easily modified" - echo " * w, wiggle | Helps to apply patches that fail to using default Git." - ;; -esac