├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src └── main ├── java └── fr │ └── customentity │ └── advancedbungeequeue │ ├── bungee │ ├── AdvancedBungeeQueue.java │ ├── command │ │ └── QueueCommand.java │ ├── data │ │ ├── Priority.java │ │ └── QueuedPlayer.java │ ├── i18n │ │ ├── I18n.java │ │ └── YamlResourceBundle.java │ ├── listener │ │ └── QueueListener.java │ ├── manager │ │ └── QueueManager.java │ ├── runnable │ │ └── ConnectRunnable.java │ └── socket │ │ ├── ServerThread.java │ │ └── SocketManager.java │ ├── common │ ├── QueueResult.java │ └── actions │ │ ├── Action.java │ │ ├── PlayerAction.java │ │ └── all │ │ ├── ConfirmConnectionAction.java │ │ └── ExecuteCommandAction.java │ └── spigot │ ├── AdvancedSpigotQueue.java │ └── SocketManager.java └── resources ├── bungee.yml ├── config.yml ├── messages_en.yml └── plugin.yml /.gitignore: -------------------------------------------------------------------------------- 1 | # User-specific stuff 2 | .idea/ 3 | 4 | *.iml 5 | *.ipr 6 | *.iws 7 | 8 | # IntelliJ 9 | out/ 10 | # mpeltonen/sbt-idea plugin 11 | .idea_modules/ 12 | 13 | # JIRA plugin 14 | atlassian-ide-plugin.xml 15 | 16 | # Compiled class file 17 | *.class 18 | 19 | # Log file 20 | *.log 21 | 22 | # BlueJ files 23 | *.ctxt 24 | 25 | # Package Files # 26 | *.jar 27 | *.war 28 | *.nar 29 | *.ear 30 | *.zip 31 | *.tar.gz 32 | *.rar 33 | 34 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 35 | hs_err_pid* 36 | 37 | *~ 38 | 39 | # temporary files which can be created if a process still has a handle open of a deleted file 40 | .fuse_hidden* 41 | 42 | # KDE directory preferences 43 | .directory 44 | 45 | # Linux trash folder which might appear on any partition or disk 46 | .Trash-* 47 | 48 | # .nfs files are created when an open file is removed but is still being accessed 49 | .nfs* 50 | 51 | # General 52 | .DS_Store 53 | .AppleDouble 54 | .LSOverride 55 | 56 | # Icon must end with two \r 57 | Icon 58 | 59 | # Thumbnails 60 | ._* 61 | 62 | # Files that might appear in the root of a volume 63 | .DocumentRevisions-V100 64 | .fseventsd 65 | .Spotlight-V100 66 | .TemporaryItems 67 | .Trashes 68 | .VolumeIcon.icns 69 | .com.apple.timemachine.donotpresent 70 | 71 | # Directories potentially created on remote AFP share 72 | .AppleDB 73 | .AppleDesktop 74 | Network Trash Folder 75 | Temporary Items 76 | .apdisk 77 | 78 | # Windows thumbnail cache files 79 | Thumbs.db 80 | Thumbs.db:encryptable 81 | ehthumbs.db 82 | ehthumbs_vista.db 83 | 84 | # Dump file 85 | *.stackdump 86 | 87 | # Folder config file 88 | [Dd]esktop.ini 89 | 90 | # Recycle Bin used on file shares 91 | $RECYCLE.BIN/ 92 | 93 | # Windows Installer files 94 | *.cab 95 | *.msi 96 | *.msix 97 | *.msm 98 | *.msp 99 | 100 | # Windows shortcuts 101 | *.lnk 102 | 103 | .gradle 104 | build/ 105 | 106 | # Ignore Gradle GUI config 107 | gradle-app.setting 108 | 109 | # Cache of project 110 | .gradletasknamecache 111 | 112 | **/build/ 113 | 114 | # Common working directory 115 | run/ 116 | 117 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 118 | !gradle-wrapper.jar 119 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | # AdvancedBungeeQueue [![GitHub issues](https://img.shields.io/github/issues/CustomEntity/CustomCore)](https://github.com/CustomEntity/AdvancedBungeeQueue/issues) [![GitHub forks](https://img.shields.io/github/forks/CustomEntity/CustomCore)](https://github.com/CustomEntity/AdvancedBungeeQueue/network) [![GitHub stars](https://img.shields.io/github/stars/CustomEntity/CustomCore?color=yellow)](https://github.com/CustomEntity/AdvancedBungeeQueue/stargazers) [![GitHub license](https://img.shields.io/github/license/CustomEntity/CustomCore?color=GREEN)](https://github.com/CustomEntity/AdvancedBungeeQueue/blob/master/LICENSE) 6 | 7 | Optimize your servers using this [queuing system](https://github.com/CustomEntity/AdvancedBungeeQueue/). 8 | 9 | ## Disclaimer 10 | AdvancedBungeeQueue is currently in pre-release. It is very likely that you will encounter bugs there. Please report any issue on GitHub. 11 | 12 | 13 | ## Table of Contents 14 | 15 | * [About the Project](#about-the-project) 16 | * [Getting Started](#getting-started) 17 | * [Prerequisites](#prerequisites) 18 | * [Installation](#installation) 19 | * [Contributing](#contributing) 20 | * [License](#license) 21 | * [Contact](#contact) 22 | 23 | 24 | 25 | 26 | ## About The Project 27 | 28 |

29 | 30 |

31 | 32 | AdvancedBungeeQueue is a queuing plugin that prevents a ton of players from connecting to one of your servers and causing lags. Compared to other plugins, it is very optimized and has many useful new features. 33 | 34 | 35 | 36 | 37 | ## Getting Started 38 | 39 | 40 | ### Prerequisites 41 | 42 | * A BungeeCord server 43 | * One or more spigot servers 44 | 45 | ### Installation 46 | 47 | 1. Get the .jar in the releases 48 | 2. Allocate a special port for the queue if you have a firewall 49 | 3. Configure the plugin to your liking 50 | 4. Now enjoy it ! 51 | 52 | 53 | ## Contributing 54 | 55 | Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**. 56 | 57 | 58 | ## License 59 | 60 | Distributed under the GPL License. See `LICENSE` for more information. 61 | 62 | 63 | ## Contact 64 | 65 | **CustomEntity#6437** 66 | 67 | [**@EntityCustom**](https://twitter.com/EntityCustom) 68 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | import org.apache.tools.ant.filters.ReplaceTokens 2 | 3 | apply plugin: 'java' 4 | 5 | group = 'fr.customentity' 6 | version = '1.1' 7 | 8 | sourceCompatibility = '1.8' 9 | targetCompatibility = '1.8' 10 | 11 | repositories { 12 | mavenCentral() 13 | maven { 14 | name = 'sonatype' 15 | url = 'https://oss.sonatype.org/content/groups/public/' 16 | } 17 | maven { 18 | name = 'spigotmc-repo' 19 | url = 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' 20 | } 21 | } 22 | 23 | dependencies { 24 | compileOnly 'net.md-5:bungeecord-api:1.16-R0.4-SNAPSHOT' 25 | compileOnly 'org.spigotmc:spigot-api:1.16.3-R0.1-SNAPSHOT' 26 | } 27 | 28 | processResources { 29 | from(sourceSets.main.resources.srcDirs) { 30 | filter ReplaceTokens, tokens: [version: version] 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CustomEntity/AdvancedBungeeQueue/4e72a637314d81cebde69028e66811181617154f/gradle.properties -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CustomEntity/AdvancedBungeeQueue/4e72a637314d81cebde69028e66811181617154f/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | # Determine the Java fr.customentity.advancedbungeequeue.command to use to start the JVM. 86 | if [ -n "$JAVA_HOME" ] ; then 87 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 88 | # IBM's JDK on AIX uses strange locations for the executables 89 | JAVACMD="$JAVA_HOME/jre/sh/java" 90 | else 91 | JAVACMD="$JAVA_HOME/bin/java" 92 | fi 93 | if [ ! -x "$JAVACMD" ] ; then 94 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 95 | 96 | Please set the JAVA_HOME variable in your environment to match the 97 | location of your Java installation." 98 | fi 99 | else 100 | JAVACMD="java" 101 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 102 | 103 | Please set the JAVA_HOME variable in your environment to match the 104 | location of your Java installation." 105 | fi 106 | 107 | # Increase the maximum file descriptors if we can. 108 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 109 | MAX_FD_LIMIT=`ulimit -H -n` 110 | if [ $? -eq 0 ] ; then 111 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 112 | MAX_FD="$MAX_FD_LIMIT" 113 | fi 114 | ulimit -n $MAX_FD 115 | if [ $? -ne 0 ] ; then 116 | warn "Could not set maximum file descriptor limit: $MAX_FD" 117 | fi 118 | else 119 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 120 | fi 121 | fi 122 | 123 | # For Darwin, add options to specify how the application appears in the dock 124 | if $darwin; then 125 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 126 | fi 127 | 128 | # For Cygwin or MSYS, switch paths to Windows format before running java 129 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 130 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 131 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 132 | JAVACMD=`cygpath --unix "$JAVACMD"` 133 | 134 | # We build the pattern for arguments to be converted via cygpath 135 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 136 | SEP="" 137 | for dir in $ROOTDIRSRAW ; do 138 | ROOTDIRS="$ROOTDIRS$SEP$dir" 139 | SEP="|" 140 | done 141 | OURCYGPATTERN="(^($ROOTDIRS))" 142 | # Add a user-defined pattern to the cygpath arguments 143 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 144 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 145 | fi 146 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 147 | i=0 148 | for arg in "$@" ; do 149 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 150 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 151 | 152 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 153 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 154 | else 155 | eval `echo args$i`="\"$arg\"" 156 | fi 157 | i=$((i+1)) 158 | done 159 | case $i in 160 | (0) set -- ;; 161 | (1) set -- "$args0" ;; 162 | (2) set -- "$args0" "$args1" ;; 163 | (3) set -- "$args0" "$args1" "$args2" ;; 164 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 165 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 166 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 167 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 168 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 169 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 170 | esac 171 | fi 172 | 173 | # Escape application args 174 | save () { 175 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 176 | echo " " 177 | } 178 | APP_ARGS=$(save "$@") 179 | 180 | # Collect all arguments for the java fr.customentity.advancedbungeequeue.command, following the shell quoting and substitution rules 181 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 182 | 183 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 184 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 185 | cd "$(dirname "$0")" 186 | fi 187 | 188 | exec "$JAVACMD" "$@" 189 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 34 | 35 | @rem Find java.exe 36 | if defined JAVA_HOME goto findJavaFromJavaHome 37 | 38 | set JAVA_EXE=java.exe 39 | %JAVA_EXE% -version >NUL 2>&1 40 | if "%ERRORLEVEL%" == "0" goto init 41 | 42 | echo. 43 | echo ERROR: JAVA_HOME is not set and no 'java' fr.customentity.advancedbungeequeue.command could be found in your PATH. 44 | echo. 45 | echo Please set the JAVA_HOME variable in your environment to match the 46 | echo location of your Java installation. 47 | 48 | goto fail 49 | 50 | :findJavaFromJavaHome 51 | set JAVA_HOME=%JAVA_HOME:"=% 52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 53 | 54 | if exist "%JAVA_EXE%" goto init 55 | 56 | echo. 57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 58 | echo. 59 | echo Please set the JAVA_HOME variable in your environment to match the 60 | echo location of your Java installation. 61 | 62 | goto fail 63 | 64 | :init 65 | @rem Get fr.customentity.advancedbungeequeue.command-line arguments, handling Windows variants 66 | 67 | if not "%OS%" == "Windows_NT" goto win9xME_args 68 | 69 | :win9xME_args 70 | @rem Slurp the fr.customentity.advancedbungeequeue.command line arguments. 71 | set CMD_LINE_ARGS= 72 | set _SKIP=2 73 | 74 | :win9xME_args_slurp 75 | if "x%~1" == "x" goto execute 76 | 77 | set CMD_LINE_ARGS=%* 78 | 79 | :execute 80 | @rem Setup the fr.customentity.advancedbungeequeue.command line 81 | 82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 83 | 84 | @rem Execute Gradle 85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 86 | 87 | :end 88 | @rem End local scope for the variables with windows NT shell 89 | if "%ERRORLEVEL%"=="0" goto mainEnd 90 | 91 | :fail 92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 93 | rem the _cmd.exe /c_ return code! 94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 95 | exit /b 1 96 | 97 | :mainEnd 98 | if "%OS%"=="Windows_NT" endlocal 99 | 100 | :omega 101 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CustomEntity/AdvancedBungeeQueue/4e72a637314d81cebde69028e66811181617154f/settings.gradle -------------------------------------------------------------------------------- /src/main/java/fr/customentity/advancedbungeequeue/bungee/AdvancedBungeeQueue.java: -------------------------------------------------------------------------------- 1 | package fr.customentity.advancedbungeequeue.bungee; 2 | 3 | import fr.customentity.advancedbungeequeue.bungee.command.QueueCommand; 4 | import fr.customentity.advancedbungeequeue.bungee.i18n.I18n; 5 | import fr.customentity.advancedbungeequeue.bungee.i18n.YamlResourceBundle; 6 | import fr.customentity.advancedbungeequeue.bungee.listener.QueueListener; 7 | import fr.customentity.advancedbungeequeue.bungee.manager.QueueManager; 8 | import fr.customentity.advancedbungeequeue.bungee.socket.SocketManager; 9 | import net.md_5.bungee.api.*; 10 | import net.md_5.bungee.api.chat.TextComponent; 11 | import net.md_5.bungee.api.connection.ProxiedPlayer; 12 | import net.md_5.bungee.api.plugin.Plugin; 13 | import net.md_5.bungee.config.Configuration; 14 | import net.md_5.bungee.config.ConfigurationProvider; 15 | import net.md_5.bungee.config.YamlConfiguration; 16 | 17 | import java.io.*; 18 | import java.net.URL; 19 | import java.net.URLConnection; 20 | import java.nio.file.Files; 21 | import java.util.*; 22 | import java.util.concurrent.TimeUnit; 23 | import java.util.logging.Level; 24 | import java.util.logging.Logger; 25 | 26 | public class AdvancedBungeeQueue extends Plugin { 27 | 28 | private QueueManager queueManager; 29 | 30 | private File file; 31 | private Configuration configFile; 32 | private SocketManager socketManager; 33 | 34 | private I18n i18n; 35 | 36 | @Override 37 | public void onEnable() { 38 | this.saveDefaultConfig(); 39 | this.i18n = new I18n(this, configFile.getString("locale")); 40 | 41 | this.queueManager = new QueueManager(this); 42 | this.getProxy().getPluginManager().registerCommand(this, new QueueCommand(this)); 43 | this.getProxy().getPluginManager().registerListener(this, new QueueListener(this)); 44 | 45 | this.getProxy().getScheduler().schedule(this, () -> queueManager.getQueues().forEach((serverInfo, queuedPlayers) -> queuedPlayers.forEach(queuedPlayer -> this.sendConfigMessage(queuedPlayer.getProxiedPlayer(), "general.repeating-position-message", 46 | "%all%", queuedPlayers.size() + "", 47 | "%position%", queuedPlayers.indexOf(queuedPlayer) + 1 + "", 48 | "%priority%", queuedPlayer.getPriority().getName() 49 | ))), 1, getConfigFile().getInt("remember-queue-position-delay", 1), TimeUnit.SECONDS); 50 | 51 | this.socketManager = new SocketManager(this); 52 | this.socketManager.initListener(); 53 | } 54 | 55 | public SocketManager getSocketManager() { 56 | return socketManager; 57 | } 58 | 59 | public void log(Level level, String message) { 60 | Logger.getLogger(this.getDescription().getName()).log(level, message); 61 | } 62 | 63 | public I18n getI18n() { 64 | return i18n; 65 | } 66 | 67 | private InputStream getResource(String filename) { 68 | if (filename == null) { 69 | throw new IllegalArgumentException("Filename cannot be null"); 70 | } 71 | 72 | try { 73 | URL url = this.getClass().getClassLoader().getResource(filename); 74 | 75 | if (url == null) { 76 | return null; 77 | } 78 | 79 | URLConnection connection = url.openConnection(); 80 | connection.setUseCaches(false); 81 | return connection.getInputStream(); 82 | } catch (IOException ex) { 83 | return null; 84 | } 85 | } 86 | 87 | public void saveResource(String resourcePath, boolean replace) { 88 | if (resourcePath == null || resourcePath.equals("")) return; 89 | 90 | resourcePath = resourcePath.replace('\\', '/'); 91 | InputStream in = getResource(resourcePath); 92 | if (in == null) return; 93 | 94 | File outFile = new File(this.getDataFolder(), resourcePath); 95 | int lastIndex = resourcePath.lastIndexOf('/'); 96 | File outDir = new File(this.getDataFolder(), resourcePath.substring(0, Math.max(lastIndex, 0))); 97 | 98 | if (!outDir.exists()) { 99 | outDir.mkdirs(); 100 | } 101 | 102 | try { 103 | if (!outFile.exists() || replace) { 104 | OutputStream out = new FileOutputStream(outFile); 105 | byte[] buf = new byte[1024]; 106 | int len; 107 | while ((len = in.read(buf)) > 0) { 108 | out.write(buf, 0, len); 109 | } 110 | out.close(); 111 | in.close(); 112 | } 113 | } catch (IOException ignore) { } 114 | } 115 | 116 | private void saveDefaultConfig() { 117 | try { 118 | if (!this.getDataFolder().exists()) 119 | this.getDataFolder().mkdirs(); 120 | 121 | file = new File(this.getDataFolder(), "config.yml"); 122 | if (!file.exists()) { 123 | Files.copy(getResourceAsStream("config.yml"), file.toPath()); 124 | } 125 | configFile = ConfigurationProvider.getProvider(YamlConfiguration.class).load(file); 126 | } catch (IOException e) { 127 | e.printStackTrace(); 128 | } 129 | } 130 | 131 | @Override 132 | public void onDisable() { 133 | try { 134 | this.getSocketManager().getSocket().close(); 135 | } catch (IOException ignored) {} 136 | } 137 | 138 | public Configuration getConfigFile() { 139 | return configFile; 140 | } 141 | 142 | public QueueManager getQueueManager() { 143 | return queueManager; 144 | } 145 | 146 | public void sendConfigMessage(CommandSender sender, String path, String... replace) { 147 | HashMap replaced = new HashMap<>(); 148 | List replaceList = Arrays.asList(replace); 149 | int index = 0; 150 | for (String str : replaceList) { 151 | index++; 152 | if (index % 2 == 0) continue; 153 | replaced.put(str, replaceList.get(index)); 154 | } 155 | Optional yamlResourceBundleOptional = i18n.getYamlResourceBundleByLang(getConfigFile().getString("locale")); 156 | if (yamlResourceBundleOptional.isPresent()) { 157 | YamlResourceBundle yamlResourceBundle = yamlResourceBundleOptional.get(); 158 | List messages = yamlResourceBundle.getYamlConfig().get(path) instanceof List ? yamlResourceBundle.getStringList(path) : Collections.singletonList(yamlResourceBundle.getString(path)); 159 | 160 | messages.forEach(s -> sendConfigMessage(sender, s, replaced)); 161 | } 162 | } 163 | 164 | private void sendConfigMessage(CommandSender sender, String configMessage, HashMap replaced) { 165 | String message = ChatColor.translateAlternateColorCodes('&', configMessage.replace("%name%", sender.getName()).replace("%prefix%", i18n.getString("prefix"))); 166 | if (message.isEmpty()) return; 167 | 168 | for (Map.Entry stringEntry : replaced.entrySet()) { 169 | message = message.replace(stringEntry.getKey(), stringEntry.getValue()); 170 | } 171 | if (message.toLowerCase().startsWith("%title%")) { 172 | if(!(sender instanceof ProxiedPlayer))return; 173 | ProxiedPlayer player = (ProxiedPlayer)sender; 174 | Title title = ProxyServer.getInstance().createTitle(); 175 | 176 | title.fadeIn(0); 177 | title.fadeOut(10); 178 | title.stay(40); 179 | 180 | if (message.toLowerCase().contains("%subtitle%")) { 181 | String[] splitted = message.split("%subtitle%"); 182 | title.title(new TextComponent(splitted[0].replaceAll("(?i)%subtitle%", "").replaceAll("(?i)%title%", ""))); 183 | title.subTitle(new TextComponent(splitted[1].replaceAll("(?i)%subtitle%", "").replaceAll("(?i)%title%", ""))); 184 | } else { 185 | title.title(new TextComponent(message.replaceAll("(?i)%title%", ""))); 186 | title.subTitle(new TextComponent("")); 187 | } 188 | title.send(player); 189 | } else if (message.toLowerCase().startsWith("%subtitle%")) { 190 | if(!(sender instanceof ProxiedPlayer))return; 191 | ProxiedPlayer player = (ProxiedPlayer)sender; 192 | Title title = ProxyServer.getInstance().createTitle(); 193 | 194 | title.fadeIn(0); 195 | title.fadeOut(10); 196 | title.stay(40); 197 | if (message.toLowerCase().contains("%title%")) { 198 | String[] splitted = message.split("%title%"); 199 | title.title(new TextComponent(splitted[1].replaceAll("(?i)%subtitle%", "").replaceAll("(?i)%title%", ""))); 200 | title.subTitle(new TextComponent(splitted[0].replaceAll("(?i)%subtitle%", "").replaceAll("(?i)%title%", ""))); 201 | } else { 202 | title.subTitle(new TextComponent(message.replaceAll("(?i)%subtitle%", ""))); 203 | title.title(new TextComponent("")); 204 | } 205 | title.send(player); 206 | } else if (message.toLowerCase().startsWith("%actionbar%")) { 207 | if(!(sender instanceof ProxiedPlayer))return; 208 | ProxiedPlayer player = (ProxiedPlayer)sender; 209 | player.sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(message.replaceAll("(?i)%actionbar%", ""))); 210 | } else { 211 | sender.sendMessage(new TextComponent(message)); 212 | } 213 | } 214 | 215 | } 216 | -------------------------------------------------------------------------------- /src/main/java/fr/customentity/advancedbungeequeue/bungee/command/QueueCommand.java: -------------------------------------------------------------------------------- 1 | package fr.customentity.advancedbungeequeue.bungee.command; 2 | 3 | import fr.customentity.advancedbungeequeue.bungee.AdvancedBungeeQueue; 4 | import net.md_5.bungee.api.CommandSender; 5 | import net.md_5.bungee.api.config.ServerInfo; 6 | import net.md_5.bungee.api.connection.ProxiedPlayer; 7 | import net.md_5.bungee.api.plugin.Command; 8 | 9 | public class QueueCommand extends Command { 10 | 11 | private AdvancedBungeeQueue plugin; 12 | 13 | public QueueCommand(AdvancedBungeeQueue plugin) { 14 | super("queue", null, "advancedbungeequeue"); 15 | this.plugin = plugin; 16 | } 17 | 18 | @Override 19 | public void execute(CommandSender sender, String[] args) { 20 | if (args.length == 0) { 21 | plugin.sendConfigMessage(sender, "help"); 22 | } else { 23 | if (args[0].equalsIgnoreCase("join")) { 24 | if (!sender.hasPermission(plugin.getConfigFile().getString("permissions.join-queue-command"))) { 25 | plugin.sendConfigMessage(sender, "commands.no-permission"); 26 | return; 27 | } 28 | if (!(sender instanceof ProxiedPlayer)) return; 29 | ProxiedPlayer proxiedPlayer = (ProxiedPlayer) sender; 30 | if (args.length != 2) { 31 | plugin.sendConfigMessage(proxiedPlayer, "commands.join-command.syntax"); 32 | return; 33 | } 34 | String serverName = args[1]; 35 | ServerInfo serverInfo = plugin.getProxy().getServerInfo(serverName); 36 | if (serverInfo == null) { 37 | plugin.sendConfigMessage(proxiedPlayer, "commands.join-command.server-doesnt-exist"); 38 | return; 39 | } 40 | 41 | if(!this.plugin.getConfigFile().getStringList("queued-servers").contains(serverInfo.getName())) { 42 | plugin.sendConfigMessage(proxiedPlayer, "commands.join-command.server-not-queued"); 43 | return; 44 | } 45 | 46 | plugin.getQueueManager().addPlayerInQueue(proxiedPlayer, serverInfo); 47 | } else if (args[0].equalsIgnoreCase("on")) { 48 | if (!sender.hasPermission(plugin.getConfigFile().getString("permissions.on-queue-command"))) { 49 | plugin.sendConfigMessage(sender, "commands.no-permission"); 50 | return; 51 | } 52 | if (plugin.getQueueManager().isEnabled()) { 53 | plugin.sendConfigMessage(sender, "commands.on-command.error"); 54 | return; 55 | } 56 | plugin.getQueueManager().setEnabled(true); 57 | plugin.sendConfigMessage(sender, "commands.on-command.success"); 58 | } else if (args[0].equalsIgnoreCase("off")) { 59 | if (!sender.hasPermission(plugin.getConfigFile().getString("permissions.off-queue-command"))) { 60 | plugin.sendConfigMessage(sender, "commands.no-permission"); 61 | return; 62 | } 63 | if (!plugin.getQueueManager().isEnabled()) { 64 | plugin.sendConfigMessage(sender, "commands.off-command.error"); 65 | return; 66 | } 67 | plugin.getQueueManager().setEnabled(false); 68 | plugin.sendConfigMessage(sender, "commands.off-command.success"); 69 | } else if (args[0].equalsIgnoreCase("pause")) { 70 | if (!sender.hasPermission(plugin.getConfigFile().getString("permissions.pause-queue-command"))) { 71 | plugin.sendConfigMessage(sender, "commands.no-permission"); 72 | return; 73 | } 74 | if (plugin.getQueueManager().isPaused()) { 75 | plugin.sendConfigMessage(sender, "commands.pause-command.error"); 76 | return; 77 | } 78 | plugin.getQueueManager().setPaused(true); 79 | plugin.sendConfigMessage(sender, "commands.pause-command.success"); 80 | } else if (args[0].equalsIgnoreCase("unpause")) { 81 | if (!sender.hasPermission(plugin.getConfigFile().getString("permissions.unpause-queue-command"))) { 82 | plugin.sendConfigMessage(sender, "commands.no-permission"); 83 | return; 84 | } 85 | if (!plugin.getQueueManager().isPaused()) { 86 | plugin.sendConfigMessage(sender, "commands.unpause-command.error"); 87 | return; 88 | } 89 | plugin.getQueueManager().setPaused(false); 90 | plugin.sendConfigMessage(sender, "commands.unpause-command.success"); 91 | } 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/fr/customentity/advancedbungeequeue/bungee/data/Priority.java: -------------------------------------------------------------------------------- 1 | package fr.customentity.advancedbungeequeue.bungee.data; 2 | 3 | public class Priority { 4 | 5 | private String name; 6 | private int priority; 7 | 8 | public Priority(String name, int priority) { 9 | this.name = name; 10 | this.priority = priority; 11 | } 12 | 13 | public int getPriority() { 14 | return priority; 15 | } 16 | 17 | public String getName() { 18 | return name; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/fr/customentity/advancedbungeequeue/bungee/data/QueuedPlayer.java: -------------------------------------------------------------------------------- 1 | package fr.customentity.advancedbungeequeue.bungee.data; 2 | 3 | import net.md_5.bungee.api.ProxyServer; 4 | import net.md_5.bungee.api.config.ServerInfo; 5 | import net.md_5.bungee.api.connection.ProxiedPlayer; 6 | 7 | import java.util.*; 8 | 9 | public class QueuedPlayer { 10 | 11 | private static Set queuedPlayerSet = Collections.synchronizedSet(new HashSet<>()); 12 | 13 | private UUID uuid; 14 | private ServerInfo targetServer; 15 | private Priority priority; 16 | private boolean connecting = false; 17 | 18 | public QueuedPlayer(ProxiedPlayer proxiedPlayer, ServerInfo targetServer, Priority priority) { 19 | this.uuid = proxiedPlayer.getUniqueId(); 20 | this.targetServer = targetServer; 21 | this.priority = priority; 22 | } 23 | 24 | public void setConnecting(boolean connecting) { 25 | this.connecting = connecting; 26 | } 27 | 28 | public boolean isConnecting() { 29 | return connecting; 30 | } 31 | 32 | public UUID getUuid() { 33 | return uuid; 34 | } 35 | 36 | public ProxiedPlayer getProxiedPlayer() { 37 | return ProxyServer.getInstance().getPlayer(uuid); 38 | } 39 | 40 | public ServerInfo getTargetServer() { 41 | return targetServer; 42 | } 43 | 44 | public void setTargetServer(ServerInfo targetServer) { 45 | this.targetServer = targetServer; 46 | } 47 | 48 | public boolean isWaiting() { 49 | return this.targetServer != null; 50 | } 51 | 52 | public Priority getPriority() { 53 | return priority; 54 | } 55 | 56 | public static Optional get(ProxiedPlayer proxiedPlayer) { 57 | for(QueuedPlayer queuedPlayer : queuedPlayerSet) { 58 | if(queuedPlayer.getProxiedPlayer().equals(proxiedPlayer)) { 59 | return Optional.of(queuedPlayer); 60 | } 61 | } 62 | return Optional.empty(); 63 | } 64 | 65 | public static Optional get(UUID uuid) { 66 | for(QueuedPlayer queuedPlayer : queuedPlayerSet) { 67 | if(queuedPlayer.getProxiedPlayer().getUniqueId().equals(uuid)) { 68 | return Optional.of(queuedPlayer); 69 | } 70 | } 71 | return Optional.empty(); 72 | } 73 | 74 | public static Set getQueuedPlayerSet() { 75 | return queuedPlayerSet; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/fr/customentity/advancedbungeequeue/bungee/i18n/I18n.java: -------------------------------------------------------------------------------- 1 | package fr.customentity.advancedbungeequeue.bungee.i18n; 2 | 3 | 4 | import fr.customentity.advancedbungeequeue.bungee.AdvancedBungeeQueue; 5 | 6 | import java.util.List; 7 | import java.util.Locale; 8 | import java.util.MissingResourceException; 9 | import java.util.Optional; 10 | import java.util.concurrent.ConcurrentHashMap; 11 | import java.util.concurrent.ConcurrentMap; 12 | 13 | public class I18n { 14 | 15 | private AdvancedBungeeQueue plugin; 16 | private Locale currentLocale; 17 | private String bundleBaseName; 18 | 19 | private ConcurrentMap localeResourceBundleConcurrentMap; 20 | 21 | public I18n(AdvancedBungeeQueue plugin) { 22 | this(plugin, Locale.getDefault().getLanguage()); 23 | } 24 | 25 | public I18n(AdvancedBungeeQueue plugin, String lang) { 26 | this(plugin, lang, "messages"); 27 | } 28 | 29 | public I18n(AdvancedBungeeQueue plugin, String lang, String bundleBaseName) { 30 | this.plugin = plugin; 31 | this.localeResourceBundleConcurrentMap = new ConcurrentHashMap<>(); 32 | 33 | this.currentLocale = getLocaleByLanguageTag(lang); 34 | this.bundleBaseName = bundleBaseName; 35 | 36 | try { 37 | currentLocale.getISO3Language(); 38 | currentLocale.getISO3Country(); 39 | } catch (MissingResourceException e) { 40 | e.printStackTrace(); 41 | } 42 | 43 | this.localeResourceBundleConcurrentMap.put(lang, new YamlResourceBundle(plugin, currentLocale, bundleBaseName)); 44 | } 45 | 46 | public String getString(String path, String lang) { 47 | YamlResourceBundle yamlResourceBundle = this.localeResourceBundleConcurrentMap.getOrDefault(lang, 48 | new YamlResourceBundle(plugin, getLocaleByLanguageTag(lang), bundleBaseName)); 49 | 50 | this.localeResourceBundleConcurrentMap.putIfAbsent(lang, yamlResourceBundle); 51 | 52 | return yamlResourceBundle.getString(path); 53 | } 54 | 55 | public List getStringList(String path, String lang) { 56 | YamlResourceBundle yamlResourceBundle = this.localeResourceBundleConcurrentMap.getOrDefault(lang, 57 | new YamlResourceBundle(plugin, getLocaleByLanguageTag(lang), bundleBaseName)); 58 | 59 | this.localeResourceBundleConcurrentMap.putIfAbsent(lang, yamlResourceBundle); 60 | 61 | return yamlResourceBundle.getStringList(path); 62 | } 63 | 64 | public String getString(String path) { 65 | return this.localeResourceBundleConcurrentMap.get(currentLocale.toLanguageTag().replace("-", "_")).getString(path); 66 | } 67 | 68 | public List getStringList(String path) { 69 | return this.localeResourceBundleConcurrentMap.get(currentLocale.toLanguageTag().replace("-", "_")).getStringList(path); 70 | } 71 | 72 | public Optional getYamlResourceBundleByLang(String lang) { 73 | return Optional.ofNullable(localeResourceBundleConcurrentMap.get(lang)); 74 | } 75 | 76 | public static Locale getLocaleByLanguageTag(String lang) { 77 | String[] splitted = lang.split("_"); 78 | return splitted.length == 1 ? new Locale(splitted[0]) : new Locale(splitted[0], splitted[1]); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/fr/customentity/advancedbungeequeue/bungee/i18n/YamlResourceBundle.java: -------------------------------------------------------------------------------- 1 | package fr.customentity.advancedbungeequeue.bungee.i18n; 2 | 3 | import com.google.common.base.Charsets; 4 | import fr.customentity.advancedbungeequeue.bungee.AdvancedBungeeQueue; 5 | import net.md_5.bungee.config.Configuration; 6 | import net.md_5.bungee.config.ConfigurationProvider; 7 | import net.md_5.bungee.config.YamlConfiguration; 8 | 9 | import java.io.*; 10 | import java.net.URL; 11 | import java.net.URLConnection; 12 | import java.nio.file.Files; 13 | import java.util.Collections; 14 | import java.util.List; 15 | import java.util.Locale; 16 | import java.util.concurrent.ConcurrentHashMap; 17 | import java.util.concurrent.ConcurrentMap; 18 | import java.util.logging.Level; 19 | 20 | public class YamlResourceBundle { 21 | 22 | private AdvancedBungeeQueue plugin; 23 | 24 | private Locale locale; 25 | 26 | private String bundleBaseName; 27 | 28 | private ConcurrentMap> cachedResourceContent; 29 | 30 | private Configuration yamlConfig; 31 | 32 | private File yamlFile; 33 | 34 | private String fileName; 35 | 36 | public YamlResourceBundle(AdvancedBungeeQueue plugin, Locale locale, String bundleBaseName) { 37 | this.plugin = plugin; 38 | this.locale = locale; 39 | this.bundleBaseName = bundleBaseName; 40 | this.cachedResourceContent = new ConcurrentHashMap<>(); 41 | this.fileName = this.bundleBaseName + "_" + locale.toLanguageTag().replace("-", "_") + ".yml"; 42 | 43 | this.setupYamlResource(); 44 | } 45 | 46 | private void setupYamlResource() { 47 | if (!plugin.getDataFolder().exists()) { 48 | plugin.getDataFolder().mkdir(); 49 | } 50 | try { 51 | yamlFile = new File(plugin.getDataFolder(), this.fileName); 52 | if (!yamlFile.exists()) { 53 | plugin.saveResource(this.fileName, true); 54 | } 55 | yamlConfig = ConfigurationProvider.getProvider(YamlConfiguration.class).load(new InputStreamReader(new FileInputStream(yamlFile), Charsets.UTF_8)); 56 | } catch (IOException e) { 57 | e.printStackTrace(); 58 | } 59 | } 60 | 61 | private void refreshCache() throws IOException { 62 | yamlConfig = ConfigurationProvider.getProvider(YamlConfiguration.class).load(yamlFile); 63 | cachedResourceContent.forEach((s, o) -> cachedResourceContent.put(s, yamlConfig.getStringList(s))); 64 | } 65 | 66 | public void clearCache() { 67 | this.cachedResourceContent.clear(); 68 | } 69 | 70 | public String getString(String path) { 71 | return this.getString(path, true); 72 | } 73 | 74 | public List getStringList(String path) { 75 | return this.getStringList(path, true); 76 | } 77 | 78 | public String getString(String path, boolean useCacheIfPresent) { 79 | if (useCacheIfPresent) { 80 | return cachedResourceContent.getOrDefault(path, Collections.singletonList(yamlConfig.getString(path))).get(0); 81 | } 82 | return yamlConfig.getString(path); 83 | } 84 | 85 | public List getStringList(String path, boolean useCacheIfPresent) { 86 | if (useCacheIfPresent) return cachedResourceContent.getOrDefault(path, yamlConfig.getStringList(path)); 87 | return yamlConfig.getStringList(path); 88 | } 89 | 90 | public Configuration getYamlConfig() { 91 | return yamlConfig; 92 | } 93 | 94 | public File getYamlFile() { 95 | return yamlFile; 96 | } 97 | 98 | public String getBundleBaseName() { 99 | return bundleBaseName; 100 | } 101 | 102 | public Locale getLocale() { 103 | return locale; 104 | } 105 | 106 | public ConcurrentMap> getCachedResourceContent() { 107 | return cachedResourceContent; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/fr/customentity/advancedbungeequeue/bungee/listener/QueueListener.java: -------------------------------------------------------------------------------- 1 | package fr.customentity.advancedbungeequeue.bungee.listener; 2 | 3 | import fr.customentity.advancedbungeequeue.bungee.AdvancedBungeeQueue; 4 | import fr.customentity.advancedbungeequeue.bungee.data.QueuedPlayer; 5 | import net.md_5.bungee.api.config.ServerInfo; 6 | import net.md_5.bungee.api.connection.ProxiedPlayer; 7 | import net.md_5.bungee.api.event.PlayerDisconnectEvent; 8 | import net.md_5.bungee.api.event.ServerSwitchEvent; 9 | import net.md_5.bungee.api.plugin.Listener; 10 | import net.md_5.bungee.event.EventHandler; 11 | 12 | import java.util.Optional; 13 | 14 | public class QueueListener implements Listener { 15 | 16 | private AdvancedBungeeQueue plugin; 17 | 18 | public QueueListener(AdvancedBungeeQueue plugin) { 19 | this.plugin = plugin; 20 | } 21 | 22 | @EventHandler 23 | public void onDisconnect(PlayerDisconnectEvent event) { 24 | ProxiedPlayer proxiedPlayer = event.getPlayer(); 25 | Optional queuedPlayer = QueuedPlayer.get(proxiedPlayer); 26 | queuedPlayer.ifPresent(player -> plugin.getQueueManager().removePlayerFromQueue(player)); 27 | } 28 | 29 | @EventHandler 30 | public void onSwitch(ServerSwitchEvent event) { 31 | ServerInfo from = event.getFrom(); 32 | if (from == null) return; 33 | if (plugin.getConfigFile().getStringList("default-servers").stream().noneMatch(s -> from.getName().contains(s))) { 34 | return; 35 | } 36 | Optional queuedPlayer = QueuedPlayer.get(event.getPlayer()); 37 | if (!queuedPlayer.isPresent()) return; 38 | 39 | if (!queuedPlayer.get().isConnecting()) { 40 | plugin.getQueueManager().removePlayerFromQueue(queuedPlayer.get()); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/fr/customentity/advancedbungeequeue/bungee/manager/QueueManager.java: -------------------------------------------------------------------------------- 1 | package fr.customentity.advancedbungeequeue.bungee.manager; 2 | 3 | import fr.customentity.advancedbungeequeue.bungee.AdvancedBungeeQueue; 4 | import fr.customentity.advancedbungeequeue.bungee.data.Priority; 5 | import fr.customentity.advancedbungeequeue.bungee.data.QueuedPlayer; 6 | import fr.customentity.advancedbungeequeue.bungee.runnable.ConnectRunnable; 7 | import net.md_5.bungee.api.config.ServerInfo; 8 | import net.md_5.bungee.api.connection.ProxiedPlayer; 9 | import net.md_5.bungee.api.event.ServerConnectEvent; 10 | 11 | import java.util.ArrayList; 12 | import java.util.Collections; 13 | import java.util.List; 14 | import java.util.Optional; 15 | import java.util.concurrent.ConcurrentHashMap; 16 | import java.util.concurrent.Executors; 17 | import java.util.concurrent.ScheduledExecutorService; 18 | import java.util.concurrent.TimeUnit; 19 | import java.util.logging.Level; 20 | 21 | public class QueueManager { 22 | 23 | private AdvancedBungeeQueue plugin; 24 | 25 | private ConcurrentHashMap> queue; 26 | private ScheduledExecutorService scheduledExecutorService; 27 | 28 | private boolean paused = false; 29 | private boolean enabled = true; 30 | 31 | public QueueManager(AdvancedBungeeQueue plugin) { 32 | this.plugin = plugin; 33 | this.queue = new ConcurrentHashMap<>(); 34 | 35 | this.startQueue(); 36 | } 37 | 38 | public void startQueue() { 39 | this.loadServersQueue(); 40 | this.scheduledExecutorService = Executors.newScheduledThreadPool(queue.keySet().size()); 41 | for (ServerInfo serverInfo : queue.keySet()) { 42 | this.scheduledExecutorService.scheduleAtFixedRate(new ConnectRunnable(plugin, serverInfo), this.plugin.getConfigFile().getLong("queue-speed"), this.plugin.getConfigFile().getLong("queue-speed"), TimeUnit.MILLISECONDS); 43 | } 44 | } 45 | 46 | public boolean isPaused() { 47 | return paused; 48 | } 49 | 50 | public boolean isEnabled() { 51 | return enabled; 52 | } 53 | 54 | public void setEnabled(boolean enabled) { 55 | if (this.enabled && !enabled) { 56 | queue.clear(); 57 | QueuedPlayer.getQueuedPlayerSet().clear(); 58 | Thread thread = new Thread(() -> { 59 | this.scheduledExecutorService.shutdown(); 60 | try { 61 | this.scheduledExecutorService.awaitTermination(5, TimeUnit.SECONDS); 62 | } catch (InterruptedException e) { 63 | e.printStackTrace(); 64 | } 65 | }); 66 | thread.start(); 67 | } else if (!this.enabled && enabled) { 68 | this.startQueue(); 69 | } 70 | this.enabled = enabled; 71 | } 72 | 73 | public void setPaused(boolean paused) { 74 | this.paused = paused; 75 | } 76 | 77 | public void addPlayerInQueue(ProxiedPlayer proxiedPlayer, ServerInfo serverInfo) { 78 | if (plugin.getConfigFile().getStringList("default-servers").stream().noneMatch(s -> proxiedPlayer.getServer().getInfo().getName().contains(s))) { 79 | plugin.sendConfigMessage(proxiedPlayer, "commands.join.cannot-join-queue"); 80 | return; 81 | } 82 | if (proxiedPlayer.hasPermission(plugin.getConfigFile().getString("permissions.bypass")) || !isEnabled()) { 83 | proxiedPlayer.connect(serverInfo); 84 | return; 85 | } 86 | List queuedPlayers = queue.get(serverInfo); 87 | if (this.plugin.getConfigFile().getBoolean("use-same-queue")) 88 | queuedPlayers = queue.values().stream().findFirst().get(); 89 | 90 | if (queuedPlayers == null) return; 91 | 92 | Optional queuedPlayerOptional = QueuedPlayer.get(proxiedPlayer); 93 | if (queuedPlayerOptional.isPresent()) return; 94 | QueuedPlayer queuedPlayer = new QueuedPlayer(proxiedPlayer, serverInfo, getPriority(proxiedPlayer)); 95 | QueuedPlayer.getQueuedPlayerSet().add(queuedPlayer); 96 | 97 | boolean added = false; 98 | for (QueuedPlayer player : queuedPlayers) { 99 | if (player.getPriority().getPriority() < queuedPlayer.getPriority().getPriority()) { 100 | queuedPlayers.add(queuedPlayers.indexOf(player), queuedPlayer); 101 | added = true; 102 | break; 103 | } 104 | } 105 | if (!added) queuedPlayers.add(queuedPlayer); 106 | 107 | if (queuedPlayers.size() == 0) queuedPlayers.add(queuedPlayer); 108 | 109 | plugin.sendConfigMessage(proxiedPlayer, "commands.join.success", "%all%", queuedPlayers.size() + "", 110 | "%position%", queuedPlayers.indexOf(queuedPlayer) + 1 + "", "%priority%", queuedPlayer.getPriority().getName()); 111 | } 112 | 113 | public void removePlayerFromQueue(QueuedPlayer queuedPlayer) { 114 | ServerInfo targetServer = queuedPlayer.getTargetServer(); 115 | 116 | if (this.plugin.getConfigFile().getBoolean("use-same-queue")) 117 | targetServer = queue.keySet().stream().findFirst().get(); 118 | 119 | if(!queue.containsKey(targetServer))return; 120 | queue.get(targetServer).remove(queuedPlayer); 121 | QueuedPlayer.getQueuedPlayerSet().remove(queuedPlayer); 122 | } 123 | 124 | public Priority getPriority(ProxiedPlayer proxiedPlayer) { 125 | for (String str : plugin.getConfigFile().getSection("priorities").getKeys()) { 126 | if (proxiedPlayer.hasPermission("advancedbungeequeue.priority." + str)) 127 | return new Priority(str, plugin.getConfigFile().getInt("priorities." + str)); 128 | } 129 | String last = plugin.getConfigFile().getSection("priorities").getKeys().toArray(new String[0])[plugin.getConfigFile().getSection("priorities").getKeys().size() - 1]; 130 | return new Priority(last, plugin.getConfigFile().getInt("priorities." + last, 0)); 131 | } 132 | 133 | public int getPlayerPosition(ProxiedPlayer proxiedPlayer) { 134 | Optional queuedPlayer = QueuedPlayer.get(proxiedPlayer); 135 | if (queuedPlayer.isPresent()) { 136 | if (queue.get(queuedPlayer.get().getTargetServer()) != null) 137 | return queue.get(queuedPlayer.get().getTargetServer()).indexOf(queuedPlayer.get()) + 1; 138 | } 139 | return -1; 140 | } 141 | 142 | public void connectNextPlayers(ServerInfo serverInfo) { 143 | for (int i = 0; i < plugin.getConfigFile().getInt("player-amount"); i++) { 144 | List queuedPlayers = queue.get(serverInfo); 145 | if (i >= queuedPlayers.size()) return; 146 | QueuedPlayer queuedPlayer = queuedPlayers.get(i); 147 | if (queuedPlayer == null) continue; 148 | queuedPlayer.getTargetServer().ping((serverPing, pingError) -> { 149 | if (serverPing == null) { 150 | plugin.sendConfigMessage(queuedPlayer.getProxiedPlayer(), "general.kick-unavailable-server"); 151 | } else { 152 | int online = serverPing.getPlayers().getOnline(); 153 | int max = serverPing.getPlayers().getMax(); 154 | 155 | if (online >= max) { 156 | if (queuedPlayers.indexOf(queuedPlayer) == 0) { 157 | plugin.sendConfigMessage(queuedPlayer.getProxiedPlayer(), "general.kick-full-server"); 158 | } 159 | return; 160 | } 161 | queuedPlayer.setConnecting(true); 162 | queuedPlayer.getProxiedPlayer().connect(queuedPlayer.getTargetServer(), (result, error) -> { 163 | if (!result) { 164 | queuedPlayer.setConnecting(false); 165 | } 166 | }, ServerConnectEvent.Reason.PLUGIN); 167 | } 168 | }); 169 | } 170 | } 171 | 172 | 173 | public void loadServersQueue() { 174 | for (String servers : this.plugin.getConfigFile().getStringList("queued-servers")) { 175 | ServerInfo serverInfo = this.plugin.getProxy().getServerInfo(servers); 176 | if (serverInfo != null) { 177 | queue.putIfAbsent(serverInfo, Collections.synchronizedList(new ArrayList<>())); 178 | plugin.log(Level.INFO, "Queue enabled for server: " + serverInfo.getName()); 179 | if (this.plugin.getConfigFile().getBoolean("use-same-queue")) break; 180 | } 181 | } 182 | } 183 | 184 | public ConcurrentHashMap> getQueues() { 185 | return queue; 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /src/main/java/fr/customentity/advancedbungeequeue/bungee/runnable/ConnectRunnable.java: -------------------------------------------------------------------------------- 1 | package fr.customentity.advancedbungeequeue.bungee.runnable; 2 | 3 | import fr.customentity.advancedbungeequeue.bungee.AdvancedBungeeQueue; 4 | import net.md_5.bungee.api.config.ServerInfo; 5 | 6 | public class ConnectRunnable implements Runnable { 7 | 8 | private AdvancedBungeeQueue plugin; 9 | private ServerInfo serverInfo; 10 | 11 | public ConnectRunnable(AdvancedBungeeQueue plugin, ServerInfo serverInfo) { 12 | this.plugin = plugin; 13 | this.serverInfo = serverInfo; 14 | } 15 | 16 | @Override 17 | public void run() { 18 | if (plugin.getQueueManager().isPaused()) { 19 | return; 20 | } 21 | plugin.getQueueManager().connectNextPlayers(serverInfo); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/fr/customentity/advancedbungeequeue/bungee/socket/ServerThread.java: -------------------------------------------------------------------------------- 1 | package fr.customentity.advancedbungeequeue.bungee.socket; 2 | 3 | import fr.customentity.advancedbungeequeue.bungee.AdvancedBungeeQueue; 4 | import fr.customentity.advancedbungeequeue.bungee.data.QueuedPlayer; 5 | import fr.customentity.advancedbungeequeue.common.QueueResult; 6 | import fr.customentity.advancedbungeequeue.common.actions.Action; 7 | import fr.customentity.advancedbungeequeue.common.actions.PlayerAction; 8 | import fr.customentity.advancedbungeequeue.common.actions.all.ConfirmConnectionAction; 9 | import fr.customentity.advancedbungeequeue.common.actions.all.ExecuteCommandAction; 10 | import net.md_5.bungee.api.connection.ProxiedPlayer; 11 | import net.md_5.bungee.protocol.packet.Chat; 12 | 13 | import java.io.IOException; 14 | import java.io.InputStream; 15 | import java.io.ObjectInputStream; 16 | import java.net.Socket; 17 | import java.util.Optional; 18 | 19 | public class ServerThread implements Runnable { 20 | 21 | private AdvancedBungeeQueue plugin; 22 | private Socket client; 23 | 24 | public ServerThread(AdvancedBungeeQueue plugin, Socket client) { 25 | this.plugin = plugin; 26 | this.client = client; 27 | } 28 | 29 | @Override 30 | public void run() { 31 | try { 32 | InputStream in = client.getInputStream(); 33 | ObjectInputStream reader = new ObjectInputStream(in); 34 | 35 | String passwd = reader.readUTF(); 36 | if (plugin.getConfigFile().getString("socket-password").equals(passwd)) { 37 | Action action = (Action) reader.readObject(); 38 | if (action instanceof PlayerAction) { 39 | if (action instanceof ConfirmConnectionAction) { 40 | ConfirmConnectionAction confirmConnectionAction = (ConfirmConnectionAction) action; 41 | QueueResult result = confirmConnectionAction.getQueueResult(); 42 | Optional queuedPlayer = QueuedPlayer.get(confirmConnectionAction.getSenderUniqueId()); 43 | if (result == QueueResult.ALLOWED) { 44 | queuedPlayer.ifPresent(queuedPlayer1 -> plugin.getQueueManager().removePlayerFromQueue(queuedPlayer1)); 45 | } else if (result == QueueResult.KICK_WHITELIST) { 46 | queuedPlayer.ifPresent(queuedPlayer1 -> plugin.sendConfigMessage(queuedPlayer1.getProxiedPlayer(), "general.kick-whitelisted")); 47 | } else if (result == QueueResult.KICK_FULL) { 48 | queuedPlayer.ifPresent(queuedPlayer1 -> plugin.sendConfigMessage(queuedPlayer1.getProxiedPlayer(), "general.kick-full-server")); 49 | } else if (result == QueueResult.KICK_BANNED) { 50 | queuedPlayer.ifPresent(queuedPlayer1 -> plugin.sendConfigMessage(queuedPlayer1.getProxiedPlayer(), "general.kick-banned")); 51 | } else if (result == QueueResult.KICK_OTHER) { 52 | queuedPlayer.ifPresent(queuedPlayer1 -> plugin.sendConfigMessage(queuedPlayer1.getProxiedPlayer(), "general.kick-unavailable-server")); 53 | } 54 | } else if (action instanceof ExecuteCommandAction) { 55 | ExecuteCommandAction executeCommandAction = (ExecuteCommandAction) action; 56 | ProxiedPlayer proxiedPlayer = plugin.getProxy().getPlayer(executeCommandAction.getSenderUniqueId()); 57 | plugin.getProxy().getPluginManager().dispatchCommand(proxiedPlayer, executeCommandAction.getCommand()); 58 | } 59 | } 60 | } 61 | 62 | in.close(); 63 | reader.close(); 64 | client.close(); 65 | } catch (IOException | ClassNotFoundException e) { 66 | e.printStackTrace(); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/fr/customentity/advancedbungeequeue/bungee/socket/SocketManager.java: -------------------------------------------------------------------------------- 1 | package fr.customentity.advancedbungeequeue.bungee.socket; 2 | 3 | import fr.customentity.advancedbungeequeue.bungee.AdvancedBungeeQueue; 4 | 5 | import java.io.IOException; 6 | import java.net.ServerSocket; 7 | import java.net.Socket; 8 | import java.net.SocketException; 9 | import java.util.concurrent.ExecutorService; 10 | import java.util.concurrent.Executors; 11 | import java.util.logging.Level; 12 | 13 | public class SocketManager { 14 | 15 | ServerSocket socket; 16 | private AdvancedBungeeQueue plugin; 17 | 18 | private ExecutorService cachedExecutorService; 19 | 20 | public SocketManager(AdvancedBungeeQueue plugin) { 21 | this.plugin = plugin; 22 | 23 | this.cachedExecutorService = Executors.newCachedThreadPool(); 24 | } 25 | 26 | public void initListener() { 27 | int port = plugin.getConfigFile().getInt("socket-port", 1233); 28 | try { 29 | plugin.log(Level.INFO, "Trying to connect on port " + port + "..."); 30 | socket = new ServerSocket(port); 31 | Thread thread = new Thread(() -> { 32 | try { 33 | plugin.log(Level.INFO, "Connected on port " + port); 34 | while (!socket.isClosed()) { 35 | Socket client = socket.accept(); 36 | client.setKeepAlive(true); 37 | 38 | this.cachedExecutorService.submit(new ServerThread(plugin, client)); 39 | } 40 | 41 | } catch (IOException e) { 42 | if(e.getMessage().contains("Socket closed"))return; 43 | e.printStackTrace(); 44 | } 45 | }); 46 | thread.start(); 47 | } catch (IOException e) { 48 | plugin.log(Level.WARNING, "Cannot connect to port: " + port + ""); 49 | e.printStackTrace(); 50 | } 51 | } 52 | 53 | public ServerSocket getSocket() { 54 | return socket; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/fr/customentity/advancedbungeequeue/common/QueueResult.java: -------------------------------------------------------------------------------- 1 | package fr.customentity.advancedbungeequeue.common; 2 | 3 | public enum QueueResult { 4 | 5 | ALLOWED, 6 | 7 | KICK_FULL, 8 | 9 | KICK_BANNED, 10 | 11 | KICK_WHITELIST, 12 | 13 | KICK_OTHER 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/fr/customentity/advancedbungeequeue/common/actions/Action.java: -------------------------------------------------------------------------------- 1 | package fr.customentity.advancedbungeequeue.common.actions; 2 | 3 | import java.io.Serializable; 4 | 5 | public abstract class Action implements Serializable { 6 | 7 | public abstract Class getEntryType(); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/fr/customentity/advancedbungeequeue/common/actions/PlayerAction.java: -------------------------------------------------------------------------------- 1 | package fr.customentity.advancedbungeequeue.common.actions; 2 | 3 | import java.util.UUID; 4 | 5 | public abstract class PlayerAction extends Action { 6 | 7 | private String uuid; 8 | 9 | public PlayerAction(UUID uuid) { 10 | this.uuid = uuid.toString(); 11 | } 12 | 13 | public UUID getSenderUniqueId() { 14 | return UUID.fromString(uuid); 15 | } 16 | 17 | @Override 18 | public Class getEntryType() { 19 | return UUID.class; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/fr/customentity/advancedbungeequeue/common/actions/all/ConfirmConnectionAction.java: -------------------------------------------------------------------------------- 1 | package fr.customentity.advancedbungeequeue.common.actions.all; 2 | 3 | import fr.customentity.advancedbungeequeue.common.QueueResult; 4 | import fr.customentity.advancedbungeequeue.common.actions.PlayerAction; 5 | 6 | import java.util.UUID; 7 | 8 | public class ConfirmConnectionAction extends PlayerAction { 9 | 10 | private QueueResult queueResult; 11 | 12 | public ConfirmConnectionAction(UUID uuid, QueueResult queueResult) { 13 | super(uuid); 14 | this.queueResult = queueResult; 15 | } 16 | 17 | public QueueResult getQueueResult() { 18 | return queueResult; 19 | } 20 | } -------------------------------------------------------------------------------- /src/main/java/fr/customentity/advancedbungeequeue/common/actions/all/ExecuteCommandAction.java: -------------------------------------------------------------------------------- 1 | package fr.customentity.advancedbungeequeue.common.actions.all; 2 | 3 | import fr.customentity.advancedbungeequeue.common.actions.PlayerAction; 4 | 5 | import java.util.UUID; 6 | 7 | public class ExecuteCommandAction extends PlayerAction { 8 | 9 | private String command; 10 | 11 | public ExecuteCommandAction(UUID uuid, String command) { 12 | super(uuid); 13 | this.command = command; 14 | } 15 | 16 | public String getCommand() { 17 | return command; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/fr/customentity/advancedbungeequeue/spigot/AdvancedSpigotQueue.java: -------------------------------------------------------------------------------- 1 | package fr.customentity.advancedbungeequeue.spigot; 2 | 3 | import com.google.common.io.ByteArrayDataOutput; 4 | import com.google.common.io.ByteStreams; 5 | import fr.customentity.advancedbungeequeue.common.QueueResult; 6 | import fr.customentity.advancedbungeequeue.bungee.i18n.I18n; 7 | import net.md_5.bungee.api.event.ServerKickEvent; 8 | import org.bukkit.Bukkit; 9 | import org.bukkit.command.Command; 10 | import org.bukkit.command.CommandSender; 11 | import org.bukkit.command.ConsoleCommandSender; 12 | import org.bukkit.entity.Player; 13 | import org.bukkit.event.EventHandler; 14 | import org.bukkit.event.Listener; 15 | import org.bukkit.event.player.PlayerLoginEvent; 16 | import org.bukkit.plugin.java.JavaPlugin; 17 | 18 | import java.io.IOException; 19 | 20 | public class AdvancedSpigotQueue extends JavaPlugin implements Listener { 21 | 22 | private SocketManager socketManager; 23 | 24 | public void onEnable() { 25 | saveDefaultConfig(); 26 | 27 | Bukkit.getPluginManager().registerEvents(this, this); 28 | 29 | this.socketManager = new SocketManager(this); 30 | } 31 | 32 | public void onDisable() { 33 | try { 34 | if(socketManager != null && socketManager.getSocket() != null) 35 | socketManager.getSocket().close(); 36 | } catch (IOException e) { 37 | e.printStackTrace(); 38 | } 39 | } 40 | 41 | @EventHandler 42 | public void onLogin(PlayerLoginEvent event) { 43 | Player player = event.getPlayer(); 44 | this.socketManager.sendConnectionConfirmation(player.getUniqueId(), QueueResult.valueOf(event.getResult().name())); 45 | } 46 | 47 | public SocketManager getSocketManager() { 48 | return socketManager; 49 | } 50 | 51 | @Override 52 | public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { 53 | if(args.length == 0) { 54 | 55 | } else { 56 | if(args[0].equalsIgnoreCase("join")) { 57 | if(!(sender instanceof Player))return true; 58 | Player player = (Player)sender; 59 | if(args.length != 2) { 60 | return true; 61 | } 62 | String serverName = args[1]; 63 | this.socketManager.sendCommandToExecute(player.getUniqueId(), "queue join " + serverName); 64 | } 65 | } 66 | return false; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/fr/customentity/advancedbungeequeue/spigot/SocketManager.java: -------------------------------------------------------------------------------- 1 | package fr.customentity.advancedbungeequeue.spigot; 2 | 3 | import fr.customentity.advancedbungeequeue.common.QueueResult; 4 | import fr.customentity.advancedbungeequeue.common.actions.all.ConfirmConnectionAction; 5 | import fr.customentity.advancedbungeequeue.common.actions.all.ExecuteCommandAction; 6 | 7 | import java.io.IOException; 8 | import java.io.ObjectOutputStream; 9 | import java.io.OutputStream; 10 | import java.net.ServerSocket; 11 | import java.net.Socket; 12 | import java.net.UnknownHostException; 13 | import java.util.UUID; 14 | import java.util.logging.Level; 15 | 16 | public class SocketManager { 17 | 18 | ServerSocket socket; 19 | private AdvancedSpigotQueue plugin; 20 | 21 | public SocketManager(AdvancedSpigotQueue plugin) { 22 | this.plugin = plugin; 23 | } 24 | 25 | public void sendConnectionConfirmation(UUID uuid, QueueResult result) { 26 | Thread thread = new Thread(() -> { 27 | Socket client; 28 | try { 29 | client = new Socket(plugin.getConfig().getString("socket-host", "localhost"), plugin.getConfig().getInt("socket-port", 1233)); 30 | OutputStream out = client.getOutputStream(); 31 | ObjectOutputStream writer = new ObjectOutputStream(out); 32 | writer.writeUTF(plugin.getConfig().getString("socket-password", "TOABSOLUTELYCHANGE")); 33 | writer.writeObject(new ConfirmConnectionAction(uuid, result)); 34 | writer.flush(); 35 | writer.close(); 36 | client.close(); 37 | } catch (UnknownHostException e) { 38 | plugin.getLogger().log(Level.SEVERE, "Failed to connect to the server."); 39 | e.printStackTrace(); 40 | } catch (IOException e) { 41 | e.printStackTrace(); 42 | } 43 | }); 44 | thread.start(); 45 | } 46 | 47 | public void sendCommandToExecute(UUID uuid, String command) { 48 | Thread thread = new Thread(() -> { 49 | Socket client; 50 | try { 51 | client = new Socket(plugin.getConfig().getString("socket-host", "localhost"), plugin.getConfig().getInt("socket-port")); 52 | OutputStream out = client.getOutputStream(); 53 | ObjectOutputStream writer = new ObjectOutputStream(out); 54 | writer.writeUTF(plugin.getConfig().getString("socket-password", "TOABSOLUTELYCHANGE")); 55 | writer.writeObject(new ExecuteCommandAction(uuid, command)); 56 | writer.flush(); 57 | writer.close(); 58 | client.close(); 59 | } catch (UnknownHostException e) { 60 | plugin.getLogger().log(Level.SEVERE, "Failed to connect to the server."); 61 | e.printStackTrace(); 62 | } catch (IOException e) { 63 | e.printStackTrace(); 64 | } 65 | }); 66 | thread.start(); 67 | } 68 | 69 | public ServerSocket getSocket() { 70 | return socket; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/resources/bungee.yml: -------------------------------------------------------------------------------- 1 | name: AdvancedBungeeQueue 2 | version: @version@ 3 | main: fr.customentity.advancedbungeequeue.bungee.AdvancedBungeeQueue 4 | -------------------------------------------------------------------------------- /src/main/resources/config.yml: -------------------------------------------------------------------------------- 1 | locale: en 2 | 3 | #In miliseconds 4 | queue-speed: 2000 5 | player-amount: 2 6 | socket-host: localhost 7 | socket-port: 1233 8 | remember-queue-position-delay: 1 9 | socket-password: "TOABSOLUTELYCHANGE" 10 | use-same-queue: false 11 | default-servers: 12 | - "lobby" 13 | queued-servers: 14 | - "faction" 15 | - "invest" 16 | permissions: 17 | join-queue-command: "advancedbungeequeue.command.join" 18 | pause-queue-command: "advancedbungeequeue.command.pause" 19 | unpause-queue-command: "advancedbungeequeue.command.unpause" 20 | on-queue-command: "advancedbungeequeue.command.on" 21 | off-queue-command: "advancedbungeequeue.command.off" 22 | bypass: "advancedbungeequeue.bypass" 23 | 24 | # Permission: advancedbungeequeue.priority.high 25 | priorities: 26 | High: 3 27 | Medium: 2 28 | Low: 1 -------------------------------------------------------------------------------- /src/main/resources/messages_en.yml: -------------------------------------------------------------------------------- 1 | prefix: "&6&lQueue &7»" 2 | help: 3 | - "&6«&6&m-&e&m-----------------------------------------&6&m-&6»" 4 | - " &f✦ &e&lAdvancedBungeeQueue &f✦" 5 | - " " 6 | - " &6● &e/queue on &8- &7Turn on the queue" 7 | - " &6● &e/queue off &8- &7Turn off the queue" 8 | - " &6● &e/queue pause &8- &7Pause the queue" 9 | - " &6● &e/queue unpause &8- &7Unpause the queue" 10 | - " " 11 | - "&6«&6&m-&e&m-----------------------------------------&6&m-&6»" 12 | commands: 13 | no-permission: "%prefix% &cYou don't have permission to execute that &ccommand !" 14 | join-command: 15 | syntax: "%prefix% &cPlease use: /queue join " 16 | success: "%prefix% &eYou have successfully joined the queue! You &eare currently &6%position%&7/&6%all% &ein the queue. &bPriority: &6%priority%" 17 | cannot-join-queue: "%prefix% &cYou cannot join queue in this server!" 18 | server-doesnt-exist: "%prefix% &cServer doesn't exist" 19 | server-not-queued: "%prefix% You cannot join the queue of this server !" 20 | on-command: 21 | success: "%prefix% &eThe queue has been &aenabled&e!" 22 | error: "%prefix% &cThe queue is already enabled!" 23 | off-command: 24 | success: "%prefix% &eThe queue has been &cdisabled&e!" 25 | error: "%prefix% &cThe queue is already &cdisabled!" 26 | pause-command: 27 | success: "%prefix% &eThe queue has been paused!" 28 | error: "%prefix% &cThe queue is already paused!" 29 | unpause-command: 30 | success: "%prefix% &eThe queue has been unpaused!" 31 | error: "%prefix% &cThe queue is already unpaused!" 32 | general: 33 | repeating-position-message: "%actionbar%&eYou are currently &6%position%&7/&6%all% &ein the queue. &bPriority: &6%priority%" 34 | kick-unavailable-server: "%title%&c✖ Server Not Available ✖" 35 | kick-full-server: "%title%&c✖ Server is Full ✖%subtitle%&cPlease wait a few moments." 36 | kick-whitelisted: "%title%&c✖ Server is Whitelisted ✖" 37 | kick-banned: "%title%&c✖ You are banned from this server ✖" -------------------------------------------------------------------------------- /src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: AdvancedBungeeQueue 2 | version: @version@ 3 | main: fr.customentity.advancedbungeequeue.spigot.AdvancedSpigotQueue 4 | api-version: 1.16 5 | authors: [ CustomEntity ] 6 | commands: 7 | queue: 8 | --------------------------------------------------------------------------------